diff --git a/docs/0.9.5/.buildinfo b/docs/0.9.5/.buildinfo deleted file mode 100644 index d470be673a..0000000000 --- a/docs/0.9.5/.buildinfo +++ /dev/null @@ -1,4 +0,0 @@ -# Sphinx build info version 1 -# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: b2570a0a5088051190d8ba488ef54bb2 -tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/0.9.5/.nojekyll b/docs/0.9.5/.nojekyll deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/docs/0.9.5/A-voice-operated-elevator-using-events.html b/docs/0.9.5/A-voice-operated-elevator-using-events.html deleted file mode 100644 index 0b416338a5..0000000000 --- a/docs/0.9.5/A-voice-operated-elevator-using-events.html +++ /dev/null @@ -1,540 +0,0 @@ - - - - - - - - - A voice operated elevator using events — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

A voice operated elevator using events

- -

This tutorial will walk you through the steps to create a voice-operated elevator, using the in- -game Python -system. -This tutorial assumes the in-game Python system is installed in your game. If it isn’t, you can -follow the installation steps given in the documentation on in-game -Python, and -come back on this tutorial once the system is installed. You do not need to read the entire -documentation, it’s a good reference, but not the easiest way to learn about it. Hence these -tutorials.

-

The in-game Python system allows to run code on individual objects in some situations. You don’t -have to modify the source code to add these features, past the installation. The entire system -makes it easy to add specific features to some objects, but not all.

-
-

What will we try to do?

-
-

In this tutorial, we are going to create a simple voice-operated elevator. In terms of features, we -will:

-
    -
  • Explore events with parameters.

  • -
  • Work on more interesting callbacks.

  • -
  • Learn about chained events.

  • -
  • Play with variable modification in callbacks.

  • -
-
-

Our study case

-

Let’s summarize what we want to achieve first. We would like to create a room that will represent -the inside of our elevator. In this room, a character could just say “1”, “2” or “3”, and the -elevator will start moving. The doors will close and open on the new floor (the exits leading in -and out of the elevator will be modified).

-

We will work on basic features first, and then will adjust some, showing you how easy and powerfully -independent actions can be configured through the in-game Python system.

-
-
-

Creating the rooms and exits we need

-

We’ll create an elevator right in our room (generally called “Limbo”, of ID 2). You could easily -adapt the following instructions if you already have some rooms and exits, of course, just remember -to check the IDs.

-
-

Note: the in-game Python system uses IDs for a lot of things. While it is not mandatory, it is -good practice to know the IDs you have for your callbacks, because it will make manipulation much -quicker. There are other ways to identify objects, but as they depend on many factors, IDs are -usually the safest path in our callbacks.

-
-

Let’s go into limbo (#2) to add our elevator. We’ll add it to the north. To create this room, -in-game you could type:

-
tunnel n = Inside of an elevator
-
-
-

The game should respond by telling you:

-
Created room Inside of an elevator(#3) of type typeclasses.rooms.Room.
-Created Exit from Limbo to Inside of an elevator: north(#4) (n).
-Created Exit back from Inside of an elevator to Limbo: south(#5) (s).
-
-
-

Note the given IDs:

-
    -
  • #2 is limbo, the first room the system created.

  • -
  • #3 is our room inside of an elevator.

  • -
  • #4 is the north exit from Limbo to our elevator.

  • -
  • #5 is the south exit from an elevator to Limbo.

  • -
-

Keep these IDs somewhere for the demonstration. You will shortly see why they are important.

-
-

Why have we created exits to our elevator and back to Limbo? Isn’t the elevator supposed to move?

-
-

It is. But we need to have exits that will represent the way inside the elevator and out. What we -will do, at every floor, will be to change these exits so they become connected to the right room. -You’ll see this process a bit later.

-

We have two more rooms to create: our floor 2 and 3. This time, we’ll use dig, because we don’t -need exits leading there, not yet anyway.

-
dig The second floor
-dig The third floor
-
-
-

Evennia should answer with:

-
Created room The second floor(#6) of type typeclasses.rooms.Room.
-Created room The third floor(#7) of type typeclasses.rooms.Room.
-
-
-

Add these IDs to your list, we will use them too.

-
-
-

Our first callback in the elevator

-

Let’s go to the elevator (you could use tel #3 if you have the same IDs I have).

-

This is our elevator room. It looks a bit empty, feel free to add a prettier description or other -things to decorate it a bit.

-

But what we want now is to be able to say “1”, “2” or “3” and have the elevator move in that -direction.

-

If you have read the previous tutorial about adding dialogues in events, you -may remember what we need to do. If not, here’s a summary: we need to run some code when somebody -speaks in the room. So we need to create a callback (the callback will contain our lines of code). -We just need to know on which event this should be set. You can enter call here to see the -possible events in this room.

-

In the table, you should see the “say” event, which is called when somebody says something in the -room. So we’ll need to add a callback to this event. Don’t worry if you’re a bit lost, just follow -the following steps, the way they connect together will become more obvious.

-
call/add here = say 1, 2, 3
-
-
-
    -
  1. We need to add a callback. A callback contains the code that will be executed at a given time. -So we use the call/add command and switch.

  2. -
  3. here is our object, the room in which we are.

  4. -
  5. An equal sign.

  6. -
  7. The name of the event to which the callback should be connected. Here, the event is “say”. -Meaning this callback will be executed every time somebody says something in the room.

  8. -
  9. But we add an event parameter to indicate the keywords said in the room that should execute our -callback. Otherwise, our callback would be called every time somebody speaks, no matter what. Here -we limit, indicating our callback should be executed only if the spoken message contains “1”, “2” or -“3”.

  10. -
-

An editor should open, inviting you to enter the Python code that should be executed. The first -thing to remember is to read the text provided (it can contain important information) and, most of -all, the list of variables that are available in this callback:

-
Variables you can use in this event:
-
-    character: the character having spoken in this room.
-    room: the room connected to this event.
-    message: the text having been spoken by the character.
-
-----------Line Editor [Callback say of Inside of an elevator]---------------------
-01|
-----------[l:01 w:000 c:0000]------------(:h for help)----------------------------
-
-
-

This is important, in order to know what variables we can use in our callback out-of-the-box. Let’s -write a single line to be sure our callback is called when we expect it to:

-
character.msg("You just said {}.".format(message))
-
-
-

You can paste this line in-game, then type the :wq command to exit the editor and save your -modifications.

-

Let’s check. Try to say “hello” in the room. You should see the standard message, but nothing -more. Now try to say “1”. Below the standard message, you should see:

-
You just said 1.
-
-
-

You can try it. Our callback is only called when we say “1”, “2” or “3”. Which is just what we -want.

-

Let’s go back in our code editor and add something more useful.

-
call/edit here = say
-
-
-
-

Notice that we used the “edit” switch this time, since the callback exists, we just want to edit -it.

-
-

The editor opens again. Let’s empty it first:

-
:DD
-
-
-

And turn off automatic indentation, which will help us:

-
:=
-
-
-
-

Auto-indentation is an interesting feature of the code editor, but we’d better not use it at this -point, it will make copy/pasting more complicated.

-
-
-
-

Our entire callback in the elevator

-

So here’s the time to truly code our callback in-game. Here’s a little reminder:

-
    -
  1. We have all the IDs of our three rooms and two exits.

  2. -
  3. When we say “1”, “2” or “3”, the elevator should move to the right room, that is change the -exits. Remember, we already have the exits, we just need to change their location and destination.

  4. -
-

It’s a good idea to try to write this callback yourself, but don’t feel bad about checking the -solution right now. Here’s a possible code that you could paste in the code editor:

-
# First let's have some constants
-ELEVATOR = get(id=3)
-FLOORS = {
-    "1": get(id=2),
-    "2": get(id=6),
-    "3": get(id=7),
-}
-TO_EXIT = get(id=4)
-BACK_EXIT = get(id=5)
-
-# Now we check that the elevator isn't already at this floor
-floor = FLOORS.get(message)
-if floor is None:
-    character.msg("Which floor do you want?")
-elif TO_EXIT.location is floor:
-    character.msg("The elevator already is at this floor.")
-else:
-    # 'floor' contains the new room where the elevator should be
-    room.msg_contents("The doors of the elevator close with a clank.")
-    TO_EXIT.location = floor
-    BACK_EXIT.destination = floor
-    room.msg_contents("The doors of the elevator open to {floor}.",
-            mapping=dict(floor=floor))
-
-
-

Let’s review this longer callback:

-
    -
  1. We first obtain the objects of both exits and our three floors. We use the get() eventfunc, -which is a shortcut to obtaining objects. We usually use it to retrieve specific objects with an -ID. We put the floors in a dictionary. The keys of the dictionary are the floor number (as str), -the values are room objects.

  2. -
  3. Remember, the message variable contains the message spoken in the room. So either “1”, “2”, or -“3”. We still need to check it, however, because if the character says something like “1 2” in the -room, our callback will be executed. Let’s be sure what she says is a floor number.

  4. -
  5. We then check if the elevator is already at this floor. Notice that we use TO_EXIT.location. -TO_EXIT contains our “north” exit, leading inside of our elevator. Therefore, its location will -be the room where the elevator currently is.

  6. -
  7. If the floor is a different one, have the elevator “move”, changing just the location and -destination of both exits.

    -
      -
    • The BACK_EXIT (that is “north”) should change its location. The elevator shouldn’t be -accessible through our old floor.

    • -
    • The TO_EXIT (that is “south”, the exit leading out of the elevator) should have a different -destination. When we go out of the elevator, we should find ourselves in the new floor, not the old -one.

    • -
    -
  8. -
-

Feel free to expand on this example, changing messages, making further checks. Usage and practice -are keys.

-

You can quit the editor as usual with :wq and test it out.

-
-
-

Adding a pause in our callback

-

Let’s improve our callback. One thing that’s worth adding would be a pause: for the time being, -when we say the floor number in the elevator, the doors close and open right away. It would be -better to have a pause of several seconds. More logical.

-

This is a great opportunity to learn about chained events. Chained events are very useful to create -pauses. Contrary to the events we have seen so far, chained events aren’t called automatically. -They must be called by you, and can be called after some time.

-
    -
  • Chained events always have the name “chain_X”. Usually, X is a number, but you can give the -chained event a more explicit name.

  • -
  • In our original callback, we will call our chained events in, say, 15 seconds.

  • -
  • We’ll also have to make sure the elevator isn’t already moving.

  • -
-

Other than that, a chained event can be connected to a callback as usual. We’ll create a chained -event in our elevator, that will only contain the code necessary to open the doors to the new floor.

-
call/add here = chain_1
-
-
-

The callback is added to the “chain_1” event, an event that will not be automatically called by the -system when something happens. Inside this event, you can paste the code to open the doors at the -new floor. You can notice a few differences:

-
TO_EXIT.location = floor
-TO_EXIT.destination = ELEVATOR
-BACK_EXIT.location = ELEVATOR
-BACK_EXIT.destination = floor
-room.msg_contents("The doors of the elevator open to {floor}.",
-        mapping=dict(floor=floor))
-
-
-

Paste this code into the editor, then use :wq to save and quit the editor.

-

Now let’s edit our callback in the “say” event. We’ll have to change it a bit:

-
    -
  • The callback will have to check the elevator isn’t already moving.

  • -
  • It must change the exits when the elevator move.

  • -
  • It has to call the “chain_1” event we have defined. It should call it 15 seconds later.

  • -
-

Let’s see the code in our callback.

-
call/edit here = say
-
-
-

Remove the current code and disable auto-indentation again:

-
:DD
-:=
-
-
-

And you can paste instead the following code. Notice the differences with our first attempt:

-
# First let's have some constants
-ELEVATOR = get(id=3)
-FLOORS = {
-    "1": get(id=2),
-    "2": get(id=6),
-    "3": get(id=7),
-}
-TO_EXIT = get(id=4)
-BACK_EXIT = get(id=5)
-
-# Now we check that the elevator isn't already at this floor
-floor = FLOORS.get(message)
-if floor is None:
-    character.msg("Which floor do you want?")
-elif BACK_EXIT.location is None:
-    character.msg("The elevator is between floors.")
-elif TO_EXIT.location is floor:
-    character.msg("The elevator already is at this floor.")
-else:
-    # 'floor' contains the new room where the elevator should be
-    room.msg_contents("The doors of the elevator close with a clank.")
-    TO_EXIT.location = None
-    BACK_EXIT.location = None
-    call_event(room, "chain_1", 15)
-
-
-

What changed?

-
    -
  1. We added a little test to make sure the elevator wasn’t already moving. If it is, the -BACK_EXIT.location (the “south” exit leading out of the elevator) should be None. We’ll remove -the exit while the elevator is moving.

  2. -
  3. When the doors close, we set both exits’ location to None. Which “removes” them from their -room but doesn’t destroy them. The exits still exist but they don’t connect anything. If you say -“2” in the elevator and look around while the elevator is moving, you won’t see any exits.

  4. -
  5. Instead of opening the doors immediately, we call call_event. We give it the object containing -the event to be called (here, our elevator), the name of the event to be called (here, “chain_1”) -and the number of seconds from now when the event should be called (here, 15).

  6. -
  7. The chain_1 callback we have created contains the code to “re-open” the elevator doors. That -is, besides displaying a message, it reset the exits’ location and destination.

  8. -
-

If you try to say “3” in the elevator, you should see the doors closing. Look around you and you -won’t see any exit. Then, 15 seconds later, the doors should open, and you can leave the elevator -to go to the third floor. While the elevator is moving, the exit leading to it will be -inaccessible.

-
-

Note: we don’t define the variables again in our chained event, we just call them. When we -execute call_event, a copy of our current variables is placed in the database. These variables -will be restored and accessible again when the chained event is called.

-
-

You can use the call/tasks command to see the tasks waiting to be executed. For instance, say “2” -in the room, notice the doors closing, and then type the call/tasks command. You will see a task -in the elevator, waiting to call the chain_1 event.

-
-
-

Changing exit messages

-

Here’s another nice little feature of events: you can modify the message of a single exit without -altering the others. In this case, when someone goes north into our elevator, we’d like to see -something like: “someone walks into the elevator.” Something similar for the back exit would be -great too.

-

Inside of the elevator, you can look at the available events on the exit leading outside (south).

-
call south
-
-
-

You should see two interesting rows in this table:

-
| msg_arrive       |   0 (0) | Customize the message when a character        |
-|                  |         | arrives through this exit.                    |
-| msg_leave        |   0 (0) | Customize the message when a character leaves |
-|                  |         | through this exit.                            |
-
-
-

So we can change the message others see when a character leaves, by editing the “msg_leave” event. -Let’s do that:

-
call/add south = msg_leave
-
-
-

Take the time to read the help. It gives you all the information you should need. We’ll need to -change the “message” variable, and use custom mapping (between braces) to alter the message. We’re -given an example, let’s use it. In the code editor, you can paste the following line:

-
message = "{character} walks out of the elevator."
-
-
-

Again, save and quit the editor by entering :wq. You can create a new character to see it leave.

-
charcreate A beggar
-tel #8 = here
-
-
-

(Obviously, adapt the ID if necessary.)

-
py self.search("beggar").move_to(self.search("south"))
-
-
-

This is a crude way to force our beggar out of the elevator, but it allows us to test. You should -see:

-
A beggar(#8) walks out of the elevator.
-
-
-

Great! Let’s do the same thing for the exit leading inside of the elevator. Follow the beggar, -then edit “msg_leave” of “north”:

-
call/add north = msg_leave
-
-
-
message = "{character} walks into the elevator."
-
-
-

Again, you can force our beggar to move and see the message we have just set. This modification -applies to these two exits, obviously: the custom message won’t be used for other exits. Since we -use the same exits for every floor, this will be available no matter at what floor the elevator is, -which is pretty neat!

-
-
-

Tutorial F.A.Q.

-
    -
  • Q: what happens if the game reloads or shuts down while a task is waiting to happen?

  • -
  • A: if your game reloads while a task is in pause (like our elevator between floors), when the -game is accessible again, the task will be called (if necessary, with a new time difference to take -into account the reload). If the server shuts down, obviously, the task will not be called, but -will be stored and executed when the server is up again.

  • -
  • Q: can I use all kinds of variables in my callback? Whether chained or not?

  • -
  • A: you can use every variable type you like in your original callback. However, if you -execute call_event, since your variables are stored in the database, they will need to respect the -constraints on persistent attributes. A callback will not be stored in this way, for instance. -This variable will not be available in your chained event.

  • -
  • Q: when you say I can call my chained events something else than “chain_1”, “chain_2” and -such, what is the naming convention?

  • -
  • A: chained events have names beginning by “chain_”. This is useful for you and for the -system. But after the underscore, you can give a more useful name, like “chain_open_doors” in our -case.

  • -
  • Q: do I have to pause several seconds to call a chained event?

  • -
  • A: no, you can call it right away. Just leave the third parameter of call_event out (it -will default to 0, meaning the chained event will be called right away). This will not create a -task.

  • -
  • Q: can I have chained events calling themselves?

  • -
  • A: you can. There’s no limitation. Just be careful, a callback that calls itself, -particularly without delay, might be a good recipe for an infinite loop. However, in some cases, it -is useful to have chained events calling themselves, to do the same repeated action every X seconds -for instance.

  • -
  • Q: what if I need several elevators, do I need to copy/paste these callbacks each time?

  • -
  • A: not advisable. There are definitely better ways to handle this situation. One of them is -to consider adding the code in the source itself. Another possibility is to call chained events -with the expected behavior, which makes porting code very easy. This side of chained events will be -shown in the next tutorial.

  • -
  • Previous tutorial: Adding dialogues in events

  • -
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/API-refactoring.html b/docs/0.9.5/API-refactoring.html deleted file mode 100644 index 8a540f9030..0000000000 --- a/docs/0.9.5/API-refactoring.html +++ /dev/null @@ -1,166 +0,0 @@ - - - - - - - - - API refactoring — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

API refactoring

-

Building up to Evennia 1.0 and beyond, it’s time to comb through the Evennia API for old cruft. This -whitepage is for anyone interested to contribute with their views on what part of the API needs -refactoring, cleanup or clarification (or extension!)

-

Note that this is not a forum. To keep things clean, each opinion text should ideally present a -clear argument or lay out a suggestion. Asking for clarification and any side-discussions should be -held in chat or forum.

-
-
-

Griatch (Aug 13, 2019)

-

This is how to enter an opinion. Use any markdown needed but stay within your section. Also remember -to copy your text to the clipboard before saving since if someone else edited the wiki in the -meantime you’ll have to start over.

-
-
-

Griatch (Sept 2, 2019)

-

I don’t agree with removing explicit keywords as suggested by [Johnny on Aug 29 below](API- -refactoring#reduce-usage-of-optionalpositional-arguments-aug-29-2019). Overriding such a method can -still be done by get(self, **kwargs) if so desired, making the kwargs explicit helps IMO -readability of the API. If just giving a generic **kwargs, one must read the docstring or even the -code to see which keywords are valid.

-

On the other hand, I think it makes sense to as a standard offer an extra **kwargs at the end of -arg-lists for common methods that are expected to be over-ridden. This make the API more flexible by -hinting to the dev that they could expand their own over-ridden implementation with their own -keyword arguments if so desired.

-
-
-
-

Johnny

-
-

Reduce usage of optional/positional arguments (Aug 29, 2019)

-
# AttributeHandler
-def get(self, key=None, default=None, category=None, return_obj=False,
-            strattr=False, raise_exception=False, accessing_obj=None,
-            default_access=True, return_list=False):
-
-
-

Many classes have methods requiring lengthy positional argument lists, which are tedious and error- -prone to extend and override especially in cases where not all arguments are even required. It would -be useful if arguments were reserved for required inputs and anything else relegated to kwargs for -easier passthrough on extension.

-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Accounts.html b/docs/0.9.5/Accounts.html deleted file mode 100644 index 7018c2680f..0000000000 --- a/docs/0.9.5/Accounts.html +++ /dev/null @@ -1,216 +0,0 @@ - - - - - - - - - Accounts — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Accounts

-

All users (real people) that starts a game Session on Evennia are doing so through an -object called Account. The Account object has no in-game representation, it represents a unique -game account. In order to actually get on the game the Account must puppet an Object -(normally a Character).

-

Exactly how many Sessions can interact with an Account and its Puppets at once is determined by -Evennia’s MULTISESSION_MODE setting.

-

Apart from storing login information and other account-specific data, the Account object is what is -chatting on Channels. It is also a good place to store Permissions to be -consistent between different in-game characters as well as configuration options. The Account -object also has its own CmdSet, the AccountCmdSet.

-

Logged into default evennia, you can use the ooc command to leave your current -character and go into OOC mode. You are quite limited in this mode, basically it works -like a simple chat program. It acts as a staging area for switching between Characters (if your -game supports that) or as a safety mode if your Character gets deleted. Use ic to attempt to -(re)puppet a Character.

-

Note that the Account object can have, and often does have, a different set of -Permissions from the Character they control. Normally you should put your -permissions on the Account level - this will overrule permissions set on the Character level. For -the permissions of the Character to come into play the default quell command can be used. This -allows for exploring the game using a different permission set (but you can’t escalate your -permissions this way - for hierarchical permissions like Builder, Admin etc, the lower of the -permissions on the Character/Account will always be used).

-
-

How to create your own Account types

-

You will usually not want more than one Account typeclass for all new accounts (but you could in -principle create a system that changes an account’s typeclass dynamically).

-

An Evennia Account is, per definition, a Python class that includes evennia.DefaultAccount among -its parents. In mygame/typeclasses/accounts.py there is an empty class ready for you to modify. -Evennia defaults to using this (it inherits directly from DefaultAccount).

-

Here’s an example of modifying the default Account class in code:

-
    # in mygame/typeclasses/accounts.py
-
-    from evennia import DefaultAccount
-
-    class Account(DefaultAccount): # [...]
-
-        at_account_creation(self): "this is called only once, when account is first created"
-            self.db.real_name = None      # this is set later self.db.real_address = None   #
-"
-            self.db.config_1 = True       # default config self.db.config_2 = False      #       "
-            self.db.config_3 = 1          #       "
-
-            # ... whatever else our game needs to know ``` Reload the server with `reload`.
-
-
-
-

… However, if you use examine *self (the asterisk makes you examine your Account object rather -than your Character), you won’t see your new Attributes yet. This is because at_account_creation -is only called the very first time the Account is called and your Account object already exists -(any new Accounts that connect will see them though). To update yourself you need to make sure to -re-fire the hook on all the Accounts you have already created. Here is an example of how to do this -using py:

-

py [account.at_account_creation() for account in evennia.managers.accounts.all()]

-

You should now see the Attributes on yourself.

-
-

If you wanted Evennia to default to a completely different Account class located elsewhere, you -must point Evennia to it. Add BASE_ACCOUNT_TYPECLASS to your settings file, and give the python -path to your custom class as its value. By default this points to typeclasses.accounts.Account, -the empty template we used above.

-
-
-
-

Properties on Accounts

-

Beyond those properties assigned to all typeclassed objects (see Typeclasses), the -Account also has the following custom properties:

-
    -
  • user - a unique link to a User Django object, representing the logged-in user.

  • -
  • obj - an alias for character.

  • -
  • name - an alias for user.username

  • -
  • sessions - an instance of -ObjectSessionHandler -managing all connected Sessions (physical connections) this object listens to (Note: In older -versions of Evennia, this was a list). The so-called session-id (used in many places) is found -as -a property sessid on each Session instance.

  • -
  • is_superuser (bool: True/False) - if this account is a superuser.

  • -
-

Special handlers:

-
    -
  • cmdset - This holds all the current Commands of this Account. By default these are -the commands found in the cmdset defined by settings.CMDSET_ACCOUNT.

  • -
  • nicks - This stores and handles Nicks, in the same way as nicks it works on Objects. -For Accounts, nicks are primarily used to store custom aliases for -Channels.

  • -
-

Selection of special methods (see evennia.DefaultAccount for details):

-
    -
  • get_puppet - get a currently puppeted object connected to the Account and a given session id, if -any.

  • -
  • puppet_object - connect a session to a puppetable Object.

  • -
  • unpuppet_object - disconnect a session from a puppetable Object.

  • -
  • msg - send text to the Account

  • -
  • execute_cmd - runs a command as if this Account did it.

  • -
  • search - search for Accounts.

  • -
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Add-a-simple-new-web-page.html b/docs/0.9.5/Add-a-simple-new-web-page.html deleted file mode 100644 index e55b71eca5..0000000000 --- a/docs/0.9.5/Add-a-simple-new-web-page.html +++ /dev/null @@ -1,205 +0,0 @@ - - - - - - - - - Add a simple new web page — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Add a simple new web page

-

Evennia leverages Django which is a web development framework. -Huge professional websites are made in Django and there is extensive documentation (and books) on it -. You are encouraged to at least look at the Django basic tutorials. Here we will just give a brief -introduction for how things hang together, to get you started.

-

We assume you have installed and set up Evennia to run. A webserver and website comes out of the -box. You can get to that by entering http://localhost:4001 in your web browser - you should see a -welcome page with some game statistics and a link to the web client. Let us add a new page that you -can get to by going to http://localhost:4001/story.

-
-

Create the view

-

A django “view” is a normal Python function that django calls to render the HTML page you will see -in the web browser. Here we will just have it spit back the raw html, but Django can do all sorts of -cool stuff with the page in the view, like adding dynamic content or change it on the fly. Open -mygame/web folder and add a new module there named story.py (you could also put it in its own -folder if you wanted to be neat. Don’t forget to add an empty __init__.py file if you do, to tell -Python you can import from the new folder). Here’s how it looks:

-
# in mygame/web/story.py
-
-from django.shortcuts import render
-
-def storypage(request):
-    return render(request, "story.html")
-
-
-

This view takes advantage of a shortcut provided to use by Django, render. This shortcut gives the -template some information from the request, for instance, the game name, and then renders it.

-
-
-

The HTML page

-

We need to find a place where Evennia (and Django) looks for html files (called templates in -Django parlance). You can specify such places in your settings (see the TEMPLATES variable in -default_settings.py for more info), but here we’ll use an existing one. Go to -mygame/template/overrides/website/ and create a page story.html there.

-

This is not a HTML tutorial, so we’ll go simple:

-
{% extends "base.html" %}
-{% block content %}
-<div class="row">
-  <div class="col">
-    <h1>A story about a tree</h1>
-    <p>
-        This is a story about a tree, a classic tale ...
-    </p>
-  </div>
-</div>
-{% endblock %}
-
-
-

Since we’ve used the render shortcut, Django will allow us to extend our base styles easily.

-

If you’d rather not take advantage of Evennia’s base styles, you can do something like this instead:

-
<html>
-  <body>
-    <h1>A story about a tree</h1>
-    <p>
-    This is a story about a tree, a classic tale ...
-  </body>
-</html>
-
-
-
-
-

The URL

-

When you enter the address http://localhost:4001/story in your web browser, Django will parse that -field to figure out which page you want to go to. You tell it which patterns are relevant in the -file -mygame/web/urls.py. -Open it now.

-

Django looks for the variable urlpatterns in this file. You want to add your new pattern to the -custom_patterns list we have prepared - that is then merged with the default urlpatterns. Here’s -how it could look:

-
from web import story
-
-# ...
-
-custom_patterns = [
-    url(r'story', story.storypage, name='Story'),
-]
-
-
-

That is, we import our story view module from where we created it earlier and then create an url -instance. The first argument to url is the pattern of the url we want to find ("story") (this is -a regular expression if you are familiar with those) and then our view function we want to direct -to.

-

That should be it. Reload Evennia and you should be able to browse to your new story page!

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Add-a-wiki-on-your-website.html b/docs/0.9.5/Add-a-wiki-on-your-website.html deleted file mode 100644 index 98ba7f3bce..0000000000 --- a/docs/0.9.5/Add-a-wiki-on-your-website.html +++ /dev/null @@ -1,353 +0,0 @@ - - - - - - - - - Add a wiki on your website — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Add a wiki on your website

-

Before doing this tutorial you will probably want to read the intro in -Basic Web tutorial. Reading the three first parts of the -Django tutorial might help as well.

-

This tutorial will provide a step-by-step process to installing a wiki on your website. -Fortunately, you don’t have to create the features manually, since it has been done by others, and -we can integrate their work quite easily with Django. I have decided to focus on -the Django-wiki.

-
-

Note: this article has been updated for Evennia 0.9. If you’re not yet using this version, be -careful, as the django wiki doesn’t support Python 2 anymore. (Remove this note when enough time -has passed.)

-
-

The Django-wiki offers a lot of features associated with -wikis, is -actively maintained (at this time, anyway), and isn’t too difficult to install in Evennia. You can -see a demonstration of Django-wiki here.

-
-

Basic installation

-

You should begin by shutting down the Evennia server if it is running. We will run migrations and -alter the virtual environment just a bit. Open a terminal and activate your Python environment, the -one you use to run the evennia command.

-
    -
  • On Linux:

    -
    source evenv/bin/activate
    -
    -
    -
  • -
  • Or Windows:

    -
    evenv\bin\activate
    -
    -
    -
  • -
-
-

Installing with pip

-

Install the wiki using pip:

-
pip install wiki
-
-
-
-

Note: this will install the last version of Django wiki. Version >0.4 doesn’t support Python 2, so -install wiki 0.3 if you haven’t updated to Python 3 yet.

-
-

It might take some time, the Django-wiki having some dependencies.

-
-
-

Adding the wiki in the settings

-

You will need to add a few settings to have the wiki app on your website. Open your -server/conf/settings.py file and add the following at the bottom (but before importing -secret_settings). Here’s what you’ll find in my own setting file (add the whole Django-wiki -section):

-
r"""
-Evennia settings file.
-
-...
-
-"""
-
-# Use the defaults from Evennia unless explicitly overridden
-from evennia.settings_default import *
-
-######################################################################
-# Evennia base server config
-######################################################################
-
-# This is the name of your game. Make it catchy!
-SERVERNAME = "demowiki"
-
-######################################################################
-# Django-wiki settings
-######################################################################
-INSTALLED_APPS += (
-    'django.contrib.humanize.apps.HumanizeConfig',
-    'django_nyt.apps.DjangoNytConfig',
-    'mptt',
-    'sorl.thumbnail',
-    'wiki.apps.WikiConfig',
-    'wiki.plugins.attachments.apps.AttachmentsConfig',
-    'wiki.plugins.notifications.apps.NotificationsConfig',
-    'wiki.plugins.images.apps.ImagesConfig',
-    'wiki.plugins.macros.apps.MacrosConfig',
-)
-
-# Disable wiki handling of login/signup
-WIKI_ACCOUNT_HANDLING = False
-WIKI_ACCOUNT_SIGNUP_ALLOWED = False
-
-######################################################################
-# Settings given in secret_settings.py override those in this file.
-######################################################################
-try:
-    from server.conf.secret_settings import *
-except ImportError:
-    print("secret_settings.py file not found or failed to import.")
-
-
-
-
-

Adding the new URLs

-

Next we need to add two URLs in our web/urls.py file. Open it and compare the following output: -you will need to add two URLs in custom_patterns and add one import line:

-
from django.conf.urls import url, include
-from django.urls import path # NEW!
-
-# default evenni        a patterns
-from evennia.web.urls import urlpatterns
-
-# eventual custom patterns
-custom_patterns = [
-    # url(r'/desired/url/', view, name='example'),
-    url('notifications/', include('django_nyt.urls')), # NEW!
-    url('wiki/', include('wiki.urls')), # NEW!
-]
-
-# this is required by Django.
-urlpatterns = custom_patterns + urlpatterns
-
-
-

You will probably need to copy line 2, 10, and 11. Be sure to place them correctly, as shown in -the example above.

-
-
-

Running migrations

-

It’s time to run the new migrations. The wiki app adds a few tables in our database. We’ll need to -run:

-
evennia migrate
-
-
-

And that’s it, you can start the server. If you go to http://localhost:4001/wiki , you should see -the wiki. Use your account’s username and password to connect to it. That’s how simple it is.

-
-
-
-

Customizing privileges

-

A wiki can be a great collaborative tool, but who can see it? Who can modify it? Django-wiki comes -with a privilege system centered around four values per wiki page. The owner of an article can -always read and write in it (which is somewhat logical). The group of the article defines who can -read and who can write, if the user seeing the page belongs to this group. The topic of groups in -wiki pages will not be discussed here. A last setting determines which other user (that is, these -who aren’t in the groups, and aren’t the article’s owner) can read and write. Each article has -these four settings (group read, group write, other read, other write). Depending on your purpose, -it might not be a good default choice, particularly if you have to remind every builder to keep the -pages private. Fortunately, Django-wiki gives us additional settings to customize who can read, and -who can write, a specific article.

-

These settings must be placed, as usual, in your server/conf/settings.py file. They take a -function as argument, said function (or callback) will be called with the article and the user. -Remember, a Django user, for us, is an account. So we could check lockstrings on them if needed. -Here is a default setting to restrict the wiki: only builders can write in it, but anyone (including -non-logged in users) can read it. The superuser has some additional privileges.

-
# In server/conf/settings.py
-# ...
-
-def is_superuser(article, user):
-    """Return True if user is a superuser, False otherwise."""
-    return not user.is_anonymous() and user.is_superuser
-
-def is_builder(article, user):
-    """Return True if user is a builder, False otherwise."""
-    return not user.is_anonymous() and user.locks.check_lockstring(user, "perm(Builders)")
-
-def is_anyone(article, user):
-    """Return True even if the user is anonymous."""
-    return True
-
-# Who can create new groups and users from the wiki?
-WIKI_CAN_ADMIN = is_superuser
-# Who can change owner and group membership?
-WIKI_CAN_ASSIGN = is_superuser
-# Who can change group membership?
-WIKI_CAN_ASSIGN_OWNER = is_superuser
-# Who can change read/write access to groups or others?
-WIKI_CAN_CHANGE_PERMISSIONS = is_superuser
-# Who can soft-delete an article?
-WIKI_CAN_DELETE = is_builder
-# Who can lock an article and permanently delete it?
-WIKI_CAN_MODERATE = is_superuser
-# Who can edit articles?
-WIKI_CAN_WRITE = is_builder
-# Who can read articles?
-WIKI_CAN_READ = is_anyone
-
-
-

Here, we have created three functions: one to return True if the user is the superuser, one to -return True if the user is a builder, one to return True no matter what (this includes if the -user is anonymous, E.G. if it’s not logged-in). We then change settings to allow either the -superuser or -each builder to moderate, read, write, delete, and more. You can, of course, add more functions, -adapting them to your need. This is just a demonstration.

-

Providing the WIKI_CAN*... settings will bypass the original permission system. The superuser -could change permissions of an article, but still, only builders would be able to write it. If you -need something more custom, you will have to expand on the functions you use.

-
-

Managing wiki pages from Evennia

-

Unfortunately, Django wiki doesn’t provide a clear and clean entry point to read and write articles -from Evennia and it doesn’t seem to be a very high priority. If you really need to keep Django wiki -and to create and manage wiki pages from your code, you can do so, but this article won’t elaborate, -as this is somewhat more technical.

-

However, it is a good opportunity to present a small project that has been created more recently: -evennia-wiki has been created to provide a simple -wiki, more tailored to Evennia and easier to connect. It doesn’t, as yet, provide as many options -as does Django wiki, but it’s perfectly usable:

-
    -
  • Pages have an inherent and much-easier to understand hierarchy based on URLs.

  • -
  • Article permissions are connected to Evennia groups and are much easier to accommodate specific -requirements.

  • -
  • Articles can easily be created, read or updated from the Evennia code itself.

  • -
  • Markdown is fully-supported with a default integration to Bootstrap to look good on an Evennia -website. Tables and table of contents are supported as well as wiki links.

  • -
  • The process to override wiki templates makes full use of the template_overrides directory.

  • -
-

However evennia-wiki doesn’t yet support:

-
    -
  • Images in markdown and the uploading schema. If images are important to you, please consider -contributing to this new project.

  • -
  • Modifying permissions on a per page/setting basis.

  • -
  • Moving pages to new locations.

  • -
  • Viewing page history.

  • -
-

Considering the list of features in Django wiki, obviously other things could be added to the list. -However, these features may be the most important and useful. Additional ones might not be that -necessary. If you’re interested in supporting this little project, you are more than welcome to -contribute to it. Thanks!

-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Adding-Command-Tutorial.html b/docs/0.9.5/Adding-Command-Tutorial.html deleted file mode 100644 index 1bd1d3f4fd..0000000000 --- a/docs/0.9.5/Adding-Command-Tutorial.html +++ /dev/null @@ -1,278 +0,0 @@ - - - - - - - - - Adding Command Tutorial — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Adding Command Tutorial

-

This is a quick first-time tutorial expanding on the Commands documentation.

-

Let’s assume you have just downloaded Evennia, installed it and created your game folder (let’s call -it just mygame here). Now you want to try to add a new command. This is the fastest way to do it.

-
-

Step 1: Creating a custom command

-
    -
  1. Open mygame/commands/command.py in a text editor. This is just one place commands could be -placed but you get it setup from the onset as an easy place to start. It also already contains some -example code.

  2. -
  3. Create a new class in command.py inheriting from default_cmds.MuxCommand. Let’s call it -CmdEcho in this example.

  4. -
  5. Set the class variable key to a good command name, like echo.

  6. -
  7. Give your class a useful docstring. A docstring is the string at the very top of a class or -function/method. The docstring at the top of the command class is read by Evennia to become the help -entry for the Command (see -Command Auto-help).

  8. -
  9. Define a class method func(self) that echoes your input back to you.

  10. -
-

Below is an example how this all could look for the echo command:

-
        # file mygame/commands/command.py
-        #[...]
-        from evennia import default_cmds
-        class CmdEcho(default_cmds.MuxCommand):
-            """
-            Simple command example
-    
-            Usage:
-              echo [text]
-    
-            This command simply echoes text back to the caller.
-            """
-    
-            key = "echo"
-    
-            def func(self):
-                "This actually does things"
-                if not self.args:
-                    self.caller.msg("You didn't enter anything!")
-                else:
-                    self.caller.msg("You gave the string: '%s'" % self.args)
-
-
-
-
-

Step 2: Adding the Command to a default Cmdset

-

The command is not available to use until it is part of a Command Set. In this -example we will go the easiest route and add it to the default Character commandset that already -exists.

-
    -
  1. Edit mygame/commands/default_cmdsets.py

  2. -
  3. Import your new command with from commands.command import CmdEcho.

  4. -
  5. Add a line self.add(CmdEcho()) to CharacterCmdSet, in the at_cmdset_creation method (the -template tells you where).

  6. -
-

This is approximately how it should look at this point:

-
        # file mygame/commands/default_cmdsets.py
-        #[...]
-        from commands.command import CmdEcho
-        #[...]
-        class CharacterCmdSet(default_cmds.CharacterCmdSet):
-        
-            key = "DefaultCharacter"
-    
-            def at_cmdset_creation(self):
-    
-                # this first adds all default commands
-                super().at_cmdset_creation()
-    
-                # all commands added after this point will extend or
-                # overwrite the default commands.
-                self.add(CmdEcho())
-
-
-

Next, run the @reload command. You should now be able to use your new echo command from inside -the game. Use help echo to see the documentation for the command.

-

If you have trouble, make sure to check the log for error messages (probably due to syntax errors in -your command definition).

-
-

Note: Typing echotest will also work. It will be handled as the command echo directly followed -by -its argument test (which will end up in self.args). To change this behavior, you can add the arg_regexproperty alongsidekey, help_category` etc. See the arg_regex -documentation for more info.

-
-

If you want to overload existing default commands (such as look or get), just add your new -command with the same key as the old one - it will then replace it. Just remember that you must use -@reload to see any changes.

-

See Commands for many more details and possibilities when defining Commands and using -Cmdsets in various ways.

-
-
-

Adding the command to specific object types

-

Adding your Command to the CharacterCmdSet is just one easy exapmple. The cmdset system is very -generic. You can create your own cmdsets (let’s say in a module mycmdsets.py) and add them to -objects as you please (how to control their merging is described in detail in the Command Set -documentation).

-
    # file mygame/commands/mycmdsets.py
-    #[...]
-    from commands.command import CmdEcho
-    from evennia import CmdSet
-    #[...]
-    class MyCmdSet(CmdSet):
-        
-        key = "MyCmdSet"
-    
-        def at_cmdset_creation(self):
-            self.add(CmdEcho())
-
-
-

Now you just need to add this to an object. To test things (as superuser) you can do

-
 @py self.cmdset.add("mycmdsets.MyCmdSet")
-
-
-

This will add this cmdset (along with its echo command) to yourself so you can test it. Note that -you cannot add a single Command to an object on its own, it must be part of a CommandSet in order to -do so.

-

The Command you added is not there permanently at this point. If you do a @reload the merger will -be gone. You could add the permanent=True keyword to the cmdset.add call. This will however -only make the new merged cmdset permanent on that single object. Often you want all objects of -this particular class to have this cmdset.

-

To make sure all new created objects get your new merged set, put the cmdset.add call in your -custom Typeclassesat_object_creation method:

-
    # e.g. in mygame/typeclasses/objects.py
-
-    from evennia import DefaultObject
-    class MyObject(DefaultObject):
-        
-        def at_object_creation(self):
-            "called when the object is first created"
-            self.cmdset.add("mycmdset.MyCmdSet", permanent=True)
-
-
-

All new objects of this typeclass will now start with this cmdset and it will survive a @reload.

-

Note: An important caveat with this is that at_object_creation is only called once, when the -object is first created. This means that if you already have existing objects in your databases -using that typeclass, they will not have been initiated the same way. There are many ways to update -them; since it’s a one-time update you can usually just simply loop through them. As superuser, try -the following:

-
 @py from typeclasses.objects import MyObject; [o.cmdset.add("mycmdset.MyCmdSet") for o in
-
-
-

MyObject.objects.all()]

-

This goes through all objects in your database having the right typeclass, adding the new cmdset to -each. The good news is that you only have to do this if you want to post-add cmdsets. If you just -want to add a new command, you can simply add that command to the cmdset’s at_cmdset_creation -and @reload to make the Command immediately available.

-
-
-

Change where Evennia looks for command sets

-

Evennia uses settings variables to know where to look for its default command sets. These are -normally not changed unless you want to re-organize your game folder in some way. For example, the -default character cmdset defaults to being defined as

-
CMDSET_CHARACTER="commands.default_cmdset.CharacterCmdSet"
-
-
-

See evennia/settings_default.py for the other settings.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Adding-Object-Typeclass-Tutorial.html b/docs/0.9.5/Adding-Object-Typeclass-Tutorial.html deleted file mode 100644 index d41e1c583b..0000000000 --- a/docs/0.9.5/Adding-Object-Typeclass-Tutorial.html +++ /dev/null @@ -1,226 +0,0 @@ - - - - - - - - - Adding Object Typeclass Tutorial — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Adding Object Typeclass Tutorial

-

Evennia comes with a few very basic classes of in-game entities:

-
DefaultObject
-   |
-   DefaultCharacter
-   DefaultRoom
-   DefaultExit
-   DefaultChannel
-
-
-

When you create a new Evennia game (with for example evennia --init mygame) Evennia will -automatically create empty child classes Object, Character, Room and Exit respectively. They -are found mygame/typeclasses/objects.py, mygame/typeclasses/rooms.py etc.

-
-

Technically these are all Typeclassed, which can be ignored for now. In -mygame/typeclasses are also base typeclasses for out-of-character things, notably -Channels, Accounts and Scripts. We don’t cover those in -this tutorial.

-
-

For your own game you will most likely want to expand on these very simple beginnings. It’s normal -to want your Characters to have various attributes, for example. Maybe Rooms should hold extra -information or even all Objects in your game should have properties not included in basic Evennia.

-
-

Change Default Rooms, Exits, Character Typeclass

-

This is the simplest case.

-

The default build commands of a new Evennia game is set up to use the Room, Exit and Character -classes found in the same-named modules under mygame/typeclasses/. By default these are empty and -just implements the default parents from the Evennia library (DefaultRoometc). Just add the -changes you want to these classes and run @reload to add your new functionality.

-
-
-

Create a new type of object

-

Say you want to create a new “Heavy” object-type that characters should not have the ability to pick -up.

-
    -
  1. Edit mygame/typeclasses/objects.py (you could also create a new module there, named something -like heavy.py, that’s up to how you want to organize things).

  2. -
  3. Create a new class inheriting at any distance from DefaultObject. It could look something like -this:

  4. -
-
    # end of file mygame/typeclasses/objects.py
-    from evennia import DefaultObject
-    
-    class Heavy(DefaultObject):
-       "Heavy object"
-       def at_object_creation(self):
-           "Called whenever a new object is created"
-           # lock the object down by default
-           self.locks.add("get:false()")
-           # the default "get" command looks for this Attribute in order
-           # to return a customized error message (we just happen to know
-           # this, you'd have to look at the code of the 'get' command to
-           # find out).
-           self.db.get_err_msg = "This is too heavy to pick up."
-
-
-
    -
  1. Once you are done, log into the game with a build-capable account and do @create/drop rock:objects.Heavy to drop a new heavy “rock” object in your location. Next try to pick it up -(@quell yourself first if you are a superuser). If you get errors, look at your log files where -you will find the traceback. The most common error is that you have some sort of syntax error in -your class.

  2. -
-

Note that the Locks and Attribute which are set in the typeclass could just -as well have been set using commands in-game, so this is a very simple example.

-
-
-

Storing data on initialization

-

The at_object_creation is only called once, when the object is first created. This makes it ideal -for database-bound things like Attributes. But sometimes you want to create temporary -properties (things that are not to be stored in the database but still always exist every time the -object is created). Such properties can be initialized in the at_init method on the object. -at_init is called every time the object is loaded into memory.

-
-

Note: It’s usually pointless and wasteful to assign database data in at_init, since this will -hit the database with the same value over and over. Put those in at_object_creation instead.

-
-

You are wise to use ndb (non-database Attributes) to store these non-persistent properties, since -ndb-properties are protected against being cached out in various ways and also allows you to list -them using various in-game tools:

-
def at_init(self):
-    self.ndb.counter = 0
-    self.ndb.mylist = []
-
-
-
-

Note: As mentioned in the Typeclasses documentation, at_init replaces the use of -the standard __init__ method of typeclasses due to how the latter may be called in situations -other than you’d expect. So use at_init where you would normally use __init__.

-
-
-
-

Updating existing objects

-

If you already have some Heavy objects created and you add a new Attribute in -at_object_creation, you will find that those existing objects will not have this Attribute. This -is not so strange, since at_object_creation is only called once, it will not be called again just -because you update it. You need to update existing objects manually.

-

If the number of objects is limited, you can use @typeclass/force/reload objectname to force a -re-load of the at_object_creation method (only) on the object. This case is common enough that -there is an alias @update objectname you can use to get the same effect. If there are multiple -objects you can use @py to loop over the objects you need:

-
@py from typeclasses.objects import Heavy; [obj.at_object_creation() for obj in Heavy.objects.all()]
-
-
-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Administrative-Docs.html b/docs/0.9.5/Administrative-Docs.html deleted file mode 100644 index e7588ce842..0000000000 --- a/docs/0.9.5/Administrative-Docs.html +++ /dev/null @@ -1,205 +0,0 @@ - - - - - - - - - Administrative Docs — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - - - -
-
- -
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Apache-Config.html b/docs/0.9.5/Apache-Config.html deleted file mode 100644 index e1214c7b21..0000000000 --- a/docs/0.9.5/Apache-Config.html +++ /dev/null @@ -1,310 +0,0 @@ - - - - - - - - - Apache Config — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Apache Config

-

Warning: This information is presented as a convenience, using another webserver than Evennia’s -own is not directly supported and you are on your own if you want to do so. Evennia’s webserver -works out of the box without any extra configuration and also runs in-process making sure to avoid -caching race conditions. The browser web client will most likely not work (at least not without -tweaking) on a third-party web server.

-

One reason for wanting to use an external webserver like Apache would be to act as a proxy in -front of the Evennia webserver. Getting this working with TLS (encryption) requires some extra work -covered at the end of this page.

-

Note that the Apache instructions below might be outdated. If something is not working right, or you -use Evennia with a different server, please let us know. Also, if there is a particular Linux distro -you would like covered, please let us know.

-
-

mod_wsgi Setup

-
-

Install mod_wsgi

-
    -
  • Fedora/RHEL - Apache HTTP Server and mod_wsgi are available in the standard package -repositories for Fedora and RHEL:

    -
    $ dnf install httpd mod_wsgi
    -or
    -$ yum install httpd mod_wsgi
    -
    -
    -
  • -
  • Ubuntu/Debian - Apache HTTP Server and mod_wsgi are available in the standard package -repositories for Ubuntu and Debian:

    -
    $ apt-get update
    -$ apt-get install apache2 libapache2-mod-wsgi
    -
    -
    -
  • -
-
-
-

Copy and modify the VHOST

-

After mod_wsgi is installed, copy the evennia/web/utils/evennia_wsgi_apache.conf file to your -apache2 vhosts/sites folder. On Debian/Ubuntu, this is /etc/apache2/sites-enabled/. Make your -modifications after copying the file there.

-

Read the comments and change the paths to point to the appropriate locations within your setup.

-
-
-

Restart/Reload Apache

-

You’ll then want to reload or restart apache2 after changing the configurations.

-
    -
  • Fedora/RHEL/Ubuntu

    -
    $ systemctl restart httpd
    -
    -
    -
  • -
  • Ubuntu/Debian

    -
    $ systemctl restart apache2
    -
    -
    -
  • -
-
-
-

Enjoy

-

With any luck, you’ll be able to point your browser at your domain or subdomain that you set up in -your vhost and see the nifty default Evennia webpage. If not, read the hopefully informative error -message and work from there. Questions may be directed to our Evennia Community -site.

-
-
-

A note on code reloading

-

If your mod_wsgi is set up to run on daemon mode (as will be the case by default on Debian and -Ubuntu), you may tell mod_wsgi to reload by using the touch command on -evennia/game/web/utils/apache_wsgi.conf. When mod_wsgi sees that the file modification time has -changed, it will force a code reload. Any modifications to the code will not be propagated to the -live instance of your site until reloaded.

-

If you are not running in daemon mode or want to force the issue, simply restart or reload apache2 -to apply your changes.

-
-
-

Further notes and hints:

-

If you get strange (and usually uninformative) Permission denied errors from Apache, make sure -that your evennia directory is located in a place the webserver may actually access. For example, -some Linux distributions may default to very restrictive access permissions on a user’s /home -directory.

-

One user commented that they had to add the following to their Apache config to get things to work. -Not confirmed, but worth trying if there are trouble.

-
<Directory "/home/<yourname>/evennia/game/web">
-                Options +ExecCGI
-                Allow from all
-</Directory>
-
-
-
-
-
-

mod_proxy and mod_ssl setup

-

Below are steps on running Evennia using a front-end proxy (Apache HTTP), mod_proxy_http, -mod_proxy_wstunnel, and mod_ssl. mod_proxy_http and mod_proxy_wstunnel will simply be -referred to as -mod_proxy below.

-
-

Install mod_ssl

-
    -
  • Fedora/RHEL - Apache HTTP Server and mod_ssl are available in the standard package -repositories for Fedora and RHEL:

    -
    $ dnf install httpd mod_ssl
    -or
    -$ yum install httpd mod_ssl
    -
    -
    -
    -
  • -
  • Ubuntu/Debian - Apache HTTP Server and mod_ssljkl are installed together in the apache2 -package and available in the -standard package repositories for Ubuntu and Debian. mod_ssl needs to be enabled after -installation:

    -
    $ apt-get update
    -$ apt-get install apache2
    -$ a2enmod ssl
    -
    -
    -
    -
  • -
-
-
-

TLS proxy+websocket configuration

-

Below is a sample configuration for Evennia with a TLS-enabled http and websocket proxy.

-
-

Apache HTTP Server Configuration

-
<VirtualHost *:80>
-  # Always redirect to https/443
-  ServerName mud.example.com
-  Redirect / https://mud.example.com
-</VirtualHost>
-
-<VirtualHost *:443>
-  ServerName mud.example.com
-  
-  SSLEngine On
-  
-  # Location of certificate and key
-  SSLCertificateFile /etc/pki/tls/certs/mud.example.com.crt
-  SSLCertificateKeyFile /etc/pki/tls/private/mud.example.com.key
-  
-  # Use a tool https://www.ssllabs.com/ssltest/ to scan your set after setting up.
-  SSLProtocol TLSv1.2
-  SSLCipherSuite HIGH:!eNULL:!NULL:!aNULL
-  
-  # Proxy all websocket traffic to port 4002 in Evennia
-  ProxyPass /ws ws://127.0.0.1:4002/
-  ProxyPassReverse /ws ws://127.0.0.1:4002/
-  
-  # Proxy all HTTP traffic to port 4001 in Evennia
-  ProxyPass / http://127.0.0.1:4001/
-  ProxyPassReverse / http://127.0.0.1:4001/
-  
-  # Configure separate logging for this Evennia proxy
-  ErrorLog logs/evennia_error.log
-  CustomLog logs/evennia_access.log combined
-</VirtualHost>
-
-
-
-
-

Evennia secure websocket configuration

-

There is a slight trick in setting up Evennia so websocket traffic is handled correctly by the -proxy. You must set the WEBSOCKET_CLIENT_URL setting in your mymud/server/conf/settings.py file:

-
WEBSOCKET_CLIENT_URL = "wss://external.example.com/ws"
-
-
-

The setting above is what the client’s browser will actually use. Note the use of wss:// is -because our client will be communicating over an encrypted connection (“wss” indicates websocket -over SSL/TLS). Also, especially note the additional path /ws at the end of the URL. This is how -Apache HTTP Server identifies that a particular request should be proxied to Evennia’s websocket -port but this should be applicable also to other types of proxies (like nginx).

-
-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Arxcode-installing-help.html b/docs/0.9.5/Arxcode-installing-help.html deleted file mode 100644 index 1078636710..0000000000 --- a/docs/0.9.5/Arxcode-installing-help.html +++ /dev/null @@ -1,366 +0,0 @@ - - - - - - - - - Arxcode installing help — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Arxcode installing help

-
-

Introduction

-

Arx - After the Reckoning is a big and very popular -Evennia-based game. Arx is heavily roleplaying-centric, relying on game -masters to drive the story. Technically it’s maybe best described as “a MUSH, but with more coded -systems”. In August of 2018, the game’s developer, Tehom, generously released the source code of -Arx on github. This is a treasure-trove for developers wanting -to pick ideas or even get a starting game to build on. These instructions are based on the Arx-code -released as of Aug 12, 2018.

-

If you are not familiar with what Evennia is, you can read -an introduction here.

-

It’s not too hard to run Arx from the sources (of course you’ll start with an empty database) but -since part of Arx has grown organically, it doesn’t follow standard Evennia paradigms everywhere. -This page covers one take on installing and setting things up while making your new Arx-based game -better match with the vanilla Evennia install.

-
-
-

Installing Evennia

-

Firstly, set aside a folder/directory on your drive for everything to follow.

-

You need to start by installing Evennia by following most of the Getting -Started -Instructions for your OS. The difference is that you need to git clone https://github.com/TehomCD/evennia.git instead of Evennia’s repo because Arx uses TehomCD’s older -Evennia 0.8 fork, notably still using Python2. This detail is -important if referring to newer Evennia documentation.

-

If you are new to Evennia it’s highly recommended that you run through the -instructions in full - including initializing and starting a new empty game and connecting to it. -That way you can be sure Evennia works correctly as a base line. If you have trouble, make sure to -read the Troubleshooting instructions for your -operating system. You can also drop into our -forums, join #evennia on irc.freenode.net -or chat from the linked Discord Server.

-

After installing you should have a virtualenv running and you should have the following file -structure in your set-aside folder:

-
vienv/
-evennia/
-mygame/
-
-
-
-

Here mygame is the empty game you created during the Evennia install, with evennia --init. Go to -that and run evennia stop to make sure your empty game is not running. We’ll instead let Evenna -run Arx, so in principle you could erase mygame - but it could also be good to have a clean game -to compare to.

-
-
-

Installing Arxcode

-
-

Clone the arxcode repo

-

Cd to the root of your directory and clone the released source code from github:

-
git clone https://github.com/Arx-Game/arxcode.git myarx
-
-
-

A new folder myarx should appear next to the ones you already had. You could rename this to -something else if you want.

-

Cd into myarx. If you wonder about the structure of the game dir, you can read more about it -here.

-
-
-

Clean up settings

-

Arx has split evennia’s normal settings into base_settings.py and production_settings.py. It -also has its own solution for managing ‘secret’ parts of the settings file. We’ll keep most of Arx -way but remove the secret-handling and replace it with the normal Evennia method.

-

Cd into myarx/server/conf/ and open the file settings.py in a text editor. The top part (within -"""...""") is just help text. Wipe everything underneath that and make it look like this instead -(don’t forget to save):

-
from base_settings import *
-    
-TELNET_PORTS = [4000]
-SERVERNAME = "MyArx"
-GAME_SLOGAN = "The cool game"
-
-try:
-    from server.conf.secret_settings import *
-except ImportError:
-    print("secret_settings.py file not found or failed to import.")
-
-
-
-

Note: Indents and capitalization matter in Python. Make indents 4 spaces (not tabs) for your own -sanity. If you want a starter on Python in Evennia, [you can look here](Python-basic- -introduction).

-
-

This will import Arx’ base settings and override them with the Evennia-default telnet port and give -the game a name. The slogan changes the sub-text shown under the name of your game in the website -header. You can tweak these to your own liking later.

-

Next, create a new, empty file secret_settings.py in the same location as the settings.py file. -This can just contain the following:

-
SECRET_KEY = "sefsefiwwj3 jnwidufhjw4545_oifej whewiu hwejfpoiwjrpw09&4er43233fwefwfw"
-
-
-
-

Replace the long random string with random ASCII characters of your own. The secret key should not -be shared.

-

Next, open myarx/server/conf/base_settings.py in your text editor. We want to remove/comment out -all mentions of the decouple package, which Evennia doesn’t use (we use private_settings.py to -hide away settings that should not be shared).

-

Comment out from decouple import config by adding a # to the start of the line: # from decouple import config. Then search for config( in the file and comment out all lines where this is used. -Many of these are specific to the server environment where the original Arx runs, so is not that -relevant to us.

-
-
-

Install Arx dependencies

-

Arx has some further dependencies beyond vanilla Evennia. Start by cd:ing to the root of your -myarx folder.

-
-

If you run Linux or Mac: Edit myarx/requirements.txt and comment out the line -pypiwin32==219 - it’s only needed on Windows and will give an error on other platforms.

-
-

Make sure your virtualenv is active, then run

-
pip install -r requirements.txt
-
-
-

The needed Python packages will be installed for you.

-
-
-

Adding logs/ folder

-

The Arx repo does not contain the myarx/server/logs/ folder Evennia expects for storing server -logs. This is simple to add:

-
# linux/mac
-mkdir server/logs
-# windows
-mkdir server\logs
-
-
-
-
-

Setting up the database and starting

-

From the myarx folder, run

-
evennia migrate
-
-
-

This creates the database and will step through all database migrations needed.

-
evennia start
-
-
-

If all goes well Evennia will now start up, running Arx! You can connect to it on localhost (or -127.0.0.1 if your platform doesn’t alias localhost), port 4000 using a Telnet client. -Alternatively, you can use your web browser to browse to http://localhost:4001 to see the game’s -website and get to the web client.

-

When you log in you’ll get the standard Evennia greeting (since the database is empty), but you can -try help to see that it’s indeed Arx that is running.

-
-
-

Additional Setup Steps

-

The first time you start Evennia after creating the database with the evennia migrate step above, -it should create a few starting objects for you - your superuser account, which it will prompt you -to enter, a starting room (Limbo), and a character object for you. If for some reason this does not -occur, you may have to follow the steps below. For the first time Superuser login you may have to -run steps 7-8 and 10 to create and connect to your in-came Character.

-
    -
  1. Login to the game website with your Superuser account.

  2. -
  3. Press the Admin button to get into the (Django-) Admin Interface.

  4. -
  5. Navigate to the Accounts section.

  6. -
  7. Add a new Account named for the new staffer. Use a place holder password and dummy e-mail -address.

  8. -
  9. Flag account as Staff and apply the Admin permission group (This assumes you have already set -up an Admin Group in Django).

  10. -
  11. Add Tags named player and developer.

  12. -
  13. Log into the game using the web client (or a third-party telnet client) using your superuser -account. Move to where you want the new staffer character to appear.

  14. -
  15. In the game client, run @create/drop <staffername>:typeclasses.characters.Character, where -<staffername> is usually the same name you used for the Staffer account you created in the -Admin earlier (if you are creating a Character for your superuser, use your superuser account -name). -This creates a new in-game Character and places it in your current location.

  16. -
  17. Have the new Admin player log into the game.

  18. -
  19. Have the new Admin puppet the character with @ic StafferName.

  20. -
  21. Have the new Admin change their password - @password <old password> = <new password>.

  22. -
-

Now that you have a Character and an Account object, there’s a few additional things you may need to -do in order for some commands to function properly. You can either execute these as in-game commands -while @ic (controlling your character object).

-
    -
  1. @py from web.character.models import RosterEntry;RosterEntry.objects.create(player=self.player, character=self)

  2. -
  3. @py from world.dominion.models import PlayerOrNpc, AssetOwner;dompc = PlayerOrNpc.objects.create(player = self.player);AssetOwner.objects.create(player=dompc)

  4. -
-

Those steps will give you a ‘RosterEntry’, ‘PlayerOrNpc’, and ‘AssetOwner’ objects. RosterEntry -explicitly connects a character and account object together, even while offline, and contains -additional information about a character’s current presence in game (such as which ‘roster’ they’re -in, if you choose to use an active roster of characters). PlayerOrNpc are more character extensions, -as well as support for npcs with no in-game presence and just represented by a name which can be -offscreen members of a character’s family. It also allows for membership in Organizations. -AssetOwner holds information about a character or organization’s money and resources.

-
-
-
-

Alternate guide by Pax for installing on Windows

-

If for some reason you cannot use the Windows Subsystem for Linux (which would use instructions -identical to the ones above), it’s possible to get Evennia running under Anaconda for Windows. The -process is a little bit trickier.

-

Make sure you have:

- -

conda update conda -conda create -n arx python=2.7 -source activate arx

-

Set up a convenient repository place for things.

-

cd ~ -mkdir Source -cd Source -mkdir Arx -cd Arx

-

Replace the SSH git clone links below with your own github forks. -If you don’t plan to change Evennia at all, you can use the -evennia/evennia.git repo instead of a forked one.

-

git clone git@github.com:/evennia.git -git clone git@github.com:/arxcode.git

-

Evennia is a package itself, so we want to install it and all of its -prerequisites, after switching to the appropriately-tagged branch for -Arxcode.

-

cd evennia -git checkout tags/v0.7 -b arx-master -pip install -e .

-

Arx has some dependencies of its own, so now we’ll go install them -As it is not a package, we’ll use the normal requirements file.

-

cd …/arxcode -pip install -r requirements.txt

-

The git repo doesn’t include the empty log directory and Evennia is unhappy if you -don’t have it, so while still in the arxcode directory…

-

mkdir server/logs

-

Now hit https://github.com/evennia/evennia/wiki/Arxcode-installing-help and -change the setup stuff as in the ‘Clean up settings’ section.

-

Then we will create our default database…

-

…/evennia/bin/windows/evennia.bat migrate

-

…and do the first run. You need winpty because Windows does not have a TTY/PTY -by default, and so the Python console input commands (used for prompts on first -run) will fail and you will end up in an unhappy place. Future runs, you should -not need winpty.

-

winpty …/evennia/bin/windows/evennia.bat start

-

Once this is done, you should have your Evennia server running Arxcode up -on localhost at port 4000, and the webserver at http://localhost:4001/

-

And you are done! Huzzah!

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Async-Process.html b/docs/0.9.5/Async-Process.html deleted file mode 100644 index bb262fff18..0000000000 --- a/docs/0.9.5/Async-Process.html +++ /dev/null @@ -1,327 +0,0 @@ - - - - - - - - - Async Process — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Async Process

-

This is considered an advanced topic.

-
-

Synchronous versus Asynchronous

-

Most program code operates synchronously. This means that each statement in your code gets -processed and finishes before the next can begin. This makes for easy-to-understand code. It is also -a requirement in many cases - a subsequent piece of code often depend on something calculated or -defined in a previous statement.

-

Consider this piece of code in a traditional Python program:

-
    print("before call ...")
-    long_running_function()
-    print("after call ...")
-
-
-
-

When run, this will print "before call ...", after which the long_running_function gets to work -for however long time. Only once that is done, the system prints "after call ...". Easy and -logical to follow. Most of Evennia work in this way and often it’s important that commands get -executed in the same strict order they were coded.

-

Evennia, via Twisted, is a single-process multi-user server. In simple terms this means that it -swiftly switches between dealing with player input so quickly that each player feels like they do -things at the same time. This is a clever illusion however: If one user, say, runs a command -containing that long_running_function, all other players are effectively forced to wait until it -finishes.

-

Now, it should be said that on a modern computer system this is rarely an issue. Very few commands -run so long that other users notice it. And as mentioned, most of the time you want to enforce -all commands to occur in strict sequence.

-

When delays do become noticeable and you don’t care in which order the command actually completes, -you can run it asynchronously. This makes use of the run_async() function in -src/utils/utils.py:

-
    run_async(function, *args, **kwargs)
-
-
-

Where function will be called asynchronously with *args and **kwargs. Example:

-
    from evennia import utils
-    print("before call ...")
-    utils.run_async(long_running_function)
-    print("after call ...")
-
-
-

Now, when running this you will find that the program will not wait around for -long_running_function to finish. In fact you will see "before call ..." and "after call ..." -printed out right away. The long-running function will run in the background and you (and other -users) can go on as normal.

-
-
-

Customizing asynchronous operation

-

A complication with using asynchronous calls is what to do with the result from that call. What if -long_running_function returns a value that you need? It makes no real sense to put any lines of -code after the call to try to deal with the result from long_running_function above - as we saw -the "after call ..." got printed long before long_running_function was finished, making that -line quite pointless for processing any data from the function. Instead one has to use callbacks.

-

utils.run_async takes reserved kwargs that won’t be passed into the long-running function:

-
    -
  • at_return(r) (the callback) is called when the asynchronous function (long_running_function -above) finishes successfully. The argument r will then be the return value of that function (or -None).

    -
        def at_return(r):
    -        print(r)
    -
    -
    -
  • -
  • at_return_kwargs - an optional dictionary that will be fed as keyword arguments to the -at_return callback.

  • -
  • at_err(e) (the errback) is called if the asynchronous function fails and raises an exception. -This exception is passed to the errback wrapped in a Failure object e. If you do not supply an -errback of your own, Evennia will automatically add one that silently writes errors to the evennia -log. An example of an errback is found below:

  • -
-
        def at_err(e):
-            print("There was an error:", str(e))
-
-
-
    -
  • at_err_kwargs - an optional dictionary that will be fed as keyword arguments to the at_err -errback.

  • -
-

An example of making an asynchronous call from inside a Command definition:

-
    from evennia import utils, Command
-
-    class CmdAsync(Command):
-
-       key = "asynccommand"
-
-       def func(self):
-
-           def long_running_function():
-               #[... lots of time-consuming code  ...]
-               return final_value
-
-           def at_return_function(r):
-               self.caller.msg("The final value is %s" % r)
-
-           def at_err_function(e):
-               self.caller.msg("There was an error: %s" % e)
-
-           # do the async call, setting all callbacks
-           utils.run_async(long_running_function, at_return=at_return_function,
-at_err=at_err_function)
-
-
-

That’s it - from here on we can forget about long_running_function and go on with what else need -to be done. Whenever it finishes, the at_return_function function will be called and the final -value will -pop up for us to see. If not we will see an error message.

-
-
-

delay

-

The delay function is a much simpler sibling to run_async. It is in fact just a way to delay the -execution of a command until a future time. This is equivalent to something like time.sleep() -except delay is asynchronous while sleep would lock the entire server for the duration of the -sleep.

-
     from evennia.utils import delay
-
-     # [...]
-     # e.g. inside a Command, where `self.caller` is available
-     def callback(obj):
-        obj.msg("Returning!")
-     delay(10, callback, self.caller)
-
-
-

This will delay the execution of the callback for 10 seconds. This function is explored much more in -the Command Duration Tutorial.

-

You can also try the following snippet just see how it works:

-
@py from evennia.utils import delay; delay(10, lambda who: who.msg("Test!"), self)
-
-
-

Wait 10 seconds and ‘Test!’ should be echoed back to you.

-
-
-

The @interactive decorator

-

As of Evennia 0.9, the @interactive decorator -is available. This makes any function or method possible to ‘pause’ and/or await player input -in an interactive way.

-
    from evennia.utils import interactive
-
-    @interactive
-    def myfunc(caller):
-
-      while True:
-          caller.msg("Getting ready to wait ...")
-          yield(5)
-          caller.msg("Now 5 seconds have passed.")
-
-          response = yield("Do you want to wait another 5 secs?")
-
-          if response.lower() not in ("yes", "y"):
-              break
-
-
-

The @interactive decorator gives the function the ability to pause. The use -of yield(seconds) will do just that - it will asynchronously pause for the -number of seconds given before continuing. This is technically equivalent to -using call_async with a callback that continues after 5 secs. But the code -with @interactive is a little easier to follow.

-

Within the @interactive function, the response = yield("question") question -allows you to ask the user for input. You can then process the input, just like -you would if you used the Python input function. There is one caveat to this -functionality though - it will only work if the function/method has an -argument named exactly caller. This is because internally Evennia will look -for the caller argument and treat that as the source of input.

-

All of this makes the @interactive decorator very useful. But it comes with a -few caveats. Notably, decorating a function/method with @interactive turns it -into a Python generator. The most -common issue is that you cannot use return <value> from a generator (just an -empty return works). To return a value from a function/method you have decorated -with @interactive, you must instead use a special Twisted function -twisted.internet.defer.returnValue. Evennia also makes this function -conveniently available from evennia.utils:

-
    from evennia.utils import interactive, returnValue
-
-    @interactive
-    def myfunc():
-
-        # ...
-        result = 10
-
-        # this must be used instead of `return result`
-        returnValue(result)
-
-
-
-
-
-

Assorted notes

-

Overall, be careful with choosing when to use asynchronous calls. It is mainly useful for large -administration operations that have no direct influence on the game world (imports and backup -operations come to mind). Since there is no telling exactly when an asynchronous call actually ends, -using them for in-game commands is to potentially invite confusion and inconsistencies (and very -hard-to-reproduce bugs).

-

The very first synchronous example above is not really correct in the case of Twisted, which is -inherently an asynchronous server. Notably you might find that you will not see the first before call ... text being printed out right away. Instead all texts could end up being delayed until -after the long-running process finishes. So all commands will retain their relative order as -expected, but they may appear with delays or in groups.

-
-
-

Further reading

-

Technically, run_async is just a very thin and simplified wrapper around a -Twisted Deferred object; the -wrapper sets -up a default errback also if none is supplied. If you know what you are doing there is nothing -stopping you from bypassing the utility function, building a more sophisticated callback chain after -your own liking.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Attributes.html b/docs/0.9.5/Attributes.html deleted file mode 100644 index 198ea9a45a..0000000000 --- a/docs/0.9.5/Attributes.html +++ /dev/null @@ -1,484 +0,0 @@ - - - - - - - - - Attributes — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Attributes

-

When performing actions in Evennia it is often important that you store data for later. If you write -a menu system, you have to keep track of the current location in the menu tree so that the player -can give correct subsequent commands. If you are writing a combat system, you might have a -combattant’s next roll get easier dependent on if their opponent failed. Your characters will -probably need to store roleplaying-attributes like strength and agility. And so on.

-

Typeclassed game entities (Accounts, Objects, -Scripts and Channels) always have Attributes associated with them. -Attributes are used to store any type of data ‘on’ such entities. This is different from storing -data in properties already defined on entities (such as key or location) - these have very -specific names and require very specific types of data (for example you couldn’t assign a python -list to the key property no matter how hard you tried). Attributes come into play when you -want to assign arbitrary data to arbitrary names.

-

Attributes are not secure by default and any player may be able to change them unless you -prevent this behavior.

-
-

The .db and .ndb shortcuts

-

To save persistent data on a Typeclassed object you normally use the db (DataBase) operator. Let’s -try to save some data to a Rose (an Object):

-
    # saving
-    rose.db.has_thorns = True
-    # getting it back
-    is_ouch = rose.db.has_thorns
-
-
-
-

This looks like any normal Python assignment, but that db makes sure that an Attribute is -created behind the scenes and is stored in the database. Your rose will continue to have thorns -throughout the life of the server now, until you deliberately remove them.

-

To be sure to save non-persistently, i.e. to make sure NOT to create a database entry, you use -ndb (NonDataBase). It works in the same way:

-
    # saving
-    rose.ndb.has_thorns = True
-    # getting it back
-    is_ouch = rose.ndb.has_thorns
-
-
-

Technically, ndb has nothing to do with Attributes, despite how similar they look. No -Attribute object is created behind the scenes when using ndb. In fact the database is not -invoked at all since we are not interested in persistence. There is however an important reason to -use ndb to store data rather than to just store variables direct on entities - ndb-stored data -is tracked by the server and will not be purged in various cache-cleanup operations Evennia may do -while it runs. Data stored on ndb (as well as db) will also be easily listed by example the -@examine command.

-

You can also del properties on db and ndb as normal. This will for example delete an -Attribute:

-
    del rose.db.has_thorns
-
-
-

Both db and ndb defaults to offering an all property on themselves. This returns all -associated attributes or non-persistent properties.

-
     list_of_all_rose_attributes = rose.db.all
-     list_of_all_rose_ndb_attrs = rose.ndb.all
-
-
-

If you use all as the name of an attribute, this will be used instead. Later deleting your custom -all will return the default behaviour.

-
-
-

The AttributeHandler

-

The .db and .ndb properties are very convenient but if you don’t know the name of the Attribute -beforehand they cannot be used. Behind the scenes .db actually accesses the AttributeHandler -which sits on typeclassed entities as the .attributes property. .ndb does the same for the -.nattributes property.

-

The handlers have normal access methods that allow you to manage and retrieve Attributes and -NAttributes:

-
    -
  • has('attrname') - this checks if the object has an Attribute with this key. This is equivalent -to doing obj.db.attrname.

  • -
  • get(...) - this retrieves the given Attribute. Normally the value property of the Attribute is -returned, but the method takes keywords for returning the Attribute object itself. By supplying an -accessing_object to the call one can also make sure to check permissions before modifying -anything.

  • -
  • add(...) - this adds a new Attribute to the object. An optional lockstring can be -supplied here to restrict future access and also the call itself may be checked against locks.

  • -
  • remove(...) - Remove the given Attribute. This can optionally be made to check for permission -before performing the deletion. - clear(...) - removes all Attributes from object.

  • -
  • all(...) - returns all Attributes (of the given category) attached to this object.

  • -
-

See this section for more about locking down Attribute -access and editing. The Nattribute offers no concept of access control.

-

Some examples:

-
    import evennia
-    obj = evennia.search_object("MyObject")
-
-    obj.attributes.add("test", "testvalue")
-    print(obj.db.test)                 # prints "testvalue"
-    print(obj.attributes.get("test"))  #       "
-    print(obj.attributes.all())        # prints [<AttributeObject>]
-    obj.attributes.remove("test")
-
-
-
-
-

Properties of Attributes

-

An Attribute object is stored in the database. It has the following properties:

-
    -
  • key - the name of the Attribute. When doing e.g. obj.db.attrname = value, this property is set -to attrname.

  • -
  • value - this is the value of the Attribute. This value can be anything which can be pickled - -objects, lists, numbers or what have you (see -this section for more info). In the -example -obj.db.attrname = value, the value is stored here.

  • -
  • category - this is an optional property that is set to None for most Attributes. Setting this -allows to use Attributes for different functionality. This is usually not needed unless you want -to use Attributes for very different functionality (Nicks is an example of using -Attributes -in this way). To modify this property you need to use the Attribute -Handler.

  • -
  • strvalue - this is a separate value field that only accepts strings. This severely limits the -data possible to store, but allows for easier database lookups. This property is usually not used -except when re-using Attributes for some other purpose (Nicks use it). It is only -accessible via the Attribute Handler.

  • -
-

There are also two special properties:

-
    -
  • attrtype - this is used internally by Evennia to separate Nicks, from Attributes (Nicks -use Attributes behind the scenes).

  • -
  • model - this is a natural-key describing the model this Attribute is attached to. This is on -the form appname.modelclass, like objects.objectdb. It is used by the Attribute and -NickHandler to quickly sort matches in the database. Neither this nor attrtype should normally -need to be modified.

  • -
-

Non-database attributes have no equivalence to category nor strvalue, attrtype or model.

-
-
-

Persistent vs non-persistent

-

So persistent data means that your data will survive a server reboot, whereas with -non-persistent data it will not …

-

… So why would you ever want to use non-persistent data? The answer is, you don’t have to. Most of -the time you really want to save as much as you possibly can. Non-persistent data is potentially -useful in a few situations though.

-
    -
  • You are worried about database performance. Since Evennia caches Attributes very aggressively, -this is not an issue unless you are reading and writing to your Attribute very often (like many -times per second). Reading from an already cached Attribute is as fast as reading any Python -property. But even then this is not likely something to worry about: Apart from Evennia’s own -caching, modern database systems themselves also cache data very efficiently for speed. Our -default -database even runs completely in RAM if possible, alleviating much of the need to write to disk -during heavy loads.

  • -
  • A more valid reason for using non-persistent data is if you want to lose your state when logging -off. Maybe you are storing throw-away data that are re-initialized at server startup. Maybe you -are implementing some caching of your own. Or maybe you are testing a buggy Script that -does potentially harmful stuff to your character object. With non-persistent storage you can be -sure -that whatever is messed up, it’s nothing a server reboot can’t clear up.

  • -
  • NAttributes have no restrictions at all on what they can store (see next section), since they -don’t need to worry about being saved to the database - they work very well for temporary storage.

  • -
  • You want to implement a fully or partly non-persistent world. Who are we to argue with your -grand vision!

  • -
-
-
-

What types of data can I save in an Attribute?

-
-

None of the following affects NAttributes, which does not invoke the database at all. There are no -restrictions to what can be stored in a NAttribute.

-
-

The database doesn’t know anything about Python objects, so Evennia must serialize Attribute -values into a string representation in order to store it to the database. This is done using the -pickle module of Python (the only exception is if you use the strattr keyword of the -AttributeHandler to save to the strvalue field of the Attribute. In that case you can only save -strings which will not be pickled).

-

It’s important to note that when you access the data in an Attribute you are always de-serializing -it from the database representation every time. This is because we allow for storing -database-entities in Attributes too. If we cached it as its Python form, we might end up with -situations where the database entity was deleted since we last accessed the Attribute. -De-serializing data with a database-entity in it means querying the database for that object and -making sure it still exists (otherwise it will be set to None). Performance-wise this is usually -not a big deal. But if you are accessing the Attribute as part of some big loop or doing a large -amount of reads/writes you should first extract it to a temporary variable, operate on that and -then save the result back to the Attribute. If you are storing a more complex structure like a -dict or a list you should make sure to “disconnect” it from the database before looping over it, -as mentioned in the Retrieving Mutable Objects section -below.

-
-

Storing single objects

-

With a single object, we mean anything that is not iterable, like numbers, strings or custom class -instances without the __iter__ method.

-
    -
  • You can generally store any non-iterable Python entity that can be -pickled.

  • -
  • Single database objects/typeclasses can be stored as any other in the Attribute. These can -normally not be pickled, but Evennia will behind the scenes convert them to an internal -representation using their classname, database-id and creation-date with a microsecond precision, -guaranteeing you get the same object back when you access the Attribute later.

  • -
  • If you hide a database object inside a non-iterable custom class (like stored as a variable -inside it), Evennia will not know it’s there and won’t convert it safely. Storing classes with -such hidden database objects is not supported and will lead to errors!

  • -
-
# Examples of valid single-value  attribute data:
-obj.db.test1 = 23
-obj.db.test1 = False
-# a database object (will be stored as an internal representation)
-obj.db.test2 = myobj
-
-# example of an invalid, "hidden" dbobject
-class Invalid(object):
-    def __init__(self, dbobj):
-        # no way for Evennia to know this is a dbobj
-        self.dbobj = dbobj
-invalid = Invalid(myobj)
-obj.db.invalid = invalid # will cause error!
-
-
-
-
-

Storing multiple objects

-

This means storing objects in a collection of some kind and are examples of iterables, pickle-able -entities you can loop over in a for-loop. Attribute-saving supports the following iterables:

-
    -
  • Tuples, like (1,2,"test", <dbobj>).

  • -
  • Lists, like [1,2,"test", <dbobj>].

  • -
  • Dicts, like {1:2, "test":<dbobj>].

  • -
  • Sets, like {1,2,"test",<dbobj>}.

  • -
  • collections.OrderedDict, like OrderedDict((1,2), ("test", <dbobj>)).

  • -
  • collections.Deque, like -deque((1,2,"test",<dbobj>)).

  • -
  • Nestings of any combinations of the above, like lists in dicts or an OrderedDict of tuples, each -containing dicts, etc.

  • -
  • All other iterables (i.e. entities with the __iter__ method) will be converted to a list. -Since you can use any combination of the above iterables, this is generally not much of a -limitation.

  • -
-

Any entity listed in the Single object section above can be -stored in the iterable.

-
-

As mentioned in the previous section, database entities (aka typeclasses) are not possible to -pickle. So when storing an iterable, Evennia must recursively traverse the iterable and all its -nested sub-iterables in order to find eventual database objects to convert. This is a very fast -process but for efficiency you may want to avoid too deeply nested structures if you can.

-
-
# examples of valid iterables to store
-obj.db.test3 = [obj1, 45, obj2, 67]
-# a dictionary
-obj.db.test4 = {'str':34, 'dex':56, 'agi':22, 'int':77}
-# a mixed dictionary/list
-obj.db.test5 = {'members': [obj1,obj2,obj3], 'enemies':[obj4,obj5]}
-# a tuple with a list in it
-obj.db.test6 = (1,3,4,8, ["test", "test2"], 9)
-# a set
-obj.db.test7 = set([1,2,3,4,5])
-# in-situ manipulation
-obj.db.test8 = [1,2,{"test":1}]
-obj.db.test8[0] = 4
-obj.db.test8[2]["test"] = 5
-# test8 is now [4,2,{"test":5}]
-
-
-
-
-

Retrieving Mutable objects

-

A side effect of the way Evennia stores Attributes is that mutable iterables (iterables that can -be modified in-place after they were created, which is everything except tuples) are handled by -custom objects called _SaverList, _SaverDict etc. These _Saver... classes behave just like the -normal variant except that they are aware of the database and saves to it whenever new data gets -assigned to them. This is what allows you to do things like self.db.mylist[7] = val and be sure -that the new version of list is saved. Without this you would have to load the list into a temporary -variable, change it and then re-assign it to the Attribute in order for it to save.

-

There is however an important thing to remember. If you retrieve your mutable iterable into another -variable, e.g. mylist2 = obj.db.mylist, your new variable (mylist2) will still be a -_SaverList. This means it will continue to save itself to the database whenever it is updated!

-
     obj.db.mylist = [1,2,3,4]
-     mylist = obj.db.mylist
-     mylist[3] = 5 # this will also update database
-     print(mylist) # this is now [1,2,3,5]
-     print(obj.db.mylist) # this is also [1,2,3,5]
-
-
-

To “disconnect” your extracted mutable variable from the database you simply need to convert the -_Saver... iterable to a normal Python structure. So to convert a _SaverList, you use the -list() function, for a _SaverDict you use dict() and so on.

-
     obj.db.mylist = [1,2,3,4]
-     mylist = list(obj.db.mylist) # convert to normal list
-     mylist[3] = 5
-     print(mylist) # this is now [1,2,3,5]
-     print(obj.db.mylist) # this is still [1,2,3,4]
-
-
-

A further problem comes with nested mutables, like a dict containing lists of dicts or something -like that. Each of these nested mutables would be _Saver* structures connected to the database and -disconnecting the outermost one of them would not disconnect those nested within. To make really -sure you disonnect a nested structure entirely from the database, Evennia provides a special -function evennia.utils.dbserialize.deserialize:

-
from evennia.utils.dbserialize import deserialize
-
-decoupled_mutables = deserialize(nested_mutables)
-
-
-
-

The result of this operation will be a structure only consisting of normal Python mutables (list -instead of _SaverList and so on).

-

Remember, this is only valid for mutable iterables. -Immutable objects (strings, numbers, tuples etc) are -already disconnected from the database from the onset.

-
     obj.db.mytup = (1,2,[3,4])
-     obj.db.mytup[0] = 5 # this fails since tuples are immutable
-
-     # this works but will NOT update database since outermost is a tuple
-     obj.db.mytup[2][1] = 5
-     print(obj.db.mytup[2][1]) # this still returns 4, not 5
-
-     mytup1 = obj.db.mytup # mytup1 is already disconnected from database since outermost
-                           # iterable is a tuple, so we can edit the internal list as we want
-                           # without affecting the database.
-
-
-
-

Attributes will fetch data fresh from the database whenever you read them, so -if you are performing big operations on a mutable Attribute property (such as looping over a list -or dict) you should make sure to “disconnect” the Attribute’s value first and operate on this -rather than on the Attribute. You can gain dramatic speed improvements to big loops this -way.

-
-
-
-
-

Locking and checking Attributes

-

Attributes are normally not locked down by default, but you can easily change that for individual -Attributes (like those that may be game-sensitive in games with user-level building).

-

First you need to set a lock string on your Attribute. Lock strings are specified Locks. -The relevant lock types are

-
    -
  • attrread - limits who may read the value of the Attribute

  • -
  • attredit - limits who may set/change this Attribute

  • -
-

You cannot use the db handler to modify Attribute object (such as setting a lock on them) - The -db handler will return the Attribute’s value, not the Attribute object itself. Instead you use -the AttributeHandler and set it to return the object instead of the value:

-
     lockstring = "attread:all();attredit:perm(Admins)"
-     obj.attributes.get("myattr", return_obj=True).locks.add(lockstring)
-
-
-

Note the return_obj keyword which makes sure to return the Attribute object so its LockHandler -could be accessed.

-

A lock is no good if nothing checks it – and by default Evennia does not check locks on Attributes. -You have to add a check to your commands/code wherever it fits (such as before setting an -Attribute).

-
    # in some command code where we want to limit
-    # setting of a given attribute name on an object
-    attr = obj.attributes.get(attrname,
-                              return_obj=True,
-                              accessing_obj=caller,
-                              default=None,
-                              default_access=False)
-    if not attr:
-        caller.msg("You cannot edit that Attribute!")
-        return
-    # edit the Attribute here
-
-
-

The same keywords are available to use with obj.attributes.set() and obj.attributes.remove(), -those will check for the attredit lock type.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Banning.html b/docs/0.9.5/Banning.html deleted file mode 100644 index 08d5f784eb..0000000000 --- a/docs/0.9.5/Banning.html +++ /dev/null @@ -1,269 +0,0 @@ - - - - - - - - - Banning — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Banning

-

Whether due to abuse, blatant breaking of your rules, or some other reason, you will eventually find -no other recourse but to kick out a particularly troublesome player. The default command set has -admin tools to handle this, primarily ban, unban, and boot.

-
-

Creating a ban

-

Say we have a troublesome player “YouSuck” - this is a person that refuses common courtesy - an -abusive -and spammy account that is clearly created by some bored internet hooligan only to cause grief. You -have tried to be nice. Now you just want this troll gone.

-
-

Name ban

-

The easiest recourse is to block the account YouSuck from ever connecting again.

-
 ban YouSuck
-
-
-

This will lock the name YouSuck (as well as ‘yousuck’ and any other capitalization combination), and -next time they try to log in with this name the server will not let them!

-

You can also give a reason so you remember later why this was a good thing (the banned account will -never see this)

-
 ban YouSuck:This is just a troll.
-
-
-

If you are sure this is just a spam account, you might even consider deleting the player account -outright:

-
 account/delete YouSuck
-
-
-

Generally, banning the name is the easier and safer way to stop the use of an account – if you -change your mind you can always remove the block later whereas a deletion is permanent.

-
-
-

IP ban

-

Just because you block YouSuck’s name might not mean the trolling human behind that account gives -up. They can just create a new account YouSuckMore and be back at it. One way to make things harder -for them is to tell the server to not allow connections from their particular IP address.

-

First, when the offending account is online, check which IP address they use. This you can do with -the who command, which will show you something like this:

-
 Account Name     On for     Idle     Room     Cmds     Host
- YouSuckMore      01:12      2m       22       212      237.333.0.223
-
-
-

The “Host” bit is the IP address from which the account is connecting. Use this to define the ban -instead of the name:

-
 ban 237.333.0.223
-
-
-

This will stop YouSuckMore connecting from their computer. Note however that IP address might change -easily - either due to how the player’s Internet Service Provider operates or by the user simply -changing computers. You can make a more general ban by putting asterisks * as wildcards for the -groups of three digits in the address. So if you figure out that !YouSuckMore mainly connects from -237.333.0.223, 237.333.0.225, and 237.333.0.256 (only changes in their subnet), it might be an idea -to put down a ban like this to include any number in that subnet:

-
 ban 237.333.0.*
-
-
-

You should combine the IP ban with a name-ban too of course, so the account YouSuckMore is truly -locked regardless of where they connect from.

-

Be careful with too general IP bans however (more asterisks above). If you are unlucky you could be -blocking out innocent players who just happen to connect from the same subnet as the offender.

-
-
-
-

Booting

-

YouSuck is not really noticing all this banning yet though - and won’t until having logged out and -trying to log back in again. Let’s help the troll along.

-
 boot YouSuck
-
-
-

Good riddance. You can give a reason for booting too (to be echoed to the player before getting -kicked out).

-
 boot YouSuck:Go troll somewhere else.
-
-
-
-

Lifting a ban

-

Use the unban (or ban) command without any arguments and you will see a list of all currently -active bans:

-
Active bans
-id   name/ip       date                      reason
-1    yousuck       Fri Jan 3 23:00:22 2020   This is just a Troll.
-2    237.333.0.*   Fri Jan 3 23:01:03 2020   YouSuck's IP.
-
-
-

Use the id from this list to find out which ban to lift.

-
 unban 2
-  
-Cleared ban 2: 237.333.0.*
-
-
-
-
-
-

Summary of abuse-handling tools

-

Below are other useful commands for dealing with annoying players.

-
    -
  • who – (as admin) Find the IP of a account. Note that one account can be connected to from -multiple IPs depending on what you allow in your settings.

  • -
  • examine/account thomas – Get all details about an account. You can also use *thomas to get -the account. If not given, you will get the Object thomas if it exists in the same location, which -is not what you want in this case.

  • -
  • boot thomas – Boot all sessions of the given account name.

  • -
  • boot 23 – Boot one specific client session/IP by its unique id.

  • -
  • ban – List all bans (listed with ids)

  • -
  • ban thomas – Ban the user with the given account name

  • -
  • ban/ip 134.233.2.111 – Ban by IP

  • -
  • ban/ip 134.233.2.* – Widen IP ban

  • -
  • ban/ip 134.233.*.* – Even wider IP ban

  • -
  • unban 34 – Remove ban with id #34

  • -
  • cboot mychannel = thomas – Boot a subscriber from a channel you control

  • -
  • clock mychannel = control:perm(Admin);listen:all();send:all() – Fine control of access to -your channel using lock definitions.

  • -
-

Locking a specific command (like page) is accomplished like so:

-
    -
  1. Examine the source of the command. The default page command class has the lock -string “cmd:not pperm(page_banned)”. This means that unless the player has the ‘permission’ -“page_banned” they can use this command. You can assign any lock string to allow finer customization -in your commands. You might look for the value of an Attribute or Tag, your -current location etc.

  2. -
  3. perm/account thomas = page_banned – Give the account the ‘permission’ which causes (in this -case) the lock to fail.

  4. -
-
    -
  • perm/del/account thomas = page_banned – Remove the given permission

  • -
  • tel thomas = jail – Teleport a player to a specified location or #dbref

  • -
  • type thomas = FlowerPot – Turn an annoying player into a flower pot (assuming you have a -FlowerPot typeclass ready)

  • -
  • userpassword thomas = fooBarFoo – Change a user’s password

  • -
  • account/delete thomas – Delete a player account (not recommended, use ban instead)

  • -
  • server – Show server statistics, such as CPU load, memory usage, and how many objects are -cached

  • -
  • time – Gives server uptime, runtime, etc

  • -
  • reload – Reloads the server without disconnecting anyone

  • -
  • reset – Restarts the server, kicking all connections

  • -
  • shutdown – Stops the server cold without it auto-starting again

  • -
  • py – Executes raw Python code, allows for direct inspection of the database and account -objects on the fly. For advanced users.

  • -
-

Useful Tip: evennia changepassword <username> entered into the command prompt will reset the -password of any account, including the superuser or admin accounts. This is a feature of Django.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Batch-Code-Processor.html b/docs/0.9.5/Batch-Code-Processor.html deleted file mode 100644 index 768bdbcf16..0000000000 --- a/docs/0.9.5/Batch-Code-Processor.html +++ /dev/null @@ -1,353 +0,0 @@ - - - - - - - - - Batch Code Processor — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Batch Code Processor

-

For an introduction and motivation to using batch processors, see here. This -page describes the Batch-code processor. The Batch-command one is covered [here](Batch-Command- -Processor).

-
-

Basic Usage

-

The batch-code processor is a superuser-only function, invoked by

-
 > @batchcode path.to.batchcodefile
-
-
-

Where path.to.batchcodefile is the path to a batch-code file. Such a file should have a name -ending in “.py” (but you shouldn’t include that in the path). The path is given like a python path -relative to a folder you define to hold your batch files, set by BATCH_IMPORT_PATH in your -settings. Default folder is (assuming your game is called “mygame”) mygame/world/. So if you want -to run the example batch file in mygame/world/batch_code.py, you could simply use

-
 > @batchcode batch_code
-
-
-

This will try to run through the entire batch file in one go. For more gradual, interactive -control you can use the /interactive switch. The switch /debug will put the processor in -debug mode. Read below for more info.

-
-
-

The batch file

-

A batch-code file is a normal Python file. The difference is that since the batch processor loads -and executes the file rather than importing it, you can reliably update the file, then call it -again, over and over and see your changes without needing to @reload the server. This makes for -easy testing. In the batch-code file you have also access to the following global variables:

-
    -
  • caller - This is a reference to the object running the batchprocessor.

  • -
  • DEBUG - This is a boolean that lets you determine if this file is currently being run in debug- -mode or not. See below how this can be useful.

  • -
-

Running a plain Python file through the processor will just execute the file from beginning to end. -If you want to get more control over the execution you can use the processor’s interactive mode. -This runs certain code blocks on their own, rerunning only that part until you are happy with it. In -order to do this you need to add special markers to your file to divide it up into smaller chunks. -These take the form of comments, so the file remains valid Python.

-

Here are the rules of syntax of the batch-code *.py file.

-
    -
  • #CODE as the first on a line marks the start of a code block. It will last until the beginning -of another marker or the end of the file. Code blocks contain functional python code. Each #CODE -block will be run in complete isolation from other parts of the file, so make sure it’s self- -contained.

  • -
  • #HEADER as the first on a line marks the start of a header block. It lasts until the next -marker or the end of the file. This is intended to hold imports and variables you will need for all -other blocks .All python code defined in a header block will always be inserted at the top of every -#CODE blocks in the file. You may have more than one #HEADER block, but that is equivalent to -having one big one. Note that you can’t exchange data between code blocks, so editing a header- -variable in one code block won’t affect that variable in any other code block!

  • -
  • #INSERT path.to.file will insert another batchcode (Python) file at that position.

  • -
  • A # that is not starting a #HEADER, #CODE or #INSERT instruction is considered a comment.

  • -
  • Inside a block, normal Python syntax rules apply. For the sake of indentation, each block acts as -a separate python module.

  • -
-

Below is a version of the example file found in evennia/contrib/tutorial_examples/.

-
    #
-    # This is an example batch-code build file for Evennia.
-    #
-    
-    #HEADER
-    
-    # This will be included in all other #CODE blocks
-    
-    from evennia import create_object, search_object
-    from evennia.contrib.tutorial_examples import red_button
-    from typeclasses.objects import Object
-    
-    limbo = search_object('Limbo')[0]
-    
-    
-    #CODE
- 
-    red_button = create_object(red_button.RedButton, key="Red button",
-                               location=limbo, aliases=["button"])
-    
-    # caller points to the one running the script
-    caller.msg("A red button was created.")
-    
-    # importing more code from another batch-code file
-    #INSERT batch_code_insert
-    
-    #CODE
-    
-    table = create_object(Object, key="Blue Table", location=limbo)
-    chair = create_object(Object, key="Blue Chair", location=limbo)
-    
-    string = "A %s and %s were created."
-    if DEBUG:
-        table.delete()
-        chair.delete()
-        string += " Since debug was active, " \
-             "they were deleted again."
-    caller.msg(string % (table, chair))
-
-
-

This uses Evennia’s Python API to create three objects in sequence.

-
-
-

Debug mode

-

Try to run the example script with

-
 > @batchcode/debug tutorial_examples.example_batch_code
-
-
-

The batch script will run to the end and tell you it completed. You will also get messages that the -button and the two pieces of furniture were created. Look around and you should see the button -there. But you won’t see any chair nor a table! This is because we ran this with the /debug -switch, which is directly visible as DEBUG==True inside the script. In the above example we -handled this state by deleting the chair and table again.

-

The debug mode is intended to be used when you test out a batchscript. Maybe you are looking for -bugs in your code or try to see if things behave as they should. Running the script over and over -would then create an ever-growing stack of chairs and tables, all with the same name. You would have -to go back and painstakingly delete them later.

-
-
-

Interactive mode

-

Interactive mode works very similar to the [batch-command processor counterpart](Batch-Command- -Processor). It allows you more step-wise control over how the batch file is executed. This is useful -for debugging or for picking and choosing only particular blocks to run. Use @batchcode with the -/interactive flag to enter interactive mode.

-
 > @batchcode/interactive tutorial_examples.example_batch_code
-
-
-

You should see the following:

-
01/02: red_button = create_object(red_button.RedButton, [...]         (hh for help)
-
-
-

This shows that you are on the first #CODE block, the first of only two commands in this batch -file. Observe that the block has not actually been executed at this point!

-

To take a look at the full code snippet you are about to run, use ll (a batch-processor version of -look).

-
    from evennia.utils import create, search
-    from evennia.contrib.tutorial_examples import red_button
-    from typeclasses.objects import Object
-    
-    limbo = search.objects(caller, 'Limbo', global_search=True)[0]
-
-    red_button = create.create_object(red_button.RedButton, key="Red button",
-                                      location=limbo, aliases=["button"])
-    
-    # caller points to the one running the script
-    caller.msg("A red button was created.")
-
-
-

Compare with the example code given earlier. Notice how the content of #HEADER has been pasted at -the top of the #CODE block. Use pp to actually execute this block (this will create the button -and give you a message). Use nn (next) to go to the next command. Use hh for a list of commands.

-

If there are tracebacks, fix them in the batch file, then use rr to reload the file. You will -still be at the same code block and can rerun it easily with pp as needed. This makes for a simple -debug cycle. It also allows you to rerun individual troublesome blocks - as mentioned, in a large -batch file this can be very useful (don’t forget the /debug mode either).

-

Use nn and bb (next and back) to step through the file; e.g. nn 12 will jump 12 steps forward -(without processing any blocks in between). All normal commands of Evennia should work too while -working in interactive mode.

-
-
-

Limitations and Caveats

-

The batch-code processor is by far the most flexible way to build a world in Evennia. There are -however some caveats you need to keep in mind.

-
-

Safety

-

Or rather the lack of it. There is a reason only superusers are allowed to run the batch-code -processor by default. The code-processor runs without any Evennia security checks and allows -full access to Python. If an untrusted party could run the code-processor they could execute -arbitrary python code on your machine, which is potentially a very dangerous thing. If you want to -allow other users to access the batch-code processor you should make sure to run Evennia as a -separate and very limited-access user on your machine (i.e. in a ‘jail’). By comparison, the batch- -command processor is much safer since the user running it is still ‘inside’ the game and can’t -really do anything outside what the game commands allow them to.

-
-
-

No communication between code blocks

-

Global variables won’t work in code batch files, each block is executed as stand-alone environments. -#HEADER blocks are literally pasted on top of each #CODE block so updating some header-variable -in your block will not make that change available in another block. Whereas a python execution -limitation, allowing this would also lead to very hard-to-debug code when using the interactive mode

-
    -
  • this would be a classical example of “spaghetti code”.

  • -
-

The main practical issue with this is when building e.g. a room in one code block and later want to -connect that room with a room you built in the current block. There are two ways to do this:

-
    -
  • Perform a database search for the name of the room you created (since you cannot know in advance -which dbref it got assigned). The problem is that a name may not be unique (you may have a lot of “A -dark forest” rooms). There is an easy way to handle this though - use Tags or Aliases. You -can assign any number of tags and/or aliases to any object. Make sure that one of those tags or -aliases is unique to the room (like “room56”) and you will henceforth be able to always uniquely -search and find it later.

  • -
  • Use the caller global property as an inter-block storage. For example, you could have a -dictionary of room references in an ndb:

    -
    #HEADER
    -if caller.ndb.all_rooms is None:
    -    caller.ndb.all_rooms = {}
    -
    -#CODE
    -# create and store the castle
    -castle = create_object("rooms.Room", key="Castle")
    -caller.ndb.all_rooms["castle"] = castle
    -
    -#CODE
    -# in another node we want to access the castle
    -castle = caller.ndb.all_rooms.get("castle")
    -
    -
    -
  • -
-

Note how we check in #HEADER if caller.ndb.all_rooms doesn’t already exist before creating the -dict. Remember that #HEADER is copied in front of every #CODE block. Without that if statement -we’d be wiping the dict every block!

-
-
-

Don’t treat a batchcode file like any Python file

-

Despite being a valid Python file, a batchcode file should only be run by the batchcode processor. -You should not do things like define Typeclasses or Commands in them, or import them into other -code. Importing a module in Python will execute base level of the module, which in the case of your -average batchcode file could mean creating a lot of new objects every time.

-
-
-

Don’t let code rely on the batch-file’s real file path

-

When you import things into your batchcode file, don’t use relative imports but always import with -paths starting from the root of your game directory or evennia library. Code that relies on the -batch file’s “actual” location will fail. Batch code files are read as text and the strings -executed. When the code runs it has no knowledge of what file those strings where once a part of.

-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Batch-Command-Processor.html b/docs/0.9.5/Batch-Command-Processor.html deleted file mode 100644 index 9ec4c10293..0000000000 --- a/docs/0.9.5/Batch-Command-Processor.html +++ /dev/null @@ -1,296 +0,0 @@ - - - - - - - - - Batch Command Processor — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Batch Command Processor

-

For an introduction and motivation to using batch processors, see here. This -page describes the Batch-command processor. The Batch-code one is covered [here](Batch-Code- -Processor).

-
-

Basic Usage

-

The batch-command processor is a superuser-only function, invoked by

-
 > @batchcommand path.to.batchcmdfile
-
-
-

Where path.to.batchcmdfile is the path to a batch-command file with the “.ev” file ending. -This path is given like a python path relative to a folder you define to hold your batch files, set -with BATCH_IMPORT_PATH in your settings. Default folder is (assuming your game is in the mygame -folder) mygame/world. So if you want to run the example batch file in -mygame/world/batch_cmds.ev, you could use

-
 > @batchcommand batch_cmds
-
-
-

A batch-command file contains a list of Evennia in-game commands separated by comments. The -processor will run the batch file from beginning to end. Note that it will not stop if commands in -it fail (there is no universal way for the processor to know what a failure looks like for all -different commands). So keep a close watch on the output, or use Interactive mode (see below) to -run the file in a more controlled, gradual manner.

-
-
-

The batch file

-

The batch file is a simple plain-text file containing Evennia commands. Just like you would write -them in-game, except you have more freedom with line breaks.

-

Here are the rules of syntax of an *.ev file. You’ll find it’s really, really simple:

-
    -
  • All lines having the # (hash)-symbol as the first one on the line are considered comments. -All non-comment lines are treated as a command and/or their arguments.

  • -
  • Comment lines have an actual function – they mark the end of the previous command definition. -So never put two commands directly after one another in the file - separate them with a comment, or -the second of the two will be considered an argument to the first one. Besides, using plenty of -comments is good practice anyway.

  • -
  • A line that starts with the word #INSERT is a comment line but also signifies a special -instruction. The syntax is #INSERT <path.batchfile> and tries to import a given batch-cmd file -into this one. The inserted batch file (file ending .ev) will run normally from the point of the -#INSERT instruction.

  • -
  • Extra whitespace in a command definition is ignored. - A completely empty line translates in to -a line break in texts. Two empty lines thus means a new paragraph (this is obviously only relevant -for commands accepting such formatting, such as the @desc command).

  • -
  • The very last command in the file is not required to end with a comment.

  • -
  • You cannot nest another @batchcommand statement into your batch file. If you want to link many -batch-files together, use the #INSERT batch instruction instead. You also cannot launch the -@batchcode command from your batch file, the two batch processors are not compatible.

  • -
-

Below is a version of the example file found in evennia/contrib/tutorial_examples/batch_cmds.ev.

-
    #
-    # This is an example batch build file for Evennia.
-    #
-    
-    # This creates a red button
-    @create button:tutorial_examples.red_button.RedButton
-    # (This comment ends input for @create)
-    # Next command. Let's create something.
-    @set button/desc =
-      This is a large red button. Now and then
-      it flashes in an evil, yet strangely tantalizing way.
-    
-      A big sign sits next to it. It says:
-
-    
-    -----------
-    
-     Press me!
-    
-    -----------
-
-    
-      ... It really begs to be pressed! You
-    know you want to!
-    
-    # This inserts the commands from another batch-cmd file named
-    # batch_insert_file.ev.
-    #INSERT examples.batch_insert_file
-    
-      
-    # (This ends the @set command). Note that single line breaks
-    # and extra whitespace in the argument are ignored. Empty lines
-    # translate into line breaks in the output.
-    # Now let's place the button where it belongs (let's say limbo #2 is
-    # the evil lair in our example)
-    @teleport #2
-    # (This comments ends the @teleport command.)
-    # Now we drop it so others can see it.
-    # The very last command in the file needs not be ended with #.
-    drop button
-
-
-

To test this, run @batchcommand on the file:

-
> @batchcommand contrib.tutorial_examples.batch_cmds
-
-
-

A button will be created, described and dropped in Limbo. All commands will be executed by the user -calling the command.

-
-

Note that if you interact with the button, you might find that its description changes, loosing -your custom-set description above. This is just the way this particular object works.

-
-
-
-

Interactive mode

-

Interactive mode allows you to more step-wise control over how the batch file is executed. This is -useful for debugging and also if you have a large batch file and is only updating a small part of it -– running the entire file again would be a waste of time (and in the case of @create-ing objects -you would to end up with multiple copies of same-named objects, for example). Use @batchcommand -with the /interactive flag to enter interactive mode.

-
 > @batchcommand/interactive tutorial_examples.batch_cmds
-
-
-

You will see this:

-
01/04: @create button:tutorial_examples.red_button.RedButton  (hh for help)
-
-
-

This shows that you are on the @create command, the first out of only four commands in this batch -file. Observe that the command @create has not been actually processed at this point!

-

To take a look at the full command you are about to run, use ll (a batch-processor version of -look). Use pp to actually process the current command (this will actually @create the button) -– and make sure it worked as planned. Use nn (next) to go to the next command. Use hh for a -list of commands.

-

If there are errors, fix them in the batch file, then use rr to reload the file. You will still be -at the same command and can rerun it easily with pp as needed. This makes for a simple debug -cycle. It also allows you to rerun individual troublesome commands - as mentioned, in a large batch -file this can be very useful. Do note that in many cases, commands depend on the previous ones (e.g. -if @create in the example above had failed, the following commands would have had nothing to -operate on).

-

Use nn and bb (next and back) to step through the file; e.g. nn 12 will jump 12 steps forward -(without processing any command in between). All normal commands of Evennia should work too while -working in interactive mode.

-
-
-

Limitations and Caveats

-

The batch-command processor is great for automating smaller builds or for testing new commands and -objects repeatedly without having to write so much. There are several caveats you have to be aware -of when using the batch-command processor for building larger, complex worlds though.

-

The main issue is that when you run a batch-command script you (you, as in your superuser -character) are actually moving around in the game creating and building rooms in sequence, just as -if you had been entering those commands manually, one by one. You have to take this into account -when creating the file, so that you can ‘walk’ (or teleport) to the right places in order.

-

This also means there are several pitfalls when designing and adding certain types of objects. Here -are some examples:

-
    -
  • Rooms that change your Command Set: Imagine that you build a ‘dark’ room, which -severely limits the cmdsets of those entering it (maybe you have to find the light switch to -proceed). In your batch script you would create this room, then teleport to it - and promptly be -shifted into the dark state where none of your normal build commands work …

  • -
  • Auto-teleportation: Rooms that automatically teleport those that enter them to another place -(like a trap room, for example). You would be teleported away too.

  • -
  • Mobiles: If you add aggressive mobs, they might attack you, drawing you into combat. If they -have AI they might even follow you around when building - or they might move away from you before -you’ve had time to finish describing and equipping them!

  • -
-

The solution to all these is to plan ahead. Make sure that superusers are never affected by whatever -effects are in play. Add an on/off switch to objects and make sure it’s always set to off upon -creation. It’s all doable, one just needs to keep it in mind.

-
-
-

Assorted notes

-

The fact that you build as ‘yourself’ can also be considered an advantage however, should you ever -decide to change the default command to allow others than superusers to call the processor. Since -normal access-checks are still performed, a malevolent builder with access to the processor should -not be able to do all that much damage (this is the main drawback of the Batch Code -Processor)

-
    -
  • GNU Emacs users might find it interesting to use emacs’ -evennia mode. This is an Emacs major mode found in evennia/utils/evennia-mode.el. It offers -correct syntax highlighting and indentation with <tab> when editing .ev files in Emacs. See the -header of that file for installation instructions.

  • -
  • VIM users can use amfl’s vim-evennia -mode instead, see its readme for install instructions.

  • -
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Batch-Processors.html b/docs/0.9.5/Batch-Processors.html deleted file mode 100644 index e0ebb8d20d..0000000000 --- a/docs/0.9.5/Batch-Processors.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - - - - Batch Processors — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Batch Processors

-

Building a game world is a lot of work, especially when starting out. Rooms should be created, -descriptions have to be written, objects must be detailed and placed in their proper places. In many -traditional MUD setups you had to do all this online, line by line, over a telnet session.

-

Evennia already moves away from much of this by shifting the main coding work to external Python -modules. But also building would be helped if one could do some or all of it externally. Enter -Evennia’s batch processors (there are two of them). The processors allows you, as a game admin, to -build your game completely offline in normal text files (batch files) that the processors -understands. Then, when you are ready, you use the processors to read it all into Evennia (and into -the database) in one go.

-

You can of course still build completely online should you want to - this is certainly the easiest -way to go when learning and for small build projects. But for major building work, the advantages of -using the batch-processors are many:

-
    -
  • It’s hard to compete with the comfort of a modern desktop text editor; Compared to a traditional -MUD line input, you can get much better overview and many more features. Also, accidentally pressing -Return won’t immediately commit things to the database.

  • -
  • You might run external spell checkers on your batch files. In the case of one of the batch- -processors (the one that deals with Python code), you could also run external debuggers and code -analyzers on your file to catch problems before feeding it to Evennia.

  • -
  • The batch files (as long as you keep them) are records of your work. They make a natural starting -point for quickly re-building your world should you ever decide to start over.

  • -
  • If you are an Evennia developer, using a batch file is a fast way to setup a test-game after -having reset the database.

  • -
  • The batch files might come in useful should you ever decide to distribute all or part of your -world to others.

  • -
-

There are two batch processors, the Batch-command processor and the Batch-code processor. The -first one is the simpler of the two. It doesn’t require any programming knowledge - you basically -just list in-game commands in a text file. The code-processor on the other hand is much more -powerful but also more complex - it lets you use Evennia’s API to code your world in full-fledged -Python code.

- -

If you plan to use international characters in your batchfiles you are wise to read about file -encodings below.

-
-

A note on File Encodings

-

As mentioned, both the processors take text files as input and then proceed to process them. As long -as you stick to the standard ASCII character set (which means -the normal English characters, basically) you should not have to worry much about this section.

-

Many languages however use characters outside the simple ASCII table. Common examples are various -apostrophes and umlauts but also completely different symbols like those of the greek or cyrillic -alphabets.

-

First, we should make it clear that Evennia itself handles international characters just fine. It -(and Django) uses unicode strings internally.

-

The problem is that when reading a text file like the batchfile, we need to know how to decode the -byte-data stored therein to universal unicode. That means we need an encoding (a mapping) for how -the file stores its data. There are many, many byte-encodings used around the world, with opaque -names such as Latin-1, ISO-8859-3 or ARMSCII-8 to pick just a few examples. Problem is that -it’s practially impossible to determine which encoding was used to save a file just by looking at it -(it’s just a bunch of bytes!). You have to know.

-

With this little introduction it should be clear that Evennia can’t guess but has to assume an -encoding when trying to load a batchfile. The text editor and Evennia must speak the same “language” -so to speak. Evennia will by default first try the international UTF-8 encoding, but you can have -Evennia try any sequence of different encodings by customizing the ENCODINGS list in your settings -file. Evennia will use the first encoding in the list that do not raise any errors. Only if none -work will the server give up and return an error message.

-

You can often change the text editor encoding (this depends on your editor though), otherwise you -need to add the editor’s encoding to Evennia’s ENCODINGS list. If you are unsure, write a test -file with lots of non-ASCII letters in the editor of your choice, then import to make sure it works -as it should.

-

More help with encodings can be found in the entry Text Encodings and also in the -Wikipedia article here.

-

A footnote for the batch-code processor: Just because Evennia can parse your file and your -fancy special characters, doesn’t mean that Python allows their use. Python syntax only allows -international characters inside strings. In all other source code only ASCII set characters are -allowed.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Bootstrap-&-Evennia.html b/docs/0.9.5/Bootstrap-&-Evennia.html deleted file mode 100644 index 78f5013d7c..0000000000 --- a/docs/0.9.5/Bootstrap-&-Evennia.html +++ /dev/null @@ -1,218 +0,0 @@ - - - - - - - - - Bootstrap & Evennia — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Bootstrap & Evennia

-
-
-

What is Bootstrap?

-

Evennia’s new default web page uses a framework called Bootstrap. This -framework is in use across the internet - you’ll probably start to recognize its influence once you -learn some of the common design patterns. This switch is great for web developers, perhaps like -yourself, because instead of wondering about setting up different grid systems or what custom class -another designer used, we have a base, a bootstrap, to work from. Bootstrap is responsive by -default, and comes with some default styles that Evennia has lightly overrode to keep some of the -same colors and styles you’re used to from the previous design.

-

For your reading pleasure, a brief overview of Bootstrap follows. For more in-depth info, please -read the documentation.

-
-
-

The Layout System

-

Other than the basic styling Bootstrap includes, it also includes a built in layout and grid -system. -The first part of this system is the -container.

-

The container is meant to hold all your page content. Bootstrap provides two types: fixed-width and -full-width. -Fixed-width containers take up a certain max-width of the page - they’re useful for limiting the -width on Desktop or Tablet platforms, instead of making the content span the width of the page.

-
<div class="container">
-    <!--- Your content here -->
-</div>
-
-
-

Full width containers take up the maximum width available to them - they’ll span across a wide- -screen desktop or a smaller screen phone, edge-to-edge.

-
<div class="container-fluid">
-    <!--- This content will span the whole page -->
-</div>
-
-
-

The second part of the layout system is the grid. -This is the bread-and-butter of the layout of Bootstrap - it allows you to change the size of -elements depending on the size of the screen, without writing any media queries. We’ll briefly go -over it - to learn more, please read the docs or look at the source code for Evennia’s home page in -your browser.

-
-

Important! Grid elements should be in a .container or .container-fluid. This will center the -contents of your site.

-
-

Bootstrap’s grid system allows you to create rows and columns by applying classes based on -breakpoints. The default breakpoints are extra small, small, medium, large, and extra-large. If -you’d like to know more about these breakpoints, please take a look at the documentation for -them.

-

To use the grid system, first create a container for your content, then add your rows and columns -like so:

-
<div class="container">
-    <div class="row">
-        <div class="col">
-           1 of 3
-        </div>
-        <div class="col">
-           2 of 3
-        </div>
-        <div class="col">
-           3 of 3
-        </div>
-    </div>
-</div>
-
-
-

This layout would create three equal-width columns.

-

To specify your sizes - for instance, Evennia’s default site has three columns on desktop and -tablet, but reflows to single-column on smaller screens. Try it out!

-
<div class="container">
-    <div class="row">
-        <div class="col col-md-6 col-lg-3">
-            1 of 4
-        </div>
-        <div class="col col-md-6 col-lg-3">
-            2 of 4
-        </div>
-        <div class="col col-md-6 col-lg-3">
-            3 of 4
-        </div>
-        <div class="col col-md-6 col-lg-3">
-            4 of 4
-        </div>
-    </div>
-</div>
-
-
-

This layout would be 4 columns on large screens, 2 columns on medium screens, and 1 column on -anything smaller.

-

To learn more about Bootstrap’s grid, please take a look at the -docs

-
-
-
-

More Bootstrap

-

Bootstrap also provides a huge amount of utilities, as well as styling and content elements. To -learn more about them, please read the Bootstrap docs or read one of our other web tutorials.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Bootstrap-Components-and-Utilities.html b/docs/0.9.5/Bootstrap-Components-and-Utilities.html deleted file mode 100644 index 684dd6017e..0000000000 --- a/docs/0.9.5/Bootstrap-Components-and-Utilities.html +++ /dev/null @@ -1,225 +0,0 @@ - - - - - - - - - Bootstrap Components and Utilities — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Bootstrap Components and Utilities

-

Bootstrap provides many utilities and components you can use when customizing Evennia’s web -presence. We’ll go over a few examples here that you might find useful.

-
-

Please take a look at either the basic web tutorial or the web -character view tutorial -to get a feel for how to add pages to Evennia’s website to test these examples.

-
-
-

General Styling

-

Bootstrap provides base styles for your site. These can be customized through CSS, but the default -styles are intended to provide a consistent, clean look for sites.

-
-

Color

-

Most elements can be styled with default colors. Take a look at the -documentation to learn more about these colors

-
    -
  • suffice to say, adding a class of text-* or bg-*, for instance, text-primary, sets the text color -or background color.

  • -
-
-
-

Borders

-

Simply adding a class of ‘border’ to an element adds a border to the element. For more in-depth -info, please read the documentation on -borders..

-
<span class="border border-dark"></span>
-
-
-

You can also easily round corners just by adding a class.

-
<img src="..." class="rounded" />
-
-
-
-
-

Spacing

-

Bootstrap provides classes to easily add responsive margin and padding. Most of the time, you might -like to add margins or padding through CSS itself - however these classes are used in the default -Evennia site. Take a look at the docs to -learn more.

-
-
-
-
-

Components

-
-

Buttons

-

Buttons in Bootstrap are very easy to use - -button styling can be added to <button>, <a>, and <input> elements.

-
<a class="btn btn-primary" href="#" role="button">I'm a Button</a>
-<button class="btn btn-primary" type="submit">Me too!</button>
-<input class="btn btn-primary" type="button" value="Button">
-<input class="btn btn-primary" type="submit" value="Also a Button">
-<input class="btn btn-primary" type="reset" value="Button as Well">
-
-
-
-
-

Cards

-

Cards provide a container for other elements -that stands out from the rest of the page. The “Accounts”, “Recently Connected”, and “Database -Stats” on the default webpage are all in cards. Cards provide quite a bit of formatting options - -the following is a simple example, but read the documentation or look at the site’s source for more.

-
<div class="card">
-  <div class="card-body">
-    <h4 class="card-title">Card title</h4>
-    <h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
-    <p class="card-text">Fancy, isn't it?</p>
-    <a href="#" class="card-link">Card link</a>
-  </div>
-</div>
-
-
-
-
-

Jumbotron

-

Jumbotrons are useful for featuring an -image or tagline for your game. They can flow with the rest of your content or take up the full -width of the page - Evennia’s base site uses the former.

-
<div class="jumbotron jumbotron-fluid">
-  <div class="container">
-    <h1 class="display-3">Full Width Jumbotron</h1>
-    <p class="lead">Look at the source of the default Evennia page for a regular Jumbotron</p>
-  </div>
-</div>
-
-
-
-
-

Forms

-

Forms are highly customizable with Bootstrap. -For a more in-depth look at how to use forms and their styles in your own Evennia site, please read -over the web character gen tutorial.

-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Builder-Docs.html b/docs/0.9.5/Builder-Docs.html deleted file mode 100644 index 55a2d204f1..0000000000 --- a/docs/0.9.5/Builder-Docs.html +++ /dev/null @@ -1,159 +0,0 @@ - - - - - - - - - Builder Docs — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Builder Docs

-

This section contains information useful to world builders.

-
-

Building basics

- -
-
-

Advanced building and World building

- -
-
-

The Tutorial world

- -
-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Building-Permissions.html b/docs/0.9.5/Building-Permissions.html deleted file mode 100644 index e681c18d2e..0000000000 --- a/docs/0.9.5/Building-Permissions.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - - - - Building Permissions — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Building Permissions

-

OBS: This gives only a brief introduction to the access system. Locks and permissions are fully -detailed here.

-
-

The super user

-

There are strictly speaking two types of users in Evennia, the super user and everyone else. The -superuser is the first user you create, object #1. This is the all-powerful server-owner account. -Technically the superuser not only has access to everything, it bypasses the permission checks -entirely. This makes the superuser impossible to lock out, but makes it unsuitable to actually play- -test the game’s locks and restrictions with (see @quell below). Usually there is no need to have -but one superuser.

-
-
-

Assigning permissions

-

Whereas permissions can be used for anything, those put in settings.PERMISSION_HIERARCHY will have -a ranking relative each other as well. We refer to these types of permissions as hierarchical -permissions. When building locks to check these permissions, the perm() lock function is -used. By default Evennia creates the following hierarchy (spelled exactly like this):

-
    -
  1. Developers basically have the same access as superusers except that they do not sidestep -the Permission system. Assign only to really trusted server-admin staff since this level gives -access both to server reload/shutdown functionality as well as (and this may be more critical) gives -access to the all-powerful @py command that allows the execution of arbitrary Python code on the -command line.

  2. -
  3. Admins can do everything except affecting the server functions themselves. So an Admin -couldn’t reload or shutdown the server for example. They also cannot execute arbitrary Python code -on the console or import files from the hard drive.

  4. -
  5. Builders - have all the build commands, but cannot affect other accounts or mess with the -server.

  6. -
  7. Helpers are almost like a normal Player, but they can also add help files to the database.

  8. -
  9. Players is the default group that new players end up in. A new player have permission to use -tells and to use and create new channels.

  10. -
-

A user having a certain level of permission automatically have access to locks specifying access of -a lower level.

-

To assign a new permission from inside the game, you need to be able to use the @perm command. -This is an Developer-level command, but it could in principle be made lower-access since it only -allows assignments equal or lower to your current level (so you cannot use it to escalate your own -permission level). So, assuming you yourself have Developer access (or is superuser), you assign -a new account “Tommy” to your core staff with the command

-
@perm/account Tommy = Developer
-
-
-

or

-
@perm *Tommy = Developer
-
-
-

We use a switch or the *name format to make sure to put the permission on the Account and not on -any eventual Character that may also be named “Tommy”. This is usually what you want since the -Account will then remain an Developer regardless of which Character they are currently controlling. -To limit permission to a per-Character level you should instead use quelling (see below). Normally -permissions can be any string, but for these special hierarchical permissions you can also use -plural (“Developer” and “Developers” both grant the same powers).

-
-
-

Quelling your permissions

-

When developing it can be useful to check just how things would look had your permission-level been -lower. For this you can use quelling. Normally, when you puppet a Character you are using your -Account-level permission. So even if your Character only has Accounts level permissions, your -Developer-level Account will take precedence. With the @quell command you can change so that the -Character’s permission takes precedence instead:

-
 @quell
-
-
-

This will allow you to test out the game using the current Character’s permission level. A developer -or builder can thus in principle maintain several test characters, all using different permission -levels. Note that you cannot escalate your permissions this way; If the Character happens to have a -higher permission level than the Account, the Account’s (lower) permission will still be used.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Building-Quickstart.html b/docs/0.9.5/Building-Quickstart.html deleted file mode 100644 index 7249995556..0000000000 --- a/docs/0.9.5/Building-Quickstart.html +++ /dev/null @@ -1,382 +0,0 @@ - - - - - - - - - Building Quickstart — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Building Quickstart

-

The default command definitions coming with Evennia -follows a style similar to that of MUX, so the -commands should be familiar if you used any such code bases before.

-
-

Throughout the larger documentation you may come across commands prefixed -with @. This is just an optional marker used in some places to make a -command stand out. Evennia defaults to ignoring the use of @ in front of -your command (so entering dig is the same as entering @dig).

-
-

The default commands have the following style (where [...] marks optional parts):

-
 command[/switch/switch...] [arguments ...]
-
-
-

A switch is a special, optional flag to the command to make it behave differently. It is always -put directly after the command name, and begins with a forward slash (/). The arguments are one -or more inputs to the commands. It’s common to use an equal sign (=) when assigning something to -an object.

-

Below are some examples of commands you can try when logged in to the game. Use help <command> for -learning more about each command and their detailed options.

-
-

Stepping Down From Godhood

-

If you just installed Evennia, your very first player account is called user #1, also known as the -superuser or god user. This user is very powerful, so powerful that it will override many game -restrictions such as locks. This can be useful, but it also hides some functionality that you might -want to test.

-

To temporarily step down from your superuser position you can use the quell command in-game:

-
quell
-
-
-

This will make you start using the permission of your current character’s level instead of your -superuser level. If you didn’t change any settings your game Character should have an Developer -level permission - high as can be without bypassing locks like the superuser does. This will work -fine for the examples on this page. Use unquell to get back to superuser status again afterwards.

-
-
-

Creating an Object

-

Basic objects can be anything – swords, flowers and non-player characters. They are created using -the create command:

-
create box
-
-
-

This created a new ‘box’ (of the default object type) in your inventory. Use the command inventory -(or i) to see it. Now, ‘box’ is a rather short name, let’s rename it and tack on a few aliases.

-
name box = very large box;box;very;crate
-
-
-

We now renamed the box to very large box (and this is what we will see when looking at it), but we -will also recognize it by any of the other names we give - like crate or simply box as before. -We could have given these aliases directly after the name in the create command, this is true for -all creation commands - you can always tag on a list of ;-separated aliases to the name of your -new object. If you had wanted to not change the name itself, but to only add aliases, you could have -used the alias command.

-

We are currently carrying the box. Let’s drop it (there is also a short cut to create and drop in -one go by using the /drop switch, for example create/drop box).

-
drop box
-
-
-

Hey presto - there it is on the ground, in all its normality.

-
examine box
-
-
-

This will show some technical details about the box object. For now we will ignore what this -information means.

-

Try to look at the box to see the (default) description.

-
look box
-You see nothing special.
-
-
-

The description you get is not very exciting. Let’s add some flavor.

-
describe box = This is a large and very heavy box.
-
-
-

If you try the get command we will pick up the box. So far so good, but if we really want this to -be a large and heavy box, people should not be able to run off with it that easily. To prevent -this we need to lock it down. This is done by assigning a Lock to it. Make sure the box was -dropped in the room, then try this:

-
lock box = get:false()
-
-
-

Locks represent a rather big topic, but for now that will do what we want. This will lock -the box so noone can lift it. The exception is superusers, they override all locks and will pick it -up anyway. Make sure you are quelling your superuser powers and try to get the box now:

-
> get box
-You can't get that.
-
-
-

Think thís default error message looks dull? The get command looks for an Attribute -named get_err_msg for returning a nicer error message (we just happen to know this, you would need -to peek into the -code for -the get command to find out.). You set attributes using the set command:

-
set box/get_err_msg = It's way too heavy for you to lift.
-
-
-

Try to get it now and you should see a nicer error message echoed back to you. To see what this -message string is in the future, you can use ‘examine.’

-
examine box/get_err_msg
-
-
-

Examine will return the value of attributes, including color codes. examine here/desc would return -the raw description of your current room (including color codes), so that you can copy-and-paste to -set its description to something else.

-

You create new Commands (or modify existing ones) in Python outside the game. See the Adding -Commands tutorial for help with creating your first own Command.

-
-
-

Get a Personality

-

Scripts are powerful out-of-character objects useful for many “under the hood” things. -One of their optional abilities is to do things on a timer. To try out a first script, let’s put one -on ourselves. There is an example script in evennia/contrib/tutorial_examples/bodyfunctions.py -that is called BodyFunctions. To add this to us we will use the script command:

-
script self = tutorial_examples.bodyfunctions.BodyFunctions
-
-
-

(note that you don’t have to give the full path as long as you are pointing to a place inside the -contrib directory, it’s one of the places Evennia looks for Scripts). Wait a while and you will -notice yourself starting making random observations.

-
script self
-
-
-

This will show details about scripts on yourself (also examine works). You will see how long it is -until it “fires” next. Don’t be alarmed if nothing happens when the countdown reaches zero - this -particular script has a randomizer to determine if it will say something or not. So you will not see -output every time it fires.

-

When you are tired of your character’s “insights”, kill the script with

-
script/stop self = tutorial_examples.bodyfunctions.BodyFunctions
-
-
-

You create your own scripts in Python, outside the game; the path you give to script is literally -the Python path to your script file. The Scripts page explains more details.

-
-
-

Pushing Your Buttons

-

If we get back to the box we made, there is only so much fun you can do with it at this point. It’s -just a dumb generic object. If you renamed it to stone and changed its description noone would be -the wiser. However, with the combined use of custom Typeclasses, Scripts -and object-based Commands, you could expand it and other items to be as unique, complex -and interactive as you want.

-

Let’s take an example. So far we have only created objects that use the default object typeclass -named simply Object. Let’s create an object that is a little more interesting. Under -evennia/contrib/tutorial_examples there is a module red_button.py. It contains the enigmatic -RedButton typeclass.

-

Let’s make us one of those!

-
create/drop button:tutorial_examples.red_button.RedButton
-
-
-

We import the RedButton python class the same way you would import it in Python except Evennia makes -sure to look inevennia/contrib/ so you don’t have to write the full path every time. There you go

-
    -
  • one red button.

  • -
-

The RedButton is an example object intended to show off a few of Evennia’s features. You will find -that the Typeclass and Commands controlling it are inside -evennia/contrib/tutorial_examples/.

-

If you wait for a while (make sure you dropped it!) the button will blink invitingly. Why don’t you -try to push it …? Surely a big red button is meant to be pushed. You know you want to.

-
-
-

Making Yourself a House

-

The main command for shaping the game world is dig. For example, if you are standing in Limbo you -can dig a route to your new house location like this:

-
dig house = large red door;door;in,to the outside;out
-
-
-

This will create a new room named ‘house’. Spaces at the start/end of names and aliases are ignored -so you could put more air if you wanted. This call will directly create an exit from your current -location named ‘large red door’ and a corresponding exit named ‘to the outside’ in the house room -leading back to Limbo. We also define a few aliases to those exits, so people don’t have to write -the full thing all the time.

-

If you wanted to use normal compass directions (north, west, southwest etc), you could do that with -dig too. But Evennia also has a limited version of dig that helps for compass directions (and -also up/down and in/out). It’s called tunnel:

-
tunnel sw = cliff
-
-
-

This will create a new room “cliff” with an exit “southwest” leading there and a path “northeast” -leading back from the cliff to your current location.

-

You can create new exits from where you are using the open command:

-
open north;n = house
-
-
-

This opens an exit north (with an alias n) to the previously created room house.

-

If you have many rooms named house you will get a list of matches and have to select which one you -want to link to. You can also give its database (#dbref) number, which is unique to every object. -This can be found with the examine command or by looking at the latest constructions with -objects.

-

Follow the north exit to your ‘house’ or teleport to it:

-
north
-
-
-

or:

-
teleport house
-
-
-

To manually open an exit back to Limbo (if you didn’t do so with the dig command):

-
open door = limbo
-
-
-

(or give limbo’s dbref which is #2)

-
-
-

Reshuffling the World

-

You can find things using the find command. Assuming you are back at Limbo, let’s teleport the -large box to our house.

-
> teleport box = house
-very large box is leaving Limbo, heading for house.
-Teleported very large box -> house.
-
-
-

We can still find the box by using find:

-
> find box
-One Match(#1-#8):
-very large box(#8) - src.objects.objects.Object
-
-
-

Knowing the #dbref of the box (#8 in this example), you can grab the box and get it back here -without actually yourself going to house first:

-
teleport #8 = here
-
-
-

(You can usually use here to refer to your current location. To refer to yourself you can use -self or me). The box should now be back in Limbo with you.

-

We are getting tired of the box. Let’s destroy it.

-
destroy box
-
-
-

You can destroy many objects in one go by giving a comma-separated list of objects (or their -#dbrefs, if they are not in the same location) to the command.

-
-
-

Adding a Help Entry

-

An important part of building is keeping the help files updated. You can add, delete and append to -existing help entries using the sethelp command.

-
sethelp/add MyTopic = This help topic is about ...
-
-
-
-
-

Adding a World

-

After this brief introduction to building you may be ready to see a more fleshed-out example. -Evennia comes with a tutorial world for you to explore.

-

First you need to switch back to superuser by using the unquell command. Next, place yourself in -Limbo and run the following command:

-
batchcommand tutorial_world.build
-
-
-

This will take a while (be patient and don’t re-run the command). You will see all the commands used -to build the world scroll by as the world is built for you.

-

You will end up with a new exit from Limbo named tutorial. Apart from being a little solo- -adventure in its own right, the tutorial world is a good source for learning Evennia building (and -coding).

-

Read the batch -file to see -exactly how it’s built, step by step. See also more info about the tutorial world [here](Tutorial- -World-Introduction).

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Building-a-mech-tutorial.html b/docs/0.9.5/Building-a-mech-tutorial.html deleted file mode 100644 index 0f8a0e1c13..0000000000 --- a/docs/0.9.5/Building-a-mech-tutorial.html +++ /dev/null @@ -1,349 +0,0 @@ - - - - - - - - - Building a mech tutorial — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Building a mech tutorial

-
-

This page was adapted from the article “Building a Giant Mech in Evennia” by Griatch, published in -Imaginary Realities Volume 6, issue 1, 2014. The original article is no longer available online, -this is a version adopted to be compatible with the latest Evennia.

-
-
-

Creating the Mech

-

Let us create a functioning giant mech using the Python MUD-creation system Evennia. Everyone likes -a giant mech, right? Start in-game as a character with build privileges (or the superuser).

-
@create/drop Giant Mech ; mech
-
-
-

Boom. We created a Giant Mech Object and dropped it in the room. We also gave it an alias mech. -Let’s describe it.

-
@desc mech = This is a huge mech. It has missiles and stuff.
-
-
-

Next we define who can “puppet” the mech object.

-
@lock mech = puppet:all()
-
-
-

This makes it so that everyone can control the mech. More mechs to the people! (Note that whereas -Evennia’s default commands may look vaguely MUX-like, you can change the syntax to look like -whatever interface style you prefer.)

-

Before we continue, let’s make a brief detour. Evennia is very flexible about its objects and even -more flexible about using and adding commands to those objects. Here are some ground rules well -worth remembering for the remainder of this article:

-
    -
  • The Account represents the real person logging in and has no game-world existence.

  • -
  • Any Object can be puppeted by an Account (with proper permissions).

  • -
  • Characters, Rooms, and Exits are just -children of normal Objects.

  • -
  • Any Object can be inside another (except if it creates a loop).

  • -
  • Any Object can store custom sets of commands on it. Those commands can:

    -
      -
    • be made available to the puppeteer (Account),

    • -
    • be made available to anyone in the same location as the Object, and

    • -
    • be made available to anyone “inside” the Object

    • -
    • Also Accounts can store commands on themselves. Account commands are always available unless -commands on a puppeted Object explicitly override them.

    • -
    -
  • -
-

In Evennia, using the @ic command will allow you to puppet a given Object (assuming you have -puppet-access to do so). As mentioned above, the bog-standard Character class is in fact like any -Object: it is auto-puppeted when logging in and just has a command set on it containing the normal -in-game commands, like look, inventory, get and so on.

-
@ic mech
-
-
-

You just jumped out of your Character and are now the mech! If people look at you in-game, they -will look at a mech. The problem at this point is that the mech Object has no commands of its own. -The usual things like look, inventory and get sat on the Character object, remember? So at the -moment the mech is not quite as cool as it could be.

-
@ic <Your old Character>
-
-
-

You just jumped back to puppeting your normal, mundane Character again. All is well.

-
-

(But, you ask, where did that @ic command come from, if the mech had no commands on it? The -answer is that it came from the Account’s command set. This is important. Without the Account being -the one with the @ic command, we would not have been able to get back out of our mech again.)

-
-
-

Arming the Mech

-

Let us make the mech a little more interesting. In our favorite text editor, we will create some new -mech-suitable commands. In Evennia, commands are defined as Python classes.

-
# in a new file mygame/commands/mechcommands.py
-
-from evennia import Command
-
-class CmdShoot(Command):
-    """
-    Firing the mech’s gun
-
-    Usage:
-      shoot [target]
-
-    This will fire your mech’s main gun. If no
-    target is given, you will shoot in the air.
-    """
-    key = "shoot"
-    aliases = ["fire", "fire!"]
-
-    def func(self):
-        "This actually does the shooting"
-
-        caller = self.caller
-        location = caller.location
-
-        if not self.args:
-            # no argument given to command - shoot in the air
-            message = "BOOM! The mech fires its gun in the air!"
-            location.msg_contents(message)
-            return
-
-        # we have an argument, search for target
-        target = caller.search(self.args.strip())
-        if target:
-            message = "BOOM! The mech fires its gun at %s" % target.key
-            location.msg_contents(message)
-
-class CmdLaunch(Command):
-    # make your own 'launch'-command here as an exercise!
-    # (it's very similar to the 'shoot' command above).
-
-
-
-

This is saved as a normal Python module (let’s call it mechcommands.py), in a place Evennia looks -for such modules (mygame/commands/). This command will trigger when the player gives the command -“shoot”, “fire,” or even “fire!” with an exclamation mark. The mech can shoot in the air or at a -target if you give one. In a real game the gun would probably be given a chance to hit and give -damage to the target, but this is enough for now.

-

We also make a second command for launching missiles (CmdLaunch). To save -space we won’t describe it here; it looks the same except it returns a text -about the missiles being fired and has different key and aliases. We leave -that up to you to create as an exercise. You could have it print “WOOSH! The -mech launches missiles against !”, for example.

-

Now we shove our commands into a command set. A Command Set (CmdSet) is a container -holding any number of commands. The command set is what we will store on the mech.

-
# in the same file mygame/commands/mechcommands.py
-
-from evennia import CmdSet
-from evennia import default_cmds
-
-class MechCmdSet(CmdSet):
-    """
-    This allows mechs to do do mech stuff.
-    """
-    key = "mechcmdset"
-
-    def at_cmdset_creation(self):
-        "Called once, when cmdset is first created"
-        self.add(CmdShoot())
-        self.add(CmdLaunch())
-
-
-

This simply groups all the commands we want. We add our new shoot/launch commands. Let’s head back -into the game. For testing we will manually attach our new CmdSet to the mech.

-
@py self.search("mech").cmdset.add("commands.mechcommands.MechCmdSet")
-
-
-

This is a little Python snippet (run from the command line as an admin) that searches for the mech -in our current location and attaches our new MechCmdSet to it. What we add is actually the Python -path to our cmdset class. Evennia will import and initialize it behind the scenes.

-
@ic mech
-
-
-

We are back as the mech! Let’s do some shooting!

-
fire!
-BOOM! The mech fires its gun in the air!
-
-
-

There we go, one functioning mech. Try your own launch command and see that it works too. We can -not only walk around as the mech — since the CharacterCmdSet is included in our MechCmdSet, the mech -can also do everything a Character could do, like look around, pick up stuff, and have an inventory. -We could now shoot the gun at a target or try the missile launch command. Once you have your own -mech, what else do you need?

-
-

Note: You’ll find that the mech’s commands are available to you by just standing in the same -location (not just by puppeting it). We’ll solve this with a lock in the next section.

-
-
-
-
-

Making a Mech production line

-

What we’ve done so far is just to make a normal Object, describe it and put some commands on it. -This is great for testing. The way we added it, the MechCmdSet will even go away if we reload the -server. Now we want to make the mech an actual object “type” so we can create mechs without those -extra steps. For this we need to create a new Typeclass.

-

A Typeclass is a near-normal Python class that stores its existence to the database -behind the scenes. A Typeclass is created in a normal Python source file:

-
# in the new file mygame/typeclasses/mech.py
-
-from typeclasses.objects import Object
-from commands.mechcommands import MechCmdSet
-from evennia import default_cmds
-
-class Mech(Object):
-    """
-    This typeclass describes an armed Mech.
-    """
-    def at_object_creation(self):
-        "This is called only when object is first created"
-        self.cmdset.add_default(default_cmds.CharacterCmdSet)
-        self.cmdset.add(MechCmdSet, permanent=True)
-        self.locks.add("puppet:all();call:false()")
-        self.db.desc = "This is a huge mech. It has missiles and stuff."
-
-
-

For convenience we include the full contents of the default CharacterCmdSet in there. This will -make a Character’s normal commands available to the mech. We also add the mech-commands from before, -making sure they are stored persistently in the database. The locks specify that anyone can puppet -the meck and no-one can “call” the mech’s Commands from ‘outside’ it - you have to puppet it to be -able to shoot.

-

That’s it. When Objects of this type are created, they will always start out with the mech’s command -set and the correct lock. We set a default description, but you would probably change this with -@desc to individualize your mechs as you build them.

-

Back in the game, just exit the old mech (@ic back to your old character) then do

-
@create/drop The Bigger Mech ; bigmech : mech.Mech
-
-
-

We create a new, bigger mech with an alias bigmech. Note how we give the python-path to our -Typeclass at the end — this tells Evennia to create the new object based on that class (we don’t -have to give the full path in our game dir typeclasses.mech.Mech because Evennia knows to look in -the typeclasses folder already). A shining new mech will appear in the room! Just use

-
@ic bigmech
-
-
-

to take it on a test drive.

-
-
-

Future Mechs

-

To expand on this you could add more commands to the mech and remove others. Maybe the mech -shouldn’t work just like a Character after all. Maybe it makes loud noises every time it passes from -room to room. Maybe it cannot pick up things without crushing them. Maybe it needs fuel, ammo and -repairs. Maybe you’ll lock it down so it can only be puppeted by emo teenagers.

-

Having you puppet the mech-object directly is also just one way to implement a giant mech in -Evennia.

-

For example, you could instead picture a mech as a “vehicle” that you “enter” as your normal -Character (since any Object can move inside another). In that case the “insides” of the mech Object -could be the “cockpit”. The cockpit would have the MechCommandSet stored on itself and all the -shooting goodness would be made available to you only when you enter it.

-

And of course you could put more guns on it. And make it fly.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Building-menus.html b/docs/0.9.5/Building-menus.html deleted file mode 100644 index 80bbac94ed..0000000000 --- a/docs/0.9.5/Building-menus.html +++ /dev/null @@ -1,1319 +0,0 @@ - - - - - - - - - Building menus — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Building menus

-
-
-

The building_menu contrib

-

This contrib allows you to write custom and easy to use building menus. As the name implies, these -menus are most useful for building things, that is, your builders might appreciate them, although -you can use them for your players as well.

-

Building menus are somewhat similar to EvMenu although they don’t use the same system at all and -are intended to make building easier. They replicate what other engines refer to as “building -editors”, which allow to you to build in a menu instead of having to enter a lot of complex -commands. Builders might appreciate this simplicity, and if the code that was used to create them -is simple as well, coders could find this contrib useful.

-
-

A simple menu

-

Before diving in, there are some things to point out:

-
    -
  • Building menus work on an object. This object will be edited by manipulations in the menu. So -you can create a menu to add/edit a room, an exit, a character and so on.

  • -
  • Building menus are arranged in layers of choices. A choice gives access to an option or to a sub- -menu. Choices are linked to commands (usually very short). For instance, in the example shown -below, to edit the room key, after opening the building menu, you can type k. That will lead you -to the key choice where you can enter a new key for the room. Then you can enter @ to leave this -choice and go back to the entire menu. (All of this can be changed).

  • -
  • To open the menu, you will need something like a command. This contrib offers a basic command for -demonstration, but we will override it in this example, using the same code with more flexibility.

  • -
-

So let’s add a very basic example to begin with.

-
-

A generic editing command

-

Let’s begin by adding a new command. You could add or edit the following file (there’s no trick -here, feel free to organize the code differently):

-
# file: commands/building.py
-from evennia.contrib.building_menu import BuildingMenu
-from commands.command import Command
-
-class EditCmd(Command):
-
-    """
-    Editing command.
-
-    Usage:
-      @edit [object]
-
-    Open a building menu to edit the specified object.  This menu allows to
-    specific information about this object.
-
-    Examples:
-      @edit here
-      @edit self
-      @edit #142
-
-    """
-
-    key = "@edit"
-    locks = "cmd:id(1) or perm(Builders)"
-    help_category = "Building"
-
-    def func(self):
-        if not self.args.strip():
-            self.msg("|rYou should provide an argument to this function: the object to edit.|n")
-            return
-
-        obj = self.caller.search(self.args.strip(), global_search=True)
-        if not obj:
-            return
-
-        if obj.typename == "Room":
-            Menu = RoomBuildingMenu
-        else:
-            self.msg("|rThe object {} cannot be
-edited.|n".format(obj.get_display_name(self.caller)))
-            return
-
-        menu = Menu(self.caller, obj)
-        menu.open()
-
-
-

This command is rather simple in itself:

-
    -
  1. It has a key @edit and a lock to only allow builders to use it.

  2. -
  3. In its func method, it begins by checking the arguments, returning an error if no argument is -specified.

  4. -
  5. It then searches for the given argument. We search globally. The search method used in this -way will return the found object or None. It will also send the error message to the caller if -necessary.

  6. -
  7. Assuming we have found an object, we check the object typename. This will be used later when -we want to display several building menus. For the time being, we only handle Room. If the -caller specified something else, we’ll display an error.

  8. -
  9. Assuming this object is a Room, we have defined a Menu object containing the class of our -building menu. We build this class (creating an instance), giving it the caller and the object to -edit.

  10. -
  11. We then open the building menu, using the open method.

  12. -
-

The end might sound a bit surprising at first glance. But the process is still very simple: we -create an instance of our building menu and call its open method. Nothing more.

-
-

Where is our building menu?

-
-

If you go ahead and add this command and test it, you’ll get an error. We haven’t defined -RoomBuildingMenu yet.

-

To add this command, edit commands/default_cmdsets.py. Import our command, adding an import line -at the top of the file:

-
"""
-...
-"""
-
-from evennia import default_cmds
-
-# The following line is to be added
-from commands.building import EditCmd
-
-
-

And in the class below (CharacterCmdSet), add the last line of this code:

-
class CharacterCmdSet(default_cmds.CharacterCmdSet):
-    """
-    The `CharacterCmdSet` contains general in-game commands like `look`,
-    `get`, etc available on in-game Character objects. It is merged with
-    the `AccountCmdSet` when an Account puppets a Character.
-    """
-    key = "DefaultCharacter"
-
-    def at_cmdset_creation(self):
-        """
-        Populates the cmdset
-        """
-        super().at_cmdset_creation()
-        #
-        # any commands you add below will overload the default ones.
-        #
-        self.add(EditCmd())
-
-
-
-
-

Our first menu

-

So far, we can’t use our building menu. Our @edit command will throw an error. We have to define -the RoomBuildingMenu class. Open the commands/building.py file and add to the end of the file:

-
# ... at the end of commands/building.py
-# Our building menu
-
-class RoomBuildingMenu(BuildingMenu):
-
-    """
-    Building menu to edit a room.
-
-    For the time being, we have only one choice: key, to edit the room key.
-
-    """
-
-    def init(self, room):
-        self.add_choice("key", "k", attr="key")
-
-
-

Save these changes, reload your game. You can now use the @edit command. Here’s what we get -(notice that the commands we enter into the game are prefixed with > , though this prefix will -probably not appear in your MUD client):

-
> look
-Limbo(#2)
-Welcome to your new Evennia-based game! Visit http://www.evennia.com if you need
-help, want to contribute, report issues or just join the community.
-As Account #1 you can create a demo/tutorial area with @batchcommand tutorial_world.build.
-
-> @edit here
-Building menu: Limbo
-
- [K]ey: Limbo
- [Q]uit the menu
-
-> q
-Closing the building menu.
-
-> @edit here
-Building menu: Limbo
-
- [K]ey: Limbo
- [Q]uit the menu
-
-> k
--------------------------------------------------------------------------------
-key for Limbo(#2)
-
-You can change this value simply by entering it.
-
-Use @ to go back to the main menu.
-
-Current value: Limbo
-
-> A beautiful meadow
--------------------------------------------------------------------------------
-
-key for A beautiful meadow(#2)
-
-You can change this value simply by entering it.
-
-Use @ to go back to the main menu.
-
-Current value: A beautiful meadow
-
-> @
-Building menu: A beautiful meadow
-
- [K]ey: A beautiful meadow
- [Q]uit the menu
-
-> q
-
-Closing the building menu.
-
-> look
-A beautiful meadow(#2)
-Welcome to your new Evennia-based game! Visit http://www.evennia.com if you need
-help, want to contribute, report issues or just join the community.
-As Account #1 you can create a demo/tutorial area with @batchcommand tutorial_world.build.
-
-
-

Before diving into the code, let’s examine what we have:

-
    -
  • When we use the @edit here command, a building menu for this room appears.

  • -
  • This menu has two choices:

    -
      -
    • Enter k to edit the room key. You will go into a choice where you can simply type the key -room key (the way we have done here). You can use @ to go back to the menu.

    • -
    • You can use q to quit the menu.

    • -
    -
  • -
-

We then check, with the look command, that the menu has modified this room key. So by adding a -class, with a method and a single line of code within, we’ve added a menu with two choices.

-
-
-

Code explanation

-

Let’s examine our code again:

-
class RoomBuildingMenu(BuildingMenu):
-
-    """
-    Building menu to edit a room.
-
-    For the time being, we have only one choice: key, to edit the room key.
-
-    """
-
-    def init(self, room):
-        self.add_choice("key", "k", attr="key")
-
-
-
    -
  • We first create a class inheriting from BuildingMenu. This is usually the case when we want to -create a building menu with this contrib.

  • -
  • In this class, we override the init method, which is called when the menu opens.

  • -
  • In this init method, we call add_choice. This takes several arguments, but we’ve defined only -three here:

    -
      -
    • The choice name. This is mandatory and will be used by the building menu to know how to -display this choice.

    • -
    • The command key to access this choice. We’ve given a simple "k". Menu commands usually are -pretty short (that’s part of the reason building menus are appreciated by builders). You can also -specify additional aliases, but we’ll see that later.

    • -
    • We’ve added a keyword argument, attr. This tells the building menu that when we are in this -choice, the text we enter goes into this attribute name. It’s called attr, but it could be a room -attribute or a typeclass persistent or non-persistent attribute (we’ll see other examples as well).

    • -
    -
  • -
-
-

We’ve added the menu choice for key here, why is another menu choice defined for quit?

-
-

Our building menu creates a choice at the end of our choice list if it’s a top-level menu (sub-menus -don’t have this feature). You can, however, override it to provide a different “quit” message or to -perform some actions.

-

I encourage you to play with this code. As simple as it is, it offers some functionalities already.

-
-
-
-

Customizing building menus

-

This somewhat long section explains how to customize building menus. There are different ways -depending on what you would like to achieve. We’ll go from specific to more advanced here.

-
-

Generic choices

-

In the previous example, we’ve used add_choice. This is one of three methods you can use to add -choices. The other two are to handle more generic actions:

-
    -
  • add_choice_edit: this is called to add a choice which points to the EvEditor. It is used to -edit a description in most cases, although you could edit other things. We’ll see an example -shortly. add_choice_edit uses most of the add_choice keyword arguments we’ll see, but usually -we specify only two (sometimes three):

    -
      -
    • The choice title as usual.

    • -
    • The choice key (command key) as usual.

    • -
    • Optionally, the attribute of the object to edit, with the attr keyword argument. By -default, attr contains db.desc. It means that this persistent data attribute will be edited by -the EvEditor. You can change that to whatever you want though.

    • -
    -
  • -
  • add_choice_quit: this allows to add a choice to quit the editor. Most advisable! If you don’t -do it, the building menu will do it automatically, except if you really tell it not to. Again, you -can specify the title and key of this menu. You can also call a function when this menu closes.

  • -
-

So here’s a more complete example (you can replace your RoomBuildingMenu class in -commands/building.py to see it):

-
class RoomBuildingMenu(BuildingMenu):
-
-    """
-    Building menu to edit a room.
-    """
-
-    def init(self, room):
-        self.add_choice("key", "k", attr="key")
-        self.add_choice_edit("description", "d")
-        self.add_choice_quit("quit this editor", "q")
-
-
-

So far, our building menu class is still thin… and yet we already have some interesting feature. -See for yourself the following MUD client output (again, the commands are prefixed with > to -distinguish them):

-
> @reload
-
-> @edit here
-Building menu: A beautiful meadow
-
- [K]ey: A beautiful meadow
- [D]escription:
-   Welcome to your new Evennia-based game! Visit http://www.evennia.com if you need
-help, want to contribute, report issues or just join the community.
-As Account #1 you can create a demo/tutorial area with @batchcommand tutorial_world.build.
- [Q]uit this editor
-
-> d
-
-----------Line Editor [editor]----------------------------------------------------
-01| Welcome to your new |wEvennia|n-based game! Visit http://www.evennia.com if you need
-02| help, want to contribute, report issues or just join the community.
-03| As Account #1 you can create a demo/tutorial area with |w@batchcommand tutorial_world.build|n.
-
-> :DD
-
-----------[l:03 w:034 c:0247]------------(:h for help)----------------------------
-Cleared 3 lines from buffer.
-
-> This is a beautiful meadow. But so beautiful I can't describe it.
-
-01| This is a beautiful meadow. But so beautiful I can't describe it.
-
-> :wq
-Building menu: A beautiful meadow
-
- [K]ey: A beautiful meadow
- [D]escription:
-   This is a beautiful meadow.  But so beautiful I can't describe it.
- [Q]uit this editor
-
-> q
-Closing the building menu.
-
-> look
-A beautiful meadow(#2)
-This is a beautiful meadow.  But so beautiful I can't describe it.
-
-
-

So by using the d shortcut in our building menu, an EvEditor opens. You can use the EvEditor -commands (like we did here, :DD to remove all, :wq to save and quit). When you quit the editor, -the description is saved (here, in room.db.desc) and you go back to the building menu.

-

Notice that the choice to quit has changed too, which is due to our adding add_choice_quit. In -most cases, you will probably not use this method, since the quit menu is added automatically.

-
-
-

add_choice options

-

add_choice and the two methods add_choice_edit and add_choice_quit take a lot of optional -arguments to make customization easier. Some of these options might not apply to add_choice_edit -or add_choice_quit however.

-

Below are the options of add_choice, specify them as arguments:

-
    -
  • The first positional, mandatory argument is the choice title, as we have seen. This will -influence how the choice appears in the menu.

  • -
  • The second positional, mandatory argument is the command key to access to this menu. It is best -to use keyword arguments for the other arguments.

  • -
  • The aliases keyword argument can contain a list of aliases that can be used to access to this -menu. For instance: add_choice(..., aliases=['t'])

  • -
  • The attr keyword argument contains the attribute to edit when this choice is selected. It’s a -string, it has to be the name, from the object (specified in the menu constructor) to reach this -attribute. For instance, a attr of "key" will try to find obj.key to read and write the -attribute. You can specify more complex attribute names, for instance, attr="db.desc" to set the -desc persistent attribute, or attr="ndb.something" so use a non-persistent data attribute on the -object.

  • -
  • The text keyword argument is used to change the text that will be displayed when the menu choice -is selected. Menu choices provide a default text that you can change. Since this is a long text, -it’s useful to use multi-line strings (see an example below).

  • -
  • The glance keyword argument is used to specify how to display the current information while in -the menu, when the choice hasn’t been opened. If you examine the previous examples, you will see -that the current (key or db.desc) was shown in the menu, next to the command key. This is -useful for seeing at a glance the current value (hence the name). Again, menu choices will provide -a default glance if you don’t specify one.

  • -
  • The on_enter keyword argument allows to add a callback to use when the menu choice is opened. -This is more advanced, but sometimes useful.

  • -
  • The on_nomatch keyword argument is called when, once in the menu, the caller enters some text -that doesn’t match any command (including the @ command). By default, this will edit the -specified attr.

  • -
  • The on_leave keyword argument allows to specify a callback used when the caller leaves the menu -choice. This can be useful for cleanup as well.

  • -
-

These are a lot of possibilities, and most of the time you won’t need them all. Here is a short -example using some of these arguments (again, replace the RoomBuildingMenu class in -commands/building.py with the following code to see it working):

-
class RoomBuildingMenu(BuildingMenu):
-
-    """
-    Building menu to edit a room.
-
-    For the time being, we have only one choice: key, to edit the room key.
-
-    """
-
-    def init(self, room):
-        self.add_choice("title", key="t", attr="key", glance="{obj.key}", text="""
-                -------------------------------------------------------------------------------
-                Editing the title of {{obj.key}}(#{{obj.id}})
-
-                You can change the title simply by entering it.
-                Use |y{back}|n to go back to the main menu.
-
-                Current title: |c{{obj.key}}|n
-        """.format(back="|n or |y".join(self.keys_go_back)))
-        self.add_choice_edit("description", "d")
-
-
-

Reload your game and see it in action:

-
> @edit here
-Building menu: A beautiful meadow
-
- [T]itle: A beautiful meadow
- [D]escription:
-   This is a beautiful meadow.  But so beautiful I can't describe it.
- [Q]uit the menu
-
-> t
--------------------------------------------------------------------------------
-
-Editing the title of A beautiful meadow(#2)
-
-You can change the title simply by entering it.
-Use @ to go back to the main menu.
-
-Current title: A beautiful meadow
-
-> @
-
-Building menu: A beautiful meadow
-
- [T]itle: A beautiful meadow
- [D]escription:
-   This is a beautiful meadow.  But so beautiful I can't describe it.
- [Q]uit the menu
-
-> q
-Closing the building menu.
-
-
-

The most surprising part is no doubt the text. We use the multi-line syntax (with """). -Excessive spaces will be removed from the left for each line automatically. We specify some -information between braces… sometimes using double braces. What might be a bit odd:

-
    -
  • {back} is a direct format argument we’ll use (see the .format specifiers).

  • -
  • {{obj...}} refers to the object being edited.  We use two braces, because .format` will remove -them.

  • -
-

In glance, we also use {obj.key} to indicate we want to show the room’s key.

-
-
-

Everything can be a function

-

The keyword arguments of add_choice are often strings (type str). But each of these arguments -can also be a function. This allows for a lot of customization, since we define the callbacks that -will be executed to achieve such and such an operation.

-

To demonstrate, we will try to add a new feature. Our building menu for rooms isn’t that bad, but -it would be great to be able to edit exits too. So we can add a new menu choice below -description… but how to actually edit exits? Exits are not just an attribute to set: exits are -objects (of type Exit by default) which stands between two rooms (object of type Room). So how -can we show that?

-

First let’s add a couple of exits in limbo, so we have something to work with:

-
@tunnel n
-@tunnel s
-
-
-

This should create two new rooms, exits leading to them from limbo and back to limbo.

-
> look
-A beautiful meadow(#2)
-This is a beautiful meadow.  But so beautiful I can't describe it.
-Exits: north(#4) and south(#7)
-
-
-

We can access room exits with the exits property:

-
> @py here.exits
-[<Exit: north>, <Exit: south>]
-
-
-

So what we need is to display this list in our building menu… and to allow to edit it would be -great. Perhaps even add new exits?

-

First of all, let’s write a function to display the glance on existing exits. Here’s the code, -it’s explained below:

-
class RoomBuildingMenu(BuildingMenu):
-
-    """
-    Building menu to edit a room.
-
-    """
-
-    def init(self, room):
-        self.add_choice("title", key="t", attr="key", glance="{obj.key}", text="""
-                -------------------------------------------------------------------------------
-                Editing the title of {{obj.key}}(#{{obj.id}})
-
-                You can change the title simply by entering it.
-                Use |y{back}|n to go back to the main menu.
-
-                Current title: |c{{obj.key}}|n
-        """.format(back="|n or |y".join(self.keys_go_back)))
-        self.add_choice_edit("description", "d")
-        self.add_choice("exits", "e", glance=glance_exits, attr="exits")
-
-
-# Menu functions
-def glance_exits(room):
-    """Show the room exits."""
-    if room.exits:
-        glance = ""
-        for exit in room.exits:
-            glance += "\n  |y{exit}|n".format(exit=exit.key)
-
-        return glance
-
-    return "\n  |gNo exit yet|n"
-
-
-

When the building menu opens, it displays each choice to the caller. A choice is displayed with its -title (rendered a bit nicely to show the key as well) and the glance. In the case of the exits -choice, the glance is a function, so the building menu calls this function giving it the object -being edited (the room here). The function should return the text to see.

-
> @edit here
-Building menu: A beautiful meadow
-
- [T]itle: A beautiful meadow
- [D]escription:
-   This is a beautiful meadow.  But so beautiful I can't describe it.
- [E]xits:
-  north
-  south
- [Q]uit the menu
-
-> q
-Closing the editor.
-
-
-
-

How do I know the parameters of the function to give?

-
-

The function you give can accept a lot of different parameters. This allows for a flexible approach -but might seem complicated at first. Basically, your function can accept any parameter, and the -building menu will send only the parameter based on their names. If your function defines an -argument named caller for instance (like def func(caller): ), then the building menu knows that -the first argument should contain the caller of the building menu. Here are the arguments, you -don’t have to specify them (if you do, they need to have the same name):

-
    -
  • menu: if your function defines an argument named menu, it will contain the building menu -itself.

  • -
  • choice: if your function defines an argument named choice, it will contain the Choice object -representing this menu choice.

  • -
  • string: if your function defines an argument named string, it will contain the user input to -reach this menu choice. This is not very useful, except on nomatch callbacks which we’ll see -later.

  • -
  • obj: if your function defines an argument named obj, it will contain the building menu edited -object.

  • -
  • caller: if your function defines an argument named caller, it will contain the caller of the -building menu.

  • -
  • Anything else: any other argument will contain the object being edited by the building menu.

  • -
-

So in our case:

-
def glance_exits(room):
-
-
-

The only argument we need is room. It’s not present in the list of possible arguments, so the -editing object of the building menu (the room, here) is given.

-
-

Why is it useful to get the menu or choice object?

-
-

Most of the time, you will not need these arguments. In very rare cases, you will use them to get -specific data (like the default attribute that was set). This tutorial will not elaborate on these -possibilities. Just know that they exist.

-

We should also define a text callback, so that we can enter our menu to see the room exits. We’ll -see how to edit them in the next section but this is a good opportunity to show a more complete -callback. To see it in action, as usual, replace the class and functions in commands/building.py:

-
# Our building menu
-
-class RoomBuildingMenu(BuildingMenu):
-
-    """
-    Building menu to edit a room.
-
-    """
-
-    def init(self, room):
-        self.add_choice("title", key="t", attr="key", glance="{obj.key}", text="""
-                -------------------------------------------------------------------------------
-                Editing the title of {{obj.key}}(#{{obj.id}})
-
-                You can change the title simply by entering it.
-                Use |y{back}|n to go back to the main menu.
-
-                Current title: |c{{obj.key}}|n
-        """.format(back="|n or |y".join(self.keys_go_back)))
-        self.add_choice_edit("description", "d")
-        self.add_choice("exits", "e", glance=glance_exits, attr="exits", text=text_exits)
-
-
-# Menu functions
-def glance_exits(room):
-    """Show the room exits."""
-    if room.exits:
-        glance = ""
-        for exit in room.exits:
-            glance += "\n  |y{exit}|n".format(exit=exit.key)
-
-        return glance
-
-    return "\n  |gNo exit yet|n"
-
-def text_exits(caller, room):
-    """Show the room exits in the choice itself."""
-    text = "-" * 79
-    text += "\n\nRoom exits:"
-    text += "\n Use |y@c|n to create a new exit."
-    text += "\n\nExisting exits:"
-    if room.exits:
-        for exit in room.exits:
-            text += "\n  |y@e {exit}|n".format(exit=exit.key)
-            if exit.aliases.all():
-                text += " (|y{aliases}|n)".format(aliases="|n, |y".join(
-                        alias for alias in exit.aliases.all()))
-            if exit.destination:
-                text += " toward {destination}".format(destination=exit.get_display_name(caller))
-    else:
-        text += "\n\n |gNo exit has yet been defined.|n"
-
-    return text
-
-
-

Look at the second callback in particular. It takes an additional argument, the caller (remember, -the argument names are important, their order is not relevant). This is useful for displaying -destination of exits accurately. Here is a demonstration of this menu:

-
> @edit here
-Building menu: A beautiful meadow
-
- [T]itle: A beautiful meadow
- [D]escription:
-   This is a beautiful meadow.  But so beautiful I can't describe it.
- [E]xits:
-  north
-  south
- [Q]uit the menu
-
-> e
--------------------------------------------------------------------------------
-
-Room exits:
- Use @c to create a new exit.
-
-Existing exits:
-  @e north (n) toward north(#4)
-  @e south (s) toward south(#7)
-
-> @
-Building menu: A beautiful meadow
-
- [T]itle: A beautiful meadow
- [D]escription:
-   This is a beautiful meadow.  But so beautiful I can't describe it.
- [E]xits:
-  north
-  south
- [Q]uit the menu
-
-> q
-Closing the building menu.
-
-
-

Using callbacks allows a great flexibility. We’ll now see how to handle sub-menus.

-
- -
-

Generic menu options

-

There are some options that can be set on any menu class. These options allow for greater -customization. They are class attributes (see the example below), so just set them in the class -body:

-
    -
  • keys_go_back (default to ["@"]): the keys to use to go back in the menu hierarchy, from choice -to root menu, from sub-menu to parent-menu. By default, only a @ is used. You can change this -key for one menu or all of them. You can define multiple return commands if you want.

  • -
  • sep_keys (default "."): this is the separator for nested keys. There is no real need to -redefine it except if you really need the dot as a key, and need nested keys in your menu.

  • -
  • joker_key (default to "*"): used for nested keys to indicate “any key”. Again, you shouldn’t -need to change it unless you want to be able to use the @*@ in a command key, and also need nested -keys in your menu.

  • -
  • min_shortcut (default to 1): although we didn’t see it here, one can create a menu choice -without giving it a key. If so, the menu system will try to “guess” the key. This option allows to -change the minimum length of any key for security reasons.

  • -
-

To set one of them just do so in your menu class(es):

-
class RoomBuildingMenu(BuildingMenu):
-    keys_go_back = ["/"]
-    min_shortcut = 2
-
-
-
-
-
-

Conclusion

-

Building menus mean to save you time and create a rich yet simple interface. But they can be -complicated to learn and require reading the source code to find out how to do such and such a -thing. This documentation, however long, is an attempt at describing this system, but chances are -you’ll still have questions about it after reading it, especially if you try to push this system to -a great extent. Do not hesitate to read the documentation of this contrib, it’s meant to be -exhaustive but user-friendly.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Choosing-An-SQL-Server.html b/docs/0.9.5/Choosing-An-SQL-Server.html deleted file mode 100644 index 9846e8abdf..0000000000 --- a/docs/0.9.5/Choosing-An-SQL-Server.html +++ /dev/null @@ -1,357 +0,0 @@ - - - - - - - - - Choosing An SQL Server — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Choosing An SQL Server

-

This page gives an overview of the supported SQL databases as well as instructions on install:

-
    -
  • SQLite3 (default)

  • -
  • PostgreSQL

  • -
  • MySQL / MariaDB

  • -
-

Since Evennia uses Django, most of our notes are based off of what we -know from the community and their documentation. While the information below may be useful, you can -always find the most up-to-date and “correct” information at Django’s Notes about supported -Databases page.

-
-

SQLite3

-

SQLite3 is a light weight single-file database. It is our default database -and Evennia will set this up for you automatically if you give no other options. SQLite stores the -database in a single file (mygame/server/evennia.db3). This means it’s very easy to reset this -database - just delete (or move) that evennia.db3 file and run evennia migrate again! No server -process is needed and the administrative overhead and resource consumption is tiny. It is also very -fast since it’s run in-memory. For the vast majority of Evennia installs it will probably be all -that’s ever needed.

-

SQLite will generally be much faster than MySQL/PostgreSQL but its performance comes with two -drawbacks:

-
    -
  • SQLite ignores length constraints by design; it is possible -to store very large strings and numbers in fields that technically should not accept them. This is -not something you will notice; your game will read and write them and function normally, but this -can create some data migration problems requiring careful thought if you do need to change -databases later.

  • -
  • SQLite can scale well to storage of millions of objects, but if you end up with a thundering herd -of users trying to access your MUD and web site at the same time, or you find yourself writing long- -running functions to update large numbers of objects on a live game, either will yield errors and -interference. SQLite does not work reliably with multiple concurrent threads or processes accessing -its records. This has to do with file-locking clashes of the database file. So for a production -server making heavy use of process- or thread pools (or when using a third-party webserver like -Apache), a proper database is a more appropriate choice.

  • -
-
-

Install of SQlite3

-

This is installed and configured as part of Evennia. The database file is created as -mygame/server/evennia.db3 when you run

-
evennia migrate
-
-
-

without changing any database options. An optional requirement is the sqlite3 client program - -this is required if you want to inspect the database data manually. A shortcut for using it with the -evennia database is evennia dbshell. Linux users should look for the sqlite3 package for their -distro while Mac/Windows should get the sqlite-tools package from this -page.

-

To inspect the default Evennia database (once it’s been created), go to your game dir and do

-
    sqlite3 server/evennia.db3
-    # or
-    evennia dbshell
-
-
-

This will bring you into the sqlite command line. Use .help for instructions and .quit to exit. -See here for a cheat-sheet of commands.

-
-
-
-

PostgreSQL

-

PostgreSQL is an open-source database engine, recommended by Django. -While not as fast as SQLite for normal usage, it will scale better than SQLite, especially if your -game has an very large database and/or extensive web presence through a separate server process.

-
-

Install and initial setup of PostgreSQL

-

First, install the posgresql server. Version 9.6 is tested with Evennia. Packages are readily -available for all distributions. You need to also get the psql client (this is called postgresql- client on debian-derived systems). Windows/Mac users can find what they need on the postgresql -download page. You should be setting up a password for your -database-superuser (always called postgres) when you install.

-

For interaction with Evennia you need to also install psycopg2 to your Evennia install (pip install psycopg2-binary in your virtualenv). This acts as the python bridge to the database server.

-

Next, start the postgres client:

-
    psql -U postgres --password
-
-
-
-

:warning: Warning: With the --password argument, Postgres should prompt you for a password. -If it won’t, replace that with -p yourpassword instead. Do not use the -p argument unless you -have to since the resulting command, and your password, will be logged in the shell history.

-
-

This will open a console to the postgres service using the psql client.

-

On the psql command line:

-
CREATE USER evennia WITH PASSWORD 'somepassword';
-CREATE DATABASE evennia;
-
--- Postgres-specific optimizations
--- https://docs.djangoproject.com/en/dev/ref/databases/#optimizing-postgresql-s-configuration
-ALTER ROLE evennia SET client_encoding TO 'utf8';
-ALTER ROLE evennia SET default_transaction_isolation TO 'read committed';
-ALTER ROLE evennia SET timezone TO 'UTC';
-
-GRANT ALL PRIVILEGES ON DATABASE evennia TO evennia;
--- Other useful commands:
---  \l       (list all databases and permissions)
---  \q       (exit)
-
-
-

Here is a cheat-sheet for psql commands.

-

We create a database user ‘evennia’ and a new database named evennia (you can call them whatever -you want though). We then grant the ‘evennia’ user full privileges to the new database so it can -read/write etc to it. -If you in the future wanted to completely wipe the database, an easy way to do is to log in as the -postgres superuser again, then do DROP DATABASE evennia;, then CREATE and GRANT steps above -again to recreate the database and grant privileges.

-
-
-

Evennia PostgreSQL configuration

-

Edit `mygame/server/conf/secret_settings.py and add the following section:

-
#
-# PostgreSQL Database Configuration
-#
-DATABASES = {
-        'default': {
-            'ENGINE': 'django.db.backends.postgresql_psycopg2',
-            'NAME': 'evennia',
-            'USER': 'evennia',
-            'PASSWORD': 'somepassword',
-            'HOST': 'localhost',
-            'PORT': ''    # use default
-        }}
-
-
-

If you used some other name for the database and user, enter those instead. Run

-
evennia migrate
-
-
-

to populate your database. Should you ever want to inspect the database directly you can from now on -also use

-
evennia dbshell
-
-
-

as a shortcut to get into the postgres command line for the right database and user.

-

With the database setup you should now be able to start start Evennia normally with your new -database.

-
-
-
-

MySQL / MariaDB

-

MySQL is a commonly used proprietary database system, on par with -PostgreSQL. There is an open-source alternative called MariaDB that mimics -all functionality and command syntax of the former. So this section covers both.

-
-

Installing and initial setup of MySQL/MariaDB

-

First, install and setup MariaDB or MySQL for your specific server. Linux users should look for the -mysql-server or mariadb-server packages for their respective distributions. Windows/Mac users -will find what they need from the MySQL downloads or MariaDB -downloads pages. You also need the respective database clients -(mysql, mariadb-client), so you can setup the database itself. When you install the server you -should usually be asked to set up the database root user and password.

-

You will finally also need a Python interface to allow Evennia to talk to the database. Django -recommends the mysqlclient one. Install this into the evennia virtualenv with pip install mysqlclient.

-

Start the database client (this is named the same for both mysql and mariadb):

-
mysql -u root -p
-
-
-

You should get to enter your database root password (set this up when you installed the database -server).

-

Inside the database client interface:

-
CREATE USER 'evennia'@'localhost' IDENTIFIED BY 'somepassword';
-CREATE DATABASE evennia;
-ALTER DATABASE `evennia` CHARACTER SET utf8; -- note that it's `evennia` with back-ticks, not
-quotes!
-GRANT ALL PRIVILEGES ON evennia.* TO 'evennia'@'localhost';
-FLUSH PRIVILEGES;
--- use 'exit' to quit client
-
-
-

Here is a mysql command cheat sheet.

-

Above we created a new local user and database (we called both ‘evennia’ here, you can name them -what you prefer). We set the character set to utf8 to avoid an issue with prefix character length -that can pop up on some installs otherwise. Next we grant the ‘evennia’ user all privileges on the -evennia database and make sure the privileges are applied. Exiting the client brings us back to -the normal terminal/console.

-
-

Note: If you are not using MySQL for anything else you might consider granting the ‘evennia’ user -full privileges with GRANT ALL PRIVILEGES ON *.* TO 'evennia'@'localhost';. If you do, it means -you can use evennia dbshell later to connect to mysql, drop your database and re-create it as a -way of easy reset. Without this extra privilege you will be able to drop the database but not re- -create it without first switching to the database-root user.

-
-
-
-
-

Add MySQL configuration to Evennia

-

To tell Evennia to use your new database you need to edit mygame/server/conf/settings.py (or -secret_settings.py if you don’t want your db info passed around on git repositories).

-
-

Note: The Django documentation suggests using an external db.cnf or other external conf- -formatted file. Evennia users have however found that this leads to problems (see e.g. issue -#1184). To avoid trouble we recommend you simply put the configuration in -your settings as below.

-
-
    #
-    # MySQL Database Configuration
-    #
-    DATABASES = {
-       'default': {
-           'ENGINE': 'django.db.backends.mysql',
-           'NAME': 'evennia',
-           'USER': 'evennia',
-           'PASSWORD': 'somepassword',
-           'HOST': 'localhost',  # or an IP Address that your DB is hosted on
-           'PORT': '', # use default port
-       }
-    }
-
-
-

Change this to fit your database setup. Next, run:

-
evennia migrate
-
-
-

to populate your database. Should you ever want to inspect the database directly you can from now on -also use

-
evennia dbshell
-
-
-

as a shortcut to get into the postgres command line for the right database and user.

-

With the database setup you should now be able to start start Evennia normally with your new -database.

-
-
-

Others

-

No testing has been performed with Oracle, but it is also supported through Django. There are -community maintained drivers for MS SQL and possibly a few -others. If you try other databases out, consider expanding this page with instructions.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Client-Support-Grid.html b/docs/0.9.5/Client-Support-Grid.html deleted file mode 100644 index 37c2c79a85..0000000000 --- a/docs/0.9.5/Client-Support-Grid.html +++ /dev/null @@ -1,278 +0,0 @@ - - - - - - - - - Client Support Grid — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Client Support Grid

-

This grid tries to gather info about different MU clients when used with Evennia. -If you want to report a problem, update an entry or add a client, make a -new documentation issue for it. Everyone’s encouraged to report their findings.

-
-

Client Grid

-

Legend:

-
    -
  • Name: The name of the client. Also note if it’s OS-specific.

  • -
  • Version: Which version or range of client versions were tested.

  • -
  • Comments: Any quirks on using this client with Evennia should be added here.

  • -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Name

Version tested

Comments

Evennia Webclient

1.0+

Evennia-specific

tintin++

2.0+

No MXP support

tinyfugue

5.0+

No UTF-8 support

MUSHclient (Win)

4.94

NAWS reports full text area

Zmud (Win)

7.21

UNTESTED

Cmud (Win)

v3

UNTESTED

Potato_

2.0.0b16

No MXP, MCCP support. Win 32bit does not understand

“localhost”, must use 127.0.0.1.

Mudlet

3.4+

No known issues. Some older versions showed <> as html

under MXP.

SimpleMU (Win)

full

Discontinued. NAWS reports pixel size.

Atlantis (Mac)

0.9.9.4

No known issues.

GMUD

0.0.1

Can’t handle any telnet handshakes. Not recommended.

BeipMU (Win)

3.0.255

No MXP support. Best to enable “MUD prompt handling”, disable

“Handle HTML tags”.

MudRammer (IOS)

1.8.7

Bad Telnet Protocol compliance: displays spurious characters.

MUDMaster

1.3.1

UNTESTED

BlowTorch (Andr)

1.1.3

Telnet NOP displays as spurious character.

Mukluk (Andr)

2015.11.20

Telnet NOP displays as spurious character. Has UTF-8/Emoji

support.

Gnome-MUD (Unix)

0.11.2

Telnet handshake errors. First (only) attempt at logging in

fails.

Spyrit

0.4

No MXP, OOB support.

JamochaMUD

5.2

Does not support ANSI within MXP text.

DuckClient (Chrome)

4.2

No MXP support. Displays Telnet Go-Ahead and

WILL SUPPRESS-GO-AHEAD as ù character. Also seems to run

the version command on connection, which will not work in

MULTISESSION_MODES above 1.

KildClient

2.11.1

No known issues.

-
-
-

Workarounds for client issues:

-
-

Issue: Telnet NOP displays as spurious character.

-

Known clients:

-
    -
  • BlowTorch (Andr)

  • -
  • Mukluk (Andr)

  • -
-

Workaround:

-
    -
  • In-game: Use @option NOPKEEPALIVE=off for the session, or use the /save -parameter to disable it for that Evennia account permanently.

  • -
  • Client-side: Set a gag-type trigger on the NOP character to make it invisible to the client.

  • -
-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Coding-FAQ.html b/docs/0.9.5/Coding-FAQ.html deleted file mode 100644 index b69879905a..0000000000 --- a/docs/0.9.5/Coding-FAQ.html +++ /dev/null @@ -1,493 +0,0 @@ - - - - - - - - - Coding FAQ — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Coding FAQ

-

This FAQ page is for users to share their solutions to coding problems. Keep it brief and link to -the docs if you can rather than too lengthy explanations. Don’t forget to check if an answer already -exists before answering - maybe you can clarify that answer rather than to make a new Q&A section.

-
-

Table of Contents

- -
-
-

Will I run out of dbrefs?

-

Q: The #dbref of a database object is ever-increasing. Evennia doesn’t allow you to change or -reuse them. Will not a big/old game run out of dbref integers eventually?

-

A: No. For example, the default sqlite3 database’s max dbref is 2**64. If you created 10 000 -objects every second every minute and every day of the year it would take ~60 million years for you -to run out of dbref numbers. That’s a database of 140 TeraBytes, if every row was empty. If you are -still using Evennia at that point and has this concern, get back to us and we can discuss adding -dbref reuse then.

-
-
-

Removing default commands

-

Q: How does one remove (not replace) e.g. the default get Command from the -Character Command Set?

-

A: Go to mygame/commands/default_cmdsets.py. Find the CharacterCmdSet class. It has one -method named at_cmdset_creation. At the end of that method, add the following line: -self.remove(default_cmds.CmdGet()). See the Adding Commands Tutorial -for more info.

-
-
-

Preventing character from moving based on a condition

-

Q: How does one keep a character from using any exit, if they meet a certain condition? (I.E. in -combat, immobilized, etc.)

-

A: The at_before_move hook is called by Evennia just before performing any move. If it returns -False, the move is aborted. Let’s say we want to check for an Attribute cantmove. -Add the following code to the Character class:

-
def at_before_move(self, destination):
-    "Called just before trying to move"
-    if self.db.cantmove: # replace with condition you want to test
-        self.msg("Something is preventing you from moving!")
-        return False
-    return True
-
-
-
-
-

Reference initiating object in an EvMenu command.

-

Q: An object has a Command on it starts up an EvMenu instance. How do I capture a reference to -that object for use in the menu?

-

A: When an EvMenu is started, the menu object is stored as caller.ndb._menutree. -This is a good place to store menu-specific things since it will clean itself up when the menu -closes. When initiating the menu, any additional keywords you give will be available for you as -properties on this menu object:

-
class MyObjectCommand(Command):
-    # A Command stored on an object (the object is always accessible from
-    # the Command as self.obj)
-    def func(self):
-        # add the object as the stored_obj menu property
-        EvMenu(caller, ..., stored_obj=self.obj)
-
-
-
-

Inside the menu you can now access the object through caller.ndb._menutree.stored_obj.

-
-
-

Adding color to default Evennia Channels

-

Q: How do I add colors to the names of Evennia channels?

-

A: The Channel typeclass’ channel_prefix method decides what is shown at the beginning of a -channel send. Edit mygame/typeclasses/channels.py (and then @reload):

-
# define our custom color names
-CHANNEL_COLORS = {'public': '|015Public|n',
-                  'newbie': '|550N|n|551e|n|552w|n|553b|n|554i|n|555e|n',
-                  'staff': '|010S|n|020t|n|030a|n|040f|n|050f|n'}
-
-# Add to the Channel class
-    # ...
-    def channel_prefix(self, msg, emit=False):
-        prefix_string = ""
-        if self.key in COLORS:
-            prefix_string = "[%s] " % CHANNEL_COLORS.get(self.key.lower())
-        else:
-            prefix_string = "[%s] " % self.key.capitalize()
-        return prefix_string
-
-
-

Additional hint: To make colors easier to change from one place you could instead put the -CHANNEL_COLORS dict in your settings file and import it as from django.conf.settings import CHANNEL_COLORS.

-
-
-

Selectively turn off commands in a room

-

Q: I want certain commands to turn off in a given room. They should still work normally for -staff.

-

A: This is done using a custom cmdset on a room locked with the ‘call’ lock type. Only -if this lock is passed will the commands on the room be made available to an object inside it. Here -is an example of a room where certain commands are disabled for non-staff:

-
# in mygame/typeclasses/rooms.py
-
-from evennia import default_commands, CmdSet
-
-class CmdBlocking(default_commands.MuxCommand):
-    # block commands give, get, inventory and drop
-    key = "give"
-    aliases = ["get", "inventory", "drop"]
-    def func(self):
-        self.caller.msg("You cannot do that in this room.")
-
-class BlockingCmdSet(CmdSet):
-    key = "blocking_cmdset"
-    # default commands have prio 0
-    priority = 1
-    def at_cmdset_creation(self):
-        self.add(CmdBlocking())
-
-class BlockingRoom(Room):
-    def at_object_creation(self):
-        self.cmdset.add(BlockingCmdSet, permanent=True)
-        # only share commands with players in the room that
-        # are NOT Builders or higher
-        self.locks.add("call:not perm(Builders)")
-
-
-

After @reload, make some BlockingRooms (or switch a room to it with @typeclass). Entering one -will now replace the given commands for anyone that does not have the Builders or higher -permission. Note that the ‘call’ lock is special in that even the superuser will be affected by it -(otherwise superusers would always see other player’s cmdsets and a game would be unplayable for -superusers).

-
-
-

Select Command based on a condition

-

Q: I want a command to be available only based on a condition. For example I want the “werewolf” -command to only be available on a full moon, from midnight to three in-game time.

-

A: This is easiest accomplished by putting the “werewolf” command on the Character as normal, -but to lock it with the “cmd” type lock. Only if the “cmd” lock type is passed will the -command be available.

-
# in mygame/commands/command.py
-
-from evennia import Command
-
-class CmdWerewolf(Command):
-    key = "werewolf"
-    # lock full moon, between 00:00 (midnight) and 03:00.
-    locks = "cmd:is_full_moon(0, 3)"
-    def func(self):
-        # ...
-
-
-

Add this to the default cmdset as usual. The is_full_moon lock -function does not yet exist. We must create that:

-
# in mygame/server/conf/lockfuncs.py
-
-def is_full_moon(accessing_obj, accessed_obj,
-                 starthour, endhour, *args, **kwargs):
-    # calculate if the moon is full here and
-    # if current game time is between starthour and endhour
-    # return True or False
-
-
-
-

After a @reload, the werewolf command will be available only at the right time, that is when the -is_full_moon lock function returns True.

-
-
-

Automatically updating code when reloading

-

Q: I have a development server running Evennia. Can I have the server update its code-base when -I reload?

-

A: Having a development server that pulls updated code whenever you reload it can be really -useful if you have limited shell access to your server, or want to have it done automatically. If -you have your project in a configured Git environment, it’s a matter of automatically calling git pull when you reload. And that’s pretty straightforward:

-

In /server/conf/at_server_startstop.py:

-
import subprocess
-
-# ... other hooks ...
-
-def at_server_reload_stop():
-    """
-    This is called only time the server stops before a reload.
-    """
-    print("Pulling from the game repository...")
-    process = subprocess.call(["git", "pull"], shell=False)
-
-
-

That’s all. We call subprocess to execute a shell command (that code works on Windows and Linux, -assuming the current directory is your game directory, which is probably the case when you run -Evennia). call waits for the process to complete, because otherwise, Evennia would reload on -partially-modified code, which would be problematic.

-

Now, when you enter @reload on your development server, the game repository is updated from the -configured remote repository (Github, for instance). Your development cycle could resemble -something like:

-
    -
  1. Coding on the local machine.

  2. -
  3. Testing modifications.

  4. -
  5. Committing once, twice or more (being sure the code is still working, unittests are pretty useful -here).

  6. -
  7. When the time comes, login to the development server and run @reload.

  8. -
-

The reloading might take one or two additional seconds, since Evennia will pull from your remote Git -repository. But it will reload on it and you will have your modifications ready, without needing -connecting to your server using SSH or something similar.

-
-
-

Changing all exit messages

-

Q: How can I change the default exit messages to something like “XXX leaves east” or “XXX -arrives from the west”?

-

A: the default exit messages are stored in two hooks, namely announce_move_from and -announce_move_to, on the Character typeclass (if what you want to change is the message other -characters will see when a character exits).

-

These two hooks provide some useful features to easily update the message to be displayed. They -take both the default message and mapping as argument. You can easily call the parent hook with -these information:

-
    -
  • The message represents the string of characters sent to characters in the room when a character -leaves.

  • -
  • The mapping is a dictionary containing additional mappings (you will probably not need it for -simple customization).

  • -
-

It is advisable to look in the code of both -hooks, and read the -hooks’ documentation. The explanations on how to quickly update the message are shown below:

-
# In typeclasses/characters.py
-"""
-Characters
-
-"""
-from evennia import DefaultCharacter
-
-class Character(DefaultCharacter):
-    """
-    The default character class.
-
-    ...
-    """
-
-    def announce_move_from(self, destination, msg=None, mapping=None):
-        """
-        Called if the move is to be announced. This is
-        called while we are still standing in the old
-        location.
-
-        Args:
-            destination (Object): The place we are going to.
-            msg (str, optional): a replacement message.
-            mapping (dict, optional): additional mapping objects.
-
-        You can override this method and call its parent with a
-        message to simply change the default message.  In the string,
-        you can use the following as mappings (between braces):
-            object: the object which is moving.
-            exit: the exit from which the object is moving (if found).
-            origin: the location of the object before the move.
-            destination: the location of the object after moving.
-
-        """
-        super().announce_move_from(destination, msg="{object} leaves {exit}.")
-
-    def announce_move_to(self, source_location, msg=None, mapping=None):
-        """
-        Called after the move if the move was not quiet. At this point
-        we are standing in the new location.
-
-        Args:
-            source_location (Object): The place we came from
-            msg (str, optional): the replacement message if location.
-            mapping (dict, optional): additional mapping objects.
-
-        You can override this method and call its parent with a
-        message to simply change the default message.  In the string,
-        you can use the following as mappings (between braces):
-            object: the object which is moving.
-            exit: the exit from which the object is moving (if found).
-            origin: the location of the object before the move.
-            destination: the location of the object after moving.
-
-        """
-        super().announce_move_to(source_location, msg="{object} arrives from the {exit}.")
-
-
-

We override both hooks, but call the parent hook to display a different message. If you read the -provided docstrings, you will better understand why and how we use mappings (information between -braces). You can provide additional mappings as well, if you want to set a verb to move, for -instance, or other, extra information.

-
-
-

Add parsing with the “to” delimiter

-

Q: How do I change commands to undestand say give obj to target as well as the default give obj = target?

-

A: You can make change the default MuxCommand parent with your own class making a small change -in its parse method:

-
    # in mygame/commands/command.py
-    from evennia import default_cmds
-    class MuxCommand(default_cmds.MuxCommand):
-        def parse(self):
-            """Implement an additional parsing of 'to'"""
-            super().parse()
-            if " to " in self.args:
-                self.lhs, self.rhs = self.args.split(" to ", 1)
-
-
-

Next you change the parent of the default commands in settings:

-
    COMMAND_DEFAULT_CLASS = "commands.command.MuxCommand"
-
-
-

Do a @reload and all default commands will now use your new tweaked parent class. A copy of the -MuxCommand class is also found commented-out in the mygame/commands/command.py file.

-
-
-

Store last used session IP address

-

Q: If a user has already logged out of an Evennia account, their IP is no longer visible to -staff that wants to ban-by-ip (instead of the user) with @ban/ip?

-

A: One approach is to write the IP from the last session onto the “account” account object.

-

typeclasses/accounts.py

-
    def at_post_login(self, session=None, **kwargs):
-        super().at_post_login(session=session, **kwargs)
-        self.db.lastsite = self.sessions.all()[-1].address
-
-
-

Adding timestamp for login time and appending to a list to keep the last N login IP addresses and -timestamps is possible, also. Additionally, if you don’t want the list to grow beyond a -do_not_exceed length, conditionally pop a value after you’ve added it, if the length has grown too -long.

-

NOTE: You’ll need to add import time to generate the login timestamp.

-
    def at_post_login(self, session=None, **kwargs):
-        super().at_post_login(session=session, **kwargs)
-        do_not_exceed = 24  # Keep the last two dozen entries
-        session = self.sessions.all()[-1]  # Most recent session
-        if not self.db.lastsite:
-           self.db.lastsite = []
-        self.db.lastsite.insert(0, (session.address, int(time.time())))
-        if len(self.db.lastsite) > do_not_exceed:
-            self.db.lastsite.pop()
-
-
-

This only stores the data. You may want to interface the @ban command or make a menu-driven viewer -for staff to browse the list and display how long ago the login occurred.

-
-
-

Non-latin characters in EvTable

-

Q: When using e.g. Chinese characters in EvTable, some lines appear to be too wide, for example

-
+------+------+
-|      |      |
-|  测试  |  测试  |
-|      |      |
-+~~~~~~+~~~~~~+
-
-
-

A: The reason for this is because certain non-latin characters are visually much wider than -their len() suggests. There is little Evennia can (reliably) do about this. If you are using such -characters, you need to make sure to use a suitable mono-spaced font where are width are equal. You -can set this in your web client and need to recommend it for telnet-client users. See this -discussion where some suitable fonts are suggested.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Coding-Introduction.html b/docs/0.9.5/Coding-Introduction.html deleted file mode 100644 index 7b368c3a56..0000000000 --- a/docs/0.9.5/Coding-Introduction.html +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - - - - Coding Introduction — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Coding Introduction

-

Evennia allows for a lot of freedom when designing your game - but to code efficiently you still -need to adopt some best practices as well as find a good place to start to learn.

-

Here are some pointers to get you going.

-
-

Python

-

Evennia is developed using Python. Even if you are more of a designer than a coder, it is wise to -learn how to read and understand basic Python code. If you are new to Python, or need a refresher, -take a look at our two-part Python introduction.

-
-
-

Explore Evennia interactively

-

When new to Evennia it can be hard to find things or figure out what is available. Evennia offers a -special interactive python shell that allows you to experiment and try out things. It’s recommended -to use ipython for this since the vanilla python prompt is very limited. Here -are some simple commands to get started:

-
# [open a new console/terminal]
-# [activate your evennia virtualenv in this console/terminal]
-pip install ipython    # [only needed the first time]
-cd mygame
-evennia shell
-
-
-

This will open an Evennia-aware python shell (using ipython). From within this shell, try

-
import evennia
-evennia.<TAB>
-
-
-

That is, enter evennia. and press the <TAB> key. This will show you all the resources made -available at the top level of Evennia’s “flat API”. See the flat API page for more -info on how to explore it efficiently.

-

You can complement your exploration by peeking at the sections of the much more detailed -Developer Central. The Tutorials section also contains a growing collection -of system- or implementation-specific help.

-
-
-

Use a python syntax checker

-

Evennia works by importing your own modules and running them as part of the server. Whereas Evennia -should just gracefully tell you what errors it finds, it can nevertheless be a good idea for you to -check your code for simple syntax errors before you load it into the running server. There are -many python syntax checkers out there. A fast and easy one is -pyflakes, a more verbose one is -pylint. You can also check so that your code looks up to snuff using -pep8. Even with a syntax checker you will not be able to catch -every possible problem - some bugs or problems will only appear when you actually run the code. But -using such a checker can be a good start to weed out the simple problems.

-
-
-

Plan before you code

-

Before you start coding away at your dream game, take a look at our Game Planning -page. It might hopefully help you avoid some common pitfalls and time sinks.

-
-
-

Code in your game folder, not in the evennia/ repository

-

As part of the Evennia setup you will create a game folder to host your game code. This is your -home. You should never need to modify anything in the evennia library (anything you download -from us, really). You import useful functionality from here and if you see code you like, copy&paste -it out into your game folder and edit it there.

-

If you find that Evennia doesn’t support some functionality you need, make a -Feature Request about it. Same goes for bugs. If you add features or fix bugs -yourself, please consider Contributing your changes upstream!

-
-
-

Learn to read tracebacks

-

Python is very good at reporting when and where things go wrong. A traceback shows everything you -need to know about crashing code. The text can be pretty long, but you usually are only interested -in the last bit, where it says what the error is and at which module and line number it happened - -armed with this info you can resolve most problems.

-

Evennia will usually not show the full traceback in-game though. Instead the server outputs errors -to the terminal/console from which you started Evennia in the first place. If you want more to show -in-game you can add IN_GAME_ERRORS = True to your settings file. This will echo most (but not all) -tracebacks both in-game as well as to the terminal/console. This is a potential security problem -though, so don’t keep this active when your game goes into production.

-
-

A common confusing error is finding that objects in-game are suddenly of the type DefaultObject -rather than your custom typeclass. This happens when you introduce a critical Syntax error to the -module holding your custom class. Since such a module is not valid Python, Evennia can’t load it at -all. Instead of crashing, Evennia will then print the full traceback to the terminal/console and -temporarily fall back to the safe DefaultObject until you fix the problem and reload.

-
-
-
-

Docs are here to help you

-

Some people find reading documentation extremely dull and shun it out of principle. That’s your -call, but reading docs really does help you, promise! Evennia’s documentation is pretty thorough -and knowing what is possible can often give you a lot of new cool game ideas. That said, if you -can’t find the answer in the docs, don’t be shy to ask questions! The -discussion group and the -irc chat are also there for you.

-
-
-

The most important point

-

And finally, of course, have fun!

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Coding-Utils.html b/docs/0.9.5/Coding-Utils.html deleted file mode 100644 index 7ac03cf3be..0000000000 --- a/docs/0.9.5/Coding-Utils.html +++ /dev/null @@ -1,425 +0,0 @@ - - - - - - - - - Coding Utils — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Coding Utils

-

Evennia comes with many utilities to help with common coding tasks. Most are accessible directly -from the flat API, otherwise you can find them in the evennia/utils/ folder.

-
-

Searching

-

A common thing to do is to search for objects. There it’s easiest to use the search method defined -on all objects. This will search for objects in the same location and inside the self object:

-
     obj = self.search(objname)
-
-
-

The most common time one needs to do this is inside a command body. obj = self.caller.search(objname) will search inside the caller’s (typically, the character that typed -the command) .contents (their “inventory”) and .location (their “room”).

-

Give the keyword global_search=True to extend search to encompass entire database. Aliases will -also be matched by this search. You will find multiple examples of this functionality in the default -command set.

-

If you need to search for objects in a code module you can use the functions in -evennia.utils.search. You can access these as shortcuts evennia.search_*.

-
     from evennia import search_object
-     obj = search_object(objname)
-
-
- -

Note that these latter methods will always return a list of results, even if the list has one or -zero entries.

-
-
-

Create

-

Apart from the in-game build commands (@create etc), you can also build all of Evennia’s game -entities directly in code (for example when defining new create commands).

-
   import evennia
-
-   myobj = evennia.create_objects("game.gamesrc.objects.myobj.MyObj", key="MyObj")
-
-
- -

Each of these create-functions have a host of arguments to further customize the created entity. See -evennia/utils/create.py for more information.

-
-
-

Logging

-

Normally you can use Python print statements to see output to the terminal/log. The print -statement should only be used for debugging though. For producion output, use the logger which -will create proper logs either to terminal or to file.

-
     from evennia import logger
-     #
-     logger.log_err("This is an Error!")
-     logger.log_warn("This is a Warning!")
-     logger.log_info("This is normal information")
-     logger.log_dep("This feature is deprecated")
-
-
-

There is a special log-message type, log_trace() that is intended to be called from inside a -traceback - this can be very useful for relaying the traceback message back to log without having it -kill the server.

-
     try:
-       # [some code that may fail...]
-     except Exception:
-       logger.log_trace("This text will show beneath the traceback itself.")
-
-
-

The log_file logger, finally, is a very useful logger for outputting arbitrary log messages. This -is a heavily optimized asynchronous log mechanism using -threads to avoid overhead. You should be -able to use it for very heavy custom logging without fearing disk-write delays.

-
 logger.log_file(message, filename="mylog.log")
-
-
-

If not an absolute path is given, the log file will appear in the mygame/server/logs/ directory. -If the file already exists, it will be appended to. Timestamps on the same format as the normal -Evennia logs will be automatically added to each entry. If a filename is not specified, output will -be written to a file game/logs/game.log.

-
-
-

Time Utilities

-
-

Game time

-

Evennia tracks the current server time. You can access this time via the evennia.gametime -shortcut:

-
from evennia import gametime
-
-# all the functions below return times in seconds).
-
-# total running time of the server
-runtime = gametime.runtime()
-# time since latest hard reboot (not including reloads)
-uptime = gametime.uptime()
-# server epoch (its start time)
-server_epoch = gametime.server_epoch()
-
-# in-game epoch (this can be set by `settings.TIME_GAME_EPOCH`.
-# If not, the server epoch is used.
-game_epoch = gametime.game_epoch()
-# in-game time passed since time started running
-gametime = gametime.gametime()
-# in-game time plus game epoch (i.e. the current in-game
-# time stamp)
-gametime = gametime.gametime(absolute=True)
-# reset the game time (back to game epoch)
-gametime.reset_gametime()
-
-
-
-

The setting TIME_FACTOR determines how fast/slow in-game time runs compared to the real world. The -setting TIME_GAME_EPOCH sets the starting game epoch (in seconds). The functions from the -gametime module all return their times in seconds. You can convert this to whatever units of time -you desire for your game. You can use the @time command to view the server time info.

-

You can also schedule things to happen at specific in-game times using the -gametime.schedule function:

-
import evennia
-
-def church_clock:
-    limbo = evennia.search_object(key="Limbo")
-    limbo.msg_contents("The church clock chimes two.")
-
-gametime.schedule(church_clock, hour=2)
-
-
-
-
-

utils.time_format()

-

This function takes a number of seconds as input (e.g. from the gametime module above) and -converts it to a nice text output in days, hours etc. It’s useful when you want to show how old -something is. It converts to four different styles of output using the style keyword:

-
    -
  • style 0 - 5d:45m:12s (standard colon output)

  • -
  • style 1 - 5d (shows only the longest time unit)

  • -
  • style 2 - 5 days, 45 minutes (full format, ignores seconds)

  • -
  • style 3 - 5 days, 45 minutes, 12 seconds (full format, with seconds)

  • -
-
-
-

utils.delay()

-
from evennia import utils
-
-def _callback(obj, text):
-    obj.msg(text)
-
-# wait 10 seconds before sending "Echo!" to obj (which we assume is defined)
-deferred = utils.delay(10, _callback, obj, "Echo!", persistent=False)
-
-# code here will run immediately, not waiting for the delay to fire!
-
-
-
-

This creates an asynchronous delayed call. It will fire the given callback function after the given -number of seconds. This is a very light wrapper over a Twisted -Deferred. Normally this is run -non-persistently, which means that if the server is @reloaded before the delay is over, the -callback will never run (the server forgets it). If setting persistent to True, the delay will be -stored in the database and survive a @reload - but for this to work it is susceptible to the same -limitations incurred when saving to an Attribute.

-

The deferred return object can usually be ignored, but calling its .cancel() method will abort -the delay prematurely.

-

utils.delay is the lightest form of delayed call in Evennia. For other way to create time-bound -tasks, see the TickerHandler and Scripts.

-
-

Note that many delayed effects can be achieved without any need for an active timer. For example -if you have a trait that should recover a point every 5 seconds you might just need its value when -it’s needed, but checking the current time and calculating on the fly what value it should have.

-
-
-
-
-

Object Classes

-
-

utils.inherits_from()

-

This useful function takes two arguments - an object to check and a parent. It returns True if -object inherits from parent at any distance (as opposed to Python’s in-built is_instance() that -will only catch immediate dependence). This function also accepts as input any combination of -classes, instances or python-paths-to-classes.

-

Note that Python code should usually work with duck -typing. But in Evennia’s case it can sometimes be useful -to check if an object inherits from a given Typeclass as a way of identification. Say -for example that we have a typeclass Animal. This has a subclass Felines which in turn has a -subclass HouseCat. Maybe there are a bunch of other animal types too, like horses and dogs. Using -inherits_from will allow you to check for all animals in one go:

-
     from evennia import utils
-     if (utils.inherits_from(obj, "typeclasses.objects.animals.Animal"):
-        obj.msg("The bouncer stops you in the door. He says: 'No talking animals allowed.'")
-
-
-
-
-
-

Text utilities

-

In a text game, you are naturally doing a lot of work shuffling text back and forth. Here is a non- -complete selection of text utilities found in evennia/utils/utils.py (shortcut evennia.utils). -If nothing else it can be good to look here before starting to develop a solution of your own.

-
-

utils.fill()

-

This flood-fills a text to a given width (shuffles the words to make each line evenly wide). It also -indents as needed.

-
     outtxt = fill(intxt, width=78, indent=4)
-
-
-
-
-

utils.crop()

-

This function will crop a very long line, adding a suffix to show the line actually continues. This -can be useful in listings when showing multiple lines would mess up things.

-
     intxt = "This is a long text that we want to crop."
-     outtxt = crop(intxt, width=19, suffix="[...]")
-     # outtxt is now "This is a long text[...]"
-
-
-
-
-

utils.dedent()

-

This solves what may at first glance appear to be a trivial problem with text - removing -indentations. It is used to shift entire paragraphs to the left, without disturbing any further -formatting they may have. A common case for this is when using Python triple-quoted strings in code

-
    -
  • they will retain whichever indentation they have in the code, and to make easily-readable source -code one usually don’t want to shift the string to the left edge.

  • -
-
    #python code is entered at a given indentation
-          intxt = """
-          This is an example text that will end
-          up with a lot of whitespace on the left.
-                    It also has indentations of
-                    its own."""
-          outtxt = dedent(intxt)
-          # outtxt will now retain all internal indentation
-          # but be shifted all the way to the left.
-
-
-

Normally you do the dedent in the display code (this is for example how the help system homogenizes -help entries).

-
-
-

to_str() and to_bytes()

-

Evennia supplies two utility functions for converting text to the correct -encodings. to_str() and to_bytes(). Unless you are adding a custom protocol and -need to send byte-data over the wire, to_str is the only one you’ll need.

-

The difference from Python’s in-built str() and bytes() operators are that -the Evennia ones makes use of the ENCODINGS setting and will try very hard to -never raise a traceback but instead echo errors through logging. See -here for more info.

-
-
-

Ansi Coloring Tools

- -
-
-
-

Display utilities

-
-

Making ascii tables

-

The EvTable class (evennia/utils/evtable.py) can be used -to create correctly formatted text tables. There is also -EvForm (evennia/utils/evform.py). This reads a fixed-format -text template from a file in order to create any level of sophisticated ascii layout. Both evtable -and evform have lots of options and inputs so see the header of each module for help.

-

The third-party PrettyTable module is also included in -Evennia. PrettyTable is considered deprecated in favor of EvTable since PrettyTable cannot handle -ANSI colour. PrettyTable can be found in evennia/utils/prettytable/. See its homepage above for -instructions.

-
- -
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Command-Cooldown.html b/docs/0.9.5/Command-Cooldown.html deleted file mode 100644 index 4524eaf30b..0000000000 --- a/docs/0.9.5/Command-Cooldown.html +++ /dev/null @@ -1,210 +0,0 @@ - - - - - - - - - Command Cooldown — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Command Cooldown

-

Some types of games want to limit how often a command can be run. If a -character casts the spell Firestorm, you might not want them to spam that -command over and over. Or in an advanced combat system, a massive swing may -offer a chance of lots of damage at the cost of not being able to re-do it for -a while. Such effects are called cooldowns.

-

This page exemplifies a very resource-efficient way to do cooldowns. A more -‘active’ way is to use asynchronous delays as in the command duration -tutorial, the two might be useful to -combine if you want to echo some message to the user after the cooldown ends.

-
-

Non-persistent cooldown

-

This little recipe will limit how often a particular command can be run. Since -Commands are class instances, and those are cached in memory, a command -instance will remember things you store on it. So just store the current time -of execution! Next time the command is run, it just needs to check if it has -that time stored, and compare it with the current time to see if a desired -delay has passed.

-
import time
-from evennia import default_cmds
-    
-class CmdSpellFirestorm(default_cmds.MuxCommand):
-    """
-    Spell - Firestorm
-
-    Usage:
-      cast firestorm <target>
-    
-    This will unleash a storm of flame. You can only release one
-    firestorm every five minutes (assuming you have the mana).
-    """
-    key = "cast firestorm"
-    locks = "cmd:isFireMage()"
-        
-    def func(self):
-        "Implement the spell"
-    
-        # check cooldown (5 minute cooldown)
-        now = time.time()
-        if hasattr(self, "lastcast") and \
-                now - self.lastcast < 5 * 60:
-            message = "You cannot cast this spell again yet."
-            self.caller.msg(message)
-            return
-    
-        #[the spell effect is implemented]
-    
-        # if the spell was successfully cast, store the casting time
-        self.lastcast = now
-
-
-

We just check the lastcast flag, and update it if everything works out. -Simple and very effective since everything is just stored in memory. The -drawback of this simple scheme is that it’s non-persistent. If you do -@reload, the cache is cleaned and all such ongoing cooldowns will be -forgotten. It is also limited only to this one command, other commands cannot -(easily) check for this value.

-
-
-

Persistent cooldown

-

This is essentially the same mechanism as the simple one above, except we use -the database to store the information which means the cooldown will survive a -server reload/reboot. Since commands themselves have no representation in the -database, you need to use the caster for the storage.

-
    # inside the func() of CmdSpellFirestorm as above
-
-    # check cooldown (5 minute cooldown)
-            
-    now = time.time()
-    lastcast = self.caller.db.firestorm_lastcast
-            
-    if lastcast and now - lastcast < 5 * 60:
-        message = "You need to wait before casting this spell again."
-        self.caller.msg(message)
-        return
-      
-    #[the spell effect is implemented]
-    
-    # if the spell was successfully cast, store the casting time
-    self.caller.db.firestorm_lastcast = now
-
-
-

Since we are storing as an Attribute, we need to identify the -variable as firestorm_lastcast so we are sure we get the right one (we’ll -likely have other skills with cooldowns after all). But this method of -using cooldowns also has the advantage of working between commands - you can -for example let all fire-related spells check the same cooldown to make sure -the casting of Firestorm blocks all fire-related spells for a while. Or, in -the case of taking that big swing with the sword, this could now block all -other types of attacks for a while before the warrior can recover.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Command-Duration.html b/docs/0.9.5/Command-Duration.html deleted file mode 100644 index ec12a288d0..0000000000 --- a/docs/0.9.5/Command-Duration.html +++ /dev/null @@ -1,511 +0,0 @@ - - - - - - - - - Command Duration — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Command Duration

-

Before reading this tutorial, if you haven’t done so already, you might want to -read the documentation on commands to get a basic understanding of -how commands work in Evennia.

-

In some types of games a command should not start and finish immediately. -Loading a crossbow might take a bit of time to do - time you don’t have when -the enemy comes rushing at you. Crafting that armour will not be immediate -either. For some types of games the very act of moving or changing pose all -comes with a certain time associated with it.

-
-

The simple way to pause commands with yield

-

Evennia allows a shortcut in syntax to create simple pauses in commands. This -syntax uses the yield keyword. The yield keyword is used in Python to -create generators, although you don’t need to know what generators are to use -this syntax. A short example will probably make it clear:

-
class CmdTest(Command):
-
-    """
-    A test command just to test waiting.
-
-    Usage:
-        test
-
-    """
-
-    key = "test"
-    locks = "cmd:all()"
-
-    def func(self):
-        self.msg("Before ten seconds...")
-        yield 10
-        self.msg("Afterwards.")
-
-
-
-

Important: The yield functionality will only work in the func method of -Commands. It only works because Evennia has especially -catered for it in Commands. If you want the same functionality elsewhere you -must use the interactive decorator.

-
-

The important line is the yield 10. It tells Evennia to “pause” the command -and to wait for 10 seconds to execute the rest. If you add this command and -run it, you’ll see the first message, then, after a pause of ten seconds, the -next message. You can use yield several times in your command.

-

This syntax will not “freeze” all commands. While the command is “pausing”, -you can execute other commands (or even call the same command again). And -other players aren’t frozen either.

-
-

Note: this will not save anything in the database. If you reload the game -while a command is “paused”, it will not resume after the server has -reloaded.

-
-
-
-

The more advanced way with utils.delay

-

The yield syntax is easy to read, easy to understand, easy to use. But it’s not that flexible if -you want more advanced options. Learning to use alternatives might be much worth it in the end.

-

Below is a simple command example for adding a duration for a command to finish.

-
from evennia import default_cmds, utils
-    
-class CmdEcho(default_cmds.MuxCommand):
-    """
-    wait for an echo
-    
-    Usage:
-      echo <string>
-    
-    Calls and waits for an echo
-    """
-    key = "echo"
-    locks = "cmd:all()"
-    
-    def func(self):
-        """
-         This is called at the initial shout.
-        """
-        self.caller.msg("You shout '%s' and wait for an echo ..." % self.args)
-        # this waits non-blocking for 10 seconds, then calls self.echo
-        utils.delay(10, self.echo) # call echo after 10 seconds
-    
-    def echo(self):
-        "Called after 10 seconds."
-        shout = self.args
-        string = "You hear an echo: %s ... %s ... %s"
-        string = string % (shout.upper(), shout.capitalize(), shout.lower())
-        self.caller.msg(string)
-
-
-

Import this new echo command into the default command set and reload the server. You will find that -it will take 10 seconds before you see your shout coming back. You will also find that this is a -non-blocking effect; you can issue other commands in the interim and the game will go on as usual. -The echo will come back to you in its own time.

-
-

About utils.delay()

-

utils.delay(timedelay, callback, persistent=False, *args, **kwargs) is a useful function. It will -wait timedelay seconds, then call the callback function, optionally passing to it the arguments -provided to utils.delay by way of *args and/or **kwargs`.

-
-

Note: The callback argument should be provided with a python path to the desired function, for -instance my_object.my_function instead of my_object.my_function(). Otherwise my_function would -get called and run immediately upon attempting to pass it to the delay function. -If you want to provide arguments for utils.delay to use, when calling your callback function, you -have to do it separatly, for instance using the utils.delay *args and/or **kwargs, as mentioned -above.

-
-
-

If you are not familiar with the syntax *args and **kwargs, see the Python documentation -here.

-
-

Looking at it you might think that utils.delay(10, callback) in the code above is just an -alternative to some more familiar thing like time.sleep(10). This is not the case. If you do -time.sleep(10) you will in fact freeze the entire server for ten seconds! The utils.delay()is -a thin wrapper around a Twisted -Deferred that will delay -execution until 10 seconds have passed, but will do so asynchronously, without bothering anyone else -(not even you - you can continue to do stuff normally while it waits to continue).

-

The point to remember here is that the delay() call will not “pause” at that point when it is -called (the way yield does in the previous section). The lines after the delay() call will -actually execute right away. What you must do is to tell it which function to call after the time -has passed (its “callback”). This may sound strange at first, but it is normal practice in -asynchronous systems. You can also link such calls together as seen below:

-
from evennia import default_cmds, utils
-    
-class CmdEcho(default_cmds.MuxCommand):
-    """
-    waits for an echo
-    
-    Usage:
-      echo <string>
-    
-    Calls and waits for an echo
-    """
-    key = "echo"
-    locks = "cmd:all()"
-    
-    def func(self):
-        "This sets off a chain of delayed calls"
-        self.caller.msg("You shout '%s', waiting for an echo ..." % self.args)
-
-        # wait 2 seconds before calling self.echo1
-        utils.delay(2, self.echo1)
-    
-    # callback chain, started above
-    def echo1(self):
-        "First echo"
-        self.caller.msg("... %s" % self.args.upper())
-        # wait 2 seconds for the next one
-        utils.delay(2, self.echo2)
-
-    def echo2(self):
-        "Second echo"
-        self.caller.msg("... %s" % self.args.capitalize())
-        # wait another 2 seconds
-        utils.delay(2, callback=self.echo3)
-
-    def echo3(self):
-        "Last echo"
-        self.caller.msg("... %s ..." % self.args.lower())
-
-
-

The above version will have the echoes arrive one after another, each separated by a two second -delay.

-
> echo Hello!
-... HELLO!
-... Hello!
-... hello! ...
-
-
-
-
-
-

Blocking commands

-

As mentioned, a great thing about the delay introduced by yield or utils.delay() is that it does -not block. It just goes on in the background and you are free to play normally in the interim. In -some cases this is not what you want however. Some commands should simply “block” other commands -while they are running. If you are in the process of crafting a helmet you shouldn’t be able to also -start crafting a shield at the same time, or if you just did a huge power-swing with your weapon you -should not be able to do it again immediately.

-

The simplest way of implementing blocking is to use the technique covered in the Command -Cooldown tutorial. In that tutorial we implemented cooldowns by having the -Command store the current time. Next time the Command was called, we compared the current time to -the stored time to determine if enough time had passed for a renewed use. This is a very -efficient, reliable and passive solution. The drawback is that there is nothing to tell the Player -when enough time has passed unless they keep trying.

-

Here is an example where we will use utils.delay to tell the player when the cooldown has passed:

-
from evennia import utils, default_cmds
-    
-class CmdBigSwing(default_cmds.MuxCommand):
-    """
-    swing your weapon in a big way
-
-    Usage:
-      swing <target>
-    
-    Makes a mighty swing. Doing so will make you vulnerable
-    to counter-attacks before you can recover.
-    """
-    key = "bigswing"
-    locks = "cmd:all()"
-    
-    def func(self):
-        "Makes the swing"
-
-        if self.caller.ndb.off_balance:
-            # we are still off-balance.
-            self.caller.msg("You are off balance and need time to recover!")
-            return
-      
-        # [attack/hit code goes here ...]
-        self.caller.msg("You swing big! You are off balance now.")
-
-        # set the off-balance flag
-        self.caller.ndb.off_balance = True
-            
-        # wait 8 seconds before we can recover. During this time
-        # we won't be able to swing again due to the check at the top.
-        utils.delay(8, self.recover)
-    
-    def recover(self):
-        "This will be called after 8 secs"
-        del self.caller.ndb.off_balance
-        self.caller.msg("You regain your balance.")
-
-
-

Note how, after the cooldown, the user will get a message telling them they are now ready for -another swing.

-

By storing the off_balance flag on the character (rather than on, say, the Command instance -itself) it can be accessed by other Commands too. Other attacks may also not work when you are off -balance. You could also have an enemy Command check your off_balance status to gain bonuses, to -take another example.

-
-
-

Abortable commands

-

One can imagine that you will want to abort a long-running command before it has a time to finish. -If you are in the middle of crafting your armor you will probably want to stop doing that when a -monster enters your smithy.

-

You can implement this in the same way as you do the “blocking” command above, just in reverse. -Below is an example of a crafting command that can be aborted by starting a fight:

-
from evennia import utils, default_cmds
-    
-class CmdCraftArmour(default_cmds.MuxCommand):
-    """
-    Craft armour
-    
-    Usage:
-       craft <name of armour>
-    
-    This will craft a suit of armour, assuming you
-    have all the components and tools. Doing some
-    other action (such as attacking someone) will
-    abort the crafting process.
-    """
-    key = "craft"
-    locks = "cmd:all()"
-    
-    def func(self):
-        "starts crafting"
-
-        if self.caller.ndb.is_crafting:
-            self.caller.msg("You are already crafting!")
-            return
-        if self._is_fighting():
-            self.caller.msg("You can't start to craft "
-                            "in the middle of a fight!")
-            return
-            
-        # [Crafting code, checking of components, skills etc]
-
-        # Start crafting
-        self.caller.ndb.is_crafting = True
-        self.caller.msg("You start crafting ...")
-        utils.delay(60, self.step1)
-    
-    def _is_fighting(self):
-        "checks if we are in a fight."
-        if self.caller.ndb.is_fighting:
-            del self.caller.ndb.is_crafting
-            return True
-      
-    def step1(self):
-        "first step of armour construction"
-        if self._is_fighting():
-            return
-        self.msg("You create the first part of the armour.")
-        utils.delay(60, callback=self.step2)
-
-    def step2(self):
-        "second step of armour construction"
-        if self._is_fighting():
-            return
-        self.msg("You create the second part of the armour.")
-        utils.delay(60, step3)
-
-    def step3(self):
-        "last step of armour construction"
-        if self._is_fighting():
-            return
-    
-        # [code for creating the armour object etc]
-
-        del self.caller.ndb.is_crafting
-        self.msg("You finalize your armour.")
-    
-    
-# example of a command that aborts crafting
-    
-class CmdAttack(default_cmds.MuxCommand):
-    """
-    attack someone
-    
-    Usage:
-        attack <target>
-    
-    Try to cause harm to someone. This will abort
-    eventual crafting you may be currently doing.
-    """
-    key = "attack"
-    aliases = ["hit", "stab"]
-    locks = "cmd:all()"
-    
-    def func(self):
-        "Implements the command"
-
-        self.caller.ndb.is_fighting = True
-    
-        # [...]
-
-
-

The above code creates a delayed crafting command that will gradually create the armour. If the -attack command is issued during this process it will set a flag that causes the crafting to be -quietly canceled next time it tries to update.

-
-
-

Persistent delays

-

In the latter examples above we used .ndb storage. This is fast and easy but it will reset all -cooldowns/blocks/crafting etc if you reload the server. If you don’t want that you can replace -.ndb with .db. But even this won’t help because the yield keyword is not persisent and nor is -the use of delay shown above. To resolve this you can use delay with the persistent=True -keyword. But wait! Making something persistent will add some extra complications, because now you -must make sure Evennia can properly store things to the database.

-

Here is the original echo-command reworked to function with persistence:

-
from evennia import default_cmds, utils
-    
-# this is now in the outermost scope and takes two args!
-def echo(caller, args):
-    "Called after 10 seconds."
-    shout = args
-    string = "You hear an echo: %s ... %s ... %s"
-    string = string % (shout.upper(), shout.capitalize(), shout.lower())
-    caller.msg(string)
-
-class CmdEcho(default_cmds.MuxCommand):
-    """
-    wait for an echo
-    
-    Usage:
-      echo <string>
-    
-    Calls and waits for an echo
-    """
-    key = "echo"
-    locks = "cmd:all()"
-    
-    def func(self):
-        """
-         This is called at the initial shout.
-        """
-        self.caller.msg("You shout '%s' and wait for an echo ..." % self.args)
-        # this waits non-blocking for 10 seconds, then calls echo(self.caller, self.args)
-        utils.delay(10, echo, self.caller, self.args, persistent=True) # changes!
-    
-
-
-

Above you notice two changes:

-
    -
  • The callback (echo) was moved out of the class and became its own stand-alone function in the -outermost scope of the module. It also now takes caller and args as arguments (it doesn’t have -access to them directly since this is now a stand-alone function).

  • -
  • utils.delay specifies the echo function (not self.echo - it’s no longer a method!) and sends -self.caller and self.args as arguments for it to use. We also set persistent=True.

  • -
-

The reason for this change is because Evennia needs to pickle the callback into storage and it -cannot do this correctly when the method sits on the command class. Now this behave the same as the -first version except if you reload (or even shut down) the server mid-delay it will still fire the -callback when the server comes back up (it will resume the countdown and ignore the downtime).

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Command-Prompt.html b/docs/0.9.5/Command-Prompt.html deleted file mode 100644 index 52b818d387..0000000000 --- a/docs/0.9.5/Command-Prompt.html +++ /dev/null @@ -1,239 +0,0 @@ - - - - - - - - - Command Prompt — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Command Prompt

-

A prompt is quite common in MUDs. The prompt display useful details about your character that you -are likely to want to keep tabs on at all times, such as health, magical power etc. It might also -show things like in-game time, weather and so on. Many modern MUD clients (including Evennia’s own -webclient) allows for identifying the prompt and have it appear in a correct location (usually just -above the input line). Usually it will remain like that until it is explicitly updated.

-
-

Sending a prompt

-

A prompt is sent using the prompt keyword to the msg() method on objects. The prompt will be -sent without any line breaks.

-
    self.msg(prompt="HP: 5, MP: 2, SP: 8")
-
-
-

You can combine the sending of normal text with the sending (updating of the prompt):

-
    self.msg("This is a text", prompt="This is a prompt")
-
-
-

You can update the prompt on demand, this is normally done using OOB-tracking of the relevant -Attributes (like the character’s health). You could also make sure that attacking commands update -the prompt when they cause a change in health, for example.

-

Here is a simple example of the prompt sent/updated from a command class:

-
    from evennia import Command
-
-    class CmdDiagnose(Command):
-        """
-        see how hurt your are
-
-        Usage:
-          diagnose [target]
-
-        This will give an estimate of the target's health. Also
-        the target's prompt will be updated.
-        """
-        key = "diagnose"
-        
-        def func(self):
-            if not self.args:
-                target = self.caller
-            else:
-                target = self.search(self.args)
-                if not target:
-                    return
-            # try to get health, mana and stamina
-            hp = target.db.hp
-            mp = target.db.mp
-            sp = target.db.sp
-
-            if None in (hp, mp, sp):
-                # Attributes not defined
-                self.caller.msg("Not a valid target!")
-                return
-             
-            text = "You diagnose %s as having " \
-                   "%i health, %i mana and %i stamina." \
-                   % (hp, mp, sp)
-            prompt = "%i HP, %i MP, %i SP" % (hp, mp, sp)
-            self.caller.msg(text, prompt=prompt)
-
-
-
-
-

A prompt sent with every command

-

The prompt sent as described above uses a standard telnet instruction (the Evennia web client gets a -special flag). Most MUD telnet clients will understand and allow users to catch this and keep the -prompt in place until it updates. So in principle you’d not need to update the prompt every -command.

-

However, with a varying user base it can be unclear which clients are used and which skill level the -users have. So sending a prompt with every command is a safe catch-all. You don’t need to manually -go in and edit every command you have though. Instead you edit the base command class for your -custom commands (like MuxCommand in your mygame/commands/command.py folder) and overload the -at_post_cmd() hook. This hook is always called after the main func() method of the Command.

-
from evennia import default_cmds
-
-class MuxCommand(default_cmds.MuxCommand):
-    # ...
-    def at_post_cmd(self):
-        "called after self.func()."
-        caller = self.caller
-        prompt = "%i HP, %i MP, %i SP" % (caller.db.hp,
-                                          caller.db.mp,
-                                          caller.db.sp)
-        caller.msg(prompt=prompt)
-
-
-
-
-

Modifying default commands

-

If you want to add something small like this to Evennia’s default commands without modifying them -directly the easiest way is to just wrap those with a multiple inheritance to your own base class:

-
# in (for example) mygame/commands/mycommands.py
-
-from evennia import default_cmds
-# our custom MuxCommand with at_post_cmd hook
-from commands.command import MuxCommand
-
-# overloading the look command
-class CmdLook(default_cmds.CmdLook, MuxCommand):
-    pass
-
-
-

The result of this is that the hooks from your custom MuxCommand will be mixed into the default -CmdLook through multiple inheritance. Next you just add this to your default command set:

-
# in mygame/commands/default_cmdsets.py
-
-from evennia import default_cmds
-from commands import mycommands
-
-class CharacterCmdSet(default_cmds.CharacterCmdSet):
-    # ...
-    def at_cmdset_creation(self):
-        # ...
-        self.add(mycommands.CmdLook())
-
-
-

This will automatically replace the default look command in your game with your own version.

-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Command-Sets.html b/docs/0.9.5/Command-Sets.html deleted file mode 100644 index 7e948541af..0000000000 --- a/docs/0.9.5/Command-Sets.html +++ /dev/null @@ -1,490 +0,0 @@ - - - - - - - - - Command Sets — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Command Sets

-

Command Sets are intimately linked with Commands and you should be familiar with -Commands before reading this page. The two pages were split for ease of reading.

-

A Command Set (often referred to as a CmdSet or cmdset) is the basic unit for storing one or more -Commands. A given Command can go into any number of different command sets. Storing Command -classes in a command set is the way to make commands available to use in your game.

-

When storing a CmdSet on an object, you will make the commands in that command set available to the -object. An example is the default command set stored on new Characters. This command set contains -all the useful commands, from look and inventory to @dig and @reload -(permissions then limit which players may use them, but that’s a separate -topic).

-

When an account enters a command, cmdsets from the Account, Character, its location, and elsewhere -are pulled together into a merge stack. This stack is merged together in a specific order to -create a single “merged” cmdset, representing the pool of commands available at that very moment.

-

An example would be a Window object that has a cmdset with two commands in it: look through window and open window. The command set would be visible to players in the room with the window, -allowing them to use those commands only there. You could imagine all sorts of clever uses of this, -like a Television object which had multiple commands for looking at it, switching channels and so -on. The tutorial world included with Evennia showcases a dark room that replaces certain critical -commands with its own versions because the Character cannot see.

-

If you want a quick start into defining your first commands and using them with command sets, you -can head over to the Adding Command Tutorial which steps through things -without the explanations.

-
-

Defining Command Sets

-

A CmdSet is, as most things in Evennia, defined as a Python class inheriting from the correct parent -(evennia.CmdSet, which is a shortcut to evennia.commands.cmdset.CmdSet). The CmdSet class only -needs to define one method, called at_cmdset_creation(). All other class parameters are optional, -but are used for more advanced set manipulation and coding (see the [merge rules](Command- -Sets#merge-rules) section).

-
# file mygame/commands/mycmdset.py
-
-from evennia import CmdSet
-
-# this is a theoretical custom module with commands we
-# created previously: mygame/commands/mycommands.py
-from commands import mycommands
-
-class MyCmdSet(CmdSet):
-    def at_cmdset_creation(self):
-        """
-        The only thing this method should need
-        to do is to add commands to the set.
-        """
-        self.add(mycommands.MyCommand1())
-        self.add(mycommands.MyCommand2())
-        self.add(mycommands.MyCommand3())
-
-
-

The CmdSet’s add() method can also take another CmdSet as input. In this case all the commands -from that CmdSet will be appended to this one as if you added them line by line:

-
    def at_cmdset_creation():
-        ...
-        self.add(AdditionalCmdSet) # adds all command from this set
-        ...
-
-
-

If you added your command to an existing cmdset (like to the default cmdset), that set is already -loaded into memory. You need to make the server aware of the code changes:

-
@reload
-
-
-

You should now be able to use the command.

-

If you created a new, fresh cmdset, this must be added to an object in order to make the commands -within available. A simple way to temporarily test a cmdset on yourself is use the @py command to -execute a python snippet:

-
@py self.cmdset.add('commands.mycmdset.MyCmdSet')
-
-
-

This will stay with you until you @reset or @shutdown the server, or you run

-
@py self.cmdset.delete('commands.mycmdset.MyCmdSet')
-
-
-

In the example above, a specific Cmdset class is removed. Calling delete without arguments will -remove the latest added cmdset.

-
-

Note: Command sets added using cmdset.add are, by default, not persistent in the database.

-
-

If you want the cmdset to survive a reload, you can do:

-
@py self.cmdset.add(commands.mycmdset.MyCmdSet, permanent=True)
-
-
-

Or you could add the cmdset as the default cmdset:

-
@py self.cmdset.add_default(commands.mycmdset.MyCmdSet)
-
-
-

An object can only have one “default” cmdset (but can also have none). This is meant as a safe fall- -back even if all other cmdsets fail or are removed. It is always persistent and will not be affected -by cmdset.delete(). To remove a default cmdset you must explicitly call cmdset.remove_default().

-

Command sets are often added to an object in its at_object_creation method. For more examples of -adding commands, read the Step by step tutorial. Generally you can -customize which command sets are added to your objects by using self.cmdset.add() or -self.cmdset.add_default().

-
-

Important: Commands are identified uniquely by key or alias (see Commands). If any -overlap exists, two commands are considered identical. Adding a Command to a command set that -already has an identical command will replace the previous command. This is very important. You -must take this behavior into account when attempting to overload any default Evennia commands with -your own. Otherwise, you may accidentally “hide” your own command in your command set when adding a -new one that has a matching alias.

-
-
-

Properties on Command Sets

-

There are several extra flags that you can set on CmdSets in order to modify how they work. All are -optional and will be set to defaults otherwise. Since many of these relate to merging cmdsets, -you might want to read the [Adding and Merging Command Sets](./Command-Sets.md#adding-and-merging- -command-sets) section for some of these to make sense.

-
    -
  • key (string) - an identifier for the cmdset. This is optional, but should be unique. It is used -for display in lists, but also to identify special merging behaviours using the key_mergetype -dictionary below.

  • -
  • mergetype (string) - allows for one of the following string values: “Union”, “Intersect”, -“Replace”, or “Remove”.

  • -
  • priority (int) - This defines the merge order of the merge stack - cmdsets will merge in rising -order of priority with the highest priority set merging last. During a merger, the commands from the -set with the higher priority will have precedence (just what happens depends on the merge -type). If priority is identical, the order in the -merge stack determines preference. The priority value must be greater or equal to -100. Most in- -game sets should usually have priorities between 0 and 100. Evennia default sets have priorities -as follows (these can be changed if you want a different distribution):

    -
      -
    • EmptySet: -101 (should be lower than all other sets)

    • -
    • SessionCmdSet: -20

    • -
    • AccountCmdSet: -10

    • -
    • CharacterCmdSet: 0

    • -
    • ExitCmdSet: 101 (generally should always be available)

    • -
    • ChannelCmdSet: 101 (should usually always be available) - since exits never accept -arguments, there is no collision between exits named the same as a channel even though the commands -“collide”.

    • -
    -
  • -
  • key_mergetype (dict) - a dict of key:mergetype pairs. This allows this cmdset to merge -differently with certain named cmdsets. If the cmdset to merge with has a key matching an entry in -key_mergetype, it will not be merged according to the setting in mergetype but according to the -mode in this dict. Please note that this is more complex than it may seem due to the merge -order of command sets. Please review that section -before using key_mergetype.

  • -
  • duplicates (bool/None default None) - this determines what happens when merging same-priority -cmdsets containing same-key commands together. Thedupicate option will only apply when merging -the cmdset with this option onto one other cmdset with the same priority. The resulting cmdset will -not retain this duplicate setting.

    -
      -
    • None (default): No duplicates are allowed and the cmdset being merged “onto” the old one -will take precedence. The result will be unique commands. However, the system will assume this -value to be True for cmdsets on Objects, to avoid dangerous clashes. This is usually the safe bet.

    • -
    • False: Like None except the system will not auto-assume any value for cmdsets defined on -Objects.

    • -
    • True: Same-named, same-prio commands will merge into the same cmdset. This will lead to a -multimatch error (the user will get a list of possibilities in order to specify which command they -meant). This is is useful e.g. for on-object cmdsets (example: There is a red button and a green button in the room. Both have a press button command, in cmdsets with the same priority. This -flag makes sure that just writing press button will force the Player to define just which object’s -command was intended).

    • -
    -
  • -
  • no_objs this is a flag for the cmdhandler that builds the set of commands available at every -moment. It tells the handler not to include cmdsets from objects around the account (nor from rooms -or inventory) when building the merged set. Exit commands will still be included. This option can -have three values:

    -
      -
    • None (default): Passthrough of any value set explicitly earlier in the merge stack. If never -set explicitly, this acts as False.

    • -
    • True/False: Explicitly turn on/off. If two sets with explicit no_objs are merged, -priority determines what is used.

    • -
    -
  • -
  • no_exits - this is a flag for the cmdhandler that builds the set of commands available at every -moment. It tells the handler not to include cmdsets from exits. This flag can have three values:

    -
      -
    • None (default): Passthrough of any value set explicitly earlier in the merge stack. If -never set explicitly, this acts as False.

    • -
    • True/False: Explicitly turn on/off. If two sets with explicit no_exits are merged, -priority determines what is used.

    • -
    -
  • -
  • no_channels (bool) - this is a flag for the cmdhandler that builds the set of commands available -at every moment. It tells the handler not to include cmdsets from available in-game channels. This -flag can have three values:

    -
      -
    • None (default): Passthrough of any value set explicitly earlier in the merge stack. If -never set explicitly, this acts as False.

    • -
    • True/False: Explicitly turn on/off. If two sets with explicit no_channels are merged, -priority determines what is used.

    • -
    -
  • -
-
-
-
-

Command Sets Searched

-

When a user issues a command, it is matched against the [merged](./Command-Sets.md#adding-and-merging- -command-sets) command sets available to the player at the moment. Which those are may change at any -time (such as when the player walks into the room with the Window object described earlier).

-

The currently valid command sets are collected from the following sources:

-
    -
  • The cmdsets stored on the currently active Session. Default is the empty -SessionCmdSet with merge priority -20.

  • -
  • The cmdsets defined on the Account. Default is the AccountCmdSet with merge priority --10.

  • -
  • All cmdsets on the Character/Object (assuming the Account is currently puppeting such a -Character/Object). Merge priority 0.

  • -
  • The cmdsets of all objects carried by the puppeted Character (checks the call lock). Will not be -included if no_objs option is active in the merge stack.

  • -
  • The cmdsets of the Character’s current location (checks the call lock). Will not be included if -no_objs option is active in the merge stack.

  • -
  • The cmdsets of objects in the current location (checks the call lock). Will not be included if -no_objs option is active in the merge stack.

  • -
  • The cmdsets of Exits in the location. Merge priority +101. Will not be included if no_exits -or no_objs option is active in the merge stack.

  • -
  • The channel cmdset containing commands for posting to all channels the account -or character is currently connected to. Merge priority +101. Will not be included if no_channels -option is active in the merge stack.

  • -
-

Note that an object does not have to share its commands with its surroundings. A Character’s -cmdsets should not be shared for example, or all other Characters would get multi-match errors just -by being in the same room. The ability of an object to share its cmdsets is managed by its call -lock. For example, Character objects defaults to call:false() so that any -cmdsets on them can only be accessed by themselves, not by other objects around them. Another -example might be to lock an object with call:inside() to only make their commands available to -objects inside them, or cmd:holds() to make their commands available only if they are held.

-
-
-

Adding and Merging Command Sets

-

Note: This is an advanced topic. It’s very useful to know about, but you might want to skip it if -this is your first time learning about commands.

-

CmdSets have the special ability that they can be merged together into new sets. Which of the -ingoing commands end up in the merged set is defined by the merge rule and the relative -priorities of the two sets. Removing the latest added set will restore things back to the way it -was before the addition.

-

CmdSets are non-destructively stored in a stack inside the cmdset handler on the object. This stack -is parsed to create the “combined” cmdset active at the moment. CmdSets from other sources are also -included in the merger such as those on objects in the same room (like buttons to press) or those -introduced by state changes (such as when entering a menu). The cmdsets are all ordered after -priority and then merged together in reverse order. That is, the higher priority will be merged -“onto” lower-prio ones. By defining a cmdset with a merge-priority between that of two other sets, -you will make sure it will be merged in between them. -The very first cmdset in this stack is called the Default cmdset and is protected from accidental -deletion. Running obj.cmdset.delete() will never delete the default set. Instead one should add -new cmdsets on top of the default to “hide” it, as described below. Use the special -obj.cmdset.delete_default() only if you really know what you are doing.

-

CmdSet merging is an advanced feature useful for implementing powerful game effects. Imagine for -example a player entering a dark room. You don’t want the player to be able to find everything in -the room at a glance - maybe you even want them to have a hard time to find stuff in their backpack! -You can then define a different CmdSet with commands that override the normal ones. While they are -in the dark room, maybe the look and inv commands now just tell the player they cannot see -anything! Another example would be to offer special combat commands only when the player is in -combat. Or when being on a boat. Or when having taken the super power-up. All this can be done on -the fly by merging command sets.

-
-

Merge Rules

-

Basic rule is that command sets are merged in reverse priority order. That is, lower-prio sets are -merged first and higher prio sets are merged “on top” of them. Think of it like a layered cake with -the highest priority on top.

-

To further understand how sets merge, we need to define some examples. Let’s call the first command -set A and the second B. We assume B is the command set already active on our object and -we will merge A onto B. In code terms this would be done by object.cdmset.add(A). -Remember, B is already active on object from before.

-

We let the A set have higher priority than B. A priority is simply an integer number. As -seen in the list above, Evennia’s default cmdsets have priorities in the range -101 to 120. You -are usually safe to use a priority of 0 or 1 for most game effects.

-

In our examples, both sets contain a number of commands which we’ll identify by numbers, like A1, A2 for set A and B1, B2, B3, B4 for B. So for that example both sets contain commands -with the same keys (or aliases) “1” and “2” (this could for example be “look” and “get” in the real -game), whereas commands 3 and 4 are unique to B. To describe a merge between these sets, we -would write A1,A2 + B1,B2,B3,B4 = ? where ? is a list of commands that depend on which merge -type A has, and which relative priorities the two sets have. By convention, we read this -statement as “New command set A is merged onto the old command set B to form ?”.

-

Below are the available merge types and how they work. Names are partly borrowed from Set -theory.

-
    -
  • Union (default) - The two cmdsets are merged so that as many commands as possible from each -cmdset ends up in the merged cmdset. Same-key commands are merged by priority.

    -
       # Union
    -   A1,A2 + B1,B2,B3,B4 = A1,A2,B3,B4
    -
    -
    -
  • -
  • Intersect - Only commands found in both cmdsets (i.e. which have the same keys) end up in -the merged cmdset, with the higher-priority cmdset replacing the lower one’s commands.

    -
       # Intersect
    -   A1,A3,A5 + B1,B2,B4,B5 = A1,A5
    -
    -
    -
  • -
  • Replace - The commands of the higher-prio cmdset completely replaces the lower-priority -cmdset’s commands, regardless of if same-key commands exist or not.

    -
       # Replace
    -   A1,A3 + B1,B2,B4,B5 = A1,A3
    -
    -
    -
  • -
  • Remove - The high-priority command sets removes same-key commands from the lower-priority -cmdset. They are not replaced with anything, so this is a sort of filter that prunes the low-prio -set using the high-prio one as a template.

    -
       # Remove
    -   A1,A3 + B1,B2,B3,B4,B5 = B2,B4,B5
    -
    -
    -
  • -
-

Besides priority and mergetype, a command-set also takes a few other variables to control how -they merge:

-
    -
  • duplicates (bool) - determines what happens when two sets of equal priority merge. Default is -that the new set in the merger (i.e. A above) automatically takes precedence. But if -duplicates is true, the result will be a merger with more than one of each name match. This will -usually lead to the player receiving a multiple-match error higher up the road, but can be good for -things like cmdsets on non-player objects in a room, to allow the system to warn that more than one -‘ball’ in the room has the same ‘kick’ command defined on it and offer a chance to select which -ball to kick … Allowing duplicates only makes sense for Union and Intersect, the setting is -ignored for the other mergetypes.

  • -
  • key_mergetypes (dict) - allows the cmdset to define a unique mergetype for particular cmdsets, -identified by their cmdset key. Format is {CmdSetkey:mergetype}. Example: -{'Myevilcmdset','Replace'} which would make sure for this set to always use ‘Replace’ on the -cmdset with the key Myevilcmdset only, no matter what the main mergetype is set to.

  • -
-
-

Warning: The key_mergetypes dictionary can only work on the cmdset we merge onto. When using -key_mergetypes it is thus important to consider the merge priorities - you must make sure that you -pick a priority between the cmdset you want to detect and the next higher one, if any. That is, if -we define a cmdset with a high priority and set it to affect a cmdset that is far down in the merge -stack, we would not “see” that set when it’s time for us to merge. Example: Merge stack is -A(prio=-10), B(prio=-5), C(prio=0), D(prio=5). We now merge a cmdset E(prio=10) onto this stack, -with a key_mergetype={"B":"Replace"}. But priorities dictate that we won’t be merged onto B, we -will be merged onto E (which is a merger of the lower-prio sets at this point). Since we are merging -onto E and not B, our key_mergetype directive won’t trigger. To make sure it works we must make -sure we merge onto B. Setting E’s priority to, say, -4 will make sure to merge it onto B and affect -it appropriately.

-
-

More advanced cmdset example:

-
from commands import mycommands
-
-class MyCmdSet(CmdSet):
-    
-    key = "MyCmdSet"
-    priority = 4
-    mergetype = "Replace"
-    key_mergetypes = {'MyOtherCmdSet':'Union'}
-    
-    def at_cmdset_creation(self):
-        """
-        The only thing this method should need
-        to do is to add commands to the set.
-        """
-        self.add(mycommands.MyCommand1())
-        self.add(mycommands.MyCommand2())
-        self.add(mycommands.MyCommand3())
-
-
-
-
-

Assorted Notes

-

It is very important to remember that two commands are compared both by their key properties -and by their aliases properties. If either keys or one of their aliases match, the two commands -are considered the same. So consider these two Commands:

-
    -
  • A Command with key “kick” and alias “fight”

  • -
  • A Command with key “punch” also with an alias “fight”

  • -
-

During the cmdset merging (which happens all the time since also things like channel commands and -exits are merged in), these two commands will be considered identical since they share alias. It -means only one of them will remain after the merger. Each will also be compared with all other -commands having any combination of the keys and/or aliases “kick”, “punch” or “fight”.

-

… So avoid duplicate aliases, it will only cause confusion.

-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Command-System.html b/docs/0.9.5/Command-System.html deleted file mode 100644 index 079da3f871..0000000000 --- a/docs/0.9.5/Command-System.html +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - Command System — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Command System

- -

See also:

- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Commands.html b/docs/0.9.5/Commands.html deleted file mode 100644 index fb54015f74..0000000000 --- a/docs/0.9.5/Commands.html +++ /dev/null @@ -1,775 +0,0 @@ - - - - - - - - - Commands — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Commands

-

Commands are intimately linked to Command Sets and you need to read that page too to -be familiar with how the command system works. The two pages were split for easy reading.

-

The basic way for users to communicate with the game is through Commands. These can be commands -directly related to the game world such as look, get, drop and so on, or administrative -commands such as examine or @dig.

-

The default commands coming with Evennia are ‘MUX-like’ in that they use @ -for admin commands, support things like switches, syntax with the ‘=’ symbol etc, but there is -nothing that prevents you from implementing a completely different command scheme for your game. You -can find the default commands in evennia/commands/default. You should not edit these directly - -they will be updated by the Evennia team as new features are added. Rather you should look to them -for inspiration and inherit your own designs from them.

-

There are two components to having a command running - the Command class and the Command -Set (command sets were split into a separate wiki page for ease of reading).

-
    -
  1. A Command is a python class containing all the functioning code for what a command does - for -example, a get command would contain code for picking up objects.

  2. -
  3. A Command Set (often referred to as a CmdSet or cmdset) is like a container for one or more -Commands. A given Command can go into any number of different command sets. Only by putting the -command set on a character object you will make all the commands therein available to use by that -character. You can also store command sets on normal objects if you want users to be able to use the -object in various ways. Consider a “Tree” object with a cmdset defining the commands climb and -chop down. Or a “Clock” with a cmdset containing the single command check time.

  4. -
-

This page goes into full detail about how to use Commands. To fully use them you must also read the -page detailing Command Sets. There is also a step-by-step Adding Command -Tutorial that will get you started quickly without the extra explanations.

-
-

Defining Commands

-

All commands are implemented as normal Python classes inheriting from the base class Command -(evennia.Command). You will find that this base class is very “bare”. The default commands of -Evennia actually inherit from a child of Command called MuxCommand - this is the class that -knows all the mux-like syntax like /switches, splitting by “=” etc. Below we’ll avoid mux- -specifics and use the base Command class directly.

-
    # basic Command definition
-    from evennia import Command
-
-    class MyCmd(Command):
-       """
-       This is the help-text for the command
-       """
-       key = "mycommand"
-       def parse(self):
-           # parsing the command line here
-       def func(self):
-           # executing the command here
-
-
-

Here is a minimalistic command with no custom parsing:

-
    from evennia import Command
-
-    class CmdEcho(Command):
-        key = "echo"
-
-        def func(self):
-            # echo the caller's input back to the caller
-            self.caller.msg("Echo: {}".format(self.args)
-
-
-
-

You define a new command by assigning a few class-global properties on your inherited class and -overloading one or two hook functions. The full gritty mechanic behind how commands work are found -towards the end of this page; for now you only need to know that the command handler creates an -instance of this class and uses that instance whenever you use this command - it also dynamically -assigns the new command instance a few useful properties that you can assume to always be available.

-
-

Who is calling the command?

-

In Evennia there are three types of objects that may call the command. It is important to be aware -of this since this will also assign appropriate caller, session, sessid and account -properties on the command body at runtime. Most often the calling type is Session.

-
    -
  • A Session. This is by far the most common case when a user is entering a command in -their client.

    -
      -
    • caller - this is set to the puppeted Object if such an object exists. If no -puppet is found, caller is set equal to account. Only if an Account is not found either (such as -before being logged in) will this be set to the Session object itself.

    • -
    • session - a reference to the Session object itself.

    • -
    • sessid - sessid.id, a unique integer identifier of the session.

    • -
    • account - the Account object connected to this Session. None if not logged in.

    • -
    -
  • -
  • An Account. This only happens if account.execute_cmd() was used. No Session -information can be obtained in this case.

    -
      -
    • caller - this is set to the puppeted Object if such an object can be determined (without -Session info this can only be determined in MULTISESSION_MODE=0 or 1). If no puppet is found, -this is equal to account.

    • -
    • session - None*

    • -
    • sessid - None*

    • -
    • account - Set to the Account object.

    • -
    -
  • -
  • An Object. This only happens if object.execute_cmd() was used (for example by an -NPC).

    -
      -
    • caller - This is set to the calling Object in question.

    • -
    • session - None*

    • -
    • sessid - None*

    • -
    • account - None

    • -
    -
  • -
-
-

*): There is a way to make the Session available also inside tests run directly on Accounts and -Objects, and that is to pass it to execute_cmd like so: account.execute_cmd("...", session=<Session>). Doing so will make the .session and .sessid properties available in the -command.

-
-
-
-

Properties assigned to the command instance at run-time

-

Let’s say account Bob with a character BigGuy enters the command look at sword. After the -system having successfully identified this as the “look” command and determined that BigGuy really -has access to a command named look, it chugs the look command class out of storage and either -loads an existing Command instance from cache or creates one. After some more checks it then assigns -it the following properties:

-
    -
  • caller - The character BigGuy, in this example. This is a reference to the object executing the -command. The value of this depends on what type of object is calling the command; see the previous -section.

  • -
  • session - the Session Bob uses to connect to the game and control BigGuy (see also -previous section).

  • -
  • sessid - the unique id of self.session, for quick lookup.

  • -
  • account - the Account Bob (see previous section).

  • -
  • cmdstring - the matched key for the command. This would be look in our example.

  • -
  • args - this is the rest of the string, except the command name. So if the string entered was -look at sword, args would be ” at sword”. Note the space kept - Evennia would correctly -interpret lookat sword too. This is useful for things like /switches that should not use space. -In the MuxCommand class used for default commands, this space is stripped. Also see the -arg_regex property if you want to enforce a space to make lookat sword give a command-not-found -error.

  • -
  • obj - the game Object on which this command is defined. This need not be the caller, -but since look is a common (default) command, this is probably defined directly on BigGuy - so -obj will point to BigGuy. Otherwise obj could be an Account or any interactive object with -commands defined on it, like in the example of the “check time” command defined on a “Clock” object.

  • -
  • cmdset - this is a reference to the merged CmdSet (see below) from which this command was -matched. This variable is rarely used, it’s main use is for the [auto-help system](Help- -System#command-auto-help-system) (Advanced note: the merged cmdset need NOT be the same as -BigGuy.cmdset. The merged set can be a combination of the cmdsets from other objects in the room, -for example).

  • -
  • raw_string - this is the raw input coming from the user, without stripping any surrounding -whitespace. The only thing that is stripped is the ending newline marker.

  • -
-
-

Other useful utility methods:

-
    -
  • .get_help(caller, cmdset) - Get the help entry for this command. By default the arguments are -not -used, but they could be used to implement alternate help-display systems.

  • -
  • .client_width() - Shortcut for getting the client’s screen-width. Note that not all clients will -truthfully report this value - that case the settings.DEFAULT_SCREEN_WIDTH will be returned.

  • -
  • .styled_table(*args, **kwargs) - This returns an [EvTable](module- -evennia.utils.evtable) styled based on the -session calling this command. The args/kwargs are the same as for EvTable, except styling defaults -are set.

  • -
  • .styled_header, _footer, separator - These will produce styled decorations for -display to the user. They are useful for creating listings and forms with colors adjustable per- -user.

  • -
-
-
-
-

Defining your own command classes

-

Beyond the properties Evennia always assigns to the command at run-time (listed above), your job is -to define the following class properties:

-
    -
  • key (string) - the identifier for the command, like look. This should (ideally) be unique. A -key can consist of more than one word, like “press button” or “pull left lever”. Note that both -key and aliases below determine the identity of a command. So two commands are considered if -either matches. This is important for merging cmdsets described below.

  • -
  • aliases (optional list) - a list of alternate names for the command (["glance", "see", "l"]). -Same name rules as for key applies.

  • -
  • locks (string) - a lock definition, usually on the form cmd:<lockfuncs>. Locks is a -rather big topic, so until you learn more about locks, stick to giving the lockstring "cmd:all()" -to make the command available to everyone (if you don’t provide a lock string, this will be assigned -for you).

  • -
  • help_category (optional string) - setting this helps to structure the auto-help into categories. -If none is set, this will be set to General.

  • -
  • save_for_next (optional boolean). This defaults to False. If True, a copy of this command -object (along with any changes you have done to it) will be stored by the system and can be accessed -by the next command by retrieving self.caller.ndb.last_cmd. The next run command will either clear -or replace the storage.

  • -
  • arg_regex (optional raw string): Used to force the parser to limit itself and tell it when the -command-name ends and arguments begin (such as requiring this to be a space or a /switch). This is -done with a regular expression. See the arg_regex section for the details.

  • -
  • auto_help (optional boolean). Defaults to True. This allows for turning off the auto-help -system on a per-command basis. This could be useful if you -either want to write your help entries manually or hide the existence of a command from help’s -generated list.

  • -
  • is_exit (bool) - this marks the command as being used for an in-game exit. This is, by default, -set by all Exit objects and you should not need to set it manually unless you make your own Exit -system. It is used for optimization and allows the cmdhandler to easily disregard this command when -the cmdset has its no_exits flag set.

  • -
  • is_channel (bool)- this marks the command as being used for an in-game channel. This is, by -default, set by all Channel objects and you should not need to set it manually unless you make your -own Channel system. is used for optimization and allows the cmdhandler to easily disregard this -command when its cmdset has its no_channels flag set.

  • -
  • msg_all_sessions (bool): This affects the behavior of the Command.msg method. If unset -(default), calling self.msg(text) from the Command will always only send text to the Session that -actually triggered this Command. If set however, self.msg(text) will send to all Sessions relevant -to the object this Command sits on. Just which Sessions receives the text depends on the object and -the server’s MULTISESSION_MODE.

  • -
-

You should also implement at least two methods, parse() and func() (You could also implement -perm(), but that’s not needed unless you want to fundamentally change how access checks work).

-
    -
  • at_pre_cmd() is called very first on the command. If this function returns anything that -evaluates to True the command execution is aborted at this point.

  • -
  • parse() is intended to parse the arguments (self.args) of the function. You can do this in any -way you like, then store the result(s) in variable(s) on the command object itself (i.e. on self). -To take an example, the default mux-like system uses this method to detect “command switches” and -store them as a list in self.switches. Since the parsing is usually quite similar inside a command -scheme you should make parse() as generic as possible and then inherit from it rather than re- -implementing it over and over. In this way, the default MuxCommand class implements a parse() -for all child commands to use.

  • -
  • func() is called right after parse() and should make use of the pre-parsed input to actually -do whatever the command is supposed to do. This is the main body of the command. The return value -from this method will be returned from the execution as a Twisted Deferred.

  • -
  • at_post_cmd() is called after func() to handle eventual cleanup.

  • -
-

Finally, you should always make an informative doc -string (__doc__) at the top of your -class. This string is dynamically read by the Help System to create the help entry -for this command. You should decide on a way to format your help and stick to that.

-

Below is how you define a simple alternative “smile” command:

-
from evennia import Command
-
-class CmdSmile(Command):
-    """
-    A smile command
-
-    Usage:
-      smile [at] [<someone>]
-      grin [at] [<someone>]
-
-    Smiles to someone in your vicinity or to the room
-    in general.
-
-    (This initial string (the __doc__ string)
-    is also used to auto-generate the help
-    for this command)
-    """
-
-    key = "smile"
-    aliases = ["smile at", "grin", "grin at"]
-    locks = "cmd:all()"
-    help_category = "General"
-
-    def parse(self):
-        "Very trivial parser"
-        self.target = self.args.strip()
-
-    def func(self):
-        "This actually does things"
-        caller = self.caller
-
-        if not self.target or self.target == "here":
-            string = f"{caller.key} smiles"
-        else:
-            target = caller.search(self.target)
-            if not target:
-                return
-            string = f"{caller.key} smiles at {target.key}"
-
-        caller.location.msg_contents(string)
-
-
-
-

The power of having commands as classes and to separate parse() and func() -lies in the ability to inherit functionality without having to parse every -command individually. For example, as mentioned the default commands all -inherit from MuxCommand. MuxCommand implements its own version of parse() -that understands all the specifics of MUX-like commands. Almost none of the -default commands thus need to implement parse() at all, but can assume the -incoming string is already split up and parsed in suitable ways by its parent.

-

Before you can actually use the command in your game, you must now store it -within a command set. See the Command Sets page.

-
-
-

On arg_regex

-

The command parser is very general and does not require a space to end your command name. This means -that the alias : to emote can be used like :smiles without modification. It also means -getstone will get you the stone (unless there is a command specifically named getstone, then -that will be used). If you want to tell the parser to require a certain separator between the -command name and its arguments (so that get stone works but getstone gives you a ‘command not -found’ error) you can do so with the arg_regex property.

-

The arg_regex is a raw regular expression string. The -regex will be compiled by the system at runtime. This allows you to customize how the part -immediately following the command name (or alias) must look in order for the parser to match for -this command. Some examples:

-
    -
  • commandname argument (arg_regex = r"\s.+"): This forces the parser to require the command name -to be followed by one or more spaces. Whatever is entered after the space will be treated as an -argument. However, if you’d forget the space (like a command having no arguments), this would not -match commandname.

  • -
  • commandname or commandname argument (arg_regex = r"\s.+|$"): This makes both look and -look me work but lookme will not.

  • -
  • commandname/switches arguments (arg_regex = r"(?:^(?:\s+|\/).*$)|^$". If you are using -Evennia’s MuxCommand Command parent, you may wish to use this since it will allow /switches to -work as well as having or not having a space.

  • -
-

The arg_regex allows you to customize the behavior of your commands. You can put it in the parent -class of your command to customize all children of your Commands. However, you can also change the -base default behavior for all Commands by modifying settings.COMMAND_DEFAULT_ARG_REGEX.

-
-
-
-

Exiting a command

-

Normally you just use return in one of your Command class’ hook methods to exit that method. That -will however still fire the other hook methods of the Command in sequence. That’s usually what you -want but sometimes it may be useful to just abort the command, for example if you find some -unacceptable input in your parse method. To exit the command this way you can raise -evennia.InterruptCommand:

-
from evennia import InterruptCommand
-
-class MyCommand(Command):
-
-   # ...
-
-   def parse(self):
-       # ...
-       # if this fires, `func()` and `at_post_cmd` will not
-       # be called at all
-       raise InterruptCommand()
-
-
-
-
-
-

Pauses in commands

-

Sometimes you want to pause the execution of your command for a little while before continuing - -maybe you want to simulate a heavy swing taking some time to finish, maybe you want the echo of your -voice to return to you with an ever-longer delay. Since Evennia is running asynchronously, you -cannot use time.sleep() in your commands (or anywhere, really). If you do, the entire game will -be frozen for everyone! So don’t do that. Fortunately, Evennia offers a really quick syntax for -making pauses in commands.

-

In your func() method, you can use the yield keyword. This is a Python keyword that will freeze -the current execution of your command and wait for more before processing.

-
-

Note that you cannot just drop yield into any code and expect it to pause. Evennia will only -pause for you if you yield inside the Command’s func() method. Don’t expect it to work anywhere -else.

-
-

Here’s an example of a command using a small pause of five seconds between messages:

-
from evennia import Command
-
-class CmdWait(Command):
-    """
-    A dummy command to show how to wait
-
-    Usage:
-      wait
-
-    """
-
-    key = "wait"
-    locks = "cmd:all()"
-    help_category = "General"
-
-    def func(self):
-        """Command execution."""
-        self.msg("Starting to wait ...")
-        yield 5
-        self.msg("... This shows after 5 seconds. Waiting ...")
-        yield 2
-        self.msg("... And now another 2 seconds have passed.")
-
-
-

The important line is the yield 5 and yield 2 lines. It will tell Evennia to pause execution -here and not continue until the number of seconds given has passed.

-

There are two things to remember when using yield in your Command’s func method:

-
    -
  1. The paused state produced by the yield is not saved anywhere. So if the server reloads in the -middle of your command pausing, it will not resume when the server comes back up - the remainder -of the command will never fire. So be careful that you are not freezing the character or account in -a way that will not be cleared on reload.

  2. -
  3. If you use yield you may not also use return <values> in your func method. You’ll get an -error explaining this. This is due to how Python generators work. You can however use a “naked” -return just fine. Usually there is no need for func to return a value, but if you ever do need -to mix yield with a final return value in the same func, look at twisted.internet.defer.returnV -alue.

  4. -
-
-
-

Asking for user input

-

The yield keyword can also be used to ask for user input. Again you can’t -use Python’s input in your command, for it would freeze Evennia for -everyone while waiting for that user to input their text. Inside a Command’s -func method, the following syntax can also be used:

-
answer = yield("Your question")
-
-
-

Here’s a very simple example:

-
class CmdConfirm(Command):
-
-    """
-    A dummy command to show confirmation.
-
-    Usage:
-        confirm
-
-    """
-
-    key = "confirm"
-
-    def func(self):
-        answer = yield("Are you sure you want to go on?")
-        if answer.strip().lower() in ("yes", "y"):
-            self.msg("Yes!")
-        else:
-            self.msg("No!")
-
-
-

This time, when the user enters the ‘confirm’ command, she will be asked if she wants to go on. -Entering ‘yes’ or “y” (regardless of case) will give the first reply, otherwise the second reply -will show.

-
-

Note again that the yield keyword does not store state. If the game reloads while waiting for -the user to answer, the user will have to start over. It is not a good idea to use yield for -important or complex choices, a persistent EvMenu might be more appropriate in this case.

-
-
-
-

System commands

-

Note: This is an advanced topic. Skip it if this is your first time learning about commands.

-

There are several command-situations that are exceptional in the eyes of the server. What happens if -the account enters an empty string? What if the ‘command’ given is infact the name of a channel the -user wants to send a message to? Or if there are multiple command possibilities?

-

Such ‘special cases’ are handled by what’s called system commands. A system command is defined -in the same way as other commands, except that their name (key) must be set to one reserved by the -engine (the names are defined at the top of evennia/commands/cmdhandler.py). You can find (unused) -implementations of the system commands in evennia/commands/default/system_commands.py. Since these -are not (by default) included in any CmdSet they are not actually used, they are just there for -show. When the special situation occurs, Evennia will look through all valid CmdSets for your -custom system command. Only after that will it resort to its own, hard-coded implementation.

-

Here are the exceptional situations that triggers system commands. You can find the command keys -they use as properties on evennia.syscmdkeys:

-
    -
  • No input (syscmdkeys.CMD_NOINPUT) - the account just pressed return without any input. Default -is to do nothing, but it can be useful to do something here for certain implementations such as line -editors that interpret non-commands as text input (an empty line in the editing buffer).

  • -
  • Command not found (syscmdkeys.CMD_NOMATCH) - No matching command was found. Default is to -display the “Huh?” error message.

  • -
  • Several matching commands where found (syscmdkeys.CMD_MULTIMATCH) - Default is to show a list of -matches.

  • -
  • User is not allowed to execute the command (syscmdkeys.CMD_NOPERM) - Default is to display the -“Huh?” error message.

  • -
  • Channel (syscmdkeys.CMD_CHANNEL) - This is a Channel name of a channel you are -subscribing to - Default is to relay the command’s argument to that channel. Such commands are -created by the Comm system on the fly depending on your subscriptions.

  • -
  • New session connection (syscmdkeys.CMD_LOGINSTART). This command name should be put in the -settings.CMDSET_UNLOGGEDIN. Whenever a new connection is established, this command is always -called on the server (default is to show the login screen).

  • -
-

Below is an example of redefining what happens when the account doesn’t provide any input (e.g. just -presses return). Of course the new system command must be added to a cmdset as well before it will -work.

-
    from evennia import syscmdkeys, Command
-
-    class MyNoInputCommand(Command):
-        "Usage: Just press return, I dare you"
-        key = syscmdkeys.CMD_NOINPUT
-        def func(self):
-            self.caller.msg("Don't just press return like that, talk to me!")
-
-
-
-
-

Dynamic Commands

-

Note: This is an advanced topic.

-

Normally Commands are created as fixed classes and used without modification. There are however -situations when the exact key, alias or other properties is not possible (or impractical) to pre- -code (Exits is an example of this).

-

To create a command with a dynamic call signature, first define the command body normally in a class -(set your key, aliases to default values), then use the following call (assuming the command -class you created is named MyCommand):

-
     cmd = MyCommand(key="newname",
-                     aliases=["test", "test2"],
-                     locks="cmd:all()",
-                     ...)
-
-
-

All keyword arguments you give to the Command constructor will be stored as a property on the -command object. This will overload existing properties defined on the parent class.

-

Normally you would define your class and only overload things like key and aliases at run-time. -But you could in principle also send method objects (like func) as keyword arguments in order to -make your command completely customized at run-time.

-
-
-

Exits

-

Note: This is an advanced topic.

-

Exits are examples of the use of a Dynamic Command.

-

The functionality of Exit objects in Evennia is not hard-coded in the engine. Instead -Exits are normal typeclassed objects that auto-create a CmdSet on -themselves when they load. This cmdset has a single dynamically created Command with the same -properties (key, aliases and locks) as the Exit object itself. When entering the name of the exit, -this dynamic exit-command is triggered and (after access checks) moves the Character to the exit’s -destination. -Whereas you could customize the Exit object and its command to achieve completely different -behaviour, you will usually be fine just using the appropriate traverse_* hooks on the Exit -object. But if you are interested in really changing how things work under the hood, check out -evennia/objects/objects.py for how the Exit typeclass is set up.

-
-
-

Command instances are re-used

-

Note: This is an advanced topic that can be skipped when first learning about Commands.

-

A Command class sitting on an object is instantiated once and then re-used. So if you run a command -from object1 over and over you are in fact running the same command instance over and over (if you -run the same command but sitting on object2 however, it will be a different instance). This is -usually not something you’ll notice, since every time the Command-instance is used, all the relevant -properties on it will be overwritten. But armed with this knowledge you can implement some of the -more exotic command mechanism out there, like the command having a ‘memory’ of what you last entered -so that you can back-reference the previous arguments etc.

-
-

Note: On a server reload, all Commands are rebuilt and memory is flushed.

-
-

To show this in practice, consider this command:

-
class CmdTestID(Command):
-    key = "testid"
-
-    def func(self):
-
-        if not hasattr(self, "xval"):
-            self.xval = 0
-        self.xval += 1
-
-        self.caller.msg("Command memory ID: {} (xval={})".format(id(self), self.xval))
-
-
-
-

Adding this to the default character cmdset gives a result like this in-game:

-
> testid
-Command memory ID: 140313967648552 (xval=1)
-> testid
-Command memory ID: 140313967648552 (xval=2)
-> testid
-Command memory ID: 140313967648552 (xval=3)
-
-
-

Note how the in-memory address of the testid command never changes, but xval keeps ticking up.

-
-
-

Dynamically created commands

-

This is also an advanced topic.

-

Commands can also be created and added to a cmdset on the fly. Creating a class instance with a -keyword argument, will assign that keyword argument as a property on this paricular command:

-
class MyCmdSet(CmdSet):
-
-    def at_cmdset_creation(self):
-
-        self.add(MyCommand(myvar=1, foo="test")
-
-
-
-

This will start the MyCommand with myvar and foo set as properties (accessable as self.myvar -and self.foo). How they are used is up to the Command. Remember however the discussion from the -previous section - since the Command instance is re-used, those properties will remain on the -command as long as this cmdset and the object it sits is in memory (i.e. until the next reload). -Unless myvar and foo are somehow reset when the command runs, they can be modified and that -change will be remembered for subsequent uses of the command.

-
-
-

How commands actually work

-

Note: This is an advanced topic mainly of interest to server developers.

-

Any time the user sends text to Evennia, the server tries to figure out if the text entered -corresponds to a known command. This is how the command handler sequence looks for a logged-in user:

-
    -
  1. A user enters a string of text and presses enter.

  2. -
  3. The user’s Session determines the text is not some protocol-specific control sequence or OOB -command, but sends it on to the command handler.

  4. -
  5. Evennia’s command handler analyzes the Session and grabs eventual references to Account and -eventual puppeted Characters (these will be stored on the command object later). The caller -property is set appropriately.

  6. -
  7. If input is an empty string, resend command as CMD_NOINPUT. If no such command is found in -cmdset, ignore.

  8. -
  9. If command.key matches settings.IDLE_COMMAND, update timers but don’t do anything more.

  10. -
  11. The command handler gathers the CmdSets available to caller at this time:

    -
      -
    • The caller’s own currently active CmdSet.

    • -
    • CmdSets defined on the current account, if caller is a puppeted object.

    • -
    • CmdSets defined on the Session itself.

    • -
    • The active CmdSets of eventual objects in the same location (if any). This includes commands -on Exits.

    • -
    • Sets of dynamically created System commands representing available -Communications.

    • -
    -
  12. -
  13. All CmdSets of the same priority are merged together in groups. Grouping avoids order- -dependent issues of merging multiple same-prio sets onto lower ones.

  14. -
  15. All the grouped CmdSets are merged in reverse priority into one combined CmdSet according to -each set’s merge rules.

  16. -
  17. Evennia’s command parser takes the merged cmdset and matches each of its commands (using its -key and aliases) against the beginning of the string entered by caller. This produces a set of -candidates.

  18. -
  19. The cmd parser next rates the matches by how many characters they have and how many percent -matches the respective known command. Only if candidates cannot be separated will it return multiple -matches.

    -
      -
    • If multiple matches were returned, resend as CMD_MULTIMATCH. If no such command is found in -cmdset, return hard-coded list of matches.

    • -
    • If no match was found, resend as CMD_NOMATCH. If no such command is found in cmdset, give -hard-coded error message.

    • -
    -
  20. -
  21. If a single command was found by the parser, the correct command object is plucked out of -storage. This usually doesn’t mean a re-initialization.

  22. -
  23. It is checked that the caller actually has access to the command by validating the lockstring -of the command. If not, it is not considered as a suitable match and CMD_NOMATCH is triggered.

  24. -
  25. If the new command is tagged as a channel-command, resend as CMD_CHANNEL. If no such command -is found in cmdset, use hard-coded implementation.

  26. -
  27. Assign several useful variables to the command instance (see previous sections).

  28. -
  29. Call at_pre_command() on the command instance.

  30. -
  31. Call parse() on the command instance. This is fed the remainder of the string, after the name -of the command. It’s intended to pre-parse the string into a form useful for the func() method.

  32. -
  33. Call func() on the command instance. This is the functional body of the command, actually -doing useful things.

  34. -
  35. Call at_post_command() on the command instance.

  36. -
-
-
-

Assorted notes

-

The return value of Command.func() is a Twisted -deferred. -Evennia does not use this return value at all by default. If you do, you must -thus do so asynchronously, using callbacks.

-
     # in command class func()
-     def callback(ret, caller):
-        caller.msg("Returned is %s" % ret)
-     deferred = self.execute_command("longrunning")
-     deferred.addCallback(callback, self.caller)
-
-
-

This is probably not relevant to any but the most advanced/exotic designs (one might use it to -create a “nested” command structure for example).

-

The save_for_next class variable can be used to implement state-persistent commands. For example -it can make a command operate on “it”, where it is determined by what the previous command operated -on.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Communications.html b/docs/0.9.5/Communications.html deleted file mode 100644 index 2431dc46b2..0000000000 --- a/docs/0.9.5/Communications.html +++ /dev/null @@ -1,233 +0,0 @@ - - - - - - - - - Communications — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Communications

-

Apart from moving around in the game world and talking, players might need other forms of -communication. This is offered by Evennia’s Comm system. Stock evennia implements a ‘MUX-like’ -system of channels, but there is nothing stopping you from changing things to better suit your -taste.

-

Comms rely on two main database objects - Msg and Channel. There is also the TempMsg which -mimics the API of a Msg but has no connection to the database.

-
-

Msg

-

The Msg object is the basic unit of communication in Evennia. A message works a little like an -e-mail; it always has a sender (a Account) and one or more recipients. The recipients -may be either other Accounts, or a Channel (see below). You can mix recipients to send the message -to both Channels and Accounts if you like.

-

Once created, a Msg is normally not changed. It is peristently saved in the database. This allows -for comprehensive logging of communications. This could be useful for allowing senders/receivers to -have ‘mailboxes’ with the messages they want to keep.

-
-

Properties defined on Msg

-
    -
  • senders - this is a reference to one or many Account or Objects (normally -Characters) sending the message. This could also be an External Connection such as a message -coming in over IRC/IMC2 (see below). There is usually only one sender, but the types can also be -mixed in any combination.

  • -
  • receivers - a list of target Accounts, Objects (usually Characters) or -Channels to send the message to. The types of receivers can be mixed in any combination.

  • -
  • header - this is a text field for storing a title or header for the message.

  • -
  • message - the actual text being sent.

  • -
  • date_sent - when message was sent (auto-created).

  • -
  • locks - a lock definition.

  • -
  • hide_from - this can optionally hold a list of objects, accounts or channels to hide this Msg -from. This relationship is stored in the database primarily for optimization reasons, allowing for -quickly post-filter out messages not intended for a given target. There is no in-game methods for -setting this, it’s intended to be done in code.

  • -
-

You create new messages in code using evennia.create_message (or -evennia.utils.create.create_message.)

-
-
-
-

TempMsg

-

evennia.comms.models also has TempMsg which mimics the API of Msg but is not connected to the -database. TempMsgs are used by Evennia for channel messages by default. They can be used for any -system expecting a Msg but when you don’t actually want to save anything.

-
-
-

Channels

-

Channels are Typeclassed entities, which mean they can be easily extended and their -functionality modified. To change which channel typeclass Evennia uses, change -settings.BASE_CHANNEL_TYPECLASS.

-

Channels act as generic distributors of messages. Think of them as “switch boards” redistributing -Msg or TempMsg objects. Internally they hold a list of “listening” objects and any Msg (or -TempMsg) sent to the channel will be distributed out to all channel listeners. Channels have -Locks to limit who may listen and/or send messages through them.

-

The sending of text to a channel is handled by a dynamically created Command that -always have the same name as the channel. This is created for each channel by the global -ChannelHandler. The Channel command is added to the Account’s cmdset and normal command locks are -used to determine which channels are possible to write to. When subscribing to a channel, you can -then just write the channel name and the text to send.

-

The default ChannelCommand (which can be customized by pointing settings.CHANNEL_COMMAND_CLASS to -your own command), implements a few convenient features:

-
    -
  • It only sends TempMsg objects. Instead of storing individual entries in the database it instead -dumps channel output a file log in server/logs/channel_<channelname>.log. This is mainly for -practical reasons - we find one rarely need to query individual Msg objects at a later date. Just -stupidly dumping the log to a file also means a lot less database overhead.

  • -
  • It adds a /history switch to view the 20 last messages in the channel. These are read from the -end of the log file. One can also supply a line number to start further back in the file (but always -20 entries at a time). It’s used like this:

    -
     > public/history
    - > public/history 35
    -
    -
    -
  • -
-

There are two default channels created in stock Evennia - MudInfo and Public. MudInfo -receives server-related messages meant for Admins whereas Public is open to everyone to chat on -(all new accounts are automatically joined to it when logging in, it is useful for asking -questions). The default channels are defined by the DEFAULT_CHANNELS list (see -evennia/settings_default.py for more details).

-

You create new channels with evennia.create_channel (or evennia.utils.create.create_channel).

-

In code, messages are sent to a channel using the msg or tempmsg methods of channels:

-
 channel.msg(msgobj, header=None, senders=None, persistent=True)
-
-
-

The argument msgobj can be either a string, a previously constructed Msg or a TempMsg - in the -latter cases all the following keywords are ignored since the message objects already contains all -this information. If msgobj is a string, the other keywords are used for creating a new Msg or -TempMsg on the fly, depending on if persistent is set or not. By default, a TempMsg is emitted -for channel communication (since the default ChannelCommand instead logs to a file).

-
    # assume we have a 'sender' object and a channel named 'mychan'
-
-    # manually sending a message to a channel
-    mychan.msg("Hello!", senders=[sender])
-
-
-
-

Properties defined on Channel

-
    -
  • key - main name for channel

  • -
  • aliases - alternative native names for channels

  • -
  • desc - optional description of channel (seen in listings)

  • -
  • keep_log (bool) - if the channel should store messages (default)

  • -
  • locks - A lock definition. Channels normally use the access_types send, control and -listen.

  • -
-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Connection-Screen.html b/docs/0.9.5/Connection-Screen.html deleted file mode 100644 index 281e0efcd1..0000000000 --- a/docs/0.9.5/Connection-Screen.html +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - - - - Connection Screen — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Connection Screen

-

When you first connect to your game you are greeted by Evennia’s default connection screen.

-
==============================================================
- Welcome to Evennia, version Beta-ra4d24e8a3cab+!
-
- If you have an existing account, connect to it by typing:
-      connect <username> <password>
- If you need to create an account, type (without the <>'s):
-      create <username> <password>
-
- If you have spaces in your username, enclose it in quotes.
- Enter help for more info. look will re-show this screen.
-==============================================================
-
-
-

Effective, but not very exciting. You will most likely want to change this to be more unique for -your game. This is simple:

-
    -
  1. Edit mygame/server/conf/connection_screens.py.

  2. -
  3. Reload Evennia.

  4. -
-

Evennia will look into this module and locate all globally defined strings in it. These strings -are used as the text in your connection screen and are shown to the user at startup. If more than -one such string/screen is defined in the module, a random screen will be picked from among those -available.

-
-

Commands available at the Connection Screen

-

You can also customize the Commands available to use while the connection screen is -shown (connect, create etc). These commands are a bit special since when the screen is running -the account is not yet logged in. A command is made available at the login screen by adding them to -UnloggedinCmdSet in mygame/commands/default_cmdset.py. See Commands and the -tutorial section on how to add new commands to a default command set.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Continuous-Integration.html b/docs/0.9.5/Continuous-Integration.html deleted file mode 100644 index 7682b351ef..0000000000 --- a/docs/0.9.5/Continuous-Integration.html +++ /dev/null @@ -1,378 +0,0 @@ - - - - - - - - - Continuous Integration — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Continuous Integration

-

One of the advantages of Evennia over traditional MUSH development systems is that Evennia is -capable of integrating into enterprise level integration environments and source control. Because of -this, it can also be the subject of automation for additional convenience, allowing a more -streamlined development environment.

-
-

What is Continuous Integration?

-

Continuous Integration (CI) is a development -practice that requires developers to integrate code into a shared repository several times a day. -Each check-in is then verified by an automated build, allowing teams to detect problems early.

-

For Evennia, continuous integration allows an automated build process to:

-
    -
  • Pull down a latest build from Source Control.

  • -
  • Run migrations on the backing SQL database.

  • -
  • Automate additional unique tasks for that project.

  • -
  • Run unit tests.

  • -
  • Publish those files to the server directory

  • -
  • Reload the game.

  • -
-
-
-

Preparation

-

To prepare a CI environment for your MU*, it will be necessary to set up some prerequisite -software for your server.

-

Among those you will need:

-
    -
  • A Continuous Integration Environment.

    - -
  • -
  • Source Control

    -
      -
    • This could be Git or SVN or any other available SC.

    • -
    -
  • -
-
-
-

Linux TeamCity Setup

-

For this part of the guide, an example setup will be provided for administrators running a TeamCity -build integration environment on Linux.

-

After meeting the preparation steps for your specific environment, log on to your teamcity interface -at http://<your server>:8111/.

-

Create a new project named “Evennia” and in it construct a new template called continuous- -integration.

-
-

A Quick Overview

-

Templates are fancy objects in TeamCity that allow an administrator to define build steps that are -shared between one or more build projects. Assigning a VCS Root (Source Control) is unnecessary at -this stage, primarily you’ll be worrying about the build steps and your default parameters (both -visible on the tabs to the left.)

-
-
-

Template Setup

-

In this template, you’ll be outlining the steps necessary to build your specific game. (A number of -sample scripts are provided under this section below!) Click Build Steps and prepare your general -flow. For this example, we will be doing a few basic example steps:

-
    -
  • Transforming the Settings.py file

    -
      -
    • We do this to update ports or other information that make your production environment unique -from your development environment.

    • -
    -
  • -
  • Making migrations and migrating the game database.

  • -
  • Publishing the game files.

  • -
  • Reloading the server.

  • -
-

For each step we’ll being use the “Command Line Runner” (a fancy name for a shell script executor).

-
    -
  • Create a build step with the name: Transform Configuration

  • -
  • For the script add:

    -
    #!/bin/bash
    -# Replaces the game configuration with one
    -# appropriate for this deployment.
    -
    -CONFIG="%system.teamcity.build.checkoutDir%/server/conf/settings.py"
    -MYCONF="%system.teamcity.build.checkoutDir%/server/conf/my.cnf"
    -
    -sed -e 's/TELNET_PORTS = [4000]/TELNET_PORTS = [%game.ports%]/g' "$CONFIG" > "$CONFIG".tmp && mv
    -
    -
    -
  • -
-

\(CONFIG".tmp "\)CONFIG” -sed -e ‘s/WEBSERVER_PORTS = [(4001, 4002)]/WEBSERVER_PORTS = [%game.webports%]/g’ “\(CONFIG" > -"\)CONFIG”.tmp && mv “\(CONFIG".tmp "\)CONFIG”

-
# settings.py MySQL DB configuration
-echo Configuring Game Database...
-echo "" >> "$CONFIG"
-echo "######################################################################" >> "$CONFIG"
-echo "# MySQL Database Configuration" >> "$CONFIG"
-echo "######################################################################" >> "$CONFIG"
-
-echo "DATABASES = {" >> "$CONFIG"
-echo "   'default': {" >> "$CONFIG"
-echo "       'ENGINE': 'django.db.backends.mysql'," >> "$CONFIG"
-echo "       'OPTIONS': {" >> "$CONFIG"
-echo "           'read_default_file': 'server/conf/my.cnf'," >> "$CONFIG"
-echo "       }," >> "$CONFIG"
-echo "   }" >> "$CONFIG"
-echo "}" >> "$CONFIG"
-
-# Create the My.CNF file.
-echo "[client]" >> "$MYCONF"
-echo "database = %mysql.db%" >> "$MYCONF"
-echo "user = %mysql.user%" >> "$MYCONF"
-echo "password = %mysql.pass%" >> "$MYCONF"
-echo "default-character-set = utf8" >> "$MYCONF"
-```
-
-
-

If you look at the parameters side of the page after saving this script, you’ll notice that some new -parameters have been populated for you. This is because we’ve included new teamcity configuration -parameters that are populated when the build itself is ran. When creating projects that inherit this -template, we’ll be able to fill in or override those parameters for project-specific configuration.

-
    -
  • Go ahead and create another build step called “Make Database Migration”

    -
      -
    • If you’re using SQLLite on your game, it will be prudent to change working directory on this -step to: %game.dir%

    • -
    -
  • -
  • In this script include:

    -
    #!/bin/bash
    -# Update the DB migration
    -
    -LOGDIR="server/logs"
    -
    -. %evenv.dir%/bin/activate
    -
    -# Check that the logs directory exists.
    -if [ ! -d "$LOGDIR" ]; then
    -  # Control will enter here if $LOGDIR doesn't exist.
    -  mkdir "$LOGDIR"
    -fi
    -
    -evennia makemigrations
    -
    -
    -
  • -
  • Create yet another build step, this time named: “Execute Database Migration”:

    -
      -
    • If you’re using SQLLite on your game, it will be prudent to change working directory on this -step to: %game.dir%

      -
      #!/bin/bash
      -# Apply the database migration.
      -
      -LOGDIR="server/logs"
      -
      -. %evenv.dir%/bin/activate
      -
      -# Check that the logs directory exists.
      -if [ ! -d "$LOGDIR" ]; then
      -  # Control will enter here if $LOGDIR doesn't exist.
      -  mkdir "$LOGDIR"
      -fi
      -
      -evennia migrate
      -
      -
      -
    • -
    -
  • -
-

Our next build step is where we actually publish our build. Up until now, all work on game has been -done in a ‘work’ directory on TeamCity’s build agent. From that directory we will now copy our files -to where our game actually exists on the local server.

-
    -
  • Create a new build step called “Publish Build”:

    -
      -
    • If you’re using SQLLite on your game, be sure to order this step ABOVE the Database Migration -steps. The build order will matter!

      -
      #!/bin/bash
      -# Publishes the build to the proper build directory.
      -
      -DIRECTORY="%game.dir%"
      -
      -if [ ! -d "$DIRECTORY" ]; then
      -  # Control will enter here if $DIRECTORY doesn't exist.
      -  mkdir "$DIRECTORY"
      -fi
      -
      -# Copy all the files.
      -cp -ruv %teamcity.build.checkoutDir%/* "$DIRECTORY"
      -chmod -R 775 "$DIRECTORY"
      -
      -
      -
    • -
    -
  • -
-

Finally the last script will reload our game for us.

-
    -
  • Create a new script called “Reload Game”:

    -
      -
    • The working directory on this build step will be: %game.dir%

      -
      #!/bin/bash
      -# Apply the database migration.
      -
      -LOGDIR="server/logs"
      -PIDDIR="server/server.pid"
      -
      -. %evenv.dir%/bin/activate
      -
      -# Check that the logs directory exists.
      -if [ ! -d "$LOGDIR" ]; then
      -  # Control will enter here if $LOGDIR doesn't exist.
      -  mkdir "$LOGDIR"
      -fi
      -
      -# Check that the server is running.
      -if [ -d "$PIDDIR" ]; then
      -  # Control will enter here if the game is running.
      -  evennia reload
      -fi
      -
      -
      -
    • -
    -
  • -
-

Now the template is ready for use! It would be useful this time to revisit the parameters page and -set the evenv parameter to the directory where your virtualenv exists: IE “/srv/mush/evenv”.

-
-
-

Creating the Project

-

Now it’s time for the last few steps to set up a CI environment.

-
    -
  • Return to the Evennia Project overview/administration page.

  • -
  • Create a new Sub-Project called “Production”

    -
      -
    • This will be the category that holds our actual game.

    • -
    -
  • -
  • Create a new Build Configuration in Production with the name of your MUSH.

    -
      -
    • Base this configuration off of the continuous-integration template we made earlier.

    • -
    -
  • -
  • In the build configuration, enter VCS roots and create a new VCS root that points to the -branch/version control that you are using.

  • -
  • Go to the parameters page and fill in the undefined parameters for your specific configuration.

  • -
  • If you wish for the CI to run every time a commit is made, go to the VCS triggers and add one for -“On Every Commit”.

  • -
-

And you’re done! At this point, you can return to the project overview page and queue a new build -for your game. If everything was set up correctly, the build will complete successfully. Additional -build steps could be added or removed at this point, adding some features like Unit Testing or more!

-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Contributing-Docs.html b/docs/0.9.5/Contributing-Docs.html deleted file mode 100644 index 248acc3f72..0000000000 --- a/docs/0.9.5/Contributing-Docs.html +++ /dev/null @@ -1,819 +0,0 @@ - - - - - - - - - Contributing to Evennia Docs — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - - -
-
-
-
- -
-

Contributing to Evennia Docs

-
-

Warning

-

This system is still WIP and many things are bound to change!

-
-

Contributing to the docs is is like contributing to the rest of Evennia: Check out the branch of Evennia -you want to edit the documentation for. Create your own work-branch, make your changes to files -in evennia/docs/source/ and make a PR for it!

-

The documentation source files are *.md (Markdown) files found in evennia/docs/source/. -Markdown files are simple text files that can be edited with a normal text editor. They can also -contain raw HTML directives (but that is very rarely needed). They use -the Markdown syntax with MyST extensions.

-
-

Important

-

You do not need to be able to test/build the docs locally to contribute a documentation PR. -We’ll resolve any issues when we merge and build documentation. If you still want to build -the docs for yourself, instructions are at the end of this document.

-
-
-

Source file structure

-

The sources are organized into several rough categories, with only a few administrative documents -at the root of evennia/docs/source/. The folders are named in singular form since they will -primarily be accessed as link refs (e.g. Component/Accounts)

-
    -
  • source/Components/ are docs describing separate Evennia building blocks, that is, things -that you can import and use. This extends and elaborates on what can be found out by reading -the api docs themselves. Example are documentation for Accounts, Objects and Commands.

  • -
  • source/Concepts/ describes how larger-scale features of Evennia hang together - things that -can’t easily be broken down into one isolated component. This can be general descriptions of -how Models and Typeclasses interact to the path a message takes from the client to the server -and back.

  • -
  • source/Setup/ holds detailed docs on installing, running and maintaining the Evennia server and -the infrastructure around it.

  • -
  • source/Coding/ has help on how to interact with, use and navigate the Evennia codebase itself. -This also has non-Evennia-specific help on general development concepts and how to set up a sane -development environment.

  • -
  • source/Contribs/ holds documentation specifically for packages in the evennia/contribs/ folder. -Any contrib-specific tutorials will be found here instead of in Howtos

  • -
  • source/Howtos/ holds docs that describe how to achieve a specific goal, effect or -result in Evennia. This is often on a tutorial or FAQ form and will refer to the rest of the -documentation for further reading.

    -
      -
    • source/Howtos/Starting/ holds all documents part of the initial tutorial sequence.

    • -
    -
  • -
-

Other files and folders:

-
    -
  • source/api/ contains the auto-generated API documentation as .rst files. Don’t edit these -files manually, your changes will be lost. To refer to these files, use api: followed by -the Python path, for example [rpsystem contrib](evennia.contrib.rpsystem).

  • -
  • source/_templates and source/_static should not be modified unless adding a new doc-page -feature or changing the look of the HTML documentation.

  • -
  • conf.py holds the Sphinx configuration. It should usually not be modified except to update -the Evennia version on a new branch.

  • -
-
-
-
-

Editing syntax

-

The format used for Evennia’s docs is Markdown (Commonmark). While markdown -supports a few alternative forms for some of these, we try to stick to the below forms for consistency.

-
-

Italic/Bold

-

We generally use underscores for italics and double-asterisks for bold:

-
    -
  • _Italic text_ - Italic text

  • -
  • **Bold Text** - Bold text

  • -
-
-
-

Headings

-

We use # to indicate sections/headings. The more # the more of a sub-heading it is (will get -smaller and smaller font).

-
    -
  • # Heading

  • -
  • ## SubHeading

  • -
  • ### SubSubHeading

  • -
  • #### SubSubSubHeading

  • -
-
-

Don’t use the same heading/subheading name more than once in one page. While Markdown -does not prevent it, it will make it impossible to refer to that heading uniquely. -The Evennia documentation preparser will detect this and give you an error.

-
-
-
-

Lists

-

One can create both bullet-point lists and numbered lists:

-
- first bulletpoint
-- second bulletpoint
-- third bulletpoint
-
-
-
    -
  • first bulletpoint

  • -
  • second bulletpoint

  • -
  • third bulletpoint

  • -
-
1. Numbered point one
-2. Numbered point two
-3. Numbered point three
-
-
-
    -
  1. Numbered point one

  2. -
  3. Numbered point two

  4. -
  5. Numbered point three

  6. -
-
-
-

Blockquotes

-

A blockquote will create an indented block. It’s useful for emphasis and is -added by starting one or more lines with >. For ‘notes’ you can also use -an explicit Note.

-
> This is an important
-> thing to remember.
-
-
-
-

Note: This is an important -thing to remember.

-
-
- -
-

Tables

-

A table is done like this:

-
| heading1 | heading2 | heading3 |
-| --- | --- | --- | 
-| value1 | value2 | value3 |
-|  | value 4 | |
-| value 5 | value 6 | |
-
-
- - - - - - - - - - - - - - - - - - - - - -

heading1

heading2

heading3

value1

value2

value3

value 4

value 5

value 6

-

As seen, the Markdown syntax can be pretty sloppy (columns don’t need to line up) as long as you -include the heading separators and make sure to add the correct number of | on every line.

-
-
-

Verbatim text

-

It’s common to want to mark something to be displayed verbatim - just as written - without any -Markdown parsing. In running text, this is done using backticks (`), like `verbatim text` becomes -verbatim text.

-

If you want to put the verbatim text on its own line, you can do so easily by simply indenting -it 4 spaces (add empty lines on each side for readability too):

-
This is normal text
-
-    This is verbatim text
-
-This is normal text
-
-
-

Another way is to use triple-backticks:

-
```
-Everything within these backticks will be verbatim.
-
-```
-
-
-
-

Code blocks

-

A special ‘verbatim’ case is code examples - we want them to get code-highlighting for readability. -This is done by using the triple-backticks and specify which language we use:

-
```python
-from evennia import Command
-class CmdEcho(Command):
-    """
-    Usage: echo <arg>
-    """
-    key = "echo"
-    def func(self):
-        self.caller.msg(self.args.strip())
-```
-
-
-
from evennia import Command
-class CmdEcho(Command):
-  """
-  Usage: echo <arg>
-  """
-  key = "echo"
-  def func(self):
-    self.caller.msg(self.args.strip())
-
-
-
-
-
-

MyST directives

-

Markdown is easy to read and use. But while it does most of what we need, there are some things it’s -not quite as expressive as it needs to be. For this we use extended MyST syntax. This is -on the form

-
```{directive} any_options_here
-
-content
-
-```
-
-
-
-

Note

-

This kind of note may pop more than doing a > Note: ....

-
```{note}
-
-This is some noteworthy content that stretches over more than one line to show how the content indents.
-Also the important/warning notes indents like this.
-
-```
-
-
-
-

Note

-

This is some noteworthy content that stretches over more than one line to show how the content indents. -Also the important/warning notes indents like this.

-
-
-
-

Important

-

This is for particularly important and visible notes.

-
```{important}
-  This is important because it is!
-```
-
-
-
-
-

Important

-

This is important because it is!

-
-
-
-

Warning

-

A warning block is used to draw attention to particularly dangerous things, or features easy to -mess up.

-
```{warning}
-  Be careful about this ...
-```
-
-
-
-

Warning

-

Be careful about this …

-
-
-
-

Version changes and deprecations

-

These will show up as one-line warnings that suggest an added, changed or deprecated -feature beginning with particular version.

-
```{versionadded} 1.0
-```
-
-
-
-

New in version 1.0.

-
-
```{versionchanged} 1.0
-  How the feature changed with this version.
-```
-
-
-
-

Changed in version 1.0: How the feature changed with this version.

-
-
```{deprecated} 1.0
-```
-
-
-
-

Deprecated since version 1.0.

-
-
- -
-

A more flexible code block

-

The regular Markdown Python codeblock is usually enough but for more direct control over the style, one -can also use the {code-block} directive that takes a set of additional :options::

-
```{code-block} python
-:linenos:
-:emphasize-lines: 1-2,8
-:caption: An example code block
-:name: A full code block example
-
-from evennia import Command
-class CmdEcho(Command):
-    """
-    Usage: echo <arg>
-    """
-    key = "echo"
-    def func(self):
-        self.caller.msg(self.args.strip())
-```
-
-
-
-
An example code block
-
1
-2
-3
-4
-5
-6
-7
-8
from evennia import Command
-class CmdEcho(Command):
-    """
-    Usage: echo <arg>
-    """
-    key = "echo"
-    def func(self):
-        self.caller.msg(self.args.strip())
-
-
-
-

Here, :linenos: turns on line-numbers and :emphasize-lines: allows for emphasizing certain lines -in a different color. The :caption: shows an instructive text and :name: is used to reference -this -block through the link that will appear (so it should be unique for a given document).

-
-
-

eval-rst directive

-

As a last resort, we can also fall back to writing ReST directives directly:

-
```{eval-rst}
-
-    This will be evaluated as ReST.
-    All content must be indented.
-
-```
-
-
-

Within a ReST block, one must use Restructured Text syntax, which is not the -same as Markdown.

-
    -
  • Single backticks around text makes it italic.

  • -
  • Double backticks around text makes it verbatim.

  • -
  • A link is written within back-ticks, with an underscore at the end:

    -
    `python <www.python.org>`_
    -
    -
    -
  • -
-

Here is a ReST formatting cheat sheet.

-
-
-
-

Code docstrings

-

The source code docstrings will be parsed as Markdown. When writing a module docstring, you can use Markdown formatting, -including header levels down to 4th level (#### SubSubSubHeader). After the module documentation it’s -a good idea to end with four dashes ----. This will create a visible line between the documentation and the -class/function docs to follow.

-

All non-private classes, methods and functions must have a Google-style docstring, as per the -[Evennia coding style guidelines][github:evennia/CODING_STYLE.md]. This will then be correctly formatted -into pretty api docs.

-
-
-

Technical

-

Evennia leverages Sphinx with the MyST extension, which allows us -to write our docs in light-weight Markdown (more specifically CommonMark, like on github) -rather than Sphinx’ normal ReST syntax. The MyST parser allows for some extra syntax to -make us able to express more complex displays than plain Markdown can.

-

For autodoc-generation generation, we use the sphinx-napoleon -extension to understand our friendly Google-style docstrings used in classes and functions etc.

-
-
-
-

Building the docs locally

-

The sources in evennia/docs/source/ are built into a documentation using the -Sphinx static generator system. To do this locally you need to use a -system with make (Linux/Unix/Mac or Windows-WSL). Lacking -that, you could in principle also run the sphinx build-commands manually - read -the evennia/docs/Makefile to see which commands are run by the make-commands -referred to in this document.

-

You don’t necessarily have to build the docs locally to contribute. Markdown is -not hard and is very readable on its raw text-form.

-

You can furthermore get a good feel for how things will look using a -Markdown-viewer like Grip. Editors like ReText or IDE’s like -PyCharm also have native Markdown previews. Building the docs locally is -however the only way to make sure the outcome is exactly as you expect. The process -will also find any mistakes you made, like making a typo in a link.

-
-

Building only the main documentation

-

This is the fastest way to compile and view your changes. It will only build -the main documentation pages and not the API auto-docs or versions. All is -done in your terminal/console.

-
    -
  • (Optional, but recommended): Activate a virtualenv with Python 3.7.

  • -
  • cd to into the evennia/docs folder.

  • -
  • Install the documentation-build requirements:

    -
    make install
    -or
    -pip install -r requirements.txt
    -
    -
    -
  • -
  • Next, build the html-based documentation (re-run this in the future to build your changes):

    -
    make quick
    -
    -
    -
  • -
  • Note any errors from files you have edited.

  • -
  • The html-based documentation will appear in the new -folder evennia/docs/build/html/.

  • -
  • Use a web browser to open file://<path-to-folder>/evennia/docs/build/html/index.html and view -the docs. Note that you will get errors if clicking a link to the auto-docs, because you didn’t -build them!

  • -
-
-
-

Building the main documentation and API docs

-

The full documentation includes both the doc pages and the API documentation -generated from the Evennia source. For this you must install Evennia and -initialize a new game with a default database (you don’t need to have any server -running)

-
    -
  • It’s recommended that you use a virtualenv. Install your cloned version of Evennia into -by pointing to the repo folder (the one containing /docs):

    -
    pip install -e evennia
    -
    -
    -
  • -
  • Make sure you are in the parent folder containing your evennia/ repo (so two levels -up from evennia/docs/).

  • -
  • Create a new game folder called exactly gamedir at the same level as your evennia -repo with

    -
    evennia --init gamedir
    -
    -
    -
  • -
  • Then cd into it and create a new, empty database. You don’t need to start the -game or do any further changes after this.

    -
    evennia migrate
    -
    -
    -
  • -
  • This is how the structure should look at this point:

    -
      (top)
    -  |
    -  ----- evennia/  (the top-level folder, containing docs/)
    -  |
    -  ----- gamedir/
    -
    -
    -
  • -
-

(If you are already working on a game, you may of course have your ‘real’ game folder there as -well. We won’t touch that.)

-
    -
  • Go to evennia/docs/ and install the doc-building requirements (you only need to do this once):

    -
    make install
    -or
    -pip install -r requirements.txt
    -
    -
    -
  • -
  • Finally, build the full documentation, including the auto-docs:

    -
    make local
    -
    -
    -
  • -
  • The rendered files will appear in a new folder evennia/docs/build/html/. -Note any errors from files you have edited.

  • -
  • Point your web browser to file://<path-to-folder>/evennia/docs/build/html/index.html to -view the full docs.

  • -
-
-

Building with another gamedir

-

If you for some reason want to use another location of your gamedir/, or want it -named something else (maybe you already use the name ‘gamedir’ for your development …), -you can do so by setting the EVGAMEDIR environment variable to the absolute path -of your alternative game dir. For example:

-
EVGAMEDIR=/my/path/to/mygamedir make local
-
-
-
-
-
-

Building for release

-

The full Evennia documentation contains docs from many Evennia -versions, old and new. This is done by pulling documentation from Evennia’s old release -branches and building them all so readers can choose which one to view. Only -specific official Evennia branches will be built, so you can’t use this to -build your own testing branch.

-
    -
  • All local changes must have been committed to git first, since the versioned -docs are built by looking at the git tree.

  • -
  • To build for local checking, run (mv stands for “multi-version”):

    -
    make mv-local
    -
    -
    -
  • -
-

This is as close to the ‘real’ version of the docs as you can get locally. The different versions -will be found under evennia/docs/build/versions/. During deploy a symlink latest will point -to the latest version of the docs.

-
-

Release

-

Releasing the official docs requires git-push access the the Evennia gh-pages branch -on github. So there is no risk of you releasing your local changes accidentally.

-
    -
  • To deploy docs in two steps

    -
    make mv-local
    -make deploy
    -
    -
    -
  • -
  • If you know what you are doing you can also do build + deploy in one step:

    -
    make release
    -
    -
    -
  • -
-

After deployment finishes, the updated live documentation will be -available at https://evennia.github.io/evennia/latest/.

-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Contributing.html b/docs/0.9.5/Contributing.html deleted file mode 100644 index 903c8777f1..0000000000 --- a/docs/0.9.5/Contributing.html +++ /dev/null @@ -1,232 +0,0 @@ - - - - - - - - - Contributing — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Contributing

-

Wanna help out? Great! Here’s how.

-
-

Spreading the word

-

Even if you are not keen on working on the server code yourself, just spreading the word is a big -help - it will help attract more people which leads to more feedback, motivation and interest. -Consider writing about Evennia on your blog or in your favorite (relevant) forum. Write a review -somewhere (good or bad, we like feedback either way). Rate it on places like ohloh. Talk -about it to your friends … that kind of thing.

-
-
-

Donations

-

The best way to support Evennia is to become an Evennia patron. Evennia is a free, -open-source project and any monetary donations you want to offer are completely voluntary. See it as -a way of announcing that you appreciate the work done - a tip of the hat! A patron donates a -(usually small) sum every month to show continued support. If this is not your thing you can also -show your appreciation via a one-time donation (this is a PayPal link but you don’t need -PayPal yourself).

-
-
-

Help with Documentation

-

Evennia depends heavily on good documentation and we are always looking for extra eyes and hands to -improve it. Even small things such as fixing typos are a great help!

-

The documentation is a wiki and as long as you have a GitHub account you can edit it. It can be a -good idea to discuss in the chat or forums if you want to add new pages/tutorials. Otherwise, it -goes a long way just pointing out wiki errors so we can fix them (in an Issue or just over -chat/forum).

-
-
-

Contributing through a forked repository

-

We always need more eyes and hands on the code. Even if you don’t feel confident with tackling a -[bug or feature][issues], just correcting typos, adjusting formatting or simply using the thing -and reporting when stuff doesn’t make sense helps us a lot.

-

The most elegant way to contribute code to Evennia is to use GitHub to create a fork of the -Evennia repository and make your changes to that. Refer to the [Forking Evennia](Version- -Control#forking-evennia) version -control instructions for detailed instructions.

-

Once you have a fork set up, you can not only work on your own game in a separate branch, you can -also commit your fixes to Evennia itself. Make separate branches for all Evennia additions you do - -don’t edit your local master or develop branches directly. It will make your life a lot easier. -If you have a change that you think is suitable for the main Evennia repository, you issue a [Pull -Request][pullrequest]. This will let Evennia devs know you have stuff to share. Bug fixes should -generally be done against the master branch of Evennia, while new features/contribs should go into -the develop branch. If you are unsure, just pick one and we’ll figure it out.

-
-
-

Contributing with Patches

-

To help with Evennia development it’s recommended to do so using a fork repository as described -above. But for small, well isolated fixes you are also welcome to submit your suggested Evennia -fixes/addendums as a [patch][patch].

-

You can include your patch in an Issue or a Mailing list post. Please avoid pasting the full patch -text directly in your post though, best is to use a site like Pastebin and -just supply the link.

-
-
-

Contributing with Contribs

-

While Evennia’s core is pretty much game-agnostic, it also has a contrib/ directory. The contrib -directory contains game systems that are specialized or useful only to certain types of games. Users -are welcome to contribute to the contrib/ directory. Such contributions should always happen via a -Forked repository as described above.

-
    -
  • If you are unsure if your idea/code is suitable as a contrib, ask the devs before putting any -work into it. This can also be a good idea in order to not duplicate efforts. This can also act as -a check that your implementation idea is sound. We are, for example, unlikely to accept contribs -that require large modifications of the game directory structure.

  • -
  • If your code is intended primarily as an example or shows a concept/principle rather than a -working system, it is probably not suitable for contrib/. You are instead welcome to use it as -part of a [new tutorial][tutorials]!

  • -
  • The code should ideally be contained within a single Python module. But if the contribution is -large this may not be practical and it should instead be grouped in its own subdirectory (not as -loose modules).

  • -
  • The contribution should preferably be isolated (only make use of core Evennia) so it can easily be -dropped into use. If it does depend on other contribs or third-party modules, these must be clearly -documented and part of the installation instructions.

  • -
  • The code itself should follow Evennia’s [Code style guidelines][codestyle].

  • -
  • The code must be well documented as described in our documentation style -guide. Expect that your -code will be read and should be possible to understand by others. Include comments as well as a -header in all modules. If a single file, the header should include info about how to include the -contrib in a game (installation instructions). If stored in a subdirectory, this info should go into -a new README.md file within that directory.

  • -
  • Within reason, your contribution should be designed as genre-agnostic as possible. Limit the -amount of game-style-specific code. Assume your code will be applied to a very different game than -you had in mind when creating it.

  • -
  • To make the licensing situation clear we assume all contributions are released with the same -license as Evennia. If this is not possible for some reason, talk to us and we’ll -handle it on a case-by-case basis.

  • -
  • Your contribution must be covered by unit tests. Having unit tests will both help -make your code more stable and make sure small changes does not break it without it being noticed, -it will also help us test its functionality and merge it quicker. If your contribution is a single -module, you can add your unit tests to evennia/contribs/tests.py. If your contribution is bigger -and in its own sub-directory you could just put the tests in your own tests.py file (Evennia will -find it automatically).

  • -
  • Merging of your code into Evennia is not guaranteed. Be ready to receive feedback and to be asked -to make corrections or fix bugs. Furthermore, merging a contrib means the Evennia project takes on -the responsibility of maintaining and supporting it. For various reasons this may be deemed to be -beyond our manpower. However, if your code were to not be accepted for merger for some reason, we -will instead add a link to your online repository so people can still find and use your work if they -want.

  • -
-

pO1X1jbKiv_- -UBBFWIuVDEZxC0M_2pM6ywO&dispatch=5885d80a13c0db1f8e263663d3faee8d66f31424b43e9a70645c907a6cbd8fb4 -[forking]: https://github.com/evennia/evennia/wiki/Version-Control#wiki-forking-from-evennia -[pullrequest]: https://github.com/evennia/evennia/pulls -[issues]: https://github.com/evennia/evennia/issues -[patch]: https://secure.wikimedia.org/wikipedia/en/wiki/Patch_(computing) -[codestyle]: https://github.com/evennia/evennia/blob/master/CODING_STYLE.md -[tutorials]: https://github.com/evennia/evennia/wiki/Tutorials

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Coordinates.html b/docs/0.9.5/Coordinates.html deleted file mode 100644 index 902f29920e..0000000000 --- a/docs/0.9.5/Coordinates.html +++ /dev/null @@ -1,455 +0,0 @@ - - - - - - - - - Coordinates — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Coordinates

-
-
-

Adding room coordinates in your game

-

This tutorial is moderately difficult in content. You might want to be familiar and at ease with -some Python concepts (like properties) and possibly Django concepts (like queries), although this -tutorial will try to walk you through the process and give enough explanations each time. If you -don’t feel very confident with math, don’t hesitate to pause, go to the example section, which shows -a tiny map, and try to walk around the code or read the explanation.

-

Evennia doesn’t have a coordinate system by default. Rooms and other objects are linked by location -and content:

-
    -
  • An object can be in a location, that is, another object. Like an exit in a room.

  • -
  • An object can access its content. A room can see what objects uses it as location (that would -include exits, rooms, characters and so on).

  • -
-

This system allows for a lot of flexibility and, fortunately, can be extended by other systems. -Here, I offer you a way to add coordinates to every room in a way most compliant with Evennia -design. This will also show you how to use coordinates, find rooms around a given point for -instance.

-
-

Coordinates as tags

-

The first concept might be the most surprising at first glance: we will create coordinates as -tags.

-
-

Why not attributes, wouldn’t that be easier?

-
-

It would. We could just do something like room.db.x = 3. The advantage of using tags is that it -will be easy and effective to search. Although this might not seem like a huge advantage right now, -with a database of thousands of rooms, it might make a difference, particularly if you have a lot of -things based on coordinates.

-

Rather than giving you a step-by-step process, I’ll show you the code. Notice that we use -properties to easily access and update coordinates. This is a Pythonic approach. Here’s our first -Room class, that you can modify in typeclasses/rooms.py:

-
# in typeclasses/rooms.py
-
-from evennia import DefaultRoom
-
-class Room(DefaultRoom):
-    """
-    Rooms are like any Object, except their location is None
-    (which is default). They also use basetype_setup() to
-    add locks so they cannot be puppeted or picked up.
-    (to change that, use at_object_creation instead)
-
-    See examples/object.py for a list of
-    properties and methods available on all Objects.
-    """
-
-    @property
-    def x(self):
-        """Return the X coordinate or None."""
-        x = self.tags.get(category="coordx")
-        return int(x) if isinstance(x, str) else None
-
-    @x.setter
-    def x(self, x):
-        """Change the X coordinate."""
-        old = self.tags.get(category="coordx")
-        if old is not None:
-            self.tags.remove(old, category="coordx")
-        if x is not None:
-            self.tags.add(str(x), category="coordx")
-
-    @property
-    def y(self):
-        """Return the Y coordinate or None."""
-        y = self.tags.get(category="coordy")
-        return int(y) if isinstance(y, str) else None
-
-    @y.setter
-    def y(self, y):
-        """Change the Y coordinate."""
-        old = self.tags.get(category="coordy")
-        if old is not None:
-            self.tags.remove(old, category="coordy")
-        if y is not None:
-            self.tags.add(str(y), category="coordy")
-
-    @property
-    def z(self):
-        """Return the Z coordinate or None."""
-        z = self.tags.get(category="coordz")
-        return int(z) if isinstance(z, str) else None
-
-    @z.setter
-    def z(self, z):
-        """Change the Z coordinate."""
-        old = self.tags.get(category="coordz")
-        if old is not None:
-            self.tags.remove(old, category="coordz")
-        if z is not None:
-            self.tags.add(str(z), category="coordz")
-
-
-

If you aren’t familiar with the concept of properties in Python, I encourage you to read a good -tutorial on the subject. This article on Python properties -is well-explained and should help you understand the idea.

-

Let’s look at our properties for x. First of all is the read property.

-
    @property
-    def x(self):
-        """Return the X coordinate or None."""
-        x = self.tags.get(category="coordx")
-        return int(x) if isinstance(x, str) else None
-
-
-

What it does is pretty simple:

-
    -
  1. It gets the tag of category "coordx". It’s the tag category where we store our X coordinate. -The tags.get method will return None if the tag can’t be found.

  2. -
  3. We convert the value to an integer, if it’s a str. Remember that tags can only contain str, -so we’ll need to convert it.

  4. -
-
-

I thought tags couldn’t contain values?

-
-

Well, technically, they can’t: they’re either here or not. But using tag categories, as we have -done, we get a tag, knowing only its category. That’s the basic approach to coordinates in this -tutorial.

-

Now, let’s look at the method that will be called when we wish to set x in our room:

-
    @x.setter
-    def x(self, x):
-        """Change the X coordinate."""
-        old = self.tags.get(category="coordx")
-        if old is not None:
-            self.tags.remove(old, category="coordx")
-        if x is not None:
-            self.tags.add(str(x), category="coordx")
-
-
-
    -
  1. First, we remove the old X coordinate, if it exists. Otherwise, we’d end up with two tags in our -room with “coordx” as their category, which wouldn’t do at all.

  2. -
  3. Then we add the new tag, giving it the proper category.

  4. -
-
-

Now what?

-
-

If you add this code and reload your game, once you’re logged in with a character in a room as its -location, you can play around:

-
@py here.x
-@py here.x = 0
-@py here.y = 3
-@py here.z = -2
-@py here.z = None
-
-
-

The code might not be that easy to read, but you have to admit it’s fairly easy to use.

-
-
-

Some additional searches

-

Having coordinates is useful for several reasons:

-
    -
  1. It can help in shaping a truly logical world, in its geography, at least.

  2. -
  3. It can allow to look for specific rooms at given coordinates.

  4. -
  5. It can be good in order to quickly find the rooms around a location.

  6. -
  7. It can even be great in path-finding (finding the shortest path between two rooms).

  8. -
-

So far, our coordinate system can help with 1., but not much else. Here are some methods that we -could add to the Room typeclass. These methods will just be search methods. Notice that they are -class methods, since we want to get rooms.

-
-

Finding one room

-

First, a simple one: how to find a room at a given coordinate? Say, what is the room at X=0, Y=0, -Z=0?

-
class Room(DefaultRoom):
-    # ...
-    @classmethod
-    def get_room_at(cls, x, y, z):
-        """
-        Return the room at the given location or None if not found.
-
-        Args:
-            x (int): the X coord.
-            y (int): the Y coord.
-            z (int): the Z coord.
-
-        Return:
-            The room at this location (Room) or None if not found.
-
-        """
-        rooms = cls.objects.filter(
-                db_tags__db_key=str(x), db_tags__db_category="coordx").filter(
-                db_tags__db_key=str(y), db_tags__db_category="coordy").filter(
-                db_tags__db_key=str(z), db_tags__db_category="coordz")
-        if rooms:
-            return rooms[0]
-
-        return None
-
-
-

This solution includes a bit of Django -queries. -Basically, what we do is reach for the object manager and search for objects with the matching tags. -Again, don’t spend too much time worrying about the mechanism, the method is quite easy to use:

-
Room.get_room_at(5, 2, -3)
-
-
-

Notice that this is a class method: you will call it from Room (the class), not an instance. -Though you still can:

-
@py here.get_room_at(3, 8, 0)
-
-
-
-
-

Finding several rooms

-

Here’s another useful method that allows us to look for rooms around a given coordinate. This is -more advanced search and doing some calculation, beware! Look at the following section if you’re -lost.

-
from math import sqrt
-
-class Room(DefaultRoom):
-
-    # ...
-
-    @classmethod
-    def get_rooms_around(cls, x, y, z, distance):
-        """
-        Return the list of rooms around the given coordinates.
-
-        This method returns a list of tuples (distance, room) that
-        can easily be browsed.  This list is sorted by distance (the
-        closest room to the specified position is always at the top
-        of the list).
-
-        Args:
-            x (int): the X coord.
-            y (int): the Y coord.
-            z (int): the Z coord.
-            distance (int): the maximum distance to the specified position.
-
-        Returns:
-            A list of tuples containing the distance to the specified
-            position and the room at this distance.  Several rooms
-            can be at equal distance from the position.
-
-        """
-        # Performs a quick search to only get rooms in a square
-        x_r = list(reversed([str(x - i) for i in range(0, distance + 1)]))
-        x_r += [str(x + i) for i in range(1, distance + 1)]
-        y_r = list(reversed([str(y - i) for i in range(0, distance + 1)]))
-        y_r += [str(y + i) for i in range(1, distance + 1)]
-        z_r = list(reversed([str(z - i) for i in range(0, distance + 1)]))
-        z_r += [str(z + i) for i in range(1, distance + 1)]
-        wide = cls.objects.filter(
-                db_tags__db_key__in=x_r, db_tags__db_category="coordx").filter(
-                db_tags__db_key__in=y_r, db_tags__db_category="coordy").filter(
-                db_tags__db_key__in=z_r, db_tags__db_category="coordz")
-
-        # We now need to filter down this list to find out whether
-        # these rooms are really close enough, and at what distance
-        # In short: we change the square to a circle.
-        rooms = []
-        for room in wide:
-            x2 = int(room.tags.get(category="coordx"))
-            y2 = int(room.tags.get(category="coordy"))
-            z2 = int(room.tags.get(category="coordz"))
-            distance_to_room = sqrt(
-                    (x2 - x) ** 2 + (y2 - y) ** 2 + (z2 - z) ** 2)
-            if distance_to_room <= distance:
-                rooms.append((distance_to_room, room))
-
-        # Finally sort the rooms by distance
-        rooms.sort(key=lambda tup: tup[0])
-        return rooms
-
-
-

This gets more serious.

-
    -
  1. We have specified coordinates as parameters. We determine a broad range using the distance. -That is, for each coordinate, we create a list of possible matches. See the example below.

  2. -
  3. We then search for the rooms within this broader range. It gives us a square -around our location. Some rooms are definitely outside the range. Again, see the example below -to follow the logic.

  4. -
  5. We filter down the list and sort it by distance from the specified coordinates.

  6. -
-

Notice that we only search starting at step 2. Thus, the Django search doesn’t look and cache all -objects, just a wider range than what would be really necessary. This method returns a circle of -coordinates around a specified point. Django looks for a square. What wouldn’t fit in the circle -is removed at step 3, which is the only part that includes systematic calculation. This method is -optimized to be quick and efficient.

-
-
-

An example

-

An example might help. Consider this very simple map (a textual description follows):

-
4 A B C D
-3 E F G H
-2 I J K L
-1 M N O P
-  1 2 3 4
-
-
-

The X coordinates are given below. The Y coordinates are given on the left. This is a simple -square with 16 rooms: 4 on each line, 4 lines of them. All the rooms are identified by letters in -this example: the first line at the top has rooms A to D, the second E to H, the third I to L and -the fourth M to P. The bottom-left room, X=1 and Y=1, is M. The upper-right room X=4 and Y=4 is D.

-

So let’s say we want to find all the neighbors, distance 1, from the room J. J is at X=2, Y=2.

-

So we use:

-
Room.get_rooms_around(x=2, y=2, z=0, distance=1)
-# we'll assume a z coordinate of 0 for simplicity
-
-
-
    -
  1. First, this method gets all the rooms in a square around J. So it gets E F G, I J K, M N O. If -you want, draw the square around these coordinates to see what’s happening.

  2. -
  3. Next, we browse over this list and check the real distance between J (X=2, Y=2) and the room. -The four corners of the square are not in this circle. For instance, the distance between J and M -is not 1. If you draw a circle of center J and radius 1, you’ll notice that the four corners of our -square (E, G, M and O) are not in this circle. So we remove them.

  4. -
  5. We sort by distance from J.

  6. -
-

So in the end we might obtain something like this:

-
[
-    (0, J), # yes, J is part of this circle after all, with a distance of 0
-    (1, F),
-    (1, I),
-    (1, K),
-    (1, N),
-]
-
-
-

You can try with more examples if you want to see this in action.

-
-
-

To conclude

-

You can definitely use this system to map other objects, not just rooms. You can easily remove the -`Z coordinate too, if you simply need X and Y.

-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Custom-Protocols.html b/docs/0.9.5/Custom-Protocols.html deleted file mode 100644 index ddaacacd10..0000000000 --- a/docs/0.9.5/Custom-Protocols.html +++ /dev/null @@ -1,342 +0,0 @@ - - - - - - - - - Custom Protocols — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Custom Protocols

-

Note: This is considered an advanced topic and is mostly of interest to users planning to implement -their own custom client protocol.

-

A PortalSession is the basic data object representing an -external -connection to the Evennia Portal – usually a human player running a mud client -of some kind. The way they connect (the language the player’s client and Evennia use to talk to -each other) is called the connection Protocol. The most common such protocol for MUD:s is the -Telnet protocol. All Portal Sessions are stored and managed by the Portal’s sessionhandler.

-

It’s technically sometimes hard to separate the concept of PortalSession from the concept of -Protocol since both depend heavily on the other (they are often created as the same class). When -data flows through this part of the system, this is how it goes

-
# In the Portal
-You <->
-  Protocol + PortalSession <->
-    PortalSessionHandler <->
-      (AMP) <->
-        ServerSessionHandler <->
-          ServerSession <->
-            InputFunc
-
-
-

(See the Message Path for the bigger picture of how data flows through Evennia). The -parts that needs to be customized to make your own custom protocol is the Protocol + PortalSession -(which translates between data coming in/out over the wire to/from Evennia internal representation) -as well as the InputFunc (which handles incoming data).

-
-

Adding custom Protocols

-

Evennia has a plugin-system that add the protocol as a new “service” to the application.

-

Take a look at evennia/server/portal/portal.py, notably the sections towards the end of that file. -These are where the various in-built services like telnet, ssh, webclient etc are added to the -Portal (there is an equivalent but shorter list in evennia/server/server.py).

-

To add a new service of your own (for example your own custom client protocol) to the Portal or -Server, look at mygame/server/conf/server_services_plugins and portal_services_plugins. By -default Evennia will look into these modules to find plugins. If you wanted to have it look for more -modules, you could do the following:

-
    # add to the Server
-    SERVER_SERVICES_PLUGIN_MODULES.append('server.conf.my_server_plugins')
-    # or, if you want to add to the Portal
-    PORTAL_SERVICES_PLUGIN_MODULES.append('server.conf.my_portal_plugins')
-
-
-

When adding a new connection you’ll most likely only need to add new things to the -PORTAL_SERVICES_PLUGIN_MODULES.

-

This module can contain whatever you need to define your protocol, but it must contain a function -start_plugin_services(app). This is called by the Portal as part of its upstart. The function -start_plugin_services must contain all startup code the server need. The app argument is a -reference to the Portal/Server application itself so the custom service can be added to it. The -function should not return anything.

-

This is how it looks:

-
    # mygame/server/conf/portal_services_plugins.py
-
-    # here the new Portal Twisted protocol is defined
-    class MyOwnFactory( ... ):
-       [...]
-
-    # some configs
-    MYPROC_ENABLED = True # convenient off-flag to avoid having to edit settings all the time
-    MY_PORT = 6666
-
-    def start_plugin_services(portal):
-        "This is called by the Portal during startup"
-         if not MYPROC_ENABLED:
-             return
-         # output to list this with the other services at startup
-         print("  myproc: %s" % MY_PORT)
-
-         # some setup (simple example)
-         factory = MyOwnFactory()
-         my_service = internet.TCPServer(MY_PORT, factory)
-         # all Evennia services must be uniquely named
-         my_service.setName("MyService")
-         # add to the main portal application
-         portal.services.addService(my_service)
-
-
-

Once the module is defined and targeted in settings, just reload the server and your new -protocol/services should start with the others.

-
-
-

Writing your own Protocol

-

Writing a stable communication protocol from scratch is not something we’ll cover here, it’s no -trivial task. The good news is that Twisted offers implementations of many common protocols, ready -for adapting.

-

Writing a protocol implementation in Twisted usually involves creating a class inheriting from an -already existing Twisted protocol class and from evennia.server.session.Session (multiple -inheritance), then overloading the methods that particular protocol uses to link them to the -Evennia-specific inputs.

-

Here’s a example to show the concept:

-
# In module that we'll later add to the system through PORTAL_SERVICE_PLUGIN_MODULES
-
-# pseudo code
-from twisted.something import TwistedClient
-# this class is used both for Portal- and Server Sessions
-from evennia.server.session import Session
-
-from evennia.server.portal.portalsessionhandler import PORTAL_SESSIONS
-
-class MyCustomClient(TwistedClient, Session):
-
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-        self.sessionhandler = PORTAL_SESSIONS
-
-    # these are methods we must know that TwistedClient uses for
-    # communication. Name and arguments could vary for different Twisted protocols
-    def onOpen(self, *args, **kwargs):
-        # let's say this is called when the client first connects
-
-        # we need to init the session and connect to the sessionhandler. The .factory
-        # is available through the Twisted parents
-
-        client_address = self.getClientAddress()  # get client address somehow
-
-        self.init_session("mycustom_protocol", client_address, self.factory.sessionhandler)
-        self.sessionhandler.connect(self)
-
-    def onClose(self, reason, *args, **kwargs):
-        # called when the client connection is dropped
-        # link to the Evennia equivalent
-        self.disconnect(reason)
-
-    def onMessage(self, indata, *args, **kwargs):
-        # called with incoming data
-        # convert as needed here
-        self.data_in(data=indata)
-
-    def sendMessage(self, outdata, *args, **kwargs):
-        # called to send data out
-        # modify if needed
-        super().sendMessage(self, outdata, *args, **kwargs)
-
-     # these are Evennia methods. They must all exist and look exactly like this
-     # The above twisted-methods call them and vice-versa. This connects the protocol
-     # the Evennia internals.
-     
-     def disconnect(self, reason=None):
-         """
-         Called when connection closes.
-         This can also be called directly by Evennia when manually closing the connection.
-         Do any cleanups here.
-         """
-         self.sessionhandler.disconnect(self)
-
-     def at_login(self):
-         """
-         Called when this session authenticates by the server (if applicable)
-         """
-
-     def data_in(self, **kwargs):
-         """
-         Data going into the server should go through this method. It
-         should pass data into `sessionhandler.data_in`. THis will be called
-         by the sessionhandler with the data it gets from the approrpriate
-         send_* method found later in this protocol.
-         """
-         self.sessionhandler.data_in(self, text=kwargs['data'])
-
-     def data_out(self, **kwargs):
-         """
-         Data going out from the server should go through this method. It should
-         hand off to the protocol's send method, whatever it's called.
-         """
-         # we assume we have a 'text' outputfunc
-         self.onMessage(kwargs['text'])
-
-     # 'outputfuncs' are defined as `send_<outputfunc_name>`. From in-code, they are called
-     # with `msg(outfunc_name=<data>)`.
-
-     def send_text(self, txt, *args, **kwargs):
-         """
-         Send text, used with e.g. `session.msg(text="foo")`
-         """
-         # we make use of the
-         self.data_out(text=txt)
-
-     def send_default(self, cmdname, *args, **kwargs):
-         """
-         Handles all outputfuncs without an explicit `send_*` method to handle them.
-         """
-         self.data_out(**{cmdname: str(args)})
-
-
-
-

The principle here is that the Twisted-specific methods are overridden to redirect inputs/outputs to -the Evennia-specific methods.

-
-

Sending data out

-

To send data out through this protocol, you’d need to get its Session and then you could e.g.

-
    session.msg(text="foo")
-
-
-

The message will pass through the system such that the sessionhandler will dig out the session and -check if it has a send_text method (it has). It will then pass the “foo” into that method, which -in our case means sending “foo” across the network.

-
-
-

Receiving data

-

Just because the protocol is there, does not mean Evennia knows what to do with it. An -Inputfunc must exist to receive it. In the case of the text input exemplified above, -Evennia alredy handles this input - it will parse it as a Command name followed by its inputs. So -handle that you need to simply add a cmdset with commands on your receiving Session (and/or the -Object/Character it is puppeting). If not you may need to add your own Inputfunc (see the -Inputfunc page for how to do this.

-

These might not be as clear-cut in all protocols, but the principle is there. These four basic -components - however they are accessed - links to the Portal Session, which is the actual common -interface between the different low-level protocols and Evennia.

-
-
-
-

Assorted notes

-

To take two examples, Evennia supports the telnet protocol as well as webclient, via ajax or -websockets. You’ll find that whereas telnet is a textbook example of a Twisted protocol as seen -above, the ajax protocol looks quite different due to how it interacts with the -webserver through long-polling (comet) style requests. All the necessary parts -mentioned above are still there, but by necessity implemented in very different -ways.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Customize-channels.html b/docs/0.9.5/Customize-channels.html deleted file mode 100644 index cbd381ae77..0000000000 --- a/docs/0.9.5/Customize-channels.html +++ /dev/null @@ -1,585 +0,0 @@ - - - - - - - - - Customize channels — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Customize channels

-
-
-

Channel commands in Evennia

-

By default, Evennia’s default channel commands are inspired by MUX. They all -begin with “c” followed by the action to perform (like “ccreate” or “cdesc”). -If this default seems strange to you compared to other Evennia commands that -rely on switches, you might want to check this tutorial out.

-

This tutorial will also give you insight into the workings of the channel system. -So it may be useful even if you don’t plan to make the exact changes shown here.

-
-

What we will try to do

-

Our mission: change the default channel commands to have a different syntax.

-

This tutorial will do the following changes:

-
    -
  • Remove all the default commands to handle channels.

  • -
  • Add a + and - command to join and leave a channel. So, assuming there is -a public channel on your game (most often the case), you could type +public -to join it and -public to leave it.

  • -
  • Group the commands to manipulate channels under the channel name, after a -switch. For instance, instead of writing cdesc public = My public channel, -you would write public/desc My public channel.

  • -
-
-

I listed removing the default Evennia commands as a first step in the -process. Actually, we’ll move it at the very bottom of the list, since we -still want to use them, we might get it wrong and rely on Evennia commands -for a while longer.

-
-
-
-

A command to join, another to leave

-

We’ll do the most simple task at first: create two commands, one to join a -channel, one to leave.

-
-

Why not have them as switches? public/join and public/leave for instance?

-
-

For security reasons, I will hide channels to which the caller is not -connected. It means that if the caller is not connected to the “public” -channel, he won’t be able to use the “public” command. This is somewhat -standard: if we create an administrator-only channel, we don’t want players to -try (or even know) the channel command. Again, you could design it a different -way should you want to.

-

First create a file named comms.py in your commands package. It’s -a rather logical place, since we’ll write different commands to handle -communication.

-

Okay, let’s add the first command to join a channel:

-
# in commands/comms.py
-from evennia.utils.search import search_channel
-from commands.command import Command
-
-class CmdConnect(Command):
-    """
-    Connect to a channel.
-    """
-
-    key = "+"
-    help_category = "Comms"
-    locks = "cmd:not pperm(channel_banned)"
-    auto_help = False
-
-    def func(self):
-        """Implement the command"""
-        caller = self.caller
-        args = self.args
-        if not args:
-            self.msg("Which channel do you want to connect to?")
-            return
-
-        channelname = self.args
-        channel = search_channel(channelname)
-        if not channel:
-            return
-
-        # Check permissions
-        if not channel.access(caller, 'listen'):
-            self.msg("%s: You are not allowed to listen to this channel." % channel.key)
-            return
-
-        # If not connected to the channel, try to connect
-        if not channel.has_connection(caller):
-            if not channel.connect(caller):
-                self.msg("%s: You are not allowed to join this channel." % channel.key)
-                return
-            else:
-                self.msg("You now are connected to the %s channel. " % channel.key.lower())
-        else:
-            self.msg("You already are connected to the %s channel. " % channel.key.lower())
-
-
-

Okay, let’s review this code, but if you’re used to Evennia commands, it shouldn’t be too strange:

-
    -
  1. We import search_channel. This is a little helper function that we will use to search for -channels by name and aliases, found in evennia.utils.search. It’s just more convenient.

  2. -
  3. Our class CmdConnect contains the body of our command to join a channel.

  4. -
  5. Notice the key of this command is simply "+". When you enter +something in the game, it will -try to find a command key +something. Failing that, it will look at other potential matches. -Evennia is smart enough to understand that when we type +something, + is the command key and -something is the command argument. This will, of course, fail if you have a command beginning by -+ conflicting with the CmdConnect key.

  6. -
  7. We have altered some class attributes, like auto_help. If you want to know what they do and -why they have changed here, you can check the documentation on commands.

  8. -
  9. In the command body, we begin by extracting the channel name. Remember that this name should be -in the command arguments (that is, in self.args). Following the same example, if a player enters -+something, self.args should contain "something". We use search_channel to see if this -channel exists.

  10. -
  11. We then check the access level of the channel, to see if the caller can listen to it (not -necessarily use it to speak, mind you, just listen to others speak, as these are two different locks -on Evennia).

  12. -
  13. Finally, we connect the caller if he’s not already connected to the channel. We use the -channel’s connect method to do this. Pretty straightforward eh?

  14. -
-

Now we’ll add a command to leave a channel. It’s almost the same, turned upside down:

-
class CmdDisconnect(Command):
-    """
-    Disconnect from a channel.
-    """
-
-    key = "-"
-    help_category = "Comms"
-    locks = "cmd:not pperm(channel_banned)"
-    auto_help = False
-
-    def func(self):
-        """Implement the command"""
-        caller = self.caller
-        args = self.args
-        if not args:
-            self.msg("Which channel do you want to disconnect from?")
-            return
-
-        channelname = self.args
-        channel = search_channel(channelname)
-        if not channel:
-            return
-
-        # If connected to the channel, try to disconnect
-        if channel.has_connection(caller):
-            if not channel.disconnect(caller):
-                self.msg("%s: You are not allowed to disconnect from this channel." % channel.key)
-                return
-            else:
-                self.msg("You stop listening to the %s channel. " % channel.key.lower())
-        else:
-            self.msg("You are not connected to the %s channel. " % channel.key.lower())
-
-
-

So far, you shouldn’t have trouble following what this command does: it’s -pretty much the same as the CmdConnect class in logic, though it accomplishes -the opposite. If you are connected to the channel public you could -disconnect from it using -public. Remember, you can use channel aliases too -(+pub and -pub will also work, assuming you have the alias pub on the -public channel).

-

It’s time to test this code, and to do so, you will need to add these two -commands. Here is a good time to say it: by default, Evennia connects accounts -to channels. Some other games (usually with a higher multisession mode) will -want to connect characters instead of accounts, so that several characters in -the same account can be connected to various channels. You can definitely add -these commands either in the AccountCmdSet or CharacterCmdSet, the caller -will be different and the command will add or remove accounts of characters. -If you decide to install these commands on the CharacterCmdSet, you might -have to disconnect your superuser account (account #1) from the channel before -joining it with your characters, as Evennia tends to subscribe all accounts -automatically if you don’t tell it otherwise.

-

So here’s an example of how to add these commands into your AccountCmdSet. -Edit the file commands/default_cmdsets.py to change a few things:

-
# In commands/default_cmdsets.py
-from evennia import default_cmds
-from commands.comms import CmdConnect, CmdDisconnect
-
-
-# ... Skip to the AccountCmdSet class ...
-
-class AccountCmdSet(default_cmds.AccountCmdSet):
-    """
-    This is the cmdset available to the Account at all times. It is
-    combined with the `CharacterCmdSet` when the Account puppets a
-    Character. It holds game-account-specific commands, channel
-    commands, etc.
-    """
-    key = "DefaultAccount"
-
-    def at_cmdset_creation(self):
-        """
-        Populates the cmdset
-        """
-        super().at_cmdset_creation()
-
-        # Channel commands
-        self.add(CmdConnect())
-        self.add(CmdDisconnect())
-
-
-

Save, reload your game, and you should be able to use +public and -public -now!

-
-
-

A generic channel command with switches

-

It’s time to dive a little deeper into channel processing. What happens in -Evennia when a player enters public Hello everybody!?

-

Like exits, channels are a particular command that Evennia automatically -creates and attaches to individual channels. So when you enter public message in your game, Evennia calls the public command.

-
-

But I didn’t add any public command…

-
-

Evennia will just create these commands automatically based on the existing -channels. The base command is the command we’ll need to edit.

-
-

Why edit it? It works just fine to talk.

-
-

Unfortunately, if we want to add switches to our channel names, we’ll have to -edit this command. It’s not too hard, however, we’ll just start writing a -standard command with minor twitches.

-
-

Some additional imports

-

You’ll need to add a line of import in your commands/comms.py file. We’ll -see why this import is important when diving in the command itself:

-
from evennia.comms.models import ChannelDB
-
-
-
-
-

The class layout

-
# In commands/comms.py
-class ChannelCommand(Command):
-    """
-    {channelkey} channel
-
-    {channeldesc}
-
-    Usage:
-      {lower_channelkey} <message>
-      {lower_channelkey}/history [start]
-      {lower_channelkey}/me <message>
-      {lower_channelkey}/who
-
-    Switch:
-      history: View 20 previous messages, either from the end or
-          from <start> number of messages from the end.
-      me: Perform an emote on this channel.
-      who: View who is connected to this channel.
-
-    Example:
-      {lower_channelkey} Hello World!
-      {lower_channelkey}/history
-      {lower_channelkey}/history 30
-      {lower_channelkey}/me grins.
-      {lower_channelkey}/who
-    """
-    # note that channeldesc and lower_channelkey will be filled
-    # automatically by ChannelHandler
-
-    # this flag is what identifies this cmd as a channel cmd
-    # and branches off to the system send-to-channel command
-    # (which is customizable by admin)
-    is_channel = True
-    key = "general"
-    help_category = "Channel Names"
-    obj = None
-    arg_regex = ""
-
-
-

There are some differences here compared to most common commands.

-
    -
  • There is something disconcerting in the class docstring. Some information is -between curly braces. This is a format-style which is only used for channel -commands. {channelkey} will be replaced by the actual channel key (like -public). {channeldesc} will be replaced by the channel description (like -“public channel”). And {lower_channelkey}.

  • -
  • We have set is_channel to True in the command class variables. You -shouldn’t worry too much about that: it just tells Evennia this is a special -command just for channels.

  • -
  • key is a bit misleading because it will be replaced eventually. So we -could set it to virtually anything.

  • -
  • The obj class variable is another one we won’t detail right now.

  • -
  • arg_regex is important: the default arg_regex in the channel command will -forbid to use switches (a slash just after the channel name is not allowed). -That’s why we enforce it here, we allow any syntax.

  • -
-
-

What will become of this command?

-
-

Well, when we’ll be through with it, and once we’ll add it as the default -command to handle channels, Evennia will create one per existing channel. For -instance, the public channel will receive one command of this class, with key -set to public and aliases set to the channel aliases (like ['pub']).

-
-

Can I see it work?

-
-

Not just yet, there’s still a lot of code needed.

-

Okay we have the command structure but it’s rather empty.

-
-
-

The parse method

-

The parse method is called before func in every command. Its job is to -parse arguments and in our case, we will analyze switches here.

-
# ...
-    def parse(self):
-        """
-        Simple parser
-        """
-        # channel-handler sends channame:msg here.
-        channelname, msg = self.args.split(":", 1)
-        self.switch = None
-        if msg.startswith("/"):
-            try:
-                switch, msg = msg[1:].split(" ", 1)
-            except ValueError:
-                switch = msg[1:]
-                msg = ""
-
-            self.switch = switch.lower().strip()
-
-        self.args = (channelname.strip(), msg.strip())
-
-
-

Reading the comments we see that the channel handler will send the command in a -strange way: a string with the channel name, a colon and the actual message -entered by the player. So if the player enters “public hello”, the command -args will contain "public:hello". You can look at the way the channel name -and message are parsed, this can be used in a lot of different commands.

-

Next we check if there’s any switch, that is, if the message starts with a -slash. This would be the case if a player entered public/me jumps up and down, for instance. If there is a switch, we save it in self.switch. We -alter self.args at the end to contain a tuple with two values: the channel -name, and the message (if a switch was used, notice that the switch will be -stored in self.switch, not in the second element of self.args).

-
-
-

The command func

-

Finally, let’s see the func method in the command class. It will have to -handle switches and also the raw message to send if no switch was used.

-
# ...
-    def func(self):
-        """
-        Create a new message and send it to channel, using
-        the already formatted input.
-        """
-        channelkey, msg = self.args
-        caller = self.caller
-        channel = ChannelDB.objects.get_channel(channelkey)
-
-        # Check that the channel exists
-        if not channel:
-            self.msg(_("Channel '%s' not found.") % channelkey)
-            return
-
-        # Check that the caller is connected
-        if not channel.has_connection(caller):
-            string = "You are not connected to channel '%s'."
-            self.msg(string % channelkey)
-            return
-
-        # Check that the caller has send access
-        if not channel.access(caller, 'send'):
-            string = "You are not permitted to send to channel '%s'."
-            self.msg(string % channelkey)
-            return
-
-        # Handle the various switches
-        if self.switch == "me":
-            if not msg:
-                self.msg("What do you want to do on this channel?")
-            else:
-                msg = "{} {}".format(caller.key, msg)
-                channel.msg(msg, online=True)
-        elif self.switch:
-            self.msg("{}: Invalid switch {}.".format(channel.key, self.switch))
-        elif not msg:
-            self.msg("Say what?")
-        else:
-            if caller in channel.mutelist:
-                self.msg("You currently have %s muted." % channel)
-                return
-            channel.msg(msg, senders=self.caller, online=True)
-
-
-
    -
  • First of all, we try to get the channel object from the channel name we have -in the self.args tuple. We use ChannelDB.objects.get_channel this time -because we know the channel name isn’t an alias (that was part of the deal, -channelname in the parse method contains a command key).

  • -
  • We check that the channel does exist.

  • -
  • We then check that the caller is connected to the channel. Remember, if the -caller isn’t connected, we shouldn’t allow him to use this command (that -includes the switches on channels).

  • -
  • We then check that the caller has access to the channel’s send lock. This -time, we make sure the caller can send messages to the channel, no matter what -operation he’s trying to perform.

  • -
  • Finally we handle switches. We try only one switch: me. This switch would -be used if a player entered public/me jumps up and down (to do a channel -emote).

  • -
  • We handle the case where the switch is unknown and where there’s no switch -(the player simply wants to talk on this channel).

  • -
-

The good news: The code is not too complicated by itself. The bad news is that -this is just an abridged version of the code. If you want to handle all the -switches mentioned in the command help, you will have more code to write. This -is left as an exercise.

-
-
-

End of class

-

It’s almost done, but we need to add a method in this command class that isn’t -often used. I won’t detail it’s usage too much, just know that Evennia will use -it and will get angry if you don’t add it. So at the end of your class, just -add:

-
# ...
-    def get_extra_info(self, caller, **kwargs):
-        """
-        Let users know that this command is for communicating on a channel.
-
-        Args:
-            caller (TypedObject): A Character or Account who has entered an ambiguous command.
-
-        Returns:
-            A string with identifying information to disambiguate the object, conventionally with a
-preceding space.
-        """
-        return " (channel)"
-
-
-
-
-

Adding this channel command

-

Contrary to most Evennia commands, we won’t add our ChannelCommand to a -CmdSet. Instead we need to tell Evennia that it should use the command we -just created instead of its default channel-command.

-

In your server/conf/settings.py file, add a new setting:

-
# Channel options
-CHANNEL_COMMAND_CLASS = "commands.comms.ChannelCommand"
-
-
-

Then you can reload your game. Try to type public hello and public/me jumps up and down. Don’t forget to enter help public to see if your command has -truly been added.

-
-
-
-

Conclusion and full code

-

That was some adventure! And there’s still things to do! But hopefully, this -tutorial will have helped you in designing your own channel system. Here are a -few things to do:

-
    -
  • Add more switches to handle various actions, like changing the description of -a channel for instance, or listing the connected participants.

  • -
  • Remove the default Evennia commands to handle channels.

  • -
  • Alter the behavior of the channel system so it better aligns with what you -want to do.

  • -
-

As a special bonus, you can find a full, working example of a communication -system similar to the one I’ve shown you: this is a working example, it -integrates all switches and does ever some extra checking, but it’s also very -close from the code I’ve provided here. Notice, however, that this resource is -external to Evennia and not maintained by anyone but the original author of -this article.

-

Read the full example on Github

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Debugging.html b/docs/0.9.5/Debugging.html deleted file mode 100644 index 41998208c9..0000000000 --- a/docs/0.9.5/Debugging.html +++ /dev/null @@ -1,407 +0,0 @@ - - - - - - - - - Debugging — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Debugging

-

Sometimes, an error is not trivial to resolve. A few simple print statements is not enough to find -the cause of the issue. Running a debugger can then be very helpful and save a lot of time. -Debugging -means running Evennia under control of a special debugger program. This allows you to stop the -action at a given point, view the current state and step forward through the program to see how its -logic works.

-

Evennia natively supports these debuggers:

-
    -
  • Pdb is a part of the Python distribution and -available out-of-the-box.

  • -
  • PuDB is a third-party debugger that has a slightly more -‘graphical’, curses-based user interface than pdb. It is installed with pip install pudb.

  • -
-
-

Debugging Evennia

-

To run Evennia with the debugger, follow these steps:

-
    -
  1. Find the point in the code where you want to have more insight. Add the following line at that -point.

    -
    from evennia import set_trace;set_trace()
    -
    -
    -
  2. -
  3. (Re-)start Evennia in interactive (foreground) mode with evennia istart. This is important - -without this step the debugger will not start correctly - it will start in this interactive -terminal.

  4. -
  5. Perform the steps that will trigger the line where you added the set_trace() call. The debugger -will start in the terminal from which Evennia was interactively started.

  6. -
-

The evennia.set_trace function takes the following arguments:

-
    evennia.set_trace(debugger='auto', term_size=(140, 40))
-
-
-

Here, debugger is one of pdb, pudb or auto. If auto, use pudb if available, otherwise -use pdb. The term_size tuple sets the viewport size for pudb only (it’s ignored by pdb).

-
-
-

A simple example using pdb

-

The debugger is useful in different cases, but to begin with, let’s see it working in a command. -Add the following test command (which has a range of deliberate errors) and also add it to your -default cmdset. Then restart Evennia in interactive mode with evennia istart.

-
# In file commands/command.py
-
-
-class CmdTest(Command):
-
-    """
-    A test command just to test pdb.
-
-    Usage:
-        test
-
-    """
-
-    key = "test"
-
-    def func(self):
-        from evennia import set_trace; set_trace()   # <--- start of debugger
-        obj = self.search(self.args)
-        self.msg("You've found {}.".format(obj.get_display_name()))
-
-
-
-

If you type test in your game, everything will freeze. You won’t get any feedback from the game, -and you won’t be able to enter any command (nor anyone else). It’s because the debugger has started -in your console, and you will find it here. Below is an example with pdb.

-
...
-> .../mygame/commands/command.py(79)func()
--> obj = self.search(self.args)
-(Pdb)
-
-
-
-

pdb notes where it has stopped execution and, what line is about to be executed (in our case, obj = self.search(self.args)), and ask what you would like to do.

-
-

Listing surrounding lines of code

-

When you have the pdb prompt (Pdb), you can type in different commands to explore the code. The -first one you should know is list (you can type l for short):

-
(Pdb) l
- 43
- 44         key = "test"
- 45
- 46         def func(self):
- 47             from evennia import set_trace; set_trace()   # <--- start of debugger
- 48  ->         obj = self.search(self.args)
- 49             self.msg("You've found {}.".format(obj.get_display_name()))
- 50
- 51     # -------------------------------------------------------------
- 52     #
- 53     # The default commands inherit from
-(Pdb)
-
-
-

Okay, this didn’t do anything spectacular, but when you become more confident with pdb and find -yourself in lots of different files, you sometimes need to see what’s around in code. Notice that -there is a little arrow (->) before the line that is about to be executed.

-

This is important: about to be, not has just been. You need to tell pdb to go on (we’ll -soon see how).

-
-
-

Examining variables

-

pdb allows you to examine variables (or really, to run any Python instruction). It is very useful -to know the values of variables at a specific line. To see a variable, just type its name (as if -you were in the Python interpreter:

-
(Pdb) self
-<commands.command.CmdTest object at 0x045A0990>
-(Pdb) self.args
-u''
-(Pdb) self.caller
-<Character: XXX>
-(Pdb)
-
-
-

If you try to see the variable obj, you’ll get an error:

-
(Pdb) obj
-*** NameError: name 'obj' is not defined
-(Pdb)
-
-
-

That figures, since at this point, we haven’t created the variable yet.

-
-

Examining variable in this way is quite powerful. You can even run Python code and keep on -executing, which can help to check that your fix is actually working when you have identified an -error. If you have variable names that will conflict with pdb commands (like a list -variable), you can prefix your variable with !, to tell pdb that what follows is Python code.

-
-
-
-

Executing the current line

-

It’s time we asked pdb to execute the current line. To do so, use the next command. You can -shorten it by just typing n:

-
(Pdb) n
-AttributeError: "'CmdTest' object has no attribute 'search'"
-> .../mygame/commands/command.py(79)func()
--> obj = self.search(self.args)
-(Pdb)
-
-
-

Pdb is complaining that you try to call the search method on a command… whereas there’s no -search method on commands. The character executing the command is in self.caller, so we might -change our line:

-
obj = self.caller.search(self.args)
-
-
-
-
-

Letting the program run

-

pdb is waiting to execute the same instruction… it provoked an error but it’s ready to try -again, just in case. We have fixed it in theory, but we need to reload, so we need to enter a -command. To tell pdb to terminate and keep on running the program, use the continue (or c) -command:

-
(Pdb) c
-...
-
-
-

You see an error being caught, that’s the error we have fixed… or hope to have. Let’s reload the -game and try again. You need to run evennia istart again and then run test to get into the -command again.

-
> .../mygame/commands/command.py(79)func()
--> obj = self.caller.search(self.args)
-(Pdb)
-
-
-
-

pdb is about to run the line again.

-
(Pdb) n
-> .../mygame/commands/command.py(80)func()
--> self.msg("You've found {}.".format(obj.get_display_name()))
-(Pdb)
-
-
-

This time the line ran without error. Let’s see what is in the obj variable:

-
(Pdb) obj
-(Pdb) print obj
-None
-(Pdb)
-
-
-

We have entered the test command without parameter, so no object could be found in the search -(self.args is an empty string).

-

Let’s allow the command to continue and try to use an object name as parameter (although, we should -fix that bug too, it would be better):

-
(Pdb) c
-...
-
-
-

Notice that you’ll have an error in the game this time. Let’s try with a valid parameter. I have -another character, barkeep, in this room:

-

test barkeep

-

And again, the command freezes, and we have the debugger opened in the console.

-

Let’s execute this line right away:

-
> .../mygame/commands/command.py(79)func()
--> obj = self.caller.search(self.args)
-(Pdb) n
-> .../mygame/commands/command.py(80)func()
--> self.msg("You've found {}.".format(obj.get_display_name()))
-(Pdb) obj
-<Character: barkeep>
-(Pdb)
-
-
-

At least this time we have found the object. Let’s process…

-
(Pdb) n
-TypeError: 'get_display_name() takes exactly 2 arguments (1 given)'
-> .../mygame/commands/command.py(80)func()
--> self.msg("You've found {}.".format(obj.get_display_name()))
-(Pdb)
-
-
-

As an exercise, fix this error, reload and run the debugger again. Nothing better than some -experimenting!

-

Your debugging will often follow the same strategy:

-
    -
  1. Receive an error you don’t understand.

  2. -
  3. Put a breaking point BEFORE the error occurs.

  4. -
  5. Run the code again and see the debugger open.

  6. -
  7. Run the program line by line,examining variables, checking the logic of instructions.

  8. -
  9. Continue and try again, each step a bit further toward the truth and the working feature.

  10. -
-
-
-

Stepping through a function

-

n is useful, but it will avoid stepping inside of functions if it can. But most of the time, when -we have an error we don’t understand, it’s because we use functions or methods in a way that wasn’t -intended by the developer of the API. Perhaps using wrong arguments, or calling the function in a -situation that would cause a bug. When we have a line in the debugger that calls a function or -method, we can “step” to examine it further. For instance, in the previous example, when pdb was -about to execute obj = self.caller.search(self.args), we may want to see what happens inside of -the search method.

-

To do so, use the step (or s) command. This command will show you the definition of the -function/method and you can then use n as before to see it line-by-line. In our little example, -stepping through a function or method isn’t that useful, but when you have an impressive set of -commands, functions and so on, it might really be handy to examine some feature and make sure they -operate as planned.

-
-
-
-

Cheat-sheet of pdb/pudb commands

-

PuDB and Pdb share the same commands. The only real difference is how it’s presented. The look -command is not needed much in pudb since it displays the code directly in its user interface.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Pdb/PuDB command

To do what

list (or l)

List the lines around the point of execution (not needed for pudb, it will show

this directly).

print (or p)

Display one or several variables.

!

Run Python code (using a ! is often optional).

continue (or c)

Continue execution and terminate the debugger for this time.

next (or n)

Execute the current line and goes to the next one.

step (or s)

Step inside of a function or method to examine it.

<RETURN>

Repeat the last command (don’t type n repeatedly, just type it once and then press

<RETURN> to repeat it).

-

If you want to learn more about debugging with Pdb, you will find an interesting tutorial on that -topic here.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Default-Commands.html b/docs/0.9.5/Default-Commands.html deleted file mode 100644 index cdf55330e6..0000000000 --- a/docs/0.9.5/Default-Commands.html +++ /dev/null @@ -1,214 +0,0 @@ - - - - - - - - - Default Commands — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Default Commands

-

The full set of default Evennia commands currently contains 98 commands in 9 source -files. Our policy for adding default commands is outlined here. The -Commands documentation explains how Commands work as well as make new or customize -existing ones. Note that this page is auto-generated. Report problems to the issue -tracker.

-
-

Note

-

Some game-states adds their own Commands which are not listed here. Examples include editing a text -with EvEditor, flipping pages in EvMore or using the -Batch-Processor’s interactive mode.

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Default-Exit-Errors.html b/docs/0.9.5/Default-Exit-Errors.html deleted file mode 100644 index ddfea93b61..0000000000 --- a/docs/0.9.5/Default-Exit-Errors.html +++ /dev/null @@ -1,231 +0,0 @@ - - - - - - - - - Default Exit Errors — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Default Exit Errors

-

Evennia allows for exits to have any name. The command “kitchen” is a valid exit name as well as -“jump out the window” or “north”. An exit actually consists of two parts: an Exit Object -and an Exit Command stored on said exit object. The command has the same key and aliases -as the object, which is why you can see the exit in the room and just write its name to traverse it.

-

If you try to enter the name of a non-existing exit, it is thus the same as trying a non-exising -command; Evennia doesn’t care about the difference:

-
 > jump out the window
- Command 'jump out the window' is not available. Type "help" for help.
-
-
-

Many games don’t need this type of freedom however. They define only the cardinal directions as -valid exit names (Evennia’s @tunnel command also offers this functionality). In this case, the -error starts to look less logical:

-
 > west
- Command 'west' is not available. Maybe you meant "@set" or "@reset"?
-
-
-

Since we for our particular game know that west is an exit direction, it would be better if the -error message just told us that we couldn’t go there.

-
-

Adding default error commands

-

To solve this you need to be aware of how to write and add new commands. -What you need to do is to create new commands for all directions you want to support in your game. -In this example all we’ll do is echo an error message, but you could certainly consider more -advanced uses. You add these commands to the default command set. Here is an example of such a set -of commands:

-
# for example in a file mygame/commands/movecommands.py
-
-from evennia import default_cmds
-
-class CmdExitError(default_cmds.MuxCommand):
-    "Parent class for all exit-errors."
-    locks = "cmd:all()"
-    arg_regex = r"\s|$"
-    auto_help = False
-    def func(self):
-        "returns the error"
-        self.caller.msg("You cannot move %s." % self.key)
-
-class CmdExitErrorNorth(CmdExitError):
-    key = "north"
-    aliases = ["n"]
-
-class CmdExitErrorEast(CmdExitError):
-    key = "east"
-    aliases = ["e"]
-
-class CmdExitErrorSouth(CmdExitError):
-    key = "south"
-    aliases = ["s"]
-
-class CmdExitErrorWest(CmdExitError):
-    key = "west"
-    aliases = ["w"]
-
-
-

Make sure to add the directional commands (not their parent) to the CharacterCmdSet class in -mygame/commands/default_cmdsets.py:

-
# in mygame/commands/default_cmdsets.py
-
-from commands import movecommands
-
-# [...]
-class CharacterCmdSet(default_cmds.CharacterCmdSet):
-    # [...]
-    def at_cmdset_creation(self):
-        # [...]
-        self.add(movecommands.CmdExitErrorNorth())
-        self.add(movecommands.CmdExitErrorEast())
-        self.add(movecommands.CmdExitErrorSouth())
-        self.add(movecommands.CmdExitErrorWest())
-
-
-

After a @reload these commands (assuming you don’t get any errors - check your log) will be -loaded. What happens henceforth is that if you are in a room with an Exitobject (let’s say it’s -“north”), the proper Exit-command will overload your error command (also named “north”). But if you -enter an direction without having a matching exit for it, you will fallback to your default error -commands:

-
 > east
- You cannot move east.
-
-
-

Further expansions by the exit system (including manipulating the way the Exit command itself is -created) can be done by modifying the Exit typeclass directly.

-
-
-

Additional Comments

-

So why didn’t we create a single error command above? Something like this:

-
     class CmdExitError(default_cmds.MuxCommand):
-        "Handles all exit-errors."
-        key = "error_cmd"
-        aliases = ["north", "n",
-                   "east", "e",
-                   "south", "s",
-                   "west", "w"]
-         #[...]
-
-
-

The anwer is that this would not work and understanding why is important in order to not be -confused when working with commands and command sets.

-

The reason it doesn’t work is because Evennia’s command system compares commands both -by key and by aliases. If either of those match, the two commands are considered identical -as far as cmdset merging system is concerned.

-

So the above example would work fine as long as there were no Exits at all in the room. But what -happens when we enter a room with an exit “north”? The Exit’s cmdset is merged onto the default one, -and since there is an alias match, the system determines our CmdExitError to be identical. It is -thus overloaded by the Exit command (which also correctly defaults to a higher priority). The result -is that you can go through the north exit normally but none of the error messages for the other -directions are available since the single error command was completely overloaded by the single -matching “north” exit-command.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Developer-Central.html b/docs/0.9.5/Developer-Central.html deleted file mode 100644 index 6c8a6ef1fd..0000000000 --- a/docs/0.9.5/Developer-Central.html +++ /dev/null @@ -1,294 +0,0 @@ - - - - - - - - - Developer Central — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - - - -
-
-
-
- -
-

Developer Central

-

This page serves as a central nexus for information on using Evennia as well as developing the -library itself.

-
-

General Evennia development information

- -
-
-

Evennia API

- -
-

Core components and protocols

- -
-
-

In-game Commands

- -
- -
-

Web

- -
-
-

Other systems

- -
-
-
-

Developer brainstorms and whitepages

-
    -
  • API refactoring, discussing what parts of the Evennia API needs a -refactoring/cleanup/simplification

  • -
  • Docs refactoring, discussing how to reorganize and structure this wiki/docs -better going forward

  • -
  • Webclient brainstorm, some ideas for a future webclient gui

  • -
  • Roadmap, a tentative list of future major features

  • -
  • Change log of big Evennia updates -over time

  • -
-

zY1RoZGc6MQ#gid=0 -[issues]: https://github.com/evennia/evennia/issues

-
-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Dialogues-in-events.html b/docs/0.9.5/Dialogues-in-events.html deleted file mode 100644 index c20148918b..0000000000 --- a/docs/0.9.5/Dialogues-in-events.html +++ /dev/null @@ -1,347 +0,0 @@ - - - - - - - - - Dialogues in events — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Dialogues in events

-
    -
  • Next tutorial: [adding a voice-operated elevator with events](A-voice-operated-elevator-using- -events).

  • -
-

This tutorial will walk you through the steps to create several dialogues with characters, using the -in-game Python -system. -This tutorial assumes the in-game Python system is installed in your game. If it isn’t, you can -follow the installation steps given in the documentation on in-game -Python, and -come back on this tutorial once the system is installed. You do not need to read the entire -documentation, it’s a good reference, but not the easiest way to learn about it. Hence these -tutorials.

-

The in-game Python system allows to run code on individual objects in some situations. You don’t -have to modify the source code to add these features, past the installation. The entire system -makes it easy to add specific features to some objects, but not all. This is why it can be very -useful to create a dialogue system taking advantage of the in-game Python system.

-
-

What will we try to do?

-
-

In this tutorial, we are going to create a basic dialogue to have several characters automatically -respond to specific messages said by others.

-
-

A first example with a first character

-

Let’s create a character to begin with.

-
@charcreate a merchant
-
-
-

This will create a merchant in the room where you currently are. It doesn’t have anything, like a -description, you can decorate it a bit if you like.

-

As said above, the in-game Python system consists in linking objects with arbitrary code. This code -will be executed in some circumstances. Here, the circumstance is “when someone says something in -the same room”, and might be more specific like “when someone says hello”. We’ll decide what code -to run (we’ll actually type the code in-game). Using the vocabulary of the in-game Python system, -we’ll create a callback: a callback is just a set of lines of code that will run under some -conditions.

-

You can have an overview of every “conditions” in which callbacks can be created using the @call -command (short for @callback). You need to give it an object as argument. Here for instance, we -could do:

-
@call a merchant
-
-
-

You should see a table with three columns, showing the list of events existing on our newly-created -merchant. There are quite a lot of them, as it is, althougn no line of code has been set yet. For -our system, you might be more interested by the line describing the say event:

-
| say              |   0 (0) | After another character has said something in |
-|                  |         | the character's room.                         |
-
-
-

We’ll create a callback on the say event, called when we say “hello” in the merchant’s room:

-
@call/add a merchant = say hello
-
-
-

Before seeing what this command displays, let’s see the command syntax itself:

-
    -
  • @call is the command name, /add is a switch. You can read the help of the command to get the -help of available switches and a brief overview of syntax.

  • -
  • We then enter the object’s name, here “a merchant”. You can enter the ID too (“#3” in my case), -which is useful to edit the object when you’re not in the same room. You can even enter part of the -name, as usual.

  • -
  • An equal sign, a simple separator.

  • -
  • The event’s name. Here, it’s “say”. The available events are displayed when you use @call -without switch.

  • -
  • After a space, we enter the conditions in which this callback should be called. Here, the -conditions represent what the other character should say. We enter “hello”. Meaning that if -someone says something containing “hello” in the room, the callback we are now creating will be -called.

  • -
-

When you enter this command, you should see something like this:

-
After another character has said something in the character's room.
-This event is called right after another character has said
-something in the same location.  The action cannot be prevented
-at this moment.  Instead, this event is ideal to create keywords
-that would trigger a character (like a NPC) in doing something
-if a specific phrase is spoken in the same location.
-
-To use this event, you have to specify a list of keywords as
-parameters that should be present, as separate words, in the
-spoken phrase.  For instance, you can set a callback that would
-fire if the phrase spoken by the character contains "menu" or
-"dinner" or "lunch":
-    @call/add ... = say menu, dinner, lunch
-Then if one of the words is present in what the character says,
-this callback will fire.
-
-Variables you can use in this event:
-    speaker: the character speaking in this room.
-    character: the character connected to this event.
-    message: the text having been spoken by the character.
-
-
-

That’s some list of information. What’s most important to us now is:

-
    -
  • The “say” event is called whenever someone else speaks in the room.

  • -
  • We can set callbacks to fire when specific keywords are present in the phrase by putting them as -additional parameters. Here we have set this parameter to “hello”. We can have several keywords -separated by a comma (we’ll see this in more details later).

  • -
  • We have three default variables we can use in this callback: speaker which contains the -character who speaks, character which contains the character who’s modified by the in-game Python -system (here, or merchant), and message which contains the spoken phrase.

  • -
-

This concept of variables is important. If it makes things more simple to you, think of them as -parameters in a function: they can be used inside of the function body because they have been set -when the function was called.

-

This command has opened an editor where we can type our Python code.

-
----------Line Editor [Callback say of a merchant]--------------------------------
-01|
-----------[l:01 w:000 c:0000]------------(:h for help)----------------------------
-
-
-

For our first test, let’s type something like:

-
character.location.msg_contents("{character} shrugs and says: 'well, yes, hello to you!'",
-mapping=dict(character=character))
-
-
-

Once you have entered this line, you can type :wq to save the editor and quit it.

-

And now if you use the “say” command with a message containing “hello”:

-
You say, "Hello sir merchant!"
-a merchant(#3) shrugs and says: 'well, yes, hello to you!'
-
-
-

If you say something that doesn’t contain “hello”, our callback won’t execute.

-

In summary:

-
    -
  1. When we say something in the room, using the “say” command, the “say” event of all characters -(except us) is called.

  2. -
  3. The in-game Python system looks at what we have said, and checks whether one of our callbacks in -the “say” event contains a keyword that we have spoken.

  4. -
  5. If so, call it, defining the event variables as we have seen.

  6. -
  7. The callback is then executed as normal Python code. Here we have called the msg_contents -method on the character’s location (probably a room) to display a message to the entire room. We -have also used mapping to easily display the character’s name. This is not specific to the in-game -Python system. If you feel overwhelmed by the code we’ve used, just shorten it and use something -more simple, for instance:

  8. -
-
speaker.msg("You have said something to me.")
-
-
-
-
-

The same callback for several keywords

-

It’s easy to create a callback that will be triggered if the sentence contains one of several -keywords.

-
@call/add merchant = say trade, trader, goods
-
-
-

And in the editor that opens:

-
character.location.msg_contents("{character} says: 'Ho well, trade's fine as long as roads are
-safe.'", mapping=dict(character=character))
-
-
-

Then you can say something with either “trade”, “trader” or “goods” in your sentence, which should -call the callback:

-
You say, "and how is your trade going?"
-a merchant(#3) says: 'Ho well, trade's fine as long as roads are safe.'
-
-
-

We can set several keywords when adding the callback. We just need to separate them with commas.

-
-
-

A longer callback

-

So far, we have only set one line in our callbacks. Which is useful, but we often need more. For -an entire dialogue, you might want to do a bit more than that.

-
@call/add merchant = say bandit, bandits
-
-
-

And in the editor you can paste the following lines:

-
character.location.msg_contents("{character} says: 'Bandits he?'",
-mapping=dict(character=character))
-character.location.msg_contents("{character} scratches his head, considering.",
-mapping=dict(character=character))
-character.location.msg_contents("{character} whispers: 'Aye, saw some of them, north from here.  No
-trouble o' mine, but...'", mapping=dict(character=character))
-speaker.msg("{character} looks at you more
-closely.".format(character=character.get_display_name(speaker)))
-speaker.msg("{character} continues in a low voice: 'Ain't my place to say, but if you need to find
-'em, they're encamped some distance away from the road, I guess near a cave or
-something.'.".format(character=character.get_display_name(speaker)))
-
-
-

Now try to ask the merchant about bandits:

-
You say, "have you seen bandits?"
-a merchant(#3) says: 'Bandits he?'
-a merchant(#3) scratches his head, considering.
-a merchant(#3) whispers: 'Aye, saw some of them, north from here.  No trouble o' mine, but...'
-a merchant(#3) looks at you more closely.
-a merchant(#3) continues in a low voice: 'Ain't my place to say, but if you need to find 'em,
-they're encamped some distance away from the road, I guess near a cave or something.'.
-
-
-

Notice here that the first lines of dialogue are spoken to the entire room, but then the merchant is -talking directly to the speaker, and only the speaker hears it. There’s no real limit to what you -can do with this.

-
    -
  • You can set a mood system, storing attributes in the NPC itself to tell you in what mood he is, -which will influence the information he will give… perhaps the accuracy of it as well.

  • -
  • You can add random phrases spoken in some context.

  • -
  • You can use other actions (you’re not limited to having the merchant say something, you can ask -him to move, gives you something, attack if you have a combat system, or whatever else).

  • -
  • The callbacks are in pure Python, so you can write conditions or loops.

  • -
  • You can add in “pauses” between some instructions using chained events. This tutorial won’t -describe how to do that however. You already have a lot to play with.

  • -
-
-
-

Tutorial F.A.Q.

-
    -
  • Q: can I create several characters who would answer to specific dialogue?

  • -
  • A: of course. Te in-game Python system is so powerful because you can set unique code for -various objects. You can have several characters answering to different things. You can even have -different characters in the room answering to greetings. All callbacks will be executed one after -another.

  • -
  • Q: can I have two characters answering to the same dialogue in exactly the same way?

  • -
  • A: It’s possible but not so easy to do. Usually, event grouping is set in code, and depends -on different games. However, if it is for some infrequent occurrences, it’s easy to do using -chained events.

  • -
  • Q: is it possible to deploy callbacks on all characters sharing the same prototype?

  • -
  • A: not out of the box. This depends on individual settings in code. One can imagine that all -characters of some type would share some events, but this is game-specific. Rooms of the same zone -could share the same events as well. It is possible to do but requires modification of the source -code.

  • -
  • Next tutorial: [adding a voice-operated elevator with events](A-voice-operated-elevator-using- -events).

  • -
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Directory-Overview.html b/docs/0.9.5/Directory-Overview.html deleted file mode 100644 index 9aa3bdbc18..0000000000 --- a/docs/0.9.5/Directory-Overview.html +++ /dev/null @@ -1,196 +0,0 @@ - - - - - - - - - Directory Overview — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Directory Overview

-

This is an overview of the directories relevant to Evennia coding.

-
-

The Game directory

-

The game directory is created with evennia --init <name>. In the Evennia documentation we always -assume it’s called mygame. Apart from the server/ subfolder within, you could reorganize this -folder if you preferred a different code structure for your game.

-
    -
  • mygame/

  • -
  • commands/ - Overload default Commands or add your own Commands/Command -sets here.

  • -
  • server/ - The structure of this folder should not change since Evennia expects it.

    -
      -
    • conf/ - All -server configuration files sits here. The most important file is settings.py.

    • -
    • logs/ - Portal log files are stored here (Server is logging to the terminal by default)

    • -
    -
  • -
  • typeclasses/ - this folder contains empty templates for overloading default game entities of -Evennia. Evennia will automatically use the changes in those templates for the game entities it -creates.

  • -
  • web/ - This holds the Web features of your game.

  • -
  • world/ - this is a “miscellaneous” folder holding everything related to the world you are -building, such as build scripts and rules modules that don’t fit with one of the other folders.

  • -
-
-
-

Evennia library layout:

-

If you cloned the GIT repo following the instructions, you will have a folder named evennia. The -top level of it contains Python package specific stuff such as a readme file, setup.py etc. It -also has two subfoldersbin/ and evennia/ (again).

-

The bin/ directory holds OS-specific binaries that will be used when installing Evennia with pip -as per the Getting started instructions. The library itself is in the evennia -subfolder. From your code you will access this subfolder simply by import evennia.

-
    -
  • evennia

    -
      -
    • __init__.py - The “flat API” of Evennia resides here.

    • -
    • commands/ - The command parser and handler.

      - -
    • -
    • comms/ - Systems for communicating in-game.

    • -
    • contrib/ - Optional plugins too game-specific for core Evennia.

    • -
    • game_template/ - Copied to become the “game directory” when using evennia --init.

    • -
    • help/ - Handles the storage and creation of help entries.

    • -
    • locale/ - Language files (i18n).

    • -
    • locks/ - Lock system for restricting access to in-game entities.

    • -
    • objects/ - In-game entities (all types of items and Characters).

    • -
    • prototypes/ - Object Prototype/spawning system and OLC menu

    • -
    • accounts/ - Out-of-game Session-controlled entities (accounts, bots etc)

    • -
    • scripts/ - Out-of-game entities equivalence to Objects, also with timer support.

    • -
    • server/ - Core server code and Session handling.

      -
        -
      • portal/ - Portal proxy and connection protocols.

      • -
      -
    • -
    • settings_default.py - Root settings of Evennia. Copy settings -from here to mygame/server/settings.py file.

    • -
    • typeclasses/ - Abstract classes for the typeclass storage and database system.

    • -
    • utils/ - Various miscellaneous useful coding resources.

    • -
    • web/ - Web resources and webserver. Partly copied into game directory on -initialization.

    • -
    -
  • -
-

All directories contain files ending in .py. These are Python modules and are the basic units of -Python code. The roots of directories also have (usually empty) files named __init__.py. These are -required by Python so as to be able to find and import modules in other directories. When you have -run Evennia at least once you will find that there will also be .pyc files appearing, these are -pre-compiled binary versions of the .py files to speed up execution.

-

The root of the evennia folder has an __init__.py file containing the “flat API”. -This holds shortcuts to various subfolders in the evennia library. It is provided to make it easier -to find things; it allows you to just import evennia and access things from that rather than -having to import from their actual locations inside the source tree.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Docs-refactoring.html b/docs/0.9.5/Docs-refactoring.html deleted file mode 100644 index cb24c151c4..0000000000 --- a/docs/0.9.5/Docs-refactoring.html +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - Docs refactoring — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Docs refactoring

-

This is a whitepage for free discussion about the wiki docs and refactorings needed.

-

Note that this is not a forum. To keep things clean, each opinion text should ideally present a -clear argument or lay out a suggestion. Asking for clarification and any side-discussions should be -held in chat or forum.

-
-

Griatch (Aug 13, 2019)

-

This is how to make a discussion entry for the whitepage. Use any markdown formatting you need. Also -remember to copy your work to the clipboard before saving the page since if someone else edited the -page since you started, you’ll have to reload and write again.

-
-

(Sept 23, 2019)

-

This (now closed) issue by DamnedScholar gives the -following suggestion:

-
-

I think it would be useful for the pages that explain how to use various features of Evennia to -have explicit and easily visible links to the respective API entry or entries. Some pages do, but -not all. I imagine this as a single entry at the top of the page […].

-
-

This (now closed) issue by taladan gives the -following suggestion:

-
-

It would help me (and probably a couple of others) if there is a way to show the file path where a -particular thing exists. Maybe up under the ‘last edited’ line we could have a line like: -evennia/locks/lockhandler.py

-
-

This would help in development to quickly refer to where a resource is located.

-
-
-
-

Kovitikus (Sept. 11, 2019)

-

Batch Code should have a link in the developer area. It is currently only -listed in the tutorials section as an afterthought to a tutorial title.

-
-

In regards to the general structure of each wiki page: I’d like to see a table of contents at the -top of each one, so that it can be quickly navigated and is immediately apparent what sections are -covered on the page. Similar to the current Getting Started page.

-
-

The structuring of the page should also include a quick reference cheatsheet for certain aspects. -Such as Tags including a quick reference section at the top that lists an example of every -available method you can use in a clear and consistent format, along with a comment. Readers -shouldn’t have to decipher the article to gather such basic information and it should instead be -available at first glance.

-

Example of a quick reference:

-

Tags

-
# Add a tag.
-obj.tags.add("label")
-
-# Remove a tag.
-obj.tags.remove("label")
-
-# Remove all tags.
-obj.tags.clear()
-
-# Search for a tag. Evennia must be imported first.
-store_result = evennia.search_tag("label")
-
-# Return a list of all tags.
-obj.tags.all()
-
-
-

Aliases

-
# Add an alias.
-obj.aliases.add("label")
-
-ETC...
-
-
-
-

In regards to comment structure, I often find that smushing together lines with comments to be too -obscure. White space should be used to clearly delineate what information the comment is for. I -understand that the current format is that a comment references whatever is below it, but newbies -may not know that until they realize it.

-

Example of poor formatting:

-
#comment
-command/code
-#comment
-command/code
-
-
-

Example of good formatting:

-
# Comment.
-command/code
-
-# Comment.
-command/code
-
-
-
-
-

Sage (3/28/20)

-

If I want to find information on the correct syntax for is_typeclass(), here’s what I do:

-
    -
  • Pop over to the wiki. Okay, this is a developer functionality. Let’s try that.

  • -
  • Ctrl+F on Developer page. No results.

  • -
  • Ctrl+F on API page. No results. Ctrl+F on Flat API page. No results

  • -
  • Ctrl+F on utils page. No results.

  • -
  • Ctrl+F on utils.utils page. No results.

  • -
  • Ctrl+F in my IDE. Results.

  • -
  • Fortunately, there’s only one result for def is_typeclass. If this was at_look, there would be -several results, and I’d have to go through each of those individually, and most of them would just -call return_appearance

  • -
-

An important part of a refactor, in my opinion, is separating out the “Tutorials” from the -“Reference” documentation.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Dynamic-In-Game-Map.html b/docs/0.9.5/Dynamic-In-Game-Map.html deleted file mode 100644 index a9c4c85ede..0000000000 --- a/docs/0.9.5/Dynamic-In-Game-Map.html +++ /dev/null @@ -1,581 +0,0 @@ - - - - - - - - - Dynamic In Game Map — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Dynamic In Game Map

-
-

Introduction

-

An often desired feature in a MUD is to show an in-game map to help navigation. The Static in-game -map tutorial solves this by creating a static map, meaning the map is pre- -drawn once and for all - the rooms are then created to match that map. When walking around, parts of -the static map is then cut out and displayed next to the room description.

-

In this tutorial we’ll instead do it the other way around; We will dynamically draw the map based on -the relationships we find between already existing rooms.

-
-
-

The Grid of Rooms

-

There are at least two requirements needed for this tutorial to work.

-
    -
  1. The structure of your mud has to follow a logical layout. Evennia supports the layout of your -world to be ‘logically’ impossible with rooms looping to themselves or exits leading to the other -side of the map. Exits can also be named anything, from “jumping out the window” to “into the fifth -dimension”. This tutorial assumes you can only move in the cardinal directions (N, E, S and W).

  2. -
  3. Rooms must be connected and linked together for the map to be generated correctly. Vanilla -Evennia comes with a admin command tunnel that allows a -user to create rooms in the cardinal directions, but additional work is needed to assure that rooms -are connected. For example, if you tunnel east and then immediately do tunnel west you’ll find -that you have created two completely stand-alone rooms. So care is needed if you want to create a -“logical” layout. In this tutorial we assume you have such a grid of rooms that we can generate the -map from.

  4. -
-
-
-

Concept

-

Before getting into the code, it is beneficial to understand and conceptualize how this is going to -work. The idea is analogous to a worm that starts at your current position. It chooses a direction -and ‘walks’ outward from it, mapping its route as it goes. Once it has traveled a pre-set distance -it stops and starts over in another direction. An important note is that we want a system which is -easily callable and not too complicated. Therefore we will wrap this entire code into a custom -Python class (not a typeclass as this doesn’t use any core objects from evennia itself).

-

We are going to create something that displays like this when you type ‘look’:

-
    Hallway
-
-          [.]   [.]
-          [@][.][.][.][.]
-          [.]   [.]   [.]
-
-    The distant echoes of the forgotten
-    wail throughout the empty halls.
-
-    Exits: North, East, South
-
-
-

Your current location is defined by [@] while the [.]s are other rooms that the “worm” has seen -since departing from your location.

-
-
-

Setting up the Map Display

-

First we must define the components for displaying the map. For the “worm” to know what symbol to -draw on the map we will have it check an Attribute on the room it visits called sector_type. For -this tutorial we understand two symbols - a normal room and the room with us in it. We also define a -fallback symbol for rooms without said Attribute - that way the map will still work even if we -didn’t prepare the room correctly. Assuming your game folder is named mygame, we create this code -in mygame/world/map.py.

-
# in mygame/world/map.py
-
-# the symbol is identified with a key "sector_type" on the
-# Room. Keys None and "you" must always exist.
-SYMBOLS = { None : ' . ', # for rooms without sector_type Attribute
-            'you' : '[@]',
-            'SECT_INSIDE': '[.]' }
-
-
-

Since trying to access an unset Attribute returns None, this means rooms without the sector_type -Atttribute will show as .. Next we start building the custom class Map. It will hold all -methods we need.

-
# in mygame/world/map.py
-
-class Map(object):
-
-    def __init__(self, caller, max_width=9, max_length=9):
-        self.caller = caller
-        self.max_width = max_width
-        self.max_length = max_length
-        self.worm_has_mapped = {}
-        self.curX = None
-        self.curY = None
-
-
-
    -
  • self.caller is normally your Character object, the one using the map.

  • -
  • self.max_width/length determine the max width and length of the map that will be generated. Note -that it’s important that these variables are set to odd numbers to make sure the display area has -a center point.

  • -
  • self.worm_has_mapped is building off the worm analogy above. This dictionary will store all -rooms the “worm” has mapped as well as its relative position within the grid. This is the most -important variable as it acts as a ‘checker’ and ‘address book’ that is able to tell us where the -worm has been and what it has mapped so far.

  • -
  • self.curX/Y are coordinates representing the worm’s current location on the grid.

  • -
-

Before any sort of mapping can actually be done we need to create an empty display area and do some -sanity checks on it by using the following methods.

-
# in mygame/world/map.py
-
-class Map(object):
-    # [... continued]
-
-    def create_grid(self):
-        # This method simply creates an empty grid/display area
-        # with the specified variables from __init__(self):
-        board = []
-        for row in range(self.max_width):
-            board.append([])
-            for column in range(self.max_length):
-                board[row].append('   ')
-        return board
-
-    def check_grid(self):
-        # this method simply checks the grid to make sure
-        # that both max_l and max_w are odd numbers.
-        return True if self.max_length % 2 != 0 or self.max_width % 2 != 0\
-            else False
-
-
-

Before we can set our worm on its way, we need to know some of the computer science behind all this -called ‘Graph Traversing’. In Pseudo code what we are trying to accomplish is this:

-
# pseudo code
-
-def draw_room_on_map(room, max_distance):
-    self.draw(room)
-
-    if max_distance == 0:
-        return
-
-    for exit in room.exits:
-        if self.has_drawn(exit.destination):
-            # skip drawing if we already visited the destination
-            continue
-        else:
-            # first time here!
-            self.draw_room_on_map(exit.destination, max_distance - 1)
-
-
-

The beauty of Python is that our actual code of doing this doesn’t differ much if at all from this -Pseudo code example.

-
    -
  • max_distance is a variable indicating to our Worm how many rooms AWAY from your current location -will it map. Obviously the larger the number the more time it will take if your current location has -many many rooms around you.

  • -
-

The first hurdle here is what value to use for ‘max_distance’. There is no reason for the worm to -travel further than what is actually displayed to you. For example, if your current location is -placed in the center of a display area of size max_length = max_width = 9, then the worm need only -go 4 spaces in either direction:

-
[.][.][.][.][@][.][.][.][.]
- 4  3  2  1  0  1  2  3  4
-
-
-

The max_distance can be set dynamically based on the size of the display area. As your width/length -changes it becomes a simple algebraic linear relationship which is simply max_distance = (min(max_width, max_length) -1) / 2.

-
-
-

Building the Mapper

-

Now we can start to fill our Map object with some methods. We are still missing a few methods that -are very important:

-
    -
  • self.draw(self, room) - responsible for actually drawing room to grid.

  • -
  • self.has_drawn(self, room) - checks to see if the room has been mapped and worm has already been -here.

  • -
  • self.median(self, number) - a simple utility method that finds the median (middle point) from 0, -n

  • -
  • self.update_pos(self, room, exit_name) - updates the worm’s physical position by reassigning -self.curX/Y. .accordingly

  • -
  • self.start_loc_on_grid(self) - the very first initial draw on the grid representing your -location in the middle of the grid

  • -
  • ‘self.show_map - after everything is done convert the map into a readable string

  • -
  • self.draw_room_on_map(self, room, max_distance) - the main method that ties it all together.`

  • -
-

Now that we know which methods we need, let’s refine our initial __init__(self) to pass some -conditional statements and set it up to start building the display.

-
#mygame/world/map.py
-
-class Map(object):
-
-    def __init__(self, caller, max_width=9, max_length=9):
-        self.caller = caller
-        self.max_width = max_width
-        self.max_length = max_length
-        self.worm_has_mapped = {}
-        self.curX = None
-        self.curY = None
-
-        if self.check_grid():
-            # we have to store the grid into a variable
-            self.grid = self.create_grid()
-            # we use the algebraic relationship
-            self.draw_room_on_map(caller.location,
-                                  ((min(max_width, max_length) -1 ) / 2)
-
-
-
-

Here we check to see if the parameters for the grid are okay, then we create an empty canvas and map -our initial location as the first room!

-

As mentioned above, the code for the self.draw_room_on_map() is not much different than the Pseudo -code. The method is shown below:

-
# in mygame/world/map.py, in the Map class
-
-def draw_room_on_map(self, room, max_distance):
-    self.draw(room)
-
-    if max_distance == 0:
-        return
-
-    for exit in room.exits:
-        if exit.name not in ("north", "east", "west", "south"):
-            # we only map in the cardinal directions. Mapping up/down would be
-            # an interesting learning project for someone who wanted to try it.
-            continue
-        if self.has_drawn(exit.destination):
-            # we've been to the destination already, skip ahead.
-            continue
-
-        self.update_pos(room, exit.name.lower())
-        self.draw_room_on_map(exit.destination, max_distance - 1)
-
-
-

The first thing the “worm” does is to draw your current location in self.draw. Lets define that…

-
#in mygame/word/map.py, in the Map class
-
-def draw(self, room):
-    # draw initial ch location on map first!
-    if room == self.caller.location:
-        self.start_loc_on_grid()
-        self.worm_has_mapped[room] = [self.curX, self.curY]
-    else:
-        # map all other rooms
-        self.worm_has_mapped[room] = [self.curX, self.curY]
-        # this will use the sector_type Attribute or None if not set.
-        self.grid[self.curX][self.curY] = SYMBOLS[room.db.sector_type]
-
-
-

In self.start_loc_on_grid():

-
def median(self, num):
-    lst = sorted(range(0, num))
-    n = len(lst)
-    m = n -1
-    return (lst[n//2] + lst[m//2]) / 2.0
-
-def start_loc_on_grid(self):
-    x = self.median(self.max_width)
-    y = self.median(self.max_length)
-    # x and y are floats by default, can't index lists with float types
-    x, y = int(x), int(y)
-
-    self.grid[x][y] = SYMBOLS['you']
-    self.curX, self.curY = x, y # updating worms current location
-
-
-

After the system has drawn the current map it checks to see if the max_distance is 0 (since this -is the inital start phase it is not). Now we handle the iteration once we have each individual exit -in the room. The first thing it does is check if the room the Worm is in has been mapped already… -lets define that…

-
def has_drawn(self, room):
-    return True if room in self.worm_has_mapped.keys() else False
-
-
-

If has_drawn returns False that means the worm has found a room that hasn’t been mapped yet. It -will then ‘move’ there. The self.curX/Y sort of lags behind, so we have to make sure to track the -position of the worm; we do this in self.update_pos() below.

-
def update_pos(self, room, exit_name):
-    # this ensures the coordinates stays up to date
-    # to where the worm is currently at.
-    self.curX, self.curY = \
-      self.worm_has_mapped[room][0], self.worm_has_mapped[room][1]
-
-    # now we have to actually move the pointer
-    # variables depending on which 'exit' it found
-    if exit_name == 'east':
-        self.curY += 1
-    elif exit_name == 'west':
-        self.curY -= 1
-    elif exit_name == 'north':
-        self.curX -= 1
-    elif exit_name == 'south':
-        self.curX += 1
-
-
-

Once the system updates the position of the worm it feeds the new room back into the original -draw_room_on_map() and starts the process all over again…

-

That is essentially the entire thing. The final method is to bring it all together and make a nice -presentational string out of it using the self.show_map() method.

-
def show_map(self):
-    map_string = ""
-    for row in self.grid:
-        map_string += " ".join(row)
-        map_string += "\n"
-
-    return map_string
-
-
-
-
-

Using the Map

-

In order for the map to get triggered we store it on the Room typeclass. If we put it in -return_appearance we will get the map back every time we look at the room.

-
-

return_appearance is a default Evennia hook available on all objects; it is called e.g. by the -look command to get the description of something (the room in this case).

-
-
# in mygame/typeclasses/rooms.py
-
-from evennia import DefaultRoom
-from world.map import Map
-
-class Room(DefaultRoom):
-    
-    def return_appearance(self, looker):
-        # [...]
-        string = "%s\n" % Map(looker).show_map()
-        # Add all the normal stuff like room description,
-        # contents, exits etc.
-        string += "\n" + super().return_appearance(looker)
-        return string
-
-
-

Obviously this method of generating maps doesn’t take into account of any doors or exits that are -hidden… etc… but hopefully it serves as a good base to start with. Like previously mentioned, it -is very important to have a solid foundation on rooms before implementing this. You can try this on -vanilla evennia by using @tunnel and essentially you can just create a long straight/edgy non- -looping rooms that will show on your in-game map.

-

The above example will display the map above the room description. You could also use an -EvTable to place description and map next to each other. Some other -things you can do is to have a Command that displays with a larger radius, maybe with a -legend and other features.

-

Below is the whole map.py for your reference. You need to update your Room typeclass (see above) -to actually call it. Remember that to see different symbols for a location you also need to set the -sector_type Attribute on the room to one of the keys in the SYMBOLS dictionary. So in this -example, to make a room be mapped as [.] you would set the room’s sector_type to -"SECT_INSIDE". Try it out with @set here/sector_type = "SECT_INSIDE". If you wanted all new -rooms to have a given sector symbol, you could change the default in the SYMBOLS´ dictionary below, or you could add the Attribute in the Room's at_object_creation` method.

-
#mygame/world/map.py
-
-# These are keys set with the Attribute sector_type on the room.
-# The keys None and "you" must always exist.
-SYMBOLS = { None : ' . ',  # for rooms without a sector_type attr
-            'you' : '[@]',
-            'SECT_INSIDE': '[.]' }
-
-class Map(object):
-
-    def __init__(self, caller, max_width=9, max_length=9):
-        self.caller = caller
-        self.max_width = max_width
-        self.max_length = max_length
-        self.worm_has_mapped = {}
-        self.curX = None
-        self.curY = None
-
-        if self.check_grid():
-            # we actually have to store the grid into a variable
-            self.grid = self.create_grid()
-            self.draw_room_on_map(caller.location,
-                                 ((min(max_width, max_length) -1 ) / 2))
-    
-    def update_pos(self, room, exit_name):
-        # this ensures the pointer variables always
-        # stays up to date to where the worm is currently at.
-        self.curX, self.curY = \
-           self.worm_has_mapped[room][0], self.worm_has_mapped[room][1]
-
-        # now we have to actually move the pointer
-        # variables depending on which 'exit' it found
-        if exit_name == 'east':
-            self.curY += 1
-        elif exit_name == 'west':
-            self.curY -= 1
-        elif exit_name == 'north':
-            self.curX -= 1
-        elif exit_name == 'south':
-            self.curX += 1
-
-    def draw_room_on_map(self, room, max_distance):
-        self.draw(room)
-
-        if max_distance == 0:
-            return
-        
-        for exit in room.exits:
-            if exit.name not in ("north", "east", "west", "south"):
-                # we only map in the cardinal directions. Mapping up/down would be
-                # an interesting learning project for someone who wanted to try it.
-                continue
-            if self.has_drawn(exit.destination):
-                # we've been to the destination already, skip ahead.
-                continue
-
-            self.update_pos(room, exit.name.lower())
-            self.draw_room_on_map(exit.destination, max_distance - 1)
-        
-    def draw(self, room):
-        # draw initial caller location on map first!
-        if room == self.caller.location:
-            self.start_loc_on_grid()
-            self.worm_has_mapped[room] = [self.curX, self.curY]
-        else:
-            # map all other rooms
-            self.worm_has_mapped[room] = [self.curX, self.curY]
-            # this will use the sector_type Attribute or None if not set.
-            self.grid[self.curX][self.curY] = SYMBOLS[room.db.sector_type]
-
-    def median(self, num):
-        lst = sorted(range(0, num))
-        n = len(lst)
-        m = n -1
-        return (lst[n//2] + lst[m//2]) / 2.0
-   
-    def start_loc_on_grid(self):
-        x = self.median(self.max_width)
-        y = self.median(self.max_length)
-        # x and y are floats by default, can't index lists with float types
-        x, y = int(x), int(y)
-
-        self.grid[x][y] = SYMBOLS['you']
-        self.curX, self.curY = x, y # updating worms current location
-     
-
-    def has_drawn(self, room):
-        return True if room in self.worm_has_mapped.keys() else False
-
-
-    def create_grid(self):
-        # This method simply creates an empty grid
-        # with the specified variables from __init__(self):
-        board = []
-        for row in range(self.max_width):
-            board.append([])
-            for column in range(self.max_length):
-                board[row].append('   ')
-        return board
-
-    def check_grid(self):
-        # this method simply checks the grid to make sure
-        # both max_l and max_w are odd numbers
-        return True if self.max_length % 2 != 0 or \
-                    self.max_width % 2 != 0 else False
-
-    def show_map(self):
-        map_string = ""
-        for row in self.grid:
-            map_string += " ".join(row)
-            map_string += "\n"
-
-        return map_string
-
-
-
-
-

Final Comments

-

The Dynamic map could be expanded with further capabilities. For example, it could mark exits or -allow NE, SE etc directions as well. It could have colors for different terrain types. One could -also look into up/down directions and figure out how to display that in a good way.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/EvEditor.html b/docs/0.9.5/EvEditor.html deleted file mode 100644 index a3e7dd7990..0000000000 --- a/docs/0.9.5/EvEditor.html +++ /dev/null @@ -1,296 +0,0 @@ - - - - - - - - - EvEditor — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

EvEditor

-

Evennia offers a powerful in-game line editor in evennia.utils.eveditor.EvEditor. This editor, -mimicking the well-known VI line editor. It offers line-by-line editing, undo/redo, line deletes, -search/replace, fill, dedent and more.

-
-

Launching the editor

-

The editor is created as follows:

-
from evennia.utils.eveditor import EvEditor
-
-EvEditor(caller,
-         loadfunc=None, savefunc=None, quitfunc=None,
-         key="")
-
-
-
    -
  • caller (Object or Account): The user of the editor.

  • -
  • loadfunc (callable, optional): This is a function called when the editor is first started. It -is called with caller as its only argument. The return value from this function is used as the -starting text in the editor buffer.

  • -
  • savefunc (callable, optional): This is called when the user saves their buffer in the editor is -called with two arguments, caller and buffer, where buffer is the current buffer.

  • -
  • quitfunc (callable, optional): This is called when the user quits the editor. If given, all -cleanup and exit messages to the user must be handled by this function.

  • -
  • key (str, optional): This text will be displayed as an identifier and reminder while editing. -It has no other mechanical function.

  • -
  • persistent (default False): if set to True, the editor will survive a reboot.

  • -
-
-
-

Example of usage

-

This is an example command for setting a specific Attribute using the editor.

-
from evennia import Command
-from evennia.utils import eveditor
-
-class CmdSetTestAttr(Command):
-    """
-    Set the "test" Attribute using
-    the line editor.
-
-    Usage:
-       settestattr
-
-    """
-    key = "settestattr"
-    def func(self):
-        "Set up the callbacks and launch the editor"
-        def load(caller):
-            "get the current value"
-            return caller.attributes.get("test")
-        def save(caller, buffer):
-            "save the buffer"
-            caller.attributes.set("test", buffer)
-        def quit(caller):
-            "Since we define it, we must handle messages"
-            caller.msg("Editor exited")
-        key = "%s/test" % self.caller
-        # launch the editor
-        eveditor.EvEditor(self.caller,
-                          loadfunc=load, savefunc=save, quitfunc=quit,
-                          key=key)
-
-
-
-
-

Persistent editor

-

If you set the persistent keyword to True when creating the editor, it will remain open even -when reloading the game. In order to be persistent, an editor needs to have its callback functions -(loadfunc, savefunc and quitfunc) as top-level functions defined in the module. Since these -functions will be stored, Python will need to find them.

-
from evennia import Command
-from evennia.utils import eveditor
-
-def load(caller):
-    "get the current value"
-    return caller.attributes.get("test")
-
-def save(caller, buffer):
-    "save the buffer"
-    caller.attributes.set("test", buffer)
-
-def quit(caller):
-    "Since we define it, we must handle messages"
-    caller.msg("Editor exited")
-
-class CmdSetTestAttr(Command):
-    """
-    Set the "test" Attribute using
-    the line editor.
-
-    Usage:
-       settestattr
-
-    """
-    key = "settestattr"
-    def func(self):
-        "Set up the callbacks and launch the editor"
-        key = "%s/test" % self.caller
-        # launch the editor
-        eveditor.EvEditor(self.caller,
-                          loadfunc=load, savefunc=save, quitfunc=quit,
-                          key=key, persistent=True)
-
-
-
-
-

Line editor usage

-

The editor mimics the VIM editor as best as possible. The below is an excerpt of the return from -the in-editor help command (:h).

-
 <txt>  - any non-command is appended to the end of the buffer.
- :  <l> - view buffer or only line <l>
- :: <l> - view buffer without line numbers or other parsing
- :::    - print a ':' as the only character on the line...
- :h     - this help.
-
- :w     - save the buffer (don't quit)
- :wq    - save buffer and quit
- :q     - quit (will be asked to save if buffer was changed)
- :q!    - quit without saving, no questions asked
-
- :u     - (undo) step backwards in undo history
- :uu    - (redo) step forward in undo history
- :UU    - reset all changes back to initial state
-
- :dd <l>     - delete line <n>
- :dw <l> <w> - delete word or regex <w> in entire buffer or on line <l>
- :DD         - clear buffer
-
- :y  <l>        - yank (copy) line <l> to the copy buffer
- :x  <l>        - cut line <l> and store it in the copy buffer
- :p  <l>        - put (paste) previously copied line directly after <l>
- :i  <l> <txt>  - insert new text <txt> at line <l>. Old line will move down
- :r  <l> <txt>  - replace line <l> with text <txt>
- :I  <l> <txt>  - insert text at the beginning of line <l>
- :A  <l> <txt>  - append text after the end of line <l>
-
- :s <l> <w> <txt> - search/replace word or regex <w> in buffer or on line <l>
-
- :f <l>    - flood-fill entire buffer or line <l>
- :fi <l>   - indent entire buffer or line <l>
- :fd <l>   - de-indent entire buffer or line <l>
-
- :echo - turn echoing of the input on/off (helpful for some clients)
-
-    Legend:
-    <l> - line numbers, or range lstart:lend, e.g. '3:7'.
-    <w> - one word or several enclosed in quotes.
-    <txt> - longer string, usually not needed to be enclosed in quotes.
-
-
-
-
-

The EvEditor to edit code

-

The EvEditor is also used to edit some Python code in Evennia. The @py command supports an -/edit switch that will open the EvEditor in code mode. This mode isn’t significantly different -from the standard one, except it handles automatic indentation of blocks and a few options to -control this behavior.

-
    -
  • :< to remove a level of indentation for the future lines.

  • -
  • :+ to add a level of indentation for the future lines.

  • -
  • := to disable automatic indentation altogether.

  • -
-

Automatic indentation is there to make code editing more simple. Python needs correct indentation, -not as an aesthetic addition, but as a requirement to determine beginning and ending of blocks. The -EvEditor will try to guess the next level of indentation. If you type a block “if”, for instance, -the EvEditor will propose you an additional level of indentation at the next line. This feature -cannot be perfect, however, and sometimes, you will have to use the above options to handle -indentation.

-

:= can be used to turn automatic indentation off completely. This can be very useful when trying -to paste several lines of code that are already correctly indented, for instance.

-

To see the EvEditor in code mode, you can use the @py/edit command. Type in your code (on one or -several lines). You can then use the :w option (save without quitting) and the code you have -typed will be executed. The :! will do the same thing. Executing code while not closing the -editor can be useful if you want to test the code you have typed but add new lines after your test.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/EvMenu.html b/docs/0.9.5/EvMenu.html deleted file mode 100644 index 9757cfa061..0000000000 --- a/docs/0.9.5/EvMenu.html +++ /dev/null @@ -1,1367 +0,0 @@ - - - - - - - - - EvMenu — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

EvMenu

-
-

Introduction

-

The EvMenu utility class is located in -evennia/utils/evmenu.py. -It allows for easily adding interactive menus to the game; for example to implement Character -creation, building commands or similar. Below is an example of offering NPC conversation choices:

-
The guard looks at you suspiciously.
-"No one is supposed to be in here ..."
-he says, a hand on his weapon.
-_______________________________________________
- 1. Try to bribe him [Cha + 10 gold]
- 2. Convince him you work here [Int]
- 3. Appeal to his vanity [Cha]
- 4. Try to knock him out [Luck + Dex]
- 5. Try to run away [Dex]
-
-
-
-

This is an example of a menu node. Think of a node as a point where the menu stops printing text -and waits for user to give some input. By jumping to different nodes depending on the input, a menu -is constructed.

-
-
-

Ways to create the menu

-
-

node functions

-

The native way to define an EvMenu is to define Python functions, one per node. It will load all -those -functions/nodes either from a module or by being passed a dictionary mapping the node’s names to -said functions, like {"nodename": <function>, ...}. Since you are dealing with raw code, this is -by -far the most powerful way - for example you could have dynamic nodes that change content depending -on game context, time and what you picked before.

-
- -
-
-

Launching the menu

-

Initializing the menu is done using a call to the evennia.utils.evmenu.EvMenu class. This is the -most common way to do so - from inside a Command:

-
# in, for example gamedir/commands/command.py
-
-from evennia.utils.evmenu import EvMenu
-
-class CmdTestMenu(Command):
-
-    key = "testcommand"
-
-    def func(self):
-
-        EvMenu(caller, "world.mymenu")
-
-
-
-

When running this command, the menu will start using the menu nodes loaded from -mygame/world/mymenu.py and use this to build the menu-tree - each function name becomes -the name of a node in the tree. See next section on how to define menu nodes.

-

Alternatively, you could pass the menu-tree to EvMenu directly:

-

-  menutree = {"start": nodestartfunc,
-              "node1": nodefunc1,
-              "node2": nodefunc2,, ...}
-  EvMenu(caller, menutree)
-
-
-
-

This menutree can also be generated from an EvMenu template

-
   from evennia.utils.evmenu import parse_menu_template
-  
-   menutree = parse_menu_template(caller, template_string, goto_callables)
-   EvMenu(caller, menutree)
-
-
-

The template_string and goto_callables are described in Template language -section.

-
-
-

The EvMenu class

-

The EvMenu has the following optional callsign:

-
EvMenu(caller, menu_data,
-       startnode="start",
-       cmdset_mergetype="Replace", cmdset_priority=1,
-       auto_quit=True, auto_look=True, auto_help=True,
-       cmd_on_exit="look",
-       persistent=False,
-       startnode_input="",
-       session=None,
-       debug=False,
-       **kwargs)
-
-
-
-
    -
  • caller (Object or Account): is a reference to the object using the menu. This object will get a -new CmdSet assigned to it, for handling the menu.

  • -
  • menu_data (str, module or dict): is a module or python path to a module where the global-level -functions will each be considered to be a menu node. Their names in the module will be the names -by which they are referred to in the module. Importantly, function names starting with an -underscore -_ will be ignored by the loader. Alternatively, this can be a direct mapping -{"nodename":function, ...}.

  • -
  • startnode (str): is the name of the menu-node to start the menu at. Changing this means that -you can jump into a menu tree at different positions depending on circumstance and thus possibly -re-use menu entries.

  • -
  • cmdset_mergetype (str): This is usually one of “Replace” or “Union” (see [CmdSets](Command- -Sets). -The first means that the menu is exclusive - the user has no access to any other commands while -in the menu. The Union mergetype means the menu co-exists with previous commands (and may -overload -them, so be careful as to what to name your menu entries in this case).

  • -
  • cmdset_priority (int): The priority with which to merge in the menu cmdset. This allows for -advanced usage.

  • -
  • auto_quit, auto_look, auto_help (bool): If either of these are True, the menu -automatically makes a quit, look or help command available to the user. The main reason why -you’d want to turn this off is if you want to use the aliases “q”, “l” or “h” for something in -your -menu. Nevertheless, at least quit is highly recommend - if False, the menu must itself -supply -an “exit node” (a node without any options), or the user will be stuck in the menu until the -server -reloads (or eternally if the menu is persistent)!

  • -
  • cmd_on_exit (str): This command string will be executed right after the menu has closed down. -From experience, it’s useful to trigger a “look” command to make sure the user is aware of the -change of state; but any command can be used. If set to None, no command will be triggered -after -exiting the menu.

  • -
  • persistent (bool) - if True, the menu will survive a reload (so the user will not be kicked -out by the reload - make sure they can exit on their own!)

  • -
  • startnode_input (str or (str, dict) tuple): Pass an input text or a input text + kwargs to the -start node as if it was entered on a fictional previous node. This can be very useful in order to -start a menu differently depending on the Command’s arguments in which it was initialized.

  • -
  • session (Session): Useful when calling the menu from an Account in -MULTISESSION_MODDE higher than 2, to make sure only the right Session sees the menu output.

  • -
  • debug (bool): If set, the menudebug command will be made available in the menu. Use it to -list the current state of the menu and use menudebug <variable> to inspect a specific state -variable from the list.

  • -
  • All other keyword arguments will be available as initial data for the nodes. They will be -available in all nodes as properties on caller.ndb._menutree (see below). These will also -survive a @reload if the menu is persistent.

  • -
-

You don’t need to store the EvMenu instance anywhere - the very act of initializing it will store it -as caller.ndb._menutree on the caller. This object will be deleted automatically when the menu -is exited and you can also use it to store your own temporary variables for access throughout the -menu. Temporary variables you store on a persistent _menutree as it runs will -not survive a @reload, only those you set as part of the original EvMenu call.

-
-
-

The Menu nodes

-

The EvMenu nodes consist of functions on one of these forms.

-
def menunodename1(caller):
-    # code
-    return text, options
-
-def menunodename2(caller, raw_string):
-    # code
-    return text, options
-
-def menunodename3(caller, raw_string, **kwargs):
-    # code
-    return text, options
-
-
-
-
-

While all of the above forms are okay, it’s recommended to stick to the third and last form since -it -gives the most flexibility. The previous forms are mainly there for backwards compatibility with -existing menus from a time when EvMenu was less able.

-
-
-

Input arguments to the node

-
    -
  • caller (Object or Account): The object using the menu - usually a Character but could also be a -Session or Account depending on where the menu is used.

  • -
  • raw_string (str): If this is given, it will be set to the exact text the user entered on the -previous node (that is, the command entered to get to this node). On the starting-node of the -menu, this will be an empty string, unless startnode_input was set.

  • -
  • kwargs (dict): These extra keyword arguments are extra optional arguments passed to the node -when the user makes a choice on the previous node. This may include things like status flags -and details about which exact option was chosen (which can be impossible to determine from -raw_string alone). Just what is passed in kwargs is up to you when you create the previous -node.

  • -
-
-
-

Return values from the node

-

Each function must return two variables, text and options.

-
-

text

-

The text variable is a string or tuple. This text is what will be displayed when the user reaches -this node. If this is a tuple, then the first element of the tuple will be considered the displayed -text and the second the help-text to display when the user enters the help command on this node.

-
    text = ("This is the text to display", "This is the help text for this node")
-
-
-

Returning a None text is allowed and simply leads to a node with no text and only options. If the -help text is not given, the menu will give a generic error message when using help.

-
-
-

options

-

The options list describe all the choices available to the user when viewing this node. If -options is -returned as None, it means that this node is an Exit node - any text is displayed and then the -menu immediately exits, running the exit_cmd if given.

-

Otherwise, options should be a list (or tuple) of dictionaries, one for each option. If only one -option is -available, a single dictionary can also be returned. This is how it could look:

-
def node_test(caller, raw_string, **kwargs):
-
-    text = "A goblin attacks you!"
-
-    options = (
-        {"key": ("Attack", "a", "att"),
-         "desc": "Strike the enemy with all your might",
-         "goto": "node_attack"},
-        {"key": ("Defend", "d", "def"),
-         "desc": "Hold back and defend yourself",
-         "goto": (_defend, {"str": 10, "enemyname": "Goblin"})})
-
-    return text, options
-
-
-
-

This will produce a menu node looking like this:

-
A goblin attacks you!
-________________________________
-
-Attack: Strike the enemy with all your might
-Defend: Hold back and defend yourself
-
-
-
-
-
option-key ‘key’
-

The option’s key is what the user should enter in order to choose that option. If given as a -tuple, the -first string of that tuple will be what is shown on-screen while the rest are aliases for picking -that option. In the above example, the user could enter “Attack” (or “attack”, it’s not -case-sensitive), “a” or “att” in order to attack the goblin. Aliasing is useful for adding custom -coloring to the choice. The first element of the aliasing tuple should then be the colored version, -followed by a version without color - since otherwise the user would have to enter the color codes -to select that choice.

-

Note that the key is optional. If no key is given, it will instead automatically be replaced -with a running number starting from 1. If removing the key part of each option, the resulting -menu node would look like this instead:

-
A goblin attacks you!
-________________________________
-
-1: Strike the enemy with all your might
-2: Hold back and defend yourself
-
-
-
-

Whether you want to use a key or rely on numbers is mostly -a matter of style and the type of menu.

-

EvMenu accepts one important special key given only as "_default". This key is used when a user -enters something that does not match any other fixed keys. It is particularly useful for getting -user input:

-
def node_readuser(caller, raw_string, **kwargs):
-    text = "Please enter your name"
-
-    options = {"key": "_default",
-               "goto": "node_parse_input"}
-
-    return text, options
-
-
-
-

A "_default" option does not show up in the menu, so the above will just be a node saying -"Please enter your name". The name they entered will appear as raw_string in the next node.

-
-
-
-

option-key ‘desc’

-

This simply contains the description as to what happens when selecting the menu option. For -"_default" options or if the key is already long or descriptive, it is not strictly needed. But -usually it’s better to keep the key short and put more detail in desc.

-
-
-

option-key ‘goto’

-

This is the operational part of the option and fires only when the user chooses said option. Here -are three ways to write it

-

-def _action_two(caller, raw_string, **kwargs):
-    # do things ...
-    return "calculated_node_to_go_to"
-
-def _action_three(caller, raw_string, **kwargs):
-    # do things ...
-    return "node_four", {"mode": 4}
-
-def node_select(caller, raw_string, **kwargs):
-
-    text = ("select one",
-            "help - they all do different things ...")
-
-    options = ({"desc": "Option one",
-                            "goto": "node_one"},
-                     {"desc": "Option two",
-                            "goto": _action_two},
-                     {"desc": "Option three",
-                            "goto": (_action_three, {"key": 1, "key2": 2})}
-              )
-
-    return text, options
-
-
-
-

As seen above, goto could just be pointing to a single nodename string - the name of the node to -go to. When given like this, EvMenu will look for a node named like this and call its associated -function as

-
    nodename(caller, raw_string, **kwargs)
-
-
-

Here, raw_string is always the input the user entered to make that choice and kwargs are the -same as those kwargs that already entered the current node (they are passed on).

-

Alternatively the goto could point to a “goto-callable”. Such callables are usually defined in the -same -module as the menu nodes and given names starting with _ (to avoid being parsed as nodes -themselves). These callables will be called the same as a node function - callable(caller, raw_string, **kwargs), where raw_string is what the user entered on this node and **kwargs is -forwarded from the node’s own input.

-

The goto option key could also point to a tuple (callable, kwargs) - this allows for customizing -the kwargs passed into the goto-callable, for example you could use the same callable but change the -kwargs passed into it depending on which option was actually chosen.

-

The “goto callable” must either return a string "nodename" or a tuple ("nodename", mykwargs). -This will lead to the next node being called as either nodename(caller, raw_string, **kwargs) or -nodename(caller, raw_string, **mykwargs) - so this allows changing (or replacing) the options -going -into the next node depending on what option was chosen.

-

There is one important case - if the goto-callable returns None for a nodename, the current -node will run again, possibly with different kwargs. This makes it very easy to re-use a node over -and over, for example allowing different options to update some text form being passed and -manipulated for every iteration.

-
-

The EvMenu also supports the exec option key. This allows for running a callable before the -goto-callable. This functionality comes from a time before goto could be a callable and is -deprecated as of Evennia 0.8. Use goto for all functionality where you’d before use exec.

-
-
-
-
-
-

Temporary storage

-

When the menu starts, the EvMenu instance is stored on the caller as caller.ndb._menutree. Through -this object you can in principle reach the menu’s internal state if you know what you are doing. -This is also a good place to store temporary, more global variables that may be cumbersome to keep -passing from node to node via the **kwargs. The _menutree will be deleted automatically when the -menu closes, meaning you don’t need to worry about cleaning anything up.

-

If you want permanent state storage, it’s instead better to use an Attribute on caller. Remember -that this will remain after the menu closes though, so you need to handle any needed cleanup -yourself.

-
-
-

Customizing Menu formatting

-

The EvMenu display of nodes, options etc are controlled by a series of formatting methods on the -EvMenu class. To customize these, simply create a new child class of EvMenu and override as -needed. Here is an example:

-
from evennia.utils.evmenu import EvMenu
-
-class MyEvMenu(EvMenu):
-
-    def nodetext_formatter(self, nodetext):
-        """
-        Format the node text itself.
-
-        Args:
-            nodetext (str): The full node text (the text describing the node).
-
-        Returns:
-            nodetext (str): The formatted node text.
-
-        """
-
-    def helptext_formatter(self, helptext):
-        """
-        Format the node's help text
-
-        Args:
-            helptext (str): The unformatted help text for the node.
-
-        Returns:
-            helptext (str): The formatted help text.
-
-        """
-
-    def options_formatter(self, optionlist):
-        """
-        Formats the option block.
-
-        Args:
-            optionlist (list): List of (key, description) tuples for every
-                option related to this node.
-            caller (Object, Account or None, optional): The caller of the node.
-
-        Returns:
-            options (str): The formatted option display.
-
-        """
-
-    def node_formatter(self, nodetext, optionstext):
-        """
-        Formats the entirety of the node.
-
-        Args:
-            nodetext (str): The node text as returned by `self.nodetext_formatter`.
-            optionstext (str): The options display as returned by `self.options_formatter`.
-            caller (Object, Account or None, optional): The caller of the node.
-
-        Returns:
-            node (str): The formatted node to display.
-
-        """
-
-
-
-

See evennia/utils/evmenu.py for the details of their default implementations.

-
-
-

Evmenu templating language

-

The EvMenu is very powerful and flexible. But often your menu is simple enough to -not require the full power of EvMenu. For this you can use the Evmenu templating language.

-

This is how the templating is used:

-
from evennia.utils.evmenu import parse_menu_template, EvMenu
-
-template_string = "(will be described below)"
-# this could be empty if you don't need to access any callables
-# in your template
-goto_callables = {"mycallable1": function, ...}
-
-# generate the menutree
-menutree = parse_menu_template(caller, template_string, goto_callables)
-# a normal EvMenu call
-EvMenu(caller, menutree, ...)
-
-
-
-

… So the parse_menu_template is just another way to generate the menutree dict needed by -EvMenu - after this EvMenu works normally.

-

The good thing with this two-step procedude is that you can mix- and match - if you wanted -you could insert a normal, fully flexible function-based node-function in the menutree before -passing -the whole thing into EvMenu and get the best of both worlds. It also makes it -easy to substitute base EvMenu with a child class that changes the menu display.

-

… But if you really don’t need any such customization, you can also apply the template in one step -using -the template2menu helper:

-
from evennia.utils.evmenu import template2menu
-
-template_string = "(will be described below)"
-goto_callables = {"mycallable1": function, ...}
-
-template2menu(caller, template_string, goto_callables, startnode="start", ...)
-
-
-
-

In addition to the template-related arguments, template2menu takes all the same **kwargs -as EvMenu and will parse the template and start the menu for you in one go.

-
-

The templating string

-

The template is a normal string with a very simple format. Each node begins -with a marker ## Node <name of node>, follwowed by a ## Options separator (the Node and -Options are -case-insensitive).

-
template_string = """
-
-## NODE start
-
-<text for the node>
-
-## OPTIONS
-
-# this is a comment. Only line-comments are allowed.
-
-key;alias;alias: description -> goto_str_or_callable
-key;alias;alias: goto_str_or_callable
->pattern: goto_str_or_callable
-
-"""
-
-
-
    -
  • The text after ## NODE defines the name of the node. This must be unique within the -menu because this is what you use for goto statements. The name could have spaces.

  • -
  • The area between ## NODE and ## OPTIONS contains the text of the node. It can have -normal formatting and will retain intentation.

  • -
  • The ## OPTIONS section, until the next ## NODE or the end of the string, -holds the options, one per line.

  • -
  • Option-indenting is ignored but can be useful for readability.

  • -
  • The options-section can also have line-comments, marked by starting the line with #.

  • -
  • A node without a following ## OPTIONS section indicates an end node, and reaching -it will print the text and immediately exit the menu (same as for regular EvMenu).

  • -
-
-
-

Templating options format

-

The normal, full syntax is:

-
key;alias;alias: description -> goto_str_or_callable
-
-
-

An example would be

-
next;n: Go to node Two -> node2
-
-
-

In the menu, this will become an option

-
next: Go to node Two
-
-
-

where you can enter next or n to go to the menu node named node2.

-

To skip the description, just add the goto without the ->:

-
next;n: node2
-
-
-

This will create a menu option without any description:

-
next
-
-
-

A special key is >. This acts as a pattern matcher. Between > and the : one -can fit an optional pattern. This -pattern will first be parsed with glob-style -parsing and then -with regex, and only if -the player’s input matches either will the option be chosen. An input-matching -option cannot have a description.

-
  # this matches the empty string (just pressing return)
-  >: node2
-
-  # this matches input starting with 'test' (regex match)
-  > ^test.+?: testnode
-
-  # this matches any number input (regex match)
-  > [0-9]+?: countnode
-
-  # this matches everything not covered by previous options
-  # (glob-matching, space is stripped without quotes)
-  > *: node3
-
-
-

You can have multiple pattern-matchers for a node but remember that options are -checked in the order they are listed. So make sure to put your pattern-matchers -in decending order of generality; if you have a ‘catch-all’ pattern, -it should be put last or those behind it will never be tried.

-
   next;n: node2
-   back;b: node1
-   >: node2
-
-
-

The above would give you the option to write next/back but you can also just press return to move on -to the next node.

-
-
-

Templating goto-callables

-

Instead of giving the name of a node to go to, you can also give the name -of a goto_callable, which in turn returns the name of the node to go to. You -tell the template it’s a callable by simply adding () at the end.

-
next: Go to node 2 -> goto_node2()
-
-
-

You can also add keyword arguments:

-
back: myfunction(from=foo)
-
-
-
-

Note: ONLY keyword-arguments are supported! Trying to pass a positional -argument will lead to an error.

-
-

The contents of the kwargs-values will be evaluated by literal_eval so -you don’t need to add quotes to strings unless they have spaces in them. Numbers -will be converted correctly, but more complex input structures (like lists or dicts) will -not - if you want more complex input you should use a full function-based EvMenu -node instead.

-

The goto-callable is defined just like any Evmenu goto-func. You must always -use the full form (including **kwargs):

-
def mygotocallable(caller, raw_string, **kwargs):
-  # ...
-  return "nodename_to_goto"
-
-
-
-

Return None to re-run the current node. Any keyword arguments you specify in -your template will be passed to your goto-callable in **kwargs. Unlike in -regular EvMenu nodes you can’t return kwargs to pass it between nodes and other dynamic -tricks.

-

All goto-callables you use in your menu-template must be added to the -goto_callable mapping that you pass to parse_menu_template or -template2menu.

-
-
-

Templating example to show all possible options:

-

-template_string = """
-
-## NODE start
-
-This is the text of the start node.
-Both ## NODE, ## node or ## Node works. The node-name can have
-spaces.
-
-The text area can have multiple lines, line breaks etc.
-
-## OPTIONS
-
-    # here starts the option-defition
-    # comments are only allowed from beginning of line.
-    # Indenting is not necessary, but good for readability
-
-    1: Option number 1 -> node1
-    2: Option number 2 -> node2
-    next: This steps next -> go_back()
-    # the -> can be ignored if there is no desc
-    back: go_back(from_node=start)
-    abort: abort
-
-# ----------------------------------- this is ignored
-
-## NODE node1
-
-Text for Node1. Enter a message!
-<return> to go back.
-
-## options
-
-    # Starting the option-line with >
-    # allows to perform different actions depending on
-    # what is inserted.
-
-    # this catches everything starting with foo
-    > foo*: handle_foo_message()
-
-    # regex are also allowed (this catches number inputs)
-    > [0-9]+?: handle_numbers()
-
-    # this catches the empty return
-    >: start
-
-    # this catches everything else
-    > *: handle_message(from_node=node1)
-
-# -----------------------------------------
-
-## NODE node2
-
-Text for Node2. Just go back.
-
-## options
-
-    >: start
-
-# node abort
-
-This exits the menu since there is no `## options` section.
-
-
-"""
-
-# we assume the callables are defined earlier
-goto_callables = {"go_back": go_back_func,
-                  "handle_foo_message": handle_message,
-                  "handle_numbers": my_number_handler,
-                  "handle_message": handle_message2}
-
-# boom - a menu
-template2menu(caller, template_string, goto_callables)
-
-
-
-
-
-
-

Examples:

- -
-

Example: Simple branching menu

-

Below is an example of a simple branching menu node leading to different other nodes depending on -choice:

-
# in mygame/world/mychargen.py
-
-def define_character(caller):
-    text = \
-    """
-    What aspect of your character do you want
-    to change next?
-    """
-    options = ({"desc": "Change the name",
-                "goto": "set_name"},
-               {"desc": "Change the description",
-                "goto": "set_description"})
-    return text, options
-
-EvMenu(caller, "world.mychargen", startnode="define_character")
-
-
-
-

This will result in the following node display:

-
What aspect of your character do you want
-to change next?
-_________________________
-1: Change the name
-2: Change the description
-
-
-

Note that since we didn’t specify the “name” key, EvMenu will let the user enter numbers instead. In -the following examples we will not include the EvMenu call but just show nodes running inside the -menu. Also, since EvMenu also takes a dictionary to describe the menu, we could have called it -like this instead in the example:

-
EvMenu(caller, {"define_character": define_character}, startnode="define_character")
-
-
-
-
-
-

Example: Dynamic goto

-

-def _is_in_mage_guild(caller, raw_string, **kwargs):
-    if caller.tags.get('mage', category="guild_member"):
-        return "mage_guild_welcome"
-    else:
-        return "mage_guild_blocked"
-
-def enter_guild:
-    text = 'You say to the mage guard:'
-    options ({'desc': 'I need to get in there.',
-              'goto': _is_in_mage_guild},
-             {'desc': 'Never mind',
-              'goto': 'end_conversation'})
-    return text, options
-
-
-

This simple callable goto will analyse what happens depending on who the caller is. The -enter_guild node will give you a choice of what to say to the guard. If you try to enter, you will -end up in different nodes depending on (in this example) if you have the right Tag set on -yourself or not. Note that since we don’t include any ‘key’s in the option dictionary, you will just -get to pick between numbers.

-
-
-

Example: Set caller properties

-

Here is an example of passing arguments into the goto callable and use that to influence -which node it should go to next:

-

-def _set_attribute(caller, raw_string, **kwargs):
-    "Get which attribute to modify and set it"
-
-    attrname, value = kwargs.get("attr", (None, None))
-    next_node = kwargs.get("next_node")
-
-    caller.attributes.add(attrname, attrvalue)
-
-    return next_node
-
-
-def node_background(caller):
-    text = \
-    """
-    {} experienced a traumatic event
-    in their childhood. What was it?
-    """.format(caller.key}
-
-    options = ({"key": "death",
-                "desc": "A violent death in the family",
-                "goto": (_set_attribute, {"attr": ("experienced_violence", True),
-                                          "next_node": "node_violent_background"})},
-               {"key": "betrayal",
-                "desc": "The betrayal of a trusted grown-up",
-                "goto": (_set_attribute, {"attr": ("experienced_betrayal", True),
-                                          "next_node": "node_betrayal_background"})})
-    return text, options
-
-
-

This will give the following output:

-
Kovash the magnificent experienced a traumatic event
-in their childhood. What was it?
-____________________________________________________
-death: A violent death in the family
-betrayal: The betrayal of a trusted grown-up
-
-
-
-

Note above how we use the _set_attribute helper function to set the attribute depending on the -User’s choice. In thie case the helper function doesn’t know anything about what node called it - we -even tell it which nodename it should return, so the choices leads to different paths in the menu. -We could also imagine the helper function analyzing what other choices

-
-
-

Example: Get arbitrary input

-

An example of the menu asking the user for input - any input.

-

-def _set_name(caller, raw_string, **kwargs):
-
-    inp = raw_string.strip()
-
-    prev_entry = kwargs.get("prev_entry")
-
-    if not inp:
-        # a blank input either means OK or Abort
-        if prev_entry:
-            caller.key = prev_entry
-            caller.msg("Set name to {}.".format(prev_entry))
-            return "node_background"
-        else:
-            caller.msg("Aborted.")
-            return "node_exit"
-    else:
-        # re-run old node, but pass in the name given
-        return None, {"prev_entry": inp}
-
-
-def enter_name(caller, raw_string, **kwargs):
-
-    # check if we already entered a name before
-    prev_entry = kwargs.get("prev_entry")
-
-    if prev_entry:
-        text = "Current name: {}.\nEnter another name or <return> to accept."
-    else:
-        text = "Enter your character's name or <return> to abort."
-
-    options = {"key": "_default",
-               "goto": (_set_name, {"prev_entry": prev_entry})}
-
-    return text, options
-
-
-
-

This will display as

-
Enter your character's name or <return> to abort.
-
-> Gandalf
-
-Current name: Gandalf
-Enter another name or <return> to accept.
-
->
-
-Set name to Gandalf.
-
-
-
-

Here we re-use the same node twice for reading the input data from the user. Whatever we enter will -be caught by the _default option and passed into the helper function. We also pass along whatever -name we have entered before. This allows us to react correctly on an “empty” input - continue to the -node named "node_background" if we accept the input or go to an exit node if we presses Return -without entering anything. By returning None from the helper function we automatically re-run the -previous node, but updating its ingoing kwargs to tell it to display a different text.

-
-
-

Example: Storing data between nodes

-

A convenient way to store data is to store it on the caller.ndb._menutree which you can reach from -every node. The advantage of doing this is that the _menutree NAttribute will be deleted -automatically when you exit the menu.

-

-def _set_name(caller, raw_string, **kwargs):
-
-    caller.ndb._menutree.charactersheet = {}
-    caller.ndb._menutree.charactersheet['name'] = raw_string
-    caller.msg("You set your name to {}".format(raw_string)
-    return "background"
-
-def node_set_name(caller):
-    text = 'Enter your name:'
-    options = {'key': '_default',
-               'goto': _set_name}
-
-    return text, options
-
-...
-
-
-def node_view_sheet(caller):
-    text = "Character sheet:\n {}".format(self.ndb._menutree.charactersheet)
-
-    options = ({"key": "Accept",
-                "goto": "finish_chargen"},
-               {"key": "Decline",
-                "goto": "start_over"})
-
-    return text, options
-
-
-
-

Instead of passing the character sheet along from node to node through the kwargs we instead -set it up temporarily on caller.ndb._menutree.charactersheet. This makes it easy to reach from -all nodes. At the end we look at it and, if we accept the character the menu will likely save the -result to permanent storage and exit.

-
-

One point to remember though is that storage on caller.ndb._menutree is not persistent across -@reloads. If you are using a persistent menu (using EvMenu(..., persistent=True) you should -use -caller.db to store in-menu data like this as well. You must then yourself make sure to clean it -when the user exits the menu.

-
-
-
-

Example: Repeating the same node

-

Sometimes you want to make a chain of menu nodes one after another, but you don’t want the user to -be able to continue to the next node until you have verified that what they input in the previous -node is ok. A common example is a login menu:

-

-def _check_username(caller, raw_string, **kwargs):
-    # we assume lookup_username() exists
-    if not lookup_username(raw_string):
-        # re-run current node by returning `None`
-        caller.msg("|rUsername not found. Try again.")
-        return None
-    else:
-        # username ok - continue to next node
-        return "node_password"
-
-
-def node_username(caller):
-    text = "Please enter your user name."
-    options = {"key": "_default",
-               "goto": _check_username}
-    return text, options
-
-
-def _check_password(caller, raw_string, **kwargs):
-
-    nattempts = kwargs.get("nattempts", 0)
-    if nattempts > 3:
-        caller.msg("Too many failed attempts. Logging out")
-        return "node_abort"
-    elif not validate_password(raw_string):
-        caller.msg("Password error. Try again.")
-        return None, {"nattempts", nattempts + 1}
-    else:
-        # password accepted
-        return "node_login"
-
-def node_password(caller, raw_string, **kwargs):
-    text = "Enter your password."
-    options = {"key": "_default",
-               "goto": _check_password}
-    return text, options
-
-
-
-

This will display something like

-
---------------------------
-Please enter your username.
----------------------------
-
-> Fo
-
-------------------------------
-Username not found. Try again.
-______________________________
-abort: (back to start)
-------------------------------
-
-> Foo
-
----------------------------
-Please enter your password.
----------------------------
-
-> Bar
-
---------------------------
-Password error. Try again.
---------------------------
-
-
-

And so on.

-

Here the goto-callables will return to the previous node if there is an error. In the case of -password attempts, this will tick up the nattempts argument that will get passed on from iteration -to iteration until too many attempts have been made.

-
-
-

Defining nodes in a dictionary

-

You can also define your nodes directly in a dictionary to feed into the EvMenu creator.

-
def mynode(caller):
-   # a normal menu node function
-   return text, options
-
-menu_data = {"node1": mynode,
-             "node2": lambda caller: (
-                      "This is the node text",
-                     ({"key": "lambda node 1",
-                       "desc": "go to node 1 (mynode)",
-                       "goto": "node1"},
-                      {"key": "lambda node 2",
-                       "desc": "go to thirdnode",
-                       "goto": "node3"})),
-             "node3": lambda caller, raw_string: (
-                       # ... etc ) }
-
-# start menu, assuming 'caller' is available from earlier
-EvMenu(caller, menu_data, startnode="node1")
-
-
-
-

The keys of the dictionary become the node identifiers. You can use any callable on the right form -to describe each node. If you use Python lambda expressions you can make nodes really on the fly. -If you do, the lambda expression must accept one or two arguments and always return a tuple with two -elements (the text of the node and its options), same as any menu node function.

-

Creating menus like this is one way to present a menu that changes with the circumstances - you -could for example remove or add nodes before launching the menu depending on some criteria. The -drawback is that a lambda expression is much more -limited than a full -function - for example you can’t use other Python keywords like if inside the body of the -lambda.

-

Unless you are dealing with a relatively simple dynamic menu, defining menus with lambda’s is -probably more work than it’s worth: You can create dynamic menus by instead making each node -function more clever. See the NPC shop tutorial for an example of this.

-
-
-
-

Ask for simple input

-

This describes two ways for asking for simple questions from the user. Using Python’s input -will not work in Evennia. input will block the entire server for everyone until that one -player has entered their text, which is not what you want.

-
-

The yield way

-

In the func method of your Commands (only) you can use Python’s built-in yield command to -request input in a similar way to input. It looks like this:

-
result = yield("Please enter your answer:")
-
-
-

This will send “Please enter your answer” to the Command’s self.caller and then pause at that -point. All other players at the server will be unaffected. Once caller enteres a reply, the code -execution will continue and you can do stuff with the result. Here is an example:

-
from evennia import Command
-class CmdTestInput(Command):
-    key = "test"
-    def func(self):
-        result = yield("Please enter something:")
-        self.caller.msg(f"You entered {result}.")
-        result2 = yield("Now enter something else:")
-        self.caller.msg(f"You now entered {result2}.")
-
-
-

Using yield is simple and intuitive, but it will only access input from self.caller and you -cannot abort or time out the pause until the player has responded. Under the hood, it is actually -just a wrapper calling get_input described in the following section.

-
-

Important Note: In Python you cannot mix yield and return <value> in the same method. It has -to do with yield turning the method into a -generator. A return without an argument works, you -can just not do return <value>. This is usually not something you need to do in func() anyway, -but worth keeping in mind.

-
-
-
-

The get_input way

-

The evmenu module offers a helper function named get_input. This is wrapped by the yield -statement which is often easier and more intuitive to use. But get_input offers more flexibility -and power if you need it. While in the same module as EvMenu, get_input is technically unrelated -to it. The get_input allows you to ask and receive simple one-line input from the user without -launching the full power of a menu to do so. To use, call get_input like this:

-
get_input(caller, prompt, callback)
-
-
-

Here caller is the entity that should receive the prompt for input given as prompt. The -callback is a callable function(caller, prompt, user_input) that you define to handle the answer -from the user. When run, the caller will see prompt appear on their screens and any text they -enter will be sent into the callback for whatever processing you want.

-

Below is a fully explained callback and example call:

-
from evennia import Command
-from evennia.utils.evmenu import get_input
-
-def callback(caller, prompt, user_input):
-    """
-    This is a callback you define yourself.
-
-    Args:
-        caller (Account or Object): The one being asked
-          for input
-        prompt (str): A copy of the current prompt
-        user_input (str): The input from the account.
-
-    Returns:
-        repeat (bool): If not set or False, exit the
-          input prompt and clean up. If returning anything
-          True, stay in the prompt, which means this callback
-          will be called again with the next user input.
-    """
-    caller.msg(f"When asked '{prompt}', you answered '{user_input}'.")
-
-get_input(caller, "Write something! ", callback)
-
-
-

This will show as

-
Write something!
-> Hello
-When asked 'Write something!', you answered 'Hello'.
-
-
-
-

Normally, the get_input function quits after any input, but as seen in the example docs, you could -return True from the callback to repeat the prompt until you pass whatever check you want.

-
-

Note: You cannot link consecutive questions by putting a new get_input call inside the -callback. If you want that you should use an EvMenu instead (see the Repeating the same -node example above). Otherwise you can either peek at the -implementation of get_input and implement your own mechanism (it’s just using cmdset nesting) or -you can look at this extension suggested on the mailing -list.

-
-
-

Example: Yes/No prompt

-

Below is an example of a Yes/No prompt using the get_input function:

-
def yesno(caller, prompt, result):
-    if result.lower() in ("y", "yes", "n", "no"):
-        # do stuff to handle the yes/no answer
-        # ...
-        # if we return None/False the prompt state
-        # will quit after this
-    else:
-        # the answer is not on the right yes/no form
-        caller.msg("Please answer Yes or No. \n{prompt}")
-@        # returning True will make sure the prompt state is not exited
-        return True
-
-# ask the question
-get_input(caller, "Is Evennia great (Yes/No)?", yesno)
-
-
-
-
-
-
-

The @list_node decorator

-

The evennia.utils.evmenu.list_node is an advanced decorator for use with EvMenu node functions. -It is used to quickly create menus for manipulating large numbers of items.

-
text here
-______________________________________________
-
-1. option1     7. option7      13. option13
-2. option2     8. option8      14. option14
-3. option3     9. option9      [p]revius page
-4. option4    10. option10      page 2
-5. option5    11. option11     [n]ext page
-6. option6    12. option12
-
-
-
-

The menu will automatically create an multi-page option listing that one can flip through. One can -inpect each entry and then select them with prev/next. This is how it is used:

-
from evennia.utils.evmenu import list_node
-
-
-...
-
-_options(caller):
-    return ['option1', 'option2', ... 'option100']
-
-_select(caller, menuchoice, available_choices):
-    # analyze choice
-    return node_matching_the_choice
-
-@list_node(_options, select=_select, pagesize=10)
-def node_mylist(caller, raw_string, **kwargs):
-    ...
-
-    # the decorator auto-creates the options; any options
-    # returned here would be appended to the auto-options
-    return node_text, {}
-
-
-

The options argument to list_node is either a list, a generator or a callable returning a list -of strings for each option that should be displayed in the node.

-

The select is a callable in the example above but could also be the name of a menu node. If a -callable, the menuchoice argument holds the selection done and available_choices holds all the -options available. The callable should return the menu to go to depending on the selection (or -None to rerun the same node). If the name of a menu node, the selection will be passed as -selection kwarg to that node.

-

The decorated node itself should return text to display in the node. It must return at least an -empty dictionary for its options. It returning options, those will supplement the options -auto-created by the list_node decorator.

-
-
-

Assorted notes

-

The EvMenu is implemented using Commands. When you start a new EvMenu, the user of the -menu will be assigned a CmdSet with the commands they need to navigate the menu. -This means that if you were to, from inside the menu, assign a new command set to the caller, you -may override the Menu Cmdset and kill the menu. If you want to assign cmdsets to the caller as part -of the menu, you should store the cmdset on caller.ndb._menutree and wait to actually assign it -until the exit node.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/EvMore.html b/docs/0.9.5/EvMore.html deleted file mode 100644 index 201daaeefc..0000000000 --- a/docs/0.9.5/EvMore.html +++ /dev/null @@ -1,150 +0,0 @@ - - - - - - - - - EvMore — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

EvMore

-

When sending a very long text to a user client, it might scroll beyond of the height of the client -window. The evennia.utils.evmore.EvMore class gives the user the in-game ability to only view one -page of text at a time. It is usually used via its access function, evmore.msg.

-

The name comes from the famous unix pager utility more which performs just this function.

-
-

Using EvMore

-

To use the pager, just pass the long text through it:

-
from evennia.utils import evmore
-
-evmore.msg(receiver, long_text)
-
-
-

Where receiver is an Object or a Account. If the text is longer than the -client’s screen height (as determined by the NAWS handshake or by settings.CLIENT_DEFAULT_HEIGHT) -the pager will show up, something like this:

-
-

[…] -aute irure dolor in reprehenderit in voluptate velit -esse cillum dolore eu fugiat nulla pariatur. Excepteur -sint occaecat cupidatat non proident, sunt in culpa qui -officia deserunt mollit anim id est laborum.

-
-
-

(more [1/6] return|back|top|end|abort)

-
-

where the user will be able to hit the return key to move to the next page, or use the suggested -commands to jump to previous pages, to the top or bottom of the document as well as abort the -paging.

-

The pager takes several more keyword arguments for controlling the message output. See the -evmore-API for more info.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Evennia-API.html b/docs/0.9.5/Evennia-API.html deleted file mode 100644 index 1e5fa6c2ee..0000000000 --- a/docs/0.9.5/Evennia-API.html +++ /dev/null @@ -1,243 +0,0 @@ - - - - - - - - - API Summary — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

API Summary

-

evennia - library root

- -
-

Shortcuts

-

Evennia’s ‘flat API’ has shortcuts to common tools, available by only importing evennia. -The flat API is defined in __init__.py viewable here

-
-

Main config

- -
-
-

Search functions

- -
-
-

Create functions

- -
-
-

Typeclasses

- -
-
-

Commands

- -
-
-

Utilities

- -
-
-

Global singleton handlers

- -
-
-

Database core models (for more advanced lookups)

- -
-
-

Contributions

- -
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Evennia-Game-Index.html b/docs/0.9.5/Evennia-Game-Index.html deleted file mode 100644 index 1498ebd387..0000000000 --- a/docs/0.9.5/Evennia-Game-Index.html +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - Evennia Game Index — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Evennia Game Index

-

The Evennia game index is a list of games built or -being built with Evennia. Anyone is allowed to add their game to the index

-
    -
  • also if you have just started development and don’t yet accept external -players. It’s a chance for us to know you are out there and for you to make us -intrigued about or excited for your upcoming game!

  • -
-

All we ask is that you check so your game-name does not collide with one -already in the list - be nice!

-
-

Connect with the wizard

-

From your game dir, run

-
evennia connections
-
-
-

This will start the Evennia Connection wizard. From the menu, select to add -your game to the Evennia Game Index. Follow the prompts and don’t forget to -save your new settings in the end. Use quit at any time if you change your -mind.

-
-

The wizard will create a new file mygame/server/conf/connection_settings.py -with the settings you chose. This is imported from the end of your main -settings file and will thus override it. You can edit this new file if you -want, but remember that if you run the wizard again, your changes may get -over-written.

-
-
-
-

Manual Settings

-

If you don’t want to use the wizard (maybe because you already have the client installed from an -earlier version), you can also configure your index entry in your settings file -(mygame/server/conf/settings.py). Add the following:

-
GAME_INDEX_ENABLED = True
-
-GAME_INDEX_LISTING = {
-    # required
-    'game_status': 'pre-alpha',            # pre-alpha, alpha, beta, launched
-    'listing_contact': "dummy@dummy.com",  # not publicly shown.
-    'short_description': 'Short blurb',
-
-    # optional
-    'long_description':
-        "Longer description that can use Markdown like *bold*, _italic_"
-        "and [linkname](http://link.com). Use \n for line breaks."
-    'telnet_hostname': 'dummy.com',
-    'telnet_port': '1234',
-    'web_client_url': 'dummy.com/webclient',
-    'game_website': 'dummy.com',
-    # 'game_name': 'MyGame',  # set only if different than settings.SERVERNAME
-}
-
-
-

Of these, the game_status, short_description and listing_contact are -required. The listing_contact is not publicly visible and is only meant as a -last resort if we need to get in touch with you over any listing issue/bug (so -far this has never happened).

-

If game_name is not set, the settings.SERVERNAME will be used. Use empty strings -('') for optional fields you don’t want to specify at this time.

-
-
-

Non-public games

-

If you don’t specify neither telnet_hostname + port nor -web_client_url, the Game index will list your game as Not yet public. -Non-public games are moved to the bottom of the index since there is no way -for people to try them out. But it’s a good way to show you are out there, even -if you are not ready for players yet.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Evennia-Introduction.html b/docs/0.9.5/Evennia-Introduction.html deleted file mode 100644 index 712e8ae070..0000000000 --- a/docs/0.9.5/Evennia-Introduction.html +++ /dev/null @@ -1,309 +0,0 @@ - - - - - - - - - Evennia Introduction — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Evennia Introduction

-
-

A MUD (originally Multi-User Dungeon, with later variants Multi-User Dimension and Multi-User -Domain) is a multiplayer real-time virtual world described primarily in text. MUDs combine elements -of role-playing games, hack and slash, player versus player, interactive fiction and online chat. -Players can read or view descriptions of rooms, objects, other players, non-player characters, and -actions performed in the virtual world. Players typically interact with each other and the world by -typing commands that resemble a natural language. - Wikipedia

-
-

If you are reading this, it’s quite likely you are dreaming of creating and running a text-based -massively-multiplayer game (MUD/MUX/MUSH etc) of your very own. You -might just be starting to think about it, or you might have lugged around that perfect game in -your mind for years … you know just how good it would be, if you could only make it come to -reality. We know how you feel. That is, after all, why Evennia came to be.

-

Evennia is in principle a MUD-building system: a bare-bones Python codebase and server intended to -be highly extendable for any style of game. “Bare-bones” in this context means that we try to impose -as few game-specific things on you as possible. So whereas we for convenience offer basic building -blocks like objects, characters, rooms, default commands for building and administration etc, we -don’t prescribe any combat rules, mob AI, races, skills, character classes or other things that will -be different from game to game anyway. It is possible that we will offer some such systems as -contributions in the future, but these will in that case all be optional.

-

What we do however, is to provide a solid foundation for all the boring database, networking, and -behind-the-scenes administration stuff that all online games need whether they like it or not. -Evennia is fully persistent, that means things you drop on the ground somewhere will still be -there a dozen server reboots later. Through Django we support a large variety of different database -systems (a database is created for you automatically if you use the defaults).

-

Using the full power of Python throughout the server offers some distinct advantages. All your -coding, from object definitions and custom commands to AI scripts and economic systems is done in -normal Python modules rather than some ad-hoc scripting language. The fact that you script the game -in the same high-level language that you code it in allows for very powerful and custom game -implementations indeed.

-

The server ships with a default set of player commands that are similar to the MUX command set. We -do not aim specifically to be a MUX server, but we had to pick some default to go with (see -this for more about our original motivations). It’s easy to remove or add commands, or -to have the command syntax mimic other systems, like Diku, LP, MOO and so on. Or why not create a -new and better command system of your own design.

-
-

Can I test it somewhere?

-

Evennia’s demo server can be found at demo.evennia.com. If you prefer to -connect to the demo via your own telnet client you can do so at silvren.com, port 4280. Here is -a screenshot.

-

Once you installed Evennia yourself it comes with its own tutorial - this shows off some of the -possibilities and gives you a small single-player quest to play. The tutorial takes only one -single in-game command to install as explained here.

-
-
-

Brief summary of features

-
-

Technical

-
    -
  • Game development is done by the server importing your normal Python modules. Specific server -features are implemented by overloading hooks that the engine calls appropriately.

  • -
  • All game entities are simply Python classes that handle database negotiations behind the scenes -without you needing to worry.

  • -
  • Command sets are stored on individual objects (including characters) to offer unique functionality -and object-specific commands. Sets can be updated and modified on the fly to expand/limit player -input options during play.

  • -
  • Scripts are used to offer asynchronous/timed execution abilities. Scripts can also be persistent. -There are easy mechanisms to thread particularly long-running processes and built-in ways to start -“tickers” for games that wants them.

  • -
  • In-game communication channels are modular and can be modified to any functionality, including -mailing systems and full logging of all messages.

  • -
  • Server can be fully rebooted/reloaded without users disconnecting.

  • -
  • An Account can freely connect/disconnect from game-objects, offering an easy way to implement -multi-character systems and puppeting.

  • -
  • Each Account can optionally control multiple Characters/Objects at the same time using the same -login information.

  • -
  • Spawning of individual objects via a prototypes-like system.

  • -
  • Tagging can be used to implement zones and object groupings.

  • -
  • All source code is extensively documented.

  • -
  • Unit-testing suite, including tests of default commands and plugins.

  • -
-
-
-

Default content

-
    -
  • Basic classes for Objects, Characters, Rooms and Exits

  • -
  • Basic login system, using the Account’s login name as their in-game Character’s name for -simplicity

  • -
  • “MUX-like” command set with administration, building, puppeting, channels and social commands

  • -
  • In-game Tutorial

  • -
  • Contributions folder with working, but optional, code such as alternative login, menus, character -generation and more

  • -
-
-
-

Standards/Protocols supported

-
    -
  • TCP/websocket HTML5 browser web client, with ajax/comet fallback for older browsers

  • -
  • Telnet and Telnet + SSL with mud-specific extensions (MCCP, -MSSP, TTYPE, -MSDP, -GMCP, -MXP links)

  • -
  • ANSI and xterm256 colours

  • -
  • SSH

  • -
  • HTTP - Website served by in-built webserver and connected to same database as game.

  • -
  • IRC - external IRC channels can be connected to in-game chat channels

  • -
  • RSS feeds can be echoed to in-game channels (things like Twitter can easily be added)

  • -
  • Several different databases supported (SQLite3, MySQL, PostgreSQL, …)

  • -
-

For more extensive feature information, see the Developer Central.

-
-
-
-

What you need to know to work with Evennia

-

Assuming you have Evennia working (see the quick start instructions) and have -gotten as far as to start the server and connect to it with the client of your choice, here’s what -you need to know depending on your skills and needs.

-
-

I don’t know (or don’t want to do) any programming - I just want to run a game!

-

Evennia comes with a default set of commands for the Python newbies and for those who need to get a -game running now. Stock Evennia is enough for running a simple ‘Talker’-type game - you can build -and describe rooms and basic objects, have chat channels, do emotes and other things suitable for a -social or free-form MU*. Combat, mobs and other game elements are not included, so you’ll have a -very basic game indeed if you are not willing to do at least some coding.

-
-
-

I know basic Python, or I am willing to learn

-

Evennia’s source code is extensively documented and is viewable online. -We also have a comprehensive online manual with lots of examples. -But while Python is -considered a very easy programming language to get into, you do have a learning curve to climb if -you are new to programming. You should probably sit down -with a Python beginner’s tutorial (there are plenty of them on -the web if you look around) so you at least know what you are seeing. See also our -link page for some reading suggestions. To efficiently code your dream game in -Evennia you don’t need to be a Python guru, but you do need to be able to read example code -containing at least these basic Python features:

- -

Obviously, the more things you feel comfortable with, the easier time you’ll have to find your way. -With just basic knowledge you should be able to define your own Commands, create custom -Objects as well as make your world come alive with basic Scripts. You can -definitely build a whole advanced and customized game from extending Evennia’s examples only.

-
-
-

I know my Python stuff and I am willing to use it!

-

Even if you started out as a Python beginner, you will likely get to this point after working on -your game for a while. With more general knowledge in Python the full power of Evennia opens up for -you. Apart from modifying commands, objects and scripts, you can develop everything from advanced -mob AI and economic systems, through sophisticated combat and social mini games, to redefining how -commands, players, rooms or channels themselves work. Since you code your game by importing normal -Python modules, there are few limits to what you can accomplish.

-

If you also happen to know some web programming (HTML, CSS, Javascript) there is also a web -presence (a website and a mud web client) to play around with …

-
-
-

Where to from here?

-

From here you can continue browsing the online documentation to -find more info about Evennia. Or you can jump into the Tutorials and get your hands -dirty with code right away. You can also read the developer’s dev blog for many tidbits and snippets about Evennia’s development and -structure.

-

Some more hints:

-
    -
  1. Get engaged in the community. Make an introductory post to our mailing list/forum and get to know people. It’s also -highly recommended you hop onto our Developer chat -on IRC. This allows you to chat directly with other developers new and old as well as with the devs -of Evennia itself. This chat is logged (you can find links on http://www.evennia.com) and can also -be searched from the same place for discussion topics you are interested in.

  2. -
  3. Read the Game Planning wiki page. It gives some ideas for your work flow and the -state of mind you should aim for - including cutting down the scope of your game for its first -release.

  4. -
  5. Do the Tutorial for basic MUSH-like game carefully from -beginning to end and try to understand what does what. Even if you are not interested in a MUSH for -your own game, you will end up with a small (very small) game that you can build or learn from.

  6. -
-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Evennia-for-Diku-Users.html b/docs/0.9.5/Evennia-for-Diku-Users.html deleted file mode 100644 index 587b9ae004..0000000000 --- a/docs/0.9.5/Evennia-for-Diku-Users.html +++ /dev/null @@ -1,297 +0,0 @@ - - - - - - - - - Evennia for Diku Users — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Evennia for Diku Users

-

Evennia represents a learning curve for those who used to code on -Diku type MUDs. While coding in Python is easy if you -already know C, the main effort is to get rid of old C programming habits. Trying to code Python the -way you code C will not only look ugly, it will lead to less optimal and harder to maintain code. -Reading Evennia example code is a good way to get a feel for how different problems are approached -in Python.

-

Overall, Python offers an extensive library of resources, safe memory management and excellent -handling of errors. While Python code does not run as fast as raw C code does, the difference is not -all that important for a text-based game. The main advantage of Python is an extremely fast -development cycle with and easy ways to create game systems that would take many times more code and -be much harder to make stable and maintainable in C.

-
-

Core Differences

-
    -
  • As mentioned, the main difference between Evennia and a Diku-derived codebase is that Evennia is -written purely in Python. Since Python is an interpreted language there is no compile stage. It is -modified and extended by the server loading Python modules at run-time. It also runs on all computer -platforms Python runs on (which is basically everywhere).

  • -
  • Vanilla Diku type engines save their data in custom flat file type storage solutions. By -contrast, Evennia stores all game data in one of several supported SQL databases. Whereas flat files -have the advantage of being easier to implement, they (normally) lack many expected safety features -and ways to effectively extract subsets of the stored data. For example, if the server loses power -while writing to a flatfile it may become corrupt and the data lost. A proper database solution is -not susceptible to this - at no point is the data in a state where it cannot be recovered. Databases -are also highly optimized for querying large data sets efficiently.

  • -
-
-
-

Some Familiar Things

-

Diku expresses the character object referenced normally by:

-

struct char ch* then all character-related fields can be accessed by ch->. In Evennia, one must -pay attention to what object you are using, and when you are accessing another through back- -handling, that you are accessing the right object. In Diku C, accessing character object is normally -done by:

-
/* creating pointer of both character and room struct */
-
-void(struct char ch*, struct room room*){
-    int dam;
-    if (ROOM_FLAGGED(room, ROOM_LAVA)){
-        dam = 100
-        ch->damage_taken = dam
-    };
-};
-
-
-

As an example for creating Commands in Evennia via the from evennia import Command the character -object that calls the command is denoted by a class property as self.caller. In this example -self.caller is essentially the ‘object’ that has called the Command, but most of the time it is an -Account object. For a more familiar Diku feel, create a variable that becomes the account object as:

-
#mygame/commands/command.py
-
-from evennia import Command
-
-class CmdMyCmd(Command):
-    """
-    This is a Command Evennia Object
-    """
-    
-    [...]
-
-    def func(self):
-        ch = self.caller
-        # then you can access the account object directly by using the familiar ch.
-        ch.msg("...")
-        account_name = ch.name
-        race = ch.db.race
-
-
-
-

As mentioned above, care must be taken what specific object you are working with. If focused on a -room object and you need to access the account object:

-
#mygame/typeclasses/room.py
-
-from evennia import DefaultRoom
-
-class MyRoom(DefaultRoom):
-    [...]
-
-    def is_account_object(self, object):
-        # a test to see if object is an account
-        [...]
-
-    def myMethod(self):
-        #self.caller would not make any sense, since self refers to the
-        # object of 'DefaultRoom', you must find the character obj first:
-        for ch in self.contents:
-            if self.is_account_object(ch):
-                # now you can access the account object with ch:
-                account_name = ch.name
-                race = ch.db.race
-
-
-
-
-

Emulating Evennia to Look and Feel Like A Diku/ROM

-

To emulate a Diku Mud on Evennia some work has to be done before hand. If there is anything that all -coders and builders remember from Diku/Rom days is the presence of VNUMs. Essentially all data was -saved in flat files and indexed by VNUMs for easy access. Evennia has the ability to emulate VNUMS -to the extent of categorising rooms/mobs/objs/trigger/zones[…] into vnum ranges.

-

Evennia has objects that are called Scripts. As defined, they are the ‘out of game’ instances that -exist within the mud, but never directly interacted with. Scripts can be used for timers, mob AI, -and even a stand alone databases.

-

Because of their wonderful structure all mob, room, zone, triggers, etc… data can be saved in -independently created global scripts.

-

Here is a sample mob file from a Diku Derived flat file.

-
#0
-mob0~
-mob0~
-mob0
-~
-   Mob0
-~
-10 0 0 0 0 0 0 0 0 E
-1 20 9 0d0+10 1d2+0
-10 100
-8 8 0
-E
-#1
-Puff dragon fractal~
-Puff~
-Puff the Fractal Dragon is here, contemplating a higher reality.
-~
-   Is that some type of differential curve involving some strange, and unknown
-calculus that she seems to be made out of?
-~
-516106 0 0 0 2128 0 0 0 1000 E
-34 9 -10 6d6+340 5d5+5
-340 115600
-8 8 2
-BareHandAttack: 12
-E
-T 95
-
-
-

Each line represents something that the MUD reads in and does something with it. This isn’t easy to -read, but let’s see if we can emulate this as a dictionary to be stored on a database script created -in Evennia.

-

First, let’s create a global script that does absolutely nothing and isn’t attached to anything. You -can either create this directly in-game with the @py command or create it in another file to do some -checks and balances if for whatever reason the script needs to be created again. Progmatically it -can be done like so:

-
from evennia import create_script
-
-mob_db = create_script("typeclasses.scripts.DefaultScript", key="mobdb",
-                       persistent=True, obj=None)
-mob_db.db.vnums = {}
-
-
-

Just by creating a simple script object and assigning it a ‘vnums’ attribute as a type dictionary. -Next we have to create the mob layout…

-
# vnum : mob_data
-
-mob_vnum_1 = {
-            'key' : 'puff',
-            'sdesc' : 'puff the fractal dragon',
-            'ldesc' : 'Puff the Fractal Dragon is here, ' \
-                      'contemplating a higher reality.',
-            'ddesc' : ' Is that some type of differential curve ' \
-                      'involving some strange, and unknown calculus ' \
-                      'that she seems to be made out of?',
-            [...]
-        }
-
-# Then saving it to the data, assuming you have the script obj stored in a variable.
-mob_db.db.vnums[1] = mob_vnum_1
-
-
-

This is a very ‘caveman’ example, but it gets the idea across. You can use the keys in the -mob_db.vnums to act as the mob vnum while the rest contains the data…

-

Much simpler to read and edit. If you plan on taking this route, you must keep in mind that by -default evennia ‘looks’ at different properties when using the look command for instance. If you -create an instance of this mob and make its self.key = 1, by default evennia will say

-

Here is : 1

-

You must restructure all default commands so that the mud looks at different properties defined on -your mob.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Evennia-for-MUSH-Users.html b/docs/0.9.5/Evennia-for-MUSH-Users.html deleted file mode 100644 index 51fc5b1088..0000000000 --- a/docs/0.9.5/Evennia-for-MUSH-Users.html +++ /dev/null @@ -1,316 +0,0 @@ - - - - - - - - - Evennia for MUSH Users — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Evennia for MUSH Users

-

This page is adopted from an article originally posted for the MUSH community here on -musoapbox.net.

-

MUSHes are text multiplayer games traditionally used for -heavily roleplay-focused game styles. They are often (but not always) utilizing game masters and -human oversight over code automation. MUSHes are traditionally built on the TinyMUSH-family of game -servers, like PennMUSH, TinyMUSH, TinyMUX and RhostMUSH. Also their siblings -MUCK and MOO are -often mentioned together with MUSH since they all inherit from the same -TinyMUD base. A major feature is the -ability to modify and program the game world from inside the game by using a custom scripting -language. We will refer to this online scripting as softcode here.

-

Evennia works quite differently from a MUSH both in its overall design and under the hood. The same -things are achievable, just in a different way. Here are some fundamental differences to keep in -mind if you are coming from the MUSH world.

-
-

Developers vs Players

-

In MUSH, users tend to code and expand all aspects of the game from inside it using softcode. A MUSH -can thus be said to be managed solely by Players with different levels of access. Evennia on the -other hand, differentiates between the role of the Player and the Developer.

-
    -
  • An Evennia Developer works in Python from outside the game, in what MUSH would consider -“hardcode”. Developers implement larger-scale code changes and can fundamentally change how the game -works. They then load their changes into the running Evennia server. Such changes will usually not -drop any connected players.

  • -
  • An Evennia Player operates from inside the game. Some staff-level players are likely to double -as developers. Depending on access level, players can modify and expand the game’s world by digging -new rooms, creating new objects, alias commands, customize their experience and so on. Trusted staff -may get access to Python via the @py command, but this would be a security risk for normal Players -to use. So the Player usually operates by making use of the tools prepared for them by the -Developer - tools that can be as rigid or flexible as the developer desires.

  • -
-
-
-

Collaborating on a game - Python vs Softcode

-

For a Player, collaborating on a game need not be too different between MUSH and Evennia. The -building and description of the game world can still happen mostly in-game using build commands, -using text tags and inline functions to prettify and customize the -experience. Evennia offers external ways to build a world but those are optional. There is also -nothing in principle stopping a Developer from offering a softcode-like language to Players if -that is deemed necessary.

-

For Developers of the game, the difference is larger: Code is mainly written outside the game in -Python modules rather than in-game on the command line. Python is a very popular and well-supported -language with tons of documentation and help to be found. The Python standard library is also a -great help for not having to reinvent the wheel. But that said, while Python is considered one of -the easier languages to learn and use it is undoubtedly very different from MUSH softcode.

-

While softcode allows collaboration in-game, Evennia’s external coding instead opens up the -possibility for collaboration using professional version control tools and bug tracking using -websites like github (or bitbucket for a free private repo). Source code can be written in proper -text editors and IDEs with refactoring, syntax highlighting and all other conveniences. In short, -collaborative development of an Evennia game is done in the same way most professional collaborative -development is done in the world, meaning all the best tools can be used.

-
-
-

@parent vs @typeclass and @spawn

-

Inheritance works differently in Python than in softcode. Evennia has no concept of a “master -object” that other objects inherit from. There is in fact no reason at all to introduce “virtual -objects” in the game world - code and data are kept separate from one another.

-

In Python (which is an object oriented -language) one instead creates classes - these are like blueprints from which you spawn any number -of object instances. Evennia also adds the extra feature that every instance is persistent in the -database (this means no SQL is ever needed). To take one example, a unique character in Evennia is -an instances of the class Character.

-

One parallel to MUSH’s @parent command may be Evennia’s @typeclass command, which changes which -class an already existing object is an instance of. This way you can literally turn a Character -into a Flowerpot on the spot.

-

if you are new to object oriented design it’s important to note that all object instances of a class -does not have to be identical. If they did, all Characters would be named the same. Evennia allows -to customize individual objects in many different ways. One way is through Attributes, which are -database-bound properties that can be linked to any object. For example, you could have an Orc -class that defines all the stuff an Orc should be able to do (probably in turn inheriting from some -Monster class shared by all monsters). Setting different Attributes on different instances -(different strength, equipment, looks etc) would make each Orc unique despite all sharing the same -class.

-

The @spawn command allows one to conveniently choose between different “sets” of Attributes to -put on each new Orc (like the “warrior” set or “shaman” set) . Such sets can even inherit one -another which is again somewhat remniscent at least of the effect of @parent and the object- -based inheritance of MUSH.

-

There are other differences for sure, but that should give some feel for things. Enough with the -theory. Let’s get down to more practical matters next. To install, see the -Getting Started instructions.

-
-
-

A first step making things more familiar

-

We will here give two examples of customizing Evennia to be more familiar to a MUSH Player.

-
-

Activating a multi-descer

-

By default Evennia’s desc command updates your description and that’s it. There is a more feature- -rich optional “multi-descer” in evennia/contrib/multidesc.py though. This alternative allows for -managing and combining a multitude of keyed descriptions.

-

To activate the multi-descer, cd to your game folder and into the commands sub-folder. There -you’ll find the file default_cmdsets.py. In Python lingo all *.py files are called modules. -Open the module in a text editor. We won’t go into Evennia in-game Commands and Command sets -further here, but suffice to say Evennia allows you to change which commands (or versions of -commands) are available to the player from moment to moment depending on circumstance.

-

Add two new lines to the module as seen below:

-
# the file mygame/commands/default_cmdsets.py
-# [...]
-
-from evennia.contrib import multidescer   # <- added now
-
-class CharacterCmdSet(default_cmds.CharacterCmdSet):
-    """
-    The CharacterCmdSet contains general in-game commands like look,
-    get etc available on in-game Character objects. It is merged with
-    the AccountCmdSet when an Account puppets a Character.
-    """
-    key = "DefaultCharacter"
-
-    def at_cmdset_creation(self):
-        """
-        Populates the cmdset
-        """
-        super().at_cmdset_creation()
-        #
-        # any commands you add below will overload the default ones.
-        #
-        self.add(multidescer.CmdMultiDesc())      # <- added now
-# [...]
-
-
-

Note that Python cares about indentation, so make sure to indent with the same number of spaces as -shown above!

-

So what happens above? We import the module evennia/contrib/multidescer.py at the top. Once -imported we can access stuff inside that module using full stop (.). The multidescer is defined as -a class CmdMultiDesc (we could find this out by opening said module in a text editor). At the -bottom we create a new instance of this class and add it to the CharacterCmdSet class. For the -sake of this tutorial we only need to know that CharacterCmdSet contains all commands that should -be be available to the Character by default.

-

This whole thing will be triggered when the command set is first created, which happens on server -start. So we need to reload Evennia with @reload - no one will be disconnected by doing this. If -all went well you should now be able to use desc (or +desc) and find that you have more -possibilities:

-
> help +desc                  # get help on the command
-> +desc eyes = His eyes are blue.
-> +desc basic = A big guy.
-> +desc/set basic + + eyes    # we add an extra space between
-> look me
-A big guy. His eyes are blue.
-
-
-

If there are errors, a traceback will show in the server log - several lines of text showing -where the error occurred. Find where the error is by locating the line number related to the -default_cmdsets.py file (it’s the only one you’ve changed so far). Most likely you mis-spelled -something or missed the indentation. Fix it and either @reload again or run evennia start as -needed.

-
-
-

Customizing the multidescer syntax

-

As seen above the multidescer uses syntax like this (where |/ are Evennia’s tags for line breaks) -:

-
> +desc/set basic + |/|/ + cape + footwear + |/|/ + attitude
-
-
-

This use of + was prescribed by the Developer that coded this +desc command. What if the -Player doesn’t like this syntax though? Do players need to pester the dev to change it? Not -necessarily. While Evennia does not allow the player to build their own multi-descer on the command -line, it does allow for re-mapping the command syntax to one they prefer. This is done using the -nick command.

-

Here’s a nick that changes how to input the command above:

-
> nick setdesc $1 $2 $3 $4 = +desc/set $1 + |/|/ + $2 + $3 + |/|/ + $4
-
-
-

The string on the left will be matched against your input and if matching, it will be replaced with -the string on the right. The $-type tags will store space-separated arguments and put them into -the replacement. The nick allows shell-like wildcards, so you -can use *, ?, [...], [!...] etc to match parts of the input.

-

The same description as before can now be set as

-
> setdesc basic cape footwear attitude
-
-
-

With the nick functionality players can mitigate a lot of syntax dislikes even without the -developer changing the underlying Python code.

-
-
-
-

Next steps

-

If you are a Developer and are interested in making a more MUSH-like Evennia game, a good start is -to look into the Evennia Tutorial for a first MUSH-like game. -That steps through building a simple little game from scratch and helps to acquaint you with the -various corners of Evennia. There is also the Tutorial for running roleplaying sessions that can be of interest.

-

An important aspect of making things more familiar for Players is adding new and tweaking existing -commands. How this is done is covered by the Tutorial on adding new commands. You may also find it useful to shop through the evennia/contrib/ folder. The Tutorial -world is a small single-player quest you can try (it’s not very MUSH- -like but it does show many Evennia concepts in action). Beyond that there are many more -tutorials to try out. If you feel you want a more visual overview you can also look at -Evennia in pictures.

-

… And of course, if you need further help you can always drop into the Evennia chatroom or post a -question in our forum/mailing list!

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Evennia-for-roleplaying-sessions.html b/docs/0.9.5/Evennia-for-roleplaying-sessions.html deleted file mode 100644 index 516bebef0c..0000000000 --- a/docs/0.9.5/Evennia-for-roleplaying-sessions.html +++ /dev/null @@ -1,840 +0,0 @@ - - - - - - - - - Evennia for roleplaying sessions — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Evennia for roleplaying sessions

-

This tutorial will explain how to set up a realtime or play-by-post tabletop style game using a -fresh Evennia server.

-

The scenario is thus: You and a bunch of friends want to play a tabletop role playing game online. -One of you will be the game master and you are all okay with playing using written text. You want -both the ability to role play in real-time (when people happen to be online at the same time) as -well as the ability for people to post when they can and catch up on what happened since they were -last online.

-

This is the functionality we will be needing and using:

-
    -
  • The ability to make one of you the GM (game master), with special abilities.

  • -
  • A Character sheet that players can create, view and fill in. It can also be locked so only the -GM can modify it.

  • -
  • A dice roller mechanism, for whatever type of dice the RPG rules require.

  • -
  • Rooms, to give a sense of location and to compartmentalize play going on- This means both -Character movements from location to location and GM explicitly moving them around.

  • -
  • Channels, for easily sending text to all subscribing accounts, regardless of location.

  • -
  • Account-to-Account messaging capability, including sending to multiple recipients -simultaneously, regardless of location.

  • -
-

We will find most of these things are already part of vanilla Evennia, but that we can expand on the -defaults for our particular use-case. Below we will flesh out these components from start to finish.

-
-

Starting out

-

We will assume you start from scratch. You need Evennia installed, as per the Getting -Started instructions. Initialize a new game directory with evennia init <gamedirname>. In this tutorial we assume your game dir is simply named mygame. You can use the -default database and keep all other settings to default for now. Familiarize yourself with the -mygame folder before continuing. You might want to browse the [First Steps Coding](First-Steps- -Coding) tutorial, just to see roughly where things are modified.

-
-
-

The Game Master role

-

In brief:

-
    -
  • Simplest way: Being an admin, just give one account Admins permission using the standard @perm -command.

  • -
  • Better but more work: Make a custom command to set/unset the above, while tweaking the Character -to show your renewed GM status to the other accounts.

  • -
-
-

The permission hierarchy

-

Evennia has the following permission hierarchy out of -the box: Players, Helpers, Builders, Admins and finally Developers. We could change these but -then we’d need to update our Default commands to use the changes. We want to keep this simple, so -instead we map our different roles on top of this permission ladder.

-
    -
  1. Players is the permission set on normal players. This is the default for anyone creating a new -account on the server.

  2. -
  3. Helpers are like Players except they also have the ability to create/edit new help entries. -This could be granted to players who are willing to help with writing lore or custom logs for -everyone.

  4. -
  5. Builders is not used in our case since the GM should be the only world-builder.

  6. -
  7. Admins is the permission level the GM should have. Admins can do everything builders can -(create/describe rooms etc) but also kick accounts, rename them and things like that.

  8. -
  9. Developers-level permission are the server administrators, the ones with the ability to -restart/shutdown the server as well as changing the permission levels.

  10. -
-
-

The superuser is not part of the hierarchy and actually -completely bypasses it. We’ll assume server admin(s) will “just” be Developers.

-
-
-
-

How to grant permissions

-

Only Developers can (by default) change permission level. Only they have access to the @perm -command:

-
> @perm Yvonne
-Permissions on Yvonne: accounts
-
-> @perm Yvonne = Admins
-> @perm Yvonne
-Permissions on Yvonne: accounts, admins
-
-> @perm/del Yvonne = Admins
-> @perm Yvonne
-Permissions on Yvonne: accounts
-
-
-

There is no need to remove the basic Players permission when adding the higher permission: the -highest will be used. Permission level names are not case sensitive. You can also use both plural -and singular, so “Admins” gives the same powers as “Admin”.

-
-
-

Optional: Making a GM-granting command

-

Use of @perm works out of the box, but it’s really the bare minimum. Would it not be nice if other -accounts could tell at a glance who the GM is? Also, we shouldn’t really need to remember that the -permission level is called “Admins”. It would be easier if we could just do @gm <account> and -@notgm <account> and at the same time change something make the new GM status apparent.

-

So let’s make this possible. This is what we’ll do:

-
    -
  1. We’ll customize the default Character class. If an object of this class has a particular flag, -its name will have the string(GM) added to the end.

  2. -
  3. We’ll add a new command, for the server admin to assign the GM-flag properly.

  4. -
-
-

Character modification

-

Let’s first start by customizing the Character. We recommend you browse the beginning of the -Account page to make sure you know how Evennia differentiates between the OOC “Account -objects” (not to be confused with the Accounts permission, which is just a string specifying your -access) and the IC “Character objects”.

-

Open mygame/typeclasses/characters.py and modify the default Character class:

-
# in mygame/typeclasses/characters.py
-
-# [...]
-
-class Character(DefaultCharacter):
-    # [...]
-    def get_display_name(self, looker, **kwargs):
-        """
-        This method customizes how character names are displayed. We assume
-        only permissions of types "Developers" and "Admins" require
-        special attention.
-        """
-        name = self.key
-        selfaccount = self.account     # will be None if we are not puppeted
-        lookaccount = looker.account   #              - " -
-
-        if selfaccount and selfaccount.db.is_gm:
-           # A GM. Show name as name(GM)
-           name = "%s(GM)" % name
-
-        if lookaccount and \
-          (lookaccount.permissions.get("Developers") or lookaccount.db.is_gm):
-            # Developers/GMs see name(#dbref) or name(GM)(#dbref)
-            return "%s(#%s)" % (name, self.id)
-        else:
-            return name
-
-
-
-

Above, we change how the Character’s name is displayed: If the account controlling this Character is -a GM, we attach the string (GM) to the Character’s name so everyone can tell who’s the boss. If we -ourselves are Developers or GM’s we will see database ids attached to Characters names, which can -help if doing database searches against Characters of exactly the same name. We base the “gm- -ingness” on having an flag (an Attribute) named is_gm. We’ll make sure new GM’s -actually get this flag below.

-
-

Extra exercise: This will only show the (GM) text on Characters puppeted by a GM account, -that is, it will show only to those in the same location. If we wanted it to also pop up in, say, -who listings and channels, we’d need to make a similar change to the Account typeclass in -mygame/typeclasses/accounts.py. We leave this as an exercise to the reader.

-
-
-
-

New @gm/@ungm command

-

We will describe in some detail how to create and add an Evennia command here with the -hope that we don’t need to be as detailed when adding commands in the future. We will build on -Evennia’s default “mux-like” commands here.

-

Open mygame/commands/command.py and add a new Command class at the bottom:

-
# in mygame/commands/command.py
-
-from evennia import default_cmds
-
-# [...]
-
-import evennia
-
-class CmdMakeGM(default_cmds.MuxCommand):
-    """
-    Change an account's GM status
-
-    Usage:
-      @gm <account>
-      @ungm <account>
-
-    """
-    # note using the key without @ means both @gm !gm etc will work
-    key = "gm"
-    aliases = "ungm"
-    locks = "cmd:perm(Developers)"
-    help_category = "RP"
-
-    def func(self):
-        "Implement the command"
-        caller = self.caller
-
-        if not self.args:
-            caller.msg("Usage: @gm account or @ungm account")
-            return
-
-        accountlist = evennia.search_account(self.args) # returns a list
-        if not accountlist:
-            caller.msg("Could not find account '%s'" % self.args)
-            return
-        elif len(accountlist) > 1:
-            caller.msg("Multiple matches for '%s': %s" % (self.args, accountlist))
-            return
-        else:
-            account = accountlist[0]
-
-        if self.cmdstring == "gm":
-            # turn someone into a GM
-            if account.permissions.get("Admins"):
-                caller.msg("Account %s is already a GM." % account)
-            else:
-                account.permissions.add("Admins")
-                caller.msg("Account %s is now a GM." % account)
-                account.msg("You are now a GM (changed by %s)." % caller)
-                account.character.db.is_gm = True
-        else:
-            # @ungm was entered - revoke GM status from someone
-            if not account.permissions.get("Admins"):
-                caller.msg("Account %s is not a GM." % account)
-            else:
-                account.permissions.remove("Admins")
-                caller.msg("Account %s is no longer a GM." % account)
-                account.msg("You are no longer a GM (changed by %s)." % caller)
-                del account.character.db.is_gm
-
-
-
-

All the command does is to locate the account target and assign it the Admins permission if we -used @gm or revoke it if using the @ungm alias. We also set/unset the is_gm Attribute that is -expected by our new Character.get_display_name method from earlier.

-
-

We could have made this into two separate commands or opted for a syntax like @gm/revoke <accountname>. Instead we examine how this command was called (stored in self.cmdstring) in order -to act accordingly. Either way works, practicality and coding style decides which to go with.

-
-

To actually make this command available (only to Developers, due to the lock on it), we add it to -the default Account command set. Open the file mygame/commands/default_cmdsets.py and find the -AccountCmdSet class:

-
# mygame/commands/default_cmdsets.py
-
-# [...]
-from commands.command import CmdMakeGM
-
-class AccountCmdSet(default_cmds.AccountCmdSet):
-    # [...]
-    def at_cmdset_creation(self):
-        # [...]
-        self.add(CmdMakeGM())
-
-
-
-

Finally, issue the @reload command to update the server to your changes. Developer-level players -(or the superuser) should now have the @gm/@ungm command available.

-
-
-
-
-

Character sheet

-

In brief:

-
    -
  • Use Evennia’s EvTable/EvForm to build a Character sheet

  • -
  • Tie individual sheets to a given Character.

  • -
  • Add new commands to modify the Character sheet, both by Accounts and GMs.

  • -
  • Make the Character sheet lockable by a GM, so the Player can no longer modify it.

  • -
-
-

Building a Character sheet

-

There are many ways to build a Character sheet in text, from manually pasting strings together to -more automated ways. Exactly what is the best/easiest way depends on the sheet one tries to create. -We will here show two examples using the EvTable and EvForm utilities.Later we will create -Commands to edit and display the output from those utilities.

-
-

Note that due to the limitations of the wiki, no color is used in any of the examples. See the -text tag documentation for how to add color to the tables and forms.

-
-
-

Making a sheet with EvTable

-

EvTable is a text-table generator. It helps with displaying text in -ordered rows and columns. This is an example of using it in code:

-
# this can be tried out in a Python shell like iPython
-
-from evennia.utils import evtable
-
-# we hardcode these for now, we'll get them as input later
-STR, CON, DEX, INT, WIS, CHA = 12, 13, 8, 10, 9, 13
-
-table = evtable.EvTable("Attr", "Value",
-                        table = [
-                           ["STR", "CON", "DEX", "INT", "WIS", "CHA"],
-                           [STR, CON, DEX, INT, WIS, CHA]
-                        ], align='r', border="incols")
-
-
-

Above, we create a two-column table by supplying the two columns directly. We also tell the table to -be right-aligned and to use the “incols” border type (borders drawns only in between columns). The -EvTable class takes a lot of arguments for customizing its look, you can see some of the possible -keyword arguments here. Once you have the table you -could also retroactively add new columns and rows to it with table.add_row() and -table.add_column(): if necessary the table will expand with empty rows/columns to always remain -rectangular.

-

The result from printing the above table will be

-
table_string = str(table)
-
-print(table_string)
-
- Attr | Value
-~~~~~~+~~~~~~~
-  STR |    12
-  CON |    13
-  DEX |     8
-  INT |    10
-  WIS |     9
-  CHA |    13
-
-
-

This is a minimalistic but effective Character sheet. By combining the table_string with other -strings one could build up a reasonably full graphical representation of a Character. For more -advanced layouts we’ll look into EvForm next.

-
-
-

Making a sheet with EvForm

-

EvForm allows the creation of a two-dimensional “graphic” made by -text characters. On this surface, one marks and tags rectangular regions (“cells”) to be filled with -content. This content can be either normal strings or EvTable instances (see the previous section, -one such instance would be the table variable in that example).

-

In the case of a Character sheet, these cells would be comparable to a line or box where you could -enter the name of your character or their strength score. EvMenu also easily allows to update the -content of those fields in code (it use EvTables so you rebuild the table first before re-sending it -to EvForm).

-

The drawback of EvForm is that its shape is static; if you try to put more text in a region than it -was sized for, the text will be cropped. Similarly, if you try to put an EvTable instance in a field -too small for it, the EvTable will do its best to try to resize to fit, but will eventually resort -to cropping its data or even give an error if too small to fit any data.

-

An EvForm is defined in a Python module. Create a new file mygame/world/charsheetform.py and -modify it thus:

-
#coding=utf-8
-
-# in mygame/world/charsheetform.py
-
-FORMCHAR = "x"
-TABLECHAR = "c"
-
-FORM = """
-.--------------------------------------.
-|                                      |
-| Name: xxxxxxxxxxxxxx1xxxxxxxxxxxxxxx |
-|       xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
-|                                      |
- >------------------------------------<
-|                                      |
-| ccccccccccc  Advantages:             |
-| ccccccccccc   xxxxxxxxxxxxxxxxxxxxxx |
-| ccccccccccc   xxxxxxxxxx3xxxxxxxxxxx |
-| ccccccccccc   xxxxxxxxxxxxxxxxxxxxxx |
-| ccccc2ccccc  Disadvantages:          |
-| ccccccccccc   xxxxxxxxxxxxxxxxxxxxxx |
-| ccccccccccc   xxxxxxxxxx4xxxxxxxxxxx |
-| ccccccccccc   xxxxxxxxxxxxxxxxxxxxxx |
-|                                      |
-+--------------------------------------+
-"""
-
-
-

The #coding statement (which must be put on the very first line to work) tells Python to use the -utf-8 encoding for the file. Using the FORMCHAR and TABLECHAR we define what single-character we -want to use to “mark” the regions of the character sheet holding cells and tables respectively. -Within each block (which must be separated from one another by at least one non-marking character) -we embed identifiers 1-4 to identify each block. The identifier could be any single character except -for the FORMCHAR and TABLECHAR

-
-

You can still use FORMCHAR and TABLECHAR elsewhere in your sheet, but not in a way that it -would identify a cell/table. The smallest identifiable cell/table area is 3 characters wide -including the identifier (for example x2x).

-
-

Now we will map content to this form.

-
# again, this can be tested in a Python shell
-
-# hard-code this info here, later we'll ask the
-# account for this info. We will re-use the 'table'
-# variable from the EvTable example.
-
-NAME = "John, the wise old admin with a chip on his shoulder"
-ADVANTAGES = "Language-wiz, Intimidation, Firebreathing"
-DISADVANTAGES = "Bad body odor, Poor eyesight, Troubled history"
-
-from evennia.utils import evform
-
-# load the form from the module
-form = evform.EvForm("world/charsheetform.py")
-
-# map the data to the form
-form.map(cells={"1":NAME, "3": ADVANTAGES, "4": DISADVANTAGES},
-         tables={"2":table})
-
-
-

We create some RP-sounding input and re-use the table variable from the previous EvTable -example.

-
-

Note, that if you didn’t want to create the form in a separate module you could also load it -directly into the EvForm call like this: EvForm(form={"FORMCHAR":"x", "TABLECHAR":"c", "FORM": formstring}) where FORM specifies the form as a string in the same way as listed in the module -above. Note however that the very first line of the FORM string is ignored, so start with a \n.

-
-

We then map those to the cells of the form:

-
print(form)
-
-
-
.--------------------------------------.
-|                                      |
-| Name: John, the wise old admin with |
-|        a chip on his shoulder        |
-|                                      |
- >------------------------------------<
-|                                      |
-|  Attr|Value  Advantages:             |
-| ~~~~~+~~~~~   Language-wiz,          |
-|   STR|   12   Intimidation,          |
-|   CON|   13   Firebreathing          |
-|   DEX|    8  Disadvantages:          |
-|   INT|   10   Bad body odor, Poor    |
-|   WIS|    9   eyesight, Troubled     |
-|   CHA|   13   history                |
-|                                      |
-+--------------------------------------+
-
-
-

As seen, the texts and tables have been slotted into the text areas and line breaks have been added -where needed. We chose to just enter the Advantages/Disadvantages as plain strings here, meaning -long names ended up split between rows. If we wanted more control over the display we could have -inserted \n line breaks after each line or used a borderless EvTable to display those as well.

-
-
-
-

Tie a Character sheet to a Character

-

We will assume we go with the EvForm example above. We now need to attach this to a Character so -it can be modified. For this we will modify our Character class a little more:

-
# mygame/typeclasses/character.py
-
-from evennia.utils import evform, evtable
-
-[...]
-
-class Character(DefaultCharacter):
-    [...]
-    def at_object_creation(self):
-        "called only once, when object is first created"
-        # we will use this to stop account from changing sheet
-        self.db.sheet_locked = False
-        # we store these so we can build these on demand
-        self.db.chardata  = {"str": 0,
-                             "con": 0,
-                             "dex": 0,
-                             "int": 0,
-                             "wis": 0,
-                             "cha": 0,
-                             "advantages": "",
-                             "disadvantages": ""}
-        self.db.charsheet = evform.EvForm("world/charsheetform.py")
-        self.update_charsheet()
-
-    def update_charsheet(self):
-        """
-        Call this to update the sheet after any of the ingoing data
-        has changed.
-        """
-        data = self.db.chardata
-        table = evtable.EvTable("Attr", "Value",
-                        table = [
-                           ["STR", "CON", "DEX", "INT", "WIS", "CHA"],
-                           [data["str"], data["con"], data["dex"],
-                            data["int"], data["wis"], data["cha"]]],
-                           align='r', border="incols")
-        self.db.charsheet.map(tables={"2": table},
-                              cells={"1":self.key,
-                                     "3":data["advantages"],
-                                     "4":data["disadvantages"]})
-
-
-
-

Use @reload to make this change available to all newly created Characters. Already existing -Characters will not have the charsheet defined, since at_object_creation is only called once. -The easiest to force an existing Character to re-fire its at_object_creation is to use the -@typeclass command in-game:

-
@typeclass/force <Character Name>
-
-
-
-
-

Command for Account to change Character sheet

-

We will add a command to edit the sections of our Character sheet. Open -mygame/commands/command.py.

-
# at the end of mygame/commands/command.py
-
-ALLOWED_ATTRS = ("str", "con", "dex", "int", "wis", "cha")
-ALLOWED_FIELDNAMES = ALLOWED_ATTRS + \
-                     ("name", "advantages", "disadvantages")
-
-def _validate_fieldname(caller, fieldname):
-    "Helper function to validate field names."
-    if fieldname not in ALLOWED_FIELDNAMES:
-        err = "Allowed field names: %s" % (", ".join(ALLOWED_FIELDNAMES))
-        caller.msg(err)
-        return False
-    if fieldname in ALLOWED_ATTRS and not value.isdigit():
-        caller.msg("%s must receive a number." % fieldname)
-        return False
-    return True
-
-class CmdSheet(MuxCommand):
-    """
-    Edit a field on the character sheet
-
-    Usage:
-      @sheet field value
-
-    Examples:
-      @sheet name Ulrik the Warrior
-      @sheet dex 12
-      @sheet advantages Super strength, Night vision
-
-    If given without arguments, will view the current character sheet.
-
-    Allowed field names are:
-       name,
-       str, con, dex, int, wis, cha,
-       advantages, disadvantages
-
-    """
-
-    key = "sheet"
-    aliases = "editsheet"
-    locks = "cmd: perm(Players)"
-    help_category = "RP"
-
-    def func(self):
-        caller = self.caller
-        if not self.args or len(self.args) < 2:
-            # not enough arguments. Display the sheet
-            if sheet:
-                caller.msg(caller.db.charsheet)
-            else:
-                caller.msg("You have no character sheet.")
-            return
-
-        # if caller.db.sheet_locked:
-            caller.msg("Your character sheet is locked.")
-            return
-
-        # split input by whitespace, once
-        fieldname, value = self.args.split(None, 1)
-        fieldname = fieldname.lower() # ignore case
-
-        if not _validate_fieldnames(caller, fieldname):
-            return
-        if fieldname == "name":
-            self.key = value
-        else:
-            caller.chardata[fieldname] = value
-        caller.update_charsheet()
-        caller.msg("%s was set to %s." % (fieldname, value))
-
-
-
-

Most of this command is error-checking to make sure the right type of data was input. Note how the -sheet_locked Attribute is checked and will return if not set.

-

This command you import into mygame/commands/default_cmdsets.py and add to the CharacterCmdSet, -in the same way the @gm command was added to the AccountCmdSet earlier.

-
-
-

Commands for GM to change Character sheet

-

Game masters use basically the same input as Players do to edit a character sheet, except they can -do it on other players than themselves. They are also not stopped by any sheet_locked flags.

-
# continuing in mygame/commands/command.py
-
-class CmdGMsheet(MuxCommand):
-    """
-    GM-modification of char sheets
-
-    Usage:
-      @gmsheet character [= fieldname value]
-
-    Switches:
-      lock - lock the character sheet so the account
-             can no longer edit it (GM's still can)
-      unlock - unlock character sheet for Account
-             editing.
-
-    Examples:
-      @gmsheet Tom
-      @gmsheet Anna = str 12
-      @gmsheet/lock Tom
-
-    """
-    key = "gmsheet"
-    locks = "cmd: perm(Admins)"
-    help_category = "RP"
-
-    def func(self):
-        caller = self.caller
-        if not self.args:
-            caller.msg("Usage: @gmsheet character [= fieldname value]")
-
-        if self.rhs:
-            # rhs (right-hand-side) is set only if a '='
-            # was given.
-            if len(self.rhs) < 2:
-                caller.msg("You must specify both a fieldname and value.")
-                return
-            fieldname, value = self.rhs.split(None, 1)
-            fieldname = fieldname.lower()
-            if not _validate_fieldname(caller, fieldname):
-                return
-            charname = self.lhs
-        else:
-            # no '=', so we must be aiming to look at a charsheet
-            fieldname, value = None, None
-            charname = self.args.strip()
-
-        character = caller.search(charname, global_search=True)
-        if not character:
-            return
-
-        if "lock" in self.switches:
-            if character.db.sheet_locked:
-                caller.msg("The character sheet is already locked.")
-            else:
-                character.db.sheet_locked = True
-                caller.msg("%s can no longer edit their character sheet." % character.key)
-        elif "unlock" in self.switches:
-            if not character.db.sheet_locked:
-                caller.msg("The character sheet is already unlocked.")
-            else:
-                character.db.sheet_locked = False
-                caller.msg("%s can now edit their character sheet." % character.key)
-
-        if fieldname:
-            if fieldname == "name":
-                character.key = value
-            else:
-                character.db.chardata[fieldname] = value
-            character.update_charsheet()
-            caller.msg("You set %s's %s to %s." % (character.key, fieldname, value)
-        else:
-            # just display
-            caller.msg(character.db.charsheet)
-
-
-

The @gmsheet command takes an additional argument to specify which Character’s character sheet to -edit. It also takes /lock and /unlock switches to block the Player from tweaking their sheet.

-

Before this can be used, it should be added to the default CharacterCmdSet in the same way as the -normal @sheet. Due to the lock set on it, this command will only be available to Admins (i.e. -GMs) or higher permission levels.

-
-
-
-

Dice roller

-

Evennia’s contrib folder already comes with a full dice roller. To add it to the game, simply -import contrib.dice.CmdDice into mygame/commands/default_cmdsets.py and add CmdDice to the -CharacterCmdset as done with other commands in this tutorial. After a @reload you will be able -to roll dice using normal RPG-style format:

-
roll 2d6 + 3
-7
-
-
-

Use help dice to see what syntax is supported or look at evennia/contrib/dice.py to see how it’s -implemented.

-
-
-

Rooms

-

Evennia comes with rooms out of the box, so no extra work needed. A GM will automatically have all -needed building commands available. A fuller go-through is found in the Building -tutorial. Here are some useful highlights:

-
    -
  • @dig roomname;alias = exit_there;alias, exit_back;alias - this is the basic command for digging -a new room. You can specify any exit-names and just enter the name of that exit to go there.

  • -
  • @tunnel direction = roomname - this is a specialized command that only accepts directions in the -cardinal directions (n,ne,e,se,s,sw,w,nw) as well as in/out and up/down. It also automatically -builds “matching” exits back in the opposite direction.

  • -
  • @create/drop objectname - this creates and drops a new simple object in the current location.

  • -
  • @desc obj - change the look-description of the object.

  • -
  • @tel object = location - teleport an object to a named location.

  • -
  • @search objectname - locate an object in the database.

  • -
-
-

TODO: Describe how to add a logging room, that logs says and poses to a log file that people can -access after the fact.

-
-
-
-

Channels

-

Evennia comes with Channels in-built and they are described fully in the -documentation. For brevity, here are the relevant commands for normal use:

-
    -
  • @ccreate new_channel;alias;alias = short description - Creates a new channel.

  • -
  • addcom channel - join an existing channel. Use addcom alias = channel to add a new alias you -can use to talk to the channel, as many as desired.

  • -
  • delcom alias or channel - remove an alias from a channel or, if the real channel name is given, -unsubscribe completely.

  • -
  • @channels lists all available channels, including your subscriptions and any aliases you have -set up for them.

  • -
-

You can read channel history: if you for example are chatting on the public channel you can do -public/history to see the 20 last posts to that channel or public/history 32 to view twenty -posts backwards, starting with the 32nd from the end.

-
-
-

PMs

-

To send PMs to one another, players can use the @page (or tell) command:

-
page recipient = message
-page recipient, recipient, ... = message
-
-
-

Players can use page alone to see the latest messages. This also works if they were not online -when the message was sent.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Execute-Python-Code.html b/docs/0.9.5/Execute-Python-Code.html deleted file mode 100644 index a72419f38b..0000000000 --- a/docs/0.9.5/Execute-Python-Code.html +++ /dev/null @@ -1,239 +0,0 @@ - - - - - - - - - Execute Python Code — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Execute Python Code

-

The @py command supplied with the default command set of Evennia allows you to execute Python -commands directly from inside the game. An alias to @py is simply “!”. Access to the @py -command should be severely restricted. This is no joke - being able to execute arbitrary Python -code on the server is not something you should entrust to just anybody.

-
@py 1+2
-<<< 3
-
-
-
-

Available variables

-

A few local variables are made available when running @py. These offer entry into the running -system.

-
    -
  • self / me - the calling object (i.e. you)

  • -
  • here - the current caller’s location

  • -
  • obj - a dummy Object instance

  • -
  • evennia - Evennia’s flat API - through this you can access all of Evennia.

  • -
-

For accessing other objects in the same room you need to use self.search(name). For objects in -other locations, use one of the evennia.search_* methods. See [below](./Execute-Python-Code.md#finding- -objects).

-
-
-

Returning output

-

This is an example where we import and test one of Evennia’s utilities found in -src/utils/utils.py, but also accessible through ev.utils:

-
@py from ev import utils; utils.time_format(33333)
-<<< Done.
-
-
-

Note that we didn’t get any return value, all we where told is that the code finished executing -without error. This is often the case in more complex pieces of code which has no single obvious -return value. To see the output from the time_format() function we need to tell the system to -echo it to us explicitly with self.msg().

-
@py from ev import utils; self.msg(str(utils.time_format(33333)))
-09:15
-<<< Done.
-
-
-
-

Warning: When using the msg function wrap our argument in str() to convert it into a string -above. This is not strictly necessary for most types of data (Evennia will usually convert to a -string behind the scenes for you). But for lists and tuples you will be confused by the output -if you don’t wrap them in str(): only the first item of the iterable will be returned. This is -because doing msg(text) is actually just a convenience shortcut; the full argument that msg -accepts is something called an outputfunc on the form (cmdname, (args), {kwargs}) (see the -message path for more info). Sending a list/tuple confuses Evennia to think you are -sending such a structure. Converting it to a string however makes it clear it should just be -displayed as-is.

-
-

If you were to use Python’s standard print, you will see the result in your current stdout (your -terminal by default, otherwise your log file).

-
-
-

Finding objects

-

A common use for @py is to explore objects in the database, for debugging and performing specific -operations that are not covered by a particular command.

-

Locating an object is best done using self.search():

-
@py self.search("red_ball")
-<<< Ball
-
-@py self.search("red_ball").db.color = "red"
-<<< Done.
-
-@py self.search("red_ball").db.color
-<<< red
-
-
-

self.search() is by far the most used case, but you can also search other database tables for -other Evennia entities like scripts or configuration entities. To do this you can use the generic -search entries found in ev.search_*.

-
@py evennia.search_script("sys_game_time")
-<<< [<src.utils.gametime.GameTime object at 0x852be2c>]
-
-
-

(Note that since this becomes a simple statement, we don’t have to wrap it in self.msg() to get -the output). You can also use the database model managers directly (accessible through the objects -properties of database models or as evennia.managers.*). This is a bit more flexible since it -gives you access to the full range of database search methods defined in each manager.

-
@py evennia.managers.scripts.script_search("sys_game_time")
-<<< [<src.utils.gametime.GameTime object at 0x852be2c>]
-
-
-

The managers are useful for all sorts of database studies.

-
@py ev.managers.configvalues.all()
-<<< [<ConfigValue: default_home]>, <ConfigValue:site_name>, ...]
-
-
-
-
-

Testing code outside the game

-

@py has the advantage of operating inside a running server (sharing the same process), where you -can test things in real time. Much of this can be done from the outside too though.

-

In a terminal, cd to the top of your game directory (this bit is important since we need access to -your config file) and run

-
evennia shell
-
-
-

Your default Python interpreter will start up, configured to be able to work with and import all -modules of your Evennia installation. From here you can explore the database and test-run individual -modules as desired.

-

It’s recommended that you get a more fully featured Python interpreter like -iPython. If you use a virtual environment, you can just get it -with pip install ipython. IPython allows you to better work over several lines, and also has a lot -of other editing features, such as tab-completion and __doc__-string reading.

-
$ evennia shell
-
-IPython 0.10 -- An enhanced Interactive Python
-...
-
-In [1]: import evennia
-In [2]: evennia.managers.objects.all()
-Out[3]: [<ObjectDB: Harry>, <ObjectDB: Limbo>, ...]
-
-
-

See the page about the Evennia-API for more things to explore.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/First-Steps-Coding.html b/docs/0.9.5/First-Steps-Coding.html deleted file mode 100644 index 14e283c5fa..0000000000 --- a/docs/0.9.5/First-Steps-Coding.html +++ /dev/null @@ -1,396 +0,0 @@ - - - - - - - - - First Steps Coding — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

First Steps Coding

-

This section gives a brief step-by-step introduction on how to set up Evennia for the first time so -you can modify and overload the defaults easily. You should only need to do these steps once. It -also walks through you making your first few tweaks.

-

Before continuing, make sure you have Evennia installed and running by following the Getting -Started instructions. You should have initialized a new game folder with the -evennia --init foldername command. We will in the following assume this folder is called -“mygame”.

-

It might be a good idea to eye through the brief Coding Introduction too -(especially the recommendations in the section about the evennia “flat” API and about using evennia shell will help you here and in the future).

-

To follow this tutorial you also need to know the basics of operating your computer’s -terminal/command line. You also need to have a text editor to edit and create source text files. -There are plenty of online tutorials on how to use the terminal and plenty of good free text -editors. We will assume these things are already familiar to you henceforth.

-
-

Your First Changes

-

Below are some first things to try with your new custom modules. You can test these to get a feel -for the system. See also Tutorials for more step-by-step help and special cases.

-
-

Tweak Default Character

-

We will add some simple rpg attributes to our default Character. In the next section we will follow -up with a new command to view those attributes.

-
    -
  1. Edit mygame/typeclasses/characters.py and modify the Character class. The -at_object_creation method also exists on the DefaultCharacter parent and will overload it. The -get_abilities method is unique to our version of Character.

    -
    class Character(DefaultCharacter):
    -    # [...]
    -    def at_object_creation(self):
    -        """
    -        Called only at initial creation. This is a rather silly
    -        example since ability scores should vary from Character to
    -        Character and is usually set during some character
    -        generation step instead.
    -        """
    -        #set persistent attributes
    -        self.db.strength = 5
    -        self.db.agility = 4
    -        self.db.magic = 2
    -
    -    def get_abilities(self):
    -        """
    -        Simple access method to return ability
    -        scores as a tuple (str,agi,mag)
    -        """
    -        return self.db.strength, self.db.agility, self.db.magic
    -
    -
    -
  2. -
  3. Reload the server (you will still be connected to the game after doing -this). Note that if you examine yourself you will not see any new Attributes appear yet. Read -the next section to understand why.

  4. -
-
-

Updating Yourself

-

It’s important to note that the new Attributes we added above will only be stored on -newly created characters. The reason for this is simple: The at_object_creation method, where we -added those Attributes, is per definition only called when the object is first created, then never -again. This is usually a good thing since those Attributes may change over time - calling that hook -would reset them back to start values. But it also means that your existing character doesn’t have -them yet. You can see this by calling the get_abilities hook on yourself at this point:

-
# (you have to be superuser to use @py)
-@py self.get_abilities()
-<<< (None, None, None)
-
-
-

This is easily remedied.

-
@update self
-
-
-

This will (only) re-run at_object_creation on yourself. You should henceforth be able to get the -abilities successfully:

-
@py self.get_abilities()
-<<< (5, 4, 2)
-
-
-

This is something to keep in mind if you start building your world before your code is stable - -startup-hooks will not (and should not) automatically run on existing objects - you have to update -your existing objects manually. Luckily this is a one-time thing and pretty simple to do. If the -typeclass you want to update is in typeclasses.myclass.MyClass, you can do the following (e.g. -from evennia shell):

-
from typeclasses.myclass import MyClass
-# loop over all MyClass instances in the database
-# and call .swap_typeclass on them
-for obj in MyClass.objects.all():
-    obj.swap_typeclass(MyClass, run_start_hooks="at_object_creation")
-
-
-

Using swap_typeclass to the same typeclass we already have will re-run the creation hooks (this is -what the @update command does under the hood). From in-game you can do the same with @py:

-
@py typeclasses.myclass import MyClass;[obj.swap_typeclass(MyClass) for obj in
-MyClass.objects.all()]
-
-
-

See the Object Typeclass tutorial for more help and the -Typeclasses and Attributes page for detailed documentation about -Typeclasses and Attributes.

-
-
-

Troubleshooting: Updating Yourself

-

One may experience errors for a number of reasons. Common beginner errors are spelling mistakes, -wrong indentations or code omissions leading to a SyntaxError. Let’s say you leave out a colon -from the end of a class function like so: def at_object_creation(self). The client will reload -without issue. However, if you look at the terminal/console (i.e. not in-game), you will see -Evennia complaining (this is called a traceback):

-
Traceback (most recent call last):
-File "C:\mygame\typeclasses\characters.py", line 33
-     def at_object_creation(self)
-                                 ^
-SyntaxError: invalid syntax
-
-
-

Evennia will still be restarting and following the tutorial, doing @py self.get_abilities() will -return the right response (None, None, None). But when attempting to @typeclass/force self you -will get this response:

-
    AttributeError: 'DefaultObject' object has no attribute 'get_abilities'
-
-
-

The full error will show in the terminal/console but this is confusing since you did add -get_abilities before. Note however what the error says - you (self) should be a Character but -the error talks about DefaultObject. What has happened is that due to your unhandled SyntaxError -earlier, Evennia could not load the character.py module at all (it’s not valid Python). Rather -than crashing, Evennia handles this by temporarily falling back to a safe default - DefaultObject

-
    -
  • in order to keep your MUD running. Fix the original SyntaxError and reload the server. Evennia -will then be able to use your modified Character class again and things should work.

  • -
-
-

Note: Learning how to interpret an error traceback is a critical skill for anyone learning Python. -Full tracebacks will appear in the terminal/Console you started Evennia from. The traceback text can -sometimes be quite long, but you are usually just looking for the last few lines: The description of -the error and the filename + line number for where the error occurred. In the example above, we see -it’s a SyntaxError happening at line 33 of mygame\typeclasses\characters.py. In this case it -even points out where on the line it encountered the error (the missing colon). Learn to read -tracebacks and you’ll be able to resolve the vast majority of common errors easily.

-
-
-
-
-

Add a New Default Command

-

The @py command used above is only available to privileged users. We want any player to be able to -see their stats. Let’s add a new command to list the abilities we added in the previous -section.

-
    -
  1. Open mygame/commands/command.py. You could in principle put your command anywhere but this -module has all the imports already set up along with some useful documentation. Make a new class at -the bottom of this file:

    -
        class CmdAbilities(BaseCommand):
    -        """
    -        List abilities
    -
    -        Usage:
    -          abilities
    -
    -        Displays a list of your current ability values.
    -        """
    -        key = "abilities"
    -        aliases = ["abi"]
    -        lock = "cmd:all()"
    -        help_category = "General"
    -
    -        def func(self):
    -            """implements the actual functionality"""
    -
    -             str, agi, mag = self.caller.get_abilities()
    -             string = "STR: %s, AGI: %s, MAG: %s" % (str, agi, mag)
    -             self.caller.msg(string)
    -
    -
    -
  2. -
  3. Next you edit mygame/commands/default_cmdsets.py and add a new import to it near the top:

    -
        from commands.command import CmdAbilities
    -
    -
    -
  4. -
  5. In the CharacterCmdSet class, add the following near the bottom (it says where):

    -
        self.add(CmdAbilities())
    -
    -
    -
  6. -
  7. Reload the server (noone will be disconnected by doing this).

  8. -
-

You (and anyone else) should now be able to use abilities (or its alias abi) as part of your -normal commands in-game:

-
abilities
-STR: 5, AGI: 4, MAG: 2
-
-
-

See the Adding a Command tutorial for more examples and the -Commands section for detailed documentation about the Command system.

-
-
-

Make a New Type of Object

-

Let’s test to make a new type of object. This example is an “wise stone” object that returns some -random comment when you look at it, like this:

-
> look stone
-
-A very wise stone
-
-This is a very wise old stone.
-It grumbles and says: 'The world is like a rock of chocolate.'
-
-
-
    -
  1. Create a new module in mygame/typeclasses/. Name it wiseobject.py for this example.

  2. -
  3. In the module import the base Object (typeclasses.objects.Object). This is empty by default, -meaning it is just a proxy for the default evennia.DefaultObject.

  4. -
  5. Make a new class in your module inheriting from Object. Overload hooks on it to add new -functionality. Here is an example of how the file could look:

    -
    from random import choice
    -from typeclasses.objects import Object
    -
    -class WiseObject(Object):
    -    """
    -    An object speaking when someone looks at it. We
    -    assume it looks like a stone in this example.
    -    """
    -    def at_object_creation(self):
    -        """Called when object is first created"""
    -        self.db.wise_texts = \
    -               ["Stones have feelings too.",
    -                "To live like a stone is to not have lived at all.",
    -                "The world is like a rock of chocolate."]
    -
    -    def return_appearance(self, looker):
    -        """
    -        Called by the look command. We want to return
    -        a wisdom when we get looked at.
    -        """
    -        # first get the base string from the
    -        # parent's return_appearance.
    -        string = super().return_appearance(looker)
    -        wisewords = "\n\nIt grumbles and says: '%s'"
    -        wisewords = wisewords % choice(self.db.wise_texts)
    -        return string + wisewords
    -
    -
    -
  6. -
  7. Check your code for bugs. Tracebacks will appear on your command line or log. If you have a grave -Syntax Error in your code, the source file itself will fail to load which can cause issues with the -entire cmdset. If so, fix your bug and reload the server from the command line -(noone will be disconnected by doing this).

  8. -
  9. Use @create/drop stone:wiseobject.WiseObject to create a talkative stone. If the @create -command spits out a warning or cannot find the typeclass (it will tell you which paths it searched), -re-check your code for bugs and that you gave the correct path. The @create command starts looking -for Typeclasses in mygame/typeclasses/.

  10. -
  11. Use look stone to test. You will see the default description (“You see nothing special”) -followed by a random message of stony wisdom. Use @desc stone = This is a wise old stone. to make -it look nicer. See the Builder Docs for more information.

  12. -
-

Note that at_object_creation is only called once, when the stone is first created. If you make -changes to this method later, already existing stones will not see those changes. As with the -Character example above you can use @typeclass/force to tell the stone to re-run its -initialization.

-

The at_object_creation is a special case though. Changing most other aspects of the typeclass does -not require manual updating like this - you just need to @reload to have all changes applied -automatically to all existing objects.

-
-
-
-

Where to Go From Here?

-

There are more Tutorials, including one for building a whole little MUSH-like -game - that is instructive also if you have no interest in -MUSHes per se. A good idea is to also get onto the IRC -chat and the mailing -list to get in touch with the community and other -developers.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Game-Planning.html b/docs/0.9.5/Game-Planning.html deleted file mode 100644 index f40a3a4890..0000000000 --- a/docs/0.9.5/Game-Planning.html +++ /dev/null @@ -1,334 +0,0 @@ - - - - - - - - - Game Planning — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Game Planning

-

So you have Evennia up and running. You have a great game idea in mind. Now it’s time to start -cracking! But where to start? Here are some ideas for a workflow. Note that the suggestions on this -page are just that - suggestions. Also, they are primarily aimed at a lone hobby designer or a small -team developing a game in their free time.

-

Below are some minimal steps for getting the first version of a new game world going with players. -It’s worth to at least make the attempt to do these steps in order even if you are itching to jump -ahead in the development cycle. On the other hand, you should also make sure to keep your work fun -for you, or motivation will falter. Making a full game is a lot of work as it is, you’ll need all -your motivation to make it a reality.

-

Remember that 99.99999% of all great game ideas never lead to a game. Especially not to an online -game that people can actually play and enjoy. So our first all overshadowing goal is to beat those -odds and get something out the door! Even if it’s a scaled-down version of your dream game, -lacking many “must-have” features! It’s better to get it out there and expand on it later than to -code in isolation forever until you burn out, lose interest or your hard drive crashes.

-

Like is common with online games, getting a game out the door does not mean you are going to be -“finished” with the game - most MUDs add features gradually over the course of years - it’s often -part of the fun!

-
-

Planning (step 1)

-

This is what you do before having coded a single line or built a single room. Many prospective game -developers are very good at parts of this process, namely in defining what their world is “about”: -The theme, the world concept, cool monsters and so on. It is by all means very important to define -what is the unique appeal of your game. But it’s unfortunately not enough to make your game a -reality. To do that you must also have an idea of how to actually map those great ideas onto -Evennia.

-

A good start is to begin by planning out the basic primitives of the game and what they need to be -able to do. Below are a far-from-complete list of examples (and for your first version you should -definitely try for a much shorter list):

-
-

Systems

-

These are the behind-the-scenes features that exist in your game, often without being represented by -a specific in-game object.

-
    -
  • Should your game rules be enforced by coded systems or are you planning for human game masters to -run and arbitrate rules?

  • -
  • What are the actual mechanical game rules? How do you decide if an action succeeds or fails? What -“rolls” does the game need to be able to do? Do you base your game off an existing system or make up -your own?

  • -
  • Does the flow of time matter in your game - does night and day change? What about seasons? Maybe -your magic system is affected by the phase of the moon?

  • -
  • Do you want changing, global weather? This might need to operate in tandem over a large number of -rooms.

  • -
  • Do you want a game-wide economy or just a simple barter system? Or no formal economy at all?

  • -
  • Should characters be able to send mail to each other in-game?

  • -
  • Should players be able to post on Bulletin boards?

  • -
  • What is the staff hierarchy in your game? What powers do you want your staff to have?

  • -
  • What should a Builder be able to build and what commands do they need in order to do that?

  • -
  • etc.

  • -
-
-
-

Rooms

-

Consider the most basic room in your game.

-
    -
  • Is a simple description enough or should the description be able to change (such as with time, by -light conditions, weather or season)?

  • -
  • Should the room have different statuses? Can it have smells, sounds? Can it be affected by -dramatic weather, fire or magical effects? If so, how would this affect things in the room? Or are -these things something admins/game masters should handle manually?

  • -
  • Can objects be hidden in the room? Can a person hide in the room? How does the room display this?

  • -
  • etc.

  • -
-
-
-

Objects

-

Consider the most basic (non-player-controlled) object in your game.

-
    -
  • How numerous are your objects? Do you want large loot-lists or are objects just role playing props -created on demand?

  • -
  • Does the game use money? If so, is each coin a separate object or do you just store a bank account -value?

  • -
  • What about multiple identical objects? Do they form stacks and how are those stacks handled in -that case?

  • -
  • Does an object have weight or volume (so you cannot carry an infinite amount of them)?

  • -
  • Can objects be broken? If so, does it have a health value? Is burning it causing the same damage -as smashing it? Can it be repaired?

  • -
  • Is a weapon a specific type of object or are you supposed to be able to fight with a chair too? -Can you fight with a flower or piece of paper as well?

  • -
  • NPCs/mobs are also objects. Should they just stand around or should they have some sort of AI?

  • -
  • Are NPCs/mobs differet entities? How is an Orc different from a Kobold, in code - are they the -same object with different names or completely different types of objects, with custom code?

  • -
  • Should there be NPCs giving quests? If so, how would you track quest status and what happens when -multiple players try to do the same quest? Do you use instances or some other mechanism?

  • -
  • etc.

  • -
-
-
-

Characters

-

These are the objects controlled directly by Players.

-
    -
  • Can players have more than one Character active at a time or are they allowed to multi-play?

  • -
  • How does a Player create their Character? A Character-creation screen? Answering questions? -Filling in a form?

  • -
  • Do you want to use classes (like “Thief”, “Warrior” etc) or some other system, like Skill-based?

  • -
  • How do you implement different “classes” or “races”? Are they separate types of objects or do you -simply load different stats on a basic object depending on what the Player wants?

  • -
  • If a Character can hide in a room, what skill will decide if they are detected?

  • -
  • What skill allows a Character to wield a weapon and hit? Do they need a special skill to wield a -chair rather than a sword?

  • -
  • Does a Character need a Strength attribute to tell how much they can carry or which objects they -can smash?

  • -
  • What does the skill tree look like? Can a Character gain experience to improve? By killing -enemies? Solving quests? By roleplaying?

  • -
  • etc.

  • -
-

A MUD’s a lot more involved than you would think and these things hang together in a complex web. It -can easily become overwhelming and it’s tempting to want all functionality right out of the door. -Try to identify the basic things that “make” your game and focus only on them for your first -release. Make a list. Keep future expansions in mind but limit yourself.

-
-
-
-

Coding (step 2)

-

This is the actual work of creating the “game” part of your game. Many “game-designer” types tend to -gloss over this bit and jump directly to World Building. Vice versa, many “game-coder” types -tend to jump directly to this part without doing the Planning first. Neither way is good and -will lead to you having to redo all your hard work at least once, probably more.

-

Evennia’s Developer Central tries to help you with this bit of development. We -also have a slew of Tutorials with worked examples. Evennia tries hard to make this -part easier for you, but there is no way around the fact that if you want anything but a very basic -Talker-type game you will have to bite the bullet and code your game (or find a coder willing to -do it for you).

-

Even if you won’t code anything yourself, as a designer you need to at least understand the basic -paradigms of Evennia, such as Objects, Commands and Scripts and -how they hang together. We recommend you go through the [Tutorial World](Tutorial-World- -Introduction) in detail (as well as glancing at its code) to get at least a feel for what is -involved behind the scenes. You could also look through the tutorial for building a game from -scratch.

-

During Coding you look back at the things you wanted during the Planning phase and try to -implement them. Don’t be shy to update your plans if you find things easier/harder than you thought. -The earlier you revise problems, the easier they will be to fix.

-

A good idea is to host your code online (publicly or privately) using version control. Not only will -this make it easy for multiple coders to collaborate (and have a bug-tracker etc), it also means -your work is backed up at all times. The Version Control tutorial has -instructions for setting up a sane developer environment with proper version control.

-
-

“Tech Demo” Building

-

This is an integral part of your Coding. It might seem obvious to experienced coders, but it cannot -be emphasized enough that you should test things on a small scale before putting your untested -code into a large game-world. The earlier you test, the easier and cheaper it will be to fix bugs -and even rework things that didn’t work out the way you thought they would. You might even have to -go back to the Planning phase if your ideas can’t handle their meet with reality.

-

This means building singular in-game examples. Make one room and one object of each important type -and test so they work correctly in isolation. Then add more if they are supposed to interact with -each other in some way. Build a small series of rooms to test how mobs move around … and so on. In -short, a test-bed for your growing code. It should be done gradually until you have a fully -functioning (if not guaranteed bug-free) miniature tech demo that shows all the features you want -in the first release of your game. There does not need to be any game play or even a theme to your -tests, this is only for you and your co-coders to see. The more testing you do on this small scale, -the less headaches you will have in the next phase.

-
-
-
-

World Building (step 3)

-

Up until this point we’ve only had a few tech-demo objects in the database. This step is the act of -populating the database with a larger, thematic world. Too many would-be developers jump to this -stage too soon (skipping the Coding or even Planning stages). What if the rooms you build -now doesn’t include all the nice weather messages the code grows to support? Or the way you store -data changes under the hood? Your building work would at best require some rework and at worst you -would have to redo the whole thing. And whereas Evennia’s typeclass system does allow you to edit -the properties of existing objects, some hooks are only called at object creation … Suffice to -say you are in for a lot of unnecessary work if you build stuff en masse without having the -underlying code systems in some reasonable shape first.

-

So before starting to build, the “game” bit (Coding + Testing) should be more or less -complete, at least to the level of your initial release.

-

Before starting to build, you should also plan ahead again. Make sure it is clear to yourself and -your eventual builders just which parts of the world you want for your initial release. Establish -for everyone which style, quality and level of detail you expect. Your goal should not be to -complete your entire world in one go. You want just enough to make the game’s “feel” come across. -You want a minimal but functioning world where the intended game play can be tested and roughly -balanced. You can always add new areas later.

-

During building you get free and extensive testing of whatever custom build commands and systems you -have made at this point. Since Building often involves different people than those Coding, you also -get a chance to hear if some things are hard to understand or non-intuitive. Make sure to respond -to this feedback.

-
-
-

Alpha Release

-

As mentioned, don’t hold onto your world more than necessary. Get it out there with a huge Alpha -flag and let people try it! Call upon your alpha-players to try everything - they will find ways -to break your game in ways that you never could have imagined. In Alpha you might be best off to -focus on inviting friends and maybe other MUD developers, people who you can pester to give proper -feedback and bug reports (there will be bugs, there is no way around it). Follow the quick -instructions for Online Setup to make your game visible online. If you hadn’t -already, make sure to put up your game on the Evennia game index so -people know it’s in the works (actually, even pre-alpha games are allowed in the index so don’t be -shy)!

-
-
-

Beta Release/Perpetual Beta

-

Once things stabilize in Alpha you can move to Beta and let more people in. Many MUDs are in -perpetual beta, meaning they are never considered -“finished”, but just repeat the cycle of Planning, Coding, Testing and Building over and over as new -features get implemented or Players come with suggestions. As the game designer it is now up to you -to gradually perfect your vision.

-
-
-

Congratulate yourself!

-

You are worthy of a celebration since at this point you have joined the small, exclusive crowd who -have made their dream game a reality!

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Gametime-Tutorial.html b/docs/0.9.5/Gametime-Tutorial.html deleted file mode 100644 index fb0c6cfefa..0000000000 --- a/docs/0.9.5/Gametime-Tutorial.html +++ /dev/null @@ -1,399 +0,0 @@ - - - - - - - - - Gametime Tutorial — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Gametime Tutorial

-

A lot of games use a separate time system we refer to as game time. This runs in parallel to what -we usually think of as real time. The game time might run at a different speed, use different -names for its time units or might even use a completely custom calendar. You don’t need to rely on a -game time system at all. But if you do, Evennia offers basic tools to handle these various -situations. This tutorial will walk you through these features.

-
-

A game time with a standard calendar

-

Many games let their in-game time run faster or slower than real time, but still use our normal -real-world calendar. This is common both for games set in present day as well as for games in -historical or futuristic settings. Using a standard calendar has some advantages:

-
    -
  • Handling repetitive actions is much easier, since converting from the real time experience to the -in-game perceived one is easy.

  • -
  • The intricacies of the real world calendar, with leap years and months of different length etc are -automatically handled by the system.

  • -
-

Evennia’s game time features assume a standard calendar (see the relevant section below for a custom -calendar).

-
-

Setting up game time for a standard calendar

-

All is done through the settings. Here are the settings you should use if you want a game time with -a standard calendar:

-
# in a file settings.py in mygame/server/conf
-# The time factor dictates if the game world runs faster (timefactor>1)
-# or slower (timefactor<1) than the real world.
-TIME_FACTOR = 2.0
-
-# The starting point of your game time (the epoch), in seconds.
-# In Python a value of 0 means Jan 1 1970 (use negatives for earlier
-# start date). This will affect the returns from the utils.gametime
-# module.
-TIME_GAME_EPOCH = None
-
-
-

By default, the game time runs twice as fast as the real time. You can set the time factor to be 1 -(the game time would run exactly at the same speed than the real time) or lower (the game time will -be slower than the real time). Most games choose to have the game time spinning faster (you will -find some games that have a time factor of 60, meaning the game time runs sixty times as fast as the -real time, a minute in real time would be an hour in game time).

-

The epoch is a slightly more complex setting. It should contain a number of seconds that would -indicate the time your game started. As indicated, an epoch of 0 would mean January 1st, 1970. If -you want to set your time in the future, you just need to find the starting point in seconds. There -are several ways to do this in Python, this method will show you how to do it in local time:

-
# We're looking for the number of seconds representing
-# January 1st, 2020
-from datetime import datetime
-import time
-start = datetime(2020, 1, 1)
-time.mktime(start.timetuple())
-
-
-

This should return a huge number - the number of seconds since Jan 1 1970. Copy that directly into -your settings (editing server/conf/settings.py):

-
# in a file settings.py in mygame/server/conf
-TIME_GAME_EPOCH = 1577865600
-
-
-

Reload the game with @reload, and then use the @time command. You should see something like -this:

-
+----------------------------+-------------------------------------+
-| Server time                |                                     |
-+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
-| Current uptime             | 20 seconds                          |
-| Total runtime              | 1 day, 1 hour, 55 minutes           |
-| First start                | 2017-02-12 15:47:50.565000          |
-| Current time               | 2017-02-13 17:43:10.760000          |
-+----------------------------+-------------------------------------+
-| In-Game time               | Real time x 2                       |
-+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
-| Epoch (from settings)      | 2020-01-01 00:00:00                 |
-| Total time passed:         | 1 day, 17 hours, 34 minutes         |
-| Current time               | 2020-01-02 17:34:55.430000          |
-+----------------------------+-------------------------------------+
-
-
-

The line that is most relevant here is the game time epoch. You see it shown at 2020-01-01. From -this point forward, the game time keeps increasing. If you keep typing @time, you’ll see the game -time updated correctly… and going (by default) twice as fast as the real time.

-
- -
-
-

A game time with a custom calendar

-

Using a custom calendar to handle game time is sometimes needed if you want to place your game in a -fictional universe. For instance you may want to create the Shire calendar which Tolkien described -having 12 months, each which 30 days. That would give only 360 days per year (presumably hobbits -weren’t really fond of the hassle of following the astronomical calendar). Another example would be -creating a planet in a different solar system with, say, days 29 hours long and months of only 18 -days.

-

Evennia handles custom calendars through an optional contrib module, called custom_gametime. -Contrary to the normal gametime module described above it is not active by default.

-
-

Setting up the custom calendar

-

In our first example of the Shire calendar, used by hobbits in books by Tolkien, we don’t really -need the notion of weeks… but we need the notion of months having 30 days, not 28.

-

The custom calendar is defined by adding the TIME_UNITS setting to your settings file. It’s a -dictionary containing as keys the name of the units, and as value the number of seconds (the -smallest unit for us) in this unit. Its keys must be picked among the following: “sec”, “min”, -“hour”, “day”, “week”, “month” and “year” but you don’t have to include them all. Here is the -configuration for the Shire calendar:

-
# in a file settings.py in mygame/server/conf
-TIME_UNITS = {"sec": 1,
-              "min": 60,
-              "hour": 60 * 60,
-              "day": 60 * 60 * 24,
-              "month": 60 * 60 * 24 * 30,
-              "year": 60 * 60 * 24 * 30 * 12 }
-
-
-

We give each unit we want as keys. Values represent the number of seconds in that unit. Hour is -set to 60 * 60 (that is, 3600 seconds per hour). Notice that we don’t specify the week unit in this -configuration: instead, we skip from days to months directly.

-

In order for this setting to work properly, remember all units have to be multiples of the previous -units. If you create “day”, it needs to be multiple of hours, for instance.

-

So for our example, our settings may look like this:

-
# in a file settings.py in mygame/server/conf
-# Time factor
-TIME_FACTOR = 4
-
-# Game time epoch
-TIME_GAME_EPOCH = 0
-
-# Units
-TIME_UNITS = {
-        "sec": 1,
-        "min": 60,
-        "hour": 60 * 60,
-        "day": 60 * 60 * 24,
-        "month": 60 * 60 * 24 * 30,
-        "year": 60 * 60 * 24 * 30 * 12,
-}
-
-
-

Notice we have set a time epoch of 0. Using a custom calendar, we will come up with a nice display -of time on our own. In our case the game time starts at year 0, month 0, day 0, and at midnight.

-

Note that while we use “month”, “week” etc in the settings, your game may not use those terms in- -game, instead referring to them as “cycles”, “moons”, “sand falls” etc. This is just a matter of you -displaying them differently. See next section.

-
-
-

A command to display the current game time

-

As pointed out earlier, the @time command is meant to be used with a standard calendar, not a -custom one. We can easily create a new command though. We’ll call it time, as is often the case -on other MU*. Here’s an example of how we could write it (for the example, you can create a file -showtime.py in your commands directory and paste this code in it):

-
# in a file mygame/commands/gametime.py
-
-from evennia.contrib import custom_gametime
-
-from commands.command import Command
-
-class CmdTime(Command):
-
-    """
-    Display the time.
-
-    Syntax:
-        time
-
-    """
-
-    key = "time"
-    locks = "cmd:all()"
-
-    def func(self):
-        """Execute the time command."""
-        # Get the absolute game time
-        year, month, day, hour, min, sec = custom_gametime.custom_gametime(absolute=True)
-        string = "We are in year {year}, day {day}, month {month}."
-        string += "\nIt's {hour:02}:{min:02}:{sec:02}."
-        self.msg(string.format(year=year, month=month, day=day,
-                hour=hour, min=min, sec=sec))
-
-
-

Don’t forget to add it in your CharacterCmdSet to see this command:

-
# in mygame/commands/default_cmdset.py
-
-from commands.gametime import CmdTime   # <-- Add
-
-# ...
-
-class CharacterCmdSet(default_cmds.CharacterCmdSet):
-    """
-    The `CharacterCmdSet` contains general in-game commands like `look`,
-    `get`, etc available on in-game Character objects. It is merged with
-    the `AccountCmdSet` when an Account puppets a Character.
-    """
-    key = "DefaultCharacter"
-
-    def at_cmdset_creation(self):
-        """
-        Populates the cmdset
-        """
-        super().at_cmdset_creation()
-        # ...
-        self.add(CmdTime())   # <- Add
-
-
-

Reload your game with the @reload command. You should now see the time command. If you enter -it, you might see something like:

-
We are in year 0, day 0, month 0.
-It's 00:52:17.
-
-
-

You could display it a bit more prettily with names for months and perhaps even days, if you want. -And if “months” are called “moons” in your game, this is where you’d add that.

-
- -
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Getting-Started.html b/docs/0.9.5/Getting-Started.html deleted file mode 100644 index a3c643b29c..0000000000 --- a/docs/0.9.5/Getting-Started.html +++ /dev/null @@ -1,637 +0,0 @@ - - - - - - - - - Getting Started — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - - - -
-
-
-
- -
-

Getting Started

-

This will help you download, install and start Evennia for the first time.

-
-

Note: You don’t need to make anything visible to the ‘net in order to run and -test out Evennia. Apart from downloading and updating you don’t even need an -internet connection until you feel ready to share your game with the world.

-
- -
-

Quick Start

-

For the impatient. If you have trouble with a step, you should jump on to the -more detailed instructions for your platform.

-
    -
  1. Install Python, GIT and python-virtualenv. Start a Console/Terminal.

  2. -
  3. cd to some place you want to do your development (like a folder -/home/anna/muddev/ on Linux or a folder in your personal user directory on Windows).

  4. -
  5. git clone https://github.com/evennia/evennia.git

  6. -
  7. virtualenv evenv

  8. -
  9. source evenv/bin/activate (Linux, Mac), evenv\Scripts\activate (Windows)

  10. -
  11. pip install -e evennia

  12. -
  13. evennia --init mygame

  14. -
  15. cd mygame

  16. -
  17. evennia migrate

  18. -
  19. evennia start (make sure to make a superuser when asked) -Evennia should now be running and you can connect to it by pointing a web browser to -http://localhost:4001 or a MUD telnet client to localhost:4000 (use 127.0.0.1 if your OS does -not recognize localhost).

  20. -
-

We also release Docker images -based on master and develop branches.

-
-
-

Requirements

-

Any system that supports Python3.7+ should work. We’ll describe how to install -everything in the following sections.

-
    -
  • Linux/Unix

  • -
  • Windows (Vista, Win7, Win8, Win10)

  • -
  • Mac OSX (>=10.5 recommended)

  • -
  • Python (v3.7, 3.8 or 3.9)

    -
      -
    • virtualenv for making isolated -Python environments. Installed with pip install virtualenv.

    • -
    -
  • -
  • GIT - version control software for getting and -updating Evennia itself - Mac users can use the -git-osx-installer or the -MacPorts version.

  • -
  • Twisted (v21.0+)

    -
      -
    • ZopeInterface (v3.0+) - usually included in -Twisted packages

    • -
    • Linux/Mac users may need the gcc and python-dev packages or equivalent.

    • -
    • Windows users need MS Visual C++ and maybe -pypiwin32.

    • -
    -
  • -
  • Django (v3.2.x), be warned that latest dev -version is usually untested with Evennia)

  • -
-
-
-

Linux Install

-

If you run into any issues during the installation and first start, please -check out Linux Troubleshooting.

-

For Debian-derived systems (like Ubuntu, Mint etc), start a terminal and -install the dependencies:

-
sudo apt-get update
-sudo apt-get install python3 python3-pip python3-dev python3-setuptools python3-git
-python3-virtualenv gcc
-
-# If you are using an Ubuntu version that defaults to Python3, like 18.04+, use this instead:
-sudo apt-get update
-sudo apt-get install python3.7 python3-pip python3.7-dev python3-setuptools virtualenv gcc
-
-
-
-

Note that, the default Python version for your distribution may still not be Python3.7 after this. -This is ok - we’ll specify exactly which Python to use later. -You should make sure to not be root after this step, running as root is a -security risk. Now create a folder where you want to do all your Evennia -development:

-
mkdir muddev
-cd muddev
-
-
-

Next we fetch Evennia itself:

-
git clone https://github.com/evennia/evennia.git
-
-
-

A new folder evennia will appear containing the Evennia library. This only -contains the source code though, it is not installed yet. To isolate the -Evennia install and its dependencies from the rest of the system, it is good -Python practice to install into a virtualenv. If you are unsure about what a -virtualenv is and why it’s useful, see the Glossary entry on -virtualenv.

-

Run python -V to see which version of Python your system defaults to.

-
# If your Linux defaults to Python3.7+:
-virtualenv evenv
-
-# If your Linux defaults to Python2 or an older version
-# of Python3, you must instead point to Python3.7+ explicitly:
-virtualenv -p /usr/bin/python3.7 evenv
-
-
-

A new folder evenv will appear (we could have called it anything). This -folder will hold a self-contained setup of Python packages without interfering -with default Python packages on your system (or the Linux distro lagging behind -on Python package versions). It will also always use the right version of Python. -Activate the virtualenv:

-
source evenv/bin/activate
-
-
-

The text (evenv) should appear next to your prompt to show that the virtual -environment is active.

-
-

Remember that you need to activate the virtualenv like this every time you -start a new terminal to get access to the Python packages (notably the -important evennia program) we are about to install.

-
-

Next, install Evennia into your active virtualenv. Make sure you are standing -at the top of your mud directory tree (so you see the evennia/ and evenv/ -folders) and run

-
pip install -e evennia
-
-
-

For more info about pip, see the Glossary entry on pip. If -install failed with any issues, see Linux Troubleshooting.

-

Next we’ll start our new game, here called “mygame”. This will create yet -another new folder where you will be creating your new game:

-
evennia --init mygame
-
-
-

Your final folder structure should look like this:

-
./muddev
-    evenv/
-    evennia/
-    mygame/
-
-
-

You can configure Evennia extensively, for example -to use a different database. For now we’ll just stick -to the defaults though.

-
cd mygame
-evennia migrate      # (this creates the database)
-evennia start        # (create a superuser when asked. Email is optional.)
-
-
-
-

Server logs are found in mygame/server/logs/. To easily view server logs -live in the terminal, use evennia -l (exit the log-view with Ctrl-C).

-
-

Your game should now be running! Open a web browser at http://localhost:4001 -or point a telnet client to localhost:4000 and log in with the user you -created. Check out where to go next.

-
-
-

Mac Install

-

The Evennia server is a terminal program. Open the terminal e.g. from -Applications->Utilities->Terminal. Here is an introduction to the Mac -terminal -if you are unsure how it works. If you run into any issues during the -installation, please check out Mac Troubleshooting.

-
    -
  • Python should already be installed but you must make sure it’s a high enough version. -(This discusses -how you may upgrade it). Remember that you need Python3.7, not Python2.7!

  • -
  • GIT can be obtained with -git-osx-installer or via -MacPorts as described -here.

  • -
  • If you run into issues with installing Twisted later you may need to -install gcc and the Python headers.

  • -
-

After this point you should not need sudo or any higher privileges to install anything.

-

Now create a folder where you want to do all your Evennia development:

-
mkdir muddev
-cd muddev
-
-
-

Next we fetch Evennia itself:

-
git clone https://github.com/evennia/evennia.git
-
-
-

A new folder evennia will appear containing the Evennia library. This only -contains the source code though, it is not installed yet. To isolate the -Evennia install and its dependencies from the rest of the system, it is good -Python practice to install into a virtualenv. If you are unsure about what a -virtualenv is and why it’s useful, see the Glossary entry on virtualenv.

-

Run python -V to check which Python your system defaults to.

-
# If your Mac defaults to Python3:
-virtualenv evenv
-
-# If your Mac defaults to Python2 you need to specify the Python3.7 binary explicitly:
-virtualenv -p /path/to/your/python3.7 evenv
-
-
-

A new folder evenv will appear (we could have called it anything). This -folder will hold a self-contained setup of Python packages without interfering -with default Python packages on your system. Activate the virtualenv:

-
source evenv/bin/activate
-
-
-

The text (evenv) should appear next to your prompt to show the virtual -environment is active.

-
-

Remember that you need to activate the virtualenv like this every time you -start a new terminal to get access to the Python packages (notably the -important evennia program) we are about to install.

-
-

Next, install Evennia into your active virtualenv. Make sure you are standing -at the top of your mud directory tree (so you see the evennia/ and evenv/ -folders) and run

-
pip install --upgrade pip   # Old pip versions may be an issue on Mac.
-pip install --upgrade setuptools   # Ditto concerning Mac issues.
-pip install -e evennia
-
-
-

For more info about pip, see the Glossary entry on pip. If -install failed with any issues, see Mac Troubleshooting.

-

Next we’ll start our new game. We’ll call it “mygame” here. This creates a new -folder where you will be creating your new game:

-
evennia --init mygame
-
-
-

Your final folder structure should look like this:

-
./muddev
-    evenv/
-    evennia/
-    mygame/
-
-
-

You can configure Evennia extensively, for example -to use a different database. We’ll go with the -defaults here.

-
cd mygame
-evennia migrate  # (this creates the database)
-evennia start    # (create a superuser when asked. Email is optional.)
-
-
-
-

Server logs are found in mygame/server/logs/. To easily view server logs -live in the terminal, use evennia -l (exit the log-view with Ctrl-C).

-
-

Your game should now be running! Open a web browser at http://localhost:4001 -or point a telnet client to localhost:4000 and log in with the user you -created. Check out where to go next.

-
-
-

Windows Install

-

If you run into any issues during the installation, please check out -Windows Troubleshooting.

-
-

If you are running Windows10, consider using the Windows Subsystem for Linux -(WSL) instead. -You should then follow the Linux install instructions above.

-
-

The Evennia server itself is a command line program. In the Windows launch -menu, start All Programs -> Accessories -> command prompt and you will get -the Windows command line interface. Here is one of many tutorials on using the Windows command -line -if you are unfamiliar with it.

-
    -
  • Install Python from the Python homepage. You will -need to be a -Windows Administrator to install packages. You want Python version 3.7.0 (latest verified -version), usually -the 64-bit version (although it doesn’t matter too much). When installing, make sure -to check-mark all install options, especially the one about making Python -available on the path (you may have to scroll to see it). This allows you to -just write python in any console without first finding where the python -program actually sits on your hard drive.

  • -
  • You need to also get GIT and install it. You -can use the default install options but when you get asked to “Adjust your PATH -environment”, you should select the second option “Use Git from the Windows -Command Prompt”, which gives you more freedom as to where you can use the -program.

  • -
  • Finally you must install the Microsoft Visual C++ compiler for -Python. Download and run the linked installer and -install the C++ tools. Keep all the defaults. Allow the install of the “Win10 SDK”, even if you are -on Win7 (not tested on older Windows versions). If you later have issues with installing Evennia due -to a failure to build the “Twisted wheels”, this is where you are missing things.

  • -
  • You may need the pypiwin32 Python headers. Install -these only if you have issues.

  • -
-

You can install Evennia wherever you want. cd to that location and create a -new folder for all your Evennia development (let’s call it muddev).

-
mkdir muddev
-cd muddev
-
-
-
-

Hint: If cd isn’t working you can use pushd instead to force the -directory change.

-
-

Next we fetch Evennia itself:

-
git clone https://github.com/evennia/evennia.git
-
-
-

A new folder evennia will appear containing the Evennia library. This only -contains the source code though, it is not installed yet. To isolate the -Evennia install and its dependencies from the rest of the system, it is good -Python practice to install into a virtualenv. If you are unsure about what a -virtualenv is and why it’s useful, see the Glossary entry on virtualenv.

-

In your console, try python -V to see which version of Python your system -defaults to.

-
pip install virtualenv
-
-# If your setup defaults to Python3.7:
-virtualenv evenv
-
-# If your setup defaults to Python2, specify path to python3.exe explicitly:
-virtualenv -p C:\Python37\python.exe evenv
-
-# If you get an infinite spooling response, press CTRL + C to interrupt and try using:
-python -m venv evenv
-
-
-
-

A new folder evenv will appear (we could have called it anything). This -folder will hold a self-contained setup of Python packages without interfering -with default Python packages on your system. Activate the virtualenv:

-
# If you are using a standard command prompt, you can use the following:
-evenv\scripts\activate.bat
-
-# If you are using a PS Shell, Git Bash, or other, you can use the following:
-.\evenv\scripts\activate
-
-
-
-

The text (evenv) should appear next to your prompt to show the virtual -environment is active.

-
-

Remember that you need to activate the virtualenv like this every time you -start a new console window if you want to get access to the Python packages -(notably the important evennia program) we are about to install.

-
-

Next, install Evennia into your active virtualenv. Make sure you are standing -at the top of your mud directory tree (so you see the evennia and evenv -folders when you use the dir command) and run

-
pip install -e evennia
-
-
-

For more info about pip, see the Glossary entry on pip. If -the install failed with any issues, see [Windows Troubleshooting](./Getting-Started.md#windows- -troubleshooting). -Next we’ll start our new game, we’ll call it “mygame” here. This creates a new folder where you will -be -creating your new game:

-
evennia --init mygame
-
-
-

Your final folder structure should look like this:

-
path\to\muddev
-    evenv\
-    evennia\
-    mygame\
-
-
-

You can configure Evennia extensively, for example -to use a different database. We’ll go with the -defaults here.

-
cd mygame
-evennia migrate    # (this creates the database)
-evennia start      # (create a superuser when asked. Email is optional.)
-
-
-
-

Server logs are found in mygame/server/logs/. To easily view server logs -live in the terminal, use evennia -l (exit the log-view with Ctrl-C).

-
-

Your game should now be running! Open a web browser at http://localhost:4001 -or point a telnet client to localhost:4000 and log in with the user you -created. Check out where to go next.

-
-
-

Where to Go Next

-

Welcome to Evennia! Your new game is fully functioning, but empty. If you just -logged in, stand in the Limbo room and run

-
@batchcommand tutorial_world.build
-
-
-

to build Evennia’s tutorial world - it’s a small solo quest to -explore. Only run the instructed @batchcommand once. You’ll get a lot of text scrolling by as the -tutorial is built. Once done, the tutorial exit will have appeared out of Limbo - just write -tutorial to enter it.

-

Once you get back to Limbo from the tutorial (if you get stuck in the tutorial quest you can do -@tel #2 to jump to Limbo), a good idea is to learn how to [start, stop and reload](Start-Stop- -Reload) the Evennia server. You may also want to familiarize yourself with some commonly used terms -in our Glossary. After that, why not experiment with creating some new items and build -some new rooms out from Limbo.

-

From here on, you could move on to do one of our introductory tutorials or simply dive -headlong into Evennia’s comprehensive manual. While -Evennia has no major game systems out of the box, we do supply a range of optional contribs that -you can use or borrow from. They range from dice rolling and alternative color schemes to barter and -combat systems. You can find the growing list of contribs -here.

-

If you have any questions, you can always ask in the developer -chat -#evennia on irc.freenode.net or by posting to the Evennia -forums. You can also join the Discord -Server.

-

Finally, if you are itching to help out or support Evennia (awesome!) have an -issue to report or a feature to request, see here.

-

Enjoy your stay!

-
-
-

Troubleshooting

-

If you have issues with installing or starting Evennia for the first time, -check the section for your operating system below. If you have an issue not -covered here, please report it -so it can be fixed or a workaround found!

-

Remember, the server logs are in mygame/server/logs/. To easily view server logs in the terminal, -you can run evennia -l, or (in the future) start the server with evennia start -l.

-
-

Linux Troubleshooting

-
    -
  • If you get an error when installing Evennia (especially with lines mentioning -failing to include Python.h) then try sudo apt-get install python3-setuptools python3-dev. -Once installed, run pip install -e evennia again.

  • -
  • Under some not-updated Linux distributions you may run into errors with a -too-old setuptools or missing functools. If so, update your environment -with pip install --upgrade pip wheel setuptools. Then try pip install -e evennia again.

  • -
  • If you get an setup.py not found error message while trying to pip install, make sure you are -in the right directory. You should be at the same level of the evenv directory, and the -evennia git repository. Note that there is an evennia directory inside of the repository too.

  • -
  • One user reported a rare issue on Ubuntu 16 is an install error on installing Twisted; Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-vnIFTg/twisted/ with errors -like distutils.errors.DistutilsError: Could not find suitable distribution for Requirement.parse('incremental>=16.10.1'). This appears possible to solve by simply updating Ubuntu -with sudo apt-get update && sudo apt-get dist-upgrade.

  • -
  • Users of Fedora (notably Fedora 24) has reported a gcc error saying the directory -/usr/lib/rpm/redhat/redhat-hardened-cc1 is missing, despite gcc itself being installed. The -confirmed work-around seems to be to -install the redhat-rpm-config package with e.g. sudo dnf install redhat-rpm-config.

  • -
  • Some users trying to set up a virtualenv on an NTFS filesystem find that it fails due to issues -with symlinks not being supported. Answer is to not use NTFS (seriously, why would you do that to -yourself?)

  • -
-
-
-

Mac Troubleshooting

-
    -
  • Mac users have reported a critical MemoryError when trying to start Evennia on Mac with a Python -version below 2.7.12. If you get this error, update to the latest XCode and Python2 version.

  • -
  • Some Mac users have reported not being able to connect to localhost (i.e. your own computer). If -so, try to connect to 127.0.0.1 instead, which is the same thing. Use port 4000 from mud clients -and port 4001 from the web browser as usual.

  • -
-
-
-

Windows Troubleshooting

-
    -
  • If you installed Python but the python command is not available (even in a new console), then -you might have missed installing Python on the path. In the Windows Python installer you get a list -of options for what to install. Most or all options are pre-checked except this one, and you may -even have to scroll down to see it. Reinstall Python and make sure it’s checked.

  • -
  • If your MUD client cannot connect to localhost:4000, try the equivalent 127.0.0.1:4000 -instead. Some MUD clients on Windows does not appear to understand the alias localhost.

  • -
  • If you run virtualenv evenv and get a 'virtualenv' is not recognized as an internal or external command, operable program or batch file. error, you can mkdir evenv, cd evenv and then python -m virtualenv . as a workaround.

  • -
  • Some Windows users get an error installing the Twisted ‘wheel’. A wheel is a pre-compiled binary -package for Python. A common reason for this error is that you are using a 32-bit version of Python, -but Twisted has not yet uploaded the latest 32-bit wheel. Easiest way to fix this is to install a -slightly older Twisted version. So if, say, version 18.1 failed, install 18.0 manually with pip install twisted==18.0. Alternatively you could try to get a 64-bit version of Python (uninstall the -32bit one). If so, you must then deactivate the virtualenv, delete the evenv folder and recreate -it anew (it will then use the new Python executable).

  • -
  • If your server won’t start, with no error messages (and no log files at all when starting from -scratch), try to start with evennia ipstart instead. If you then see an error about system cannot find the path specified, it may be that the file evennia/evennia/server/twistd.bat has the wrong -path to the twistd executable. This file is auto-generated, so try to delete it and then run -evennia start to rebuild it and see if it works. If it still doesn’t work you need to open it in a -text editor like Notepad. It’s just one line containing the path to the twistd.exe executable as -determined by Evennia. If you installed Twisted in a non-standard location this might be wrong and -you should update the line to the real location.

  • -
  • Some users have reported issues with Windows WSL and anti-virus software during Evennia -development. Timeout errors and the inability to run evennia connections may be due to your anti- -virus software interfering. Try disabling or changing your anti-virus software settings.

  • -
-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Glossary.html b/docs/0.9.5/Glossary.html deleted file mode 100644 index f3653a47af..0000000000 --- a/docs/0.9.5/Glossary.html +++ /dev/null @@ -1,512 +0,0 @@ - - - - - - - - - Glossary — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Glossary

-

This explains common recurring terms used in the Evennia docs. It will be expanded as needed.

-
    -
  • account - the player’s account on the game

  • -
  • admin-site - the Django web page for manipulating the database

  • -
  • attribute - persistent, custom data stored on typeclasses

  • -
  • channel - game communication channels

  • -
  • character - the player’s avatar in the game, controlled from -account

  • -
  • core - a term used for the code distributed with Evennia proper

  • -
  • django - web framework Evennia uses for database access and web integration

  • -
  • field - a typeclass property representing a database -column

  • -
  • git - the version-control system we use

  • -
  • github - the online hosting of our source code

  • -
  • migrate - updating the database schema

  • -
  • multisession mode` - a setting defining how users connect to Evennia

  • -
  • object - Python instance, general term or in-game -typeclass

  • -
  • pip - the Python installer

  • -
  • player - the human connecting to the game with their client

  • -
  • puppet - when an account controls an in-game -object

  • -
  • property - a python property

  • -
  • evenv - see virtualenv

  • -
  • repository - a store of source code + source history

  • -
  • script - a building block for custom storage, systems and time-keepint

  • -
  • session - represents one client connection

  • -
  • ticker - Allows to run events on a steady ‘tick’

  • -
  • twisted - networking engine responsible for Evennia’s event loop and -communications

  • -
  • typeclass - Evennia’s database-connected Python class

  • -
  • upstream - see github

  • -
  • virtualenv - a Python program and way to make an isolated Python install

  • -
-
-
-

account

-

The term ‘account’ refers to the player’s unique account on the game. It is -represented by the Account typeclass and holds things like email, password, -configuration etc.

-

When a player connects to the game, they connect to their account. The account has no -representation in the game world. Through their Account they can instead choose to -puppet one (or more, depending on game mode) Characters in -the game.

-

In the default multisession mode of Evennia, you immediately start -puppeting a Character with the same name as your Account when you log in - mimicking how older -servers used to work.

-
-
-

admin-site

-

This usually refers to Django’s Admin site or database-administration web page -(link to Django docs). The admin site is -an automatically generated web interface to the database (it can be customized extensively). It’s -reachable from the admin link on the default Evennia website you get with your server.

-
-
-

attribute

-

The term Attribute should not be confused with (properties or -fields. The Attribute represents arbitrary pieces of data that can be attached -to any typeclassed entity in Evennia. Attributes allows storing new persistent -data on typeclasses without changing their underlying database schemas. Read more about Attributes -here.

-
-
-

channel

-

A Channel refers to an in-game communication channel. It’s an entity that people subscribe to and -which re-distributes messages between all subscribers. Such subscribers default to being -Accounts, for out-of-game communication but could also be Objects (usually -Characters) if one wanted to adopt Channels for things like in-game walkie- -talkies or phone systems. It is represented by the Channel typeclass. You can read more about the -comm system here.

-
-
-

character

-

The Character is the term we use for the default avatar being puppeted by the -account in the game world. It is represented by the Character typeclass (which -is a child of Object). Many developers use children of this class to represent -monsters and other NPCs. You can read more about it here.

-
-
-

django

-

Django is a professional and very popular Python web framework, -similar to Rails for the Ruby language. It is one of Evennia’s central library dependencies (the -other one is Twisted). Evennia uses Django for two main things - to map all -database operations to Python and for structuring our web site.

-

Through Django, we can work with any supported database (SQlite3, Postgres, MySQL …) using generic -Python instead of database-specific SQL: A database table is represented in Django as a Python class -(called a model). An Python instance of such a class represents a row in that table.

-

There is usually no need to know the details of Django’s database handling in order to use Evennia - -it will handle most of the complexity for you under the hood using what we call -typeclasses. But should you need the power of Django you can always get it. -Most commonly people want to use “raw” Django when doing more advanced/custom database queries than -offered by Evennia’s default search functions. One will then need -to read about Django’s querysets. Querysets are Python method calls on a special form that lets -you build complex queries. They get converted into optimized SQL queries under the hood, suitable -for your current database. [Here is our tutorial/explanation of Django queries](Tutorial-Searching- -For-Objects#queries-in-django).

-
-

By the way, Django (and Evennia) does allow you to fall through and send raw SQL if you really -want to. It’s highly unlikely to be needed though; the Django database abstraction is very, very -powerful.

-
-

The other aspect where Evennia uses Django is for web integration. On one end Django gives an -infrastructure for wiring Python functions (called views) to URLs: the view/function is called -when a user goes that URL in their browser, enters data into a form etc. The return is the web page -to show. Django also offers templating with features such as being able to add special markers in -HTML where it will insert the values of Python variables on the fly (like showing the current player -count on the web page). [Here is one of our tutorials on wiring up such a web page](Add-a-simple- -new-web-page). Django also comes with the admin site, which automatically -maps the database into a form accessible from a web browser.

-
-
-

contrib

-

Contribs are optional and often more game-specific code-snippets contributed by the Evennia community. -They are distributed with Evennia in the contrib/ folder.

-
-
-

core

-

This term is sometimes used to represent the main Evennia library code suite, excluding its -contrib directory. It can sometimes come up in code reviews, such as

-
-

Evennia is game-agnostic but this feature is for a particular game genre. So it does not belong in -core. Better make it a contrib.

-
-
-
-

field

-

A field or database field in Evennia refers to a property on a -typeclass directly linked to an underlying database column. Only a few fixed -properties per typeclass are database fields but they are often tied to the core functionality of -that base typeclass (for example Objects store its location as a field). In all -other cases, attributes are used to add new persistent data to the typeclass. -Read more about typeclass properties here.

-
-
-

git

-

Git is a version control -tool. It allows us to track the development of the Evennia code by dividing it into units called -commits. A ‘commit’ is sort of a save-spot - you save the current state of your code and can then -come back to it later if later changes caused problems. By tracking commits we know what ‘version’ -of the code we are currently using.

-

Evennia’s source code + its source history is jointly called a repository. -This is centrally stored at our online home on GitHub. Everyone using or -developing Evennia makes a ‘clone’ of this repository to their own computer - everyone -automatically gets everything that is online, including all the code history.

-
-

Don’t confuse Git and GitHub. The former is the version control system. The -latter is a website (run by a company) that allows you to upload source code controlled by Git for -others to see (among other things).

-
-

Git allows multiple users from around the world to efficiently collaborate on Evennia’s code: People -can make local commits on their cloned code. The commits they do can then be uploaded to GitHub and -reviewed by the Evennia lead devs - and if the changes look ok they can be safely merged into the -central Evennia code - and everyone can pull those changes to update their local copies.

-

Developers using Evennia often uses Git on their own games in the same way - to track their changes -and to help collaboration with team mates. This is done completely independently of Evennia’s Git -usage.

-

Common usage (for non-Evennia developers):

-
    -
  • git clone <github-url> - clone an online repository to your computer. This is what you do when -you ‘download’ Evennia. You only need to do this once.

  • -
  • git pull (inside local copy of repository) - sync your local repository with what is online.

  • -
-
-

Full usage of Git is way beyond the scope of this glossary. See Tutorial - version -control for more info and links to the Git documentation.

-
-
-
-

migrate

-

This term is used for upgrading the database structure (it’s schema )to a new version. Most often -this is due to Evennia’s upstream schema changing. When that happens you need to -migrate that schema to the new version as well. Once you have used git to pull the -latest changes, just cd into your game dir and run

-
evennia migrate
-
-
-

That should be it (see virtualenv if you get a warning that the evennia -command is not available). See also Updating your game for more details.

-
-

Technically, migrations are shipped as little Python snippets of code that explains which database -actions must be taken to upgrade from one version of the schema to the next. When you run the -command above, those snippets are run in sequence.

-
-
-
-

multisession mode

-

This term refers to the MULTISESSION_MODE setting, which has a value of 0 to 3. The mode alters -how players can connect to the game, such as how many Sessions a player can start with one account -and how many Characters they can control at the same time. It is described in detail -here.

-
-
-

github

-

Github is where Evennia’s source code and documentation is hosted. -This online repository of code we also sometimes refer to as upstream.

-

GitHub is a business, offering free hosting to Open-source projects like Evennia. Despite the -similarity in name, don’t confuse GitHub the website with Git, the versioning -system. Github hosts Git repositories online and helps with collaboration and -infrastructure. Git itself is a separate project.

-
-
-

object

-

In general Python (and other object-oriented languages), an object is what we call the instance of a class. But one of Evennia’s -core typeclasses is also called “Object”. To separate these in the docs we -try to use object to refer to the general term and capitalized Object when we refer to the -typeclass.

-

The Object is a typeclass that represents all in-game entities, including -Characters, rooms, trees, weapons etc. Read more about Objects -here.

-
-
-

pip

-

pip comes with Python and is the main tool for installing third- -party Python packages from the web. Once a python package is installed you can do import <packagename> in your Python code.

-

Common usage:

-
    -
  • pip install <package-name> - install the given package along with all its dependencies.

  • -
  • pip search <name> - search Python’s central package repository PyPi for a -package of that name.

  • -
  • pip install --upgrade <package_name> - upgrade a package you already have to the latest version.

  • -
  • pip install <packagename>==1.5 - install exactly a specific package version.

  • -
  • pip install <folder> - install a Python package you have downloaded earlier (or cloned using -git).

  • -
  • pip install -e <folder> - install a local package by just making a soft link to the folder. This -means that if the code in <folder> changes, the installed Python package is immediately updated. -If not using -e, one would need to run pip install --upgrade <folder> every time to make the -changes available when you import this package into your code. Evennia is installed this way.

  • -
-

For development, pip is usually used together with a virtualenv to install -all packages and dependencies needed for a project in one, isolated location on the hard drive.

-
-
-

puppet

-

An account can take control and “play as” any Object. When -doing so, we call this puppeting, (like puppeteering). -Normally the entity being puppeted is of the Character subclass but it does -not have to be.

-
-
-

property

-

A property is a general term used for properties on any Python object. The term also sometimes -refers to the property built-in function of Python (read more here). Note the distinction between properties, -fields and Attributes.

-
-
-

repository

-

A repository is a version control/git term. It represents a folder containing -source code plus its versioning history.

-
-

In Git’s case, that history is stored in a hidden folder .git. If you ever feel the need to look -into this folder you probably already know enough Git to know why.

-
-

The evennia folder you download from us with git clone is a repository. The code on -GitHub is often referred to as the ‘online repository’ (or the upstream -repository). If you put your game dir under version control, that of course becomes a repository as -well.

-
-
-

script

-

When we refer to Scripts, we generally refer to the Script typeclass. Scripts are -the mavericks of Evennia - they are like Objects but without any in-game -existence. They are useful as custom places to store data but also as building blocks in persistent -game systems. Since the can be initialized with timing capabilities they can also be used for long- -time persistent time keeping (for fast updates other types of timers may be better though). Read -more about Scripts here

-
-
-

session

-

A Session is a Python object representing a single client connection to the server. A -given human player could connect to the game from different clients and each would get a Session -(even if you did not allow them to actually log in and get access to an -account).

-

Sessions are not typeclassed and has no database persistence. But since they -always exist (also when not logged in), they share some common functionality with typeclasses that -can be useful for certain game states.

-
-
-

tag

-

A Tag is a simple label one can attach to one or more objects in the game. Tagging is a -powerful way to group entities and can also be used to indicate they have particular shared abilities. -Tags are shared between objects (unlike Attributes).

-
-
-

ticker

-

The Ticker handler runs Evennia’s optional ‘ticker’ system. In other engines, such -as DIKU, all game events are processed only at specific -intervals called ‘ticks’. Evennia has no such technical limitation (events are processed whenever -needed) but using a fixed tick can still be useful for certain types of game systems, like combat. -Ticker Handler allows you to emulate any number of tick rates (not just one) and subscribe actions -to be called when those ticks come around.

-
-
-

typeclass

-

The typeclass is an Evennia-specific term. A typeclass allows developers to work with -database-persistent objects as if they were normal Python objects. It makes use of specific -Django features to link a Python class to a database table. Sometimes we refer to -such code entities as being typeclassed.

-

Evennia’s main typeclasses are Account, Object, -Script and Channel. Children of the base class (such as -Character) will use the same database table as the parent, but can have vastly -different Python capabilities (and persistent features through Attributes and -Tags. A typeclass can be coded and treated pretty much like any other Python class -except it must inherit (at any distance) from one of the base typeclasses. Also, creating a new -instance of a typeclass will add a new row to the database table to which it is linked.

-

The core typeclasses in the Evennia library are all named DefaultAccount, -DefaultObject etc. When you initialize your [game dir] you automatically get empty children of -these, called Account, Object etc that you can start working with.

-
-
-

twisted

-

Twisted is a heavy-duty asynchronous networking engine. It is one -of Evennia’s two major library dependencies (the other one is Django). Twisted is -what “runs” Evennia - it handles Evennia’s event loop. Twisted also has the building blocks we need -to construct network protocols and communicate with the outside world; such as our MUD-custom -version of Telnet, Telnet+SSL, SSH, webclient-websockets etc. Twisted also runs our integrated web -server, serving the Django-based website for your game.

-
-
-

virtualenv

-

The standard virtualenv program comes with Python. It is -used to isolate all Python packages needed by a given Python project into one folder (we call that -folder evenv but it could be called anything). A package environment created this way is usually -referred to as “a virtualenv”. If you ever try to run the evennia program and get an error saying -something like “the command ‘evennia’ is not available” - it’s probably because your virtualenv is -not ‘active’ yet (see below).

-

Usage:

-
    -
  • virtualenv <name> - initialize a new virtualenv <name> in a new folder <name> in the current -location. Called evenv in these docs.

  • -
  • virtualenv -p path/to/alternate/python_executable <name> - create a virtualenv using another -Python version than default.

  • -
  • source <folder_name>/bin/activate(linux/mac) - activate the virtualenv in <folder_name>.

  • -
  • <folder_name>\Scripts\activate (windows)

  • -
  • deactivate - turn off the currently activated virtualenv.

  • -
-

A virtualenv is ‘activated’ only for the console/terminal it was started in, but it’s safe to -activate the same virtualenv many times in different windows if you want. Once activated, all Python -packages now installed with pip will install to evenv rather than to a global -location like /usr/local/bin or C:\Program Files.

-
-

Note that if you have root/admin access you could install Evennia globally just fine, without -using a virtualenv. It’s strongly discouraged and considered bad practice though. Experienced Python -developers tend to rather create one new virtualenv per project they are working on, to keep the -varying installs cleanly separated from one another.

-
-

When you execute Python code within this activated virtualenv, only those packages installed -within will be possible to import into your code. So if you installed a Python package globally on -your computer, you’ll need to install it again in your virtualenv.

-
-

Virtualenvs only deal with Python programs/packages. Other programs on your computer couldn’t -care less if your virtualenv is active or not. So you could use git without the virtualenv being -active, for example.

-
-

When your virtualenv is active you should see your console/terminal prompt change to

-
(evenv) ...
-
-
-

… or whatever name you gave the virtualenv when you initialized it.

-
-

We sometimes say that we are “in” the virtualenv when it’s active. But just to be clear - you -never have to actually cd into the evenv folder. You can activate it from anywhere and will -still be considered “in” the virtualenv wherever you go until you deactivate or close the -console/terminal.

-
-

So, when do I need to activate my virtualenv? If the virtualenv is not active, none of the Python -packages/programs you installed in it will be available to you. So at a minimum, it needs to be -activated whenever you want to use the evennia command for any reason.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Grapevine.html b/docs/0.9.5/Grapevine.html deleted file mode 100644 index 6cbacd182f..0000000000 --- a/docs/0.9.5/Grapevine.html +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - - - - Grapevine — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Grapevine

-

Grapevine is a new chat network for MU**** games. By -connecting an in-game channel to the grapevine network, players on your game -can chat with players in other games, also non-Evennia ones.

-
-

Configuring Grapevine

-

To use Grapevine, you first need the pyopenssl module. Install it into your -Evennia python environment with

-
pip install pyopenssl
-
-
-

To configure Grapevine, you’ll need to activate it in your settings file.

-
    GRAPEVINE_ENABLED = True
-
-
-

Next, register an account at https://grapevine.haus. When you have logged in, -go to your Settings/Profile and to the Games sub menu. Here you register your -new game by filling in its information. At the end of registration you are going -to get a Client ID and a Client Secret. These should not be shared.

-

Open/create the file mygame/server/conf/secret_settings.py and add the following:

-
  GRAPEVINE_CLIENT_ID = "<client ID>"
-  GRAPEVINE_CLIENT_SECRET = "<client_secret>"
-
-
-

You can also customize the Grapevine channels you are allowed to connect to. This -is added to the GRAPEVINE_CHANNELS setting. You can see which channels are available -by going to the Grapevine online chat here: https://grapevine.haus/chat.

-

Start/reload Evennia and log in as a privileged user. You should now have a new -command available: @grapevine2chan. This command is called like this:

-
 @grapevine2chan[/switches] <evennia_channel> = <grapevine_channel>
-
-
-

Here, the evennia_channel must be the name of an existing Evennia channel and -grapevine_channel one of the supported channels in GRAPEVINE_CHANNELS.

-
-

At the time of writing, the Grapevine network only has two channels: -testing and gossip. Evennia defaults to allowing connecting to both. Use -testing for trying your connection.

-
-
-
-

Setting up Grapevine, step by step

-

You can connect Grapevine to any Evennia channel (so you could connect it to -the default public channel if you like), but for testing, let’s set up a -new channel gw.

-
 @ccreate gw = This is connected to an gw channel!
-
-
-

You will automatically join the new channel.

-

Next we will create a connection to the Grapevine network.

-
 @grapevine2chan gw = gossip
-
-
-

Evennia will now create a new connection and connect it to Grapevine. Connect -to https://grapevine.haus/chat to check.

-

Write something in the Evennia channel gw and check so a message appears in -the Grapevine chat. Write a reply in the chat and the grapevine bot should echo -it to your channel in-game.

-

Your Evennia gamers can now chat with users on external Grapevine channels!

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Guest-Logins.html b/docs/0.9.5/Guest-Logins.html deleted file mode 100644 index 7e3e3875dc..0000000000 --- a/docs/0.9.5/Guest-Logins.html +++ /dev/null @@ -1,136 +0,0 @@ - - - - - - - - - Guest Logins — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Guest Logins

-

Evennia supports guest logins out of the box. A guest login is an anonymous, low-access account -and can be useful if you want users to have a chance to try out your game without committing to -creating a real account.

-

Guest accounts are turned off by default. To activate, add this to your game/settings.py file:

-
GUEST_ENABLED = True
-
-
-

Henceforth users can use connect guest (in the default command set) to login with a guest account. -You may need to change your Connection Screen to inform them of this -possibility. Guest accounts work differently from normal accounts - they are automatically deleted -whenever the user logs off or the server resets (but not during a reload). They are literally re- -usable throw-away accounts.

-

You can add a few more variables to your settings.py file to customize your guests:

-
    -
  • BASE_GUEST_TYPECLASS - the python-path to the default typeclass for guests. -Defaults to "typeclasses.accounts.Guest".

  • -
  • PERMISSION_GUEST_DEFAULT - permission level for guest accounts. Defaults to "Guests", -which is the lowest permission level in the hierarchy.

  • -
  • GUEST_START_LOCATION - the #dbref to the starting location newly logged-in guests should -appear at. Defaults to "#2 (Limbo).

  • -
  • GUEST_HOME - guest home locations. Defaults to Limbo as well.

  • -
  • GUEST_LIST - this is a list holding the possible guest names to use when entering the game. The -length of this list also sets how many guests may log in at the same time. By default this is a list -of nine names from "Guest1" to "Guest9".

  • -
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/HAProxy-Config.html b/docs/0.9.5/HAProxy-Config.html deleted file mode 100644 index a37de5b4e5..0000000000 --- a/docs/0.9.5/HAProxy-Config.html +++ /dev/null @@ -1,269 +0,0 @@ - - - - - - - - - HAProxy Config (Optional) — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

HAProxy Config (Optional)

-
-

Making Evennia, HTTPS and Secure Websockets play nicely together

-

This we can do by installing a proxy between Evennia and the outgoing ports of your server. -Essentially, -Evennia will think it’s only running locally (on localhost, IP 127.0.0.1) - the proxy will -transparently -map that to the “real” outgoing ports and handle HTTPS/WSS for us.

-
Evennia <-> (inside-visible IP/ports) <-> Proxy <-> (outside-visible IP/ports) <-> Internet
-
-
-

Here we will use HAProxy, an open-source proxy that is easy to set up -and use. We will -also be using LetsEncrypt, especially the excellent -helper-program Certbot which pretty much automates the whole -certificate setup process for us.

-

Before starting you also need the following:

-
    -
  • (optional) The host name of your game (like myawesomegame.com). This is something you must -previously have purchased from a domain registrar and set up with DNS to point to the IP of your -server.

  • -
  • If you don’t have a domain name or haven’t set it up yet, you must at least know the IP of your -server. Find this with ifconfig or similar from inside the server. If you use a hosting service -like DigitalOcean you can also find the droplet’s IP address in the control panel.

  • -
  • You must open port 80 in your firewall. This is used by Certbot below to auto-renew certificates. -So you can’t really run another webserver alongside this setup without tweaking.

  • -
  • You must open port 443 (HTTPS) in your firewall.

  • -
  • You must open port 4002 (the default Websocket port) in your firewall.

  • -
-
-
-

Getting certificates

-

Certificates guarantee that you are you. Easiest is to get this with -Letsencrypt and the -Certbot program. Certbot has a lot of install instructions -for various operating systems. Here’s for Debian/Ubuntu:

-
sudo apt install certbot
-
-
-

Make sure to stop Evennia and that no port-80 using service is running, then

-
sudo certbot certonly --standalone
-
-
-

You will get some questions you need to answer, such as an email to send certificate errors to and -the host name (or IP, supposedly) to use with this certificate. After this, the certificates will -end up in /etc/letsencrypt/live/<your-host-or-ip>/*pem (example from Ubuntu). The critical files -for our purposes are fullchain.pem and privkey.pem.

-

Certbot sets up a cron-job/systemd job to regularly renew the certificate. To check this works, try

-
sudo certbot renew --dry-run
-
-
-

The certificate is only valid for 3 months at a time, so make sure this test works (it requires port -80 to be open). Look up Certbot’s page for more help.

-

We are not quite done. HAProxy expects these two files to be one file.

-
sudo cp /etc/letsencrypt/live/<your-host-or-ip>/privkey.pem /etc/letsencrypt/live/<your-host-or-
-ip>/<yourhostname>.pem
-sudo bash -c "cat /etc/letsencrypt/live/<your-host-or-ip>/fullchain.pem >>
-/etc/letsencrypt/live/<your-host-or-ip>/<yourhostname>.pem"
-
-
-

This will create a new .pem file by concatenating the two files together. The yourhostname.pem -file (or whatever you named it) is what we will use when the the HAProxy config file (below) asks -for “your-certificate.pem”.

-
-
-

Installing and configuring HAProxy

-

Installing HaProxy is usually as simple as:

-
# Debian derivatives (Ubuntu, Mint etc)
-sudo apt install haproxy
-
-# Redhat derivatives (dnf instead of yum for very recent Fedora distros)
-sudo yum install haproxy
-
-
-
-

Configuration of HAProxy is done in a single file. Put this wherever you like, for example in -your game dir; name it something like haproxy.conf.

-

Here is an example tested on Centos7 and Ubuntu. Make sure to change the file to put in your own -values.

-
# base stuff to set up haproxy
-global
-    log /dev/log local0
-    chroot /var/lib/haproxy
-    maxconn  4000
-    user  haproxy
-    tune.ssl.default-dh-param 2048
-    ## uncomment this when everything works
-    # daemon
-defaults
-    mode http
-    option forwardfor
-
-# Evennia Specifics
-listen evennia-https-website
-    bind <ip-address-or-hostname>:<public-SSL-port--probably-443> ssl no-sslv3 no-tlsv10 crt
-/etc/letsencrypt/live/<your-host-or-ip>/<yourhostname>.pem
-    server localhost 127.0.0.1:<evennia-web-port-probably-4001>
-    timeout client 10m
-    timeout server 10m
-    timeout connect 5m
-
-listen evennia-secure-websocket
-    bind <ip-address-or-hostname>:<wss-port--probably-4002> ssl no-sslv3 no-tlsv10 crt
-/etc/letsencrypt/live/<your-host-or-ip>/<yourhostname>.pem
-    server localhost 127.0.0.1:<WEBSOCKET_CLIENT_PORT-probably-4002>
-    timeout client 10m
-    timeout server 10m
-    timeout connect 5m
-
-
-
-
-

Putting it all together

-

Get back to the Evennia game dir and edit mygame/server/conf/settings.py. Add:

-
WEBSERVER_INTERFACES = ['127.0.0.1']
-WEBSOCKET_CLIENT_INTERFACE = '127.0.0.1'
-
-
-

and

-
WEBSOCKET_CLIENT_URL="wss://fullhost.domain.name:4002/"
-
-
-

Make sure to reboot (stop + start) evennia completely:

-
evennia reboot
-
-
-

Finally you start the proxy:

-
sudo haproxy -f /path/to/the/above/config_file.cfg
-
-
-

Make sure you can connect to your game from your browser and that you end up with an https:// page -and can use the websocket webclient.

-

Once everything works you may want to start the proxy automatically and in the background. Stop the -proxy with Ctrl-C and uncomment the line # daemon in the config file, then start the proxy again

-
    -
  • it will now start in the bacground.

  • -
-

You may also want to have the proxy start automatically; this you can do with cron, the inbuilt -Linux mechanism for running things at specific times.

-
sudo crontab -e
-
-
-

Choose your editor and add a new line at the end of the crontab file that opens:

-
@reboot haproxy -f /path/to/the/above/config_file.cfg
-
-
-

Save the file and haproxy should start up automatically when you reboot the server.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Help-System-Tutorial.html b/docs/0.9.5/Help-System-Tutorial.html deleted file mode 100644 index 655fd1d3fa..0000000000 --- a/docs/0.9.5/Help-System-Tutorial.html +++ /dev/null @@ -1,576 +0,0 @@ - - - - - - - - - Help System Tutorial — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Help System Tutorial

-

Before doing this tutorial you will probably want to read the intro in Basic Web tutorial. Reading the three first parts of the Django tutorial might help as well.

-

This tutorial will show you how to access the help system through your website. Both help commands -and regular help entries will be visible, depending on the logged-in user or an anonymous character.

-

This tutorial will show you how to:

-
    -
  • Create a new page to add to your website.

  • -
  • Take advantage of a basic view and basic templates.

  • -
  • Access the help system on your website.

  • -
  • Identify whether the viewer of this page is logged-in and, if so, to what account.

  • -
-
-

Creating our app

-

The first step is to create our new Django app. An app in Django can contain pages and -mechanisms: your website may contain different apps. Actually, the website provided out-of-the-box -by Evennia has already three apps: a “webclient” app, to handle the entire webclient, a “website” -app to contain your basic pages, and a third app provided by Django to create a simple admin -interface. So we’ll create another app in parallel, giving it a clear name to represent our help -system.

-

From your game directory, use the following command:

-
evennia startapp help_system
-
-
-
-

Note: calling the app “help” would have been more explicit, but this name is already used by -Django.

-
-

This will create a directory named help_system at the root of your game directory. It’s a good -idea to keep things organized and move this directory in the “web” directory of your game. Your -game directory should look like:

-
mygame/
-    ...
-    web/
-        help_system/
-        ...
-
-
-

The “web/help_system” directory contains files created by Django. We’ll use some of them, but if -you want to learn more about them all, you should read the Django -tutorial.

-

There is a last thing to be done: your folder has been added, but Django doesn’t know about it, it -doesn’t know it’s a new app. We need to tell it, and we do so by editing a simple setting. Open -your “server/conf/settings.py” file and add, or edit, these lines:

-
# Web configuration
-INSTALLED_APPS += (
-        "web.help_system",
-)
-
-
-

You can start Evennia if you want, and go to your website, probably at -http://localhost:4001 . You won’t see anything different though: we added -the app but it’s fairly empty.

-
-
-

Our new page

-

At this point, our new app contains mostly empty files that you can explore. In order to create -a page for our help system, we need to add:

-
    -
  • A view, dealing with the logic of our page.

  • -
  • A template to display our new page.

  • -
  • A new URL pointing to our page.

  • -
-
-

We could get away by creating just a view and a new URL, but that’s not a recommended way to work -with your website. Building on templates is so much more convenient.

-
-
-

Create a view

-

A view in Django is a simple Python function placed in the “views.py” file in your app. It will -handle the behavior that is triggered when a user asks for this information by entering a URL (the -connection between views and URLs will be discussed later).

-

So let’s create our view. You can open the “web/help_system/views.py” file and paste the following -lines:

-
from django.shortcuts import render
-
-def index(request):
-    """The 'index' view."""
-    return render(request, "help_system/index.html")
-
-
-

Our view handles all code logic. This time, there’s not much: when this function is called, it will -render the template we will now create. But that’s where we will do most of our work afterward.

-
-
-

Create a template

-

The render function called into our view asks the template help_system/index.html. The -templates of our apps are stored in the app directory, “templates” sub-directory. Django may have -created the “templates” folder already. If not, create it yourself. In it, create another folder -“help_system”, and inside of this folder, create a file named “index.html”. Wow, that’s some -hierarchy. Your directory structure (starting from web) should look like this:

-
web/
-    help_system/
-        ...
-        templates/
-            help_system/
-                index.html
-
-
-

Open the “index.html” file and paste in the following lines:

-
{% extends "base.html" %}
-{% block titleblock %}Help index{% endblock %}
-{% block content %}
-<h2>Help index</h2>
-{% endblock %}
-
-
-

Here’s a little explanation line by line of what this template does:

-
    -
  1. It loads the “base.html” template. This describes the basic structure of all your pages, with -a menu at the top and a footer, and perhaps other information like images and things to be present -on each page. You can create templates that do not inherit from “base.html”, but you should have a -good reason for doing so.

  2. -
  3. The “base.html” template defines all the structure of the page. What is left is to override -some sections of our pages. These sections are called blocks. On line 2, we override the block -named “blocktitle”, which contains the title of our page.

  4. -
  5. Same thing here, we override the block named “content”, which contains the main content of our -web page. This block is bigger, so we define it on several lines.

  6. -
  7. This is perfectly normal HTML code to display a level-2 heading.

  8. -
  9. And finally we close the block named “content”.

  10. -
-
-
-

Create a new URL

-

Last step to add our page: we need to add a URL leading to it… otherwise users won’t be able to -access it. The URLs of our apps are stored in the app’s directory “urls.py” file.

-

Open the “web/help_system/urls.py” file (you might have to create it) and write in it:

-
# URL patterns for the help_system app
-
-from django.urls import include, path
-from web.help_system.views import index
-
-urlpatterns = [
-    path(r'', index, name="help-index")
-]
-
-
-

We also need to add our app as a namespace holder for URLS. Edit the file “web/urls.py” (you might -have to create this one too). In it you will find the custom_patterns variable. Replace it with:

-
custom_patterns = [
-    path(r'help_system/', include('web.help_system.urls')),
-]
-
-
-

When a user will ask for a specific URL on your site, Django will:

-
    -
  1. Read the list of custom patterns defined in “web/urls.py”. There’s one pattern here, which -describes to Django that all URLs beginning by ‘help/’ should be sent to the ‘help_system’ app. The -‘help/’ part is removed.

  2. -
  3. Then Django will check the “web.help_system/urls.py” file. It contains only one URL, which is -empty.

  4. -
-

In other words, if the URL is ‘/help/’, then Django will execute our defined view.

-
-
-

Let’s see it work

-

You can now reload or start Evennia. Open a tab in your browser and go to -http://localhost:4001/help_system/ . If everything goes well, -you should see your new page… which isn’t empty since Evennia uses our “base.html” template. In -the content of our page, there’s only a heading that reads “help index”. Notice that the title of -our page is “mygame - Help index” (“mygame” is replaced by the name of your game).

-

From now on, it will be easier to move forward and add features.

-
-
-

A brief reminder

-

We’ll be trying the following things:

-
    -
  • Have the help of commands and help entries accessed online.

  • -
  • Have various commands and help entries depending on whether the user is logged in or not.

  • -
-

In terms of pages, we’ll have:

-
    -
  • One to display the list of help topics.

  • -
  • One to display the content of a help topic.

  • -
-

The first one would link to the second.

-
-

Should we create two URLs?

-
-

The answer is… maybe. It depends on what you want to do. We have our help index accessible -through the “/help_system/” URL. We could have the detail of a help entry accessible through -“/help_system/desc” (to see the detail of the “desc” command). The problem is that our commands or -help topics may contain special characters that aren’t to be present in URLs. There are different -ways around this problem. I have decided to use a GET variable here, which would create URLs like -this:

-
/help_system?name=desc
-
-
-

If you use this system, you don’t have to add a new URL: GET and POST variables are accessible -through our requests and we’ll see how soon enough.

-
-
-
-

Handling logged-in users

-

One of our requirements is to have a help system tailored to our accounts. If an account with admin -access logs in, the page should display a lot of commands that aren’t accessible to common users. -And perhaps even some additional help topics.

-

Fortunately, it’s fairly easy to get the logged in account in our view (remember that we’ll do most -of our coding there). The request object, passed to our function, contains a user attribute. -This attribute will always be there: we cannot test whether it’s None or not, for instance. But -when the request comes from a user that isn’t logged in, the user attribute will contain an -anonymous Django user. We then can use the is_anonymous method to see whether the user is logged- -in or not. Last gift by Evennia, if the user is logged in, request.user contains a reference to -an account object, which will help us a lot in coupling the game and online system.

-

So we might end up with something like:

-
def index(request):
-    """The 'index' view."""
-    user = request.user
-    if not user.is_anonymous() and user.character:
-        character = user.character
-
-
-
-

Note: this code works when your MULTISESSION_MODE is set to 0 or 1. When it’s above, you would -have something like:

-
-
def index(request):
-    """The 'index' view."""
-    user = request.user
-    if not user.is_anonymous() and user.db._playable_characters:
-        character = user.db._playable_characters[0]
-
-
-

In this second case, it will select the first character of the account.

-

But what if the user’s not logged in? Again, we have different solutions. One of the most simple -is to create a character that will behave as our default character for the help system. You can -create it through your game: connect to it and enter:

-
@charcreate anonymous
-
-
-

The system should answer:

-
Created new character anonymous. Use @ic anonymous to enter the game as this character.
-
-
-

So in our view, we could have something like this:

-
from typeclasses.characters import Character
-
-def index(request):
-    """The 'index' view."""
-    user = request.user
-    if not user.is_anonymous() and user.character:
-        character = user.character
-    else:
-        character = Character.objects.get(db_key="anonymous")
-
-
-

This time, we have a valid character no matter what: remember to adapt this code if you’re running -in multisession mode above 1.

-
-
-

The full system

-

What we’re going to do is to browse through all commands and help entries, and list all the commands -that can be seen by this character (either our ‘anonymous’ character, or our logged-in character).

-

The code is longer, but it presents the entire concept in our view. Edit the -“web/help_system/views.py” file and paste into it:

-
from django.http import Http404
-from django.shortcuts import render
-from evennia.help.models import HelpEntry
-
-from typeclasses.characters import Character
-
-def index(request):
-    """The 'index' view."""
-    user = request.user
-    if not user.is_anonymous() and user.character:
-        character = user.character
-    else:
-        character = Character.objects.get(db_key="anonymous")
-
-    # Get the categories and topics accessible to this character
-    categories, topics = _get_topics(character)
-
-    # If we have the 'name' in our GET variable
-    topic = request.GET.get("name")
-    if topic:
-        if topic not in topics:
-            raise Http404("This help topic doesn't exist.")
-
-        topic = topics[topic]
-        context = {
-                "character": character,
-                "topic": topic,
-        }
-        return render(request, "help_system/detail.html", context)
-    else:
-        context = {
-                "character": character,
-                "categories": categories,
-        }
-        return render(request, "help_system/index.html", context)
-
-def _get_topics(character):
-    """Return the categories and topics for this character."""
-    cmdset = character.cmdset.all()[0]
-    commands = cmdset.commands
-    entries = [entry for entry in HelpEntry.objects.all()]
-    categories = {}
-    topics = {}
-
-    # Browse commands
-    for command in commands:
-        if not command.auto_help or not command.access(character):
-            continue
-
-        # Create the template for a command
-        template = {
-                "name": command.key,
-                "category": command.help_category,
-                "content": command.get_help(character, cmdset),
-        }
-
-        category = command.help_category
-        if category not in categories:
-            categories[category] = []
-        categories[category].append(template)
-        topics[command.key] = template
-
-    # Browse through the help entries
-    for entry in entries:
-        if not entry.access(character, 'view', default=True):
-            continue
-
-        # Create the template for an entry
-        template = {
-                "name": entry.key,
-                "category": entry.help_category,
-                "content": entry.entrytext,
-        }
-
-        category = entry.help_category
-        if category not in categories:
-            categories[category] = []
-        categories[category].append(template)
-        topics[entry.key] = template
-
-    # Sort categories
-    for entries in categories.values():
-        entries.sort(key=lambda c: c["name"])
-
-    categories = list(sorted(categories.items()))
-    return categories, topics
-
-
-

That’s a bit more complicated here, but all in all, it can be divided in small chunks:

-
    -
  • The index function is our view:

    -
      -
    • It begins by getting the character as we saw in the previous section.

    • -
    • It gets the help topics (commands and help entries) accessible to this character. It’s another -function that handles that part.

    • -
    • If there’s a GET variable “name” in our URL (like “/help?name=drop”), it will retrieve it. If -it’s not a valid topic’s name, it returns a 404. Otherwise, it renders the template called -“detail.html”, to display the detail of our topic.

    • -
    • If there’s no GET variable “name”, render “index.html”, to display the list of topics.

    • -
    -
  • -
  • The _get_topics is a private function. Its sole mission is to retrieve the commands a character -can execute, and the help entries this same character can see. This code is more Evennia-specific -than Django-specific, it will not be detailed in this tutorial. Just notice that all help topics -are stored in a dictionary. This is to simplify our job when displaying them in our templates.

  • -
-

Notice that, in both cases when we asked to render a template, we passed to render a third -argument which is the dictionary of variables used in our templates. We can pass variables this -way, and we will use them in our templates.

-
-

The index template

-

Let’s look at our full “index” template. You can open the -“web/help_system/templates/help_system/index.html” file and paste the following into it:

-
{% extends "base.html" %}
-{% block titleblock %}Help index{% endblock %}
-{% block content %}
-<h2>Help index</h2>
-{% if categories %}
-    {% for category, topics in categories %}
-        <h2>{{ category|capfirst }}</h2>
-        <table>
-        <tr>
-        {% for topic in topics %}
-            {% if forloop.counter|divisibleby:"5" %}
-                </tr>
-                <tr>
-            {% endif %}
-            <td><a href="{% url 'help-index' %}?name={{ topic.name|urlencode }}">
-            {{ topic.name }}</td>
-        {% endfor %}
-        </tr>
-        </table>
-    {% endfor %}
-{% endif %}
-{% endblock %}
-
-
-

This template is definitely more detailed. What it does is:

-
    -
  1. Browse through all categories.

  2. -
  3. For all categories, display a level-2 heading with the name of the category.

  4. -
  5. All topics in a category (remember, they can be either commands or help entries) are displayed in -a table. The trickier part may be that, when the loop is above 5, it will create a new line. The -table will have 5 columns at the most per row.

  6. -
  7. For every cell in the table, we create a link redirecting to the detail page (see below). The -URL would look something like “help?name=say”. We use urlencode to ensure special characters are -properly escaped.

  8. -
-
-
-

The detail template

-

It’s now time to show the detail of a topic (command or help entry). You can create the file -“web/help_system/templates/help_system/detail.html”. You can paste into it the following code:

-
{% extends "base.html" %}
-{% block titleblock %}Help for {{ topic.name }}{% endblock %}
-{% block content %}
-<h2>{{ topic.name|capfirst }} help topic</h2>
-<p>Category: {{ topic.category|capfirst }}</p>
-{{ topic.content|linebreaks }}
-{% endblock %}
-
-
-

This template is much easier to read. Some filters might be unknown to you, but they are just -used to format here.

-
-
-

Put it all together

-

Remember to reload or start Evennia, and then go to -http://localhost:4001/help_system. You should see the list of -commands and topics accessible by all characters. Try to login (click the “login” link in the menu -of your website) and go to the same page again. You should now see a more detailed list of commands -and help entries. Click on one to see its detail.

-
-
-
-

To improve this feature

-

As always, a tutorial is here to help you feel comfortable adding new features and code by yourself. -Here are some ideas of things to improve this little feature:

-
    -
  • Links at the bottom of the detail template to go back to the index might be useful.

  • -
  • A link in the main menu to link to this page would be great… for the time being you have to -enter the URL, users won’t guess it’s there.

  • -
  • Colors aren’t handled at this point, which isn’t exactly surprising. You could add it though.

  • -
  • Linking help entries between one another won’t be simple, but it would be great. For instance, if -you see a help entry about how to use several commands, it would be great if these commands were -themselves links to display their details.

  • -
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Help-System.html b/docs/0.9.5/Help-System.html deleted file mode 100644 index 43d1064eba..0000000000 --- a/docs/0.9.5/Help-System.html +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - Help System — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Help System

-

An important part of Evennia is the online help system. This allows the players and staff alike to -learn how to use the game’s commands as well as other information pertinent to the game. The help -system has many different aspects, from the normal editing of help entries from inside the game, to -auto-generated help entries during code development using the auto-help system.

-
-

Viewing the help database

-

The main command is help:

-
 help [searchstring]
-
-
-

This will show a list of help entries, ordered after categories. You will find two sections, -Command help entries and Other help entries (initially you will only have the first one). You -can use help to get more info about an entry; you can also give partial matches to get suggestions. -If you give category names you will only be shown the topics in that category.

-
-
-

Command Auto-help system

-

A common item that requires help entries are in-game commands. Keeping these entries up-to-date with -the actual source code functionality can be a chore. Evennia’s commands are therefore auto- -documenting straight from the sources through its auto-help system. Only commands that you and -your character can actually currently use are picked up by the auto-help system. That means an admin -will see a considerably larger amount of help topics than a normal player when using the default -help command.

-

The auto-help system uses the __doc__ strings of your command classes and formats this to a nice- -looking help entry. This makes for a very easy way to keep the help updated - just document your -commands well and updating the help file is just a @reload away. There is no need to manually -create and maintain help database entries for commands; as long as you keep the docstrings updated -your help will be dynamically updated for you as well.

-

Example (from a module with command definitions):

-
    class CmdMyCmd(Command):
-       """
-       mycmd - my very own command
-    
-       Usage:
-         mycmd[/switches] <args>
-    
-       Switches:
-         test - test the command
-         run  - do something else
-    
-       This is my own command that does this and that.
-    
-       """
-       # [...]
-
-       help_category = "General"    # default
-       auto_help = True             # default
-       
-       # [...]
-
-
-

The text at the very top of the command class definition is the class’ __doc__-string and will be -shown to users looking for help. Try to use a consistent format - all default commands are using the -structure shown above.

-

You should also supply the help_category class property if you can; this helps to group help -entries together for people to more easily find them. See the help command in-game to see the -default categories. If you don’t specify the category, “General” is assumed.

-

If you don’t want your command to be picked up by the auto-help system at all (like if you want to -write its docs manually using the info in the next section or you use a cmdset that -has its own help functionality) you can explicitly set auto_help class property to False in your -command definition.

-

Alternatively, you can keep the advantages of auto-help in commands, but control the display of -command helps. You can do so by overriding the command’s get_help() method. By default, this -method will return the class docstring. You could modify it to add custom behavior: the text -returned by this method will be displayed to the character asking for help in this command.

-
-
-

Database help entries

-

These are all help entries not involving commands (this is handled automatically by the Command -Auto-help system). Non-automatic help entries describe how -your particular game is played - its rules, world descriptions and so on.

-

A help entry consists of four parts:

-
    -
  • The topic. This is the name of the help entry. This is what players search for when they are -looking for help. The topic can contain spaces and also partial matches will be found.

  • -
  • The help category. Examples are Administration, Building, Comms or General. This is an -overall grouping of similar help topics, used by the engine to give a better overview.

  • -
  • The text - the help text itself, of any length.

  • -
  • locks - a lock definition. This can be used to limit access to this help entry, maybe -because it’s staff-only or otherwise meant to be restricted. Help commands check for access_types -view and edit. An example of a lock string would be view:perm(Builders).

  • -
-

You can create new help entries in code by using evennia.create_help_entry().

-
from evennia import create_help_entry
-entry = create_help_entry("emote",
-                "Emoting is important because ...",
-                category="Roleplaying", locks="view:all()")
-
-
-

From inside the game those with the right permissions can use the @sethelp command to add and -modify help entries.

-
> @sethelp/add emote = The emote command is ...
-
-
-

Using @sethelp you can add, delete and append text to existing entries. By default new entries -will go in the General help category. You can change this using a different form of the @sethelp -command:

-
> @sethelp/add emote, Roleplaying = Emoting is important because ...
-
-
-

If the category Roleplaying did not already exist, it is created and will appear in the help -index.

-

You can, finally, define a lock for the help entry by following the category with a lock -definition:

-
> @sethelp/add emote, Roleplaying, view:all() = Emoting is ...
-
-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/How-To-Get-And-Give-Help.html b/docs/0.9.5/How-To-Get-And-Give-Help.html deleted file mode 100644 index 597be8299f..0000000000 --- a/docs/0.9.5/How-To-Get-And-Give-Help.html +++ /dev/null @@ -1,178 +0,0 @@ - - - - - - - - - How To Get And Give Help — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

How To Get And Give Help

-
-

How to get Help

-

If you cannot find what you are looking for in the online documentation, here’s what to do:

-
    -
  • If you think the documentation is not clear enough and are short on time, fill in our quick little -online form and let us know - no login required. Maybe the docs need to be improved or a new -tutorial added! Note that while this form is useful as a suggestion box we cannot answer questions -or reply to you. Use the discussion group or chat (linked below) if you want feedback.

  • -
  • If you have trouble with a missing feature or a problem you think is a bug, go to the -issue tracker and search to see if has been reported/suggested already. If you can’t find an -existing entry create a new one.

  • -
  • If you need help, want to start a discussion or get some input on something you are working on, -make a post to the discussions group This is technically a ‘mailing list’, but you don’t -need to use e-mail; you can post and read all messages just as easily from your browser via the -online interface.

  • -
  • If you want more direct discussions with developers and other users, consider dropping into our -IRC chat channel #evennia on the Freenode network. Please note however that you have to be -patient if you don’t get any response immediately; we are all in very different time zones and many -have busy personal lives. So you might have to hang around for a while - you’ll get noticed -eventually!

  • -
-
-
-

How to give Help

-

Evennia is a completely non-funded project. It relies on the time donated by its users and -developers in order to progress.

-

The first and easiest way you as a user can help us out is by taking part in -community discussions and by giving feedback on what is good or bad. Report bugs you find and features -you lack to our issue tracker. Just the simple act of letting developers know you are out -there using their program is worth a lot. Generally mentioning and reviewing Evennia elsewhere is -also a nice way to spread the word.

-

If you’d like to help develop Evennia more hands-on, here are some ways to get going:

-
    -
  • Look through our online documentation wiki and see if you -can help improve or expand the documentation (even small things like fixing typos!). You don’t need -any particular permissions to edit the wiki.

  • -
  • Send a message to our discussion group and/or our IRC chat asking about what -needs doing, along with what your interests and skills are.

  • -
  • Take a look at our issue tracker and see if there’s something you feel like taking on. -here are bugs that need fixes. At any given time there may also be some -[bounties][issues-bounties] open - these are issues members of the community has put up money to see -fixed (if you want to put up a bounty yourself you can do so via our page on -[bountysource][bountysource]).

  • -
  • Check out the Contributing page on how to practically contribute with code using -github.

  • -
-

… And finally, if you want to help motivate and support development you can also drop some coins -in the developer’s cup. You can make a donation via PayPal or, even better, -[become an Evennia patron on Patreon][patreon]! This is a great way to tip your hat and show that you -appreciate the work done with the server! Finally, if you want to encourage the community to resolve -a particular

-

b2 -[donate-img]: http://images-focus-opensocial.googleusercontent.com/gadgets/proxy?url=https://www.paypalobjects.com/en%5fUS/SE/i/btn/btn%5fdonateCC%5fLG.gif&container=focus&gadget=a&rewriteMime=image/* -[patreon]: https://www.patreon.com/griatch -[patreon-img]: http://www.evennia.com/_/rsrc/1424724909023/home/evennia_patreon_100x100.png -[issues-bounties]: https://github.com/evennia/evennia/labels/bounty -[bountysource]: https://www.bountysource.com/teams/evennia

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/How-to-connect-Evennia-to-Twitter.html b/docs/0.9.5/How-to-connect-Evennia-to-Twitter.html deleted file mode 100644 index e78cf8e8af..0000000000 --- a/docs/0.9.5/How-to-connect-Evennia-to-Twitter.html +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - - - - How to connect Evennia to Twitter — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

How to connect Evennia to Twitter

-

Twitter is an online social networking service that enables -users to send and read short 280-character messages called “tweets”. Following is a short tutorial -explaining how to enable users to send tweets from inside Evennia.

-
-

Configuring Twitter

-

You must first have a Twitter account. Log in and register an App at the Twitter Dev -Site. Make sure you enable access to “write” tweets!

-

To tweet from Evennia you will need both the “API Token” and the “API secret” strings as well as the -“Access Token” and “Access Secret” strings.

-

Twitter changed their requirements to require a Mobile number on the Twitter account to register new -apps with write access. If you’re unable to do this, please see this Dev -post which describes how to get around -it.

-
-
-

Install the twitter python module

-

To use Twitter you must install the Twitter Python module:

-
pip install python-twitter
-
-
-
-
-

A basic tweet command

-

Evennia doesn’t have a tweet command out of the box so you need to write your own little -Command in order to tweet. If you are unsure about how commands work and how to add -them, it can be an idea to go through the Adding a Command Tutorial -before continuing.

-

You can create the command in a separate command module (something like mygame/commands/tweet.py) -or together with your other custom commands, as you prefer.

-

This is how it can look:

-
import twitter
-from evennia import Command
-
-# here you insert your unique App tokens
-# from the Twitter dev site
-TWITTER_API = twitter.Api(consumer_key='api_key',
-                          consumer_secret='api_secret',
-                          access_token_key='access_token_key',
-                          access_token_secret='access_token_secret')
-
-class CmdTweet(Command):
-    """
-    Tweet a message
-
-    Usage:
-      tweet <message>
-
-    This will send a Twitter tweet to a pre-configured Twitter account.
-    A tweet has a maximum length of 280 characters.
-    """
-
-    key = "tweet"
-    locks = "cmd:pperm(tweet) or pperm(Developers)"
-    help_category = "Comms"
-
-    def func(self):
-        "This performs the tweet"
- 
-        caller = self.caller
-        tweet = self.args
-
-        if not tweet:
-            caller.msg("Usage: tweet <message>")
-            return
- 
-        tlen = len(tweet)
-        if tlen > 280:
-            caller.msg("Your tweet was %i chars long (max 280)." % tlen)
-            return
-
-        # post the tweet
-        TWITTER_API.PostUpdate(tweet)
-
-        caller.msg("You tweeted:\n%s" % tweet)
-
-
-

Be sure to substitute your own actual API/Access keys and secrets in the appropriate places.

-

We default to limiting tweet access to players with Developers-level access or to those players -that have the permission “tweet” (allow individual characters to tweet with @perm/player playername = tweet). You may change the lock as you feel is appropriate. Change the overall -permission to Players if you want everyone to be able to tweet.

-

Now add this command to your default command set (e.g in mygame/commands/defalt_cmdsets.py”) and -reload the server. From now on those with access can simply use tweet <message> to see the tweet -posted from the game’s Twitter account.

-
-
-

Next Steps

-

This shows only a basic tweet setup, other things to do could be:

-
    -
  • Auto-Adding the character name to the tweet

  • -
  • More error-checking of postings

  • -
  • Changing locks to make tweeting open to more people

  • -
  • Echo your tweets to an in-game channel

  • -
-

Rather than using an explicit command you can set up a Script to send automatic tweets, for example -to post updated game stats. See the Tweeting Game Stats tutorial for -help.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/IRC.html b/docs/0.9.5/IRC.html deleted file mode 100644 index 7e796b4e58..0000000000 --- a/docs/0.9.5/IRC.html +++ /dev/null @@ -1,198 +0,0 @@ - - - - - - - - - IRC — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

IRC

-

Disambiguation: This page is related to using IRC inside an Evennia game. To join the official -Evennia IRC chat, connect to irc.freenode.net and join #evennia. Alternatively, you can join our -Discord, which is mirrored to IRC.

-

IRC (Internet Relay Chat) is a long standing -chat protocol used by many open-source projects for communicating in real time. By connecting one of -Evennia’s Channels to an IRC channel you can communicate also with people not on -an mud themselves. You can also use IRC if you are only running your Evennia MUD locally on your -computer (your game doesn’t need to be open to the public)! All you need is an internet connection. -For IRC operation you also need twisted.words. -This is available simply as a package python-twisted-words in many Linux distros, or directly -downloadable from the link.

-
-

Configuring IRC

-

To configure IRC, you’ll need to activate it in your settings file.

-
    IRC_ENABLED = True
-
-
-

Start Evennia and log in as a privileged user. You should now have a new command available: -@irc2chan. This command is called like this:

-
 @irc2chan[/switches] <evennia_channel> = <ircnetwork> <port> <#irchannel> <botname>
-
-
-

If you already know how IRC works, this should be pretty self-evident to use. Read the help entry -for more features.

-
-
-

Setting up IRC, step by step

-

You can connect IRC to any Evennia channel (so you could connect it to the default public channel -if you like), but for testing, let’s set up a new channel irc.

-
 @ccreate irc = This is connected to an irc channel!
-
-
-

You will automatically join the new channel.

-

Next we will create a connection to an external IRC network and channel. There are many, many IRC -nets. Here is a list of some of the biggest -ones, the one you choose is not really very important unless you want to connect to a particular -channel (also make sure that the network allows for “bots” to connect).

-

For testing, we choose the Freenode network, irc.freenode.net. We will connect to a test -channel, let’s call it #myevennia-test (an IRC channel always begins with #). It’s best if you -pick an obscure channel name that didn’t exist previously - if it didn’t exist it will be created -for you.

-
-

Don’t connect to #evennia for testing and debugging, that is Evennia’s official chat channel! -You are welcome to connect your game to #evennia once you have everything working though - it -can be a good way to get help and ideas. But if you do, please do so with an in-game channel open -only to your game admins and developers).

-
-

The port needed depends on the network. For Freenode this is 6667.

-

What will happen is that your Evennia server will connect to this IRC channel as a normal user. This -“user” (or “bot”) needs a name, which you must also supply. Let’s call it “mud-bot”.

-

To test that the bot connects correctly you also want to log onto this channel with a separate, -third-party IRC client. There are hundreds of such clients available. If you use Firefox, the -Chatzilla plugin is good and easy. Freenode also offers its own web-based chat page. Once you -have connected to a network, the command to join is usually /join #channelname (don’t forget the -#).

-

Next we connect Evennia with the IRC channel.

-
 @irc2chan irc = irc.freenode.net 6667 #myevennia-test mud-bot
-
-
-

Evennia will now create a new IRC bot mud-bot and connect it to the IRC network and the channel -#myevennia. If you are connected to the IRC channel you will soon see the user mud-bot connect.

-

Write something in the Evennia channel irc.

-
 irc Hello, World!
-[irc] Anna: Hello, World!
-
-
-

If you are viewing your IRC channel with a separate IRC client you should see your text appearing -there, spoken by the bot:

-
mud-bot> [irc] Anna: Hello, World!
-
-
-

Write Hello! in your IRC client window and it will appear in your normal channel, marked with the -name of the IRC channel you used (#evennia here).

-
[irc] Anna@#myevennia-test: Hello!
-
-
-

Your Evennia gamers can now chat with users on external IRC channels!

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Implementing-a-game-rule-system.html b/docs/0.9.5/Implementing-a-game-rule-system.html deleted file mode 100644 index 93c5986c6b..0000000000 --- a/docs/0.9.5/Implementing-a-game-rule-system.html +++ /dev/null @@ -1,425 +0,0 @@ - - - - - - - - - Implementing a game rule system — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Implementing a game rule system

-

The simplest way to create an online roleplaying game (at least from a code perspective) is to -simply grab a paperback RPG rule book, get a staff of game masters together and start to run scenes -with whomever logs in. Game masters can roll their dice in front of their computers and tell the -players the results. This is only one step away from a traditional tabletop game and puts heavy -demands on the staff - it is unlikely staff will be able to keep up around the clock even if they -are very dedicated.

-

Many games, even the most roleplay-dedicated, thus tend to allow for players to mediate themselves -to some extent. A common way to do this is to introduce coded systems - that is, to let the -computer do some of the heavy lifting. A basic thing is to add an online dice-roller so everyone can -make rolls and make sure noone is cheating. Somewhere at this level you find the most bare-bones -roleplaying MUSHes.

-

The advantage of a coded system is that as long as the rules are fair the computer is too - it makes -no judgement calls and holds no personal grudges (and cannot be accused of holding any). Also, the -computer doesn’t need to sleep and can always be online regardless of when a player logs on. The -drawback is that a coded system is not flexible and won’t adapt to the unprogrammed actions human -players may come up with in role play. For this reason many roleplay-heavy MUDs do a hybrid -variation - they use coded systems for things like combat and skill progression but leave role play -to be mostly freeform, overseen by staff game masters.

-

Finally, on the other end of the scale are less- or no-roleplay games, where game mechanics (and -thus player fairness) is the most important aspect. In such games the only events with in-game value -are those resulting from code. Such games are very common and include everything from hack-and-slash -MUDs to various tactical simulations.

-

So your first decision needs to be just what type of system you are aiming for. This page will try -to give some ideas for how to organize the “coded” part of your system, however big that may be.

-
-

Overall system infrastructure

-

We strongly recommend that you code your rule system as stand-alone as possible. That is, don’t -spread your skill check code, race bonus calculation, die modifiers or what have you all over your -game.

-
    -
  • Put everything you would need to look up in a rule book into a module in mygame/world. Hide away -as much as you can. Think of it as a black box (or maybe the code representation of an all-knowing -game master). The rest of your game will ask this black box questions and get answers back. Exactly -how it arrives at those results should not need to be known outside the box. Doing it this way -makes it easier to change and update things in one place later.

  • -
  • Store only the minimum stuff you need with each game object. That is, if your Characters need -values for Health, a list of skills etc, store those things on the Character - don’t store how to -roll or change them.

  • -
  • Next is to determine just how you want to store things on your Objects and Characters. You can -choose to either store things as individual Attributes, like character.db.STR=34 and -character.db.Hunting_skill=20. But you could also use some custom storage method, like a -dictionary character.db.skills = {"Hunting":34, "Fishing":20, ...}. A much more fancy solution is -to look at the Ainneve Trait -handler. Finally you could even go -with a custom django model. Which is the better depends on your game and the -complexity of your system.

  • -
  • Make a clear API into your -rules. That is, make methods/functions that you feed with, say, your Character and which skill you -want to check. That is, you want something similar to this:

    -
        from world import rules
    -    result = rules.roll_skill(character, "hunting")
    -    result = rules.roll_challenge(character1, character2, "swords")
    -
    -
    -
  • -
-

You might need to make these functions more or less complex depending on your game. For example the -properties of the room might matter to the outcome of a roll (if the room is dark, burning etc). -Establishing just what you need to send into your game mechanic module is a great way to also get a -feel for what you need to add to your engine.

-
-
-

Coded systems

-

Inspired by tabletop role playing games, most game systems mimic some sort of die mechanic. To this -end Evennia offers a full dice -roller in its contrib -folder. For custom implementations, Python offers many ways to randomize a result using its in-built -random module. No matter how it’s implemented, we will in this text refer to the action of -determining an outcome as a “roll”.

-

In a freeform system, the result of the roll is just compared with values and people (or the game -master) just agree on what it means. In a coded system the result now needs to be processed somehow. -There are many things that may happen as a result of rule enforcement:

-
    -
  • Health may be added or deducted. This can effect the character in various ways.

  • -
  • Experience may need to be added, and if a level-based system is used, the player might need to be -informed they have increased a level.

  • -
  • Room-wide effects need to be reported to the room, possibly affecting everyone in the room.

  • -
-

There are also a slew of other things that fall under “Coded systems”, including things like -weather, NPC artificial intelligence and game economy. Basically everything about the world that a -Game master would control in a tabletop role playing game can be mimicked to some level by coded -systems.

-
-
-

Example of Rule module

-

Here is a simple example of a rule module. This is what we assume about our simple example game:

-
    -
  • Characters have only four numerical values:

    -
      -
    • Their level, which starts at 1.

    • -
    • A skill combat, which determines how good they are at hitting things. Starts between 5 and

    • -
    -
  • -
-
    -
    • -
    • Their Strength, STR, which determine how much damage they do. Starts between 1 and 10.

    • -
    • Their Health points, HP, which starts at 100.

    • -
    -
  1. -
-
    -
  • When a Character reaches HP = 0, they are presumed “defeated”. Their HP is reset and they get a -failure message (as a stand-in for death code).

  • -
  • Abilities are stored as simple Attributes on the Character.

  • -
  • “Rolls” are done by rolling a 100-sided die. If the result plus the combatvalue is greater than -the other character, it’s a success and damage is rolled. Damage is rolled as a six-sided die + the -value of STR (for this example we ignore weapons and assume STR is all that matters).

  • -
  • Every successful attack roll gives 1-3 experience points (XP). Every time the number of XP -reaches (level + 1) ** 2, the Character levels up. When leveling up, the Character’s combat -value goes up by 2 points and STR by one (this is a stand-in for a real progression system).

  • -
  • Characters with the name dummy will gain no XP. Allowing us to make a dummy to train with.

  • -
-
-

Character

-

The Character typeclass is simple. It goes in mygame/typeclasses/characters.py. There is already -an empty Character class there that Evennia will look to and use.

-
from random import randint
-from evennia import DefaultCharacter
-
-class Character(DefaultCharacter):
-    """
-    Custom rule-restricted character. We randomize
-    the initial skill and ability values bettween 1-10.
-    """
-    def at_object_creation(self):
-        "Called only when first created"
-        self.db.level = 1
-        self.db.HP = 100
-        self.db.XP = 0
-        self.db.STR = randint(1, 10)
-        self.db.combat = randint(5, 10)
-
-
-

@reload the server to load up the new code. Doing examine self will however not show the new -Attributes on yourself. This is because the at_object_creation hook is only called on new -Characters. Your Character was already created and will thus not have them. To force a reload, use -the following command:

-
@typeclass/force/reset self
-
-
-

The examine self command will now show the new Attributes.

-
-
-

Rule module

-

This is a module mygame/world/rules.py.

-
"""
-mygame/world/rules.py
-"""
-from random import randint
-
-
-def roll_hit():
-    "Roll 1d100"
-    return randint(1, 100)
-
-
-def roll_dmg():
-    "Roll 1d6"
-    return randint(1, 6)
-
-
-def check_defeat(character):
-    "Checks if a character is 'defeated'."
-    if character.db.HP <= 0:
-        character.msg("You fall down, defeated!")
-        character.db.HP = 100   # reset
-
-
-def add_XP(character, amount):
-    "Add XP to character, tracking level increases."
-    if "training_dummy" in character.tags.all():  # don't allow the training dummy to level
-        character.location.msg_contents("Training Dummies can not gain XP.")
-        return
-    else:
-        character.db.XP += amount
-        if character.db.XP >= (character.db.level + 1) ** 2:
-            character.db.level += 1
-            character.db.STR += 1
-            character.db.combat += 2
-            character.msg("You are now level %i!" % character.db.level)
-
-
-def skill_combat(*args):
-    """
-    This determines outcome of combat. The one who
-    rolls under their combat skill AND higher than
-    their opponent's roll hits.
-    """
-    char1, char2 = args
-    roll1, roll2 = roll_hit(), roll_hit()
-    failtext = "You are hit by %s for %i damage!"
-    wintext = "You hit %s for %i damage!"
-    xp_gain = randint(1, 3)
-
-    # display messages showing attack numbers
-    attack_message = f"{char1.name} rolls {roll1} + combat {char1.db.combat} " \
-    f"= {char1.db.combat+roll1} | {char2.name} rolls {roll2} + combat " \
-    f"{char2.db.combat} = {char2.db.combat+roll2}"
-    char1.location.msg_contents(attack_message)
-    attack_summary = f"{char1.name} {char1.db.combat+roll1} " \
-    f"vs {char2.name} {char2.db.combat+roll2}"
-    char1.location.msg_contents(attack_summary)
-
-    if char1.db.combat+roll1 > char2.db.combat+roll2:
-        # char 1 hits
-        dmg = roll_dmg() + char1.db.STR
-        char1.msg(wintext % (char2, dmg))
-        add_XP(char1, xp_gain)
-        char2.msg(failtext % (char1, dmg))
-        char2.db.HP -= dmg
-        check_defeat(char2)
-    elif char2.db.combat+roll2 > char1.db.combat+roll1:
-        # char 2 hits
-        dmg = roll_dmg() + char2.db.STR
-        char1.msg(failtext % (char2, dmg))
-        char1.db.HP -= dmg
-        check_defeat(char1)
-        char2.msg(wintext % (char1, dmg))
-        add_XP(char2, xp_gain)
-    else:
-        # a draw
-        drawtext = "Neither of you can find an opening."
-        char1.msg(drawtext)
-        char2.msg(drawtext)
-
-
-SKILLS = {"combat": skill_combat}
-
-
-def roll_challenge(character1, character2, skillname):
-    """
-    Determine the outcome of a skill challenge between
-    two characters based on the skillname given.
-    """
-    if skillname in SKILLS:
-        SKILLS[skillname](character1, character2)
-    else:
-        raise RunTimeError("Skillname %s not found." % skillname)
-
-
-

These few functions implement the entirety of our simple rule system. We have a function to check -the “defeat” condition and reset the HP back to 100 again. We define a generic “skill” function. -Multiple skills could all be added with the same signature; our SKILLS dictionary makes it easy to -look up the skills regardless of what their actual functions are called. Finally, the access -function roll_challenge just picks the skill and gets the result.

-

In this example, the skill function actually does a lot - it not only rolls results, it also informs -everyone of their results via character.msg() calls.

-
-
-

Attack Command

-

Here is an example of usage in a game command:

-
from evennia import Command
-from world import rules
-
-class CmdAttack(Command):
-    """
-    attack an opponent
-
-    Usage:
-      attack <target>
-
-    This will attack a target in the same room, dealing
-    damage with your bare hands.
-    """
-    def func(self):
-        "Implementing combat"
-
-        caller = self.caller
-        if not self.args:
-            caller.msg("You need to pick a target to attack.")
-            return
-
-        target = caller.search(self.args)
-        if target:
-            rules.roll_challenge(caller, target, "combat")
-
-
-

Note how simple the command becomes and how generic you can make it. It becomes simple to offer any -number of Combat commands by just extending this functionality - you can easily roll challenges and -pick different skills to check. And if you ever decided to, say, change how to determine hit chance, -you don’t have to change every command, but need only change the single roll_hit function inside -your rules module.

-
-
-

Training dummy

-

Create a dummy to test the attack command. Give it a training_dummy tag anything with the tag -training_dummy will not gain xp.

-
-

create/drop dummy:characters.Character
-tag dummy=training_dummy

-
-

Attack it with your new command

-
-

attack dummy

-
-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Inputfuncs.html b/docs/0.9.5/Inputfuncs.html deleted file mode 100644 index afc6d86888..0000000000 --- a/docs/0.9.5/Inputfuncs.html +++ /dev/null @@ -1,312 +0,0 @@ - - - - - - - - - Inputfuncs — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Inputfuncs

-

An inputfunc is an Evennia function that handles a particular input (an inputcommand) from -the client. The inputfunc is the last destination for the inputcommand along the ingoing message -path. The inputcommand always has the form (commandname, (args), {kwargs}) and Evennia will use this to try to find and call an inputfunc on the form

-
    def commandname(session, *args, **kwargs):
-        # ...
-
-
-
-

Or, if no match was found, it will call an inputfunc named “default” on this form

-
    def default(session, cmdname, *args, **kwargs):
-        # cmdname is the name of the mismatched inputcommand
-
-
-
-
-

Adding your own inputfuncs

-

This is simple. Add a function on the above form to mygame/server/conf/inputfuncs.py. Your -function must be in the global, outermost scope of that module and not start with an underscore -(_) to be recognized as an inputfunc. Reload the server. That’s it. To overload a default -inputfunc (see below), just add a function with the same name.

-

The modules Evennia looks into for inputfuncs are defined in the list settings.INPUT_FUNC_MODULES. -This list will be imported from left to right and later imported functions will replace earlier -ones.

-
-
-

Default inputfuncs

-

Evennia defines a few default inputfuncs to handle the common cases. These are defined in -evennia/server/inputfuncs.py.

-
-

text

-
    -
  • Input: ("text", (textstring,), {})

  • -
  • Output: Depends on Command triggered

  • -
-

This is the most common of inputcommands, and the only one supported by every traditional mud. The -argument is usually what the user sent from their command line. Since all text input from the user -like this is considered a Command, this inputfunc will do things like nick-replacement -and then pass on the input to the central Commandhandler.

-
-
-

echo

-
    -
  • Input: ("echo", (args), {})

  • -
  • Output: ("text", ("Echo returns: %s" % args), {})

  • -
-

This is a test input, which just echoes the argument back to the session as text. Can be used for -testing custom client input.

-
-
-

default

-

The default function, as mentioned above, absorbs all non-recognized inputcommands. The default one -will just log an error.

-
-
-

client_options

-
    -
  • Input: ("client_options, (), {key:value, ...})

  • -
  • Output:

  • -
  • normal: None

  • -
  • get: ("client_options", (), {key:value, ...})

  • -
-

This is a direct command for setting protocol options. These are settable with the @option -command, but this offers a client-side way to set them. Not all connection protocols makes use of -all flags, but here are the possible keywords:

-
    -
  • get (bool): If this is true, ignore all other kwargs and immediately return the current settings -as an outputcommand ("client_options", (), {key=value, ...})-

  • -
  • client (str): A client identifier, like “mushclient”.

  • -
  • version (str): A client version

  • -
  • ansi (bool): Supports ansi colors

  • -
  • xterm256 (bool): Supports xterm256 colors or not

  • -
  • mxp (bool): Supports MXP or not

  • -
  • utf-8 (bool): Supports UTF-8 or not

  • -
  • screenreader (bool): Screen-reader mode on/off

  • -
  • mccp (bool): MCCP compression on/off

  • -
  • screenheight (int): Screen height in lines

  • -
  • screenwidth (int): Screen width in characters

  • -
  • inputdebug (bool): Debug input functions

  • -
  • nomarkup (bool): Strip all text tags

  • -
  • raw (bool): Leave text tags unparsed

  • -
-
-

Note that there are two GMCP aliases to this inputfunc - hello and supports_set, which means -it will be accessed via the GMCP Hello and Supports.Set instructions assumed by some clients.

-
-
-
-

get_client_options

-
    -
  • Input: ("get_client_options, (), {key:value, ...})

  • -
  • Output: ("client_options, (), {key:value, ...})

  • -
-

This is a convenience wrapper that retrieves the current options by sending “get” to -client_options above.

-
-
-

get_inputfuncs

-
    -
  • Input: ("get_inputfuncs", (), {})

  • -
  • Output: ("get_inputfuncs", (), {funcname:docstring, ...})

  • -
-

Returns an outputcommand on the form ("get_inputfuncs", (), {funcname:docstring, ...}) - a list of -all the available inputfunctions along with their docstrings.

-
-
-

login

-
-

Note: this is currently experimental and not very well tested.

-
-
    -
  • Input: ("login", (username, password), {})

  • -
  • Output: Depends on login hooks

  • -
-

This performs the inputfunc version of a login operation on the current Session.

-
-
-

get_value

-

Input: ("get_value", (name, ), {}) -Output: ("get_value", (value, ), {})

-

Retrieves a value from the Character or Account currently controlled by this Session. Takes one -argument, This will only accept particular white-listed names, you’ll need to overload the function -to expand. By default the following values can be retrieved:

-
    -
  • “name” or “key”: The key of the Account or puppeted Character.

  • -
  • “location”: Name of the current location, or “None”.

  • -
  • “servername”: Name of the Evennia server connected to.

  • -
-
-
-

repeat

-
    -
  • Input: ("repeat", (), {"callback":funcname,                     "interval": secs, "stop": False})

  • -
  • Output: Depends on the repeated function. Will return ("text", (repeatlist),{} with a list of -accepted names if given an unfamiliar callback name.

  • -
-

This will tell evennia to repeatedly call a named function at a given interval. Behind the scenes -this will set up a Ticker. Only previously acceptable functions are possible to -repeat-call in this way, you’ll need to overload this inputfunc to add the ones you want to offer. -By default only two example functions are allowed, “test1” and “test2”, which will just echo a text -back at the given interval. Stop the repeat by sending "stop": True (note that you must include -both the callback name and interval for Evennia to know what to stop).

-
-
-

unrepeat

-
    -
  • Input: ("unrepeat", (), ("callback":funcname,                           "interval": secs)

  • -
  • Output: None

  • -
-

This is a convenience wrapper for sending “stop” to the repeat inputfunc.

-
-
-

monitor

-
    -
  • Input: ("monitor", (), ("name":field_or_argname, stop=False)

  • -
  • Output (on change): ("monitor", (), {"name":name, "value":value})

  • -
-

This sets up on-object monitoring of Attributes or database fields. Whenever the field or Attribute -changes in any way, the outputcommand will be sent. This is using the -MonitorHandler behind the scenes. Pass the “stop” key to stop monitoring. Note -that you must supply the name also when stopping to let the system know which monitor should be -cancelled.

-

Only fields/attributes in a whitelist are allowed to be used, you have to overload this function to -add more. By default the following fields/attributes can be monitored:

-
    -
  • “name”: The current character name

  • -
  • “location”: The current location

  • -
  • “desc”: The description Argument

  • -
-
-
-
-

unmonitor

-
    -
  • Input: ("unmonitor", (), {"name":name})

  • -
  • Output: None

  • -
-

A convenience wrapper that sends “stop” to the monitor function.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Installing-on-Android.html b/docs/0.9.5/Installing-on-Android.html deleted file mode 100644 index 8cf607c4d2..0000000000 --- a/docs/0.9.5/Installing-on-Android.html +++ /dev/null @@ -1,249 +0,0 @@ - - - - - - - - - Installing on Android — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Installing on Android

-

This page describes how to install and run the Evennia server on an Android phone. This will involve -installing a slew of third-party programs from the Google Play store, so make sure you are okay with -this before starting.

-
-

Install Termux

-

The first thing to do is install a terminal emulator that allows a “full” version of linux to be -run. Note that Android is essentially running on top of linux so if you have a rooted phone, you may -be able to skip this step. You don’t require a rooted phone to install Evennia though.

-

Assuming we do not have root, we will install -Termux. -Termux provides a base installation of Linux essentials, including apt and Python, and makes them -available under a writeable directory. It also gives us a terminal where we can enter commands. By -default, Android doesn’t give you permissions to the root folder, so Termux pretends that its own -installation directory is the root directory.

-

Termux will set up a base system for us on first launch, but we will need to install some -prerequisites for Evennia. Commands you should run in Termux will look like this:

-
$ cat file.txt
-
-
-

The $ symbol is your prompt - do not include it when running commands.

-
-
-

Prerequisites

-

To install some of the libraries Evennia requires, namely Pillow and Twisted, we have to first -install some packages they depend on. In Termux, run the following

-
$ pkg install -y clang git zlib ndk-sysroot libjpeg-turbo libcrypt python
-
-
-

Termux ships with Python 3, perfect. Python 3 has venv (virtualenv) and pip (Python’s module -installer) built-in.

-

So, let’s set up our virtualenv. This keeps the Python packages we install separate from the system -versions.

-
$ cd
-$ python3 -m venv evenv
-
-
-

This will create a new folder, called evenv, containing the new python executable. -Next, let’s activate our new virtualenv. Every time you want to work on Evennia, you need to run the -following command:

-
$ source evenv/bin/activate
-
-
-

Your prompt will change to look like this:

-
(evenv) $
-
-
-

Update the updaters and installers in the venv: pip, setuptools and wheel.

-
python3 -m pip install --upgrade pip setuptools wheel
-
-
-
-

Installing Evennia

-

Now that we have everything in place, we’re ready to download and install Evennia itself.

-

Mysterious incantations

-
export LDFLAGS="-L/data/data/com.termux/files/usr/lib/"
-export CFLAGS="-I/data/data/com.termux/files/usr/include/"
-
-
-

(these tell clang, the C compiler, where to find the bits for zlib when building Pillow)

-

Install the latest Evennia in a way that lets you edit the source

-
(evenv) $ pip install --upgrade -e 'git+https://github.com/evennia/evennia#egg=evennia'
-
-
-

This step will possibly take quite a while - we are downloading Evennia and are then installing it, -building all of the requirements for Evennia to run. If you run into trouble on this step, please -see Troubleshooting.

-

You can go to the dir where Evennia is installed with cd $VIRTUAL_ENV/src/evennia. git grep (something) can be handy, as can git diff

-
-
-

Final steps

-

At this point, Evennia is installed on your phone! You can now continue with the original Getting -Started instruction, we repeat them here for clarity.

-

To start a new game:

-
(evenv) $ evennia --init mygame
-(evenv) $ ls
-mygame evenv
-
-
-

To start the game for the first time:

-
(evenv) $ cd mygame
-(evenv) $ evennia migrate
-(evenv) $ evennia start
-
-
-

Your game should now be running! Open a web browser at http://localhost:4001 or point a telnet -client to localhost:4000 and log in with the user you created.

-
-
-
-

Running Evennia

-

When you wish to run Evennia, get into your Termux console and make sure you have activated your -virtualenv as well as are in your game’s directory. You can then run evennia start as normal.

-
$ cd ~ && source evenv/bin/activate
-(evenv) $ cd mygame
-(evenv) $ evennia start
-
-
-

You may wish to look at the Linux Instructions for more.

-
-
-

Caveats

-
    -
  • Android’s os module doesn’t support certain functions - in particular getloadavg. Thusly, running -the command @server in-game will throw an exception. So far, there is no fix for this problem.

  • -
  • As you might expect, performance is not amazing.

  • -
  • Android is fairly aggressive about memory handling, and you may find that your server process is -killed if your phone is heavily taxed. Termux seems to keep a notification up to discourage this.

  • -
-
-
-

Troubleshooting

-

As time goes by and errors are reported, this section will be added to.

-

Some steps to try anyway:

-
    -
  • Make sure your packages are up-to-date, try running pkg update && pkg upgrade -y

  • -
  • Make sure you’ve installed the clang package. If not, try pkg install clang -y

  • -
  • Make sure you’re in the right directory. `cd ~/mygame

  • -
  • Make sure you’ve sourced your virtualenv. type cd && source evenv/bin/activate

  • -
  • See if a shell will start: cd ~/mygame ; evennia shell

  • -
  • Look at the log files in ~/mygame/server/logs/

  • -
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Internationalization.html b/docs/0.9.5/Internationalization.html deleted file mode 100644 index 448b2ed655..0000000000 --- a/docs/0.9.5/Internationalization.html +++ /dev/null @@ -1,202 +0,0 @@ - - - - - - - - - Internationalization — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Internationalization

-

Internationalization (often abbreviated i18n since there are 18 characters between the first “i” -and the last “n” in that word) allows Evennia’s core server to return texts in other languages than -English - without anyone having to edit the source code. Take a look at the locale directory of -the Evennia installation, there you will find which languages are currently supported.

-
-

Changing server language

-

Change language by adding the following to your mygame/server/conf/settings.py file:

-
    USE_I18N = True
-    LANGUAGE_CODE = 'en'
-
-
-

Here 'en' should be changed to the abbreviation for one of the supported languages found in -locale/. Restart the server to activate i18n. The two-character international language codes are -found here.

-
-

Windows Note: If you get errors concerning gettext or xgettext on Windows, see the Django -documentation. A -self-installing and up-to-date version of gettext for Windows (32/64-bit) is available on -Github.

-
-
-
-

Translating Evennia

-
-

Important Note: Evennia offers translations of hard-coded strings in the server, things like -“Connection closed” or “Server restarted”, strings that end users will see and which game devs are -not supposed to change on their own. Text you see in the log file or on the command line (like error -messages) are generally not translated (this is a part of Python).

-
-
-

In addition, text in default Commands and in default Typeclasses will not be translated by -switching i18n language. To translate Commands and Typeclass hooks you must overload them in your -game directory and translate their returns to the language you want. This is because from Evennia’s -perspective, adding i18n code to commands tend to add complexity to code that is meant to be -changed anyway. One of the goals of Evennia is to keep the user-changeable code as clean and easy- -to-read as possible.

-
-

If you cannot find your language in evennia/locale/ it’s because noone has translated it yet. -Alternatively you might have the language but find the translation bad … You are welcome to help -improve the situation!

-

To start a new translation you need to first have cloned the Evennia repositry with GIT and -activated a python virtualenv as described on the Getting Started page. You now -need to cd to the evennia/ directory. This is not your created game folder but the main -Evennia library folder. If you see a folder locale/ then you are in the right place. From here you -run:

-
 evennia makemessages <language-code>
-
-
-

where <language-code> is the two-letter locale code -for the language you want, like ‘sv’ for Swedish or ‘es’ for Spanish. After a moment it will tell -you the language has been processed. For instance:

-
 evennia makemessages sv
-
-
-

If you started a new language a new folder for that language will have emerged in the locale/ -folder. Otherwise the system will just have updated the existing translation with eventual new -strings found in the server. Running this command will not overwrite any existing strings so you can -run it as much as you want.

-
-

Note: in Django, the makemessages command prefixes the locale name by the -l option (... makemessages -l sv for instance). This syntax is not allowed in Evennia, due to the fact that -l -is the option to tail log files. Hence, makemessages doesn’t use the -l flag.

-
-

Next head to locale/<language-code>/LC_MESSAGES and edit the **.po file you find there. You can -edit this with a normal text editor but it is easiest if you use a special po-file editor from the -web (search the web for “po editor” for many free alternatives).

-

The concept of translating is simple, it’s just a matter of taking the english strings you find in -the **.po file and add your language’s translation best you can. The **.po format (and many -supporting editors) allow you to mark translations as “fuzzy”. This tells the system (and future -translators) that you are unsure about the translation, or that you couldn’t find a translation that -exactly matched the intention of the original text. Other translators will see this and might be -able to improve it later. -Finally, you need to compile your translation into a more efficient form. Do so from the evennia -folder -again:

-
evennia compilemessages
-
-
-

This will go through all languages and create/update compiled files (**.mo) for them. This needs -to be done whenever a **.po file is updated.

-

When you are done, send the **.po and *.mo file to the Evennia developer list (or push it into -your own repository clone) so we can integrate your translation into Evennia!

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Learn-Python-for-Evennia-The-Hard-Way.html b/docs/0.9.5/Learn-Python-for-Evennia-The-Hard-Way.html deleted file mode 100644 index a9204a85f4..0000000000 --- a/docs/0.9.5/Learn-Python-for-Evennia-The-Hard-Way.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - - - - Learn Python for Evennia The Hard Way — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Learn Python for Evennia The Hard Way

-
-
-

WORK IN PROGRESS - DO NOT USE

-

Evennia provides a great foundation to build your very own MU* whether you have programming -experience or none at all. Whilst Evennia has a number of in-game building commands and tutorials -available to get you started, when approaching game systems of any complexity it is advisable to -have the basics of Python under your belt before jumping into the code. There are many Python -tutorials freely available online however this page focuses on Learn Python the Hard Way (LPTHW) by -Zed Shaw. This tutorial takes you through the basics of Python and progresses you to creating your -very own online text based game. Whilst completing the course feel free to install Evennia and try -out some of our beginner tutorials. On completion you can return to this page, which will act as an -overview to the concepts separating your online text based game and the inner-workings of Evennia. --The latter portion of the tutorial focuses working your engine into a webpage and is not strictly -required for development in Evennia.

-
-

Exercise 23

-

You may have returned here when you were invited to read some code. If you haven’t already, you -should now have the knowledge necessary to install Evennia. Head over to the Getting Started page -for install instructions. You can also try some of our tutorials to get you started on working with -Evennia.

-
-
-

Bridging the gap.

-

If you have successfully completed the Learn Python the Hard Way tutorial you should now have a -simple browser based Interactive Fiction engine which looks similar to this. -This engine is built using a single interactive object type, the Room class. The Room class holds a -description of itself that is presented to the user and a list of hardcoded commands which if -selected correctly will present you with the next rooms’ description and commands. Whilst your game -only has one interactive object, MU* have many more: Swords and shields, potions and scrolls or even -laser guns and robots. Even the player has an in-game representation in the form of your character. -Each of these examples are represented by their own object with their own description that can be -presented to the user.

-

A basic object in Evennia has a number of default functions but perhaps most important is the idea -of location. In your text engine you receive a description of a room but you are not really in the -room because you have no in-game representation. However, in Evennia when you enter a Dungeon you -ARE in the dungeon. That is to say your character.location = Dungeon whilst the Dungeon.contents now -has a spunky young adventurer added to it. In turn, your character.contents may have amongst it a -number of swords and potions to help you on your adventure and their location would be you.

-

In reality each of these “objects” are just an entry in your Evennia projects database which keeps -track of all these attributes, such as location and contents. Making changes to those attributes and -the rules in which they are changed is the most fundamental perspective of how your game works. We -define those rules in the objects Typeclass. The Typeclass is a Python class with a special -connection to the games database which changes values for us through various class methods. Let’s -look at your characters Typeclass rules for changing location.

-
         1. `self.at_before_move(destination)` (if this returns False, move is aborted)
-         2. `self.announce_move_from(destination)`
-         3. (move happens here)
-         4. `self.announce_move_to(source_location)`
-         5. `self.at_after_move(source_location)`
-
-
-

First we check if it’s okay to leave our current location, then we tell everyone there that we’re -leaving. We move locations and tell everyone at our new location that we’ve arrived before checking -we’re okay to be there. By default stages 1 and 5 are empty ready for us to add some rules. We’ll -leave an explanation as to how to make those changes for the tutorial section, but imagine if you -were an astronaut. A smart astronaut might stop at step 1 to remember to put his helmet on whilst a -slower astronaut might realise he’s forgotten in step 5 before shortly after ceasing to be an -astronaut.

-

With all these objects and all this moving around it raises another problem. In your text engine the -commands available to the player were hard-coded to the room. That means if we have commands we -always want available to the player we’ll need to have those commands hard-coded on every single -room. What about an armoury? When all the swords are gone the command to take a sword would still -remain causing confusion. Evennia solves this problem by giving each object the ability to hold -commands. Rooms can have commands attached to them specific to that location, like climbing a tree; -Players can have commands which are always available to them, like ‘look’, ‘get’ and ‘say’; and -objects can have commands attached to them which unlock when taking possession of it, like attack -commands when obtaining a weapon.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Licensing.html b/docs/0.9.5/Licensing.html deleted file mode 100644 index 65bae64a4d..0000000000 --- a/docs/0.9.5/Licensing.html +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - - - - Licensing — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Licensing

-

Evennia is licensed under the very friendly BSD -(3-clause) license. You can find the license as -LICENSE.txt in the Evennia -repository’s root.

-

Q: When creating a game using Evennia, what does the license permit me to do with it?

-

A: It’s your own game world to do with as you please! Keep it to yourself or re-distribute it -under another license of your choice - or sell it and become filthy rich for all we care.

-

Q: I have modified the Evennia library itself, what does the license say about that?

-

A: Our license allows you to do whatever you want with your modified Evennia, including -re-distributing or selling it, as long as you include our license and copyright info found in -LICENSE.txt along with your distribution.

-

… Of course, if you fix bugs or add some new snazzy feature we softly nudge you to make those -changes available so they can be added to the core Evennia package for everyone’s benefit. The -license doesn’t require you to do it, but that doesn’t mean we won’t still greatly appreciate it -if you do!

-

Q: Can I re-distribute the Evennia server package along with my custom game implementation?

-

A: Sure. As long as the text in LICENSE.txt is included.

-

Q: What about Contributions?

-

The contributions in evennia/evennia/contrib are considered to be released under the same license -as Evennia itself, unless the individual contributor has specifically defined otherwise.

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Links.html b/docs/0.9.5/Links.html deleted file mode 100644 index ebfa51007e..0000000000 --- a/docs/0.9.5/Links.html +++ /dev/null @@ -1,322 +0,0 @@ - - - - - - - - - Links — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- - - - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Locks.html b/docs/0.9.5/Locks.html deleted file mode 100644 index 6090c4da27..0000000000 --- a/docs/0.9.5/Locks.html +++ /dev/null @@ -1,606 +0,0 @@ - - - - - - - - - Locks — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Locks

-

For most games it is a good idea to restrict what people can do. In Evennia such restrictions are -applied and checked by something called locks. All Evennia entities (Commands, -Objects, Scripts, Accounts, Help System, -messages and channels) are accessed through locks.

-

A lock can be thought of as an “access rule” restricting a particular use of an Evennia entity. -Whenever another entity wants that kind of access the lock will analyze that entity in different -ways to determine if access should be granted or not. Evennia implements a “lockdown” philosophy - -all entities are inaccessible unless you explicitly define a lock that allows some or full access.

-

Let’s take an example: An object has a lock on itself that restricts how people may “delete” that -object. Apart from knowing that it restricts deletion, the lock also knows that only players with -the specific ID of, say, 34 are allowed to delete it. So whenever a player tries to run delete -on the object, the delete command makes sure to check if this player is really allowed to do so. -It calls the lock, which in turn checks if the player’s id is 34. Only then will it allow delete -to go on with its job.

-
-

Setting and checking a lock

-

The in-game command for setting locks on objects is lock:

-
 > lock obj = <lockstring>
-
-
-

The <lockstring> is a string of a certain form that defines the behaviour of the lock. We will go -into more detail on how <lockstring> should look in the next section.

-

Code-wise, Evennia handles locks through what is usually called locks on all relevant entities. -This is a handler that allows you to add, delete and check locks.

-
     myobj.locks.add(<lockstring>)
-
-
-

One can call locks.check() to perform a lock check, but to hide the underlying implementation all -objects also have a convenience function called access. This should preferably be used. In the -example below, accessing_obj is the object requesting the ‘delete’ access whereas obj is the -object that might get deleted. This is how it would look (and does look) from inside the delete -command:

-
     if not obj.access(accessing_obj, 'delete'):
-         accessing_obj.msg("Sorry, you may not delete that.")
-         return
-
-
-
-
-

Defining locks

-

Defining a lock (i.e. an access restriction) in Evennia is done by adding simple strings of lock -definitions to the object’s locks property using obj.locks.add().

-

Here are some examples of lock strings (not including the quotes):

-
     delete:id(34)   # only allow obj #34 to delete
-     edit:all()      # let everyone edit
-     # only those who are not "very_weak" or are Admins may pick this up
-     get: not attr(very_weak) or perm(Admin)
-
-
-

Formally, a lockstring has the following syntax:

-
     access_type: [NOT] lockfunc1([arg1,..]) [AND|OR] [NOT] lockfunc2([arg1,...]) [...]
-
-
-

where [] marks optional parts. AND, OR and NOT are not case sensitive and excess spaces are -ignored. lockfunc1, lockfunc2 etc are special lock functions available to the lock system.

-

So, a lockstring consists of the type of restriction (the access_type), a colon (:) and then an -expression involving function calls that determine what is needed to pass the lock. Each function -returns either True or False. AND, OR and NOT work as they do normally in Python. If the -total result is True, the lock is passed.

-

You can create several lock types one after the other by separating them with a semicolon (;) in -the lockstring. The string below yields the same result as the previous example:

-
delete:id(34);edit:all();get: not attr(very_weak) or perm(Admin)
-
-
-
-

Valid access_types

-

An access_type, the first part of a lockstring, defines what kind of capability a lock controls, -such as “delete” or “edit”. You may in principle name your access_type anything as long as it is -unique for the particular object. The name of the access types is not case-sensitive.

-

If you want to make sure the lock is used however, you should pick access_type names that you (or -the default command set) actually checks for, as in the example of delete above that uses the -‘delete’ access_type.

-

Below are the access_types checked by the default commandset.

-
    -
  • Commands

    -
      -
    • cmd - this defines who may call this command at all.

    • -
    -
  • -
  • Objects:

    -
      -
    • control - who is the “owner” of the object. Can set locks, delete it etc. Defaults to the -creator of the object.

    • -
    • call - who may call Object-commands stored on this Object except for the Object itself. By -default, Objects share their Commands with anyone in the same location (e.g. so you can ‘press’ a -Button object in the room). For Characters and Mobs (who likely only use those Commands for -themselves and don’t want to share them) this should usually be turned off completely, using -something like call:false().

    • -
    • examine - who may examine this object’s properties.

    • -
    • delete - who may delete the object.

    • -
    • edit - who may edit properties and attributes of the object.

    • -
    • view - if the look command will display/list this object

    • -
    • get- who may pick up the object and carry it around.

    • -
    • puppet - who may “become” this object and control it as their “character”.

    • -
    • attrcreate - who may create new attributes on the object (default True)

    • -
    -
  • -
  • Characters:

    -
      -
    • Same as for Objects

    • -
    -
  • -
  • Exits:

    -
      -
    • Same as for Objects

    • -
    • traverse - who may pass the exit.

    • -
    -
  • -
  • Accounts:

    -
      -
    • examine - who may examine the account’s properties.

    • -
    • delete - who may delete the account.

    • -
    • edit - who may edit the account’s attributes and properties.

    • -
    • msg - who may send messages to the account.

    • -
    • boot - who may boot the account.

    • -
    -
  • -
  • Attributes: (only checked by obj.secure_attr)

    -
      -
    • attrread - see/access attribute

    • -
    • attredit - change/delete attribute

    • -
    -
  • -
  • Channels:

    -
      -
    • control - who is administrating the channel. This means the ability to delete the channel, -boot listeners etc.

    • -
    • send - who may send to the channel.

    • -
    • listen - who may subscribe and listen to the channel.

    • -
    -
  • -
  • HelpEntry:

    -
      -
    • examine - who may view this help entry (usually everyone)

    • -
    • edit - who may edit this help entry.

    • -
    -
  • -
-

So to take an example, whenever an exit is to be traversed, a lock of the type traverse will be -checked. Defining a suitable lock type for an exit object would thus involve a lockstring traverse: <lock functions>.

-
-
-

Custom access_types

-

As stated above, the access_type part of the lock is simply the ‘name’ or ‘type’ of the lock. The -text is an arbitrary string that must be unique for an object. If adding a lock with the same -access_type as one that already exists on the object, the new one override the old one.

-

For example, if you wanted to create a bulletin board system and wanted to restrict who can either -read a board or post to a board. You could then define locks such as:

-
     obj.locks.add("read:perm(Player);post:perm(Admin)")
-
-
-

This will create a ‘read’ access type for Characters having the Player permission or above and a -‘post’ access type for those with Admin permissions or above (see below how the perm() lock -function works). When it comes time to test these permissions, simply check like this (in this -example, the obj may be a board on the bulletin board system and accessing_obj is the player -trying to read the board):

-
     if not obj.access(accessing_obj, 'read'):
-         accessing_obj.msg("Sorry, you may not read that.")
-         return
-
-
-
-
-

Lock functions

-

A lock function is a normal Python function put in a place Evennia looks for such functions. The -modules Evennia looks at is the list settings.LOCK_FUNC_MODULES. All functions in any of those -modules will automatically be considered a valid lock function. The default ones are found in -evennia/locks/lockfuncs.py and you can start adding your own in mygame/server/conf/lockfuncs.py. -You can append the setting to add more module paths. To replace a default lock function, just add -your own with the same name.

-

A lock function must always accept at least two arguments - the accessing object (this is the -object wanting to get access) and the accessed object (this is the object with the lock). Those -two are fed automatically as the first two arguments to the function when the lock is checked. Any -arguments explicitly given in the lock definition will appear as extra arguments.

-
    # A simple example lock function. Called with e.g. `id(34)`. This is
-    # defined in, say mygame/server/conf/lockfuncs.py
-    
-    def id(accessing_obj, accessed_obj, *args, **kwargs):
-        if args:
-            wanted_id = args[0]
-            return accessing_obj.id == wanted_id
-        return False
-
-
-

The above could for example be used in a lock function like this:

-
    # we have `obj` and `owner_object` from before
-    obj.locks.add("edit: id(%i)" % owner_object.id)
-
-
-

We could check if the “edit” lock is passed with something like this:

-
    # as part of a Command's func() method, for example
-    if not obj.access(caller, "edit"):
-        caller.msg("You don't have access to edit this!")
-        return
-
-
-

In this example, everyone except the caller with the right id will get the error.

-
-

(Using the * and ** syntax causes Python to magically put all extra arguments into a list -args and all keyword arguments into a dictionary kwargs respectively. If you are unfamiliar with -how *args and **kwargs work, see the Python manuals).

-
-

Some useful default lockfuncs (see src/locks/lockfuncs.py for more):

-
    -
  • true()/all() - give access to everyone

  • -
  • false()/none()/superuser() - give access to none. Superusers bypass the check entirely and are -thus the only ones who will pass this check.

  • -
  • perm(perm) - this tries to match a given permission property, on an Account firsthand, on a -Character second. See below.

  • -
  • perm_above(perm) - like perm but requires a “higher” permission level than the one given.

  • -
  • id(num)/dbref(num) - checks so the access_object has a certain dbref/id.

  • -
  • attr(attrname) - checks if a certain Attribute exists on accessing_object.

  • -
  • attr(attrname, value) - checks so an attribute exists on accessing_object and has the given -value.

  • -
  • attr_gt(attrname, value) - checks so accessing_object has a value larger (>) than the given -value.

  • -
  • attr_ge, attr_lt, attr_le, attr_ne - corresponding for >=, <, <= and !=.

  • -
  • holds(objid) - checks so the accessing objects contains an object of given name or dbref.

  • -
  • inside() - checks so the accessing object is inside the accessed object (the inverse of -holds()).

  • -
  • pperm(perm), pid(num)/pdbref(num) - same as perm, id/dbref but always looks for -permissions and dbrefs of Accounts, not on Characters.

  • -
  • serversetting(settingname, value) - Only returns True if Evennia has a given setting or a -setting set to a given value.

  • -
-
-
-
-

Checking simple strings

-

Sometimes you don’t really need to look up a certain lock, you just want to check a lockstring. A -common use is inside Commands, in order to check if a user has a certain permission. The lockhandler -has a method check_lockstring(accessing_obj, lockstring, bypass_superuser=False) that allows this.

-
     # inside command definition
-     if not self.caller.locks.check_lockstring(self.caller, "dummy:perm(Admin)"):
-         self.caller.msg("You must be an Admin or higher to do this!")
-         return
-
-
-

Note here that the access_type can be left to a dummy value since this method does not actually do -a Lock lookup.

-
-
-

Default locks

-

Evennia sets up a few basic locks on all new objects and accounts (if we didn’t, noone would have -any access to anything from the start). This is all defined in the root Typeclasses -of the respective entity, in the hook method basetype_setup() (which you usually don’t want to -edit unless you want to change how basic stuff like rooms and exits store their internal variables). -This is called once, before at_object_creation, so just put them in the latter method on your -child object to change the default. Also creation commands like create changes the locks of -objects you create - for example it sets the control lock_type so as to allow you, its creator, to -control and delete the object.

-
-
-
-

Permissions

-
-

This section covers the underlying code use of permissions. If you just want to learn how to -practically assign permissions in-game, refer to the Building Permissions -page, which details how you use the perm command.

-
-

A permission is simply a list of text strings stored in the handler permissions on Objects -and Accounts. Permissions can be used as a convenient way to structure access levels and -hierarchies. It is set by the perm command. Permissions are especially handled by the perm() and -pperm() lock functions listed above.

-

Let’s say we have a red_key object. We also have red chests that we want to unlock with this key.

-
perm red_key = unlocks_red_chests
-
-
-

This gives the red_key object the permission “unlocks_red_chests”. Next we lock our red chests:

-
lock red chest = unlock:perm(unlocks_red_chests)
-
-
-

What this lock will expect is to the fed the actual key object. The perm() lock function will -check the permissions set on the key and only return true if the permission is the one given.

-

Finally we need to actually check this lock somehow. Let’s say the chest has an command open <key> -sitting on itself. Somewhere in its code the command needs to figure out which key you are using and -test if this key has the correct permission:

-
    # self.obj is the chest
-    # and used_key is the key we used as argument to
-    # the command. The self.caller is the one trying
-    # to unlock the chest
-    if not self.obj.access(used_key, "unlock"):
-        self.caller.msg("The key does not fit!")
-        return
-
-
-

All new accounts are given a default set of permissions defined by -settings.PERMISSION_ACCOUNT_DEFAULT.

-

Selected permission strings can be organized in a permission hierarchy by editing the tuple -settings.PERMISSION_HIERARCHY. Evennia’s default permission hierarchy is as follows:

-
 Developer        # like superuser but affected by locks
- Admin            # can administrate accounts
- Builder          # can edit the world
- Helper           # can edit help files
- Player           # can chat and send tells (default level)
-
-
-

(Also the plural form works, so you could use Developers etc too).

-
-

There is also a Guest level below Player that is only active if settings.GUEST_ENABLED is -set. This is never part of settings.PERMISSION_HIERARCHY.

-
-

The main use of this is that if you use the lock function perm() mentioned above, a lock check for -a particular permission in the hierarchy will also grant access to those with higher hierarchy -access. So if you have the permission “Admin” you will also pass a lock defined as perm(Builder) -or any of those levels below “Admin”.

-

When doing an access check from an Object or Character, the perm() lock function will -always first use the permissions of any Account connected to that Object before checking for -permissions on the Object. In the case of hierarchical permissions (Admins, Builders etc), the -Account permission will always be used (this stops an Account from escalating their permission by -puppeting a high-level Character). If the permission looked for is not in the hierarchy, an exact -match is required, first on the Account and if not found there (or if no Account is connected), then -on the Object itself.

-

Here is how you use perm to give an account more permissions:

-
 perm/account Tommy = Builders
- perm/account/del Tommy = Builders # remove it again
-
-
-

Note the use of the /account switch. It means you assign the permission to the -Accounts Tommy instead of any Character that also happens to be named -“Tommy”.

-

Putting permissions on the Account guarantees that they are kept, regardless of which Character -they are currently puppeting. This is especially important to remember when assigning permissions -from the hierarchy tree - as mentioned above, an Account’s permissions will overrule that of its -character. So to be sure to avoid confusion you should generally put hierarchy permissions on the -Account, not on their Characters (but see also quelling).

-

Below is an example of an object without any connected account

-
    obj1.permissions = ["Builders", "cool_guy"]
-    obj2.locks.add("enter:perm_above(Accounts) and perm(cool_guy)")
-    
-    obj2.access(obj1, "enter") # this returns True!
-
-
-

And one example of a puppet with a connected account:

-
    account.permissions.add("Accounts")
-    puppet.permissions.add("Builders", "cool_guy")
-    obj2.locks.add("enter:perm_above(Accounts) and perm(cool_guy)")
-    
-    obj2.access(puppet, "enter") # this returns False!
-
-
-
-

Superusers

-

There is normally only one superuser account and that is the one first created when starting -Evennia (User #1). This is sometimes known as the “Owner” or “God” user. A superuser has more than -full access - it completely bypasses all locks so no checks are even run. This allows for the -superuser to always have access to everything in an emergency. But it also hides any eventual errors -you might have made in your lock definitions. So when trying out game systems you should either use -quelling (see below) or make a second Developer-level character so your locks get tested correctly.

-
-
-

Quelling

-

The quell command can be used to enforce the perm() lockfunc to ignore permissions on the -Account and instead use the permissions on the Character only. This can be used e.g. by staff to -test out things with a lower permission level. Return to the normal operation with unquell. Note -that quelling will use the smallest of any hierarchical permission on the Account or Character, so -one cannot escalate one’s Account permission by quelling to a high-permission Character. Also the -superuser can quell their powers this way, making them affectable by locks.

-
-
-

More Lock definition examples

-
examine: attr(eyesight, excellent) or perm(Builders)
-
-
-

You are only allowed to do examine on this object if you have ‘excellent’ eyesight (that is, has -an Attribute eyesight with the value excellent defined on yourself) or if you have the -“Builders” permission string assigned to you.

-
open: holds('the green key') or perm(Builder)
-
-
-

This could be called by the open command on a “door” object. The check is passed if you are a -Builder or has the right key in your inventory.

-
cmd: perm(Builders)
-
-
-

Evennia’s command handler looks for a lock of type cmd to determine if a user is allowed to even -call upon a particular command or not. When you define a command, this is the kind of lock you must -set. See the default command set for lots of examples. If a character/account don’t pass the cmd -lock type the command will not even appear in their help list.

-
cmd: not perm(no_tell)
-
-
-

“Permissions” can also be used to block users or implement highly specific bans. The above example -would be be added as a lock string to the tell command. This will allow everyone not having the -“permission” no_tell to use the tell command. You could easily give an account the “permission” -no_tell to disable their use of this particular command henceforth.

-
    dbref = caller.id
-    lockstring = "control:id(%s);examine:perm(Builders);delete:id(%s) or perm(Admin);get:all()" %
-(dbref, dbref)
-    new_obj.locks.add(lockstring)
-
-
-

This is how the create command sets up new objects. In sequence, this permission string sets the -owner of this object be the creator (the one running create). Builders may examine the object -whereas only Admins and the creator may delete it. Everyone can pick it up.

-
-
-

A complete example of setting locks on an object

-

Assume we have two objects - one is ourselves (not superuser) and the other is an Object -called box.

-
 > create/drop box
- > desc box = "This is a very big and heavy box."
-
-
-

We want to limit which objects can pick up this heavy box. Let’s say that to do that we require the -would-be lifter to to have an attribute strength on themselves, with a value greater than 50. We -assign it to ourselves to begin with.

-
 > set self/strength = 45
-
-
-

Ok, so for testing we made ourselves strong, but not strong enough. Now we need to look at what -happens when someone tries to pick up the the box - they use the get command (in the default set). -This is defined in evennia/commands/default/general.py. In its code we find this snippet:

-
    if not obj.access(caller, 'get'):
-        if obj.db.get_err_msg:
-            caller.msg(obj.db.get_err_msg)
-        else:
-            caller.msg("You can't get that.")
-        return
-
-
-

So the get command looks for a lock with the type get (not so surprising). It also looks for an -Attribute on the checked object called get_err_msg in order to return a customized -error message. Sounds good! Let’s start by setting that on the box:

-
 > set box/get_err_msg = You are not strong enough to lift this box.
-
-
-

Next we need to craft a Lock of type get on our box. We want it to only be passed if the accessing -object has the attribute strength of the right value. For this we would need to create a lock -function that checks if attributes have a value greater than a given value. Luckily there is already -such a one included in evennia (see evennia/locks/lockfuncs.py), called attr_gt.

-

So the lock string will look like this: get:attr_gt(strength, 50). We put this on the box now:

-
 lock box = get:attr_gt(strength, 50)
-
-
-

Try to get the object and you should get the message that we are not strong enough. Increase your -strength above 50 however and you’ll pick it up no problem. Done! A very heavy box!

-

If you wanted to set this up in python code, it would look something like this:

-
   
- from evennia import create_object
-    
-    # create, then set the lock
-    box = create_object(None, key="box")
-    box.locks.add("get:attr_gt(strength, 50)")
-    
-    # or we can assign locks in one go right away
-    box = create_object(None, key="box", locks="get:attr_gt(strength, 50)")
-    
-    # set the attributes
-    box.db.desc = "This is a very big and heavy box."
-    box.db.get_err_msg = "You are not strong enough to lift this box."
-    
-    # one heavy box, ready to withstand all but the strongest...
-
-
-
-
-

On Django’s permission system

-

Django also implements a comprehensive permission/security system of its own. The reason we don’t -use that is because it is app-centric (app in the Django sense). Its permission strings are of the -form appname.permstring and it automatically adds three of them for each database model in the app

-
    -
  • for the app evennia/object this would be for example ‘object.create’, ‘object.admin’ and -‘object.edit’. This makes a lot of sense for a web application, not so much for a MUD, especially -when we try to hide away as much of the underlying architecture as possible.

  • -
-

The django permissions are not completely gone however. We use it for validating passwords during -login. It is also used exclusively for managing Evennia’s web-based admin site, which is a graphical -front-end for the database of Evennia. You edit and assign such permissions directly from the web -interface. It’s stand-alone from the permissions described above.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Manually-Configuring-Color.html b/docs/0.9.5/Manually-Configuring-Color.html deleted file mode 100644 index 2aac920e32..0000000000 --- a/docs/0.9.5/Manually-Configuring-Color.html +++ /dev/null @@ -1,275 +0,0 @@ - - - - - - - - - Manually Configuring Color — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Manually Configuring Color

-

This is a small tutorial for customizing your character objects, using the example of letting users -turn on and off ANSI color parsing as an example. @options NOCOLOR=True will now do what this -tutorial shows, but the tutorial subject can be applied to other toggles you may want, as well.

-

In the Building guide’s Colors page you can learn how to add color to your -game by using special markup. Colors enhance the gaming experience, but not all users want color. -Examples would be users working from clients that don’t support color, or people with various seeing -disabilities that rely on screen readers to play your game. Also, whereas Evennia normally -automatically detects if a client supports color, it may get it wrong. Being able to turn it on -manually if you know it should work could be a nice feature.

-

So here’s how to allow those users to remove color. It basically means you implementing a simple -configuration system for your characters. This is the basic sequence:

-
    -
  1. Define your own default character typeclass, inheriting from Evennia’s default.

  2. -
  3. Set an attribute on the character to control markup on/off.

  4. -
  5. Set your custom character class to be the default for new accounts.

  6. -
  7. Overload the msg() method on the typeclass and change how it uses markup.

  8. -
  9. Create a custom command to allow users to change their setting.

  10. -
-
-

Setting up a custom Typeclass

-

Create a new module in mygame/typeclasses named, for example, mycharacter.py. Alternatively you -can simply add a new class to ‘mygamegame/typeclasses/characters.py’.

-

In your new module(or characters.py), create a new Typeclass inheriting from -evennia.DefaultCharacter. We will also import evennia.utils.ansi, which we will use later.

-
    from evennia import Character
-    from evennia.utils import ansi
-
-    class ColorableCharacter(Character):
-        at_object_creation(self):
-            # set a color config value
-            self.db.config_color = True
-
-
-

Above we set a simple config value as an Attribute.

-

Let’s make sure that new characters are created of this type. Edit your -mygame/server/conf/settings.py file and add/change BASE_CHARACTER_TYPECLASS to point to your new -character class. Observe that this will only affect new characters, not those already created. You -have to convert already created characters to the new typeclass by using the @typeclass command -(try on a secondary character first though, to test that everything works - you don’t want to render -your root user unusable!).

-
 @typeclass/reset/force Bob = mycharacter.ColorableCharacter
-
-
-

@typeclass changes Bob’s typeclass and runs all its creation hooks all over again. The /reset -switch clears all attributes and properties back to the default for the new typeclass - this is -useful in this case to avoid ending up with an object having a “mixture” of properties from the old -typeclass and the new one. /force might be needed if you edit the typeclass and want to update the -object despite the actual typeclass name not having changed.

-
-
-

Overload the msg() method

-

Next we need to overload the msg() method. What we want is to check the configuration value before -calling the main function. The original msg method call is seen in evennia/objects/objects.py -and is called like this:

-
    msg(self, text=None, from_obj=None, session=None, options=None, **kwargs):
-
-
-

As long as we define a method on our custom object with the same name and keep the same number of -arguments/keywords we will overload the original. Here’s how it could look:

-
    class ColorableCharacter(Character):
-        # [...]
-        msg(self, text=None, from_obj=None, session=None, options=None,
-            **kwargs):
-            "our custom msg()"
-            if self.db.config_color is not None: # this would mean it was not set
-                if not self.db.config_color:
-                    # remove the ANSI from the text
-                    text = ansi.strip_ansi(text)
-            super().msg(text=text, from_obj=from_obj,
-                                               session=session, **kwargs)
-
-
-

Above we create a custom version of the msg() method. If the configuration Attribute is set, it -strips the ANSI from the text it is about to send, and then calls the parent msg() as usual. You -need to @reload before your changes become visible.

-

There we go! Just flip the attribute config_color to False and your users will not see any color. -As superuser (assuming you use the Typeclass ColorableCharacter) you can test this with the @py -command:

-
 @py self.db.config_color = False
-
-
-
-
-

Custom color config command

-

For completeness, let’s add a custom command so users can turn off their color display themselves if -they want.

-

In mygame/commands, create a new file, call it for example configcmds.py (it’s likely that -you’ll want to add other commands for configuration down the line). You can also copy/rename the -command template.

-
    from evennia import Command
-
-    class CmdConfigColor(Command):
-        """
-        Configures your color
-
-        Usage:
-          @togglecolor on|off
-
-        This turns ANSI-colors on/off.
-        Default is on.
-        """
-
-        key = "@togglecolor"
-        aliases = ["@setcolor"]
-
-        def func(self):
-            "implements the command"
-            # first we must remove whitespace from the argument
-            self.args = self.args.strip()
-            if not self.args or not self.args in ("on", "off"):
-                self.caller.msg("Usage: @setcolor on|off")
-                return
-            if self.args == "on":
-                self.caller.db.config_color = True
-                # send a message with a tiny bit of formatting, just for fun
-                self.caller.msg("Color was turned |won|W.")
-            else:
-                self.caller.db.config_color = False
-                self.caller.msg("Color was turned off.")
-
-
-

Lastly, we make this command available to the user by adding it to the default CharacterCmdSet in -mygame/commands/default_cmdsets.py and reloading the server. Make sure you also import the -command:

-
from mygame.commands import configcmds
-class CharacterCmdSet(default_cmds.CharacterCmdSet):
-    # [...]
-    def at_cmdset_creation(self):
-        """
-        Populates the cmdset
-        """
-        super().at_cmdset_creation()
-        #
-        # any commands you add below will overload the default ones.
-        #
-
-        # here is the only line that we edit
-        self.add(configcmds.CmdConfigColor())
-
-
-
-
-

More colors

-

Apart from ANSI colors, Evennia also supports Xterm256 colors (See [Colors](./TextTags.md#colored- -text)). The msg() method supports the xterm256 keyword for manually activating/deactiving -xterm256. It should be easy to expand the above example to allow players to customize xterm256 -regardless of if Evennia thinks their client supports it or not.

-

To get a better understanding of how msg() works with keywords, you can try this as superuser:

-
@py self.msg("|123Dark blue with xterm256, bright blue with ANSI", xterm256=True)
-@py self.msg("|gThis should be uncolored", nomarkup=True)
-
-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Mass-and-weight-for-objects.html b/docs/0.9.5/Mass-and-weight-for-objects.html deleted file mode 100644 index 64e0c89765..0000000000 --- a/docs/0.9.5/Mass-and-weight-for-objects.html +++ /dev/null @@ -1,204 +0,0 @@ - - - - - - - - - Mass and weight for objects — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Mass and weight for objects

-

An easy addition to add dynamic variety to your world objects is to give them some mass. Why mass -and not weight? Weight varies in setting; for example things on the Moon weigh 1/6 as much. On -Earth’s surface and in most environments, no relative weight factor is needed.

-

In most settings, mass can be used as weight to spring a pressure plate trap or a floor giving way, -determine a character’s burden weight for travel speed… The total mass of an object can -contribute to the force of a weapon swing, or a speeding meteor to give it a potential striking -force.

-
-

Objects

-

Now that we have reasons for keeping track of object mass, let’s look at the default object class -inside your mygame/typeclasses/objects.py and see how easy it is to total up mass from an object and -its contents.

-
# inside your mygame/typeclasses/objects.py
-
-class Object(DefaultObject):
-# [...]
-    def get_mass(self):
-        mass = self.attributes.get('mass', 1) # Default objects have 1 unit mass.
-        return mass + sum(obj.get_mass() for obj in self.contents)
-
-
-

Adding the get_mass definition to the objects you want to sum up the masses for is done with -Python’s “sum” function which operates on all the contents, in this case by summing them to -return a total mass value.

-

If you only wanted specific object types to have mass or have the new object type in a different -module, see [[Adding-Object-Typeclass-Tutorial]] with its Heavy class object. You could set the -default for Heavy types to something much larger than 1 gram or whatever unit you want to use. Any -non-default mass would be stored on the mass [[Attributes]] of the objects.

-
-
-

Characters and rooms

-

You can add a get_mass definition to characters and rooms, also.

-

If you were in a one metric-ton elevator with four other friends also wearing armor and carrying -gold bricks, you might wonder if this elevator’s going to move, and how fast.

-

Assuming the unit is grams and the elevator itself weights 1,000 kilograms, it would already be -@set elevator/mass=1000000, we’re @set me/mass=85000 and our armor is @set armor/mass=50000. -We’re each carrying 20 gold bars each @set gold bar/mass=12400 then step into the elevator and see -the following message in the elevator’s appearance: Elevator weight and contents should not exceed 3 metric tons. Are we safe? Maybe not if you consider dynamic loading. But at rest:

-
# Elevator object knows when it checks itself:
-if self.get_mass() < 3000000:
-    pass  # Elevator functions as normal.
-else:
-    pass  # Danger! Alarm sounds, cable snaps, elevator stops...
-
-
-
-
-

Inventory

-

Example of listing mass of items in your inventory, don’t forget to add it to your -default_cmdsets.py file:

-
from evennia import utils
-
-class CmdInventory(Command):
-    """
-    view inventory
-    Usage:
-      inventory
-      inv
-    Switches:
-      /weight to display all available channels.
-    Shows your inventory: carrying, wielding, wearing, obscuring.
-    """
-
-    key = "inventory"
-    aliases = ["inv", "i"]
-    locks = "cmd:all()"
-
-    def func(self):
-        "check inventory"
-        items = self.caller.contents
-        if not items:
-            string = "You are not carrying anything."
-        else:
-            table = utils.evtable.EvTable("name", "weight")
-            for item in items:
-                mass = item.get_mass()
-                table.add_row(item.name, mass)
-            string = f"|wYou are carrying:|n\n{table}"
-        self.caller.msg(string)
-
-
-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Messagepath.html b/docs/0.9.5/Messagepath.html deleted file mode 100644 index 082018d518..0000000000 --- a/docs/0.9.5/Messagepath.html +++ /dev/null @@ -1,402 +0,0 @@ - - - - - - - - - Messagepath — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Messagepath

-

The main functionality of Evennia is to communicate with clients connected to it; a player enters -commands or their client queries for a gui update (ingoing data). The server responds or sends data -on its own as the game changes (outgoing data). It’s important to understand how this flow of -information works in Evennia.

-
-

The ingoing message path

-

We’ll start by tracing data from the client to the server. Here it is in short:

-
Client ->
- PortalSession ->
-  PortalSessionhandler ->
-   (AMP) ->
-    ServerSessionHandler ->
-      ServerSession ->
-        Inputfunc
-
-
-
-

Client (ingoing)

-

The client sends data to Evennia in two ways.

-
    -
  • When first connecting, the client can send data to the server about its -capabilities. This is things like “I support xterm256 but not unicode” and is -mainly used when a Telnet client connects. This is called a “handshake” and -will generally set some flags on the Portal Session that -are later synced to the Server Session. Since this is not something the player -controls, we’ll not explore this further here.

  • -
  • The client can send an inputcommand to the server. Traditionally this only -happens when the player enters text on the command line. But with a custom -client GUI, a command could also come from the pressing of a button. Finally -the client may send commands based on a timer or some trigger.

  • -
-

Exactly how the inputcommand looks when it travels from the client to Evennia -depends on the Protocol used:

-
    -
  • Telnet: A string. If GMCP or MSDP OOB protocols are used, this string will -be formatted in a special way, but it’s still a raw string. If Telnet SSL is -active, the string will be encrypted.

  • -
  • SSH: An encrypted string

  • -
  • Webclient: A JSON-serialized string.

  • -
-
-
-

Portal Session (ingoing)

-

Each client is connected to the game via a Portal Session, one per connection. This Session is -different depending on the type of connection (telnet, webclient etc) and thus know how to handle -that particular data type. So regardless of how the data arrives, the Session will identify the type -of the instruction and any arguments it should have. For example, the telnet protocol will figure -that anything arriving normally over the wire should be passed on as a “text” type.

-
-
-

PortalSessionHandler (ingoing)

-

The PortalSessionhandler manages all connected Sessions in the Portal. Its data_in method -(called by each Portal Session) will parse the command names and arguments from the protocols and -convert them to a standardized form we call the inputcommand:

-
    (commandname, (args), {kwargs})
-
-
-

All inputcommands must have a name, but they may or may not have arguments and keyword arguments - -in fact no default inputcommands use kwargs at all. The most common inputcommand is “text”, which -has the argument the player input on the command line:

-
    ("text", ("look",), {})
-
-
-

This inputcommand-structure is pickled together with the unique session-id of the Session to which -it belongs. This is then sent over the AMP connection.

-
-
-

ServerSessionHandler (ingoing)

-

On the Server side, the AMP unpickles the data and associates the session id with the server-side -Session. Data and Session are passed to the server-side SessionHandler.data_in. This -in turn calls ServerSession.data_in()

-
-
-

ServerSession (ingoing)

-

The method ServerSession.data_in is meant to offer a single place to override if they want to -examine all data passing into the server from the client. It is meant to call the -ssessionhandler.call_inputfuncs with the (potentially processed) data (so this is technically a -sort of detour back to the sessionhandler).

-

In call_inputfuncs, the inputcommand’s name is compared against the names of all the inputfuncs -registered with the server. The inputfuncs are named the same as the inputcommand they are supposed -to handle, so the (default) inputfunc for handling our “look” command is called “text”. These are -just normal functions and one can plugin new ones by simply putting them in a module where Evennia -looks for such functions.

-

If a matching inputfunc is found, it will be called with the Session and the inputcommand’s -arguments:

-
    text(session, *("look",), **{})
-
-
-

If no matching inputfunc is found, an inputfunc named “default” will be tried and if that is also -not found, an error will be raised.

-
-
-

Inputfunc

-

The Inputfunc must be on the form func(session, *args, **kwargs). An exception is -the default inputfunc which has form default(session, cmdname, *args, **kwargs), where cmdname -is the un-matched inputcommand string.

-

This is where the message’s path diverges, since just what happens next depends on the type of -inputfunc was triggered. In the example of sending “look”, the inputfunc is named “text”. It will -pass the argument to the cmdhandler which will eventually lead to the look command being -executed.

-
-
-
-

The outgoing message path

-

Next let’s trace the passage from server to client.

-
msg ->
- ServerSession ->
-  ServerSessionHandler ->
-   (AMP) ->
-    PortalSessionHandler ->
-     PortalSession ->
-      Client
-
-
-
-

msg

-

All outgoing messages start in the msg method. This is accessible from three places:

-
    -
  • Object.msg

  • -
  • Account.msg

  • -
  • Session.msg

  • -
-

The call sign of the msg method looks like this:

-
    msg(text=None, from_obj=None, session=None, options=None, **kwargs)
-
-
-

For our purposes, what is important to know is that with the exception of from_obj, session and -options, all keywords given to the msg method is the name of an outputcommand and its -arguments. So text is actually such a command, taking a string as its argument. The reason text -sits as the first keyword argument is that it’s so commonly used (caller.msg("Text") for example). -Here are some examples

-
    msg("Hello!")   # using the 'text' outputfunc
-    msg(prompt="HP:%i, SP: %i, MP: %i" % (HP, SP, MP))
-    msg(mycommand=((1,2,3,4), {"foo": "bar"})
-
-
-
-

Note the form of the mycommand outputfunction. This explicitly defines the arguments and keyword -arguments for the function. In the case of the text and prompt calls we just specify a string - -this works too: The system will convert this into a single argument for us later in the message -path.

-
-

Note: The msg method sits on your Object- and Account typeclasses. It means you can easily -override msg and make custom- or per-object modifications to the flow of data as it passes -through.

-
-
-
-

ServerSession (outgoing)

-

Nothing is processed on the Session, it just serves as a gathering points for all different msg. -It immediately passes the data on to …

-
-
-

ServerSessionHandler (outgoing)

-

In the ServerSessionhandler, the keywords from the msg method are collated into one or more -outputcommands on a standardized form (identical to inputcommands):

-
    (commandname, (args), {kwargs})
-
-
-

This will intelligently convert different input to the same form. So msg("Hello") will end up as -an outputcommand ("text", ("Hello",), {}).

-

This is also the point where Inlinefuncs are parsed, depending on the -session to receive the data. Said data is pickled together with the Session id then sent over the -AMP bridge.

-
-
-

PortalSessionHandler (outgoing)

-

After the AMP connection has unpickled the data and paired the session id to the matching -PortalSession, the handler next determines if this Session has a suitable method for handling the -outputcommand.

-

The situation is analogous to how inputfuncs work, except that protocols are fixed things that don’t -need a plugin infrastructure like the inputfuncs are handled. So instead of an “outputfunc”, the -handler looks for methods on the PortalSession with names of the form send_<commandname>.

-

For example, the common sending of text expects a PortalSession method send_text. This will be -called as send_text(*("Hello",), **{}). If the “prompt” outputfunction was used, send_prompt is -called. In all other cases the send_default(cmdname, *args, **kwargs) will be called - this is the -case for all client-custom outputcommands, like when wanting to tell the client to update a graphic -or play a sound.

-
-
-

PortalSession (outgoing)

-

At this point it is up to the session to convert the command into a form understood by this -particular protocol. For telnet, send_text will just send the argument as a string (since that is -what telnet clients expect when “text” is coming). If send_default was called (basically -everything that is not traditional text or a prompt), it will pack the data as an GMCP or MSDP -command packet if the telnet client supports either (otherwise it won’t send at all). If sending to -the webclient, the data will get packed into a JSON structure at all times.

-
-
-

Client (outgoing)

-

Once arrived at the client, the outputcommand is handled in the way supported by the client (or it -may be quietly ignored if not). “text” commands will be displayed in the main window while others -may trigger changes in the GUI or play a sound etc.

-
-
-

Full example of Outgoing Message

-

For a full outgoing message, you need to have the outgoing function defined in the javascript. See -https://evennia.readthedocs.io/en/latest/Web-Client-Webclient.html for getting set up with custom -webclient code. Once you have a custom plugin defined and loaded, create a new function in the -plugin, onCustomFunc() for example:

-
    var onCustomFunc = function(args, kwargs) {
-        var = args.var
-        console.log(var)
-    }
-
-
-

You’ll also need to add the function to what the main plugin function returns:

-
    return {
-        init: init,
-        onCustomFunc,
-    }
-
-
-

This defines the function and looks for “var” as a variable that is passed to it. Once you have this -in place in your custom plugin, you also need to update the static/webclient/js/webclient_gui.js -file to recognize the new function when it’s called. First you should add a new function inside the -plugin_handler function to recognize the new function:

-
    var onCustomFunc = function (cmdname, args, kwargs) {
-        for( let n=0; n < ordered_plugins.length; n++ ) {
-            let plugin = ordered_plugins[n];
-            if( 'onCustomFunc' in plugin ) {
-                if( plugin.onCustomFunc(args, kwargs) ) {
-                    // True -- means this plugin claims this command exclusively.
-                    return;
-                }
-            }
-        }
-    }
-
-
-

This looks through all the plugins for a function that corresponds to the custom function being -called. Next, add the custom function to the return statement of the plugin handler:

-
    return {
-        add: add,
-        onKeydown: onKeydown,
-        onBeforeUnload: onBeforeUnload,
-        onLoggedIn: onLoggedIn,
-        onText: onText,
-        onGotOptions: onGotOptions,
-        onPrompt: onPrompt,
-        onDefault: onDefault,
-        onSilence: onSilence,
-        onConnectionClose: onConnectionClose,
-        onSend: onSend,
-        init: init,
-        postInit: postInit,
-        onCustomFunc: onCustomFunc,
-    }
-
-
-

Lastly, you will also need to need to add an entry to the Evennia emitter to tie the python function -call to this new javascript function (this is in the $(document).ready function):

-
    Evennia.emitter.on("customFunc", plugin_handler.onCustomFunc);
-
-
-

Now you can make a call from your python code to the new custom function to pass information from -the server to the client:

-
    character.msg(customFunc=({"var": "blarg"}))
-
-
-

When this code in your python is run, you should be able to see the “blarg” string printed in the -web client console. You should now be able to update the function call and definition to pass any -information needed between server and client.

-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/MonitorHandler.html b/docs/0.9.5/MonitorHandler.html deleted file mode 100644 index 848a1663f1..0000000000 --- a/docs/0.9.5/MonitorHandler.html +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - MonitorHandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

MonitorHandler

-

The MonitorHandler is a system for watching changes in properties or Attributes on objects. A -monitor can be thought of as a sort of trigger that responds to change.

-

The main use for the MonitorHandler is to report changes to the client; for example the client -Session may ask Evennia to monitor the value of the Characer’s health attribute and report -whenever it changes. This way the client could for example update its health bar graphic as needed.

-
-

Using the MonitorHandler

-

The MontorHandler is accessed from the singleton evennia.MONITOR_HANDLER. The code for the handler -is in evennia.scripts.monitorhandler.

-

Here’s how to add a new monitor:

-
from evennia import MONITOR_HANDLER
-
-MONITOR_HANDLER.add(obj, fieldname, callback,
-                    idstring="", persistent=False, **kwargs)
-
-
-
-
    -
  • obj (Typeclassed entity) - the object to monitor. Since this must be -typeclassed, it means you can’t monitor changes on Sessions with the monitorhandler, for -example.

  • -
  • fieldname (str) - the name of a field or Attribute on obj. If you want to -monitor a database field you must specify its full name, including the starting db_ (like -db_key, db_location etc). Any names not starting with db_ are instead assumed to be the names -of Attributes. This difference matters, since the MonitorHandler will automatically know to watch -the db_value field of the Attribute.

  • -
  • callback(callable) - This will be called as callback(fieldname=fieldname, obj=obj, **kwargs) -when the field updates.

  • -
  • idstring (str) - this is used to separate multiple monitors on the same object and fieldname. -This is required in order to properly identify and remove the monitor later. It’s also used for -saving it.

  • -
  • persistent (bool) - if True, the monitor will survive a server reboot.

  • -
-

Example:

-
from evennia import MONITOR_HANDLER as monitorhandler
-
-def _monitor_callback(fieldname="", obj=None, **kwargs):
-    # reporting callback that works both
-    # for db-fields and Attributes
-    if fieldname.startswith("db_"):
-        new_value = getattr(obj, fieldname)
-    else: # an attribute
-        new_value = obj.attributes.get(fieldname)
-
-    obj.msg("%s.%s changed to '%s'." % \
-                  (obj.key, fieldname, new_value))
-
-# (we could add _some_other_monitor_callback here too)
-
-# monitor Attribute (assume we have obj from before)
-monitorhandler.add(obj, "desc", _monitor_callback)
-
-# monitor same db-field with two different callbacks (must separate by id_string)
-monitorhandler.add(obj, "db_key", _monitor_callback, id_string="foo")
-monitorhandler.add(obj, "db_key", _some_other_monitor_callback, id_string="bar")
-
-
-
-

A monitor is uniquely identified by the combination of the object instance it is monitoring, the -name of the field/attribute to monitor on that object and its idstring (obj + fieldname + -idstring). The idstring will be the empty string unless given explicitly.

-

So to “un-monitor” the above you need to supply enough information for the system to uniquely find -the monitor to remove:

-
monitorhandler.remove(obj, "desc")
-monitorhandler.remove(obj, "db_key", idstring="foo")
-monitorhandler.remove(obj, "db_key", idstring="bar")
-
-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/NPC-shop-Tutorial.html b/docs/0.9.5/NPC-shop-Tutorial.html deleted file mode 100644 index e928630e66..0000000000 --- a/docs/0.9.5/NPC-shop-Tutorial.html +++ /dev/null @@ -1,441 +0,0 @@ - - - - - - - - - NPC shop Tutorial — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

NPC shop Tutorial

-

This tutorial will describe how to make an NPC-run shop. We will make use of the EvMenu -system to present shoppers with a menu where they can buy things from the store’s stock.

-

Our shop extends over two rooms - a “front” room open to the shop’s customers and a locked “store -room” holding the wares the shop should be able to sell. We aim for the following features:

-
    -
  • The front room should have an Attribute storeroom that points to the store room.

  • -
  • Inside the front room, the customer should have a command buy or browse. This will open a -menu listing all items available to buy from the store room.

  • -
  • A customer should be able to look at individual items before buying.

  • -
  • We use “gold” as an example currency. To determine cost, the system will look for an Attribute -gold_value on the items in the store room. If not found, a fixed base value of 1 will be assumed. -The wealth of the customer should be set as an Attribute gold on the Character. If not set, they -have no gold and can’t buy anything.

  • -
  • When the customer makes a purchase, the system will check the gold_value of the goods and -compare it to the gold Attribute of the customer. If enough gold is available, this will be -deducted and the goods transferred from the store room to the inventory of the customer.

  • -
  • We will lock the store room so that only people with the right key can get in there.

  • -
-
-

The shop menu

-

We want to show a menu to the customer where they can list, examine and buy items in the store. This -menu should change depending on what is currently for sale. Evennia’s EvMenu utility will manage -the menu for us. It’s a good idea to read up on EvMenu if you are not familiar with it.

-
-

Designing the menu

-

The shopping menu’s design is straightforward. First we want the main screen. You get this when you -enter a shop and use the browse or buy command:

-
*** Welcome to ye Old Sword shop! ***
-   Things for sale (choose 1-3 to inspect, quit to exit):
-_________________________________________________________
-1. A rusty sword (5 gold)
-2. A sword with a leather handle (10 gold)
-3. Excalibur (100 gold)
-
-
-

There are only three items to buy in this example but the menu should expand to however many items -are needed. When you make a selection you will get a new screen showing the options for that -particular item:

-
You inspect A rusty sword:
-
-This is an old weapon maybe once used by soldiers in some
-long forgotten army. It is rusty and in bad condition.
-__________________________________________________________
-1. Buy A rusty sword (5 gold)
-2. Look for something else.
-
-
-

Finally, when you buy something, a brief message should pop up:

-
You pay 5 gold and purchase A rusty sword!
-
-
-

or

-
You cannot afford 5 gold for A rusty sword!
-
-
-

After this you should be back to the top level of the shopping menu again and can continue browsing.

-
-
-

Coding the menu

-

EvMenu defines the nodes (each menu screen with options) as normal Python functions. Each node -must be able to change on the fly depending on what items are currently for sale. EvMenu will -automatically make the quit command available to us so we won’t add that manually. For compactness -we will put everything needed for our shop in one module, mygame/typeclasses/npcshop.py.

-
# mygame/typeclasses/npcshop.py
-
-from evennia.utils import evmenu
-
-def menunode_shopfront(caller):
-    "This is the top-menu screen."
-
-    shopname = caller.location.key
-    wares = caller.location.db.storeroom.contents
-
-    # Wares includes all items inside the storeroom, including the
-    # door! Let's remove that from our for sale list.
-    wares = [ware for ware in wares if ware.key.lower() != "door"]
-
-    text = "*** Welcome to %s! ***\n" % shopname
-    if wares:
-        text += "   Things for sale (choose 1-%i to inspect);" \
-                " quit to exit:" % len(wares)
-    else:
-        text += "   There is nothing for sale; quit to exit."
-
-    options = []
-    for ware in wares:
-        # add an option for every ware in store
-        options.append({"desc": "%s (%s gold)" %
-                             (ware.key, ware.db.gold_value or 1),
-                        "goto": "menunode_inspect_and_buy"})
-    return text, options
-
-
-

In this code we assume the caller to be inside the shop when accessing the menu. This means we can -access the shop room via caller.location and get its key to display as the shop’s name. We also -assume the shop has an Attribute storeroom we can use to get to our stock. We loop over our goods -to build up the menu’s options.

-

Note that all options point to the same menu node called menunode_inspect_and_buy! We can’t know -which goods will be available to sale so we rely on this node to modify itself depending on the -circumstances. Let’s create it now.

-
# further down in mygame/typeclasses/npcshop.py
-
-def menunode_inspect_and_buy(caller, raw_string):
-    "Sets up the buy menu screen."
-
-    wares = caller.location.db.storeroom.contents
-    # Don't forget, we will need to remove that pesky door again!
-    wares = [ware for ware in wares if ware.key.lower() != "door"]
-    iware = int(raw_string) - 1
-    ware = wares[iware]
-    value = ware.db.gold_value or 1
-    wealth = caller.db.gold or 0
-    text = "You inspect %s:\n\n%s" % (ware.key, ware.db.desc)
-
-    def buy_ware_result(caller):
-        "This will be executed first when choosing to buy."
-        if wealth >= value:
-            rtext = "You pay %i gold and purchase %s!" % \
-                         (value, ware.key)
-            caller.db.gold -= value
-            ware.move_to(caller, quiet=True)
-        else:
-            rtext = "You cannot afford %i gold for %s!" % \
-                          (value, ware.key)
-        caller.msg(rtext)
-
-    options = ({"desc": "Buy %s for %s gold" % \
-                        (ware.key, ware.db.gold_value or 1),
-                "goto": "menunode_shopfront",
-                "exec": buy_ware_result},
-               {"desc": "Look for something else",
-                "goto": "menunode_shopfront"})
-
-    return text, options
-
-
-

In this menu node we make use of the raw_string argument to the node. This is the text the menu -user entered on the previous node to get here. Since we only allow numbered options in our menu, -raw_input must be an number for the player to get to this point. So we convert it to an integer -index (menu lists start from 1, whereas Python indices always starts at 0, so we need to subtract -1). We then use the index to get the corresponding item from storage.

-

We just show the customer the desc of the item. In a more elaborate setup you might want to show -things like weapon damage and special stats here as well.

-

When the user choose the “buy” option, EvMenu will execute the exec instruction before we go -back to the top node (the goto instruction). For this we make a little inline function -buy_ware_result. EvMenu will call the function given to exec like any menu node but it does not -need to return anything. In buy_ware_result we determine if the customer can afford the cost and -give proper return messages. This is also where we actually move the bought item into the inventory -of the customer.

-
-
-

The command to start the menu

-

We could in principle launch the shopping menu the moment a customer steps into our shop room, but -this would probably be considered pretty annoying. It’s better to create a Command for -customers to explicitly wanting to shop around.

-
# mygame/typeclasses/npcshop.py
-
-from evennia import Command
-
-class CmdBuy(Command):
-    """
-    Start to do some shopping
-
-    Usage:
-      buy
-      shop
-      browse
-
-    This will allow you to browse the wares of the
-    current shop and buy items you want.
-    """
-    key = "buy"
-    aliases = ("shop", "browse")
-
-    def func(self):
-        "Starts the shop EvMenu instance"
-        evmenu.EvMenu(self.caller,
-                      "typeclasses.npcshop",
-                      startnode="menunode_shopfront")
-
-
-

This will launch the menu. The EvMenu instance is initialized with the path to this very module - -since the only global functions available in this module are our menu nodes, this will work fine -(you could also have put those in a separate module). We now just need to put this command in a -CmdSet so we can add it correctly to the game:

-
from evennia import CmdSet
-
-class ShopCmdSet(CmdSet):
-    def at_cmdset_creation(self):
-        self.add(CmdBuy())
-
-
-
-
-
-

Building the shop

-

There are really only two things that separate our shop from any other Room:

-
    -
  • The shop has the storeroom Attribute set on it, pointing to a second (completely normal) room.

  • -
  • It has the ShopCmdSet stored on itself. This makes the buy command available to users entering -the shop.

  • -
-

For testing we could easily add these features manually to a room using @py or other admin -commands. Just to show how it can be done we’ll instead make a custom Typeclass for -the shop room and make a small command that builders can use to build both the shop and the -storeroom at once.

-
# bottom of mygame/typeclasses/npcshop.py
-
-from evennia import DefaultRoom, DefaultExit, DefaultObject
-from evennia.utils.create import create_object
-
-# class for our front shop room
-class NPCShop(DefaultRoom):
-    def at_object_creation(self):
-        # we could also use add(ShopCmdSet, permanent=True)
-        self.cmdset.add_default(ShopCmdSet)
-        self.db.storeroom = None
-
-# command to build a complete shop (the Command base class
-# should already have been imported earlier in this file)
-class CmdBuildShop(Command):
-    """
-    Build a new shop
-
-    Usage:
-        @buildshop shopname
-
-    This will create a new NPCshop room
-    as well as a linked store room (named
-    simply <storename>-storage) for the
-    wares on sale. The store room will be
-    accessed through a locked door in
-    the shop.
-    """
-    key = "@buildshop"
-    locks = "cmd:perm(Builders)"
-    help_category = "Builders"
-
-    def func(self):
-        "Create the shop rooms"
-        if not self.args:
-            self.msg("Usage: @buildshop <storename>")
-            return
-        # create the shop and storeroom
-        shopname = self.args.strip()
-        shop = create_object(NPCShop,
-                             key=shopname,
-                             location=None)
-        storeroom = create_object(DefaultRoom,
-                             key="%s-storage" % shopname,
-                             location=None)
-        shop.db.storeroom = storeroom
-        # create a door between the two
-        shop_exit = create_object(DefaultExit,
-                                  key="back door",
-                                  aliases=["storage", "store room"],
-                                  location=shop,
-                                  destination=storeroom)
-        storeroom_exit = create_object(DefaultExit,
-                                  key="door",
-                                  location=storeroom,
-                                  destination=shop)
-        # make a key for accessing the store room
-        storeroom_key_name = "%s-storekey" % shopname
-        storeroom_key = create_object(DefaultObject,
-                                       key=storeroom_key_name,
-                                       location=shop)
-        # only allow chars with this key to enter the store room
-        shop_exit.locks.add("traverse:holds(%s)" % storeroom_key_name)
-
-        # inform the builder about progress
-        self.caller.msg("The shop %s was created!" % shop)
-
-
-

Our typeclass is simple and so is our buildshop command. The command (which is for Builders only) -just takes the name of the shop and builds the front room and a store room to go with it (always -named "<shopname>-storage". It connects the rooms with a two-way exit. You need to add -CmdBuildShop [to the default cmdset](./Adding-Command-Tutorial.md#step-2-adding-the-command-to-a- -default-cmdset) before you can use it. Once having created the shop you can now @teleport to it or -@open a new exit to it. You could also easily expand the above command to automatically create -exits to and from the new shop from your current location.

-

To avoid customers walking in and stealing everything, we create a Lock on the storage -door. It’s a simple lock that requires the one entering to carry an object named -<shopname>-storekey. We even create such a key object and drop it in the shop for the new shop -keeper to pick up.

-
-

If players are given the right to name their own objects, this simple lock is not very secure and -you need to come up with a more robust lock-key solution.

-
-
-

We don’t add any descriptions to all these objects so looking “at” them will not be too thrilling. -You could add better default descriptions as part of the @buildshop command or leave descriptions -this up to the Builder.

-
-
-
-

The shop is open for business!

-

We now have a functioning shop and an easy way for Builders to create it. All you need now is to -@open a new exit from the rest of the game into the shop and put some sell-able items in the store -room. Our shop does have some shortcomings:

-
    -
  • For Characters to be able to buy stuff they need to also have the gold Attribute set on -themselves.

  • -
  • We manually remove the “door” exit from our items for sale. But what if there are other unsellable -items in the store room? What if the shop owner walks in there for example - anyone in the store -could then buy them for 1 gold.

  • -
  • What if someone else were to buy the item we’re looking at just before we decide to buy it? It -would then be gone and the counter be wrong - the shop would pass us the next item in the list.

  • -
-

Fixing these issues are left as an exercise.

-

If you want to keep the shop fully NPC-run you could add a Script to restock the shop’s -store room regularly. This shop example could also easily be owned by a human Player (run for them -by a hired NPC) - the shop owner would get the key to the store room and be responsible for keeping -it well stocked.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/New-Models.html b/docs/0.9.5/New-Models.html deleted file mode 100644 index 5539d6973f..0000000000 --- a/docs/0.9.5/New-Models.html +++ /dev/null @@ -1,362 +0,0 @@ - - - - - - - - - New Models — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

New Models

-

Note: This is considered an advanced topic.

-

Evennia offers many convenient ways to store object data, such as via Attributes or Scripts. This is -sufficient for most use cases. But if you aim to build a large stand-alone system, trying to squeeze -your storage requirements into those may be more complex than you bargain for. Examples may be to -store guild data for guild members to be able to change, tracking the flow of money across a game- -wide economic system or implement other custom game systems that requires the storage of custom data -in a quickly accessible way. Whereas Tags or Scripts can handle many situations, -sometimes things may be easier to handle by adding your own database model.

-
-

Overview of database tables

-

SQL-type databases (which is what Evennia supports) are basically highly optimized systems for -retrieving text stored in tables. A table may look like this

-
     id | db_key    | db_typeclass_path          | db_permissions  ...
-    ------------------------------------------------------------------
-     1  |  Griatch  | evennia.DefaultCharacter   | Developers       ...
-     2  |  Rock     | evennia.DefaultObject      | None            ...
-
-
-

Each line is considerably longer in your database. Each column is referred to as a “field” and every -row is a separate object. You can check this out for yourself. If you use the default sqlite3 -database, go to your game folder and run

-
 evennia dbshell
-
-
-

You will drop into the database shell. While there, try:

-
 sqlite> .help       # view help
-
- sqlite> .tables     # view all tables
-
- # show the table field names for objects_objectdb
- sqlite> .schema objects_objectdb
-
- # show the first row from the objects_objectdb table
- sqlite> select * from objects_objectdb limit 1;
-
- sqlite> .exit
-
-
-

Evennia uses Django, which abstracts away the database SQL -manipulation and allows you to search and manipulate your database entirely in Python. Each database -table is in Django represented by a class commonly called a model since it describes the look of -the table. In Evennia, Objects, Scripts, Channels etc are examples of Django models that we then -extend and build on.

-
-
-

Adding a new database table

-

Here is how you add your own database table/models:

-
    -
  1. In Django lingo, we will create a new “application” - a subsystem under the main Evennia program. -For this example we’ll call it “myapp”. Run the following (you need to have a working Evennia -running before you do this, so make sure you have run the steps in [Getting Started](Getting- -Started) first):

    -
     cd mygame/world
    - evennia startapp myapp
    -
    -
    -
  2. -
  3. A new folder myapp is created. “myapp” will also be the name (the “app label”) from now on. We -chose to put it in the world/ subfolder here, but you could put it in the root of your mygame if -that makes more sense.

  4. -
  5. The myapp folder contains a few empty default files. What we are -interested in for now is models.py. In models.py you define your model(s). Each model will be a -table in the database. See the next section and don’t continue until you have added the models you -want.

  6. -
  7. You now need to tell Evennia that the models of your app should be a part of your database -scheme. Add this line to your mygame/server/conf/settings.pyfile (make sure to use the path where -you put myapp and don’t forget the comma at the end of the tuple):

    -
    INSTALLED_APPS = INSTALLED_APPS + ("world.myapp", )
    -
    -
    -
  8. -
  9. From mygame/, run

    -
     evennia makemigrations myapp
    - evennia migrate
    -
    -
    -
  10. -
-

This will add your new database table to the database. If you have put your game under version -control (if not, you should), don’t forget to git add myapp/* to add all items -to version control.

-
-
-

Defining your models

-

A Django model is the Python representation of a database table. It can be handled like any other -Python class. It defines fields on itself, objects of a special type. These become the “columns” -of the database table. Finally, you create new instances of the model to add new rows to the -database.

-

We won’t describe all aspects of Django models here, for that we refer to the vast Django -documentation on the subject. Here is a -(very) brief example:

-
from django.db import models
-
-class MyDataStore(models.Model):
-    "A simple model for storing some data"
-    db_key = models.CharField(max_length=80, db_index=True)
-    db_category = models.CharField(max_length=80, null=True, blank=True)
-    db_text = models.TextField(null=True, blank=True)
-    # we need this one if we want to be
-    # able to store this in an Evennia Attribute!
-    db_date_created = models.DateTimeField('date created', editable=False,
-                                            auto_now_add=True, db_index=True)
-
-
-

We create four fields: two character fields of limited length and one text field which has no -maximum length. Finally we create a field containing the current time of us creating this object.

-
-

The db_date_created field, with exactly this name, is required if you want to be able to store -instances of your custom model in an Evennia Attribute. It will automatically be set -upon creation and can after that not be changed. Having this field will allow you to do e.g. -obj.db.myinstance = mydatastore. If you know you’ll never store your model instances in Attributes -the db_date_created field is optional.

-
-

You don’t have to start field names with db_, this is an Evennia convention. It’s nevertheless -recommended that you do use db_, partly for clarity and consistency with Evennia (if you ever want -to share your code) and partly for the case of you later deciding to use Evennia’s -SharedMemoryModel parent down the line.

-

The field keyword db_index creates a database index for this field, which allows quicker -lookups, so it’s recommended to put it on fields you know you’ll often use in queries. The -null=True and blank=True keywords means that these fields may be left empty or set to the empty -string without the database complaining. There are many other field types and keywords to define -them, see django docs for more info.

-

Similar to using django-admin you -are able to do evennia inspectdb to get an automated listing of model information for an existing -database. As is the case with any model generating tool you should only use this as a starting -point for your models.

-
-
-

Creating a new model instance

-

To create a new row in your table, you instantiate the model and then call its save() method:

-
     from evennia.myapp import MyDataStore
-
-     new_datastore = MyDataStore(db_key="LargeSword",
-                                 db_category="weapons",
-                                 db_text="This is a huge weapon!")
-     # this is required to actually create the row in the database!
-     new_datastore.save()
-
-
-
-

Note that the db_date_created field of the model is not specified. Its flag at_now_add=True -makes sure to set it to the current date when the object is created (it can also not be changed -further after creation).

-

When you update an existing object with some new field value, remember that you have to save the -object afterwards, otherwise the database will not update:

-
    my_datastore.db_key = "Larger Sword"
-    my_datastore.save()
-
-
-

Evennia’s normal models don’t need to explicitly save, since they are based on SharedMemoryModel -rather than the raw django model. This is covered in the next section.

-
-
-

Using the SharedMemoryModel parent

-

Evennia doesn’t base most of its models on the raw django.db.models but on the Evennia base model -evennia.utils.idmapper.models.SharedMemoryModel. There are two main reasons for this:

-
    -
  1. Ease of updating fields without having to explicitly call save()

  2. -
  3. On-object memory persistence and database caching

  4. -
-

The first (and least important) point means that as long as you named your fields db_*, Evennia -will automatically create field wrappers for them. This happens in the model’s -Metaclass so there is no speed -penalty for this. The name of the wrapper will be the same name as the field, minus the db_ -prefix. So the db_key field will have a wrapper property named key. You can then do:

-
    my_datastore.key = "Larger Sword"
-
-
-

and don’t have to explicitly call save() afterwards. The saving also happens in a more efficient -way under the hood, updating only the field rather than the entire model using django optimizations. -Note that if you were to manually add the property or method key to your model, this will be used -instead of the automatic wrapper and allows you to fully customize access as needed.

-

To explain the second and more important point, consider the following example using the default -Django model parent:

-
    shield = MyDataStore.objects.get(db_key="SmallShield")
-    shield.cracked = True # where cracked is not a database field
-
-
-

And then later:

-
    shield = MyDataStore.objects.get(db_key="SmallShield")
-    print(shield.cracked)  # error!
-
-
-

The outcome of that last print statement is undefined! It could maybe randomly work but most -likely you will get an AttributeError for not finding the cracked property. The reason is that -cracked doesn’t represent an actual field in the database. It was just added at run-time and thus -Django don’t care about it. When you retrieve your shield-match later there is no guarantee you -will get back the same Python instance of the model where you defined cracked, even if you -search for the same database object.

-

Evennia relies heavily on on-model handlers and other dynamically created properties. So rather than -using the vanilla Django models, Evennia uses SharedMemoryModel, which levies something called -idmapper. The idmapper caches model instances so that we will always get the same instance back -after the first lookup of a given object. Using idmapper, the above example would work fine and you -could retrieve your cracked property at any time - until you rebooted when all non-persistent data -goes.

-

Using the idmapper is both more intuitive and more efficient per object; it leads to a lot less -reading from disk. The drawback is that this system tends to be more memory hungry overall. So if -you know that you’ll never need to add new properties to running instances or know that you will -create new objects all the time yet rarely access them again (like for a log system), you are -probably better off making “plain” Django models rather than using SharedMemoryModel and its -idmapper.

-

To use the idmapper and the field-wrapper functionality you just have to have your model classes -inherit from evennia.utils.idmapper.models.SharedMemoryModel instead of from the default -django.db.models.Model:

-
from evennia.utils.idmapper.models import SharedMemoryModel
-
-class MyDataStore(SharedMemoryModel):
-    # the rest is the same as before, but db_* is important; these will
-    # later be settable as .key, .category, .text ...
-    db_key = models.CharField(max_length=80, db_index=True)
-    db_category = models.CharField(max_length=80, null=True, blank=True)
-    db_text = models.TextField(null=True, blank=True)
-    db_date_created = models.DateTimeField('date created', editable=False,
-                                            auto_now_add=True, db_index=True)
-
-
-
-
-

Searching for your models

-

To search your new custom database table you need to use its database manager to build a query. -Note that even if you use SharedMemoryModel as described in the previous section, you have to use -the actual field names in the query, not the wrapper name (so db_key and not just key).

-
     from world.myapp import MyDataStore
-
-     # get all datastore objects exactly matching a given key
-     matches = MyDataStore.objects.filter(db_key="Larger Sword")
-     # get all datastore objects with a key containing "sword"
-     # and having the category "weapons" (both ignoring upper/lower case)
-     matches2 = MyDataStore.objects.filter(db_key__icontains="sword",
-                                           db_category__iequals="weapons")
-     # show the matching data (e.g. inside a command)
-     for match in matches2:
-        self.caller.msg(match.db_text)
-
-
-

See the Django query documentation for a -lot more information about querying the database.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Nicks.html b/docs/0.9.5/Nicks.html deleted file mode 100644 index bd9f8c1e81..0000000000 --- a/docs/0.9.5/Nicks.html +++ /dev/null @@ -1,230 +0,0 @@ - - - - - - - - - Nicks — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Nicks

-

Nicks, short for Nicknames is a system allowing an object (usually a Account) to -assign custom replacement names for other game entities.

-

Nicks are not to be confused with Aliases. Setting an Alias on a game entity actually changes an -inherent attribute on that entity, and everyone in the game will be able to use that alias to -address the entity thereafter. A Nick on the other hand, is used to map a different way you -alone can refer to that entity. Nicks are also commonly used to replace your input text which means -you can create your own aliases to default commands.

-

Default Evennia use Nicks in three flavours that determine when Evennia actually tries to do the -substitution.

-
    -
  • inputline - replacement is attempted whenever you write anything on the command line. This is the -default.

  • -
  • objects - replacement is only attempted when referring to an object

  • -
  • accounts - replacement is only attempted when referring an account

  • -
-

Here’s how to use it in the default command set (using the nick command):

-
 nick ls = look
-
-
-

This is a good one for unix/linux users who are accustomed to using the ls command in their daily -life. It is equivalent to nick/inputline ls = look.

-
 nick/object mycar2 = The red sports car
-
-
-

With this example, substitutions will only be done specifically for commands expecting an object -reference, such as

-
 look mycar2
-
-
-

becomes equivalent to “look The red sports car”.

-
 nick/accounts tom = Thomas Johnsson
-
-
-

This is useful for commands searching for accounts explicitly:

-
 @find *tom
-
-
-

One can use nicks to speed up input. Below we add ourselves a quicker way to build red buttons. In -the future just writing rb will be enough to execute that whole long string.

-
 nick rb = @create button:examples.red_button.RedButton
-
-
-

Nicks could also be used as the start for building a “recog” system suitable for an RP mud.

-
 nick/account Arnold = The mysterious hooded man
-
-
-

The nick replacer also supports unix-style templating:

-
 nick build $1 $2 = @create/drop $1;$2
-
-
-

This will catch space separated arguments and store them in the the tags $1 and $2, to be -inserted in the replacement string. This example allows you to do build box crate and have Evennia -see @create/drop box;crate. You may use any $ numbers between 1 and 99, but the markers must -match between the nick pattern and the replacement.

-
-

If you want to catch “the rest” of a command argument, make sure to put a $ tag with no spaces -to the right of it - it will then receive everything up until the end of the line.

-
-

You can also use shell-type wildcards:

-
    -
  • * - matches everything.

  • -
  • ? - matches a single character.

  • -
  • [seq] - matches everything in the sequence, e.g. [xyz] will match both x, y and z

  • -
  • [!seq] - matches everything not in the sequence. e.g. [!xyz] will match all but x,y z.

  • -
-
-

Coding with nicks

-

Nicks are stored as the Nick database model and are referred from the normal Evennia -object through the nicks property - this is known as the NickHandler. The NickHandler -offers effective error checking, searches and conversion.

-
    # A command/channel nick:
-      obj.nicks.add("greetjack", "tell Jack = Hello pal!")
-    
-    # An object nick:
-      obj.nicks.add("rose", "The red flower", nick_type="object")
-    
-    # An account nick:
-      obj.nicks.add("tom", "Tommy Hill", nick_type="account")
-    
-    # My own custom nick type (handled by my own game code somehow):
-      obj.nicks.add("hood", "The hooded man", nick_type="my_identsystem")
-    
-    # get back the translated nick:
-     full_name = obj.nicks.get("rose", nick_type="object")
-    
-    # delete a previous set nick
-      object.nicks.remove("rose", nick_type="object")
-
-
-

In a command definition you can reach the nick handler through self.caller.nicks. See the nick -command in evennia/commands/default/general.py for more examples.

-

As a last note, The Evennia channel alias systems are using nicks with the -nick_type="channel" in order to allow users to create their own custom aliases to channels.

-
-
-
-

Advanced note

-

Internally, nicks are Attributes saved with the db_attrype set to “nick” (normal -Attributes has this set to None).

-

The nick stores the replacement data in the Attribute.db_value field as a tuple with four fields -(regex_nick, template_string, raw_nick, raw_template). Here regex_nick is the converted regex -representation of the raw_nick and the template-string is a version of the raw_template -prepared for efficient replacement of any $- type markers. The raw_nick and raw_template are -basically the unchanged strings you enter to the nick command (with unparsed $ etc).

-

If you need to access the tuple for some reason, here’s how:

-
tuple = obj.nicks.get("nickname", return_tuple=True)
-# or, alternatively
-tuple = obj.nicks.get("nickname", return_obj=True).value
-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/OOB.html b/docs/0.9.5/OOB.html deleted file mode 100644 index c576043825..0000000000 --- a/docs/0.9.5/OOB.html +++ /dev/null @@ -1,296 +0,0 @@ - - - - - - - - - OOB — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

OOB

-

OOB, or Out-Of-Band, means sending data between Evennia and the user’s client without the user -prompting it or necessarily being aware that it’s being passed. Common uses would be to update -client health-bars, handle client button-presses or to display certain tagged text in a different -window pane.

-
-

Briefly on input/outputcommands

-

Inside Evennia, all server-client communication happens in the same way (so plain text is also an -‘OOB message’ as far as Evennia is concerned). The message follows the Message Path. -You should read up on that if you are unfamiliar with it. As the message travels along the path it -has a standardized internal form: a tuple with a string, a tuple and a dict:

-
("cmdname", (args), {kwargs})
-
-
-

This is often referred to as an inputcommand or outputcommand, depending on the direction it’s -traveling. The end point for an inputcommand, (the ‘Evennia-end’ of the message path) is a matching -Inputfunc. This function is called as cmdname(session, *args, **kwargs) where -session is the Session-source of the command. Inputfuncs can easily be added by the developer to -support/map client commands to actions inside Evennia (see the inputfunc page for more -details).

-

When a message is outgoing (at the ‘Client-end’ of the message path) the outputcommand is handled by -a matching Outputfunc. This is responsible for converting the internal Evennia representation to a -form suitable to send over the wire to the Client. Outputfuncs are hard-coded. Which is chosen and -how it processes the outgoing data depends on the nature of the client it’s connected to. The only -time one would want to add new outputfuncs is as part of developing support for a new Evennia -Protocol.

-
-
-

Sending and receiving an OOB message

-

Sending is simple. You just use the normal msg method of the object whose session you want to send -to. For example in a Command:

-
    caller.msg(cmdname=((args, ...), {key:value, ...}))
-
-
-

A special case is the text input/outputfunc. It’s so common that it’s the default of the msg -method. So these are equivalent:

-
    caller.msg("Hello")
-    caller.msg(text="Hello")
-
-
-

You don’t have to specify the full output/input definition. So for example, if your particular -command only needs kwargs, you can skip the (args) part. Like in the text case you can skip -writing the tuple if there is only one arg … and so on - the input is pretty flexible. If there -are no args at all you need to give the empty tuple msg(cmdname=(,) (giving None would mean a -single argument None).

-

Which commands you can send depends on the client. If the client does not support an explicit OOB -protocol (like many old/legacy MUD clients) Evennia can only send text to them and will quietly -drop any other types of outputfuncs.

-
-

Remember that a given message may go to multiple clients with different capabilities. So unless -you turn off telnet completely and only rely on the webclient, you should never rely on non-text -OOB messages always reaching all targets.

-
-

Inputfuncs lists the default inputfuncs available to handle incoming OOB messages. To -accept more you need to add more inputfuncs (see that page for more info).

-
-
-

Supported OOB protocols

-

Evennia supports clients using one of the following protocols:

-
-

Telnet

-

By default telnet (and telnet+SSL) supports only the plain text outputcommand. Evennia however -detects if the Client supports one of two MUD-specific OOB extensions to the standard telnet -protocol - GMCP or MSDP. Evennia supports both simultaneously and will switch to the protocol the -client uses. If the client supports both, GMCP will be used.

-
-

Note that for Telnet, text has a special status as the “in-band” operation. So the text -outputcommand sends the text argument directly over the wire, without going through the OOB -translations described below.

-
-
-

Telnet + GMCP

-

GMCP, the Generic Mud Communication Protocol sends data on the -form cmdname + JSONdata. Here the cmdname is expected to be on the form “Package.Subpackage”. -There could also be additional Sub-sub packages etc. The names of these ‘packages’ and ‘subpackages’ -are not that well standardized beyond what individual MUDs or companies have chosen to go with over -the years. You can decide on your own package names, but here are what others are using:

- -

Evennia will translate underscores to . and capitalize to fit the specification. So the -outputcommand foo_bar will become a GMCP command-name Foo.Bar. A GMCP command “Foo.Bar” will be -come foo_bar. To send a GMCP command that turns into an Evennia inputcommand without an -underscore, use the Core package. So Core.Cmdname becomes just cmdname in Evennia and vice -versa.

-

On the wire, a GMCP instruction for ("cmdname", ("arg",), {}) will look like this:

-
IAC SB GMCP "cmdname" "arg" IAC SE
-
-
-

where all the capitalized words are telnet character constants specified in -evennia/server/portal/telnet_oob.py. These are parsed/added by the protocol and we don’t include -these in the listings below.

-
-
-
-
-

Input/Outputfunc | GMCP-Command

-

[cmd_name, [], {}] | Cmd.Name -[cmd_name, [arg], {}] | Cmd.Name arg -[cmd_na_me, [args],{}] | Cmd.Na.Me [args] -[cmd_name, [], {kwargs}] | Cmd.Name {kwargs} -[cmdname, [args, {kwargs}] | Core.Cmdname [[args],{kwargs}]

-

Since Evennia already supplies default inputfuncs that don’t match the names expected by the most -common GMCP implementations we have a few hard-coded mappings for those:

-
-
-

GMCP command name | Input/Outputfunc name

-

“Core.Hello” | “client_options” -“Core.Supports.Get” | “client_options” -“Core.Commands.Get” | “get_inputfuncs” -“Char.Value.Get” | “get_value” -“Char.Repeat.Update” | “repeat” -“Char.Monitor.Update” | “monitor”

-
-

Telnet + MSDP

-

MSDP, the Mud Server Data Protocol, is a competing standard -to GMCP. The MSDP protocol page specifies a range of “recommended” available MSDP command names. -Evennia does not support those - since MSDP doesn’t specify a special format for its command names -(like GMCP does) the client can and should just call the internal Evennia inputfunc by its actual -name.

-

MSDP uses Telnet character constants to package various structured data over the wire. MSDP supports -strings, arrays (lists) and tables (dicts). These are used to define the cmdname, args and kwargs -needed. When sending MSDP for ("cmdname", ("arg",), {}) the resulting MSDP instruction will look -like this:

-
IAC SB MSDP VAR cmdname VAL arg IAC SE
-
-
-

The various available MSDP constants like VAR (variable), VAL (value), ARRAYOPEN/ARRAYCLOSE -and TABLEOPEN/TABLECLOSE are specified in evennia/server/portal/telnet_oob.

-
-
-
-

Outputfunc/Inputfunc | MSDP instruction

-

[cmdname, [], {}] | VAR cmdname VAL -[cmdname, [arg], {}] | VAR cmdname VAL arg -[cmdname, [args],{}] | VAR cmdname VAL ARRAYOPEN VAL arg VAL arg … ARRAYCLOSE -[cmdname, [], {kwargs}] | VAR cmdname VAL TABLEOPEN VAR key VAL val … TABLECLOSE -[cmdname, [args], {kwargs}] | VAR cmdname VAL ARRAYOPEN VAL arg VAL arg … ARRAYCLOSE VAR cmdname -VAL TABLEOPEN VAR key VAL val … TABLECLOSE

-

Observe that VAR ... VAL always identifies cmdnames, so if there are multiple arrays/dicts tagged -with the same cmdname they will be appended to the args, kwargs of that inputfunc. Vice-versa, a -different VAR ... VAL (outside a table) will come out as a second, different command input.

-
-

SSH

-

SSH only supports the text input/outputcommand.

-
-
-

Web client

-

Our web client uses pure JSON structures for all its communication, including text. This maps -directly to the Evennia internal output/inputcommand, including eventual empty args/kwargs. So the -same example ("cmdname", ("arg",), {}) will be sent/received as a valid JSON structure

-
["cmdname, ["arg"], {}]
-
-
-

Since JSON is native to Javascript, this becomes very easy for the webclient to handle.

-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Objects.html b/docs/0.9.5/Objects.html deleted file mode 100644 index 1b04fcf336..0000000000 --- a/docs/0.9.5/Objects.html +++ /dev/null @@ -1,304 +0,0 @@ - - - - - - - - - Objects — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Objects

-

All in-game objects in Evennia, be it characters, chairs, monsters, rooms or hand grenades are -represented by an Evennia Object. Objects form the core of Evennia and is probably what you’ll -spend most time working with. Objects are Typeclassed entities.

-
-

How to create your own object types

-

An Evennia Object is, per definition, a Python class that includes evennia.DefaultObject among its -parents. In mygame/typeclasses/objects.py there is already a class Object that inherits from -DefaultObject and that you can inherit from. You can put your new typeclass directly in that -module or you could organize your code in some other way. Here we assume we make a new module -mygame/typeclasses/flowers.py:

-
    # mygame/typeclasses/flowers.py
-
-    from typeclasses.objects import Object
-
-    class Rose(Object):
-        """
-        This creates a simple rose object
-        """
-        def at_object_creation(self):
-            "this is called only once, when object is first created"
-            # add a persistent attribute 'desc'
-            # to object (silly example).
-            self.db.desc = "This is a pretty rose with thorns."
-
-
-

You could save this in the mygame/typeclasses/objects.py (then you’d not need to import Object) -or you can put it in a new module. Let’s say we do the latter, making a module -typeclasses/flowers.py. Now you just need to point to the class Rose with the @create command -to make a new rose:

-
 @create/drop MyRose:flowers.Rose
-
-
-

What the @create command actually does is to use evennia.create_object. You can do the same -thing yourself in code:

-
    from evennia import create_object
-    new_rose = create_object("typeclasses.flowers.Rose", key="MyRose")
-
-
-

(The @create command will auto-append the most likely path to your typeclass, if you enter the -call manually you have to give the full path to the class. The create.create_object function is -powerful and should be used for all coded object creating (so this is what you use when defining -your own building commands). Check out the ev.create_* functions for how to build other entities -like Scripts).

-

This particular Rose class doesn’t really do much, all it does it make sure the attribute -desc(which is what the look command looks for) is pre-set, which is pretty pointless since you -will usually want to change this at build time (using the @desc command or using the -Spawner). The Object typeclass offers many more hooks that is available -to use though - see next section.

-
-
-

Properties and functions on Objects

-

Beyond the properties assigned to all typeclassed objects (see that page for a list -of those), the Object also has the following custom properties:

-
    -
  • aliases - a handler that allows you to add and remove aliases from this object. Use -aliases.add() to add a new alias and aliases.remove() to remove one.

  • -
  • location - a reference to the object currently containing this object.

  • -
  • home is a backup location. The main motivation is to have a safe place to move the object to if -its location is destroyed. All objects should usually have a home location for safety.

  • -
  • destination - this holds a reference to another object this object links to in some way. Its -main use is for Exits, it’s otherwise usually unset.

  • -
  • nicks - as opposed to aliases, a Nick holds a convenient nickname replacement for a -real name, word or sequence, only valid for this object. This mainly makes sense if the Object is -used as a game character - it can then store briefer shorts, example so as to quickly reference game -commands or other characters. Use nicks.add(alias, realname) to add a new one.

  • -
  • account - this holds a reference to a connected Account controlling this object (if -any). Note that this is set also if the controlling account is not currently online - to test if -an account is online, use the has_account property instead.

  • -
  • sessions - if account field is set and the account is online, this is a list of all active -sessions (server connections) to contact them through (it may be more than one if multiple -connections are allowed in settings).

  • -
  • has_account - a shorthand for checking if an online account is currently connected to this -object.

  • -
  • contents - this returns a list referencing all objects ‘inside’ this object (i,e. which has this -object set as their location).

  • -
  • exits - this returns all objects inside this object that are Exits, that is, has the -destination property set.

  • -
-

The last two properties are special:

-
    -
  • cmdset - this is a handler that stores all command sets defined on the -object (if any).

  • -
  • scripts - this is a handler that manages Scripts attached to the object (if any).

  • -
-

The Object also has a host of useful utility functions. See the function headers in -src/objects/objects.py for their arguments and more details.

-
    -
  • msg() - this function is used to send messages from the server to an account connected to this -object.

  • -
  • msg_contents() - calls msg on all objects inside this object.

  • -
  • search() - this is a convenient shorthand to search for a specific object, at a given location -or globally. It’s mainly useful when defining commands (in which case the object executing the -command is named caller and one can do caller.search() to find objects in the room to operate -on).

  • -
  • execute_cmd() - Lets the object execute the given string as if it was given on the command line.

  • -
  • move_to - perform a full move of this object to a new location. This is the main move method -and will call all relevant hooks, do all checks etc.

  • -
  • clear_exits() - will delete all Exits to and from this object.

  • -
  • clear_contents() - this will not delete anything, but rather move all contents (except Exits) to -their designated Home locations.

  • -
  • delete() - deletes this object, first calling clear_exits() and -clear_contents().

  • -
-

The Object Typeclass defines many more hook methods beyond at_object_creation. Evennia calls -these hooks at various points. When implementing your custom objects, you will inherit from the -base parent and overload these hooks with your own custom code. See evennia.objects.objects for an -updated list of all the available hooks or the API for DefaultObject -here.

-
-
-

Subclasses of Object

-

There are three special subclasses of Object in default Evennia - Characters, Rooms and -Exits. The reason they are separated is because these particular object types are fundamental, -something you will always need and in some cases requires some extra attention in order to be -recognized by the game engine (there is nothing stopping you from redefining them though). In -practice they are all pretty similar to the base Object.

-
-

Characters

-

Characters are objects controlled by Accounts. When a new Account -logs in to Evennia for the first time, a new Character object is created and -the Account object is assigned to the account attribute. A Character object -must have a Default Commandset set on itself at -creation, or the account will not be able to issue any commands! If you just -inherit your own class from evennia.DefaultCharacter and make sure to use -super() to call the parent methods you should be fine. In -mygame/typeclasses/characters.py is an empty Character class ready for you -to modify.

-
-
-

Rooms

-

Rooms are the root containers of all other objects. The only thing really separating a room from -any other object is that they have no location of their own and that default commands like @dig -creates objects of this class - so if you want to expand your rooms with more functionality, just -inherit from ev.DefaultRoom. In mygame/typeclasses/rooms.py is an empty Room class ready for -you to modify.

-
-
-

Exits

-

Exits are objects connecting other objects (usually Rooms) together. An object named North or -in might be an exit, as well as door, portal or jump out the window. An exit has two things -that separate them from other objects. Firstly, their destination property is set and points to a -valid object. This fact makes it easy and fast to locate exits in the database. Secondly, exits -define a special Transit Command on themselves when they are created. This command is -named the same as the exit object and will, when called, handle the practicalities of moving the -character to the Exits’s destination - this allows you to just enter the name of the exit on its -own to move around, just as you would expect.

-

The exit functionality is all defined on the Exit typeclass, so you could in principle completely -change how exits work in your game (it’s not recommended though, unless you really know what you are -doing). Exits are locked using an access_type called traverse and also make use of a few -hook methods for giving feedback if the traversal fails. See evennia.DefaultExit for more info. -In mygame/typeclasses/exits.py there is an empty Exit class for you to modify.

-

The process of traversing an exit is as follows:

-
    -
  1. The traversing obj sends a command that matches the Exit-command name on the Exit object. The -cmdhandler detects this and triggers the command defined on the Exit. Traversal always -involves the “source” (the current location) and the destination (this is stored on the Exit -object).

  2. -
  3. The Exit command checks the traverse lock on the Exit object

  4. -
  5. The Exit command triggers at_traverse(obj, destination) on the Exit object.

  6. -
  7. In at_traverse, object.move_to(destination) is triggered. This triggers the following hooks, -in order:

    -
      -
    1. obj.at_before_move(destination) - if this returns False, move is aborted.

    2. -
    3. origin.at_object_leave(obj, destination)

    4. -
    5. obj.announce_move_from(destination)

    6. -
    7. Move is performed by changing obj.location from source location to destination.

    8. -
    9. obj.announce_move_to(source)

    10. -
    11. destination.at_object_receive(obj, source)

    12. -
    13. obj.at_after_move(source)

    14. -
    -
  8. -
  9. On the Exit object, at_after_traverse(obj, source) is triggered.

  10. -
-

If the move fails for whatever reason, the Exit will look for an Attribute err_traverse on itself -and display this as an error message. If this is not found, the Exit will instead call -at_failed_traverse(obj) on itself.

-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Online-Setup.html b/docs/0.9.5/Online-Setup.html deleted file mode 100644 index 0afde31ccb..0000000000 --- a/docs/0.9.5/Online-Setup.html +++ /dev/null @@ -1,601 +0,0 @@ - - - - - - - - - Online Setup — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Online Setup

-

Evennia development can be made without any Internet connection beyond fetching updates. At some -point however, you are likely to want to make your game visible online, either as part opening it to -the public or to allow other developers or beta testers access to it.

-
-

Connecting from the outside

-

Accessing your Evennia server from the outside is not hard on its own. Any issues are usually due to -the various security measures your computer, network or hosting service has. These will generally -(and correctly) block outside access to servers on your machine unless you tell them otherwise.

-

We will start by showing how to host your server on your own local computer. Even if you plan to -host your “real” game on a remote host later, setting it up locally is useful practice. We cover -remote hosting later in this document.

-

Out of the box, Evennia uses three ports for outward communication. If your computer has a firewall, -these should be open for in/out communication (and only these, other ports used by Evennia are -internal to your computer only).

-
    -
  • 4000, telnet, for traditional mud clients

  • -
  • 4001, HTTP for the website)

  • -
  • 4002, websocket, for the web client

  • -
-

Evennia will by default accept incoming connections on all interfaces (0.0.0.0) so in principle -anyone knowing the ports to use and has the IP address to your machine should be able to connect to -your game.

-
    -
  • Make sure Evennia is installed and that you have activated the virtualenv. Start the server with -evennia start --log. The --log (or -l) will make sure that the logs are echoed to the -terminal.

  • -
-
-

Note: If you need to close the log-view, use Ctrl-C. Use just evennia --log on its own to -start tailing the logs again.

-
-
    -
  • Make sure you can connect with your web browser to http://localhost:4001 or, alternatively, -http://127.0.0.1:4001 which is the same thing. You should get your Evennia web site and be able to -play the game in the web client. Also check so that you can connect with a mud client to host -localhost, port 4000 or host 127.0.0.1, port 4000.

  • -
  • Google for “my ip” or use any online service to figure out -what your “outward-facing” IP address is. For our purposes, let’s say your outward-facing IP is -203.0.113.0.

  • -
  • Next try your outward-facing IP by opening http://203.0.113.0:4001 in a browser. If this works, -that’s it! Also try telnet, with the server set to 203.0.113.0 and port 4000. However, most -likely it will not work. If so, read on.

  • -
  • If your computer has a firewall, it may be blocking the ports we need (it may also block telnet -overall). If so, you need to open the outward-facing ports to in/out communication. See the -manual/instructions for your firewall software on how to do this. To test you could also temporarily -turn off your firewall entirely to see if that was indeed the problem.

  • -
  • Another common problem for not being able to connect is that you are using a hardware router -(like a wifi router). The router sits ‘between’ your computer and the Internet. So the IP you find -with Google is the router’s IP, not that of your computer. To resolve this you need to configure -your router to forward data it gets on its ports to the IP and ports of your computer sitting in -your private network. How to do this depends on the make of your router; you usually configure it -using a normal web browser. In the router interface, look for “Port forwarding” or maybe “Virtual -server”. If that doesn’t work, try to temporarily wire your computer directly to the Internet outlet -(assuming your computer has the ports for it). You’ll need to check for your IP again. If that -works, you know the problem is the router.

  • -
-
-

Note: If you need to reconfigure a router, the router’s Internet-facing ports do not have to -have to have the same numbers as your computer’s (and Evennia’s) ports! For example, you might want -to connect Evennia’s outgoing port 4001 to an outgoing router port 80 - this is the port HTTP -requests use and web browsers automatically look for - if you do that you could go to -http://203.0.113.0 without having to add the port at the end. This would collide with any other -web services you are running through this router though.

-
-
-

Settings example

-

You can connect Evennia to the Internet without any changes to your settings. The default settings -are easy to use but are not necessarily the safest. You can customize your online presence in your -settings file. To have Evennia recognize changed port settings you have -to do a full evennia reboot to also restart the Portal and not just the Server component.

-

Below is an example of a simple set of settings, mostly using the defaults. Evennia will require -access to five computer ports, of which three (only) should be open to the outside world. Below we -continue to assume that our server address is 203.0.113.0.

-
# in mygame/server/conf/settings.py
-
-SERVERNAME = "MyGame"
-
-# open to the internet: 4000, 4001, 4002
-# closed to the internet (internal use): 4005, 4006
-TELNET_PORTS = [4000]
-WEBSOCKET_CLIENT_PORT = 4002
-WEBSERVER_PORTS = [(4001, 4005)]
-AMP_PORT = 4006
-
-# Optional - security measures limiting interface access
-# (don't set these before you know things work without them)
-TELNET_INTERFACES = ['203.0.113.0']
-WEBSOCKET_CLIENT_INTERFACE = '203.0.113.0'
-ALLOWED_HOSTS = [".mymudgame.com"]
-
-# uncomment if you want to lock the server down for maintenance.
-# LOCKDOWN_MODE = True
-
-
-
-

Read on for a description of the individual settings.

-
-
-

Telnet

-
# Required. Change to whichever outgoing Telnet port(s)
-# you are allowed to use on your host.
-TELNET_PORTS = [4000]
-# Optional for security. Restrict which telnet
-# interfaces we should accept. Should be set to your
-# outward-facing IP address(es). Default is ´0.0.0.0´
-# which accepts all interfaces.
-TELNET_INTERFACES = ['0.0.0.0']
-
-
-

The TELNET_* settings are the most important ones for getting a traditional base game going. Which -IP addresses you have available depends on your server hosting solution (see the next sections). -Some hosts will restrict which ports you are allowed you use so make sure to check.

-
-
-

Web server

-
# Required. This is a list of tuples
-# (outgoing_port, internal_port). Only the outgoing
-# port should be open to the world!
-# set outgoing port to 80 if you want to run Evennia
-# as the only web server on your machine (if available).
-WEBSERVER_PORTS = [(4001, 4005)]
-# Optional for security. Change this to the IP your
-# server can be reached at (normally the same
-# as TELNET_INTERFACES)
-WEBSERVER_INTERFACES = ['0.0.0.0']
-# Optional for security. Protects against
-# man-in-the-middle attacks. Change  it to your server's
-# IP address or URL when you run a production server.
-ALLOWED_HOSTS = ['*']
-
-
-

The web server is always configured with two ports at a time. The outgoing port (4001 by -default) is the port external connections can use. If you don’t want users to have to specify the -port when they connect, you should set this to 80 - this however only works if you are not running -any other web server on the machine. -The internal port (4005 by default) is used internally by Evennia to communicate between the -Server and the Portal. It should not be available to the outside world. You usually only need to -change the outgoing port unless the default internal port is clashing with some other program.

-
-
-

Web client

-
# Required. Change this to the main IP address of your server.
-WEBSOCKET_CLIENT_INTERFACE = '0.0.0.0'
-# Optional and needed only if using a proxy or similar. Change
-# to the IP or address where the client can reach
-# your server. The ws:// part is then required. If not given, the client
-# will use its host location.
-WEBSOCKET_CLIENT_URL = ""
-# Required. Change to a free port for the websocket client to reach
-# the server on. This will be automatically appended
-# to WEBSOCKET_CLIENT_URL by the web client.
-WEBSOCKET_CLIENT_PORT = 4002
-
-
-

The websocket-based web client needs to be able to call back to the server, and these settings must -be changed for it to find where to look. If it cannot find the server you will get an warning in -your browser’s Console (in the dev tools of the browser), and the client will revert to the AJAX- -based of the client instead, which tends to be slower.

-
-
-

Other ports

-
# Optional public facing. Only allows SSL connections (off by default).
-SSL_PORTS = [4003]
-SSL_INTERFACES = ['0.0.0.0']
-# Optional public facing. Only if you allow SSH connections (off by default).
-SSH_PORTS = [4004]
-SSH_INTERFACES = ['0.0.0.0']
-# Required private. You should only change this if there is a clash
-# with other services on your host. Should NOT be open to the
-# outside world.
-AMP_PORT = 4006
-
-
-

The AMP_PORT is required to work, since this is the internal port linking Evennia’s -Server and Portal components together. The other ports are encrypted ports that may be -useful for custom protocols but are otherwise not used.

-
-
-

Lockdown mode

-

When you test things out and check configurations you may not want players to drop in on you. -Similarly, if you are doing maintenance on a live game you may want to take it offline for a while -to fix eventual problems without risking people connecting. To do this, stop the server with -evennia stop and add LOCKDOWN_MODE = True to your settings file. When you start the server -again, your game will only be accessible from localhost.

-
-
-

Registering with the Evennia game directory

-

Once your game is online you should make sure to register it with the Evennia Game -Index. Registering with the index will help people find your server, -drum up interest for your game and also shows people that Evennia is being used. You can do this -even if you are just starting development - if you don’t give any telnet/web address it will appear -as Not yet public and just be a teaser. If so, pick pre-alpha as the development status.

-

To register, stand in your game dir, run

-
evennia connections
-
-
-

and follow the instructions. See the Game index page for more details.

-
-
-
-

SSL

-

SSL can be very useful for web clients. It will protect the credentials and gameplay of your users -over a web client if they are in a public place, and your websocket can also be switched to WSS for -the same benefit. SSL certificates used to cost money on a yearly basis, but there is now a program -that issues them for free with assisted setup to make the entire process less painful.

-

Options that may be useful in combination with an SSL proxy:

-
# See above for the section on Lockdown Mode.
-# Useful for a proxy on the public interface connecting to Evennia on localhost.
-LOCKDOWN_MODE = True
-
-# Have clients communicate via wss after connecting with https to port 4001.
-# Without this, you may get DOMException errors when the browser tries
-# to create an insecure websocket from a secure webpage.
-WEBSOCKET_CLIENT_URL = "wss://fqdn:4002"
-
-
-
-

Let’s Encrypt

-

Let’s Encrypt is a certificate authority offering free certificates to -secure a website with HTTPS. To get started issuing a certificate for your web server using Let’s -Encrypt, see these links:

- -

Also, on Freenode visit the #letsencrypt channel for assistance from the community. For an -additional resource, Let’s Encrypt has a very active community -forum.

-

[A blog where someone sets up Let’s Encrypt](https://www.digitalocean.com/community/tutorials/how- -to-secure-apache-with-let-s-encrypt-on-ubuntu-16-04)

-

The only process missing from all of the above documentation is how to pass verification. This is -how Let’s Encrypt verifies that you have control over your domain (not necessarily ownership, it’s -Domain Validation (DV)). This can be done either with configuring a certain path on your web server -or through a TXT record in your DNS. Which one you will want to do is a personal preference, but can -also be based on your hosting choice. In a controlled/cPanel environment, you will most likely have -to use DNS verification.

-
-
-
-

Relevant SSL Proxy Setup Information

- -
-
-

Hosting locally or remotely?

-
-

Using your own computer as a server

-

What we showed above is by far the simplest and probably cheapest option: Run Evennia on your own -home computer. Moreover, since Evennia is its own web server, you don’t need to install anything -extra to have a website.

-

Advantages

-
    -
  • Free (except for internet costs and the electrical bill).

  • -
  • Full control over the server and hardware (it sits right there!).

  • -
  • Easy to set up.

  • -
  • Suitable for quick setups - e.g. to briefly show off results to your collaborators.

  • -
-

Disadvantages

-
    -
  • You need a good internet connection, ideally without any upload/download limits/costs.

  • -
  • If you want to run a full game this way, your computer needs to always be on. It could be noisy, -and as mentioned, the electrical bill must be considered.

  • -
  • No support or safety - if your house burns down, so will your game. Also, you are yourself -responsible for doing regular backups.

  • -
  • Potentially not as easy if you don’t know how to open ports in your firewall or router.

  • -
  • Home IP numbers are often dynamically allocated, so for permanent online time you need to set up a -DNS to always re-point to the right place (see below).

  • -
  • You are personally responsible for any use/misuse of your internet connection– though unlikely -(but not impossible) if running your server somehow causes issues for other customers on the -network, goes against your ISP’s terms of service (many ISPs insist on upselling you to a business- -tier connection) or you are the subject of legal action by a copyright holder, you may find your -main internet connection terminated as a consequence.

  • -
-
-

Setting up your own machine as a server

-

The first section of this page describes how to do this -and allow users to connect to the IP address of your machine/router.

-

A complication with using a specific IP address like this is that your home IP might not remain the -same. Many ISPs (Internet Service Providers) allocates a dynamic IP to you which could change at -any time. When that happens, that IP you told people to go to will be worthless. Also, that long -string of numbers is not very pretty, is it? It’s hard to remember and not easy to use in marketing -your game. What you need is to alias it to a more sensible domain name - an alias that follows you -around also when the IP changes.

-
    -
  1. To set up a domain name alias, we recommend starting with a free domain name from -FreeDNS. Once you register there (it’s free) you have access to tens -of thousands domain names that people have “donated” to allow you to use for your own sub domain. -For example, strangled.net is one of those available domains. So tying our IP address to -strangled.net using the subdomain evennia would mean that one could henceforth direct people to -http://evennia.strangled.net:4001 for their gaming needs - far easier to remember!

  2. -
  3. So how do we make this new, nice domain name follow us also if our IP changes? For this we need -to set up a little program on our computer. It will check whenever our ISP decides to change our IP -and tell FreeDNS that. There are many alternatives to be found from FreeDNS:s homepage, one that -works on multiple platforms is inadyn. Get it from their page or, -in Linux, through something like apt-get install inadyn.

  4. -
  5. Next, you login to your account on FreeDNS and go to the -Dynamic page. You should have a list of your subdomains. Click -the Direct URL link and you’ll get a page with a text message. Ignore that and look at the URL of -the page. It should be ending in a lot of random letters. Everything after the question mark is your -unique “hash”. Copy this string.

  6. -
  7. You now start inadyn with the following command (Linux):

    -

    inadyn --dyndns_system default@freedns.afraid.org -a <my.domain>,<hash> &

    -
  8. -
-

where <my.domain> would be evennia.strangled.net and <hash> the string of numbers we copied -from FreeDNS. The & means we run in the background (might not be valid in other operating -systems). inadyn will henceforth check for changes every 60 seconds. You should put the inadyn -command string in a startup script somewhere so it kicks into gear whenever your computer starts.

-
-
-
-

Remote hosting

-

Your normal “web hotel” will probably not be enough to run Evennia. A web hotel is normally aimed at -a very specific usage - delivering web pages, at the most with some dynamic content. The “Python -scripts” they refer to on their home pages are usually only intended to be CGI-like scripts launched -by their webserver. Even if they allow you shell access (so you can install the Evennia dependencies -in the first place), resource usage will likely be very restricted. Running a full-fledged game -server like Evennia will probably be shunned upon or be outright impossible. If you are unsure, -contact your web hotel and ask about their policy on you running third-party servers that will want -to open custom ports.

-

The options you probably need to look for are shell account services, VPS:es or Cloud -services. A “Shell account” service means that you get a shell account on a server and can log in -like any normal user. By contrast, a VPS (Virtual Private Server) service usually means that you -get root access, but in a virtual machine. There are also Cloud-type services which allows for -starting up multiple virtual machines and pay for what resources you use.

-

Advantages

-
    -
  • Shell accounts/VPS/clouds offer more flexibility than your average web hotel - it’s the ability to -log onto a shared computer away from home.

  • -
  • Usually runs a Linux flavor, making it easy to install Evennia.

  • -
  • Support. You don’t need to maintain the server hardware. If your house burns down, at least your -game stays online. Many services guarantee a certain level of up-time and also do regular backups -for you. Make sure to check, some offer lower rates in exchange for you yourself being fully -responsible for your data/backups.

  • -
  • Usually offers a fixed domain name, so no need to mess with IP addresses.

  • -
  • May have the ability to easily deploy docker versions of evennia -and/or your game.

  • -
-

Disadvantages

-
    -
  • Might be pretty expensive (more so than a web hotel). Note that Evennia will normally need at -least 100MB RAM and likely much more for a large production game.

  • -
  • Linux flavors might feel unfamiliar to users not used to ssh/PuTTy and the Linux command line.

  • -
  • You are probably sharing the server with many others, so you are not completely in charge. CPU -usage might be limited. Also, if the server people decides to take the server down for maintenance, -you have no choice but to sit it out (but you’ll hopefully be warned ahead of time).

  • -
-
-

Installing Evennia on a remote server

-

Firstly, if you are familiar with server infrastructure, consider using [Docker](Running-Evennia-in- -Docker) to deploy your game to the remote server; it will likely ease installation and deployment. -Docker images may be a little confusing if you are completely new to them though.

-

If not using docker, and assuming you know how to connect to your account over ssh/PuTTy, you should -be able to follow the Setup Quickstart instructions normally. You only need Python -and GIT pre-installed; these should both be available on any servers (if not you should be able to -easily ask for them to be installed). On a VPS or Cloud service you can install them yourself as -needed.

-

If virtualenv is not available and you can’t get it, you can download it (it’s just a single file) -from the virtualenv pypi. Using virtualenv you can -install everything without actually needing to have further root access. Ports might be an issue, -so make sure you know which ports are available to use and reconfigure Evennia accordingly.

-
-
-
-

Hosting options

-

To find commercial solutions, browse the web for “shell access”, “VPS” or “Cloud services” in your -region. You may find useful offers for “low cost” VPS hosting on Low End Box. The associated -Low End Talk forum can be useful for health checking the many small businesses that offer -“value” hosting, and occasionally for technical suggestions.

-

There are all sorts of services available. Below are some international suggestions offered by -Evennia users:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Hosting name

Type

Lowest price

Comments

silvren.com

Shell account

Free for MU*

Private hobby provider so don’t assume backups or expect immediate support. To ask for an account,connect with a MUD client to rostdev.mushpark.com, port 4201 and ask for “Jarin”.

Digital Ocean

VPS

$5/month

You can get a $50 credit if you use the referral link https://m.do.co/c/8f64fec2670c - if you do, once you’ve had it long enough to have paid $25 we will get that as a referral bonus to help Evennia development.

Amazon Web services

Cloud

~$5/month / on-demand

Free Tier first 12 months. Regions available around the globe.

Amazon Lightsail

Cloud

$5/month

Free first month. AWS’s new “fixed cost” offering.

Azure App Services

Cloud

Free

Provides a free tier for hobbyist. Limited regions to be deployed to under the free tier

Huawei Cloud

Cloud

on demand

Similar to Amazon. Free Tier first 12 months. Limited regions to be deployed to

Genesis MUD hosting

Shell account

$8/month

Dedicated MUD host with very limited memory offerings. As for 2017, runs a 13 years old Python version (2.4) so you’d need to either convince them to update or compile yourself. Note that Evennia needs at least the “Deluxe” package (50MB RAM) and probably a lot higher for a production game. This host is not recommended for Evennia.

Host1Plus

VPS & Cloud

$4/month

$4-$8/month depending on length of sign-up period.

Scaleway

Cloud

€3/month / on-demand

EU based (Paris, Amsterdam). Smallest option provides 2GB RAM.

Prgmr

VPS

$5/month

1 month free with a year prepay. You likely want some experience with servers with this option as they don’t have a lot of support.

Linode

Cloud

$5/month / on-demand

Multiple regions. Smallest option provides 1GB RAM

-

Please help us expand this list.

-
-
-
-

Cloud9

-

If you are interested in running Evennia in the online dev environment Cloud9, you -can spin it up through their normal online setup using the Evennia Linux install instructions. The -one extra thing you will have to do is update mygame/server/conf/settings.py and add -WEBSERVER_PORTS = [(8080, 4001)]. This will then let you access the web server and do everything -else as normal.

-

Note that, as of December 2017, Cloud9 was re-released by Amazon as a service within their AWS cloud -service offering. New customers entitled to the 1 year AWS “free tier” may find it provides -sufficient resources to operate a Cloud9 development environment without charge. -https://aws.amazon.com/cloud9/

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Parsing-command-arguments,-theory-and-best-practices.html b/docs/0.9.5/Parsing-command-arguments,-theory-and-best-practices.html deleted file mode 100644 index 687697a01d..0000000000 --- a/docs/0.9.5/Parsing-command-arguments,-theory-and-best-practices.html +++ /dev/null @@ -1,830 +0,0 @@ - - - - - - - - - Parsing command arguments, theory and best practices — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Parsing command arguments, theory and best practices

-

This tutorial will elaborate on the many ways one can parse command arguments. The first step after -adding a command usually is to parse its arguments. There are lots of -ways to do it, but some are indeed better than others and this tutorial will try to present them.

-

If you’re a Python beginner, this tutorial might help you a lot. If you’re already familiar with -Python syntax, this tutorial might still contain useful information. There are still a lot of -things I find in the standard library that come as a surprise, though they were there all along. -This might be true for others.

-

In this tutorial we will:

-
    -
  • Parse arguments with numbers.

  • -
  • Parse arguments with delimiters.

  • -
  • Take a look at optional arguments.

  • -
  • Parse argument containing object names.

  • -
-
-

What are command arguments?

-

I’m going to talk about command arguments and parsing a lot in this tutorial. So let’s be sure we -talk about the same thing before going any further:

-
-

A command is an Evennia object that handles specific user input.

-
-

For instance, the default look is a command. After having created your Evennia game, and -connected to it, you should be able to type look to see what’s around. In this context, look is -a command.

-
-

Command arguments are additional text passed after the command.

-
-

Following the same example, you can type look self to look at yourself. In this context, self -is the text specified after look. " self" is the argument to the look command.

-

Part of our task as a game developer is to connect user inputs (mostly commands) with actions in the -game. And most of the time, entering commands is not enough, we have to rely on arguments for -specifying actions with more accuracy.

-

Take the say command. If you couldn’t specify what to say as a command argument (say hello!), -you would have trouble communicating with others in the game. One would need to create a different -command for every kind of word or sentence, which is, of course, not practical.

-

Last thing: what is parsing?

-
-

In our case, parsing is the process by which we convert command arguments into something we can -work with.

-
-

We don’t usually use the command argument as is (which is just text, of type str in Python). We -need to extract useful information. We might want to ask the user for a number, or the name of -another character present in the same room. We’re going to see how to do all that now.

-
-
-

Working with strings

-

In object terms, when you write a command in Evennia (when you write the Python class), the -arguments are stored in the args attribute. Which is to say, inside your func method, you can -access the command arguments in self.args.

-
-

self.args

-

To begin with, look at this example:

-
class CmdTest(Command):
-
-    """
-    Test command.
-
-    Syntax:
-      test [argument]
-
-    Enter any argument after test.
-
-    """
-
-    key = "test"
-
-    def func(self):
-        self.msg(f"You have entered: {self.args}.")
-
-
-

If you add this command and test it, you will receive exactly what you have entered without any -parsing:

-
> test Whatever
-You have entered:  Whatever.
-> test
-You have entered: .
-
-
-
-

The lines starting with > indicate what you enter into your client. The other lines are what -you receive from the game server.

-
-

Notice two things here:

-
    -
  1. The left space between our command key (“test”, here) and our command argument is not removed. -That’s why there are two spaces in our output at line 2. Try entering something like “testok”.

  2. -
  3. Even if you don’t enter command arguments, the command will still be called with an empty string -in self.args.

  4. -
-

Perhaps a slight modification to our code would be appropriate to see what’s happening. We will -force Python to display the command arguments as a debug string using a little shortcut.

-
class CmdTest(Command):
-
-    """
-    Test command.
-
-    Syntax:
-      test [argument]
-
-    Enter any argument after test.
-
-    """
-
-    key = "test"
-
-    def func(self):
-        self.msg(f"You have entered: {self.args!r}.")
-
-
-

The only line we have changed is the last one, and we have added !r between our braces to tell -Python to print the debug version of the argument (the repr-ed version). Let’s see the result:

-
> test Whatever
-You have entered: ' Whatever'.
-> test
-You have entered: ''.
-> test And something with '?
-You have entered: " And something with '?".
-
-
-

This displays the string in a way you could see in the Python interpreter. It might be easier to -read… to debug, anyway.

-

I insist so much on that point because it’s crucial: the command argument is just a string (of type -str) and we will use this to parse it. What you will see is mostly not Evennia-specific, it’s -Python-specific and could be used in any other project where you have the same need.

-
-
-

Stripping

-

As you’ve seen, our command arguments are stored with the space. And the space between the command -and the arguments is often of no importance.

-
-

Why is it ever there?

-
-

Evennia will try its best to find a matching command. If the user enters your command key with -arguments (but omits the space), Evennia will still be able to find and call the command. You might -have seen what happened if the user entered testok. In this case, testok could very well be a -command (Evennia checks for that) but seeing none, and because there’s a test command, Evennia -calls it with the arguments "ok".

-

But most of the time, we don’t really care about this left space, so you will often see code to -remove it. There are different ways to do it in Python, but a command use case is the strip -method on str and its cousins, lstrip and rstrip.

-
    -
  • strip: removes one or more characters (either spaces or other characters) from both ends of the -string.

  • -
  • lstrip: same thing but only removes from the left end (left strip) of the string.

  • -
  • rstrip: same thing but only removes from the right end (right strip) of the string.

  • -
-

Some Python examples might help:

-
>>> '   this is '.strip() # remove spaces by default
-'this is'
->>> "   What if I'm right?   ".lstrip() # strip spaces from the left
-"What if I'm right?   "
->>> 'Looks good to me...'.strip('.') # removes '.'
-'Looks good to me'
->>> '"Now, what is it?"'.strip('"?') # removes '"' and '?' from both ends
-'Now, what is it'
-
-
-

Usually, since we don’t need the space separator, but still want our command to work if there’s no -separator, we call lstrip on the command arguments:

-
class CmdTest(Command):
-
-    """
-    Test command.
-
-    Syntax:
-      test [argument]
-
-    Enter any argument after test.
-
-    """
-
-    key = "test"
-
-    def parse(self):
-        """Parse arguments, just strip them."""
-        self.args = self.args.lstrip()
-
-    def func(self):
-        self.msg(f"You have entered: {self.args!r}.")
-
-
-
-

We are now beginning to override the command’s parse method, which is typically useful just for -argument parsing. This method is executed before func and so self.args in func() will contain -our self.args.lstrip().

-
-

Let’s try it:

-
> test Whatever
-You have entered: 'Whatever'.
-> test
-You have entered: ''.
-> test And something with '?
-You have entered: "And something with '?".
-> test     And something with lots of spaces
-You have entered: 'And something with lots of spaces'.
-
-
-

Spaces at the end of the string are kept, but all spaces at the beginning are removed:

-
-

strip, lstrip and rstrip without arguments will strip spaces, line breaks and other common -separators. You can specify one or more characters as a parameter. If you specify more than one -character, all of them will be stripped from your original string.

-
-
-
-

Convert arguments to numbers

-

As pointed out, self.args is a string (of type str). What if we want the user to enter a -number?

-

Let’s take a very simple example: creating a command, roll, that allows to roll a six-sided die. -The player has to guess the number, specifying the number as argument. To win, the player has to -match the number with the die. Let’s see an example:

-
> roll 3
-You roll a die.  It lands on the number 4.
-You played 3, you have lost.
-> dice 1
-You roll a die.  It lands on the number 2.
-You played 1, you have lost.
-> dice 1
-You roll a die.  It lands on the number 1.
-You played 1, you have won!
-
-
-

If that’s your first command, it’s a good opportunity to try to write it. A command with a simple -and finite role always is a good starting choice. Here’s how we could (first) write it… but it -won’t work as is, I warn you:

-
from random import randint
-
-from evennia import Command
-
-class CmdRoll(Command):
-
-    """
-    Play random, enter a number and try your luck.
-
-    Usage:
-      roll <number>
-
-    Enter a valid number as argument.  A random die will be rolled and you
-    will win if you have specified the correct number.
-
-    Example:
-      roll 3
-
-    """
-
-    key = "roll"
-
-    def parse(self):
-        """Convert the argument to a number."""
-        self.args = self.args.lstrip()
-
-    def func(self):
-        # Roll a random die
-        figure = randint(1, 6) # return a pseudo-random number between 1 and 6, including both
-        self.msg(f"You roll a die.  It lands on the number {figure}.")
-
-        if self.args == figure: # THAT WILL BREAK!
-            self.msg(f"You played {self.args}, you have won!")
-        else:
-            self.msg(f"You played {self.args}, you have lost.")
-
-
-

If you try this code, Python will complain that you try to compare a number with a string: figure -is a number and self.args is a string and can’t be compared as-is in Python. Python doesn’t do -“implicit converting” as some languages do. By the way, this might be annoying sometimes, and other -times you will be glad it tries to encourage you to be explicit rather than implicit about what to -do. This is an ongoing debate between programmers. Let’s move on!

-

So we need to convert the command argument from a str into an int. There are a few ways to do -it. But the proper way is to try to convert and deal with the ValueError Python exception.

-

Converting a str into an int in Python is extremely simple: just use the int function, give it -the string and it returns an integer, if it could. If it can’t, it will raise ValueError. So -we’ll need to catch that. However, we also have to indicate to Evennia that, should the number be -invalid, no further parsing should be done. Here’s a new attempt at our command with this -converting:

-
from random import randint
-
-from evennia import Command, InterruptCommand
-
-class CmdRoll(Command):
-
-    """
-    Play random, enter a number and try your luck.
-
-    Usage:
-      roll <number>
-
-    Enter a valid number as argument.  A random die will be rolled and you
-    will win if you have specified the correct number.
-
-    Example:
-      roll 3
-
-    """
-
-    key = "roll"
-
-    def parse(self):
-        """Convert the argument to number if possible."""
-        args = self.args.lstrip()
-
-        # Convert to int if possible
-        # If not, raise InterruptCommand.  Evennia will catch this
-        # exception and not call the 'func' method.
-        try:
-            self.entered = int(args)
-        except ValueError:
-            self.msg(f"{args} is not a valid number.")
-            raise InterruptCommand
-
-    def func(self):
-        # Roll a random die
-        figure = randint(1, 6) # return a pseudo-random number between 1 and 6, including both
-        self.msg(f"You roll a die.  It lands on the number {figure}.")
-
-        if self.entered == figure:
-            self.msg(f"You played {self.entered}, you have won!")
-        else:
-            self.msg(f"You played {self.entered}, you have lost.")
-
-
-

Before enjoying the result, let’s examine the parse method a little more: what it does is try to -convert the entered argument from a str to an int. This might fail (if a user enters roll something). In such a case, Python raises a ValueError exception. We catch it in our -try/except block, send a message to the user and raise the InterruptCommand exception in -response to tell Evennia to not run func(), since we have no valid number to give it.

-

In the func method, instead of using self.args, we use self.entered which we have defined in -our parse method. You can expect that, if func() is run, then self.entered contains a valid -number.

-

If you try this command, it will work as expected this time: the number is converted as it should -and compared to the die roll. You might spend some minutes playing this game. Time out!

-

Something else we could want to address: in our small example, we only want the user to enter a -positive number between 1 and 6. And the user can enter roll 0 or roll -8 or roll 208 for -that matter, the game still works. It might be worth addressing. Again, you could write a -condition to do that, but since we’re catching an exception, we might end up with something cleaner -by grouping:

-
from random import randint
-
-from evennia import Command, InterruptCommand
-
-class CmdRoll(Command):
-
-    """
-    Play random, enter a number and try your luck.
-
-    Usage:
-      roll <number>
-
-    Enter a valid number as argument.  A random die will be rolled and you
-    will win if you have specified the correct number.
-
-    Example:
-      roll 3
-
-    """
-
-    key = "roll"
-
-    def parse(self):
-        """Convert the argument to number if possible."""
-        args = self.args.lstrip()
-
-        # Convert to int if possible
-        try:
-            self.entered = int(args)
-            if not 1 <= self.entered <= 6:
-                # self.entered is not between 1 and 6 (including both)
-                raise ValueError
-        except ValueError:
-            self.msg(f"{args} is not a valid number.")
-            raise InterruptCommand
-
-    def func(self):
-        # Roll a random die
-        figure = randint(1, 6) # return a pseudo-random number between 1 and 6, including both
-        self.msg(f"You roll a die.  It lands on the number {figure}.")
-
-        if self.entered == figure:
-            self.msg(f"You played {self.entered}, you have won!")
-        else:
-            self.msg(f"You played {self.entered}, you have lost.")
-
-
-

Using grouped exceptions like that makes our code easier to read, but if you feel more comfortable -checking, afterward, that the number the user entered is in the right range, you can do so in a -latter condition.

-
-

Notice that we have updated our parse method only in this last attempt, not our func() method -which remains the same. This is one goal of separating argument parsing from command processing, -these two actions are best kept isolated.

-
-
-
-

Working with several arguments

-

Often a command expects several arguments. So far, in our example with the “roll” command, we only -expect one argument: a number and just a number. What if we want the user to specify several -numbers? First the number of dice to roll, then the guess?

-
-

You won’t win often if you roll 5 dice but that’s for the example.

-
-

So we would like to interpret a command like this:

-
> roll 3 12
-
-
-

(To be understood: roll 3 dice, my guess is the total number will be 12.)

-

What we need is to cut our command argument, which is a str, break it at the space (we use the -space as a delimiter). Python provides the str.split method which we’ll use. Again, here are -some examples from the Python interpreter:

-
>>> args = "3 12"
->>> args.split(" ")
-['3', '12']
->>> args = "a command with several arguments"
->>> args.split(" ")
-['a', 'command', 'with', 'several', 'arguments']
->>>
-
-
-

As you can see, str.split will “convert” our strings into a list of strings. The specified -argument (" " in our case) is used as delimiter. So Python browses our original string. When it -sees a delimiter, it takes whatever is before this delimiter and append it to a list.

-

The point here is that str.split will be used to split our argument. But, as you can see from the -above output, we can never be sure of the length of the list at this point:

-
>>> args = "something"
->>> args.split(" ")
-['something']
->>> args = ""
->>> args.split(" ")
-['']
->>>
-
-
-

Again we could use a condition to check the number of split arguments, but Python offers a better -approach, making use of its exception mechanism. We’ll give a second argument to str.split, the -maximum number of splits to do. Let’s see an example, this feature might be confusing at first -glance:

-
>>> args = "that is something great"
->>> args.split(" ", 1) # one split, that is a list with two elements (before, after)
-
-
-

[‘that’, ‘is something great’]

-
-
-
-
-

Read this example as many times as needed to understand it. The second argument we give to -str.split is not the length of the list that should be returned, but the number of times we have -to split. Therefore, we specify 1 here, but we get a list of two elements (before the separator, -after the separator).

-
-

What will happen if Python can’t split the number of times we ask?

-
-

It won’t:

-
>>> args = "whatever"
->>> args.split(" ", 1) # there isn't even a space here...
-['whatever']
->>>
-
-
-

This is one moment I would have hoped for an exception and didn’t get one. But there’s another way -which will raise an exception if there is an error: variable unpacking.

-

We won’t talk about this feature in details here. It would be complicated. But the code is really -straightforward to use. Let’s take our example of the roll command but let’s add a first argument: -the number of dice to roll.

-
from random import randint
-
-from evennia import Command, InterruptCommand
-
-class CmdRoll(Command):
-
-    """
-    Play random, enter a number and try your luck.
-
-    Specify two numbers separated by a space.  The first number is the
-    number of dice to roll (1, 2, 3) and the second is the expected sum
-    of the roll.
-
-    Usage:
-      roll <dice> <number>
-
-    For instance, to roll two 6-figure dice, enter 2 as first argument.
-    If you think the sum of these two dice roll will be 10, you could enter:
-
-        roll 2 10
-
-    """
-
-    key = "roll"
-
-    def parse(self):
-        """Split the arguments and convert them."""
-        args = self.args.lstrip()
-
-        # Split: we expect two arguments separated by a space
-        try:
-            number, guess = args.split(" ", 1)
-        except ValueError:
-            self.msg("Invalid usage.  Enter two numbers separated by a space.")
-            raise InterruptCommand
-
-        # Convert the entered number (first argument)
-        try:
-            self.number = int(number)
-            if self.number <= 0:
-                raise ValueError
-        except ValueError:
-            self.msg(f"{number} is not a valid number of dice.")
-            raise InterruptCommand
-
-        # Convert the entered guess (second argument)
-        try:
-            self.guess = int(guess)
-            if not 1 <= self.guess <= self.number * 6:
-                raise ValueError
-        except ValueError:
-            self.msg(f"{self.guess} is not a valid guess.")
-            raise InterruptCommand
-
-    def func(self):
-        # Roll a random die X times (X being self.number)
-        figure = 0
-        for _ in range(self.number):
-            figure += randint(1, 6)
-
-        self.msg(f"You roll {self.number} dice and obtain the sum {figure}.")
-
-        if self.guess == figure:
-            self.msg(f"You played {self.guess}, you have won!")
-        else:
-            self.msg(f"You played {self.guess}, you have lost.")
-
-
-

The beginning of the parse() method is what interests us most:

-
try:
-    number, guess = args.split(" ", 1)
-except ValueError:
-    self.msg("Invalid usage.  Enter two numbers separated by a space.")
-    raise InterruptCommand
-
-
-

We split the argument using str.split but we capture the result in two variables. Python is smart -enough to know that we want what’s left of the space in the first variable, what’s right of the -space in the second variable. If there is not even a space in the string, Python will raise a -ValueError exception.

-

This code is much easier to read than browsing through the returned strings of str.split. We can -convert both variables the way we did previously. Actually there are not so many changes in this -version and the previous one, most of it is due to name changes for clarity.

-
-

Splitting a string with a maximum of splits is a common occurrence while parsing command -arguments. You can also see the str.rspli8t method that does the same thing but from the right of -the string. Therefore, it will attempt to find delimiters at the end of the string and work toward -the beginning of it.

-
-

We have used a space as a delimiter. This is absolutely not necessary. You might remember that -most default Evennia commands can take an = sign as a delimiter. Now you know how to parse them -as well:

-
>>> cmd_key = "tel"
->>> cmd_args = "book = chest"
->>> left, right = cmd_args.split("=") # mighht raise ValueError!
->>> left
-'book '
->>> right
-' chest'
->>>
-
-
-
-
-

Optional arguments

-

Sometimes, you’ll come across commands that have optional arguments. These arguments are not -necessary but they can be set if more information is needed. I will not provide the entire command -code here but just enough code to show the mechanism in Python:

-

Again, we’ll use str.split, knowing that we might not have any delimiter at all. For instance, -the player could enter the “tel” command like this:

-
> tel book
-> tell book = chest
-
-
-

The equal sign is optional along with whatever is specified after it. A possible solution in our -parse method would be:

-
    def parse(self):
-        args = self.args.lstrip()
-
-        # = is optional
-        try:
-            obj, destination = args.split("=", 1)
-        except ValueError:
-            obj = args
-            destination = None
-
-
-

This code would place everything the user entered in obj if she didn’t specify any equal sign. -Otherwise, what’s before the equal sign will go in obj, what’s after the equal sign will go in -destination. This makes for quick testing after that, more robust code with less conditions that -might too easily break your code if you’re not careful.

-
-

Again, here we specified a maximum numbers of splits. If the users enters:

-
-
> tel book = chest = chair
-
-
-

Then destination will contain: " chest = chair". This is often desired, but it’s up to you to -set parsing however you like.

-
-
-
-

Evennia searches

-

After this quick tour of some str methods, we’ll take a look at some Evennia-specific features -that you won’t find in standard Python.

-

One very common task is to convert a str into an Evennia object. Take the previous example: -having "book" in a variable is great, but we would prefer to know what the user is talking -about… what is this "book"?

-

To get an object from a string, we perform an Evennia search. Evennia provides a search method on -all typeclassed objects (you will most likely use the one on characters or accounts). This method -supports a very wide array of arguments and has its own tutorial. -Some examples of useful cases follow:

-
-

Local searches

-

When an account or a character enters a command, the account or character is found in the caller -attribute. Therefore, self.caller will contain an account or a character (or a session if that’s -a session command, though that’s not as frequent). The search method will be available on this -caller.

-

Let’s take the same example of our little “tel” command. The user can specify an object as -argument:

-
    def parse(self):
-        name = self.args.lstrip()
-
-
-

We then need to “convert” this string into an Evennia object. The Evennia object will be searched -in the caller’s location and its contents by default (that is to say, if the command has been -entered by a character, it will search the object in the character’s room and the character’s -inventory).

-
    def parse(self):
-        name = self.args.lstrip()
-
-        self.obj = self.caller.search(name)
-
-
-

We specify only one argument to the search method here: the string to search. If Evennia finds a -match, it will return it and we keep it in the obj attribute. If it can’t find anything, it will -return None so we need to check for that:

-
    def parse(self):
-        name = self.args.lstrip()
-
-        self.obj = self.caller.search(name)
-        if self.obj is None:
-            # A proper error message has already been sent to the caller
-            raise InterruptCommand
-
-
-

That’s it. After this condition, you know that whatever is in self.obj is a valid Evennia object -(another character, an object, an exit…).

-
-
-

Quiet searches

-

By default, Evennia will handle the case when more than one match is found in the search. The user -will be asked to narrow down and re-enter the command. You can, however, ask to be returned the -list of matches and handle this list yourself:

-
    def parse(self):
-        name = self.args.lstrip()
-
-        objs = self.caller.search(name, quiet=True)
-        if not objs:
-            # This is an empty list, so no match
-            self.msg(f"No {name!r} was found.")
-            raise InterruptCommand
-        
-        self.obj = objs[0] # Take the first match even if there are several
-
-
-

All we have changed to obtain a list is a keyword argument in the search method: quiet. If set -to True, then errors are ignored and a list is always returned, so we need to handle it as such. -Notice in this example, self.obj will contain a valid object too, but if several matches are -found, self.obj will contain the first one, even if more matches are available.

-
-
-

Global searches

-

By default, Evennia will perform a local search, that is, a search limited by the location in which -the caller is. If you want to perform a global search (search in the entire database), just set the -global_search keyword argument to True:

-
    def parse(self):
-        name = self.args.lstrip()
-        self.obj = self.caller.search(name, global_search=True)
-
-
-
-
-
-

Conclusion

-

Parsing command arguments is vital for most game designers. If you design “intelligent” commands, -users should be able to guess how to use them without reading the help, or with a very quick peek at -said help. Good commands are intuitive to users. Better commands do what they’re told to do. For -game designers working on MUDs, commands are the main entry point for users into your game. This is -no trivial. If commands execute correctly (if their argument is parsed, if they don’t behave in -unexpected ways and report back the right errors), you will have happier players that might stay -longer on your game. I hope this tutorial gave you some pointers on ways to improve your command -parsing. There are, of course, other ways you will discover, or ways you are already using in your -code.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Portal-And-Server.html b/docs/0.9.5/Portal-And-Server.html deleted file mode 100644 index 948ef68496..0000000000 --- a/docs/0.9.5/Portal-And-Server.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - - - Portal And Server — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Portal And Server

-

Evennia consists of two processes, known as Portal and Server. They can be controlled from -inside the game or from the command line as described here.

-

If you are new to the concept, the main purpose of separating the two is to have accounts connect to -the Portal but keep the MUD running on the Server. This way one can restart/reload the game (the -Server part) without Accounts getting disconnected.

-

portal and server layout

-

The Server and Portal are glued together via an AMP (Asynchronous Messaging Protocol) connection. -This allows the two programs to communicate seamlessly.

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Profiling.html b/docs/0.9.5/Profiling.html deleted file mode 100644 index e556ad6bb2..0000000000 --- a/docs/0.9.5/Profiling.html +++ /dev/null @@ -1,234 +0,0 @@ - - - - - - - - - Profiling — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Profiling

-

This is considered an advanced topic mainly of interest to server developers.

-
-

Introduction

-

Sometimes it can be useful to try to determine just how efficient a particular piece of code is, or -to figure out if one could speed up things more than they are. There are many ways to test the -performance of Python and the running server.

-

Before digging into this section, remember Donald Knuth’s words of -wisdom:

-
-

[…]about 97% of the time: Premature optimization is the root of all evil.

-
-

That is, don’t start to try to optimize your code until you have actually identified a need to do -so. This means your code must actually be working before you start to consider optimization. -Optimization will also often make your code more complex and harder to read. Consider readability -and maintainability and you may find that a small gain in speed is just not worth it.

-
-
-

Simple timer tests

-

Python’s timeit module is very good for testing small things. For example, in order to test if it -is faster to use a for loop or a list comprehension you could use the following code:

-
    import timeit
-    # Time to do 1000000 for loops
-    timeit.timeit("for i in range(100):\n    a.append(i)", setup="a = []")
-   <<< 10.70982813835144
-    # Time to do 1000000 list comprehensions
-    timeit.timeit("a = [i for i in range(100)]")
-   <<<  5.358283996582031
-
-
-

The setup keyword is used to set up things that should not be included in the time measurement, -like a = [] in the first call.

-

By default the timeit function will re-run the given test 1000000 times and returns the total -time to do so (so not the average per test). A hint is to not use this default for testing -something that includes database writes - for that you may want to use a lower number of repeats -(say 100 or 1000) using the number=100 keyword.

-
-
-

Using cProfile

-

Python comes with its own profiler, named cProfile (this is for cPython, no tests have been done -with pypy at this point). Due to the way Evennia’s processes are handled, there is no point in -using the normal way to start the profiler (python -m cProfile evennia.py). Instead you start the -profiler through the launcher:

-
evennia --profiler start
-
-
-

This will start Evennia with the Server component running (in daemon mode) under cProfile. You could -instead try --profile with the portal argument to profile the Portal (you would then need to -start the Server separately).

-

Please note that while the profiler is running, your process will use a lot more memory than usual. -Memory usage is even likely to climb over time. So don’t leave it running perpetually but monitor it -carefully (for example using the top command on Linux or the Task Manager’s memory display on -Windows).

-

Once you have run the server for a while, you need to stop it so the profiler can give its report. -Do not kill the program from your task manager or by sending it a kill signal - this will most -likely also mess with the profiler. Instead either use evennia.py stop or (which may be even -better), use @shutdown from inside the game.

-

Once the server has fully shut down (this may be a lot slower than usual) you will find that -profiler has created a new file mygame/server/logs/server.prof.

-
-
-

Analyzing the profile

-

The server.prof file is a binary file. There are many ways to analyze and display its contents, -all of which has only been tested in Linux (If you are a Windows/Mac user, let us know what works).

-

We recommend the -Runsnake visualizer to see the processor usage -of different processes in a graphical form. For more detailed listing of usage time, you can use -KCachegrind. To make KCachegrind work with -Python profiles you also need the wrapper script -pyprof2calltree. You can get pyprof2calltree via -pip whereas KCacheGrind is something you need to get via your package manager or their homepage.

-

How to analyze and interpret profiling data is not a trivial issue and depends on what you are -profiling for. Evennia being an asynchronous server can also confuse profiling. Ask on the mailing -list if you need help and be ready to be able to supply your server.prof file for comparison, -along with the exact conditions under which it was obtained.

-
-
-

The Dummyrunner

-

It is difficult to test “actual” game performance without having players in your game. For this -reason Evennia comes with the Dummyrunner system. The Dummyrunner is a stress-testing system: a -separate program that logs into your game with simulated players (aka “bots” or “dummies”). Once -connected these dummies will semi-randomly perform various tasks from a list of possible actions. -Use Ctrl-C to stop the Dummyrunner.

-
-

Warning: You should not run the Dummyrunner on a production database. It will spawn many objects -and also needs to run with general permissions.

-
-

To launch the Dummyrunner, first start your server normally (with or without profiling, as above). -Then start a new terminal/console window and active your virtualenv there too. In the new terminal, -try to connect 10 dummy players:

-
evennia --dummyrunner 10
-
-
-

The first time you do this you will most likely get a warning from Dummyrunner. It will tell you to -copy an import string to the end of your settings file. Quit the Dummyrunner (Ctrl-C) and follow -the instructions. Restart Evennia and try evennia --dummyrunner 10 again. Make sure to remove that -extra settings line when running a public server.

-

The actions perform by the dummies is controlled by a settings file. The default Dummyrunner -settings file is evennia/server/server/profiling/dummyrunner_settings.py but you shouldn’t modify -this directly. Rather create/copy the default file to mygame/server/conf/ and modify it there. To -make sure to use your file over the default, add the following line to your settings file:

-
DUMMYRUNNER_SETTINGS_MODULE = "server/conf/dummyrunner_settings.py"
-
-
-
-

Hint: Don’t start with too many dummies. The Dummyrunner defaults to taxing the server much more -intensely than an equal number of human players. A good dummy number to start with is 10-100.

-
-

Once you have the dummyrunner running, stop it with Ctrl-C.

-

Generally, the dummyrunner system makes for a decent test of general performance; but it is of -course hard to actually mimic human user behavior. For this, actual real-game testing is required.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Python-3.html b/docs/0.9.5/Python-3.html deleted file mode 100644 index ce2e7d1f36..0000000000 --- a/docs/0.9.5/Python-3.html +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - - - Python 3 — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Python 3

-

Evennia supports Python 3+ since v0.8. This page is deprecated.

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Python-basic-introduction.html b/docs/0.9.5/Python-basic-introduction.html deleted file mode 100644 index df1ffd01fd..0000000000 --- a/docs/0.9.5/Python-basic-introduction.html +++ /dev/null @@ -1,362 +0,0 @@ - - - - - - - - - Python basic introduction — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Python basic introduction

-

This is the first part of our beginner’s guide to the basics of using Python with Evennia. It’s -aimed at you with limited or no programming/Python experience. But also if you are an experienced -programmer new to Evennia or Python you might still pick up a thing or two. It is by necessity brief -and low on detail. There are countless Python guides and tutorials, books and videos out there for -learning more in-depth - use them!

-

Contents:

- -

This quickstart assumes you have gotten Evennia started. You should make sure -that you are able to see the output from the server in the console from which you started it. Log -into the game either with a mud client on localhost:4000 or by pointing a web browser to -localhost:4001/webclient. Log in as your superuser (the user you created during install).

-

Below, lines starting with a single > means command input.

-
-

Evennia Hello world

-

The py (or ! which is an alias) command allows you as a superuser to run raw Python from in- -game. From the game’s input line, enter the following:

-
> py print("Hello World!")
-
-
-

You will see

-
> print("Hello world!")
-Hello World
-
-
-

To understand what is going on: some extra info: The print(...) function is the basic, in-built -way to output text in Python. The quotes "..." means you are inputing a string (i.e. text). You -could also have used single-quotes '...', Python accepts both.

-

The first return line (with >>>) is just py echoing what you input (we won’t include that in the -examples henceforth).

-
-

Note: You may sometimes see people/docs refer to @py or other commands starting with @. -Evennia ignores @ by default, so @py is the exact same thing as py.

-
-

The print command is a standard Python structure. We can use that here in the py command, and -it’s great for debugging and quick testing. But if you need to send a text to an actual player, -print won’t do, because it doesn’t know who to send to. Try this:

-
> py me.msg("Hello world!")
-Hello world!
-
-
-

This looks the same as the print result, but we are now actually messaging a specific object, -me. The me is something uniquely available in the py command (we could also use self, it’s -an alias). It represents “us”, the ones calling the py command. The me is an example of an -Object instance. Objects are fundamental in Python and Evennia. The me object not only -represents the character we play in the game, it also contains a lot of useful resources for doing -things with that Object. One such resource is msg. msg works like print except it sends the -text to the object it is attached to. So if we, for example, had an object you, doing -you.msg(...) would send a message to the object you.

-

You access an Object’s resources by using the full-stop character .. So self.msg accesses the -msg resource and then we call it like we did print, with our “Hello World!” greeting in -parentheses.

-
-

Important: something like print(...) we refer to as a function, while msg(...) which sits on -an object is called a method.

-
-

For now, print and me.msg behaves the same, just remember that you’re going to mostly be using -the latter in the future. Try printing other things. Also try to include |r at the start of your -string to make the output red in-game. Use color to learn more color tags.

-
-
-

Importing modules

-

Keep your game running, then open a text editor of your choice. If your game folder is called -mygame, create a new text file test.py in the subfolder mygame/world. This is how the file -structure should look:

-
mygame/
-    world/
-        test.py
-
-
-

For now, only add one line to test.py:

-
print("Hello World!")
-
-
-

Don’t forget to save the file. A file with the ending .py is referred to as a Python module. To -use this in-game we have to import it. Try this:

-
> @py import world.test
-Hello World
-
-
-

If you make some error (we’ll cover how to handle errors below) you may need to run the @reload -command for your changes to take effect.

-

So importing world.test actually means importing world/test.py. Think of the period . as -replacing / (or \ for Windows) in your path. The .py ending of test.py is also never -included in this “Python-path”, but only files with that ending can be imported this way. Where is -mygame in that Python-path? The answer is that Evennia has already told Python that your mygame -folder is a good place to look for imports. So we don’t include mygame in the path - Evennia -handles this for us.

-

When you import the module, the top “level” of it will execute. In this case, it will immediately -print “Hello World”.

-
-

If you look in the folder you’ll also often find new files ending with .pyc. These are compiled -Python binaries that Python auto-creates when running code. Just ignore them, you should never edit -those anyway.

-
-

Now try to run this a second time:

-
> py import world.test
-
-
-

You will not see any output this second time or any subsequent times! This is not a bug. Rather -it is because Python is being clever - it stores all imported modules and to be efficient it will -avoid importing them more than once. So your print will only run the first time, when the module -is first imported. To see it again you need to @reload first, so Python forgets about the module -and has to import it again.

-

We’ll get back to importing code in the second part of this tutorial. For now, let’s press on.

-
-
-

Parsing Python errors

-

Next, erase the single print statement you had in test.py and replace it with this instead:

-
me.msg("Hello World!")
-
-
-

As you recall we used this from py earlier - it echoed “Hello World!” in-game. -Save your file and reload your server - this makes sure Evennia sees the new version of your code. -Try to import it from py in the same way as earlier:

-
> py import world.test
-
-
-

No go - this time you get an error!

-
File "./world/test.py", line 1, in <module>
-    me.msg("Hello world!")
-NameError: name 'me' is not defined
-
-
-

This is called a traceback. Python’s errors are very friendly and will most of the time tell you -exactly what and where things are wrong. It’s important that you learn to parse tracebacks so you -can fix your code. Let’s look at this one. A traceback is to be read from the bottom up. The last -line is the error Python balked at, while the two lines above it details exactly where that error -was encountered.

-
    -
  1. An error of type NameError is the problem …

  2. -
  3. … more specifically it is due to the variable me not being defined.

  4. -
  5. This happened on the line me.msg("Hello world!")

  6. -
  7. … which is on line 1 of the file ./world/test.py.

  8. -
-

In our case the traceback is short. There may be many more lines above it, tracking just how -different modules called each other until it got to the faulty line. That can sometimes be useful -information, but reading from the bottom is always a good start.

-

The NameError we see here is due to a module being its own isolated thing. It knows nothing about -the environment into which it is imported. It knew what print is because that is a special -reserved Python keyword. But me is not such a -reserved word. As far as the module is concerned me is just there out of nowhere. Hence the -NameError.

-
-
-

Our first function

-

Let’s see if we can resolve that NameError from the previous section. We know that me is defined -at the time we use the @py command because if we do py me.msg("Hello World!") directly in-game -it works fine. What if we could send that me to the test.py module so it knows what it is? One -way to do this is with a function.

-

Change your mygame/world/test.py file to look like this:

-
def hello_world(who):
-    who.msg("Hello World!")
-
-
-

Now that we are moving onto multi-line Python code, there are some important things to remember:

-
    -
  • Capitalization matters in Python. It must be def and not DEF, who is not the same as Who -etc.

  • -
  • Indentation matters in Python. The second line must be indented or it’s not valid code. You should -also use a consistent indentation length. We strongly recommend that you set up your editor to -always indent 4 spaces (not a single tab-character) when you press the TAB key - it will make -your life a lot easier.

  • -
  • def is short for “define” and defines a function (or a method, if sitting on an object). -This is a reserved Python keyword; try not to use -these words anywhere else.

  • -
  • A function name can not have spaces but otherwise we could have called it almost anything. We call -it hello_world. Evennia follows [Python’s standard naming style](https://github.com/evennia/evennia/blob/master/CODING_STYLE.md#a-quick-list-of-code-style- -points) with lowercase letters and underscores. Use this style for now.

  • -
  • who is what we call the argument to our function. Arguments are variables we pass to the -function. We could have named it anything and we could also have multiple arguments separated by -commas. What who is depends on what we pass to this function when we call it later (hint: we’ll -pass me to it).

  • -
  • The colon (:) at the end of the first line indicates that the header of the function is -complete.

  • -
  • The indentation marks the beginning of the actual operating code of the function (the function’s -body). If we wanted more lines to belong to this function those lines would all have to have to -start at this indentation level.

  • -
  • In the function body we take the who argument and treat it as we would have treated me earlier

  • -
  • we expect it to have a .msg method we can use to send “Hello World” to.

  • -
-

First, reload your game to make it aware of the updated Python module. Now we have defined our -first function, let’s use it.

-
> reload
-> py import world.test
-
-
-

Nothing happened! That is because the function in our module won’t do anything just by importing it. -It will only act when we call it. We will need to enter the module we just imported and do so.

-
> py import world.test ; world.test.hello_world(me)
-Hello world!
-
-
-

There is our “Hello World”! The ; is the way to put multiple Python-statements on one line.

-
-

Some MUD clients use ; for their own purposes to separate client-inputs. If so you’ll get a -NameError stating that world is not defined. Check so you understand why this is! Change the use -of ; in your client or use the Evennia web client if this is a problem.

-
-

In the second statement we access the module path we imported (world.test) and reach for the -hello_world function within. We call the function with me, which becomes the who variable we -use inside the hello_function.

-
-

As an exercise, try to pass something else into hello_world. Try for example to pass who as -the number 5 or the simple string "foo". You’ll get errors that they don’t have the attribute -msg. As we’ve seen, me does make msg available which is why it works (you’ll learn more -about Objects like me in the next part of this tutorial). If you are familiar with other -programming languages you may be tempted to start validating who to make sure it works as -expected. This is usually not recommended in Python which suggests it’s better to -handle the error if it happens rather than to make -a lot of code to prevent it from happening. See also duck -typing.

-
-
-
-
-

Looking at the log

-

As you start to explore Evennia, it’s important that you know where to look when things go wrong. -While using the friendly py command you’ll see errors directly in-game. But if something goes -wrong in your code while the game runs, you must know where to find the log.

-

Open a terminal (or go back to the terminal you started Evennia in), make sure your virtualenv is -active and that you are standing in your game directory (the one created with evennia --init -during installation). Enter

-
evennia --log
-
-
-

(or evennia -l)

-

This will show the log. New entries will show up in real time. Whenever you want to leave the log, -enter Ctrl-C or Cmd-C depending on your system. As a game dev it is important to look at the -log output when working in Evennia - many errors will only appear with full details here. You may -sometimes have to scroll up in the history if you miss it.

-

This tutorial is continued in Part 2, where we’ll start learning -about objects and to explore the Evennia library.

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Python-basic-tutorial-part-two.html b/docs/0.9.5/Python-basic-tutorial-part-two.html deleted file mode 100644 index 71d9ad1893..0000000000 --- a/docs/0.9.5/Python-basic-tutorial-part-two.html +++ /dev/null @@ -1,571 +0,0 @@ - - - - - - - - - Python basic tutorial part two — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Python basic tutorial part two

-

In the first part of this Python-for-Evennia basic tutorial we learned -how to run some simple Python code from inside the game. We also made our first new module -containing a function that we called. Now we’re going to start exploring the very important -subject of objects.

-

Contents:

- -
-

On the subject of objects

-

In the first part of the tutorial we did things like

-
> py me.msg("Hello World!")
-
-
-

To learn about functions and imports we also passed that me on to a function hello_world in -another module.

-

Let’s learn some more about this me thing we are passing around all over the place. In the -following we assume that we named our superuser Character “Christine”.

-
> py me
-Christine
-> py me.key
-Christine
-
-
-

These returns look the same at first glance, but not if we examine them more closely:

-
> py type(me)
-<class 'typeclasses.characters.Character'>
-> py type(me.key)
-<type str>
-
-
-
-

Note: In some MU clients, such as Mudlet and MUSHclient simply returning type(me), you may not -see the proper return from the above commands. This is likely due to the HTML-like tags <...>, -being swallowed by the client.

-
-

The type function is, like print, another in-built function in Python. It -tells us that we (me) are of the class typeclasses.characters.Character. -Meanwhile me.key is a property on us, a string. It holds the name of this -object.

-
-

When you do py me, the me is defined in such a way that it will use its .key property to -represent itself. That is why the result is the same as when doing py me.key. Also, remember that -as noted in the first part of the tutorial, the me is not a reserved Python word; it was just -defined by the Evennia developers as a convenient short-hand when creating the py command. So -don’t expect me to be available elsewhere.

-
-

A class is like a “factory” or blueprint. From a class you then create individual instances. So -if class isDog, an instance of Dog might be fido. Our in-game persona is of a class -Character. The superuser christine is an instance of the Character class (an instance is -also often referred to as an object). This is an important concept in object oriented -programming. You are wise to familiarize yourself with it a little.

-
-

In other terms:

-
    -
  • class: A description of a thing, all the methods (code) and data (information)

  • -
  • object: A thing, defined as an instance of a class.

  • -
-

So in “Fido is a Dog”, “Fido” is an object–a unique thing–and “Dog” is a class. Coders would -also say, “Fido is an instance of Dog”. There can be other dogs too, such as Butch and Fifi. They, -too, would be instances of Dog.

-

As another example: “Christine is a Character”, or “Christine is an instance of -typeclasses.characters.Character”. To start, all characters will be instances of -typeclass.characters.Character.

-

You’ll be writing your own class soon! The important thing to know here is how classes and objects -relate.

-
-

The string 'typeclasses.characters.Character' we got from the type() function is not arbitrary. -You’ll recognize this from when we imported world.test in part one. This is a path exactly -describing where to find the python code describing this class. Python treats source code files on -your hard drive (known as modules) as well as folders (known as packages) as objects that you -access with the . operator. It starts looking at a place that Evennia has set up for you - namely -the root of your own game directory.

-

Open and look at your game folder (named mygame if you exactly followed the Getting Started -instructions) in a file editor or in a new terminal/console. Locate the file -mygame/typeclasses/characters.py

-
mygame/
-    typeclasses
-        characters.py
-
-
-

This represents the first part of the python path - typeclasses.characters (the .py file ending -is never included in the python path). The last bit, .Character is the actual class name inside -the characters.py module. Open that file in a text editor and you will see something like this:

-
"""
-(Doc string for module)
-"""
-
-from evennia import DefaultCharacter
-
-class Character(DefaultCharacter):
-    """
-    (Doc string for class)
-    """
-    pass
-
-
-
-

There is Character, the last part of the path. Note how empty this file is. At first glance one -would think a Character had no functionality at all. But from what we have used already we know it -has at least the key property and the method msg! Where is the code? The answer is that this -‘emptiness’ is an illusion caused by something called inheritance. Read on.

-

Firstly, in the same way as the little hello.py we did in the first part of the tutorial, this is -an example of full, multi-line Python code. Those triple-quoted strings are used for strings that -have line breaks in them. When they appear on their own like this, at the top of a python module, -class or similar they are called doc strings. Doc strings are read by Python and is used for -producing online help about the function/method/class/module. By contrast, a line starting with # -is a comment. It is ignored completely by Python and is only useful to help guide a human to -understand the code.

-

The line

-
    class Character(DefaultCharacter):
-
-
-

means that the class Character is a child of the class DefaultCharacter. This is called -inheritance and is another fundamental concept. The answer to the question “where is the code?” is -that the code is inherited from its parent, DefaultCharacter. And that in turn may inherit code -from its parent(s) and so on. Since our child, Character is empty, its functionality is exactly -identical to that of its parent. The moment we add new things to Character, these will take -precedence. And if we add something that already existed in the parent, our child-version will -override the version in the parent. This is very practical: It means that we can let the parent do -the heavy lifting and only tweak the things we want to change. It also means that we could easily -have many different Character classes, all inheriting from DefaultCharacter but changing different -things. And those can in turn also have children …

-

Let’s go on an expedition up the inheritance tree.

-
-
-

Exploring the Evennia library

-

Let’s figure out how to tweak Character. Right now we don’t know much about DefaultCharacter -though. Without knowing that we won’t know what to override. At the top of the file you find

-
from evennia import DefaultCharacter
-
-
-

This is an import statement again, but on a different form to what we’ve seen before. from ... import ... is very commonly used and allows you to precisely dip into a module to extract just the -component you need to use. In this case we head into the evennia package to get -DefaultCharacter.

-

Where is evennia? To find it you need to go to the evennia folder (repository) you originally -cloned from us. If you open it, this is how it looks:

-
evennia/
-   __init__.py
-   bin/
-   CHANGELOG.txt etc.
-   ...
-   evennia/
-   ...
-
-
-

There are lots of things in there. There are some docs but most of those have to do with the -distribution of Evennia and does not concern us right now. The evennia subfolder is what we are -looking for. This is what you are accessing when you do from evennia import .... It’s set up by -Evennia as a good place to find modules when the server starts. The exact layout of the Evennia -library is covered by our directory overview. You can -also explore it online on github.

-

The structure of the library directly reflects how you import from it.

-
    -
  • To, for example, import the text justify function from -evennia/utils/utils.py you would do from evennia.utils.utils import justify. In your code you -could then just call justify(...) to access its functionality.

  • -
  • You could also do from evennia.utils import utils. In code you would then have to write -utils.justify(...). This is practical if want a lot of stuff from that utils.py module and don’t -want to import each component separately.

  • -
  • You could also do import evennia. You would then have to enter the full -evennia.utils.utils.justify(...) every time you use it. Using from to only import the things you -need is usually easier and more readable.

  • -
  • See this overview about the different ways to -import in Python.

  • -
-

Now, remember that our characters.py module did from evennia import DefaultCharacter. But if we -look at the contents of the evennia folder, there is no DefaultCharacter anywhere! This is -because Evennia gives a large number of optional “shortcuts”, known as the “flat” API. The intention is to make it easier to remember where to find stuff. The flat API is defined in -that weirdly named __init__.py file. This file just basically imports useful things from all over -Evennia so you can more easily find them in one place.

-

We could just look at the documenation to find out where we can look -at our DefaultCharacter parent. But for practice, let’s figure it out. Here is where -DefaultCharacter is imported from inside __init__.py:

-
from .objects.objects import DefaultCharacter
-
-
-

The period at the start means that it imports beginning from the same location this module sits(i.e. -the evennia folder). The full python-path accessible from the outside is thus -evennia.objects.objects.DefaultCharacter. So to import this into our game it’d be perfectly valid -to do

-
from evennia.objects.objects import DefaultCharacter
-
-
-

Using

-
from evennia import DefaultCharacter
-
-
-

is the same thing, just a little easier to remember.

-
-

To access the shortcuts of the flat API you must use from evennia import .... Using something like import evennia.DefaultCharacter will not work. -See more about the Flat API here.

-
-
-
-

Tweaking our Character class

-

In the previous section we traced the parent of our Character class to be -DefaultCharacter in -evennia/objects/objects.py. -Open that file and locate the DefaultCharacter class. It’s quite a bit down -in this module so you might want to search using your editor’s (or browser’s) -search function. Once you find it, you’ll find that the class starts like this:

-

-class DefaultCharacter(DefaultObject):
-    """
-    This implements an Object puppeted by a Session - that is, a character
-    avatar controlled by an account.
-    """
-
-    def basetype_setup(self):
-        """
-        Setup character-specific security.
-        You should normally not need to overload this, but if you do,
-        make sure to reproduce at least the two last commands in this
-        method (unless you want to fundamentally change how a
-        Character object works).
-        """
-        super().basetype_setup()
-        self.locks.add(";".join(["get:false()",     # noone can pick up the character
-                                 "call:false()"]))  # no commands can be called on character from
-outside
-        # add the default cmdset
-        self.cmdset.add_default(settings.CMDSET_CHARACTER, permanent=True)
-
-    def at_after_move(self, source_location, **kwargs):
-        """
-        We make sure to look around after a move.
-        """
-        if self.location.access(self, "view"):
-            self.msg(self.at_look(self.location))
-
-    def at_pre_puppet(self, account, session=None, **kwargs):
-        """
-        Return the character from storage in None location in `at_post_unpuppet`.
-        """
-
-    # ...
-
-
-
-

… And so on (you can see the full class online here). Here we -have functional code! These methods may not be directly visible in Character back in our game dir, -but they are still available since Character is a child of DefaultCharacter above. Here is a -brief summary of the methods we find in DefaultCharacter (follow in the code to see if you can see -roughly where things happen)::

-
    -
  • basetype_setup is called by Evennia only once, when a Character is first created. In the -DefaultCharacter class it sets some particular Locks so that people can’t pick up and -puppet Characters just like that. It also adds the Character Cmdset so that -Characters always can accept command-input (this should usually not be modified - the normal hook to -override is at_object_creation, which is called after basetype_setup (it’s in the parent)).

  • -
  • at_after_move makes it so that every time the Character moves, the look command is -automatically fired (this would not make sense for just any regular Object).

  • -
  • at_pre_puppet is called when an Account begins to puppet this Character. When not puppeted, the -Character is hidden away to a None location. This brings it back to the location it was in before. -Without this, “headless” Characters would remain in the game world just standing around.

  • -
  • at_post_puppet is called when puppeting is complete. It echoes a message to the room that his -Character has now connected.

  • -
  • at_post_unpuppet is called once stopping puppeting of the Character. This hides away the -Character to a None location again.

  • -
  • There are also some utility properties which makes it easier to get some time stamps from the -Character.

  • -
-

Reading the class we notice another thing:

-
class DefaultCharacter(DefaultObject):
-    # ...
-
-
-

This means that DefaultCharacter is in itself a child of something called DefaultObject! Let’s -see what this parent class provides. It’s in the same module as DefaultCharacter, you just need to -scroll up near the top:

-
class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
-   # ...
-
-
-

This is a really big class where the bulk of code defining an in-game object resides. It consists of -a large number of methods, all of which thus also becomes available on the DefaultCharacter class -below and by extension in your Character class over in your game dir. In this class you can for -example find the msg method we have been using before.

-
-

You should probably not expect to understand all details yet, but as an exercise, find and read -the doc string of msg.

-
-
-

As seen, DefaultObject actually has multiple parents. In one of those the basic key property -is defined, but we won’t travel further up the inheritance tree in this tutorial. If you are -interested to see them, you can find TypeclassBase in evennia/typeclasses/models.py and ObjectDB in evennia/obj -ects/models.py. We -will also not go into the details of Multiple Inheritance or -Metaclasses here. The general rule -is that if you realize that you need these features, you already know enough to use them.

-
-

Remember the at_pre_puppet method we looked at in DefaultCharacter? If you look at the -at_pre_puppet hook as defined in DefaultObject you’ll find it to be completely empty (just a -pass). So if you puppet a regular object it won’t be hiding/retrieving the object when you -unpuppet it. The DefaultCharacter class overrides its parent’s functionality with a version of -its own. And since it’s DefaultCharacter that our Character class inherits back in our game dir, -it’s that version of at_pre_puppet we’ll get. Anything not explicitly overridden will be passed -down as-is.

-

While it’s useful to read the code, we should never actually modify anything inside the evennia -folder. Only time you would want that is if you are planning to release a bug fix or new feature for -Evennia itself. Instead you override the default functionality inside your game dir.

-

So to conclude our little foray into classes, objects and inheritance, locate the simple little -at_before_say method in the DefaultObject class:

-
    def at_before_say(self, message, **kwargs):
-        """
-        (doc string here)
-        """
-        return message
-
-
-

If you read the doc string you’ll find that this can be used to modify the output of say before it -goes out. You can think of it like this: Evennia knows the name of this method, and when someone -speaks, Evennia will make sure to redirect the outgoing message through this method. It makes it -ripe for us to replace with a version of our own.

-
-

In the Evennia documentation you may sometimes see the term hook used for a method explicitly -meant to be overridden like this.

-
-

As you can see, the first argument to at_before_say is self. In Python, the first argument of a -method is always a back-reference to the object instance on which the method is defined. By -convention this argument is always called self but it could in principle be named anything. The -self is very useful. If you wanted to, say, send a message to the same object from inside -at_before_say, you would do self.msg(...).

-

What can trip up newcomers is that you don’t include self when you call the method. Try:

-
> @py me.at_before_say("Hello World!")
-Hello World!
-
-
-

Note that we don’t send self but only the message argument. Python will automatically add self -for us. In this case, self will become equal to the Character instance me.

-

By default the at_before_say method doesn’t do anything. It just takes the message input and -returns it just the way it was (the return is another reserved Python word).

-
-

We won’t go into **kwargs here, but it (and its sibling *args) is also important to -understand, extra reading is here for **kwargs.

-
-

Now, open your game folder and edit mygame/typeclasses/characters.py. Locate your Character -class and modify it as such:

-
class Character(DefaultCharacter):
-    """
-    (docstring here)
-    """
-    def at_before_say(self, message, **kwargs):
-        "Called before say, allows for tweaking message"
-        return f"{message} ..."
-
-
-

So we add our own version of at_before_say, duplicating the def line from the parent but putting -new code in it. All we do in this tutorial is to add an ellipsis (...) to the message as it passes -through the method.

-

Note that f in front of the string, it means we turned the string into a ‘formatted string’. We -can now easily inject stuff directly into the string by wrapping them in curly brackets { }. In -this example, we put the incoming message into the string, followed by an ellipsis. This is only -one way to format a string. Python has very powerful string formatting and -you are wise to learn it well, considering your game will be mainly text-based.

-
-

You could also copy & paste the relevant method from DefaultObject here to get the full doc -string. For more complex methods, or if you only want to change some small part of the default -behavior, copy & pasting will eliminate the need to constantly look up the original method and keep -you sane.

-
-

In-game, now try

-
> @reload
-> say Hello
-You say, "Hello ..."
-
-
-

An ellipsis ... is added to what you said! This is a silly example but you have just made your -first code change to core functionality - without touching any of Evennia’s original code! We just -plugged in our own version of the at_before_say method and it replaced the default one. Evennia -happily redirected the message through our version and we got a different output.

-
-

For sane overriding of parent methods you should also be aware of Python’s -super, which allows you to call the -methods defined on a parent in your child class.

-
-
-
-

The Evennia shell

-

Now on to some generally useful tools as you continue learning Python and Evennia. We have so far -explored using py and have inserted Python code directly in-game. We have also modified Evennia’s -behavior by overriding default functionality with our own. There is a third way to conveniently -explore Evennia and Python - the Evennia shell.

-

Outside of your game, cd to your mygame folder and make sure any needed virtualenv is running. -Next:

-
> pip install ipython      # only needed once
-
-
-

The IPython program is just a nicer interface to the -Python interpreter - you only need to install it once, after which Evennia will use it -automatically.

-
> evennia shell
-
-
-

If you did this call from your game dir you will now be in a Python prompt managed by the IPython -program.

-
IPython ...
-...
-In [1]: IPython has some very nice ways to explore what Evennia has to offer.
-
-> import evennia
-> evennia.<TAB>
-
-
-

That is, write evennia. and press the Tab key. You will be presented with a list of all available -resources in the Evennia Flat API. We looked at the __init__.py file in the evennia folder -earlier, so some of what you see should be familiar. From the IPython prompt, do:

-
> from evennia import DefaultCharacter
-> DefaultCharacter.at_before_say?
-
-
-

Don’t forget that you can use <TAB> to auto-complete code as you write. Appending a single ? to -the end will show you the doc-string for at_before_say we looked at earlier. Use ?? to get the -whole source code.

-

Let’s look at our over-ridden version instead. Since we started the evennia shell from our game -dir we can easily get to our code too:

-
> from typeclasses.characters import Character
-> Character.at_before_say??
-
-
-

This will show us the changed code we just did. Having a window with IPython running is very -convenient for quickly exploring code without having to go digging through the file structure!

-
-
-

Where to go from here

-

This should give you a running start using Python with Evennia. If you are completely new to -programming or Python you might want to look at a more formal Python tutorial. You can find links -and resources on our link page.

-

We have touched upon many of the concepts here but to use Evennia and to be able to follow along in -the code, you will need basic understanding of Python -modules, -variables, -conditional statements, -loops, -functions, -lists, dictionaries, list comprehensions -and string formatting. You should also have a basic -understanding of object-oriented programming -and what Python Classes are.

-

Once you have familiarized yourself, or if you prefer to pick Python up as you go, continue to one -of the beginning-level Evennia tutorials to gradually build up your understanding.

-

Good luck!

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Quirks.html b/docs/0.9.5/Quirks.html deleted file mode 100644 index 7c8f20383e..0000000000 --- a/docs/0.9.5/Quirks.html +++ /dev/null @@ -1,231 +0,0 @@ - - - - - - - - - Quirks — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Quirks

-

This is a list of various quirks or common stumbling blocks that people often ask about or report -when using (or trying to use) Evennia. They are not bugs.

-
-

Forgetting to use @reload to see changes to your typeclasses

-

Firstly: Reloading the server is a safe and usually quick operation which will not disconnect any -accounts.

-

New users tend to forget this step. When editing source code (such as when tweaking typeclasses and -commands or adding new commands to command sets) you need to either use the in-game @reload -command or, from the command line do python evennia.py reload before you see your changes.

-
-
-

Web admin to create new Account

-

If you use the default login system and are trying to use the Web admin to create a new Player -account, you need to consider which MULTIACCOUNT_MODE you are in. If you are in -MULTIACCOUNT_MODE 0 or 1, the login system expects each Account to also have a Character -object named the same as the Account - there is no character creation screen by default. If using -the normal mud login screen, a Character with the same name is automatically created and connected -to your Account. From the web interface you must do this manually.

-

So, when creating the Account, make sure to also create the Character from the same form as you -create the Account from. This should set everything up for you. Otherwise you need to manually set -the “account” property on the Character and the “character” property on the Account to point to each -other. You must also set the lockstring of the Character to allow the Account to “puppet” this -particular character.

-
-
-

Mutable attributes and their connection to the database

-

When storing a mutable object (usually a list or a dictionary) in an Attribute

-
     object.db.mylist = [1,2,3]
-
-
-

you should know that the connection to the database is retained also if you later extract that -Attribute into another variable (what is stored and retrieved is actually a PackedList or a -PackedDict that works just like their namesakes except they save themselves to the database when -changed). So if you do

-
     alist = object.db.mylist
-     alist.append(4)
-
-
-

this updates the database behind the scenes, so both alist and object.db.mylist are now -[1,2,3,4]

-

If you don’t want this, Evennia provides a way to stably disconnect the mutable from the database by -use of evennia.utils.dbserialize.deserialize:

-
     from evennia.utils.dbserialize import deserialize
-
-     blist = deserialize(object.db.mylist)
-     blist.append(4)
-
-
-

The property blist is now [1,2,3,4] whereas object.db.mylist remains unchanged. If you want to -update the database you’d need to explicitly re-assign the updated data to the mylist Attribute.

-
-
-

Commands are matched by name or alias

-

When merging command sets it’s important to remember that command objects are identified -both by key or alias. So if you have a command with a key look and an alias ls, introducing -another command with a key ls will be assumed by the system to be identical to the first one. -This usually means merging cmdsets will overload one of them depending on priority. Whereas this is -logical once you know how command objects are handled, it may be confusing if you are just looking -at the command strings thinking they are parsed as-is.

-
-
-

Objects turning to DefaultObject

-

A common confusing error for new developers is finding that one or more objects in-game are suddenly -of the type DefaultObject rather than the typeclass you wanted it to be. This happens when you -introduce a critical Syntax error to the module holding your custom class. Since such a module is -not valid Python, Evennia can’t load it at all to get to the typeclasses within. To keep on running, -Evennia will solve this by printing the full traceback to the terminal/console and temporarily fall -back to the safe DefaultObject until you fix the problem and reload. Most errors of this kind will -be caught by any good text editors. Keep an eye on the terminal/console during a reload to catch -such errors - you may have to scroll up if your window is small.

-
-
-

Overriding of magic methods

-

Python implements a system of magic -methods, usually -prefixed and suffixed by double-underscores (__example__) that allow object instances to have -certain operations performed on them without needing to do things like turn them into strings or -numbers first– for example, is obj1 greater than or equal to obj2?

-

Neither object is a number, but given obj1.size == "small" and obj2.size == "large", how might -one compare these two arbitrary English adjective strings to figure out which is greater than the -other? By defining the __ge__ (greater than or equal to) magic method on the object class in which -you figure out which word has greater significance, perhaps through use of a mapping table -({'small':0, 'large':10}) or other lookup and comparing the numeric values of each.

-

Evennia extensively makes use of magic methods on typeclasses to do things like initialize objects, -check object existence or iterate over objects in an inventory or container. If you override or -interfere with the return values from the methods Evennia expects to be both present and working, it -can result in very inconsistent and hard-to-diagnose errors.

-

The moral of the story– it can be dangerous to tinker with magic methods on typeclassed objects. -Try to avoid doing so.

-
-
-

Known upstream bugs

-
    -
  • There is currently (Autumn 2017) a bug in the zope.interface installer on some Linux Ubuntu -distributions (notably Ubuntu 16.04 LTS). Zope is a dependency of Twisted. The error manifests in -the server not starting with an error that zope.interface is not found even though pip list -shows it’s installed. The reason is a missing empty __init__.py file at the root of the zope -package. If the virtualenv is named “evenv” as suggested in the Getting Started -instructions, use the following command to fix it:

    -
    touch evenv/local/lib/python2.7/site-packages/zope/__init__.py
    -
    -
    -

    This will create the missing file and things should henceforth work correctly.

    -
  • -
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/RSS.html b/docs/0.9.5/RSS.html deleted file mode 100644 index 81d79a25eb..0000000000 --- a/docs/0.9.5/RSS.html +++ /dev/null @@ -1,165 +0,0 @@ - - - - - - - - - RSS — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

RSS

-

RSS is a format for easily tracking updates on websites. The -principle is simple - whenever a site is updated, a small text file is updated. An RSS reader can -then regularly go online, check this file for updates and let the user know what’s new.

-

Evennia allows for connecting any number of RSS feeds to any number of in-game channels. Updates to -the feed will be conveniently echoed to the channel. There are many potential uses for this: For -example the MUD might use a separate website to host its forums. Through RSS, the players can then -be notified when new posts are made. Another example is to let everyone know you updated your dev -blog. Admins might also want to track the latest Evennia updates through our own RSS feed -here.

-
-

Configuring RSS

-

To use RSS, you first need to install the feedparser python -module.

-
pip install feedparser
-
-
-

Next you activate RSS support in your config file by settting RSS_ENABLED=True.

-

Start/reload Evennia as a privileged user. You should now have a new command available, @rss2chan:

-
 @rss2chan <evennia_channel> = <rss_url>
-
-
-
-

Setting up RSS, step by step

-

You can connect RSS to any Evennia channel, but for testing, let’s set up a new channel “rss”.

-
 @ccreate rss = RSS feeds are echoed to this channel!
-
-
-

Let’s connect Evennia’s code-update feed to this channel. The RSS url for evennia updates is -https://github.com/evennia/evennia/commits/master.atom, so let’s add that:

-
 @rss2chan rss = https://github.com/evennia/evennia/commits/master.atom
-
-
-

That’s it, really. New Evennia updates will now show up as a one-line title and link in the channel. -Give the @rss2chan command on its own to show all connections. To remove a feed from a channel, -you specify the connection again (use the command to see it in the list) but add the /delete -switch:

-
 @rss2chan/delete rss = https://github.com/evennia/evennia/commits/master.atom
-
-
-

You can connect any number of RSS feeds to a channel this way. You could also connect them to the -same channels as IRC to have the feed echo to external chat channels as well.

-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Roadmap.html b/docs/0.9.5/Roadmap.html deleted file mode 100644 index f93b693a54..0000000000 --- a/docs/0.9.5/Roadmap.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - - - Roadmap — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Roadmap

-

As of Autumn 2016, Evennia’s development roadmap is tracked through the Evennia Projects -Page.

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Running-Evennia-in-Docker.html b/docs/0.9.5/Running-Evennia-in-Docker.html deleted file mode 100644 index 284b233289..0000000000 --- a/docs/0.9.5/Running-Evennia-in-Docker.html +++ /dev/null @@ -1,408 +0,0 @@ - - - - - - - - - Running Evennia in Docker — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Running Evennia in Docker

-

Evennia has an official docker image which makes -running an Evennia-based game in a Docker container easy.

-
-

Install Evennia through docker

-

First, install the docker program so you can run the Evennia container. You can get it freely from -docker.com. Linux users can likely also get it through their normal -package manager.

-

To fetch the latest evennia docker image, run:

-
docker pull evennia/evennia
-
-
-

This is a good command to know, it is also how you update to the latest version when we make updates -in the future. This tracks the master branch of Evennia.

-
-

Note: If you want to experiment with the (unstable) develop branch, use docker pull evennia/evennia:develop.

-
-

Next cd to a place where your game dir is, or where you want to create it. Then run:

-
docker run -it --rm -p 4000:4000 -p 4001:4001 -p 4002:4002 --rm -v $PWD:/usr/src/game --user
-
-
-

\(UID:\)GID evennia/evennia

-

Having run this (see next section for a description of what’s what), you will be at a prompt inside -the docker container:

-
evennia|docker /usr/src/game $
-
-
-

This is a normal shell prompt. We are in the /usr/src/game location inside the docker container. -If you had anything in the folder you started from, you should see it here (with ls) since we -mounted the current directory to /usr/src/game (with -v above). You have the evennia command -available and can now proceed to create a new game as per the Getting Started -instructions (you can skip the virtualenv and install ‘globally’ in the container though).

-

You can run Evennia from inside this container if you want to, it’s like you are root in a little -isolated Linux environment. To exit the container and all processes in there, press Ctrl-D. If you -created a new game folder, you will find that it has appeared on-disk.

-
-

The game folder or any new files that you created from inside the container will appear as owned -by root. If you want to edit the files outside of the container you should change the ownership. -On Linux/Mac you do this with sudo chown myname:myname -R mygame, where you replace myname with -your username and mygame with whatever your game folder is named.

-
-
-

Description of the docker run command

-
    docker run -it --rm -p 4000:4000 -p 4001:4001 -p 4002:4002 --rm -v $PWD:/usr/src/game --user
-$UID:$GID evennia/evennia
-
-
-

This is what it does:

-
    -
  • docker run ... evennia/evennia tells us that we want to run a new container based on the -evennia/evennia docker image. Everything in between are options for this. The evennia/evennia is -the name of our official docker image on the dockerhub -repository. If you didn’t do docker pull evennia/evennia first, the image will be downloaded when running this, otherwise your already -downloaded version will be used. It contains everything needed to run Evennia.

  • -
  • -it has to do with creating an interactive session inside the container we start.

  • -
  • --rm will make sure to delete the container when it shuts down. This is nice to keep things tidy -on your drive.

  • -
  • -p 4000:4000 -p 4001:4001 -p 4002:4002 means that we map ports 4000, 4001 and 4002 from -inside the docker container to same-numbered ports on our host machine. These are ports for telnet, -webserver and websockets. This is what allows your Evennia server to be accessed from outside the -container (such as by your MUD client)!

  • -
  • -v $PWD:/usr/src/game mounts the current directory (outside the container) to the path -/usr/src/game inside the container. This means that when you edit that path in the container you -will actually be modifying the “real” place on your hard drive. If you didn’t do this, any changes -would only exist inside the container and be gone if we create a new one. Note that in linux a -shortcut for the current directory is $PWD. If you don’t have this for your OS, you can replace it -with the full path to the current on-disk directory (like C:/Development/evennia/game or wherever -you want your evennia files to appear).

  • -
  • --user $UID:$GID ensures the container’s modifications to $PWD are done with you user and -group IDs instead of root’s IDs (root is the user running evennia inside the container). This avoids -having stale .pid files in your filesystem between container reboots which you have to force -delete with sudo rm server/*.pid before each boot.

  • -
-
-
-
-

Running your game as a docker image

-

If you run the docker command given in the previous section from your game dir you can then -easily start Evennia and have a running server without any further fuss.

-

But apart from ease of install, the primary benefit to running an Evennia-based game in a container -is to simplify its deployment into a public production environment. Most cloud-based hosting -providers these days support the ability to run container-based applications. This makes deploying -or updating your game as simple as building a new container image locally, pushing it to your Docker -Hub account, and then pulling from Docker Hub into your AWS/Azure/other docker-enabled hosting -account. The container eliminates the need to install Python, set up a virtualenv, or run pip to -install dependencies.

-
-

Start Evennia and run through docker

-

For remote or automated deployment you may want to start Evennia immediately as soon as the docker -container comes up. If you already have a game folder with a database set up you can also start the -docker container and pass commands directly to it. The command you pass will be the main process to -run in the container. From your game dir, run for example this command:

-
docker run -it --rm -p 4000:4000 -p 4001:4001 -p 4002:4002 --rm -v $PWD:/usr/src/game
-
-
-

evennia/evennia evennia start –log

-

This will start Evennia as the foreground process, echoing the log to the terminal. Closing the -terminal will kill the server. Note that you must use a foreground command like evennia start --log or evennia ipstart to start the server - otherwise the foreground process will finish -immediately and the container go down.

-
-
-

Create your own game image

-

You may want to create your own image in order to bake in your gamedir directly into the docker -container for easy upload and deployment. -These steps assume that you have created or otherwise obtained a game directory already. First, cd -to your game dir and create a new empty text file named Dockerfile. Save the following two lines -into it:

-
FROM evennia/evennia:latest
-
-ENTRYPOINT evennia start --log
-
-
-

These are instructions for building a new docker image. This one is based on the official -evennia/evennia image. We add the second line to -make make sure evennia starts immediately along with the container (so we don’t need to enter it and -run commands).

-

To build the image:

-
    docker build -t mydhaccount/mygame .
-
-
-

(don’t forget the period . at the end, it tells docker to use use the Dockerfile from the -current location). Here mydhaccount is the name of your dockerhub account. If you don’t have a -dockerhub account you can build the image locally only (name the container whatever you like in that -case, like just mygame).

-

Docker images are stored centrally on your computer. You can see which ones you have available -locally with docker images. Once built, you have a couple of options to run your game.

-

If you have a docker-hub account, you can push your (new or updated) image there:

-
    docker push myhdaccount/mygame
-
-
-
-
-

Run container from your game image for development

-

To run the container based on your game image locally for development, mount the local game -directory as before:

-
docker run -it --rm -p 4000:4000 -p 4001:4001 -p 4002:4002 -v $PWD:/usr/src/game --user $UID:$GID
-mydhaccount/mygame
-
-
-

Evennia will start and you’ll get output in the terminal, perfect for development. You should be -able to connect to the game with your clients normally.

-
-
-

Deploy game image for production

-

Each time you rebuild the docker image as per the above instructions, the latest copy of your game -directory is actually copied inside the image (at /usr/src/game/). If you don’t mount your on-disk -folder there, the internal one will be used. So for deploying evennia on a server, omit the -v -option and just give the following command:

-
docker run -it --rm -d -p 4000:4000 -p 4001:4001 -p 4002:4002 --user $UID:$GID mydhaccount/mygame
-
-
-

Your game will be downloaded from your docker-hub account and a new container will be built using -the image and started on the server! If your server environment forces you to use different ports, -you can just map the normal ports differently in the command above.

-

Above we added the -d option, which starts the container in daemon mode - you won’t see any -return in the console. You can see it running with docker ps:

-
$ docker ps
-
-CONTAINER ID     IMAGE       COMMAND                  CREATED              ...
-f6d4ca9b2b22     mygame      "/bin/sh -c 'evenn..."   About a minute ago   ...
-
-
-

Note the container ID, this is how you manage the container as it runs.

-
   docker logs f6d4ca9b2b22
-
-
-

Looks at the STDOUT output of the container (i.e. the normal server log)

-
   docker logs -f f6d4ca9b2b22
-
-
-

Tail the log (so it updates to your screen ‘live’).

-
   docker pause f6d4ca9b2b22
-
-
-

Suspend the state of the container.

-
   docker unpause f6d4ca9b2b22
-
-
-

Un-suspend it again after a pause. It will pick up exactly where it were.

-
   docker stop f6d4ca9b2b22
-
-
-

Stop the container. To get it up again you need to use docker run, specifying ports etc. A new -container will get a new container id to reference.

-
-
-
-

How it Works

-

The evennia/evennia docker image holds the evennia library and all of its dependencies. It also -has an ONBUILD directive which is triggered during builds of images derived from it. This -ONBUILD directive handles setting up a volume and copying your game directory code into the proper -location within the container.

-

In most cases, the Dockerfile for an Evennia-based game will only need the FROM evennia/evennia:latest directive, and optionally a MAINTAINER directive if you plan to publish -your image on Docker Hub and would like to provide contact info.

-

For more information on Dockerfile directives, see the Dockerfile -Reference.

-

For more information on volumes and Docker containers, see the Docker site’s Manage data in -containers page.

-
-

What if I Don’t Want “LATEST”?

-

A new evennia/evennia image is built automatically whenever there is a new commit to the master -branch of Evennia. It is possible to create your own custom evennia base docker image based on any -arbitrary commit.

-
    -
  1. Use git tools to checkout the commit that you want to base your image upon. (In the example -below, we’re checking out commit a8oc3d5b.)

  2. -
-
git checkout -b my-stable-branch a8oc3d5b
-
-
-
    -
  1. Change your working directory to the evennia directory containing Dockerfile. Note that -Dockerfile has changed over time, so if you are going far back in the commit history you might -want to bring a copy of the latest Dockerfile with you and use that instead of whatever version -was used at the time.

  2. -
  3. Use the docker build command to build the image based off of the currently checked out commit. -The example below assumes your docker account is mydhaccount.

  4. -
-
docker build -t mydhaccount/evennia .
-
-
-
    -
  1. Now you have a base evennia docker image built off of a specific commit. To use this image to -build your game, you would modify FROM directive in the Dockerfile for your game directory -to be:

  2. -
-
FROM mydhacct/evennia:latest
-
-
-

Note: From this point, you can also use the docker tag command to set a specific tag on your image -and/or upload it into Docker Hub under your account.

-
    -
  1. At this point, build your game using the same docker build command as usual. Change your -working directory to be your game directory and run

  2. -
-
docker build -t mydhaccountt/mygame .
-
-
-
-
-
-

Additional Creature Comforts

-

The Docker ecosystem includes a tool called docker-compose, which can orchestrate complex multi- -container applications, or in our case, store the default port and terminal parameters that we want -specified every time we run our container. A sample docker-compose.yml file to run a containerized -Evennia game in development might look like this:

-
version: '2'
-
-services:
-  evennia:
-    image: mydhacct/mygame
-    stdin_open: true
-    tty: true
-    ports:
-      - "4001-4002:4001-4002"
-      - "4000:4000"
-    volumes:
-      - .:/usr/src/game
-
-
-

With this file in the game directory next to the Dockerfile, starting the container is as simple -as

-
docker-compose up
-
-
-

For more information about docker-compose, see Getting Started with docker- -compose.

-
-

Note that with this setup you lose the --user $UID option. The problem is that the variable -UID is not available inside the configuration file docker-compose.yml. A workaround is to -hardcode your user and group id. In a terminal run echo  $UID:$GID and if for example you get -1000:1000 you can add to docker-compose.yml a line user: 1000:1000 just below the image: ... -line.

-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Screenshot.html b/docs/0.9.5/Screenshot.html deleted file mode 100644 index 8737ed5bd6..0000000000 --- a/docs/0.9.5/Screenshot.html +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - Screenshot — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Screenshot

-

evennia_screenshot2017 -(right-click and choose your browser’s equivalent of “view image” to see it full size)

-

This screenshot shows a vanilla install of the just started Evennia MUD server. -In the bottom window we can see the log messages from the running server.

-

In the top left window we see the default website of our new game displayed in a web browser (it has -shrunk to accomodate the smaller screen). Evennia contains its own webserver to serve this page. The -default site shows some brief info about the database. From here you can also reach Django’s admin -interface for editing the database online.

-

To the upper right is the included web-browser client showing a connection to the server on port -4001. This allows users to access the game without downloading a mud client separately.

-

Bottom right we see a login into the stock game using a third-party MUD client -(Mudlet). This connects to the server via the telnet protocol on port 4000.

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Scripts.html b/docs/0.9.5/Scripts.html deleted file mode 100644 index 9dba45c5bb..0000000000 --- a/docs/0.9.5/Scripts.html +++ /dev/null @@ -1,485 +0,0 @@ - - - - - - - - - Scripts — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Scripts

-

Scripts are the out-of-character siblings to the in-character -Objects. Scripts are so flexible that the “Script” is a bit limiting

-
    -
  • we had to pick something to name them after all. Other possible names -(depending on what you’d use them for) would be OOBObjects, -StorageContainers or TimerObjects.

  • -
-

Scripts can be used for many different things in Evennia:

-
    -
  • They can attach to Objects to influence them in various ways - or exist -independently of any one in-game entity (so-called Global Scripts).

  • -
  • They can work as timers and tickers - anything that may change with Time. But -they can also have no time dependence at all. Note though that if all you want -is just to have an object method called repeatedly, you should consider using -the TickerHandler which is more limited but is specialized on -just this task.

  • -
  • They can describe State changes. A Script is an excellent platform for -hosting a persistent, but unique system handler. For example, a Script could be -used as the base to track the state of a turn-based combat system. Since -Scripts can also operate on a timer they can also update themselves regularly -to perform various actions.

  • -
  • They can act as data stores for storing game data persistently in the database -(thanks to its ability to have Attributes).

  • -
  • They can be used as OOC stores for sharing data between groups of objects, for -example for tracking the turns in a turn-based combat system or barter exchange.

  • -
-

Scripts are Typeclassed entities and are manipulated in a similar -way to how it works for other such Evennia entities:

-
# create a new script
-new_script = evennia.create_script(key="myscript", typeclass=...)
-
-# search (this is always a list, also if there is only one match)
-list_of_myscript = evennia.search_script("myscript")
-
-
-
-
-

Defining new Scripts

-

A Script is defined as a class and is created in the same way as other -typeclassed entities. The class has several properties -to control the timer-component of the scripts. These are all optional - -leaving them out will just create a Script with no timer components (useful to act as -a database store or to hold a persistent game system, for example).

-

This you can do for example in the module -evennia/typeclasses/scripts.py. Below is an example Script -Typeclass.

-
from evennia import DefaultScript
-
-class MyScript(DefaultScript):
-
-    def at_script_creation(self):
-        self.key = "myscript"
-        self.interval = 60  # 1 min repeat
-
-    def at_repeat(self):
-        # do stuff every minute
-
-
-

In mygame/typeclasses/scripts.py is the Script class which inherits from DefaultScript -already. This is provided as your own base class to do with what you like: You can tweak Script if -you want to change the default behavior and it is usually convenient to inherit from this instead. -Here’s an example:

-
    # for example in mygame/typeclasses/scripts.py
-    # Script class is defined at the top of this module
-
-    import random
-
-    class Weather(Script):
-        """
-        A timer script that displays weather info. Meant to
-        be attached to a room.
-          
-        """
-        def at_script_creation(self):
-            self.key = "weather_script"
-            self.desc = "Gives random weather messages."
-            self.interval = 60 * 5  # every 5 minutes
-            self.persistent = True  # will survive reload
-
-        def at_repeat(self):
-            "called every self.interval seconds."
-            rand = random.random()
-            if rand < 0.5:
-                weather = "A faint breeze is felt."
-            elif rand < 0.7:
-                weather = "Clouds sweep across the sky."
-            else:
-                weather = "There is a light drizzle of rain."
-            # send this message to everyone inside the object this
-            # script is attached to (likely a room)
-            self.obj.msg_contents(weather)
-
-
-

If we put this script on a room, it will randomly report some weather -to everyone in the room every 5 minutes.

-

To activate it, just add it to the script handler (scripts) on an -Room. That object becomes self.obj in the example above. Here we -put it on a room called myroom:

-
    myroom.scripts.add(scripts.Weather)
-
-
-
-

Note that typeclasses in your game dir is added to the setting TYPECLASS_PATHS. -Therefore we don’t need to give the full path (typeclasses.scripts.Weather -but only scripts.Weather above.

-
-

If you wanted to stop and delete that script on the Room. You could do that -with the script handler by passing the delete method with the script key (self.key) as:

-
    myroom.scripts.delete('weather_script')
-
-
-
-

Note that If no key is given, this will delete all scripts on the object!

-
-

You can also create scripts using the evennia.create_script function:

-
    from evennia import create_script
-    create_script('typeclasses.weather.Weather', obj=myroom)
-
-
-

Note that if you were to give a keyword argument to create_script, that would -override the default value in your Typeclass. So for example, here is an instance -of the weather script that runs every 10 minutes instead (and also not survive -a server reload):

-
    create_script('typeclasses.weather.Weather', obj=myroom,
-                   persistent=False, interval=10*60)
-
-
-

From in-game you can use the @script command to launch the Script on things:

-
     @script here = typeclasses.scripts.Weather
-
-
-

You can conveniently view and kill running Scripts by using the @scripts -command in-game.

-
-
-

Properties and functions defined on Scripts

-

A Script has all the properties of a typeclassed object, such as db and ndb(see -Typeclasses). Setting key is useful in order to manage scripts (delete them by name -etc). These are usually set up in the Script’s typeclass, but can also be assigned on the fly as -keyword arguments to evennia.create_script.

-
    -
  • desc - an optional description of the script’s function. Seen in script listings.

  • -
  • interval - how often the script should run. If interval == 0 (default), this script has no -timing component, will not repeat and will exist forever. This is useful for Scripts used for -storage or acting as bases for various non-time dependent game systems.

  • -
  • start_delay - (bool), if we should wait interval seconds before firing for the first time or -not.

  • -
  • repeats - How many times we should repeat, assuming interval > 0. If repeats is set to <= 0, -the script will repeat indefinitely. Note that each firing of the script (including the first one) -counts towards this value. So a Script with start_delay=False and repeats=1 will start, -immediately fire and shut down right away.

  • -
  • persistent- if this script should survive a server reset or server shutdown. (You don’t need -to set this for it to survive a normal reload - the script will be paused and seamlessly restart -after the reload is complete).

  • -
-

There is one special property:

-
    -
  • obj - the Object this script is attached to (if any). You should not need to set -this manually. If you add the script to the Object with myobj.scripts.add(myscriptpath) or give -myobj as an argument to the utils.create.create_script function, the obj property will be set -to myobj for you.

  • -
-

It’s also imperative to know the hook functions. Normally, overriding -these are all the customization you’ll need to do in Scripts. You can -find longer descriptions of these in src/scripts/scripts.py.

-
    -
  • at_script_creation() - this is usually where the script class sets things like interval and -repeats; things that control how the script runs. It is only called once - when the script is -first created.

  • -
  • is_valid() - determines if the script should still be running or not. This is called when -running obj.scripts.validate(), which you can run manually, but which is also called by Evennia -during certain situations such as reloads. This is also useful for using scripts as state managers. -If the method returns False, the script is stopped and cleanly removed.

  • -
  • at_start() - this is called when the script starts or is unpaused. For persistent scripts this -is at least once ever server startup. Note that this will always be called right away, also if -start_delay is True.

  • -
  • at_repeat() - this is called every interval seconds, or not at all. It is called right away at -startup, unless start_delay is True, in which case the system will wait interval seconds -before calling.

  • -
  • at_stop() - this is called when the script stops for whatever reason. It’s a good place to do -custom cleanup.

  • -
  • at_server_reload() - this is called whenever the server is warm-rebooted (e.g. with the -@reload command). It’s a good place to save non-persistent data you might want to survive a -reload.

  • -
  • at_server_shutdown() - this is called when a system reset or systems shutdown is invoked.

  • -
-

Running methods (usually called automatically by the engine, but possible to also invoke manually)

-
    -
  • start() - this will start the script. This is called automatically whenever you add a new script -to a handler. at_start() will be called.

  • -
  • stop() - this will stop the script and delete it. Removing a script from a handler will stop it -automatically. at_stop() will be called.

  • -
  • pause() - this pauses a running script, rendering it inactive, but not deleting it. All -properties are saved and timers can be resumed. This is called automatically when the server reloads -and will not lead to the at_stop() hook being called. This is a suspension of the script, not a -change of state.

  • -
  • unpause() - resumes a previously paused script. The at_start() hook will be called to allow -it to reclaim its internal state. Timers etc are restored to what they were before pause. The server -automatically unpauses all paused scripts after a server reload.

  • -
  • force_repeat() - this will forcibly step the script, regardless of when it would otherwise have -fired. The timer will reset and the at_repeat() hook is called as normal. This also counts towards -the total number of repeats, if limited.

  • -
  • time_until_next_repeat() - for timed scripts, this returns the time in seconds until it next -fires. Returns None if interval==0.

  • -
  • remaining_repeats() - if the Script should run a limited amount of times, this tells us how many -are currently left.

  • -
  • reset_callcount(value=0) - this allows you to reset the number of times the Script has fired. It -only makes sense if repeats > 0.

  • -
  • restart(interval=None, repeats=None, start_delay=None) - this method allows you to restart the -Script in-place with different run settings. If you do, the at_stop hook will be called and the -Script brought to a halt, then the at_start hook will be called as the Script starts up with your -(possibly changed) settings. Any keyword left at None means to not change the original setting.

  • -
-
-
-

Global Scripts

-

A script does not have to be connected to an in-game object. If not it is -called a Global script. You can create global scripts by simply not supplying an object to store -it on:

-
     # adding a global script
-     from evennia import create_script
-     create_script("typeclasses.globals.MyGlobalEconomy",
-                    key="economy", persistent=True, obj=None)
-
-
-

Henceforth you can then get it back by searching for its key or other identifier with -evennia.search_script. In-game, the scripts command will show all scripts.

-

Evennia supplies a convenient “container” called GLOBAL_SCRIPTS that can offer an easy -way to access global scripts. If you know the name (key) of the script you can get it like so:

-
from evennia import GLOBAL_SCRIPTS
-
-my_script = GLOBAL_SCRIPTS.my_script
-# needed if there are spaces in name or name determined on the fly
-another_script = GLOBAL_SCRIPTS.get("another script")
-# get all global scripts (this returns a Queryset)
-all_scripts = GLOBAL_SCRIPTS.all()
-# you can operate directly on the script
-GLOBAL_SCRIPTS.weather.db.current_weather = "Cloudy"
-
-
-
-
-

Note that global scripts appear as properties on GLOBAL_SCRIPTS based on their key. -If you were to create two global scripts with the same key (even with different typeclasses), -the GLOBAL_SCRIPTS container will only return one of them (which one depends on order in -the database). Best is to organize your scripts so that this does not happen. Otherwise, use -evennia.search_script to get exactly the script you want.

-
-

There are two ways to make a script appear as a property on GLOBAL_SCRIPTS. The first is -to manually create a new global script with create_script as mentioned above. Often you want this -to happen automatically when the server starts though. For this you add a python global dictionary -named GLOBAL_SCRIPTS to your settings.py file. The settings.py fie is located in -mygame/conf/settings.py:

-
GLOBAL_SCRIPTS = {
-    "my_script": {
-        "typeclass": "typeclasses.scripts.Weather",
-        "repeats": -1,
-        "interval": 50,
-        "desc": "Weather script",
-        "persistent": True
-    },
-    "storagescript": {
-        "typeclass": "typeclasses.scripts.Storage",
-        "persistent": True
-    },
-    {
-    "another_script": {
-        "typeclass": "typeclasses.another_script.AnotherScript"
-    }
-}
-
-
-

Here the key (myscript and storagescript above) is required, all other fields are optional. If -typeclass is not given, a script of type settings.BASE_SCRIPT_TYPECLASS is assumed. The keys -related to timing and intervals are only needed if the script is timed.

-
-

Note: Provide the full path to the scripts module in GLOBAL_SCRIPTS. In the example with -another_script, you can also create separate script modules that exist beyond scrypt.py for -further organizational requirements if needed.

-
-

Evennia will use the information in settings.GLOBAL_SCRIPTS to automatically create and start -these -scripts when the server starts (unless they already exist, based on their key). You need to reload -the server before the setting is read and new scripts become available. You can then find the key -you gave as properties on evennia.GLOBAL_SCRIPTS -(such as evennia.GLOBAL_SCRIPTS.storagescript).

-
-

Note: Make sure that your Script typeclass does not have any critical errors. If so, you’ll see -errors in your log and your Script will temporarily fall back to being a DefaultScript type.

-
-

Moreover, a script defined this way is guaranteed to exist when you try to access it:

-
from evennia import GLOBAL_SCRIPTS
-# first stop the script
-GLOBAL_SCRIPTS.storagescript.stop()
-# running the `scripts` command now will show no storagescript
-# but below now it's recreated again!
-storage = GLOBAL_SCRIPTS.storagescript
-
-
-

That is, if the script is deleted, next time you get it from GLOBAL_SCRIPTS, it will use the -information -in settings to recreate it for you.

-
-

Note that if your goal with the Script is to store persistent data, you should set it as -persistent=True, either in settings.GLOBAL_SCRIPTS or in the Scripts typeclass. Otherwise any -data you wanted to store on it will be gone (since a new script of the same name is restarted -instead).

-
-
-
-

Dealing with Errors

-

Errors inside an timed, executing script can sometimes be rather terse or point to -parts of the execution mechanism that is hard to interpret. One way to make it -easier to debug scripts is to import Evennia’s native logger and wrap your -functions in a try/catch block. Evennia’s logger can show you where the -traceback occurred in your script.

-

-from evennia.utils import logger
-
-class Weather(DefaultScript):
-
-    # [...]
-
-    def at_repeat(self):
-        
-        try:
-            # [...] code as above
-        except Exception:
-            # logs the error
-            logger.log_trace()
-    
-
-
-
-
-

Example of a timed script

-

In-game you can try out scripts using the @script command. In the -evennia/contrib/tutorial_examples/bodyfunctions.py is a little example script -that makes you do little ‘sounds’ at random intervals. Try the following to apply an -example time-based script to your character.

-
> @script self = bodyfunctions.BodyFunctions
-
-
-
-

Note: Since evennia/contrib/tutorial_examples is in the default setting -TYPECLASS_PATHS, we only need to specify the final part of the path, -that is, bodyfunctions.BodyFunctions.

-
-

If you want to inflict your flatulence script on another person, place or -thing, try something like the following:

-
> @py self.location.search('matt').scripts.add('bodyfunctions.BodyFunctions')
-
-
-

Here’s how you stop it on yourself.

-
> @script/stop self = bodyfunctions.BodyFunctions
-
-
-

This will kill the script again. You can use the @scripts command to list all -active scripts in the game, if any (there are none by default).

-

For another example of a Script in use, check out the Turn Based Combat System -tutorial.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Security.html b/docs/0.9.5/Security.html deleted file mode 100644 index 668326318f..0000000000 --- a/docs/0.9.5/Security.html +++ /dev/null @@ -1,277 +0,0 @@ - - - - - - - - - Security — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Security

-

Hackers these days aren’t discriminating, and their backgrounds range from bored teenagers to -international intelligence agencies. Their scripts and bots endlessly crawl the web, looking for -vulnerable systems they can break into. Who owns the system is irrelevant– it doesn’t matter if it -belongs to you or the Pentagon, the goal is to take advantage of poorly-secured systems and see what -resources can be controlled or stolen from them.

-

If you’re considering deploying to a cloud-based host, you have a vested interest in securing your -applications– you likely have a credit card on file that your host can freely bill. Hackers pegging -your CPU to mine cryptocurrency or saturating your network connection to participate in a botnet or -send spam can run up your hosting bill, get your service suspended or get your address/site -blacklisted by ISPs. It can be a difficult legal or political battle to undo this damage after the -fact.

-

As a developer about to expose a web application to the threat landscape of the modern internet, -here are a few tips to consider to increase the security of your Evennia install.

-
-

Know your logs

-

In case of emergency, check your logs! By default they are located in the server/logs/ folder. -Here are some of the more important ones and why you should care:

-
    -
  • http_requests.log will show you what HTTP requests have been made against Evennia’s built-in -webserver (TwistedWeb). This is a good way to see if people are innocuously browsing your site or -trying to break it through code injection.

  • -
  • portal.log will show you various networking-related information. This is a good place to check -for odd or unusual types or amounts of connections to your game, or other networking-related -issues– like when users are reporting an inability to connect.

  • -
  • server.log is the MUX administrator’s best friend. Here is where you’ll find information -pertaining to who’s trying to break into your system by guessing at passwords, who created what -objects, and more. If your game fails to start or crashes and you can’t tell why, this is the first -place you should look for answers. Security-related events are prefixed with an [SS] so when -there’s a problem you might want to pay special attention to those.

  • -
-
-
-

Disable development/debugging options

-

There are a few Evennia/Django options that are set when you first create your game to make it more -obvious to you where problems arise. These options should be disabled before you push your game into -production– leaving them on can expose variables or code someone with malicious intent can easily -abuse to compromise your environment.

-

In server/conf/settings.py:

-
# Disable Django's debug mode
-DEBUG = False
-# Disable the in-game equivalent
-IN_GAME_ERRORS = False
-# If you've registered a domain name, force Django to check host headers. Otherwise leave this
-
-
-

as-is. -# Note the leading period– it is not a typo! -ALLOWED_HOSTS = [‘.example.com’]

-
-
-

Handle user-uploaded images with care

-

If you decide to allow users to upload their own images to be served from your site, special care -must be taken. Django will read the file headers to confirm it’s an image (as opposed to a document -or zip archive), but code can be injected into an image -file after the headers -that can be interpreted as HTML and/or give an attacker a web shell through which they can access -other filesystem resources.

-

Django has a more comprehensive overview of how to handle user-uploaded -files, but -in short you should take care to do one of two things–

-
    -
  • Serve all user-uploaded assets from a separate domain or CDN (not a subdomain of the one you -already have!). For example, you may be browsing reddit.com but note that all the user-submitted -images are being served from the redd.it domain. There are both security and performance benefits -to this (webservers tend to load local resources one-by-one, whereas they will request external -resources in bulk).

  • -
  • If you don’t want to pay for a second domain, don’t understand what any of this means or can’t be -bothered with additional infrastructure, then simply reprocess user images upon receipt using an -image library. Convert them to a different format, for example. Destroy the originals!

  • -
-
-
-

Disable the web interface

-

The web interface allows visitors to see an informational page as well as log into a browser-based -telnet client with which to access Evennia. It also provides authentication endpoints against which -an attacker can attempt to validate stolen lists of credentials to see which ones might be shared by -your users. Django’s security is robust, but if you don’t want/need these features and fully intend -to force your users to use traditional clients to access your game, you might consider disabling -either/both to minimize your attack surface.

-

In server/conf/settings.py:

-
# Disable the Javascript webclient
-WEBCLIENT_ENABLED = False
-# Disable the website altogether
-WEBSERVER_ENABLED = False
-
-
-
-
-

Change your ssh port

-

Automated attacks will often target port 22 seeing as how it’s the standard port for SSH traffic. -Also, -many public wifi hotspots block ssh traffic over port 22 so you might not be able to access your -server from these locations if you like to work remotely or don’t have a home internet connection.

-

If you don’t intend on running a website or securing it with TLS, you can mitigate both problems by -changing the port used for ssh to 443, which most/all hotspot providers assume is HTTPS traffic and -allows through.

-

(Ubuntu) In /etc/ssh/sshd_config, change the following variable:

-
# What ports, IPs and protocols we listen for
-Port 443
-
-
-

Save, close, then run the following command:

-
sudo service ssh restart
-
-
-
-
-

Set up a firewall

-

Ubuntu users can make use of the simple ufw utility. Anybody else can use iptables.

-
# Install ufw (if not already)
-sudo apt-get install ufw
-
-
-

UFW’s default policy is to deny everything. We must specify what we want to allow through our -firewall.

-
# Allow terminal connections to your game
-sudo ufw allow 4000/tcp
-# Allow browser connections to your website
-sudo ufw allow 4001/tcp
-
-
-

Use ONE of the next two commands depending on which port your ssh daemon is listening on:

-
sudo ufw allow 22/tcp
-sudo ufw allow 443/tcp
-
-
-

Finally:

-
sudo ufw enable
-
-
-

Now the only ports open will be your administrative ssh port (whichever you chose), and Evennia on -4000-4001.

-
-
-

Use an external webserver

-

Though not officially supported, there are some benefits to deploying a webserver -to handle/proxy traffic to your Evennia instance.

-

For example, Evennia’s game engine and webservice are tightly integrated. If you bring your game -down for maintenance (or if it simply crashes) your website will go down with it. In these cases a -standalone webserver can still be used to display a maintenance page or otherwise communicate to -your users the reason for the downtime, instead of disappearing off the face of the earth and -returning opaque SERVER NOT FOUND error messages.

-

Proper webservers are also written in more efficient programming languages than Python, and while -Twisted can handle its own, putting a webserver in front of it is like hiring a bouncer to deal with -nuisances and crowds before they even get in the door.

-

Many of the popular webservers also let you plug in additional modules (like -mod_security for Apache) that can be used to detect -(and block!) malicious users or requests before they even touch your game or site. There are also -automated solutions for installing and configuring TLS (via Certbot/Let’s -Encrypt) to secure your website against hotspot and -ISP snooping.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Server-Conf.html b/docs/0.9.5/Server-Conf.html deleted file mode 100644 index ea8698be72..0000000000 --- a/docs/0.9.5/Server-Conf.html +++ /dev/null @@ -1,218 +0,0 @@ - - - - - - - - - Server Conf — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Server Conf

-

Evennia runs out of the box without any changes to its settings. But there are several important -ways to customize the server and expand it with your own plugins.

-
-

Settings file

-

The “Settings” file referenced throughout the documentation is the file -mygame/server/conf/settings.py. This is automatically created on the first run of evennia --init -(see the Getting Started page).

-

Your new settings.py is relatively bare out of the box. Evennia’s core settings file is actually -[evennia/settings_default.py](https://github.com/evennia/evennia/blob/master/evennia/settings_default -.py) and is considerably more extensive (it is also heavily documented so you should refer to this -file directly for the available settings).

-

Since mygame/server/conf/settings.py is a normal Python module, it simply imports -evennia/settings_default.py into itself at the top.

-

This means that if any setting you want to change were to depend on some other default setting, -you might need to copy & paste both in order to change them and get the effect you want (for most -commonly changed settings, this is not something you need to worry about).

-

You should never edit evennia/settings_default.py. Rather you should copy&paste the select -variables you want to change into your settings.py and edit them there. This will overload the -previously imported defaults.

-
-

Warning: It may be tempting to copy everything from settings_default.py into your own settings -file. There is a reason we don’t do this out of the box though: it makes it directly clear what -changes you did. Also, if you limit your copying to the things you really need you will directly be -able to take advantage of upstream changes and additions to Evennia for anything you didn’t -customize.

-
-

In code, the settings is accessed through

-
    from django.conf import settings
-     # or (shorter):
-    from evennia import settings
-     # example:
-    servername = settings.SERVER_NAME
-
-
-

Each setting appears as a property on the imported settings object. You can also explore all -possible options with evennia.settings_full (this also includes advanced Django defaults that are -not touched in default Evennia).

-
-

It should be pointed out that when importing settings into your code like this, it will be read -only. You cannot edit your settings from your code! The only way to change an Evennia setting is -to edit mygame/server/conf/settings.py directly. You also generally need to restart the server -(possibly also the Portal) before a changed setting becomes available.

-
-
-
-

Other files in the server/conf directory

-

Apart from the main settings.py file,

-
    -
  • at_initial_setup.py - this allows you to add a custom startup method to be called (only) the -very first time Evennia starts (at the same time as user #1 and Limbo is created). It can be made to -start your own global scripts or set up other system/world-related things your game needs to have -running from the start.

  • -
  • at_server_startstop.py - this module contains two functions that Evennia will call every time -the Server starts and stops respectively - this includes stopping due to reloading and resetting as -well as shutting down completely. It’s a useful place to put custom startup code for handlers and -other things that must run in your game but which has no database persistence.

  • -
  • connection_screens.py - all global string variables in this module are interpreted by Evennia as -a greeting screen to show when an Account first connects. If more than one string variable is -present in the module a random one will be picked.

  • -
  • inlinefuncs.py - this is where you can define custom Inline functions.

  • -
  • inputfuncs.py - this is where you define custom Input functions to handle data -from the client.

  • -
  • lockfuncs.py - this is one of many possible modules to hold your own “safe” lock functions to -make available to Evennia’s Locks.

  • -
  • mssp.py - this holds meta information about your game. It is used by MUD search engines (which -you often have to register with) in order to display what kind of game you are running along with -statistics such as number of online accounts and online status.

  • -
  • oobfuncs.py - in here you can define custom OOB functions.

  • -
  • portal_services_plugin.py - this allows for adding your own custom services/protocols to the -Portal. It must define one particular function that will be called by Evennia at startup. There can -be any number of service plugin modules, all will be imported and used if defined. More info can be -found here.

  • -
  • server_services_plugin.py - this is equivalent to the previous one, but used for adding new -services to the Server instead. More info can be found -here.

  • -
-

Some other Evennia systems can be customized by plugin modules but has no explicit template in -conf/:

-
    -
  • cmdparser.py - a custom module can be used to totally replace Evennia’s default command parser. -All this does is to split the incoming string into “command name” and “the rest”. It also handles -things like error messages for no-matches and multiple-matches among other things that makes this -more complex than it sounds. The default parser is very generic, so you are most often best served -by modifying things further down the line (on the command parse level) than here.

  • -
  • at_search.py - this allows for replacing the way Evennia handles search results. It allows to -change how errors are echoed and how multi-matches are resolved and reported (like how the default -understands that “2-ball” should match the second “ball” object if there are two of them in the -room).

  • -
-
-
-

ServerConf

-

There is a special database model called ServerConf that stores server internal data and settings -such as current account count (for interfacing with the webserver), startup status and many other -things. It’s rarely of use outside the server core itself but may be good to -know about if you are an Evennia developer.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Sessions.html b/docs/0.9.5/Sessions.html deleted file mode 100644 index c112d7ea14..0000000000 --- a/docs/0.9.5/Sessions.html +++ /dev/null @@ -1,302 +0,0 @@ - - - - - - - - - Sessions — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Sessions

-

An Evennia Session represents one single established connection to the server. Depending on the -Evennia session, it is possible for a person to connect multiple times, for example using different -clients in multiple windows. Each such connection is represented by a session object.

-

A session object has its own cmdset, usually the “unloggedin” cmdset. This is what -is used to show the login screen and to handle commands to create a new account (or -Account in evennia lingo) read initial help and to log into the game with an existing -account. A session object can either be “logged in” or not. Logged in means that the user has -authenticated. When this happens the session is associated with an Account object (which is what -holds account-centric stuff). The account can then in turn puppet any number of objects/characters.

-
-

Warning: A Session is not persistent - it is not a Typeclass and has no -connection to the database. The Session will go away when a user disconnects and you will lose any -custom data on it if the server reloads. The .db handler on Sessions is there to present a uniform -API (so you can assume .db exists even if you don’t know if you receive an Object or a Session), -but this is just an alias to .ndb. So don’t store any data on Sessions that you can’t afford to -lose in a reload. You have been warned.

-
-
-

Properties on Sessions

-

Here are some important properties available on (Server-)Sessions

-
    -
  • sessid - The unique session-id. This is an integer starting from 1.

  • -
  • address - The connected client’s address. Different protocols give different information here.

  • -
  • logged_in - True if the user authenticated to this session.

  • -
  • account - The Account this Session is attached to. If not logged in yet, this is -None.

  • -
  • puppet - The Character/Object currently puppeted by this Account/Session combo. If -not logged in or in OOC mode, this is None.

  • -
  • ndb - The Non-persistent Attribute handler.

  • -
  • db - As noted above, Sessions don’t have regular Attributes. This is an alias to ndb.

  • -
  • cmdset - The Session’s CmdSetHandler

  • -
-

Session statistics are mainly used internally by Evennia.

-
    -
  • conn_time - How long this Session has been connected

  • -
  • cmd_last - Last active time stamp. This will be reset by sending idle keepalives.

  • -
  • cmd_last_visible - last active time stamp. This ignores idle keepalives and representes the -last time this session was truly visibly active.

  • -
  • cmd_total - Total number of Commands passed through this Session.

  • -
-
-
-

Multisession mode

-

The number of sessions possible to connect to a given account at the same time and how it works is -given by the MULTISESSION_MODE setting:

-
    -
  • MULTISESSION_MODE=0: One session per account. When connecting with a new session the old one is -disconnected. This is the default mode and emulates many classic mud code bases. In default Evennia, -this mode also changes how the create account Command works - it will automatically create a -Character with the same name as the Account. When logging in, the login command is also modified -to have the player automatically puppet that Character. This makes the distinction between Account -and Character minimal from the player’s perspective.

  • -
  • MULTISESSION_MODE=1: Many sessions per account, input/output from/to each session is treated the -same. For the player this means they can connect to the game from multiple clients and see the same -output in all of them. The result of a command given in one client (that is, through one Session) -will be returned to all connected Sessions/clients with no distinction. This mode will have the -Session(s) auto-create and puppet a Character in the same way as mode 0.

  • -
  • MULTISESSION_MODE=2: Many sessions per account, one character per session. In this mode, -puppeting an Object/Character will link the puppet back only to the particular Session doing the -puppeting. That is, input from that Session will make use of the CmdSet of that Object/Character and -outgoing messages (such as the result of a look) will be passed back only to that puppeting -Session. If another Session tries to puppet the same Character, the old Session will automatically -un-puppet it. From the player’s perspective, this will mean that they can open separate game clients -and play a different Character in each using one game account. -This mode will not auto-create a Character and not auto-puppet on login like in modes 0 and 1. -Instead it changes how the account-cmdsets’s OOCLook command works so as to show a simple -‘character select’ menu.

  • -
  • MULTISESSION_MODE=3: Many sessions per account and character. This is the full multi-puppeting -mode, where multiple sessions may not only connect to the player account but multiple sessions may -also puppet a single character at the same time. From the user’s perspective it means one can open -multiple client windows, some for controlling different Characters and some that share a Character’s -input/output like in mode 1. This mode otherwise works the same as mode 2.

  • -
-
-

Note that even if multiple Sessions puppet one Character, there is only ever one instance of that -Character.

-
-
-
-

Returning data to the session

-

When you use msg() to return data to a user, the object on which you call the msg() matters. The -MULTISESSION_MODE also matters, especially if greater than 1.

-

For example, if you use account.msg("hello") there is no way for evennia to know which session it -should send the greeting to. In this case it will send it to all sessions. If you want a specific -session you need to supply its session to the msg call (account.msg("hello", session=mysession)).

-

On the other hand, if you call the msg() message on a puppeted object, like -character.msg("hello"), the character already knows the session that controls it - it will -cleverly auto-add this for you (you can specify a different session if you specifically want to send -stuff to another session).

-

Finally, there is a wrapper for msg() on all command classes: command.msg(). This will -transparently detect which session was triggering the command (if any) and redirects to that session -(this is most often what you want). If you are having trouble redirecting to a given session, -command.msg() is often the safest bet.

-

You can get the session in two main ways:

-
    -
  • Accounts and Objects (including Characters) have a sessions property. -This is a handler that tracks all Sessions attached to or puppeting them. Use e.g. -accounts.sessions.get() to get a list of Sessions attached to that entity.

  • -
  • A Command instance has a session property that always points back to the Session that triggered -it (it’s always a single one). It will be None if no session is involved, like when a mob or -script triggers the Command.

  • -
-
-
-

Customizing the Session object

-

When would one want to customize the Session object? Consider for example a character creation -system: You might decide to keep this on the out-of-character level. This would mean that you create -the character at the end of some sort of menu choice. The actual char-create cmdset would then -normally be put on the account. This works fine as long as you are MULTISESSION_MODE below 2. -For higher modes, replacing the Account cmdset will affect all your connected sessions, also those -not involved in character creation. In this case you want to instead put the char-create cmdset on -the Session level - then all other sessions will keep working normally despite you creating a new -character in one of them.

-

By default, the session object gets the commands.default_cmdsets.UnloggedinCmdSet when the user -first connects. Once the session is authenticated it has no default sets. To add a “logged-in” -cmdset to the Session, give the path to the cmdset class with settings.CMDSET_SESSION. This set -will then henceforth always be present as soon as the account logs in.

-

To customize further you can completely override the Session with your own subclass. To replace the -default Session class, change settings.SERVER_SESSION_CLASS to point to your custom class. This is -a dangerous practice and errors can easily make your game unplayable. Make sure to take heed of the -original and make your -changes carefully.

-
-
-

Portal and Server Sessions

-

Note: This is considered an advanced topic. You don’t need to know this on a first read-through.

-

Evennia is split into two parts, the Portal and the Server. Each side tracks -its own Sessions, syncing them to each other.

-

The “Session” we normally refer to is actually the ServerSession. Its counter-part on the Portal -side is the PortalSession. Whereas the server sessions deal with game states, the portal session -deals with details of the connection-protocol itself. The two are also acting as backups of critical -data such as when the server reboots.

-

New Account connections are listened for and handled by the Portal using the [protocols](Portal-And- -Server) it understands (such as telnet, ssh, webclient etc). When a new connection is established, a -PortalSession is created on the Portal side. This session object looks different depending on -which protocol is used to connect, but all still have a minimum set of attributes that are generic -to all -sessions.

-

These common properties are piped from the Portal, through the AMP connection, to the Server, which -is now informed a new connection has been established. On the Server side, a ServerSession object -is created to represent this. There is only one type of ServerSession; It looks the same -regardless of how the Account connects.

-

From now on, there is a one-to-one match between the ServerSession on one side of the AMP -connection and the PortalSession on the other. Data arriving to the Portal Session is sent on to -its mirror Server session and vice versa.

-

During certain situations, the portal- and server-side sessions are -“synced” with each other:

-
    -
  • The Player closes their client, killing the Portal Session. The Portal syncs with the Server to -make sure the corresponding Server Session is also deleted.

  • -
  • The Player quits from inside the game, killing the Server Session. The Server then syncs with the -Portal to make sure to close the Portal connection cleanly.

  • -
  • The Server is rebooted/reset/shutdown - The Server Sessions are copied over (“saved”) to the -Portal side. When the Server comes back up, this data is returned by the Portal so the two are again -in sync. This way an Account’s login status and other connection-critical things can survive a -server reboot (assuming the Portal is not stopped at the same time, obviously).

  • -
-
-
-

Sessionhandlers

-

Both the Portal and Server each have a sessionhandler to manage the connections. These handlers -are global entities contain all methods for relaying data across the AMP bridge. All types of -Sessions hold a reference to their respective Sessionhandler (the property is called -sessionhandler) so they can relay data. See protocols for more info -on building new protocols.

-

To get all Sessions in the game (i.e. all currently connected clients), you access the server-side -Session handler, which you get by

-
from evennia.server.sessionhandler import SESSION_HANDLER
-
-
-
-

Note: The SESSION_HANDLER singleton has an older alias SESSIONS that is commonly seen in -various places as well.

-
-

See the -sessionhandler.py -module for details on the capabilities of the ServerSessionHandler.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Setting-up-PyCharm.html b/docs/0.9.5/Setting-up-PyCharm.html deleted file mode 100644 index 35a8e1a348..0000000000 --- a/docs/0.9.5/Setting-up-PyCharm.html +++ /dev/null @@ -1,239 +0,0 @@ - - - - - - - - - Setting up PyCharm — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Setting up PyCharm

-
-
-

Directions for setting up PyCharm with Evennia

-

PyCharm is a Python developer’s IDE from Jetbrains available -for Windows, Mac and Linux. It is a commercial product but offer free trials, a scaled-down -community edition and also generous licenses for OSS projects like Evennia.

-
-

This page was originally tested on Windows (so use Windows-style path examples), but should work -the same for all platforms.

-
-

First, install Evennia on your local machine with [[Getting Started]]. If you’re new to PyCharm, -loading your project is as easy as selecting the Open option when PyCharm starts, and browsing to -your game folder (the one created with evennia --init). We refer to it as mygame here.

-

If you want to be able to examine evennia’s core code or the scripts inside your virtualenv, you’ll -need to add them to your project too:

-
    -
  1. Go to File > Open...

  2. -
  3. Select the folder (i.e. the evennia root)

  4. -
  5. Select “Open in current window” and “Add to currently opened projects”

  6. -
-
-

Setting up the project interpreter

-

It’s a good idea to do this before attempting anything further. The rest of this page assumes your -project is already configured in PyCharm.

-
    -
  1. Go to File > Settings... > Project: \<mygame\> > Project Interpreter

  2. -
  3. Click the Gear symbol > Add local

  4. -
  5. Navigate to your evenv/scripts directory, and select Python.exe

  6. -
-

Enjoy seeing all your imports checked properly, setting breakpoints, and live variable watching!

-
-
-

Attaching PyCharm debugger to Evennia

-
    -
  1. Launch Evennia in your preferred way (usually from a console/terminal)

  2. -
  3. Open your project in PyCharm

  4. -
  5. In the PyCharm menu, select Run > Attach to Local Process...

  6. -
  7. From the list, pick the twistd process with the server.py parameter (Example: twistd.exe --nodaemon --logfile=\<mygame\>\server\logs\server.log --python=\<evennia repo\>\evennia\server\server.py)

  8. -
-

Of course you can attach to the portal process as well. If you want to debug the Evennia launcher -or runner for some reason (or just learn how they work!), see Run Configuration below.

-
-

NOTE: Whenever you reload Evennia, the old Server process will die and a new one start. So when -you restart you have to detach from the old and then reattach to the new process that was created.

-
-
-

To make the process less tedious you can apply a filter in settings to show only the server.py -process in the list. To do that navigate to: Settings/Preferences | Build, Execution, Deployment | Python Debugger and then in Attach to process field put in: twistd.exe" --nodaemon. This is an -example for windows, I don’t have a working mac/linux box. -Example process filter configuration

-
-
-
-

Setting up an Evennia run configuration

-

This configuration allows you to launch Evennia from inside PyCharm. Besides convenience, it also -allows suspending and debugging the evennia_launcher or evennia_runner at points earlier than you -could by running them externally and attaching. In fact by the time the server and/or portal are -running the launcher will have exited already.

-
    -
  1. Go to Run > Edit Configutations...

  2. -
  3. Click the plus-symbol to add a new configuration and choose Python

  4. -
  5. Add the script: \<yourrepo\>\evenv\Scripts\evennia_launcher.py (substitute your virtualenv if -it’s not named evenv)

  6. -
  7. Set script parameters to: start -l (-l enables console logging)

  8. -
  9. Ensure the chosen interpreter is from your virtualenv

  10. -
  11. Set Working directory to your mygame folder (not evenv nor evennia)

  12. -
  13. You can refer to the PyCharm documentation for general info, but you’ll want to set at least a -config name (like “MyMUD start” or similar).

  14. -
-

Now set up a “stop” configuration by following the same steps as above, but set your Script -parameters to: stop (and name the configuration appropriately).

-

A dropdown box holding your new configurations should appear next to your PyCharm run button. -Select MyMUD start and press the debug icon to begin debugging. Depending on how far you let the -program run, you may need to run your “MyMUD stop” config to actually stop the server, before you’ll -be able start it again.

-
-
-

Alternative run configuration - utilizing logfiles as source of data

-

This configuration takes a bit different approach as instead of focusing on getting the data back -through logfiles. Reason for that is this way you can easily separate data streams, for example you -rarely want to follow both server and portal at the same time, and this will allow it. This will -also make sure to stop the evennia before starting it, essentially working as reload command (it -will also include instructions how to disable that part of functionality). We will start by defining -a configuration that will stop evennia. This assumes that upfire is your pycharm project name, and -also the game name, hence the upfire/upfire path.

-
    -
  1. Go to Run > Edit Configutations...\

  2. -
  3. Click the plus-symbol to add a new configuration and choose the python interpreter to use (should -be project default)

  4. -
  5. Name the configuration as “stop evennia” and fill rest of the fields accordingly to the image: -Stop run configuration

  6. -
  7. Press Apply

  8. -
-

Now we will define the start/reload command that will make sure that evennia is not running already, -and then start the server in one go.

-
    -
  1. Go to Run > Edit Configutations...\

  2. -
  3. Click the plus-symbol to add a new configuration and choose the python interpreter to use (should -be project default)

  4. -
  5. Name the configuration as “start evennia” and fill rest of the fields accordingly to the image: -Start run configuration

  6. -
  7. Navigate to the Logs tab and add the log files you would like to follow. The picture shows -adding portal.log which will show itself in portal tab when running: -Configuring logs following

  8. -
  9. Skip the following steps if you don’t want the launcher to stop evennia before starting.

  10. -
  11. Head back to Configuration tab and press the + sign at the bottom, under Before launch.... -and select Run another configuration from the submenu that will pop up.

  12. -
  13. Click stop evennia and make sure that it’s added to the list like on the image above.

  14. -
  15. Click Apply and close the run configuration window.

  16. -
-

You are now ready to go, and if you will fire up start evennia configuration you should see -following in the bottom panel: -Example of running alternative configuration -and you can click through the tabs to check appropriate logs, or even the console output as it is -still running in interactive mode.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Signals.html b/docs/0.9.5/Signals.html deleted file mode 100644 index c0d13a5454..0000000000 --- a/docs/0.9.5/Signals.html +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - Signals — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Signals

-

This is feature available from evennia 0.9 and onward.

-

There are multiple ways for you to plug in your own functionality into Evennia. -The most common way to do so is through hooks - methods on typeclasses that -gets called at particular events. Hooks are great when you want a game entity -to behave a certain way when something happens to it. Signals complements -hooks for cases when you want to easily attach new functionality without -overriding things on the typeclass.

-

When certain events happen in Evennia, a Signal is fired. The idea is that -you can “attach” any number of event-handlers to these signals. You can attach -any number of handlers and they’ll all fire whenever any entity triggers the -signal.

-

Evennia uses the Django Signal system.

-
-

Attaching a handler to a signal

-

First you create your handler

-

-def myhandler(sender, **kwargs):
-  # do stuff
-
-
-
-

The **kwargs is mandatory. Then you attach it to the signal of your choice:

-
from evennia.server import signals
-
-signals.SIGNAL_OBJECT_POST_CREATE.connect(myhandler)
-
-
-
-

This particular signal fires after (post) an Account has connected to the game. -When that happens, myhandler will fire with the sender being the Account that just connected.

-

If you want to respond only to the effects of a specific entity you can do so -like this:

-
from evennia import search_account
-from evennia import signals
-
-account = search_account("foo")[0]
-signals.SIGNAL_ACCOUNT_POST_CONNECT.connect(myhandler, account)
-
-
-
-
-

Available signals

-

All signals (including some django-specific defaults) are available in the module -evennia.server.signals -(with a shortcut evennia.signals). Signals are named by the sender type. So SIGNAL_ACCOUNT_* -returns -Account instances as senders, SIGNAL_OBJECT_* returns Objects etc. Extra keywords (kwargs) -should -be extracted from the **kwargs dict in the signal handler.

-
    -
  • SIGNAL_ACCOUNT_POST_CREATE - this is triggered at the very end of Account.create(). Note that -calling evennia.create.create_account (which is called internally by Account.create) will -not -trigger this signal. This is because using Account.create() is expected to be the most commonly -used way for users to themselves create accounts during login. It passes and extra kwarg ip with -the client IP of the connecting account.

  • -
  • SIGNAL_ACCOUNT_POST_LOGIN - this will always fire when the account has authenticated. Sends -extra kwarg session with the new Session object involved.

  • -
  • SIGNAL_ACCCOUNT_POST_FIRST_LOGIN - this fires just before SIGNAL_ACCOUNT_POST_LOGIN but only -if -this is the first connection done (that is, if there are no previous sessions connected). Also -passes the session along as a kwarg.

  • -
  • SIGNAL_ACCOUNT_POST_LOGIN_FAIL - sent when someone tried to log into an account by failed. -Passes -the session as an extra kwarg.

  • -
  • SIGNAL_ACCOUNT_POST_LOGOUT - always fires when an account logs off, no matter if other sessions -remain or not. Passes the disconnecting session along as a kwarg.

  • -
  • SIGNAL_ACCOUNT_POST_LAST_LOGOUT - fires before SIGNAL_ACCOUNT_POST_LOGOUT, but only if this is -the last Session to disconnect for that account. Passes the session as a kwarg.

  • -
  • SIGNAL_OBJECT_POST_PUPPET - fires when an account puppets this object. Extra kwargs session -and account represent the puppeting entities. -SIGNAL_OBJECT_POST_UNPUPPET - fires when the sending object is unpuppeted. Extra kwargs are -session and account.

  • -
  • SIGNAL_ACCOUNT_POST_RENAME - triggered by the setting of Account.username. Passes extra -kwargs old_name, new_name.

  • -
  • SIGNAL_TYPED_OBJECT_POST_RENAME - triggered when any Typeclassed entity’s key is changed. -Extra -kwargs passed are old_key and new_key.

  • -
  • SIGNAL_SCRIPT_POST_CREATE - fires when a script is first created, after any hooks.

  • -
  • SIGNAL_CHANNEL_POST_CREATE - fires when a Channel is first created, after any hooks.

  • -
  • SIGNAL_HELPENTRY_POST_CREATE - fires when a help entry is first created.

  • -
-

The evennia.signals module also gives you conveneient access to the default Django signals (these -use a -different naming convention).

-
    -
  • pre_save - fired when any database entitiy’s .save method fires, before any saving has -happened.

  • -
  • post_save - fires after saving a database entity.

  • -
  • pre_delete - fires just before a database entity is deleted.

  • -
  • post_delete - fires after a database entity was deleted.

  • -
  • pre_init - fires before a typeclass’ __init__ method (which in turn -happens before the at_init hook fires).

  • -
  • post_init - triggers at the end of __init__ (still before the at_init hook).

  • -
-

These are highly specialized Django signals that are unlikely to be useful to most users. But -they are included here for completeness.

-
    -
  • m2m_changed - fires after a Many-to-Many field (like db_attributes) changes.

  • -
  • pre_migrate - fires before database migration starts with evennia migrate.

  • -
  • post_migrate - fires after database migration finished.

  • -
  • request_started - sent when HTTP request begins.

  • -
  • request_finished - sent when HTTP request ends.

  • -
  • settings_changed - sent when changing settings due to @override_settings -decorator (only relevant for unit testing)

  • -
  • template_rendered - sent when test system renders http template (only useful for unit tests).

  • -
  • connection_creation - sent when making initial connection to database.

  • -
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Soft-Code.html b/docs/0.9.5/Soft-Code.html deleted file mode 100644 index 92f6ba5f1f..0000000000 --- a/docs/0.9.5/Soft-Code.html +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - - - Soft Code — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Soft Code

-

Softcode is a very simple programming language that was created for in-game development on TinyMUD -derivatives such as MUX, PennMUSH, TinyMUSH, and RhostMUSH. The idea is that by providing a stripped -down, minimalistic language for in-game use, you can allow quick and easy building and game -development to happen without having to learn C/C++. There is an added benefit of not having to have -to hand out shell access to all developers, and permissions can be used to alleviate many security -problems.

-

Writing and installing softcode is done through a MUD client. Thus it is not a formatted language. -Each softcode function is a single line of varying size. Some functions can be a half of a page long -or more which is obviously not very readable nor (easily) maintainable over time.

-
-

Examples of Softcode

-

Here is a simple ‘Hello World!’ command:

-
    @set me=HELLO_WORLD.C:$hello:@pemit %#=Hello World!
-
-
-

Pasting this into a MUX/MUSH and typing ‘hello’ will theoretically yield ‘Hello World!’, assuming -certain flags are not set on your account object.

-

Setting attributes is done via @set. Softcode also allows the use of the ampersand (&) symbol. -This shorter version looks like this:

-
    &HELLO_WORLD.C me=$hello:@pemit %#=Hello World!
-
-
-

Perhaps I want to break the Hello World into an attribute which is retrieved when emitting:

-
    &HELLO_VALUE.D me=Hello World
-    &HELLO_WORLD.C me=$hello:@pemit %#=[v(HELLO_VALUE.D)]
-
-
-

The v() function returns the HELLO_VALUE.D attribute on the object that the command resides -(me, which is yourself in this case). This should yield the same output as the first example.

-

If you are still curious about how Softcode works, take a look at some external resources:

- -
-
-

Problems with Softcode

-

Softcode is excellent at what it was intended for: simple things. It is a great tool for making an -interactive object, a room with ambiance, simple global commands, simple economies and coded -systems. However, once you start to try to write something like a complex combat system or a higher -end economy, you’re likely to find yourself buried under a mountain of functions that span multiple -objects across your entire code.

-

Not to mention, softcode is not an inherently fast language. It is not compiled, it is parsed with -each calling of a function. While MUX and MUSH parsers have jumped light years ahead of where they -once were they can still stutter under the weight of more complex systems if not designed properly.

-
-
-

Changing Times

-

Now that starting text-based games is easy and an option for even the most technically inarticulate, -new projects are a dime a dozen. People are starting new MUDs every day with varying levels of -commitment and ability. Because of this shift from fewer, larger, well-staffed games to a bunch of -small, one or two developer games, some of the benefit of softcode fades.

-

Softcode is great in that it allows a mid to large sized staff all work on the same game without -stepping on one another’s toes. As mentioned before, shell access is not necessary to develop a MUX -or a MUSH. However, now that we are seeing a lot more small, one or two-man shops, the issue of -shell access and stepping on each other’s toes is a lot less.

-
-
-

Our Solution

-

Evennia shuns in-game softcode for on-disk Python modules. Python is a popular, mature and -professional programming language. You code it using the conveniences of modern text editors. -Evennia developers have access to the entire library of Python modules out there in the wild - not -to mention the vast online help resources available. Python code is not bound to one-line functions -on objects but complex systems may be organized neatly into real source code modules, sub-modules, -or even broken out into entire Python packages as desired.

-

So what is not included in Evennia is a MUX/MOO-like online player-coding system. Advanced coding -in Evennia is primarily intended to be done outside the game, in full-fledged Python modules. -Advanced building is best handled by extending Evennia’s command system with your own sophisticated -building commands. We feel that with a small development team you are better off using a -professional source-control system (svn, git, bazaar, mercurial etc) anyway.

-
-
-

Your Solution

-

Adding advanced and flexible building commands to your game is easy and will probably be enough to -satisfy most creative builders. However, if you really, really want to offer online coding, there -is of course nothing stopping you from adding that to Evennia, no matter our recommendations. You -could even re-implement MUX’ softcode in Python should you be very ambitious. The -in-game-python is an optional -pseudo-softcode plugin aimed at developers wanting to script their game from inside it.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Spawner-and-Prototypes.html b/docs/0.9.5/Spawner-and-Prototypes.html deleted file mode 100644 index ebec972dff..0000000000 --- a/docs/0.9.5/Spawner-and-Prototypes.html +++ /dev/null @@ -1,440 +0,0 @@ - - - - - - - - - Spawner and Prototypes — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Spawner and Prototypes

-

The spawner is a system for defining and creating individual objects from a base template called a -prototype. It is only designed for use with in-game Objects, not any other type of -entity.

-

The normal way to create a custom object in Evennia is to make a Typeclass. If you -haven’t read up on Typeclasses yet, think of them as normal Python classes that save to the database -behind the scenes. Say you wanted to create a “Goblin” enemy. A common way to do this would be to -first create a Mobile typeclass that holds everything common to mobiles in the game, like generic -AI, combat code and various movement methods. A Goblin subclass is then made to inherit from -Mobile. The Goblin class adds stuff unique to goblins, like group-based AI (because goblins are -smarter in a group), the ability to panic, dig for gold etc.

-

But now it’s time to actually start to create some goblins and put them in the world. What if we -wanted those goblins to not all look the same? Maybe we want grey-skinned and green-skinned goblins -or some goblins that can cast spells or which wield different weapons? We could make subclasses of -Goblin, like GreySkinnedGoblin and GoblinWieldingClub. But that seems a bit excessive (and a -lot of Python code for every little thing). Using classes can also become impractical when wanting -to combine them - what if we want a grey-skinned goblin shaman wielding a spear - setting up a web -of classes inheriting each other with multiple inheritance can be tricky.

-

This is what the prototype is for. It is a Python dictionary that describes these per-instance -changes to an object. The prototype also has the advantage of allowing an in-game builder to -customize an object without access to the Python backend. Evennia also allows for saving and -searching prototypes so other builders can find and use (and tweak) them later. Having a library of -interesting prototypes is a good reasource for builders. The OLC system allows for creating, saving, -loading and manipulating prototypes using a menu system.

-

The spawner takes a prototype and uses it to create (spawn) new, custom objects.

-
-

Using the OLC

-

Enter the olc command or @spawn/olc to enter the prototype wizard. This is a menu system for -creating, loading, saving and manipulating prototypes. It’s intended to be used by in-game builders -and will give a better understanding of prototypes in general. Use help on each node of the menu -for more information. Below are further details about how prototypes work and how they are used.

-
-
-

The prototype

-

The prototype dictionary can either be created for you by the OLC (see above), be written manually -in a Python module (and then referenced by the @spawn command/OLC), or created on-the-fly and -manually loaded into the spawner function or @spawn command.

-

The dictionary defines all possible database-properties of an Object. It has a fixed set of allowed -keys. When preparing to store the prototype in the database (or when using the OLC), some -of these keys are mandatory. When just passing a one-time prototype-dict to the spawner the system -is -more lenient and will use defaults for keys not explicitly provided.

-

In dictionary form, a prototype can look something like this:

-
{
-   "prototype_key": "house"
-   "key": "Large house"
-   "typeclass": "typeclasses.rooms.house.House"
- }
-
-
-

If you wanted to load it into the spawner in-game you could just put all on one line:

-
@spawn {"prototype_key="house", "key": "Large house", ...}
-
-
-
-

Note that the prototype dict as given on the command line must be a valid Python structure - -so you need to put quotes around strings etc. For security reasons, a dict inserted from-in game -cannot have any -other advanced Python functionality, such as executable code, lambda etc. If builders are supposed -to be able to use such features, you need to offer them through [$protfuncs](Spawner-and- -Prototypes#protfuncs), embedded runnable functions that you have full control to check and vet -before running.

-
-
-

Prototype keys

-

All keys starting with prototype_ are for book keeping.

-
    -
  • prototype_key - the ‘name’ of the prototype. While this can sometimes be skipped (such as when -defining a prototype in a module or feeding a prototype-dict manually to the spawner function), -it’s good -practice to try to include this. It is used for book-keeping and storing of the prototype so you -can find it later.

  • -
  • prototype_parent - If given, this should be the prototype_key of another prototype stored in -the system or available in a module. This makes this prototype inherit the keys from the -parent and only override what is needed. Give a tuple (parent1, parent2, ...) for multiple -left-right inheritance. If this is not given, a typeclass should usually be defined (below).

  • -
  • prototype_desc - this is optional and used when listing the prototype in in-game listings.

  • -
  • protototype_tags - this is optional and allows for tagging the prototype in order to find it -easier later.

  • -
  • prototype_locks - two lock types are supported: edit and spawn. The first lock restricts -the copying and editing of the prototype when loaded through the OLC. The second determines who -may use the prototype to create new objects.

  • -
-

The remaining keys determine actual aspects of the objects to spawn from this prototype:

-
    -
  • key - the main object identifier. Defaults to “Spawned Object X”, where X is a random -integer.

  • -
  • typeclass - A full python-path (from your gamedir) to the typeclass you want to use. If not -set, the prototype_parent should be -defined, with typeclass defined somewhere in the parent chain. When creating a one-time -prototype -dict just for spawning, one could omit this - settings.BASE_OBJECT_TYPECLASS will be used -instead.

  • -
  • location - this should be a #dbref.

  • -
  • home - a valid #dbref. Defaults to location or settings.DEFAULT_HOME if location does not -exist.

  • -
  • destination - a valid #dbref. Only used by exits.

  • -
  • permissions - list of permission strings, like ["Accounts", "may_use_red_door"]

  • -
  • locks - a lock-string like "edit:all();control:perm(Builder)"

  • -
  • aliases - list of strings for use as aliases

  • -
  • tags - list Tags. These are given as tuples (tag, category, data).

  • -
  • attrs - list of Attributes. These are given as tuples (attrname, value, category, lockstring)

  • -
  • Any other keywords are interpreted as non-category Attributes and their values. -This is -convenient for simple Attributes - use attrs for full control of Attributes.

  • -
-

Deprecated as of Evennia 0.8:

-
    -
  • ndb_<name> - sets the value of a non-persistent attribute ("ndb_" is stripped from the name). -This is simply not useful in a prototype and is deprecated.

  • -
  • exec - This accepts a code snippet or a list of code snippets to run. This should not be used - -use callables or $protfuncs instead (see below).

  • -
-
-
-

Prototype values

-

The prototype supports values of several different types.

-

It can be a hard-coded value:

-
    {"key": "An ugly goblin", ...}
-
-
-
-

It can also be a callable. This callable is called without arguments whenever the prototype is -used to -spawn a new object:

-
    {"key": _get_a_random_goblin_name, ...}
-
-
-
-

By use of Python lambda one can wrap the callable so as to make immediate settings in the -prototype:

-
    {"key": lambda: random.choice(("Urfgar", "Rick the smelly", "Blargh the foul", ...)), ...}
-
-
-
-
-

Protfuncs

-

Finally, the value can be a prototype function (Protfunc). These look like simple function calls -that you embed in strings and that has a $ in front, like

-
    {"key": "$choice(Urfgar, Rick the smelly, Blargh the foul)",
-     "attrs": {"desc": "This is a large $red(and very red) demon. "
-                       "He has $randint(2,5) skulls in a chain around his neck."}
-
-
-

At execution time, the place of the protfunc will be replaced with the result of that protfunc being -called (this is always a string). A protfunc works in much the same way as an -InlineFunc - they are actually -parsed using the same parser - except protfuncs are run every time the prototype is used to spawn a -new object (whereas an inlinefunc is called when a text is returned to the user).

-

Here is how a protfunc is defined (same as an inlinefunc).

-
# this is a silly example, you can just color the text red with |r directly!
-def red(*args, **kwargs):
-   """
-   Usage: $red(<text>)
-   Returns the same text you entered, but red.
-   """
-   if not args or len(args) > 1:
-      raise ValueError("Must have one argument, the text to color red!")
-   return "|r{}|n".format(args[0])
-
-
-
-

Note that we must make sure to validate input and raise ValueError if that fails. Also, it is -not possible to use keywords in the call to the protfunc (so something like $echo(text, align=left) is invalid). The kwargs requred is for internal evennia use and not used at all for -protfuncs (only by inlinefuncs).

-
-

To make this protfunc available to builders in-game, add it to a new module and add the path to that -module to settings.PROT_FUNC_MODULES:

-
# in mygame/server/conf/settings.py
-
-PROT_FUNC_MODULES += ["world.myprotfuncs"]
-
-
-
-

All global callables in your added module will be considered a new protfunc. To avoid this (e.g. -to have helper functions that are not protfuncs on their own), name your function something starting -with _.

-

The default protfuncs available out of the box are defined in evennia/prototypes/profuncs.py. To -override the ones available, just add the same-named function in your own protfunc module.

-

| Protfunc | Description |

-

| $random() | Returns random value in range [0, 1) | -| $randint(start, end) | Returns random value in range [start, end] | -| $left_justify(<text>) | Left-justify text | -| $right_justify(<text>) | Right-justify text to screen width | -| $center_justify(<text>) | Center-justify text to screen width | -| $full_justify(<text>) | Spread text across screen width by adding spaces | -| $protkey(<name>) | Returns value of another key in this prototype (self-reference) | -| $add(<value1>, <value2>) | Returns value1 + value2. Can also be lists, dicts etc | -| $sub(<value1>, <value2>) | Returns value1 - value2 | -| $mult(<value1>, <value2>) | Returns value1 * value2 | -| $div(<value1>, <value2>) | Returns value2 / value1 | -| $toint(<value>) | Returns value converted to integer (or value if not possible) | -| $eval(<code>) | Returns result of literal- -eval of code string. Only simple -python expressions. | -| $obj(<query>) | Returns object #dbref searched globally by key, tag or #dbref. Error if more -than one found.” | -| $objlist(<query>) | Like $obj, except always returns a list of zero, one or more results. | -| $dbref(dbref) | Returns argument if it is formed as a #dbref (e.g. #1234), otherwise error.

-

For developers with access to Python, using protfuncs in prototypes is generally not useful. Passing -real Python functions is a lot more powerful and flexible. Their main use is to allow in-game -builders to -do limited coding/scripting for their prototypes without giving them direct access to raw Python.

-
-
-
-
-

Storing prototypes

-

A prototype can be defined and stored in two ways, either in the database or as a dict in a module.

-
-

Database prototypes

-

Stored as Scripts in the database. These are sometimes referred to as database- -prototypes This is the only way for in-game builders to modify and add prototypes. They have the -advantage of being easily modifiable and sharable between builders but you need to work with them -using in-game tools.

-
-
-

Module-based prototypes

-

These prototypes are defined as dictionaries assigned to global variables in one of the modules -defined in settings.PROTOTYPE_MODULES. They can only be modified from outside the game so they are -are necessarily “read-only” from in-game and cannot be modified (but copies of them could be made -into database-prototypes). These were the only prototypes available before Evennia 0.8. Module based -prototypes can be useful in order for developers to provide read-only “starting” or “base” -prototypes to build from or if they just prefer to work offline in an external code editor.

-

By default mygame/world/prototypes.py is set up for you to add your own prototypes. All global -dicts in this module will be considered by Evennia to be a prototype. You could also tell Evennia -to look for prototypes in more modules if you want:

-
# in mygame/server/conf/settings.py
-
-PROTOTYPE_MODULES += ["world.myownprototypes", "combat.prototypes"]
-
-
-
-
-

Note the += operator in the above example. This will extend the already defined world.prototypes -definition in the settings_default.py file in Evennia. If you would like to completely override the -location of your PROTOTYPE_MODULES then set this to just = without the addition operator.

-
-

Here is an example of a prototype defined in a module:

-
    # in a module Evennia looks at for prototypes,
-    # (like mygame/world/prototypes.py)
-
-    ORC_SHAMAN = {"key":"Orc shaman",
-                  "typeclass": "typeclasses.monsters.Orc",
-                  "weapon": "wooden staff",
-                  "health": 20}
-
-
-
-

Note that in the example above, "ORC_SHAMAN" will become the prototype_key of this prototype. -It’s the only case when prototype_key can be skipped in a prototype. However, if prototype_key -was given explicitly, that would take precedence. This is a legacy behavior and it’s recommended -that you always add prototype_key to be consistent.

-
-
-
-
-

Using @spawn

-

The spawner can be used from inside the game through the Builder-only @spawn command. Assuming the -“goblin” typeclass is available to the system (either as a database-prototype or read from module), -you can spawn a new goblin with

-
@spawn goblin
-
-
-

You can also specify the prototype directly as a valid Python dictionary:

-
@spawn {"prototype_key": "shaman", \
-        "key":"Orc shaman", \
-        "prototype_parent": "goblin", \
-        "weapon": "wooden staff", \
-        "health": 20}
-
-
-
-

Note: The @spawn command is more lenient about the prototype dictionary than shown here. So you -can for example skip the prototype_key if you are just testing a throw-away prototype. A random -hash will be used to please the validation. You could also skip prototype_parent/typeclass - then -the typeclass given by settings.BASE_OBJECT_TYPECLASS will be used.

-
-
-
-

Using evennia.prototypes.spawner()

-

In code you access the spawner mechanism directly via the call

-
    new_objects = evennia.prototypes.spawner.spawn(*prototypes)
-
-
-

All arguments are prototype dictionaries or the unique prototype_keys of prototypes -known to the system (either database- or module-based). The function will return a matching list of -created objects. Example:

-
    obj1, obj2, obj3 = evennia.prototypes.spawner.spawn({"key": "Obj1", "desc": "A test"},
-                                                        {"key": "Obj2", "desc": "Another test"},
-                                                         "GOBLIN_SHAMAN")
-
-
-
-

Hint: Same as when using @spawn, when spawning from a one-time prototype dict like this, you can -skip otherwise required keys, like prototype_key or typeclass/prototype_parent. Defaults will -be used.

-
-

Note that no location will be set automatically when using evennia.prototypes.spawner.spawn(), -you -have to specify location explicitly in the prototype dict.

-

If the prototypes you supply are using prototype_parent keywords, the spawner will read prototypes -from modules -in settings.PROTOTYPE_MODULES as well as those saved to the database to determine the body of -available parents. The spawn command takes many optional keywords, you can find its definition in -the api docs.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Start-Stop-Reload.html b/docs/0.9.5/Start-Stop-Reload.html deleted file mode 100644 index 7cace2d2ee..0000000000 --- a/docs/0.9.5/Start-Stop-Reload.html +++ /dev/null @@ -1,314 +0,0 @@ - - - - - - - - - Start Stop Reload — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Start Stop Reload

-

You control Evennia from your game folder (we refer to it as mygame/ here), using the evennia -program. If the evennia program is not available on the command line you must first install -Evennia as described in the Getting Started page.

-
-

Hint: If you ever try the evennia command and get an error complaining that the command is not -available, make sure your virtualenv is active.

-
-

Below are described the various management options. Run

-
evennia -h
-
-
-

to give you a brief help and

-
evennia menu
-
-
-

to give you a menu with options.

-
-

Starting Evennia

-

Evennia consists of two components, the Evennia Server and Portal. Briefly, -the Server is what is running the mud. It handles all game-specific things but doesn’t care -exactly how players connect, only that they have. The Portal is a gateway to which players -connect. It knows everything about telnet, ssh, webclient protocols etc but very little about the -game. Both are required for a functioning mud.

-
 evennia start
-
-
-

The above command will start the Portal, which in turn will boot up the Server. The command will -print a summary of the process and unless there is an error you will see no further output. Both -components will instead log to log files in mygame/server/logs/. For convenience you can follow -those logs directly in your terminal by attaching -l to commands:

-
 evennia -l
-
-
-

Will start following the logs of an already running server. When starting Evennia you can also do

-
 evennia start -l
-
-
-
-

To stop viewing the log files, press Ctrl-C.

-
-
-
-

Foreground mode

-

Normally, Evennia runs as a ‘daemon’, in the background. If you want you can start either of the -processes (but not both) as foreground processes in interactive mode. This means they will log -directly to the terminal (rather than to log files that we then echo to the terminal) and you can -kill the process (not just the log-file view) with Ctrl-C.

-
evennia istart
-
-
-

will start/restart the Server in interactive mode. This is required if you want to run a -debugger. Next time you reload the server, it will return to normal mode.

-
evennia ipstart
-
-
-

will start the Portal in interactive mode. This is usually only necessary if you want to run -Evennia under the control of some other type of process.

-
-
-

Reloading

-

The act of reloading means the Portal will tell the Server to shut down and then boot it back up -again. Everyone will get a message and the game will be briefly paused for all accounts as the -server -reboots. Since they are connected to the Portal, their connections are not lost.

-

Reloading is as close to a “warm reboot” you can get. It reinitializes all code of Evennia, but -doesn’t kill “persistent” Scripts. It also calls at_server_reload() hooks on all -objects so you -can save eventual temporary properties you want.

-

From in-game the @reload command is used. You can also reload the server from outside the game:

-
 evennia reload
-
-
-

Sometimes reloading from “the outside” is necessary in case you have added some sort of bug that -blocks in-game input.

-
-
-

Resetting

-

Resetting is the equivalent of a “cold reboot” - the Server will shut down and then restarted -again, but will behave as if it was fully shut down. As opposed to a “real” shutdown, no accounts -will be disconnected during a -reset. A reset will however purge all non-persistent scripts and will call at_server_shutdown() -hooks. It can be a good way to clean unsafe scripts during development, for example.

-

From in-game the @reset command is used. From the terminal:

-
evennia reset
-
-
-
-
-

Rebooting

-

This will shut down both Server and Portal, which means all connected players will lose their -connection. It can only be initiated from the terminal:

-
evennia reboot
-
-
-

This is identical to doing these two commands:

-
 evennia stop
- evennia start
-
-
-
-
-

Shutting down

-

A full shutdown closes Evennia completely, both Server and Portal. All accounts will be booted and -systems saved and turned off cleanly.

-

From inside the game you initiate a shutdown with the @shutdown command. From command line you do

-
 evennia stop
-
-
-

You will see messages of both Server and Portal closing down. All accounts will see the shutdown -message and then be disconnected. The same effect happens if you press Ctrl+C while the server -runs in interactive mode.

-
-
-

Status and info

-

To check basic Evennia settings, such as which ports and services are active, this will repeat the -initial return given when starting the server:

-
evennia info
-
-
-

You can also get a briefer run-status from both components with this command

-
evennia status
-
-
-

This can be useful for automating checks to make sure the game is running and is responding.

-
-
-

Killing (Linux/Mac only)

-

In the extreme case that neither of the server processes locks up and does not respond to commands, -you can send them kill-signals to force them to shut down. To kill only the Server:

-
evennia skill
-
-
-

To kill both Server and Portal:

-
evennia kill
-
-
-

Note that this functionality is not supported on Windows.

-
-
-

Django options

-

The evennia program will also pass-through options used by the django-admin. These operate on -the database in various ways.

-
 evennia migrate # migrate the database
- evennia shell   # launch an interactive, django-aware python shell
- evennia dbshell # launch database shell
-
-
-

For (many) more options, see the django-admin -docs.

-
-
-

Advanced handling of Evennia processes

-

If you should need to manually manage Evennia’s processors (or view them in a task manager program -such as Linux’ top or the more advanced htop), you will find the following processes to be -related to Evennia:

-
    -
  • 1 x twistd ... evennia/server/portal/portal.py - this is the Portal process.

  • -
  • 3 x twistd ... server.py - One of these processes manages Evennia’s Server component, the main -game. The other processes (with the same name but different process id) handle’s Evennia’s -internal web server threads. You can look at mygame/server/server.pid to determine which is the -main process.

  • -
-
-

Syntax errors during live development

-

During development, you will usually modify code and then reload the server to see your changes. -This is done by Evennia re-importing your custom modules from disk. Usually bugs in a module will -just have you see a traceback in the game, in the log or on the command line. For some really -serious syntax errors though, your module might not even be recognized as valid Python. Evennia may -then fail to restart correctly.

-

From inside the game you see a text about the Server restarting followed by an ever growing list of -“…”. Usually this only lasts a very short time (up to a few seconds). If it seems to go on, it -means the Portal is still running (you are still connected to the game) but the Server-component of -Evennia failed to restart (that is, it remains in a shut-down state). Look at your log files or -terminal to see what the problem is - you will usually see a clear traceback showing what went -wrong.

-

Fix your bug then run

-
evennia start
-
-
-

Assuming the bug was fixed, this will start the Server manually (while not restarting the Portal). -In-game you should now get the message that the Server has successfully restarted.

-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Static-In-Game-Map.html b/docs/0.9.5/Static-In-Game-Map.html deleted file mode 100644 index 5f4ca0e012..0000000000 --- a/docs/0.9.5/Static-In-Game-Map.html +++ /dev/null @@ -1,506 +0,0 @@ - - - - - - - - - Static In Game Map — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Static In Game Map

-
-

Introduction

-

This tutorial describes the creation of an in-game map display based on a pre-drawn map. It also -details how to use the Batch code processor for advanced building. There is -also the Dynamic in-game map tutorial that works in the opposite direction, -by generating a map from an existing grid of rooms.

-

Evennia does not require its rooms to be positioned in a “logical” way. Your exits could be named -anything. You could make an exit “west” that leads to a room described to be in the far north. You -could have rooms inside one another, exits leading back to the same room or describing spatial -geometries impossible in the real world.

-

That said, most games do organize their rooms in a logical fashion, if nothing else to retain the -sanity of their players. And when they do, the game becomes possible to map. This tutorial will give -an example of a simple but flexible in-game map system to further help player’s to navigate. We will

-

To simplify development and error-checking we’ll break down the work into bite-size chunks, each -building on what came before. For this we’ll make extensive use of the Batch code processor, so you may want to familiarize yourself with that.

-
    -
  1. Planning the map - Here we’ll come up with a small example map to use for the rest of the -tutorial.

  2. -
  3. Making a map object - This will showcase how to make a static in-game “map” object a -Character could pick up and look at.

  4. -
  5. Building the map areas - Here we’ll actually create the small example area according to the -map we designed before.

  6. -
  7. Map code - This will link the map to the location so our output looks something like this:

    -
    crossroads(#3)
    -↑╚∞╝↑
    -≈↑│↑∩  The merger of two roads. To the north looms a mighty castle.
    -O─O─O  To the south, the glow of a campfire can be seen. To the east lie
    -≈↑│↑∩  the vast mountains and to the west is heard the waves of the sea.
    -↑▲O▲↑
    -
    -Exits: north(#8), east(#9), south(#10), west(#11)
    -
    -
    -
  8. -
-

We will henceforth assume your game folder is name named mygame and that you haven’t modified the -default commands. We will also not be using Colors for our map since they -don’t show in the documentation wiki.

-
-
-

Planning the Map

-

Let’s begin with the fun part! Maps in MUDs come in many different shapes and sizes. Some appear as just boxes connected by lines. Others have complex graphics that are -external to the game itself.

-

Our map will be in-game text but that doesn’t mean we’re restricted to the normal alphabet! If -you’ve ever selected the Wingdings font in Microsoft Word -you will know there are a multitude of other characters around to use. When creating your game with -Evennia you have access to the UTF-8 character encoding which -put at your disposal thousands of letters, number and geometric shapes.

-

For this exercise, we’ve copy-and-pasted from the pallet of special characters used over at Dwarf -Fortress to create what is hopefully a -pleasing and easy to understood landscape:

-
≈≈↑↑↑↑↑∩∩
-≈≈↑╔═╗↑∩∩   Places the account can visit are indicated by "O".
-≈≈↑║O║↑∩∩   Up the top is a castle visitable by the account.
-≈≈↑╚∞╝↑∩∩   To the right is a cottage and to the left the beach.
-≈≈≈↑│↑∩∩∩   And down the bottom is a camp site with tents.
-≈≈O─O─O⌂∩   In the center is the starting location, a crossroads
-≈≈≈↑│↑∩∩∩   which connect the four other areas.
-≈≈↑▲O▲↑∩∩
-≈≈↑↑▲↑↑∩∩
-≈≈↑↑↑↑↑∩∩
-
-
-

There are many considerations when making a game map depending on the play style and requirements -you intend to implement. Here we will display a 5x5 character map of the area surrounding the -account. This means making sure to account for 2 characters around every visitable location. Good -planning at this stage can solve many problems before they happen.

-
-
-

Creating a Map Object

-

In this section we will try to create an actual “map” object that an account can pick up and look -at.

-

Evennia offers a range of default commands for creating objects and rooms -in-game. While readily accessible, these commands are made to do very -specific, restricted things and will thus not offer as much flexibility to experiment (for an -advanced exception see in-line functions). Additionally, entering long -descriptions and properties over and over in the game client can become tedious; especially when -testing and you may want to delete and recreate things over and over.

-

To overcome this, Evennia offers batch processors that work as input-files -created out-of-game. In this tutorial we’ll be using the more powerful of the two available batch -processors, the Batch Code Processor , called with the @batchcode command. -This is a very powerful tool. It allows you to craft Python files to act as blueprints of your -entire game world. These files have access to use Evennia’s Python API directly. Batchcode allows -for easy editing and creation in whatever text editor you prefer, avoiding having to manually build -the world line-by-line inside the game.

-
-

Important warning: @batchcode’s power is only rivaled by the @py command. Batchcode is so -powerful it should be reserved only for the superuser. Think carefully -before you let others (such as Developer- level staff) run @batchcode on their own - make sure -you are okay with them running arbitrary Python code on your server.

-
-

While a simple example, the map object it serves as good way to try out @batchcode. Go to -mygame/world and create a new file there named batchcode_map.py:

-
# mygame/world/batchcode_map.py
-
-from evennia import create_object
-from evennia import DefaultObject
-
-# We use the create_object function to call into existence a
-# DefaultObject named "Map" wherever you are standing.
-
-map = create_object(DefaultObject, key="Map", location=caller.location)
-
-# We then access its description directly to make it our map.
-
-map.db.desc = """
-≈≈↑↑↑↑↑∩∩
-≈≈↑╔═╗↑∩∩
-≈≈↑║O║↑∩∩
-≈≈↑╚∞╝↑∩∩
-≈≈≈↑│↑∩∩∩
-≈≈O─O─O⌂∩
-≈≈≈↑│↑∩∩∩
-≈≈↑▲O▲↑∩∩
-≈≈↑↑▲↑↑∩∩
-≈≈↑↑↑↑↑∩∩
-"""
-
-# This message lets us know our map was created successfully.
-caller.msg("A map appears out of thin air and falls to the ground.")
-
-
-

Log into your game project as the superuser and run the command

-
@batchcode batchcode_map
-
-
-

This will load your batchcode_map.py file and execute the code (Evennia will look in your world/ -folder automatically so you don’t need to specify it).

-

A new map object should have appeared on the ground. You can view the map by using look map. Let’s -take it with the get map command. We’ll need it in case we get lost!

-
-
-

Building the map areas

-

We’ve just used batchcode to create an object useful for our adventures. But the locations on that -map does not actually exist yet - we’re all mapped up with nowhere to go! Let’s use batchcode to -build a game area based on our map. We have five areas outlined: a castle, a cottage, a campsite, a -coastal beach and the crossroads which connects them. Create a new batchcode file for this in -mygame/world, named batchcode_world.py.

-
# mygame/world/batchcode_world.py
-
-from evennia import create_object, search_object
-from typeclasses import rooms, exits
-
-# We begin by creating our rooms so we can detail them later.
-
-centre = create_object(rooms.Room, key="crossroads")
-north = create_object(rooms.Room, key="castle")
-east = create_object(rooms.Room, key="cottage")
-south = create_object(rooms.Room, key="camp")
-west = create_object(rooms.Room, key="coast")
-
-# This is where we set up the cross roads.
-# The rooms description is what we see with the 'look' command.
-
-centre.db.desc = """
-The merger of two roads. A single lamp post dimly illuminates the lonely crossroads.
-To the north looms a mighty castle. To the south the glow of a campfire can be seen.
-To the east lie a wall of mountains and to the west the dull roar of the open sea.
-"""
-
-# Here we are creating exits from the centre "crossroads" location to
-# destinations to the north, east, south, and west. We will be able
-# to use the exit by typing it's key e.g. "north" or an alias e.g. "n".
-
-centre_north = create_object(exits.Exit, key="north",
-                            aliases=["n"], location=centre, destination=north)
-centre_east = create_object(exits.Exit, key="east",
-                            aliases=["e"], location=centre, destination=east)
-centre_south = create_object(exits.Exit, key="south",
-                            aliases=["s"], location=centre, destination=south)
-centre_west = create_object(exits.Exit, key="west",
-                            aliases=["w"], location=centre, destination=west)
-
-# Now we repeat this for the other rooms we'll be implementing.
-# This is where we set up the northern castle.
-
-north.db.desc = "An impressive castle surrounds you. " \
-                "There might be a princess in one of these towers."
-north_south = create_object(exits.Exit, key="south",
-                            aliases=["s"], location=north, destination=centre)
-
-# This is where we set up the eastern cottage.
-
-east.db.desc = "A cosy cottage nestled among mountains " \
-               "stretching east as far as the eye can see."
-east_west = create_object(exits.Exit, key="west",
-                            aliases=["w"], location=east, destination=centre)
-
-# This is where we set up the southern camp.
-
-south.db.desc = "Surrounding a clearing are a number of " \
-                "tribal tents and at their centre a roaring fire."
-south_north = create_object(exits.Exit, key="north",
-                            aliases=["n"], location=south, destination=centre)
-
-# This is where we set up the western coast.
-
-west.db.desc = "The dark forest halts to a sandy beach. " \
-               "The sound of crashing waves calms the soul."
-west_east = create_object(exits.Exit, key="east",
-                            aliases=["e"], location=west, destination=centre)
-
-# Lastly, lets make an entrance to our world from the default Limbo room.
-
-limbo = search_object('Limbo')[0]
-limbo_exit = create_object(exits.Exit, key="enter world",
-                            aliases=["enter"], location=limbo, destination=centre)
-
-
-

Apply this new batch code with @batchcode batchcode_world. If there are no errors in the code we -now have a nice mini-world to explore. Remember that if you get lost you can look at the map we -created!

-
-
-

In-game minimap

-

Now we have a landscape and matching map, but what we really want is a mini-map that displays -whenever we move to a room or use the look command.

-

We could manually enter a part of the map into the description of every room like we did our map -object description. But some MUDs have tens of thousands of rooms! Besides, if we ever changed our -map we would have to potentially alter a lot of those room descriptions manually to match the -change. So instead we will make one central module to hold our map. Rooms will reference this -central location on creation and the map changes will thus come into effect when next running our -batchcode.

-

To make our mini-map we need to be able to cut our full map into parts. To do this we need to put it -in a format which allows us to do that easily. Luckily, python allows us to treat strings as lists -of characters allowing us to pick out the characters we need.

-

mygame/world/map_module.py

-
# We place our map into a sting here.
-world_map = """\
-≈≈↑↑↑↑↑∩∩
-≈≈↑╔═╗↑∩∩
-≈≈↑║O║↑∩∩
-≈≈↑╚∞╝↑∩∩
-≈≈≈↑│↑∩∩∩
-≈≈O─O─O⌂∩
-≈≈≈↑│↑∩∩∩
-≈≈↑▲O▲↑∩∩
-≈≈↑↑▲↑↑∩∩
-≈≈↑↑↑↑↑∩∩
-"""
-
-# This turns our map string into a list of rows. Because python
-# allows us to treat strings as a list of characters, we can access
-# those characters with world_map[5][5] where world_map[row][column].
-world_map = world_map.split('\n')
-
-def return_map():
-    """
-    This function returns the whole map
-    """
-    map = ""
-
-    #For each row in our map, add it to map
-    for valuey in world_map:
-        map += valuey
-        map += "\n"
-
-    return map
-
-def return_minimap(x, y, radius = 2):
-    """
-    This function returns only part of the map.
-    Returning all chars in a 2 char radius from (x,y)
-    """
-    map = ""
-
-    #For each row we need, add the characters we need.
-    for valuey in world_map[y-radius:y+radius+1]:         for valuex in valuey[x-radius:x+radius+1]:
-            map += valuex
-        map += "\n"
-
-    return map
-
-
-

With our map_module set up, let’s replace our hardcoded map in mygame/world/batchcode_map.py with -a reference to our map module. Make sure to import our map_module!

-
# mygame/world/batchcode_map.py
-
-from evennia import create_object
-from evennia import DefaultObject
-from world import map_module
-
-map = create_object(DefaultObject, key="Map", location=caller.location)
-
-map.db.desc = map_module.return_map()
-
-caller.msg("A map appears out of thin air and falls to the ground.")
-
-
-

Log into Evennia as the superuser and run this batchcode. If everything worked our new map should -look exactly the same as the old map - you can use @delete to delete the old one (use a number to -pick which to delete).

-

Now, lets turn our attention towards our game’s rooms. Let’s use the return_minimap method we -created above in order to include a minimap in our room descriptions. This is a little more -complicated.

-

By itself we would have to settle for either the map being above the description with -room.db.desc = map_string + description_string, or the map going below by reversing their order. -Both options are rather unsatisfactory - we would like to have the map next to the text! For this -solution we’ll explore the utilities that ship with Evennia. Tucked away in evennia\evennia\utils -is a little module called EvTable . This is an advanced ASCII table -creator for you to utilize in your game. We’ll use it by creating a basic table with 1 row and two -columns (one for our map and one for our text) whilst also hiding the borders. Open the batchfile -again

-
# mygame\world\batchcode_world.py
-
-# Add to imports
-from evennia.utils import evtable
-from world import map_module
-
-# [...]
-
-# Replace the descriptions with the below code.
-
-# The cross roads.
-# We pass what we want in our table and EvTable does the rest.
-# Passing two arguments will create two columns but we could add more.
-# We also specify no border.
-centre.db.desc = evtable.EvTable(map_module.return_minimap(4,5),
-                 "The merger of two roads. A single lamp post dimly " \
-                 "illuminates the lonely crossroads. To the north " \
-                 "looms a mighty castle. To the south the glow of " \
-                 "a campfire can be seen. To the east lie a wall of " \
-                 "mountains and to the west the dull roar of the open sea.",
-                 border=None)
-# EvTable allows formatting individual columns and cells. We use that here
-# to set a maximum width for our description, but letting the map fill
-# whatever space it needs.
-centre.db.desc.reformat_column(1, width=70)
-
-# [...]
-
-# The northern castle.
-north.db.desc = evtable.EvTable(map_module.return_minimap(4,2),
-                "An impressive castle surrounds you. There might be " \
-                "a princess in one of these towers.",
-                border=None)
-north.db.desc.reformat_column(1, width=70)
-
-# [...]
-
-# The eastern cottage.
-east.db.desc = evtable.EvTable(map_module.return_minimap(6,5),
-               "A cosy cottage nestled among mountains stretching " \
-               "east as far as the eye can see.",
-               border=None)
-east.db.desc.reformat_column(1, width=70)
-
-# [...]
-
-# The southern camp.
-south.db.desc = evtable.EvTable(map_module.return_minimap(4,7),
-                "Surrounding a clearing are a number of tribal tents " \
-                "and at their centre a roaring fire.",
-                border=None)
-south.db.desc.reformat_column(1, width=70)
-
-# [...]
-
-# The western coast.
-west.db.desc = evtable.EvTable(map_module.return_minimap(2,5),
-               "The dark forest halts to a sandy beach. The sound of " \
-               "crashing waves calms the soul.",
-               border=None)
-west.db.desc.reformat_column(1, width=70)
-
-
-

Before we run our new batchcode, if you are anything like me you would have something like 100 maps -lying around and 3-4 different versions of our rooms extending from limbo. Let’s wipe it all and -start with a clean slate. In Command Prompt you can run evennia flush to clear the database and -start anew. It won’t reset dbref values however, so if you are at #100 it will start from there. -Alternatively you can navigate to mygame/server and delete the evennia.db3 file. Now in Command -Prompt use evennia migrate to have a completely freshly made database.

-

Log in to evennia and run @batchcode batchcode_world and you’ll have a little world to explore.

-
-
-

Conclusions

-

You should now have a mapped little world and a basic understanding of batchcode, EvTable and how -easily new game defining features can be added to Evennia.

-

You can easily build from this tutorial by expanding the map and creating more rooms to explore. Why -not add more features to your game by trying other tutorials: Add weather to your world, -fill your world with NPC’s or implement a combat system.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Tags.html b/docs/0.9.5/Tags.html deleted file mode 100644 index 7c3d0aa1e8..0000000000 --- a/docs/0.9.5/Tags.html +++ /dev/null @@ -1,277 +0,0 @@ - - - - - - - - - Tags — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Tags

-

A common task of a game designer is to organize and find groups of objects and do operations on -them. A classic example is to have a weather script affect all “outside” rooms. Another would be for -a player casting a magic spell that affects every location “in the dungeon”, but not those -“outside”. Another would be to quickly find everyone joined with a particular guild or everyone -currently dead.

-

Tags are short text labels that you attach to objects so as to easily be able to retrieve and -group them. An Evennia entity can be tagged with any number of Tags. On the database side, Tag -entities are shared between all objects with that tag. This makes them very efficient but also -fundamentally different from Attributes, each of which always belongs to one single -object.

-

In Evennia, Tags are technically also used to implement Aliases (alternative names for objects) -and Permissions (simple strings for Locks to check for).

-
-

Properties of Tags (and Aliases and Permissions)

-

Tags are unique per object model. This means that for each object model (Objects, Scripts, -Msgs, etc.) there is only ever one Tag object with a given key and category.

-
-

Not specifying a category (default) gives the tag a category of None, which is also considered a -unique key + category combination.

-
-

When Tags are assigned to game entities, these entities are actually sharing the same Tag. This -means that Tags are not suitable for storing information about a single object - use an -Attribute for this instead. Tags are a lot more limited than Attributes but this also -makes them very quick to lookup in the database - this is the whole point.

-

Tags have the following properties, stored in the database:

-
    -
  • key - the name of the Tag. This is the main property to search for when looking up a Tag.

  • -
  • category - this category allows for retrieving only specific subsets of tags used for -different purposes. You could have one category of tags for “zones”, another for “outdoor -locations”, for example. If not given, the category will be None, which is also considered a -separate, default, category.

  • -
  • data - this is an optional text field with information about the tag. Remember that Tags are -shared between entities, so this field cannot hold any object-specific information. Usually it would -be used to hold info about the group of entities the Tag is tagging - possibly used for contextual -help like a tool tip. It is not used by default.

  • -
-

There are also two special properties. These should usually not need to be changed or set, it is -used internally by Evennia to implement various other uses it makes of the Tag object:

-
    -
  • model - this holds a natural-key description of the model object that this tag deals with, -on the form application.modelclass, for example objects.objectdb. It used by the TagHandler of -each entity type for correctly storing the data behind the scenes.

  • -
  • tagtype - this is a “top-level category” of sorts for the inbuilt children of Tags, namely -Aliases and Permissions. The Taghandlers using this special field are especially intended to -free up the category property for any use you desire.

  • -
-
-
-

Adding/Removing Tags

-

You can tag any typeclassed object, namely Objects, Accounts, -Scripts and Channels. General tags are added by the Taghandler. The -tag handler is accessed as a property tags on the relevant entity:

-
     mychair.tags.add("furniture")
-     mychair.tags.add("furniture", category="luxurious")
-     myroom.tags.add("dungeon#01")
-     myscript.tags.add("weather", category="climate")
-     myaccount.tags.add("guestaccount")
-
-     mychair.tags.all()  # returns a list of Tags
-     mychair.tags.remove("furniture")
-     mychair.tags.clear()
-
-
-

Adding a new tag will either create a new Tag or re-use an already existing one. Note that there are -two “furniture” tags, one with a None category, and one with the “luxurious” category.

-

When using remove, the Tag is not deleted but are just disconnected from the tagged object. This -makes for very quick operations. The clear method removes (disconnects) all Tags from the object. -You can also use the default @tag command:

-
 @tag mychair = furniture
-
-
-

This tags the chair with a ‘furniture’ Tag (the one with a None category).

-
-
-

Searching for objects with a given tag

-

Usually tags are used as a quick way to find tagged database entities. You can retrieve all objects -with a given Tag like this in code:

-
     import evennia
-     
-     # all methods return Querysets
-
-     # search for objects
-     objs = evennia.search_tag("furniture")
-     objs2 = evennia.search_tag("furniture", category="luxurious")
-     dungeon = evennia.search_tag("dungeon#01")
-     forest_rooms = evennia.search_tag(category="forest")
-     forest_meadows = evennia.search_tag("meadow", category="forest")
-     magic_meadows = evennia.search_tag("meadow", category="magical")
-
-     # search for scripts
-     weather = evennia.search_tag_script("weather")
-     climates = evennia.search_tag_script(category="climate")
-
-     # search for accounts
-     accounts = evennia.search_tag_account("guestaccount")
-
-
-
-

Note that searching for just “furniture” will only return the objects tagged with the “furniture” -tag that -has a category of None. We must explicitly give the category to get the “luxurious” furniture.

-
-

Using any of the search_tag variants will all return Django -Querysets, including if you only have -one match. You can treat querysets as lists and iterate over them, or continue building search -queries with them.

-

Remember when searching that not setting a category means setting it to None - this does not -mean that category is undefined, rather None is considered the default, unnamed category.

-
import evennia
-
-myobj1.tags.add("foo")  # implies category=None
-myobj2.tags.add("foo", category="bar")
-
-# this returns a queryset with *only* myobj1
-objs = evennia.search_tag("foo")
-
-# these return a queryset with *only* myobj2
-objs = evennia.search_tag("foo", category="bar")
-# or
-objs = evennia.search_tag(category="bar")
-
-
-
-

There is also an in-game command that deals with assigning and using (Object-) tags:

-
 @tag/search furniture
-
-
-
-
-

Using Aliases and Permissions

-

Aliases and Permissions are implemented using normal TagHandlers that simply save Tags with a -different tagtype. These handlers are named aliases and permissions on all Objects. They are -used in the same way as Tags above:

-
    boy.aliases.add("rascal")
-    boy.permissions.add("Builders")
-    boy.permissions.remove("Builders")
-
-    all_aliases = boy.aliases.all()
-
-
-

and so on. Similarly to how @tag works in-game, there is also the @perm command for assigning -permissions and @alias command for aliases.

-
-
-

Assorted notes

-

Generally, tags are enough on their own for grouping objects. Having no tag category is perfectly -fine and the normal operation. Simply adding a new Tag for grouping objects is often better than -making a new category. So think hard before deciding you really need to categorize your Tags.

-

That said, tag categories can be useful if you build some game system that uses tags. You can then -use tag categories to make sure to separate tags created with this system from any other tags -created elsewhere. You can then supply custom search methods that only find objects tagged with -tags of that category. An example of this -is found in the Zone tutorial.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Text-Encodings.html b/docs/0.9.5/Text-Encodings.html deleted file mode 100644 index 9d1d768b34..0000000000 --- a/docs/0.9.5/Text-Encodings.html +++ /dev/null @@ -1,176 +0,0 @@ - - - - - - - - - Text Encodings — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Text Encodings

-

Evennia is a text-based game server. This makes it important to understand how -it actually deals with data in the form of text.

-

Text byte encodings describe how a string of text is actually stored in the -computer - that is, the particular sequence of bytes used to represent the -letters of your particular alphabet. A common encoding used in English-speaking -languages is the ASCII encoding. This describes the letters in the English -alphabet (Aa-Zz) as well as a bunch of special characters. For describing other -character sets (such as that of other languages with other letters than -English), sets with names such as Latin-1, ISO-8859-3 and ARMSCII-8 -are used. There are hundreds of different byte encodings in use around the -world.

-

A string of letters in a byte encoding is represented with the bytes type. -In contrast to the byte encoding is the unicode representation. In Python -this is the str type. The unicode is an internationally agreed-upon table -describing essentially all available letters you could ever want to print. -Everything from English to Chinese alphabets and all in between. So what -Evennia (as well as Python and Django) does is to store everything in Unicode -internally, but then converts the data to one of the encodings whenever -outputting data to the user.

-

An easy memory aid is that bytes are what are sent over the network wire. At -all other times, str (unicode) is used. This means that we must convert -between the two at the points where we send/receive network data.

-

The problem is that when receiving a string of bytes over the network it’s -impossible for Evennia to guess which encoding was used - it’s just a bunch of -bytes! Evennia must know the encoding in order to convert back and from the -correct unicode representation.

-
-

How to customize encodings

-

As long as you stick to the standard ASCII character set (which means the -normal English characters, basically) you should not have to worry much -about this section.

-

If you want to build your game in another language however, or expect your -users to want to use special characters not in ASCII, you need to consider -which encodings you want to support.

-

As mentioned, there are many, many byte-encodings used around the world. It -should be clear at this point that Evennia can’t guess but has to assume or -somehow be told which encoding you want to use to communicate with the server. -Basically the encoding used by your client must be the same encoding used by -the server. This can be customized in two complementary ways.

-
    -
  1. Point users to the default @encoding command or the @options command. -This allows them to themselves set which encoding they (and their client of -choice) uses. Whereas data will remain stored as unicode strings internally in -Evennia, all data received from and sent to this particular player will be -converted to the given format before transmitting.

  2. -
  3. As a back-up, in case the user-set encoding translation is erroneous or -fails in some other way, Evennia will fall back to trying with the names -defined in the settings variable ENCODINGS. This is a list of encoding -names Evennia will try, in order, before giving up and giving an encoding -error message.

  4. -
-

Note that having to try several different encodings every input/output adds -unneccesary overhead. Try to guess the most common encodings you players will -use and make sure these are tried first. The International UTF-8 encoding is -what Evennia assumes by default (and also what Python/Django use normally). See -the Wikipedia article here for more help.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/TextTags.html b/docs/0.9.5/TextTags.html deleted file mode 100644 index 7998179b00..0000000000 --- a/docs/0.9.5/TextTags.html +++ /dev/null @@ -1,448 +0,0 @@ - - - - - - - - - TextTags — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

TextTags

-

This documentation details the various text tags supported by Evennia, namely colours, command -links and inline functions.

-

There is also an Understanding Color Tags tutorial which expands on the -use of ANSI color tags and the pitfalls of mixing ANSI and Xterms256 color tags in the same context.

-
-

Coloured text

-

Note that the Documentation does not display colour the way it would look on the screen.

-

Color can be a very useful tool for your game. It can be used to increase readability and make your -game more appealing visually.

-

Remember however that, with the exception of the webclient, you generally don’t control the client -used to connect to the game. There is, for example, one special tag meaning “yellow”. But exactly -which hue of yellow is actually displayed on the user’s screen depends on the settings of their -particular mud client. They could even swap the colours around or turn them off altogether if so -desired. Some clients don’t even support color - text games are also played with special reading -equipment by people who are blind or have otherwise diminished eyesight.

-

So a good rule of thumb is to use colour to enhance your game but don’t rely on it to display -critical information. If you are coding the game, you can add functionality to let users disable -colours as they please, as described here.

-

To see which colours your client support, use the default @color command. This will list all -available colours for ANSI and Xterm256 along with the codes you use for them. You can find a list -of all the parsed ANSI-colour codes in evennia/utils/ansi.py.

-
-

ANSI colours

-

Evennia supports the ANSI standard for text. This is by far the most supported MUD-color standard, -available in all but the most ancient mud clients. The ANSI colours are red, green, -yellow, blue, magenta, cyan, white and black. They are abbreviated by their -first letter except for black which is abbreviated with the letter x. In ANSI there are “bright” -and “normal” (darker) versions of each color, adding up to a total of 16 colours to use for -foreground text. There are also 8 “background” colours. These have no bright alternative in ANSI -(but Evennia uses the Xterm256 extension behind the scenes to offer -them anyway).

-

To colour your text you put special tags in it. Evennia will parse these and convert them to the -correct markup for the client used. If the user’s client/console/display supports ANSI colour, they -will see the text in the specified colour, otherwise the tags will be stripped (uncolored text). -This works also for non-terminal clients, such as the webclient. For the webclient, Evennia will -translate the codes to HTML RGB colors.

-

Here is an example of the tags in action:

-
 |rThis text is bright red.|n This is normal text.
- |RThis is a dark red text.|n This is normal text.
- |[rThis text has red background.|n This is normal text.
- |b|[yThis is bright blue text on yellow background.|n This is normal text.
-
-
-
    -
  • |n - this tag will turn off all color formatting, including background colors.

  • -
  • |#- markup marks the start of foreground color. The case defines if the text is “bright” or -“normal”. So |g is a bright green and |G is “normal” (darker) green.

  • -
  • |[# is used to add a background colour to the text. The case again specifies if it is “bright” -or “normal”, so |[c starts a bright cyan background and |[C a darker cyan background.

  • -
  • |!# is used to add foreground color without any enforced brightness/normal information. -These are normal-intensity and are thus always given as uppercase, such as -|!R for red. The difference between e.g. |!R and |R is that -|!R will “inherit” the brightness setting from previously set color tags, whereas |R will -always reset to the normal-intensity red. The |# format contains an implicit |h/|H tag in it: -disabling highlighting when switching to a normal color, and enabling it for bright ones. So |btest |!Rtest2 will result in a bright red test2 since the brightness setting from |b “bleeds over”. -You could use this to for example quickly switch the intensity of a multitude of color tags. There -is no background-color equivalent to |! style tags.

  • -
  • |h is used to make any following foreground ANSI colors bright (it has no effect on Xterm -colors). This is only relevant to use with |! type tags and will be valid until the next |n, -|H or normal (upper-case) |# tag. This tag will never affect background colors, those have to be -set bright/normal explicitly. Technically, |h|!G is identical to |g.

  • -
  • |H negates the effects |h and returns all ANSI foreground colors (|! and | types) to -‘normal’ intensity. It has no effect on background and Xterm colors.

  • -
-
-

Note: The ANSI standard does not actually support bright backgrounds like |[r - the standard -only supports “normal” intensity backgrounds. To get around this Evennia instead implements these -as Xterm256 colours behind the scenes. If the client does not support -Xterm256 the ANSI colors will be used instead and there will be no visible difference between using -upper- and lower-case background tags.

-
-

If you want to display an ANSI marker as output text (without having any effect), you need to escape -it by preceding its | with another |:

-
say The ||r ANSI marker changes text color to bright red.
-
-
-

This will output the raw |r without any color change. This can also be necessary if you are doing -ansi art that uses | with a letter directly following it.

-

Use the command

-
@color ansi
-
-
-

to get a list of all supported ANSI colours and the tags used to produce them.

-

A few additional ANSI codes are supported:

-
    -
  • |/ A line break. You cannot put the normal Python \n line breaks in text entered inside the -game (Evennia will filter this for security reasons). This is what you use instead: use the |/ -marker to format text with line breaks from the game command line.

  • -
  • `` This will translate into a TAB character. This will not always show (or show differently) to -the client since it depends on their local settings. It’s often better to use multiple spaces.

  • -
  • |_ This is a space. You can usually use the normal space character, but if the space is at the -end of the line, Evennia will likely crop it. This tag will not be cropped but always result in a -space.

  • -
  • |* This will invert the current text/background colours. Can be useful to mark things (but see -below).

  • -
-
-

Caveats of |*

-

The |* tag (inverse video) is an old ANSI standard and should usually not be used for more than to -mark short snippets of text. If combined with other tags it comes with a series of potentially -confusing behaviors:

-
    -
  • The |* tag will only work once in a row:, ie: after using it once it won’t have an effect again -until you declare another tag. This is an example:

    -
    Normal text, |*reversed text|*, still reversed text.
    -
    -
    -

    that is, it will not reverse to normal at the second |*. You need to reset it manually:

    -
    Normal text, |*reversed text|n, normal again.
    -
    -
    -
  • -
  • The |* tag does not take “bright” colors into account:

    -
    |RNormal red, |hnow brightened. |*BG is normal red.
    -
    -
    -
  • -
-

So |* only considers the ‘true’ foreground color, ignoring any highlighting. Think of the bright -state (|h) as something like like <strong> in HTML: it modifies the appearance of a normal -foreground color to match its bright counterpart, without changing its normal color.

-
    -
  • Finally, after a |*, if the previous background was set to a dark color (via |[), |!#) will -actually change the background color instead of the foreground:

    -
    |*reversed text |!R now BG is red.
    -
    -
    -
  • -
-

For a detailed explanation of these caveats, see the [Understanding Color Tags](Understanding-Color- -Tags) tutorial. But most of the time you might be better off to simply avoid |* and mark your text -manually instead.

-
-
-
-

Xterm256 Colours

-

The Xterm256 standard is a colour scheme that supports 256 colours for text and/or background. -While this offers many more possibilities than traditional ANSI colours, be wary that too many text -colors will be confusing to the eye. Also, not all clients support Xterm256 - these will instead see -the closest equivalent ANSI color. You can mix Xterm256 tags with ANSI tags as you please.

-
|555 This is pure white text.|n This is normal text.
-|230 This is olive green text.
-|[300 This text has a dark red background.
-|005|[054 This is dark blue text on a bright cyan background.
-|=a This is a greyscale value, equal to black.
-|=m This is a greyscale value, midway between white and black.
-|=z This is a greyscale value, equal to white.
-|[=m This is a background greyscale value.
-
-
-
    -
  • |### - markup consists of three digits, each an integer from 0 to 5. The three digits describe -the amount of red, green and blue (RGB) components used in the colour. So |500 means -maximum red and none of the other colours - the result is a bright red. |520 is red with a touch -of green - the result is orange. As opposed to ANSI colors, Xterm256 syntax does not worry about -bright/normal intensity, a brighter (lighter) color is just achieved by upping all RGB values with -the same amount.

  • -
  • |[### - this works the same way but produces a coloured background.

  • -
  • |=# - markup produces the xterm256 gray scale tones, where # is a letter from a (black) to -z (white). This offers many more nuances of gray than the normal |### markup (which only has -four gray tones between solid black and white (|000, |111, |222, |333 and |444)).

  • -
  • |[=# - this works in the same way but produces background gray scale tones.

  • -
-

If you have a client that supports Xterm256, you can use

-
@color xterm256
-
-
-

to get a table of all the 256 colours and the codes that produce them. If the table looks broken up -into a few blocks of colors, it means Xterm256 is not supported and ANSI are used as a replacement. -You can use the @options command to see if xterm256 is active for you. This depends on if your -client told Evennia what it supports - if not, and you know what your client supports, you may have -to activate some features manually.

-
-
- -
-

Inline functions

-
-

Note: Inlinefuncs are not activated by default. To use them you need to add -INLINEFUNC_ENABLED=True to your settings file.

-
-

Evennia has its own inline text formatting language, known as inlinefuncs. It allows the builder -to include special function calls in code. They are executed dynamically by each session that -receives them.

-

To add an inlinefunc, you embed it in a text string like this:

-
"A normal string with $funcname(arg, arg, ...) embedded inside it."
-
-
-

When this string is sent to a session (with the msg() method), these embedded inlinefuncs will be -parsed. Their return value (which always is a string) replace their call location in the finalized -string. The interesting thing with this is that the function called will have access to which -session is seeing the string, meaning the string can end up looking different depending on who is -looking. It could of course also vary depending on other factors like game time.

-

Any number of comma-separated arguments can be given (or none). No keywords are supported. You can -also nest inlinefuncs by letting an argument itself also be another $funcname(arg, arg, ...) call -(down to a depth of nesting given by settings.INLINEFUNC_STACK_MAXSIZE). Function call resolution -happens as in all programming languages inside-out, with the nested calls replacing the argument -with their return strings before calling he parent.

-
   > say  "This is $pad(a center-padded text, 30,c,-) of width 30."
-   You say, "This is ---- a center-padded text----- of width 30."
-   > say "I roll a die and the result is ... a $random(1,6)!"
-   You say, "I roll a die and the result is ... a 5!"
-
-
-

A special case happens if wanting to use an inlinefunc argument that itself includes a comma - this -would be parsed as an argument separator. To escape commas you can either escape each comma manually -with a backslash \,, or you can embed the entire string in python triple-quotes """ or ''' - -this will escape the entire argument, including commas and any nested inlinefunc calls within.

-

Only certain functions are available to use as inlinefuncs and the game developer may add their own -functions as needed.

-
-

New inlinefuncs

-

To add new inlinefuncs, edit the file mygame/server/conf/inlinefuncs.py.

-

All globally defined functions in this module are considered inline functions by the system. The -only exception is functions whose name starts with an underscore _. An inlinefunc must be of the -following form:

-
def funcname(*args, **kwargs):
-    # ...
-    return modified_text
-
-
-

where *args denotes all the arguments this function will accept as an $inlinefunc. The inline -function is expected to clean arguments and check that they are valid. If needed arguments are not -given, default values should be used. The function should always return a string (even if it’s -empty). An inlinefunc should never cause a traceback regardless of the input (but it could log -errors if desired).

-

Note that whereas the function should accept **kwargs, keyword inputs are not usable in the call -to the inlinefunction. The kwargs part is instead intended for Evennia to be able to supply extra -information. Currently Evennia sends a single keyword to every inline function and that is -session, which holds the serversession this text is targeted at. Through the session -object, a lot of dynamic possibilities are opened up for your inline functions.

-

The settings.INLINEFUNC_MODULES configuration option is a list that decides which modules should -be parsed for inline function definitions. This will include mygame/server/conf/inlinefuncs.py but -more could be added. The list is read from left to right so if you want to overload default -functions you just have to put your custom module-paths later in the list and name your functions -the same as default ones.

-

Here is an example, the crop default inlinefunction:

-
from evennia.utils import utils
-
-def crop(*args, **kwargs):
-    """
-    Inlinefunc. Crops ingoing text to given widths.
-    Args:
-        text (str, optional): Text to crop.
-        width (str, optional): Will be converted to an integer. Width of
-            crop in characters.
-        suffix (str, optional): End string to mark the fact that a part
-            of the string was cropped. Defaults to `[...]`.
-    Kwargs:
-        session (Session): Session performing the crop.
-    Example:
-        `$crop(text, 50, [...])`
-
-    """
-    text, width, suffix = "", 78, "[...]"
-    nargs = len(args)
-    if nargs > 0:
-        text = args[0]
-    if nargs > 1:
-        width = int(args[1]) if args[1].strip().isdigit() else 78
-    if nargs > 2:
-        suffix = args[2]
-    return utils.crop(text, width=width, suffix=suffix)
-
-
-

Another example, making use of the Session:

-
def charactername(*args, **kwargs):
-    """
-    Inserts the character name of whomever sees the string
-    (so everyone will see their own name). Uses the account
-    name for OOC communications.
-
-    Example:
-        say "This means YOU, $charactername()!"
-
-    """
-    session = kwargs["session"]
-    if session.puppet:
-        return kwargs["session"].puppet.key
-    else:
-        return session.account.key
-
-
-

Evennia itself offers the following default inline functions (mostly as examples):

-
    -
  • crop(text, width, suffix) - See above.

  • -
  • pad(text, width, align, fillchar) - this pads the text to width (default 78), alignment (“c”, -“l” or “r”, defaulting to “c”) and fill-in character (defaults to space). Example: $pad(40,l,-)

  • -
  • clr(startclr, text, endclr) - A programmatic way to enter colored text for those who don’t want -to use the normal |c type color markers for some reason. The color argument is the same as the -color markers except without the actual pre-marker, so |r would be just r. If endclr is not -given, it defaults to resetting the color (n). Example: $clr(b, A blue text)

  • -
  • space(number) - Inserts the given number of spaces. If no argument is given, use 4 spaces.

  • -
  • random(), random(max), random(min, max) - gives a random value between min and max. With no -arguments, give 0 or 1 (on/off). If one argument, returns 0…max. If values are floats, random -value will be a float (so random(1.0) replicates the normal Python random function).

  • -
-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/TickerHandler.html b/docs/0.9.5/TickerHandler.html deleted file mode 100644 index 36d5de7ace..0000000000 --- a/docs/0.9.5/TickerHandler.html +++ /dev/null @@ -1,232 +0,0 @@ - - - - - - - - - TickerHandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

TickerHandler

-

One way to implement a dynamic MUD is by using “tickers”, also known as “heartbeats”. A ticker is a -timer that fires (“ticks”) at a given interval. The tick triggers updates in various game systems.

-
-

About Tickers

-

Tickers are very common or even unavoidable in other mud code bases. Certain code bases are even -hard-coded to rely on the concept of the global ‘tick’. Evennia has no such notion - the decision to -use tickers is very much up to the need of your game and which requirements you have. The “ticker -recipe” is just one way of cranking the wheels.

-

The most fine-grained way to manage the flow of time is of course to use Scripts. Many -types of operations (weather being the classic example) are however done on multiple objects in the -same way at regular intervals, and for this, storing separate Scripts on each object is inefficient. -The way to do this is to use a ticker with a “subscription model” - let objects sign up to be -triggered at the same interval, unsubscribing when the updating is no longer desired.

-

Evennia offers an optimized implementation of the subscription model - the TickerHandler. This is -a singleton global handler reachable from evennia.TICKER_HANDLER. You can assign any callable (a -function or, more commonly, a method on a database object) to this handler. The TickerHandler will -then call this callable at an interval you specify, and with the arguments you supply when adding -it. This continues until the callable un-subscribes from the ticker. The handler survives a reboot -and is highly optimized in resource usage.

-

Here is an example of importing TICKER_HANDLER and using it:

-
    # we assume that obj has a hook "at_tick" defined on itself
-    from evennia import TICKER_HANDLER as tickerhandler
-
-    tickerhandler.add(20, obj.at_tick)
-
-
-

That’s it - from now on, obj.at_tick() will be called every 20 seconds.

-

You can also import function and tick that:

-
    from evennia import TICKER_HANDLER as tickerhandler
-    from mymodule import myfunc
-
-    tickerhandler.add(30, myfunc)
-
-
-

Removing (stopping) the ticker works as expected:

-
    tickerhandler.remove(20, obj.at_tick)
-    tickerhandler.remove(30, myfunc)
-
-
-

Note that you have to also supply interval to identify which subscription to remove. This is -because the TickerHandler maintains a pool of tickers and a given callable can subscribe to be -ticked at any number of different intervals.

-

The full definition of the tickerhandler.add method is

-
    tickerhandler.add(interval, callback,
-                      idstring="", persistent=True, *args, **kwargs)
-
-
-

Here *args and **kwargs will be passed to callback every interval seconds. If persistent -is False, this subscription will not survive a server reload.

-

Tickers are identified and stored by making a key of the callable itself, the ticker-interval, the -persistent flag and the idstring (the latter being an empty string when not given explicitly).

-

Since the arguments are not included in the ticker’s identification, the idstring must be used to -have a specific callback triggered multiple times on the same interval but with different arguments:

-
    tickerhandler.add(10, obj.update, "ticker1", True, 1, 2, 3)
-    tickerhandler.add(10, obj.update, "ticker2", True, 4, 5)
-
-
-
-

Note that, when we want to send arguments to our callback within a ticker handler, we need to -specify idstring and persistent before, unless we call our arguments as keywords, which would -often be more readable:

-
-
    tickerhandler.add(10, obj.update, caller=self, value=118)
-
-
-

If you add a ticker with exactly the same combination of callback, interval and idstring, it will -overload the existing ticker. This identification is also crucial for later removing (stopping) the -subscription:

-
    tickerhandler.remove(10, obj.update, idstring="ticker1")
-    tickerhandler.remove(10, obj.update, idstring="ticker2")
-
-
-

The callable can be on any form as long as it accepts the arguments you give to send to it in -TickerHandler.add.

-
-

Note that everything you supply to the TickerHandler will need to be pickled at some point to be -saved into the database. Most of the time the handler will correctly store things like database -objects, but the same restrictions as for Attributes apply to what the TickerHandler -may store.

-
-

When testing, you can stop all tickers in the entire game with tickerhandler.clear(). You can also -view the currently subscribed objects with tickerhandler.all().

-

See the Weather Tutorial for an example of using the TickerHandler.

-
-

When not to use TickerHandler

-

Using the TickerHandler may sound very useful but it is important to consider when not to use it. -Even if you are used to habitually relying on tickers for everything in other code bases, stop and -think about what you really need it for. This is the main point:

-
-

You should never use a ticker to catch changes.

-
-

Think about it - you might have to run the ticker every second to react to the change fast enough. -Most likely nothing will have changed at a given moment. So you are doing pointless calls (since -skipping the call gives the same result as doing it). Making sure nothing’s changed might even be -computationally expensive depending on the complexity of your system. Not to mention that you might -need to run the check on every object in the database. Every second. Just to maintain status quo -…

-

Rather than checking over and over on the off-chance that something changed, consider a more -proactive approach. Could you implement your rarely changing system to itself report when its -status changes? It’s almost always much cheaper/efficient if you can do things “on demand”. Evennia -itself uses hook methods for this very reason.

-

So, if you consider a ticker that will fire very often but which you expect to have no effect 99% of -the time, consider handling things things some other way. A self-reporting on-demand solution is -usually cheaper also for fast-updating properties. Also remember that some things may not need to be -updated until someone actually is examining or using them - any interim changes happening up to that -moment are pointless waste of computing time.

-

The main reason for needing a ticker is when you want things to happen to multiple objects at the -same time without input from something else.

-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Turn-based-Combat-System.html b/docs/0.9.5/Turn-based-Combat-System.html deleted file mode 100644 index 83e358b4c1..0000000000 --- a/docs/0.9.5/Turn-based-Combat-System.html +++ /dev/null @@ -1,620 +0,0 @@ - - - - - - - - - Turn based Combat System — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Turn based Combat System

-

This tutorial gives an example of a full, if simplified, combat system for Evennia. It was inspired -by the discussions held on the mailing list.

-
-

Overview of combat system concepts

-

Most MUDs will use some sort of combat system. There are several main variations:

-
    -
  • Freeform - the simplest form of combat to implement, common to MUSH-style roleplaying games. -This means the system only supplies dice rollers or maybe commands to compare skills and spit out -the result. Dice rolls are done to resolve combat according to the rules of the game and to direct -the scene. A game master may be required to resolve rule disputes.

  • -
  • Twitch - This is the traditional MUD hack&slash style combat. In a twitch system there is often -no difference between your normal “move-around-and-explore mode” and the “combat mode”. You enter an -attack command and the system will calculate if the attack hits and how much damage was caused. -Normally attack commands have some sort of timeout or notion of recovery/balance to reduce the -advantage of spamming or client scripting. Whereas the simplest systems just means entering kill <target> over and over, more sophisticated twitch systems include anything from defensive stances -to tactical positioning.

  • -
  • Turn-based - a turn based system means that the system pauses to make sure all combatants can -choose their actions before continuing. In some systems, such entered actions happen immediately -(like twitch-based) whereas in others the resolution happens simultaneously at the end of the turn. -The disadvantage of a turn-based system is that the game must switch to a “combat mode” and one also -needs to take special care of how to handle new combatants and the passage of time. The advantage is -that success is not dependent on typing speed or of setting up quick client macros. This potentially -allows for emoting as part of combat which is an advantage for roleplay-heavy games.

  • -
-

To implement a freeform combat system all you need is a dice roller and a roleplaying rulebook. See -contrib/dice.py for an -example dice roller. To implement at twitch-based system you basically need a few combat -commands, possibly ones with a cooldown. You also need a game rule -module that makes use of it. We will focus on the turn-based -variety here.

-
-
-

Tutorial overview

-

This tutorial will implement the slightly more complex turn-based combat system. Our example has the -following properties:

-
    -
  • Combat is initiated with attack <target>, this initiates the combat mode.

  • -
  • Characters may join an ongoing battle using attack <target> against a character already in -combat.

  • -
  • Each turn every combating character will get to enter two commands, their internal order matters -and they are compared one-to-one in the order given by each combatant. Use of say and pose is -free.

  • -
  • The commands are (in our example) simple; they can either hit <target>, feint <target> or -parry <target>. They can also defend, a generic passive defense. Finally they may choose to -disengage/flee.

  • -
  • When attacking we use a classic rock-paper-scissors mechanic to determine success: hit defeats feint, which defeats parry which defeats -hit. defend is a general passive action that has a percentage chance to win against hit -(only).

  • -
  • disengage/flee must be entered two times in a row and will only succeed if there is no hit -against them in that time. If so they will leave combat mode.

  • -
  • Once every player has entered two commands, all commands are resolved in order and the result is -reported. A new turn then begins.

  • -
  • If players are too slow the turn will time out and any unset commands will be set to defend.

  • -
-

For creating the combat system we will need the following components:

-
    -
  • A combat handler. This is the main mechanic of the system. This is a Script object -created for each combat. It is not assigned to a specific object but is shared by the combating -characters and handles all the combat information. Since Scripts are database entities it also means -that the combat will not be affected by a server reload.

  • -
  • A combat command set with the relevant commands needed for combat, such as the -various attack/defend options and the flee/disengage command to leave the combat mode.

  • -
  • A rule resolution system. The basics of making such a module is described in the rule system tutorial. We will only sketch such a module here for our end-turn -combat resolution.

  • -
  • An attack command for initiating the combat mode. This is added to the default -command set. It will create the combat handler and add the character(s) to it. It will also assign -the combat command set to the characters.

  • -
-
-
-

The combat handler

-

The combat handler is implemented as a stand-alone Script. This Script is created when -the first Character decides to attack another and is deleted when no one is fighting any more. Each -handler represents one instance of combat and one combat only. Each instance of combat can hold any -number of characters but each character can only be part of one combat at a time (a player would -need to disengage from the first combat before they could join another).

-

The reason we don’t store this Script “on” any specific character is because any character may leave -the combat at any time. Instead the script holds references to all characters involved in the -combat. Vice-versa, all characters holds a back-reference to the current combat handler. While we -don’t use this very much here this might allow the combat commands on the characters to access and -update the combat handler state directly.

-

Note: Another way to implement a combat handler would be to use a normal Python object and handle -time-keeping with the TickerHandler. This would require either adding custom hook -methods on the character or to implement a custom child of the TickerHandler class to track turns. -Whereas the TickerHandler is easy to use, a Script offers more power in this case.

-

Here is a basic combat handler. Assuming our game folder is named mygame, we store it in -mygame/typeclasses/combat_handler.py:

-
# mygame/typeclasses/combat_handler.py
-
-import random
-from evennia import DefaultScript
-from world.rules import resolve_combat
-
-class CombatHandler(DefaultScript):
-    """
-    This implements the combat handler.
-    """
-
-    # standard Script hooks
-
-    def at_script_creation(self):
-        "Called when script is first created"
-
-        self.key = "combat_handler_%i" % random.randint(1, 1000)
-        self.desc = "handles combat"
-        self.interval = 60 * 2  # two minute timeout
-        self.start_delay = True
-        self.persistent = True
-
-        # store all combatants
-        self.db.characters = {}
-        # store all actions for each turn
-        self.db.turn_actions = {}
-        # number of actions entered per combatant
-        self.db.action_count = {}
-
-    def _init_character(self, character):
-        """
-        This initializes handler back-reference
-        and combat cmdset on a character
-        """
-        character.ndb.combat_handler = self
-        character.cmdset.add("commands.combat.CombatCmdSet")
-
-    def _cleanup_character(self, character):
-        """
-        Remove character from handler and clean
-        it of the back-reference and cmdset
-        """
-        dbref = character.id
-        del self.db.characters[dbref]
-        del self.db.turn_actions[dbref]
-        del self.db.action_count[dbref]
-        del character.ndb.combat_handler
-        character.cmdset.delete("commands.combat.CombatCmdSet")
-
-    def at_start(self):
-        """
-        This is called on first start but also when the script is restarted
-        after a server reboot. We need to re-assign this combat handler to
-        all characters as well as re-assign the cmdset.
-        """
-        for character in self.db.characters.values():
-            self._init_character(character)
-
-    def at_stop(self):
-        "Called just before the script is stopped/destroyed."
-        for character in list(self.db.characters.values()):
-            # note: the list() call above disconnects list from database
-            self._cleanup_character(character)
-
-    def at_repeat(self):
-        """
-        This is called every self.interval seconds (turn timeout) or
-        when force_repeat is called (because everyone has entered their
-        commands). We know this by checking the existence of the
-        `normal_turn_end` NAttribute, set just before calling
-        force_repeat.
-
-        """
-        if self.ndb.normal_turn_end:
-            # we get here because the turn ended normally
-            # (force_repeat was called) - no msg output
-            del self.ndb.normal_turn_end
-        else:
-            # turn timeout
-            self.msg_all("Turn timer timed out. Continuing.")
-        self.end_turn()
-
-    # Combat-handler methods
-
-    def add_character(self, character):
-        "Add combatant to handler"
-        dbref = character.id
-        self.db.characters[dbref] = character
-        self.db.action_count[dbref] = 0
-        self.db.turn_actions[dbref] = [("defend", character, None),
-                                       ("defend", character, None)]
-        # set up back-reference
-        self._init_character(character)
-
-    def remove_character(self, character):
-        "Remove combatant from handler"
-        if character.id in self.db.characters:
-            self._cleanup_character(character)
-        if not self.db.characters:
-            # if no more characters in battle, kill this handler
-            self.stop()
-
-    def msg_all(self, message):
-        "Send message to all combatants"
-        for character in self.db.characters.values():
-            character.msg(message)
-
-    def add_action(self, action, character, target):
-        """
-        Called by combat commands to register an action with the handler.
-
-         action - string identifying the action, like "hit" or "parry"
-         character - the character performing the action
-         target - the target character or None
-
-        actions are stored in a dictionary keyed to each character, each
-        of which holds a list of max 2 actions. An action is stored as
-        a tuple (character, action, target).
-        """
-        dbref = character.id
-        count = self.db.action_count[dbref]
-        if 0 <= count <= 1: # only allow 2 actions
-            self.db.turn_actions[dbref][count] = (action, character, target)
-        else:
-            # report if we already used too many actions
-            return False
-        self.db.action_count[dbref] += 1
-        return True
-
-    def check_end_turn(self):
-        """
-        Called by the command to eventually trigger
-        the resolution of the turn. We check if everyone
-        has added all their actions; if so we call force the
-        script to repeat immediately (which will call
-        `self.at_repeat()` while resetting all timers).
-        """
-        if all(count > 1 for count in self.db.action_count.values()):
-            self.ndb.normal_turn_end = True
-            self.force_repeat()
-
-    def end_turn(self):
-        """
-        This resolves all actions by calling the rules module.
-        It then resets everything and starts the next turn. It
-        is called by at_repeat().
-        """
-        resolve_combat(self, self.db.turn_actions)
-
-        if len(self.db.characters) < 2:
-            # less than 2 characters in battle, kill this handler
-            self.msg_all("Combat has ended")
-            self.stop()
-        else:
-            # reset counters before next turn
-            for character in self.db.characters.values():
-                self.db.characters[character.id] = character
-                self.db.action_count[character.id] = 0
-                self.db.turn_actions[character.id] = [("defend", character, None),
-                                                  ("defend", character, None)]
-            self.msg_all("Next turn begins ...")
-
-
-

This implements all the useful properties of our combat handler. This Script will survive a reboot -and will automatically re-assert itself when it comes back online. Even the current state of the -combat should be unaffected since it is saved in Attributes at every turn. An important part to note -is the use of the Script’s standard at_repeat hook and the force_repeat method to end each turn. -This allows for everything to go through the same mechanisms with minimal repetition of code.

-

What is not present in this handler is a way for players to view the actions they set or to change -their actions once they have been added (but before the last one has added theirs). We leave this as -an exercise.

-
-
-

Combat commands

-

Our combat commands - the commands that are to be available to us during the combat - are (in our -example) very simple. In a full implementation the commands available might be determined by the -weapon(s) held by the player or by which skills they know.

-

We create them in mygame/commands/combat.py.

-
# mygame/commands/combat.py
-
-from evennia import Command
-
-class CmdHit(Command):
-    """
-    hit an enemy
-
-    Usage:
-      hit <target>
-
-    Strikes the given enemy with your current weapon.
-    """
-    key = "hit"
-    aliases = ["strike", "slash"]
-    help_category = "combat"
-
-    def func(self):
-        "Implements the command"
-        if not self.args:
-            self.caller.msg("Usage: hit <target>")
-            return
-        target = self.caller.search(self.args)
-        if not target:
-            return
-        ok = self.caller.ndb.combat_handler.add_action("hit",
-                                                       self.caller,
-                                                       target)
-        if ok:
-            self.caller.msg("You add 'hit' to the combat queue")
-        else:
-            self.caller.msg("You can only queue two actions per turn!")
-
-        # tell the handler to check if turn is over
-        self.caller.ndb.combat_handler.check_end_turn()
-
-
-

The other commands CmdParry, CmdFeint, CmdDefend and CmdDisengage look basically the same. -We should also add a custom help command to list all the available combat commands and what they -do.

-

We just need to put them all in a cmdset. We do this at the end of the same module:

-
# mygame/commands/combat.py
-
-from evennia import CmdSet
-from evennia import default_cmds
-
-class CombatCmdSet(CmdSet):
-    key = "combat_cmdset"
-    mergetype = "Replace"
-    priority = 10
-    no_exits = True
-
-    def at_cmdset_creation(self):
-        self.add(CmdHit())
-        self.add(CmdParry())
-        self.add(CmdFeint())
-        self.add(CmdDefend())
-        self.add(CmdDisengage())
-        self.add(CmdHelp())
-        self.add(default_cmds.CmdPose())
-        self.add(default_cmds.CmdSay())
-
-
-
-
-

Rules module

-

A general way to implement a rule module is found in the rule system tutorial. Proper resolution would likely require us to change our Characters to store things -like strength, weapon skills and so on. So for this example we will settle for a very simplistic -rock-paper-scissors kind of setup with some randomness thrown in. We will not deal with damage here -but just announce the results of each turn. In a real system the Character objects would hold stats -to affect their skills, their chosen weapon affect the choices, they would be able to lose health -etc.

-

Within each turn, there are “sub-turns”, each consisting of one action per character. The actions -within each sub-turn happens simultaneously and only once they have all been resolved we move on to -the next sub-turn (or end the full turn).

-

Note: In our simple example the sub-turns don’t affect each other (except for disengage/flee), -nor do any effects carry over between turns. The real power of a turn-based system would be to add -real tactical possibilities here though; For example if your hit got parried you could be out of -balance and your next action would be at a disadvantage. A successful feint would open up for a -subsequent attack and so on …

-

Our rock-paper-scissor setup works like this:

-
    -
  • hit beats feint and flee/disengage. It has a random chance to fail against defend.

  • -
  • parry beats hit.

  • -
  • feint beats parry and is then counted as a hit.

  • -
  • defend does nothing but has a chance to beat hit.

  • -
  • flee/disengage must succeed two times in a row (i.e. not beaten by a hit once during the -turn). If so the character leaves combat.

  • -
-
# mygame/world/rules.py
-
-import random
-
-# messages
-
-def resolve_combat(combat_handler, actiondict):
-    """
-    This is called by the combat handler
-    actiondict is a dictionary with a list of two actions
-    for each character:
-    {char.id:[(action1, char, target), (action2, char, target)], ...}
-    """
-    flee = {} # track number of flee commands per character
-    for isub in range(2):
-        # loop over sub-turns
-        messages = []
-        for subturn in (sub[isub] for sub in actiondict.values()):
-            # for each character, resolve the sub-turn
-            action, char, target = subturn
-            if target:
-                taction, tchar, ttarget = actiondict[target.id][isub]
-            if action == "hit":
-                if taction == "parry" and ttarget == char:
-                    msg = "%s tries to hit %s, but %s parries the attack!"
-                    messages.append(msg % (char, tchar, tchar))
-                elif taction == "defend" and random.random() < 0.5:
-                    msg = "%s defends against the attack by %s."
-                    messages.append(msg % (tchar, char))
-                elif taction == "flee":
-                    msg = "%s stops %s from disengaging, with a hit!"
-                    flee[tchar] = -2
-                    messages.append(msg % (char, tchar))
-                else:
-                    msg = "%s hits %s, bypassing their %s!"
-                    messages.append(msg % (char, tchar, taction))
-            elif action == "parry":
-                if taction == "hit":
-                    msg = "%s parries the attack by %s."
-                    messages.append(msg % (char, tchar))
-                elif taction == "feint":
-                    msg = "%s tries to parry, but %s feints and hits!"
-                    messages.append(msg % (char, tchar))
-                else:
-                    msg = "%s parries to no avail."
-                    messages.append(msg % char)
-            elif action == "feint":
-                if taction == "parry":
-                    msg = "%s feints past %s's parry, landing a hit!"
-                    messages.append(msg % (char, tchar))
-                elif taction == "hit":
-                    msg = "%s feints but is defeated by %s hit!"
-                    messages.append(msg % (char, tchar))
-                else:
-                    msg = "%s feints to no avail."
-                    messages.append(msg % char)
-            elif action == "defend":
-                msg = "%s defends."
-                messages.append(msg % char)
-            elif action == "flee":
-                if char in flee:
-                    flee[char] += 1
-                else:
-                    flee[char] = 1
-                    msg = "%s tries to disengage (two subsequent turns needed)"
-                    messages.append(msg % char)
-
-        # echo results of each subturn
-        combat_handler.msg_all("\n".join(messages))
-
-    # at the end of both sub-turns, test if anyone fled
-    msg = "%s withdraws from combat."
-    for (char, fleevalue) in flee.items():
-        if fleevalue == 2:
-            combat_handler.msg_all(msg % char)
-            combat_handler.remove_character(char)
-
-
-

To make it simple (and to save space), this example rule module actually resolves each interchange -twice - first when it gets to each character and then again when handling the target. Also, since we -use the combat handler’s msg_all method here, the system will get pretty spammy. To clean it up, -one could imagine tracking all the possible interactions to make sure each pair is only handled and -reported once.

-
-
-

Combat initiator command

-

This is the last component we need, a command to initiate combat. This will tie everything together. -We store this with the other combat commands.

-
# mygame/commands/combat.py
-
-from evennia import create_script
-
-class CmdAttack(Command):
-    """
-    initiates combat
-
-    Usage:
-      attack <target>
-
-    This will initiate combat with <target>. If <target is
-    already in combat, you will join the combat.
-    """
-    key = "attack"
-    help_category = "General"
-
-    def func(self):
-        "Handle command"
-        if not self.args:
-            self.caller.msg("Usage: attack <target>")
-            return
-        target = self.caller.search(self.args)
-        if not target:
-            return
-        # set up combat
-        if target.ndb.combat_handler:
-            # target is already in combat - join it
-            target.ndb.combat_handler.add_character(self.caller)
-            target.ndb.combat_handler.msg_all("%s joins combat!" % self.caller)
-        else:
-            # create a new combat handler
-            chandler = create_script("combat_handler.CombatHandler")
-            chandler.add_character(self.caller)
-            chandler.add_character(target)
-            self.caller.msg("You attack %s! You are in combat." % target)
-            target.msg("%s attacks you! You are in combat." % self.caller)
-
-
-

The attack command will not go into the combat cmdset but rather into the default cmdset. See e.g. -the Adding Command Tutorial if you are unsure about how to do this.

-
-
-

Expanding the example

-

At this point you should have a simple but flexible turn-based combat system. We have taken several -shortcuts and simplifications in this example. The output to the players is likely too verbose -during combat and too limited when it comes to informing about things surrounding it. Methods for -changing your commands or list them, view who is in combat etc is likely needed - this will require -play testing for each game and style. There is also currently no information displayed for other -people happening to be in the same room as the combat - some less detailed information should -probably be echoed to the room to -show others what’s going on.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Tutorial-Aggressive-NPCs.html b/docs/0.9.5/Tutorial-Aggressive-NPCs.html deleted file mode 100644 index 7850413c45..0000000000 --- a/docs/0.9.5/Tutorial-Aggressive-NPCs.html +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - - - - Tutorial Aggressive NPCs — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Tutorial Aggressive NPCs

-

This tutorial shows the implementation of an NPC object that responds to characters entering their -location. In this example the NPC has the option to respond aggressively or not, but any actions -could be triggered this way.

-

One could imagine using a Script that is constantly checking for newcomers. This would be -highly inefficient (most of the time its check would fail). Instead we handle this on-demand by -using a couple of existing object hooks to inform the NPC that a Character has entered.

-

It is assumed that you already know how to create custom room and character typeclasses, please see -the Basic Game tutorial if you haven’t already done this.

-

What we will need is the following:

-
    -
  • An NPC typeclass that can react when someone enters.

  • -
  • A custom Room typeclass that can tell the NPC that someone entered.

  • -
  • We will also tweak our default Character typeclass a little.

  • -
-

To begin with, we need to create an NPC typeclass. Create a new file inside of your typeclasses -folder and name it npcs.py and then add the following code:

-
from typeclasses.characters import Character
-
-class NPC(Character):
-    """
-    A NPC typeclass which extends the character class.
-    """
-    def at_char_entered(self, character):
-        """
-         A simple is_aggressive check.
-         Can be expanded upon later.
-        """
-        if self.db.is_aggressive:
-            self.execute_cmd(f"say Graaah, die {character}!")
-        else:
-            self.execute_cmd(f"say Greetings, {character}!")
-
-
-

We will define our custom Character typeclass below. As for the new at_char_entered method we’ve -just defined, we’ll ensure that it will be called by the room where the NPC is located, when a -player enters that room. You’ll notice that right now, the NPC merely speaks. You can expand this -part as you like and trigger all sorts of effects here (like combat code, fleeing, bartering or -quest-giving) as your game design dictates.

-

Now your typeclasses.rooms module needs to have the following added:

-
# Add this import to the top of your file.
-from evennia import utils
-
-    # Add this hook in any empty area within your Room class.
-    def at_object_receive(self, obj, source_location):
-        if utils.inherits_from(obj, 'typeclasses.npcs.NPC'): # An NPC has entered
-            return
-        elif utils.inherits_from(obj, 'typeclasses.characters.Character'):
-            # A PC has entered.
-            # Cause the player's character to look around.
-            obj.execute_cmd('look')
-            for item in self.contents:
-                if utils.inherits_from(item, 'typeclasses.npcs.NPC'):
-                    # An NPC is in the room
-                    item.at_char_entered(obj)
-
-
-

inherits_from must be given the full path of the class. If the object inherited a class from your -world.races module, then you would check inheritance with world.races.Human, for example. There -is no need to import these prior, as we are passing in the full path. As a matter of a fact, -inherits_from does not properly work if you import the class and only pass in the name of the -class.

-
-

Note: -at_object_receive -is a default hook of the DefaultObject typeclass (and its children). Here we are overriding this -hook in our customized room typeclass to suit our needs.

-
-

This room checks the typeclass of objects entering it (using utils.inherits_from and responds to -Characters, ignoring other NPCs or objects. When triggered the room will look through its -contents and inform any NPCs inside by calling their at_char_entered` method.

-

You’ll also see that we have added a ‘look’ into this code. This is because, by default, the -at_object_receive is carried out before the character’s at_after_move which, we will now -overload. This means that a character entering would see the NPC perform its actions before the -‘look’ command. Deactivate the look command in the default Character class within the -typeclasses.characters module:

-
    # Add this hook in any blank area within your Character class.
-    def at_after_move(self, source_location):
-        """
-        Default is to look around after a move
-        Note:  This has been moved to Room.at_object_receive
-        """
-        #self.execute_cmd('look')
-        pass
-
-
-

Now let’s create an NPC and make it aggressive. Type the following commands into your MUD client:

-
reload
-create/drop Orc:npcs.NPC
-
-
-
-

Note: You could also give the path as typeclasses.npcs.NPC, but Evennia will look into the -typeclasses folder automatically, so this is a little shorter.

-
-

When you enter the aggressive NPC’s location, it will default to using its peaceful action (say your -name is Anna):

-
Orc says, "Greetings, Anna!"
-
-
-

Now we turn on the aggressive mode (we do it manually but it could also be triggered by some sort of -AI code).

-
set orc/is_aggressive = True
-
-
-

Now it will perform its aggressive action whenever a character enters.

-
Orc says, "Graaah, die, Anna!"
-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Tutorial-NPCs-listening.html b/docs/0.9.5/Tutorial-NPCs-listening.html deleted file mode 100644 index ab1ebc5154..0000000000 --- a/docs/0.9.5/Tutorial-NPCs-listening.html +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - - - - Tutorial NPCs listening — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Tutorial NPCs listening

-

This tutorial shows the implementation of an NPC object that responds to characters speaking in -their location. In this example the NPC parrots what is said, but any actions could be triggered -this way.

-

It is assumed that you already know how to create custom room and character typeclasses, please see -the Basic Game tutorial if you haven’t already done this.

-

What we will need is simply a new NPC typeclass that can react when someone speaks.

-
# mygame/typeclasses/npc.py
-
-from characters import Character
-class Npc(Character):
-    """
-    A NPC typeclass which extends the character class.
-    """
-    def at_heard_say(self, message, from_obj):
-        """
-        A simple listener and response. This makes it easy to change for
-        subclasses of NPCs reacting differently to says.
-
-        """
-        # message will be on the form `<Person> says, "say_text"`
-        # we want to get only say_text without the quotes and any spaces
-        message = message.split('says, ')[1].strip(' "')
-
-        # we'll make use of this in .msg() below
-        return "%s said: '%s'" % (from_obj, message)
-
-
-

When someone in the room speaks to this NPC, its msg method will be called. We will modify the -NPCs .msg method to catch says so the NPC can respond.

-
# mygame/typeclasses/npc.py
-
-from characters import Character
-class Npc(Character):
-
-    # [at_heard_say() goes here]
-
-    def msg(self, text=None, from_obj=None, **kwargs):
-        "Custom msg() method reacting to say."
-
-        if from_obj != self:
-            # make sure to not repeat what we ourselves said or we'll create a loop
-            try:
-                # if text comes from a say, `text` is `('say_text', {'type': 'say'})`
-                say_text, is_say = text[0], text[1]['type'] == 'say'
-            except Exception:
-                is_say = False
-            if is_say:
-                # First get the response (if any)
-                response = self.at_heard_say(say_text, from_obj)
-                # If there is a response
-                if response != None:
-                    # speak ourselves, using the return
-                    self.execute_cmd("say %s" % response)
-    
-        # this is needed if anyone ever puppets this NPC - without it you would never
-        # get any feedback from the server (not even the results of look)
-        super().msg(text=text, from_obj=from_obj, **kwargs)
-
-
-

So if the NPC gets a say and that say is not coming from the NPC itself, it will echo it using the -at_heard_say hook. Some things of note in the above example:

-
    -
  • The text input can be on many different forms depending on where this msg is called from. -Instead of trying to analyze text in detail with a range of if statements we just assume the -form we want and catch the error if it does not match. This simplifies the code considerably. It’s -called ‘leap before you look’ and is a Python paradigm that may feel unfamiliar if you are used to -other languages. Here we ‘swallow’ the error silently, which is fine when the code checked is -simple. If not we may want to import evennia.logger.log_trace and add log_trace() in the -except clause.
    -If you would like to learn more about the text list used above refer to the Out-Of-Band -documentation.

  • -
  • We use execute_cmd to fire the say command back. We could also have called -self.location.msg_contents directly but using the Command makes sure all hooks are called (so -those seeing the NPC’s say can in turn react if they want).

  • -
  • Note the comments about super at the end. This will trigger the ‘default’ msg (in the parent -class) as well. It’s not really necessary as long as no one puppets the NPC (by @ic <npcname>) but -it’s wise to keep in there since the puppeting player will be totally blind if msg() is never -returning anything to them!

  • -
-

Now that’s done, let’s create an NPC and see what it has to say for itself.

-
@reload
-@create/drop Guild Master:npc.Npc
-
-
-

(you could also give the path as typeclasses.npc.Npc, but Evennia will look into the typeclasses -folder automatically so this is a little shorter).

-
> say hi
-You say, "hi"
-Guild Master says, "Anna said: 'hi'"
-
-
-
-

Assorted notes

-

There are many ways to implement this kind of functionality. An alternative example to overriding -msg would be to modify the at_say hook on the Character instead. It could detect that it’s -sending to an NPC and call the at_heard_say hook directly.

-

While the tutorial solution has the advantage of being contained only within the NPC class, -combining this with using the Character class gives more direct control over how the NPC will react. -Which way to go depends on the design requirements of your particular game.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Tutorial-Searching-For-Objects.html b/docs/0.9.5/Tutorial-Searching-For-Objects.html deleted file mode 100644 index e42ad642f8..0000000000 --- a/docs/0.9.5/Tutorial-Searching-For-Objects.html +++ /dev/null @@ -1,527 +0,0 @@ - - - - - - - - - Tutorial Searching For Objects — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Tutorial Searching For Objects

-

You will often want to operate on a specific object in the database. For example when a player -attacks a named target you’ll need to find that target so it can be attacked. Or when a rain storm -draws in you need to find all outdoor-rooms so you can show it raining in them. This tutorial -explains Evennia’s tools for searching.

-
-

Things to search for

-

The first thing to consider is the base type of the thing you are searching for. Evennia organizes -its database into a few main tables: Objects, Accounts, Scripts, -Channels, Messages and Help Entries. -Most of the time you’ll likely spend your time searching for Objects and the occasional Accounts.

-

So to find an entity, what can be searched for?

-
    -
  • The key is the name of the entity. While you can get this from obj.key the database field -is actually named obj.db_key - this is useful to know only when you do direct database -queries. The one exception is Accounts, where -the database field for .key is instead named username (this is a Django requirement). When you -don’t specify search-type, you’ll usually search based on key. Aliases are extra names given to -Objects using something like @alias or obj.aliases.add('name'). The main search functions (see -below) will automatically search for aliases whenever you search by-key.

  • -
  • Tags are the main way to group and identify objects in Evennia. Tags can most often be -used (sometimes together with keys) to uniquely identify an object. For example, even though you -have two locations with the same name, you can separate them by their tagging (this is how Evennia -implements ‘zones’ seen in other systems). Tags can also have categories, to further organize your -data for quick lookups.

  • -
  • An object’s Attributes can also used to find an object. This can be very useful but -since Attributes can store almost any data they are far less optimized to search for than Tags or -keys.

  • -
  • The object’s Typeclass indicate the sub-type of entity. A Character, Flower or -Sword are all types of Objects. A Bot is a kind of Account. The database field is called -typeclass_path and holds the full Python-path to the class. You can usually specify the -typeclass as an argument to Evennia’s search functions as well as use the class directly to limit -queries.

  • -
  • The location is only relevant for Objects but is a very common way to weed down the -number of candidates before starting to search. The reason is that most in-game commands tend to -operate on things nearby (in the same room) so the choices can be limited from the start.

  • -
  • The database id or the ‘#dbref’ is unique (and never re-used) within each database table. So while -there is one and only one Object with dbref #42 there could also be an Account or Script with the -dbref #42 at the same time. In almost all search methods you can replace the “key” search -criterion with "#dbref" to search for that id. This can occasionally be practical and may be what -you are used to from other code bases. But it is considered bad practice in Evennia to rely on -hard-coded #dbrefs to do your searches. It makes your code tied to the exact layout of the database. -It’s also not very maintainable to have to remember abstract numbers. Passing the actual objects -around and searching by Tags and/or keys will usually get you what you need.

  • -
-
-
-

Getting objects inside another

-

All in-game Objects have a .contents property that returns all objects ‘inside’ them -(that is, all objects which has its .location property set to that object. This is a simple way to -get everything in a room and is also faster since this lookup is cached and won’t hit the database.

-
    -
  • roomobj.contents returns a list of all objects inside roomobj.

  • -
  • obj.contents same as for a room, except this usually represents the object’s inventory

  • -
  • obj.location.contents gets everything in obj’s location (including obj itself).

  • -
  • roomobj.exits returns all exits starting from roomobj (Exits are here defined as Objects with -their destination field set).

  • -
  • obj.location.contents_get(exclude=obj) - this helper method returns all objects in obj’s -location except obj.

  • -
-
- - -
-

Queries in Django

-

This is an advanced topic.

-

Evennia’s search methods should be sufficient for the vast majority of situations. But eventually -you might find yourself trying to figure out how to get searches for unusual circumstances: Maybe -you want to find all characters who are not in rooms tagged as hangouts and have the lycanthrope -tag and whose names start with a vowel, but not with ‘Ab’, and only if they have 3 or more -objects in their inventory … You could in principle use one of the earlier search methods to find -all candidates and then loop over them with a lot of if statements in raw Python. But you can do -this much more efficiently by querying the database directly.

-

Enter django’s querysets. A QuerySet -is the representation of a database query and can be modified as desired. Only once one tries to -retrieve the data of that query is it evaluated and does an actual database request. This is -useful because it means you can modify a query as much as you want (even pass it around) and only -hit the database once you are happy with it. -Evennia’s search functions are themselves an even higher level wrapper around Django’s queries, and -many search methods return querysets. That means that you could get the result from a search -function and modify the resulting query to your own ends to further tweak what you search for.

-

Evaluated querysets can either contain objects such as Character objects, or lists of values derived -from the objects. Queries usually use the ‘manager’ object of a class, which by convention is the -.objects attribute of a class. For example, a query of Accounts that contain the letter ‘a’ could -be:

-
    from typeclasses.accounts import Account
-
-queryset = Account.objects.filter(username__contains='a')
-
-
-
-

The filter method of a manager takes arguments that allow you to define the query, and you can -continue to refine the query by calling additional methods until you evaluate the queryset, causing -the query to be executed and return a result. For example, if you have the result above, you could, -without causing the queryset to be evaluated yet, get rid of matches that contain the letter ‘e by -doing this:

-
queryset = result.exclude(username__contains='e')
-
-
-
-
-

You could also have chained .exclude directly to the end of the previous line.

-
-

Once you try to access the result, the queryset will be evaluated automatically under the hood:

-
accounts = list(queryset)  # this fills list with matches
-
-for account in queryset:
-    # do something with account
-
-accounts = queryset[:4]  # get first four matches
-account = queryset[0]  # get first match
-# etc
-
-
-
-
-

Limiting by typeclass

-

Although Characters, Exits, Rooms, and other children of DefaultObject all shares the same -underlying database table, Evennia provides a shortcut to do more specific queries only for those -typeclasses. For example, to find only Characters whose names start with ‘A’, you might do:

-
Character.objects.filter(db_key__startswith="A")
-
-
-
-

If Character has a subclass Npc and you wanted to find only Npc’s you’d instead do

-
Npc.objects.filter(db_key__startswith="A")
-
-
-
-

If you wanted to search both Characters and all its subclasses (like Npc) you use the *_family -method which is added by Evennia:

-
Character.objects.filter_family(db_key__startswith="A")
-
-
-

The higher up in the inheritance hierarchy you go the more objects will be included in these -searches. There is one special case, if you really want to include everything from a given -database table. You do that by searching on the database model itself. These are named ObjectDB, -AccountDB, ScriptDB etc.

-
from evennia import AccountDB
-
-# all Accounts in the database, regardless of typeclass
-all = AccountDB.objects.all()
-
-
-
-

Here are the most commonly used methods to use with the objects managers:

-
    -
  • filter - query for a listing of objects based on search criteria. Gives empty queryset if none -were found.

  • -
  • get - query for a single match - raises exception if none were found, or more than one was -found.

  • -
  • all - get all instances of the particular type.

  • -
  • filter_family - like filter, but search all sub classes as well.

  • -
  • get_family - like get, but search all sub classes as well.

  • -
  • all_family - like all, but return entities of all subclasses as well.

  • -
-
-
-
-

Multiple conditions

-

If you pass more than one keyword argument to a query method, the query becomes an AND -relationship. For example, if we want to find characters whose names start with “A” and are also -werewolves (have the lycanthrope tag), we might do:

-
queryset = Character.objects.filter(db_key__startswith="A", db_tags__db_key="lycanthrope")
-
-
-

To exclude lycanthropes currently in rooms tagged as hangouts, we might tack on an .exclude as -before:

-
queryset = quersyet.exclude(db_location__db_tags__db_key="hangout")
-
-
-

Note the syntax of the keywords in building the queryset. For example, db_location is the name of -the database field sitting on (in this case) the Character (Object). Double underscore __ works -like dot-notation in normal Python (it’s used since dots are not allowed in keyword names). So the -instruction db_location__db_tags__db_key="hangout" should be read as such:

-
    -
  1. “On the Character object … (this comes from us building this queryset using the -Character.objects manager)

  2. -
  3. … get the value of the db_location field … (this references a Room object, normally)

  4. -
  5. … on that location, get the value of the db_tags field … (this is a many-to-many field that -can be treated like an object for this purpose. It references all tags on the location)

  6. -
  7. … through the db_tag manager, find all Tags having a field db_key set to the value -“hangout”.”

  8. -
-

This may seem a little complex at first, but this syntax will work the same for all queries. Just -remember that all database-fields in Evennia are prefaced with db_. So even though Evennia is -nice enough to alias the db_key field so you can normally just do char.key to get a character’s -name, the database field is actually called db_key and the real name must be used for the purpose -of building a query.

-
-

Don’t confuse database fields with Attributes you set via obj.db.attr = 'foo' or -obj.attributes.add(). Attributes are custom database entities linked to an object. They are not -separate fields on that object like db_key or db_location are. You can get attached Attributes -manually through the db_attributes many-to-many field in the same way as db_tags above.

-
-
-

Complex queries

-

What if you want to have a query with with OR conditions or negated requirements (NOT)? Enter -Django’s Complex Query object, -Q. Q() -objects take a normal django keyword query as its arguments. The special thing is that these Q -objects can then be chained together with set operations: | for OR, & for AND, and preceded with -~ for NOT to build a combined, complex query.

-

In our original Lycanthrope example we wanted our werewolves to have names that could start with any -vowel except for the specific beginning “ab”.

-
from django.db.models import Q
-from typeclasses.characters import Character
-
-query = Q()
-for letter in ("aeiouy"):
-    query |= Q(db_key__istartswith=letter)
-query &= ~Q(db_key__istartswith="ab")
-query = Character.objects.filter(query)
-
-list_of_lycanthropes = list(query)
-
-
-

In the above example, we construct our query our of several Q objects that each represent one part -of the query. We iterate over the list of vowels, and add an OR condition to the query using |= -(this is the same idea as using += which may be more familiar). Each OR condition checks that -the name starts with one of the valid vowels. Afterwards, we add (using &=) an AND condition -that is negated with the ~ symbol. In other words we require that any match should not start -with the string “ab”. Note that we don’t actually hit the database until we convert the query to a -list at the end (we didn’t need to do that either, but could just have kept the query until we -needed to do something with the matches).

-
-
-

Annotations and F objects

-

What if we wanted to filter on some condition that isn’t represented easily by a field on the -object? Maybe we want to find rooms only containing five or more objects?

-

We could retrieve all interesting candidates and run them through a for-loop to get and count -their .content properties. We’d then just return a list of only those objects with enough -contents. It would look something like this (note: don’t actually do this!):

-
# probably not a good idea to do it this way
-
-from typeclasses.rooms import Room
-
-queryset = Room.objects.all()  # get all Rooms
-rooms = [room for room in queryset if len(room.contents) >= 5]
-
-
-
-

Once the number of rooms in your game increases, this could become quite expensive. Additionally, in -some particular contexts, like when using the web features of Evennia, you must have the result as a -queryset in order to use it in operations, such as in Django’s admin interface when creating list -filters.

-

Enter F objects and -annotations. So-called F expressions allow you to do a query that looks at a value of each object -in the database, while annotations allow you to calculate and attach a value to a query. So, let’s -do the same example as before directly in the database:

-
from typeclasses.rooms import Room
-from django.db.models import Count
-
-room_count = Room.objects.annotate(num_objects=Count('locations_set'))
-queryset = room_count.filter(num_objects__gte=5)
-
-rooms = (Room.objects.annotate(num_objects=Count('locations_set'))
-                     .filter(num_objects__gte=5))
-
-rooms = list(rooms)
-
-
-
-

Here we first create an annotation num_objects of type Count, which is a Django class. Note that -use of location_set in that Count. The *_set is a back-reference automatically created by -Django. In this case it allows you to find all objects that has the current object as location. -Once we have those, they are counted. -Next we filter on this annotation, using the name num_objects as something we can filter for. We -use num_objects__gte=5 which means that num_objects should be greater than 5. This is a little -harder to get one’s head around but much more efficient than lopping over all objects in Python.

-

What if we wanted to compare two parameters against one another in a query? For example, what if -instead of having 5 or more objects, we only wanted objects that had a bigger inventory than they -had tags? Here an F-object comes in handy:

-
from django.db.models import Count, F
-from typeclasses.rooms import Room
-
-result = (Room.objects.annotate(num_objects=Count('locations_set'),
-                                num_tags=Count('db_tags'))
-                      .filter(num_objects__gt=F('num_tags')))
-
-
-

F-objects allows for wrapping an annotated structure on the right-hand-side of the expression. It -will be evaluated on-the-fly as needed.

-
-
-

Grouping By and Values

-

Suppose you used tags to mark someone belonging an organization. Now you want to make a list and -need to get the membership count of every organization all at once. That’s where annotations and the -.values_list queryset method come in. Values/Values Lists are an alternate way of returning a -queryset - instead of objects, you get a list of dicts or tuples that hold selected properties from -the the matches. It also allows you a way to ‘group up’ queries for returning information. For -example, to get a display about each tag per Character and the names of the tag:

-
result = (Character.objects.filter(db_tags__db_category="organization")
-                           .values_list('db_tags__db_key')
-                           .annotate(cnt=Count('id'))
-                           .order_by('-cnt'))
-
-
-

The result queryset will be a list of tuples ordered in descending order by the number of matches, -in a format like the following:

-
[('Griatch Fanclub', 3872), ("Chainsol's Ainneve Testers", 2076), ("Blaufeuer's Whitespace Fixers",
-1903),
- ("Volund's Bikeshed Design Crew", 1764), ("Tehom's Misanthropes", 1)]
-
-
-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Tutorial-Tweeting-Game-Stats.html b/docs/0.9.5/Tutorial-Tweeting-Game-Stats.html deleted file mode 100644 index 780cb30055..0000000000 --- a/docs/0.9.5/Tutorial-Tweeting-Game-Stats.html +++ /dev/null @@ -1,201 +0,0 @@ - - - - - - - - - Tutorial Tweeting Game Stats — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Tutorial Tweeting Game Stats

-

This tutorial will create a simple script that will send a tweet to your already configured twitter -account. Please see: How to connect Evennia to Twitter if you -haven’t already done so.

-

The script could be expanded to cover a variety of statistics you might wish to tweet about -regularly, from player deaths to how much currency is in the economy etc.

-
# evennia/typeclasses/tweet_stats.py
-
-import twitter
-from random import randint
-from django.conf import settings
-from evennia import ObjectDB
-from evennia import spawner
-from evennia import logger
-from evennia import DefaultScript
-
-class TweetStats(DefaultScript):
-    """
-    This implements the tweeting of stats to a registered twitter account
-    """
-
-    # standard Script hooks
-
-    def at_script_creation(self):
-        "Called when script is first created"
-
-        self.key = "tweet_stats"
-        self.desc = "Tweets interesting stats about the game"
-        self.interval = 86400  # 1 day timeout
-        self.start_delay = False
-        
-    def at_repeat(self):
-        """
-        This is called every self.interval seconds to tweet interesting stats about the game.
-        """
-        
-        api = twitter.Api(consumer_key='consumer_key',
-          consumer_secret='consumer_secret',
-          access_token_key='access_token_key',
-          access_token_secret='access_token_secret')
-        
-        number_tweet_outputs = 2
-
-        tweet_output = randint(1, number_tweet_outputs)
-
-        if tweet_output == 1:
-        ##Game Chars, Rooms, Objects taken from @stats command
-            nobjs = ObjectDB.objects.count()
-            base_char_typeclass = settings.BASE_CHARACTER_TYPECLASS
-            nchars = ObjectDB.objects.filter(db_typeclass_path=base_char_typeclass).count()
-            nrooms = ObjectDB.objects.filter(db_location__isnull=True).exclude(db_typeclass_path=bas
-e_char_typeclass).count()
-            nexits = ObjectDB.objects.filter(db_location__isnull=False,
-db_destination__isnull=False).count()
-            nother = nobjs - nchars - nrooms - nexits
-            tweet = "Chars: %s, Rooms: %s, Objects: %s" %(nchars, nrooms, nother)
-        else:
-            if tweet_output == 2: ##Number of prototypes and 3 random keys - taken from @spawn
-command
-                prototypes = spawner.spawn(return_prototypes=True)
-            
-                keys = prototypes.keys()
-                nprots = len(prototypes)
-                tweet = "Prototype Count: %s  Random Keys: " % nprots
-
-                tweet += " %s" % keys[randint(0,len(keys)-1)]
-                for x in range(0,2): ##tweet 3
-                    tweet += ", %s" % keys[randint(0,len(keys)-1)]
-        # post the tweet
-        try:
-            response = api.PostUpdate(tweet)
-        except:
-            logger.log_trace("Tweet Error: When attempting to tweet %s" % tweet)
-
-
-

In the at_script_creation method, we configure the script to fire immediately (useful for testing) -and setup the delay (1 day) as well as script information seen when you use @scripts

-

In the at_repeat method (which is called immediately and then at interval seconds later) we setup -the Twitter API (just like in the initial configuration of twitter). numberTweetOutputs is used to -show how many different types of outputs we have (in this case 2). We then build the tweet based on -randomly choosing between these outputs.

-
    -
  1. Shows the number of Player Characters, Rooms and Other/Objects

  2. -
  3. Shows the number of prototypes currently in the game and then selects 3 random keys to show

  4. -
-

Scripts Information will show you how to add it as a Global script, however, for testing -it may be useful to start/stop it quickly from within the game. Assuming that you create the file -as mygame/typeclasses/tweet_stats.py it can be started by using the following command

-
@script Here = tweet_stats.TweetStats
-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Tutorial-Vehicles.html b/docs/0.9.5/Tutorial-Vehicles.html deleted file mode 100644 index 0bcc0f000a..0000000000 --- a/docs/0.9.5/Tutorial-Vehicles.html +++ /dev/null @@ -1,503 +0,0 @@ - - - - - - - - - Tutorial Vehicles — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Tutorial Vehicles

-

This tutorial explains how you can create vehicles that can move around in your world. The tutorial -will explain how to create a train, but this can be equally applied to create other kind of vehicles -(cars, planes, boats, spaceships, submarines, …).

-
-

How it works

-

Objects in Evennia have an interesting property: you can put any object inside another object. This -is most obvious in rooms: a room in Evennia is just like any other game object (except rooms tend to -not themselves be inside anything else).

-

Our train will be similar: it will be an object that other objects can get inside. We then simply -move the Train, which brings along everyone inside it.

-
-
-

Creating our train object

-

The first step we need to do is create our train object, including a new typeclass. To do this, -create a new file, for instance in mygame/typeclasses/train.py with the following content:

-
# file mygame/typeclasses/train.py
-
-from evennia import DefaultObject
-
-class TrainObject(DefaultObject):
-
-    def at_object_creation(self):
-        # We'll add in code here later.
-        pass
-
-
-
-

Now we can create our train in our game:

-
@create/drop train:train.TrainObject
-
-
-

Now this is just an object that doesn’t do much yet… but we can already force our way inside it -and back (assuming we created it in limbo).

-
@tel train
-@tel limbo
-
-
-
-
-

Entering and leaving the train

-

Using the @telcommand like shown above is obviously not what we want. @tel is an admin command -and normal players will thus never be able to enter the train! It is also not really a good idea to -use Exits to get in and out of the train - Exits are (at least by default) objects -too. They point to a specific destination. If we put an Exit in this room leading inside the train -it would stay here when the train moved away (still leading into the train like a magic portal!). In -the same way, if we put an Exit object inside the train, it would always point back to this room, -regardless of where the Train has moved. Now, one could define custom Exit types that move with -the train or change their destination in the right way - but this seems to be a pretty cumbersome -solution.

-

What we will do instead is to create some new commands: one for entering the train and -another for leaving it again. These will be stored on the train object and will thus be made -available to whomever is either inside it or in the same room as the train.

-

Let’s create a new command module as mygame/commands/train.py:

-
# mygame/commands/train.py
-
-from evennia import Command, CmdSet
-
-class CmdEnterTrain(Command):
-    """
-    entering the train
-    
-    Usage:
-      enter train
-
-    This will be available to players in the same location
-    as the train and allows them to embark.
-    """
-
-    key = "enter train"
-    locks = "cmd:all()"
-
-    def func(self):
-        train = self.obj
-        self.caller.msg("You board the train.")
-        self.caller.move_to(train)
-
-
-class CmdLeaveTrain(Command):
-    """
-    leaving the train
- 
-    Usage:
-      leave train
-
-    This will be available to everyone inside the
-    train. It allows them to exit to the train's
-    current location.
-    """
-
-    key = "leave train"
-    locks = "cmd:all()"
-
-    def func(self):
-        train = self.obj
-        parent = train.location
-        self.caller.move_to(parent)
-
-
-class CmdSetTrain(CmdSet):
-
-    def at_cmdset_creation(self):
-        self.add(CmdEnterTrain())
-        self.add(CmdLeaveTrain())
-
-
-

Note that while this seems like a lot of text, the majority of lines here are taken up by -documentation.

-

These commands are work in a pretty straightforward way: CmdEnterTrain moves the location of the -player to inside the train and CmdLeaveTrain does the opposite: it moves the player back to the -current location of the train (back outside to its current location). We stacked them in a -cmdset CmdSetTrain so they can be used.

-

To make the commands work we need to add this cmdset to our train typeclass:

-
# file mygame/typeclasses/train.py
-
-from evennia import DefaultObject
-from commands.train import CmdSetTrain
-
-class TrainObject(DefaultObject):
-
-    def at_object_creation(self):
-        self.cmdset.add_default(CmdSetTrain)
-
-
-
-

If we now @reload our game and reset our train, those commands should work and we can now enter -and leave the train:

-
@reload
-@typeclass/force/reset train = train.TrainObject
-enter train
-leave train
-
-
-

Note the switches used with the @typeclass command: The /force switch is necessary to assign our -object the same typeclass we already have. The /reset re-triggers the typeclass’ -at_object_creation() hook (which is otherwise only called the very first an instance is created). -As seen above, when this hook is called on our train, our new cmdset will be loaded.

-
-
-

Locking down the commands

-

If you have played around a bit, you’ve probably figured out that you can use leave train when -outside the train and enter train when inside. This doesn’t make any sense … so let’s go ahead -and fix that. We need to tell Evennia that you can not enter the train when you’re already inside -or leave the train when you’re outside. One solution to this is locks: we will lock down -the commands so that they can only be called if the player is at the correct location.

-

Right now commands defaults to the lock cmd:all(). The cmd lock type in combination with the -all() lock function means that everyone can run those commands as long as they are in the same -room as the train or inside the train. We’re going to change this to check the location of the -player and only allow access if they are inside the train.

-

First of all we need to create a new lock function. Evennia comes with many lock functions built-in -already, but none that we can use for locking a command in this particular case. Create a new entry -in mygame/server/conf/lockfuncs.py:

-

-# file mygame/server/conf/lockfuncs.py
-
-def cmdinside(accessing_obj, accessed_obj, *args, **kwargs):
-    """
-    Usage: cmdinside()
-    Used to lock commands and only allows access if the command
-    is defined on an object which accessing_obj is inside of.
-    """
-    return accessed_obj.obj == accessing_obj.location
-
-
-
-

If you didn’t know, Evennia is by default set up to use all functions in this module as lock -functions (there is a setting variable that points to it).

-

Our new lock function, cmdinside, is to be used by Commands. The accessed_obj is the Command -object (in our case this will be CmdEnterTrain and CmdLeaveTrain) — Every command has an obj -property: this is the the object on which the command “sits”. Since we added those commands to our -train object, the .obj property will be set to the train object. Conversely, accessing_obj is -the object that called the command: in our case it’s the Character trying to enter or leave the -train.

-

What this function does is to check that the player’s location is the same as the train object. If -it is, it means the player is inside the train. Otherwise it means the player is somewhere else and -the check will fail.

-

The next step is to actually use this new lock function to create a lock of type cmd:

-
# file commands/train.py
-...
-class CmdEnterTrain(Command):
-    key = "enter train"
-    locks = "cmd:not cmdinside()"
-    # ...
-
-class CmdLeaveTrain(Command):
-    key = "leave train"
-    locks = "cmd:cmdinside()"
-    # ...
-
-
-

Notice how we use the not here so that we can use the same cmdinside to check if we are inside -and outside, without having to create two separate lock functions. After a @reload our commands -should be locked down appropriately and you should only be able to use them at the right places.

-
-

Note: If you’re logged in as the super user (user #1) then this lock will not work: the super -user ignores lock functions. In order to use this functionality you need to @quell first.

-
-
-
-

Making our train move

-

Now that we can enter and leave the train correctly, it’s time to make it move. There are different -things we need to consider for this:

-
    -
  • Who can control your vehicle? The first player to enter it, only players that have a certain -“drive” skill, automatically?

  • -
  • Where should it go? Can the player steer the vehicle to go somewhere else or will it always follow -the same route?

  • -
-

For our example train we’re going to go with automatic movement through a predefined route (its -track). The train will stop for a bit at the start and end of the route to allow players to enter -and leave it.

-

Go ahead and create some rooms for our train. Make a list of the room ids along the route (using the -@ex command).

-
@dig/tel South station
-@ex              # note the id of the station
-@tunnel/tel n = Following a railroad
-@ex              # note the id of the track
-@tunnel/tel n = Following a railroad
-...
-@tunnel/tel n = North Station
-
-
-

Put the train onto the tracks:

-
@tel south station
-@tel train = here
-
-
-

Next we will tell the train how to move and which route to take.

-
# file typeclasses/train.py
-
-from evennia import DefaultObject, search_object
-
-from commands.train import CmdSetTrain
-
-class TrainObject(DefaultObject):
-
-    def at_object_creation(self):
-        self.cmdset.add_default(CmdSetTrain)
-        self.db.driving = False
-        # The direction our train is driving (1 for forward, -1 for backwards)
-        self.db.direction = 1
-        # The rooms our train will pass through (change to fit your game)
-        self.db.rooms = ["#2", "#47", "#50", "#53", "#56", "#59"]
-
-    def start_driving(self):
-        self.db.driving = True
-
-    def stop_driving(self):
-        self.db.driving = False
-
-    def goto_next_room(self):
-        currentroom = self.location.dbref
-        idx = self.db.rooms.index(currentroom) + self.db.direction
-
-        if idx < 0 or idx >= len(self.db.rooms):
-            # We reached the end of our path
-            self.stop_driving()
-            # Reverse the direction of the train
-            self.db.direction *= -1
-        else:
-            roomref = self.db.rooms[idx]
-            room = search_object(roomref)[0]
-            self.move_to(room)
-            self.msg_contents("The train is moving forward to %s." % (room.name, ))
-
-
-

We added a lot of code here. Since we changed the at_object_creation to add in variables we will -have to reset our train object like earlier (using the @typeclass/force/reset command).

-

We are keeping track of a few different things now: whether the train is moving or standing still, -which direction the train is heading to and what rooms the train will pass through.

-

We also added some methods: one to start moving the train, another to stop and a third that actually -moves the train to the next room in the list. Or makes it stop driving if it reaches the last stop.

-

Let’s try it out, using @py to call the new train functionality:

-
@reload
-@typeclass/force/reset train = train.TrainObject
-enter train
-@py here.goto_next_room()
-
-
-

You should see the train moving forward one step along the rail road.

-
-
-

Adding in scripts

-

If we wanted full control of the train we could now just add a command to step it along the track -when desired. We want the train to move on its own though, without us having to force it by manually -calling the goto_next_room method.

-

To do this we will create two scripts: one script that runs when the train has stopped at -a station and is responsible for starting the train again after a while. The other script will take -care of the driving.

-

Let’s make a new file in mygame/typeclasses/trainscript.py

-
# file mygame/typeclasses/trainscript.py
-
-from evennia import DefaultScript
-
-class TrainStoppedScript(DefaultScript):
-
-    def at_script_creation(self):
-        self.key = "trainstopped"
-        self.interval = 30
-        self.persistent = True
-        self.repeats = 1
-        self.start_delay = True
-
-    def at_repeat(self):
-        self.obj.start_driving()
-
-    def at_stop(self):
-        self.obj.scripts.add(TrainDrivingScript)
-
-
-class TrainDrivingScript(DefaultScript):
-
-    def at_script_creation(self):
-        self.key = "traindriving"
-        self.interval = 1
-        self.persistent = True
-
-    def is_valid(self):
-        return self.obj.db.driving
-
-    def at_repeat(self):
-        if not self.obj.db.driving:
-            self.stop()
-        else:
-            self.obj.goto_next_room()
-
-    def at_stop(self):
-        self.obj.scripts.add(TrainStoppedScript)
-
-
-

Those scripts work as a state system: when the train is stopped, it waits for 30 seconds and then -starts again. When the train is driving, it moves to the next room every second. The train is always -in one of those two states - both scripts take care of adding the other one once they are done.

-

As a last step we need to link the stopped-state script to our train, reload the game and reset our -train again., and we’re ready to ride it around!

-
# file typeclasses/train.py
-
-from typeclasses.trainscript import TrainStoppedScript
-
-class TrainObject(DefaultObject):
-
-    def at_object_creation(self):
-        # ...
-        self.scripts.add(TrainStoppedScript)
-
-
-
@reload
-@typeclass/force/reset train = train.TrainObject
-enter train
-
-# output:
-< The train is moving forward to Following a railroad.
-< The train is moving forward to Following a railroad.
-< The train is moving forward to Following a railroad.
-...
-< The train is moving forward to Following a railroad.
-< The train is moving forward to North station.
-
-leave train
-
-
-

Our train will stop 30 seconds at each end station and then turn around to go back to the other end.

-
-
-

Expanding

-

This train is very basic and still has some flaws. Some more things to do:

-
    -
  • Make it look like a train.

  • -
  • Make it impossible to exit and enter the train mid-ride. This could be made by having the -enter/exit commands check so the train is not moving before allowing the caller to proceed.

  • -
  • Have train conductor commands that can override the automatic start/stop.

  • -
  • Allow for in-between stops between the start- and end station

  • -
  • Have a rail road track instead of hard-coding the rooms in the train object. This could for -example be a custom Exit only traversable by trains. The train will follow the -track. Some track segments can split to lead to two different rooms and a player can switch the -direction to which room it goes.

  • -
  • Create another kind of vehicle!

  • -
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Tutorial-World-Introduction.html b/docs/0.9.5/Tutorial-World-Introduction.html deleted file mode 100644 index babd40c307..0000000000 --- a/docs/0.9.5/Tutorial-World-Introduction.html +++ /dev/null @@ -1,221 +0,0 @@ - - - - - - - - - Tutorial World Introduction — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Tutorial World Introduction

-

The Tutorial World is a small and functioning MUD-style game world. It is intended to be -deconstructed and used as a way to learn Evennia. The game consists of a single-player quest and -has some 20 rooms that you can explore as you seek to discover the whereabouts of a mythical weapon.

-

The source code is fully documented. You can find the whole thing in -evennia/contrib/tutorial_world/.

-

Some features exemplified by the tutorial world:

-
    -
  • Tutorial command, giving “behind-the-scenes” help for every room and some of the special objects

  • -
  • Rooms with custom return_appearance to show details.

  • -
  • Hidden exits

  • -
  • Objects with multiple custom interactions

  • -
  • Large-area rooms

  • -
  • Outdoor weather rooms

  • -
  • Dark room, needing light source

  • -
  • Puzzle object

  • -
  • Multi-room puzzle

  • -
  • Aggressive mobile with roam, pursue and battle state-engine AI

  • -
  • Weapons, also used by mobs

  • -
  • Simple combat system with attack/defend commands

  • -
  • Object spawning

  • -
  • Teleporter trap rooms

  • -
-
-

Install

-

The tutorial world consists of a few modules in evennia/contrib/tutorial_world/ containing custom -Typeclasses for rooms and objects and associated Commands.

-

These reusable bits and pieces are then put together into a functioning game area (“world” is maybe -too big a word for such a small zone) using a batch script called build.ev. To -install, log into the server as the superuser (user #1) and run:

-
@batchcommand tutorial_world.build
-
-
-

The world will be built (this might take a while, so don’t rerun the command even if it seems the -system has frozen). After finishing you will end up back in Limbo with a new exit called tutorial.

-

An alternative is

-
@batchcommand/interactive tutorial_world.build
-
-
-

with the /interactive switch you are able to step through the building process at your own pace to -see what happens in detail.

-
-
-

Quelling and permissions in the tutorial-world

-

Non-superusers entering the tutorial will be auto-quelled so they play with their Character’s -permission. As superuser you will not be auto-quelled, but it’s recommended that you still quell -manually to play the tutorial “correctly”. The reason for this is that many game systems ignore the -presence of a superuser and will thus not work as normal.

-

Use unquell if you want to get back your main account-level permissions to examine things under -the hood. When you exit the tutorial (either by winning or using the abort/give up command) you -will automatically be unquelled.

-
-
-

Gameplay

-

the castle off the moor

-

To get into the mood of this miniature quest, imagine you are an adventurer out to find fame and -fortune. You have heard rumours of an old castle ruin by the coast. In its depth a warrior princess -was buried together with her powerful magical weapon - a valuable prize, if it’s true. Of course -this is a chance to adventure that you cannot turn down!

-

You reach the ocean in the midst of a raging thunderstorm. With wind and rain screaming in your -face you stand where the moor meets the sea along a high, rocky coast …

-
    -
  • Look at everything.

  • -
  • Some objects are interactive in more than one way. Use the normal help command to get a feel for -which commands are available at any given time. (use the command tutorial to get insight behind -the scenes of the tutorial).

  • -
  • In order to fight, you need to first find some type of weapon.

  • -
  • slash is a normal attack

  • -
  • stab launches an attack that makes more damage but has a lower chance to hit.

  • -
  • defend will lower the chance to taking damage on your enemy’s next attack.

  • -
  • You can run from a fight that feels too deadly. Expect to be chased though.

  • -
  • Being defeated is a part of the experience …

  • -
-
-
-

Uninstall

-

Uninstalling the tutorial world basically means deleting all the rooms and objects it consists of. -First, move out of the tutorial area.

-
 @find tut#01
- @find tut#16
-
-
-

This should locate the first and last rooms created by build.ev - Intro and Outro. If you -installed normally, everything created between these two numbers should be part of the tutorial. -Note their dbref numbers, for example 5 and 80. Next we just delete all objects in that range:

-
 @del 5-80
-
-
-

You will see some errors since some objects are auto-deleted and so cannot be found when the delete -mechanism gets to them. That’s fine. You should have removed the tutorial completely once the -command finishes.

-
-
-

Notes

-

When reading and learning from the code, keep in mind that Tutorial World was created with a very -specific goal: to install easily and to not permanently modify the rest of the server. It therefore -goes to some length to use only temporary solutions and to clean up after -itself.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Tutorial-for-basic-MUSH-like-game.html b/docs/0.9.5/Tutorial-for-basic-MUSH-like-game.html deleted file mode 100644 index ff38249db5..0000000000 --- a/docs/0.9.5/Tutorial-for-basic-MUSH-like-game.html +++ /dev/null @@ -1,738 +0,0 @@ - - - - - - - - - Tutorial for basic MUSH like game — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Tutorial for basic MUSH like game

-

This tutorial lets you code a small but complete and functioning MUSH-like game in Evennia. A -MUSH is, for our purposes, a class of roleplay-centric games -focused on free form storytelling. Even if you are not interested in MUSH:es, this is still a good -first game-type to try since it’s not so code heavy. You will be able to use the same principles for -building other types of games.

-

The tutorial starts from scratch. If you did the First Steps Coding tutorial -already you should have some ideas about how to do some of the steps already.

-

The following are the (very simplistic and cut-down) features we will implement (this was taken from -a feature request from a MUSH user new to Evennia). A Character in this system should:

-
    -
  • Have a “Power” score from 1 to 10 that measures how strong they are (stand-in for the stat -system).

  • -
  • Have a command (e.g. +setpower 4) that sets their power (stand-in for character generation -code).

  • -
  • Have a command (e.g. +attack) that lets them roll their power and produce a “Combat Score” -between 1 and 10*Power, displaying the result and editing their object to record this number -(stand-in for +actions in the command code).

  • -
  • Have a command that displays everyone in the room and what their most recent “Combat Score” roll -was (stand-in for the combat code).

  • -
  • Have a command (e.g. +createNPC Jenkins) that creates an NPC with full abilities.

  • -
  • Have a command to control NPCs, such as +npc/cmd (name)=(command) (stand-in for the NPC -controlling code).

  • -
-

In this tutorial we will assume you are starting from an empty database without any previous -modifications.

-
-

Server Settings

-

To emulate a MUSH, the default MULTISESSION_MODE=0 is enough (one unique session per -account/character). This is the default so you don’t need to change anything. You will still be able -to puppet/unpuppet objects you have permission to, but there is no character selection out of the -box in this mode.

-

We will assume our game folder is called mygame henceforth. You should be fine with the default -SQLite3 database.

-
-
-

Creating the Character

-

First thing is to choose how our Character class works. We don’t need to define a special NPC object -– an NPC is after all just a Character without an Account currently controlling them.

-

Make your changes in the mygame/typeclasses/characters.py file:

-
# mygame/typeclasses/characters.py
-
-from evennia import DefaultCharacter
-
-class Character(DefaultCharacter):
-    """
-     [...]
-    """
-    def at_object_creation(self):
-        "This is called when object is first created, only."
-        self.db.power = 1
-        self.db.combat_score = 1
-
-
-

We defined two new Attributes power and combat_score and set them to default -values. Make sure to @reload the server if you had it already running (you need to reload every -time you update your python code, don’t worry, no accounts will be disconnected by the reload).

-

Note that only new characters will see your new Attributes (since the at_object_creation hook is -called when the object is first created, existing Characters won’t have it). To update yourself, -run

-
 @typeclass/force self
-
-
-

This resets your own typeclass (the /force switch is a safety measure to not do this -accidentally), this means that at_object_creation is re-run.

-
 examine self
-
-
-

Under the “Persistent attributes” heading you should now find the new Attributes power and score -set on yourself by at_object_creation. If you don’t, first make sure you @reloaded into the new -code, next look at your server log (in the terminal/console) to see if there were any syntax errors -in your code that may have stopped your new code from loading correctly.

-
-
-

Character Generation

-

We assume in this example that Accounts first connect into a “character generation area”. Evennia -also supports full OOC menu-driven character generation, but for this example, a simple start room -is enough. When in this room (or rooms) we allow character generation commands. In fact, character -generation commands will only be available in such rooms.

-

Note that this again is made so as to be easy to expand to a full-fledged game. With our simple -example, we could simply set an is_in_chargen flag on the account and have the +setpower command -check it. Using this method however will make it easy to add more functionality later.

-

What we need are the following:

-
    -
  • One character generation Command to set the “Power” on the Character.

  • -
  • A chargen CmdSet to hold this command. Lets call it ChargenCmdset.

  • -
  • A custom ChargenRoom type that makes this set of commands available to players in such rooms.

  • -
  • One such room to test things in.

  • -
-
-

The +setpower command

-

For this tutorial we will add all our new commands to mygame/commands/command.py but you could -split your commands into multiple module if you prefered.

-

For this tutorial character generation will only consist of one Command to set the -Character s “power” stat. It will be called on the following MUSH-like form:

-
 +setpower 4
-
-
-

Open command.py file. It contains documented empty templates for the base command and the -“MuxCommand” type used by default in Evennia. We will use the plain Command type here, the -MuxCommand class offers some extra features like stripping whitespace that may be useful - if so, -just import from that instead.

-

Add the following to the end of the command.py file:

-
# end of command.py
-from evennia import Command # just for clarity; already imported above
-
-class CmdSetPower(Command):
-    """
-    set the power of a character
-
-    Usage:
-      +setpower <1-10>
-
-    This sets the power of the current character. This can only be
-    used during character generation.
-    """
-    
-    key = "+setpower"
-    help_category = "mush"
-
-    def func(self):
-        "This performs the actual command"
-        errmsg = "You must supply a number between 1 and 10."
-        if not self.args:
-            self.caller.msg(errmsg)
-            return
-        try:
-            power = int(self.args)
-        except ValueError:
-            self.caller.msg(errmsg)
-            return
-        if not (1 <= power <= 10):
-            self.caller.msg(errmsg)
-            return
-        # at this point the argument is tested as valid. Let's set it.
-        self.caller.db.power = power
-        self.caller.msg("Your Power was set to %i." % power)
-
-
-

This is a pretty straightforward command. We do some error checking, then set the power on ourself. -We use a help_category of “mush” for all our commands, just so they are easy to find and separate -in the help list.

-

Save the file. We will now add it to a new CmdSet so it can be accessed (in a full -chargen system you would of course have more than one command here).

-

Open mygame/commands/default_cmdsets.py and import your command.py module at the top. We also -import the default CmdSet class for the next step:

-
from evennia import CmdSet
-from commands import command
-
-
-

Next scroll down and define a new command set (based on the base CmdSet class we just imported at -the end of this file, to hold only our chargen-specific command(s):

-
# end of default_cmdsets.py
-
-class ChargenCmdset(CmdSet):
-    """
-    This cmdset it used in character generation areas.
-    """
-    key = "Chargen"
-    def at_cmdset_creation(self):
-        "This is called at initialization"
-        self.add(command.CmdSetPower())
-
-
-

In the future you can add any number of commands to this cmdset, to expand your character generation -system as you desire. Now we need to actually put that cmdset on something so it’s made available to -users. We could put it directly on the Character, but that would make it available all the time. -It’s cleaner to put it on a room, so it’s only available when players are in that room.

-
-
-

Chargen areas

-

We will create a simple Room typeclass to act as a template for all our Chargen areas. Edit -mygame/typeclasses/rooms.py next:

-
from commands.default_cmdsets import ChargenCmdset
-
-# ...
-# down at the end of rooms.py
-
-class ChargenRoom(Room):
-    """
-    This room class is used by character-generation rooms. It makes
-    the ChargenCmdset available.
-    """
-    def at_object_creation(self):
-        "this is called only at first creation"
-        self.cmdset.add(ChargenCmdset, permanent=True)
-
-
-

Note how new rooms created with this typeclass will always start with ChargenCmdset on themselves. -Don’t forget the permanent=True keyword or you will lose the cmdset after a server reload. For -more information about Command Sets and Commands, see the respective -links.

-
-
-

Testing chargen

-

First, make sure you have @reloaded the server (or use evennia reload from the terminal) to have -your new python code added to the game. Check your terminal and fix any errors you see - the error -traceback lists exactly where the error is found - look line numbers in files you have changed.

-

We can’t test things unless we have some chargen areas to test. Log into the game (you should at -this point be using the new, custom Character class). Let’s dig a chargen area to test.

-
 @dig chargen:rooms.ChargenRoom = chargen,finish
-
-
-

If you read the help for @dig you will find that this will create a new room named chargen. The -part after the : is the python-path to the Typeclass you want to use. Since Evennia will -automatically try the typeclasses folder of our game directory, we just specify -rooms.ChargenRoom, meaning it will look inside the module rooms.py for a class named -ChargenRoom (which is what we created above). The names given after = are the names of exits to -and from the room from your current location. You could also append aliases to each one name, such -as chargen;character generation.

-

So in summary, this will create a new room of type ChargenRoom and open an exit chargen to it and -an exit back here named finish. If you see errors at this stage, you must fix them in your code. -@reload -between fixes. Don’t continue until the creation seems to have worked okay.

-
 chargen
-
-
-

This should bring you to the chargen room. Being in there you should now have the +setpower -command available, so test it out. When you leave (via the finish exit), the command will go away -and trying +setpower should now give you a command-not-found error. Use ex me (as a privileged -user) to check so the Power Attribute has been set correctly.

-

If things are not working, make sure your typeclasses and commands are free of bugs and that you -have entered the paths to the various command sets and commands correctly. Check the logs or command -line for tracebacks and errors.

-
-
-
-

Combat System

-

We will add our combat command to the default command set, meaning it will be available to everyone -at all times. The combat system consists of a +attack command to get how successful our attack is. -We also change the default look command to display the current combat score.

-
-

Attacking with the +attack command

-

Attacking in this simple system means rolling a random “combat score” influenced by the power stat -set during Character generation:

-
> +attack
-You +attack with a combat score of 12!
-
-
-

Go back to mygame/commands/command.py and add the command to the end like this:

-
import random
-
-# ...
-
-class CmdAttack(Command):
-    """
-    issues an attack
-
-    Usage:
-        +attack
-
-    This will calculate a new combat score based on your Power.
-    Your combat score is visible to everyone in the same location.
-    """
-    key = "+attack"
-    help_category = "mush"
-
-    def func(self):
-        "Calculate the random score between 1-10*Power"
-        caller = self.caller
-        power = caller.db.power
-        if not power:
-            # this can happen if caller is not of
-            # our custom Character typeclass
-            power = 1
-        combat_score = random.randint(1, 10 * power)
-        caller.db.combat_score = combat_score
-
-        # announce
-        message = "%s +attack%s with a combat score of %s!"
-        caller.msg(message % ("You", "", combat_score))
-        caller.location.msg_contents(message %
-                                     (caller.key, "s", combat_score),
-                                     exclude=caller)
-
-
-

What we do here is simply to generate a “combat score” using Python’s inbuilt random.randint() -function. We then store that and echo the result to everyone involved.

-

To make the +attack command available to you in game, go back to -mygame/commands/default_cmdsets.py and scroll down to the CharacterCmdSet class. At the correct -place add this line:

-
self.add(command.CmdAttack())
-
-
-

@reload Evennia and the +attack command should be available to you. Run it and use e.g. @ex to -make sure the combat_score attribute is saved correctly.

-
-
-

Have “look” show combat scores

-

Players should be able to view all current combat scores in the room. We could do this by simply -adding a second command named something like +combatscores, but we will instead let the default -look command do the heavy lifting for us and display our scores as part of its normal output, like -this:

-
>  look Tom
-Tom (combat score: 3)
-This is a great warrior.
-
-
-

We don’t actually have to modify the look command itself however. To understand why, take a look -at how the default look is actually defined. It sits in evennia/commands/default/general.py (or -browse it online -here). -You will find that the actual return text is done by the look command calling a hook method -named return_appearance on the object looked at. All the look does is to echo whatever this hook -returns. So what we need to do is to edit our custom Character typeclass and overload its -return_appearance to return what we want (this is where the advantage of having a custom typeclass -comes into play for real).

-

Go back to your custom Character typeclass in mygame/typeclasses/characters.py. The default -implementation of return appearance is found in evennia.DefaultCharacter (or online -here). If you -want to make bigger changes you could copy & paste the whole default thing into our overloading -method. In our case the change is small though:

-
class Character(DefaultCharacter):
-    """
-     [...]
-    """
-    def at_object_creation(self):
-        "This is called when object is first created, only."
-        self.db.power = 1
-        self.db.combat_score = 1
-
-    def return_appearance(self, looker):
-        """
-        The return from this method is what
-        looker sees when looking at this object.
-        """
-        text = super().return_appearance(looker)
-        cscore = " (combat score: %s)" % self.db.combat_score
-        if "\n" in text:
-            # text is multi-line, add score after first line
-            first_line, rest = text.split("\n", 1)
-            text = first_line + cscore + "\n" + rest
-        else:
-            # text is only one line; add score to end
-            text += cscore
-        return text
-
-
-

What we do is to simply let the default return_appearance do its thing (super will call the -parent’s version of the same method). We then split out the first line of this text, append our -combat_score and put it back together again.

-

@reload the server and you should be able to look at other Characters and see their current combat -scores.

-
-

Note: A potentially more useful way to do this would be to overload the entire return_appearance -of the Rooms of your mush and change how they list their contents; in that way one could see all -combat scores of all present Characters at the same time as looking at the room. We leave this as an -exercise.

-
-
-
-
-

NPC system

-

Here we will re-use the Character class by introducing a command that can create NPC objects. We -should also be able to set its Power and order it around.

-

There are a few ways to define the NPC class. We could in theory create a custom typeclass for it -and put a custom NPC-specific cmdset on all NPCs. This cmdset could hold all manipulation commands. -Since we expect NPC manipulation to be a common occurrence among the user base however, we will -instead put all relevant NPC commands in the default command set and limit eventual access with -Permissions and Locks.

-
-

Creating an NPC with +createNPC

-

We need a command for creating the NPC, this is a very straightforward command:

-
> +createnpc Anna
-You created the NPC 'Anna'.
-
-
-

At the end of command.py, create our new command:

-
from evennia import create_object
-    
-class CmdCreateNPC(Command):
-    """
-    create a new npc
-
-    Usage:
-        +createNPC <name>
-
-    Creates a new, named NPC. The NPC will start with a Power of 1.
-    """
-    key = "+createnpc"
-    aliases = ["+createNPC"]
-    locks = "call:not perm(nonpcs)"
-    help_category = "mush"
-    
-    def func(self):
-        "creates the object and names it"
-        caller = self.caller
-        if not self.args:
-            caller.msg("Usage: +createNPC <name>")
-            return
-        if not caller.location:
-            # may not create npc when OOC
-            caller.msg("You must have a location to create an npc.")
-            return
-        # make name always start with capital letter
-        name = self.args.strip().capitalize()
-        # create npc in caller's location
-        npc = create_object("characters.Character",
-                      key=name,
-                      location=caller.location,
-                      locks="edit:id(%i) and perm(Builders);call:false()" % caller.id)
-        # announce
-        message = "%s created the NPC '%s'."
-        caller.msg(message % ("You", name))
-        caller.location.msg_contents(message % (caller.key, name),
-                                                exclude=caller)
-
-
-

Here we define a +createnpc (+createNPC works too) that is callable by everyone not having the -nonpcspermission” (in Evennia, a “permission” can just as well be used to -block access, it depends on the lock we define). We create the NPC object in the caller’s current -location, using our custom Character typeclass to do so.

-

We set an extra lock condition on the NPC, which we will use to check who may edit the NPC later – -we allow the creator to do so, and anyone with the Builders permission (or higher). See -Locks for more information about the lock system.

-

Note that we just give the object default permissions (by not specifying the permissions keyword -to the create_object() call). In some games one might want to give the NPC the same permissions -as the Character creating them, this might be a security risk though.

-

Add this command to your default cmdset the same way you did the +attack command earlier. -@reload and it will be available to test.

-
-
-

Editing the NPC with +editNPC

-

Since we re-used our custom character typeclass, our new NPC already has a Power value - it -defaults to 1. How do we change this?

-

There are a few ways we can do this. The easiest is to remember that the power attribute is just a -simple Attribute stored on the NPC object. So as a Builder or Admin we could set this -right away with the default @set command:

-
 @set mynpc/power = 6
-
-
-

The @set command is too generally powerful though, and thus only available to staff. We will add a -custom command that only changes the things we want players to be allowed to change. We could in -principle re-work our old +setpower command, but let’s try something more useful. Let’s make a -+editNPC command.

-
> +editNPC Anna/power = 10
-Set Anna's property 'power' to 10.
-
-
-

This is a slightly more complex command. It goes at the end of your command.py file as before.

-
class CmdEditNPC(Command):
-    """
-    edit an existing NPC
-
-    Usage:
-      +editnpc <name>[/<attribute> [= value]]
-
-    Examples:
-      +editnpc mynpc/power = 5
-      +editnpc mynpc/power    - displays power value
-      +editnpc mynpc          - shows all editable
-                                attributes and values
-
-    This command edits an existing NPC. You must have
-    permission to edit the NPC to use this.
-    """
-    key = "+editnpc"
-    aliases = ["+editNPC"]
-    locks = "cmd:not perm(nonpcs)"
-    help_category = "mush"
-
-    def parse(self):
-        "We need to do some parsing here"
-        args = self.args
-        propname, propval = None, None
-        if "=" in args:
-            args, propval = [part.strip() for part in args.rsplit("=", 1)]
-        if "/" in args:
-            args, propname = [part.strip() for part in args.rsplit("/", 1)]
-        # store, so we can access it below in func()
-        self.name = args
-        self.propname = propname
-        # a propval without a propname is meaningless
-        self.propval = propval if propname else None
-
-    def func(self):
-        "do the editing"
-
-        allowed_propnames = ("power", "attribute1", "attribute2")
-
-        caller = self.caller
-        if not self.args or not self.name:
-            caller.msg("Usage: +editnpc name[/propname][=propval]")
-            return
-        npc = caller.search(self.name)
-        if not npc:
-            return
-        if not npc.access(caller, "edit"):
-            caller.msg("You cannot change this NPC.")
-            return
-        if not self.propname:
-            # this means we just list the values
-            output = f"Properties of {npc.key}:"
-            for propname in allowed_propnames:
-                output += f"\n {propname} = {npc.attributes.get(propname, default='N/A')}"
-            caller.msg(output)
-        elif self.propname not in allowed_propnames:
-            caller.msg(f"You may only change {', '.join(allowed_propnames)}.")
-        elif self.propval:
-            # assigning a new propvalue
-            # in this example, the properties are all integers...
-            intpropval = int(self.propval)
-            npc.attributes.add(self.propname, intpropval)
-            caller.msg(f"Set {npc.key}'s property {self.propname} to {self.propval}")
-        else:
-            # propname set, but not propval - show current value
-            caller.msg(f"{npc.key} has property {self.propname} = {npc.attributes.get(self.propname,
-default='N/A')}")
-
-
-

This command example shows off the use of more advanced parsing but otherwise it’s mostly error -checking. It searches for the given npc in the same room, and checks so the caller actually has -permission to “edit” it before continuing. An account without the proper permission won’t even be -able to view the properties on the given NPC. It’s up to each game if this is the way it should be.

-

Add this to the default command set like before and you should be able to try it out.

-

Note: If you wanted a player to use this command to change an on-object property like the NPC’s -name (the key property), you’d need to modify the command since “key” is not an Attribute (it is -not retrievable via npc.attributes.get but directly via npc.key). We leave this as an optional -exercise.

-
-
-

Making the NPC do stuff - the +npc command

-

Finally, we will make a command to order our NPC around. For now, we will limit this command to only -be usable by those having the “edit” permission on the NPC. This can be changed if it’s possible for -anyone to use the NPC.

-

The NPC, since it inherited our Character typeclass has access to most commands a player does. What -it doesn’t have access to are Session and Player-based cmdsets (which means, among other things that -they cannot chat on channels, but they could do that if you just added those commands). This makes -the +npc command simple:

-
+npc Anna = say Hello!
-Anna says, 'Hello!'
-
-
-

Again, add to the end of your command.py module:

-
class CmdNPC(Command):
-    """
-    controls an NPC
-
-    Usage:
-        +npc <name> = <command>
-
-    This causes the npc to perform a command as itself. It will do so
-    with its own permissions and accesses.
-    """
-    key = "+npc"
-    locks = "call:not perm(nonpcs)"
-    help_category = "mush"
-
-    def parse(self):
-        "Simple split of the = sign"
-        name, cmdname = None, None
-        if "=" in self.args:
-            name, cmdname = self.args.rsplit("=", 1)
-            name = name.strip()
-            cmdname = cmdname.strip()
-        self.name, self.cmdname = name, cmdname
-
-    def func(self):
-        "Run the command"
-        caller = self.caller
-        if not self.cmdname:
-            caller.msg("Usage: +npc <name> = <command>")
-            return
-        npc = caller.search(self.name)
-        if not npc:
-            return
-        if not npc.access(caller, "edit"):
-            caller.msg("You may not order this NPC to do anything.")
-            return
-        # send the command order
-        npc.execute_cmd(self.cmdname)
-        caller.msg(f"You told {npc.key} to do '{self.cmdname}'.")
-
-
-

Note that if you give an erroneous command, you will not see any error message, since that error -will be returned to the npc object, not to you. If you want players to see this, you can give the -caller’s session ID to the execute_cmd call, like this:

-
npc.execute_cmd(self.cmdname, sessid=self.caller.sessid)
-
-
-

Another thing to remember is however that this is a very simplistic way to control NPCs. Evennia -supports full puppeting very easily. An Account (assuming the “puppet” permission was set correctly) -could simply do @ic mynpc and be able to play the game “as” that NPC. This is in fact just what -happens when an Account takes control of their normal Character as well.

-
-
-
-

Concluding remarks

-

This ends the tutorial. It looks like a lot of text but the amount of code you have to write is -actually relatively short. At this point you should have a basic skeleton of a game and a feel for -what is involved in coding your game.

-

From here on you could build a few more ChargenRooms and link that to a bigger grid. The +setpower -command can either be built upon or accompanied by many more to get a more elaborate character -generation.

-

The simple “Power” game mechanic should be easily expandable to something more full-fledged and -useful, same is true for the combat score principle. The +attack could be made to target a -specific player (or npc) and automatically compare their relevant attributes to determine a result.

-

To continue from here, you can take a look at the Tutorial World. For -more specific ideas, see the other tutorials and hints as well -as the Developer Central.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Tutorials.html b/docs/0.9.5/Tutorials.html deleted file mode 100644 index 773e7b3b30..0000000000 --- a/docs/0.9.5/Tutorials.html +++ /dev/null @@ -1,300 +0,0 @@ - - - - - - - - - Tutorials — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - - - -
-
-
-
- -
-

Tutorials

-

Before continuing to read these tutorials (and especially before you start to code or build your -game in earnest) it’s strongly recommended that you read the -Evennia coding introduction as well as the Planning your own game pages first.

-

Please note that it’s not within the scope of our tutorials to teach you basic Python. If you are -new to the language, expect to have to look up concepts you are unfamiliar with. Usually a quick -internet search will give you all info you need. Furthermore, our tutorials tend to focus on -implementation and concepts. As such they give only brief explanations to use Evennia features while -providing ample links to the relevant detailed documentation.

-

The main information resource for builders is the Builder Documentation. Coders -should refer to the Developer Central for further information.

-
-

Building

-

Help with populating your game world.

- -
-
-

General Development tutorials

-

General code practices for newbie game developers.

-

To use Evennia, you will need basic understanding of Python -modules, -variables, conditional statements, -loops, -functions, lists, dictionaries, list comprehensions and string formatting. You should also have a basic -understanding of object-oriented programming and what Python -Classes are.

- -
-
-

Coding - First Step tutorials

-

Starting tutorials for you who are new to developing with Evennia.

- -
-
-

Custom objects and typeclasses

-

Examples of designing new objects for your game world

- -
-
-

Game mechanics tutorials

-

Creating the underlying game mechanics of game play.

- -
-
-

Miscellaneous system tutorials

-

Design various game systems and achieve particular effects.

- -
-
-

Contrib

-

This section contains tutorials linked with contribs. These contribs can be used in your game, but -you’ll need to install them explicitly. They add common features that can earn you time in -implementation.

- -
-
-

Web tutorials

-

Expanding Evennia’s web presence.

- -
-
-

Evennia for [Engine]-Users

-

Hints for new users more familiar with other game engines.

- -
-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Typeclasses.html b/docs/0.9.5/Typeclasses.html deleted file mode 100644 index a96bcd77b3..0000000000 --- a/docs/0.9.5/Typeclasses.html +++ /dev/null @@ -1,440 +0,0 @@ - - - - - - - - - Typeclasses — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Typeclasses

-

Typeclasses form the core of Evennia data storage. It allows Evennia to represent any number of -different game entities as Python classes, without having to modify the database schema for every -new type.

-

In Evennia the most important game entities, Accounts, Objects, -Scripts and Channels are all Python classes inheriting, at -varying distance, from evennia.typeclasses.models.TypedObject. In the documentation we refer to -these objects as being “typeclassed” or even “being a typeclass”.

-

This is how the inheritance looks for the typeclasses in Evennia:

-
                  TypedObject
-      _________________|_________________________________
-     |                 |                 |               |
-1: AccountDB        ObjectDB           ScriptDB         ChannelDB
-     |                 |                 |               |
-2: DefaultAccount   DefaultObject      DefaultScript    DefaultChannel
-     |              DefaultCharacter     |               |
-     |              DefaultRoom          |               |
-     |              DefaultExit          |               |
-     |                 |                 |               |
-3: Account          Object              Script           Channel
-                   Character
-                   Room
-                   Exit
-
-
-
    -
  • Level 1 above is the “database model” level. This describes the database tables and fields -(this is technically a Django model).

  • -
  • Level 2 is where we find Evennia’s default implementations of the various game entities, on -top of the database. These classes define all the hook methods that Evennia calls in various -situations. DefaultObject is a little special since it’s the parent for DefaultCharacter, -DefaultRoom and DefaultExit. They are all grouped under level 2 because they all represents -defaults to build from.

  • -
  • Level 3, finally, holds empty template classes created in your game directory. This is the -level you are meant to modify and tweak as you please, overloading the defaults as befits your game. -The templates inherit directly from their defaults, so Object inherits from DefaultObject and -Room inherits from DefaultRoom.

  • -
-

The typeclass/list command will provide a list of all typeclasses known to -Evennia. This can be useful for getting a feel for what is available. Note -however that if you add a new module with a class in it but do not import that -module from anywhere, the typeclass/list will not find it. To make it known -to Evennia you must import that module from somewhere.

-
-

Difference between typeclasses and classes

-

All Evennia classes inheriting from class in the table above share one important feature and two -important limitations. This is why we don’t simply call them “classes” but “typeclasses”.

-
    -
  1. A typeclass can save itself to the database. This means that some properties (actually not that -many) on the class actually represents database fields and can only hold very specific data types. -This is detailed below.

  2. -
  3. Due to its connection to the database, the typeclass’ name must be unique across the entire -server namespace. That is, there must never be two same-named classes defined anywhere. So the below -code would give an error (since DefaultObject is now globally found both in this module and in the -default library):

    -
    from evennia import DefaultObject as BaseObject
    -class DefaultObject(BaseObject):
    -     pass
    -
    -
    -
  4. -
  5. A typeclass’ __init__ method should normally not be overloaded. This has mostly to do with the -fact that the __init__ method is not called in a predictable way. Instead Evennia suggest you use -the at_*_creation hooks (like at_object_creation for Objects) for setting things the very first -time the typeclass is saved to the database or the at_init hook which is called every time the -object is cached to memory. If you know what you are doing and want to use __init__, it must -both accept arbitrary keyword arguments and use super to call its parent::

    -
    def __init__(self, **kwargs):
    -    # my content
    -    super().__init__(**kwargs)
    -    # my content
    -
    -
    -
  6. -
-

Apart from this, a typeclass works like any normal Python class and you can -treat it as such.

-
-
-

Creating a new typeclass

-

It’s easy to work with Typeclasses. Either you use an existing typeclass or you create a new Python -class inheriting from an existing typeclass. Here is an example of creating a new type of Object:

-
    from evennia import DefaultObject
-
-    class Furniture(DefaultObject):
-        # this defines what 'furniture' is, like
-        # storing who sits on it or something.
-        pass
-
-
-
-

You can now create a new Furniture object in two ways. First (and usually not the most -convenient) way is to create an instance of the class and then save it manually to the database:

-
chair = Furniture(db_key="Chair")
-chair.save()
-
-
-
-

To use this you must give the database field names as keywords to the call. Which are available -depends on the entity you are creating, but all start with db_* in Evennia. This is a method you -may be familiar with if you know Django from before.

-

It is recommended that you instead use the create_* functions to create typeclassed entities:

-
from evennia import create_object
-
-chair = create_object(Furniture, key="Chair")
-# or (if your typeclass is in a module furniture.py)
-chair = create_object("furniture.Furniture", key="Chair")
-
-
-

The create_object (create_account, create_script etc) takes the typeclass as its first -argument; this can both be the actual class or the python path to the typeclass as found under your -game directory. So if your Furniture typeclass sits in mygame/typeclasses/furniture.py, you -could point to it as typeclasses.furniture.Furniture. Since Evennia will itself look in -mygame/typeclasses, you can shorten this even further to just furniture.Furniture. The create- -functions take a lot of extra keywords allowing you to set things like Attributes and -Tags all in one go. These keywords don’t use the db_* prefix. This will also automatically -save the new instance to the database, so you don’t need to call save() explicitly.

-
-

About typeclass properties

-

An example of a database field is db_key. This stores the “name” of the entity you are modifying -and can thus only hold a string. This is one way of making sure to update the db_key:

-
chair.db_key = "Table"
-chair.save()
-
-print(chair.db_key)
-<<< Table
-
-
-

That is, we change the chair object to have the db_key “Table”, then save this to the database. -However, you almost never do things this way; Evennia defines property wrappers for all the database -fields. These are named the same as the field, but without the db_ part:

-
chair.key = "Table"
-
-print(chair.key)
-<<< Table
-
-
-
-

The key wrapper is not only shorter to write, it will make sure to save the field for you, and -does so more efficiently by levering sql update mechanics under the hood. So whereas it is good to -be aware that the field is named db_key you should use key as much as you can.

-

Each typeclass entity has some unique fields relevant to that type. But all also share the -following fields (the wrapper name without db_ is given):

-
    -
  • key (str): The main identifier for the entity, like “Rose”, “myscript” or “Paul”. name is an -alias.

  • -
  • date_created (datetime): Time stamp when this object was created.

  • -
  • typeclass_path (str): A python path pointing to the location of this (type)class

  • -
-

There is one special field that doesn’t use the db_ prefix (it’s defined by Django):

-
    -
  • id (int): the database id (database ref) of the object. This is an ever-increasing, unique -integer. It can also be accessed as dbid (database ID) or pk (primary key). The dbref property -returns the string form “#id”.

  • -
-

The typeclassed entity has several common handlers:

-
    -
  • tags - the TagHandler that handles tagging. Use tags.add() , tags.get() etc.

  • -
  • locks - the LockHandler that manages access restrictions. Use locks.add(), -locks.get() etc.

  • -
  • attributes - the AttributeHandler that manages Attributes on the object. Use -attributes.add() -etc.

  • -
  • db (DataBase) - a shortcut property to the AttributeHandler; allowing obj.db.attrname = value

  • -
  • nattributes - the Non-persistent AttributeHandler for attributes not saved in the -database.

  • -
  • ndb (NotDataBase) - a shortcut property to the Non-peristent AttributeHandler. Allows -obj.ndb.attrname = value

  • -
-

Each of the typeclassed entities then extend this list with their own properties. Go to the -respective pages for Objects, Scripts, Accounts and -Channels for more info. It’s also recommended that you explore the available -entities using Evennia’s flat API to explore which properties and methods they have -available.

-
-
-

Overloading hooks

-

The way to customize typeclasses is usually to overload hook methods on them. Hooks are methods -that Evennia call in various situations. An example is the at_object_creation hook on Objects, -which is only called once, the very first time this object is saved to the database. Other examples -are the at_login hook of Accounts and the at_repeat hook of Scripts.

-
-
-

Querying for typeclasses

-

Most of the time you search for objects in the database by using convenience methods like the -caller.search() of Commands or the search functions like evennia.search_objects.

-

You can however also query for them directly using Django’s query -language. This makes use of a database -manager that sits on all typeclasses, named objects. This manager holds methods that allow -database searches against that particular type of object (this is the way Django normally works -too). When using Django queries, you need to use the full field names (like db_key) to search:

-
matches = Furniture.objects.get(db_key="Chair")
-
-
-
-

It is important that this will only find objects inheriting directly from Furniture in your -database. If there was a subclass of Furniture named Sitables you would not find any chairs -derived from Sitables with this query (this is not a Django feature but special to Evennia). To -find objects from subclasses Evennia instead makes the get_family and filter_family query -methods available:

-
# search for all furnitures and subclasses of furnitures
-# whose names starts with "Chair"
-matches = Furniture.objects.filter_family(db_key__startswith="Chair")
-
-
-
-

To make sure to search, say, all Scripts regardless of typeclass, you need to query from the -database model itself. So for Objects, this would be ObjectDB in the diagram above. Here’s an -example for Scripts:

-
from evennia import ScriptDB
-matches = ScriptDB.objects.filter(db_key__contains="Combat")
-
-
-

When querying from the database model parent you don’t need to use filter_family or get_family - -you will always query all children on the database model.

-
-
-
-

Updating existing typeclass instances

-

If you already have created instances of Typeclasses, you can modify the Python code at any time - -due to how Python inheritance works your changes will automatically be applied to all children once -you have reloaded the server.

-

However, database-saved data, like db_* fields, Attributes, Tags etc, are -not themselves embedded into the class and will not be updated automatically. This you need to -manage yourself, by searching for all relevant objects and updating or adding the data:

-
# add a worth Attribute to all existing Furniture
-for obj in Furniture.objects.all():
-    # this will loop over all Furniture instances
-    obj.db.worth = 100
-
-
-

A common use case is putting all Attributes in the at_*_creation hook of the entity, such as -at_object_creation for Objects. This is called every time an object is created - and only then. -This is usually what you want but it does mean already existing objects won’t get updated if you -change the contents of at_object_creation later. You can fix this in a similar way as above -(manually setting each Attribute) or with something like this:

-
# Re-run at_object_creation only on those objects not having the new Attribute
-for obj in Furniture.objects.all():
-    if not obj.db.worth:
-        obj.at_object_creation()
-
-
-

The above examples can be run in the command prompt created by evennia shell. You could also run -it all in-game using @py. That however requires you to put the code (including imports) as one -single line using ; and list -comprehensions, like this (ignore the -line break, that’s only for readability in the wiki):

-
@py from typeclasses.furniture import Furniture;
-[obj.at_object_creation() for obj in Furniture.objects.all() if not obj.db.worth]
-
-
-

It is recommended that you plan your game properly before starting to build, to avoid having to -retroactively update objects more than necessary.

-
-
-

Swap typeclass

-

If you want to swap an already existing typeclass, there are two ways to do so: From in-game and via -code. From inside the game you can use the default @typeclass command:

-
@typeclass objname = path.to.new.typeclass
-
-
-

There are two important switches to this command:

-
    -
  • /reset - This will purge all existing Attributes on the object and re-run the creation hook -(like at_object_creation for Objects). This assures you get an object which is purely of this new -class.

  • -
  • /force - This is required if you are changing the class to be the same class the object -already has - it’s a safety check to avoid user errors. This is usually used together with /reset -to re-run the creation hook on an existing class.

  • -
-

In code you instead use the swap_typeclass method which you can find on all typeclassed entities:

-
obj_to_change.swap_typeclass(new_typeclass_path, clean_attributes=False,
-                   run_start_hooks="all", no_default=True, clean_cmdsets=False)
-
-
-

The arguments to this method are described in the API docs -here.

-
-
-

How typeclasses actually work

-

This is considered an advanced section.

-

Technically, typeclasses are Django proxy -models. The only database -models that are “real” in the typeclass system (that is, are represented by actual tables in the -database) are AccountDB, ObjectDB, ScriptDB and ChannelDB (there are also -Attributes and Tags but they are not typeclasses themselves). All the -subclasses of them are “proxies”, extending them with Python code without actually modifying the -database layout.

-

Evennia modifies Django’s proxy model in various ways to allow them to work without any boiler plate -(for example you don’t need to set the Django “proxy” property in the model Meta subclass, Evennia -handles this for you using metaclasses). Evennia also makes sure you can query subclasses as well as -patches django to allow multiple inheritance from the same base class.

-
-

Caveats

-

Evennia uses the idmapper to cache its typeclasses (Django proxy models) in memory. The idmapper -allows things like on-object handlers and properties to be stored on typeclass instances and to not -get lost as long as the server is running (they will only be cleared on a Server reload). Django -does not work like this by default; by default every time you search for an object in the database -you’ll get a different instance of that object back and anything you stored on it that was not in -the database would be lost. The bottom line is that Evennia’s Typeclass instances subside in memory -a lot longer than vanilla Django model instance do.

-

There is one caveat to consider with this, and that relates to [making your own models](New- -Models): Foreign relationships to typeclasses are cached by Django and that means that if you were -to change an object in a foreign relationship via some other means than via that relationship, the -object seeing the relationship may not reliably update but will still see its old cached version. -Due to typeclasses staying so long in memory, stale caches of such relationships could be more -visible than common in Django. See the closed issue #1098 and its -comments for examples and solutions.

-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Understanding-Color-Tags.html b/docs/0.9.5/Understanding-Color-Tags.html deleted file mode 100644 index 1d2d373b99..0000000000 --- a/docs/0.9.5/Understanding-Color-Tags.html +++ /dev/null @@ -1,278 +0,0 @@ - - - - - - - - - Understanding Color Tags — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Understanding Color Tags

-

This tutorial aims at dispelling confusions regarding the use of color tags within Evennia.

-

Correct understanding of this topic requires having read the TextTags page and learned -Evennia’s color tags. Here we’ll explain by examples the reasons behind the unexpected (or -apparently incoherent) behaviors of some color tags, as mentioned en passant in the -TextTags page.

-

All you’ll need for this tutorial is access to a running instance of Evennia via a color-enabled -client. The examples provided are just commands that you can type in your client.

-
-
-

Evennia, ANSI and Xterm256

-

All modern MUD clients support colors; nevertheless, the standards to which all clients abide dates -back to old day of terminals, and when it comes to colors we are dealing with ANSI and Xterm256 -standards.

-

Evennia handles transparently, behind the scenes, all the code required to enforce these -standards—so, if a user connects with a client which doesn’t support colors, or supports only ANSI -(16 colors), Evennia will take all due steps to ensure that the output will be adjusted to look -right at the client side.

-

As for you, the developer, all you need to care about is knowing how to correctly use the color tags -within your MUD. Most likely, you’ll be adding colors to help pages, descriptions, automatically -generated text, etc.

-

You are free to mix together ANSI and Xterm256 color tags, but you should be aware of a few -pitfalls. ANSI and Xterm256 coexist without conflicts in Evennia, but in many ways they don’t «see» -each other: ANSI-specific color tags will have no effect on Xterm-defined colors, as we shall see -here.

-
-
-

ANSI

-

ANSI has a set of 16 colors, to be more precise: ANSI has 8 basic colors which come in dark and -bright flavours—with dark being normal. The colors are: red, green, yellow, blue, magenta, -cyan, white and black. White in its dark version is usually referred to as gray, and black in its -bright version as darkgray. Here, for sake of simplicity they’ll be referred to as dark and bright: -bright/dark black, bright/dark white.

-

The default colors of MUD clients is normal (dark) white on normal black (ie: gray on black).

-

It’s important to grasp that in the ANSI standard bright colors apply only to text (foreground), not -to background. Evennia allows to bypass this limitation via Xterm256, but doing so will impact the -behavior of ANSI tags, as we shall see.

-

Also, it’s important to remember that the 16 ANSI colors are a convention, and the final user can -always customize their appearance—he might decide to have green show as red, and dark green as blue, -etc.

-
-
-

Xterm256

-

The 16 colors of ANSI should be more than enough to handle simple coloring of text. But when an -author wants to be sure that a given color will show as he intended it, she might choose to rely on -Xterm256 colors.

-

Xterm256 doesn’t rely on a palette of named colors, it instead represent colors by their values. So, -a red color could be |[500 (bright and pure red), or |[300 (darker red), and so on.

-
-
-

ANSI Color Tags in Evennia

-
-

NOTE: for ease of reading, the examples contain extra white spaces after the -color tags (eg: |g green |b blue ). This is done only so that it’s easier -to see the tags separated from their context; it wouldn’t be good practice -in real-life coding.

-
-

Let’s proceed by examples. In your MUD client type:

-
say Normal |* Negative
-
-
-

Evennia should output the word “Normal” normally (ie: gray on black) and “Negative” in reversed -colors (ie: black on gray).

-

This is pretty straight forward, the |* ANSI invert tag switches between foreground and -background—from now on, FG and BG shorthands will be used to refer to foreground and -background.

-

But take mental note of this: |* has switched dark white and dark black.

-

Now try this:

-
say |w Bright white FG |* Negative
-
-
-

You’ll notice that the word “Negative” is not black on white, it’s darkgray on gray. Why is this? -Shouldn’t it be black text on a white BG? Two things are happening here.

-

As mentioned, ANSI has 8 base colors, the dark ones. The bright ones are achieved by means of -highlighting the base/dark/normal colors, and they only apply to FG.

-

What happened here is that when we set the bright white FG with |w, Evennia translated this into -the ANSI sequence of Highlight On + White FG. In terms of Evennia’s color tags, it’s as if we typed:

-
say |h|!W Bright white FG |* Negative
-
-
-

Furthermore, the Highlight-On property (which only works for BG!) is preserved after the FG/BG -switch, this being the reason why we see black as darkgray: highlighting makes it bright black -(ie: darkgray).

-

As for the BG being also grey, that is normal—ie: you are seeing normal white (ie: dark white = -gray). Remember that since there are no bright BG colors, the ANSI |* tag will transpose any FG -color in its normal/dark version. So here the FG’s bright white became dark white in the BG! In -reality, it was always normal/dark white, except that in the FG is seen as bright because of the -highlight tag behind the scenes.

-

Let’s try the same thing with some color:

-
say |m |[G Bright Magenta on Dark Green |* Negative
-
-
-

Again, the BG stays dark because of ANSI rules, and the FG stays bright because of the implicit |h -in |m.

-

Now, let’s see what happens if we set a bright BG and then invert—yes, Evennia kindly allows us to -do it, even if it’s not within ANSI expectations.

-
say |[b Dark White on Bright Blue |* Negative
-
-
-

Before color inversion, the BG does show in bright blue, and after inversion (as expected) it’s -dark white (gray). The bright blue of the BG survived the inversion and gave us a bright blue FG. -This behavior is tricky though, and not as simple as it might look.

-

If the inversion were to be pure ANSI, the bright blue would have been accounted just as normal -blue, and should have converted to normal blue in the FG (after all, there was no highlighting on). -The fact is that in reality this color is not bright blue at all, it just an Xterm version of it!

-

To demonstrate this, type:

-
say |[b Dark White on Bright Blue |* Negative |H un-bright
-
-
-

The |H Highlight-Off tag should have turned dark blue the last word; but it didn’t because it -couldn’t: in order to enforce the non-ANSI bright BG Evennia turned to Xterm, and Xterm entities are -not affected by ANSI tags!

-

So, we are getting at the heart of all confusions and possible odd-behaviors pertaining color tags -in Evennia: apart from Evennia’s translations from- and to- ANSI/Xterm, the two systems are -independent and transparent to each other.

-

The bright blue of the previous example was just an Xterm representation of the ANSI standard blue. -Try to change the default settings of your client, so that blue shows as some other color, you’ll -then realize the difference when Evennia is sending a true ANSI color (which will show up according -to your settings) and when instead it’s sending an Xterm representation of that color (which will -show up always as defined by Evennia).

-

You’ll have to keep in mind that the presence of an Xterm BG or FG color might affect the way your -tags work on the text. For example:

-
say |[b Bright Blue BG |* Negative |!Y Dark Yellow |h not bright
-
-
-

Here the |h tag no longer affects the FG color. Even though it was changed via the |! tag, the -ANSI system is out-of-tune because of the intrusion of an Xterm color (bright blue BG, then moved to -FG with |*).

-

All unexpected ANSI behaviours are the result of mixing Xterm colors (either on purpose or either -via bright BG colors). The |n tag will restore things in place and ANSI tags will respond properly -again. So, at the end is just an issue of being mindful when using Xterm colors or bright BGs, and -avoid wild mixing them with ANSI tags without normalizing (|n) things again.

-

Try this:

-
say |[b Bright Blue BG |* Negative |!R Red FG
-
-
-

And then:

-
say |[B Dark Blue BG |* Negative |!R Red BG??
-
-
-

In this second example the |! changes the BG color instead of the FG! In fact, the odd behavior is -the one from the former example, non the latter. When you invert FG and BG with |* you actually -inverting their references. This is why the last example (which has a normal/dark BG!) allows |! -to change the BG color. In the first example, it’s again the presence of an Xterm color (bright blue -BG) which changes the default behavior.

-

Try this:

-

say Normal |* Negative |!R Red BG

-

This is the normal behavior, and as you can see it allows |! to change BG color after the -inversion of FG and BG.

-

As long as you have an understanding of how ANSI works, it should be easy to handle color tags -avoiding the pitfalls of Xterm-ANSI promisquity.

-

One last example:

-

say Normal |* Negative |* still Negative

-

Shows that |* only works once in a row and will not (and should not!) revert back if used again. -Nor it will have any effect until the |n tag is called to “reset” ANSI back to normal. This is how -it is meant to work.

-

ANSI operates according to a simple states-based mechanism, and it’s important to understand the -positive effect of resetting with the |n tag, and not try to -push it over the limit, so to speak.

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Unit-Testing.html b/docs/0.9.5/Unit-Testing.html deleted file mode 100644 index 87538121f6..0000000000 --- a/docs/0.9.5/Unit-Testing.html +++ /dev/null @@ -1,536 +0,0 @@ - - - - - - - - - Unit Testing — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Unit Testing

-

Unit testing means testing components of a program in isolation from each other to make sure every -part works on its own before using it with others. Extensive testing helps avoid new updates causing -unexpected side effects as well as alleviates general code rot (a more comprehensive wikipedia -article on unit testing can be found here).

-

A typical unit test set calls some function or method with a given input, looks at the result and -makes sure that this result looks as expected. Rather than having lots of stand-alone test programs, -Evennia makes use of a central test runner. This is a program that gathers all available tests all -over the Evennia source code (called test suites) and runs them all in one go. Errors and -tracebacks are reported.

-

By default Evennia only tests itself. But you can also add your own tests to your game code and have -Evennia run those for you.

-
-

Running the Evennia test suite

-

To run the full Evennia test suite, go to your game folder and issue the command

-
evennia test evennia
-
-
-

This will run all the evennia tests using the default settings. You could also run only a subset of -all tests by specifying a subpackage of the library:

-
evennia test evennia.commands.default
-
-
-

A temporary database will be instantiated to manage the tests. If everything works out you will see -how many tests were run and how long it took. If something went wrong you will get error messages. -If you contribute to Evennia, this is a useful sanity check to see you haven’t introduced an -unexpected bug.

-
-
-

Running tests with custom settings file

-

If you have implemented your own tests for your game (see below) you can run them from your game dir -with

-
evennia test .
-
-
-

The period (.) means to run all tests found in the current directory and all subdirectories. You -could also specify, say, typeclasses or world if you wanted to just run tests in those subdirs.

-

Those tests will all be run using the default settings. To run the tests with your own settings file -you must use the --settings option:

-
evennia test --settings settings.py .
-
-
-

The --settings option of Evennia takes a file name in the mygame/server/conf folder. It is -normally used to swap settings files for testing and development. In combination with test, it -forces Evennia to use this settings file over the default one.

-
-
-

Writing new tests

-

Evennia’s test suite makes use of Django unit test system, which in turn relies on Python’s -unittest module.

-
-

If you want to help out writing unittests for Evennia, take a look at Evennia’s coveralls.io page. There you see which modules have any form of -test coverage and which does not.

-
-

To make the test runner find the tests, they must be put in a module named test*.py (so test.py, -tests.py etc). Such a test module will be found wherever it is in the package. It can be a good -idea to look at some of Evennia’s tests.py modules to see how they look.

-

Inside a testing file, a unittest.TestCase class is used to test a single aspect or component in -various ways. Each test case contains one or more test methods - these define the actual tests to -run. You can name the test methods anything you want as long as the name starts with “test_”. -Your TestCase class can also have a method setUp(self):. This is run before each test, setting -up and storing whatever preparations the test methods need. Conversely, a tearDown(self): method -can optionally do cleanup after each test.

-

To test the results, you use special methods of the TestCase class. Many of those start with -“assert”, such as assertEqual or assertTrue.

-

Example of a TestCase class:

-
    import unittest
-
-    # the function we want to test
-    from mypath import myfunc
-
-    class TestObj(unittest.TestCase):
-       "This tests a function myfunc."
-
-       def test_return_value(self):
-           "test method. Makes sure return value is as expected."
-           expected_return = "This is me being nice."
-           actual_return = myfunc()
-           # test
-           self.assertEqual(expected_return, actual_return)
-       def test_alternative_call(self):
-           "test method. Calls with a keyword argument."
-           expected_return = "This is me being baaaad."
-           actual_return = myfunc(bad=True)
-           # test
-           self.assertEqual(expected_return, actual_return)
-
-
-

You might also want to read the documentation for the unittest module.

-
-

Using the EvenniaTest class

-

Evennia offers a custom TestCase, the evennia.utils.test_resources.EvenniaTest class. This class -initiates a range of useful properties on themselves for testing Evennia systems. Examples are -.account and .session representing a mock connected Account and its Session and .char1 and -.char2 representing Characters complete with a location in the test database. These are all useful -when testing Evennia system requiring any of the default Evennia typeclasses as inputs. See the full -definition of the EvenniaTest class in evennia/utils/test_resources.py.

-
# in a test module
-
-from evennia.utils.test_resources import EvenniaTest
-
-class TestObject(EvenniaTest):
-    def test_object_search(self):
-        # char1 and char2 are both created in room1
-        self.assertEqual(self.char1.search(self.char2.key), self.char2)
-        self.assertEqual(self.char1.search(self.char1.location.key), self.char1.location)
-        # ...
-
-
-
-
-

Testing in-game Commands

-

In-game Commands are a special case. Tests for the default commands are put in -evennia/commands/default/tests.py. This uses a custom CommandTest class that inherits from -evennia.utils.test_resources.EvenniaTest described above. CommandTest supplies extra convenience -functions for executing commands and check that their return values (calls of msg() returns -expected values. It uses Characters and Sessions generated on the EvenniaTest class to call each -class).

-

Each command tested should have its own TestCase class. Inherit this class from the CommandTest -class in the same module to get access to the command-specific utilities mentioned.

-
    from evennia.commands.default.tests import CommandTest
-    from evennia.commands.default import general
-    class TestSet(CommandTest):
-        "tests the look command by simple call, using Char2 as a target"
-        def test_mycmd_char(self):
-            self.call(general.CmdLook(), "Char2", "Char2(#7)")
-        "tests the look command by simple call, with target as room"
-        def test_mycmd_room(self):
-            self.call(general.CmdLook(), "Room",
-                      "Room(#1)\nroom_desc\nExits: out(#3)\n"
-                      "You see: Obj(#4), Obj2(#5), Char2(#7)")
-
-
-
-
-

Unit testing contribs with custom models

-

A special case is if you were to create a contribution to go to the evennia/contrib folder that -uses its own database models. The problem with this is that Evennia (and Django) will -only recognize models in settings.INSTALLED_APPS. If a user wants to use your contrib, they will -be required to add your models to their settings file. But since contribs are optional you cannot -add the model to Evennia’s central settings_default.py file - this would always create your -optional models regardless of if the user wants them. But at the same time a contribution is a part -of the Evennia distribution and its unit tests should be run with all other Evennia tests using -evennia test evennia.

-

The way to do this is to only temporarily add your models to the INSTALLED_APPS directory when the -test runs. here is an example of how to do it.

-
-

Note that this solution, derived from this stackexchange answer is currently untested! Please report your findings.

-
-
# a file contrib/mycontrib/tests.py
-
-from django.conf import settings
-import django
-from evennia.utils.test_resources import EvenniaTest
-
-OLD_DEFAULT_SETTINGS = settings.INSTALLED_APPS
-DEFAULT_SETTINGS = dict(
-    INSTALLED_APPS=(
-        'contrib.mycontrib.tests',
-        ),
-    DATABASES={
-        "default": {
-            "ENGINE": "django.db.backends.sqlite3"
-            }
-        },
-    SILENCED_SYSTEM_CHECKS=["1_7.W001"],
-    )
-
-class TestMyModel(EvenniaTest):
-    def setUp(self):
-
-        if not settings.configured:
-           settings.configure(**DEFAULT_SETTINGS)
-        django.setup()
-
-        from django.core.management import call_command
-        from django.db.models import loading
-        loading.cache.loaded = False
-        call_command('syncdb', verbosity=0)
-
-    def tearDown(self):
-        settings.configure(**OLD_DEFAULT_SETTINGS)
-        django.setup()
-
-        from django.core.management import call_command
-        from django.db.models import loading
-        loading.cache.loaded = False
-        call_command('syncdb', verbosity=0)
-
-    # test cases below ...
-
-    def test_case(self):
-        # test case here
-
-
-
-
-

A note on adding new tests

-

Having an extensive tests suite is very important for avoiding code degradation as Evennia is -developed. Only a small fraction of the Evennia codebase is covered by test suites at this point. -Writing new tests is not hard, it’s more a matter of finding the time to do so. So adding new tests -is really an area where everyone can contribute, also with only limited Python skills.

-
-
-

A note on making the test runner faster

-

If you have custom models with a large number of migrations, creating the test database can take a -very long time. If you don’t require migrations to run for your tests, you can disable them with the -django-test-without-migrations package. To install it, simply:

-
$ pip install django-test-without-migrations
-
-
-

Then add it to your INSTALLED_APPS in your server.conf.settings.py:

-
INSTALLED_APPS = (
-    # ...
-    'test_without_migrations',
-)
-
-
-

After doing so, you can then run tests without migrations by adding the --nomigrations argument:

-
evennia test --settings settings.py --nomigrations .
-
-
-
-
-
-

Testing for Game development (mini-tutorial)

-

Unit testing can be of paramount importance to game developers. When starting with a new game, it is -recommended to look into unit testing as soon as possible; an already huge game is much harder to -write tests for. The benefits of testing a game aren’t different from the ones regarding library -testing. For example it is easy to introduce bugs that affect previously working code. Testing is -there to ensure your project behaves the way it should and continue to do so.

-

If you have never used unit testing (with Python or another language), you might want to check the -official Python documentation about unit testing, -particularly the first section dedicated to a basic example.

-
-

Basic testing using Evennia

-

Evennia’s test runner can be used to launch tests in your game directory (let’s call it ‘mygame’). -Evennia’s test runner does a few useful things beyond the normal Python unittest module:

-
    -
  • It creates and sets up an empty database, with some useful objects (accounts, characters and -rooms, among others).

  • -
  • It provides simple ways to test commands, which can be somewhat tricky at times, if not tested -properly.

  • -
-

Therefore, you should use the command-line to execute the test runner, while specifying your own -game directories (not the one containing evennia). Go to your game directory (referred as ‘mygame’ -in this section) and execute the test runner:

-
evennia test --settings settings.py commands
-
-
-

This command will execute Evennia’s test runner using your own settings file. It will set up a dummy -database of your choice and look into the ‘commands’ package defined in your game directory -(mygame/commands in this example) to find tests. The test module’s name should begin with ‘test’ -and contain one or more TestCase. A full example can be found below.

-
-
-

A simple example

-

In your game directory, go to commands and create a new file tests.py inside (it could be named -anything starting with test). We will start by making a test that has nothing to do with Commands, -just to show how unit testing works:

-
    # mygame/commands/tests.py
-
-    import unittest
-
-    class TestString(unittest.TestCase):
-
-        """Unittest for strings (just a basic example)."""
-
-        def test_upper(self):
-            """Test the upper() str method."""
-            self.assertEqual('foo'.upper(), 'FOO')
-
-
-

This example, inspired from the Python documentation, is used to test the ‘upper()’ method of the -‘str’ class. Not very useful, but it should give you a basic idea of how tests are used.

-

Let’s execute that test to see if it works.

-
> evennia test --settings settings.py commands
-
-TESTING: Using specified settings file 'server.conf.settings'.
-
-(Obs: Evennia's full test suite may not pass if the settings are very
-different from the default. Use 'test .' as arguments to run only tests
-on the game dir.)
-
-Creating test database for alias 'default'...
-.
-----------------------------------------------------------------------
-Ran 1 test in 0.001s
-
-OK
-Destroying test database for alias 'default'...
-
-
-

We specified the commands package to the evennia test command since that’s where we put our test -file. In this case we could just as well just said . to search all of mygame for testing files. -If we have a lot of tests it may be useful to test only a single set at a time though. We get an -information text telling us we are using our custom settings file (instead of Evennia’s default -file) and then the test runs. The test passes! Change the “FOO” string to something else in the test -to see how it looks when it fails.

-
-
-

Testing commands

-

This section will test the proper execution of the ‘abilities’ command, as described in the -First Steps Coding page. Follow this tutorial to create the ‘abilities’ command, we -will need it to test it.

-

Testing commands in Evennia is a bit more complex than the simple testing example we have seen. -Luckily, Evennia supplies a special test class to do just that … we just need to inherit from it -and use it properly. This class is called ‘CommandTest’ and is defined in the -‘evennia.commands.default.tests’ package. To create a test for our ‘abilities’ command, we just -need to create a class that inherits from ‘CommandTest’ and add methods.

-

We could create a new test file for this but for now we just append to the tests.py file we -already have in commands from before.

-
    # bottom of mygame/commands/tests.py
-
-    from evennia.commands.default.tests import CommandTest
-
-    from commands.command import CmdAbilities
-    from typeclasses.characters import Character
-
-    class TestAbilities(CommandTest):
-
-        character_typeclass = Character
-
-        def test_simple(self):
-            self.call(CmdAbilities(), "", "STR: 5, AGI: 4, MAG: 2")
-
-
-
    -
  • Line 1-4: we do some importing. ‘CommandTest’ is going to be our base class for our test, so we -need it. We also import our command (‘CmdAbilities’ in this case). Finally we import the -‘Character’ typeclass. We need it, since ‘CommandTest’ doesn’t use ‘Character’, but -‘DefaultCharacter’, which means the character calling the command won’t have the abilities we have -written in the ‘Character’ typeclass.

  • -
  • Line 6-8: that’s the body of our test. Here, a single command is tested in an entire class. -Default commands are usually grouped by category in a single class. There is no rule, as long as -you know where you put your tests. Note that we set the ‘character_typeclass’ class attribute to -Character. As explained above, if you didn’t do that, the system would create a ‘DefaultCharacter’ -object, not a ‘Character’. You can try to remove line 4 and 8 to see what happens when running the -test.

  • -
  • Line 10-11: our unique testing method. Note its name: it should begin by ‘test_’. Apart from -that, the method is quite simple: it’s an instance method (so it takes the ‘self’ argument) but no -other arguments are needed. Line 11 uses the ‘call’ method, which is defined in ‘CommandTest’. -It’s a useful method that compares a command against an expected result. It would be like comparing -two strings with ‘assertEqual’, but the ‘call’ method does more things, including testing the -command in a realistic way (calling its hooks in the right order, so you don’t have to worry about -that).

  • -
-

Line 11 can be understood as: test the ‘abilities’ command (first parameter), with no argument -(second parameter), and check that the character using it receives his/her abilities (third -parameter).

-

Let’s run our new test:

-
> evennia test --settings settings.py commands
-[...]
-Creating test database for alias 'default'...
-..
-----------------------------------------------------------------------
-Ran 2 tests in 0.156s
-
-OK
-Destroying test database for alias 'default'...
-
-
-

Two tests were executed, since we have kept ‘TestString’ from last time. In case of failure, you -will get much more information to help you fix the bug.

-
-
-

Testing Dynamic Output

-

Having read the unit test tutorial on Testing commands we can see -the code expects static unchanging numbers. While very good for learning it is unlikely a project -will have nothing but static output to test. Here we are going to learn how to test against dynamic -output.

-

This tutorial assumes you have a basic understanding of what regular expressions are. If you do not -I recommend reading the Introduction and Simple Pattern sections at -Python regular expressions tutorial. If you do plan on making a complete Evennia -project learning regular expressions will save a great deal of time.

-

Append the code below to your tests.py file.

-
    # bottom of mygame/commands/tests.py
-
-    class TestDynamicAbilities(CommandTest):
-
-        character_typeclass = Character
-
-        def test_simple(self):
-            cmd_abil_result = self.call(CmdAbilities(), "")
-            self.assertRegex(cmd_abil_result, "STR: \d+, AGI: \d+, MAG: \d+")
-
-
-

Noticed that we removed the test string from self.call. That method always returns the string it -found from the commands output. If we remove the string to test against, all self.call will do is -return the screen output from the command object passed to it.

-

We are instead using the next line to test our command’s output. -assertRegex is a -method of unittest.TestCase this is inherited to TestDynamicAbilities from CommandTest who -inherited it from EvenniaTest.

-

What we are doing is testing the result of the CmdAbilities method or command against a regular -expression pattern. In this case, "STR: \d+, AGI: \d+, MAG: \d+". \d in regular expressions or -regex are digits (numbers), the + is to state we want 1 or more of that pattern. Together \d+ is -telling assertRegex -that in that position of the string we expect 1 or more digits (numbers) to appear in the -string.

-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Updating-Your-Game.html b/docs/0.9.5/Updating-Your-Game.html deleted file mode 100644 index 8f348f67a8..0000000000 --- a/docs/0.9.5/Updating-Your-Game.html +++ /dev/null @@ -1,246 +0,0 @@ - - - - - - - - - Updating Your Game — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Updating Your Game

-

Fortunately, it’s extremely easy to keep your Evennia server up-to-date. If you haven’t already, see -the Getting Started guide and get everything running.

-
-

Updating with the latest Evennia code changes

-

Very commonly we make changes to the Evennia code to improve things. There are many ways to get told -when to update: You can subscribe to the RSS feed or manually check up on the feeds from -http://www.evennia.com. You can also simply fetch the latest regularly.

-

When you’re wanting to apply updates, simply cd to your cloned evennia root directory and type:

-
 git pull
-
-
-

assuming you’ve got the command line client. If you’re using a graphical client, you will probably -want to navigate to the evennia directory and either right click and find your client’s pull -function, or use one of the menus (if applicable).

-

You can review the latest changes with

-
 git log
-
-
-

or the equivalent in the graphical client. You can also see the latest changes online -here.

-

You will always need to do evennia reload (or reload from -in-game) from your game-dir to have -the new code affect your game. If you want to be really sure you should run a full evennia reboot -so that both Server and Portal can restart (this will disconnect everyone though, so if you know the -Portal has had no updates you don’t have to do that).

-
-
-

Upgrading Evennia dependencies

-

On occasion we update the versions of third-party libraries Evennia depend on (or we may add a new -dependency). This will be announced on the mailing list/forum. If you run into errors when starting -Evennia, always make sure you have the latest versions of everything. In some cases, like for -Django, starting the server may also give warning saying that you are using a working, but too-old -version that should not be used in production.

-

Upgrading evennia will automatically fetch all the latest packages that it now need. First cd to -your cloned evennia folder. Make sure your virtualenv is active and use

-
pip install --upgrade -e .
-
-
-

Remember the period (.) at the end - that applies the upgrade to the current location (your -evennia dir).

-
-

The -e means that we are linking the evennia sources rather than copying them into the -environment. This means we can most of the time just update the sources (with git pull) and see -those changes directly applied to our installed evennia package. Without installing/upgrading the -package with -e, we would have to remember to upgrade the package every time we downloaded any new -source-code changes.

-
-

Follow the upgrade output to make sure it finishes without errors. To check what packages are -currently available in your python environment after the upgrade, use

-
pip list
-
-
-

This will show you the version of all installed packages. The evennia package will also show the -location of its source code.

-
-
-

Migrating the Database Schema

-

Whenever we change the database layout of Evennia upstream (such as when we add new features) you -will need to migrate your existing database. When this happens it will be clearly noted in the -git log (it will say something to the effect of “Run migrations”). Database changes will also be -announced on the Evennia mailing list.

-

When the database schema changes, you just go to your game folder and run

-
 evennia migrate
-
-
-
-

Hint: If the evennia command is not found, you most likely need to activate your -virtualenv.

-
-
-
-

Resetting your database

-

Should you ever want to start over completely from scratch, there is no need to re-download Evennia -or anything like that. You just need to clear your database. Once you are done, you just rebuild it -from scratch as described in the second step of the Getting Started guide.

-

First stop a running server with

-
evennia stop
-
-
-

If you run the default SQlite3 database (to change this you need to edit your settings.py file), -the database is actually just a normal file in mygame/server/ called evennia.db3. Simply delete -that file - that’s it. Now run evennia migrate to recreate a new, fresh one.

-

If you run some other database system you can instead flush the database:

-
evennia flush
-
-
-

This will empty the database. However, it will not reset the internal counters of the database, so -you will start with higher dbref values. If this is okay, this is all you need.

-

Django also offers an easy way to start the database’s own management should we want more direct -control:

-
 evennia dbshell
-
-
-

In e.g. MySQL you can then do something like this (assuming your MySQL database is named “Evennia”:

-
mysql> DROP DATABASE Evennia;
-mysql> exit
-
-
-
-

NOTE: Under Windows OS, in order to access SQLite dbshell you need to download the SQLite -command-line shell program. It’s a single executable file -(sqlite3.exe) that you should place in the root of either your MUD folder or Evennia’s (it’s the -same, in both cases Django will find it).

-
-
-
-

More about schema migrations

-

If and when an Evennia update modifies the database schema (that is, the under-the-hood details as -to how data is stored in the database), you must update your existing database correspondingly to -match the change. If you don’t, the updated Evennia will complain that it cannot read the database -properly. Whereas schema changes should become more and more rare as Evennia matures, it may still -happen from time to time.

-

One way one could handle this is to apply the changes manually to your database using the database’s -command line. This often means adding/removing new tables or fields as well as possibly convert -existing data to match what the new Evennia version expects. It should be quite obvious that this -quickly becomes cumbersome and error-prone. If your database doesn’t contain anything critical yet -it’s probably easiest to simply reset it and start over rather than to bother converting.

-

Enter migrations. Migrations keeps track of changes in the database schema and applies them -automatically for you. Basically, whenever the schema changes we distribute small files called -“migrations” with the source. Those tell the system exactly how to implement the change so you don’t -have to do so manually. When a migration has been added we will tell you so on Evennia’s mailing -lists and in commit messages - -you then just run evennia migrate to be up-to-date again.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Using-MUX-as-a-Standard.html b/docs/0.9.5/Using-MUX-as-a-Standard.html deleted file mode 100644 index 939d84981c..0000000000 --- a/docs/0.9.5/Using-MUX-as-a-Standard.html +++ /dev/null @@ -1,195 +0,0 @@ - - - - - - - - - Using MUX as a Standard — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Using MUX as a Standard

-

Evennia allows for any command syntax. If you like the way DikuMUDs, LPMuds or MOOs handle things, -you could emulate that with Evennia. If you are ambitious you could even design a whole new style, -perfectly fitting your own dreams of the ideal game.

-

We do offer a default however. The default Evennia setup tends to resemble -MUX2, and its cousins PennMUSH, -TinyMUSH, and RhostMUSH. While the -reason for this similarity is partly historical, these codebases offer very mature feature sets for -administration and building.

-

Evennia is not a MUX system though. It works very differently in many ways. For example, Evennia -deliberately lacks an online softcode language (a policy explained on our softcode policy -page). Evennia also does not shy from using its own syntax when deemed appropriate: the -MUX syntax has grown organically over a long time and is, frankly, rather arcane in places. All in -all the default command syntax should at most be referred to as “MUX-like” or “MUX-inspired”.

-
-

Documentation policy

-

All the commands in the default command sets should have their doc-strings formatted on a similar -form:

-
      """
-      Short header
-    
-      Usage:
-        key[/switches, if any] <mandatory args> [optional] choice1||choice2||choice3
-    
-      Switches:
-        switch1    - description
-        switch2    - description
-    
-      Examples:
-        usage example and output
-    
-      Longer documentation detailing the command.
-    
-      """
-
-
-
    -
  • Two spaces are used for indentation in all default commands.

  • -
  • Square brackets [ ] surround optional, skippable arguments.

  • -
  • Angled brackets < > surround a description of what to write rather than the exact syntax.

  • -
  • *Explicit choices are separated by |. To avoid this being parsed as a color code, use || (this -will come out as a single |) or put spaces around the character (“|”) if there’s plenty of -room.

  • -
  • The Switches and Examples blocks are optional based on the Command.

  • -
-

Here is the nick command as an example:

-
      """
-      Define a personal alias/nick
-    
-      Usage:
-        nick[/switches] <nickname> = [<string>]
-        alias             ''
-    
-      Switches:
-        object   - alias an object
-        account   - alias an account
-        clearall - clear all your aliases
-        list     - show all defined aliases (also "nicks" works)
-    
-      Examples:
-        nick hi = say Hello, I'm Sarah!
-        nick/object tom = the tall man
-    
-      A 'nick' is a personal shortcut you create for your own use [...]
-    
-        """
-
-
-

For commands that require arguments, the policy is for it to return a Usage: string if the -command is entered without any arguments. So for such commands, the Command body should contain -something to the effect of

-
      if not self.args:
-          self.caller.msg("Usage: nick[/switches] <nickname> = [<string>]")
-          return
-
-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Using-Travis.html b/docs/0.9.5/Using-Travis.html deleted file mode 100644 index 8d24901db4..0000000000 --- a/docs/0.9.5/Using-Travis.html +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - - - - Using Travis — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Using Travis

-

Evennia uses Travis CI to check that it’s building successfully after every -commit to its Github repository (you can for example see the build: passing badge at the top of -Evennia’s Readme file). If your game is open source on Github -you may use Travis for free. See the Travis docs -for how to get started.

-

After logging in you need to point Travis to your repository on github. One further thing you need -to set up yourself is a Travis config file named .travis.yml (note the initial period .). This -should be created in the root of your game directory.

-
dist: xenial
-language: python
-cache: pip
-
-python:
-  - "3.7"
-  - "3.8"
-
-install:
-  - git clone https://github.com/evennia/evennia.git ../evennia
-  - pip install -e ../evennia
-
-script:
-  - evennia test --settings settings.py
-  
-
-
-

Here we tell Travis how to download and install Evennia into a folder a level up from your game dir. -It will then install the server (so the evennia command is available) and run the tests only for -your game dir (based on your settings.py file in server/conf/).

-

Running this will not actually do anything though, because there are no unit tests in your game dir -yet. We have a page on how we set those up for Evennia, you should be able to refer -to that for making tests fitting your game.

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Version-Control.html b/docs/0.9.5/Version-Control.html deleted file mode 100644 index d53b238702..0000000000 --- a/docs/0.9.5/Version-Control.html +++ /dev/null @@ -1,568 +0,0 @@ - - - - - - - - - Version Control — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Version Control

-

Version control software allows you to track the changes you make to your code, as well as being -able to easily backtrack these changes, share your development efforts and more. Even if you are not -contributing to Evennia itself, and only wish to develop your own MU* using Evennia, having a -version control system in place is a good idea (and standard coding practice). For an introduction -to the concept, start with the Wikipedia article -here. Evennia uses the version control system -Git and this is what will be covered henceforth. Note that this page also -deals with commands for Linux operating systems, and the steps below may vary for other systems, -however where possible links will be provided for alternative instructions.

-

For more help on using Git, please refer to the Official GitHub -documentation.

-
-

Setting up Git

-

If you have gotten Evennia installed, you will have Git already and can skip to Step 2 below. -Otherwise you will need to install Git on your platform. You can find expanded instructions for -installation here.

-
-

Step 1: Install Git

-
    -
  • Fedora Linux

    -
      yum install git-core
    -
    -
    -
  • -
  • Debian Linux (Ubuntu, Linux Mint, etc.)

    -
      apt-get install git
    -
    -
    -
  • -
  • Windows: It is recommended to use Git for Windows.

  • -
  • Mac: Mac platforms offer two methods for installation, one via MacPorts, which you can find -out about here, or -you can use the Git OSX Installer.

  • -
-
-
-

Step 2: Define user/e-mail Settings for Git

-

To avoid a common issue later, you will need to set a couple of settings; first you will need to -tell Git your username, followed by your e-mail address, so that when you commit code later you will -be properly credited.

-
-

Note that your commit information will be visible to everyone if you ever contribute to Evennia or -use an online service like github to host your code. So if you are not comfortable with using your -real, full name online, put a nickname here.

-
-
    -
  1. Set the default name for git to use when you commit:

    -
     git config --global user.name "Your Name Here"
    -
    -
    -
  2. -
  3. Set the default email for git to use when you commit:

    -
     git config --global user.email "your_email@example.com"
    -
    -
    -
  4. -
-
-
-
-

Putting your game folder under version control

-
-

Note: The game folder’s version control is completely separate from Evennia’s repository.

-
-

After you have set up your game you will have created a new folder to host your particular game -(let’s call this folder mygame for now).

-

This folder is not under version control at this point.

-
git init mygame
-
-
-

Your mygame folder is now ready for version control! Now add all the content and make a first -commit:

-
cd mygame
-git add *
-git commit -m "Initial commit"
-
-
-

Read on for help on what these commands do.

-
-

Tracking files

-

When working on your code or fix bugs in your local branches you may end up creating new files. If -you do you must tell Git to track them by using the add command:

-
git add <filename>
-
-
-

You can check the current status of version control with git status. This will show if you have -any modified, added or otherwise changed files. Some files, like database files, logs and temporary -PID files are usually not tracked in version control. These should either not show up or have a -question mark in front of them.

-
-
-

Controlling tracking

-

You will notice that some files are not covered by your git version control, notably your settings -file (mygame/server/conf/settings.py) and your sqlite3 database file mygame/server/evennia.db3. -This is controlled by the hidden file mygame/.gitignore. Evennia creates this file as part of the -creation of your game directory. Everything matched in this file will be ignored by GIT. If you want -to, for example, include your settings file for collaborators to access, remove that entry in -.gitignore.

-
-

Note: You should never put your sqlite3 database file into git by removing its entry in -.gitignore. GIT is for backing up your code, not your database. That way lies madness and a good -chance you’ll confuse yourself so that after a few commits and reverts don’t know what is in your -database or not. If you want to backup your database, do so by simply copying the file on your hard -drive to a backup-name.

-
-
-
-

Committing your Code

-
-

Committing means storing the current snapshot of your code within git. This creates a “save point” -or “history” of your development process. You can later jump back and forth in your history, for -example to figure out just when a bug was introduced or see what results the code used to produce -compared to now.

-
-

It’s usually a good idea to commit your changes often. Committing is fast and local only - you will -never commit anything online at this point. To commit your changes, use

-
git commit --all
-
-
-

This will save all changes you made since last commit. The command will open a text editor where you -can add a message detailing the changes you’ve made. Make it brief but informative. You can see the -history of commits with git log. If you don’t want to use the editor you can set the message -directly by using the -m flag:

-
git commit --all -m "This fixes a bug in the combat code."
-
-
-
-
-

Changing your mind

-

If you have non-committed changes that you realize you want to throw away, you can do the following:

-
git checkout <file to revert>
-
-
-

This will revert the file to the state it was in at your last commit, throwing away the changes -you did to it since. It’s a good way to make wild experiments without having to remember just what -you changed. If you do git checkout . you will throw away all changes since the last commit.

-
-
-

Pushing your code online

-

So far your code is only located on your private machine. A good idea is to back it up online. The -easiest way to do this is to push it to your own remote repository on GitHub.

-
    -
  1. Make sure you have your game directory setup under git version control as described above. Make -sure to commit any changes.

  2. -
  3. Create a new, empty repository on Github. Github explains how -here (do not “Initialize the repository with a -README” or else you’ll create unrelated histories).

  4. -
  5. From your local game dir, do git remote add origin <github URL> where <github URL> is the URL -to your online repo. This tells your game dir that it should be pushing to the remote online dir.

  6. -
  7. git remote -v to verify the online dir.

  8. -
  9. git push origin master now pushes your game dir online so you can see it on github.com.

  10. -
-

You can commit your work locally (git commit --all -m "Make a change that ...") as many times as -you want. When you want to push those changes to your online repo, you do git push. You can also -git clone <url_to_online_repo> from your online repo to somewhere else (like your production -server) and henceforth do git pull to update that to the latest thing you pushed.

-

Note that GitHub’s repos are, by default publicly visible by all. Creating a publicly visible online -clone might not be what you want for all parts of your development process - you may prefer a more -private venue when sharing your revolutionary work with your team. If that’s the case you can change -your repository to “Private” in the github settings. Then your code will only be visible to those -you specifically grant access.

-
-
-
-

Forking Evennia

-

This helps you set up an online fork of Evennia so you can easily commit fixes and help with -upstream development.

-
-

Step 1: Fork the evennia/master repository

-
-

Before proceeding with the following step, make sure you have registered and created an account on -GitHub.com. This is necessary in order to create a fork of Evennia’s master -repository, and to push your commits to your fork either for yourself or for contributing to -Evennia.

-
-

A fork is a clone of the master repository that you can make your own commits and changes to. At -the top of this page, click the “Fork” button, as it appears -below.

-
-
-

Step 2: Clone your fork

-

The fork only exists online as of yet. In a terminal, change your directory to the folder you wish -to develop in. From this directory run the following command:

-
git clone https://github.com/yourusername/evennia.git
-
-
-

This will download your fork to your computer. It creates a new folder evennia/ at your current -location.

-
-
-

Step 3: Configure remotes

-

A remote is a repository stored on another computer, in this case on GitHub’s server. When a -repository is cloned, it has a default remote called origin. This points to your fork on GitHub, -not the original repository it was forked from. To easily keep track of the original repository -(that is, Evennia’s official repository), you need to add another remote. The standard name for this -remote is “upstream”.

-

Below we change the active directory to the newly cloned “evennia” directory and then assign the -original Evennia repository to a remote called “upstream”:

-
cd evennia
-git remote add upstream https://github.com/evennia/evennia.git
-
-
-

If you also want to access Evennia’s develop branch (the bleeding edge development branch) do the -following:

-
git fetch upstream develop
-git checkout develop
-
-
-

You should now have the upstream branch available locally. You can use this instead of master -below if you are contributing new features rather than bug fixes.

-
-
-
-

Working with your fork

-
-

A branch is a separate instance of your code. Changes you do to code in a branch does not affect -that in other branches (so if you for example add/commit a file to one branch and then switches to -another branch, that file will be gone until you switch back to the first branch again). One can -switch between branches at will and create as many branches as one needs for a given project. The -content of branches can also be merged together or deleted without affecting other branches. This is -not only a common way to organize development but also to test features without messing with -existing code.

-
-

The default branch of git is called the “master” branch. As a rule of thumb, you should never -make modifications directly to your local copy of the master branch. Rather keep the master clean -and only update it by pulling our latest changes to it. Any work you do should instead happen in a -local, other branches.

-
-

Making a work branch

-
git checkout -b myfixes
-
-
-

This command will checkout and automatically create the new branch myfixes on your machine. If you -stared out in the master branch, myfixes will be a perfect copy of the master branch. You can see -which branch you are on with git branch and change between different branches with git checkout <branchname>.

-

Branches are fast and cheap to create and manage. It is common practice to create a new branch for -every bug you want to work on or feature you want to create, then create a pull request for that -branch to be merged upstream (see below). Not only will this organize your work, it will also make -sure that your master branch version of Evennia is always exactly in sync with the upstream -version’s master branch.

-
-
-

Updating with upstream changes

-

When Evennia’s official repository updates, first make sure to commit all your changes to your -branch and then checkout the “clean” master branch:

-
git commit --all
-git checkout master
-
-
-

Pull the latest changes from upstream:

-
git pull upstream master
-
-
-

This should sync your local master branch with upstream Evennia’s master branch. Now we go back to -our own work-branch (let’s say it’s still called “myfixes”) and merge the updated master into our -branch.

-
git checkout myfixes
-git merge master
-
-
-

If everything went well, your myfixes branch will now have the latest version of Evennia merged -with whatever changes you have done. Use git log to see what has changed. You may need to restart -the server or run manage.py migrate if the database schema changed (this will be seen in the -commit log and on the mailing list). See the Git manuals for -learning more about useful day-to-day commands, and special situations such as dealing with merge -collisions.

-
-
-
-

Sharing your Code Publicly

-

Up to this point your myfixes branch only exists on your local computer. No one else can see it. -If you want a copy of this branch to also appear in your online fork on GitHub, make sure to have -checked out your “myfixes” branch and then run the following:

-
git push -u origin myfixes
-
-
-

This will create a new remote branch named “myfixes” in your online repository (which is refered -to as “origin” by default); the -u flag makes sure to set this to the default push location. -Henceforth you can just use git push from your myfixes branch to push your changes online. This is -a great way to keep your source backed-up and accessible. Remember though that by default your -repository will be public so everyone will be able to browse and download your code (same way as you -can with Evennia itself). If you want secrecy you can change your repository to “Private” in the -Github settings. Note though that if you do, you might have trouble contributing to Evennia (since -we can’t see the code you want to share).

-

Note: If you hadn’t setup a public key on GitHub or aren’t asked for a username/password, you might -get an error 403: Forbidden Access at this stage. In that case, some users have reported that the -workaround is to create a file .netrc under your home directory and add your credentials there:

-
machine github.com
-login <my_github_username>
-password <my_github_password>
-
-
-
-
-

Committing fixes to Evennia

-

Contributing can mean both bug-fixes or adding new features to Evennia. Please note that if your -change is not already listed and accepted in the Issue -Tracker, it is recommended that you first hit the -developer mailing list or IRC chat to see beforehand if your feature is deemed suitable to include -as a core feature in the engine. When it comes to bug-fixes, other developers may also have good -input on how to go about resolving the issue.

-

To contribute you need to have forked Evennia first. As described -above you should do your modification in a separate local branch (not in the master branch). This -branch is what you then present to us (as a Pull request, PR, see below). We can then merge your -change into the upstream master and you then do git pull to update master usual. Now that the -master is updated with your fixes, you can safely delete your local work branch. Below we describe -this work flow.

-

First update the Evennia master branch to the latest Evennia version:

-
git checkout master
-git pull upstream master
-
-
-

Next, create a new branch to hold your contribution. Let’s call it the “fixing_strange_bug” branch:

-
git checkout -b fixing_strange_bug
-
-
-

It is wise to make separate branches for every fix or series of fixes you want to contribute. You -are now in your new fixing_strange_bug branch. You can list all branches with git branch and -jump between branches with git checkout <branchname>. Code and test things in here, committing as -you go:

-
git commit --all -m "Fix strange bug in look command. Resolves #123."
-
-
-

You can make multiple commits if you want, depending on your work flow and progress. Make sure to -always make clear and descriptive commit messages so it’s easy to see what you intended. To refer -to, say, issue number 123, write #123, it will turn to a link on GitHub. If you include the text -“Resolves #123”, that issue will be auto-closed on GitHub if your commit gets merged into main -Evennia.

-
-

If you refer to in-game commands that start with @(such as @examine), please put them in -backticks `, for example `@examine`. The reason for this is that GitHub uses @username to refer -to GitHub users, so if you forget the ticks, any user happening to be named examine will get a -notification …

-
-

If you implement multiple separate features/bug-fixes, split them into different branches if they -are very different and should be handled as separate PRs. You can do any number of commits to your -branch as you work. Once you are at a stage where you want to show the world what you did you might -want to consider making it clean for merging into Evennia’s master branch by using git -rebase (this is not always necessary, -and if it sounds too hard, say so and we’ll handle it on our end).

-

Once you are ready, push your work to your online Evennia fork on github, in a new remote branch:

-
git push -u origin fixing_strange_bug
-
-
-

The -u flag is only needed the first time - this tells GIT to create a remote branch. If you -already created the remote branch earlier, just stand in your fixing_strange_bug branch and do -git push.

-

Now you should tell the Evennia developers that they should consider merging your brilliant changes -into Evennia proper. Create a pull request and follow -the instructions. Make sure to specifically select your fixing_strange_bug branch to be the source -of the merge. Evennia developers will then be able to examine your request and merge it if it’s -deemed suitable.

-

Once your changes have been merged into Evennia your local fixing_strange_bug can be deleted -(since your changes are now available in the “clean” Evennia repository). Do

-
git branch -D fixing_strange_bug
-
-
-

to delete your work branch. Update your master branch (checkout master and then git pull) and -you should get your fix back, now as a part of official Evennia!

-
-
-

GIT tips and tricks

-

Some of the GIT commands can feel a little long and clunky if you need to do them often. Luckily you -can create aliases for those. Here are some useful commands to run:

-
# git st
-# - view brief status info
-git config --global alias.st 'status -s'
-
-
-

Above, you only need to ever enter the git config ... command once - you have then added the new -alias. Afterwards, just do git st to get status info. All the examples below follow the same -template.

-
# git cl
-# - clone a repository
-git config --global alias.cl clone
-
-
-
# git cma "commit message"
-# - commit all changes without opening editor for message
-git config --global alias.cma 'commit -a -m'
-
-
-
# git ca
-# - amend text to your latest commit message
-git config --global alias.ca 'commit --amend'
-
-
-
# git fl
-# - file log; shows diffs of files in latest commits
-git config --global alias.fl 'log -u'
-
-
-
# git co [branchname]
-# - checkout
-git config --global alias.co checkout
-
-
-
# git br <branchname>
-# - create branch
-git config --global alias.br branch
-
-
-
# git ls
-# - view log tree
-git config --global alias.ls 'log --pretty=format:"%C(green)%h\ %C(yellow)[%ad]%Cred%d\
-%Creset%s%Cblue\ [%cn]" --decorate --date=relative --graph'
-
-
-
# git diff
-# - show current uncommitted changes
-git config --global alias.diff 'diff --word-diff'
-
-
-
# git grep <query>
-# - search (grep) codebase for a search criterion
-git config --global alias.grep 'grep -Ii'
-
-
-

To get a further feel for GIT there is also a good YouTube talk about -it - it’s a bit long but it will help you -understand the underlying ideas behind GIT -(which in turn makes it a lot more intuitive to use).

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Weather-Tutorial.html b/docs/0.9.5/Weather-Tutorial.html deleted file mode 100644 index 6a034ef8ce..0000000000 --- a/docs/0.9.5/Weather-Tutorial.html +++ /dev/null @@ -1,155 +0,0 @@ - - - - - - - - - Weather Tutorial — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Weather Tutorial

-

This tutorial will have us create a simple weather system for our MUD. The way we want to use this -is to have all outdoor rooms echo weather-related messages to the room at regular and semi-random -intervals. Things like “Clouds gather above”, “It starts to rain” and so on.

-

One could imagine every outdoor room in the game having a script running on themselves that fires -regularly. For this particular example it is however more efficient to do it another way, namely by -using a “ticker-subscription” model. The principle is simple: Instead of having each Object -individually track the time, they instead subscribe to be called by a global ticker who handles time -keeping. Not only does this centralize and organize much of the code in one place, it also has less -computing overhead.

-

Evennia offers the TickerHandler specifically for using the subscription model. We -will use it for our weather system.

-

We will assume you know how to make your own Typeclasses. If not see one of the beginning tutorials. -We will create a new WeatherRoom typeclass that is aware of the day-night cycle.

-

-    import random
-    from evennia import DefaultRoom, TICKER_HANDLER
-    
-    ECHOES = ["The sky is clear.",
-              "Clouds gather overhead.",
-              "It's starting to drizzle.",
-              "A breeze of wind is felt.",
-              "The wind is picking up"] # etc
-
-    class WeatherRoom(DefaultRoom):
-        "This room is ticked at regular intervals"
-       
-        def at_object_creation(self):
-            "called only when the object is first created"
-            TICKER_HANDLER.add(60 * 60, self.at_weather_update)
-
-        def at_weather_update(self, *args, **kwargs):
-            "ticked at regular intervals"
-            echo = random.choice(ECHOES)
-            self.msg_contents(echo)
-
-
-

In the at_object_creation method, we simply added ourselves to the TickerHandler and tell it to -call at_weather_update every hour (60*60 seconds). During testing you might want to play with a -shorter time duration.

-

For this to work we also create a custom hook at_weather_update(*args, **kwargs), which is the -call sign required by TickerHandler hooks.

-

Henceforth the room will inform everyone inside it when the weather changes. This particular example -is of course very simplistic - the weather echoes are just randomly chosen and don’t care what -weather came before it. Expanding it to be more realistic is a useful exercise.

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Web-Character-Generation.html b/docs/0.9.5/Web-Character-Generation.html deleted file mode 100644 index cafae4235b..0000000000 --- a/docs/0.9.5/Web-Character-Generation.html +++ /dev/null @@ -1,750 +0,0 @@ - - - - - - - - - Web Character Generation — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Web Character Generation

-
-

Introduction

-

This tutorial will create a simple web-based interface for generating a new in-game Character. -Accounts will need to have first logged into the website (with their AccountDB account). Once -finishing character generation the Character will be created immediately and the Accounts can then -log into the game and play immediately (the Character will not require staff approval or anything -like that). This guide does not go over how to create an AccountDB on the website with the right -permissions to transfer to their web-created characters.

-

It is probably most useful to set MULTISESSION_MODE = 2 or 3 (which gives you a character- -selection screen when you log into the game later). Other modes can be used with some adaptation to -auto-puppet the new Character.

-

You should have some familiarity with how Django sets up its Model Template View framework. You need -to understand what is happening in the basic Web Character View tutorial. If you don’t understand the listed tutorial or have a grasp of Django basics, please look -at the Django tutorial to get a taste of what Django -does, before throwing Evennia into the mix (Evennia shares its API and attributes with the website -interface). This guide will outline the format of the models, views, urls, and html templates -needed.

-
-
-

Pictures

-

Here are some screenshots of the simple app we will be making.

-

Index page, with no character application yet done:

-
-

Index page, with no character application yet done.

-
-

Having clicked the “create” link you get to create your character (here we will only have name and -background, you can add whatever is needed to fit your game):

-
-

Character creation.

-
-

Back to the index page. Having entered our character application (we called our character “TestApp”) -you see it listed:

-
-

Having entered an application.

-
-

We can also view an already written character application by clicking on it - this brings us to the -detail page:

-
-

Detail view of character application.

-
-
-
-

Installing an App

-

Assuming your game is named “mygame”, navigate to your mygame/ directory, and type:

-
evennia startapp chargen
-
-
-

This will initialize a new Django app we choose to call “chargen”. It is directory containing some -basic starting things Django needs. You will need to move this directory: for the time being, it is -in your mygame directory. Better to move it in your mygame/web directory, so you have -mygame/web/chargen in the end.

-

Next, navigate to mygame/server/conf/settings.py and add or edit the following line to make -Evennia (and Django) aware of our new app:

-
INSTALLED_APPS += ('web.chargen',)
-
-
-

After this, we will get into defining our models (the description of the database storage), -views (the server-side website content generators), urls (how the web browser finds the pages) -and templates (how the web page should be structured).

-
-

Installing - Checkpoint:

-
    -
  • you should have a folder named chargen or whatever you chose in your mygame/web/ directory

  • -
  • you should have your application name added to your INSTALLED_APPS in settings.py

  • -
-
-
-
-

Create Models

-

Models are created in mygame/web/chargen/models.py.

-

A Django database model is a Python class that describes the database storage of the -data you want to manage. Any data you choose to store is stored in the same database as the game and -you have access to all the game’s objects here.

-

We need to define what a character application actually is. This will differ from game to game so -for this tutorial we will define a simple character sheet with the following database fields:

-
    -
  • app_id (AutoField): Primary key for this character application sheet.

  • -
  • char_name (CharField): The new character’s name.

  • -
  • date_applied (DateTimeField): Date that this application was received.

  • -
  • background (TextField): Character story background.

  • -
  • account_id (IntegerField): Which account ID does this application belong to? This is an -AccountID from the AccountDB object.

  • -
  • submitted (BooleanField): True/False depending on if the application has been submitted yet.

  • -
-
-

Note: In a full-fledged game, you’d likely want them to be able to select races, skills, -attributes and so on.

-
-

Our models.py file should look something like this:

-
# in mygame/web/chargen/models.py
-
-from django.db import models
-
-class CharApp(models.Model):
-    app_id = models.AutoField(primary_key=True)
-    char_name = models.CharField(max_length=80, verbose_name='Character Name')
-    date_applied = models.DateTimeField(verbose_name='Date Applied')
-    background = models.TextField(verbose_name='Background')
-    account_id = models.IntegerField(default=1, verbose_name='Account ID')
-    submitted = models.BooleanField(default=False)
-
-
-

You should consider how you are going to link your application to your account. For this tutorial, -we are using the account_id attribute on our character application model in order to keep track of -which characters are owned by which accounts. Since the account id is a primary key in Evennia, it -is a good candidate, as you will never have two of the same IDs in Evennia. You can feel free to use -anything else, but for the purposes of this guide, we are going to use account ID to join the -character applications with the proper account.

-
-

Model - Checkpoint:

-
    -
  • you should have filled out mygame/web/chargen/models.py with the model class shown above -(eventually adding fields matching what you need for your game).

  • -
-
-
-
-

Create Views

-

Views are server-side constructs that make dynamic data available to a web page. We are going to -add them to mygame/web/chargen.views.py. Each view in our example represents the backbone of a -specific web page. We will use three views and three pages here:

-
    -
  • The index (managing index.html). This is what you see when you navigate to -http://yoursite.com/chargen.

  • -
  • The detail display sheet (manages detail.html). A page that passively displays the stats of a -given Character.

  • -
  • Character creation sheet (manages create.html). This is the main form with fields to fill in.

  • -
-
-

Index view

-

Let’s get started with the index first.

-

We’ll want characters to be able to see their created characters so let’s

-
# file mygame/web/chargen.views.py
-
-from .models import CharApp
-
-def index(request):
-    current_user = request.user # current user logged in
-    p_id = current_user.id # the account id
-    # submitted Characters by this account
-    sub_apps = CharApp.objects.filter(account_id=p_id, submitted=True)
-    context = {'sub_apps': sub_apps}
-    # make the variables in 'context' available to the web page template
-    return render(request, 'chargen/index.html', context)
-
-
-
-
-

Detail view

-

Our detail page will have pertinent character application information our users can see. Since this -is a basic demonstration, our detail page will only show two fields:

-
    -
  • Character name

  • -
  • Character background

  • -
-

We will use the account ID again just to double-check that whoever tries to check our character page -is actually the account who owns the application.

-
# file mygame/web/chargen.views.py
-
-def detail(request, app_id):
-    app = CharApp.objects.get(app_id=app_id)
-    name = app.char_name
-    background = app.background
-    submitted = app.submitted
-    p_id = request.user.id
-    context = {'name': name, 'background': background,
-        'p_id': p_id, 'submitted': submitted}
-    return render(request, 'chargen/detail.html', context)
-
-
-
-
-
-

Creating view

-

Predictably, our create function will be the most complicated of the views, as it needs to accept -information from the user, validate the information, and send the information to the server. Once -the form content is validated will actually create a playable Character.

-

The form itself we will define first. In our simple example we are just looking for the Character’s -name and background. This form we create in mygame/web/chargen/forms.py:

-
# file mygame/web/chargen/forms.py
-
-from django import forms
-
-class AppForm(forms.Form):
-    name = forms.CharField(label='Character Name', max_length=80)
-    background = forms.CharField(label='Background')
-
-
-

Now we make use of this form in our view.

-
# file mygame/web/chargen/views.py
-
-from web.chargen.models import CharApp
-from web.chargen.forms import AppForm
-from django.http import HttpResponseRedirect
-from datetime import datetime
-from evennia.objects.models import ObjectDB
-from django.conf import settings
-from evennia.utils import create
-
-def creating(request):
-    user = request.user
-    if request.method == 'POST':
-        form = AppForm(request.POST)
-        if form.is_valid():
-            name = form.cleaned_data['name']
-            background = form.cleaned_data['background']
-            applied_date = datetime.now()
-            submitted = True
-            if 'save' in request.POST:
-                submitted = False
-            app = CharApp(char_name=name, background=background,
-            date_applied=applied_date, account_id=user.id,
-            submitted=submitted)
-            app.save()
-            if submitted:
-                # Create the actual character object
-                typeclass = settings.BASE_CHARACTER_TYPECLASS
-                home = ObjectDB.objects.get_id(settings.GUEST_HOME)
-                # turn the permissionhandler to a string
-                perms = str(user.permissions)
-                # create the character
-                char = create.create_object(typeclass=typeclass, key=name,
-                    home=home, permissions=perms)
-                user.db._playable_characters.append(char)
-                # add the right locks for the character so the account can
-                #  puppet it
-                char.locks.add("puppet:id(%i) or pid(%i) or perm(Developers) "
-                    "or pperm(Developers)" % (char.id, user.id))
-                char.db.background = background # set the character background
-            return HttpResponseRedirect('/chargen')
-    else:
-        form = AppForm()
-    return render(request, 'chargen/create.html', {'form': form})
-
-
-
-

Note also that we basically create the character using the Evennia API, and we grab the proper -permissions from the AccountDB object and copy them to the character object. We take the user -permissions attribute and turn that list of strings into a string object in order for the -create_object function to properly process the permissions.

-
-

Most importantly, the following attributes must be set on the created character object:

-
    -
  • Evennia permissions (copied from the AccountDB).

  • -
  • The right puppet locks so the Account can actually play as this Character later.

  • -
  • The relevant Character typeclass

  • -
  • Character name (key)

  • -
  • The Character’s home room location (#2 by default)

  • -
-

Other attributes are strictly speaking optional, such as the background attribute on our -character. It may be a good idea to decompose this function and create a separate _create_character -function in order to set up your character object the account owns. But with the Evennia API, -setting custom attributes is as easy as doing it in the meat of your Evennia game directory.

-

After all of this, our views.py file should look like something like this:

-
# file mygame/web/chargen/views.py
-
-from django.shortcuts import render
-from web.chargen.models import CharApp
-from web.chargen.forms import AppForm
-from django.http import HttpResponseRedirect
-from datetime import datetime
-from evennia.objects.models import ObjectDB
-from django.conf import settings
-from evennia.utils import create
-
-def index(request):
-    current_user = request.user # current user logged in
-    p_id = current_user.id # the account id
-    # submitted apps under this account
-    sub_apps = CharApp.objects.filter(account_id=p_id, submitted=True)
-    context = {'sub_apps': sub_apps}
-    return render(request, 'chargen/index.html', context)
-
-def detail(request, app_id):
-    app = CharApp.objects.get(app_id=app_id)
-    name = app.char_name
-    background = app.background
-    submitted = app.submitted
-    p_id = request.user.id
-    context = {'name': name, 'background': background,
-        'p_id': p_id, 'submitted': submitted}
-    return render(request, 'chargen/detail.html', context)
-
-def creating(request):
-    user = request.user
-    if request.method == 'POST':
-        form = AppForm(request.POST)
-        if form.is_valid():
-            name = form.cleaned_data['name']
-            background = form.cleaned_data['background']
-            applied_date = datetime.now()
-            submitted = True
-            if 'save' in request.POST:
-                submitted = False
-            app = CharApp(char_name=name, background=background,
-            date_applied=applied_date, account_id=user.id,
-            submitted=submitted)
-            app.save()
-            if submitted:
-                # Create the actual character object
-                typeclass = settings.BASE_CHARACTER_TYPECLASS
-                home = ObjectDB.objects.get_id(settings.GUEST_HOME)
-                # turn the permissionhandler to a string
-                perms = str(user.permissions)
-                # create the character
-                char = create.create_object(typeclass=typeclass, key=name,
-                    home=home, permissions=perms)
-                user.db._playable_characters.append(char)
-                # add the right locks for the character so the account can
-                #  puppet it
-                char.locks.add("puppet:id(%i) or pid(%i) or perm(Developers) "
-                    "or pperm(Developers)" % (char.id, user.id))
-                char.db.background = background # set the character background
-            return HttpResponseRedirect('/chargen')
-    else:
-        form = AppForm()
-    return render(request, 'chargen/create.html', {'form': form})
-
-
-
-

Create Views - Checkpoint:

-
    -
  • you’ve defined a views.py that has an index, detail, and creating functions.

  • -
  • you’ve defined a forms.py with the AppForm class needed by the creating function of -views.py.

  • -
  • your mygame/web/chargen directory should now have a views.py and forms.py file

  • -
-
-
-
-

Create URLs

-

URL patterns helps redirect requests from the web browser to the right views. These patterns are -created in mygame/web/chargen/urls.py.

-
# file mygame/web/chargen/urls.py
-
-from django.conf.urls import url
-from web.chargen import views
-
-urlpatterns = [
-    # ex: /chargen/
-    url(r'^$', views.index, name='index'),
-    # ex: /chargen/5/
-    url(r'^(?P<app_id>[0-9]+)/$', views.detail, name='detail'),
-    # ex: /chargen/create
-    url(r'^create/$', views.creating, name='creating'),
-]
-
-
-

You could change the format as you desire. To make it more secure, you could remove app_id from the -“detail” url, and instead just fetch the account’s applications using a unifying field like -account_id to find all the character application objects to display.

-

We must also update the main mygame/web/urls.py file (that is, one level up from our chargen app), -so the main website knows where our app’s views are located. Find the patterns variable, and -change it to include:

-
# in file mygame/web/urls.py
-
-from django.conf.urls import url, include
-
-# default evennia patterns
-from evennia.web.urls import urlpatterns
-
-# eventual custom patterns
-custom_patterns = [
-    # url(r'/desired/url/', view, name='example'),
-]
-
-# this is required by Django.
-urlpatterns += [
-    url(r'^chargen/', include('web.chargen.urls')),
-]
-
-urlpatterns = custom_patterns + urlpatterns
-
-
-
-

URLs - Checkpoint:

-
    -
  • You’ve created a urls.py file in the mygame/web/chargen directory

  • -
  • You have edited the main mygame/web/urls.py file to include urls to the chargen directory.

  • -
-
-
-
-

HTML Templates

-

So we have our url patterns, views, and models defined. Now we must define our HTML templates that -the actual user will see and interact with. For this tutorial we us the basic prosimii template -that comes with Evennia.

-

Take note that we use user.is_authenticated to make sure that the user cannot create a character -without logging in.

-

These files will all go into the /mygame/web/chargen/templates/chargen/ directory.

-
-

index.html

-

This HTML template should hold a list of all the applications the account currently has active. For -this demonstration, we will only list the applications that the account has submitted. You could -easily adjust this to include saved applications, or other types of applications if you have -different kinds.

-

Please refer back to views.py to see where we define the variables these templates make use of.

-
<!-- file mygame/web/chargen/templates/chargen/index.html-->
-
-{% extends "base.html" %}
-{% block content %}
-{% if user.is_authenticated %}
-    <h1>Character Generation</h1>
-    {% if sub_apps %}
-        <ul>
-        {% for sub_app in sub_apps %}
-            <li><a href="/chargen/{{ sub_app.app_id }}/">{{ sub_app.char_name }}</a></li>
-        {% endfor %}
-        </ul>
-    {% else %}
-        <p>You haven't submitted any character applications.</p>
-    {% endif %}
-  {% else %}
-    <p>Please <a href="{% url 'login'%}">login</a>first.<a/></p>
-{% endif %}
-{% endblock %}
-
-
-
-
-

detail.html

-

This page should show a detailed character sheet of their application. This will only show their -name and character background. You will likely want to extend this to show many more fields for your -game. In a full-fledged character generation, you may want to extend the boolean attribute of -submitted to allow accounts to save character applications and submit them later.

-
<!-- file mygame/web/chargen/templates/chargen/detail.html-->
-
-{% extends "base.html" %}
-{% block content %}
-<h1>Character Information</h1>
-{% if user.is_authenticated %}
-    {% if user.id == p_id %}
-        <h2>{{name}}</h2>
-        <h2>Background</h2>
-        <p>{{background}}</p>
-        <p>Submitted: {{submitted}}</p>
-    {% else %}
-        <p>You didn't submit this character.</p>
-    {% endif %}
-{% else %}
-<p>You aren't logged in.</p>
-{% endif %}
-{% endblock %}
-
-
-
-
-

create.html

-

Our create HTML template will use the Django form we defined back in views.py/forms.py to drive the -majority of the application process. There will be a form input for every field we defined in -forms.py, which is handy. We have used POST as our method because we are sending information to the -server that will update the database. As an alternative, GET would be much less secure. You can read -up on documentation elsewhere on the web for GET vs. POST.

-
<!-- file mygame/web/chargen/templates/chargen/create.html-->
-
-{% extends "base.html" %}
-{% block content %}
-<h1>Character Creation</h1>
-{% if user.is_authenticated %}
-<form action="/chargen/create/" method="post">
-    {% csrf_token %}
-    {{ form }}
-    <input type="submit" name="submit" value="Submit"/>
-</form>
-{% else %}
-<p>You aren't logged in.</p>
-{% endif %}
-{% endblock %}
-
-
-
-
-

Templates - Checkpoint:

-
    -
  • Create a index.html, detail.html and create.html template in your -mygame/web/chargen/templates/chargen directory

  • -
-
-
-
-

Activating your new character generation

-

After finishing this tutorial you should have edited or created the following files:

-
mygame/web/urls.py
-mygame/web/chargen/models.py
-mygame/web/chargen/views.py
-mygame/web/chargen/urls.py
-mygame/web/chargen/templates/chargen/index.html
-mygame/web/chargen/templates/chargen/create.html
-mygame/web/chargen/templates/chargen/detail.html
-
-
-

Once you have all these files stand in your mygame/folder and run:

-
evennia makemigrations
-evennia migrate
-
-
-

This will create and update the models. If you see any errors at this stage, read the traceback -carefully, it should be relatively easy to figure out where the error is.

-

Login to the website (you need to have previously registered an Player account with the game to do -this). Next you navigate to http://yourwebsite.com/chargen (if you are running locally this will -be something like http://localhost:4001/chargen and you will see your new app in action.

-

This should hopefully give you a good starting point in figuring out how you’d like to approach your -own web generation. The main difficulties are in setting the appropriate settings on your newly -created character object. Thankfully, the Evennia API makes this easy.

-
-
-

Adding a no CAPCHA reCAPCHA on your character generation

-

As sad as it is, if your server is open to the web, bots might come to visit and take advantage of -your open form to create hundreds, thousands, millions of characters if you give them the -opportunity. This section shows you how to use the No CAPCHA reCAPCHA designed by Google. Not only is it -easy to use, it is user-friendly… for humans. A simple checkbox to check, except if Google has -some suspicion, in which case you will have a more difficult test with an image and the usual text -inside. It’s worth pointing out that, as long as Google doesn’t suspect you of being a robot, this -is quite useful, not only for common users, but to screen-reader users, to which reading inside of -an image is pretty difficult, if not impossible. And to top it all, it will be so easy to add in -your website.

-
-

Step 1: Obtain a SiteKey and secret from Google

-

The first thing is to ask Google for a way to safely authenticate your website to their service. To -do it, we need to create a site key and a secret. Go to -https://www.google.com/recaptcha/admin to create such a -site key. It’s quite easy when you have a Google account.

-

When you have created your site key, save it safely. Also copy your secret key as well. You should -find both information on the web page. Both would contain a lot of letters and figures.

-
-
-

Step 2: installing and configuring the dedicated Django app

-

Since Evennia runs on Django, the easiest way to add our CAPCHA and perform the proper check is to -install the dedicated Django app. Quite easy:

-
pip install django-nocaptcha-recaptcha
-
-
-

And add it to the installed apps in your settings. In your mygame/server/conf/settings.py, you -might have something like this:

-
# ...
-INSTALLED_APPS += (
-    'web.chargen',
-    'nocaptcha_recaptcha',
-)
-
-
-

Don’t close the setting file just yet. We have to add in the site key and secret key. You can add -them below:

-
# NoReCAPCHA site key
-NORECAPTCHA_SITE_KEY = "PASTE YOUR SITE KEY HERE"
-# NoReCAPCHA secret key
-NORECAPTCHA_SECRET_KEY = "PUT YOUR SECRET KEY HERE"
-
-
-
-
-

Step 3: Adding the CAPCHA to our form

-

Finally we have to add the CAPCHA to our form. It will be pretty easy too. First, open your -web/chargen/forms.py file. We’re going to add a new field, but hopefully, all the hard work has -been done for us. Update at your convenience, You might end up with something like this:

-
from django import forms
-from nocaptcha_recaptcha.fields import NoReCaptchaField
-
-class AppForm(forms.Form):
-    name = forms.CharField(label='Character Name', max_length=80)
-    background = forms.CharField(label='Background')
-    captcha = NoReCaptchaField()
-
-
-

As you see, we added a line of import (line 2) and a field in our form.

-

And lastly, we need to update our HTML file to add in the Google library. You can open -web/chargen/templates/chargen/create.html. There’s only one line to add:

-
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
-
-
-

And you should put it at the bottom of the page. Just before the closing body would be good, but -for the time being, the base page doesn’t provide a footer block, so we’ll put it in the content -block. Note that it’s not the best place, but it will work. In the end, your -web/chargen/templates/chargen/create.html file should look like this:

-
{% extends "base.html" %}
-{% block content %}
-<h1>Character Creation</h1>
-{% if user.is_authenticated %}
-<form action="/chargen/create/" method="post">
-    {% csrf_token %}
-    {{ form }}
-    <input type="submit" name="submit" value="Submit"/>
-</form>
-{% else %}
-<p>You aren't logged in.</p>
-{% endif %}
-<script src="https://www.google.com/recaptcha/api.js" async defer></script>
-{% endblock %}
-
-
-

Reload and open http://localhost:4001/chargen/create and -you should see your beautiful CAPCHA just before the “submit” button. Try not to check the checkbox -to see what happens. And do the same while checking the checkbox!

-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Web-Character-View-Tutorial.html b/docs/0.9.5/Web-Character-View-Tutorial.html deleted file mode 100644 index 852436d8c9..0000000000 --- a/docs/0.9.5/Web-Character-View-Tutorial.html +++ /dev/null @@ -1,312 +0,0 @@ - - - - - - - - - Web Character View Tutorial — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Web Character View Tutorial

-

Before doing this tutorial you will probably want to read the intro in Basic Web tutorial.

-

In this tutorial we will create a web page that displays the stats of a game character. For this, -and all other pages we want to make specific to our game, we’ll need to create our own Django “app”

-

We’ll call our app character, since it will be dealing with character information. From your game -dir, run

-
evennia startapp character
-
-
-

This will create a directory named character in the root of your game dir. It contains all basic -files that a Django app needs. To keep mygame well ordered, move it to your mygame/web/ -directory instead:

-
mv character web/
-
-
-

Note that we will not edit all files in this new directory, many of the generated files are outside -the scope of this tutorial.

-

In order for Django to find our new web app, we’ll need to add it to the INSTALLED_APPS setting. -Evennia’s default installed apps are already set, so in server/conf/settings.py, we’ll just extend -them:

-
INSTALLED_APPS += ('web.character',)
-
-
-
-

Note: That end comma is important. It makes sure that Python interprets the addition as a tuple -instead of a string.

-
-

The first thing we need to do is to create a view and an URL pattern to point to it. A view is a -function that generates the web page that a visitor wants to see, while the URL pattern lets Django -know what URL should trigger the view. The pattern may also provide some information of its own as -we shall see.

-

Here is our character/urls.py file (Note: you may have to create this file if a blank one -wasn’t generated for you):

-
# URL patterns for the character app
-
-from django.conf.urls import url
-from web.character.views import sheet
-
-urlpatterns = [
-    url(r'^sheet/(?P<object_id>\d+)/$', sheet, name="sheet")
-]
-
-
-

This file contains all of the URL patterns for the application. The url function in the -urlpatterns list are given three arguments. The first argument is a pattern-string used to -identify which URLs are valid. Patterns are specified as regular expressions. Regular expressions -are used to match strings and are written in a special, very compact, syntax. A detailed description -of regular expressions is beyond this tutorial but you can learn more about them -here. For now, just accept that this regular -expression requires that the visitor’s URL looks something like this:

-
sheet/123/
-
-
-

That is, sheet/ followed by a number, rather than some other possible URL pattern. We will -interpret this number as object ID. Thanks to how the regular expression is formulated, the pattern -recognizer stores the number in a variable called object_id. This will be passed to the view (see -below). We add the imported view function (sheet) in the second argument. We also add the name -keyword to identify the URL pattern itself. You should always name your URL patterns, this makes -them easy to refer to in html templates using the {% url %} tag (but we won’t get more into that -in this tutorial).

-
-

Security Note: Normally, users do not have the ability to see object IDs within the game (it’s -restricted to superusers only). Exposing the game’s object IDs to the public like this enables -griefers to perform what is known as an account enumeration -attack in the efforts of -hijacking your superuser account. Consider this: in every Evennia installation, there are two -objects that we can always expect to exist and have the same object IDs– Limbo (#2) and the -superuser you create in the beginning (#1). Thus, the griefer can get 50% of the information they -need to hijack the admin account (the admin’s username) just by navigating to sheet/1!

-
-

Next we create views.py, the view file that urls.py refers to.

-
# Views for our character app
-
-from django.http import Http404
-from django.shortcuts import render
-from django.conf import settings
-
-from evennia.utils.search import object_search
-from evennia.utils.utils import inherits_from
-
-def sheet(request, object_id):
-    object_id = '#' + object_id
-    try:
-        character = object_search(object_id)[0]
-    except IndexError:
-        raise Http404("I couldn't find a character with that ID.")
-    if not inherits_from(character, settings.BASE_CHARACTER_TYPECLASS):
-        raise Http404("I couldn't find a character with that ID. "
-                      "Found something else instead.")
-    return render(request, 'character/sheet.html', {'character': character})
-
-
-

As explained earlier, the URL pattern parser in urls.py parses the URL and passes object_id to -our view function sheet. We do a database search for the object using this number. We also make -sure such an object exists and that it is actually a Character. The view function is also handed a -request object. This gives us information about the request, such as if a logged-in user viewed it

-
    -
  • we won’t use that information here but it is good to keep in mind.

  • -
-

On the last line, we call the render function. Apart from the request object, the render -function takes a path to an html template and a dictionary with extra data you want to pass into -said template. As extra data we pass the Character object we just found. In the template it will be -available as the variable “character”.

-

The html template is created as templates/character/sheet.html under your character app folder. -You may have to manually create both template and its subfolder character. Here’s the template -to create:

-
{% extends "base.html" %}
-{% block content %}
-
-    <h1>{{ character.name }}</h1>
-
-    <p>{{ character.db.desc }}</p>
-
-    <h2>Stats</h2>
-    <table>
-      <thead>
-        <tr>
-          <th>Stat</th>
-          <th>Value</th>
-        </tr>
-      </thead>
-      <tbody>
-        <tr>
-          <td>Strength</td>
-          <td>{{ character.db.str }}</td>
-        </tr>
-        <tr>
-          <td>Intelligence</td>
-          <td>{{ character.db.int }}</td>
-        </tr>
-        <tr>
-          <td>Speed</td>
-          <td>{{ character.db.spd }}</td>
-        </tr>
-      </tbody>
-    </table>
-
-    <h2>Skills</h2>
-    <ul>
-      {% for skill in character.db.skills %}
-        <li>{{ skill }}</li>
-      {% empty %}
-        <li>This character has no skills yet.</li>
-      {% endfor %}
-    </ul>
-
-    {% if character.db.approved %}
-      <p class="success">This character has been approved!</p>
-    {% else %}
-      <p class="warning">This character has not yet been approved!</p>
-    {% endif %}
-{% endblock %}
-
-
-

In Django templates, {% ... %} denotes special in-template “functions” that Django understands. -The {{ ... }} blocks work as “slots”. They are replaced with whatever value the code inside the -block returns.

-

The first line, {% extends "base.html" %}, tells Django that this template extends the base -template that Evennia is using. The base template is provided by the theme. Evennia comes with the -open-source third-party theme prosimii. You can find it and its base.html in -evennia/web/templates/prosimii. Like other templates, these can be overwritten.

-

The next line is {% block content %}. The base.html file has blocks, which are placeholders -that templates can extend. The main block, and the one we use, is named content.

-

We can access the character variable anywhere in the template because we passed it in the render -call at the end of view.py. That means we also have access to the Character’s db attributes, -much like you would in normal Python code. You don’t have the ability to call functions with -arguments in the template– in fact, if you need to do any complicated logic, you should do it in -view.py and pass the results as more variables to the template. But you still have a great deal of -flexibility in how you display the data.

-

We can do a little bit of logic here as well. We use the {% for %} ... {% endfor %} and {% if %} ... {% else %} ... {% endif %} structures to change how the template renders depending on how many -skills the user has, or if the user is approved (assuming your game has an approval system).

-

The last file we need to edit is the master URLs file. This is needed in order to smoothly integrate -the URLs from your new character app with the URLs from Evennia’s existing pages. Find the file -web/urls.py and update its patterns list as follows:

-
# web/urls.py
-
-custom_patterns = [
-    url(r'^character/', include('web.character.urls'))
-   ]
-
-
-

Now reload the server with evennia reload and visit the page in your browser. If you haven’t -changed your defaults, you should be able to find the sheet for character #1 at -http://localhost:4001/character/sheet/1/

-

Try updating the stats in-game and refresh the page in your browser. The results should show -immediately.

-

As an optional final step, you can also change your character typeclass to have a method called -‘get_absolute_url’.

-
# typeclasses/characters.py
-
-    # inside Character
-    def get_absolute_url(self):
-        from django.urls import reverse
-        return reverse('character:sheet', kwargs={'object_id':self.id})
-
-
-

Doing so will give you a ‘view on site’ button in the top right of the Django Admin Objects -changepage that links to your new character sheet, and allow you to get the link to a character’s -page by using in any template where you have a given object.

-

Now that you’ve made a basic page and app with Django, you may want to read the full Django -tutorial to get a better idea of what it can do. You can find Django’s tutorial -here.

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Web-Features.html b/docs/0.9.5/Web-Features.html deleted file mode 100644 index 9c0b6adb80..0000000000 --- a/docs/0.9.5/Web-Features.html +++ /dev/null @@ -1,242 +0,0 @@ - - - - - - - - - Web Features — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Web Features

-

Evennia is its own webserver and hosts a default website and browser webclient.

-
-

Web site

-

The Evennia website is a Django application that ties in with the MUD database. Since the website -shares this database you could, for example, tell website visitors how many accounts are logged into -the game at the moment, how long the server has been up and any other database information you may -want. During development you can access the website by pointing your browser to -http://localhost:4001.

-
-

You may also want to set DEBUG = True in your settings file for debugging the website. You will -then see proper tracebacks in the browser rather than just error codes. Note however that this will -leak memory a lot (it stores everything all the time) and is not to be used in production. It’s -recommended to only use DEBUG for active web development and to turn it off otherwise.

-
-

A Django (and thus Evennia) website basically consists of three parts, a -view an associated -template and an urls.py file. Think of -the view as the Python back-end and the template as the HTML files you are served, optionally filled -with data from the back-end. The urls file is a sort of mapping that tells Django that if a specific -URL is given in the browser, a particular view should be triggered. You are wise to review the -Django documentation for details on how to use these components.

-

Evennia’s default website is located in -evennia/web/website. In this -folder you’ll find the simple default view as well as subfolders templates and static. Static -files are things like images, CSS files and Javascript.

-
-

Customizing the Website

-

You customize your website from your game directory. In the folder web you’ll find folders -static, templates, static_overrides and templates_overrides. The first two of those are -populated automatically by Django and used to serve the website. You should not edit anything in -them - the change will be lost. To customize the website you’ll need to copy the file you want to -change from the web/website/template/ or web/website/static/ path to the corresponding place -under one of _overrides directories.

-

Example: To override or modify evennia/web/website/template/website/index.html you need to -add/modify mygame/web/template_overrides/website/index.html.

-

The detailed description on how to customize the website is best described in tutorial form. See the -Web Tutorial for more information.

-
-
-

Overloading Django views

-

The Python backend for every HTML page is called a Django -view. A view can do all sorts of -functions, but the main one is to update variables data that the page can display, like how your -out-of-the-box website will display statistics about number of users and database objects.

-

To re-point a given page to a view.py of your own, you need to modify mygame/web/urls.py. An -URL pattern is a regular -expression that you need to enter in the address -field of your web browser to get to the page in question. If you put your own URL pattern before -the default ones, your own view will be used instead. The file urls.py even marks where you should -put your change.

-

Here’s an example:

-
# mygame/web/urls.py
-
-from django.conf.urls import url, include
-# default patterns
-from evennia.web.urls import urlpatterns
-
-# our own view to use as a replacement
-from web.myviews import myview
-
-# custom patterns to add
-patterns = [
-    # overload the main page view
-    url(r'^', myview, name='mycustomview'),
-]
-
-urlpatterns = patterns + urlpatterns
-
-
-
-

Django will always look for a list named urlpatterns which consists of the results of url() -calls. It will use the first match it finds in this list. Above, we add a new URL redirect from -the root of the website. It will now our own function myview from a new module -mygame/web/myviews.py.

-
-

If our game is found on http://mygame.com, the regular expression "^" means we just entered -mygame.com in the address bar. If we had wanted to add a view for http://mygame.com/awesome, the -regular expression would have been ^/awesome.

-
-

Look at evennia/web/website/views.py to see the inputs and outputs you must have to define a view. Easiest may be to -copy the default file to mygame/web to have something to modify and expand on.

-

Restart the server and reload the page in the browser - the website will now use your custom view. -If there are errors, consider turning on settings.DEBUG to see the full tracebacks - in debug mode -you will also log all requests in mygame/server/logs/http_requests.log.

-
-
-
-

Web client

-

Evennia comes with a MUD client accessible from a normal web browser. During -development you can try it at http://localhost:4001/webclient. -See the Webclient page for more details.

-
-
-

The Django ‘Admin’ Page

-

Django comes with a built-in admin -website. This is accessible by clicking -the ‘admin’ button from your game website. The admin site allows you to see, edit and create objects -in your database from a graphical interface.

-

The behavior of default Evennia models are controlled by files admin.py in the Evennia package. -New database models you choose to add yourself (such as in the Web Character View Tutorial) can/will -also have admin.py files. New models are registered to the admin website by a call of -admin.site.register(model class, admin class) inside an admin.py file. It is an error to attempt -to register a model that has already been registered.

-

To overload Evennia’s admin files you don’t need to modify Evennia itself. To customize you can call -admin.site.unregister(model class), then follow that with admin.site.register in one of your own -admin.py files in a new app that you add.

-
-
-

More reading

-

Evennia relies on Django for its web features. For details on expanding your web experience, the -Django documentation or the Django -Book are the main resources to look into. In Django -lingo, the Evennia is a django “project” that consists of Django “applications”. For the sake of web -implementation, the relevant django “applications” in default Evennia are web/website or -web/webclient.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Web-Tutorial.html b/docs/0.9.5/Web-Tutorial.html deleted file mode 100644 index ae44c93c57..0000000000 --- a/docs/0.9.5/Web-Tutorial.html +++ /dev/null @@ -1,228 +0,0 @@ - - - - - - - - - Web Tutorial — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Web Tutorial

-

Evennia uses the Django web framework as the basis of both its -database configuration and the website it provides. While a full understanding of Django requires -reading the Django documentation, we have provided this tutorial to get you running with the basics -and how they pertain to Evennia. This text details getting everything set up. The Web-based -Character view Tutorial gives a more explicit example of making a -custom web page connected to your game, and you may want to read that after finishing this guide.

-
-

A Basic Overview

-

Django is a web framework. It gives you a set of development tools for building a website quickly -and easily.

-

Django projects are split up into apps and these apps all contribute to one project. For instance, -you might have an app for conducting polls, or an app for showing news posts or, like us, one for -creating a web client.

-

Each of these applications has a urls.py file, which specifies what -URLs are used by the app, a views.py file -for the code that the URLs activate, a templates directory for displaying the results of that code -in HTML for the user, and a static folder that holds assets -like CSS, Javascript, -and Image files (You may note your mygame/web folder does not have a static or template folder. -This is intended and explained further below). Django applications may also have a models.py file -for storing information in the database. We “cmd: attr(locktest, 80, compare=gt)”will not change any -models here, take a look at the New Models page (as well as the Django -docs on models) if you are interested.

-

There is also a root urls.py that determines the URL structure for the entire project. A starter -urls.py is included in the default game template, and automatically imports all of Evennia’s -default URLs for you. This is located in web/urls.py.

-
-
-

Changing the logo on the front page

-

Evennia’s default logo is a fun little googly-eyed snake wrapped around a gear globe. As cute as it -is, it probably doesn’t represent your game. So one of the first things you may wish to do is -replace it with a logo of your own.

-

Django web apps all have static assets: CSS files, Javascript files, and Image files. In order to -make sure the final project has all the static files it needs, the system collects the files from -every app’s static folder and places it in the STATIC_ROOT defined in settings.py. By default, -the Evennia STATIC_ROOT is in web/static.

-

Because Django pulls files from all of those separate places and puts them in one folder, it’s -possible for one file to overwrite another. We will use this to plug in our own files without having -to change anything in the Evennia itself.

-

By default, Evennia is configured to pull files you put in the web/static_overrides after all -other static files. That means that files in static_overrides folder will overwrite any previously -loaded files having the same path under its static folder. This last part is important to repeat: -To overload the static resource from a standard static folder you need to replicate the path of -folders and file names from that static folder in exactly the same way inside static_overrides.

-

Let’s see how this works for our logo. The default web application is in the Evennia library itself, -in evennia/web/. We can see that there is a static folder here. If we browse down, we’ll -eventually find the full path to the Evennia logo file: -evennia/web/website/static/website/images/evennia_logo.png.

-

Inside our static_overrides we must replicate the part of the path inside the website’s static -folder, in other words, we must replicate website/images/evennia_logo.png.

-

So, to change the logo, we need to create the folder path website/images/ in static_overrides. -You may already have this folder structure prepared for you. We then rename our own logo file to -evennia_logo.png and copy it there. The final path for this file would thus be: -mygame/web/static_overrides/website/images/evennia_logo.png.

-

To get this file pulled in, just change to your own game directory and reload the server:

-
evennia reload
-
-
-

This will reload the configuration and bring in the new static file(s). If you didn’t want to reload -the server you could instead use

-
evennia collectstatic
-
-
-

to only update the static files without any other changes.

-
-

Note: Evennia will collect static files automatically during startup. So if evennia collectstatic reports finding 0 files to collect, make sure you didn’t start the engine at some -point - if so the collector has already done its work! To make sure, connect to the website and -check so the logo has actually changed to your own version.

-
-
-

Note: Sometimes the static asset collector can get confused. If no matter what you do, your -overridden files aren’t getting copied over the defaults, try removing the target file (or -everything) in the web/static directory, and re-running collectstatic to gather everything from -scratch.

-
-
-
-

Changing the Front Page’s Text

-

The default front page for Evennia contains information about the Evennia project. You’ll probably -want to replace this information with information about your own project. Changing the page template -is done in a similar way to changing static resources.

-

Like static files, Django looks through a series of template folders to find the file it wants. The -difference is that Django does not copy all of the template files into one place, it just searches -through the template folders until it finds a template that matches what it’s looking for. This -means that when you edit a template, the changes are instant. You don’t have to reload the server or -run any extra commands to see these changes - reloading the web page in your browser is enough.

-

To replace the index page’s text, we’ll need to find the template for it. We’ll go into more detail -about how to determine which template is used for rendering a page in the Web-based Character view -Tutorial. For now, you should know that the template we want to change -is stored in evennia/web/website/templates/website/index.html.

-

To replace this template file, you will put your changed template inside the -web/template_overrides/website directory in your game folder. In the same way as with static -resources you must replicate the path inside the default template directory exactly. So we must -copy our replacement template named index.html there (or create the website directory in -web/template_overridesif it does not exist, first). The final path to the file should thus be:web/template_overrides/website/index.html` within your game directory.

-

Note that it is usually easier to just copy the original template over and edit it in place. The -original file already has all the markup and tags, ready for editing.

-
-
-

Further reading

-

For further hints on working with the web presence, you could now continue to the Web-based -Character view Tutorial where you learn to make a web page that -displays in-game character stats. You can also look at Django’s own -tutorial to get more insight in how Django works and what -possibilities exist.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Webclient-brainstorm.html b/docs/0.9.5/Webclient-brainstorm.html deleted file mode 100644 index 63937e7ded..0000000000 --- a/docs/0.9.5/Webclient-brainstorm.html +++ /dev/null @@ -1,449 +0,0 @@ - - - - - - - - - Webclient brainstorm — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Webclient brainstorm

-
-
-

Ideas for a future webclient gui

-

This is a brainstorming whitepage. Add your own comments in a named section below.

-
-

From Chat on 2019/09/02

-
  Griatch (IRC)APP  @friarzen: Could one (with goldenlayout) programmatically provide pane positions
-and sizes?
-I recall it was not trivial for the old split.js solution.
-  friarzen  take a look at the goldenlayout_default_config.js
-It is kinda cryptic but that is the layout json.
-  Griatch (IRC)APP  @friarzen: Hm, so dynamically replacing the goldenlayout_config in the global
-scope at the right
- thing would do it?
-  friarzen  yep
-  friarzen  the biggest pain in the butt is that goldenlayout_config needs to be set before the
-goldenlayout init()
-is called, which isn't trivial with the current structure, but it isn't impossible.
-  Griatch (IRC)APP  One could in principle re-run init() at a later date though, right?
-  friarzen  Hmm...not sure I've ever tried it... seems doable off the top of my head...
-right now, that whole file exists to be overridden on page load as a separate <script> HTML tag, so
-it can get
-force-loaded early.
-you could just as easily call the server at that time for the proper config info and store it into
-the variable.
-  Griatch (IRC)APP  @friarzen: Right. I picture the default would either be modified directly in
-that file or even be
-in settings.
-  friarzen  And if you have it call with an authenticated session at that early point, you could
-even have the layout
-be defined as a per-user setting.
-  Griatch (IRC)APP  Yeah, I think that'd be a very important feature.
-So one part of the config would be the golden-layout config blob; then another section with custom
-per-pane
-settings. Things like which tag a pane filters on, its type, and options for that type (like
-replace/scroll for a
-text pane etc).
-And probably one general config section; things like notifications, sounds, popup settings and the
-like
-  friarzen  Actually, that information is already somewhat stored into the data as componentState {}
-  Griatch (IRC)APP  I imagine a pane would need to be identified uniquely for golden-layout to know
-which is which,
-so that'd need to be associated.
-  friarzen  see line 55.
-that's....where it gets tricky...
-goldenlayout is kinda dumb in that it treats the whole json blob as a state object.
-  Griatch (IRC)APP  componentState, is the idea that it takes arbitrary settings then?
-  friarzen  so each sub-dictionary with a type of "component" in it is a window and as you move
-stuff around it
-dynamically creates new dictionaries as needed to keep it all together.
-yep
-right now I'm storing the list of types as a string and the updateMethod type as a string, just to
-be as obvious as
-possible.
-  Griatch (IRC)APP  I wonder if one could populate componentState(s) just before initializing the
-system, and then
-extract them into a more Evennia-friendly storage when saving. Or maybe it's no big deal to just
-store that whole
-blob as-is, with some extra things added?
-  friarzen  if you want to see it in action, take a look at the values in your localstorage after
-you've moved stuff
-around, created new windows, etc.
-I think their preference is to just store the whole blob.
-which is what the localstorage save does, in fact.
-  Griatch (IRC)APP  Yes, I see.
-It allows you to retain the session within your browser as well
-  friarzen  One trick I've been thinking about for the whole interface is to have another pair of
-components, one
-being a "dynamic" config window that displays a series of dropdowns, one for each plugin that
-defines it's own
-settings.
-And another that has an embedded i-frame to allow a split-screen where half of the display is the
-text interface
-and the other loads the local main website page and allows further browsing.
-  Griatch (IRC)APP  I think ideally, each pane should handle its per-pane settings as a dropdown or
-popup triggered
-from its header.
-  friarzen  well, pane != plugin...
-  Griatch (IRC)APP  True, one tends to sometimes make the other available but they are not the same
-  friarzen  think of the history plugin for example...if you want to make keyboard keys dynamically
-configurable, you
-need some place to enter that information.
-yeah.
-  Griatch (IRC)APP  Yes, I buy that - a dynamical option window would be needed. I'd say the
-'global' settings should
-be treated as just another module in this regard though
-So that if you have no modules installed, there is one entry in that option pane, the one that opens
-the global
-options
-  friarzen  Yeah, so that is that component...one pane.
-  Griatch (IRC)APP  Another thing that the config should contain would be the available message
-tags. Waiting for
-them to actually show up before being able to use them is not that useful. This would likely have to
-be a setting
-though I imagine.
-  friarzen  we could remove the current pop-up and just open the new component pane instead, and
-then that pane would
-display the list of plugins that registered a config() callback.
-  Griatch (IRC)APP  Yes
-  friarzen  yeah, the server has to pre-define what tags it is going to send.
-  Griatch (IRC)APP  The process for adding a tag would be to adding to, say, a list in settings,
-restart and then .. profit
-  friarzen  yep, which is kind of how I see spawns working.
-  Griatch (IRC)APP  spawns, meaning stand-alone windows?
-  friarzen  we just have a plugin that defines it's config pane with a "match this text" box and a
-tag type to send
-the data to, or spawn a new pane with that tag type preselected to capture that text.
-wouldn't be stand alone windows.  just new tabs, for now.
-  Griatch (IRC)APP  Ok, so a filter target that filters on text content and directs to tag
-  friarzen  yep.
-  Griatch (IRC)APP  (or re-tags it, I suppose)
-  friarzen  yeah, exactly.
-and opens a new window for that tag if one doesn't already exist.
-  Griatch (IRC)APP  A lot of complex effects could be achieved there. Should the filter extract the
-text and re-tag,
-or should it keep the text with its original tag and make a copy of it with the new tag? O_o;
-  friarzen  yet more options for the user. :slightly_smiling_face:
-baby steps first I think.
-"pages from bob should go to bob's window, not the general chat window"
-  Griatch (IRC)APP  It doesn't sound too hard to do - using tagging like that is really neat since
-then the rerouting
-can just work normally without knowing which pane you are actually rerouting too (and you could have
-multiple panes
-getting the same content too)
-  friarzen  yep.
-and the i-frame component, I think, provides just as much wow facter.
-  Griatch (IRC)APP  Yes, the setting would be something like: If text contains "bob" -> set tag
-"bob" (auto-create
-pane if not exist []?)
-  friarzen  just being able to load a character page from the wiki side in half the screen
-(including the pictures
-and whatnot) while playing/reading the text from the other half is really nice.
-  Griatch (IRC)APP  Could there not be some cross-scripting warnings in modern browsers if trying to
-load another
-website in an iframe?
-I doubt you could open Github like that, for example.
-friarzen  well, assuming it is all from the same origin game server, it will all be from the same
-domain, so should
-avoid that, but it will take some testing to make sure.  I want to get it to the point where you can
-click on
-somebody's name in the general terminal-style window and have it pop up that characters' wiki page.
-  Griatch (IRC)APP  That does sound nice :)
-  friarzen  i-frames are pretty much the only way to handle cross-domain content, but they are a
-pain in the butt to
-get that to work.
-  Griatch (IRC)APP  If it's on the same domain it would be fine, but it should probably give a "you
-are now leaving
-..." message and switch to a new window if going elsewhere.
-  friarzen  (without getting into modern CORS url blessings)
-yeah
-  Griatch (IRC)APP  Just to avoid headaches :)
-  friarzen  So, yeah, two new goldenlayout components that I am working on but they aren't ready
-yet. heh.
-  Griatch (IRC)APP  Oh, you are working on them already?
-  friarzen  yeah, some initial "will this work" structure.
-I haven't found anything yet that will not make it work.
-it's mostly just not going to look very pretty to start with. It'll take a few iterations I bet.
-  Griatch (IRC)APP  Sounds good! We should probably try to formalize our thoughts around a future
-config format as
-well. Depending just how and when the golden-layout blob needs to be in place and if we can
-construct it on-the-
-fly, it affects the format style chosen.
-  friarzen  Yeah, that's new from today's conversation, so I don't really have anything built for
-that.
-  Griatch (IRC)APP  I'm still unsure about how the Evennia/pane specific things (that'd need to be
-serialized to the
-database on a per-account basis) would interact with the golden-layout structure.
-  friarzen  maybe the place to start is to wipe-out/update the old
-https://github.com/evennia/evennia/wiki/Webclient-
-brainstorm entry?
-  Griatch (IRC)APP  I don't think we need to wipe the old, but we could certainly add a new section
-above the old and
-start some new discussions.
-  friarzen  It is really just that per componentState bit.
-anything in that json is treated as a blackbox that goldenlayout just passes around.
-  Griatch (IRC)APP  So would we save the whole blob then, componentState and all, and simply not
-worry about
-ourselves storing per-pane options?
-The drawback with that would be that a dev could not offer an exact default layout/setup for the
-user.
-... unless they set it up and saved the blob I guess
-  friarzen  Yeah, that's exactly how I built mine. :slightly_smiling_face:
-not the most dev-friendly way to do it, but it works.
-  Griatch (IRC)APP  Heh. Ok, so the config would be one section for the golden-layout-blob, one for
-module settings,
-one of which is the global settings.
-and a list of the available tags
-  friarzen  yep
-  Griatch (IRC)APP  And probably an empty misc section for future use ...
-  friarzen  seems reasonable.
-  Griatch (IRC)APP  So, that means that in the future one would need a procedure for the dev to
-easily create and
-save the player-wide default to central storage. Well, one step at a time.
-For now, good night!
-  friarzen  Yep, I expect that would be some kind of admin-approved api/command
-  Griatch (IRC)APP  And thanks for the discussion!
-
-
-
-

Relates to the activity happening relating to the Webclient extensions task -#614.

-
-
-

Griatch Jan 23, 2017 post 2

-

These are my ideas for the functionality of Evennia’s webclient in the (possibly distant) future. It -assumes the webclient options have been implemented as per -#1172.

-

Mockup 1

-

The idea of the GUI is based around panes (a “window” feels like something that pops open). These -are areas of the window of the type you would see from a javascript library like -Split.js. Each pane has a separator with a handle for -resizing it.

-

Each pane has an icon for opening a dropdown menu (see next mockup image).

-

Above image could show the default setup; mimicking the traditional telnet mud client setup. There -should be at least one input pane (but you could add multiple). The Input pane has the icon for -launching the main webclient options window. Alternatively the options icon could hover -transparently in the upper left, “above” all panes.

-

The main webclient options window should have an option for hiding all GUI customization icons (the -draggable handles of panes and the dropdown menu) for users who does not want to have to worry about -changing things accidentally. Devs not wanting to offer players the ability to customize their -client GUIs could maybe just set it up the way they want and then turn the gui controls off on the -javascript level.

-

Mockup 2

-

The dropdown menu allows for splitting each pane horizontally and vertically.

-

Mockup 3

-

Each pane is “tagged” with what data will be sent to it. It could accept more than one type of -tagged data. Just which tags are available is different for each game (and should be reported by the -server).

-

For example, the server could send the return of the “look” command as

-
    msg("you see ...", {"pane": "look"})
-
-
-

If one (or more) of the panes is set to receive “look” data, all such will go there. If no pane is -assigned to “look”, this text will end up in the pane(s) with the “Unassigned” designation. It might -be necessary to enforce that at least one window has the “unassigned” designation in order to not -lose output without a clear pane target. By contrast the pane tagged with “All” receives all output -regardless of if it is also being sent to other panes.

-

Another thing that came to mind is logging. It might be an idea to tie a given log file to a -specific pane (panes?) to limit spam in the log (it might be one reason for having a pane with the -“All” tag, for those wanting to log everything). This could also be set in the dropdown menu or in -the webclient options window, maybe.

-

Comments?

-
-
-

titeuf87 Jan 23, 2017

-

That way of splitting panes seems easy to manage while still being powerful at the same time. -It’s certainly a lot more flexible than what I had in mind.

-

This is a quick sketch of what I was thinking about:

-
=====================
-Options           [x]
-=====================
-help:         [popup]
-map:       [top left]
-channels: [top right]
-look:   [main output]
-
-
-

But that’s not as good as Griatch’s proposal.

-

The panes themselves can work differently depending on the content though:

-
    -
  • channel messages: when someone talks on a channel, the output text needs to be appended to the -text already shown.

  • -
  • inventory: this pane should clear its output every time the inventory is displayed, so old -inventory is not displayed. Also what about dropping items? As long as the player doesn’t check its -inventory then that pane won’t be updated, unless more OOB data is added to track the inventory.

  • -
  • help/look: those pane should probably also clear their content before displaying new content.

  • -
-

logging: do you mean have a “save to log” item in the pane menu?

-
-
-

Griatch Jan 23, 2017, post 1

-

It makes sense that different types of panes would have different functionality. I was thinking that -something like inventory would be very specific to a given game. But titeuf87 has a point - maybe -you can get a rather generalized behavior just by defining if a pane should replace or append to the -existing data.

-

As for the updating of inventory when dropping items, not sure if that can be generalized, but I -guess drop/get commands could be wired to do that.

-

As for logging - yes I picture a “save to log” thing in the menu. The problem is just where to save -the log. I think at least for an initial setup, one could maybe set the logging file path in the -webclient options and just append logs from all the panes marked for logging to that same file.

-
-
-

chainsol 3rd of October, 2017

-

I’ve been messing a little bit with split.js - I’ve managed to split a split dynamically with a data -attribute on a button and jQuery. My current thinking on this issue is to use jQuery -Templates to write the template for horizontal and -vertical splits, then using jQuery to set up the initial split layout by inserting those templates -as appropriate for user settings.

-

We would have a dropdown per split that decides what tag it’s meant to handle - perhaps a data -attribute that we change in the template for easy selection through jQuery - and then send tags for -messages to the webclient. This dropdown would also have a setting per split to either append new -content or replace content - again, perhaps a data attribute.

-

We might also want to store “mobile” and “desktop” layouts separately - or just default to a mobile- -friendly layout at a certain screen size, and turn off the splits.

-

Oh, and embedding Bootstrap containers in splits works perfectly - that could help us too.

-
-
-

chainsol 9th of October, 2017

-

I’ve got a demo of this working at my development box, -if anyone wants to take a look. So far, I’ve got tag handling, dynamic splits, and the ability to -swap splits’ contents. Since this doesn’t have a fancy interface yet, if you want to see a dynamic -split, open your browser’s console and try these commands:

-

SplitHandler.split("#main", "horizontal") will split the top-half into two 50-50 splits, both -receiving content that’s not tagged or is tagged “all” from the server.

-

SplitHandler.swapContent("#input", "#split_2") after doing so will swap the input into the top- -left split.

-

I’m trying to figure out where to put each split’s configuration - maybe a dropdown button that’s -semi-transparent until you hover over it? So far, if you edited the data attributes, you could -change each split to receive only tagged messages ( data-tag=“all” ), and you could change them to -overwrite instead of append data ( data-update-append or data-update-overwrite )

-
-
-

Griatch Oct 13, 2017

-

I would suggest that, assuming the game dev allows the user to modify their GUI in the first place, -that modification is a “mode”. I picture that 99% of the time a user doesn’t need to modify their -interface. They only want to click whatever game-related buttons etc are present in the pane without -risk of resizing things accidentally.

-

So I’d say that normally the panes are all fixed, with minimal spacing between them, no handles etc. -But you can enter the client settings window and choose Customize GUI mode (or something like -that). When you do, then separators get handles and the dropdown menu markers appear (permanently) -in the corner of each pane. This means that if a user wants to easily tweak their window they -could stay in this mode, but they could also “lock” the gui layout at any time.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Webclient.html b/docs/0.9.5/Webclient.html deleted file mode 100644 index 3d5f4b9a0b..0000000000 --- a/docs/0.9.5/Webclient.html +++ /dev/null @@ -1,388 +0,0 @@ - - - - - - - - - Webclient — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Webclient

-
-
-

Web client

-

Evennia comes with a MUD client accessible from a normal web browser. During development you can try -it at http://localhost:4001/webclient. The client consists of several parts, all under -evennia/web/webclient/:

-

templates/webclient/webclient.html and templates/webclient/base.html are the very simplistic -django html templates describing the webclient layout.

-

static/webclient/js/evennia.js is the main evennia javascript library. This handles all -communication between Evennia and the client over websockets and via AJAX/COMET if the browser can’t -handle websockets. It will make the Evennia object available to the javascript namespace, which -offers methods for sending and receiving data to/from the server transparently. This is intended to -be used also if swapping out the gui front end.

-

static/webclient/js/webclient_gui.js is the default plugin manager. It adds the plugins and -plugin_manager objects to the javascript namespace, coordinates the GUI operations between the -various plugins, and uses the Evennia object library for all in/out.

-

static/webclient/js/plugins provides a default set of plugins that implement a “telnet-like” -interface.

-

static/webclient/css/webclient.css is the CSS file for the client; it also defines things like how -to display ANSI/Xterm256 colors etc.

-

The server-side webclient protocols are found in evennia/server/portal/webclient.py and -webclient_ajax.py for the two types of connections. You can’t (and should not need to) modify -these.

-
-

Customizing the web client

-

Like was the case for the website, you override the webclient from your game directory. You need to -add/modify a file in the matching directory location within one of the _overrides directories. -These _override directories are NOT directly used by the web server when the game is running, the -server copies everything web related in the Evennia folder over to mygame/web/static/ and then -copies in all of your _overrides. This can cause some cases were you edit a file, but it doesn’t -seem to make any difference in the servers behavior. Before doing anything else, try shutting -down the game and running evennia collectstatic from the command line then start it back up, clear -your browser cache, and see if your edit shows up.

-

Example: To change the utilized plugin list, you need to override base.html by copying -evennia/web/webclient/templates/webclient/base.html to -mygame/web/template_overrides/webclient/base.html and editing it to add your new plugin.

-
-
-
-

Evennia Web Client API (from evennia.js)

-
    -
  • Evennia.init( opts )

  • -
  • Evennia.connect()

  • -
  • Evennia.isConnected()

  • -
  • Evennia.msg( cmdname, args, kwargs, callback )

  • -
  • Evennia.emit( cmdname, args, kwargs )

  • -
  • log()

  • -
-
-
-

Plugin Manager API (from webclient_gui.js)

-
    -
  • options Object, Stores key/value ‘state’ that can be used by plugins to coordinate behavior.

  • -
  • plugins Object, key/value list of the all the loaded plugins.

  • -
  • plugin_handler Object

    -
      -
    • plugin_handler.add("name", plugin)

    • -
    • plugin_handler.onSend(string)

    • -
    -
  • -
-
-
-

Plugin callbacks API

-
    -
  • init() – The only required callback

  • -
  • boolean onKeydown(event) This plugin listens for Keydown events

  • -
  • onBeforeUnload() This plugin does something special just before the webclient page/tab is -closed.

  • -
  • onLoggedIn(args, kwargs) This plugin does something when the webclient first logs in.

  • -
  • onGotOptions(args, kwargs) This plugin does something with options sent from the server.

  • -
  • boolean onText(args, kwargs) This plugin does something with messages sent from the server.

  • -
  • boolean onPrompt(args, kwargs) This plugin does something when the server sends a prompt.

  • -
  • boolean onUnknownCmd(cmdname, args, kwargs) This plugin does something with “unknown commands”.

  • -
  • onConnectionClose(args, kwargs) This plugin does something when the webclient disconnects from -the server.

  • -
  • newstring onSend(string) This plugin examines/alters text that other plugins generate. Use -with caution

  • -
-

The order of the plugins defined in base.html is important. All the callbacks for each plugin -will be executed in that order. Functions marked “boolean” above must return true/false. Returning -true will short-circuit the execution, so no other plugins lower in the base.html list will have -their callback for this event called. This enables things like the up/down arrow keys for the -history.js plugin to always occur before the default_in.js plugin adds that key to the current input -buffer.

-
-
-

Example/Default Plugins (plugins/*.js)

-
    -
  • clienthelp.js Defines onOptionsUI from the options2 plugin. This is a mostly empty plugin to -add some “How To” information for your game.

  • -
  • default_in.js Defines onKeydown. key or mouse clicking the arrow will send the currently -typed text.

  • -
  • default_out.js Defines onText, onPrompt, and onUnknownCmd. Generates HTML output for the user.

  • -
  • default_unload.js Defines onBeforeUnload. Prompts the user to confirm that they meant to -leave/close the game.

  • -
  • font.js Defines onOptionsUI. The plugin adds the ability to select your font and font size.

  • -
  • goldenlayout_default_config.js Not actually a plugin, defines a global variable that -goldenlayout uses to determine its window layout, known tag routing, etc.

  • -
  • goldenlayout.js Defines onKeydown, onText and custom functions. A very powerful “tabbed” window -manager for drag-n-drop windows, text routing and more.

  • -
  • history.js Defines onKeydown and onSend. Creates a history of past sent commands, and uses arrow -keys to peruse.

  • -
  • hotbuttons.js Defines onGotOptions. A Disabled-by-default plugin that defines a button bar with -user-assignable commands.

  • -
  • iframe.js Defines onOptionsUI. A goldenlayout-only plugin to create a restricted browsing sub- -window for a side-by-side web/text interface, mostly an example of how to build new HTML -“components” for goldenlayout.

  • -
  • message_routing.js Defines onOptionsUI, onText, onKeydown. This goldenlayout-only plugin -implements regex matching to allow users to “tag” arbitrary text that matches, so that it gets -routed to proper windows. Similar to “Spawn” functions for other clients.

  • -
  • multimedia.js An basic plugin to allow the client to handle “image” “audio” and “video” messages -from the server and display them as inline HTML.

  • -
  • notifications.js Defines onText. Generates browser notification events for each new message -while the tab is hidden.

  • -
  • oob.js Defines onSend. Allows the user to test/send Out Of Band json messages to the server.

  • -
  • options.js Defines most callbacks. Provides a popup-based UI to coordinate options settings with -the server.

  • -
  • options2.js Defines most callbacks. Provides a goldenlayout-based version of the -options/settings tab. Integrates with other plugins via the custom onOptionsUI callback.

  • -
  • popups.js Provides default popups/Dialog UI for other plugins to use.

  • -
-
-
-

Writing your own Plugins

-

So, you love the functionality of the webclient, but your game has specific types of text that need -to be separated out into their own space, visually. The Goldenlayout plugin framework can help with -this.

-
-

GoldenLayout

-

GoldenLayout is a web framework that allows web developers and their users to create their own -tabbed/windowed layouts. Windows/tabs can be click-and-dragged from location to location by -clicking on their titlebar and dragging until the “frame lines” appear. Dragging a window onto -another window’s titlebar will create a tabbed “Stack”. The Evennia goldenlayout plugin defines 3 -basic types of window: The Main window, input windows and non-main text output windows. The Main -window and the first input window are unique in that they can’t be “closed”.

-

The most basic customization is to provide your users with a default layout other than just one Main -output and the one starting input window. This is done by modifying your server’s -goldenlayout_default_config.js.

-

Start by creating a new -mygame/web/static_overrides/webclient/js/plugins/goldenlayout_default_config.js file, and adding -the following JSON variable:

-
var goldenlayout_config = {
-    content: [{
-        type: 'column',
-        content: [{
-            type: 'row',
-            content: [{
-                type: 'column',
-                content: [{
-                    type: 'component',
-                    componentName: 'Main',
-                    isClosable: false,
-                    tooltip: 'Main - drag to desired position.',
-                    componentState: {
-                        cssClass: 'content',
-                        types: 'untagged',
-                        updateMethod: 'newlines',
-                    },
-                }, {
-                    type: 'component',
-                    componentName: 'input',
-                    id: 'inputComponent',
-                    height: 10,
-                    tooltip: 'Input - The last input in the layout is always the default.',
-                }, {
-                    type: 'component',
-                    componentName: 'input',
-                    id: 'inputComponent',
-                    height: 10,
-                    isClosable: false,
-                    tooltip: 'Input - The last input in the layout is always the default.',
-                }]
-            },{
-                type: 'column',
-                content: [{
-                    type: 'component',
-                    componentName: 'evennia',
-                    componentId: 'evennia',
-                    title: 'example',
-                    height: 60,
-                    isClosable: false,
-                    componentState: {
-                        types: 'some-tag-here another-tag-here',
-                        updateMethod: 'newlines',
-                    },
-                }, {
-                    type: 'component',
-                    componentName: 'evennia',
-                    componentId: 'evennia',
-                    title: 'sheet',
-                    isClosable: false,
-                    componentState: {
-                        types: 'sheet',
-                        updateMethod: 'replace',
-                    },
-                }],
-            }],
-        }]
-    }]
-};
-
-
-

This is a bit ugly, but hopefully, from the indentation, you can see that it creates a side-by-side -(2-column) interface with 3 windows down the left side (The Main and 2 inputs) and a pair of windows -on the right side for extra outputs. Any text tagged with “some-tag-here” will flow to the bottom -of the “example” window, and any text tagged “sheet” will replace the text already in the “sheet” -window.

-

Note: GoldenLayout gets VERY confused and will break if you create two windows with the “Main” -componentName.

-

Now, let’s say you want to display text on each window using different CSS. This is where new -goldenlayout “components” come in. Each component is like a blueprint that gets stamped out when -you create a new instance of that component, once it is defined, it won’t be easily altered. You -will need to define a new component, preferably in a new plugin file, and then add that into your -page (either dynamically to the DOM via javascript, or by including the new plugin file into the -base.html).

-

First up, follow the directions in Customizing the Web Client section above to override the -base.html.

-

Next, add the new plugin to your copy of base.html:

-
<script src={% static "webclient/js/plugins/myplugin.js" %} language="javascript"
-type="text/javascript"></script>
-
-
-

Remember, plugins are load-order dependent, so make sure the new <script> tag comes before the -goldenlayout.js

-

Next, create a new plugin file mygame/web/static_overrides/webclient/js/plugins/myplugin.js and -edit it.

-
let myplugin = (function () {
-    //
-    //
-    var postInit = function() {
-        var myLayout = window.plugins['goldenlayout'].getGL();
-
-        // register our component and replace the default messagewindow
-        myLayout.registerComponent( 'mycomponent', function (container, componentState) {
-            let mycssdiv = $('<div>').addClass('content myCSS');
-            mycssdiv.attr('types', 'mytag1 mytag2');
-            mycssdiv.attr('updateMethod', 'newlines');
-            mycssdiv.appendTo( container.getElement() );
-            container.on("tab", plugins['goldenlayout'].onTabCreate);
-        });
-
-        console.log("MyPlugin Initialized.");
-    }
-
-    return {
-        init: function () {},
-        postInit: postInit,
-    }
-})();
-window.plugin_handler.add("myplugin", myplugin);
-
-
-

You can then switch componentName: 'evennia' with componentName: 'mycomponent' in your -goldenlayout_default_config.js (and update the tags: to match).

-

When you tag text with mytag1, it will then be sent to the mycomponent pane. Example: -caller.msg(("Text with a type.", {"type": "mytag1"}))

-

Make sure to run evennia stop, evennia collectstatic, and evennia start. Then make sure to -clear your browser cache before loading the webclient page.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Wiki-Index.html b/docs/0.9.5/Wiki-Index.html deleted file mode 100644 index b5e52677a6..0000000000 --- a/docs/0.9.5/Wiki-Index.html +++ /dev/null @@ -1,326 +0,0 @@ - - - - - - - - - Wiki Index — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Wiki Index

-

This wiki index is automatically generated. Do not modify, your changes will be lost.

-
-

A-Z

-

There are 141 entries in the wiki.

- -
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/Zones.html b/docs/0.9.5/Zones.html deleted file mode 100644 index c475511ca5..0000000000 --- a/docs/0.9.5/Zones.html +++ /dev/null @@ -1,165 +0,0 @@ - - - - - - - - - Zones — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

Zones

-

Say you create a room named Meadow in your nice big forest MUD. That’s all nice and dandy, but -what if you, in the other end of that forest want another Meadow? As a game creator, this can -cause all sorts of confusion. For example, teleporting to Meadow will now give you a warning that -there are two Meadow s and you have to select which one. It’s no problem to do that, you just -choose for example to go to 2-meadow, but unless you examine them you couldn’t be sure which of -the two sat in the magical part of the forest and which didn’t.

-

Another issue is if you want to group rooms in geographic regions. Let’s say the “normal” part of -the forest should have separate weather patterns from the magical part. Or maybe a magical -disturbance echoes through all magical-forest rooms. It would then be convenient to be able to -simply find all rooms that are “magical” so you could send messages to them.

-
-

Zones in Evennia

-

Zones try to separate rooms by global location. In our example we would separate the forest into -two parts - the magical and the non-magical part. Each have a Meadow and rooms belonging to each -part should be easy to retrieve.

-

Many MUD codebases hardcode zones as part of the engine and database. Evennia does no such -distinction due to the fact that rooms themselves are meant to be customized to any level anyway. -Below is a suggestion for how to implement zones in Evennia.

-

All objects in Evennia can hold any number of Tags. Tags are short labels that you attach to -objects. They make it very easy to retrieve groups of objects. An object can have any number of -different tags. So let’s attach the relevant tag to our forest:

-
     forestobj.tags.add("magicalforest", category="zone")
-
-
-

You could add this manually, or automatically during creation somehow (you’d need to modify your -@dig command for this, most likely). You can also use the default @tag command during building:

-
 @tag forestobj = magicalforest : zone
-
-
-

Henceforth you can then easily retrieve only objects with a given tag:

-
     import evennia
-     rooms = evennia.search_tag("magicalforest", category="zone")
-
-
-
-
-

Using typeclasses and inheritance for zoning

-

The tagging or aliasing systems above don’t instill any sort of functional difference between a -magical forest room and a normal one - they are just arbitrary ways to mark objects for quick -retrieval later. Any functional differences must be expressed using Typeclasses.

-

Of course, an alternative way to implement zones themselves is to have all rooms/objects in a zone -inherit from a given typeclass parent - and then limit your searches to objects inheriting from that -given parent. The effect would be similar but you’d need to expand the search functionality to -properly search the inheritance tree.

-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/django/conf.html b/docs/0.9.5/_modules/django/conf.html deleted file mode 100644 index 4c8ca8dc45..0000000000 --- a/docs/0.9.5/_modules/django/conf.html +++ /dev/null @@ -1,376 +0,0 @@ - - - - - - - - django.conf — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for django.conf

-"""
-Settings and configuration for Django.
-
-Read values from the module specified by the DJANGO_SETTINGS_MODULE environment
-variable, and then from django.conf.global_settings; see the global_settings.py
-for a list of all possible variables.
-"""
-
-import importlib
-import os
-import time
-import traceback
-import warnings
-from pathlib import Path
-
-import django
-from django.conf import global_settings
-from django.core.exceptions import ImproperlyConfigured
-from django.utils.deprecation import RemovedInDjango40Warning
-from django.utils.functional import LazyObject, empty
-
-ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
-
-PASSWORD_RESET_TIMEOUT_DAYS_DEPRECATED_MSG = (
-    'The PASSWORD_RESET_TIMEOUT_DAYS setting is deprecated. Use '
-    'PASSWORD_RESET_TIMEOUT instead.'
-)
-
-DEFAULT_HASHING_ALGORITHM_DEPRECATED_MSG = (
-    'The DEFAULT_HASHING_ALGORITHM transitional setting is deprecated. '
-    'Support for it and tokens, cookies, sessions, and signatures that use '
-    'SHA-1 hashing algorithm will be removed in Django 4.0.'
-)
-
-
-class SettingsReference(str):
-    """
-    String subclass which references a current settings value. It's treated as
-    the value in memory but serializes to a settings.NAME attribute reference.
-    """
-    def __new__(self, value, setting_name):
-        return str.__new__(self, value)
-
-    def __init__(self, value, setting_name):
-        self.setting_name = setting_name
-
-
-class LazySettings(LazyObject):
-    """
-    A lazy proxy for either global Django settings or a custom settings object.
-    The user can manually configure settings prior to using them. Otherwise,
-    Django uses the settings module pointed to by DJANGO_SETTINGS_MODULE.
-    """
-    def _setup(self, name=None):
-        """
-        Load the settings module pointed to by the environment variable. This
-        is used the first time settings are needed, if the user hasn't
-        configured settings manually.
-        """
-        settings_module = os.environ.get(ENVIRONMENT_VARIABLE)
-        if not settings_module:
-            desc = ("setting %s" % name) if name else "settings"
-            raise ImproperlyConfigured(
-                "Requested %s, but settings are not configured. "
-                "You must either define the environment variable %s "
-                "or call settings.configure() before accessing settings."
-                % (desc, ENVIRONMENT_VARIABLE))
-
-        self._wrapped = Settings(settings_module)
-
-    def __repr__(self):
-        # Hardcode the class name as otherwise it yields 'Settings'.
-        if self._wrapped is empty:
-            return '<LazySettings [Unevaluated]>'
-        return '<LazySettings "%(settings_module)s">' % {
-            'settings_module': self._wrapped.SETTINGS_MODULE,
-        }
-
-    def __getattr__(self, name):
-        """Return the value of a setting and cache it in self.__dict__."""
-        if self._wrapped is empty:
-            self._setup(name)
-        val = getattr(self._wrapped, name)
-
-        # Special case some settings which require further modification.
-        # This is done here for performance reasons so the modified value is cached.
-        if name in {'MEDIA_URL', 'STATIC_URL'} and val is not None:
-            val = self._add_script_prefix(val)
-        elif name == 'SECRET_KEY' and not val:
-            raise ImproperlyConfigured("The SECRET_KEY setting must not be empty.")
-
-        self.__dict__[name] = val
-        return val
-
-    def __setattr__(self, name, value):
-        """
-        Set the value of setting. Clear all cached values if _wrapped changes
-        (@override_settings does this) or clear single values when set.
-        """
-        if name == '_wrapped':
-            self.__dict__.clear()
-        else:
-            self.__dict__.pop(name, None)
-        super().__setattr__(name, value)
-
-    def __delattr__(self, name):
-        """Delete a setting and clear it from cache if needed."""
-        super().__delattr__(name)
-        self.__dict__.pop(name, None)
-
-    def configure(self, default_settings=global_settings, **options):
-        """
-        Called to manually configure the settings. The 'default_settings'
-        parameter sets where to retrieve any unspecified values from (its
-        argument must support attribute access (__getattr__)).
-        """
-        if self._wrapped is not empty:
-            raise RuntimeError('Settings already configured.')
-        holder = UserSettingsHolder(default_settings)
-        for name, value in options.items():
-            if not name.isupper():
-                raise TypeError('Setting %r must be uppercase.' % name)
-            setattr(holder, name, value)
-        self._wrapped = holder
-
-    @staticmethod
-    def _add_script_prefix(value):
-        """
-        Add SCRIPT_NAME prefix to relative paths.
-
-        Useful when the app is being served at a subpath and manually prefixing
-        subpath to STATIC_URL and MEDIA_URL in settings is inconvenient.
-        """
-        # Don't apply prefix to absolute paths and URLs.
-        if value.startswith(('http://', 'https://', '/')):
-            return value
-        from django.urls import get_script_prefix
-        return '%s%s' % (get_script_prefix(), value)
-
-    @property
-    def configured(self):
-        """Return True if the settings have already been configured."""
-        return self._wrapped is not empty
-
-    @property
-    def PASSWORD_RESET_TIMEOUT_DAYS(self):
-        stack = traceback.extract_stack()
-        # Show a warning if the setting is used outside of Django.
-        # Stack index: -1 this line, -2 the caller.
-        filename, _, _, _ = stack[-2]
-        if not filename.startswith(os.path.dirname(django.__file__)):
-            warnings.warn(
-                PASSWORD_RESET_TIMEOUT_DAYS_DEPRECATED_MSG,
-                RemovedInDjango40Warning,
-                stacklevel=2,
-            )
-        return self.__getattr__('PASSWORD_RESET_TIMEOUT_DAYS')
-
-
-class Settings:
-    def __init__(self, settings_module):
-        # update this dict from global settings (but only for ALL_CAPS settings)
-        for setting in dir(global_settings):
-            if setting.isupper():
-                setattr(self, setting, getattr(global_settings, setting))
-
-        # store the settings module in case someone later cares
-        self.SETTINGS_MODULE = settings_module
-
-        mod = importlib.import_module(self.SETTINGS_MODULE)
-
-        tuple_settings = (
-            "INSTALLED_APPS",
-            "TEMPLATE_DIRS",
-            "LOCALE_PATHS",
-        )
-        self._explicit_settings = set()
-        for setting in dir(mod):
-            if setting.isupper():
-                setting_value = getattr(mod, setting)
-
-                if (setting in tuple_settings and
-                        not isinstance(setting_value, (list, tuple))):
-                    raise ImproperlyConfigured("The %s setting must be a list or a tuple. " % setting)
-                setattr(self, setting, setting_value)
-                self._explicit_settings.add(setting)
-
-        if self.is_overridden('PASSWORD_RESET_TIMEOUT_DAYS'):
-            if self.is_overridden('PASSWORD_RESET_TIMEOUT'):
-                raise ImproperlyConfigured(
-                    'PASSWORD_RESET_TIMEOUT_DAYS/PASSWORD_RESET_TIMEOUT are '
-                    'mutually exclusive.'
-                )
-            setattr(self, 'PASSWORD_RESET_TIMEOUT', self.PASSWORD_RESET_TIMEOUT_DAYS * 60 * 60 * 24)
-            warnings.warn(PASSWORD_RESET_TIMEOUT_DAYS_DEPRECATED_MSG, RemovedInDjango40Warning)
-
-        if self.is_overridden('DEFAULT_HASHING_ALGORITHM'):
-            warnings.warn(DEFAULT_HASHING_ALGORITHM_DEPRECATED_MSG, RemovedInDjango40Warning)
-
-        if hasattr(time, 'tzset') and self.TIME_ZONE:
-            # When we can, attempt to validate the timezone. If we can't find
-            # this file, no check happens and it's harmless.
-            zoneinfo_root = Path('/usr/share/zoneinfo')
-            zone_info_file = zoneinfo_root.joinpath(*self.TIME_ZONE.split('/'))
-            if zoneinfo_root.exists() and not zone_info_file.exists():
-                raise ValueError("Incorrect timezone setting: %s" % self.TIME_ZONE)
-            # Move the time zone info into os.environ. See ticket #2315 for why
-            # we don't do this unconditionally (breaks Windows).
-            os.environ['TZ'] = self.TIME_ZONE
-            time.tzset()
-
-    def is_overridden(self, setting):
-        return setting in self._explicit_settings
-
-    def __repr__(self):
-        return '<%(cls)s "%(settings_module)s">' % {
-            'cls': self.__class__.__name__,
-            'settings_module': self.SETTINGS_MODULE,
-        }
-
-
-class UserSettingsHolder:
-    """Holder for user configured settings."""
-    # SETTINGS_MODULE doesn't make much sense in the manually configured
-    # (standalone) case.
-    SETTINGS_MODULE = None
-
-    def __init__(self, default_settings):
-        """
-        Requests for configuration variables not in this class are satisfied
-        from the module specified in default_settings (if possible).
-        """
-        self.__dict__['_deleted'] = set()
-        self.default_settings = default_settings
-
-    def __getattr__(self, name):
-        if not name.isupper() or name in self._deleted:
-            raise AttributeError
-        return getattr(self.default_settings, name)
-
-    def __setattr__(self, name, value):
-        self._deleted.discard(name)
-        if name == 'PASSWORD_RESET_TIMEOUT_DAYS':
-            setattr(self, 'PASSWORD_RESET_TIMEOUT', value * 60 * 60 * 24)
-            warnings.warn(PASSWORD_RESET_TIMEOUT_DAYS_DEPRECATED_MSG, RemovedInDjango40Warning)
-        if name == 'DEFAULT_HASHING_ALGORITHM':
-            warnings.warn(DEFAULT_HASHING_ALGORITHM_DEPRECATED_MSG, RemovedInDjango40Warning)
-        super().__setattr__(name, value)
-
-    def __delattr__(self, name):
-        self._deleted.add(name)
-        if hasattr(self, name):
-            super().__delattr__(name)
-
-    def __dir__(self):
-        return sorted(
-            s for s in [*self.__dict__, *dir(self.default_settings)]
-            if s not in self._deleted
-        )
-
-    def is_overridden(self, setting):
-        deleted = (setting in self._deleted)
-        set_locally = (setting in self.__dict__)
-        set_on_default = getattr(self.default_settings, 'is_overridden', lambda s: False)(setting)
-        return deleted or set_locally or set_on_default
-
-    def __repr__(self):
-        return '<%(cls)s>' % {
-            'cls': self.__class__.__name__,
-        }
-
-
-settings = LazySettings()
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/django/db/models/fields/related_descriptors.html b/docs/0.9.5/_modules/django/db/models/fields/related_descriptors.html deleted file mode 100644 index 92c73afde5..0000000000 --- a/docs/0.9.5/_modules/django/db/models/fields/related_descriptors.html +++ /dev/null @@ -1,1308 +0,0 @@ - - - - - - - - django.db.models.fields.related_descriptors — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for django.db.models.fields.related_descriptors

-"""
-Accessors for related objects.
-
-When a field defines a relation between two models, each model class provides
-an attribute to access related instances of the other model class (unless the
-reverse accessor has been disabled with related_name='+').
-
-Accessors are implemented as descriptors in order to customize access and
-assignment. This module defines the descriptor classes.
-
-Forward accessors follow foreign keys. Reverse accessors trace them back. For
-example, with the following models::
-
-    class Parent(Model):
-        pass
-
-    class Child(Model):
-        parent = ForeignKey(Parent, related_name='children')
-
- ``child.parent`` is a forward many-to-one relation. ``parent.children`` is a
-reverse many-to-one relation.
-
-There are three types of relations (many-to-one, one-to-one, and many-to-many)
-and two directions (forward and reverse) for a total of six combinations.
-
-1. Related instance on the forward side of a many-to-one relation:
-   ``ForwardManyToOneDescriptor``.
-
-   Uniqueness of foreign key values is irrelevant to accessing the related
-   instance, making the many-to-one and one-to-one cases identical as far as
-   the descriptor is concerned. The constraint is checked upstream (unicity
-   validation in forms) or downstream (unique indexes in the database).
-
-2. Related instance on the forward side of a one-to-one
-   relation: ``ForwardOneToOneDescriptor``.
-
-   It avoids querying the database when accessing the parent link field in
-   a multi-table inheritance scenario.
-
-3. Related instance on the reverse side of a one-to-one relation:
-   ``ReverseOneToOneDescriptor``.
-
-   One-to-one relations are asymmetrical, despite the apparent symmetry of the
-   name, because they're implemented in the database with a foreign key from
-   one table to another. As a consequence ``ReverseOneToOneDescriptor`` is
-   slightly different from ``ForwardManyToOneDescriptor``.
-
-4. Related objects manager for related instances on the reverse side of a
-   many-to-one relation: ``ReverseManyToOneDescriptor``.
-
-   Unlike the previous two classes, this one provides access to a collection
-   of objects. It returns a manager rather than an instance.
-
-5. Related objects manager for related instances on the forward or reverse
-   sides of a many-to-many relation: ``ManyToManyDescriptor``.
-
-   Many-to-many relations are symmetrical. The syntax of Django models
-   requires declaring them on one side but that's an implementation detail.
-   They could be declared on the other side without any change in behavior.
-   Therefore the forward and reverse descriptors can be the same.
-
-   If you're looking for ``ForwardManyToManyDescriptor`` or
-   ``ReverseManyToManyDescriptor``, use ``ManyToManyDescriptor`` instead.
-"""
-
-from django.core.exceptions import FieldError
-from django.db import connections, router, transaction
-from django.db.models import Q, signals
-from django.db.models.query import QuerySet
-from django.db.models.query_utils import DeferredAttribute
-from django.db.models.utils import resolve_callables
-from django.utils.functional import cached_property
-
-
-class ForeignKeyDeferredAttribute(DeferredAttribute):
-    def __set__(self, instance, value):
-        if instance.__dict__.get(self.field.attname) != value and self.field.is_cached(instance):
-            self.field.delete_cached_value(instance)
-        instance.__dict__[self.field.attname] = value
-
-
-class ForwardManyToOneDescriptor:
-    """
-    Accessor to the related object on the forward side of a many-to-one or
-    one-to-one (via ForwardOneToOneDescriptor subclass) relation.
-
-    In the example::
-
-        class Child(Model):
-            parent = ForeignKey(Parent, related_name='children')
-
-    ``Child.parent`` is a ``ForwardManyToOneDescriptor`` instance.
-    """
-
-    def __init__(self, field_with_rel):
-        self.field = field_with_rel
-
-    @cached_property
-    def RelatedObjectDoesNotExist(self):
-        # The exception can't be created at initialization time since the
-        # related model might not be resolved yet; `self.field.model` might
-        # still be a string model reference.
-        return type(
-            'RelatedObjectDoesNotExist',
-            (self.field.remote_field.model.DoesNotExist, AttributeError), {
-                '__module__': self.field.model.__module__,
-                '__qualname__': '%s.%s.RelatedObjectDoesNotExist' % (
-                    self.field.model.__qualname__,
-                    self.field.name,
-                ),
-            }
-        )
-
-    def is_cached(self, instance):
-        return self.field.is_cached(instance)
-
-    def get_queryset(self, **hints):
-        return self.field.remote_field.model._base_manager.db_manager(hints=hints).all()
-
-    def get_prefetch_queryset(self, instances, queryset=None):
-        if queryset is None:
-            queryset = self.get_queryset()
-        queryset._add_hints(instance=instances[0])
-
-        rel_obj_attr = self.field.get_foreign_related_value
-        instance_attr = self.field.get_local_related_value
-        instances_dict = {instance_attr(inst): inst for inst in instances}
-        related_field = self.field.foreign_related_fields[0]
-        remote_field = self.field.remote_field
-
-        # FIXME: This will need to be revisited when we introduce support for
-        # composite fields. In the meantime we take this practical approach to
-        # solve a regression on 1.6 when the reverse manager in hidden
-        # (related_name ends with a '+'). Refs #21410.
-        # The check for len(...) == 1 is a special case that allows the query
-        # to be join-less and smaller. Refs #21760.
-        if remote_field.is_hidden() or len(self.field.foreign_related_fields) == 1:
-            query = {'%s__in' % related_field.name: {instance_attr(inst)[0] for inst in instances}}
-        else:
-            query = {'%s__in' % self.field.related_query_name(): instances}
-        queryset = queryset.filter(**query)
-
-        # Since we're going to assign directly in the cache,
-        # we must manage the reverse relation cache manually.
-        if not remote_field.multiple:
-            for rel_obj in queryset:
-                instance = instances_dict[rel_obj_attr(rel_obj)]
-                remote_field.set_cached_value(rel_obj, instance)
-        return queryset, rel_obj_attr, instance_attr, True, self.field.get_cache_name(), False
-
-    def get_object(self, instance):
-        qs = self.get_queryset(instance=instance)
-        # Assuming the database enforces foreign keys, this won't fail.
-        return qs.get(self.field.get_reverse_related_filter(instance))
-
-    def __get__(self, instance, cls=None):
-        """
-        Get the related instance through the forward relation.
-
-        With the example above, when getting ``child.parent``:
-
-        - ``self`` is the descriptor managing the ``parent`` attribute
-        - ``instance`` is the ``child`` instance
-        - ``cls`` is the ``Child`` class (we don't need it)
-        """
-        if instance is None:
-            return self
-
-        # The related instance is loaded from the database and then cached
-        # by the field on the model instance state. It can also be pre-cached
-        # by the reverse accessor (ReverseOneToOneDescriptor).
-        try:
-            rel_obj = self.field.get_cached_value(instance)
-        except KeyError:
-            has_value = None not in self.field.get_local_related_value(instance)
-            ancestor_link = instance._meta.get_ancestor_link(self.field.model) if has_value else None
-            if ancestor_link and ancestor_link.is_cached(instance):
-                # An ancestor link will exist if this field is defined on a
-                # multi-table inheritance parent of the instance's class.
-                ancestor = ancestor_link.get_cached_value(instance)
-                # The value might be cached on an ancestor if the instance
-                # originated from walking down the inheritance chain.
-                rel_obj = self.field.get_cached_value(ancestor, default=None)
-            else:
-                rel_obj = None
-            if rel_obj is None and has_value:
-                rel_obj = self.get_object(instance)
-                remote_field = self.field.remote_field
-                # If this is a one-to-one relation, set the reverse accessor
-                # cache on the related object to the current instance to avoid
-                # an extra SQL query if it's accessed later on.
-                if not remote_field.multiple:
-                    remote_field.set_cached_value(rel_obj, instance)
-            self.field.set_cached_value(instance, rel_obj)
-
-        if rel_obj is None and not self.field.null:
-            raise self.RelatedObjectDoesNotExist(
-                "%s has no %s." % (self.field.model.__name__, self.field.name)
-            )
-        else:
-            return rel_obj
-
-    def __set__(self, instance, value):
-        """
-        Set the related instance through the forward relation.
-
-        With the example above, when setting ``child.parent = parent``:
-
-        - ``self`` is the descriptor managing the ``parent`` attribute
-        - ``instance`` is the ``child`` instance
-        - ``value`` is the ``parent`` instance on the right of the equal sign
-        """
-        # An object must be an instance of the related class.
-        if value is not None and not isinstance(value, self.field.remote_field.model._meta.concrete_model):
-            raise ValueError(
-                'Cannot assign "%r": "%s.%s" must be a "%s" instance.' % (
-                    value,
-                    instance._meta.object_name,
-                    self.field.name,
-                    self.field.remote_field.model._meta.object_name,
-                )
-            )
-        elif value is not None:
-            if instance._state.db is None:
-                instance._state.db = router.db_for_write(instance.__class__, instance=value)
-            if value._state.db is None:
-                value._state.db = router.db_for_write(value.__class__, instance=instance)
-            if not router.allow_relation(value, instance):
-                raise ValueError('Cannot assign "%r": the current database router prevents this relation.' % value)
-
-        remote_field = self.field.remote_field
-        # If we're setting the value of a OneToOneField to None, we need to clear
-        # out the cache on any old related object. Otherwise, deleting the
-        # previously-related object will also cause this object to be deleted,
-        # which is wrong.
-        if value is None:
-            # Look up the previously-related object, which may still be available
-            # since we've not yet cleared out the related field.
-            # Use the cache directly, instead of the accessor; if we haven't
-            # populated the cache, then we don't care - we're only accessing
-            # the object to invalidate the accessor cache, so there's no
-            # need to populate the cache just to expire it again.
-            related = self.field.get_cached_value(instance, default=None)
-
-            # If we've got an old related object, we need to clear out its
-            # cache. This cache also might not exist if the related object
-            # hasn't been accessed yet.
-            if related is not None:
-                remote_field.set_cached_value(related, None)
-
-            for lh_field, rh_field in self.field.related_fields:
-                setattr(instance, lh_field.attname, None)
-
-        # Set the values of the related field.
-        else:
-            for lh_field, rh_field in self.field.related_fields:
-                setattr(instance, lh_field.attname, getattr(value, rh_field.attname))
-
-        # Set the related instance cache used by __get__ to avoid an SQL query
-        # when accessing the attribute we just set.
-        self.field.set_cached_value(instance, value)
-
-        # If this is a one-to-one relation, set the reverse accessor cache on
-        # the related object to the current instance to avoid an extra SQL
-        # query if it's accessed later on.
-        if value is not None and not remote_field.multiple:
-            remote_field.set_cached_value(value, instance)
-
-    def __reduce__(self):
-        """
-        Pickling should return the instance attached by self.field on the
-        model, not a new copy of that descriptor. Use getattr() to retrieve
-        the instance directly from the model.
-        """
-        return getattr, (self.field.model, self.field.name)
-
-
-class ForwardOneToOneDescriptor(ForwardManyToOneDescriptor):
-    """
-    Accessor to the related object on the forward side of a one-to-one relation.
-
-    In the example::
-
-        class Restaurant(Model):
-            place = OneToOneField(Place, related_name='restaurant')
-
-    ``Restaurant.place`` is a ``ForwardOneToOneDescriptor`` instance.
-    """
-
-    def get_object(self, instance):
-        if self.field.remote_field.parent_link:
-            deferred = instance.get_deferred_fields()
-            # Because it's a parent link, all the data is available in the
-            # instance, so populate the parent model with this data.
-            rel_model = self.field.remote_field.model
-            fields = [field.attname for field in rel_model._meta.concrete_fields]
-
-            # If any of the related model's fields are deferred, fallback to
-            # fetching all fields from the related model. This avoids a query
-            # on the related model for every deferred field.
-            if not any(field in fields for field in deferred):
-                kwargs = {field: getattr(instance, field) for field in fields}
-                obj = rel_model(**kwargs)
-                obj._state.adding = instance._state.adding
-                obj._state.db = instance._state.db
-                return obj
-        return super().get_object(instance)
-
-    def __set__(self, instance, value):
-        super().__set__(instance, value)
-        # If the primary key is a link to a parent model and a parent instance
-        # is being set, update the value of the inherited pk(s).
-        if self.field.primary_key and self.field.remote_field.parent_link:
-            opts = instance._meta
-            # Inherited primary key fields from this object's base classes.
-            inherited_pk_fields = [
-                field for field in opts.concrete_fields
-                if field.primary_key and field.remote_field
-            ]
-            for field in inherited_pk_fields:
-                rel_model_pk_name = field.remote_field.model._meta.pk.attname
-                raw_value = getattr(value, rel_model_pk_name) if value is not None else None
-                setattr(instance, rel_model_pk_name, raw_value)
-
-
-class ReverseOneToOneDescriptor:
-    """
-    Accessor to the related object on the reverse side of a one-to-one
-    relation.
-
-    In the example::
-
-        class Restaurant(Model):
-            place = OneToOneField(Place, related_name='restaurant')
-
-    ``Place.restaurant`` is a ``ReverseOneToOneDescriptor`` instance.
-    """
-
-    def __init__(self, related):
-        # Following the example above, `related` is an instance of OneToOneRel
-        # which represents the reverse restaurant field (place.restaurant).
-        self.related = related
-
-    @cached_property
-    def RelatedObjectDoesNotExist(self):
-        # The exception isn't created at initialization time for the sake of
-        # consistency with `ForwardManyToOneDescriptor`.
-        return type(
-            'RelatedObjectDoesNotExist',
-            (self.related.related_model.DoesNotExist, AttributeError), {
-                '__module__': self.related.model.__module__,
-                '__qualname__': '%s.%s.RelatedObjectDoesNotExist' % (
-                    self.related.model.__qualname__,
-                    self.related.name,
-                )
-            },
-        )
-
-    def is_cached(self, instance):
-        return self.related.is_cached(instance)
-
-    def get_queryset(self, **hints):
-        return self.related.related_model._base_manager.db_manager(hints=hints).all()
-
-    def get_prefetch_queryset(self, instances, queryset=None):
-        if queryset is None:
-            queryset = self.get_queryset()
-        queryset._add_hints(instance=instances[0])
-
-        rel_obj_attr = self.related.field.get_local_related_value
-        instance_attr = self.related.field.get_foreign_related_value
-        instances_dict = {instance_attr(inst): inst for inst in instances}
-        query = {'%s__in' % self.related.field.name: instances}
-        queryset = queryset.filter(**query)
-
-        # Since we're going to assign directly in the cache,
-        # we must manage the reverse relation cache manually.
-        for rel_obj in queryset:
-            instance = instances_dict[rel_obj_attr(rel_obj)]
-            self.related.field.set_cached_value(rel_obj, instance)
-        return queryset, rel_obj_attr, instance_attr, True, self.related.get_cache_name(), False
-
-    def __get__(self, instance, cls=None):
-        """
-        Get the related instance through the reverse relation.
-
-        With the example above, when getting ``place.restaurant``:
-
-        - ``self`` is the descriptor managing the ``restaurant`` attribute
-        - ``instance`` is the ``place`` instance
-        - ``cls`` is the ``Place`` class (unused)
-
-        Keep in mind that ``Restaurant`` holds the foreign key to ``Place``.
-        """
-        if instance is None:
-            return self
-
-        # The related instance is loaded from the database and then cached
-        # by the field on the model instance state. It can also be pre-cached
-        # by the forward accessor (ForwardManyToOneDescriptor).
-        try:
-            rel_obj = self.related.get_cached_value(instance)
-        except KeyError:
-            related_pk = instance.pk
-            if related_pk is None:
-                rel_obj = None
-            else:
-                filter_args = self.related.field.get_forward_related_filter(instance)
-                try:
-                    rel_obj = self.get_queryset(instance=instance).get(**filter_args)
-                except self.related.related_model.DoesNotExist:
-                    rel_obj = None
-                else:
-                    # Set the forward accessor cache on the related object to
-                    # the current instance to avoid an extra SQL query if it's
-                    # accessed later on.
-                    self.related.field.set_cached_value(rel_obj, instance)
-            self.related.set_cached_value(instance, rel_obj)
-
-        if rel_obj is None:
-            raise self.RelatedObjectDoesNotExist(
-                "%s has no %s." % (
-                    instance.__class__.__name__,
-                    self.related.get_accessor_name()
-                )
-            )
-        else:
-            return rel_obj
-
-    def __set__(self, instance, value):
-        """
-        Set the related instance through the reverse relation.
-
-        With the example above, when setting ``place.restaurant = restaurant``:
-
-        - ``self`` is the descriptor managing the ``restaurant`` attribute
-        - ``instance`` is the ``place`` instance
-        - ``value`` is the ``restaurant`` instance on the right of the equal sign
-
-        Keep in mind that ``Restaurant`` holds the foreign key to ``Place``.
-        """
-        # The similarity of the code below to the code in
-        # ForwardManyToOneDescriptor is annoying, but there's a bunch
-        # of small differences that would make a common base class convoluted.
-
-        if value is None:
-            # Update the cached related instance (if any) & clear the cache.
-            # Following the example above, this would be the cached
-            # ``restaurant`` instance (if any).
-            rel_obj = self.related.get_cached_value(instance, default=None)
-            if rel_obj is not None:
-                # Remove the ``restaurant`` instance from the ``place``
-                # instance cache.
-                self.related.delete_cached_value(instance)
-                # Set the ``place`` field on the ``restaurant``
-                # instance to None.
-                setattr(rel_obj, self.related.field.name, None)
-        elif not isinstance(value, self.related.related_model):
-            # An object must be an instance of the related class.
-            raise ValueError(
-                'Cannot assign "%r": "%s.%s" must be a "%s" instance.' % (
-                    value,
-                    instance._meta.object_name,
-                    self.related.get_accessor_name(),
-                    self.related.related_model._meta.object_name,
-                )
-            )
-        else:
-            if instance._state.db is None:
-                instance._state.db = router.db_for_write(instance.__class__, instance=value)
-            if value._state.db is None:
-                value._state.db = router.db_for_write(value.__class__, instance=instance)
-            if not router.allow_relation(value, instance):
-                raise ValueError('Cannot assign "%r": the current database router prevents this relation.' % value)
-
-            related_pk = tuple(getattr(instance, field.attname) for field in self.related.field.foreign_related_fields)
-            # Set the value of the related field to the value of the related object's related field
-            for index, field in enumerate(self.related.field.local_related_fields):
-                setattr(value, field.attname, related_pk[index])
-
-            # Set the related instance cache used by __get__ to avoid an SQL query
-            # when accessing the attribute we just set.
-            self.related.set_cached_value(instance, value)
-
-            # Set the forward accessor cache on the related object to the current
-            # instance to avoid an extra SQL query if it's accessed later on.
-            self.related.field.set_cached_value(value, instance)
-
-    def __reduce__(self):
-        # Same purpose as ForwardManyToOneDescriptor.__reduce__().
-        return getattr, (self.related.model, self.related.name)
-
-
-class ReverseManyToOneDescriptor:
-    """
-    Accessor to the related objects manager on the reverse side of a
-    many-to-one relation.
-
-    In the example::
-
-        class Child(Model):
-            parent = ForeignKey(Parent, related_name='children')
-
-    ``Parent.children`` is a ``ReverseManyToOneDescriptor`` instance.
-
-    Most of the implementation is delegated to a dynamically defined manager
-    class built by ``create_forward_many_to_many_manager()`` defined below.
-    """
-
-    def __init__(self, rel):
-        self.rel = rel
-        self.field = rel.field
-
-    @cached_property
-    def related_manager_cls(self):
-        related_model = self.rel.related_model
-
-        return create_reverse_many_to_one_manager(
-            related_model._default_manager.__class__,
-            self.rel,
-        )
-
-    def __get__(self, instance, cls=None):
-        """
-        Get the related objects through the reverse relation.
-
-        With the example above, when getting ``parent.children``:
-
-        - ``self`` is the descriptor managing the ``children`` attribute
-        - ``instance`` is the ``parent`` instance
-        - ``cls`` is the ``Parent`` class (unused)
-        """
-        if instance is None:
-            return self
-
-        return self.related_manager_cls(instance)
-
-    def _get_set_deprecation_msg_params(self):
-        return (
-            'reverse side of a related set',
-            self.rel.get_accessor_name(),
-        )
-
-    def __set__(self, instance, value):
-        raise TypeError(
-            'Direct assignment to the %s is prohibited. Use %s.set() instead.'
-            % self._get_set_deprecation_msg_params(),
-        )
-
-
-def create_reverse_many_to_one_manager(superclass, rel):
-    """
-    Create a manager for the reverse side of a many-to-one relation.
-
-    This manager subclasses another manager, generally the default manager of
-    the related model, and adds behaviors specific to many-to-one relations.
-    """
-
-    class RelatedManager(superclass):
-        def __init__(self, instance):
-            super().__init__()
-
-            self.instance = instance
-            self.model = rel.related_model
-            self.field = rel.field
-
-            self.core_filters = {self.field.name: instance}
-
-        def __call__(self, *, manager):
-            manager = getattr(self.model, manager)
-            manager_class = create_reverse_many_to_one_manager(manager.__class__, rel)
-            return manager_class(self.instance)
-        do_not_call_in_templates = True
-
-        def _apply_rel_filters(self, queryset):
-            """
-            Filter the queryset for the instance this manager is bound to.
-            """
-            db = self._db or router.db_for_read(self.model, instance=self.instance)
-            empty_strings_as_null = connections[db].features.interprets_empty_strings_as_nulls
-            queryset._add_hints(instance=self.instance)
-            if self._db:
-                queryset = queryset.using(self._db)
-            queryset._defer_next_filter = True
-            queryset = queryset.filter(**self.core_filters)
-            for field in self.field.foreign_related_fields:
-                val = getattr(self.instance, field.attname)
-                if val is None or (val == '' and empty_strings_as_null):
-                    return queryset.none()
-            if self.field.many_to_one:
-                # Guard against field-like objects such as GenericRelation
-                # that abuse create_reverse_many_to_one_manager() with reverse
-                # one-to-many relationships instead and break known related
-                # objects assignment.
-                try:
-                    target_field = self.field.target_field
-                except FieldError:
-                    # The relationship has multiple target fields. Use a tuple
-                    # for related object id.
-                    rel_obj_id = tuple([
-                        getattr(self.instance, target_field.attname)
-                        for target_field in self.field.get_path_info()[-1].target_fields
-                    ])
-                else:
-                    rel_obj_id = getattr(self.instance, target_field.attname)
-                queryset._known_related_objects = {self.field: {rel_obj_id: self.instance}}
-            return queryset
-
-        def _remove_prefetched_objects(self):
-            try:
-                self.instance._prefetched_objects_cache.pop(self.field.remote_field.get_cache_name())
-            except (AttributeError, KeyError):
-                pass  # nothing to clear from cache
-
-        def get_queryset(self):
-            try:
-                return self.instance._prefetched_objects_cache[self.field.remote_field.get_cache_name()]
-            except (AttributeError, KeyError):
-                queryset = super().get_queryset()
-                return self._apply_rel_filters(queryset)
-
-        def get_prefetch_queryset(self, instances, queryset=None):
-            if queryset is None:
-                queryset = super().get_queryset()
-
-            queryset._add_hints(instance=instances[0])
-            queryset = queryset.using(queryset._db or self._db)
-
-            rel_obj_attr = self.field.get_local_related_value
-            instance_attr = self.field.get_foreign_related_value
-            instances_dict = {instance_attr(inst): inst for inst in instances}
-            query = {'%s__in' % self.field.name: instances}
-            queryset = queryset.filter(**query)
-
-            # Since we just bypassed this class' get_queryset(), we must manage
-            # the reverse relation manually.
-            for rel_obj in queryset:
-                instance = instances_dict[rel_obj_attr(rel_obj)]
-                setattr(rel_obj, self.field.name, instance)
-            cache_name = self.field.remote_field.get_cache_name()
-            return queryset, rel_obj_attr, instance_attr, False, cache_name, False
-
-        def add(self, *objs, bulk=True):
-            self._remove_prefetched_objects()
-            db = router.db_for_write(self.model, instance=self.instance)
-
-            def check_and_update_obj(obj):
-                if not isinstance(obj, self.model):
-                    raise TypeError("'%s' instance expected, got %r" % (
-                        self.model._meta.object_name, obj,
-                    ))
-                setattr(obj, self.field.name, self.instance)
-
-            if bulk:
-                pks = []
-                for obj in objs:
-                    check_and_update_obj(obj)
-                    if obj._state.adding or obj._state.db != db:
-                        raise ValueError(
-                            "%r instance isn't saved. Use bulk=False or save "
-                            "the object first." % obj
-                        )
-                    pks.append(obj.pk)
-                self.model._base_manager.using(db).filter(pk__in=pks).update(**{
-                    self.field.name: self.instance,
-                })
-            else:
-                with transaction.atomic(using=db, savepoint=False):
-                    for obj in objs:
-                        check_and_update_obj(obj)
-                        obj.save()
-        add.alters_data = True
-
-        def create(self, **kwargs):
-            kwargs[self.field.name] = self.instance
-            db = router.db_for_write(self.model, instance=self.instance)
-            return super(RelatedManager, self.db_manager(db)).create(**kwargs)
-        create.alters_data = True
-
-        def get_or_create(self, **kwargs):
-            kwargs[self.field.name] = self.instance
-            db = router.db_for_write(self.model, instance=self.instance)
-            return super(RelatedManager, self.db_manager(db)).get_or_create(**kwargs)
-        get_or_create.alters_data = True
-
-        def update_or_create(self, **kwargs):
-            kwargs[self.field.name] = self.instance
-            db = router.db_for_write(self.model, instance=self.instance)
-            return super(RelatedManager, self.db_manager(db)).update_or_create(**kwargs)
-        update_or_create.alters_data = True
-
-        # remove() and clear() are only provided if the ForeignKey can have a value of null.
-        if rel.field.null:
-            def remove(self, *objs, bulk=True):
-                if not objs:
-                    return
-                val = self.field.get_foreign_related_value(self.instance)
-                old_ids = set()
-                for obj in objs:
-                    if not isinstance(obj, self.model):
-                        raise TypeError("'%s' instance expected, got %r" % (
-                            self.model._meta.object_name, obj,
-                        ))
-                    # Is obj actually part of this descriptor set?
-                    if self.field.get_local_related_value(obj) == val:
-                        old_ids.add(obj.pk)
-                    else:
-                        raise self.field.remote_field.model.DoesNotExist(
-                            "%r is not related to %r." % (obj, self.instance)
-                        )
-                self._clear(self.filter(pk__in=old_ids), bulk)
-            remove.alters_data = True
-
-            def clear(self, *, bulk=True):
-                self._clear(self, bulk)
-            clear.alters_data = True
-
-            def _clear(self, queryset, bulk):
-                self._remove_prefetched_objects()
-                db = router.db_for_write(self.model, instance=self.instance)
-                queryset = queryset.using(db)
-                if bulk:
-                    # `QuerySet.update()` is intrinsically atomic.
-                    queryset.update(**{self.field.name: None})
-                else:
-                    with transaction.atomic(using=db, savepoint=False):
-                        for obj in queryset:
-                            setattr(obj, self.field.name, None)
-                            obj.save(update_fields=[self.field.name])
-            _clear.alters_data = True
-
-        def set(self, objs, *, bulk=True, clear=False):
-            # Force evaluation of `objs` in case it's a queryset whose value
-            # could be affected by `manager.clear()`. Refs #19816.
-            objs = tuple(objs)
-
-            if self.field.null:
-                db = router.db_for_write(self.model, instance=self.instance)
-                with transaction.atomic(using=db, savepoint=False):
-                    if clear:
-                        self.clear(bulk=bulk)
-                        self.add(*objs, bulk=bulk)
-                    else:
-                        old_objs = set(self.using(db).all())
-                        new_objs = []
-                        for obj in objs:
-                            if obj in old_objs:
-                                old_objs.remove(obj)
-                            else:
-                                new_objs.append(obj)
-
-                        self.remove(*old_objs, bulk=bulk)
-                        self.add(*new_objs, bulk=bulk)
-            else:
-                self.add(*objs, bulk=bulk)
-        set.alters_data = True
-
-    return RelatedManager
-
-
-class ManyToManyDescriptor(ReverseManyToOneDescriptor):
-    """
-    Accessor to the related objects manager on the forward and reverse sides of
-    a many-to-many relation.
-
-    In the example::
-
-        class Pizza(Model):
-            toppings = ManyToManyField(Topping, related_name='pizzas')
-
-    ``Pizza.toppings`` and ``Topping.pizzas`` are ``ManyToManyDescriptor``
-    instances.
-
-    Most of the implementation is delegated to a dynamically defined manager
-    class built by ``create_forward_many_to_many_manager()`` defined below.
-    """
-
-    def __init__(self, rel, reverse=False):
-        super().__init__(rel)
-
-        self.reverse = reverse
-
-    @property
-    def through(self):
-        # through is provided so that you have easy access to the through
-        # model (Book.authors.through) for inlines, etc. This is done as
-        # a property to ensure that the fully resolved value is returned.
-        return self.rel.through
-
-    @cached_property
-    def related_manager_cls(self):
-        related_model = self.rel.related_model if self.reverse else self.rel.model
-
-        return create_forward_many_to_many_manager(
-            related_model._default_manager.__class__,
-            self.rel,
-            reverse=self.reverse,
-        )
-
-    def _get_set_deprecation_msg_params(self):
-        return (
-            '%s side of a many-to-many set' % ('reverse' if self.reverse else 'forward'),
-            self.rel.get_accessor_name() if self.reverse else self.field.name,
-        )
-
-
-def create_forward_many_to_many_manager(superclass, rel, reverse):
-    """
-    Create a manager for the either side of a many-to-many relation.
-
-    This manager subclasses another manager, generally the default manager of
-    the related model, and adds behaviors specific to many-to-many relations.
-    """
-
-    class ManyRelatedManager(superclass):
-        def __init__(self, instance=None):
-            super().__init__()
-
-            self.instance = instance
-
-            if not reverse:
-                self.model = rel.model
-                self.query_field_name = rel.field.related_query_name()
-                self.prefetch_cache_name = rel.field.name
-                self.source_field_name = rel.field.m2m_field_name()
-                self.target_field_name = rel.field.m2m_reverse_field_name()
-                self.symmetrical = rel.symmetrical
-            else:
-                self.model = rel.related_model
-                self.query_field_name = rel.field.name
-                self.prefetch_cache_name = rel.field.related_query_name()
-                self.source_field_name = rel.field.m2m_reverse_field_name()
-                self.target_field_name = rel.field.m2m_field_name()
-                self.symmetrical = False
-
-            self.through = rel.through
-            self.reverse = reverse
-
-            self.source_field = self.through._meta.get_field(self.source_field_name)
-            self.target_field = self.through._meta.get_field(self.target_field_name)
-
-            self.core_filters = {}
-            self.pk_field_names = {}
-            for lh_field, rh_field in self.source_field.related_fields:
-                core_filter_key = '%s__%s' % (self.query_field_name, rh_field.name)
-                self.core_filters[core_filter_key] = getattr(instance, rh_field.attname)
-                self.pk_field_names[lh_field.name] = rh_field.name
-
-            self.related_val = self.source_field.get_foreign_related_value(instance)
-            if None in self.related_val:
-                raise ValueError('"%r" needs to have a value for field "%s" before '
-                                 'this many-to-many relationship can be used.' %
-                                 (instance, self.pk_field_names[self.source_field_name]))
-            # Even if this relation is not to pk, we require still pk value.
-            # The wish is that the instance has been already saved to DB,
-            # although having a pk value isn't a guarantee of that.
-            if instance.pk is None:
-                raise ValueError("%r instance needs to have a primary key value before "
-                                 "a many-to-many relationship can be used." %
-                                 instance.__class__.__name__)
-
-        def __call__(self, *, manager):
-            manager = getattr(self.model, manager)
-            manager_class = create_forward_many_to_many_manager(manager.__class__, rel, reverse)
-            return manager_class(instance=self.instance)
-        do_not_call_in_templates = True
-
-        def _build_remove_filters(self, removed_vals):
-            filters = Q(**{self.source_field_name: self.related_val})
-            # No need to add a subquery condition if removed_vals is a QuerySet without
-            # filters.
-            removed_vals_filters = (not isinstance(removed_vals, QuerySet) or
-                                    removed_vals._has_filters())
-            if removed_vals_filters:
-                filters &= Q(**{'%s__in' % self.target_field_name: removed_vals})
-            if self.symmetrical:
-                symmetrical_filters = Q(**{self.target_field_name: self.related_val})
-                if removed_vals_filters:
-                    symmetrical_filters &= Q(
-                        **{'%s__in' % self.source_field_name: removed_vals})
-                filters |= symmetrical_filters
-            return filters
-
-        def _apply_rel_filters(self, queryset):
-            """
-            Filter the queryset for the instance this manager is bound to.
-            """
-            queryset._add_hints(instance=self.instance)
-            if self._db:
-                queryset = queryset.using(self._db)
-            queryset._defer_next_filter = True
-            return queryset._next_is_sticky().filter(**self.core_filters)
-
-        def _remove_prefetched_objects(self):
-            try:
-                self.instance._prefetched_objects_cache.pop(self.prefetch_cache_name)
-            except (AttributeError, KeyError):
-                pass  # nothing to clear from cache
-
-        def get_queryset(self):
-            try:
-                return self.instance._prefetched_objects_cache[self.prefetch_cache_name]
-            except (AttributeError, KeyError):
-                queryset = super().get_queryset()
-                return self._apply_rel_filters(queryset)
-
-        def get_prefetch_queryset(self, instances, queryset=None):
-            if queryset is None:
-                queryset = super().get_queryset()
-
-            queryset._add_hints(instance=instances[0])
-            queryset = queryset.using(queryset._db or self._db)
-
-            query = {'%s__in' % self.query_field_name: instances}
-            queryset = queryset._next_is_sticky().filter(**query)
-
-            # M2M: need to annotate the query in order to get the primary model
-            # that the secondary model was actually related to. We know that
-            # there will already be a join on the join table, so we can just add
-            # the select.
-
-            # For non-autocreated 'through' models, can't assume we are
-            # dealing with PK values.
-            fk = self.through._meta.get_field(self.source_field_name)
-            join_table = fk.model._meta.db_table
-            connection = connections[queryset.db]
-            qn = connection.ops.quote_name
-            queryset = queryset.extra(select={
-                '_prefetch_related_val_%s' % f.attname:
-                '%s.%s' % (qn(join_table), qn(f.column)) for f in fk.local_related_fields})
-            return (
-                queryset,
-                lambda result: tuple(
-                    getattr(result, '_prefetch_related_val_%s' % f.attname)
-                    for f in fk.local_related_fields
-                ),
-                lambda inst: tuple(
-                    f.get_db_prep_value(getattr(inst, f.attname), connection)
-                    for f in fk.foreign_related_fields
-                ),
-                False,
-                self.prefetch_cache_name,
-                False,
-            )
-
-        def add(self, *objs, through_defaults=None):
-            self._remove_prefetched_objects()
-            db = router.db_for_write(self.through, instance=self.instance)
-            with transaction.atomic(using=db, savepoint=False):
-                self._add_items(
-                    self.source_field_name, self.target_field_name, *objs,
-                    through_defaults=through_defaults,
-                )
-                # If this is a symmetrical m2m relation to self, add the mirror
-                # entry in the m2m table.
-                if self.symmetrical:
-                    self._add_items(
-                        self.target_field_name,
-                        self.source_field_name,
-                        *objs,
-                        through_defaults=through_defaults,
-                    )
-        add.alters_data = True
-
-        def remove(self, *objs):
-            self._remove_prefetched_objects()
-            self._remove_items(self.source_field_name, self.target_field_name, *objs)
-        remove.alters_data = True
-
-        def clear(self):
-            db = router.db_for_write(self.through, instance=self.instance)
-            with transaction.atomic(using=db, savepoint=False):
-                signals.m2m_changed.send(
-                    sender=self.through, action="pre_clear",
-                    instance=self.instance, reverse=self.reverse,
-                    model=self.model, pk_set=None, using=db,
-                )
-                self._remove_prefetched_objects()
-                filters = self._build_remove_filters(super().get_queryset().using(db))
-                self.through._default_manager.using(db).filter(filters).delete()
-
-                signals.m2m_changed.send(
-                    sender=self.through, action="post_clear",
-                    instance=self.instance, reverse=self.reverse,
-                    model=self.model, pk_set=None, using=db,
-                )
-        clear.alters_data = True
-
-        def set(self, objs, *, clear=False, through_defaults=None):
-            # Force evaluation of `objs` in case it's a queryset whose value
-            # could be affected by `manager.clear()`. Refs #19816.
-            objs = tuple(objs)
-
-            db = router.db_for_write(self.through, instance=self.instance)
-            with transaction.atomic(using=db, savepoint=False):
-                if clear:
-                    self.clear()
-                    self.add(*objs, through_defaults=through_defaults)
-                else:
-                    old_ids = set(self.using(db).values_list(self.target_field.target_field.attname, flat=True))
-
-                    new_objs = []
-                    for obj in objs:
-                        fk_val = (
-                            self.target_field.get_foreign_related_value(obj)[0]
-                            if isinstance(obj, self.model)
-                            else self.target_field.get_prep_value(obj)
-                        )
-                        if fk_val in old_ids:
-                            old_ids.remove(fk_val)
-                        else:
-                            new_objs.append(obj)
-
-                    self.remove(*old_ids)
-                    self.add(*new_objs, through_defaults=through_defaults)
-        set.alters_data = True
-
-        def create(self, *, through_defaults=None, **kwargs):
-            db = router.db_for_write(self.instance.__class__, instance=self.instance)
-            new_obj = super(ManyRelatedManager, self.db_manager(db)).create(**kwargs)
-            self.add(new_obj, through_defaults=through_defaults)
-            return new_obj
-        create.alters_data = True
-
-        def get_or_create(self, *, through_defaults=None, **kwargs):
-            db = router.db_for_write(self.instance.__class__, instance=self.instance)
-            obj, created = super(ManyRelatedManager, self.db_manager(db)).get_or_create(**kwargs)
-            # We only need to add() if created because if we got an object back
-            # from get() then the relationship already exists.
-            if created:
-                self.add(obj, through_defaults=through_defaults)
-            return obj, created
-        get_or_create.alters_data = True
-
-        def update_or_create(self, *, through_defaults=None, **kwargs):
-            db = router.db_for_write(self.instance.__class__, instance=self.instance)
-            obj, created = super(ManyRelatedManager, self.db_manager(db)).update_or_create(**kwargs)
-            # We only need to add() if created because if we got an object back
-            # from get() then the relationship already exists.
-            if created:
-                self.add(obj, through_defaults=through_defaults)
-            return obj, created
-        update_or_create.alters_data = True
-
-        def _get_target_ids(self, target_field_name, objs):
-            """
-            Return the set of ids of `objs` that the target field references.
-            """
-            from django.db.models import Model
-            target_ids = set()
-            target_field = self.through._meta.get_field(target_field_name)
-            for obj in objs:
-                if isinstance(obj, self.model):
-                    if not router.allow_relation(obj, self.instance):
-                        raise ValueError(
-                            'Cannot add "%r": instance is on database "%s", '
-                            'value is on database "%s"' %
-                            (obj, self.instance._state.db, obj._state.db)
-                        )
-                    target_id = target_field.get_foreign_related_value(obj)[0]
-                    if target_id is None:
-                        raise ValueError(
-                            'Cannot add "%r": the value for field "%s" is None' %
-                            (obj, target_field_name)
-                        )
-                    target_ids.add(target_id)
-                elif isinstance(obj, Model):
-                    raise TypeError(
-                        "'%s' instance expected, got %r" %
-                        (self.model._meta.object_name, obj)
-                    )
-                else:
-                    target_ids.add(target_field.get_prep_value(obj))
-            return target_ids
-
-        def _get_missing_target_ids(self, source_field_name, target_field_name, db, target_ids):
-            """
-            Return the subset of ids of `objs` that aren't already assigned to
-            this relationship.
-            """
-            vals = self.through._default_manager.using(db).values_list(
-                target_field_name, flat=True
-            ).filter(**{
-                source_field_name: self.related_val[0],
-                '%s__in' % target_field_name: target_ids,
-            })
-            return target_ids.difference(vals)
-
-        def _get_add_plan(self, db, source_field_name):
-            """
-            Return a boolean triple of the way the add should be performed.
-
-            The first element is whether or not bulk_create(ignore_conflicts)
-            can be used, the second whether or not signals must be sent, and
-            the third element is whether or not the immediate bulk insertion
-            with conflicts ignored can be performed.
-            """
-            # Conflicts can be ignored when the intermediary model is
-            # auto-created as the only possible collision is on the
-            # (source_id, target_id) tuple. The same assertion doesn't hold for
-            # user-defined intermediary models as they could have other fields
-            # causing conflicts which must be surfaced.
-            can_ignore_conflicts = (
-                connections[db].features.supports_ignore_conflicts and
-                self.through._meta.auto_created is not False
-            )
-            # Don't send the signal when inserting duplicate data row
-            # for symmetrical reverse entries.
-            must_send_signals = (self.reverse or source_field_name == self.source_field_name) and (
-                signals.m2m_changed.has_listeners(self.through)
-            )
-            # Fast addition through bulk insertion can only be performed
-            # if no m2m_changed listeners are connected for self.through
-            # as they require the added set of ids to be provided via
-            # pk_set.
-            return can_ignore_conflicts, must_send_signals, (can_ignore_conflicts and not must_send_signals)
-
-        def _add_items(self, source_field_name, target_field_name, *objs, through_defaults=None):
-            # source_field_name: the PK fieldname in join table for the source object
-            # target_field_name: the PK fieldname in join table for the target object
-            # *objs - objects to add. Either object instances, or primary keys of object instances.
-            if not objs:
-                return
-
-            through_defaults = dict(resolve_callables(through_defaults or {}))
-            target_ids = self._get_target_ids(target_field_name, objs)
-            db = router.db_for_write(self.through, instance=self.instance)
-            can_ignore_conflicts, must_send_signals, can_fast_add = self._get_add_plan(db, source_field_name)
-            if can_fast_add:
-                self.through._default_manager.using(db).bulk_create([
-                    self.through(**{
-                        '%s_id' % source_field_name: self.related_val[0],
-                        '%s_id' % target_field_name: target_id,
-                    })
-                    for target_id in target_ids
-                ], ignore_conflicts=True)
-                return
-
-            missing_target_ids = self._get_missing_target_ids(
-                source_field_name, target_field_name, db, target_ids
-            )
-            with transaction.atomic(using=db, savepoint=False):
-                if must_send_signals:
-                    signals.m2m_changed.send(
-                        sender=self.through, action='pre_add',
-                        instance=self.instance, reverse=self.reverse,
-                        model=self.model, pk_set=missing_target_ids, using=db,
-                    )
-                # Add the ones that aren't there already.
-                self.through._default_manager.using(db).bulk_create([
-                    self.through(**through_defaults, **{
-                        '%s_id' % source_field_name: self.related_val[0],
-                        '%s_id' % target_field_name: target_id,
-                    })
-                    for target_id in missing_target_ids
-                ], ignore_conflicts=can_ignore_conflicts)
-
-                if must_send_signals:
-                    signals.m2m_changed.send(
-                        sender=self.through, action='post_add',
-                        instance=self.instance, reverse=self.reverse,
-                        model=self.model, pk_set=missing_target_ids, using=db,
-                    )
-
-        def _remove_items(self, source_field_name, target_field_name, *objs):
-            # source_field_name: the PK colname in join table for the source object
-            # target_field_name: the PK colname in join table for the target object
-            # *objs - objects to remove. Either object instances, or primary
-            # keys of object instances.
-            if not objs:
-                return
-
-            # Check that all the objects are of the right type
-            old_ids = set()
-            for obj in objs:
-                if isinstance(obj, self.model):
-                    fk_val = self.target_field.get_foreign_related_value(obj)[0]
-                    old_ids.add(fk_val)
-                else:
-                    old_ids.add(obj)
-
-            db = router.db_for_write(self.through, instance=self.instance)
-            with transaction.atomic(using=db, savepoint=False):
-                # Send a signal to the other end if need be.
-                signals.m2m_changed.send(
-                    sender=self.through, action="pre_remove",
-                    instance=self.instance, reverse=self.reverse,
-                    model=self.model, pk_set=old_ids, using=db,
-                )
-                target_model_qs = super().get_queryset()
-                if target_model_qs._has_filters():
-                    old_vals = target_model_qs.using(db).filter(**{
-                        '%s__in' % self.target_field.target_field.attname: old_ids})
-                else:
-                    old_vals = old_ids
-                filters = self._build_remove_filters(old_vals)
-                self.through._default_manager.using(db).filter(filters).delete()
-
-                signals.m2m_changed.send(
-                    sender=self.through, action="post_remove",
-                    instance=self.instance, reverse=self.reverse,
-                    model=self.model, pk_set=old_ids, using=db,
-                )
-
-    return ManyRelatedManager
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/django/db/models/manager.html b/docs/0.9.5/_modules/django/db/models/manager.html deleted file mode 100644 index 3222547381..0000000000 --- a/docs/0.9.5/_modules/django/db/models/manager.html +++ /dev/null @@ -1,306 +0,0 @@ - - - - - - - - django.db.models.manager — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for django.db.models.manager

-import copy
-import inspect
-from importlib import import_module
-
-from django.db import router
-from django.db.models.query import QuerySet
-
-
-class BaseManager:
-    # To retain order, track each time a Manager instance is created.
-    creation_counter = 0
-
-    # Set to True for the 'objects' managers that are automatically created.
-    auto_created = False
-
-    #: If set to True the manager will be serialized into migrations and will
-    #: thus be available in e.g. RunPython operations.
-    use_in_migrations = False
-
-    def __new__(cls, *args, **kwargs):
-        # Capture the arguments to make returning them trivial.
-        obj = super().__new__(cls)
-        obj._constructor_args = (args, kwargs)
-        return obj
-
-    def __init__(self):
-        super().__init__()
-        self._set_creation_counter()
-        self.model = None
-        self.name = None
-        self._db = None
-        self._hints = {}
-
-    def __str__(self):
-        """Return "app_label.model_label.manager_name"."""
-        return '%s.%s' % (self.model._meta.label, self.name)
-
-    def __class_getitem__(cls, *args, **kwargs):
-        return cls
-
-    def deconstruct(self):
-        """
-        Return a 5-tuple of the form (as_manager (True), manager_class,
-        queryset_class, args, kwargs).
-
-        Raise a ValueError if the manager is dynamically generated.
-        """
-        qs_class = self._queryset_class
-        if getattr(self, '_built_with_as_manager', False):
-            # using MyQuerySet.as_manager()
-            return (
-                True,  # as_manager
-                None,  # manager_class
-                '%s.%s' % (qs_class.__module__, qs_class.__name__),  # qs_class
-                None,  # args
-                None,  # kwargs
-            )
-        else:
-            module_name = self.__module__
-            name = self.__class__.__name__
-            # Make sure it's actually there and not an inner class
-            module = import_module(module_name)
-            if not hasattr(module, name):
-                raise ValueError(
-                    "Could not find manager %s in %s.\n"
-                    "Please note that you need to inherit from managers you "
-                    "dynamically generated with 'from_queryset()'."
-                    % (name, module_name)
-                )
-            return (
-                False,  # as_manager
-                '%s.%s' % (module_name, name),  # manager_class
-                None,  # qs_class
-                self._constructor_args[0],  # args
-                self._constructor_args[1],  # kwargs
-            )
-
-    def check(self, **kwargs):
-        return []
-
-    @classmethod
-    def _get_queryset_methods(cls, queryset_class):
-        def create_method(name, method):
-            def manager_method(self, *args, **kwargs):
-                return getattr(self.get_queryset(), name)(*args, **kwargs)
-            manager_method.__name__ = method.__name__
-            manager_method.__doc__ = method.__doc__
-            return manager_method
-
-        new_methods = {}
-        for name, method in inspect.getmembers(queryset_class, predicate=inspect.isfunction):
-            # Only copy missing methods.
-            if hasattr(cls, name):
-                continue
-            # Only copy public methods or methods with the attribute `queryset_only=False`.
-            queryset_only = getattr(method, 'queryset_only', None)
-            if queryset_only or (queryset_only is None and name.startswith('_')):
-                continue
-            # Copy the method onto the manager.
-            new_methods[name] = create_method(name, method)
-        return new_methods
-
-    @classmethod
-    def from_queryset(cls, queryset_class, class_name=None):
-        if class_name is None:
-            class_name = '%sFrom%s' % (cls.__name__, queryset_class.__name__)
-        return type(class_name, (cls,), {
-            '_queryset_class': queryset_class,
-            **cls._get_queryset_methods(queryset_class),
-        })
-
-    def contribute_to_class(self, cls, name):
-        self.name = self.name or name
-        self.model = cls
-
-        setattr(cls, name, ManagerDescriptor(self))
-
-        cls._meta.add_manager(self)
-
-    def _set_creation_counter(self):
-        """
-        Set the creation counter value for this instance and increment the
-        class-level copy.
-        """
-        self.creation_counter = BaseManager.creation_counter
-        BaseManager.creation_counter += 1
-
-    def db_manager(self, using=None, hints=None):
-        obj = copy.copy(self)
-        obj._db = using or self._db
-        obj._hints = hints or self._hints
-        return obj
-
-    @property
-    def db(self):
-        return self._db or router.db_for_read(self.model, **self._hints)
-
-    #######################
-    # PROXIES TO QUERYSET #
-    #######################
-
-    def get_queryset(self):
-        """
-        Return a new QuerySet object. Subclasses can override this method to
-        customize the behavior of the Manager.
-        """
-        return self._queryset_class(model=self.model, using=self._db, hints=self._hints)
-
-    def all(self):
-        # We can't proxy this method through the `QuerySet` like we do for the
-        # rest of the `QuerySet` methods. This is because `QuerySet.all()`
-        # works by creating a "copy" of the current queryset and in making said
-        # copy, all the cached `prefetch_related` lookups are lost. See the
-        # implementation of `RelatedManager.get_queryset()` for a better
-        # understanding of how this comes into play.
-        return self.get_queryset()
-
-    def __eq__(self, other):
-        return (
-            isinstance(other, self.__class__) and
-            self._constructor_args == other._constructor_args
-        )
-
-    def __hash__(self):
-        return id(self)
-
-
-class Manager(BaseManager.from_queryset(QuerySet)):
-    pass
-
-
-class ManagerDescriptor:
-
-    def __init__(self, manager):
-        self.manager = manager
-
-    def __get__(self, instance, cls=None):
-        if instance is not None:
-            raise AttributeError("Manager isn't accessible via %s instances" % cls.__name__)
-
-        if cls._meta.abstract:
-            raise AttributeError("Manager isn't available; %s is abstract" % (
-                cls._meta.object_name,
-            ))
-
-        if cls._meta.swapped:
-            raise AttributeError(
-                "Manager isn't available; '%s' has been swapped for '%s'" % (
-                    cls._meta.label,
-                    cls._meta.swapped,
-                )
-            )
-
-        return cls._meta.managers_map[self.manager.name]
-
-
-class EmptyManager(Manager):
-    def __init__(self, model):
-        super().__init__()
-        self.model = model
-
-    def get_queryset(self):
-        return super().get_queryset().none()
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/django/db/models/query_utils.html b/docs/0.9.5/_modules/django/db/models/query_utils.html deleted file mode 100644 index 9656f03139..0000000000 --- a/docs/0.9.5/_modules/django/db/models/query_utils.html +++ /dev/null @@ -1,449 +0,0 @@ - - - - - - - - django.db.models.query_utils — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for django.db.models.query_utils

-"""
-Various data structures used in query construction.
-
-Factored out from django.db.models.query to avoid making the main module very
-large and/or so that they can be used by other modules without getting into
-circular import difficulties.
-"""
-import copy
-import functools
-import inspect
-import warnings
-from collections import namedtuple
-
-from django.core.exceptions import FieldDoesNotExist, FieldError
-from django.db.models.constants import LOOKUP_SEP
-from django.utils import tree
-from django.utils.deprecation import RemovedInDjango40Warning
-
-# PathInfo is used when converting lookups (fk__somecol). The contents
-# describe the relation in Model terms (model Options and Fields for both
-# sides of the relation. The join_field is the field backing the relation.
-PathInfo = namedtuple('PathInfo', 'from_opts to_opts target_fields join_field m2m direct filtered_relation')
-
-
-class InvalidQueryType(type):
-    @property
-    def _subclasses(self):
-        return (FieldDoesNotExist, FieldError)
-
-    def __warn(self):
-        warnings.warn(
-            'The InvalidQuery exception class is deprecated. Use '
-            'FieldDoesNotExist or FieldError instead.',
-            category=RemovedInDjango40Warning,
-            stacklevel=4,
-        )
-
-    def __instancecheck__(self, instance):
-        self.__warn()
-        return isinstance(instance, self._subclasses) or super().__instancecheck__(instance)
-
-    def __subclasscheck__(self, subclass):
-        self.__warn()
-        return issubclass(subclass, self._subclasses) or super().__subclasscheck__(subclass)
-
-
-class InvalidQuery(Exception, metaclass=InvalidQueryType):
-    pass
-
-
-def subclasses(cls):
-    yield cls
-    for subclass in cls.__subclasses__():
-        yield from subclasses(subclass)
-
-
-class Q(tree.Node):
-    """
-    Encapsulate filters as objects that can then be combined logically (using
-    `&` and `|`).
-    """
-    # Connection types
-    AND = 'AND'
-    OR = 'OR'
-    default = AND
-    conditional = True
-
-    def __init__(self, *args, _connector=None, _negated=False, **kwargs):
-        super().__init__(children=[*args, *sorted(kwargs.items())], connector=_connector, negated=_negated)
-
-    def _combine(self, other, conn):
-        if not(isinstance(other, Q) or getattr(other, 'conditional', False) is True):
-            raise TypeError(other)
-
-        if not self:
-            return other.copy() if hasattr(other, 'copy') else copy.copy(other)
-        elif isinstance(other, Q) and not other:
-            _, args, kwargs = self.deconstruct()
-            return type(self)(*args, **kwargs)
-
-        obj = type(self)()
-        obj.connector = conn
-        obj.add(self, conn)
-        obj.add(other, conn)
-        return obj
-
-    def __or__(self, other):
-        return self._combine(other, self.OR)
-
-    def __and__(self, other):
-        return self._combine(other, self.AND)
-
-    def __invert__(self):
-        obj = type(self)()
-        obj.add(self, self.AND)
-        obj.negate()
-        return obj
-
-    def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False):
-        # We must promote any new joins to left outer joins so that when Q is
-        # used as an expression, rows aren't filtered due to joins.
-        clause, joins = query._add_q(
-            self, reuse, allow_joins=allow_joins, split_subq=False,
-            check_filterable=False,
-        )
-        query.promote_joins(joins)
-        return clause
-
-    def deconstruct(self):
-        path = '%s.%s' % (self.__class__.__module__, self.__class__.__name__)
-        if path.startswith('django.db.models.query_utils'):
-            path = path.replace('django.db.models.query_utils', 'django.db.models')
-        args = tuple(self.children)
-        kwargs = {}
-        if self.connector != self.default:
-            kwargs['_connector'] = self.connector
-        if self.negated:
-            kwargs['_negated'] = True
-        return path, args, kwargs
-
-
-class DeferredAttribute:
-    """
-    A wrapper for a deferred-loading field. When the value is read from this
-    object the first time, the query is executed.
-    """
-    def __init__(self, field):
-        self.field = field
-
-    def __get__(self, instance, cls=None):
-        """
-        Retrieve and caches the value from the datastore on the first lookup.
-        Return the cached value.
-        """
-        if instance is None:
-            return self
-        data = instance.__dict__
-        field_name = self.field.attname
-        if field_name not in data:
-            # Let's see if the field is part of the parent chain. If so we
-            # might be able to reuse the already loaded value. Refs #18343.
-            val = self._check_parent_chain(instance)
-            if val is None:
-                instance.refresh_from_db(fields=[field_name])
-            else:
-                data[field_name] = val
-        return data[field_name]
-
-    def _check_parent_chain(self, instance):
-        """
-        Check if the field value can be fetched from a parent field already
-        loaded in the instance. This can be done if the to-be fetched
-        field is a primary key field.
-        """
-        opts = instance._meta
-        link_field = opts.get_ancestor_link(self.field.model)
-        if self.field.primary_key and self.field != link_field:
-            return getattr(instance, link_field.attname)
-        return None
-
-
-class RegisterLookupMixin:
-
-    @classmethod
-    def _get_lookup(cls, lookup_name):
-        return cls.get_lookups().get(lookup_name, None)
-
-    @classmethod
-    @functools.lru_cache(maxsize=None)
-    def get_lookups(cls):
-        class_lookups = [parent.__dict__.get('class_lookups', {}) for parent in inspect.getmro(cls)]
-        return cls.merge_dicts(class_lookups)
-
-    def get_lookup(self, lookup_name):
-        from django.db.models.lookups import Lookup
-        found = self._get_lookup(lookup_name)
-        if found is None and hasattr(self, 'output_field'):
-            return self.output_field.get_lookup(lookup_name)
-        if found is not None and not issubclass(found, Lookup):
-            return None
-        return found
-
-    def get_transform(self, lookup_name):
-        from django.db.models.lookups import Transform
-        found = self._get_lookup(lookup_name)
-        if found is None and hasattr(self, 'output_field'):
-            return self.output_field.get_transform(lookup_name)
-        if found is not None and not issubclass(found, Transform):
-            return None
-        return found
-
-    @staticmethod
-    def merge_dicts(dicts):
-        """
-        Merge dicts in reverse to preference the order of the original list. e.g.,
-        merge_dicts([a, b]) will preference the keys in 'a' over those in 'b'.
-        """
-        merged = {}
-        for d in reversed(dicts):
-            merged.update(d)
-        return merged
-
-    @classmethod
-    def _clear_cached_lookups(cls):
-        for subclass in subclasses(cls):
-            subclass.get_lookups.cache_clear()
-
-    @classmethod
-    def register_lookup(cls, lookup, lookup_name=None):
-        if lookup_name is None:
-            lookup_name = lookup.lookup_name
-        if 'class_lookups' not in cls.__dict__:
-            cls.class_lookups = {}
-        cls.class_lookups[lookup_name] = lookup
-        cls._clear_cached_lookups()
-        return lookup
-
-    @classmethod
-    def _unregister_lookup(cls, lookup, lookup_name=None):
-        """
-        Remove given lookup from cls lookups. For use in tests only as it's
-        not thread-safe.
-        """
-        if lookup_name is None:
-            lookup_name = lookup.lookup_name
-        del cls.class_lookups[lookup_name]
-
-
-def select_related_descend(field, restricted, requested, load_fields, reverse=False):
-    """
-    Return True if this field should be used to descend deeper for
-    select_related() purposes. Used by both the query construction code
-    (sql.query.fill_related_selections()) and the model instance creation code
-    (query.get_klass_info()).
-
-    Arguments:
-     * field - the field to be checked
-     * restricted - a boolean field, indicating if the field list has been
-       manually restricted using a requested clause)
-     * requested - The select_related() dictionary.
-     * load_fields - the set of fields to be loaded on this model
-     * reverse - boolean, True if we are checking a reverse select related
-    """
-    if not field.remote_field:
-        return False
-    if field.remote_field.parent_link and not reverse:
-        return False
-    if restricted:
-        if reverse and field.related_query_name() not in requested:
-            return False
-        if not reverse and field.name not in requested:
-            return False
-    if not restricted and field.null:
-        return False
-    if load_fields:
-        if field.attname not in load_fields:
-            if restricted and field.name in requested:
-                msg = (
-                    'Field %s.%s cannot be both deferred and traversed using '
-                    'select_related at the same time.'
-                ) % (field.model._meta.object_name, field.name)
-                raise FieldError(msg)
-    return True
-
-
-def refs_expression(lookup_parts, annotations):
-    """
-    Check if the lookup_parts contains references to the given annotations set.
-    Because the LOOKUP_SEP is contained in the default annotation names, check
-    each prefix of the lookup_parts for a match.
-    """
-    for n in range(1, len(lookup_parts) + 1):
-        level_n_lookup = LOOKUP_SEP.join(lookup_parts[0:n])
-        if level_n_lookup in annotations and annotations[level_n_lookup]:
-            return annotations[level_n_lookup], lookup_parts[n:]
-    return False, ()
-
-
-def check_rel_lookup_compatibility(model, target_opts, field):
-    """
-    Check that self.model is compatible with target_opts. Compatibility
-    is OK if:
-      1) model and opts match (where proxy inheritance is removed)
-      2) model is parent of opts' model or the other way around
-    """
-    def check(opts):
-        return (
-            model._meta.concrete_model == opts.concrete_model or
-            opts.concrete_model in model._meta.get_parent_list() or
-            model in opts.get_parent_list()
-        )
-    # If the field is a primary key, then doing a query against the field's
-    # model is ok, too. Consider the case:
-    # class Restaurant(models.Model):
-    #     place = OneToOneField(Place, primary_key=True):
-    # Restaurant.objects.filter(pk__in=Restaurant.objects.all()).
-    # If we didn't have the primary key check, then pk__in (== place__in) would
-    # give Place's opts as the target opts, but Restaurant isn't compatible
-    # with that. This logic applies only to primary keys, as when doing __in=qs,
-    # we are going to turn this into __in=qs.values('pk') later on.
-    return (
-        check(target_opts) or
-        (getattr(field, 'primary_key', False) and check(field.model._meta))
-    )
-
-
-class FilteredRelation:
-    """Specify custom filtering in the ON clause of SQL joins."""
-
-    def __init__(self, relation_name, *, condition=Q()):
-        if not relation_name:
-            raise ValueError('relation_name cannot be empty.')
-        self.relation_name = relation_name
-        self.alias = None
-        if not isinstance(condition, Q):
-            raise ValueError('condition argument must be a Q() instance.')
-        self.condition = condition
-        self.path = []
-
-    def __eq__(self, other):
-        if not isinstance(other, self.__class__):
-            return NotImplemented
-        return (
-            self.relation_name == other.relation_name and
-            self.alias == other.alias and
-            self.condition == other.condition
-        )
-
-    def clone(self):
-        clone = FilteredRelation(self.relation_name, condition=self.condition)
-        clone.alias = self.alias
-        clone.path = self.path[:]
-        return clone
-
-    def resolve_expression(self, *args, **kwargs):
-        """
-        QuerySet.annotate() only accepts expression-like arguments
-        (with a resolve_expression() method).
-        """
-        raise NotImplementedError('FilteredRelation.resolve_expression() is unused.')
-
-    def as_sql(self, compiler, connection):
-        # Resolve the condition in Join.filtered_relation.
-        query = compiler.query
-        where = query.build_filtered_relation_q(self.condition, reuse=set(self.path))
-        return compiler.compile(where)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia.html b/docs/0.9.5/_modules/evennia.html deleted file mode 100644 index e51db77f49..0000000000 --- a/docs/0.9.5/_modules/evennia.html +++ /dev/null @@ -1,535 +0,0 @@ - - - - - - - - evennia — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia

-"""
-Evennia MUD/MUX/MU* creation system
-
-This is the main top-level API for Evennia. You can explore the evennia library
-by accessing evennia.<subpackage> directly. From inside the game you can read
-docs of all object by viewing its `__doc__` string, such as through
-
-    py evennia.ObjectDB.__doc__
-
-For full functionality you should explore this module via a django-
-aware shell. Go to your game directory and use the command
-
-   evennia shell
-
-to launch such a shell (using python or ipython depending on your install).
-See www.evennia.com for full documentation.
-
-"""
-
-# docstring header
-
-DOCSTRING = """
-Evennia MU* creation system.
-
-Online manual and API docs are found at http://www.evennia.com.
-
-Flat-API shortcut names:
-{}
-"""
-
-# Delayed loading of properties
-
-# Typeclasses
-
-DefaultAccount = None
-DefaultGuest = None
-DefaultObject = None
-DefaultCharacter = None
-DefaultRoom = None
-DefaultExit = None
-DefaultChannel = None
-DefaultScript = None
-
-# Database models
-ObjectDB = None
-AccountDB = None
-ScriptDB = None
-ChannelDB = None
-Msg = None
-
-# commands
-Command = None
-CmdSet = None
-default_cmds = None
-syscmdkeys = None
-InterruptCommand = None
-
-# search functions
-search_object = None
-search_script = None
-search_account = None
-search_channel = None
-search_message = None
-search_help = None
-search_tag = None
-
-# create functions
-create_object = None
-create_script = None
-create_account = None
-create_channel = None
-create_message = None
-create_help_entry = None
-
-# utilities
-settings = None
-lockfuncs = None
-inputhandler = None
-logger = None
-gametime = None
-ansi = None
-spawn = None
-managers = None
-contrib = None
-EvMenu = None
-EvTable = None
-EvForm = None
-EvEditor = None
-EvMore = None
-ANSIString = None
-signals = None
-
-# Handlers
-SESSION_HANDLER = None
-TASK_HANDLER = None
-TICKER_HANDLER = None
-MONITOR_HANDLER = None
-
-# Containers
-GLOBAL_SCRIPTS = None
-OPTION_CLASSES = None
-
-def _create_version():
-    """
-    Helper function for building the version string
-    """
-    import os
-    from subprocess import check_output, CalledProcessError, STDOUT
-
-    version = "Unknown"
-    root = os.path.dirname(os.path.abspath(__file__))
-    try:
-        with open(os.path.join(root, "VERSION.txt"), "r") as f:
-            version = f.read().strip()
-    except IOError as err:
-        print(err)
-    try:
-        rev = (
-            check_output("git rev-parse --short HEAD", shell=True, cwd=root, stderr=STDOUT)
-            .strip()
-            .decode()
-        )
-        version = "%s (rev %s)" % (version, rev)
-    except (IOError, CalledProcessError, OSError):
-        # ignore if we cannot get to git
-        pass
-    return version
-
-
-__version__ = _create_version()
-del _create_version
-
-
-def _init():
-    """
-    This function is called automatically by the launcher only after
-    Evennia has fully initialized all its models. It sets up the API
-    in a safe environment where all models are available already.
-    """
-    global DefaultAccount, DefaultObject, DefaultGuest, DefaultCharacter
-    global DefaultRoom, DefaultExit, DefaultChannel, DefaultScript
-    global ObjectDB, AccountDB, ScriptDB, ChannelDB, Msg
-    global Command, CmdSet, default_cmds, syscmdkeys, InterruptCommand
-    global search_object, search_script, search_account, search_channel
-    global search_help, search_tag, search_message
-    global create_object, create_script, create_account, create_channel
-    global create_message, create_help_entry
-    global signals
-    global settings, lockfuncs, logger, utils, gametime, ansi, spawn, managers
-    global contrib, TICKER_HANDLER, MONITOR_HANDLER, SESSION_HANDLER
-    global TASK_HANDLER
-    global GLOBAL_SCRIPTS, OPTION_CLASSES
-    global EvMenu, EvTable, EvForm, EvMore, EvEditor
-    global ANSIString
-
-    # Parent typeclasses
-    from .accounts.accounts import DefaultAccount
-    from .accounts.accounts import DefaultGuest
-    from .objects.objects import DefaultObject
-    from .objects.objects import DefaultCharacter
-    from .objects.objects import DefaultRoom
-    from .objects.objects import DefaultExit
-    from .comms.comms import DefaultChannel
-    from .scripts.scripts import DefaultScript
-
-    # Database models
-    from .objects.models import ObjectDB
-    from .accounts.models import AccountDB
-    from .scripts.models import ScriptDB
-    from .comms.models import ChannelDB
-    from .comms.models import Msg
-
-    # commands
-    from .commands.command import Command, InterruptCommand
-    from .commands.cmdset import CmdSet
-
-    # search functions
-    from .utils.search import search_object
-    from .utils.search import search_script
-    from .utils.search import search_account
-    from .utils.search import search_message
-    from .utils.search import search_channel
-    from .utils.search import search_help
-    from .utils.search import search_tag
-
-    # create functions
-    from .utils.create import create_object
-    from .utils.create import create_script
-    from .utils.create import create_account
-    from .utils.create import create_channel
-    from .utils.create import create_message
-    from .utils.create import create_help_entry
-
-    # utilities
-    from django.conf import settings
-    from .locks import lockfuncs
-    from .utils import logger
-    from .utils import gametime
-    from .utils import ansi
-    from .prototypes.spawner import spawn
-    from . import contrib
-    from .utils.evmenu import EvMenu
-    from .utils.evtable import EvTable
-    from .utils.evmore import EvMore
-    from .utils.evform import EvForm
-    from .utils.eveditor import EvEditor
-    from .utils.ansi import ANSIString
-    from .server import signals
-
-    # handlers
-    from .scripts.tickerhandler import TICKER_HANDLER
-    from .scripts.taskhandler import TASK_HANDLER
-    from .server.sessionhandler import SESSION_HANDLER
-    from .scripts.monitorhandler import MONITOR_HANDLER
-
-    # containers
-    from .utils.containers import GLOBAL_SCRIPTS
-    from .utils.containers import OPTION_CLASSES
-
-    # API containers
-
-    class _EvContainer(object):
-        """
-        Parent for other containers
-
-        """
-
-        def _help(self):
-            "Returns list of contents"
-            names = [name for name in self.__class__.__dict__ if not name.startswith("_")]
-            names += [name for name in self.__dict__ if not name.startswith("_")]
-            print(self.__doc__ + "-" * 60 + "\n" + ", ".join(names))
-
-        help = property(_help)
-
-    class DBmanagers(_EvContainer):
-        """
-        Links to instantiated Django database managers. These are used
-        to perform more advanced custom database queries than the standard
-        search functions allow.
-
-        helpentries - HelpEntry.objects
-        accounts - AccountDB.objects
-        scripts - ScriptDB.objects
-        msgs    - Msg.objects
-        channels - Channel.objects
-        objects - ObjectDB.objects
-        serverconfigs - ServerConfig.objects
-        tags - Tags.objects
-        attributes - Attributes.objects
-
-        """
-
-        from .help.models import HelpEntry
-        from .accounts.models import AccountDB
-        from .scripts.models import ScriptDB
-        from .comms.models import Msg, ChannelDB
-        from .objects.models import ObjectDB
-        from .server.models import ServerConfig
-        from .typeclasses.attributes import Attribute
-        from .typeclasses.tags import Tag
-
-        # create container's properties
-        helpentries = HelpEntry.objects
-        accounts = AccountDB.objects
-        scripts = ScriptDB.objects
-        msgs = Msg.objects
-        channels = ChannelDB.objects
-        objects = ObjectDB.objects
-        serverconfigs = ServerConfig.objects
-        attributes = Attribute.objects
-        tags = Tag.objects
-        # remove these so they are not visible as properties
-        del HelpEntry, AccountDB, ScriptDB, Msg, ChannelDB
-        # del ExternalChannelConnection
-        del ObjectDB, ServerConfig, Tag, Attribute
-
-    managers = DBmanagers()
-    del DBmanagers
-
-    class DefaultCmds(_EvContainer):
-        """
-        This container holds direct shortcuts to all default commands in Evennia.
-
-        To access in code, do 'from evennia import default_cmds' then
-        access the properties on the imported default_cmds object.
-
-        """
-
-        from .commands.default.cmdset_character import CharacterCmdSet
-        from .commands.default.cmdset_account import AccountCmdSet
-        from .commands.default.cmdset_unloggedin import UnloggedinCmdSet
-        from .commands.default.cmdset_session import SessionCmdSet
-        from .commands.default.muxcommand import MuxCommand, MuxAccountCommand
-
-        def __init__(self):
-            "populate the object with commands"
-
-            def add_cmds(module):
-                "helper method for populating this object with cmds"
-                from evennia.utils import utils
-
-                cmdlist = utils.variable_from_module(module, module.__all__)
-                self.__dict__.update(dict([(c.__name__, c) for c in cmdlist]))
-
-            from .commands.default import (
-                admin,
-                batchprocess,
-                building,
-                comms,
-                general,
-                account,
-                help,
-                system,
-                unloggedin,
-            )
-
-            add_cmds(admin)
-            add_cmds(building)
-            add_cmds(batchprocess)
-            add_cmds(building)
-            add_cmds(comms)
-            add_cmds(general)
-            add_cmds(account)
-            add_cmds(help)
-            add_cmds(system)
-            add_cmds(unloggedin)
-
-    default_cmds = DefaultCmds()
-    del DefaultCmds
-
-    class SystemCmds(_EvContainer):
-        """
-        Creating commands with keys set to these constants will make
-        them system commands called as a replacement by the parser when
-        special situations occur. If not defined, the hard-coded
-        responses in the server are used.
-
-        CMD_NOINPUT - no input was given on command line
-        CMD_NOMATCH - no valid command key was found
-        CMD_MULTIMATCH - multiple command matches were found
-        CMD_LOGINSTART - this command will be called as the very
-                         first command when an account connects to
-                         the server.
-
-        To access in code, do 'from evennia import syscmdkeys' then
-        access the properties on the imported syscmdkeys object.
-
-        """
-
-        from .commands import cmdhandler
-
-        CMD_NOINPUT = cmdhandler.CMD_NOINPUT
-        CMD_NOMATCH = cmdhandler.CMD_NOMATCH
-        CMD_MULTIMATCH = cmdhandler.CMD_MULTIMATCH
-        CMD_LOGINSTART = cmdhandler.CMD_LOGINSTART
-        del cmdhandler
-
-    syscmdkeys = SystemCmds()
-    del SystemCmds
-    del _EvContainer
-
-    # delayed starts - important so as to not back-access evennia before it has
-    # finished initializing
-    GLOBAL_SCRIPTS.start()
-
-
-
[docs]def set_trace(term_size=(140, 80), debugger="auto"): - """ - Helper function for running a debugger inside the Evennia event loop. - - Args: - term_size (tuple, optional): Only used for Pudb and defines the size of the terminal - (width, height) in number of characters. - debugger (str, optional): One of 'auto', 'pdb' or 'pudb'. Pdb is the standard debugger. Pudb - is an external package with a different, more 'graphical', ncurses-based UI. With - 'auto', will use pudb if possible, otherwise fall back to pdb. Pudb is available through - `pip install pudb`. - - Notes: - To use: - - 1) add this to a line to act as a breakpoint for entering the debugger: - - from evennia import set_trace; set_trace() - - 2) restart evennia in interactive mode - - evennia istart - - 3) debugger will appear in the interactive terminal when breakpoint is reached. Exit - with 'q', remove the break line and restart server when finished. - - """ - import sys - - dbg = None - - if debugger in ("auto", "pudb"): - try: - from pudb import debugger - - dbg = debugger.Debugger(stdout=sys.__stdout__, term_size=term_size) - except ImportError: - if debugger == "pudb": - raise - pass - - if not dbg: - import pdb - - dbg = pdb.Pdb(stdout=sys.__stdout__) - - try: - # Start debugger, forcing it up one stack frame (otherwise `set_trace` - # will start debugger this point, not the actual code location) - dbg.set_trace(sys._getframe().f_back) - except Exception: - # Stopped at breakpoint. Press 'n' to continue into the code. - dbg.set_trace()
- - -# initialize the doc string -global __doc__ -__doc__ = DOCSTRING.format( - "\n- " - + "\n- ".join( - f"evennia.{key}" - for key in sorted(globals()) - if not key.startswith("_") and key not in ("DOCSTRING",) - ) -) -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/accounts/accounts.html b/docs/0.9.5/_modules/evennia/accounts/accounts.html deleted file mode 100644 index 29f5475580..0000000000 --- a/docs/0.9.5/_modules/evennia/accounts/accounts.html +++ /dev/null @@ -1,1912 +0,0 @@ - - - - - - - - evennia.accounts.accounts — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.accounts.accounts

-"""
-Typeclass for Account objects.
-
-Note that this object is primarily intended to
-store OOC information, not game info! This
-object represents the actual user (not their
-character) and has NO actual presence in the
-game world (this is handled by the associated
-character object, so you should customize that
-instead for most things).
-
-"""
-import re
-import time
-from django.conf import settings
-from django.contrib.auth import authenticate, password_validation
-from django.core.exceptions import ImproperlyConfigured, ValidationError
-from django.utils import timezone
-from django.utils.module_loading import import_string
-from evennia.typeclasses.models import TypeclassBase
-from evennia.accounts.manager import AccountManager
-from evennia.accounts.models import AccountDB
-from evennia.objects.models import ObjectDB
-from evennia.comms.models import ChannelDB
-from evennia.server.models import ServerConfig
-from evennia.server.throttle import Throttle
-from evennia.utils import class_from_module, create, logger
-from evennia.utils.utils import lazy_property, to_str, make_iter, is_iter, variable_from_module
-from evennia.server.signals import (
-    SIGNAL_ACCOUNT_POST_CREATE,
-    SIGNAL_OBJECT_POST_PUPPET,
-    SIGNAL_OBJECT_POST_UNPUPPET,
-)
-from evennia.typeclasses.attributes import NickHandler, ModelAttributeBackend
-from evennia.scripts.scripthandler import ScriptHandler
-from evennia.commands.cmdsethandler import CmdSetHandler
-from evennia.utils.optionhandler import OptionHandler
-
-from django.utils.translation import gettext as _
-from random import getrandbits
-
-__all__ = ("DefaultAccount", "DefaultGuest")
-
-_SESSIONS = None
-
-_AT_SEARCH_RESULT = variable_from_module(*settings.SEARCH_AT_RESULT.rsplit(".", 1))
-_MULTISESSION_MODE = settings.MULTISESSION_MODE
-_MAX_NR_CHARACTERS = settings.MAX_NR_CHARACTERS
-_CMDSET_ACCOUNT = settings.CMDSET_ACCOUNT
-_MUDINFO_CHANNEL = None
-_CONNECT_CHANNEL = None
-_CMDHANDLER = None
-
-
-# Create throttles for too many account-creations and login attempts
-CREATION_THROTTLE = Throttle(
-    name='creation', limit=settings.CREATION_THROTTLE_LIMIT,
-    timeout=settings.CREATION_THROTTLE_TIMEOUT
-)
-LOGIN_THROTTLE = Throttle(
-    name='login', limit=settings.LOGIN_THROTTLE_LIMIT, timeout=settings.LOGIN_THROTTLE_TIMEOUT
-)
-
-
-class AccountSessionHandler(object):
-    """
-    Manages the session(s) attached to an account.
-
-    """
-
-    def __init__(self, account):
-        """
-        Initializes the handler.
-
-        Args:
-            account (Account): The Account on which this handler is defined.
-
-        """
-        self.account = account
-
-    def get(self, sessid=None):
-        """
-        Get the sessions linked to this object.
-
-        Args:
-            sessid (int, optional): Specify a given session by
-                session id.
-
-        Returns:
-            sessions (list): A list of Session objects. If `sessid`
-                is given, this is a list with one (or zero) elements.
-
-        """
-        global _SESSIONS
-        if not _SESSIONS:
-            from evennia.server.sessionhandler import SESSIONS as _SESSIONS
-        if sessid:
-            return make_iter(_SESSIONS.session_from_account(self.account, sessid))
-        else:
-            return _SESSIONS.sessions_from_account(self.account)
-
-    def all(self):
-        """
-        Alias to get(), returning all sessions.
-
-        Returns:
-            sessions (list): All sessions.
-
-        """
-        return self.get()
-
-    def count(self):
-        """
-        Get amount of sessions connected.
-
-        Returns:
-            sesslen (int): Number of sessions handled.
-
-        """
-        return len(self.get())
-
-
-
[docs]class DefaultAccount(AccountDB, metaclass=TypeclassBase): - """ - This is the base Typeclass for all Accounts. Accounts represent - the person playing the game and tracks account info, password - etc. They are OOC entities without presence in-game. An Account - can connect to a Character Object in order to "enter" the - game. - - Account Typeclass API: - - * Available properties (only available on initiated typeclass objects) - - - key (string) - name of account - - name (string)- wrapper for user.username - - aliases (list of strings) - aliases to the object. Will be saved to - database as AliasDB entries but returned as strings. - - dbref (int, read-only) - unique #id-number. Also "id" can be used. - - date_created (string) - time stamp of object creation - - permissions (list of strings) - list of permission strings - - user (User, read-only) - django User authorization object - - obj (Object) - game object controlled by account. 'character' can also - be used. - - sessions (list of Sessions) - sessions connected to this account - - is_superuser (bool, read-only) - if the connected user is a superuser - - * Handlers - - - locks - lock-handler: use locks.add() to add new lock strings - - db - attribute-handler: store/retrieve database attributes on this - self.db.myattr=val, val=self.db.myattr - - ndb - non-persistent attribute handler: same as db but does not - create a database entry when storing data - - scripts - script-handler. Add new scripts to object with scripts.add() - - cmdset - cmdset-handler. Use cmdset.add() to add new cmdsets to object - - nicks - nick-handler. New nicks with nicks.add(). - - * Helper methods - - - msg(text=None, from_obj=None, session=None, options=None, **kwargs) - - execute_cmd(raw_string) - - search(ostring, global_search=False, attribute_name=None, - use_nicks=False, location=None, - ignore_errors=False, account=False) - - is_typeclass(typeclass, exact=False) - - swap_typeclass(new_typeclass, clean_attributes=False, no_default=True) - - access(accessing_obj, access_type='read', default=False, no_superuser_bypass=False) - - check_permstring(permstring) - - * Hook methods - - basetype_setup() - at_account_creation() - - > note that the following hooks are also found on Objects and are - usually handled on the character level: - - - at_init() - - at_access() - - at_cmdset_get(**kwargs) - - at_first_login() - - at_post_login(session=None) - - at_disconnect() - - at_message_receive() - - at_message_send() - - at_server_reload() - - at_server_shutdown() - - """ - - objects = AccountManager() - - # properties -
[docs] @lazy_property - def cmdset(self): - return CmdSetHandler(self, True)
- -
[docs] @lazy_property - def scripts(self): - return ScriptHandler(self)
- -
[docs] @lazy_property - def nicks(self): - return NickHandler(self, ModelAttributeBackend)
- -
[docs] @lazy_property - def sessions(self): - return AccountSessionHandler(self)
- -
[docs] @lazy_property - def options(self): - return OptionHandler( - self, - options_dict=settings.OPTIONS_ACCOUNT_DEFAULT, - savefunc=self.attributes.add, - loadfunc=self.attributes.get, - save_kwargs={"category": "option"}, - load_kwargs={"category": "option"}, - )
- - # Do not make this a lazy property; the web UI will not refresh it! - @property - def characters(self): - # Get playable characters list - objs = self.db._playable_characters or [] - - # Rebuild the list if legacy code left null values after deletion - try: - if None in objs: - objs = [x for x in self.db._playable_characters if x] - self.db._playable_characters = objs - except Exception as e: - logger.log_trace(e) - logger.log_err(e) - - return objs - -
[docs] def get_display_name(self, looker, **kwargs): - """ - This is used by channels and other OOC communications methods to give a - custom display of this account's input. - - Args: - looker (Account): The one that will see this name. - **kwargs: Unused by default, can be used to pass game-specific data. - - Returns: - str: The name, possibly modified. - - """ - return f"|c{self.key}|n"
- - # session-related methods - -
[docs] def disconnect_session_from_account(self, session, reason=None): - """ - Access method for disconnecting a given session from the - account (connection happens automatically in the - sessionhandler) - - Args: - session (Session): Session to disconnect. - reason (str, optional): Eventual reason for the disconnect. - - """ - global _SESSIONS - if not _SESSIONS: - from evennia.server.sessionhandler import SESSIONS as _SESSIONS - _SESSIONS.disconnect(session, reason)
- - # puppeting operations - -
[docs] def puppet_object(self, session, obj): - """ - Use the given session to control (puppet) the given object (usually - a Character type). - - Args: - session (Session): session to use for puppeting - obj (Object): the object to start puppeting - - Raises: - RuntimeError: If puppeting is not possible, the - `exception.msg` will contain the reason. - - - """ - # safety checks - if not obj: - raise RuntimeError("Object not found") - if not session: - raise RuntimeError("Session not found") - if self.get_puppet(session) == obj: - # already puppeting this object - self.msg("You are already puppeting this object.") - return - if not obj.access(self, "puppet"): - # no access - self.msg("You don't have permission to puppet '{obj.key}'.") - return - if obj.account: - # object already puppeted - if obj.account == self: - if obj.sessions.count(): - # we may take over another of our sessions - # output messages to the affected sessions - if _MULTISESSION_MODE in (1, 3): - txt1 = f"Sharing |c{obj.name}|n with another of your sessions." - txt2 = f"|c{obj.name}|n|G is now shared from another of your sessions.|n" - self.msg(txt1, session=session) - self.msg(txt2, session=obj.sessions.all()) - else: - txt1 = f"Taking over |c{obj.name}|n from another of your sessions." - txt2 = f"|c{obj.name}|n|R is now acted from another of your sessions.|n" - self.msg(txt1, session=session) - self.msg(txt2, session=obj.sessions.all()) - self.unpuppet_object(obj.sessions.get()) - elif obj.account.is_connected: - # controlled by another account - self.msg(_("|c{key}|R is already puppeted by another Account.").format(key=obj.key)) - return - - # do the puppeting - if session.puppet: - # cleanly unpuppet eventual previous object puppeted by this session - self.unpuppet_object(session) - # if we get to this point the character is ready to puppet or it - # was left with a lingering account/session reference from an unclean - # server kill or similar - - obj.at_pre_puppet(self, session=session) - - # do the connection - obj.sessions.add(session) - obj.account = self - session.puid = obj.id - session.puppet = obj - - # re-cache locks to make sure superuser bypass is updated - obj.locks.cache_lock_bypass(obj) - # final hook - obj.at_post_puppet() - SIGNAL_OBJECT_POST_PUPPET.send(sender=obj, account=self, session=session)
- -
[docs] def unpuppet_object(self, session): - """ - Disengage control over an object. - - Args: - session (Session or list): The session or a list of - sessions to disengage from their puppets. - - Raises: - RuntimeError With message about error. - - """ - for session in make_iter(session): - obj = session.puppet - if obj: - # do the disconnect, but only if we are the last session to puppet - obj.at_pre_unpuppet() - obj.sessions.remove(session) - if not obj.sessions.count(): - del obj.account - obj.at_post_unpuppet(self, session=session) - SIGNAL_OBJECT_POST_UNPUPPET.send(sender=obj, session=session, account=self) - # Just to be sure we're always clear. - session.puppet = None - session.puid = None
- -
[docs] def unpuppet_all(self): - """ - Disconnect all puppets. This is called by server before a - reset/shutdown. - """ - self.unpuppet_object(self.sessions.all())
- -
[docs] def get_puppet(self, session): - """ - Get an object puppeted by this session through this account. This is - the main method for retrieving the puppeted object from the - account's end. - - Args: - session (Session): Find puppeted object based on this session - - Returns: - puppet (Object): The matching puppeted object, if any. - - """ - return session.puppet if session else None
- -
[docs] def get_all_puppets(self): - """ - Get all currently puppeted objects. - - Returns: - puppets (list): All puppeted objects currently controlled - by this Account. - - """ - return list(set(session.puppet for session in self.sessions.all() if session.puppet))
- - def __get_single_puppet(self): - """ - This is a legacy convenience link for use with `MULTISESSION_MODE`. - - Returns: - puppets (Object or list): Users of `MULTISESSION_MODE` 0 or 1 will - always get the first puppet back. Users of higher `MULTISESSION_MODE`s will - get a list of all puppeted objects. - - """ - puppets = self.get_all_puppets() - if _MULTISESSION_MODE in (0, 1): - return puppets and puppets[0] or None - return puppets - - character = property(__get_single_puppet) - puppet = property(__get_single_puppet) - - # utility methods -
[docs] @classmethod - def is_banned(cls, **kwargs): - """ - Checks if a given username or IP is banned. - - Keyword Args: - ip (str, optional): IP address. - username (str, optional): Username. - - Returns: - is_banned (bool): Whether either is banned or not. - - """ - - ip = kwargs.get("ip", "").strip() - username = kwargs.get("username", "").lower().strip() - - # Check IP and/or name bans - bans = ServerConfig.objects.conf("server_bans") - if bans and ( - any(tup[0] == username for tup in bans if username) - or any(tup[2].match(ip) for tup in bans if ip and tup[2]) - ): - return True - - return False
- -
[docs] @classmethod - def get_username_validators( - cls, validator_config=getattr(settings, "AUTH_USERNAME_VALIDATORS", []) - ): - """ - Retrieves and instantiates validators for usernames. - - Args: - validator_config (list): List of dicts comprising the battery of - validators to apply to a username. - - Returns: - validators (list): List of instantiated Validator objects. - """ - - objs = [] - for validator in validator_config: - try: - klass = import_string(validator["NAME"]) - except ImportError: - msg = ( - f"The module in NAME could not be imported: {validator['NAME']}. " - "Check your AUTH_USERNAME_VALIDATORS setting." - ) - raise ImproperlyConfigured(msg) - objs.append(klass(**validator.get("OPTIONS", {}))) - return objs
- -
[docs] @classmethod - def authenticate(cls, username, password, ip="", **kwargs): - """ - Checks the given username/password against the database to see if the - credentials are valid. - - Note that this simply checks credentials and returns a valid reference - to the user-- it does not log them in! - - To finish the job: - After calling this from a Command, associate the account with a Session: - - session.sessionhandler.login(session, account) - - ...or after calling this from a View, associate it with an HttpRequest: - - django.contrib.auth.login(account, request) - - Args: - username (str): Username of account - password (str): Password of account - ip (str, optional): IP address of client - - Keyword Args: - session (Session, optional): Session requesting authentication - - Returns: - account (DefaultAccount, None): Account whose credentials were - provided if not banned. - errors (list): Error messages of any failures. - - """ - errors = [] - if ip: - ip = str(ip) - - # See if authentication is currently being throttled - if ip and LOGIN_THROTTLE.check(ip): - errors.append(_("Too many login failures; please try again in a few minutes.")) - - # With throttle active, do not log continued hits-- it is a - # waste of storage and can be abused to make your logs harder to - # read and/or fill up your disk. - return None, errors - - # Check IP and/or name bans - banned = cls.is_banned(username=username, ip=ip) - if banned: - # this is a banned IP or name! - errors.append( - _( - "|rYou have been banned and cannot continue from here." - "\nIf you feel this ban is in error, please email an admin.|x" - ) - ) - logger.log_sec(f"Authentication Denied (Banned): {username} (IP: {ip}).") - LOGIN_THROTTLE.update(ip, "Too many sightings of banned artifact.") - return None, errors - - # Authenticate and get Account object - account = authenticate(username=username, password=password) - if not account: - # User-facing message - errors.append(_("Username and/or password is incorrect.")) - - # Log auth failures while throttle is inactive - logger.log_sec(f"Authentication Failure: {username} (IP: {ip}).") - - # Update throttle - if ip: - LOGIN_THROTTLE.update(ip, _("Too many authentication failures.")) - - # Try to call post-failure hook - session = kwargs.get("session", None) - if session: - account = AccountDB.objects.get_account_from_name(username) - if account: - account.at_failed_login(session) - - return None, errors - - # Account successfully authenticated - logger.log_sec(f"Authentication Success: {account} (IP: {ip}).") - return account, errors
- -
[docs] @classmethod - def normalize_username(cls, username): - """ - Django: Applies NFKC Unicode normalization to usernames so that visually - identical characters with different Unicode code points are considered - identical. - - (This deals with the Turkish "i" problem and similar - annoyances. Only relevant if you go out of your way to allow Unicode - usernames though-- Evennia accepts ASCII by default.) - - In this case we're simply piggybacking on this feature to apply - additional normalization per Evennia's standards. - """ - username = super(DefaultAccount, cls).normalize_username(username) - - # strip excessive spaces in accountname - username = re.sub(r"\s+", " ", username).strip() - - return username
- -
[docs] @classmethod - def validate_username(cls, username): - """ - Checks the given username against the username validator associated with - Account objects, and also checks the database to make sure it is unique. - - Args: - username (str): Username to validate - - Returns: - valid (bool): Whether or not the password passed validation - errors (list): Error messages of any failures - - """ - valid = [] - errors = [] - - # Make sure we're at least using the default validator - validators = cls.get_username_validators() - if not validators: - validators = [cls.username_validator] - - # Try username against all enabled validators - for validator in validators: - try: - valid.append(not validator(username)) - except ValidationError as e: - valid.append(False) - errors.extend(e.messages) - - # Disqualify if any check failed - if False in valid: - valid = False - else: - valid = True - - return valid, errors
- -
[docs] @classmethod - def validate_password(cls, password, account=None): - """ - Checks the given password against the list of Django validators enabled - in the server.conf file. - - Args: - password (str): Password to validate - - Keyword Args: - account (DefaultAccount, optional): Account object to validate the - password for. Optional, but Django includes some validators to - do things like making sure users aren't setting passwords to the - same value as their username. If left blank, these user-specific - checks are skipped. - - Returns: - valid (bool): Whether or not the password passed validation - error (ValidationError, None): Any validation error(s) raised. Multiple - errors can be nested within a single object. - - """ - valid = False - error = None - - # Validation returns None on success; invert it and return a more sensible bool - try: - valid = not password_validation.validate_password(password, user=account) - except ValidationError as e: - error = e - - return valid, error
- -
[docs] def set_password(self, password, **kwargs): - """ - Applies the given password to the account. Logs and triggers the `at_password_change` hook. - - Args: - password (str): Password to set. - - Notes: - This is called by Django also when logging in; it should not be mixed up with - validation, since that would mean old passwords in the database (pre validation checks) - could get invalidated. - - """ - super(DefaultAccount, self).set_password(password) - logger.log_sec(f"Password successfully changed for {self}.") - self.at_password_change()
- -
[docs] def create_character(self, *args, **kwargs): - """ - Create a character linked to this account. - - Args: - key (str, optional): If not given, use the same name as the account. - typeclass (str, optional): Typeclass to use for this character. If - not given, use settings.BASE_CHARACTER_TYPECLASS. - permissions (list, optional): If not given, use the account's permissions. - ip (str, optiona): The client IP creating this character. Will fall back to the - one stored for the account if not given. - kwargs (any): Other kwargs will be used in the create_call. - Returns: - Object: A new character of the `character_typeclass` type. None on an error. - list or None: A list of errors, or None. - - """ - # parse inputs - character_key = kwargs.pop("key", self.key) - character_ip = kwargs.pop("ip", self.db.creator_ip) - character_permissions = kwargs.pop("permissions", self.permissions) - - # Load the appropriate Character class - character_typeclass = kwargs.pop("typeclass", None) - character_typeclass = ( - character_typeclass if character_typeclass else settings.BASE_CHARACTER_TYPECLASS - ) - Character = class_from_module(character_typeclass) - - if "location" not in kwargs: - kwargs["location"] = ObjectDB.objects.get_id(settings.START_LOCATION) - - # Create the character - character, errs = Character.create( - character_key, - self, - ip=character_ip, - typeclass=character_typeclass, - permissions=character_permissions, - **kwargs, - ) - if character: - # Update playable character list - if character not in self.characters: - self.db._playable_characters.append(character) - - # We need to set this to have @ic auto-connect to this character - self.db._last_puppet = character - return character, errs
- -
[docs] @classmethod - def create(cls, *args, **kwargs): - """ - Creates an Account (or Account/Character pair for MULTISESSION_MODE<2) - with default (or overridden) permissions and having joined them to the - appropriate default channels. - - Keyword Args: - username (str): Username of Account owner - password (str): Password of Account owner - email (str, optional): Email address of Account owner - ip (str, optional): IP address of requesting connection - guest (bool, optional): Whether or not this is to be a Guest account - - permissions (str, optional): Default permissions for the Account - typeclass (str, optional): Typeclass to use for new Account - character_typeclass (str, optional): Typeclass to use for new char - when applicable. - - Returns: - account (Account): Account if successfully created; None if not - errors (list): List of error messages in string form - - """ - - account = None - errors = [] - - username = kwargs.get("username") - password = kwargs.get("password") - email = kwargs.get("email", "").strip() - guest = kwargs.get("guest", False) - - permissions = kwargs.get("permissions", settings.PERMISSION_ACCOUNT_DEFAULT) - typeclass = kwargs.get("typeclass", cls) - - ip = kwargs.get("ip", "") - if ip and CREATION_THROTTLE.check(ip): - errors.append( - _("You are creating too many accounts. Please log into an existing account.") - ) - return None, errors - - # Normalize username - username = cls.normalize_username(username) - - # Validate username - if not guest: - valid, errs = cls.validate_username(username) - if not valid: - # this echoes the restrictions made by django's auth - # module (except not allowing spaces, for convenience of - # logging in). - errors.extend(errs) - return None, errors - - # Validate password - # Have to create a dummy Account object to check username similarity - valid, errs = cls.validate_password(password, account=cls(username=username)) - if not valid: - errors.extend(errs) - return None, errors - - # Check IP and/or name bans - banned = cls.is_banned(username=username, ip=ip) - if banned: - # this is a banned IP or name! - string = _( - "|rYou have been banned and cannot continue from here." - "\nIf you feel this ban is in error, please email an admin.|x" - ) - errors.append(string) - return None, errors - - # everything's ok. Create the new account. - try: - try: - account = create.create_account( - username, email, password, permissions=permissions, typeclass=typeclass - ) - logger.log_sec(f"Account Created: {account} (IP: {ip}).") - - except Exception: - errors.append( - _("There was an error creating the Account. " - "If this problem persists, contact an admin.")) - logger.log_trace() - return None, errors - - # This needs to be set so the engine knows this account is - # logging in for the first time. (so it knows to call the right - # hooks during login later) - account.db.FIRST_LOGIN = True - - # Record IP address of creation, if available - if ip: - account.db.creator_ip = ip - - # join the new account to the public channel - pchannel = ChannelDB.objects.get_channel(settings.DEFAULT_CHANNELS[0]["key"]) - if not pchannel or not pchannel.connect(account): - string = "New account '{account.key}' could not connect to public channel!" - errors.append(string) - logger.log_err(string) - - if account and settings.MULTISESSION_MODE < 2: - # Auto-create a character to go with this account - - character, errs = account.create_character( - typeclass=kwargs.get("character_typeclass") - ) - if errs: - errors.extend(errs) - - except Exception: - # We are in the middle between logged in and -not, so we have - # to handle tracebacks ourselves at this point. If we don't, - # we won't see any errors at all. - errors.append(_("An error occurred. Please e-mail an admin if the problem persists.")) - logger.log_trace() - - # Update the throttle to indicate a new account was created from this IP - if ip and not guest: - CREATION_THROTTLE.update(ip, "Too many accounts being created.") - SIGNAL_ACCOUNT_POST_CREATE.send(sender=account, ip=ip) - return account, errors
- -
[docs] def delete(self, *args, **kwargs): - """ - Deletes the account persistently. - - Notes: - `*args` and `**kwargs` are passed on to the base delete - mechanism (these are usually not used). - - Return: - bool: If deletion was successful. Only time it fails would be - if the Account was already deleted. Note that even on a failure, - connected resources (nicks/aliases etc) will still have been - deleted. - - """ - for session in self.sessions.all(): - # unpuppeting all objects and disconnecting the user, if any - # sessions remain (should usually be handled from the - # deleting command) - try: - self.unpuppet_object(session) - except RuntimeError: - # no puppet to disconnect from - pass - session.sessionhandler.disconnect(session, reason=_("Account being deleted.")) - self.scripts.stop() - self.attributes.clear() - self.nicks.clear() - self.aliases.clear() - if not self.pk: - return False - super().delete(*args, **kwargs) - return True
- - - # methods inherited from database model - -
[docs] def msg(self, text=None, from_obj=None, session=None, options=None, **kwargs): - """ - Evennia -> User - This is the main route for sending data back to the user from the - server. - - Args: - text (str or tuple, optional): The message to send. This - is treated internally like any send-command, so its - value can be a tuple if sending multiple arguments to - the `text` oob command. - from_obj (Object or Account or list, optional): Object sending. If given, its - at_msg_send() hook will be called. If iterable, call on all entities. - session (Session or list, optional): Session object or a list of - Sessions to receive this send. If given, overrules the - default send behavior for the current - MULTISESSION_MODE. - options (list): Protocol-specific options. Passed on to the protocol. - Keyword Args: - any (dict): All other keywords are passed on to the protocol. - - """ - if from_obj: - # call hook - for obj in make_iter(from_obj): - try: - obj.at_msg_send(text=text, to_obj=self, **kwargs) - except Exception: - # this may not be assigned. - logger.log_trace() - try: - if not self.at_msg_receive(text=text, **kwargs): - # abort message to this account - return - except Exception: - # this may not be assigned. - pass - - kwargs["options"] = options - - if text is not None: - if not (isinstance(text, str) or isinstance(text, tuple)): - # sanitize text before sending across the wire - try: - text = to_str(text) - except Exception: - text = repr(text) - kwargs["text"] = text - - # session relay - sessions = make_iter(session) if session else self.sessions.all() - for session in sessions: - session.data_out(**kwargs)
- -
[docs] def execute_cmd(self, raw_string, session=None, **kwargs): - """ - Do something as this account. This method is never called normally, - but only when the account object itself is supposed to execute the - command. It takes account nicks into account, but not nicks of - eventual puppets. - - Args: - raw_string (str): Raw command input coming from the command line. - session (Session, optional): The session to be responsible - for the command-send - - Keyword Args: - kwargs (any): Other keyword arguments will be added to the - found command object instance as variables before it - executes. This is unused by default Evennia but may be - used to set flags and change operating paramaters for - commands at run-time. - - """ - # break circular import issues - global _CMDHANDLER - if not _CMDHANDLER: - from evennia.commands.cmdhandler import cmdhandler as _CMDHANDLER - raw_string = self.nicks.nickreplace( - raw_string, categories=("inputline", "channel"), include_account=False - ) - if not session and _MULTISESSION_MODE in (0, 1): - # for these modes we use the first/only session - sessions = self.sessions.get() - session = sessions[0] if sessions else None - - return _CMDHANDLER( - self, raw_string, callertype="account", session=session, **kwargs - )
- - # channel receive hooks - -
[docs] def at_pre_channel_msg(self, message, channel, senders=None, **kwargs): - """ - Called by the Channel just before passing a message into `channel_msg`. - This allows for tweak messages per-user and also to abort the - receive on the receiver-level. - - Args: - message (str): The message sent to the channel. - channel (Channel): The sending channel. - senders (list, optional): Accounts or Objects acting as senders. - For most normal messages, there is only a single sender. If - there are no senders, this may be a broadcasting message. - **kwargs: These are additional keywords passed into `channel_msg`. - If `no_prefix=True` or `emit=True` are passed, the channel - prefix will not be added (`[channelname]: ` by default) - - Returns: - str or None: Allows for customizing the message for this recipient. - If returning `None` (or `False`) message-receiving is aborted. - The returning string will be passed into `self.channel_msg`. - - Notes: - This support posing/emotes by starting channel-send with : or ;. - - """ - if senders: - sender_string = ', '.join(sender.get_display_name(self) for sender in senders) - message_lstrip = message.lstrip() - if message_lstrip.startswith((':', ';')): - # this is a pose, should show as e.g. "User1 smiles to channel" - spacing = "" if message_lstrip[1:].startswith((':', '\'', ',')) else " " - message = f"{sender_string}{spacing}{message_lstrip[1:]}" - else: - # normal message - message = f"{sender_string}: {message}" - - if not kwargs.get("no_prefix") or not kwargs.get("emit"): - message = channel.channel_prefix() + message - - return message
- -
[docs] def channel_msg(self, message, channel, senders=None, **kwargs): - """ - This performs the actions of receiving a message to an un-muted - channel. - - Args: - message (str): The message sent to the channel. - channel (Channel): The sending channel. - senders (list, optional): Accounts or Objects acting as senders. - For most normal messages, there is only a single sender. If - there are no senders, this may be a broadcasting message or - similar. - **kwargs: These are additional keywords originally passed into - `Channel.msg`. - - Notes: - Before this, `Channel.at_pre_channel_msg` will fire, which offers a way - to customize the message for the receiver on the channel-level. - - """ - self.msg(text=(message, {"from_channel": channel.id}), - from_obj=senders, options={"from_channel": channel.id})
- -
[docs] def at_post_channel_msg(self, message, channel, senders=None, **kwargs): - """ - Called by `self.channel_msg` after message was received. - - Args: - message (str): The message sent to the channel. - channel (Channel): The sending channel. - senders (list, optional): Accounts or Objects acting as senders. - For most normal messages, there is only a single sender. If - there are no senders, this may be a broadcasting message. - **kwargs: These are additional keywords passed into `channel_msg`. - - """ - pass
- - # search method - -
[docs] def search( - self, - searchdata, - return_puppet=False, - search_object=False, - typeclass=None, - nofound_string=None, - multimatch_string=None, - use_nicks=True, - quiet=False, - **kwargs, - ): - """ - This is similar to `DefaultObject.search` but defaults to searching - for Accounts only. - - Args: - searchdata (str or int): Search criterion, the Account's - key or dbref to search for. - return_puppet (bool, optional): Instructs the method to - return matches as the object the Account controls rather - than the Account itself (or None) if nothing is puppeted). - search_object (bool, optional): Search for Objects instead of - Accounts. This is used by e.g. the @examine command when - wanting to examine Objects while OOC. - typeclass (Account typeclass, optional): Limit the search - only to this particular typeclass. This can be used to - limit to specific account typeclasses or to limit the search - to a particular Object typeclass if `search_object` is True. - nofound_string (str, optional): A one-time error message - to echo if `searchdata` leads to no matches. If not given, - will fall back to the default handler. - multimatch_string (str, optional): A one-time error - message to echo if `searchdata` leads to multiple matches. - If not given, will fall back to the default handler. - use_nicks (bool, optional): Use account-level nick replacement. - quiet (bool, optional): If set, will not show any error to the user, - and will also lead to returning a list of matches. - - Return: - match (Account, Object or None): A single Account or Object match. - list: If `quiet=True` this is a list of 0, 1 or more Account or Object matches. - - Notes: - Extra keywords are ignored, but are allowed in call in - order to make API more consistent with - objects.objects.DefaultObject.search. - - """ - # handle me, self and *me, *self - if isinstance(searchdata, str): - # handle wrapping of common terms - if searchdata.lower() in ("me", "*me", "self", "*self"): - return self - searchdata = self.nicks.nickreplace( - searchdata, categories=("account",), include_account=False - ) - if search_object: - matches = ObjectDB.objects.object_search(searchdata, typeclass=typeclass) - else: - matches = AccountDB.objects.account_search(searchdata, typeclass=typeclass) - - if quiet: - matches = list(matches) - if return_puppet: - matches = [match.puppet for match in matches] - else: - matches = _AT_SEARCH_RESULT( - matches, - self, - query=searchdata, - nofound_string=nofound_string, - multimatch_string=multimatch_string, - ) - if matches and return_puppet: - try: - matches = matches.puppet - except AttributeError: - return None - return matches
- -
[docs] def access( - self, accessing_obj, access_type="read", default=False, no_superuser_bypass=False, **kwargs - ): - """ - Determines if another object has permission to access this - object in whatever way. - - Args: - accessing_obj (Object): Object trying to access this one. - access_type (str, optional): Type of access sought. - default (bool, optional): What to return if no lock of - access_type was found - no_superuser_bypass (bool, optional): Turn off superuser - lock bypassing. Be careful with this one. - - Keyword Args: - kwargs (any): Passed to the at_access hook along with the result. - - Returns: - result (bool): Result of access check. - - """ - result = super().access( - accessing_obj, - access_type=access_type, - default=default, - no_superuser_bypass=no_superuser_bypass, - ) - self.at_access(result, accessing_obj, access_type, **kwargs) - return result
- - @property - def idle_time(self): - """ - Returns the idle time of the least idle session in seconds. If - no sessions are connected it returns nothing. - """ - idle = [session.cmd_last_visible for session in self.sessions.all()] - if idle: - return time.time() - float(max(idle)) - return None - - @property - def connection_time(self): - """ - Returns the maximum connection time of all connected sessions - in seconds. Returns nothing if there are no sessions. - """ - conn = [session.conn_time for session in self.sessions.all()] - if conn: - return time.time() - float(min(conn)) - return None - - # account hooks - -
[docs] def basetype_setup(self): - """ - This sets up the basic properties for an account. Overload this - with at_account_creation rather than changing this method. - - """ - # A basic security setup - lockstring = ( - "examine:perm(Admin);edit:perm(Admin);" - "delete:perm(Admin);boot:perm(Admin);msg:all();" - "noidletimeout:perm(Builder) or perm(noidletimeout)" - ) - self.locks.add(lockstring) - - # The ooc account cmdset - self.cmdset.add_default(_CMDSET_ACCOUNT, persistent=True)
- -
[docs] def at_account_creation(self): - """ - This is called once, the very first time the account is created - (i.e. first time they register with the game). It's a good - place to store attributes all accounts should have, like - configuration values etc. - - """ - # set an (empty) attribute holding the characters this account has - lockstring = "attrread:perm(Admins);attredit:perm(Admins);" "attrcreate:perm(Admins);" - self.attributes.add("_playable_characters", [], lockstring=lockstring) - self.attributes.add("_saved_protocol_flags", {}, lockstring=lockstring)
- -
[docs] def at_init(self): - """ - This is always called whenever this object is initiated -- - that is, whenever it its typeclass is cached from memory. This - happens on-demand first time the object is used or activated - in some way after being created but also after each server - restart or reload. In the case of account objects, this usually - happens the moment the account logs in or reconnects after a - reload. - - """ - pass
- - # Note that the hooks below also exist in the character object's - # typeclass. You can often ignore these and rely on the character - # ones instead, unless you are implementing a multi-character game - # and have some things that should be done regardless of which - # character is currently connected to this account. - -
[docs] def at_first_save(self): - """ - This is a generic hook called by Evennia when this object is - saved to the database the very first time. You generally - don't override this method but the hooks called by it. - - """ - self.basetype_setup() - self.at_account_creation() - - permissions = [settings.PERMISSION_ACCOUNT_DEFAULT] - if hasattr(self, "_createdict"): - # this will only be set if the utils.create_account - # function was used to create the object. - cdict = self._createdict - updates = [] - if not cdict.get("key"): - if not self.db_key: - self.db_key = f"#{self.dbid}" - updates.append("db_key") - elif self.key != cdict.get("key"): - updates.append("db_key") - self.db_key = cdict["key"] - if updates: - self.save(update_fields=updates) - - if cdict.get("locks"): - self.locks.add(cdict["locks"]) - if cdict.get("permissions"): - permissions = cdict["permissions"] - if cdict.get("tags"): - # this should be a list of tags, tuples (key, category) or (key, category, data) - self.tags.batch_add(*cdict["tags"]) - if cdict.get("attributes"): - # this should be tuples (key, val, ...) - self.attributes.batch_add(*cdict["attributes"]) - if cdict.get("nattributes"): - # this should be a dict of nattrname:value - for key, value in cdict["nattributes"]: - self.nattributes.add(key, value) - del self._createdict - - self.permissions.batch_add(*permissions)
- -
[docs] def at_access(self, result, accessing_obj, access_type, **kwargs): - """ - This is triggered after an access-call on this Account has - completed. - - Args: - result (bool): The result of the access check. - accessing_obj (any): The object requesting the access - check. - access_type (str): The type of access checked. - - Keyword Args: - kwargs (any): These are passed on from the access check - and can be used to relay custom instructions from the - check mechanism. - - Notes: - This method cannot affect the result of the lock check and - its return value is not used in any way. It can be used - e.g. to customize error messages in a central location or - create other effects based on the access result. - - """ - pass
- -
[docs] def at_cmdset_get(self, **kwargs): - """ - Called just *before* cmdsets on this account are requested by - the command handler. The cmdsets are available as - `self.cmdset`. If changes need to be done on the fly to the - cmdset before passing them on to the cmdhandler, this is the - place to do it. This is called also if the account currently - have no cmdsets. kwargs are usually not used unless the - cmdset is generated dynamically. - - """ - pass
- -
[docs] def at_first_login(self, **kwargs): - """ - Called the very first time this account logs into the game. - Note that this is called *before* at_pre_login, so no session - is established and usually no character is yet assigned at - this point. This hook is intended for account-specific setup - like configurations. - - Args: - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - """ - pass
- -
[docs] def at_password_change(self, **kwargs): - """ - Called after a successful password set/modify. - - Args: - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - """ - pass
- -
[docs] def at_pre_login(self, **kwargs): - """ - Called every time the user logs in, just before the actual - login-state is set. - - Args: - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - """ - pass
- - def _send_to_connect_channel(self, message): - """ - Helper method for loading and sending to the comm channel dedicated to - connection messages. This will also be sent to the mudinfo channel. - - Args: - message (str): A message to send to the connect channel. - - """ - global _MUDINFO_CHANNEL, _CONNECT_CHANNEL - if _MUDINFO_CHANNEL is None: - if settings.CHANNEL_MUDINFO: - try: - _MUDINFO_CHANNEL = ChannelDB.objects.get( - db_key=settings.CHANNEL_MUDINFO["key"]) - except ChannelDB.DoesNotExist: - logger.log_trace() - else: - _MUDINFO = False - if _CONNECT_CHANNEL is None: - if settings.CHANNEL_CONNECTINFO: - try: - _CONNECT_CHANNEL = ChannelDB.objects.get( - db_key=settings.CHANNEL_CONNECTINFO["key"]) - except ChannelDB.DoesNotExist: - logger.log_trace() - else: - _CONNECT_CHANNEL = False - - if settings.USE_TZ: - now = timezone.localtime() - else: - now = timezone.now() - now = "%02i-%02i-%02i(%02i:%02i)" % (now.year, now.month, now.day, now.hour, now.minute) - if _MUDINFO_CHANNEL: - _MUDINFO_CHANNEL.msg(f"[{now}]: {message}") - if _CONNECT_CHANNEL: - _CONNECT_CHANNEL.msg(f"[{now}]: {message}") - -
[docs] def at_post_login(self, session=None, **kwargs): - """ - Called at the end of the login process, just before letting - the account loose. - - Args: - session (Session, optional): Session logging in, if any. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Notes: - This is called *before* an eventual Character's - `at_post_login` hook. By default it is used to set up - auto-puppeting based on `MULTISESSION_MODE`. - - """ - # if we have saved protocol flags on ourselves, load them here. - protocol_flags = self.attributes.get("_saved_protocol_flags", {}) - if session and protocol_flags: - session.update_flags(**protocol_flags) - - # inform the client that we logged in through an OOB message - if session: - session.msg(logged_in={}) - - self._send_to_connect_channel(_("|G{key} connected|n").format(key=self.key)) - if _MULTISESSION_MODE == 0: - # in this mode we should have only one character available. We - # try to auto-connect to our last conneted object, if any - try: - self.puppet_object(session, self.db._last_puppet) - except RuntimeError: - self.msg(_("The Character does not exist.")) - return - elif _MULTISESSION_MODE == 1: - # in this mode all sessions connect to the same puppet. - try: - self.puppet_object(session, self.db._last_puppet) - except RuntimeError: - self.msg(_("The Character does not exist.")) - return - elif _MULTISESSION_MODE in (2, 3): - # In this mode we by default end up at a character selection - # screen. We execute look on the account. - # we make sure to clean up the _playable_characters list in case - # any was deleted in the interim. - self.db._playable_characters = [char for char in self.db._playable_characters if char] - self.msg( - self.at_look(target=self.db._playable_characters, session=session), session=session - )
- -
[docs] def at_failed_login(self, session, **kwargs): - """ - Called by the login process if a user account is targeted correctly - but provided with an invalid password. By default it does nothing, - but exists to be overriden. - - Args: - session (session): Session logging in. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - """ - pass
- -
[docs] def at_disconnect(self, reason=None, **kwargs): - """ - Called just before user is disconnected. - - Args: - reason (str, optional): The reason given for the disconnect, - (echoed to the connection channel by default). - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - - """ - reason = f" ({reason if reason else ''})" - self._send_to_connect_channel( - _("|R{key} disconnected{reason}|n").format(key=self.key, reason=reason) - )
- -
[docs] def at_post_disconnect(self, **kwargs): - """ - This is called *after* disconnection is complete. No messages - can be relayed to the account from here. After this call, the - account should not be accessed any more, making this a good - spot for deleting it (in the case of a guest account account, - for example). - - Args: - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - """ - pass
- -
[docs] def at_msg_receive(self, text=None, from_obj=None, **kwargs): - """ - This hook is called whenever someone sends a message to this - object using the `msg` method. - - Note that from_obj may be None if the sender did not include - itself as an argument to the obj.msg() call - so you have to - check for this. . - - Consider this a pre-processing method before msg is passed on - to the user session. If this method returns False, the msg - will not be passed on. - - Args: - text (str, optional): The message received. - from_obj (any, optional): The object sending the message. - - Keyword Args: - This includes any keywords sent to the `msg` method. - - Returns: - receive (bool): If this message should be received. - - Notes: - If this method returns False, the `msg` operation - will abort without sending the message. - - """ - return True
- -
[docs] def at_msg_send(self, text=None, to_obj=None, **kwargs): - """ - This is a hook that is called when *this* object sends a - message to another object with `obj.msg(text, to_obj=obj)`. - - Args: - text (str, optional): Text to send. - to_obj (any, optional): The object to send to. - - Keyword Args: - Keywords passed from msg() - - Notes: - Since this method is executed by `from_obj`, if no `from_obj` - was passed to `DefaultCharacter.msg` this hook will never - get called. - - """ - pass
- -
[docs] def at_server_reload(self): - """ - This hook is called whenever the server is shutting down for - restart/reboot. If you want to, for example, save - non-persistent properties across a restart, this is the place - to do it. - """ - pass
- -
[docs] def at_server_shutdown(self): - """ - This hook is called whenever the server is shutting down fully - (i.e. not for a restart). - """ - pass
- -
[docs] def at_look(self, target=None, session=None, **kwargs): - """ - Called when this object executes a look. It allows to customize - just what this means. - - Args: - target (Object or list, optional): An object or a list - objects to inspect. - session (Session, optional): The session doing this look. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Returns: - look_string (str): A prepared look string, ready to send - off to any recipient (usually to ourselves) - - """ - - if target and not is_iter(target): - # single target - just show it - if hasattr(target, "return_appearance"): - return target.return_appearance(self) - else: - return f"{target} has no in-game appearance." - else: - # list of targets - make list to disconnect from db - characters = list(tar for tar in target if tar) if target else [] - sessions = self.sessions.all() - if not sessions: - # no sessions, nothing to report - return "" - is_su = self.is_superuser - - # text shown when looking in the ooc area - result = [f"Account |g{self.key}|n (you are Out-of-Character)"] - - nsess = len(sessions) - result.append( - nsess == 1 - and "\n\n|wConnected session:|n" - or f"\n\n|wConnected sessions ({nsess}):|n" - ) - for isess, sess in enumerate(sessions): - csessid = sess.sessid - addr = "%s (%s)" % ( - sess.protocol_key, - isinstance(sess.address, tuple) and str(sess.address[0]) or str(sess.address), - ) - result.append( - "\n %s %s" - % ( - session - and session.sessid == csessid - and "|w* %s|n" % (isess + 1) - or " %s" % (isess + 1), - addr, - ) - ) - result.append("\n\n |whelp|n - more commands") - result.append("\n |wpublic <Text>|n - talk on public channel") - - charmax = _MAX_NR_CHARACTERS - - if is_su or len(characters) < charmax: - if not characters: - result.append( - "\n\n You don't have any characters yet. See |whelp charcreate|n for " - "creating one." - ) - else: - result.append("\n |wcharcreate <name> [=description]|n - create new character") - result.append( - "\n |wchardelete <name>|n - delete a character (cannot be undone!)" - ) - - if characters: - string_s_ending = len(characters) > 1 and "s" or "" - result.append("\n |wic <character>|n - enter the game (|wooc|n to get back here)") - if is_su: - result.append( - f"\n\nAvailable character{string_s_ending} ({len(characters)}/unlimited):" - ) - else: - result.append( - "\n\nAvailable character%s%s:" - % ( - string_s_ending, - charmax > 1 and " (%i/%i)" % (len(characters), charmax) or "", - ) - ) - - for char in characters: - csessions = char.sessions.all() - if csessions: - for sess in csessions: - # character is already puppeted - sid = sess in sessions and sessions.index(sess) + 1 - if sess and sid: - result.append( - f"\n - |G{char.key}|n [{', '.join(char.permissions.all())}] " - f"(played by you in session {sid})") - else: - result.append( - f"\n - |R{char.key}|n [{', '.join(char.permissions.all())}] " - "(played by someone else)" - ) - else: - # character is "free to puppet" - result.append(f"\n - {char.key} [{', '.join(char.permissions.all())}]") - look_string = ("-" * 68) + "\n" + "".join(result) + "\n" + ("-" * 68) - return look_string
- - -
[docs]class DefaultGuest(DefaultAccount): - """ - This class is used for guest logins. Unlike Accounts, Guests and - their characters are deleted after disconnection. - - """ - -
[docs] @classmethod - def create(cls, **kwargs): - """ - Forwards request to cls.authenticate(); returns a DefaultGuest object - if one is available for use. - - """ - return cls.authenticate(**kwargs)
- -
[docs] @classmethod - def authenticate(cls, **kwargs): - """ - Gets or creates a Guest account object. - - Keyword Args: - ip (str, optional): IP address of requestor; used for ban checking, - throttling and logging - - Returns: - account (Object): Guest account object, if available - errors (list): List of error messages accrued during this request. - - """ - errors = [] - account = None - username = None - ip = kwargs.get("ip", "").strip() - - # check if guests are enabled. - if not settings.GUEST_ENABLED: - errors.append(_("Guest accounts are not enabled on this server.")) - return None, errors - - try: - # Find an available guest name. - for name in settings.GUEST_LIST: - if not AccountDB.objects.filter(username__iexact=name).exists(): - username = name - break - if not username: - errors.append(_("All guest accounts are in use. Please try again later.")) - if ip: - LOGIN_THROTTLE.update(ip, "Too many requests for Guest access.") - return None, errors - else: - # build a new account with the found guest username - password = "%016x" % getrandbits(64) - home = settings.GUEST_HOME - permissions = settings.PERMISSION_GUEST_DEFAULT - typeclass = settings.BASE_GUEST_TYPECLASS - - # Call parent class creator - account, errs = super(DefaultGuest, cls).create( - guest=True, - username=username, - password=password, - permissions=permissions, - typeclass=typeclass, - home=home, - ip=ip, - ) - errors.extend(errs) - - if not account.characters: - # this can happen for multisession_mode > 1. For guests we - # always auto-create a character, regardless of multi-session-mode. - character, errs = account.create_character() - - if errs: - errors.extend(errs) - - return account, errors - - except Exception: - # We are in the middle between logged in and -not, so we have - # to handle tracebacks ourselves at this point. If we don't, - # we won't see any errors at all. - errors.append(_("An error occurred. Please e-mail an admin if the problem persists.")) - logger.log_trace() - return None, errors - - return account, errors
- -
[docs] def at_post_login(self, session=None, **kwargs): - """ - In theory, guests only have one character regardless of which - MULTISESSION_MODE we're in. They don't get a choice. - - Args: - session (Session, optional): Session connecting. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - """ - self._send_to_connect_channel(_("|G{key} connected|n").format(key=self.key)) - self.puppet_object(session, self.db._last_puppet)
- -
[docs] def at_server_shutdown(self): - """ - We repeat the functionality of `at_disconnect()` here just to - be on the safe side. - """ - super().at_server_shutdown() - characters = self.db._playable_characters - if characters: - for character in characters: - if character: - character.delete()
- -
[docs] def at_post_disconnect(self, **kwargs): - """ - Once having disconnected, destroy the guest's characters and - - Args: - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - """ - super().at_post_disconnect() - characters = self.db._playable_characters - for character in characters: - if character: - character.delete() - self.delete()
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/accounts/bots.html b/docs/0.9.5/_modules/evennia/accounts/bots.html deleted file mode 100644 index 3463be37de..0000000000 --- a/docs/0.9.5/_modules/evennia/accounts/bots.html +++ /dev/null @@ -1,685 +0,0 @@ - - - - - - - - evennia.accounts.bots — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.accounts.bots

-"""
-Bots are a special child typeclasses of
-Account that are  controlled by the server.
-
-"""
-
-import time
-from django.conf import settings
-from evennia.accounts.accounts import DefaultAccount
-from evennia.scripts.scripts import DefaultScript
-from evennia.utils import search
-from evennia.utils import utils
-from django.utils.translation import gettext as _
-
-_IDLE_TIMEOUT = settings.IDLE_TIMEOUT
-
-_IRC_ENABLED = settings.IRC_ENABLED
-_RSS_ENABLED = settings.RSS_ENABLED
-_GRAPEVINE_ENABLED = settings.GRAPEVINE_ENABLED
-
-
-_SESSIONS = None
-
-
-# Bot helper utilities
-
-
-
[docs]class BotStarter(DefaultScript): - """ - This non-repeating script has the - sole purpose of kicking its bot - into gear when it is initialized. - - """ - -
[docs] def at_script_creation(self): - """ - Called once, when script is created. - - """ - self.key = "botstarter" - self.desc = "bot start/keepalive" - self.persistent = True - self.db.started = False
- -
[docs] def at_start(self): - """ - Kick bot into gear. - - """ - if not self.db.started: - self.account.start() - self.db.started = True
- -
[docs] def at_repeat(self): - """ - Called self.interval seconds to keep connection. We cannot use - the IDLE command from inside the game since the system will - not catch it (commands executed from the server side usually - has no sessions). So we update the idle counter manually here - instead. This keeps the bot getting hit by IDLE_TIMEOUT. - - """ - global _SESSIONS - if not _SESSIONS: - from evennia.server.sessionhandler import SESSIONS as _SESSIONS - for session in _SESSIONS.sessions_from_account(self.account): - session.update_session_counters(idle=True)
- -
[docs] def at_server_reload(self): - """ - If server reloads we don't need to reconnect the protocol - again, this is handled by the portal reconnect mechanism. - - """ - self.db.started = True
- -
[docs] def at_server_shutdown(self): - """ - Make sure we are shutdown. - - """ - self.db.started = False
- - -# -# Bot base class - - -
[docs]class Bot(DefaultAccount): - """ - A Bot will start itself when the server starts (it will generally - not do so on a reload - that will be handled by the normal Portal - session resync) - - """ - -
[docs] def basetype_setup(self): - """ - This sets up the basic properties for the bot. - - """ - # the text encoding to use. - self.db.encoding = "utf-8" - # A basic security setup (also avoid idle disconnects) - lockstring = ( - "examine:perm(Admin);edit:perm(Admin);delete:perm(Admin);" - "boot:perm(Admin);msg:false();noidletimeout:true()" - ) - self.locks.add(lockstring) - # set the basics of being a bot - script_key = str(self.key) - self.scripts.add(BotStarter, key=script_key) - self.is_bot = True
- -
[docs] def start(self, **kwargs): - """ - This starts the bot, whatever that may mean. - - """ - pass
- -
[docs] def msg(self, text=None, from_obj=None, session=None, options=None, **kwargs): - """ - Evennia -> outgoing protocol - - """ - super().msg(text=text, from_obj=from_obj, session=session, options=options, **kwargs)
- -
[docs] def execute_cmd(self, raw_string, session=None): - """ - Incoming protocol -> Evennia - - """ - super().msg(raw_string, session=session)
- -
[docs] def at_server_shutdown(self): - """ - We need to handle this case manually since the shutdown may be - a reset. - - """ - for session in self.sessions.all(): - session.sessionhandler.disconnect(session)
- - -# Bot implementations - -# IRC - - -
[docs]class IRCBot(Bot): - """ - Bot for handling IRC connections. - - """ - - # override this on a child class to use custom factory - factory_path = "evennia.server.portal.irc.IRCBotFactory" - -
[docs] def start( - self, - ev_channel=None, - irc_botname=None, - irc_channel=None, - irc_network=None, - irc_port=None, - irc_ssl=None, - ): - """ - Start by telling the portal to start a new session. - - Args: - ev_channel (str): Key of the Evennia channel to connect to. - irc_botname (str): Name of bot to connect to irc channel. If - not set, use `self.key`. - irc_channel (str): Name of channel on the form `#channelname`. - irc_network (str): URL of the IRC network, like `irc.freenode.net`. - irc_port (str): Port number of the irc network, like `6667`. - irc_ssl (bool): Indicates whether to use SSL connection. - - """ - if not _IRC_ENABLED: - # the bot was created, then IRC was turned off. We delete - # ourselves (this will also kill the start script) - self.delete() - return - - global _SESSIONS - if not _SESSIONS: - from evennia.server.sessionhandler import SESSIONS as _SESSIONS - - # if keywords are given, store (the BotStarter script - # will not give any keywords, so this should normally only - # happen at initialization) - if irc_botname: - self.db.irc_botname = irc_botname - elif not self.db.irc_botname: - self.db.irc_botname = self.key - if ev_channel: - # connect to Evennia channel - channel = search.channel_search(ev_channel) - if not channel: - raise RuntimeError(f"Evennia Channel '{ev_channel}' not found.") - channel = channel[0] - channel.connect(self) - self.db.ev_channel = channel - if irc_channel: - self.db.irc_channel = irc_channel - if irc_network: - self.db.irc_network = irc_network - if irc_port: - self.db.irc_port = irc_port - if irc_ssl: - self.db.irc_ssl = irc_ssl - - # instruct the server and portal to create a new session with - # the stored configuration - configdict = { - "uid": self.dbid, - "botname": self.db.irc_botname, - "channel": self.db.irc_channel, - "network": self.db.irc_network, - "port": self.db.irc_port, - "ssl": self.db.irc_ssl, - } - _SESSIONS.start_bot_session(self.factory_path, configdict)
- -
[docs] def at_msg_send(self, **kwargs): - "Shortcut here or we can end up in infinite loop" - pass
- -
[docs] def get_nicklist(self, caller): - """ - Retrive the nick list from the connected channel. - - Args: - caller (Object or Account): The requester of the list. This will - be stored and echoed to when the irc network replies with the - requested info. - - Notes: Since the return is asynchronous, the caller is stored internally - in a list; all callers in this list will get the nick info once it - returns (it is a custom OOB inputfunc option). The callback will not - survive a reload (which should be fine, it's very quick). - """ - if not hasattr(self, "_nicklist_callers"): - self._nicklist_callers = [] - self._nicklist_callers.append(caller) - super().msg(request_nicklist="") - return
- -
[docs] def ping(self, caller): - """ - Fire a ping to the IRC server. - - Args: - caller (Object or Account): The requester of the ping. - - """ - if not hasattr(self, "_ping_callers"): - self._ping_callers = [] - self._ping_callers.append(caller) - super().msg(ping="")
- -
[docs] def reconnect(self): - """ - Force a protocol-side reconnect of the client without - having to destroy/recreate the bot "account". - - """ - super().msg(reconnect="")
- -
[docs] def msg(self, text=None, **kwargs): - """ - Takes text from connected channel (only). - - Args: - text (str, optional): Incoming text from channel. - - Keyword Args: - options (dict): Options dict with the following allowed keys: - - from_channel (str): dbid of a channel this text originated from. - - from_obj (list): list of objects sending this text. - - """ - from_obj = kwargs.get("from_obj", None) - options = kwargs.get("options", None) or {} - - if not self.ndb.ev_channel and self.db.ev_channel: - # cache channel lookup - self.ndb.ev_channel = self.db.ev_channel - - if ( - "from_channel" in options - and text - and self.ndb.ev_channel.dbid == options["from_channel"] - ): - if not from_obj or from_obj != [self]: - super().msg(channel=text)
- -
[docs] def execute_cmd(self, session=None, txt=None, **kwargs): - """ - Take incoming data and send it to connected channel. This is - triggered by the bot_data_in Inputfunc. - - Args: - session (Session, optional): Session responsible for this - command. Note that this is the bot. - txt (str, optional): Command string. - Keyword Args: - user (str): The name of the user who sent the message. - channel (str): The name of channel the message was sent to. - type (str): Nature of message. Either 'msg', 'action', 'nicklist' - or 'ping'. - nicklist (list, optional): Set if `type='nicklist'`. This is a list - of nicks returned by calling the `self.get_nicklist`. It must look - for a list `self._nicklist_callers` which will contain all callers - waiting for the nicklist. - timings (float, optional): Set if `type='ping'`. This is the return - (in seconds) of a ping request triggered with `self.ping`. The - return must look for a list `self._ping_callers` which will contain - all callers waiting for the ping return. - - """ - if kwargs["type"] == "nicklist": - # the return of a nicklist request - if hasattr(self, "_nicklist_callers") and self._nicklist_callers: - chstr = f"{self.db.irc_channel} ({self.db.irc_network}:{self.db.irc_port})" - nicklist = ", ".join(sorted(kwargs["nicklist"], key=lambda n: n.lower())) - for obj in self._nicklist_callers: - obj.msg( - "Nicks at {chstr}:\n {nicklist}".format(chstr=chstr, nicklist=nicklist) - ) - self._nicklist_callers = [] - return - - elif kwargs["type"] == "ping": - # the return of a ping - if hasattr(self, "_ping_callers") and self._ping_callers: - chstr = f"{self.db.irc_channel} ({self.db.irc_network}:{self.db.irc_port})" - for obj in self._ping_callers: - obj.msg( - "IRC ping return from {chstr} took {time}s.".format( - chstr=chstr, time=kwargs["timing"] - ) - ) - self._ping_callers = [] - return - - elif kwargs["type"] == "privmsg": - # A private message to the bot - a command. - user = kwargs["user"] - - if txt.lower().startswith("who"): - # return server WHO list (abbreviated for IRC) - global _SESSIONS - if not _SESSIONS: - from evennia.server.sessionhandler import SESSIONS as _SESSIONS - whos = [] - t0 = time.time() - for sess in _SESSIONS.get_sessions(): - delta_cmd = t0 - sess.cmd_last_visible - delta_conn = t0 - session.conn_time - account = sess.get_account() - whos.append( - "%s (%s/%s)" - % ( - utils.crop("|w%s|n" % account.name, width=25), - utils.time_format(delta_conn, 0), - utils.time_format(delta_cmd, 1), - ) - ) - text = f"Who list (online/idle): {', '.join(sorted(whos, key=lambda w: w.lower()))}" - elif txt.lower().startswith("about"): - # some bot info - text = f"This is an Evennia IRC bot connecting from '{settings.SERVERNAME}'." - else: - text = "I understand 'who' and 'about'." - super().msg(privmsg=((text,), {"user": user})) - else: - # something to send to the main channel - if kwargs["type"] == "action": - # An action (irc pose) - text = f"{kwargs['user']}@{kwargs['channel']} {txt}" - else: - # msg - A normal channel message - text = f"{kwargs['user']}@{kwargs['channel']}: {txt}" - - if not self.ndb.ev_channel and self.db.ev_channel: - # cache channel lookup - self.ndb.ev_channel = self.db.ev_channel - - if self.ndb.ev_channel: - self.ndb.ev_channel.msg(text, senders=self)
- - -# -# RSS -# - - -
[docs]class RSSBot(Bot): - """ - An RSS relayer. The RSS protocol itself runs a ticker to update - its feed at regular intervals. - - """ - -
[docs] def start(self, ev_channel=None, rss_url=None, rss_rate=None): - """ - Start by telling the portal to start a new RSS session - - Args: - ev_channel (str): Key of the Evennia channel to connect to. - rss_url (str): Full URL to the RSS feed to subscribe to. - rss_rate (int): How often for the feedreader to update. - - Raises: - RuntimeError: If `ev_channel` does not exist. - - """ - if not _RSS_ENABLED: - # The bot was created, then RSS was turned off. Delete ourselves. - self.delete() - return - - global _SESSIONS - if not _SESSIONS: - from evennia.server.sessionhandler import SESSIONS as _SESSIONS - - if ev_channel: - # connect to Evennia channel - channel = search.channel_search(ev_channel) - if not channel: - raise RuntimeError(f"Evennia Channel '{ev_channel}' not found.") - channel = channel[0] - self.db.ev_channel = channel - if rss_url: - self.db.rss_url = rss_url - if rss_rate: - self.db.rss_rate = rss_rate - # instruct the server and portal to create a new session with - # the stored configuration - configdict = {"uid": self.dbid, "url": self.db.rss_url, "rate": self.db.rss_rate} - _SESSIONS.start_bot_session("evennia.server.portal.rss.RSSBotFactory", configdict)
- -
[docs] def execute_cmd(self, txt=None, session=None, **kwargs): - """ - Take incoming data and send it to connected channel. This is - triggered by the bot_data_in Inputfunc. - - Args: - session (Session, optional): Session responsible for this - command. - txt (str, optional): Command string. - kwargs (dict, optional): Additional Information passed from bot. - Not used by the RSSbot by default. - - """ - if not self.ndb.ev_channel and self.db.ev_channel: - # cache channel lookup - self.ndb.ev_channel = self.db.ev_channel - if self.ndb.ev_channel: - self.ndb.ev_channel.msg(txt, senders=self.id)
- - -# Grapevine bot - - -
[docs]class GrapevineBot(Bot): - """ - g Grapevine (https://grapevine.haus) relayer. The channel to connect to is the first - name in the settings.GRAPEVINE_CHANNELS list. - - """ - - factory_path = "evennia.server.portal.grapevine.RestartingWebsocketServerFactory" - -
[docs] def start(self, ev_channel=None, grapevine_channel=None): - """ - Start by telling the portal to connect to the grapevine network. - - """ - if not _GRAPEVINE_ENABLED: - self.delete() - return - - global _SESSIONS - if not _SESSIONS: - from evennia.server.sessionhandler import SESSIONS as _SESSIONS - - # connect to Evennia channel - if ev_channel: - # connect to Evennia channel - channel = search.channel_search(ev_channel) - if not channel: - raise RuntimeError(f"Evennia Channel '{ev_channel}' not found.") - channel = channel[0] - channel.connect(self) - self.db.ev_channel = channel - - if grapevine_channel: - self.db.grapevine_channel = grapevine_channel - - # these will be made available as properties on the protocol factory - configdict = {"uid": self.dbid, "grapevine_channel": self.db.grapevine_channel} - - _SESSIONS.start_bot_session(self.factory_path, configdict)
- -
[docs] def at_msg_send(self, **kwargs): - "Shortcut here or we can end up in infinite loop" - pass
- -
[docs] def msg(self, text=None, **kwargs): - """ - Takes text from connected channel (only). - - Args: - text (str, optional): Incoming text from channel. - - Keyword Args: - options (dict): Options dict with the following allowed keys: - - from_channel (str): dbid of a channel this text originated from. - - from_obj (list): list of objects sending this text. - - """ - from_obj = kwargs.get("from_obj", None) - options = kwargs.get("options", None) or {} - - if not self.ndb.ev_channel and self.db.ev_channel: - # cache channel lookup - self.ndb.ev_channel = self.db.ev_channel - - if ( - "from_channel" in options - and text - and self.ndb.ev_channel.dbid == options["from_channel"] - ): - if not from_obj or from_obj != [self]: - # send outputfunc channel(msg, chan, sender) - - # TODO we should refactor channel formatting to operate on the - # account/object level instead. For now, remove the channel/name - # prefix since we pass that explicitly anyway - prefix, text = text.split(":", 1) - - super().msg( - channel=( - text.strip(), - self.db.grapevine_channel, - ", ".join(obj.key for obj in from_obj), - {}, - ) - )
- -
[docs] def execute_cmd( - self, - txt=None, - session=None, - event=None, - grapevine_channel=None, - sender=None, - game=None, - **kwargs, - ): - """ - Take incoming data from protocol and send it to connected channel. This is - triggered by the bot_data_in Inputfunc. - """ - if event == "channels/broadcast": - # A private message to the bot - a command. - - text = f"{sender}@{game}: {txt}" - - if not self.ndb.ev_channel and self.db.ev_channel: - # simple cache of channel lookup - self.ndb.ev_channel = self.db.ev_channel - if self.ndb.ev_channel: - self.ndb.ev_channel.msg(text, senders=self)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/accounts/manager.html b/docs/0.9.5/_modules/evennia/accounts/manager.html deleted file mode 100644 index c53bf73108..0000000000 --- a/docs/0.9.5/_modules/evennia/accounts/manager.html +++ /dev/null @@ -1,402 +0,0 @@ - - - - - - - - evennia.accounts.manager — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.accounts.manager

-"""
-The managers for the custom Account object and permissions.
-"""
-
-import datetime
-from django.conf import settings
-from django.utils import timezone
-from django.contrib.auth.models import UserManager
-from evennia.typeclasses.managers import TypedObjectManager, TypeclassManager
-from evennia.server import signals
-from evennia.utils.utils import make_iter, class_from_module, dbid_to_obj
-
-__all__ = ("AccountManager", "AccountDBManager")
-
-
-#
-# Account Manager
-#
-
-
-
[docs]class AccountDBManager(TypedObjectManager, UserManager): - """ - This AccountManager implements methods for searching - and manipulating Accounts directly from the database. - - Evennia-specific search methods (will return Characters if - possible or a Typeclass/list of Typeclassed objects, whereas - Django-general methods will return Querysets or database objects): - - dbref (converter) - dbref_search - get_dbref_range - object_totals - typeclass_search - num_total_accounts - get_connected_accounts - get_recently_created_accounts - get_recently_connected_accounts - get_account_from_email - get_account_from_uid - get_account_from_name - account_search (equivalent to evennia.search_account) - - """ - -
[docs] def num_total_accounts(self): - """ - Get total number of accounts. - - Returns: - count (int): The total number of registered accounts. - - """ - return self.count()
- -
[docs] def get_connected_accounts(self): - """ - Get all currently connected accounts. - - Returns: - count (list): Account objects with currently - connected sessions. - - """ - return self.filter(db_is_connected=True)
- -
[docs] def get_recently_created_accounts(self, days=7): - """ - Get accounts recently created. - - Args: - days (int, optional): How many days in the past "recently" means. - - Returns: - accounts (list): The Accounts created the last `days` interval. - - """ - end_date = timezone.now() - tdelta = datetime.timedelta(days) - start_date = end_date - tdelta - return self.filter(date_joined__range=(start_date, end_date))
- -
[docs] def get_recently_connected_accounts(self, days=7): - """ - Get accounts recently connected to the game. - - Args: - days (int, optional): Number of days backwards to check - - Returns: - accounts (list): The Accounts connected to the game in the - last `days` interval. - - """ - end_date = timezone.now() - tdelta = datetime.timedelta(days) - start_date = end_date - tdelta - return self.filter(last_login__range=(start_date, end_date)).order_by("-last_login")
- -
[docs] def get_account_from_email(self, uemail): - """ - Search account by - Returns an account object based on email address. - - Args: - uemail (str): An email address to search for. - - Returns: - account (Account): A found account, if found. - - """ - return self.filter(email__iexact=uemail)
- -
[docs] def get_account_from_uid(self, uid): - """ - Get an account by id. - - Args: - uid (int): Account database id. - - Returns: - account (Account): The result. - - """ - try: - return self.get(id=uid) - except self.model.DoesNotExist: - return None
- -
[docs] def get_account_from_name(self, uname): - """ - Get account object based on name. - - Args: - uname (str): The Account name to search for. - - Returns: - account (Account): The found account. - - """ - try: - return self.get(username__iexact=uname) - except self.model.DoesNotExist: - return None
- -
[docs] def search_account(self, ostring, exact=True, typeclass=None): - """ - Searches for a particular account by name or - database id. - - Args: - ostring (str or int): A key string or database id. - exact (bool, optional): Only valid for string matches. If - `True`, requires exact (non-case-sensitive) match, - otherwise also match also keys containing the `ostring` - (non-case-sensitive fuzzy match). - typeclass (str or Typeclass, optional): Limit the search only to - accounts of this typeclass. - Returns: - Queryset: A queryset (an iterable) with 0, 1 or more matches. - - """ - dbref = self.dbref(ostring) - if dbref or dbref == 0: - # dbref search is always exact - dbref_match = self.search_dbref(dbref) - if dbref_match: - return dbref_match - - query = {"username__iexact" if exact else "username__icontains": ostring} - if typeclass: - # we accept both strings and actual typeclasses - if callable(typeclass): - typeclass = f"{typeclass.__module__}.{typeclass.__name__}" - else: - typeclass = str(typeclass) - query["db_typeclass_path"] = typeclass - if exact: - matches = self.filter(**query) - else: - matches = self.filter(**query) - if not matches: - # try alias match - matches = self.filter( - db_tags__db_tagtype__iexact="alias", - **{"db_tags__db_key__iexact" if exact else "db_tags__db_key__icontains": ostring}, - ) - return matches
- -
[docs] def create_account( - self, - key, - email, - password, - typeclass=None, - is_superuser=False, - locks=None, - permissions=None, - tags=None, - attributes=None, - report_to=None, - ): - """ - This creates a new account. - - Args: - key (str): The account's name. This should be unique. - email (str or None): Email on valid addr@addr.domain form. If - the empty string, will be set to None. - password (str): Password in cleartext. - - Keyword Args: - typeclass (str): The typeclass to use for the account. - is_superuser (bool): Wether or not this account is to be a superuser - locks (str): Lockstring. - permission (list): List of permission strings. - tags (list): List of Tags on form `(key, category[, data])` - attributes (list): List of Attributes on form - `(key, value [, category, [,lockstring [, default_pass]]])` - report_to (Object): An object with a msg() method to report - errors to. If not given, errors will be logged. - - Returns: - Account: The newly created Account. - Raises: - ValueError: If `key` already exists in database. - - - Notes: - Usually only the server admin should need to be superuser, all - other access levels can be handled with more fine-grained - permissions or groups. A superuser bypasses all lock checking - operations and is thus not suitable for play-testing the game. - - """ - typeclass = typeclass if typeclass else settings.BASE_ACCOUNT_TYPECLASS - locks = make_iter(locks) if locks is not None else None - permissions = make_iter(permissions) if permissions is not None else None - tags = make_iter(tags) if tags is not None else None - attributes = make_iter(attributes) if attributes is not None else None - - if isinstance(typeclass, str): - # a path is given. Load the actual typeclass. - typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS) - - # setup input for the create command. We use AccountDB as baseclass - # here to give us maximum freedom (the typeclasses will load - # correctly when each object is recovered). - - if not email: - email = None - if self.model.objects.filter(username__iexact=key): - raise ValueError("An Account with the name '%s' already exists." % key) - - # this handles a given dbref-relocate to an account. - report_to = dbid_to_obj(report_to, self.model) - - # create the correct account entity, using the setup from - # base django auth. - now = timezone.now() - email = typeclass.objects.normalize_email(email) - new_account = typeclass( - username=key, - email=email, - is_staff=is_superuser, - is_superuser=is_superuser, - last_login=now, - date_joined=now, - ) - if password is not None: - # the password may be None for 'fake' accounts, like bots - valid, error = new_account.validate_password(password, new_account) - if not valid: - raise error - - new_account.set_password(password) - - new_account._createdict = dict( - locks=locks, permissions=permissions, - report_to=report_to, tags=tags, attributes=attributes - ) - # saving will trigger the signal that calls the - # at_first_save hook on the typeclass, where the _createdict - # can be used. - new_account.save() - - # note that we don't send a signal here, that is sent from the Account.create helper method - # instead. - - return new_account
- - # back-compatibility alias - account_search = search_account
- - -
[docs]class AccountManager(AccountDBManager, TypeclassManager): - pass
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/accounts/models.html b/docs/0.9.5/_modules/evennia/accounts/models.html deleted file mode 100644 index a081358191..0000000000 --- a/docs/0.9.5/_modules/evennia/accounts/models.html +++ /dev/null @@ -1,287 +0,0 @@ - - - - - - - - evennia.accounts.models — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.accounts.models

-"""
-Account
-
-The account class is an extension of the default Django user class,
-and is customized for the needs of Evennia.
-
-We use the Account to store a more mud-friendly style of permission
-system as well as to allow the admin more flexibility by storing
-attributes on the Account.  Within the game we should normally use the
-Account manager's methods to create users so that permissions are set
-correctly.
-
-To make the Account model more flexible for your own game, it can also
-persistently store attributes of its own. This is ideal for extra
-account info and OOC account configuration variables etc.
-
-"""
-from django.conf import settings
-from django.db import models
-from django.contrib.auth.models import AbstractUser
-from django.utils.encoding import smart_str
-
-from evennia.accounts.manager import AccountDBManager
-from evennia.typeclasses.models import TypedObject
-from evennia.utils.utils import make_iter
-from evennia.server.signals import SIGNAL_ACCOUNT_POST_RENAME
-
-__all__ = ("AccountDB",)
-
-# _ME = _("me")
-# _SELF = _("self")
-
-_MULTISESSION_MODE = settings.MULTISESSION_MODE
-
-_GA = object.__getattribute__
-_SA = object.__setattr__
-_DA = object.__delattr__
-
-_TYPECLASS = None
-
-
-# ------------------------------------------------------------
-#
-# AccountDB
-#
-# ------------------------------------------------------------
-
-
-
[docs]class AccountDB(TypedObject, AbstractUser): - """ - This is a special model using Django's 'profile' functionality - and extends the default Django User model. It is defined as such - by use of the variable AUTH_PROFILE_MODULE in the settings. - One accesses the fields/methods. We try use this model as much - as possible rather than User, since we can customize this to - our liking. - - The TypedObject supplies the following (inherited) properties: - - - key - main name - - typeclass_path - the path to the decorating typeclass - - typeclass - auto-linked typeclass - - date_created - time stamp of object creation - - permissions - perm strings - - dbref - #id of object - - db - persistent attribute storage - - ndb - non-persistent attribute storage - - The AccountDB adds the following properties: - - - is_connected - If any Session is currently connected to this Account - - name - alias for user.username - - sessions - sessions connected to this account - - is_superuser - bool if this account is a superuser - - is_bot - bool if this account is a bot and not a real account - - """ - - # - # AccountDB Database model setup - # - # inherited fields (from TypedObject): - # db_key, db_typeclass_path, db_date_created, db_permissions - - # store a connected flag here too, not just in sessionhandler. - # This makes it easier to track from various out-of-process locations - db_is_connected = models.BooleanField( - default=False, - verbose_name="is_connected", - help_text="If player is connected to game or not", - ) - # database storage of persistant cmdsets. - db_cmdset_storage = models.CharField( - "cmdset", - max_length=255, - null=True, - help_text="optional python path to a cmdset class. If creating a Character, this will " - "default to settings.CMDSET_CHARACTER.", - ) - # marks if this is a "virtual" bot account object - db_is_bot = models.BooleanField( - default=False, verbose_name="is_bot", help_text="Used to identify irc/rss bots" - ) - - # Database manager - objects = AccountDBManager() - - # defaults - __defaultclasspath__ = "evennia.accounts.accounts.DefaultAccount" - __applabel__ = "accounts" - __settingsclasspath__ = settings.BASE_SCRIPT_TYPECLASS - - class Meta: - verbose_name = "Account" - - # cmdset_storage property - # This seems very sensitive to caching, so leaving it be for now /Griatch - # @property - def __cmdset_storage_get(self): - """ - Getter. Allows for value = self.name. Returns a list of cmdset_storage. - """ - storage = self.db_cmdset_storage - # we need to check so storage is not None - return [path.strip() for path in storage.split(",")] if storage else [] - - # @cmdset_storage.setter - def __cmdset_storage_set(self, value): - """ - Setter. Allows for self.name = value. Stores as a comma-separated - string. - """ - _SA(self, "db_cmdset_storage", ",".join(str(val).strip() for val in make_iter(value))) - _GA(self, "save")() - - # @cmdset_storage.deleter - def __cmdset_storage_del(self): - "Deleter. Allows for del self.name" - _SA(self, "db_cmdset_storage", None) - _GA(self, "save")() - - cmdset_storage = property(__cmdset_storage_get, __cmdset_storage_set, __cmdset_storage_del) - - # - # property/field access - # - - def __str__(self): - return smart_str(f"{self.name}(account {self.dbid})") - - def __repr__(self): - return f"{self.name}(account#{self.dbid})" - - # @property - def __username_get(self): - return self.username - - def __username_set(self, value): - old_name = self.username - self.username = value - self.save(update_fields=["username"]) - SIGNAL_ACCOUNT_POST_RENAME.send(self, old_name=old_name, new_name=value) - - def __username_del(self): - del self.username - - # aliases - name = property(__username_get, __username_set, __username_del) - key = property(__username_get, __username_set, __username_del) - - # @property - def __uid_get(self): - "Getter. Retrieves the user id" - return self.id - - def __uid_set(self, value): - raise Exception("User id cannot be set!") - - def __uid_del(self): - raise Exception("User id cannot be deleted!") - - uid = property(__uid_get, __uid_set, __uid_del)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/commands/cmdhandler.html b/docs/0.9.5/_modules/evennia/commands/cmdhandler.html deleted file mode 100644 index d2eee130a4..0000000000 --- a/docs/0.9.5/_modules/evennia/commands/cmdhandler.html +++ /dev/null @@ -1,885 +0,0 @@ - - - - - - - - evennia.commands.cmdhandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.commands.cmdhandler

-"""
-Command handler
-
-This module contains the infrastructure for accepting commands on the
-command line. The processing of a command works as follows:
-
-1. The calling object (caller) is analyzed based on its callertype.
-2. Cmdsets are gathered from different sources:
-   - object cmdsets: all objects at caller's location are scanned for non-empty
-     cmdsets. This includes cmdsets on exits.
-   - caller: the caller is searched for its own currently active cmdset.
-   - account: lastly the cmdsets defined on caller.account are added.
-3. The collected cmdsets are merged together to a combined, current cmdset.
-4. If the input string is empty -> check for CMD_NOINPUT command in
-   current cmdset or fallback to error message. Exit.
-5. The Command Parser is triggered, using the current cmdset to analyze the
-   input string for possible command matches.
-6. If multiple matches are found -> check for CMD_MULTIMATCH in current
-   cmdset, or fallback to error message. Exit.
-7. If no match was found -> check for CMD_NOMATCH in current cmdset or
-   fallback to error message. Exit.
-8. At this point we have found a normal command. We assign useful variables to it that
-   will be available to the command coder at run-time.
-9. We have a unique cmdobject, primed for use. Call all hooks:
-   `at_pre_cmd()`, `cmdobj.parse()`, `cmdobj.func()` and finally `at_post_cmd()`.
-10. Return deferred that will fire with the return from `cmdobj.func()` (unused by default).
-
-"""
-
-from collections import defaultdict
-from weakref import WeakValueDictionary
-from traceback import format_exc
-from itertools import chain
-from copy import copy
-import types
-from twisted.internet import reactor
-from twisted.internet.task import deferLater
-from twisted.internet.defer import inlineCallbacks, returnValue
-from django.conf import settings
-from evennia.commands.command import InterruptCommand
-from evennia.utils import logger, utils
-from evennia.utils.utils import string_suggestions
-
-from django.utils.translation import gettext as _
-
-_IN_GAME_ERRORS = settings.IN_GAME_ERRORS
-
-__all__ = ("cmdhandler", "InterruptCommand")
-_GA = object.__getattribute__
-_CMDSET_MERGE_CACHE = WeakValueDictionary()
-
-# tracks recursive calls by each caller
-# to avoid infinite loops (commands calling themselves)
-_COMMAND_NESTING = defaultdict(lambda: 0)
-_COMMAND_RECURSION_LIMIT = 10
-
-# This decides which command parser is to be used.
-# You have to restart the server for changes to take effect.
-_COMMAND_PARSER = utils.variable_from_module(*settings.COMMAND_PARSER.rsplit(".", 1))
-
-# System command names - import these variables rather than trying to
-# remember the actual string constants. If not defined, Evennia
-# hard-coded defaults are used instead.
-
-# command to call if user just presses <return> with no input
-CMD_NOINPUT = "__noinput_command"
-# command to call if no command match was found
-CMD_NOMATCH = "__nomatch_command"
-# command to call if multiple command matches were found
-CMD_MULTIMATCH = "__multimatch_command"
-# command to call as the very first one when the user connects.
-# (is expected to display the login screen)
-CMD_LOGINSTART = "__unloggedin_look_command"
-
-
-# Function for handling multiple command matches.
-_SEARCH_AT_RESULT = utils.variable_from_module(*settings.SEARCH_AT_RESULT.rsplit(".", 1))
-
-# Output strings. The first is the IN_GAME_ERRORS return, the second
-# is the normal "production message to echo to the account.
-
-_ERROR_UNTRAPPED = (
-    _("""
-An untrapped error occurred.
-"""),
-    _("""
-An untrapped error occurred. Please file a bug report detailing the steps to reproduce.
-"""),
-)
-
-_ERROR_CMDSETS = (
-    _("""
-A cmdset merger-error occurred. This is often due to a syntax
-error in one of the cmdsets to merge.
-"""),
-    _("""
-A cmdset merger-error occurred. Please file a bug report detailing the
-steps to reproduce.
-"""),
-)
-
-_ERROR_NOCMDSETS = (
-    _("""
-No command sets found! This is a critical bug that can have
-multiple causes.
-"""),
-    _("""
-No command sets found! This is a sign of a critical bug.  If
-disconnecting/reconnecting doesn't" solve the problem, try to contact
-the server admin through" some other means for assistance.
-"""),
-)
-
-_ERROR_CMDHANDLER = (
-    _("""
-A command handler bug occurred. If this is not due to a local change,
-please file a bug report with the Evennia project, including the
-traceback and steps to reproduce.
-"""),
-    _("""
-A command handler bug occurred. Please notify staff - they should
-likely file a bug report with the Evennia project.
-"""),
-)
-
-_ERROR_RECURSION_LIMIT = _(
-    "Command recursion limit ({recursion_limit}) " "reached for '{raw_cmdname}' ({cmdclass})."
-)
-
-
-# delayed imports
-_GET_INPUT = None
-
-
-# helper functions
-
-
-def _msg_err(receiver, stringtuple):
-    """
-    Helper function for returning an error to the caller.
-
-    Args:
-        receiver (Object): object to get the error message.
-        stringtuple (tuple): tuple with two strings - one for the
-            _IN_GAME_ERRORS mode (with the traceback) and one with the
-            production string (with a timestamp) to be shown to the user.
-
-    """
-    string = _("{traceback}\n{errmsg}\n(Traceback was logged {timestamp}).")
-    timestamp = logger.timeformat()
-    tracestring = format_exc()
-    logger.log_trace()
-    if _IN_GAME_ERRORS:
-        receiver.msg(
-            string.format(
-                traceback=tracestring, errmsg=stringtuple[0].strip(), timestamp=timestamp
-            ).strip()
-        )
-    else:
-        receiver.msg(
-            string.format(
-                traceback=tracestring.splitlines()[-1],
-                errmsg=stringtuple[1].strip(),
-                timestamp=timestamp,
-            ).strip()
-        )
-
-
-def _process_input(caller, prompt, result, cmd, generator):
-    """
-    Specifically handle the get_input value to send to _progressive_cmd_run as
-    part of yielding from a Command's `func`.
-
-    Args:
-        caller (Character, Account or Session): the caller.
-        prompt (str): The sent prompt.
-        result (str): The unprocessed answer.
-        cmd (Command): The command itself.
-        generator (GeneratorType): The generator.
-
-    Returns:
-        result (bool): Always `False` (stop processing).
-
-    """
-    # We call it using a Twisted deferLater to make sure the input is properly closed.
-    deferLater(reactor, 0, _progressive_cmd_run, cmd, generator, response=result)
-    return False
-
-
-def _progressive_cmd_run(cmd, generator, response=None):
-    """
-    Progressively call the command that was given in argument. Used
-    when `yield` is present in the Command's `func()` method.
-
-    Args:
-        cmd (Command): the command itself.
-        generator (GeneratorType): the generator describing the processing.
-        reponse (str, optional): the response to send to the generator.
-
-    Raises:
-        ValueError: If the func call yields something not identifiable as a
-            time-delay or a string prompt.
-
-    Note:
-        This function is responsible for executing the command, if
-        the func() method contains 'yield' instructions.  The yielded
-        value will be accessible at each step and will affect the
-        process.  If the value is a number, just delay the execution
-        of the command.  If it's a string, wait for the user input.
-
-    """
-    global _GET_INPUT
-    if not _GET_INPUT:
-        from evennia.utils.evmenu import get_input as _GET_INPUT
-
-    try:
-        if response is None:
-            value = next(generator)
-        else:
-            value = generator.send(response)
-    except StopIteration:
-        # duplicated from cmdhandler._run_command, to have these
-        # run in the right order while staying inside the deferred
-        cmd.at_post_cmd()
-        if cmd.save_for_next:
-            # store a reference to this command, possibly
-            # accessible by the next command.
-            cmd.caller.ndb.last_cmd = copy(cmd)
-        else:
-            cmd.caller.ndb.last_cmd = None
-    else:
-        if isinstance(value, (int, float)):
-            utils.delay(value, _progressive_cmd_run, cmd, generator)
-        elif isinstance(value, str):
-            _GET_INPUT(cmd.caller, value, _process_input, cmd=cmd, generator=generator)
-        else:
-            raise ValueError("unknown type for a yielded value in command: {}".format(type(value)))
-
-
-# custom Exceptions
-
-
-class NoCmdSets(Exception):
-    "No cmdsets found. Critical error."
-    pass
-
-
-class ExecSystemCommand(Exception):
-    "Run a system command"
-
-    def __init__(self, syscmd, sysarg):
-        self.args = (syscmd, sysarg)  # needed by exception error handling
-        self.syscmd = syscmd
-        self.sysarg = sysarg
-
-
-class ErrorReported(Exception):
-    "Re-raised when a subsructure already reported the error"
-
-    def __init__(self, raw_string):
-        self.args = (raw_string,)
-        self.raw_string = raw_string
-
-
-# Helper function
-
-
-@inlineCallbacks
-def get_and_merge_cmdsets(caller, session, account, obj, callertype, raw_string):
-    """
-    Gather all relevant cmdsets and merge them.
-
-    Args:
-        caller (Session, Account or Object): The entity executing the command. Which
-            type of object this is depends on the current game state; for example
-            when the user is not logged in, this will be a Session, when being OOC
-            it will be an Account and when puppeting an object this will (often) be
-            a Character Object. In the end it depends on where the cmdset is stored.
-        session (Session or None): The Session associated with caller, if any.
-        account (Account or None): The calling Account associated with caller, if any.
-        obj (Object or None): The Object associated with caller, if any.
-        callertype (str): This identifies caller as either "account", "object" or "session"
-            to avoid having to do this check internally.
-        raw_string (str): The input string. This is only used for error reporting.
-
-    Returns:
-        cmdset (Deferred): This deferred fires with the merged cmdset
-        result once merger finishes.
-
-    Notes:
-        The cdmsets are merged in order or generality, so that the
-        Object's cmdset is merged last (and will thus take precedence
-        over same-named and same-prio commands on Account and Session).
-
-    """
-    try:
-
-        @inlineCallbacks
-        def _get_local_obj_cmdsets(obj):
-            """
-            Helper-method; Get Object-level cmdsets
-
-            """
-            # Gather cmdsets from location, objects in location or carried
-            try:
-                local_obj_cmdsets = [None]
-                try:
-                    location = obj.location
-                except Exception:
-                    location = None
-                if location:
-                    # Gather all cmdsets stored on objects in the room and
-                    # also in the caller's inventory and the location itself
-                    local_objlist = yield (
-                        location.contents_get(exclude=obj) + obj.contents_get() + [location]
-                    )
-                    local_objlist = [o for o in local_objlist if not o._is_deleted]
-                    for lobj in local_objlist:
-                        try:
-                            # call hook in case we need to do dynamic changing to cmdset
-                            _GA(lobj, "at_cmdset_get")(caller=caller)
-                        except Exception:
-                            logger.log_trace()
-                    # the call-type lock is checked here, it makes sure an account
-                    # is not seeing e.g. the commands on a fellow account (which is why
-                    # the no_superuser_bypass must be True)
-                    local_obj_cmdsets = yield list(
-                        chain.from_iterable(
-                            lobj.cmdset.cmdset_stack
-                            for lobj in local_objlist
-                            if (
-                                lobj.cmdset.current
-                                and lobj.access(
-                                    caller, access_type="call", no_superuser_bypass=True
-                                )
-                            )
-                        )
-                    )
-                    for cset in local_obj_cmdsets:
-                        # This is necessary for object sets, or we won't be able to
-                        # separate the command sets from each other in a busy room. We
-                        # only keep the setting if duplicates were set to False/True
-                        # explicitly.
-                        cset.old_duplicates = cset.duplicates
-                        cset.duplicates = True if cset.duplicates is None else cset.duplicates
-                returnValue(local_obj_cmdsets)
-            except Exception:
-                _msg_err(caller, _ERROR_CMDSETS)
-                raise ErrorReported(raw_string)
-
-        @inlineCallbacks
-        def _get_cmdsets(obj):
-            """
-            Helper method; Get cmdset while making sure to trigger all
-            hooks safely. Returns the stack and the valid options.
-
-            """
-            try:
-                yield obj.at_cmdset_get()
-            except Exception:
-                _msg_err(caller, _ERROR_CMDSETS)
-                raise ErrorReported(raw_string)
-            try:
-                returnValue((obj.cmdset.current, list(obj.cmdset.cmdset_stack)))
-            except AttributeError:
-                returnValue(((None, None, None), []))
-
-        local_obj_cmdsets = []
-        if callertype == "session":
-            # we are calling the command from the session level
-            report_to = session
-            current, cmdsets = yield _get_cmdsets(session)
-            if account:  # this automatically implies logged-in
-                pcurrent, account_cmdsets = yield _get_cmdsets(account)
-                cmdsets += account_cmdsets
-                current = current + pcurrent
-                if obj:
-                    ocurrent, obj_cmdsets = yield _get_cmdsets(obj)
-                    current = current + ocurrent
-                    cmdsets += obj_cmdsets
-                    if not current.no_objs:
-                        local_obj_cmdsets = yield _get_local_obj_cmdsets(obj)
-                        if current.no_exits:
-                            # filter out all exits
-                            local_obj_cmdsets = [
-                                cmdset for cmdset in local_obj_cmdsets if cmdset.key != "ExitCmdSet"
-                            ]
-                        cmdsets += local_obj_cmdsets
-
-        elif callertype == "account":
-            # we are calling the command from the account level
-            report_to = account
-            current, cmdsets = yield _get_cmdsets(account)
-            if obj:
-                ocurrent, obj_cmdsets = yield _get_cmdsets(obj)
-                current = current + ocurrent
-                cmdsets += obj_cmdsets
-                if not current.no_objs:
-                    local_obj_cmdsets = yield _get_local_obj_cmdsets(obj)
-                    if current.no_exits:
-                        # filter out all exits
-                        local_obj_cmdsets = [
-                            cmdset for cmdset in local_obj_cmdsets if cmdset.key != "ExitCmdSet"
-                        ]
-                    cmdsets += local_obj_cmdsets
-
-        elif callertype == "object":
-            # we are calling the command from the object level
-            report_to = obj
-            current, cmdsets = yield _get_cmdsets(obj)
-            if not current.no_objs:
-                local_obj_cmdsets = yield _get_local_obj_cmdsets(obj)
-                if current.no_exits:
-                    # filter out all exits
-                    local_obj_cmdsets = [
-                        cmdset for cmdset in local_obj_cmdsets if cmdset.key != "ExitCmdSet"
-                    ]
-                cmdsets += yield local_obj_cmdsets
-        else:
-            raise Exception("get_and_merge_cmdsets: callertype %s is not valid." % callertype)
-
-        # weed out all non-found sets
-        cmdsets = yield [cmdset for cmdset in cmdsets if cmdset and cmdset.key != "_EMPTY_CMDSET"]
-        # report cmdset errors to user (these should already have been logged)
-        yield [
-            report_to.msg(cmdset.errmessage) for cmdset in cmdsets if cmdset.key == "_CMDSET_ERROR"
-        ]
-
-        if cmdsets:
-            # faster to do tuple on list than to build tuple directly
-            mergehash = tuple([id(cmdset) for cmdset in cmdsets])
-            if mergehash in _CMDSET_MERGE_CACHE:
-                # cached merge exist; use that
-                cmdset = _CMDSET_MERGE_CACHE[mergehash]
-            else:
-                # we group and merge all same-prio cmdsets separately (this avoids
-                # order-dependent clashes in certain cases, such as
-                # when duplicates=True)
-                tempmergers = {}
-                for cmdset in cmdsets:
-                    prio = cmdset.priority
-                    if prio in tempmergers:
-                        # merge same-prio cmdset together separately
-                        tempmergers[prio] = yield tempmergers[prio] + cmdset
-                    else:
-                        tempmergers[prio] = cmdset
-
-                # sort cmdsets after reverse priority (highest prio are merged in last)
-                sorted_cmdsets = yield sorted(list(tempmergers.values()), key=lambda x: x.priority)
-
-                # Merge all command sets into one, beginning with the lowest-prio one
-                cmdset = sorted_cmdsets[0]
-                for merging_cmdset in sorted_cmdsets[1:]:
-                    cmdset = yield cmdset + merging_cmdset
-                # store the original, ungrouped set for diagnosis
-                cmdset.merged_from = cmdsets
-                # cache
-                _CMDSET_MERGE_CACHE[mergehash] = cmdset
-        else:
-            cmdset = None
-        for cset in (cset for cset in local_obj_cmdsets if cset):
-            cset.duplicates = cset.old_duplicates
-        # important - this syncs the CmdSetHandler's .current field with the
-        # true current cmdset!
-        if cmdset:
-            caller.cmdset.current = cmdset
-
-        returnValue(cmdset)
-    except ErrorReported:
-        raise
-    except Exception:
-        _msg_err(caller, _ERROR_CMDSETS)
-        raise
-        # raise ErrorReported
-
-
-# Main command-handler function
-
-
-
[docs]@inlineCallbacks -def cmdhandler( - called_by, - raw_string, - _testing=False, - callertype="session", - session=None, - cmdobj=None, - cmdobj_key=None, - **kwargs, -): - """ - This is the main mechanism that handles any string sent to the engine. - - Args: - called_by (Session, Account or Object): Object from which this - command was called. which this was called from. What this is - depends on the game state. - raw_string (str): The command string as given on the command line. - _testing (bool, optional): Used for debug purposes and decides if we - should actually execute the command or not. If True, the - command instance will be returned. - callertype (str, optional): One of "session", "account" or - "object". These are treated in decending order, so when the - Session is the caller, it will merge its own cmdset into - cmdsets from both Account and eventual puppeted Object (and - cmdsets in its room etc). An Account will only include its own - cmdset and the Objects and so on. Merge order is the same - order, so that Object cmdsets are merged in last, giving them - precendence for same-name and same-prio commands. - session (Session, optional): Relevant if callertype is "account" - the session will help - retrieve the correct cmdsets from puppeted objects. - cmdobj (Command, optional): If given a command instance, this will be executed using - `called_by` as the caller, `raw_string` representing its arguments and (optionally) - `cmdobj_key` as its input command name. No cmdset lookup will be performed but - all other options apply as normal. This allows for running a specific Command - within the command system mechanism. - cmdobj_key (string, optional): Used together with `cmdobj` keyword to specify - which cmdname should be assigned when calling the specified Command instance. This - is made available as `self.cmdstring` when the Command runs. - If not given, the command will be assumed to be called as `cmdobj.key`. - - Keyword Args: - kwargs (any): other keyword arguments will be assigned as named variables on the - retrieved command object *before* it is executed. This is unused - in default Evennia but may be used by code to set custom flags or - special operating conditions for a command as it executes. - - Returns: - deferred (Deferred): This deferred is fired with the return - value of the command's `func` method. This is not used in - default Evennia. - - """ - - @inlineCallbacks - def _run_command(cmd, cmdname, args, raw_cmdname, cmdset, session, account): - """ - Helper function: This initializes and runs the Command - instance once the parser has identified it as either a normal - command or one of the system commands. - - Args: - cmd (Command): Command object - cmdname (str): Name of command - args (str): extra text entered after the identified command - raw_cmdname (str): Name of Command, unaffected by eventual - prefix-stripping (if no prefix-stripping, this is the same - as cmdname). - cmdset (CmdSet): Command sert the command belongs to (if any).. - session (Session): Session of caller (if any). - account (Account): Account of caller (if any). - - Returns: - deferred (Deferred): this will fire with the return of the - command's `func` method. - - Raises: - RuntimeError: If command recursion limit was reached. - - """ - global _COMMAND_NESTING - try: - # Assign useful variables to the instance - cmd.caller = caller - cmd.cmdname = cmdname - cmd.raw_cmdname = raw_cmdname - cmd.cmdstring = cmdname # deprecated - cmd.args = args - cmd.cmdset = cmdset - cmd.session = session - cmd.account = account - cmd.raw_string = unformatted_raw_string - # cmd.obj # set via on-object cmdset handler for each command, - # since this may be different for every command when - # merging multiple cmdsets - - if _testing: - # only return the command instance - returnValue(cmd) - - # assign custom kwargs to found cmd object - for key, val in kwargs.items(): - setattr(cmd, key, val) - - _COMMAND_NESTING[called_by] += 1 - if _COMMAND_NESTING[called_by] > _COMMAND_RECURSION_LIMIT: - err = _ERROR_RECURSION_LIMIT.format( - recursion_limit=_COMMAND_RECURSION_LIMIT, - raw_cmdname=raw_cmdname, - cmdclass=cmd.__class__, - ) - raise RuntimeError(err) - - # pre-command hook - abort = yield cmd.at_pre_cmd() - if abort: - # abort sequence - returnValue(abort) - - # Parse and execute - yield cmd.parse() - - # main command code - # (return value is normally None) - ret = cmd.func() - if isinstance(ret, types.GeneratorType): - # cmd.func() is a generator, execute progressively - _progressive_cmd_run(cmd, ret) - ret = yield ret - # note that the _progressive_cmd_run will itself run - # the at_post_cmd etc as it finishes; this is a bit of - # code duplication but there seems to be no way to - # catch the StopIteration here (it's not in the same - # frame since this is in a deferred chain) - else: - ret = yield ret - # post-command hook - yield cmd.at_post_cmd() - - if cmd.save_for_next: - # store a reference to this command, possibly - # accessible by the next command. - caller.ndb.last_cmd = yield copy(cmd) - else: - caller.ndb.last_cmd = None - - # return result to the deferred - returnValue(ret) - - except InterruptCommand: - # Do nothing, clean exit - pass - except Exception: - _msg_err(caller, _ERROR_UNTRAPPED) - raise ErrorReported(raw_string) - finally: - _COMMAND_NESTING[called_by] -= 1 - - session, account, obj = session, None, None - if callertype == "session": - session = called_by - account = session.account - obj = session.puppet - elif callertype == "account": - account = called_by - if session: - obj = yield session.puppet - elif callertype == "object": - obj = called_by - else: - raise RuntimeError("cmdhandler: callertype %s is not valid." % callertype) - # the caller will be the one to receive messages and excert its permissions. - # we assign the caller with preference 'bottom up' - caller = obj or account or session - # The error_to is the default recipient for errors. Tries to make sure an account - # does not get spammed for errors while preserving character mirroring. - error_to = obj or session or account - - try: # catch bugs in cmdhandler itself - try: # catch special-type commands - if cmdobj: - # the command object is already given - cmd = cmdobj() if callable(cmdobj) else cmdobj - cmdname = cmdobj_key if cmdobj_key else cmd.key - args = raw_string - unformatted_raw_string = "%s%s" % (cmdname, args) - cmdset = None - raw_cmdname = cmdname - # session = session - # account = account - - else: - # no explicit cmdobject given, figure it out - cmdset = yield get_and_merge_cmdsets( - caller, session, account, obj, callertype, raw_string - ) - if not cmdset: - # this is bad and shouldn't happen. - raise NoCmdSets - # store the completely unmodified raw string - including - # whitespace and eventual prefixes-to-be-stripped. - unformatted_raw_string = raw_string - raw_string = raw_string.strip() - if not raw_string: - # Empty input. Test for system command instead. - syscmd = yield cmdset.get(CMD_NOINPUT) - sysarg = "" - raise ExecSystemCommand(syscmd, sysarg) - # Parse the input string and match to available cmdset. - # This also checks for permissions, so all commands in match - # are commands the caller is allowed to call. - matches = yield _COMMAND_PARSER(raw_string, cmdset, caller) - - # Deal with matches - - if len(matches) > 1: - # We have a multiple-match - syscmd = yield cmdset.get(CMD_MULTIMATCH) - sysarg = _("There were multiple matches.") - if syscmd: - # use custom CMD_MULTIMATCH - syscmd.matches = matches - else: - # fall back to default error handling - sysarg = yield _SEARCH_AT_RESULT( - [match[2] for match in matches], caller, query=matches[0][0] - ) - raise ExecSystemCommand(syscmd, sysarg) - - cmdname, args, cmd, raw_cmdname = "", "", None, "" - if len(matches) == 1: - # We have a unique command match. But it may still be invalid. - match = matches[0] - cmdname, args, cmd, raw_cmdname = (match[0], match[1], match[2], match[5]) - - if not matches: - # No commands match our entered command - syscmd = yield cmdset.get(CMD_NOMATCH) - if syscmd: - # use custom CMD_NOMATCH command - sysarg = raw_string - else: - # fallback to default error text - sysarg = _("Command '{command}' is not available.").format( - command=raw_string - ) - suggestions = string_suggestions( - raw_string, - cmdset.get_all_cmd_keys_and_aliases(caller), - cutoff=0.7, - maxnum=3, - ) - if suggestions: - sysarg += _(" Maybe you meant {command}?").format( - command=utils.list_to_string(suggestions, _("or"), addquote=True) - ) - else: - sysarg += _(' Type "help" for help.') - raise ExecSystemCommand(syscmd, sysarg) - - if not cmd.retain_instance: - # making a copy allows multiple users to share the command also when yield is used - cmd = copy(cmd) - - # A normal command. - ret = yield _run_command(cmd, cmdname, args, raw_cmdname, cmdset, session, account) - returnValue(ret) - - except ErrorReported as exc: - # this error was already reported, so we - # catch it here and don't pass it on. - logger.log_err("User input was: '%s'." % exc.raw_string) - - except ExecSystemCommand as exc: - # Not a normal command: run a system command, if available, - # or fall back to a return string. - syscmd = exc.syscmd - sysarg = exc.sysarg - - if syscmd: - ret = yield _run_command( - syscmd, syscmd.key, sysarg, unformatted_raw_string, cmdset, session, account - ) - returnValue(ret) - elif sysarg: - # return system arg - error_to.msg(exc.sysarg) - - except NoCmdSets: - # Critical error. - logger.log_err("No cmdsets found: %s" % caller) - error_to.msg(_ERROR_NOCMDSETS) - - except Exception: - # We should not end up here. If we do, it's a programming bug. - _msg_err(error_to, _ERROR_UNTRAPPED) - - except Exception: - # This catches exceptions in cmdhandler exceptions themselves - _msg_err(error_to, _ERROR_CMDHANDLER)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/commands/cmdparser.html b/docs/0.9.5/_modules/evennia/commands/cmdparser.html deleted file mode 100644 index cbd10b79a8..0000000000 --- a/docs/0.9.5/_modules/evennia/commands/cmdparser.html +++ /dev/null @@ -1,331 +0,0 @@ - - - - - - - - evennia.commands.cmdparser — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.commands.cmdparser

-"""
-The default command parser. Use your own by assigning
-`settings.COMMAND_PARSER` to a Python path to a module containing the
-replacing cmdparser function. The replacement parser must accept the
-same inputs as the default one.
-
-"""
-
-
-import re
-from django.conf import settings
-from evennia.utils.logger import log_trace
-
-_MULTIMATCH_REGEX = re.compile(settings.SEARCH_MULTIMATCH_REGEX, re.I + re.U)
-_CMD_IGNORE_PREFIXES = settings.CMD_IGNORE_PREFIXES
-
-
-
[docs]def create_match(cmdname, string, cmdobj, raw_cmdname): - """ - Builds a command match by splitting the incoming string and - evaluating the quality of the match. - - Args: - cmdname (str): Name of command to check for. - string (str): The string to match against. - cmdobj (str): The full Command instance. - raw_cmdname (str, optional): If CMD_IGNORE_PREFIX is set and the cmdname starts with - one of the prefixes to ignore, this contains the raw, unstripped cmdname, - otherwise it is None. - - Returns: - match (tuple): This is on the form (cmdname, args, cmdobj, cmdlen, mratio, raw_cmdname), - where `cmdname` is the command's name and `args` is the rest of the incoming - string, without said command name. `cmdobj` is - the Command instance, the cmdlen is the same as len(cmdname) and mratio - is a measure of how big a part of the full input string the cmdname - takes up - an exact match would be 1.0. Finally, the `raw_cmdname` is - the cmdname unmodified by eventual prefix-stripping. - - """ - cmdlen, strlen = len(str(cmdname)), len(str(string)) - mratio = 1 - (strlen - cmdlen) / (1.0 * strlen) - args = string[cmdlen:] - return (cmdname, args, cmdobj, cmdlen, mratio, raw_cmdname)
- - -
[docs]def build_matches(raw_string, cmdset, include_prefixes=False): - """ - Build match tuples by matching raw_string against available commands. - - Args: - raw_string (str): Input string that can look in any way; the only assumption is - that the sought command's name/alias must be *first* in the string. - cmdset (CmdSet): The current cmdset to pick Commands from. - include_prefixes (bool): If set, include prefixes like @, ! etc (specified in settings) - in the match, otherwise strip them before matching. - - Returns: - matches (list) A list of match tuples created by `cmdparser.create_match`. - - """ - matches = [] - try: - if include_prefixes: - # use the cmdname as-is - l_raw_string = raw_string.lower() - for cmd in cmdset: - matches.extend( - [ - create_match(cmdname, raw_string, cmd, cmdname) - for cmdname in [cmd.key] + cmd.aliases - if cmdname - and l_raw_string.startswith(cmdname.lower()) - and (not cmd.arg_regex or cmd.arg_regex.match(l_raw_string[len(cmdname):])) - ] - ) - else: - # strip prefixes set in settings - raw_string = ( - raw_string.lstrip(_CMD_IGNORE_PREFIXES) if len(raw_string) > 1 else raw_string - ) - l_raw_string = raw_string.lower() - for cmd in cmdset: - for raw_cmdname in [cmd.key] + cmd.aliases: - cmdname = ( - raw_cmdname.lstrip(_CMD_IGNORE_PREFIXES) - if len(raw_cmdname) > 1 - else raw_cmdname - ) - if ( - cmdname - and l_raw_string.startswith(cmdname.lower()) - and (not cmd.arg_regex or cmd.arg_regex.match(l_raw_string[len(cmdname):])) - ): - matches.append(create_match(cmdname, raw_string, cmd, raw_cmdname)) - except Exception: - log_trace("cmdhandler error. raw_input:%s" % raw_string) - return matches
- - -
[docs]def try_num_differentiators(raw_string): - """ - Test if user tried to separate multi-matches with a number separator - (default 1-name, 2-name etc). This is usually called last, if no other - match was found. - - Args: - raw_string (str): The user input to parse. - - Returns: - mindex, new_raw_string (tuple): If a multimatch-separator was detected, - this is stripped out as an integer to separate between the matches. The - new_raw_string is the result of stripping out that identifier. If no - such form was found, returns (None, None). - - Example: - In the default configuration, entering 2-ball (e.g. in a room will more - than one 'ball' object), will lead to a multimatch and this function - will parse `"2-ball"` and return `(2, "ball")`. - - """ - # no matches found - num_ref_match = _MULTIMATCH_REGEX.match(raw_string) - if num_ref_match: - # the user might be trying to identify the command - # with a #num-command style syntax. We expect the regex to - # contain the groups "number" and "name". - mindex, new_raw_string = (num_ref_match.group("number"), num_ref_match.group("name") + num_ref_match.group("args")) - return int(mindex), new_raw_string - else: - return None, None
- - -
[docs]def cmdparser(raw_string, cmdset, caller, match_index=None): - """ - This function is called by the cmdhandler once it has - gathered and merged all valid cmdsets valid for this particular parsing. - - Args: - raw_string (str): The unparsed text entered by the caller. - cmdset (CmdSet): The merged, currently valid cmdset - caller (Session, Account or Object): The caller triggering this parsing. - match_index (int, optional): Index to pick a given match in a - list of same-named command matches. If this is given, it suggests - this is not the first time this function was called: normally - the first run resulted in a multimatch, and the index is given - to select between the results for the second run. - - Returns: - matches (list): This is a list of match-tuples as returned by `create_match`. - If no matches were found, this is an empty list. - - Notes: - The cmdparser understand the following command combinations (where - [] marks optional parts. - - ``` - [cmdname[ cmdname2 cmdname3 ...] [the rest] - ``` - - A command may consist of any number of space-separated words of any - length, and contain any character. It may also be empty. - - The parser makes use of the cmdset to find command candidates. The - parser return a list of matches. Each match is a tuple with its - first three elements being the parsed cmdname (lower case), - the remaining arguments, and the matched cmdobject from the cmdset. - - """ - if not raw_string: - return [] - - # find matches, first using the full name - matches = build_matches(raw_string, cmdset, include_prefixes=True) - - if not matches or len(matches) > 1: - # no single match, try parsing for optional numerical tags like 1-cmd - # or cmd-2, cmd.2 etc - match_index, new_raw_string = try_num_differentiators(raw_string) - if match_index is not None: - matches.extend(build_matches(new_raw_string, cmdset, include_prefixes=True)) - - if not matches and _CMD_IGNORE_PREFIXES: - # still no match. Try to strip prefixes - raw_string = ( - raw_string.lstrip(_CMD_IGNORE_PREFIXES) if len(raw_string) > 1 else raw_string - ) - matches = build_matches(raw_string, cmdset, include_prefixes=False) - - # only select command matches we are actually allowed to call. - matches = [match for match in matches if match[2].access(caller, "cmd")] - - # try to bring the number of matches down to 1 - if len(matches) > 1: - # See if it helps to analyze the match with preserved case but only if - # it leaves at least one match. - trimmed = [match for match in matches if raw_string.startswith(match[0])] - if trimmed: - matches = trimmed - - if len(matches) > 1: - # we still have multiple matches. Sort them by count quality. - matches = sorted(matches, key=lambda m: m[3]) - # only pick the matches with highest count quality - quality = [mat[3] for mat in matches] - matches = matches[-quality.count(quality[-1]) :] - - if len(matches) > 1: - # still multiple matches. Fall back to ratio-based quality. - matches = sorted(matches, key=lambda m: m[4]) - # only pick the highest rated ratio match - quality = [mat[4] for mat in matches] - matches = matches[-quality.count(quality[-1]) :] - - if len(matches) > 1 and match_index is not None: - # We couldn't separate match by quality, but we have an - # index argument to tell us which match to use. - if 0 < match_index <= len(matches): - matches = [matches[match_index - 1]] - else: - # we tried to give an index outside of the range - this means - # a no-match - matches = [] - - # no matter what we have at this point, we have to return it. - return matches
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/commands/cmdset.html b/docs/0.9.5/_modules/evennia/commands/cmdset.html deleted file mode 100644 index 205b00167b..0000000000 --- a/docs/0.9.5/_modules/evennia/commands/cmdset.html +++ /dev/null @@ -1,781 +0,0 @@ - - - - - - - - evennia.commands.cmdset — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.commands.cmdset

-"""
-
-A Command Set (CmdSet) holds a set of commands. The Cmdsets can be
-merged and combined to create new sets of commands in a
-non-destructive way. This makes them very powerful for implementing
-custom game states where different commands (or different variations
-of commands) are available to the accounts depending on circumstance.
-
-The available merge operations are partly borrowed from mathematical
-Set theory.
-
-
-* Union The two command sets are merged so that as many commands as
-    possible of each cmdset ends up in the merged cmdset. Same-name
-    commands are merged by priority.  This is the most common default.
-    Ex: A1,A3 + B1,B2,B4,B5 = A1,B2,A3,B4,B5
-* Intersect - Only commands found in *both* cmdsets (i.e. which have
-    same names) end up in the merged cmdset, with the higher-priority
-    cmdset replacing the lower one. Ex: A1,A3 + B1,B2,B4,B5 = A1
-* Replace -   The commands of this cmdset completely replaces the
-    lower-priority cmdset's commands, regardless of if same-name commands
-    exist. Ex: A1,A3 + B1,B2,B4,B5 = A1,A3
-* Remove -    This removes the relevant commands from the
-    lower-priority cmdset completely.  They are not replaced with
-    anything, so this in effects uses the high-priority cmdset as a filter
-    to affect the low-priority cmdset.  Ex: A1,A3 + B1,B2,B4,B5 = B2,B4,B5
-
-"""
-from weakref import WeakKeyDictionary
-from django.utils.translation import gettext as _
-from evennia.utils.utils import inherits_from, is_iter
-
-__all__ = ("CmdSet",)
-
-
-class _CmdSetMeta(type):
-    """
-    This metaclass makes some minor on-the-fly convenience fixes to
-    the cmdset class.
-
-    """
-
-    def __init__(cls, *args, **kwargs):
-        """
-        Fixes some things in the cmdclass
-
-        """
-        # by default we key the cmdset the same as the
-        # name of its class.
-        if not hasattr(cls, "key") or not cls.key:
-            cls.key = cls.__name__
-        cls.path = "%s.%s" % (cls.__module__, cls.__name__)
-
-        if not isinstance(cls.key_mergetypes, dict):
-            cls.key_mergetypes = {}
-
-        super().__init__(*args, **kwargs)
-
-
-
[docs]class CmdSet(object, metaclass=_CmdSetMeta): - """ - This class describes a unique cmdset that understands priorities. - CmdSets can be merged and made to perform various set operations - on each other. CmdSets have priorities that affect which of their - ingoing commands gets used. - - In the examples, cmdset A always have higher priority than cmdset B. - - key - the name of the cmdset. This can be used on its own for game - operations - - mergetype (partly from Set theory): - - Union - The two command sets are merged so that as many - commands as possible of each cmdset ends up in the - merged cmdset. Same-name commands are merged by - priority. This is the most common default. - Ex: A1,A3 + B1,B2,B4,B5 = A1,B2,A3,B4,B5 - Intersect - Only commands found in *both* cmdsets - (i.e. which have same names) end up in the merged - cmdset, with the higher-priority cmdset replacing the - lower one. Ex: A1,A3 + B1,B2,B4,B5 = A1 - Replace - The commands of this cmdset completely replaces - the lower-priority cmdset's commands, regardless - of if same-name commands exist. - Ex: A1,A3 + B1,B2,B4,B5 = A1,A3 - Remove - This removes the relevant commands from the - lower-priority cmdset completely. They are not - replaced with anything, so this in effects uses the - high-priority cmdset as a filter to affect the - low-priority cmdset. - Ex: A1,A3 + B1,B2,B4,B5 = B2,B4,B5 - - Note: Commands longer than 2 characters and starting - with double underscrores, like '__noinput_command' - are considered 'system commands' and are - excempt from all merge operations - they are - ALWAYS included across mergers and only affected - if same-named system commands replace them. - - priority- All cmdsets are always merged in pairs of two so that - the higher set's mergetype is applied to the - lower-priority cmdset. Default commands have priority 0, - high-priority ones like Exits and Channels have 10 and 9. - Priorities can be negative as well to give default - commands preference. - - duplicates - determines what happens when two sets of equal - priority merge (only). Defaults to None and has the first of them in the - merger (i.e. A above) automatically taking - precedence. But if `duplicates` is true, the - result will be a merger with more than one of each - name match. This will usually lead to the account - receiving a multiple-match error higher up the road, - but can be good for things like cmdsets on non-account - objects in a room, to allow the system to warn that - more than one 'ball' in the room has the same 'kick' - command defined on it, so it may offer a chance to - select which ball to kick ... Allowing duplicates - only makes sense for Union and Intersect, the setting - is ignored for the other mergetypes. - Note that the `duplicates` flag is *not* propagated in - a cmdset merger. So `A + B = C` will result in - a cmdset with duplicate commands, but C.duplicates will - be `None`. For duplication to apply to a whole cmdset - stack merge, _all_ cmdsets in the stack must have - `.duplicates=True` set. - Finally, if a final cmdset has `.duplicates=None` (the normal - unless created alone with another value), the cmdhandler - will assume True for object-based cmdsets and False for - all other. This is usually the most intuitive outcome. - - key_mergetype (dict) - allows the cmdset to define a unique - mergetype for particular cmdsets. Format is - {CmdSetkeystring:mergetype}. Priorities still apply. - Example: {'Myevilcmdset','Replace'} which would make - sure for this set to always use 'Replace' on - Myevilcmdset no matter what overall mergetype this set - has. - - no_objs - don't include any commands from nearby objects - when searching for suitable commands - no_exits - ignore the names of exits when matching against - commands - no_channels - ignore the name of channels when matching against - commands (WARNING- this is dangerous since the - account can then not even ask staff for help if - something goes wrong) - - - """ - - key = "Unnamed CmdSet" - mergetype = "Union" - priority = 0 - - # These flags, if set to None should be interpreted as 'I don't care' and, - # will allow "pass-through" even of lower-prio cmdsets' explicitly True/False - # options. If this is set to True/False however, priority matters. - no_exits = None - no_objs = None - no_channels = None - # The .duplicates setting does not propagate and since duplicates can only happen - # on same-prio cmdsets, there is no concept of passthrough on `None`. - # The merger of two cmdsets always return in a cmdset with `duplicates=None` - # (even if the result may have duplicated commands). - # If a final cmdset has `duplicates=None` (normal, unless the cmdset is - # created on its own with the flag set), the cmdhandler will auto-assume it to be - # True for Object-based cmdsets and stay None/False for all other entities. - # - # Example: - # A and C has .duplicates=True, B has .duplicates=None (or False) - # B + A = BA, where BA will have duplicate cmds, but BA.duplicates = None - # BA + C = BAC, where BAC will have more duplication, but BAC.duplicates = None - # - # Basically, for the `.duplicate` setting to survive throughout a - # merge-stack, every cmdset in the stack must have `duplicates` set explicitly. - duplicates = None - - persistent = False - key_mergetypes = {} - errmessage = "" - # pre-store properties to duplicate straight off - to_duplicate = ( - "key", - "cmdsetobj", - "no_exits", - "no_objs", - "no_channels", - "persistent", - "mergetype", - "priority", - "duplicates", - "errmessage", - ) - -
[docs] def __init__(self, cmdsetobj=None, key=None): - """ - Creates a new CmdSet instance. - - Args: - cmdsetobj (Session, Account, Object, optional): This is the database object - to which this particular instance of cmdset is related. It - is often a character but may also be a regular object, Account - or Session. - key (str, optional): The idenfier for this cmdset. This - helps if wanting to selectively remov cmdsets. - - """ - - if key: - self.key = key - self.commands = [] - self.system_commands = [] - self.actual_mergetype = self.mergetype - self.cmdsetobj = cmdsetobj - # this is set only on merged sets, in cmdhandler.py, in order to - # track, list and debug mergers correctly. - self.merged_from = [] - - # initialize system - self.at_cmdset_creation() - self._contains_cache = WeakKeyDictionary() # {}
- - # Priority-sensitive merge operations for cmdsets - - def _union(self, cmdset_a, cmdset_b): - """ - Merge two sets using union merger - - Args: - cmdset_a (Cmdset): Cmdset given higher priority in the case of a tie. - cmdset_b (Cmdset): Cmdset given lower priority in the case of a tie. - - Returns: - cmdset_c (Cmdset): The result of A U B operation. - - Notes: - Union, C = A U B, means that C gets all elements from both A and B. - - """ - cmdset_c = cmdset_a._duplicate() - # we make copies, not refs by use of [:] - cmdset_c.commands = cmdset_a.commands[:] - if cmdset_a.duplicates and cmdset_a.priority == cmdset_b.priority: - cmdset_c.commands.extend(cmdset_b.commands) - else: - cmdset_c.commands.extend([cmd for cmd in cmdset_b if cmd not in cmdset_a]) - return cmdset_c - - def _intersect(self, cmdset_a, cmdset_b): - """ - Merge two sets using intersection merger - - Args: - cmdset_a (Cmdset): Cmdset given higher priority in the case of a tie. - cmdset_b (Cmdset): Cmdset given lower priority in the case of a tie. - - Returns: - cmdset_c (Cmdset): The result of A (intersect) B operation. - - Notes: - Intersection, C = A (intersect) B, means that C only gets the - parts of A and B that are the same (that is, the commands - of each set having the same name. Only the one of these - having the higher prio ends up in C). - - """ - cmdset_c = cmdset_a._duplicate() - if cmdset_a.duplicates and cmdset_a.priority == cmdset_b.priority: - for cmd in [cmd for cmd in cmdset_a if cmd in cmdset_b]: - cmdset_c.add(cmd) - cmdset_c.add(cmdset_b.get(cmd)) - else: - cmdset_c.commands = [cmd for cmd in cmdset_a if cmd in cmdset_b] - return cmdset_c - - def _replace(self, cmdset_a, cmdset_b): - """ - Replace the contents of one set with another - - Args: - cmdset_a (Cmdset): Cmdset replacing - cmdset_b (Cmdset): Cmdset to replace - - Returns: - cmdset_c (Cmdset): This is indentical to cmdset_a. - - Notes: - C = A, where B is ignored. - - """ - cmdset_c = cmdset_a._duplicate() - cmdset_c.commands = cmdset_a.commands[:] - return cmdset_c - - def _remove(self, cmdset_a, cmdset_b): - """ - Filter a set by another. - - Args: - cmdset_a (Cmdset): Cmdset acting as a removal filter. - cmdset_b (Cmdset): Cmdset to filter - - Returns: - cmdset_c (Cmdset): B, with all matching commands from A removed. - - Notes: - C = B - A, where A is used to remove the commands of B. - - """ - - cmdset_c = cmdset_a._duplicate() - cmdset_c.commands = [cmd for cmd in cmdset_b if cmd not in cmdset_a] - return cmdset_c - - def _instantiate(self, cmd): - """ - checks so that object is an instantiated command and not, say - a cmdclass. If it is, instantiate it. Other types, like - strings, are passed through. - - Args: - cmd (any): Entity to analyze. - - Returns: - result (any): An instantiated Command or the input unmodified. - - """ - if callable(cmd): - return cmd() - else: - return cmd - - def _duplicate(self): - """ - Returns a new cmdset with the same settings as this one (no - actual commands are copied over) - - Returns: - cmdset (Cmdset): A copy of the current cmdset. - """ - cmdset = CmdSet() - for key, val in ((key, getattr(self, key)) for key in self.to_duplicate): - if val != getattr(cmdset, key): - # only copy if different from default; avoid turning - # class-vars into instance vars - setattr(cmdset, key, val) - cmdset.key_mergetypes = self.key_mergetypes.copy() - return cmdset - - def __str__(self): - """ - Show all commands in cmdset when printing it. - - Returns: - commands (str): Representation of commands in Cmdset. - - """ - perm = "perm" if self.persistent else "non-perm" - options = ", ".join([ - "{}:{}".format(opt, "T" if getattr(self, opt) else "F") - for opt in ("no_exits", "no_objs", "no_channels", "duplicates") - if getattr(self, opt) is not None - ]) - options = (", " + options) if options else "" - return (f"<CmdSet {self.key}, {self.mergetype}, {perm}, prio {self.priority}{options}>: " - + ", ".join([str(cmd) for cmd in sorted(self.commands, key=lambda o: o.key)])) - - def __iter__(self): - """ - Allows for things like 'for cmd in cmdset': - - Returns: - iterable (iter): Commands in Cmdset. - - """ - return iter(self.commands) - - def __contains__(self, othercmd): - """ - Returns True if this cmdset contains the given command (as - defined by command name and aliases). This allows for things - like 'if cmd in cmdset' - - """ - ret = self._contains_cache.get(othercmd) - if ret is None: - ret = othercmd in self.commands - self._contains_cache[othercmd] = ret - return ret - - def __add__(self, cmdset_a): - """ - Merge this cmdset (B) with another cmdset (A) using the + operator, - - C = B + A - - Here, we (by convention) say that 'A is merged onto B to form - C'. The actual merge operation used in the 'addition' depends - on which priorities A and B have. The one of the two with the - highest priority will apply and give its properties to C. In - the case of a tie, A takes priority and replaces the - same-named commands in B unless A has the 'duplicate' variable - set (which means both sets' commands are kept). - """ - - # It's okay to merge with None - if not cmdset_a: - return self - - sys_commands_a = cmdset_a.get_system_cmds() - sys_commands_b = self.get_system_cmds() - - if self.priority <= cmdset_a.priority: - # A higher or equal priority to B - - # preserve system __commands - sys_commands = sys_commands_a + [ - cmd for cmd in sys_commands_b if cmd not in sys_commands_a - ] - - mergetype = cmdset_a.key_mergetypes.get(self.key, cmdset_a.mergetype) - if mergetype == "Intersect": - cmdset_c = self._intersect(cmdset_a, self) - elif mergetype == "Replace": - cmdset_c = self._replace(cmdset_a, self) - elif mergetype == "Remove": - cmdset_c = self._remove(cmdset_a, self) - else: # Union - cmdset_c = self._union(cmdset_a, self) - - # pass through options whenever they are set, unless the merging or higher-prio - # set changes the setting (i.e. has a non-None value). We don't pass through - # the duplicates setting; that is per-merge; the resulting .duplicates value - # is always None (so merging cmdsets must all have explicit values if wanting - # to cause duplicates). - cmdset_c.no_channels = ( - self.no_channels if cmdset_a.no_channels is None else cmdset_a.no_channels - ) - cmdset_c.no_exits = self.no_exits if cmdset_a.no_exits is None else cmdset_a.no_exits - cmdset_c.no_objs = self.no_objs if cmdset_a.no_objs is None else cmdset_a.no_objs - cmdset_c.duplicates = None - - else: - # B higher priority than A - - # preserver system __commands - sys_commands = sys_commands_b + [ - cmd for cmd in sys_commands_a if cmd not in sys_commands_b - ] - - mergetype = self.key_mergetypes.get(cmdset_a.key, self.mergetype) - if mergetype == "Intersect": - cmdset_c = self._intersect(self, cmdset_a) - elif mergetype == "Replace": - cmdset_c = self._replace(self, cmdset_a) - elif mergetype == "Remove": - cmdset_c = self._remove(self, cmdset_a) - else: # Union - cmdset_c = self._union(self, cmdset_a) - - # pass through options whenever they are set, unless the higher-prio - # set changes the setting (i.e. has a non-None value). We don't pass through - # the duplicates setting; that is per-merge; the resulting .duplicates value# - # is always None (so merging cmdsets must all have explicit values if wanting - # to cause duplicates). - cmdset_c.no_channels = ( - cmdset_a.no_channels if self.no_channels is None else self.no_channels - ) - cmdset_c.no_exits = cmdset_a.no_exits if self.no_exits is None else self.no_exits - cmdset_c.no_objs = cmdset_a.no_objs if self.no_objs is None else self.no_objs - cmdset_c.duplicates = None - - # we store actual_mergetype since key_mergetypes - # might be different from the main mergetype. - # This is used for diagnosis. - cmdset_c.actual_mergetype = mergetype - - # print "__add__ for %s (prio %i) called with %s (prio %i)." % (self.key, self.priority, - # cmdset_a.key, cmdset_a.priority) - - # return the system commands to the cmdset - cmdset_c.add(sys_commands, allow_duplicates=True) - return cmdset_c - -
[docs] def add(self, cmd, allow_duplicates=False): - """ - Add a new command or commands to this CmdSet, a list of - commands or a cmdset to this cmdset. Note that this is *not* - a merge operation (that is handled by the + operator). - - Args: - cmd (Command, list, Cmdset): This allows for adding one or - more commands to this Cmdset in one go. If another Cmdset - is given, all its commands will be added. - allow_duplicates (bool, optional): If set, will not try to remove - duplicate cmds in the set. This is needed during the merge process - to avoid wiping commands coming from cmdsets with duplicate=True. - - Notes: - If cmd already exists in set, it will replace the old one - (no priority checking etc happens here). This is very useful - when overloading default commands). - - If cmd is another cmdset class or -instance, the commands of - that command set is added to this one, as if they were part of - the original cmdset definition. No merging or priority checks - are made, rather later added commands will simply replace - existing ones to make a unique set. - - """ - - if inherits_from(cmd, "evennia.commands.cmdset.CmdSet"): - # cmd is a command set so merge all commands in that set - # to this one. We raise a visible error if we created - # an infinite loop (adding cmdset to itself somehow) - cmdset = cmd - try: - cmdset = self._instantiate(cmdset) - except RuntimeError: - err = ("Adding cmdset {cmdset} to {cls} lead to an " - "infinite loop. When adding a cmdset to another, " - "make sure they are not themself cyclically added to " - "the new cmdset somewhere in the chain.") - raise RuntimeError(_(err.format(cmdset=cmdset, cls=self.__class__))) - cmds = cmdset.commands - elif is_iter(cmd): - cmds = [self._instantiate(c) for c in cmd] - else: - cmds = [self._instantiate(cmd)] - commands = self.commands - system_commands = self.system_commands - for cmd in cmds: - # add all commands - if not hasattr(cmd, "obj") or cmd.obj is None: - cmd.obj = self.cmdsetobj - try: - ic = commands.index(cmd) - commands[ic] = cmd # replace - except ValueError: - commands.append(cmd) - self.commands = commands - if not allow_duplicates: - # extra run to make sure to avoid doublets - self.commands = list(set(self.commands)) - # add system_command to separate list as well, - # for quick look-up - if cmd.key.startswith("__"): - try: - ic = system_commands.index(cmd) - system_commands[ic] = cmd # replace - except ValueError: - system_commands.append(cmd)
- -
[docs] def remove(self, cmd): - """ - Remove a command instance from the cmdset. - - Args: - cmd (Command or str): Either the Command object to remove - or the key of such a command. - - """ - cmd = self._instantiate(cmd) - if cmd.key.startswith("__"): - try: - ic = self.system_commands.index(cmd) - del self.system_commands[ic] - except ValueError: - # ignore error - pass - else: - self.commands = [oldcmd for oldcmd in self.commands if oldcmd != cmd]
- -
[docs] def get(self, cmd): - """ - Get a command from the cmdset. This is mostly useful to - check if the command is part of this cmdset or not. - - Args: - cmd (Command or str): Either the Command object or its key. - - Returns: - cmd (Command): The first matching Command in the set. - - """ - cmd = self._instantiate(cmd) - for thiscmd in self.commands: - if thiscmd == cmd: - return thiscmd - return None
- -
[docs] def count(self): - """ - Number of commands in set. - - Returns: - N (int): Number of commands in this Cmdset. - - """ - return len(self.commands)
- -
[docs] def get_system_cmds(self): - """ - Get system commands in cmdset - - Returns: - sys_cmds (list): The system commands in the set. - - Notes: - As far as the Cmdset is concerned, system commands are any - commands with a key starting with double underscore __. - These are excempt from merge operations. - - """ - return self.system_commands
- -
[docs] def make_unique(self, caller): - """ - Remove duplicate command-keys (unsafe) - - Args: - caller (object): Commands on this object will - get preference in the duplicate removal. - - Notes: - This is an unsafe command meant to clean out a cmdset of - doublet commands after it has been created. It is useful - for commands inheriting cmdsets from the cmdhandler where - obj-based cmdsets always are added double. Doublets will - be weeded out with preference to commands defined on - caller, otherwise just by first-come-first-served. - - """ - unique = {} - for cmd in self.commands: - if cmd.key in unique: - ocmd = unique[cmd.key] - if (hasattr(cmd, "obj") and cmd.obj == caller) and not ( - hasattr(ocmd, "obj") and ocmd.obj == caller - ): - unique[cmd.key] = cmd - else: - unique[cmd.key] = cmd - self.commands = list(unique.values())
- -
[docs] def get_all_cmd_keys_and_aliases(self, caller=None): - """ - Collects keys/aliases from commands - - Args: - caller (Object, optional): If set, this is used to check access permissions - on each command. Only commands that pass are returned. - - Returns: - names (list): A list of all command keys and aliases in this cmdset. If `caller` - was given, this list will only contain commands to which `caller` passed - the `call` locktype check. - - """ - names = [] - if caller: - [names.extend(cmd._keyaliases) for cmd in self.commands if cmd.access(caller)] - else: - [names.extend(cmd._keyaliases) for cmd in self.commands] - return names
- -
[docs] def at_cmdset_creation(self): - """ - Hook method - this should be overloaded in the inheriting - class, and should take care of populating the cmdset by use of - self.add(). - - """ - pass
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/commands/cmdsethandler.html b/docs/0.9.5/_modules/evennia/commands/cmdsethandler.html deleted file mode 100644 index c75211cac3..0000000000 --- a/docs/0.9.5/_modules/evennia/commands/cmdsethandler.html +++ /dev/null @@ -1,771 +0,0 @@ - - - - - - - - evennia.commands.cmdsethandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.commands.cmdsethandler

-"""
-CmdSethandler
-
-The Cmdsethandler tracks an object's 'Current CmdSet', which is the
-current merged sum of all CmdSets added to it.
-
-A CmdSet constitues a set of commands. The CmdSet works as a special
-intelligent container that, when added to other CmdSet make sure that
-same-name commands are treated correctly (usually so there are no
-doublets).  This temporary but up-to-date merger of CmdSet is jointly
-called the Current Cmset. It is this Current CmdSet that the
-commandhandler looks through whenever an account enters a command (it
-also adds CmdSets from objects in the room in real-time). All account
-objects have a 'default cmdset' containing all the normal in-game mud
-commands (look etc).
-
-So what is all this cmdset complexity good for?
-
-In its simplest form, a CmdSet has no commands, only a key name. In
-this case the cmdset's use is up to each individual game - it can be
-used by an AI module for example (mobs in cmdset 'roam' move from room
-to room, in cmdset 'attack' they enter combat with accounts).
-
-Defining commands in cmdsets offer some further powerful game-design
-consequences however. Here are some examples:
-
-As mentioned above, all accounts always have at least the Default
-CmdSet.  This contains the set of all normal-use commands in-game,
-stuff like look and @desc etc. Now assume our players end up in a dark
-room. You don't want the player to be able to do much in that dark
-room unless they light a candle. You could handle this by changing all
-your normal commands to check if the player is in a dark room. This
-rapidly goes unwieldly and error prone. Instead you just define a
-cmdset with only those commands you want to be available in the 'dark'
-cmdset - maybe a modified look command and a 'light candle' command -
-and have this completely replace the default cmdset.
-
-Another example: Say you want your players to be able to go
-fishing. You could implement this as a 'fish' command that fails
-whenever the account has no fishing rod. Easy enough.  But what if you
-want to make fishing more complex - maybe you want four-five different
-commands for throwing your line, reeling in, etc? Most players won't
-(we assume) have fishing gear, and having all those detailed commands
-is cluttering up the command list. And what if you want to use the
-'throw' command also for throwing rocks etc instead of 'using it up'
-for a minor thing like fishing?
-
-So instead you put all those detailed fishing commands into their own
-CommandSet called 'Fishing'. Whenever the player gives the command
-'fish' (presumably the code checks there is also water nearby), only
-THEN this CommandSet is added to the Cmdhandler of the account. The
-'throw' command (which normally throws rocks) is replaced by the
-custom 'fishing variant' of throw. What has happened is that the
-Fishing CommandSet was merged on top of the Default ones, and due to
-how we defined it, its command overrules the default ones.
-
-When we are tired of fishing, we give the 'go home' command (or
-whatever) and the Cmdhandler simply removes the fishing CommandSet
-so that we are back at defaults (and can throw rocks again).
-
-Since any number of CommandSets can be piled on top of each other, you
-can then implement separate sets for different situations. For
-example, you can have a 'On a boat' set, onto which you then tack on
-the 'Fishing' set. Fishing from a boat? No problem!
-
-"""
-import sys
-from traceback import format_exc
-from importlib import import_module
-from inspect import trace
-from django.conf import settings
-from evennia.utils import logger, utils
-from evennia.commands.cmdset import CmdSet
-from evennia.server.models import ServerConfig
-
-from django.utils.translation import gettext as _
-
-__all__ = ("import_cmdset", "CmdSetHandler")
-
-_CACHED_CMDSETS = {}
-_CMDSET_PATHS = utils.make_iter(settings.CMDSET_PATHS)
-_IN_GAME_ERRORS = settings.IN_GAME_ERRORS
-_CMDSET_FALLBACKS = settings.CMDSET_FALLBACKS
-
-
-# Output strings
-
-_ERROR_CMDSET_IMPORT = _(
-    """{traceback}
-Error loading cmdset '{path}'
-(Traceback was logged {timestamp})"""
-)
-
-_ERROR_CMDSET_KEYERROR = _(
-    """Error loading cmdset: No cmdset class '{classname}' in '{path}'.
-(Traceback was logged {timestamp})"""
-)
-
-_ERROR_CMDSET_SYNTAXERROR = _(
-    """{traceback}
-SyntaxError encountered when loading cmdset '{path}'.
-(Traceback was logged {timestamp})"""
-)
-
-_ERROR_CMDSET_EXCEPTION = _(
-    """{traceback}
-Compile/Run error when loading cmdset '{path}'.
-(Traceback was logged {timestamp})"""
-)
-
-_ERROR_CMDSET_FALLBACK = _(
-    """
-Error encountered for cmdset at path '{path}'.
-Replacing with fallback '{fallback_path}'.
-"""
-)
-
-_ERROR_CMDSET_NO_FALLBACK = _("""Fallback path '{fallback_path}' failed to generate a cmdset.""")
-
-
-class _ErrorCmdSet(CmdSet):
-    """
-    This is a special cmdset used to report errors.
-    """
-
-    key = "_CMDSET_ERROR"
-    errmessage = "Error when loading cmdset."
-
-
-class _EmptyCmdSet(CmdSet):
-    """
-    This cmdset represents an empty cmdset
-    """
-
-    key = "_EMPTY_CMDSET"
-    priority = -101
-    mergetype = "Union"
-
-
-
[docs]def import_cmdset(path, cmdsetobj, emit_to_obj=None, no_logging=False): - """ - This helper function is used by the cmdsethandler to load a cmdset - instance from a python module, given a python_path. It's usually accessed - through the cmdsethandler's add() and add_default() methods. - path - This is the full path to the cmdset object on python dot-form - - Args: - path (str): The path to the command set to load. - cmdsetobj (CmdSet): The database object/typeclass on which this cmdset is to be - assigned (this can be also channels and exits, as well as accounts - but there will always be such an object) - emit_to_obj (Object, optional): If given, error is emitted to - this object (in addition to logging) - no_logging (bool, optional): Don't log/send error messages. - This can be useful if import_cmdset is just used to check if - this is a valid python path or not. - Returns: - cmdset (CmdSet): The imported command set. If an error was - encountered, `commands.cmdsethandler._ErrorCmdSet` is returned - for the benefit of the handler. - - """ - python_paths = [path] + [ - "%s.%s" % (prefix, path) for prefix in _CMDSET_PATHS if not path.startswith(prefix) - ] - errstring = "" - for python_path in python_paths: - - if "." in path: - modpath, classname = python_path.rsplit(".", 1) - else: - raise ImportError(f"The path '{path}' is not on the form modulepath.ClassName") - - try: - # first try to get from cache - cmdsetclass = _CACHED_CMDSETS.get(python_path, None) - - if not cmdsetclass: - try: - module = import_module(modpath, package="evennia") - except ImportError as exc: - if len(trace()) > 2: - # error in module, make sure to not hide it. - dum, dum, tb = sys.exc_info() - raise exc.with_traceback(tb) - else: - # try next suggested path - errstring += _("\n(Unsuccessfully tried '{path}').").format( - path=python_path - ) - continue - try: - cmdsetclass = getattr(module, classname) - except AttributeError as exc: - if len(trace()) > 2: - # Attribute error within module, don't hide it - dum, dum, tb = sys.exc_info() - raise exc.with_traceback(tb) - else: - errstring += _("\n(Unsuccessfully tried '{path}').").format( - path=python_path - ) - continue - _CACHED_CMDSETS[python_path] = cmdsetclass - - # instantiate the cmdset (and catch its errors) - if callable(cmdsetclass): - cmdsetclass = cmdsetclass(cmdsetobj) - return cmdsetclass - except ImportError as err: - logger.log_trace() - errstring += _ERROR_CMDSET_IMPORT - if _IN_GAME_ERRORS: - errstring = errstring.format( - path=python_path, traceback=format_exc(), timestamp=logger.timeformat() - ) - else: - errstring = errstring.format( - path=python_path, traceback=err, timestamp=logger.timeformat() - ) - break - except KeyError: - logger.log_trace() - errstring += _ERROR_CMDSET_KEYERROR - errstring = errstring.format( - classname=classname, path=python_path, timestamp=logger.timeformat() - ) - break - except SyntaxError as err: - logger.log_trace() - errstring += _ERROR_CMDSET_SYNTAXERROR - if _IN_GAME_ERRORS: - errstring = errstring.format( - path=python_path, traceback=format_exc(), timestamp=logger.timeformat() - ) - else: - errstring = errstring.format( - path=python_path, traceback=err, timestamp=logger.timeformat() - ) - break - except Exception as err: - logger.log_trace() - errstring += _ERROR_CMDSET_EXCEPTION - if _IN_GAME_ERRORS: - errstring = errstring.format( - path=python_path, traceback=format_exc(), timestamp=logger.timeformat() - ) - else: - errstring = errstring.format( - path=python_path, traceback=err, timestamp=logger.timeformat() - ) - break - - if errstring: - # returning an empty error cmdset - errstring = errstring.strip() - if not no_logging: - logger.log_err(errstring) - if emit_to_obj and not ServerConfig.objects.conf("server_starting_mode"): - emit_to_obj.msg(errstring) - err_cmdset = _ErrorCmdSet() - err_cmdset.errmessage = errstring - return err_cmdset - return None # undefined error
- - -# classes - - -
[docs]class CmdSetHandler(object): - """ - The CmdSetHandler is always stored on an object, this object is supplied - as an argument. - - The 'current' cmdset is the merged set currently active for this object. - This is the set the game engine will retrieve when determining which - commands are available to the object. The cmdset_stack holds a history of - all CmdSets to allow the handler to remove/add cmdsets at will. Doing so - will re-calculate the 'current' cmdset. - """ - -
[docs] def __init__(self, obj, init_true=True): - """ - This method is called whenever an object is recreated. - - Args: - obj (Object): An reference to the game object this handler - belongs to. - init_true (bool, optional): Set when the handler is initializing - and loads the current cmdset. - - """ - self.obj = obj - - # the id of the "merged" current cmdset for easy access. - self.key = None - # this holds the "merged" current command set. Note that while the .update - # method updates this field in order to have it synced when operating on - # cmdsets in-code, when the game runs, this field is kept up-to-date by - # the cmdsethandler's get_and_merge_cmdsets! - self.current = None - # this holds a history of CommandSets - self.cmdset_stack = [_EmptyCmdSet(cmdsetobj=self.obj)] - # this tracks which mergetypes are actually in play in the stack - self.mergetype_stack = ["Union"] - - # the subset of the cmdset_paths that are to be stored in the database - self.persistent_paths = [""] - - if init_true: - self.update(init_mode=True) # is then called from the object __init__.
- - def __str__(self): - """ - Display current commands - - """ - - strings = ["<CmdSetHandler> stack:"] - mergelist = [] - if len(self.cmdset_stack) > 1: - # We have more than one cmdset in stack; list them all - for snum, cmdset in enumerate(self.cmdset_stack): - mergelist.append(str(snum + 1)) - strings.append(f" {snum + 1}: {cmdset}") - - # Display the currently active cmdset, limited by self.obj's permissions - mergetype = self.mergetype_stack[-1] - if mergetype != self.current.mergetype: - merged_on = self.cmdset_stack[-2].key - mergetype = _("custom {mergetype} on cmdset '{cmdset}'") - mergetype = mergetype.format(mergetype=mergetype, cmdset=merged_on) - - if mergelist: - # current is a result of mergers - mergelist = "+".join(mergelist) - strings.append(f" <Merged {mergelist}>: {self.current}") - else: - # current is a single cmdset - strings.append(" " + str(self.current)) - return "\n".join(strings).rstrip() - - def _import_cmdset(self, cmdset_path, emit_to_obj=None): - """ - Method wrapper for import_cmdset; Loads a cmdset from a - module. - - Args: - cmdset_path (str): The python path to an cmdset object. - emit_to_obj (Object): The object to send error messages to - - Returns: - cmdset (Cmdset): The imported cmdset. - - """ - if not emit_to_obj: - emit_to_obj = self.obj - return import_cmdset(cmdset_path, self.obj, emit_to_obj) - -
[docs] def update(self, init_mode=False): - """ - Re-adds all sets in the handler to have an updated current - - Args: - init_mode (bool, optional): Used automatically right after - this handler was created; it imports all persistent cmdsets - from the database. - - Notes: - This method is necessary in order to always have a `.current` - cmdset when working with the cmdsethandler in code. But the - CmdSetHandler doesn't (cannot) consider external cmdsets and game - state. This means that the .current calculated from this method - will likely not match the true current cmdset as determined at - run-time by `cmdhandler.get_and_merge_cmdsets()`. So in a running - game the responsibility of keeping `.current` upt-to-date belongs - to the central `cmdhandler.get_and_merge_cmdsets()`! - - """ - if init_mode: - # reimport all persistent cmdsets - storage = self.obj.cmdset_storage - if storage: - self.cmdset_stack = [] - for pos, path in enumerate(storage): - if pos == 0 and not path: - self.cmdset_stack = [_EmptyCmdSet(cmdsetobj=self.obj)] - elif path: - cmdset = self._import_cmdset(path) - if cmdset: - if cmdset.key == "_CMDSET_ERROR": - # If a cmdset fails to load, check if we have a fallback path to use - fallback_path = _CMDSET_FALLBACKS.get(path, None) - if fallback_path: - err = _ERROR_CMDSET_FALLBACK.format( - path=path, fallback_path=fallback_path - ) - logger.log_err(err) - if _IN_GAME_ERRORS: - self.obj.msg(err) - cmdset = self._import_cmdset(fallback_path) - # If no cmdset is returned from the fallback, we can't go further - if not cmdset: - err = _ERROR_CMDSET_NO_FALLBACK.format( - fallback_path=fallback_path - ) - logger.log_err(err) - if _IN_GAME_ERRORS: - self.obj.msg(err) - continue - cmdset.persistent = cmdset.key != "_CMDSET_ERROR" - self.cmdset_stack.append(cmdset) - - # merge the stack into a new merged cmdset - new_current = None - self.mergetype_stack = [] - for cmdset in self.cmdset_stack: - try: - # for cmdset's '+' operator, order matters. - new_current = cmdset + new_current - except TypeError: - continue - self.mergetype_stack.append(new_current.actual_mergetype) - self.current = new_current
- -
[docs] def add(self, cmdset, emit_to_obj=None, persistent=False, default_cmdset=False, - **kwargs): - """ - Add a cmdset to the handler, on top of the old ones, unless it - is set as the default one (it will then end up at the bottom of the stack) - - Args: - cmdset (CmdSet or str): Can be a cmdset object or the python path - to such an object. - emit_to_obj (Object, optional): An object to receive error messages. - persistent (bool, optional): Let cmdset remain across server reload. - default_cmdset (Cmdset, optional): Insert this to replace the - default cmdset position (there is only one such position, - always at the bottom of the stack). - - Notes: - An interesting feature of this method is if you were to send - it an *already instantiated cmdset* (i.e. not a class), the - current cmdsethandler's obj attribute will then *not* be - transferred over to this already instantiated set (this is - because it might be used elsewhere and can cause strange - effects). This means you could in principle have the - handler launch command sets tied to a *different* object - than the handler. Not sure when this would be useful, but - it's a 'quirk' that has to be documented. - - """ - if "permanent" in kwargs: - logger.log_dep("obj.cmdset.add() kwarg 'permanent' has changed name to " - "'persistent' and now defaults to True.") - persistent = kwargs['permanent'] if persistent is None else persistent - - if not (isinstance(cmdset, str) or utils.inherits_from(cmdset, CmdSet)): - string = _("Only CmdSets can be added to the cmdsethandler!") - raise Exception(string) - - if callable(cmdset): - cmdset = cmdset(self.obj) - elif isinstance(cmdset, str): - # this is (maybe) a python path. Try to import from cache. - cmdset = self._import_cmdset(cmdset) - if cmdset and cmdset.key != "_CMDSET_ERROR": - cmdset.persistent = persistent - if persistent and cmdset.key != "_CMDSET_ERROR": - # store the path permanently - storage = self.obj.cmdset_storage or [""] - if default_cmdset: - storage[0] = cmdset.path - else: - storage.append(cmdset.path) - self.obj.cmdset_storage = storage - if default_cmdset: - self.cmdset_stack[0] = cmdset - else: - self.cmdset_stack.append(cmdset) - self.update()
- -
[docs] def add_default(self, cmdset, emit_to_obj=None, persistent=True, **kwargs): - """ - Shortcut for adding a default cmdset. - - Args: - cmdset (Cmdset): The Cmdset to add. - emit_to_obj (Object, optional): Gets error messages - persistent (bool, optional): The new Cmdset should survive a server reboot. - - """ - if "permanent" in kwargs: - logger.log_dep("obj.cmdset.add_default() kwarg 'permanent' has changed name to " - "'persistent'.") - persistent = kwargs['permanent'] if persistent is None else persistent - self.add(cmdset, emit_to_obj=emit_to_obj, persistent=persistent, default_cmdset=True)
- -
[docs] def remove(self, cmdset=None, default_cmdset=False): - """ - Remove a cmdset from the handler. - - Args: - cmdset (CommandSet or str, optional): This can can be supplied either as a cmdset-key, - an instance of the CmdSet or a python path to the cmdset. - If no key is given, the last cmdset in the stack is - removed. Whenever the cmdset_stack changes, the cmdset is - updated. If default_cmdset is set, this argument is ignored. - default_cmdset (bool, optional): If set, this will remove the - default cmdset (at the bottom of the stack). - - """ - if default_cmdset: - # remove the default cmdset only - if self.cmdset_stack: - cmdset = self.cmdset_stack[0] - if cmdset.persistent: - storage = self.obj.cmdset_storage or [""] - storage[0] = "" - self.obj.cmdset_storage = storage - self.cmdset_stack[0] = _EmptyCmdSet(cmdsetobj=self.obj) - else: - self.cmdset_stack = [_EmptyCmdSet(cmdsetobj=self.obj)] - self.update() - return - - if len(self.cmdset_stack) < 2: - # don't allow deleting default cmdsets here. - return - - if not cmdset: - # remove the last one in the stack - cmdset = self.cmdset_stack.pop() - if cmdset.persistent: - storage = self.obj.cmdset_storage - storage.pop() - self.obj.cmdset_storage = storage - else: - # try it as a callable - if callable(cmdset) and hasattr(cmdset, "path"): - delcmdsets = [cset for cset in self.cmdset_stack[1:] if cset.path == cmdset.path] - else: - # try it as a path or key - delcmdsets = [ - cset - for cset in self.cmdset_stack[1:] - if cset.path == cmdset or cset.key == cmdset - ] - storage = [] - - if any(cset.persistent for cset in delcmdsets): - # only hit database if there's need to - storage = self.obj.cmdset_storage - updated = False - for cset in delcmdsets: - if cset.persistent: - try: - storage.remove(cset.path) - updated = True - except ValueError: - # nothing to remove - pass - if updated: - self.obj.cmdset_storage = storage - for cset in delcmdsets: - # clean the in-memory stack - try: - self.cmdset_stack.remove(cset) - except ValueError: - # nothing to remove - pass - # re-sync the cmdsethandler. - self.update()
- - # legacy alias - delete = remove - -
[docs] def remove_default(self): - """ - This explicitly deletes only the default cmdset. - - """ - self.remove(default_cmdset=True)
- - # legacy alias - delete_default = remove_default - -
[docs] def get(self): - """ - Get all cmdsets. - - Returns: - cmdsets (list): All the command sets currently in the handler. - - """ - return self.cmdset_stack
- - # backwards-compatible alias - all = get - -
[docs] def clear(self): - """ - Removes all Command Sets from the handler except the default one - (use `self.remove_default` to remove that). - - """ - self.cmdset_stack = [self.cmdset_stack[0]] - storage = self.obj.cmdset_storage - if storage: - storage = storage[0] - self.obj.cmdset_storage = storage - self.update()
- -
[docs] def has(self, cmdset, must_be_default=False): - """ - checks so the cmdsethandler contains a given cmdset - - Args: - cmdset (str or Cmdset): Cmdset key, pythonpath or - Cmdset to check the existence for. - must_be_default (bool, optional): Only return True if - the checked cmdset is the default one. - - Returns: - has_cmdset (bool): Whether or not the cmdset is in the handler. - - """ - if callable(cmdset) and hasattr(cmdset, "path"): - # try it as a callable - if must_be_default: - return self.cmdset_stack and (self.cmdset_stack[0].path == cmdset.path) - else: - return any([cset for cset in self.cmdset_stack if cset.path == cmdset.path]) - else: - # try it as a path or key - if must_be_default: - return self.cmdset_stack and ( - self.cmdset_stack[0].key == cmdset or self.cmdset_stack[0].path == cmdset - ) - else: - return any( - [ - cset - for cset in self.cmdset_stack - if cset.path == cmdset or cset.key == cmdset - ] - )
- - # backwards-compatability alias - has_cmdset = has - -
[docs] def reset(self): - """ - Force reload of all cmdsets in handler. This should be called - after _CACHED_CMDSETS have been cleared (normally this is - handled automatically by @reload). - - """ - new_cmdset_stack = [] - for cmdset in self.cmdset_stack: - if cmdset.key == "_EMPTY_CMDSET": - new_cmdset_stack.append(cmdset) - else: - new_cmdset_stack.append(self._import_cmdset(cmdset.path)) - self.cmdset_stack = new_cmdset_stack - self.update()
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/commands/command.html b/docs/0.9.5/_modules/evennia/commands/command.html deleted file mode 100644 index 833cd29a49..0000000000 --- a/docs/0.9.5/_modules/evennia/commands/command.html +++ /dev/null @@ -1,849 +0,0 @@ - - - - - - - - evennia.commands.command — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.commands.command

-"""
-The base Command class.
-
-All commands in Evennia inherit from the 'Command' class in this module.
-
-"""
-import re
-import math
-import inspect
-
-from django.conf import settings
-from django.urls import reverse
-from django.utils.text import slugify
-
-from evennia.locks.lockhandler import LockHandler
-from evennia.utils.utils import is_iter, fill, lazy_property, make_iter
-from evennia.utils.evtable import EvTable
-from evennia.utils.ansi import ANSIString
-
-
-CMD_IGNORE_PREFIXES = settings.CMD_IGNORE_PREFIXES
-
-
-
[docs]class InterruptCommand(Exception): - - """Cleanly interrupt a command.""" - - pass
- - -def _init_command(cls, **kwargs): - """ - Helper command. - Makes sure all data are stored as lowercase and - do checking on all properties that should be in list form. - Sets up locks to be more forgiving. This is used both by the metaclass - and (optionally) at instantiation time. - - If kwargs are given, these are set as instance-specific properties - on the command - but note that the Command instance is *re-used* on a given - host object, so a kwarg value set on the instance will *remain* on the instance - for subsequent uses of that Command on that particular object. - - """ - for i in range(len(kwargs)): - # used for dynamic creation of commands - key, value = kwargs.popitem() - setattr(cls, key, value) - - cls.key = cls.key.lower() - if cls.aliases and not is_iter(cls.aliases): - try: - cls.aliases = [str(alias).strip().lower() for alias in cls.aliases.split(",")] - except Exception: - cls.aliases = [] - cls.aliases = list(set(alias for alias in cls.aliases if alias and alias != cls.key)) - - # optimization - a set is much faster to match against than a list - cls._matchset = set([cls.key] + cls.aliases) - # optimization for looping over keys+aliases - cls._keyaliases = tuple(cls._matchset) - - # by default we don't save the command between runs - if not hasattr(cls, "save_for_next"): - cls.save_for_next = False - - # pre-process locks as defined in class definition - temp = [] - if hasattr(cls, "permissions"): - cls.locks = cls.permissions - if not hasattr(cls, "locks"): - # default if one forgets to define completely - cls.locks = "cmd:all()" - if "cmd:" not in cls.locks: - cls.locks = "cmd:all();" + cls.locks - for lockstring in cls.locks.split(";"): - if lockstring and ":" not in lockstring: - lockstring = "cmd:%s" % lockstring - temp.append(lockstring) - cls.lock_storage = ";".join(temp) - - if hasattr(cls, "arg_regex") and isinstance(cls.arg_regex, str): - cls.arg_regex = re.compile(r"%s" % cls.arg_regex, re.I + re.UNICODE) - if not hasattr(cls, "auto_help"): - cls.auto_help = True - if not hasattr(cls, "is_exit"): - cls.is_exit = False - if not hasattr(cls, "help_category"): - cls.help_category = "general" - if not hasattr(cls, "retain_instance"): - cls.retain_instance = False - - # make sure to pick up the parent's docstring if the child class is - # missing one (important for auto-help) - if cls.__doc__ is None: - for parent_class in inspect.getmro(cls): - if parent_class.__doc__ is not None: - cls.__doc__ = parent_class.__doc__ - break - cls.help_category = cls.help_category.lower() - - # pre-prepare a help index entry for quicker lookup - # strip the @- etc to allow help to be agnostic - stripped_key = cls.key[1:] if cls.key and cls.key[0] in CMD_IGNORE_PREFIXES else "" - stripped_aliases = ( - " ".join(al[1:] if al and al[0] in CMD_IGNORE_PREFIXES else al - for al in cls.aliases)) - cls.search_index_entry = { - "key": cls.key, - "aliases": " ".join(cls.aliases), - "no_prefix": f"{stripped_key} {stripped_aliases}", - "category": cls.help_category, - "text": cls.__doc__, - "tags": "" - } - - -
[docs]class CommandMeta(type): - """ - The metaclass cleans up all properties on the class - """ - -
[docs] def __init__(cls, *args, **kwargs): - _init_command(cls, **kwargs) - super().__init__(*args, **kwargs)
- - -# The Command class is the basic unit of an Evennia command; when -# defining new commands, the admin subclass this class and -# define their own parser method to handle the input. The -# advantage of this is inheritage; commands that have similar -# structure can parse the input string the same way, minimizing -# parsing errors. - - -
[docs]class Command(metaclass=CommandMeta): - """ - ## Base command - - (you may see this if a child command had no help text defined) - - Usage: - command [args] - - This is the base command class. Inherit from this - to create new commands. - - The cmdhandler makes the following variables available to the - command methods (so you can always assume them to be there): - self.caller - the game object calling the command - self.cmdstring - the command name used to trigger this command (allows - you to know which alias was used, for example) - cmd.args - everything supplied to the command following the cmdstring - (this is usually what is parsed in self.parse()) - cmd.cmdset - the cmdset from which this command was matched (useful only - seldomly, notably for help-type commands, to create dynamic - help entries and lists) - cmd.obj - the object on which this command is defined. If a default command, - this is usually the same as caller. - cmd.rawstring - the full raw string input, including any args and no parsing. - - The following class properties can/should be defined on your child class: - - key - identifier for command (e.g. "look") - aliases - (optional) list of aliases (e.g. ["l", "loo"]) - locks - lock string (default is "cmd:all()") - help_category - how to organize this help entry in help system - (default is "General") - auto_help - defaults to True. Allows for turning off auto-help generation - arg_regex - (optional) raw string regex defining how the argument part of - the command should look in order to match for this command - (e.g. must it be a space between cmdname and arg?) - auto_help_display_key - (optional) if given, this replaces the string shown - in the auto-help listing. This is particularly useful for system-commands - whose actual key is not really meaningful. - - (Note that if auto_help is on, this initial string is also used by the - system to create the help entry for the command, so it's a good idea to - format it similar to this one). This behavior can be changed by - overriding the method 'get_help' of a command: by default, this - method returns cmd.__doc__ (that is, this very docstring, or - the docstring of your command). You can, however, extend or - replace this without disabling auto_help. - """ - - # the main way to call this command (e.g. 'look') - key = "command" - # alternative ways to call the command (e.g. 'l', 'glance', 'examine') - aliases = [] - # a list of lock definitions on the form - # cmd:[NOT] func(args) [ AND|OR][ NOT] func2(args) - locks = settings.COMMAND_DEFAULT_LOCKS - # used by the help system to group commands in lists. - help_category = settings.COMMAND_DEFAULT_HELP_CATEGORY - # This allows to turn off auto-help entry creation for individual commands. - auto_help = True - # optimization for quickly separating exit-commands from normal commands - is_exit = False - # define the command not only by key but by the regex form of its arguments - arg_regex = settings.COMMAND_DEFAULT_ARG_REGEX - # whether self.msg sends to all sessions of a related account/object (default - # is to only send to the session sending the command). - msg_all_sessions = settings.COMMAND_DEFAULT_MSG_ALL_SESSIONS - # whether the exact command instance should be retained between command calls. - # By default it's False; this allows for retaining state and saves some CPU, but - # can cause cross-talk between users if multiple users access the same command - # (especially if the command is using yield) - retain_instance = False - - # auto-set (by Evennia on command instantiation) are: - # obj - which object this command is defined on - # session - which session is responsible for triggering this command. Only set - # if triggered by an account. - -
[docs] def __init__(self, **kwargs): - """ - The lockhandler works the same as for objects. - optional kwargs will be set as properties on the Command at runtime, - overloading evential same-named class properties. - - """ - if kwargs: - _init_command(self, **kwargs)
- -
[docs] @lazy_property - def lockhandler(self): - return LockHandler(self)
- - def __str__(self): - """ - Print the command key - """ - return self.key - - def __eq__(self, cmd): - """ - Compare two command instances to each other by matching their - key and aliases. - - Args: - cmd (Command or str): Allows for equating both Command - objects and their keys. - - Returns: - equal (bool): If the commands are equal or not. - - """ - try: - # first assume input is a command (the most common case) - return self._matchset.intersection(cmd._matchset) - except AttributeError: - # probably got a string - return cmd in self._matchset - - def __hash__(self): - """ - Python 3 requires that any class which implements __eq__ must also - implement __hash__ and that the corresponding hashes for equivalent - instances are themselves equivalent. - - Technically, the following implementation is only valid for comparison - against other Commands, as our __eq__ supports comparison against - str, too. - - """ - return hash("\n".join(self._matchset)) - - def __ne__(self, cmd): - """ - The logical negation of __eq__. Since this is one of the most - called methods in Evennia (along with __eq__) we do some - code-duplication here rather than issuing a method-lookup to - __eq__. - """ - try: - return self._matchset.isdisjoint(cmd._matchset) - except AttributeError: - return cmd not in self._matchset - - def __contains__(self, query): - """ - This implements searches like 'if query in cmd'. It's a fuzzy - matching used by the help system, returning True if query can - be found as a substring of the commands key or its aliases. - - Args: - query (str): query to match against. Should be lower case. - - Returns: - result (bool): Fuzzy matching result. - - """ - return any(query in keyalias for keyalias in self._keyaliases) - - def _optimize(self): - """ - Optimize the key and aliases for lookups. - """ - # optimization - a set is much faster to match against than a list - self._matchset = set([self.key] + self.aliases) - # optimization for looping over keys+aliases - self._keyaliases = tuple(self._matchset) - -
[docs] def set_key(self, new_key): - """ - Update key. - - Args: - new_key (str): The new key. - - Notes: - This is necessary to use to make sure the optimization - caches are properly updated as well. - - """ - self.key = new_key.lower() - self._optimize()
- -
[docs] def set_aliases(self, new_aliases): - """ - Replace aliases with new ones. - - Args: - new_aliases (str or list): Either a ;-separated string - or a list of aliases. These aliases will replace the - existing ones, if any. - - Notes: - This is necessary to use to make sure the optimization - caches are properly updated as well. - - """ - if isinstance(new_aliases, str): - new_aliases = new_aliases.split(";") - aliases = (str(alias).strip().lower() for alias in make_iter(new_aliases)) - self.aliases = list(set(alias for alias in aliases if alias != self.key)) - self._optimize()
- -
[docs] def match(self, cmdname): - """ - This is called by the system when searching the available commands, - in order to determine if this is the one we wanted. cmdname was - previously extracted from the raw string by the system. - - Args: - cmdname (str): Always lowercase when reaching this point. - - Returns: - result (bool): Match result. - - """ - return cmdname in self._matchset
- -
[docs] def access(self, srcobj, access_type="cmd", default=False): - """ - This hook is called by the cmdhandler to determine if srcobj - is allowed to execute this command. It should return a boolean - value and is not normally something that need to be changed since - it's using the Evennia permission system directly. - - Args: - srcobj (Object): Object trying to gain permission - access_type (str, optional): The lock type to check. - default (bool, optional): The fallback result if no lock - of matching `access_type` is found on this Command. - - """ - return self.lockhandler.check(srcobj, access_type, default=default)
- -
[docs] def msg(self, text=None, to_obj=None, from_obj=None, session=None, **kwargs): - """ - This is a shortcut instead of calling msg() directly on an - object - it will detect if caller is an Object or an Account and - also appends self.session automatically if self.msg_all_sessions is False. - - Args: - text (str, optional): Text string of message to send. - to_obj (Object, optional): Target object of message. Defaults to self.caller. - from_obj (Object, optional): Source of message. Defaults to to_obj. - session (Session, optional): Supply data only to a unique - session (ignores the value of `self.msg_all_sessions`). - - Keyword Args: - options (dict): Options to the protocol. - any (any): All other keywords are interpreted as th - name of send-instructions. - - """ - from_obj = from_obj or self.caller - to_obj = to_obj or from_obj - if not session and not self.msg_all_sessions: - if to_obj == self.caller: - session = self.session - else: - session = to_obj.sessions.get() - to_obj.msg(text=text, from_obj=from_obj, session=session, **kwargs)
- -
[docs] def execute_cmd(self, raw_string, session=None, obj=None, **kwargs): - """ - A shortcut of execute_cmd on the caller. It appends the - session automatically. - - Args: - raw_string (str): Execute this string as a command input. - session (Session, optional): If not given, the current command's Session will be used. - obj (Object or Account, optional): Object or Account on which to call the execute_cmd. - If not given, self.caller will be used. - - Keyword Args: - Other keyword arguments will be added to the found command - object instace as variables before it executes. This is - unused by default Evennia but may be used to set flags and - change operating paramaters for commands at run-time. - - """ - obj = self.caller if obj is None else obj - session = self.session if session is None else session - obj.execute_cmd(raw_string, session=session, **kwargs)
- - # Common Command hooks - -
[docs] def at_pre_cmd(self): - """ - This hook is called before self.parse() on all commands. If - this hook returns anything but False/None, the command - sequence is aborted. - - """ - pass
- -
[docs] def at_post_cmd(self): - """ - This hook is called after the command has finished executing - (after self.func()). - - """ - pass
- -
[docs] def parse(self): - """ - Once the cmdhandler has identified this as the command we - want, this function is run. If many of your commands have a - similar syntax (for example 'cmd arg1 = arg2') you should - simply define this once and just let other commands of the - same form inherit from this. See the docstring of this module - for which object properties are available to use (notably - self.args). - - """ - pass
- -
[docs] def get_command_info(self): - """ - This is the default output of func() if no func() overload is done. - Provided here as a separate method so that it can be called for debugging - purposes when making commands. - - """ - variables = "\n".join( - " |w{}|n ({}): {}".format(key, type(val), val) for key, val in self.__dict__.items() - ) - string = f""" -Command {self} has no defined `func()` - showing on-command variables: -{variables} - """ - # a simple test command to show the available properties - string += "-" * 50 - string += "\n|w%s|n - Command variables from evennia:\n" % self.key - string += "-" * 50 - string += "\nname of cmd (self.key): |w%s|n\n" % self.key - string += "cmd aliases (self.aliases): |w%s|n\n" % self.aliases - string += "cmd locks (self.locks): |w%s|n\n" % self.locks - string += "help category (self.help_category): |w%s|n\n" % self.help_category.capitalize() - string += "object calling (self.caller): |w%s|n\n" % self.caller - string += "object storing cmdset (self.obj): |w%s|n\n" % self.obj - string += "command string given (self.cmdstring): |w%s|n\n" % self.cmdstring - # show cmdset.key instead of cmdset to shorten output - string += fill( - "current cmdset (self.cmdset): |w%s|n\n" - % (self.cmdset.key if self.cmdset.key else self.cmdset.__class__) - ) - - self.caller.msg(string)
- -
[docs] def func(self): - """ - This is the actual executing part of the command. It is - called directly after self.parse(). See the docstring of this - module for which object properties are available (beyond those - set in self.parse()) - - """ - self.get_command_info()
- -
[docs] def get_extra_info(self, caller, **kwargs): - """ - Display some extra information that may help distinguish this - command from others, for instance, in a disambiguity prompt. - - If this command is a potential match in an ambiguous - situation, one distinguishing feature may be its attachment to - a nearby object, so we include this if available. - - Args: - caller (TypedObject): The caller who typed an ambiguous - term handed to the search function. - - Returns: - A string with identifying information to disambiguate the - object, conventionally with a preceding space. - - """ - if hasattr(self, "obj") and self.obj and self.obj != caller: - return " (%s)" % self.obj.get_display_name(caller).strip() - return ""
- -
[docs] def get_help(self, caller, cmdset): - """ - Return the help message for this command and this caller. - - By default, return self.__doc__ (the docstring just under - the class definition). You can override this behavior, - though, and even customize it depending on the caller, or other - commands the caller can use. - - Args: - caller (Object or Account): the caller asking for help on the command. - cmdset (CmdSet): the command set (if you need additional commands). - - Returns: - docstring (str): the help text to provide the caller for this command. - - """ - return self.__doc__
- -
[docs] def web_get_detail_url(self): - """ - Returns the URI path for a View that allows users to view details for - this object. - - ex. Oscar (Character) = '/characters/oscar/1/' - - For this to work, the developer must have defined a named view somewhere - in urls.py that follows the format 'modelname-action', so in this case - a named view of 'character-detail' would be referenced by this method. - - ex. - :: - url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$', - CharDetailView.as_view(), name='character-detail') - - If no View has been created and defined in urls.py, returns an - HTML anchor. - - This method is naive and simply returns a path. Securing access to - the actual view and limiting who can view this object is the developer's - responsibility. - - Returns: - path (str): URI path to object detail page, if defined. - - """ - try: - return reverse( - 'help-entry-detail', - kwargs={"category": slugify(self.help_category), "topic": slugify(self.key)}, - ) - except Exception as e: - return "#"
- -
[docs] def web_get_admin_url(self): - """ - Returns the URI path for the Django Admin page for this object. - - ex. Account#1 = '/admin/accounts/accountdb/1/change/' - - Returns: - path (str): URI path to Django Admin page for object. - - """ - return False
- -
[docs] def client_width(self): - """ - Get the client screenwidth for the session using this command. - - Returns: - client width (int): The width (in characters) of the client window. - - """ - if self.session: - return self.session.protocol_flags.get( - "SCREENWIDTH", {0: settings.CLIENT_DEFAULT_WIDTH} - )[0] - return settings.CLIENT_DEFAULT_WIDTH
- -
[docs] def styled_table(self, *args, **kwargs): - """ - Create an EvTable styled by on user preferences. - - Args: - *args (str): Column headers. If not colored explicitly, these will get colors - from user options. - Keyword Args: - any (str, int or dict): EvTable options, including, optionally a `table` dict - detailing the contents of the table. - Returns: - table (EvTable): An initialized evtable entity, either complete (if using `table` kwarg) - or incomplete and ready for use with `.add_row` or `.add_collumn`. - - """ - border_color = self.account.options.get("border_color") - column_color = self.account.options.get("column_names_color") - - colornames = ["|%s%s|n" % (column_color, col) for col in args] - - h_line_char = kwargs.pop("header_line_char", "~") - header_line_char = ANSIString(f"|{border_color}{h_line_char}|n") - c_char = kwargs.pop("corner_char", "+") - corner_char = ANSIString(f"|{border_color}{c_char}|n") - - b_left_char = kwargs.pop("border_left_char", "||") - border_left_char = ANSIString(f"|{border_color}{b_left_char}|n") - - b_right_char = kwargs.pop("border_right_char", "||") - border_right_char = ANSIString(f"|{border_color}{b_right_char}|n") - - b_bottom_char = kwargs.pop("border_bottom_char", "-") - border_bottom_char = ANSIString(f"|{border_color}{b_bottom_char}|n") - - b_top_char = kwargs.pop("border_top_char", "-") - border_top_char = ANSIString(f"|{border_color}{b_top_char}|n") - - table = EvTable( - *colornames, - header_line_char=header_line_char, - corner_char=corner_char, - border_left_char=border_left_char, - border_right_char=border_right_char, - border_top_char=border_top_char, - border_bottom_char=border_bottom_char, - **kwargs, - ) - return table
- - def _render_decoration( - self, - header_text=None, - fill_character=None, - edge_character=None, - mode="header", - color_header=True, - width=None, - ): - """ - Helper for formatting a string into a pretty display, for a header, separator or footer. - - Keyword Args: - header_text (str): Text to include in header. - fill_character (str): This single character will be used to fill the width of the - display. - edge_character (str): This character caps the edges of the display. - mode(str): One of 'header', 'separator' or 'footer'. - color_header (bool): If the header should be colorized based on user options. - width (int): If not given, the client's width will be used if available. - - Returns: - string (str): The decorated and formatted text. - - """ - - colors = dict() - colors["border"] = self.account.options.get("border_color") - colors["headertext"] = self.account.options.get("%s_text_color" % mode) - colors["headerstar"] = self.account.options.get("%s_star_color" % mode) - - width = width or self.client_width() - if edge_character: - width -= 2 - - if header_text: - if color_header: - header_text = ANSIString(header_text).clean() - header_text = ANSIString("|n|%s%s|n" % (colors["headertext"], header_text)) - if mode == "header": - begin_center = ANSIString( - "|n|%s<|%s* |n" % (colors["border"], colors["headerstar"]) - ) - end_center = ANSIString("|n |%s*|%s>|n" % (colors["headerstar"], colors["border"])) - center_string = ANSIString(begin_center + header_text + end_center) - else: - center_string = ANSIString("|n |%s%s |n" % (colors["headertext"], header_text)) - else: - center_string = "" - - fill_character = self.account.options.get("%s_fill" % mode) - - remain_fill = width - len(center_string) - if remain_fill % 2 == 0: - right_width = remain_fill / 2 - left_width = remain_fill / 2 - else: - right_width = math.floor(remain_fill / 2) - left_width = math.ceil(remain_fill / 2) - - right_fill = ANSIString("|n|%s%s|n" % (colors["border"], fill_character * int(right_width))) - left_fill = ANSIString("|n|%s%s|n" % (colors["border"], fill_character * int(left_width))) - - if edge_character: - edge_fill = ANSIString("|n|%s%s|n" % (colors["border"], edge_character)) - main_string = ANSIString(center_string) - final_send = ( - ANSIString(edge_fill) + left_fill + main_string + right_fill + ANSIString(edge_fill) - ) - else: - final_send = left_fill + ANSIString(center_string) + right_fill - return final_send - -
[docs] def styled_header(self, *args, **kwargs): - """ - Create a pretty header. - """ - - if "mode" not in kwargs: - kwargs["mode"] = "header" - return self._render_decoration(*args, **kwargs)
- -
[docs] def styled_separator(self, *args, **kwargs): - """ - Create a separator. - - """ - if "mode" not in kwargs: - kwargs["mode"] = "separator" - return self._render_decoration(*args, **kwargs)
- -
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/commands/default/account.html b/docs/0.9.5/_modules/evennia/commands/default/account.html deleted file mode 100644 index d4068942e4..0000000000 --- a/docs/0.9.5/_modules/evennia/commands/default/account.html +++ /dev/null @@ -1,1160 +0,0 @@ - - - - - - - - evennia.commands.default.account — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.commands.default.account

-"""
-Account (OOC) commands. These are stored on the Account object
-and self.caller is thus always an Account, not an Object/Character.
-
-These commands go in the AccountCmdset and are accessible also
-when puppeting a Character (although with lower priority)
-
-These commands use the account_caller property which tells the command
-parent (MuxCommand, usually) to setup caller correctly. They use
-self.account to make sure to always use the account object rather than
-self.caller (which change depending on the level you are calling from)
-The property self.character can be used to access the character when
-these commands are triggered with a connected character (such as the
-case of the `ooc` command), it is None if we are OOC.
-
-Note that under MULTISESSION_MODE > 2, Account commands should use
-self.msg() and similar methods to reroute returns to the correct
-method. Otherwise all text will be returned to all connected sessions.
-
-"""
-import time
-from codecs import lookup as codecs_lookup
-from django.conf import settings
-from evennia.server.sessionhandler import SESSIONS
-from evennia.utils import utils, create, logger, search
-
-COMMAND_DEFAULT_CLASS = utils.class_from_module(settings.COMMAND_DEFAULT_CLASS)
-
-_MAX_NR_CHARACTERS = settings.MAX_NR_CHARACTERS
-_MULTISESSION_MODE = settings.MULTISESSION_MODE
-
-# limit symbol import for API
-__all__ = (
-    "CmdOOCLook",
-    "CmdIC",
-    "CmdOOC",
-    "CmdPassword",
-    "CmdQuit",
-    "CmdCharCreate",
-    "CmdOption",
-    "CmdSessions",
-    "CmdWho",
-    "CmdColorTest",
-    "CmdQuell",
-    "CmdCharDelete",
-    "CmdStyle",
-)
-
-
-class MuxAccountLookCommand(COMMAND_DEFAULT_CLASS):
-    """
-    Custom parent (only) parsing for OOC looking, sets a "playable"
-    property on the command based on the parsing.
-
-    """
-
-    def parse(self):
-        """Custom parsing"""
-
-        super().parse()
-
-        if _MULTISESSION_MODE < 2:
-            # only one character allowed - not used in this mode
-            self.playable = None
-            return
-
-        playable = self.account.db._playable_characters
-        if playable is not None:
-            # clean up list if character object was deleted in between
-            if None in playable:
-                playable = [character for character in playable if character]
-                self.account.db._playable_characters = playable
-        # store playable property
-        if self.args:
-            self.playable = dict((utils.to_str(char.key.lower()), char) for char in playable).get(
-                self.args.lower(), None
-            )
-        else:
-            self.playable = playable
-
-
-# Obs - these are all intended to be stored on the Account, and as such,
-# use self.account instead of self.caller, just to be sure. Also self.msg()
-# is used to make sure returns go to the right session
-
-# note that this is inheriting from MuxAccountLookCommand,
-# and has the .playable property.
-
[docs]class CmdOOCLook(MuxAccountLookCommand): - """ - look while out-of-character - - Usage: - look - - Look in the ooc state. - """ - - # This is an OOC version of the look command. Since a - # Account doesn't have an in-game existence, there is no - # concept of location or "self". If we are controlling - # a character, pass control over to normal look. - - key = "look" - aliases = ["l", "ls"] - locks = "cmd:all()" - help_category = "General" - - # this is used by the parent - account_caller = True - -
[docs] def func(self): - """implement the ooc look command""" - - if _MULTISESSION_MODE < 2: - # only one character allowed - self.msg("You are out-of-character (OOC).\nUse |wic|n to get back into the game.") - return - - # call on-account look helper method - self.msg(self.account.at_look(target=self.playable, session=self.session))
- - -
[docs]class CmdCharCreate(COMMAND_DEFAULT_CLASS): - """ - create a new character - - Usage: - charcreate <charname> [= desc] - - Create a new character, optionally giving it a description. You - may use upper-case letters in the name - you will nevertheless - always be able to access your character using lower-case letters - if you want. - """ - - key = "charcreate" - locks = "cmd:pperm(Player)" - help_category = "General" - - # this is used by the parent - account_caller = True - -
[docs] def func(self): - """create the new character""" - account = self.account - if not self.args: - self.msg("Usage: charcreate <charname> [= description]") - return - key = self.lhs - desc = self.rhs - - charmax = _MAX_NR_CHARACTERS - - if not account.is_superuser and ( - account.db._playable_characters and len(account.db._playable_characters) >= charmax - ): - plural = "" if charmax == 1 else "s" - self.msg(f"You may only create a maximum of {charmax} character{plural}.") - return - from evennia.objects.models import ObjectDB - - typeclass = settings.BASE_CHARACTER_TYPECLASS - - if ObjectDB.objects.filter(db_typeclass_path=typeclass, db_key__iexact=key): - # check if this Character already exists. Note that we are only - # searching the base character typeclass here, not any child - # classes. - self.msg("|rA character named '|w%s|r' already exists.|n" % key) - return - - # create the character - start_location = ObjectDB.objects.get_id(settings.START_LOCATION) - default_home = ObjectDB.objects.get_id(settings.DEFAULT_HOME) - permissions = settings.PERMISSION_ACCOUNT_DEFAULT - new_character = create.create_object( - typeclass, key=key, location=start_location, home=default_home, permissions=permissions - ) - # only allow creator (and developers) to puppet this char - new_character.locks.add( - "puppet:id(%i) or pid(%i) or perm(Developer) or pperm(Developer);delete:id(%i) or perm(Admin)" - % (new_character.id, account.id, account.id) - ) - account.db._playable_characters.append(new_character) - if desc: - new_character.db.desc = desc - elif not new_character.db.desc: - new_character.db.desc = "This is a character." - self.msg( - "Created new character %s. Use |wic %s|n to enter the game as this character." - % (new_character.key, new_character.key) - ) - logger.log_sec( - "Character Created: %s (Caller: %s, IP: %s)." - % (new_character, account, self.session.address) - )
- - -
[docs]class CmdCharDelete(COMMAND_DEFAULT_CLASS): - """ - delete a character - this cannot be undone! - - Usage: - chardelete <charname> - - Permanently deletes one of your characters. - """ - - key = "chardelete" - locks = "cmd:pperm(Player)" - help_category = "General" - -
[docs] def func(self): - """delete the character""" - account = self.account - - if not self.args: - self.msg("Usage: chardelete <charactername>") - return - - # use the playable_characters list to search - match = [ - char - for char in utils.make_iter(account.db._playable_characters) - if char.key.lower() == self.args.lower() - ] - if not match: - self.msg("You have no such character to delete.") - return - elif len(match) > 1: - self.msg( - "Aborting - there are two characters with the same name. Ask an admin to delete the right one." - ) - return - else: # one match - from evennia.utils.evmenu import get_input - - def _callback(caller, callback_prompt, result): - if result.lower() == "yes": - # only take action - delobj = caller.ndb._char_to_delete - key = delobj.key - caller.db._playable_characters = [ - pc for pc in caller.db._playable_characters if pc != delobj - ] - delobj.delete() - self.msg("Character '%s' was permanently deleted." % key) - logger.log_sec( - "Character Deleted: %s (Caller: %s, IP: %s)." - % (key, account, self.session.address) - ) - else: - self.msg("Deletion was aborted.") - del caller.ndb._char_to_delete - - match = match[0] - account.ndb._char_to_delete = match - - # Return if caller has no permission to delete this - if not match.access(account, "delete"): - self.msg("You do not have permission to delete this character.") - return - - prompt = ( - "|rThis will permanently destroy '%s'. This cannot be undone.|n Continue yes/[no]?" - ) - get_input(account, prompt % match.key, _callback)
- - -
[docs]class CmdIC(COMMAND_DEFAULT_CLASS): - """ - control an object you have permission to puppet - - Usage: - ic <character> - - Go in-character (IC) as a given Character. - - This will attempt to "become" a different object assuming you have - the right to do so. Note that it's the ACCOUNT character that puppets - characters/objects and which needs to have the correct permission! - - You cannot become an object that is already controlled by another - account. In principle <character> can be any in-game object as long - as you the account have access right to puppet it. - """ - - key = "ic" - # lock must be all() for different puppeted objects to access it. - locks = "cmd:all()" - aliases = "puppet" - help_category = "General" - - # this is used by the parent - account_caller = True - -
[docs] def func(self): - """ - Main puppet method - """ - account = self.account - session = self.session - - new_character = None - character_candidates = [] - - if not self.args: - character_candidates = [account.db._last_puppet] if account.db._last_puppet else [] - if not character_candidates: - self.msg("Usage: ic <character>") - return - else: - # argument given - - if account.db._playable_characters: - # look at the playable_characters list first - character_candidates.extend( - account.search( - self.args, - candidates=account.db._playable_characters, - search_object=True, - quiet=True, - ) - ) - - if account.locks.check_lockstring(account, "perm(Builder)"): - # builders and higher should be able to puppet more than their - # playable characters. - if session.puppet: - # start by local search - this helps to avoid the user - # getting locked into their playable characters should one - # happen to be named the same as another. We replace the suggestion - # from playable_characters here - this allows builders to puppet objects - # with the same name as their playable chars should it be necessary - # (by going to the same location). - character_candidates = [ - char - for char in session.puppet.search(self.args, quiet=True) - if char.access(account, "puppet") - ] - if not character_candidates: - # fall back to global search only if Builder+ has no - # playable_characers in list and is not standing in a room - # with a matching char. - character_candidates.extend( - [ - char - for char in search.object_search(self.args) - if char.access(account, "puppet") - ] - ) - - # handle possible candidates - if not character_candidates: - self.msg("That is not a valid character choice.") - return - if len(character_candidates) > 1: - self.msg( - "Multiple targets with the same name:\n %s" - % ", ".join("%s(#%s)" % (obj.key, obj.id) for obj in character_candidates) - ) - return - else: - new_character = character_candidates[0] - - # do the puppet puppet - try: - account.puppet_object(session, new_character) - account.db._last_puppet = new_character - logger.log_sec( - "Puppet Success: (Caller: %s, Target: %s, IP: %s)." - % (account, new_character, self.session.address) - ) - except RuntimeError as exc: - self.msg("|rYou cannot become |C%s|n: %s" % (new_character.name, exc)) - logger.log_sec( - "Puppet Failed: %s (Caller: %s, Target: %s, IP: %s)." - % (exc, account, new_character, self.session.address) - )
- - -# note that this is inheriting from MuxAccountLookCommand, -# and as such has the .playable property. -
[docs]class CmdOOC(MuxAccountLookCommand): - """ - stop puppeting and go ooc - - Usage: - ooc - - Go out-of-character (OOC). - - This will leave your current character and put you in a incorporeal OOC state. - """ - - key = "ooc" - locks = "cmd:pperm(Player)" - aliases = "unpuppet" - help_category = "General" - - # this is used by the parent - account_caller = True - -
[docs] def func(self): - """Implement function""" - - account = self.account - session = self.session - - old_char = account.get_puppet(session) - if not old_char: - string = "You are already OOC." - self.msg(string) - return - - account.db._last_puppet = old_char - - # disconnect - try: - account.unpuppet_object(session) - self.msg("\n|GYou go OOC.|n\n") - - if _MULTISESSION_MODE < 2: - # only one character allowed - self.msg("You are out-of-character (OOC).\nUse |wic|n to get back into the game.") - return - - self.msg(account.at_look(target=self.playable, session=session)) - - except RuntimeError as exc: - self.msg("|rCould not unpuppet from |c%s|n: %s" % (old_char, exc))
- - -
[docs]class CmdSessions(COMMAND_DEFAULT_CLASS): - """ - check your connected session(s) - - Usage: - sessions - - Lists the sessions currently connected to your account. - - """ - - key = "sessions" - locks = "cmd:all()" - help_category = "General" - - # this is used by the parent - account_caller = True - -
[docs] def func(self): - """Implement function""" - account = self.account - sessions = account.sessions.all() - table = self.styled_table( - "|wsessid", "|wprotocol", "|whost", "|wpuppet/character", "|wlocation" - ) - for sess in sorted(sessions, key=lambda x: x.sessid): - char = account.get_puppet(sess) - table.add_row( - str(sess.sessid), - str(sess.protocol_key), - isinstance(sess.address, tuple) and sess.address[0] or sess.address, - char and str(char) or "None", - char and str(char.location) or "N/A", - ) - self.msg("|wYour current session(s):|n\n%s" % table)
- - -
[docs]class CmdWho(COMMAND_DEFAULT_CLASS): - """ - list who is currently online - - Usage: - who - doing - - Shows who is currently online. Doing is an alias that limits info - also for those with all permissions. - """ - - key = "who" - aliases = "doing" - locks = "cmd:all()" - - # this is used by the parent - account_caller = True - -
[docs] def func(self): - """ - Get all connected accounts by polling session. - """ - - account = self.account - session_list = SESSIONS.get_sessions() - - session_list = sorted(session_list, key=lambda o: o.account.key) - - if self.cmdstring == "doing": - show_session_data = False - else: - show_session_data = account.check_permstring("Developer") or account.check_permstring( - "Admins" - ) - - naccounts = SESSIONS.account_count() - if show_session_data: - # privileged info - table = self.styled_table( - "|wAccount Name", - "|wOn for", - "|wIdle", - "|wPuppeting", - "|wRoom", - "|wCmds", - "|wProtocol", - "|wHost", - ) - for session in session_list: - if not session.logged_in: - continue - delta_cmd = time.time() - session.cmd_last_visible - delta_conn = time.time() - session.conn_time - session_account = session.get_account() - puppet = session.get_puppet() - location = puppet.location.key if puppet and puppet.location else "None" - table.add_row( - utils.crop(session_account.get_display_name(account), width=25), - utils.time_format(delta_conn, 0), - utils.time_format(delta_cmd, 1), - utils.crop(puppet.get_display_name(account) if puppet else "None", width=25), - utils.crop(location, width=25), - session.cmd_total, - session.protocol_key, - isinstance(session.address, tuple) and session.address[0] or session.address, - ) - else: - # unprivileged - table = self.styled_table("|wAccount name", "|wOn for", "|wIdle") - for session in session_list: - if not session.logged_in: - continue - delta_cmd = time.time() - session.cmd_last_visible - delta_conn = time.time() - session.conn_time - session_account = session.get_account() - table.add_row( - utils.crop(session_account.get_display_name(account), width=25), - utils.time_format(delta_conn, 0), - utils.time_format(delta_cmd, 1), - ) - is_one = naccounts == 1 - self.msg( - "|wAccounts:|n\n%s\n%s unique account%s logged in." - % (table, "One" if is_one else naccounts, "" if is_one else "s") - )
- - -
[docs]class CmdOption(COMMAND_DEFAULT_CLASS): - """ - Set an account option - - Usage: - option[/save] [name = value] - - Switches: - save - Save the current option settings for future logins. - clear - Clear the saved options. - - This command allows for viewing and setting client interface - settings. Note that saved options may not be able to be used if - later connecting with a client with different capabilities. - - - """ - - key = "option" - aliases = "options" - switch_options = ("save", "clear") - locks = "cmd:all()" - - # this is used by the parent - account_caller = True - -
[docs] def func(self): - """ - Implements the command - """ - if self.session is None: - return - - flags = self.session.protocol_flags - - # Display current options - if not self.args: - # list the option settings - - if "save" in self.switches: - # save all options - self.caller.db._saved_protocol_flags = flags - self.msg("|gSaved all options. Use option/clear to remove.|n") - if "clear" in self.switches: - # clear all saves - self.caller.db._saved_protocol_flags = {} - self.msg("|gCleared all saved options.") - - options = dict(flags) # make a copy of the flag dict - saved_options = dict(self.caller.attributes.get("_saved_protocol_flags", default={})) - - if "SCREENWIDTH" in options: - if len(options["SCREENWIDTH"]) == 1: - options["SCREENWIDTH"] = options["SCREENWIDTH"][0] - else: - options["SCREENWIDTH"] = " \n".join( - "%s : %s" % (screenid, size) - for screenid, size in options["SCREENWIDTH"].items() - ) - if "SCREENHEIGHT" in options: - if len(options["SCREENHEIGHT"]) == 1: - options["SCREENHEIGHT"] = options["SCREENHEIGHT"][0] - else: - options["SCREENHEIGHT"] = " \n".join( - "%s : %s" % (screenid, size) - for screenid, size in options["SCREENHEIGHT"].items() - ) - options.pop("TTYPE", None) - - header = ("Name", "Value", "Saved") if saved_options else ("Name", "Value") - table = self.styled_table(*header) - for key in sorted(options): - row = [key, options[key]] - if saved_options: - saved = " |YYes|n" if key in saved_options else "" - changed = ( - "|y*|n" if key in saved_options and flags[key] != saved_options[key] else "" - ) - row.append("%s%s" % (saved, changed)) - table.add_row(*row) - self.msg("|wClient settings (%s):|n\n%s|n" % (self.session.protocol_key, table)) - - return - - if not self.rhs: - self.msg("Usage: option [name = [value]]") - return - - # Try to assign new values - - def validate_encoding(new_encoding): - # helper: change encoding - try: - codecs_lookup(new_encoding) - except LookupError: - raise RuntimeError("The encoding '|w%s|n' is invalid. " % new_encoding) - return val - - def validate_size(new_size): - return {0: int(new_size)} - - def validate_bool(new_bool): - return True if new_bool.lower() in ("true", "on", "1") else False - - def update(new_name, new_val, validator): - # helper: update property and report errors - try: - old_val = flags.get(new_name, False) - new_val = validator(new_val) - if old_val == new_val: - self.msg("Option |w%s|n was kept as '|w%s|n'." % (new_name, old_val)) - else: - flags[new_name] = new_val - self.msg( - "Option |w%s|n was changed from '|w%s|n' to '|w%s|n'." - % (new_name, old_val, new_val) - ) - return {new_name: new_val} - except Exception as err: - self.msg("|rCould not set option |w%s|r:|n %s" % (new_name, err)) - return False - - validators = { - "ANSI": validate_bool, - "CLIENTNAME": utils.to_str, - "ENCODING": validate_encoding, - "MCCP": validate_bool, - "NOGOAHEAD": validate_bool, - "MXP": validate_bool, - "NOCOLOR": validate_bool, - "NOPKEEPALIVE": validate_bool, - "OOB": validate_bool, - "RAW": validate_bool, - "SCREENHEIGHT": validate_size, - "SCREENWIDTH": validate_size, - "SCREENREADER": validate_bool, - "TERM": utils.to_str, - "UTF-8": validate_bool, - "XTERM256": validate_bool, - "INPUTDEBUG": validate_bool, - "FORCEDENDLINE": validate_bool, - "LOCALECHO": validate_bool, - } - - name = self.lhs.upper() - val = self.rhs.strip() - optiondict = False - if val and name in validators: - optiondict = update(name, val, validators[name]) - else: - self.msg("|rNo option named '|w%s|r'." % name) - if optiondict: - # a valid setting - if "save" in self.switches: - # save this option only - saved_options = self.account.attributes.get("_saved_protocol_flags", default={}) - saved_options.update(optiondict) - self.account.attributes.add("_saved_protocol_flags", saved_options) - for key in optiondict: - self.msg("|gSaved option %s.|n" % key) - if "clear" in self.switches: - # clear this save - for key in optiondict: - self.account.attributes.get("_saved_protocol_flags", {}).pop(key, None) - self.msg("|gCleared saved %s." % key) - self.session.update_flags(**optiondict)
- - -
[docs]class CmdPassword(COMMAND_DEFAULT_CLASS): - """ - change your password - - Usage: - password <old password> = <new password> - - Changes your password. Make sure to pick a safe one. - """ - - key = "password" - locks = "cmd:pperm(Player)" - - # this is used by the parent - account_caller = True - -
[docs] def func(self): - """hook function.""" - - account = self.account - if not self.rhs: - self.msg("Usage: password <oldpass> = <newpass>") - return - oldpass = self.lhslist[0] # Both of these are - newpass = self.rhslist[0] # already stripped by parse() - - # Validate password - validated, error = account.validate_password(newpass) - - if not account.check_password(oldpass): - self.msg("The specified old password isn't correct.") - elif not validated: - errors = [e for suberror in error.messages for e in error.messages] - string = "\n".join(errors) - self.msg(string) - else: - account.set_password(newpass) - account.save() - self.msg("Password changed.") - logger.log_sec( - "Password Changed: %s (Caller: %s, IP: %s)." - % (account, account, self.session.address) - )
- - -
[docs]class CmdQuit(COMMAND_DEFAULT_CLASS): - """ - quit the game - - Usage: - quit - - Switch: - all - disconnect all connected sessions - - Gracefully disconnect your current session from the - game. Use the /all switch to disconnect from all sessions. - """ - - key = "quit" - switch_options = ("all",) - locks = "cmd:all()" - - # this is used by the parent - account_caller = True - -
[docs] def func(self): - """hook function""" - account = self.account - - if "all" in self.switches: - account.msg( - "|RQuitting|n all sessions. Hope to see you soon again.", session=self.session - ) - reason = "quit/all" - for session in account.sessions.all(): - account.disconnect_session_from_account(session, reason) - else: - nsess = len(account.sessions.all()) - reason = "quit" - if nsess == 2: - account.msg("|RQuitting|n. One session is still connected.", session=self.session) - elif nsess > 2: - account.msg( - "|RQuitting|n. %i sessions are still connected." % (nsess - 1), - session=self.session, - ) - else: - # we are quitting the last available session - account.msg("|RQuitting|n. Hope to see you again, soon.", session=self.session) - account.disconnect_session_from_account(self.session, reason)
- - -
[docs]class CmdColorTest(COMMAND_DEFAULT_CLASS): - """ - testing which colors your client support - - Usage: - color ansi | xterm256 - - Prints a color map along with in-mud color codes to use to produce - them. It also tests what is supported in your client. Choices are - 16-color ansi (supported in most muds) or the 256-color xterm256 - standard. No checking is done to determine your client supports - color - if not you will see rubbish appear. - """ - - key = "color" - locks = "cmd:all()" - help_category = "General" - - # this is used by the parent - account_caller = True - - # the slices of the ANSI_PARSER lists to use for retrieving the - # relevant color tags to display. Replace if using another schema. - # This command can only show one set of markup. - slice_bright_fg = slice(7, 15) # from ANSI_PARSER.ansi_map - slice_dark_fg = slice(15, 23) # from ANSI_PARSER.ansi_map - slice_dark_bg = slice(-8, None) # from ANSI_PARSER.ansi_map - slice_bright_bg = slice(None, None) # from ANSI_PARSER.ansi_xterm256_bright_bg_map - -
[docs] def table_format(self, table): - """ - Helper method to format the ansi/xterm256 tables. - Takes a table of columns [[val,val,...],[val,val,...],...] - """ - if not table: - return [[]] - - extra_space = 1 - max_widths = [max([len(str(val)) for val in col]) for col in table] - ftable = [] - for irow in range(len(table[0])): - ftable.append( - [ - str(col[irow]).ljust(max_widths[icol]) + " " * extra_space - for icol, col in enumerate(table) - ] - ) - return ftable
- -
[docs] def func(self): - """Show color tables""" - - if self.args.startswith("a"): - # show ansi 16-color table - from evennia.utils import ansi - - ap = ansi.ANSI_PARSER - # ansi colors - # show all ansi color-related codes - bright_fg = [ - "%s%s|n" % (code, code.replace("|", "||")) - for code, _ in ap.ansi_map[self.slice_bright_fg] - ] - dark_fg = [ - "%s%s|n" % (code, code.replace("|", "||")) - for code, _ in ap.ansi_map[self.slice_dark_fg] - ] - dark_bg = [ - "%s%s|n" % (code.replace("\\", ""), code.replace("|", "||").replace("\\", "")) - for code, _ in ap.ansi_map[self.slice_dark_bg] - ] - bright_bg = [ - "%s%s|n" % (code.replace("\\", ""), code.replace("|", "||").replace("\\", "")) - for code, _ in ap.ansi_xterm256_bright_bg_map[self.slice_bright_bg] - ] - dark_fg.extend(["" for _ in range(len(bright_fg) - len(dark_fg))]) - table = utils.format_table([bright_fg, dark_fg, bright_bg, dark_bg]) - string = "ANSI colors:" - for row in table: - string += "\n " + " ".join(row) - self.msg(string) - self.msg( - "||X : black. ||/ : return, ||- : tab, ||_ : space, ||* : invert, ||u : underline\n" - "To combine background and foreground, add background marker last, e.g. ||r||[B.\n" - "Note: bright backgrounds like ||[r requires your client handling Xterm256 colors." - ) - - elif self.args.startswith("x"): - # show xterm256 table - table = [[], [], [], [], [], [], [], [], [], [], [], []] - for ir in range(6): - for ig in range(6): - for ib in range(6): - # foreground table - table[ir].append("|%i%i%i%s|n" % (ir, ig, ib, "||%i%i%i" % (ir, ig, ib))) - # background table - table[6 + ir].append( - "|%i%i%i|[%i%i%i%s|n" - % (5 - ir, 5 - ig, 5 - ib, ir, ig, ib, "||[%i%i%i" % (ir, ig, ib)) - ) - table = self.table_format(table) - string = "Xterm256 colors (if not all hues show, your client might not report that it can handle xterm256):" - string += "\n" + "\n".join("".join(row) for row in table) - table = [[], [], [], [], [], [], [], [], [], [], [], []] - for ibatch in range(4): - for igray in range(6): - letter = chr(97 + (ibatch * 6 + igray)) - inverse = chr(122 - (ibatch * 6 + igray)) - table[0 + igray].append("|=%s%s |n" % (letter, "||=%s" % letter)) - table[6 + igray].append("|=%s|[=%s%s |n" % (inverse, letter, "||[=%s" % letter)) - for igray in range(6): - # the last row (y, z) has empty columns - if igray < 2: - letter = chr(121 + igray) - inverse = chr(98 - igray) - fg = "|=%s%s |n" % (letter, "||=%s" % letter) - bg = "|=%s|[=%s%s |n" % (inverse, letter, "||[=%s" % letter) - else: - fg, bg = " ", " " - table[0 + igray].append(fg) - table[6 + igray].append(bg) - table = self.table_format(table) - string += "\n" + "\n".join("".join(row) for row in table) - self.msg(string) - else: - # malformed input - self.msg("Usage: color ansi||xterm256")
- - -
[docs]class CmdQuell(COMMAND_DEFAULT_CLASS): - """ - use character's permissions instead of account's - - Usage: - quell - unquell - - Normally the permission level of the Account is used when puppeting a - Character/Object to determine access. This command will switch the lock - system to make use of the puppeted Object's permissions instead. This is - useful mainly for testing. - Hierarchical permission quelling only work downwards, thus an Account cannot - use a higher-permission Character to escalate their permission level. - Use the unquell command to revert back to normal operation. - """ - - key = "quell" - aliases = ["unquell"] - locks = "cmd:pperm(Player)" - help_category = "General" - - # this is used by the parent - account_caller = True - - def _recache_locks(self, account): - """Helper method to reset the lockhandler on an already puppeted object""" - if self.session: - char = self.session.puppet - if char: - # we are already puppeting an object. We need to reset - # the lock caches (otherwise the superuser status change - # won't be visible until repuppet) - char.locks.reset() - account.locks.reset() - -
[docs] def func(self): - """Perform the command""" - account = self.account - permstr = ( - account.is_superuser - and " (superuser)" - or "(%s)" % (", ".join(account.permissions.all())) - ) - if self.cmdstring in ("unquell", "unquell"): - if not account.attributes.get("_quell"): - self.msg("Already using normal Account permissions %s." % permstr) - else: - account.attributes.remove("_quell") - self.msg("Account permissions %s restored." % permstr) - else: - if account.attributes.get("_quell"): - self.msg("Already quelling Account %s permissions." % permstr) - return - account.attributes.add("_quell", True) - puppet = self.session.puppet if self.session else None - if puppet: - cpermstr = "(%s)" % ", ".join(puppet.permissions.all()) - cpermstr = "Quelling to current puppet's permissions %s." % cpermstr - cpermstr += ( - "\n(Note: If this is higher than Account permissions %s," - " the lowest of the two will be used.)" % permstr - ) - cpermstr += "\nUse unquell to return to normal permission usage." - self.msg(cpermstr) - else: - self.msg("Quelling Account permissions%s. Use unquell to get them back." % permstr) - self._recache_locks(account)
- - -
[docs]class CmdStyle(COMMAND_DEFAULT_CLASS): - """ - In-game style options - - Usage: - style - style <option> = <value> - - Configure stylings for in-game display elements like table borders, help - entriest etc. Use without arguments to see all available options. - - """ - - key = "style" - switch_options = ["clear"] - -
[docs] def func(self): - if not self.args: - self.list_styles() - return - self.set()
- -
[docs] def list_styles(self): - table = self.styled_table("Option", "Description", "Type", "Value", width=78) - for op_key in self.account.options.options_dict.keys(): - op_found = self.account.options.get(op_key, return_obj=True) - table.add_row( - op_key, op_found.description, op_found.__class__.__name__, op_found.display() - ) - self.msg(str(table))
- -
[docs] def set(self): - try: - result = self.account.options.set(self.lhs, self.rhs) - except ValueError as e: - self.msg(str(e)) - return - self.msg("Style %s set to %s" % (self.lhs, result))
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/commands/default/admin.html b/docs/0.9.5/_modules/evennia/commands/default/admin.html deleted file mode 100644 index c1a4455e28..0000000000 --- a/docs/0.9.5/_modules/evennia/commands/default/admin.html +++ /dev/null @@ -1,710 +0,0 @@ - - - - - - - - evennia.commands.default.admin — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.commands.default.admin

-"""
-
-Admin commands
-
-"""
-
-import time
-import re
-from django.conf import settings
-from evennia.server.sessionhandler import SESSIONS
-from evennia.server.models import ServerConfig
-from evennia.utils import evtable, logger, search, class_from_module
-
-COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
-
-PERMISSION_HIERARCHY = [p.lower() for p in settings.PERMISSION_HIERARCHY]
-
-# limit members for API inclusion
-__all__ = (
-    "CmdBoot",
-    "CmdBan",
-    "CmdUnban",
-    "CmdEmit",
-    "CmdNewPassword",
-    "CmdPerm",
-    "CmdWall",
-    "CmdForce",
-)
-
-
-
[docs]class CmdBoot(COMMAND_DEFAULT_CLASS): - """ - kick an account from the server. - - Usage - boot[/switches] <account obj> [: reason] - - Switches: - quiet - Silently boot without informing account - sid - boot by session id instead of name or dbref - - Boot an account object from the server. If a reason is - supplied it will be echoed to the user unless /quiet is set. - """ - - key = "boot" - switch_options = ("quiet", "sid") - locks = "cmd:perm(boot) or perm(Admin)" - help_category = "Admin" - -
[docs] def func(self): - """Implementing the function""" - caller = self.caller - args = self.args - - if not args: - caller.msg("Usage: boot[/switches] <account> [:reason]") - return - - if ":" in args: - args, reason = [a.strip() for a in args.split(":", 1)] - else: - args, reason = args, "" - - boot_list = [] - - if "sid" in self.switches: - # Boot a particular session id. - sessions = SESSIONS.get_sessions(True) - for sess in sessions: - # Find the session with the matching session id. - if sess.sessid == int(args): - boot_list.append(sess) - break - else: - # Boot by account object - pobj = search.account_search(args) - if not pobj: - caller.msg("Account %s was not found." % args) - return - pobj = pobj[0] - if not pobj.access(caller, "boot"): - string = "You don't have the permission to boot %s." % (pobj.key,) - caller.msg(string) - return - # we have a bootable object with a connected user - matches = SESSIONS.sessions_from_account(pobj) - for match in matches: - boot_list.append(match) - - if not boot_list: - caller.msg("No matching sessions found. The Account does not seem to be online.") - return - - # Carry out the booting of the sessions in the boot list. - - feedback = None - if "quiet" not in self.switches: - feedback = "You have been disconnected by %s.\n" % caller.name - if reason: - feedback += "\nReason given: %s" % reason - - for session in boot_list: - session.msg(feedback) - session.account.disconnect_session_from_account(session) - - if pobj and boot_list: - logger.log_sec( - "Booted: %s (Reason: %s, Caller: %s, IP: %s)." - % (pobj, reason, caller, self.session.address) - )
- - -# regex matching IP addresses with wildcards, eg. 233.122.4.* -IPREGEX = re.compile(r"[0-9*]{1,3}\.[0-9*]{1,3}\.[0-9*]{1,3}\.[0-9*]{1,3}") - - -def list_bans(cmd, banlist): - """ - Helper function to display a list of active bans. Input argument - is the banlist read into the two commands ban and unban below. - - Args: - cmd (Command): Instance of the Ban command. - banlist (list): List of bans to list. - """ - if not banlist: - return "No active bans were found." - - table = cmd.styled_table("|wid", "|wname/ip", "|wdate", "|wreason") - for inum, ban in enumerate(banlist): - table.add_row(str(inum + 1), ban[0] and ban[0] or ban[1], ban[3], ban[4]) - return "|wActive bans:|n\n%s" % table - - -
[docs]class CmdBan(COMMAND_DEFAULT_CLASS): - """ - ban an account from the server - - Usage: - ban [<name or ip> [: reason]] - - Without any arguments, shows numbered list of active bans. - - This command bans a user from accessing the game. Supply an optional - reason to be able to later remember why the ban was put in place. - - It is often preferable to ban an account from the server than to - delete an account with accounts/delete. If banned by name, that account - account can no longer be logged into. - - IP (Internet Protocol) address banning allows blocking all access - from a specific address or subnet. Use an asterisk (*) as a - wildcard. - - Examples: - ban thomas - ban account 'thomas' - ban/ip 134.233.2.111 - ban specific ip address - ban/ip 134.233.2.* - ban all in a subnet - ban/ip 134.233.*.* - even wider ban - - A single IP filter can be easy to circumvent by changing computers - or requesting a new IP address. Setting a wide IP block filter with - wildcards might be tempting, but remember that it may also - accidentally block innocent users connecting from the same country - or region. - - """ - - key = "ban" - aliases = ["bans"] - locks = "cmd:perm(ban) or perm(Developer)" - help_category = "Admin" - -
[docs] def func(self): - """ - Bans are stored in a serverconf db object as a list of - dictionaries: - [ (name, ip, ipregex, date, reason), - (name, ip, ipregex, date, reason),... ] - where name and ip are set by the user and are shown in - lists. ipregex is a converted form of ip where the * is - replaced by an appropriate regex pattern for fast - matching. date is the time stamp the ban was instigated and - 'reason' is any optional info given to the command. Unset - values in each tuple is set to the empty string. - """ - banlist = ServerConfig.objects.conf("server_bans") - if not banlist: - banlist = [] - - if not self.args or ( - self.switches and not any(switch in ("ip", "name") for switch in self.switches) - ): - self.caller.msg(list_bans(self, banlist)) - return - - now = time.ctime() - reason = "" - if ":" in self.args: - ban, reason = self.args.rsplit(":", 1) - else: - ban = self.args - ban = ban.lower() - ipban = IPREGEX.findall(ban) - if not ipban: - # store as name - typ = "Name" - bantup = (ban, "", "", now, reason) - else: - # an ip address. - typ = "IP" - ban = ipban[0] - # replace * with regex form and compile it - ipregex = ban.replace(".", "\.") - ipregex = ipregex.replace("*", "[0-9]{1,3}") - ipregex = re.compile(r"%s" % ipregex) - bantup = ("", ban, ipregex, now, reason) - - ret = yield(f"Are you sure you want to {typ}-ban '|w{ban}|n' [Y]/N?") - if str(ret).lower() in ("no", "n"): - self.caller.msg("Aborted.") - return - - # save updated banlist - banlist.append(bantup) - ServerConfig.objects.conf("server_bans", banlist) - self.caller.msg(f"{typ}-ban '|w{ban}|n' was added. Use |wunban|n to reinstate.") - logger.log_sec( - "Banned {typ}: {ban.strip()} (Caller: {self.caller}, IP: {self.session.address})." - )
- - -
[docs]class CmdUnban(COMMAND_DEFAULT_CLASS): - """ - remove a ban from an account - - Usage: - unban <banid> - - This will clear an account name/ip ban previously set with the ban - command. Use this command without an argument to view a numbered - list of bans. Use the numbers in this list to select which one to - unban. - - """ - - key = "unban" - locks = "cmd:perm(unban) or perm(Developer)" - help_category = "Admin" - -
[docs] def func(self): - """Implement unbanning""" - - banlist = ServerConfig.objects.conf("server_bans") - - if not self.args: - self.caller.msg(list_bans(self, banlist)) - return - - try: - num = int(self.args) - except Exception: - self.caller.msg("You must supply a valid ban id to clear.") - return - - if not banlist: - self.caller.msg("There are no bans to clear.") - elif not (0 < num < len(banlist) + 1): - self.caller.msg("Ban id |w%s|x was not found." % self.args) - else: - # all is ok, ask, then clear ban - ban = banlist[num - 1] - value = (" ".join([s for s in ban[:2]])).strip() - - ret = yield(f"Are you sure you want to unban {num}: '|w{value}|n' [Y]/N?") - if str(ret).lower() in ("n", "no"): - self.caller.msg("Aborted.") - return - - del banlist[num - 1] - ServerConfig.objects.conf("server_bans", banlist) - self.caller.msg(f"Cleared ban {num}: '{value}'") - logger.log_sec( - "Unbanned: {value.strip()} (Caller: {self.caller}, IP: {self.session.address})." - )
- - -
[docs]class CmdEmit(COMMAND_DEFAULT_CLASS): - """ - admin command for emitting message to multiple objects - - Usage: - emit[/switches] [<obj>, <obj>, ... =] <message> - remit [<obj>, <obj>, ... =] <message> - pemit [<obj>, <obj>, ... =] <message> - - Switches: - room - limit emits to rooms only (default) - accounts - limit emits to accounts only - contents - send to the contents of matched objects too - - Emits a message to the selected objects or to - your immediate surroundings. If the object is a room, - send to its contents. remit and pemit are just - limited forms of emit, for sending to rooms and - to accounts respectively. - """ - - key = "emit" - aliases = ["pemit", "remit"] - switch_options = ("room", "accounts", "contents") - locks = "cmd:perm(emit) or perm(Builder)" - help_category = "Admin" - -
[docs] def func(self): - """Implement the command""" - - caller = self.caller - args = self.args - - if not args: - string = "Usage: " - string += "\nemit[/switches] [<obj>, <obj>, ... =] <message>" - string += "\nremit [<obj>, <obj>, ... =] <message>" - string += "\npemit [<obj>, <obj>, ... =] <message>" - caller.msg(string) - return - - rooms_only = "rooms" in self.switches - accounts_only = "accounts" in self.switches - send_to_contents = "contents" in self.switches - - # we check which command was used to force the switches - if self.cmdstring == "remit": - rooms_only = True - send_to_contents = True - elif self.cmdstring == "pemit": - accounts_only = True - - if not self.rhs: - message = self.args - objnames = [caller.location.key] - else: - message = self.rhs - objnames = self.lhslist - - # send to all objects - for objname in objnames: - obj = caller.search(objname, global_search=True) - if not obj: - return - if rooms_only and obj.location is not None: - caller.msg("%s is not a room. Ignored." % objname) - continue - if accounts_only and not obj.has_account: - caller.msg("%s has no active account. Ignored." % objname) - continue - if obj.access(caller, "tell"): - obj.msg(message) - if send_to_contents and hasattr(obj, "msg_contents"): - obj.msg_contents(message) - caller.msg("Emitted to %s and contents:\n%s" % (objname, message)) - else: - caller.msg("Emitted to %s:\n%s" % (objname, message)) - else: - caller.msg("You are not allowed to emit to %s." % objname)
- - -
[docs]class CmdNewPassword(COMMAND_DEFAULT_CLASS): - """ - change the password of an account - - Usage: - userpassword <user obj> = <new password> - - Set an account's password. - """ - - key = "userpassword" - locks = "cmd:perm(newpassword) or perm(Admin)" - help_category = "Admin" - -
[docs] def func(self): - """Implement the function.""" - - caller = self.caller - - if not self.rhs: - self.msg("Usage: userpassword <user obj> = <new password>") - return - - # the account search also matches 'me' etc. - account = caller.search_account(self.lhs) - if not account: - return - - newpass = self.rhs - - # Validate password - validated, error = account.validate_password(newpass) - if not validated: - errors = [e for suberror in error.messages for e in error.messages] - string = "\n".join(errors) - caller.msg(string) - return - - account.set_password(newpass) - account.save() - self.msg("%s - new password set to '%s'." % (account.name, newpass)) - if account.character != caller: - account.msg("%s has changed your password to '%s'." % (caller.name, newpass)) - logger.log_sec( - "Password Changed: %s (Caller: %s, IP: %s)." % (account, caller, self.session.address) - )
- - -
[docs]class CmdPerm(COMMAND_DEFAULT_CLASS): - """ - set the permissions of an account/object - - Usage: - perm[/switch] <object> [= <permission>[,<permission>,...]] - perm[/switch] *<account> [= <permission>[,<permission>,...]] - - Switches: - del - delete the given permission from <object> or <account>. - account - set permission on an account (same as adding * to name) - - This command sets/clears individual permission strings on an object - or account. If no permission is given, list all permissions on <object>. - """ - - key = "perm" - aliases = "setperm" - switch_options = ("del", "account") - locks = "cmd:perm(perm) or perm(Developer)" - help_category = "Admin" - -
[docs] def func(self): - """Implement function""" - - caller = self.caller - switches = self.switches - lhs, rhs = self.lhs, self.rhs - - if not self.args: - string = "Usage: perm[/switch] object [ = permission, permission, ...]" - caller.msg(string) - return - - accountmode = "account" in self.switches or lhs.startswith("*") - lhs = lhs.lstrip("*") - - if accountmode: - obj = caller.search_account(lhs) - else: - obj = caller.search(lhs, global_search=True) - if not obj: - return - - if not rhs: - if not obj.access(caller, "examine"): - caller.msg("You are not allowed to examine this object.") - return - - string = "Permissions on |w%s|n: " % obj.key - if not obj.permissions.all(): - string += "<None>" - else: - string += ", ".join(obj.permissions.all()) - if ( - hasattr(obj, "account") - and hasattr(obj.account, "is_superuser") - and obj.account.is_superuser - ): - string += "\n(... but this object is currently controlled by a SUPERUSER! " - string += "All access checks are passed automatically.)" - caller.msg(string) - return - - # we supplied an argument on the form obj = perm - locktype = "edit" if accountmode else "control" - if not obj.access(caller, locktype): - caller.msg( - "You are not allowed to edit this %s's permissions." - % ("account" if accountmode else "object") - ) - return - - caller_result = [] - target_result = [] - if "del" in switches: - # delete the given permission(s) from object. - for perm in self.rhslist: - obj.permissions.remove(perm) - if obj.permissions.get(perm): - caller_result.append( - "\nPermissions %s could not be removed from %s." % (perm, obj.name) - ) - else: - caller_result.append( - "\nPermission %s removed from %s (if they existed)." % (perm, obj.name) - ) - target_result.append( - "\n%s revokes the permission(s) %s from you." % (caller.name, perm) - ) - logger.log_sec( - "Permissions Deleted: %s, %s (Caller: %s, IP: %s)." - % (perm, obj, caller, self.session.address) - ) - else: - # add a new permission - permissions = obj.permissions.all() - - for perm in self.rhslist: - - # don't allow to set a permission higher in the hierarchy than - # the one the caller has (to prevent self-escalation) - if perm.lower() in PERMISSION_HIERARCHY and not obj.locks.check_lockstring( - caller, "dummy:perm(%s)" % perm - ): - caller.msg( - "You cannot assign a permission higher than the one you have yourself." - ) - return - - if perm in permissions: - caller_result.append( - "\nPermission '%s' is already defined on %s." % (perm, obj.name) - ) - else: - obj.permissions.add(perm) - plystring = "the Account" if accountmode else "the Object/Character" - caller_result.append( - "\nPermission '%s' given to %s (%s)." % (perm, obj.name, plystring) - ) - target_result.append( - "\n%s gives you (%s, %s) the permission '%s'." - % (caller.name, obj.name, plystring, perm) - ) - logger.log_sec( - "Permissions Added: %s, %s (Caller: %s, IP: %s)." - % (obj, perm, caller, self.session.address) - ) - - caller.msg("".join(caller_result).strip()) - if target_result: - obj.msg("".join(target_result).strip())
- - -
[docs]class CmdWall(COMMAND_DEFAULT_CLASS): - """ - make an announcement to all - - Usage: - wall <message> - - Announces a message to all connected sessions - including all currently unlogged in. - """ - - key = "wall" - locks = "cmd:perm(wall) or perm(Admin)" - help_category = "Admin" - -
[docs] def func(self): - """Implements command""" - if not self.args: - self.caller.msg("Usage: wall <message>") - return - message = '%s shouts "%s"' % (self.caller.name, self.args) - self.msg("Announcing to all connected sessions ...") - SESSIONS.announce_all(message)
- - -
[docs]class CmdForce(COMMAND_DEFAULT_CLASS): - """ - forces an object to execute a command - - Usage: - force <object>=<command string> - - Example: - force bob=get stick - """ - - key = "force" - locks = "cmd:perm(spawn) or perm(Builder)" - help_category = "Building" - perm_used = "edit" - -
[docs] def func(self): - """Implements the force command""" - if not self.lhs or not self.rhs: - self.caller.msg("You must provide a target and a command string to execute.") - return - targ = self.caller.search(self.lhs) - if not targ: - return - if not targ.access(self.caller, self.perm_used): - self.caller.msg("You don't have permission to force them to execute commands.") - return - targ.execute_cmd(self.rhs) - self.caller.msg("You have forced %s to: %s" % (targ, self.rhs))
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/commands/default/batchprocess.html b/docs/0.9.5/_modules/evennia/commands/default/batchprocess.html deleted file mode 100644 index 89934fd180..0000000000 --- a/docs/0.9.5/_modules/evennia/commands/default/batchprocess.html +++ /dev/null @@ -1,926 +0,0 @@ - - - - - - - - evennia.commands.default.batchprocess — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.commands.default.batchprocess

-"""
-Batch processors
-
-These commands implements the 'batch-command' and 'batch-code'
-processors, using the functionality in evennia.utils.batchprocessors.
-They allow for offline world-building.
-
-Batch-command is the simpler system. This reads a file (*.ev)
-containing a list of in-game commands and executes them in sequence as
-if they had been entered in the game (including permission checks
-etc).
-
-Batch-code is a full-fledged python code interpreter that reads blocks
-of python code (*.py) and executes them in sequence. This allows for
-much more power than Batch-command, but requires knowing Python and
-the Evennia API.  It is also a severe security risk and should
-therefore always be limited to superusers only.
-
-"""
-import re
-
-from django.conf import settings
-from evennia.utils.batchprocessors import BATCHCMD, BATCHCODE
-from evennia.commands.cmdset import CmdSet
-from evennia.utils import logger, utils
-
-
-_RE_COMMENT = re.compile(r"^#.*?$", re.MULTILINE + re.DOTALL)
-_RE_CODE_START = re.compile(r"^# batchcode code:", re.MULTILINE)
-_COMMAND_DEFAULT_CLASS = utils.class_from_module(settings.COMMAND_DEFAULT_CLASS)
-
-# limit symbols for API inclusion
-__all__ = ("CmdBatchCommands", "CmdBatchCode")
-
-_HEADER_WIDTH = 70
-_UTF8_ERROR = """
- |rDecode error in '%s'.|n
-
- This file contains non-ascii character(s). This is common if you
- wrote some input in a language that has more letters and special
- symbols than English; such as accents or umlauts.  This is usually
- fine and fully supported! But for Evennia to know how to decode such
- characters in a universal way, the batchfile must be saved with the
- international 'UTF-8' encoding. This file is not.
-
- Please re-save the batchfile with the UTF-8 encoding (refer to the
- documentation of your text editor on how to do this, or switch to a
- better featured one) and try again.
-
- Error reported was: '%s'
-"""
-
-
-# -------------------------------------------------------------
-# Helper functions
-# -------------------------------------------------------------
-
-
-def format_header(caller, entry):
-    """
-    Formats a header
-    """
-    width = _HEADER_WIDTH - 10
-    # strip all comments for the header
-    if caller.ndb.batch_batchmode != "batch_commands":
-        # only do cleanup for  batchcode
-        entry = _RE_CODE_START.split(entry, 1)[1]
-        entry = _RE_COMMENT.sub("", entry).strip()
-    header = utils.crop(entry, width=width)
-    ptr = caller.ndb.batch_stackptr + 1
-    stacklen = len(caller.ndb.batch_stack)
-    header = "|w%02i/%02i|G: %s|n" % (ptr, stacklen, header)
-    # add extra space to the side for padding.
-    header = "%s%s" % (header, " " * (width - len(header)))
-    header = header.replace("\n", "\\n")
-
-    return header
-
-
-def format_code(entry):
-    """
-    Formats the viewing of code and errors
-    """
-    code = ""
-    for line in entry.split("\n"):
-        code += "\n|G>>>|n %s" % line
-    return code.strip()
-
-
-def batch_cmd_exec(caller):
-    """
-    Helper function for executing a single batch-command entry
-    """
-    ptr = caller.ndb.batch_stackptr
-    stack = caller.ndb.batch_stack
-    command = stack[ptr]
-    caller.msg(format_header(caller, command))
-    try:
-        caller.execute_cmd(command)
-    except Exception:
-        logger.log_trace()
-        return False
-    return True
-
-
-def batch_code_exec(caller):
-    """
-    Helper function for executing a single batch-code entry
-    """
-    ptr = caller.ndb.batch_stackptr
-    stack = caller.ndb.batch_stack
-    debug = caller.ndb.batch_debug
-    code = stack[ptr]
-
-    caller.msg(format_header(caller, code))
-    err = BATCHCODE.code_exec(code, extra_environ={"caller": caller}, debug=debug)
-    if err:
-        caller.msg(format_code(err))
-        return False
-    return True
-
-
-def step_pointer(caller, step=1):
-    """
-    Step in stack, returning the item located.
-
-    stackptr - current position in stack
-    stack - the stack of units
-    step - how many steps to move from stackptr
-    """
-    ptr = caller.ndb.batch_stackptr
-    stack = caller.ndb.batch_stack
-    nstack = len(stack)
-    if ptr + step <= 0:
-        caller.msg("|RBeginning of batch file.")
-    if ptr + step >= nstack:
-        caller.msg("|REnd of batch file.")
-    caller.ndb.batch_stackptr = max(0, min(nstack - 1, ptr + step))
-
-
-def show_curr(caller, showall=False):
-    """
-    Show the current position in stack
-    """
-    stackptr = caller.ndb.batch_stackptr
-    stack = caller.ndb.batch_stack
-
-    if stackptr >= len(stack):
-        caller.ndb.batch_stackptr = len(stack) - 1
-        show_curr(caller, showall)
-        return
-
-    entry = stack[stackptr]
-
-    string = format_header(caller, entry)
-    codeall = entry.strip()
-    string += "|G(hh for help)"
-    if showall:
-        for line in codeall.split("\n"):
-            string += "\n|G||n %s" % line
-    caller.msg(string)
-
-
-def purge_processor(caller):
-    """
-    This purges all effects running
-    on the caller.
-    """
-    try:
-        del caller.ndb.batch_stack
-        del caller.ndb.batch_stackptr
-        del caller.ndb.batch_pythonpath
-        del caller.ndb.batch_batchmode
-    except Exception:
-        # something might have already been erased; it's not critical
-        pass
-    # clear everything back to the state before the batch call
-    if caller.ndb.batch_cmdset_backup:
-        caller.cmdset.cmdset_stack = caller.ndb.batch_cmdset_backup
-        caller.cmdset.update()
-        del caller.ndb.batch_cmdset_backup
-    else:
-        # something went wrong. Purge cmdset except default
-        caller.cmdset.clear()
-
-    # caller.scripts.validate()  # this will purge interactive mode
-
-
-# -------------------------------------------------------------
-# main access commands
-# -------------------------------------------------------------
-
-
-
[docs]class CmdBatchCommands(_COMMAND_DEFAULT_CLASS): - """ - build from batch-command file - - Usage: - batchcommands[/interactive] <python.path.to.file> - - Switch: - interactive - this mode will offer more control when - executing the batch file, like stepping, - skipping, reloading etc. - - Runs batches of commands from a batch-cmd text file (*.ev). - - """ - - key = "batchcommands" - aliases = ["batchcommand", "batchcmd"] - switch_options = ("interactive",) - locks = "cmd:perm(batchcommands) or perm(Developer)" - help_category = "Building" - -
[docs] def func(self): - """Starts the processor.""" - - caller = self.caller - - args = self.args - if not args: - caller.msg("Usage: batchcommands[/interactive] <path.to.file>") - return - python_path = self.args - - # parse indata file - - try: - commands = BATCHCMD.parse_file(python_path) - except UnicodeDecodeError as err: - caller.msg(_UTF8_ERROR % (python_path, err)) - return - except IOError as err: - if err: - err = "{}\n".format(str(err)) - else: - err = "" - string = ( - "%s'%s' could not load. You have to supply python paths " - "from one of the defined batch-file directories\n (%s)." - ) - caller.msg(string % (err, python_path, ", ".join(settings.BASE_BATCHPROCESS_PATHS))) - return - if not commands: - caller.msg("File %s seems empty of valid commands." % python_path) - return - - switches = self.switches - - # Store work data in cache - caller.ndb.batch_stack = commands - caller.ndb.batch_stackptr = 0 - caller.ndb.batch_pythonpath = python_path - caller.ndb.batch_batchmode = "batch_commands" - # we use list() here to create a new copy of the cmdset stack - caller.ndb.batch_cmdset_backup = list(caller.cmdset.cmdset_stack) - caller.cmdset.add(BatchSafeCmdSet) - - if "inter" in switches or "interactive" in switches: - # Allow more control over how batch file is executed - - # Set interactive state directly - caller.cmdset.add(BatchInteractiveCmdSet) - - caller.msg("\nBatch-command processor - Interactive mode for %s ..." % python_path) - show_curr(caller) - else: - caller.msg( - "Running Batch-command processor - Automatic mode " - "for %s (this might take some time) ..." % python_path - ) - - # run in-process (might block) - for _ in range(len(commands)): - # loop through the batch file - if not batch_cmd_exec(caller): - return - step_pointer(caller, 1) - # clean out the safety cmdset and clean out all other - # temporary attrs. - string = " Batchfile '%s' applied." % python_path - caller.msg("|G%s" % string) - purge_processor(caller)
- - -
[docs]class CmdBatchCode(_COMMAND_DEFAULT_CLASS): - """ - build from batch-code file - - Usage: - batchcode[/interactive] <python path to file> - - Switch: - interactive - this mode will offer more control when - executing the batch file, like stepping, - skipping, reloading etc. - debug - auto-delete all objects that has been marked as - deletable in the script file (see example files for - syntax). This is useful so as to to not leave multiple - object copies behind when testing out the script. - - Runs batches of commands from a batch-code text file (*.py). - - """ - - key = "batchcode" - aliases = ["batchcodes"] - switch_options = ("interactive", "debug") - locks = "cmd:superuser()" - help_category = "Building" - -
[docs] def func(self): - """Starts the processor.""" - - caller = self.caller - - args = self.args - if not args: - caller.msg("Usage: batchcode[/interactive/debug] <path.to.file>") - return - python_path = self.args - debug = "debug" in self.switches - - # parse indata file - try: - codes = BATCHCODE.parse_file(python_path) - except UnicodeDecodeError as err: - caller.msg(_UTF8_ERROR % (python_path, err)) - return - except IOError as err: - if err: - err = "{}\n".format(str(err)) - else: - err = "" - string = ( - "%s'%s' could not load. You have to supply python paths " - "from one of the defined batch-file directories\n (%s)." - ) - caller.msg(string % (err, python_path, ", ".join(settings.BASE_BATCHPROCESS_PATHS))) - return - if not codes: - caller.msg("File %s seems empty of functional code." % python_path) - return - - switches = self.switches - - # Store work data in cache - caller.ndb.batch_stack = codes - caller.ndb.batch_stackptr = 0 - caller.ndb.batch_pythonpath = python_path - caller.ndb.batch_batchmode = "batch_code" - caller.ndb.batch_debug = debug - # we use list() here to create a new copy of cmdset_stack - caller.ndb.batch_cmdset_backup = list(caller.cmdset.cmdset_stack) - caller.cmdset.add(BatchSafeCmdSet) - - if "inter" in switches or "interactive" in switches: - # Allow more control over how batch file is executed - - # Set interactive state directly - caller.cmdset.add(BatchInteractiveCmdSet) - - caller.msg("\nBatch-code processor - Interactive mode for %s ..." % python_path) - show_curr(caller) - else: - caller.msg("Running Batch-code processor - Automatic mode for %s ..." % python_path) - - for _ in range(len(codes)): - # loop through the batch file - if not batch_code_exec(caller): - return - step_pointer(caller, 1) - # clean out the safety cmdset and clean out all other - # temporary attrs. - string = " Batchfile '%s' applied." % python_path - caller.msg("|G%s" % string) - purge_processor(caller)
- - -# ------------------------------------------------------------- -# State-commands for the interactive batch processor modes -# (these are the same for both processors) -# ------------------------------------------------------------- - - -class CmdStateAbort(_COMMAND_DEFAULT_CLASS): - """ - abort - - This is a safety feature. It force-ejects us out of the processor and to - the default cmdset, regardless of what current cmdset the processor might - have put us in (e.g. when testing buggy scripts etc). - """ - - key = "abort" - help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" - - def func(self): - """Exit back to default.""" - purge_processor(self.caller) - self.caller.msg("Exited processor and reset out active cmdset back to the default one.") - - -class CmdStateLL(_COMMAND_DEFAULT_CLASS): - """ - ll - - Look at the full source for the current - command definition. - """ - - key = "ll" - help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" - - def func(self): - show_curr(self.caller, showall=True) - - -class CmdStatePP(_COMMAND_DEFAULT_CLASS): - """ - pp - - Process the currently shown command definition. - """ - - key = "pp" - help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" - - def func(self): - """ - This checks which type of processor we are running. - """ - caller = self.caller - if caller.ndb.batch_batchmode == "batch_code": - batch_code_exec(caller) - else: - batch_cmd_exec(caller) - - -class CmdStateRR(_COMMAND_DEFAULT_CLASS): - """ - rr - - Reload the batch file, keeping the current - position in it. - """ - - key = "rr" - help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" - - def func(self): - caller = self.caller - if caller.ndb.batch_batchmode == "batch_code": - new_data = BATCHCODE.parse_file(caller.ndb.batch_pythonpath) - else: - new_data = BATCHCMD.parse_file(caller.ndb.batch_pythonpath) - caller.ndb.batch_stack = new_data - caller.msg(format_code("File reloaded. Staying on same command.")) - show_curr(caller) - - -class CmdStateRRR(_COMMAND_DEFAULT_CLASS): - """ - rrr - - Reload the batch file, starting over - from the beginning. - """ - - key = "rrr" - help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" - - def func(self): - caller = self.caller - if caller.ndb.batch_batchmode == "batch_code": - BATCHCODE.parse_file(caller.ndb.batch_pythonpath) - else: - BATCHCMD.parse_file(caller.ndb.batch_pythonpath) - caller.ndb.batch_stackptr = 0 - caller.msg(format_code("File reloaded. Restarting from top.")) - show_curr(caller) - - -class CmdStateNN(_COMMAND_DEFAULT_CLASS): - """ - nn - - Go to next command. No commands are executed. - """ - - key = "nn" - help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" - - def func(self): - caller = self.caller - arg = self.args - if arg and arg.isdigit(): - step = int(self.args) - else: - step = 1 - step_pointer(caller, step) - show_curr(caller) - - -class CmdStateNL(_COMMAND_DEFAULT_CLASS): - """ - nl - - Go to next command, viewing its full source. - No commands are executed. - """ - - key = "nl" - help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" - - def func(self): - caller = self.caller - arg = self.args - if arg and arg.isdigit(): - step = int(self.args) - else: - step = 1 - step_pointer(caller, step) - show_curr(caller, showall=True) - - -class CmdStateBB(_COMMAND_DEFAULT_CLASS): - """ - bb - - Backwards to previous command. No commands - are executed. - """ - - key = "bb" - help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" - - def func(self): - caller = self.caller - arg = self.args - if arg and arg.isdigit(): - step = -int(self.args) - else: - step = -1 - step_pointer(caller, step) - show_curr(caller) - - -class CmdStateBL(_COMMAND_DEFAULT_CLASS): - """ - bl - - Backwards to previous command, viewing its full - source. No commands are executed. - """ - - key = "bl" - help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" - - def func(self): - caller = self.caller - arg = self.args - if arg and arg.isdigit(): - step = -int(self.args) - else: - step = -1 - step_pointer(caller, step) - show_curr(caller, showall=True) - - -class CmdStateSS(_COMMAND_DEFAULT_CLASS): - """ - ss [steps] - - Process current command, then step to the next - one. If steps is given, - process this many commands. - """ - - key = "ss" - help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" - - def func(self): - caller = self.caller - arg = self.args - if arg and arg.isdigit(): - step = int(self.args) - else: - step = 1 - - for _ in range(step): - if caller.ndb.batch_batchmode == "batch_code": - batch_code_exec(caller) - else: - batch_cmd_exec(caller) - step_pointer(caller, 1) - show_curr(caller) - - -class CmdStateSL(_COMMAND_DEFAULT_CLASS): - """ - sl [steps] - - Process current command, then step to the next - one, viewing its full source. If steps is given, - process this many commands. - """ - - key = "sl" - help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" - - def func(self): - caller = self.caller - arg = self.args - if arg and arg.isdigit(): - step = int(self.args) - else: - step = 1 - - for _ in range(step): - if caller.ndb.batch_batchmode == "batch_code": - batch_code_exec(caller) - else: - batch_cmd_exec(caller) - step_pointer(caller, 1) - show_curr(caller) - - -class CmdStateCC(_COMMAND_DEFAULT_CLASS): - """ - cc - - Continue to process all remaining - commands. - """ - - key = "cc" - help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" - - def func(self): - caller = self.caller - nstack = len(caller.ndb.batch_stack) - ptr = caller.ndb.batch_stackptr - step = nstack - ptr - - for _ in range(step): - if caller.ndb.batch_batchmode == "batch_code": - batch_code_exec(caller) - else: - batch_cmd_exec(caller) - step_pointer(caller, 1) - show_curr(caller) - - purge_processor(self) - caller.msg(format_code("Finished processing batch file.")) - - -class CmdStateJJ(_COMMAND_DEFAULT_CLASS): - """ - jj <command number> - - Jump to specific command number - """ - - key = "jj" - help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" - - def func(self): - caller = self.caller - arg = self.args - if arg and arg.isdigit(): - number = int(self.args) - 1 - else: - caller.msg(format_code("You must give a number index.")) - return - ptr = caller.ndb.batch_stackptr - step = number - ptr - step_pointer(caller, step) - show_curr(caller) - - -class CmdStateJL(_COMMAND_DEFAULT_CLASS): - """ - jl <command number> - - Jump to specific command number and view its full source. - """ - - key = "jl" - help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" - - def func(self): - caller = self.caller - arg = self.args - if arg and arg.isdigit(): - number = int(self.args) - 1 - else: - caller.msg(format_code("You must give a number index.")) - return - ptr = caller.ndb.batch_stackptr - step = number - ptr - step_pointer(caller, step) - show_curr(caller, showall=True) - - -class CmdStateQQ(_COMMAND_DEFAULT_CLASS): - """ - qq - - Quit the batchprocessor. - """ - - key = "qq" - help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" - - def func(self): - purge_processor(self.caller) - self.caller.msg("Aborted interactive batch mode.") - - -class CmdStateHH(_COMMAND_DEFAULT_CLASS): - """Help command""" - - key = "hh" - help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" - - def func(self): - string = """ - Interactive batch processing commands: - - nn [steps] - next command (no processing) - nl [steps] - next & look - bb [steps] - back to previous command (no processing) - bl [steps] - back & look - jj <N> - jump to command nr N (no processing) - jl <N> - jump & look - pp - process currently shown command (no step) - ss [steps] - process & step - sl [steps] - process & step & look - ll - look at full definition of current command - rr - reload batch file (stay on current) - rrr - reload batch file (start from first) - hh - this help list - - cc - continue processing to end, then quit. - qq - quit (abort all remaining commands) - - abort - this is a safety command that always is available - regardless of what cmdsets gets added to us during - batch-command processing. It immediately shuts down - the processor and returns us to the default cmdset. - """ - self.caller.msg(string) - - -# ------------------------------------------------------------- -# -# Defining the cmdsets for the interactive batchprocessor -# mode (same for both processors) -# -# ------------------------------------------------------------- - - -class BatchSafeCmdSet(CmdSet): - """ - The base cmdset for the batch processor. - This sets a 'safe' abort command that will - always be available to get out of everything. - """ - - key = "Batch_default" - priority = 150 # override other cmdsets. - - def at_cmdset_creation(self): - """Init the cmdset""" - self.add(CmdStateAbort()) - - -class BatchInteractiveCmdSet(CmdSet): - """ - The cmdset for the interactive batch processor mode. - """ - - key = "Batch_interactive" - priority = 104 - - def at_cmdset_creation(self): - """init the cmdset""" - self.add(CmdStateAbort()) - self.add(CmdStateLL()) - self.add(CmdStatePP()) - self.add(CmdStateRR()) - self.add(CmdStateRRR()) - self.add(CmdStateNN()) - self.add(CmdStateNL()) - self.add(CmdStateBB()) - self.add(CmdStateBL()) - self.add(CmdStateSS()) - self.add(CmdStateSL()) - self.add(CmdStateCC()) - self.add(CmdStateJJ()) - self.add(CmdStateJL()) - self.add(CmdStateQQ()) - self.add(CmdStateHH()) -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/commands/default/building.html b/docs/0.9.5/_modules/evennia/commands/default/building.html deleted file mode 100644 index 4c8a1003d3..0000000000 --- a/docs/0.9.5/_modules/evennia/commands/default/building.html +++ /dev/null @@ -1,4406 +0,0 @@ - - - - - - - - evennia.commands.default.building — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.commands.default.building

-"""
-Building and world design commands
-"""
-import re
-from django.core.paginator import Paginator
-from django.conf import settings
-from django.db.models import Q, Min, Max
-from evennia import InterruptCommand
-from evennia.scripts.models import ScriptDB
-from evennia.objects.models import ObjectDB
-from evennia.locks.lockhandler import LockException
-from evennia.commands.cmdhandler import get_and_merge_cmdsets
-from evennia.utils import create, utils, search, logger, funcparser
-from evennia.utils.dbserialize import deserialize
-from evennia.utils.utils import (
-    inherits_from,
-    class_from_module,
-    get_all_typeclasses,
-    variable_from_module,
-    dbref, crop,
-    interactive,
-    list_to_string,
-    display_len,
-    format_grid,
-)
-from evennia.utils.eveditor import EvEditor
-from evennia.utils.evmore import EvMore
-from evennia.utils.evtable import EvTable
-from evennia.prototypes import spawner, prototypes as protlib, menus as olc_menus
-from evennia.utils.ansi import raw as ansi_raw
-
-COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
-
-_FUNCPARSER = None
-_ATTRFUNCPARSER = None
-
-# limit symbol import for API
-__all__ = (
-    "ObjManipCommand",
-    "CmdSetObjAlias",
-    "CmdCopy",
-    "CmdCpAttr",
-    "CmdMvAttr",
-    "CmdCreate",
-    "CmdDesc",
-    "CmdDestroy",
-    "CmdDig",
-    "CmdTunnel",
-    "CmdLink",
-    "CmdUnLink",
-    "CmdSetHome",
-    "CmdListCmdSets",
-    "CmdName",
-    "CmdOpen",
-    "CmdSetAttribute",
-    "CmdTypeclass",
-    "CmdWipe",
-    "CmdLock",
-    "CmdExamine",
-    "CmdFind",
-    "CmdTeleport",
-    "CmdScripts",
-    "CmdObjects",
-    "CmdTag",
-    "CmdSpawn",
-)
-
-# used by set
-from ast import literal_eval as _LITERAL_EVAL
-
-LIST_APPEND_CHAR = "+"
-
-# used by find
-CHAR_TYPECLASS = settings.BASE_CHARACTER_TYPECLASS
-ROOM_TYPECLASS = settings.BASE_ROOM_TYPECLASS
-EXIT_TYPECLASS = settings.BASE_EXIT_TYPECLASS
-_DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
-
-_PROTOTYPE_PARENTS = None
-
-
-
[docs]class ObjManipCommand(COMMAND_DEFAULT_CLASS): - """ - This is a parent class for some of the defining objmanip commands - since they tend to have some more variables to define new objects. - - Each object definition can have several components. First is - always a name, followed by an optional alias list and finally an - some optional data, such as a typeclass or a location. A comma ',' - separates different objects. Like this: - - name1;alias;alias;alias:option, name2;alias;alias ... - - Spaces between all components are stripped. - - A second situation is attribute manipulation. Such commands - are simpler and offer combinations - - objname/attr/attr/attr, objname/attr, ... - - """ - - # OBS - this is just a parent - it's not intended to actually be - # included in a commandset on its own! - -
[docs] def parse(self): - """ - We need to expand the default parsing to get all - the cases, see the module doc. - """ - # get all the normal parsing done (switches etc) - super().parse() - - obj_defs = ([], []) # stores left- and right-hand side of '=' - obj_attrs = ([], []) # " - - for iside, arglist in enumerate((self.lhslist, self.rhslist)): - # lhslist/rhslist is already split by ',' at this point - for objdef in arglist: - aliases, option, attrs = [], None, [] - if ":" in objdef: - objdef, option = [part.strip() for part in objdef.rsplit(":", 1)] - if ";" in objdef: - objdef, aliases = [part.strip() for part in objdef.split(";", 1)] - aliases = [alias.strip() for alias in aliases.split(";") if alias.strip()] - if "/" in objdef: - objdef, attrs = [part.strip() for part in objdef.split("/", 1)] - attrs = [part.strip().lower() for part in attrs.split("/") if part.strip()] - # store data - obj_defs[iside].append({"name": objdef, "option": option, "aliases": aliases}) - obj_attrs[iside].append({"name": objdef, "attrs": attrs}) - - # store for future access - self.lhs_objs = obj_defs[0] - self.rhs_objs = obj_defs[1] - self.lhs_objattr = obj_attrs[0] - self.rhs_objattr = obj_attrs[1]
- - -
[docs]class CmdSetObjAlias(COMMAND_DEFAULT_CLASS): - """ - adding permanent aliases for object - - Usage: - alias <obj> [= [alias[,alias,alias,...]]] - alias <obj> = - alias/category <obj> = [alias[,alias,...]:<category> - - Switches: - category - requires ending input with :category, to store the - given aliases with the given category. - - Assigns aliases to an object so it can be referenced by more - than one name. Assign empty to remove all aliases from object. If - assigning a category, all aliases given will be using this category. - - Observe that this is not the same thing as personal aliases - created with the 'nick' command! Aliases set with alias are - changing the object in question, making those aliases usable - by everyone. - """ - - key = "@alias" - aliases = "setobjalias" - switch_options = ("category",) - locks = "cmd:perm(setobjalias) or perm(Builder)" - help_category = "Building" - -
[docs] def func(self): - """Set the aliases.""" - - caller = self.caller - - if not self.lhs: - string = "Usage: alias <obj> [= [alias[,alias ...]]]" - self.caller.msg(string) - return - objname = self.lhs - - # Find the object to receive aliases - obj = caller.search(objname) - if not obj: - return - if self.rhs is None: - # no =, so we just list aliases on object. - aliases = obj.aliases.all(return_key_and_category=True) - if aliases: - caller.msg( - "Aliases for %s: %s" - % ( - obj.get_display_name(caller), - ", ".join( - "'%s'%s" - % (alias, "" if category is None else "[category:'%s']" % category) - for (alias, category) in aliases - ), - ) - ) - else: - caller.msg("No aliases exist for '%s'." % obj.get_display_name(caller)) - return - - if not (obj.access(caller, "control") or obj.access(caller, "edit")): - caller.msg("You don't have permission to do that.") - return - - if not self.rhs: - # we have given an empty =, so delete aliases - old_aliases = obj.aliases.all() - if old_aliases: - caller.msg( - "Cleared aliases from %s: %s" - % (obj.get_display_name(caller), ", ".join(old_aliases)) - ) - obj.aliases.clear() - else: - caller.msg("No aliases to clear.") - return - - category = None - if "category" in self.switches: - if ":" in self.rhs: - rhs, category = self.rhs.rsplit(":", 1) - category = category.strip() - else: - caller.msg( - "If specifying the /category switch, the category must be given " - "as :category at the end." - ) - else: - rhs = self.rhs - - # merge the old and new aliases (if any) - old_aliases = obj.aliases.get(category=category, return_list=True) - new_aliases = [alias.strip().lower() for alias in rhs.split(",") if alias.strip()] - - # make the aliases only appear once - old_aliases.extend(new_aliases) - aliases = list(set(old_aliases)) - - # save back to object. - obj.aliases.add(aliases, category=category) - - # we need to trigger this here, since this will force - # (default) Exits to rebuild their Exit commands with the new - # aliases - obj.at_cmdset_get(force_init=True) - - # report all aliases on the object - caller.msg( - "Alias(es) for '%s' set to '%s'%s." - % ( - obj.get_display_name(caller), - str(obj.aliases), - " (category: '%s')" % category if category else "", - ) - )
- - -
[docs]class CmdCopy(ObjManipCommand): - """ - copy an object and its properties - - Usage: - copy <original obj> [= <new_name>][;alias;alias..] - [:<new_location>] [,<new_name2> ...] - - Create one or more copies of an object. If you don't supply any targets, - one exact copy of the original object will be created with the name *_copy. - """ - - key = "@copy" - locks = "cmd:perm(copy) or perm(Builder)" - help_category = "Building" - -
[docs] def func(self): - """Uses ObjManipCommand.parse()""" - - caller = self.caller - args = self.args - if not args: - caller.msg( - "Usage: copy <obj> [=<new_name>[;alias;alias..]]" - "[:<new_location>] [, <new_name2>...]" - ) - return - - if not self.rhs: - # this has no target =, so an identical new object is created. - from_obj_name = self.args - from_obj = caller.search(from_obj_name) - if not from_obj: - return - to_obj_name = "%s_copy" % from_obj_name - to_obj_aliases = ["%s_copy" % alias for alias in from_obj.aliases.all()] - copiedobj = ObjectDB.objects.copy_object( - from_obj, new_key=to_obj_name, new_aliases=to_obj_aliases - ) - if copiedobj: - string = "Identical copy of %s, named '%s' was created." % ( - from_obj_name, - to_obj_name, - ) - else: - string = "There was an error copying %s." - else: - # we have specified =. This might mean many object targets - from_obj_name = self.lhs_objs[0]["name"] - from_obj = caller.search(from_obj_name) - if not from_obj: - return - for objdef in self.rhs_objs: - # loop through all possible copy-to targets - to_obj_name = objdef["name"] - to_obj_aliases = objdef["aliases"] - to_obj_location = objdef["option"] - if to_obj_location: - to_obj_location = caller.search(to_obj_location, global_search=True) - if not to_obj_location: - return - - copiedobj = ObjectDB.objects.copy_object( - from_obj, - new_key=to_obj_name, - new_location=to_obj_location, - new_aliases=to_obj_aliases, - ) - if copiedobj: - string = "Copied %s to '%s' (aliases: %s)." % ( - from_obj_name, - to_obj_name, - to_obj_aliases, - ) - else: - string = "There was an error copying %s to '%s'." % (from_obj_name, to_obj_name) - # we are done, echo to user - caller.msg(string)
- - -
[docs]class CmdCpAttr(ObjManipCommand): - """ - copy attributes between objects - - Usage: - cpattr[/switch] <obj>/<attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...] - cpattr[/switch] <obj>/<attr> = <obj1> [,<obj2>,<obj3>,...] - cpattr[/switch] <attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...] - cpattr[/switch] <attr> = <obj1>[,<obj2>,<obj3>,...] - - Switches: - move - delete the attribute from the source object after copying. - - Example: - cpattr coolness = Anna/chillout, Anna/nicety, Tom/nicety - -> - copies the coolness attribute (defined on yourself), to attributes - on Anna and Tom. - - Copy the attribute one object to one or more attributes on another object. - If you don't supply a source object, yourself is used. - """ - - key = "@cpattr" - switch_options = ("move",) - locks = "cmd:perm(cpattr) or perm(Builder)" - help_category = "Building" - -
[docs] def check_from_attr(self, obj, attr, clear=False): - """ - Hook for overriding on subclassed commands. Checks to make sure a - caller can copy the attr from the object in question. If not, return a - false value and the command will abort. An error message should be - provided by this function. - - If clear is True, user is attempting to move the attribute. - """ - return True
- -
[docs] def check_to_attr(self, obj, attr): - """ - Hook for overriding on subclassed commands. Checks to make sure a - caller can write to the specified attribute on the specified object. - If not, return a false value and the attribute will be skipped. An - error message should be provided by this function. - """ - return True
- -
[docs] def check_has_attr(self, obj, attr): - """ - Hook for overriding on subclassed commands. Do any preprocessing - required and verify an object has an attribute. - """ - if not obj.attributes.has(attr): - self.caller.msg("%s doesn't have an attribute %s." % (obj.name, attr)) - return False - return True
- -
[docs] def get_attr(self, obj, attr): - """ - Hook for overriding on subclassed commands. Do any preprocessing - required and get the attribute from the object. - """ - return obj.attributes.get(attr)
- -
[docs] def func(self): - """ - Do the copying. - """ - caller = self.caller - - if not self.rhs: - string = """Usage: - cpattr[/switch] <obj>/<attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...] - cpattr[/switch] <obj>/<attr> = <obj1> [,<obj2>,<obj3>,...] - cpattr[/switch] <attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...] - cpattr[/switch] <attr> = <obj1>[,<obj2>,<obj3>,...]""" - caller.msg(string) - return - - lhs_objattr = self.lhs_objattr - to_objs = self.rhs_objattr - from_obj_name = lhs_objattr[0]["name"] - from_obj_attrs = lhs_objattr[0]["attrs"] - - if not from_obj_attrs: - # this means the from_obj_name is actually an attribute - # name on self. - from_obj_attrs = [from_obj_name] - from_obj = self.caller - else: - from_obj = caller.search(from_obj_name) - if not from_obj or not to_objs: - caller.msg("You have to supply both source object and target(s).") - return - # copy to all to_obj:ects - if "move" in self.switches: - clear = True - else: - clear = False - if not self.check_from_attr(from_obj, from_obj_attrs[0], clear=clear): - return - - for attr in from_obj_attrs: - if not self.check_has_attr(from_obj, attr): - return - - if (len(from_obj_attrs) != len(set(from_obj_attrs))) and clear: - self.caller.msg("|RCannot have duplicate source names when moving!") - return - - result = [] - - for to_obj in to_objs: - to_obj_name = to_obj["name"] - to_obj_attrs = to_obj["attrs"] - to_obj = caller.search(to_obj_name) - if not to_obj: - result.append("\nCould not find object '%s'" % to_obj_name) - continue - for inum, from_attr in enumerate(from_obj_attrs): - try: - to_attr = to_obj_attrs[inum] - except IndexError: - # if there are too few attributes given - # on the to_obj, we copy the original name instead. - to_attr = from_attr - if not self.check_to_attr(to_obj, to_attr): - continue - value = self.get_attr(from_obj, from_attr) - to_obj.attributes.add(to_attr, value) - if clear and not (from_obj == to_obj and from_attr == to_attr): - from_obj.attributes.remove(from_attr) - result.append( - "\nMoved %s.%s -> %s.%s. (value: %s)" - % (from_obj.name, from_attr, to_obj_name, to_attr, repr(value)) - ) - else: - result.append( - "\nCopied %s.%s -> %s.%s. (value: %s)" - % (from_obj.name, from_attr, to_obj_name, to_attr, repr(value)) - ) - caller.msg("".join(result))
- - -
[docs]class CmdMvAttr(ObjManipCommand): - """ - move attributes between objects - - Usage: - mvattr[/switch] <obj>/<attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...] - mvattr[/switch] <obj>/<attr> = <obj1> [,<obj2>,<obj3>,...] - mvattr[/switch] <attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...] - mvattr[/switch] <attr> = <obj1>[,<obj2>,<obj3>,...] - - Switches: - copy - Don't delete the original after moving. - - Move an attribute from one object to one or more attributes on another - object. If you don't supply a source object, yourself is used. - """ - - key = "@mvattr" - switch_options = ("copy",) - locks = "cmd:perm(mvattr) or perm(Builder)" - help_category = "Building" - -
[docs] def func(self): - """ - Do the moving - """ - if not self.rhs: - string = """Usage: - mvattr[/switch] <obj>/<attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...] - mvattr[/switch] <obj>/<attr> = <obj1> [,<obj2>,<obj3>,...] - mvattr[/switch] <attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...] - mvattr[/switch] <attr> = <obj1>[,<obj2>,<obj3>,...]""" - self.caller.msg(string) - return - - # simply use cpattr for all the functionality - if "copy" in self.switches: - self.execute_cmd("cpattr %s" % self.args) - else: - self.execute_cmd("cpattr/move %s" % self.args)
- - -
[docs]class CmdCreate(ObjManipCommand): - """ - create new objects - - Usage: - create[/drop] <objname>[;alias;alias...][:typeclass], <objname>... - - switch: - drop - automatically drop the new object into your current - location (this is not echoed). This also sets the new - object's home to the current location rather than to you. - - Creates one or more new objects. If typeclass is given, the object - is created as a child of this typeclass. The typeclass script is - assumed to be located under types/ and any further - directory structure is given in Python notation. So if you have a - correct typeclass 'RedButton' defined in - types/examples/red_button.py, you could create a new - object of this type like this: - - create/drop button;red : examples.red_button.RedButton - - """ - - key = "@create" - switch_options = ("drop",) - locks = "cmd:perm(create) or perm(Builder)" - help_category = "Building" - - # lockstring of newly created objects, for easy overloading. - # Will be formatted with the {id} of the creating object. - new_obj_lockstring = "control:id({id}) or perm(Admin);delete:id({id}) or perm(Admin)" - -
[docs] def func(self): - """ - Creates the object. - """ - - caller = self.caller - - if not self.args: - string = "Usage: create[/drop] <newname>[;alias;alias...] [:typeclass.path]" - caller.msg(string) - return - - # create the objects - for objdef in self.lhs_objs: - string = "" - name = objdef["name"] - aliases = objdef["aliases"] - typeclass = objdef["option"] - - # create object (if not a valid typeclass, the default - # object typeclass will automatically be used) - lockstring = self.new_obj_lockstring.format(id=caller.id) - obj = create.create_object( - typeclass, - name, - caller, - home=caller, - aliases=aliases, - locks=lockstring, - report_to=caller, - ) - if not obj: - continue - if aliases: - string = "You create a new %s: %s (aliases: %s)." - string = string % (obj.typename, obj.name, ", ".join(aliases)) - else: - string = "You create a new %s: %s." - string = string % (obj.typename, obj.name) - # set a default desc - if not obj.db.desc: - obj.db.desc = "You see nothing special." - if "drop" in self.switches: - if caller.location: - obj.home = caller.location - obj.move_to(caller.location, quiet=True) - if string: - caller.msg(string)
- - -def _desc_load(caller): - return caller.db.evmenu_target.db.desc or "" - - -def _desc_save(caller, buf): - """ - Save line buffer to the desc prop. This should - return True if successful and also report its status to the user. - """ - caller.db.evmenu_target.db.desc = buf - caller.msg("Saved.") - return True - - -def _desc_quit(caller): - caller.attributes.remove("evmenu_target") - caller.msg("Exited editor.") - - -
[docs]class CmdDesc(COMMAND_DEFAULT_CLASS): - """ - describe an object or the current room. - - Usage: - desc [<obj> =] <description> - - Switches: - edit - Open up a line editor for more advanced editing. - - Sets the "desc" attribute on an object. If an object is not given, - describe the current room. - """ - - key = "@desc" - switch_options = ("edit",) - locks = "cmd:perm(desc) or perm(Builder)" - help_category = "Building" - -
[docs] def edit_handler(self): - if self.rhs: - self.msg("|rYou may specify a value, or use the edit switch, but not both.|n") - return - if self.args: - obj = self.caller.search(self.args) - else: - obj = self.caller.location or self.msg("|rYou can't describe oblivion.|n") - if not obj: - return - - if not (obj.access(self.caller, "control") or obj.access(self.caller, "edit")): - self.caller.msg("You don't have permission to edit the description of %s." % obj.key) - return - - self.caller.db.evmenu_target = obj - # launch the editor - EvEditor( - self.caller, - loadfunc=_desc_load, - savefunc=_desc_save, - quitfunc=_desc_quit, - key="desc", - persistent=True, - ) - return
- -
[docs] def func(self): - """Define command""" - - caller = self.caller - if not self.args and "edit" not in self.switches: - caller.msg("Usage: desc [<obj> =] <description>") - return - - if "edit" in self.switches: - self.edit_handler() - return - - if "=" in self.args: - # We have an = - obj = caller.search(self.lhs) - if not obj: - return - desc = self.rhs or "" - else: - obj = caller.location or self.msg("|rYou don't have a location to describe.|n") - if not obj: - return - desc = self.args - if obj.access(self.caller, "control") or obj.access(self.caller, "edit"): - obj.db.desc = desc - caller.msg("The description was set on %s." % obj.get_display_name(caller)) - else: - caller.msg("You don't have permission to edit the description of %s." % obj.key)
- - -
[docs]class CmdDestroy(COMMAND_DEFAULT_CLASS): - """ - permanently delete objects - - Usage: - destroy[/switches] [obj, obj2, obj3, [dbref-dbref], ...] - - Switches: - override - The destroy command will usually avoid accidentally - destroying account objects. This switch overrides this safety. - force - destroy without confirmation. - Examples: - destroy house, roof, door, 44-78 - destroy 5-10, flower, 45 - destroy/force north - - Destroys one or many objects. If dbrefs are used, a range to delete can be - given, e.g. 4-10. Also the end points will be deleted. This command - displays a confirmation before destroying, to make sure of your choice. - You can specify the /force switch to bypass this confirmation. - """ - - key = "@destroy" - aliases = ["@delete", "@del"] - switch_options = ("override", "force") - locks = "cmd:perm(destroy) or perm(Builder)" - help_category = "Building" - - confirm = True # set to False to always bypass confirmation - default_confirm = "yes" # what to assume if just pressing enter (yes/no) - -
[docs] def func(self): - """Implements the command.""" - - caller = self.caller - delete = True - - if not self.args or not self.lhslist: - caller.msg("Usage: destroy[/switches] [obj, obj2, obj3, [dbref-dbref],...]") - delete = False - - def delobj(obj): - # helper function for deleting a single object - string = "" - if not obj.pk: - string = "\nObject %s was already deleted." % obj.db_key - else: - objname = obj.name - if not (obj.access(caller, "control") or obj.access(caller, "delete")): - return "\nYou don't have permission to delete %s." % objname - if obj.account and "override" not in self.switches: - return ( - "\nObject %s is controlled by an active account. Use /override to delete anyway." - % objname - ) - if obj.dbid == int(settings.DEFAULT_HOME.lstrip("#")): - return ( - "\nYou are trying to delete |c%s|n, which is set as DEFAULT_HOME. " - "Re-point settings.DEFAULT_HOME to another " - "object before continuing." % objname - ) - - had_exits = hasattr(obj, "exits") and obj.exits - had_objs = hasattr(obj, "contents") and any( - obj - for obj in obj.contents - if not (hasattr(obj, "exits") and obj not in obj.exits) - ) - # do the deletion - okay = obj.delete() - if not okay: - string += ( - "\nERROR: %s not deleted, probably because delete() returned False." - % objname - ) - else: - string += "\n%s was destroyed." % objname - if had_exits: - string += " Exits to and from %s were destroyed as well." % objname - if had_objs: - string += " Objects inside %s were moved to their homes." % objname - return string - - objs = [] - for objname in self.lhslist: - if not delete: - continue - - if "-" in objname: - # might be a range of dbrefs - dmin, dmax = [utils.dbref(part, reqhash=False) for part in objname.split("-", 1)] - if dmin and dmax: - for dbref in range(int(dmin), int(dmax + 1)): - obj = caller.search("#" + str(dbref)) - if obj: - objs.append(obj) - continue - else: - obj = caller.search(objname) - else: - obj = caller.search(objname) - - if obj is None: - self.caller.msg( - " (Objects to destroy must either be local or specified with a unique #dbref.)" - ) - elif obj not in objs: - objs.append(obj) - - if objs and ("force" not in self.switches and type(self).confirm): - confirm = "Are you sure you want to destroy " - if len(objs) == 1: - confirm += objs[0].get_display_name(caller) - elif len(objs) < 5: - confirm += ", ".join([obj.get_display_name(caller) for obj in objs]) - else: - confirm += ", ".join(["#{}".format(obj.id) for obj in objs]) - confirm += " [yes]/no?" if self.default_confirm == "yes" else " yes/[no]" - answer = "" - answer = yield (confirm) - answer = self.default_confirm if answer == "" else answer - - if answer and answer not in ("yes", "y", "no", "n"): - caller.msg( - "Canceled: Either accept the default by pressing return or specify yes/no." - ) - delete = False - elif answer.strip().lower() in ("n", "no"): - caller.msg("Canceled: No object was destroyed.") - delete = False - - if delete: - results = [] - for obj in objs: - results.append(delobj(obj)) - - if results: - caller.msg("".join(results).strip())
- - -
[docs]class CmdDig(ObjManipCommand): - """ - build new rooms and connect them to the current location - - Usage: - dig[/switches] <roomname>[;alias;alias...][:typeclass] - [= <exit_to_there>[;alias][:typeclass]] - [, <exit_to_here>[;alias][:typeclass]] - - Switches: - tel or teleport - move yourself to the new room - - Examples: - dig kitchen = north;n, south;s - dig house:myrooms.MyHouseTypeclass - dig sheer cliff;cliff;sheer = climb up, climb down - - This command is a convenient way to build rooms quickly; it creates the - new room and you can optionally set up exits back and forth between your - current room and the new one. You can add as many aliases as you - like to the name of the room and the exits in question; an example - would be 'north;no;n'. - """ - - key = "@dig" - switch_options = ("teleport",) - locks = "cmd:perm(dig) or perm(Builder)" - help_category = "Building" - - # lockstring of newly created rooms, for easy overloading. - # Will be formatted with the {id} of the creating object. - new_room_lockstring = ( - "control:id({id}) or perm(Admin); " - "delete:id({id}) or perm(Admin); " - "edit:id({id}) or perm(Admin)" - ) - -
[docs] def func(self): - """Do the digging. Inherits variables from ObjManipCommand.parse()""" - - caller = self.caller - - if not self.lhs: - string = "Usage: dig[/teleport] <roomname>[;alias;alias...]" "[:parent] [= <exit_there>" - string += "[;alias;alias..][:parent]] " - string += "[, <exit_back_here>[;alias;alias..][:parent]]" - caller.msg(string) - return - - room = self.lhs_objs[0] - - if not room["name"]: - caller.msg("You must supply a new room name.") - return - location = caller.location - - # Create the new room - typeclass = room["option"] - if not typeclass: - typeclass = settings.BASE_ROOM_TYPECLASS - - # create room - new_room = create.create_object( - typeclass, room["name"], aliases=room["aliases"], report_to=caller - ) - lockstring = self.new_room_lockstring.format(id=caller.id) - new_room.locks.add(lockstring) - alias_string = "" - if new_room.aliases.all(): - alias_string = " (%s)" % ", ".join(new_room.aliases.all()) - room_string = "Created room %s(%s)%s of type %s." % ( - new_room, - new_room.dbref, - alias_string, - typeclass, - ) - - # create exit to room - - exit_to_string = "" - exit_back_string = "" - - if self.rhs_objs: - to_exit = self.rhs_objs[0] - if not to_exit["name"]: - exit_to_string = "\nNo exit created to new room." - elif not location: - exit_to_string = "\nYou cannot create an exit from a None-location." - else: - # Build the exit to the new room from the current one - typeclass = to_exit["option"] - if not typeclass: - typeclass = settings.BASE_EXIT_TYPECLASS - - new_to_exit = create.create_object( - typeclass, - to_exit["name"], - location, - aliases=to_exit["aliases"], - locks=lockstring, - destination=new_room, - report_to=caller, - ) - alias_string = "" - if new_to_exit.aliases.all(): - alias_string = " (%s)" % ", ".join(new_to_exit.aliases.all()) - exit_to_string = "\nCreated Exit from %s to %s: %s(%s)%s." - exit_to_string = exit_to_string % ( - location.name, - new_room.name, - new_to_exit, - new_to_exit.dbref, - alias_string, - ) - - # Create exit back from new room - - if len(self.rhs_objs) > 1: - # Building the exit back to the current room - back_exit = self.rhs_objs[1] - if not back_exit["name"]: - exit_back_string = "\nNo back exit created." - elif not location: - exit_back_string = "\nYou cannot create an exit back to a None-location." - else: - typeclass = back_exit["option"] - if not typeclass: - typeclass = settings.BASE_EXIT_TYPECLASS - new_back_exit = create.create_object( - typeclass, - back_exit["name"], - new_room, - aliases=back_exit["aliases"], - locks=lockstring, - destination=location, - report_to=caller, - ) - alias_string = "" - if new_back_exit.aliases.all(): - alias_string = " (%s)" % ", ".join(new_back_exit.aliases.all()) - exit_back_string = "\nCreated Exit back from %s to %s: %s(%s)%s." - exit_back_string = exit_back_string % ( - new_room.name, - location.name, - new_back_exit, - new_back_exit.dbref, - alias_string, - ) - caller.msg("%s%s%s" % (room_string, exit_to_string, exit_back_string)) - if new_room and "teleport" in self.switches: - caller.move_to(new_room)
- - -
[docs]class CmdTunnel(COMMAND_DEFAULT_CLASS): - """ - create new rooms in cardinal directions only - - Usage: - tunnel[/switch] <direction>[:typeclass] [= <roomname>[;alias;alias;...][:typeclass]] - - Switches: - oneway - do not create an exit back to the current location - tel - teleport to the newly created room - - Example: - tunnel n - tunnel n = house;mike's place;green building - - This is a simple way to build using pre-defined directions: - |wn,ne,e,se,s,sw,w,nw|n (north, northeast etc) - |wu,d|n (up and down) - |wi,o|n (in and out) - The full names (north, in, southwest, etc) will always be put as - main name for the exit, using the abbreviation as an alias (so an - exit will always be able to be used with both "north" as well as - "n" for example). Opposite directions will automatically be - created back from the new room unless the /oneway switch is given. - For more flexibility and power in creating rooms, use dig. - """ - - key = "@tunnel" - aliases = ["@tun"] - switch_options = ("oneway", "tel") - locks = "cmd: perm(tunnel) or perm(Builder)" - help_category = "Building" - - # store the direction, full name and its opposite - directions = { - "n": ("north", "s"), - "ne": ("northeast", "sw"), - "e": ("east", "w"), - "se": ("southeast", "nw"), - "s": ("south", "n"), - "sw": ("southwest", "ne"), - "w": ("west", "e"), - "nw": ("northwest", "se"), - "u": ("up", "d"), - "d": ("down", "u"), - "i": ("in", "o"), - "o": ("out", "i"), - } - -
[docs] def func(self): - """Implements the tunnel command""" - - if not self.args or not self.lhs: - string = ( - "Usage: tunnel[/switch] <direction>[:typeclass] [= <roomname>" - "[;alias;alias;...][:typeclass]]" - ) - self.caller.msg(string) - return - - # If we get a typeclass, we need to get just the exitname - exitshort = self.lhs.split(":")[0] - - if exitshort not in self.directions: - string = "tunnel can only understand the following directions: %s." % ",".join( - sorted(self.directions.keys()) - ) - string += "\n(use dig for more freedom)" - self.caller.msg(string) - return - - # retrieve all input and parse it - exitname, backshort = self.directions[exitshort] - backname = self.directions[backshort][0] - - # if we recieved a typeclass for the exit, add it to the alias(short name) - if ":" in self.lhs: - # limit to only the first : character - exit_typeclass = ":" + self.lhs.split(":", 1)[-1] - # exitshort and backshort are the last part of the exit strings, - # so we add our typeclass argument after - exitshort += exit_typeclass - backshort += exit_typeclass - - roomname = "Some place" - if self.rhs: - roomname = self.rhs # this may include aliases; that's fine. - - telswitch = "" - if "tel" in self.switches: - telswitch = "/teleport" - backstring = "" - if "oneway" not in self.switches: - backstring = ", %s;%s" % (backname, backshort) - - # build the string we will use to call dig - digstring = "dig%s %s = %s;%s%s" % (telswitch, roomname, exitname, exitshort, backstring) - self.execute_cmd(digstring)
- - - - - - - - -
[docs]class CmdSetHome(CmdLink): - """ - set an object's home location - - Usage: - sethome <obj> [= <home_location>] - sethom <obj> - - The "home" location is a "safety" location for objects; they - will be moved there if their current location ceases to exist. All - objects should always have a home location for this reason. - It is also a convenient target of the "home" command. - - If no location is given, just view the object's home location. - """ - - key = "@sethome" - locks = "cmd:perm(sethome) or perm(Builder)" - help_category = "Building" - -
[docs] def func(self): - """implement the command""" - if not self.args: - string = "Usage: sethome <obj> [= <home_location>]" - self.caller.msg(string) - return - - obj = self.caller.search(self.lhs, global_search=True) - if not obj: - return - if not self.rhs: - # just view - home = obj.home - if not home: - string = "This object has no home location set!" - else: - string = "%s's current home is %s(%s)." % (obj, home, home.dbref) - else: - # set a home location - new_home = self.caller.search(self.rhs, global_search=True) - if not new_home: - return - old_home = obj.home - obj.home = new_home - if old_home: - string = "Home location of %s was changed from %s(%s) to %s(%s)." % ( - obj, - old_home, - old_home.dbref, - new_home, - new_home.dbref, - ) - else: - string = "Home location of %s was set to %s(%s)." % (obj, new_home, new_home.dbref) - self.caller.msg(string)
- - -
[docs]class CmdListCmdSets(COMMAND_DEFAULT_CLASS): - """ - list command sets defined on an object - - Usage: - cmdsets <obj> - - This displays all cmdsets assigned - to a user. Defaults to yourself. - """ - - key = "@cmdsets" - locks = "cmd:perm(listcmdsets) or perm(Builder)" - help_category = "Building" - -
[docs] def func(self): - """list the cmdsets""" - - caller = self.caller - if self.arglist: - obj = caller.search(self.arglist[0]) - if not obj: - return - else: - obj = caller - string = "%s" % obj.cmdset - caller.msg(string)
- - -
[docs]class CmdName(ObjManipCommand): - """ - change the name and/or aliases of an object - - Usage: - name <obj> = <newname>;alias1;alias2 - - Rename an object to something new. Use *obj to - rename an account. - - """ - - key = "@name" - aliases = ["@rename"] - locks = "cmd:perm(rename) or perm(Builder)" - help_category = "Building" - -
[docs] def func(self): - """change the name""" - - caller = self.caller - if not self.args: - caller.msg("Usage: name <obj> = <newname>[;alias;alias;...]") - return - - obj = None - if self.lhs_objs: - objname = self.lhs_objs[0]["name"] - if objname.startswith("*"): - # account mode - obj = caller.account.search(objname.lstrip("*")) - if obj: - if self.rhs_objs[0]["aliases"]: - caller.msg("Accounts can't have aliases.") - return - newname = self.rhs - if not newname: - caller.msg("No name defined!") - return - if not (obj.access(caller, "control") or obj.access(caller, "edit")): - caller.msg("You don't have right to edit this account %s." % obj) - return - obj.username = newname - obj.save() - caller.msg("Account's name changed to '%s'." % newname) - return - # object search, also with * - obj = caller.search(objname) - if not obj: - return - if self.rhs_objs: - newname = self.rhs_objs[0]["name"] - aliases = self.rhs_objs[0]["aliases"] - else: - newname = self.rhs - aliases = None - if not newname and not aliases: - caller.msg("No names or aliases defined!") - return - if not (obj.access(caller, "control") or obj.access(caller, "edit")): - caller.msg("You don't have the right to edit %s." % obj) - return - # change the name and set aliases: - if newname: - obj.key = newname - astring = "" - if aliases: - [obj.aliases.add(alias) for alias in aliases] - astring = " (%s)" % (", ".join(aliases)) - # fix for exits - we need their exit-command to change name too - if obj.destination: - obj.flush_from_cache(force=True) - caller.msg("Object's name changed to '%s'%s." % (newname, astring))
- - -
[docs]class CmdOpen(ObjManipCommand): - """ - open a new exit from the current room - - Usage: - open <new exit>[;alias;alias..][:typeclass] [,<return exit>[;alias;..][:typeclass]]] = <destination> - - Handles the creation of exits. If a destination is given, the exit - will point there. The <return exit> argument sets up an exit at the - destination leading back to the current room. Destination name - can be given both as a #dbref and a name, if that name is globally - unique. - - """ - - key = "@open" - locks = "cmd:perm(open) or perm(Builder)" - help_category = "Building" - - new_obj_lockstring = "control:id({id}) or perm(Admin);delete:id({id}) or perm(Admin)" - # a custom member method to chug out exits and do checks -
[docs] def create_exit(self, exit_name, location, destination, exit_aliases=None, typeclass=None): - """ - Helper function to avoid code duplication. - At this point we know destination is a valid location - - """ - caller = self.caller - string = "" - # check if this exit object already exists at the location. - # we need to ignore errors (so no automatic feedback)since we - # have to know the result of the search to decide what to do. - exit_obj = caller.search(exit_name, location=location, quiet=True, exact=True) - if len(exit_obj) > 1: - # give error message and return - caller.search(exit_name, location=location, exact=True) - return None - if exit_obj: - exit_obj = exit_obj[0] - if not exit_obj.destination: - # we are trying to link a non-exit - string = "'%s' already exists and is not an exit!\nIf you want to convert it " - string += ( - "to an exit, you must assign an object to the 'destination' property first." - ) - caller.msg(string % exit_name) - return None - # we are re-linking an old exit. - old_destination = exit_obj.destination - if old_destination: - string = "Exit %s already exists." % exit_name - if old_destination.id != destination.id: - # reroute the old exit. - exit_obj.destination = destination - if exit_aliases: - [exit_obj.aliases.add(alias) for alias in exit_aliases] - string += " Rerouted its old destination '%s' to '%s' and changed aliases." % ( - old_destination.name, - destination.name, - ) - else: - string += " It already points to the correct place." - - else: - # exit does not exist before. Create a new one. - lockstring = self.new_obj_lockstring.format(id=caller.id) - if not typeclass: - typeclass = settings.BASE_EXIT_TYPECLASS - exit_obj = create.create_object( - typeclass, - key=exit_name, - location=location, - aliases=exit_aliases, - locks=lockstring, - report_to=caller, - ) - if exit_obj: - # storing a destination is what makes it an exit! - exit_obj.destination = destination - string = ( - "" - if not exit_aliases - else " (aliases: %s)" % (", ".join([str(e) for e in exit_aliases])) - ) - string = "Created new Exit '%s' from %s to %s%s." % ( - exit_name, - location.name, - destination.name, - string, - ) - else: - string = "Error: Exit '%s' not created." % exit_name - # emit results - caller.msg(string) - return exit_obj
- -
[docs] def parse(self): - super().parse() - self.location = self.caller.location - if not self.args or not self.rhs: - self.caller.msg("Usage: open <new exit>[;alias...][:typeclass]" - "[,<return exit>[;alias..][:typeclass]]] " - "= <destination>") - raise InterruptCommand - if not self.location: - self.caller.msg("You cannot create an exit from a None-location.") - raise InterruptCommand - self.destination = self.caller.search(self.rhs, global_search=True) - if not self.destination: - raise InterruptCommand - self.exit_name = self.lhs_objs[0]["name"] - self.exit_aliases = self.lhs_objs[0]["aliases"] - self.exit_typeclass = self.lhs_objs[0]["option"]
- -
[docs] def func(self): - """ - This is where the processing starts. - Uses the ObjManipCommand.parser() for pre-processing - as well as the self.create_exit() method. - """ - # Create exit - ok = self.create_exit(self.exit_name, self.location, self.destination, - self.exit_aliases, self.exit_typeclass) - if not ok: - # an error; the exit was not created, so we quit. - return - # Create back exit, if any - if len(self.lhs_objs) > 1: - back_exit_name = self.lhs_objs[1]["name"] - back_exit_aliases = self.lhs_objs[1]["aliases"] - back_exit_typeclass = self.lhs_objs[1]["option"] - self.create_exit(back_exit_name, self.destination, self.location, back_exit_aliases, - back_exit_typeclass)
- - -def _convert_from_string(cmd, strobj): - """ - Converts a single object in *string form* to its equivalent python - type. - - Python earlier than 2.6: - Handles floats, ints, and limited nested lists and dicts - (can't handle lists in a dict, for example, this is mainly due to - the complexity of parsing this rather than any technical difficulty - - if there is a need for set-ing such complex structures on the - command line we might consider adding it). - Python 2.6 and later: - Supports all Python structures through literal_eval as long as they - are valid Python syntax. If they are not (such as [test, test2], ie - without the quotes around the strings), the entire structure will - be converted to a string and a warning will be given. - - We need to convert like this since all data being sent over the - telnet connection by the Account is text - but we will want to - store it as the "real" python type so we can do convenient - comparisons later (e.g. obj.db.value = 2, if value is stored as a - string this will always fail). - """ - - # Use literal_eval to parse python structure exactly. - try: - return _LITERAL_EVAL(strobj) - except (SyntaxError, ValueError): - # treat as string - strobj = utils.to_str(strobj) - string = ( - '|RNote: name "|r%s|R" was converted to a string. ' - "Make sure this is acceptable." % strobj - ) - cmd.caller.msg(string) - return strobj - except Exception as err: - string = "|RUnknown error in evaluating Attribute: {}".format(err) - return string - - -
[docs]class CmdSetAttribute(ObjManipCommand): - """ - set attribute on an object or account - - Usage: - set[/switch] <obj>/<attr>[:category] = <value> - set[/switch] <obj>/<attr>[:category] = # delete attribute - set[/switch] <obj>/<attr>[:category] # view attribute - set[/switch] *<account>/<attr>[:category] = <value> - - Switch: - edit: Open the line editor (string values only) - script: If we're trying to set an attribute on a script - channel: If we're trying to set an attribute on a channel - account: If we're trying to set an attribute on an account - room: Setting an attribute on a room (global search) - exit: Setting an attribute on an exit (global search) - char: Setting an attribute on a character (global search) - character: Alias for char, as above. - - Example: - set self/foo = "bar" - set/delete self/foo - set self/foo = $dbref(#53) - - Sets attributes on objects. The second example form above clears a - previously set attribute while the third form inspects the current value of - the attribute (if any). The last one (with the star) is a shortcut for - operating on a player Account rather than an Object. - - If you want <value> to be an object, use $dbef(#dbref) or - $search(key) to assign it. You need control or edit access to - the object you are adding. - - The most common data to save with this command are strings and - numbers. You can however also set Python primitives such as lists, - dictionaries and tuples on objects (this might be important for - the functionality of certain custom objects). This is indicated - by you starting your value with one of |c'|n, |c"|n, |c(|n, |c[|n - or |c{ |n. - - Once you have stored a Python primitive as noted above, you can include - |c[<key>]|n in <attr> to reference nested values in e.g. a list or dict. - - Remember that if you use Python primitives like this, you must - write proper Python syntax too - notably you must include quotes - around your strings or you will get an error. - - """ - - key = "@set" - locks = "cmd:perm(set) or perm(Builder)" - help_category = "Building" - nested_re = re.compile(r"\[.*?\]") - not_found = object() - -
[docs] def check_obj(self, obj): - """ - This may be overridden by subclasses in case restrictions need to be - placed on whether certain objects can have attributes set by certain - accounts. - - This function is expected to display its own error message. - - Returning False will abort the command. - """ - return True
- -
[docs] def check_attr(self, obj, attr_name, category): - """ - This may be overridden by subclasses in case restrictions need to be - placed on what attributes can be set by who beyond the normal lock. - - This functions is expected to display its own error message. It is - run once for every attribute that is checked, blocking only those - attributes which are not permitted and letting the others through. - """ - return attr_name
- -
[docs] def split_nested_attr(self, attr): - """ - Yields tuples of (possible attr name, nested keys on that attr). - For performance, this is biased to the deepest match, but allows compatability - with older attrs that might have been named with `[]`'s. - - > list(split_nested_attr("nested['asdf'][0]")) - [ - ('nested', ['asdf', 0]), - ("nested['asdf']", [0]), - ("nested['asdf'][0]", []), - ] - """ - quotes = "\"'" - - def clean_key(val): - val = val.strip("[]") - if val[0] in quotes: - return val.strip(quotes) - if val[0] == LIST_APPEND_CHAR: - # List insert/append syntax - return val - try: - return int(val) - except ValueError: - return val - - parts = self.nested_re.findall(attr) - - base_attr = "" - if parts: - base_attr = attr[: attr.find(parts[0])] - for index, part in enumerate(parts): - yield (base_attr, [clean_key(p) for p in parts[index:]]) - base_attr += part - yield (attr, [])
- -
[docs] def do_nested_lookup(self, value, *keys): - result = value - for key in keys: - try: - result = result.__getitem__(key) - except (IndexError, KeyError, TypeError): - return self.not_found - return result
- -
[docs] def view_attr(self, obj, attr, category): - """ - Look up the value of an attribute and return a string displaying it. - """ - nested = False - for key, nested_keys in self.split_nested_attr(attr): - nested = True - if obj.attributes.has(key): - val = obj.attributes.get(key) - val = self.do_nested_lookup(val, *nested_keys) - if val is not self.not_found: - return f"\nAttribute {obj.name}/|w{attr}|n [category:{category}] = {val}" - error = f"\nAttribute {obj.name}/|w{attr} [category:{category}] does not exist." - if nested: - error += " (Nested lookups attempted)" - return error
- -
[docs] def rm_attr(self, obj, attr, category): - """ - Remove an attribute from the object, or a nested data structure, and report back. - """ - nested = False - for key, nested_keys in self.split_nested_attr(attr): - nested = True - if obj.attributes.has(key, category): - if nested_keys: - del_key = nested_keys[-1] - val = obj.attributes.get(key, category=category) - deep = self.do_nested_lookup(val, *nested_keys[:-1]) - if deep is not self.not_found: - try: - del deep[del_key] - except (IndexError, KeyError, TypeError): - continue - return f"\nDeleted attribute {obj.name}/|w{attr}|n [category:{category}]." - else: - exists = obj.attributes.has(key, category) - if exists: - obj.attributes.remove(attr, category=category) - return f"\nDeleted attribute {obj.name}/|w{attr}|n [category:{category}]." - else: - return (f"\nNo attribute {obj.name}/|w{attr}|n [category: {category}] " - "was found to delete.") - error = f"\nNo attribute {obj.name}/|w{attr}|n [category: {category}] was found to delete." - if nested: - error += " (Nested lookups attempted)" - return error
- -
[docs] def set_attr(self, obj, attr, value, category): - done = False - for key, nested_keys in self.split_nested_attr(attr): - if obj.attributes.has(key, category) and nested_keys: - acc_key = nested_keys[-1] - lookup_value = obj.attributes.get(key, category) - deep = self.do_nested_lookup(lookup_value, *nested_keys[:-1]) - if deep is not self.not_found: - # To support appending and inserting to lists - # a key that starts with LIST_APPEND_CHAR will insert a new item at that - # location, and move the other elements down. - # Using LIST_APPEND_CHAR alone will append to the list - if isinstance(acc_key, str) and acc_key[0] == LIST_APPEND_CHAR: - try: - if len(acc_key) > 1: - where = int(acc_key[1:]) - deep.insert(where, value) - else: - deep.append(value) - except (ValueError, AttributeError): - pass - else: - value = lookup_value - attr = key - done = True - break - - # List magic failed, just use like a key/index - try: - deep[acc_key] = value - except TypeError as err: - # Tuples can't be modified - return f"\n{err} - {deep}" - - value = lookup_value - attr = key - done = True - break - - verb = "Modified" if obj.attributes.has(attr) else "Created" - try: - if not done: - obj.attributes.add(attr, value, category) - return f"\n{verb} attribute {obj.name}/|w{attr}|n [category:{category}] = {value}" - except SyntaxError: - # this means literal_eval tried to parse a faulty string - return ( - "\n|RCritical Python syntax error in your value. Only " - "primitive Python structures are allowed.\nYou also " - "need to use correct Python syntax. Remember especially " - "to put quotes around all strings inside lists and " - "dicts.|n" - )
- - @interactive - def edit_handler(self, obj, attr, caller): - """Activate the line editor""" - - def load(caller): - """Called for the editor to load the buffer""" - - try: - old_value = obj.attributes.get(attr, raise_exception=True) - except AttributeError: - # we set empty buffer on nonexisting Attribute because otherwise - # we'd always have the string "None" in the buffer to start with - old_value = '' - return str(old_value) # we already confirmed we are ok with this - - def save(caller, buf): - """Called when editor saves its buffer.""" - obj.attributes.add(attr, buf) - caller.msg("Saved Attribute %s." % attr) - - # check non-strings before activating editor - try: - old_value = obj.attributes.get(attr, raise_exception=True) - if not isinstance(old_value, str): - answer = yield( - f"|rWarning: Attribute |w{attr}|r is of type |w{type(old_value).__name__}|r. " - "\nTo continue editing, it must be converted to (and saved as) a string. " - "Continue? [Y]/N?") - if answer.lower() in ('n', 'no'): - self.caller.msg("Aborted edit.") - return - except AttributeError: - pass - - # start the editor - EvEditor(self.caller, load, save, key=f"{obj}/{attr}") - -
[docs] def search_for_obj(self, objname): - """ - Searches for an object matching objname. The object may be of different typeclasses. - Args: - objname: Name of the object we're looking for - - Returns: - A typeclassed object, or None if nothing is found. - """ - from evennia.utils.utils import variable_from_module - - _AT_SEARCH_RESULT = variable_from_module(*settings.SEARCH_AT_RESULT.rsplit(".", 1)) - caller = self.caller - if objname.startswith("*") or "account" in self.switches: - found_obj = caller.search_account(objname.lstrip("*")) - elif "script" in self.switches: - found_obj = _AT_SEARCH_RESULT(search.search_script(objname), caller) - elif "channel" in self.switches: - found_obj = _AT_SEARCH_RESULT(search.search_channel(objname), caller) - else: - global_search = True - if "char" in self.switches or "character" in self.switches: - typeclass = settings.BASE_CHARACTER_TYPECLASS - elif "room" in self.switches: - typeclass = settings.BASE_ROOM_TYPECLASS - elif "exit" in self.switches: - typeclass = settings.BASE_EXIT_TYPECLASS - else: - global_search = False - typeclass = None - found_obj = caller.search(objname, global_search=global_search, typeclass=typeclass) - return found_obj
- -
[docs] def func(self): - """Implement the set attribute - a limited form of py.""" - - caller = self.caller - if not self.args: - caller.msg("Usage: set obj/attr[:category] = value. Use empty value to clear.") - return - - # get values prepared by the parser - value = self.rhs - objname = self.lhs_objattr[0]["name"] - attrs = self.lhs_objattr[0]["attrs"] - category = self.lhs_objs[0].get("option") # None if unset - - obj = self.search_for_obj(objname) - if not obj: - return - - if not self.check_obj(obj): - return - - result = [] - if "edit" in self.switches: - # edit in the line editor - if not (obj.access(self.caller, "control") or obj.access(self.caller, "edit")): - caller.msg("You don't have permission to edit %s." % obj.key) - return - - if len(attrs) > 1: - caller.msg("The Line editor can only be applied " "to one attribute at a time.") - return - if not attrs: - caller.msg("Use `set/edit <objname>/<attr>` to define the Attribute to edit.\nTo " - "edit the current room description, use `set/edit here/desc` (or " - "use the `desc` command).") - return - self.edit_handler(obj, attrs[0], caller) - return - if not value: - if self.rhs is None: - # no = means we inspect the attribute(s) - if not attrs: - attrs = [attr.key for attr in obj.attributes.get(category=None)] - for attr in attrs: - if not self.check_attr(obj, attr, category): - continue - result.append(self.view_attr(obj, attr, category)) - # we view it without parsing markup. - self.caller.msg("".join(result).strip(), options={"raw": True}) - return - else: - # deleting the attribute(s) - if not (obj.access(self.caller, "control") or obj.access(self.caller, "edit")): - caller.msg("You don't have permission to edit %s." % obj.key) - return - for attr in attrs: - if not self.check_attr(obj, attr, category): - continue - result.append(self.rm_attr(obj, attr, category)) - else: - # setting attribute(s). Make sure to convert to real Python type before saving. - # add support for $dbref() and $search() in set argument - global _ATTRFUNCPARSER - if not _ATTRFUNCPARSER: - _ATTRFUNCPARSER = funcparser.FuncParser( - {"dbref": funcparser.funcparser_callable_search, - "search": funcparser.funcparser_callable_search} - ) - - if not (obj.access(self.caller, "control") or obj.access(self.caller, "edit")): - caller.msg("You don't have permission to edit %s." % obj.key) - return - for attr in attrs: - if not self.check_attr(obj, attr, category): - continue - # from evennia import set_trace;set_trace() - parsed_value = _ATTRFUNCPARSER.parse(value, return_str=False, caller=caller) - if hasattr(parsed_value, "access"): - # if this is an object we must have the right to read it, if so, - # we will not convert it to a string - if not (parsed_value.access(caller, "control") - or parsed_value.access(self.caller, "edit")): - caller.msg("You don't have permission to set " - f"object with identifier '{value}'.") - continue - value = parsed_value - else: - value = _convert_from_string(self, value) - result.append(self.set_attr(obj, attr, value, category)) - # send feedback - caller.msg("".join(result).strip("\n"))
- - -
[docs]class CmdTypeclass(COMMAND_DEFAULT_CLASS): - """ - set or change an object's typeclass - - Usage: - typeclass[/switch] <object> [= typeclass.path] - typeclass/prototype <object> = prototype_key - - typeclasses or typeclass/list/show [typeclass.path] - swap - this is a shorthand for using /force/reset flags. - update - this is a shorthand for using the /force/reload flag. - - Switch: - show, examine - display the current typeclass of object (default) or, if - given a typeclass path, show the docstring of that typeclass. - update - *only* re-run at_object_creation on this object - meaning locks or other properties set later may remain. - reset - clean out *all* the attributes and properties on the - object - basically making this a new clean object. This will also - reset cmdsets! - force - change to the typeclass also if the object - already has a typeclass of the same name. - list - show available typeclasses. Only typeclasses in modules actually - imported or used from somewhere in the code will show up here - (those typeclasses are still available if you know the path) - prototype - clean and overwrite the object with the specified - prototype key - effectively making a whole new object. - - Example: - type button = examples.red_button.RedButton - type/prototype button=a red button - - If the typeclass_path is not given, the current object's typeclass is - assumed. - - View or set an object's typeclass. If setting, the creation hooks of the - new typeclass will be run on the object. If you have clashing properties on - the old class, use /reset. By default you are protected from changing to a - typeclass of the same name as the one you already have - use /force to - override this protection. - - The given typeclass must be identified by its location using python - dot-notation pointing to the correct module and class. If no typeclass is - given (or a wrong typeclass is given). Errors in the path or new typeclass - will lead to the old typeclass being kept. The location of the typeclass - module is searched from the default typeclass directory, as defined in the - server settings. - - """ - - key = "@typeclass" - aliases = ["@type", "@parent", "@swap", "@update", "@typeclasses"] - switch_options = ("show", "examine", "update", "reset", "force", "list", "prototype") - locks = "cmd:perm(typeclass) or perm(Builder)" - help_category = "Building" - - def _generic_search(self, query, typeclass_path): - - caller = self.caller - if typeclass_path: - # make sure we search the right database table - try: - new_typeclass = class_from_module(typeclass_path) - except ImportError: - # this could be a prototype and not a typeclass at all - return caller.search(query) - - dbclass = new_typeclass.__dbclass__ - - if caller.__dbclass__ == dbclass: - # object or account match - obj = caller.search(query) - if not obj: - return - elif (self.account and self.account.__dbclass__ == dbclass): - # applying account while caller is object - caller.msg(f"Trying to search {new_typeclass} with query '{self.lhs}'.") - obj = self.account.search(query) - if not obj: - return - elif hasattr(caller, "puppet") and caller.puppet.__dbclass__ == dbclass: - # applying object while caller is account - caller.msg(f"Trying to search {new_typeclass} with query '{self.lhs}'.") - obj = caller.puppet.search(query) - if not obj: - return - else: - # other mismatch between caller and specified typeclass - caller.msg(f"Trying to search {new_typeclass} with query '{self.lhs}'.") - obj = new_typeclass.search(query) - if not obj: - if isinstance(obj, list): - caller.msg(f"Could not find {new_typeclass} with query '{self.lhs}'.") - return - else: - # no rhs, use caller's typeclass - obj = caller.search(query) - if not obj: - return - - return obj - -
[docs] def func(self): - """Implements command""" - - caller = self.caller - - if "list" in self.switches or self.cmdname in ('typeclasses', '@typeclasses'): - tclasses = get_all_typeclasses() - contribs = [key for key in sorted(tclasses) if key.startswith("evennia.contrib")] or [ - "<None loaded>" - ] - core = [ - key for key in sorted(tclasses) if key.startswith("evennia") and key not in contribs - ] or ["<None loaded>"] - game = [key for key in sorted(tclasses) if not key.startswith("evennia")] or [ - "<None loaded>" - ] - string = ( - "|wCore typeclasses|n\n" - " {core}\n" - "|wLoaded Contrib typeclasses|n\n" - " {contrib}\n" - "|wGame-dir typeclasses|n\n" - " {game}" - ).format( - core="\n ".join(core), contrib="\n ".join(contribs), game="\n ".join(game) - ) - EvMore(caller, string, exit_on_lastpage=True) - return - - if not self.args: - caller.msg("Usage: %s <object> [= typeclass]" % self.cmdstring) - return - - if "show" in self.switches or "examine" in self.switches: - oquery = self.lhs - obj = caller.search(oquery, quiet=True) - if not obj: - # no object found to examine, see if it's a typeclass-path instead - tclasses = get_all_typeclasses() - matches = [ - (key, tclass) for key, tclass in tclasses.items() if key.endswith(oquery) - ] - nmatches = len(matches) - if nmatches > 1: - caller.msg( - "Multiple typeclasses found matching {}:\n {}".format( - oquery, "\n ".join(tup[0] for tup in matches) - ) - ) - elif not matches: - caller.msg("No object or typeclass path found to match '{}'".format(oquery)) - else: - # one match found - caller.msg( - "Docstring for typeclass '{}':\n{}".format(oquery, matches[0][1].__doc__) - ) - else: - # do the search again to get the error handling in case of multi-match - obj = caller.search(oquery) - if not obj: - return - caller.msg( - "{}'s current typeclass is '{}.{}'".format( - obj.name, obj.__class__.__module__, obj.__class__.__name__ - ) - ) - return - - obj = self._generic_search(self.lhs, self.rhs) - if not obj: - return - - if not hasattr(obj, "__dbclass__"): - string = "%s is not a typed object." % obj.name - caller.msg(string) - return - - new_typeclass = self.rhs or obj.path - - prototype = None - if "prototype" in self.switches: - key = self.rhs - prototype = protlib.search_prototype(key=key) - if len(prototype) > 1: - caller.msg( - "More than one match for {}:\n{}".format( - key, "\n".join(proto.get("prototype_key", "") for proto in prototype) - ) - ) - return - elif prototype: - # one match - prototype = prototype[0] - else: - # no match - caller.msg("No prototype '{}' was found.".format(key)) - return - new_typeclass = prototype["typeclass"] - self.switches.append("force") - - if "show" in self.switches or "examine" in self.switches: - string = "%s's current typeclass is %s." % (obj.name, obj.__class__) - caller.msg(string) - return - - if self.cmdstring in ("swap", "@swap"): - self.switches.append("force") - self.switches.append("reset") - elif self.cmdstring in ("update", "@update"): - self.switches.append("force") - self.switches.append("update") - - if not (obj.access(caller, "control") or obj.access(caller, "edit")): - caller.msg("You are not allowed to do that.") - return - - if not hasattr(obj, "swap_typeclass"): - caller.msg("This object cannot have a type at all!") - return - - is_same = obj.is_typeclass(new_typeclass, exact=True) - if is_same and "force" not in self.switches: - string = (f"{obj.name} already has the typeclass '{new_typeclass}'. " - "Use /force to override.") - else: - update = "update" in self.switches - reset = "reset" in self.switches - hooks = "at_object_creation" if update and not reset else "all" - old_typeclass_path = obj.typeclass_path - - # special prompt for the user in cases where we want - # to confirm changes. - if "prototype" in self.switches: - diff, _ = spawner.prototype_diff_from_object(prototype, obj) - txt = spawner.format_diff(diff) - prompt = ( - "Applying prototype '%s' over '%s' will cause the follow changes:\n%s\n" - % (prototype["key"], obj.name, txt) - ) - if not reset: - prompt += "\n|yWARNING:|n Use the /reset switch to apply the prototype over a blank state." - prompt += "\nAre you sure you want to apply these changes [yes]/no?" - answer = yield (prompt) - if answer and answer in ("no", "n"): - caller.msg("Canceled: No changes were applied.") - return - - # we let this raise exception if needed - obj.swap_typeclass( - new_typeclass, clean_attributes=reset, clean_cmdsets=reset, run_start_hooks=hooks - ) - - if "prototype" in self.switches: - modified = spawner.batch_update_objects_with_prototype( - prototype, objects=[obj], caller=self.caller) - prototype_success = modified > 0 - if not prototype_success: - caller.msg("Prototype %s failed to apply." % prototype["key"]) - - if is_same: - string = "%s updated its existing typeclass (%s).\n" % (obj.name, obj.path) - else: - string = "%s changed typeclass from %s to %s.\n" % ( - obj.name, - old_typeclass_path, - obj.typeclass_path, - ) - if update: - string += "Only the at_object_creation hook was run (update mode)." - else: - string += "All object creation hooks were run." - if reset: - string += " All old attributes where deleted before the swap." - else: - string += " Attributes set before swap were not removed." - if "prototype" in self.switches and prototype_success: - string += ( - " Prototype '%s' was successfully applied over the object type." - % prototype["key"] - ) - - caller.msg(string)
- - -
[docs]class CmdWipe(ObjManipCommand): - """ - clear all attributes from an object - - Usage: - wipe <object>[/<attr>[/<attr>...]] - - Example: - wipe box - wipe box/colour - - Wipes all of an object's attributes, or optionally only those - matching the given attribute-wildcard search string. - """ - - key = "@wipe" - locks = "cmd:perm(wipe) or perm(Builder)" - help_category = "Building" - -
[docs] def func(self): - """ - inp is the dict produced in ObjManipCommand.parse() - """ - - caller = self.caller - - if not self.args: - caller.msg("Usage: wipe <object>[/<attr>/<attr>...]") - return - - # get the attributes set by our custom parser - objname = self.lhs_objattr[0]["name"] - attrs = self.lhs_objattr[0]["attrs"] - - obj = caller.search(objname) - if not obj: - return - if not (obj.access(caller, "control") or obj.access(caller, "edit")): - caller.msg("You are not allowed to do that.") - return - if not attrs: - # wipe everything - obj.attributes.clear() - string = "Wiped all attributes on %s." % obj.name - else: - for attrname in attrs: - obj.attributes.remove(attrname) - string = "Wiped attributes %s on %s." - string = string % (",".join(attrs), obj.name) - caller.msg(string)
- - -
[docs]class CmdLock(ObjManipCommand): - """ - assign a lock definition to an object - - Usage: - lock <object or *account>[ = <lockstring>] - or - lock[/switch] <object or *account>/<access_type> - - Switch: - del - delete given access type - view - view lock associated with given access type (default) - - If no lockstring is given, shows all locks on - object. - - Lockstring is of the form - access_type:[NOT] func1(args)[ AND|OR][ NOT] func2(args) ...] - Where func1, func2 ... valid lockfuncs with or without arguments. - Separator expressions need not be capitalized. - - For example: - 'get: id(25) or perm(Admin)' - The 'get' lock access_type is checked e.g. by the 'get' command. - An object locked with this example lock will only be possible to pick up - by Admins or by an object with id=25. - - You can add several access_types after one another by separating - them by ';', i.e: - 'get:id(25); delete:perm(Builder)' - """ - - key = "@lock" - aliases = ["@locks"] - locks = "cmd: perm(locks) or perm(Builder)" - help_category = "Building" - -
[docs] def func(self): - """Sets up the command""" - - caller = self.caller - if not self.args: - string = ( - "Usage: lock <object>[ = <lockstring>] or lock[/switch] " "<object>/<access_type>" - ) - caller.msg(string) - return - - if "/" in self.lhs: - # call of the form lock obj/access_type - objname, access_type = [p.strip() for p in self.lhs.split("/", 1)] - obj = None - if objname.startswith("*"): - obj = caller.search_account(objname.lstrip("*")) - if not obj: - obj = caller.search(objname) - if not obj: - return - has_control_access = obj.access(caller, "control") - if access_type == "control" and not has_control_access: - # only allow to change 'control' access if you have 'control' access already - caller.msg("You need 'control' access to change this type of lock.") - return - - if not (has_control_access or obj.access(caller, "edit")): - caller.msg("You are not allowed to do that.") - return - - lockdef = obj.locks.get(access_type) - - if lockdef: - if "del" in self.switches: - obj.locks.delete(access_type) - string = "deleted lock %s" % lockdef - else: - string = lockdef - else: - string = "%s has no lock of access type '%s'." % (obj, access_type) - caller.msg(string) - return - - if self.rhs: - # we have a = separator, so we are assigning a new lock - if self.switches: - swi = ", ".join(self.switches) - caller.msg( - "Switch(es) |w%s|n can not be used with a " - "lock assignment. Use e.g. " - "|wlock/del objname/locktype|n instead." % swi - ) - return - - objname, lockdef = self.lhs, self.rhs - obj = None - if objname.startswith("*"): - obj = caller.search_account(objname.lstrip("*")) - if not obj: - obj = caller.search(objname) - if not obj: - return - if not (obj.access(caller, "control") or obj.access(caller, "edit")): - caller.msg("You are not allowed to do that.") - return - ok = False - lockdef = re.sub(r"\'|\"", "", lockdef) - try: - ok = obj.locks.add(lockdef) - except LockException as e: - caller.msg(str(e)) - if "cmd" in lockdef.lower() and inherits_from( - obj, "evennia.objects.objects.DefaultExit" - ): - # special fix to update Exits since "cmd"-type locks won't - # update on them unless their cmdsets are rebuilt. - obj.at_init() - if ok: - caller.msg("Added lock '%s' to %s." % (lockdef, obj)) - return - - # if we get here, we are just viewing all locks on obj - obj = None - if self.lhs.startswith("*"): - obj = caller.search_account(self.lhs.lstrip("*")) - if not obj: - obj = caller.search(self.lhs) - if not obj: - return - if not (obj.access(caller, "control") or obj.access(caller, "edit")): - caller.msg("You are not allowed to do that.") - return - caller.msg("\n".join(obj.locks.all()))
- - -
[docs]class CmdExamine(ObjManipCommand): - """ - get detailed information about an object - - Usage: - examine [<object>[/attrname]] - examine [*<account>[/attrname]] - - Switch: - account - examine an Account (same as adding *) - object - examine an Object (useful when OOC) - script - examine a Script - channel - examine a Channel - - The examine command shows detailed game info about an - object and optionally a specific attribute on it. - If object is not specified, the current location is examined. - - Append a * before the search string to examine an account. - - """ - - key = "@examine" - aliases = ["@ex", "@exam"] - locks = "cmd:perm(examine) or perm(Builder)" - help_category = "Building" - arg_regex = r"(/\w+?(\s|$))|\s|$" - switch_options = ["account", "object", "script", "channel"] - - object_type = "object" - - detail_color = "|c" - header_color = "|w" - quell_color = "|r" - separator = "-" - -
[docs] def msg(self, text): - """ - Central point for sending messages to the caller. This tags - the message as 'examine' for eventual custom markup in the client. - - Attributes: - text (str): The text to send. - - """ - self.caller.msg(text=(text, {"type": "examine"}))
- -
[docs] def format_key(self, obj): - return f"{obj.name} ({obj.dbref})"
- -
[docs] def format_aliases(self, obj): - if hasattr(obj, "aliases") and obj.aliases.all(): - return ", ".join(utils.make_iter(str(obj.aliases)))
- -
[docs] def format_typeclass(self, obj): - if hasattr(obj, "typeclass_path"): - return f"{obj.typename} ({obj.typeclass_path})"
- -
[docs] def format_sessions(self, obj): - if hasattr(obj, "sessions"): - sessions = obj.sessions.all() - if sessions: - return ", ".join(f"#{sess.sessid}" for sess in obj.sessions.all())
- -
[docs] def format_email(self, obj): - if hasattr(obj, "email") and obj.email: - return f"{self.detail_color}{obj.email}|n"
- -
[docs] def format_account_key(self, account): - return f"{self.detail_color}{account.name}|n ({account.dbref})"
- -
[docs] def format_account_typeclass(self, account): - return f"{account.typename} ({account.typeclass_path})"
- -
[docs] def format_account_permissions(self, account): - perms = account.permissions.all() - if account.is_superuser: - perms = ["<Superuser>"] - elif not perms: - perms = ["<None>"] - perms = ", ".join(perms) - if account.attributes.has("_quell"): - perms += f" {self.quell_color}(quelled)|n" - return perms
- -
[docs] def format_location(self, obj): - if hasattr(obj, "location") and obj.location: - return f"{obj.location.key} (#{obj.location.id})"
- -
[docs] def format_home(self, obj): - if hasattr(obj, "home") and obj.home: - return f"{obj.home.key} (#{obj.home.id})"
- -
[docs] def format_destination(self, obj): - if hasattr(obj, "destination") and obj.destination: - return f"{obj.destination.key} (#{obj.destination.id})"
- -
[docs] def format_permissions(self, obj): - perms = obj.permissions.all() - if perms: - perms_string = ", ".join(perms) - if obj.is_superuser: - perms_string += " <Superuser>" - return perms_string
- -
[docs] def format_locks(self, obj): - locks = str(obj.locks) - if locks: - return utils.fill( - "; ".join([lock for lock in locks.split(";")]), indent=2 - ) - return "Default"
- -
[docs] def format_scripts(self, obj): - if hasattr(obj, "scripts") and hasattr(obj.scripts, "all") and obj.scripts.all(): - return f"{obj.scripts}"
- -
[docs] def format_single_tag(self, tag): - if tag.db_category: - return f"{tag.db_key}[{tag.db_category}]" - else: - return f"{tag.db_key}"
- -
[docs] def format_tags(self, obj): - if hasattr(obj, "tags"): - tags = sorted(obj.tags.all(return_objs=True)) - if tags: - formatted_tags = [self.format_single_tag(tag) for tag in tags] - return utils.fill(", ".join(formatted_tags), indent=2)
- -
[docs] def format_single_cmdset_options(self, cmdset): - def _truefalse(string, value): - if value is None: - return "" - if value: - return f"{string}: T" - return f"{string}: F" - return ", ".join( - _truefalse(opt, getattr(cmdset, opt)) - for opt in ("no_exits", "no_objs", "no_channels", "duplicates") - if getattr(cmdset, opt) is not None - )
- -
[docs] def format_single_cmdset(self, cmdset): - options = self.format_single_cmdset_options(cmdset) - return f"{cmdset.path} [{cmdset.key}] ({cmdset.mergetype}, prio {cmdset.priority}{options}"
- -
[docs] def format_stored_cmdsets(self, obj): - if hasattr(obj, "cmdset"): - stored_cmdset_strings = [] - stored_cmdsets = sorted(obj.cmdset.all(), key=lambda x: x.priority, reverse=True) - for cmdset in stored_cmdsets: - if cmdset.key != "_EMPTY_CMDSET": - stored_cmdset_strings.append(self.format_single_cmdset(cmdset)) - return "\n " + "\n ".join(stored_cmdset_strings)
- -
[docs] def format_merged_cmdsets(self, obj, current_cmdset): - if not hasattr(obj, "cmdset"): - return None - - all_cmdsets = [(cmdset.key, cmdset) for cmdset in current_cmdset.merged_from] - # we always at least try to add account- and session sets since these are ignored - # if we merge on the object level. - if hasattr(obj, "account") and obj.account: - # get Attribute-cmdsets if they exist - all_cmdsets.extend([(cmdset.key, cmdset) for cmdset in obj.account.cmdset.all()]) - if obj.sessions.count(): - # if there are more sessions than one on objects it's because of multisession mode - # we only show the first session's cmdset here (it is -in principle- possible - # that different sessions have different cmdsets but for admins who want such - # madness it is better that they overload with their own CmdExamine to handle it). - all_cmdsets.extend([(cmdset.key, cmdset) - for cmdset in obj.account.sessions.all()[0].cmdset.all()]) - else: - try: - # we have to protect this since many objects don't have sessions. - all_cmdsets.extend([(cmdset.key, cmdset) - for cmdset in obj.get_session(obj.sessions.get()).cmdset.all()]) - except (TypeError, AttributeError): - # an error means we are merging an object without a session - pass - all_cmdsets = [cmdset for cmdset in dict(all_cmdsets).values()] - all_cmdsets.sort(key=lambda x: x.priority, reverse=True) - - merged_cmdset_strings = [] - for cmdset in all_cmdsets: - if cmdset.key != "_EMPTY_CMDSET": - merged_cmdset_strings.append(self.format_single_cmdset(cmdset)) - return "\n " + "\n ".join(merged_cmdset_strings)
- -
[docs] def format_current_cmds(self, obj, current_cmdset): - current_commands = sorted([cmd.key for cmd in current_cmdset if cmd.access(obj, "cmd")]) - return "\n" + utils.fill(", ".join(current_commands), indent=2)
- - def _get_attribute_value_type(self, attrvalue): - typ = "" - if not isinstance(attrvalue, str): - try: - name = attrvalue.__class__.__name__ - except AttributeError: - try: - name = attrvalue.__name__ - except AttributeError: - name = attrvalue - if str(name).startswith("_Saver"): - try: - typ = str(type(deserialize(attrvalue))) - except Exception: - typ = str(type(deserialize(attrvalue))) - else: - typ = str(type(attrvalue)) - return typ - -
[docs] def format_single_attribute_detail(self, obj, attr): - global _FUNCPARSER - if not _FUNCPARSER: - _FUNCPARSER = funcparser.FuncParser(settings.FUNCPARSER_OUTGOING_MESSAGES_MODULES) - - key, category, value = attr.db_key, attr.db_category, attr.value - typ = self._get_attribute_value_type(value) - typ = f" |B[type: {typ}]|n" if typ else "" - value = utils.to_str(value) - value = _FUNCPARSER.parse(ansi_raw(value), escape=True) - return (f"Attribute {obj.name}/{self.header_color}{key}|n " - f"[category={category}]{typ}:\n\n{value}")
- -
[docs] def format_single_attribute(self, attr): - global _FUNCPARSER - if not _FUNCPARSER: - _FUNCPARSER = funcparser.FuncParser(settings.FUNCPARSER_OUTGOING_MESSAGES_MODULES) - - key, category, value = attr.db_key, attr.db_category, attr.value - typ = self._get_attribute_value_type(value) - typ = f" |B[type: {typ}]|n" if typ else "" - value = utils.to_str(value) - value = _FUNCPARSER.parse(ansi_raw(value), escape=True) - value = utils.crop(value) - if category: - return f"{self.header_color}{key}|n[{category}]={value}{typ}" - else: - return f"{self.header_color}{key}|n={value}{typ}"
- -
[docs] def format_attributes(self, obj): - output = "\n " + "\n ".join( - sorted(self.format_single_attribute(attr) - for attr in obj.db_attributes.all()) - ) - if output.strip(): - # we don't want just an empty line - return output
- -
[docs] def format_nattributes(self, obj): - try: - ndb_attr = obj.nattributes.all(return_tuples=True) - except Exception: - return - - if ndb_attr and ndb_attr[0]: - return "\n " + " \n".join( - sorted(self.format_single_attribute(attr) - for attr, value in ndb_attr) - )
- -
[docs] def format_exits(self, obj): - if hasattr(obj, "exits"): - exits = ", ".join(f"{exit.name}({exit.dbref})" for exit in obj.exits) - return exits if exits else None
- -
[docs] def format_chars(self, obj): - if hasattr(obj, "contents"): - chars = ", ".join(f"{obj.name}({obj.dbref})" for obj in obj.contents - if obj.account) - return chars if chars else None
- -
[docs] def format_things(self, obj): - if hasattr(obj, "contents"): - things = ", ".join(f"{obj.name}({obj.dbref})" for obj in obj.contents - if not obj.account and not obj.destination) - return things if things else None
- -
[docs] def format_script_desc(self, obj): - if hasattr(obj, "db_desc") and obj.db_desc: - return crop(obj.db_desc, 20)
- -
[docs] def format_script_is_persistent(self, obj): - if hasattr(obj, "db_persistent"): - return "T" if obj.db_persistent else "F"
- -
[docs] def format_script_timer_data(self, obj): - if hasattr(obj, "db_interval") and obj.db_interval > 0: - start_delay = "T" if obj.db_start_delay else "F" - next_repeat = obj.time_until_next_repeat() - active = "|grunning|n" if obj.db_is_active and next_repeat else "|rinactive|n" - interval = obj.db_interval - next_repeat = "N/A" if next_repeat is None else f"{next_repeat}s" - repeats = "" - if obj.db_repeats: - remaining_repeats = obj.remaining_repeats() - remaining_repeats = 0 if remaining_repeats is None else remaining_repeats - repeats = f" - {remaining_repeats}/{obj.db_repeats} remain" - return (f"{active} - interval: {interval}s " - f"(next: {next_repeat}{repeats}, start_delay: {start_delay})")
- -
[docs] def format_channel_sub_totals(self, obj): - if hasattr(obj, "db_account_subscriptions"): - account_subs = obj.db_account_subscriptions.all() - object_subs = obj.db_object_subscriptions.all() - online = len(obj.subscriptions.online()) - ntotal = account_subs.count() + object_subs.count() - return f"{ntotal} ({online} online)"
- -
[docs] def format_channel_account_subs(self, obj): - if hasattr(obj, "db_account_subscriptions"): - account_subs = obj.db_account_subscriptions.all() - if account_subs: - return "\n " + "\n ".join( - format_grid([sub.key for sub in account_subs], sep=' ', width=_DEFAULT_WIDTH))
- -
[docs] def format_channel_object_subs(self, obj): - if hasattr(obj, "db_object_subscriptions"): - object_subs = obj.db_object_subscriptions.all() - if object_subs: - return "\n " + "\n ".join( - format_grid([sub.key for sub in object_subs], sep=' ', width=_DEFAULT_WIDTH))
- -
[docs] def get_formatted_obj_data(self, obj, current_cmdset): - """ - Calls all other `format_*` methods. - - """ - objdata = {} - objdata["Name/key"] = self.format_key(obj) - objdata["Aliases"] = self.format_aliases(obj) - objdata["Typeclass"] = self.format_typeclass(obj) - objdata["Sessions"] = self.format_sessions(obj) - objdata["Email"] = self.format_email(obj) - if hasattr(obj, "has_account") and obj.has_account: - objdata["Account"] = self.format_account_key(obj.account) - objdata[" Account Typeclass"] = self.format_account_typeclass(obj.account) - objdata[" Account Permissions"] = self.format_account_permissions(obj.account) - objdata["Location"] = self.format_location(obj) - objdata["Home"] = self.format_home(obj) - objdata["Destination"] = self.format_destination(obj) - objdata["Permissions"] = self.format_permissions(obj) - objdata["Locks"] = self.format_locks(obj) - if (current_cmdset - and not (len(obj.cmdset.all()) == 1 - and obj.cmdset.current.key == "_EMPTY_CMDSET")): - objdata["Stored Cmdset(s)"] = self.format_stored_cmdsets(obj) - objdata["Merged Cmdset(s)"] = self.format_merged_cmdsets(obj, current_cmdset) - objdata[f"Commands vailable to {obj.key} (result of Merged Cmdset(s))"] = ( - self.format_current_cmds(obj, current_cmdset)) - if self.object_type == "script": - objdata["Description"] = self.format_script_desc(obj) - objdata["Persistent"] = self.format_script_is_persistent(obj) - objdata["Script Repeat"] = self.format_script_timer_data(obj) - objdata["Scripts"] = self.format_scripts(obj) - objdata["Tags"] = self.format_tags(obj) - objdata["Persistent Attributes"] = self.format_attributes(obj) - objdata["Non-Persistent Attributes"] = self.format_nattributes(obj) - objdata["Exits"] = self.format_exits(obj) - objdata["Characters"] = self.format_chars(obj) - objdata["Content"] = self.format_things(obj) - if self.object_type == "channel": - objdata["Subscription Totals"] = self.format_channel_sub_totals(obj) - objdata["Account Subscriptions"] = self.format_channel_account_subs(obj) - objdata["Object Subscriptions"] = self.format_channel_object_subs(obj) - - return objdata
- -
[docs] def format_output(self, obj, current_cmdset): - """ - Formats the full examine page return. - - """ - objdata = self.get_formatted_obj_data(obj, current_cmdset) - - # format output - main_str = [] - max_width = -1 - for header, block in objdata.items(): - if block is not None: - blockstr = f"{self.header_color}{header}|n: {block}" - max_width = max(max_width, max(display_len(line) for line in blockstr.split("\n"))) - main_str.append(blockstr) - main_str = "\n".join(main_str) - - max_width = max(0, min(self.client_width(), max_width)) - sep = self.separator * max_width - - return f"{sep}\n{main_str}\n{sep}"
- - def _search_by_object_type(self, obj_name, objtype): - """ - Route to different search functions depending on the object type being - examined. This also handles error reporting for multimatches/no matches. - - Args: - obj_name (str): The search query. - objtype (str): One of 'object', 'account', 'script' or 'channel'. - Returns: - any: `None` if no match or multimatch, otherwise a single result. - - """ - obj = None - - if objtype == "object": - obj = self.caller.search(obj_name) - elif objtype == "account": - try: - obj = self.caller.search_account(obj_name.lstrip("*")) - except AttributeError: - # this means we are calling examine from an account object - obj = self.caller.search( - obj_name.lstrip("*"), search_object="object" in self.switches - ) - else: - obj = getattr(search, f"search_{objtype}")(obj_name) - if not obj: - self.caller.msg(f"No {objtype} found with key {obj_name}.") - obj = None - elif len(obj) > 1: - err = "Multiple {objtype} found with key {obj_name}:\n{matches}" - self.caller.msg(err.format( - obj_name=obj_name, - matches=", ".join(f"{ob.key}(#{ob.id})" for ob in obj) - )) - obj = None - else: - obj = obj[0] - return obj - -
[docs] def parse(self): - super().parse() - - self.examine_objs = [] - - if not self.args: - # If no arguments are provided, examine the invoker's location. - if hasattr(self.caller, "location"): - self.examine_objs.append((self.caller.location, None)) - else: - self.msg("You need to supply a target to examine.") - raise InterruptCommand - else: - for objdef in self.lhs_objattr: - # note that we check the objtype for every repeat; this will always - # be the same result, but it makes for a cleaner code and multi-examine - # is not so common anyway. - - obj = None - obj_name = objdef["name"] # name - obj_attrs = objdef["attrs"] # /attrs - - # identify object type, in prio account - script - channel - object_type = "object" - if (utils.inherits_from(self.caller, "evennia.accounts.accounts.DefaultAccount") - or "account" in self.switches or obj_name.startswith("*")): - object_type = "account" - elif "script" in self.switches: - object_type = "script" - elif "channel" in self.switches: - object_type = "channel" - - self.object_type = object_type - obj = self._search_by_object_type(obj_name, object_type) - - if obj: - self.examine_objs.append((obj, obj_attrs))
- -
[docs] def func(self): - """Process command""" - for obj, obj_attrs in self.examine_objs: - # these are parsed out in .parse already - - if not obj.access(self.caller, "examine"): - # If we don't have special info access, just look - # at the object instead. - self.msg(self.caller.at_look(obj)) - continue - - if obj_attrs: - # we are only interested in specific attributes - attrs = [attr for attr in obj.db_attributes.all() if attr.db_key in obj_attrs] - if not attrs: - self.msg("No attributes found on {obj.name}.") - else: - out_strings = [] - for attr in attrs: - out_strings.append(self.format_single_attribute_detail(obj, attr)) - out_str = "\n".join(out_strings) - max_width = max(display_len(line) for line in out_strings) - max_width = max(0, min(max_width, self.client_width())) - sep = self.separator * max_width - self.msg(f"{sep}\n{out_str}") - return - - # examine the obj itself - - if self.object_type in ("object", "account"): - # for objects and accounts we need to set up an asynchronous - # fetch of the cmdset and not proceed with the examine display - # until the fetch is complete - session = None - if obj.sessions.count(): - mergemode = "session" - session = obj.sessions.get()[0] - elif self.object_type == "account": - mergemode = "account" - else: - mergemode = "object" - - account = None - objct = None - if self.object_type == "account": - account = obj - else: - account = obj.account - objct = obj - - # this is usually handled when a command runs, but when we examine - # we may have leftover inherited cmdsets directly after a move etc. - obj.cmdset.update() - # using callback to print results whenever function returns. - - def _get_cmdset_callback(current_cmdset): - self.msg(self.format_output(obj, current_cmdset).strip()) - - get_and_merge_cmdsets( - obj, session, account, objct, mergemode, self.raw_string - ).addCallback(_get_cmdset_callback) - - else: - # for objects without cmdsets we can proceed to examine immediately - self.msg(self.format_output(obj, None).strip())
- - -
[docs]class CmdFind(COMMAND_DEFAULT_CLASS): - """ - search the database for objects - - Usage: - find[/switches] <name or dbref or *account> [= dbrefmin[-dbrefmax]] - locate - this is a shorthand for using the /loc switch. - - Switches: - room - only look for rooms (location=None) - exit - only look for exits (destination!=None) - char - only look for characters (BASE_CHARACTER_TYPECLASS) - exact - only exact matches are returned. - loc - display object location if exists and match has one result - startswith - search for names starting with the string, rather than containing - - Searches the database for an object of a particular name or exact #dbref. - Use *accountname to search for an account. The switches allows for - limiting object matches to certain game entities. Dbrefmin and dbrefmax - limits matches to within the given dbrefs range, or above/below if only - one is given. - """ - - key = "@find" - aliases = ["@search", "@locate"] - switch_options = ("room", "exit", "char", "exact", "loc", "startswith") - locks = "cmd:perm(find) or perm(Builder)" - help_category = "Building" - -
[docs] def func(self): - """Search functionality""" - caller = self.caller - switches = self.switches - - if not self.args or (not self.lhs and not self.rhs): - caller.msg("Usage: find <string> [= low [-high]]") - return - - if "locate" in self.cmdstring: # Use option /loc as a default for locate command alias - switches.append("loc") - - searchstring = self.lhs - - try: - # Try grabbing the actual min/max id values by database aggregation - qs = ObjectDB.objects.values("id").aggregate(low=Min("id"), high=Max("id")) - low, high = sorted(qs.values()) - if not (low and high): - raise ValueError( - f"{self.__class__.__name__}: Min and max ID not returned by aggregation; falling back to queryset slicing." - ) - except Exception as e: - logger.log_trace(e) - # If that doesn't work for some reason (empty DB?), guess the lower - # bound and do a less-efficient query to find the upper. - low, high = 1, ObjectDB.objects.all().order_by("-id").first().id - - if self.rhs: - try: - # Check that rhs is either a valid dbref or dbref range - bounds = tuple( - sorted(dbref(x, False) for x in re.split("[-\s]+", self.rhs.strip())) - ) - - # dbref() will return either a valid int or None - assert bounds - # None should not exist in the bounds list - assert None not in bounds - - low = bounds[0] - if len(bounds) > 1: - high = bounds[-1] - - except AssertionError: - caller.msg("Invalid dbref range provided (not a number).") - return - except IndexError as e: - logger.log_err( - f"{self.__class__.__name__}: Error parsing upper and lower bounds of query." - ) - logger.log_trace(e) - - low = min(low, high) - high = max(low, high) - - is_dbref = utils.dbref(searchstring) - is_account = searchstring.startswith("*") - - restrictions = "" - if self.switches: - restrictions = ", %s" % (", ".join(self.switches)) - - if is_dbref or is_account: - if is_dbref: - # a dbref search - result = caller.search(searchstring, global_search=True, quiet=True) - string = "|wExact dbref match|n(#%i-#%i%s):" % (low, high, restrictions) - else: - # an account search - searchstring = searchstring.lstrip("*") - result = caller.search_account(searchstring, quiet=True) - string = "|wMatch|n(#%i-#%i%s):" % (low, high, restrictions) - - if "room" in switches: - result = result if inherits_from(result, ROOM_TYPECLASS) else None - if "exit" in switches: - result = result if inherits_from(result, EXIT_TYPECLASS) else None - if "char" in switches: - result = result if inherits_from(result, CHAR_TYPECLASS) else None - - if not result: - string += "\n |RNo match found.|n" - elif not low <= int(result[0].id) <= high: - string += "\n |RNo match found for '%s' in #dbref interval.|n" % searchstring - else: - result = result[0] - string += "\n|g %s - %s|n" % (result.get_display_name(caller), result.path) - if "loc" in self.switches and not is_account and result.location: - string += " (|wlocation|n: |g{}|n)".format( - result.location.get_display_name(caller) - ) - else: - # Not an account/dbref search but a wider search; build a queryset. - # Searches for key and aliases - if "exact" in switches: - keyquery = Q(db_key__iexact=searchstring, id__gte=low, id__lte=high) - aliasquery = Q( - db_tags__db_key__iexact=searchstring, - db_tags__db_tagtype__iexact="alias", - id__gte=low, - id__lte=high, - ) - elif "startswith" in switches: - keyquery = Q(db_key__istartswith=searchstring, id__gte=low, id__lte=high) - aliasquery = Q( - db_tags__db_key__istartswith=searchstring, - db_tags__db_tagtype__iexact="alias", - id__gte=low, - id__lte=high, - ) - else: - keyquery = Q(db_key__icontains=searchstring, id__gte=low, id__lte=high) - aliasquery = Q( - db_tags__db_key__icontains=searchstring, - db_tags__db_tagtype__iexact="alias", - id__gte=low, - id__lte=high, - ) - - # Keep the initial queryset handy for later reuse - result_qs = ObjectDB.objects.filter(keyquery | aliasquery).distinct() - nresults = result_qs.count() - - # Use iterator to minimize memory ballooning on large result sets - results = result_qs.iterator() - - # Check and see if type filtering was requested; skip it if not - if any(x in switches for x in ("room", "exit", "char")): - obj_ids = set() - for obj in results: - if ( - ("room" in switches and inherits_from(obj, ROOM_TYPECLASS)) - or ("exit" in switches and inherits_from(obj, EXIT_TYPECLASS)) - or ("char" in switches and inherits_from(obj, CHAR_TYPECLASS)) - ): - obj_ids.add(obj.id) - - # Filter previous queryset instead of requesting another - filtered_qs = result_qs.filter(id__in=obj_ids).distinct() - nresults = filtered_qs.count() - - # Use iterator again to minimize memory ballooning - results = filtered_qs.iterator() - - # still results after type filtering? - if nresults: - if nresults > 1: - header = f"{nresults} Matches" - else: - header = "One Match" - - string = f"|w{header}|n(#{low}-#{high}{restrictions}):" - res = None - for res in results: - string += f"\n |g{res.get_display_name(caller)} - {res.path}|n" - if ( - "loc" in self.switches - and nresults == 1 - and res - and getattr(res, "location", None) - ): - string += f" (|wlocation|n: |g{res.location.get_display_name(caller)}|n)" - else: - string = f"|wNo Matches|n(#{low}-#{high}{restrictions}):" - string += f"\n |RNo matches found for '{searchstring}'|n" - - # send result - caller.msg(string.strip())
- - -class ScriptEvMore(EvMore): - """ - Listing 1000+ Scripts can be very slow and memory-consuming. So - we use this custom EvMore child to build en EvTable only for - each page of the list. - - """ - - def init_pages(self, scripts): - """Prepare the script list pagination""" - script_pages = Paginator(scripts, max(1, int(self.height / 2))) - super().init_pages(script_pages) - - def page_formatter(self, scripts): - """Takes a page of scripts and formats the output - into an EvTable.""" - - if not scripts: - return "<No scripts>" - - table = EvTable( - "|wdbref|n", - "|wobj|n", - "|wkey|n", - "|wintval|n", - "|wnext|n", - "|wrept|n", - "|wtypeclass|n", - "|wdesc|n", - align="r", - border="tablecols", - width=self.width, - ) - - for script in scripts: - - nextrep = script.time_until_next_repeat() - if nextrep is None: - nextrep = script.db._paused_time - nextrep = f"PAUSED {int(nextrep)}s" if nextrep else "--" - else: - nextrep = f"{nextrep}s" - - maxrepeat = script.repeats - remaining = script.remaining_repeats() or 0 - if maxrepeat: - rept = "%i/%i" % (maxrepeat - remaining, maxrepeat) - else: - rept = "-/-" - - table.add_row( - f"#{script.id}", - f"{script.obj.key}({script.obj.dbref})" - if (hasattr(script, "obj") and script.obj) - else "<Global>", - script.key, - script.interval if script.interval > 0 else "--", - nextrep, - rept, - script.typeclass_path.rsplit(".", 1)[-1], - crop(script.desc, width=20), - ) - - return str(table) - - -
[docs]class CmdScripts(COMMAND_DEFAULT_CLASS): - """ - List and manage all running scripts. Allows for creating new global - scripts. - - Usage: - script[/switches] [script-#dbref, key, script.path or <obj>] - script[/start||stop] <obj> = <script.path or script-key> - - Switches: - start - start/unpause an existing script's timer. - stop - stops an existing script's timer - pause - pause a script's timer - delete - deletes script. This will also stop the timer as needed - - Examples: - script - list scripts - script myobj - list all scripts on object - script foo.bar.Script - create a new global Script - script scriptname - examine named existing global script - script myobj = foo.bar.Script - create and assign script to object - script/stop myobj = scriptname - stop script on object - script/pause foo.Bar.Script - pause global script - script/delete myobj - delete ALL scripts on object - script/delete #dbref[-#dbref] - delete script or range by dbref - - When given with an `<obj>` as left-hand-side, this creates and - assigns a new script to that object. Without an `<obj>`, this - manages and inspects global scripts - - If no switches are given, this command just views all active - scripts. The argument can be either an object, at which point it - will be searched for all scripts defined on it, or a script name - or #dbref. For using the /stop switch, a unique script #dbref is - required since whole classes of scripts often have the same name. - - Use the `script` build-level command for managing scripts attached to - objects. - - """ - - key = "@scripts" - aliases = ["@script"] - switch_options = ("create", "start", "stop", "pause", "delete") - locks = "cmd:perm(scripts) or perm(Builder)" - help_category = "System" - - excluded_typeclass_paths = ["evennia.prototypes.prototypes.DbPrototype"] - - switch_mapping = { - "create": "|gCreated|n", - "start": "|gStarted|n", - "stop": "|RStopped|n", - "pause": "|Paused|n", - "delete": "|rDeleted|n" - } - - def _search_script(self, args): - # test first if this is a script match - scripts = ScriptDB.objects.get_all_scripts(key=args) - if scripts: - return scripts - # try typeclass path - scripts = ScriptDB.objects.filter(db_typeclass_path__iendswith=args) - if scripts: - return scripts - if "-" in args: - # may be a dbref-range - val1, val2 = (dbref(part.strip()) for part in args.split('-', 1)) - if val1 and val2: - scripts = ScriptDB.objects.filter(id__in=(range(val1, val2 + 1))) - if scripts: - return scripts - -
[docs] def func(self): - """implement method""" - - caller = self.caller - - if not self.args: - # show all scripts - scripts = ScriptDB.objects.all() - if not scripts: - caller.msg("No scripts found.") - return - ScriptEvMore(caller, scripts.order_by("id"), session=self.session) - return - - # find script or object to operate on - scripts, obj = None, None - if self.rhs: - obj_query = self.lhs - script_query = self.rhs - else: - obj_query = script_query = self.args - - scripts = self._search_script(script_query) - objects = ObjectDB.objects.object_search(obj_query) - obj = objects[0] if objects else None - - if not self.switches: - # creation / view mode - if obj: - # we have an object - if self.rhs: - # creation mode - if obj.scripts.add(self.rhs, autostart=True): - caller.msg( - f"Script |w{self.rhs}|n successfully added and " - f"started on {obj.get_display_name(caller)}.") - else: - caller.msg(f"Script {self.rhs} could not be added and/or started " - f"on {obj.get_display_name(caller)} (or it started and " - "immediately shut down).") - else: - # just show all scripts on object - scripts = ScriptDB.objects.filter(db_obj=obj) - if scripts: - ScriptEvMore(caller, scripts.order_by("id"), session=self.session) - else: - caller.msg(f"No scripts defined on {obj}") - - elif scripts: - # show found script(s) - ScriptEvMore(caller, scripts.order_by("id"), session=self.session) - - else: - # create global script - try: - new_script = create.create_script(self.args) - except ImportError: - logger.log_trace() - new_script = None - - if new_script: - caller.msg(f"Global Script Created - " - f"{new_script.key} ({new_script.typeclass_path})") - ScriptEvMore(caller, [new_script], session=self.session) - else: - caller.msg(f"Global Script |rNOT|n Created |r(see log)|n - " - f"arguments: {self.args}") - - elif scripts or obj: - # modification switches - must operate on existing scripts - - if not scripts: - scripts = ScriptDB.objects.filter(db_obj=obj) - - if scripts.count() > 1: - ret = yield(f"Multiple scripts found: {scripts}. Are you sure you want to " - "operate on all of them? [Y]/N? ") - if ret.lower() in ('n', 'no'): - caller.msg("Aborted.") - return - - for script in scripts: - script_key = script.key - script_typeclass_path = script.typeclass_path - scripttype = f"Script on {obj}" if obj else "Global Script" - - for switch in self.switches: - verb = self.switch_mapping[switch] - msgs = [] - try: - getattr(script, switch)() - except Exception: - logger.log_trace() - msgs.append(f"{scripttype} |rNOT|n {verb} |r(see log)|n - " - f"{script_key} ({script_typeclass_path})|n") - else: - msgs.append(f"{scripttype} {verb} - " - f"{script_key} ({script_typeclass_path})") - caller.msg("\n".join(msgs)) - if "delete" not in self.switches: - ScriptEvMore(caller, [script], session=self.session) - else: - caller.msg("No scripts found.")
- - -
[docs]class CmdObjects(COMMAND_DEFAULT_CLASS): - """ - statistics on objects in the database - - Usage: - objects [<nr>] - - Gives statictics on objects in database as well as - a list of <nr> latest objects in database. If not - given, <nr> defaults to 10. - """ - - key = "@objects" - locks = "cmd:perm(listobjects) or perm(Builder)" - help_category = "System" - -
[docs] def func(self): - """Implement the command""" - - caller = self.caller - nlim = int(self.args) if self.args and self.args.isdigit() else 10 - nobjs = ObjectDB.objects.count() - Character = class_from_module(settings.BASE_CHARACTER_TYPECLASS) - nchars = Character.objects.all_family().count() - Room = class_from_module(settings.BASE_ROOM_TYPECLASS) - nrooms = Room.objects.all_family().count() - Exit = class_from_module(settings.BASE_EXIT_TYPECLASS) - nexits = Exit.objects.all_family().count() - nother = nobjs - nchars - nrooms - nexits - nobjs = nobjs or 1 # fix zero-div error with empty database - - # total object sum table - totaltable = self.styled_table( - "|wtype|n", "|wcomment|n", "|wcount|n", "|w%|n", border="table", align="l" - ) - totaltable.align = "l" - totaltable.add_row( - "Characters", - "(BASE_CHARACTER_TYPECLASS + children)", - nchars, - "%.2f" % ((float(nchars) / nobjs) * 100), - ) - totaltable.add_row( - "Rooms", - "(BASE_ROOM_TYPECLASS + children)", - nrooms, - "%.2f" % ((float(nrooms) / nobjs) * 100), - ) - totaltable.add_row( - "Exits", - "(BASE_EXIT_TYPECLASS + children)", - nexits, - "%.2f" % ((float(nexits) / nobjs) * 100), - ) - totaltable.add_row("Other", "", nother, "%.2f" % ((float(nother) / nobjs) * 100)) - - # typeclass table - typetable = self.styled_table( - "|wtypeclass|n", "|wcount|n", "|w%|n", border="table", align="l" - ) - typetable.align = "l" - dbtotals = ObjectDB.objects.get_typeclass_totals() - for stat in dbtotals: - typetable.add_row( - stat.get("typeclass", "<error>"), - stat.get("count", -1), - "%.2f" % stat.get("percent", -1), - ) - - # last N table - objs = ObjectDB.objects.all().order_by("db_date_created")[max(0, nobjs - nlim): ] - latesttable = self.styled_table( - "|wcreated|n", "|wdbref|n", "|wname|n", "|wtypeclass|n", align="l", border="table" - ) - latesttable.align = "l" - for obj in objs: - latesttable.add_row( - utils.datetime_format(obj.date_created), obj.dbref, obj.key, obj.path - ) - - string = "\n|wObject subtype totals (out of %i Objects):|n\n%s" % (nobjs, totaltable) - string += "\n|wObject typeclass distribution:|n\n%s" % typetable - string += "\n|wLast %s Objects created:|n\n%s" % (min(nobjs, nlim), latesttable) - caller.msg(string)
- - -
[docs]class CmdTeleport(COMMAND_DEFAULT_CLASS): - """ - teleport object to another location - - Usage: - tel/switch [<object> to||=] <target location> - - Examples: - tel Limbo - tel/quiet box = Limbo - tel/tonone box - - Switches: - quiet - don't echo leave/arrive messages to the source/target - locations for the move. - intoexit - if target is an exit, teleport INTO - the exit object instead of to its destination - tonone - if set, teleport the object to a None-location. If this - switch is set, <target location> is ignored. - Note that the only way to retrieve - an object from a None location is by direct #dbref - reference. A puppeted object cannot be moved to None. - loc - teleport object to the target's location instead of its contents - - Teleports an object somewhere. If no object is given, you yourself are - teleported to the target location. - - To lock an object from being teleported, set its `teleport` lock, it will be - checked with the caller. To block - a destination from being teleported to, set the destination's `teleport_here` - lock - it will be checked with the thing being teleported. Admins and - higher permissions can always teleport. - - """ - - key = "@teleport" - aliases = "@tel" - switch_options = ("quiet", "intoexit", "tonone", "loc") - rhs_split = ("=", " to ") # Prefer = delimiter, but allow " to " usage. - locks = "cmd:perm(teleport) or perm(Builder)" - help_category = "Building" - -
[docs] def parse(self): - """ - Breaking out searching here to make this easier to override. - - """ - super().parse() - self.obj_to_teleport = self.caller - self.destination = None - if self.rhs: - self.obj_to_teleport = self.caller.search(self.lhs, global_search=True) - if not self.obj_to_teleport: - self.caller.msg("Did not find object to teleport.") - raise InterruptCommand - self.destination = self.caller.search(self.rhs, global_search=True) - elif self.lhs: - self.destination = self.caller.search(self.lhs, global_search=True)
- -
[docs] def func(self): - """Performs the teleport""" - - caller = self.caller - obj_to_teleport = self.obj_to_teleport - destination = self.destination - - if "tonone" in self.switches: - # teleporting to None - - if destination: - # in this case lhs is always the object to teleport - obj_to_teleport = destination - - if obj_to_teleport.has_account: - caller.msg( - "Cannot teleport a puppeted object " - "(%s, puppeted by %s) to a None-location." - % (obj_to_teleport.key, obj_to_teleport.account) - ) - return - caller.msg("Teleported %s -> None-location." % obj_to_teleport) - if obj_to_teleport.location and "quiet" not in self.switches: - obj_to_teleport.location.msg_contents( - "%s teleported %s into nothingness." % (caller, obj_to_teleport), exclude=caller - ) - obj_to_teleport.location = None - return - - if not self.args: - caller.msg("Usage: teleport[/switches] [<obj> =] <target or (X,Y,Z)>||home") - return - - if not destination: - caller.msg("Destination not found.") - return - - if "loc" in self.switches: - destination = destination.location - if not destination: - caller.msg("Destination has no location.") - return - - if obj_to_teleport == destination: - caller.msg("You can't teleport an object inside of itself!") - return - - if obj_to_teleport == destination.location: - caller.msg("You can't teleport an object inside something it holds!") - return - - if obj_to_teleport.location and obj_to_teleport.location == destination: - caller.msg("%s is already at %s." % (obj_to_teleport, destination)) - return - - # check any locks - if not (caller.permissions.check("Admin") or obj_to_teleport.access(caller, "teleport")): - caller.msg(f"{obj_to_teleport} 'teleport'-lock blocks you from teleporting " - "it anywhere.") - return - - if not (caller.permissions.check("Admin") - or destination.access(obj_to_teleport, "teleport_here")): - caller.msg(f"{destination} 'teleport_here'-lock blocks {obj_to_teleport} from " - "moving there.") - return - - # try the teleport - if not obj_to_teleport.location: - # teleporting from none-location - obj_to_teleport.location = destination - caller.msg(f"Teleported {obj_to_teleport} None -> {destination}") - elif obj_to_teleport.move_to( - destination, quiet="quiet" in self.switches, - emit_to_obj=caller, use_destination="intoexit" not in self.switches): - - if obj_to_teleport == caller: - caller.msg(f"Teleported to {destination}.") - else: - caller.msg(f"Teleported {obj_to_teleport} -> {destination}.") - else: - caller.msg("Teleportation failed.")
- - -
[docs]class CmdTag(COMMAND_DEFAULT_CLASS): - """ - handles the tags of an object - - Usage: - tag[/del] <obj> [= <tag>[:<category>]] - tag/search <tag>[:<category] - - Switches: - search - return all objects with a given Tag - del - remove the given tag. If no tag is specified, - clear all tags on object. - - Manipulates and lists tags on objects. Tags allow for quick - grouping of and searching for objects. If only <obj> is given, - list all tags on the object. If /search is used, list objects - with the given tag. - The category can be used for grouping tags themselves, but it - should be used with restrain - tags on their own are usually - enough to for most grouping schemes. - """ - - key = "@tag" - aliases = ["@tags"] - options = ("search", "del") - locks = "cmd:perm(tag) or perm(Builder)" - help_category = "Building" - arg_regex = r"(/\w+?(\s|$))|\s|$" - -
[docs] def func(self): - """Implement the tag functionality""" - - if not self.args: - self.caller.msg("Usage: tag[/switches] <obj> [= <tag>[:<category>]]") - return - if "search" in self.switches: - # search by tag - tag = self.args - category = None - if ":" in tag: - tag, category = [part.strip() for part in tag.split(":", 1)] - objs = search.search_tag(tag, category=category) - nobjs = len(objs) - if nobjs > 0: - catstr = ( - " (category: '|w%s|n')" % category - if category - else ("" if nobjs == 1 else " (may have different tag categories)") - ) - matchstr = ", ".join(o.get_display_name(self.caller) for o in objs) - - string = "Found |w%i|n object%s with tag '|w%s|n'%s:\n %s" % ( - nobjs, - "s" if nobjs > 1 else "", - tag, - catstr, - matchstr, - ) - else: - string = "No objects found with tag '%s%s'." % ( - tag, - " (category: %s)" % category if category else "", - ) - self.caller.msg(string) - return - if "del" in self.switches: - # remove one or all tags - obj = self.caller.search(self.lhs, global_search=True) - if not obj: - return - if self.rhs: - # remove individual tag - tag = self.rhs - category = None - if ":" in tag: - tag, category = [part.strip() for part in tag.split(":", 1)] - if obj.tags.get(tag, category=category): - obj.tags.remove(tag, category=category) - string = "Removed tag '%s'%s from %s." % ( - tag, - " (category: %s)" % category if category else "", - obj, - ) - else: - string = "No tag '%s'%s to delete on %s." % ( - tag, - " (category: %s)" % category if category else "", - obj, - ) - else: - # no tag specified, clear all tags - old_tags = [ - "%s%s" % (tag, " (category: %s)" % category if category else "") - for tag, category in obj.tags.all(return_key_and_category=True) - ] - if old_tags: - obj.tags.clear() - string = "Cleared all tags from %s: %s" % (obj, ", ".join(sorted(old_tags))) - else: - string = "No Tags to clear on %s." % obj - self.caller.msg(string) - return - # no search/deletion - if self.rhs: - # = is found; command args are of the form obj = tag - obj = self.caller.search(self.lhs, global_search=True) - if not obj: - return - tag = self.rhs - category = None - if ":" in tag: - tag, category = [part.strip() for part in tag.split(":", 1)] - # create the tag - obj.tags.add(tag, category=category) - string = "Added tag '%s'%s to %s." % ( - tag, - " (category: %s)" % category if category else "", - obj, - ) - self.caller.msg(string) - else: - # no = found - list tags on object - obj = self.caller.search(self.args, global_search=True) - if not obj: - return - tagtuples = obj.tags.all(return_key_and_category=True) - ntags = len(tagtuples) - tags = [tup[0] for tup in tagtuples] - categories = [" (category: %s)" % tup[1] if tup[1] else "" for tup in tagtuples] - if ntags: - string = "Tag%s on %s: %s" % ( - "s" if ntags > 1 else "", - obj, - ", ".join(sorted("'%s'%s" % (tags[i], categories[i]) for i in range(ntags))), - ) - else: - string = "No tags attached to %s." % obj - self.caller.msg(string)
- - -# helper functions for spawn - - -
[docs]class CmdSpawn(COMMAND_DEFAULT_CLASS): - """ - spawn objects from prototype - - Usage: - spawn[/noloc] <prototype_key> - spawn[/noloc] <prototype_dict> - - spawn/search [prototype_keykey][;tag[,tag]] - spawn/list [tag, tag, ...] - spawn/list modules - list only module-based prototypes - spawn/show [<prototype_key>] - spawn/update <prototype_key> - - spawn/save <prototype_dict> - spawn/edit [<prototype_key>] - olc - equivalent to spawn/edit - - Switches: - noloc - allow location to be None if not specified explicitly. Otherwise, - location will default to caller's current location. - search - search prototype by name or tags. - list - list available prototypes, optionally limit by tags. - show, examine - inspect prototype by key. If not given, acts like list. - raw - show the raw dict of the prototype as a one-line string for manual editing. - save - save a prototype to the database. It will be listable by /list. - delete - remove a prototype from database, if allowed to. - update - find existing objects with the same prototype_key and update - them with latest version of given prototype. If given with /save, - will auto-update all objects with the old version of the prototype - without asking first. - edit, menu, olc - create/manipulate prototype in a menu interface. - - Example: - spawn GOBLIN - spawn {"key":"goblin", "typeclass":"monster.Monster", "location":"#2"} - spawn/save {"key": "grunt", prototype: "goblin"};;mobs;edit:all() - \f - Dictionary keys: - |wprototype_parent |n - name of parent prototype to use. Required if typeclass is - not set. Can be a path or a list for multiple inheritance (inherits - left to right). If set one of the parents must have a typeclass. - |wtypeclass |n - string. Required if prototype_parent is not set. - |wkey |n - string, the main object identifier - |wlocation |n - this should be a valid object or #dbref - |whome |n - valid object or #dbref - |wdestination|n - only valid for exits (object or dbref) - |wpermissions|n - string or list of permission strings - |wlocks |n - a lock-string - |waliases |n - string or list of strings. - |wndb_|n<name> - value of a nattribute (ndb_ is stripped) - - |wprototype_key|n - name of this prototype. Unique. Used to store/retrieve from db - and update existing prototyped objects if desired. - |wprototype_desc|n - desc of this prototype. Used in listings - |wprototype_locks|n - locks of this prototype. Limits who may use prototype - |wprototype_tags|n - tags of this prototype. Used to find prototype - - any other keywords are interpreted as Attributes and their values. - - The available prototypes are defined globally in modules set in - settings.PROTOTYPE_MODULES. If spawn is used without arguments it - displays a list of available prototypes. - - """ - - key = "@spawn" - aliases = ["@olc"] - switch_options = ( - "noloc", - "search", - "list", - "show", - "raw", - "examine", - "save", - "delete", - "menu", - "olc", - "update", - "edit", - ) - locks = "cmd:perm(spawn) or perm(Builder)" - help_category = "Building" - - def _search_prototype(self, prototype_key, quiet=False): - """ - Search for prototype and handle no/multi-match and access. - - Returns a single found prototype or None - in the - case, the caller has already been informed of the - search error we need not do any further action. - - """ - prototypes = protlib.search_prototype(prototype_key) - nprots = len(prototypes) - - # handle the search result - err = None - if not prototypes: - err = f"No prototype named '{prototype_key}' was found." - elif nprots > 1: - err = "Found {} prototypes matching '{}':\n {}".format( - nprots, - prototype_key, - ", ".join(proto.get("prototype_key", "") for proto in prototypes), - ) - else: - # we have a single prototype, check access - prototype = prototypes[0] - if not self.caller.locks.check_lockstring( - self.caller, prototype.get("prototype_locks", ""), access_type="spawn", default=True - ): - err = "You don't have access to use this prototype." - - if err: - # return None on any error - if not quiet: - self.caller.msg(err) - return - return prototype - - def _parse_prototype(self, inp, expect=dict): - """ - Parse a prototype dict or key from the input and convert it safely - into a dict if appropriate. - - Args: - inp (str): The input from user. - expect (type, optional): - Returns: - prototype (dict, str or None): The parsed prototype. If None, the error - was already reported. - - """ - eval_err = None - try: - prototype = _LITERAL_EVAL(inp) - except (SyntaxError, ValueError) as err: - # treat as string - eval_err = err - prototype = utils.to_str(inp) - finally: - # it's possible that the input was a prototype-key, in which case - # it's okay for the LITERAL_EVAL to fail. Only if the result does not - # match the expected type do we have a problem. - if not isinstance(prototype, expect): - if eval_err: - string = ( - f"{inp}\n{eval_err}\n|RCritical Python syntax error in argument. Only primitive " - "Python structures are allowed. \nMake sure to use correct " - "Python syntax. Remember especially to put quotes around all " - "strings inside lists and dicts.|n For more advanced uses, embed " - "funcparser callables ($funcs) in the strings." - ) - else: - string = "Expected {}, got {}.".format(expect, type(prototype)) - self.caller.msg(string) - return - - if expect == dict: - # an actual prototype. We need to make sure it's safe, - # so don't allow exec. - # TODO: Exec support is deprecated. Remove completely for 1.0. - if "exec" in prototype and not self.caller.check_permstring("Developer"): - self.caller.msg( - "Spawn aborted: You are not allowed to " "use the 'exec' prototype key." - ) - return - try: - # we homogenize the protoype first, to be more lenient with free-form - protlib.validate_prototype(protlib.homogenize_prototype(prototype)) - except RuntimeError as err: - self.caller.msg(str(err)) - return - return prototype - - def _get_prototype_detail(self, query=None, prototypes=None): - """ - Display the detailed specs of one or more prototypes. - - Args: - query (str, optional): If this is given and `prototypes` is not, search for - the prototype(s) by this query. This may be a partial query which - may lead to multiple matches, all being displayed. - prototypes (list, optional): If given, ignore `query` and only show these - prototype-details. - Returns: - display (str, None): A formatted string of one or more prototype details. - If None, the caller was already informed of the error. - - - """ - if not prototypes: - # we need to query. Note that if query is None, all prototypes will - # be returned. - prototypes = protlib.search_prototype(key=query) - if prototypes: - return "\n".join(protlib.prototype_to_str(prot) for prot in prototypes) - elif query: - self.caller.msg(f"No prototype named '{query}' was found.") - else: - self.caller.msg("No prototypes found.") - - def _list_prototypes(self, key=None, tags=None): - """Display prototypes as a list, optionally limited by key/tags. """ - protlib.list_prototypes(self.caller, key=key, tags=tags, session=self.session) - - @interactive - def _update_existing_objects(self, caller, prototype_key, quiet=False): - """ - Update existing objects (if any) with this prototype-key to the latest - prototype version. - - Args: - caller (Object): This is necessary for @interactive to work. - prototype_key (str): The prototype to update. - quiet (bool, optional): If set, don't report to user if no - old objects were found to update. - Returns: - n_updated (int): Number of updated objects. - - """ - prototype = self._search_prototype(prototype_key) - if not prototype: - return - - existing_objects = protlib.search_objects_with_prototype(prototype_key) - if not existing_objects: - if not quiet: - caller.msg("No existing objects found with an older version of this prototype.") - return - - if existing_objects: - n_existing = len(existing_objects) - slow = " (note that this may be slow)" if n_existing > 10 else "" - string = ( - f"There are {n_existing} existing object(s) with an older version " - f"of prototype '{prototype_key}'. Should it be re-applied to them{slow}? [Y]/N" - ) - answer = yield (string) - if answer.lower() in ["n", "no"]: - caller.msg( - "|rNo update was done of existing objects. " - "Use spawn/update <key> to apply later as needed.|n" - ) - return - try: - n_updated = spawner.batch_update_objects_with_prototype( - prototype, objects=existing_objects, caller=caller, - ) - except Exception: - logger.log_trace() - caller.msg(f"{n_updated} objects were updated.") - return - - def _parse_key_desc_tags(self, argstring, desc=True): - """ - Parse ;-separated input list. - """ - key, desc, tags = "", "", [] - if ";" in argstring: - parts = [part.strip().lower() for part in argstring.split(";")] - if len(parts) > 1 and desc: - key = parts[0] - desc = parts[1] - tags = parts[2:] - else: - key = parts[0] - tags = parts[1:] - else: - key = argstring.strip().lower() - return key, desc, tags - -
[docs] def func(self): - """Implements the spawner""" - - caller = self.caller - noloc = "noloc" in self.switches - - # run the menu/olc - if ( - self.cmdstring == "olc" - or "menu" in self.switches - or "olc" in self.switches - or "edit" in self.switches - ): - # OLC menu mode - prototype = None - if self.lhs: - prototype_key = self.lhs - prototype = self._search_prototype(prototype_key) - if not prototype: - return - olc_menus.start_olc(caller, session=self.session, prototype=prototype) - return - - if "search" in self.switches: - # query for a key match. The arg is a search query or nothing. - - if not self.args: - # an empty search returns the full list - self._list_prototypes() - return - - # search for key;tag combinations - key, _, tags = self._parse_key_desc_tags(self.args, desc=False) - self._list_prototypes(key, tags) - return - - if "raw" in self.switches: - # query for key match and return the prototype as a safe one-liner string. - if not self.args: - caller.msg("You need to specify a prototype-key to get the raw data for.") - prototype = self._search_prototype(self.args) - if not prototype: - return - caller.msg(str(prototype)) - return - - if "show" in self.switches or "examine" in self.switches: - # show a specific prot detail. The argument is a search query or empty. - if not self.args: - # we don't show the list of all details, that's too spammy. - caller.msg("You need to specify a prototype-key to show.") - return - - detail_string = self._get_prototype_detail(self.args) - if not detail_string: - return - caller.msg(detail_string) - return - - if "list" in self.switches: - # for list, all optional arguments are tags. - tags = self.lhslist - err = self._list_prototypes(tags=tags) - if err: - caller.msg( - "No prototypes found with prototype-tag(s): {}".format( - list_to_string(tags, "or") - ) - ) - return - - if "save" in self.switches: - # store a prototype to the database store - if not self.args: - caller.msg( - "Usage: spawn/save [<key>[;desc[;tag,tag[,...][;lockstring]]]] = <prototype_dict>" - ) - return - if self.rhs: - # input on the form key = prototype - prototype_key, prototype_desc, prototype_tags = self._parse_key_desc_tags(self.lhs) - prototype_key = None if not prototype_key else prototype_key - prototype_desc = None if not prototype_desc else prototype_desc - prototype_tags = None if not prototype_tags else prototype_tags - prototype_input = self.rhs.strip() - else: - prototype_key = prototype_desc = None - prototype_tags = None - prototype_input = self.lhs.strip() - - # handle parsing - prototype = self._parse_prototype(prototype_input) - if not prototype: - return - - prot_prototype_key = prototype.get("prototype_key") - - if not (prototype_key or prot_prototype_key): - caller.msg( - "A prototype_key must be given, either as `prototype_key = <prototype>` " - "or as a key 'prototype_key' inside the prototype structure." - ) - return - - if prototype_key is None: - prototype_key = prot_prototype_key - - if prot_prototype_key != prototype_key: - caller.msg("(Replacing `prototype_key` in prototype with given key.)") - prototype["prototype_key"] = prototype_key - - if prototype_desc is not None and prot_prototype_key != prototype_desc: - caller.msg("(Replacing `prototype_desc` in prototype with given desc.)") - prototype["prototype_desc"] = prototype_desc - if prototype_tags is not None and prototype.get("prototype_tags") != prototype_tags: - caller.msg("(Replacing `prototype_tags` in prototype with given tag(s))") - prototype["prototype_tags"] = prototype_tags - - string = "" - # check for existing prototype (exact match) - old_prototype = self._search_prototype(prototype_key, quiet=True) - - diff = spawner.prototype_diff(old_prototype, prototype, homogenize=True) - diffstr = spawner.format_diff(diff) - new_prototype_detail = self._get_prototype_detail(prototypes=[prototype]) - - if old_prototype: - if not diffstr: - string = f"|yAlready existing Prototype:|n\n{new_prototype_detail}\n" - question = ( - "\nThere seems to be no changes. Do you still want to (re)save? [Y]/N" - ) - else: - string = ( - f'|yExisting prototype "{prototype_key}" found. Change:|n\n{diffstr}\n' - f"|yNew changed prototype:|n\n{new_prototype_detail}" - ) - question = ( - "\n|yDo you want to apply the change to the existing prototype?|n [Y]/N" - ) - else: - string = f"|yCreating new prototype:|n\n{new_prototype_detail}" - question = "\nDo you want to continue saving? [Y]/N" - - answer = yield (string + question) - if answer.lower() in ["n", "no"]: - caller.msg("|rSave cancelled.|n") - return - - # all seems ok. Try to save. - try: - prot = protlib.save_prototype(prototype) - if not prot: - caller.msg("|rError saving:|R {}.|n".format(prototype_key)) - return - except protlib.PermissionError as err: - caller.msg("|rError saving:|R {}|n".format(err)) - return - caller.msg("|gSaved prototype:|n {}".format(prototype_key)) - - # check if we want to update existing objects - - self._update_existing_objects(self.caller, prototype_key, quiet=True) - return - - if not self.args: - # all switches beyond this point gets a common non-arg return - ncount = len(protlib.search_prototype()) - caller.msg( - "Usage: spawn <prototype-key> or {{key: value, ...}}" - f"\n ({ncount} existing prototypes. Use /list to inspect)" - ) - return - - if "delete" in self.switches: - # remove db-based prototype - prototype_detail = self._get_prototype_detail(self.args) - if not prototype_detail: - return - - string = f"|rDeleting prototype:|n\n{prototype_detail}" - question = "\nDo you want to continue deleting? [Y]/N" - answer = yield (string + question) - if answer.lower() in ["n", "no"]: - caller.msg("|rDeletion cancelled.|n") - return - - try: - success = protlib.delete_prototype(self.args) - except protlib.PermissionError as err: - retmsg = f"|rError deleting:|R {err}|n" - else: - retmsg = ( - "Deletion successful" - if success - else "Deletion failed (does the prototype exist?)" - ) - caller.msg(retmsg) - return - - if "update" in self.switches: - # update existing prototypes - prototype_key = self.args.strip().lower() - self._update_existing_objects(self.caller, prototype_key) - return - - # If we get to this point, we use not switches but are trying a - # direct creation of an object from a given prototype or -key - - prototype = self._parse_prototype( - self.args, expect=dict if self.args.strip().startswith("{") else str - ) - if not prototype: - # this will only let through dicts or strings - return - - key = "<unnamed>" - if isinstance(prototype, str): - # A prototype key we are looking to apply - prototype_key = prototype - prototype = self._search_prototype(prototype_key) - - if not prototype: - return - - # proceed to spawning - try: - for obj in spawner.spawn(prototype, caller=self.caller): - self.caller.msg("Spawned %s." % obj.get_display_name(self.caller)) - if not prototype.get("location") and not noloc: - # we don't hardcode the location in the prototype (unless the user - # did so manually) - that would lead to it having to be 'removed' every - # time we try to update objects with this prototype in the future. - obj.location = caller.location - except RuntimeError as err: - caller.msg(err)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/commands/default/cmdset_account.html b/docs/0.9.5/_modules/evennia/commands/default/cmdset_account.html deleted file mode 100644 index 8aea2c35c8..0000000000 --- a/docs/0.9.5/_modules/evennia/commands/default/cmdset_account.html +++ /dev/null @@ -1,182 +0,0 @@ - - - - - - - - evennia.commands.default.cmdset_account — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.commands.default.cmdset_account

-"""
-
-This is the cmdset for Account (OOC) commands.  These are
-stored on the Account object and should thus be able to handle getting
-an Account object as caller rather than a Character.
-
-Note - in order for session-rerouting (in MULTISESSION_MODE=2) to
-function, all commands in this cmdset should use the self.msg()
-command method rather than caller.msg().
-"""
-
-from evennia.commands.cmdset import CmdSet
-from evennia.commands.default import help, comms, admin, system
-from evennia.commands.default import building, account, general
-
-
-
[docs]class AccountCmdSet(CmdSet): - """ - Implements the account command set. - """ - - key = "DefaultAccount" - priority = -10 - -
[docs] def at_cmdset_creation(self): - "Populates the cmdset" - - # Account-specific commands - self.add(account.CmdOOCLook()) - self.add(account.CmdIC()) - self.add(account.CmdOOC()) - self.add(account.CmdCharCreate()) - self.add(account.CmdCharDelete()) - # self.add(account.CmdSessions()) - self.add(account.CmdWho()) - self.add(account.CmdOption()) - self.add(account.CmdQuit()) - self.add(account.CmdPassword()) - self.add(account.CmdColorTest()) - self.add(account.CmdQuell()) - self.add(account.CmdStyle()) - - # nicks - self.add(general.CmdNick()) - - # testing - self.add(building.CmdExamine()) - - # Help command - self.add(help.CmdHelp()) - - # system commands - self.add(system.CmdReload()) - self.add(system.CmdReset()) - self.add(system.CmdShutdown()) - self.add(system.CmdPy()) - - # Admin commands - self.add(admin.CmdNewPassword()) - - # Comm commands - self.add(comms.CmdChannel()) - self.add(comms.CmdPage()) - self.add(comms.CmdIRC2Chan()) - self.add(comms.CmdIRCStatus()) - self.add(comms.CmdRSS2Chan()) - self.add(comms.CmdGrapevine2Chan())
- # self.add(comms.CmdChannels()) - # self.add(comms.CmdAddCom()) - # self.add(comms.CmdDelCom()) - # self.add(comms.CmdAllCom()) - # self.add(comms.CmdCdestroy()) - # self.add(comms.CmdChannelCreate()) - # self.add(comms.CmdClock()) - # self.add(comms.CmdCBoot()) - # self.add(comms.CmdCWho()) - # self.add(comms.CmdCdesc()) -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/commands/default/cmdset_character.html b/docs/0.9.5/_modules/evennia/commands/default/cmdset_character.html deleted file mode 100644 index 6239d5bbcd..0000000000 --- a/docs/0.9.5/_modules/evennia/commands/default/cmdset_character.html +++ /dev/null @@ -1,197 +0,0 @@ - - - - - - - - evennia.commands.default.cmdset_character — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.commands.default.cmdset_character

-"""
-This module ties together all the commands default Character objects have
-available (i.e. IC commands). Note that some commands, such as
-communication-commands are instead put on the account level, in the
-Account cmdset. Account commands remain available also to Characters.
-"""
-from evennia.commands.cmdset import CmdSet
-from evennia.commands.default import general, help, admin, system
-from evennia.commands.default import building
-from evennia.commands.default import batchprocess
-
-
-
[docs]class CharacterCmdSet(CmdSet): - """ - Implements the default command set. - """ - - key = "DefaultCharacter" - priority = 0 - -
[docs] def at_cmdset_creation(self): - "Populates the cmdset" - - # The general commands - self.add(general.CmdLook()) - self.add(general.CmdHome()) - self.add(general.CmdInventory()) - self.add(general.CmdPose()) - self.add(general.CmdNick()) - self.add(general.CmdSetDesc()) - self.add(general.CmdGet()) - self.add(general.CmdDrop()) - self.add(general.CmdGive()) - self.add(general.CmdSay()) - self.add(general.CmdWhisper()) - self.add(general.CmdAccess()) - - # The help system - self.add(help.CmdHelp()) - self.add(help.CmdSetHelp()) - - # System commands - self.add(system.CmdPy()) - self.add(system.CmdAccounts()) - self.add(system.CmdService()) - self.add(system.CmdAbout()) - self.add(system.CmdTime()) - self.add(system.CmdServerLoad()) - # self.add(system.CmdPs()) - self.add(system.CmdTickers()) - self.add(system.CmdTasks()) - - # Admin commands - self.add(admin.CmdBoot()) - self.add(admin.CmdBan()) - self.add(admin.CmdUnban()) - self.add(admin.CmdEmit()) - self.add(admin.CmdPerm()) - self.add(admin.CmdWall()) - self.add(admin.CmdForce()) - - # Building and world manipulation - self.add(building.CmdTeleport()) - self.add(building.CmdSetObjAlias()) - self.add(building.CmdListCmdSets()) - self.add(building.CmdWipe()) - self.add(building.CmdSetAttribute()) - self.add(building.CmdName()) - self.add(building.CmdDesc()) - self.add(building.CmdCpAttr()) - self.add(building.CmdMvAttr()) - self.add(building.CmdCopy()) - self.add(building.CmdFind()) - self.add(building.CmdOpen()) - self.add(building.CmdLink()) - self.add(building.CmdUnLink()) - self.add(building.CmdCreate()) - self.add(building.CmdDig()) - self.add(building.CmdTunnel()) - self.add(building.CmdDestroy()) - self.add(building.CmdExamine()) - self.add(building.CmdTypeclass()) - self.add(building.CmdLock()) - self.add(building.CmdSetHome()) - self.add(building.CmdTag()) - self.add(building.CmdSpawn()) - self.add(building.CmdScripts()) - self.add(building.CmdObjects()) - - # Batchprocessor commands - self.add(batchprocess.CmdBatchCommands()) - self.add(batchprocess.CmdBatchCode())
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/commands/default/cmdset_session.html b/docs/0.9.5/_modules/evennia/commands/default/cmdset_session.html deleted file mode 100644 index 493f75943f..0000000000 --- a/docs/0.9.5/_modules/evennia/commands/default/cmdset_session.html +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - evennia.commands.default.cmdset_session — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.commands.default.cmdset_session

-"""
-This module stores session-level commands.
-"""
-from evennia.commands.cmdset import CmdSet
-from evennia.commands.default import account
-
-
-
[docs]class SessionCmdSet(CmdSet): - """ - Sets up the unlogged cmdset. - """ - - key = "DefaultSession" - priority = -20 - -
[docs] def at_cmdset_creation(self): - "Populate the cmdset" - self.add(account.CmdSessions())
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/commands/default/cmdset_unloggedin.html b/docs/0.9.5/_modules/evennia/commands/default/cmdset_unloggedin.html deleted file mode 100644 index 8b7e08e819..0000000000 --- a/docs/0.9.5/_modules/evennia/commands/default/cmdset_unloggedin.html +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - - - evennia.commands.default.cmdset_unloggedin — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.commands.default.cmdset_unloggedin

-"""
-This module describes the unlogged state of the default game.
-The setting STATE_UNLOGGED should be set to the python path
-of the state instance in this module.
-"""
-from evennia.commands.cmdset import CmdSet
-from evennia.commands.default import unloggedin
-
-
-
[docs]class UnloggedinCmdSet(CmdSet): - """ - Sets up the unlogged cmdset. - """ - - key = "DefaultUnloggedin" - priority = 0 - -
[docs] def at_cmdset_creation(self): - "Populate the cmdset" - self.add(unloggedin.CmdUnconnectedConnect()) - self.add(unloggedin.CmdUnconnectedCreate()) - self.add(unloggedin.CmdUnconnectedQuit()) - self.add(unloggedin.CmdUnconnectedLook()) - self.add(unloggedin.CmdUnconnectedHelp()) - self.add(unloggedin.CmdUnconnectedEncoding()) - self.add(unloggedin.CmdUnconnectedScreenreader()) - self.add(unloggedin.CmdUnconnectedInfo())
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/commands/default/comms.html b/docs/0.9.5/_modules/evennia/commands/default/comms.html deleted file mode 100644 index 9581136b9a..0000000000 --- a/docs/0.9.5/_modules/evennia/commands/default/comms.html +++ /dev/null @@ -1,1969 +0,0 @@ - - - - - - - - evennia.commands.default.comms — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.commands.default.comms

-"""
-Communication commands:
-
-- channel
-- page
-- irc/rss/grapevine linking
-
-"""
-
-from django.conf import settings
-from evennia.comms.models import Msg
-from evennia.accounts.models import AccountDB
-from evennia.accounts import bots
-from evennia.locks.lockhandler import LockException
-from evennia.comms.comms import DefaultChannel
-from evennia.utils import create, logger, utils
-from evennia.utils.logger import tail_log_file
-from evennia.utils.utils import class_from_module, strip_unsafe_input
-from evennia.utils.evmenu import ask_yes_no
-
-COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
-CHANNEL_DEFAULT_TYPECLASS = class_from_module(
-    settings.BASE_CHANNEL_TYPECLASS, fallback=settings.FALLBACK_CHANNEL_TYPECLASS)
-
-
-# limit symbol import for API
-__all__ = (
-    "CmdChannel",
-    "CmdObjectChannel",
-
-    "CmdPage",
-
-    "CmdIRC2Chan",
-    "CmdIRCStatus",
-    "CmdRSS2Chan",
-    "CmdGrapevine2Chan",
-)
-_DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
-
-# helper functions to make it easier to override the main CmdChannel
-# command and to keep the legacy addcom etc commands around.
-
-
-
[docs]class CmdChannel(COMMAND_DEFAULT_CLASS): - """ - Use and manage in-game channels. - - Usage: - channel channelname <msg> - channel channel name = <msg> - channel (show all subscription) - channel/all (show available channels) - channel/alias channelname = alias[;alias...] - channel/unalias alias - channel/who channelname - channel/history channelname [= index] - channel/sub channelname [= alias[;alias...]] - channel/unsub channelname[,channelname, ...] - channel/mute channelname[,channelname,...] - channel/unmute channelname[,channelname,...] - - channel/create channelname[;alias;alias[:typeclass]] [= description] - channel/destroy channelname [= reason] - channel/desc channelname = description - channel/lock channelname = lockstring - channel/unlock channelname = lockstring - channel/ban channelname (list bans) - channel/ban[/quiet] channelname[, channelname, ...] = subscribername [: reason] - channel/unban[/quiet] channelname[, channelname, ...] = subscribername - channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason] - - # subtopics - - ## sending - - Usage: channel channelname msg - channel channel name = msg (with space in channel name) - - This sends a message to the channel. Note that you will rarely use this - command like this; instead you can use the alias - - channelname <msg> - channelalias <msg> - - For example - - public Hello World - pub Hello World - - (this shortcut doesn't work for aliases containing spaces) - - See channel/alias for help on setting channel aliases. - - ## alias and unalias - - Usage: channel/alias channel = alias[;alias[;alias...]] - channel/unalias alias - channel - this will list your subs and aliases to each channel - - Set one or more personal aliases for referencing a channel. For example: - - channel/alias warrior's guild = warrior;wguild;warchannel;warrior guild - - You can now send to the channel using all of these: - - warrior's guild Hello - warrior Hello - wguild Hello - warchannel Hello - - Note that this will not work if the alias has a space in it. So the - 'warrior guild' alias must be used with the `channel` command: - - channel warrior guild = Hello - - Channel-aliases can be removed one at a time, using the '/unalias' switch. - - ## who - - Usage: channel/who channelname - - List the channel's subscribers. Shows who are currently offline or are - muting the channel. Subscribers who are 'muting' will not see messages sent - to the channel (use channel/mute to mute a channel). - - ## history - - Usage: channel/history channel [= index] - - This will display the last |c20|n lines of channel history. By supplying an - index number, you will step that many lines back before viewing those 20 lines. - - For example: - - channel/history public = 35 - - will go back 35 lines and show the previous 20 lines from that point (so - lines -35 to -55). - - ## sub and unsub - - Usage: channel/sub channel [=alias[;alias;...]] - channel/unsub channel - - This subscribes you to a channel and optionally assigns personal shortcuts - for you to use to send to that channel (see aliases). When you unsub, all - your personal aliases will also be removed. - - ## mute and unmute - - Usage: channel/mute channelname - channel/unmute channelname - - Muting silences all output from the channel without actually - un-subscribing. Other channel members will see that you are muted in the /who - list. Sending a message to the channel will automatically unmute you. - - ## create and destroy - - Usage: channel/create channelname[;alias;alias[:typeclass]] [= description] - channel/destroy channelname [= reason] - - Creates a new channel (or destroys one you control). You will automatically - join the channel you create and everyone will be kicked and loose all aliases - to a destroyed channel. - - ## lock and unlock - - Usage: channel/lock channelname = lockstring - channel/unlock channelname = lockstring - - Note: this is an admin command. - - A lockstring is on the form locktype:lockfunc(). Channels understand three - locktypes: - listen - who may listen or join the channel. - send - who may send messages to the channel - control - who controls the channel. This is usually the one creating - the channel. - - Common lockfuncs are all() and perm(). To make a channel everyone can - listen to but only builders can talk on, use this: - - listen:all() - send: perm(Builders) - - ## boot and ban - - Usage: - channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason] - channel/ban channelname[, channelname, ...] = subscribername [: reason] - channel/unban channelname[, channelname, ...] = subscribername - channel/unban channelname - channel/ban channelname (list bans) - - Booting will kick a named subscriber from channel(s) temporarily. The - 'reason' will be passed to the booted user. Unless the /quiet switch is - used, the channel will also be informed of the action. A booted user is - still able to re-connect, but they'll have to set up their aliases again. - - Banning will blacklist a user from (re)joining the provided channels. It - will then proceed to boot them from those channels if they were connected. - The 'reason' and `/quiet` works the same as for booting. - - Example: - boot mychannel1 = EvilUser : Kicking you to cool down a bit. - ban mychannel1,mychannel2= EvilUser : Was banned for spamming. - - """ - key = "@channel" - aliases = ["@chan", "@channels"] - help_category = "Comms" - # these cmd: lock controls access to the channel command itself - # the admin: lock controls access to /boot/ban/unban switches - # the manage: lock controls access to /create/destroy/desc/lock/unlock switches - locks = "cmd:not pperm(channel_banned);admin:all();manage:all();changelocks:perm(Admin)" - switch_options = ( - "list", "all", "history", "sub", "unsub", "mute", "unmute", "alias", "unalias", - "create", "destroy", "desc", "lock", "unlock", "boot", "ban", "unban", "who",) - # disable this in child command classes if wanting on-character channels - account_caller = True - -
[docs] def search_channel(self, channelname, exact=False, handle_errors=True): - """ - Helper function for searching for a single channel with some error - handling. - - Args: - channelname (str): Name, alias #dbref or partial name/alias to search - for. - exact (bool, optional): If an exact or fuzzy-match of the name should be done. - Note that even for a fuzzy match, an exactly given, unique channel name - will always be returned. - handle_errors (bool): If true, use `self.msg` to report errors if - there are non/multiple matches. If so, the return will always be - a single match or None. - Returns: - object, list or None: If `handle_errors` is `True`, this is either a found Channel - or `None`. Otherwise it's a list of zero, one or more channels found. - Notes: - The 'listen' and 'control' accesses are checked before returning. - - """ - caller = self.caller - # first see if this is a personal alias - channelname = caller.nicks.get(key=channelname, category="channel") or channelname - - # always try the exact match first. - channels = CHANNEL_DEFAULT_TYPECLASS.objects.channel_search(channelname, exact=True) - - if not channels and not exact: - # try fuzzy matching as well - channels = CHANNEL_DEFAULT_TYPECLASS.objects.channel_search(channelname, exact=exact) - - # check permissions - channels = [channel for channel in channels - if channel.access(caller, 'listen') or channel.access(caller, 'control')] - - if handle_errors: - if not channels: - self.msg(f"No channel found matching '{channelname}' " - "(could also be due to missing access).") - return None - elif len(channels) > 1: - self.msg("Multiple possible channel matches/alias for " - "'{channelname}':\n" + ", ".join(chan.key for chan in channels)) - return None - return channels[0] - else: - if not channels: - return [] - elif len(channels) > 1: - return list(channels) - return [channels[0]]
- -
[docs] def msg_channel(self, channel, message, **kwargs): - """ - Send a message to a given channel. This will check the 'send' - permission on the channel. - - Args: - channel (Channel): The channel to send to. - message (str): The message to send. - **kwargs: Unused by default. These kwargs will be passed into - all channel messaging hooks for custom overriding. - - """ - if not channel.access(self.caller, "send"): - caller.msg(f"You are not allowed to send messages to channel {channel}") - return - - # avoid unsafe tokens in message - message = strip_unsafe_input(message, self.session) - - channel.msg(message, senders=self.caller, **kwargs)
- -
[docs] def get_channel_history(self, channel, start_index=0): - """ - View a channel's history. - - Args: - channel (Channel): The channel to access. - message (str): The message to send. - **kwargs: Unused by default. These kwargs will be passed into - all channel messaging hooks for custom overriding. - - """ - caller = self.caller - log_file = channel.get_log_filename() - - def send_msg(lines): - return self.msg( - "".join(line.split("[-]", 1)[1] if "[-]" in line else line for line in lines) - ) - # asynchronously tail the log file - tail_log_file(log_file, start_index, 20, callback=send_msg)
- -
[docs] def sub_to_channel(self, channel): - """ - Subscribe to a channel. Note that all permissions should - be checked before this step. - - Args: - channel (Channel): The channel to access. - - Returns: - bool, str: True, None if connection failed. If False, - the second part is an error string. - - """ - caller = self.caller - - if channel.has_connection(caller): - return False, f"Already listening to channel {channel.key}." - - # this sets up aliases in post_join_channel by default - result = channel.connect(caller) - - return result, "" if result else f"Were not allowed to subscribe to channel {channel.key}"
- -
[docs] def unsub_from_channel(self, channel, **kwargs): - """ - Un-Subscribe to a channel. Note that all permissions should - be checked before this step. - - Args: - channel (Channel): The channel to unsub from. - **kwargs: Passed on to nick removal. - - Returns: - bool, str: True, None if un-connection succeeded. If False, - the second part is an error string. - - """ - caller = self.caller - - if not channel.has_connection(caller): - return False, f"Not listening to channel {channel.key}." - - # this will also clean aliases - result = channel.disconnect(caller) - - return result, "" if result else f"Could not unsubscribe from channel {channel.key}"
- -
[docs] def add_alias(self, channel, alias, **kwargs): - """ - Add a new alias (nick) for the user to use with this channel. - - Args: - channel (Channel): The channel to alias. - alias (str): The personal alias to use for this channel. - **kwargs: If given, passed into nicks.add. - - Note: - We add two nicks - one is a plain `alias -> channel.key` that - we need to be able to reference this channel easily. The other - is a templated nick to easily be able to send messages to the - channel without needing to give the full `channel` command. The - structure of this nick is given by `self.channel_msg_pattern` - and `self.channel_msg_nick_replacement`. By default it maps - `alias <msg> -> channel <channelname> = <msg>`, so that you can - for example just write `pub Hello` to send a message. - - The alias created is `alias $1 -> channel channel = $1`, to allow - for sending to channel using the main channel command. - - """ - channel.add_user_channel_alias(self.caller, alias, **kwargs)
- -
[docs] def remove_alias(self, alias, **kwargs): - """ - Remove an alias from a channel. - - Args: - alias (str, optional): The alias to remove. - The channel will be reverse-determined from the - alias, if it exists. - - Returns: - bool, str: True, None if removal succeeded. If False, - the second part is an error string. - **kwargs: If given, passed into nicks.get/add. - - Note: - This will remove two nicks - the plain channel alias and the templated - nick used for easily sending messages to the channel. - - """ - if self.caller.nicks.has(alias, category="channel", **kwargs): - DefaultChannel.remove_user_channel_alias(self.caller, alias) - return True, "" - return False, "No such alias was defined."
- -
[docs] def get_channel_aliases(self, channel): - """ - Get a user's aliases for a given channel. The user is retrieved - through self.caller. - - Args: - channel (Channel): The channel to act on. - - Returns: - list: A list of zero, one or more alias-strings. - - """ - chan_key = channel.key.lower() - nicktuples = self.caller.nicks.get(category="channel", return_tuple=True, return_list=True) - if nicktuples: - return [tup[2] for tup in nicktuples if tup[3].lower() == chan_key] - return []
- -
[docs] def mute_channel(self, channel): - """ - Temporarily mute a channel. - - Args: - channel (Channel): The channel to alias. - - Returns: - bool, str: True, None if muting successful. If False, - the second part is an error string. - """ - if channel.mute(self.caller): - return True, "" - return False, f"Channel {channel.key} was already muted."
- -
[docs] def unmute_channel(self, channel): - """ - Unmute a channel. - - Args: - channel (Channel): The channel to alias. - - Returns: - bool, str: True, None if unmuting successful. If False, - the second part is an error string. - - """ - if channel.unmute(self.caller): - return True, "" - return False, f"Channel {channel.key} was already unmuted."
- -
[docs] def create_channel(self, name, description, typeclass=None, aliases=None): - """ - Create a new channel. Its name must not previously exist - (users can alias as needed). Will also connect to the - new channel. - - Args: - name (str): The new channel name/key. - description (str): This is used in listings. - aliases (list): A list of strings - alternative aliases for the channel - (not to be confused with per-user aliases; these are available for - everyone). - - Returns: - channel, str: new_channel, "" if creation successful. If False, - the second part is an error string. - - """ - caller = self.caller - if typeclass: - typeclass = class_from_module(typeclass) - else: - typeclass = CHANNEL_DEFAULT_TYPECLASS - - if typeclass.objects.channel_search(name, exact=True): - return False, f"Channel {name} already exists." - - # set up the new channel - lockstring = "send:all();listen:all();control:id(%s)" % caller.id - - new_chan = create.create_channel( - name, aliases=aliases, desc=description, locks=lockstring, typeclass=typeclass) - self.sub_to_channel(new_chan) - return new_chan, ""
- -
[docs] def destroy_channel(self, channel, message=None): - """ - Destroy an existing channel. Access should be checked before - calling this function. - - Args: - channel (Channel): The channel to alias. - message (str, optional): Final message to send onto the channel - before destroying it. If not given, a default message is - used. Set to the empty string for no message. - - if typeclass: - pass - - """ - caller = self.caller - - channel_key = channel.key - if message is None: - message = (f"|rChannel {channel_key} is being destroyed. " - "Make sure to clean any channel aliases.|n") - if message: - channel.msg(message, senders=caller, bypass_mute=True) - channel.delete() - logger.log_sec( - "Channel {} was deleted by {}".format(channel_key, caller) - )
- -
[docs] def set_lock(self, channel, lockstring): - """ - Set a lockstring on a channel. Permissions must have been - checked before this call. - - Args: - channel (Channel): The channel to operate on. - lockstring (str): A lockstring on the form 'type:lockfunc();...' - - Returns: - bool, str: True, None if setting lock was successful. If False, - the second part is an error string. - - """ - try: - channel.locks.add(lockstring) - except LockException as err: - return False, err - return True, ""
- -
[docs] def unset_lock(self, channel, lockstring): - """ - Remove locks in a lockstring on a channel. Permissions must have been - checked before this call. - - Args: - channel (Channel): The channel to operate on. - lockstring (str): A lockstring on the form 'type:lockfunc();...' - - Returns: - bool, str: True, None if setting lock was successful. If False, - the second part is an error string. - - """ - try: - channel.locks.remove(lockstring) - except LockException as err: - return False, err - return True, ""
- -
[docs] def set_desc(self, channel, description): - """ - Set a channel description. This is shown in listings etc. - - Args: - caller (Object or Account): The entity performing the action. - channel (Channel): The channel to operate on. - description (str): A short description of the channel. - - Returns: - bool, str: True, None if setting lock was successful. If False, - the second part is an error string. - - """ - channel.db.desc = description
- -
[docs] def boot_user(self, channel, target, quiet=False, reason=""): - """ - Boot a user from a channel, with optional reason. This will - also remove all their aliases for this channel. - - Args: - channel (Channel): The channel to operate on. - target (Object or Account): The entity to boot. - quiet (bool, optional): Whether or not to announce to channel. - reason (str, optional): A reason for the boot. - - Returns: - bool, str: True, None if setting lock was successful. If False, - the second part is an error string. - - """ - if not channel.subscriptions.has(target): - return False, f"{target} is not connected to channel {channel.key}." - # find all of target's nicks linked to this channel and delete them - for nick in [ - nick - for nick in target.nicks.get(category="channel") or [] - if nick.value[3].lower() == channel.key - ]: - nick.delete() - channel.disconnect(target) - reason = f" Reason: {reason}" if reason else "" - target.msg(f"You were booted from channel {channel.key} by {self.caller.key}.{reason}") - if not quiet: - channel.msg(f"{target.key} was booted from channel by {self.caller.key}.{reason}") - - logger.log_sec(f"Channel Boot: {target} (Channel: {channel}, " - f"Reason: {reason.strip()}, Caller: {self.caller}") - return True, ""
- -
[docs] def ban_user(self, channel, target, quiet=False, reason=""): - """ - Ban a user from a channel, by locking them out. This will also - boot them, if they are currently connected. - - Args: - channel (Channel): The channel to operate on. - target (Object or Account): The entity to ban - quiet (bool, optional): Whether or not to announce to channel. - reason (str, optional): A reason for the ban - - Returns: - bool, str: True, None if banning was successful. If False, - the second part is an error string. - - """ - self.boot_user(channel, target, quiet=quiet, reason=reason) - if channel.ban(target): - return True, "" - return False, f"{target} is already banned from this channel."
- -
[docs] def unban_user(self, channel, target): - """ - Un-Ban a user from a channel. This will not reconnect them - to the channel, just allow them to connect again (assuming - they have the suitable 'listen' lock like everyone else). - - Args: - channel (Channel): The channel to operate on. - target (Object or Account): The entity to unban - - Returns: - bool, str: True, None if unbanning was successful. If False, - the second part is an error string. - - """ - if channel.unban(target): - return True, "" - return False, f"{target} was not previously banned from this channel."
- -
[docs] def channel_list_bans(self, channel): - """ - Show a channel's bans. - - Args: - channel (Channel): The channel to operate on. - - Returns: - list: A list of strings, each the name of a banned user. - - """ - return [banned.key for banned in channel.banlist]
- -
[docs] def channel_list_who(self, channel): - """ - Show a list of online people is subscribing to a channel. This will check - the 'control' permission of `caller` to determine if only online users - should be returned or everyone. - - Args: - channel (Channel): The channel to operate on. - - Returns: - list: A list of prepared strings, with name + markers for if they are - muted or offline. - - """ - caller = self.caller - mute_list = list(channel.mutelist) - online_list = channel.subscriptions.online() - if channel.access(caller, 'control'): - # for those with channel control, show also offline users - all_subs = list(channel.subscriptions.all()) - else: - # for others, only show online users - all_subs = online_list - - who_list = [] - for subscriber in all_subs: - name = subscriber.get_display_name(caller) - conditions = ("muting" if subscriber in mute_list else "", - "offline" if subscriber not in online_list else "") - conditions = [cond for cond in conditions if cond] - cond_text = "(" + ", ".join(conditions) + ")" if conditions else "" - who_list.append(f"{name}{cond_text}") - - return who_list
- -
[docs] def list_channels(self, channelcls=CHANNEL_DEFAULT_TYPECLASS): - """ - Return a available channels. - - Args: - channelcls (Channel, optional): The channel-class to query on. Defaults - to the default channel class from settings. - - Returns: - tuple: A tuple `(subbed_chans, available_chans)` with the channels - currently subscribed to, and those we have 'listen' access to but - don't actually sub to yet. - - """ - caller = self.caller - subscribed_channels = list(channelcls.objects.get_subscriptions(caller)) - unsubscribed_available_channels = [ - chan - for chan in channelcls.objects.get_all_channels() - if chan not in subscribed_channels and chan.access(caller, "listen") - ] - return subscribed_channels, unsubscribed_available_channels
- -
[docs] def display_subbed_channels(self, subscribed): - """ - Display channels subscribed to. - - Args: - subscribed (list): List of subscribed channels - - Returns: - EvTable: Table to display. - - """ - comtable = self.styled_table( - "id", - "channel", - "my aliases", - "locks", - "description", - align="l", - maxwidth=_DEFAULT_WIDTH - ) - for chan in subscribed: - - locks = "-" - chanid = "-" - if chan.access(self.caller, "control"): - locks = chan.locks - chanid = chan.id - - my_aliases = ", ".join(self.get_channel_aliases(chan)) - comtable.add_row( - *( - chanid, - "{key}{aliases}".format( - key=chan.key, - aliases=";"+ ";".join(chan.aliases.all()) if chan.aliases.all() else "" - ), - my_aliases, - locks, - chan.db.desc - ) - ) - return comtable
- -
[docs] def display_all_channels(self, subscribed, available): - """ - Display all available channels - - Args: - subscribed (list): List of subscribed channels - Returns: - EvTable: Table to display. - - """ - caller = self.caller - - comtable = self.styled_table( - "sub", - "channel", - "aliases", - "my aliases", - "description", - maxwidth=_DEFAULT_WIDTH, - ) - channels = subscribed + available - - for chan in channels: - if chan not in subscribed: - substatus = "|rNo|n" - elif caller in chan.mutelist: - substatus = "|rMuting|n" - else: - substatus = "|gYes|n" - my_aliases = ", ".join(self.get_channel_aliases(chan)) - comtable.add_row( - *(substatus, - chan.key, - ",".join(chan.aliases.all()) if chan.aliases.all() else "", - my_aliases, - chan.db.desc)) - comtable.reformat_column(0, width=8) - - return comtable
- -
[docs] def func(self): - """ - Main functionality of command. - """ - # from evennia import set_trace;set_trace() - - caller = self.caller - switches = self.switches - channel_names = [name for name in self.lhslist if name] - - #from evennia import set_trace;set_trace() - - if 'all' in switches: - # show all available channels - subscribed, available = self.list_channels() - table = self.display_all_channels(subscribed, available) - - self.msg( - "\n|wAvailable channels|n (use no argument to " - f"only show your subscriptions)\n{table}") - return - - if not channel_names: - # empty arg show only subscribed channels - subscribed, _ = self.list_channels() - table = self.display_subbed_channels(subscribed) - - self.msg("\n|wChannel subscriptions|n " - f"(use |w/all|n to see all available):\n{table}") - return - - if not self.switches and not self.args: - self.msg("Usage[/switches]: channel [= message]") - return - - if 'create' in switches: - # create a new channel - - if not self.access(caller, "manage"): - self.msg("You don't have access to use channel/create.") - return - - config = self.lhs - if not config: - self.msg("To create: channel/create name[;aliases][:typeclass] [= description]") - return - name, *typeclass = config.rsplit(":", 1) - typeclass = typeclass[0] if typeclass else None - name, *aliases = name.rsplit(";") - description = self.rhs or "" - chan, err = self.create_channel(name, description, typeclass=typeclass, aliases=aliases) - if chan: - self.msg(f"Created (and joined) new channel '{chan.key}'.") - else: - self.msg(err) - return - - if 'unalias' in switches: - # remove a personal alias (no channel needed) - alias = self.args.strip() - if not alias: - self.msg("Specify the alias to remove as channel/unalias <alias>") - return - success, err = self.remove_alias(alias) - if success: - self.msg(f"Removed your channel alias '{alias}'.") - else: - self.msg(err) - return - - possible_lhs_message = "" - if not self.rhs and self.args and " " in self.args: - # since we want to support messaging with `channel name text` (for - # channels without a space in their name), we need to check if the - # first 'channel name' is in fact 'channelname text' - no_rhs_channel_name = self.args.split(" ", 1)[0] - possible_lhs_message = self.args[len(no_rhs_channel_name):] - if possible_lhs_message.strip() == '=': - possible_lhs_message = "" - channel_names.append(no_rhs_channel_name) - - - channels = [] - errors = [] - for channel_name in channel_names: - # find a channel by fuzzy-matching. This also checks - # 'listen/control' perms. - found_channels = self.search_channel(channel_name, exact=False, handle_errors=False) - if not found_channels: - errors.append(f"No channel found matching '{channel_name}' " - "(could also be due to missing access).") - elif len(found_channels) > 1: - errors.append("Multiple possible channel matches/alias for " - "'{channel_name}':\n" + ", ".join(chan.key for chan in found_channels)) - else: - channels.append(found_channels[0]) - - if not channels: - self.msg('\n'.join(errors)) - return - - # we have at least one channel at this point - channel = channels[0] - - if not switches: - if self.rhs: - # send message to channel - self.msg_channel(channel, self.rhs.strip()) - elif channel and possible_lhs_message: - # called on the form channelname message without = - self.msg_channel(channel, possible_lhs_message.strip()) - else: - # inspect a given channel - subscribed, available = self.list_channels() - if channel in subscribed: - table = self.display_subbed_channels([channel]) - header = f"Channel |w{channel.key}|n" - self.msg(f"{header}\n(use |w{channel.key} <msg>|n (or a channel-alias) " - f"to chat and the 'channel' command " - f"to customize)\n{table}") - elif channel in available: - table = self.display_all_channels([], [channel]) - self.msg( - "\n|wNot subscribed to this channel|n (use /list to " - f"show all subscriptions)\n{table}") - return - - if 'history' in switches or 'hist' in switches: - # view channel history - - index = self.rhs or 0 - try: - index = max(0, int(index)) - except ValueError: - self.msg("The history index (describing how many lines to go back) " - "must be an integer >= 0.") - return - self.get_channel_history(channel, start_index=index) - return - - if 'sub' in switches: - # subscribe to a channel - aliases = [] - if self.rhs: - aliases = set(alias.strip().lower() for alias in self.rhs.split(";")) - success, err = self.sub_to_channel(channel) - if success: - for alias in aliases: - self.add_alias(channel, alias) - alias_txt = ', '.join(aliases) - alias_txt = f" using alias(es) {alias_txt}" if aliases else '' - self.msg("You are now subscribed " - f"to the channel {channel.key}{alias_txt}. Use /alias to " - "add additional aliases for referring to the channel.") - else: - self.msg(err) - return - - if 'unsub' in switches: - # un-subscribe from a channel - success, err = self.unsub_from_channel(channel) - if success: - self.msg(f"You un-subscribed from channel {channel.key}. " - "All aliases were cleared.") - else: - self.msg(err) - return - - if 'alias' in switches: - # create a new personal alias for a channel - alias = self.rhs - if not alias: - self.msg("Specify the alias as channel/alias channelname = alias") - return - self.add_alias(channel, alias) - self.msg(f"Added/updated your alias '{alias}' for channel {channel.key}.") - return - - if 'mute' in switches: - # mute a given channel - success, err = self.mute_channel(channel) - if success: - self.msg(f"Muted channel {channel.key}.") - else: - self.msg(err) - return - - if 'unmute' in switches: - # unmute a given channel - success, err = self.unmute_channel(channel) - if success: - self.msg(f"Un-muted channel {channel.key}.") - else: - self.msg(err) - return - - if 'destroy' in switches or 'delete' in switches: - # destroy a channel we control - - if not self.access(caller, "manage"): - self.msg("You don't have access to use channel/destroy.") - return - - if not channel.access(caller, "control"): - self.msg("You can only delete channels you control.") - return - - reason = self.rhs or None - - def _perform_delete(caller, *args, **kwargs): - self.destroy_channel(channel, message=reason) - self.msg(f"Channel {channel.key} was successfully deleted.") - - ask_yes_no( - caller, - prompt=f"Are you sure you want to delete channel '{channel.key}' " - "(make sure name is correct!)?\nThis will disconnect and " - "remove all users' aliases. {options}?", - yes_action=_perform_delete, - no_action="Aborted.", - default="N" - ) - - if 'desc' in switches: - # set channel description - - if not self.access(caller, "manage"): - self.msg("You don't have access to use channel/desc.") - return - - if not channel.access(caller, "control"): - self.msg("You can only change description of channels you control.") - return - - desc = self.rhs.strip() - - if not desc: - self.msg("Usage: /desc channel = description") - return - - self.set_desc(channel, desc) - self.msg("Updated channel description.") - - if 'lock' in switches: - # add a lockstring to channel - - if not self.access(caller, "changelocks"): - self.msg("You don't have access to use channel/lock.") - return - - if not channel.access(caller, "control"): - self.msg("You need 'control'-access to change locks on this channel.") - return - - lockstring = self.rhs.strip() - - if not lockstring: - self.msg("Usage: channel/lock channelname = lockstring") - return - - success, err = self.set_lock(channel, self.rhs) - if success: - self.msg("Added/updated lock on channel.") - else: - self.msg(f"Could not add/update lock: {err}") - return - - if 'unlock' in switches: - # remove/update lockstring from channel - - if not self.access(caller, "changelocks"): - self.msg("You don't have access to use channel/unlock.") - return - - if not channel.access(caller, "control"): - self.msg("You need 'control'-access to change locks on this channel.") - return - - lockstring = self.rhs.strip() - - if not lockstring: - self.msg("Usage: channel/unlock channelname = lockstring") - return - - success, err = self.unset_lock(channel, self.rhs) - if success: - self.msg("Removed lock from channel.") - else: - self.msg(f"Could not remove lock: {err}") - return - - if 'boot' in switches: - # boot a user from channel(s) - - if not self.access(caller, "admin"): - self.msg("You don't have access to use channel/boot.") - return - - if not self.rhs: - self.msg("Usage: channel/boot channel[,channel,...] = username [:reason]") - return - - target_str, *reason = self.rhs.rsplit(":", 1) - reason = reason[0].strip() if reason else "" - - for chan in channels: - - if not chan.access(caller, "control"): - self.msg(f"You need 'control'-access to boot a user from {chan.key}.") - return - - # the target must be a member of all given channels - target = caller.search(target_str, candidates=chan.subscriptions.all()) - if not target: - self.msg(f"Cannot boot '{target_str}' - not in channel {chan.key}.") - return - - def _boot_user(caller, *args, **kwargs): - for chan in channels: - success, err = self.boot_user(chan, target, quiet=False, reason=reason) - if success: - self.msg(f"Booted {target.key} from channel {chan.key}.") - else: - self.msg(f"Cannot boot {target.key} from channel {chan.key}: {err}") - - channames = ", ".join(chan.key for chan in channels) - reasonwarn = (". Also note that your reason will be echoed to the channel" - if reason else '') - ask_yes_no( - caller, - prompt=f"Are you sure you want to boot user {target.key} from " - f"channel(s) {channames} (make sure name/channels are correct{reasonwarn}). " - "{options}?", - yes_action=_boot_user, - no_action="Aborted.", - default="Y" - ) - return - - if 'ban' in switches: - # ban a user from channel(s) - - if not self.access(caller, "admin"): - self.msg("You don't have access to use channel/ban.") - return - - if not self.rhs: - # view bans for channels - - if not channel.access(caller, "control"): - self.msg(f"You need 'control'-access to view bans on channel {channel.key}") - return - - bans = ["Channel bans " - "(to ban, use channel/ban channel[,channel,...] = username [:reason]"] - bans.extend(self.channel_list_bans(channel)) - self.msg("\n".join(bans)) - return - - target_str, *reason = self.rhs.rsplit(":", 1) - reason = reason[0].strip() if reason else "" - - for chan in channels: - # the target must be a member of all given channels - if not chan.access(caller, "control"): - self.msg(f"You don't have access to ban users on channel {chan.key}") - return - - target = caller.search(target_str, candidates=chan.subscriptions.all()) - - if not target: - self.msg(f"Cannot ban '{target_str}' - not in channel {chan.key}.") - return - - def _ban_user(caller, *args, **kwargs): - for chan in channels: - success, err = self.ban_user(chan, target, quiet=False, reason=reason) - if success: - self.msg(f"Banned {target.key} from channel {chan.key}.") - else: - self.msg(f"Cannot boot {target.key} from channel {chan.key}: {err}") - - channames = ", ".join(chan.key for chan in channels) - reasonwarn = (". Also note that your reason will be echoed to the channel" - if reason else '') - ask_yes_no( - caller, - f"Are you sure you want to ban user {target.key} from " - f"channel(s) {channames} (make sure name/channels are correct{reasonwarn}) " - "{options}?", - _ban_user, - "Aborted.", - ) - return - - if 'unban' in switches: - # unban a previously banned user from channel - - if not self.access(caller, "admin"): - self.msg("You don't have access to use channel/unban.") - return - - target_str = self.rhs.strip() - - if not target_str: - self.msg("Usage: channel[,channel,...] = user") - return - - banlists = [] - for chan in channels: - # the target must be a member of all given channels - if not chan.access(caller, "control"): - self.msg(f"You don't have access to unban users on channel {chan.key}") - return - banlists.extend(chan.banlist) - - target = caller.search(target_str, candidates=banlists) - if not target: - self.msg("Could not find a banned user '{target_str}' in given channel(s).") - return - - for chan in channels: - success, err = self.unban_user(channel, target) - if success: - self.msg(f"Un-banned {target_str} from channel {chan.key}") - else: - self.msg(err) - return - - if "who" in switches: - # view who's a member of a channel - - who_list = [f"Subscribed to {channel.key}:"] - who_list.extend(self.channel_list_who(channel)) - self.msg("\n".join(who_list)) - return
- - -# a channel-command parent for use with Characters/Objects. -
[docs]class CmdObjectChannel(CmdChannel): - account_caller = False
- - -
[docs]class CmdPage(COMMAND_DEFAULT_CLASS): - """ - send a private message to another account - - Usage: - page <account> <message> - page[/switches] [<account>,<account>,... = <message>] - tell '' - page <number> - - Switches: - last - shows who you last messaged - list - show your last <number> of tells/pages (default) - - Send a message to target user (if online). If no argument is given, you - will get a list of your latest messages. The equal sign is needed for - multiple targets or if sending to target with space in the name. - - """ - - key = "page" - aliases = ["tell"] - switch_options = ("last", "list") - locks = "cmd:not pperm(page_banned)" - help_category = "Comms" - - # this is used by the COMMAND_DEFAULT_CLASS parent - account_caller = True - -
[docs] def func(self): - """Implement function using the Msg methods""" - - # Since account_caller is set above, this will be an Account. - caller = self.caller - - # get the messages we've sent (not to channels) - pages_we_sent = Msg.objects.get_messages_by_sender(caller) - # get last messages we've got - pages_we_got = Msg.objects.get_messages_by_receiver(caller) - targets, message, number = [], None, None - - if "last" in self.switches: - if pages_we_sent: - recv = ",".join(obj.key for obj in pages_we_sent[-1].receivers) - self.msg("You last paged |c%s|n:%s" % (recv, pages_we_sent[-1].message)) - return - else: - self.msg("You haven't paged anyone yet.") - return - - if self.args: - if self.rhs: - for target in self.lhslist: - target_obj = self.caller.search(target) - if not target_obj: - return - targets.append(target_obj) - message = self.rhs.strip() - else: - target, *message = self.args.split(" ", 4) - if target and target.isnumeric(): - # a number to specify a historic page - number = int(target) - elif target: - target_obj = self.caller.search(target, quiet=True) - if target_obj: - # a proper target - targets = [target_obj[0]] - message = message[0].strip() - else: - # a message with a space in it - put it back together - message = target + " " + (message[0] if message else "") - else: - # a single-word message - message = message[0].strip() - - pages = list(pages_we_sent) + list(pages_we_got) - pages = sorted(pages, key=lambda page: page.date_created) - - if message: - # send a message - if not targets: - # no target given - send to last person we paged - if pages_we_sent: - targets = pages_we_sent[-1].receivers - else: - self.msg("Who do you want page?") - return - - header = "|wAccount|n |c%s|n |wpages:|n" % caller.key - if message.startswith(":"): - message = "%s %s" % (caller.key, message.strip(":").strip()) - - # create the persistent message object - create.create_message(caller, message, receivers=targets) - - # tell the accounts they got a message. - received = [] - rstrings = [] - for target in targets: - if not target.access(caller, "msg"): - rstrings.append(f"You are not allowed to page {target}.") - continue - target.msg(f"{header} {message}") - if hasattr(target, "sessions") and not target.sessions.count(): - received.append(f"|C{target.name}|n") - rstrings.append( - f"{received[-1]} is offline. They will see your message " - "if they list their pages later." - ) - else: - received.append(f"|c{target.name}|n") - if rstrings: - self.msg("\n".join(rstrings)) - self.msg("You paged %s with: '%s'." % (", ".join(received), message)) - return - - else: - # no message to send - if number is not None and len(pages) > number: - lastpages = pages[-number:] - else: - lastpages = pages - to_template = "|w{date}{clr} {sender}|nto{clr}{receiver}|n:> {message}" - from_template = "|w{date}{clr} {receiver}|nfrom{clr}{sender}|n:< {message}" - listing = [] - prev_selfsend = False - for page in lastpages: - multi_send = len(page.senders) > 1 - multi_recv = len(page.receivers) > 1 - sending = self.caller in page.senders - # self-messages all look like sends, so we assume they always - # come in close pairs and treat the second of the pair as the recv. - selfsend = sending and self.caller in page.receivers - if selfsend: - if prev_selfsend: - # this is actually a receive of a self-message - sending = False - prev_selfsend = False - else: - prev_selfsend = True - - clr = "|c" if sending else "|g" - - sender = f"|n,{clr}".join(obj.key for obj in page.senders) - receiver = f"|n,{clr}".join([obj.name for obj in page.receivers]) - if sending: - template = to_template - sender = f"{sender} " if multi_send else "" - receiver = f" {receiver}" if multi_recv else f" {receiver}" - else: - template = from_template - receiver = f"{receiver} " if multi_recv else "" - sender = f" {sender} " if multi_send else f" {sender}" - - listing.append( - template.format( - date=utils.datetime_format(page.date_created), - clr=clr, - sender=sender, - receiver=receiver, - message=page.message, - ) - - ) - lastpages = "\n ".join(listing) - - if lastpages: - string = "Your latest pages:\n %s" % lastpages - else: - string = "You haven't paged anyone yet." - self.msg(string) - return
- - -def _list_bots(cmd): - """ - Helper function to produce a list of all IRC bots. - - Args: - cmd (Command): Instance of the Bot command. - Returns: - bots (str): A table of bots or an error message. - - """ - ircbots = [ - bot for bot in AccountDB.objects.filter(db_is_bot=True, username__startswith="ircbot-") - ] - if ircbots: - table = cmd.styled_table( - "|w#dbref|n", - "|wbotname|n", - "|wev-channel|n", - "|wirc-channel|n", - "|wSSL|n", - maxwidth=_DEFAULT_WIDTH, - ) - for ircbot in ircbots: - ircinfo = "%s (%s:%s)" % ( - ircbot.db.irc_channel, - ircbot.db.irc_network, - ircbot.db.irc_port, - ) - table.add_row( - "#%i" % ircbot.id, - ircbot.db.irc_botname, - ircbot.db.ev_channel, - ircinfo, - ircbot.db.irc_ssl, - ) - return table - else: - return "No irc bots found." - -
[docs]class CmdIRC2Chan(COMMAND_DEFAULT_CLASS): - """ - Link an evennia channel to an external IRC channel - - Usage: - irc2chan[/switches] <evennia_channel> = <ircnetwork> <port> <#irchannel> <botname>[:typeclass] - irc2chan/delete botname|#dbid - - Switches: - /delete - this will delete the bot and remove the irc connection - to the channel. Requires the botname or #dbid as input. - /remove - alias to /delete - /disconnect - alias to /delete - /list - show all irc<->evennia mappings - /ssl - use an SSL-encrypted connection - - Example: - irc2chan myircchan = irc.dalnet.net 6667 #mychannel evennia-bot - irc2chan public = irc.freenode.net 6667 #evgaming #evbot:accounts.mybot.MyBot - - This creates an IRC bot that connects to a given IRC network and - channel. If a custom typeclass path is given, this will be used - instead of the default bot class. - The bot will relay everything said in the evennia channel to the - IRC channel and vice versa. The bot will automatically connect at - server start, so this command need only be given once. The - /disconnect switch will permanently delete the bot. To only - temporarily deactivate it, use the |wservices|n command instead. - Provide an optional bot class path to use a custom bot. - """ - - key = "irc2chan" - switch_options = ("delete", "remove", "disconnect", "list", "ssl") - locks = "cmd:serversetting(IRC_ENABLED) and pperm(Developer)" - help_category = "Comms" - -
[docs] def func(self): - """Setup the irc-channel mapping""" - - if not settings.IRC_ENABLED: - string = """IRC is not enabled. You need to activate it in game/settings.py.""" - self.msg(string) - return - - if "list" in self.switches: - # show all connections - self.msg(_list_bots(self)) - return - - if "disconnect" in self.switches or "remove" in self.switches or "delete" in self.switches: - botname = "ircbot-%s" % self.lhs - matches = AccountDB.objects.filter(db_is_bot=True, username=botname) - dbref = utils.dbref(self.lhs) - if not matches and dbref: - # try dbref match - matches = AccountDB.objects.filter(db_is_bot=True, id=dbref) - if matches: - matches[0].delete() - self.msg("IRC connection destroyed.") - else: - self.msg("IRC connection/bot could not be removed, does it exist?") - return - - if not self.args or not self.rhs: - string = ( - "Usage: irc2chan[/switches] <evennia_channel> =" - " <ircnetwork> <port> <#irchannel> <botname>[:typeclass]" - ) - self.msg(string) - return - - channel = self.lhs - self.rhs = self.rhs.replace("#", " ") # to avoid Python comment issues - try: - irc_network, irc_port, irc_channel, irc_botname = [ - part.strip() for part in self.rhs.split(None, 4) - ] - irc_channel = "#%s" % irc_channel - except Exception: - string = "IRC bot definition '%s' is not valid." % self.rhs - self.msg(string) - return - - botclass = None - if ":" in irc_botname: - irc_botname, botclass = [part.strip() for part in irc_botname.split(":", 2)] - botname = "ircbot-%s" % irc_botname - # If path given, use custom bot otherwise use default. - botclass = botclass if botclass else bots.IRCBot - irc_ssl = "ssl" in self.switches - - # create a new bot - bot = AccountDB.objects.filter(username__iexact=botname) - if bot: - # re-use an existing bot - bot = bot[0] - if not bot.is_bot: - self.msg("Account '%s' already exists and is not a bot." % botname) - return - else: - try: - bot = create.create_account(botname, None, None, typeclass=botclass) - except Exception as err: - self.msg("|rError, could not create the bot:|n '%s'." % err) - return - bot.start( - ev_channel=channel, - irc_botname=irc_botname, - irc_channel=irc_channel, - irc_network=irc_network, - irc_port=irc_port, - irc_ssl=irc_ssl, - ) - self.msg("Connection created. Starting IRC bot.")
- - -
[docs]class CmdIRCStatus(COMMAND_DEFAULT_CLASS): - """ - Check and reboot IRC bot. - - Usage: - ircstatus [#dbref ping | nicklist | reconnect] - - If not given arguments, will return a list of all bots (like - irc2chan/list). The 'ping' argument will ping the IRC network to - see if the connection is still responsive. The 'nicklist' argument - (aliases are 'who' and 'users') will return a list of users on the - remote IRC channel. Finally, 'reconnect' will force the client to - disconnect and reconnect again. This may be a last resort if the - client has silently lost connection (this may happen if the remote - network experience network issues). During the reconnection - messages sent to either channel will be lost. - - """ - - key = "ircstatus" - locks = "cmd:serversetting(IRC_ENABLED) and perm(ircstatus) or perm(Builder))" - help_category = "Comms" - -
[docs] def func(self): - """Handles the functioning of the command.""" - - if not self.args: - self.msg(_list_bots(self)) - return - # should always be on the form botname option - args = self.args.split() - if len(args) != 2: - self.msg("Usage: ircstatus [#dbref ping||nicklist||reconnect]") - return - botname, option = args - if option not in ("ping", "users", "reconnect", "nicklist", "who"): - self.msg("Not a valid option.") - return - matches = None - if utils.dbref(botname): - matches = AccountDB.objects.filter(db_is_bot=True, id=utils.dbref(botname)) - if not matches: - self.msg( - "No matching IRC-bot found. Use ircstatus without arguments to list active bots." - ) - return - ircbot = matches[0] - channel = ircbot.db.irc_channel - network = ircbot.db.irc_network - port = ircbot.db.irc_port - chtext = "IRC bot '%s' on channel %s (%s:%s)" % ( - ircbot.db.irc_botname, - channel, - network, - port, - ) - if option == "ping": - # check connection by sending outself a ping through the server. - self.caller.msg("Pinging through %s." % chtext) - ircbot.ping(self.caller) - elif option in ("users", "nicklist", "who"): - # retrieve user list. The bot must handles the echo since it's - # an asynchronous call. - self.caller.msg("Requesting nicklist from %s (%s:%s)." % (channel, network, port)) - ircbot.get_nicklist(self.caller) - elif self.caller.locks.check_lockstring( - self.caller, "dummy:perm(ircstatus) or perm(Developer)" - ): - # reboot the client - self.caller.msg("Forcing a disconnect + reconnect of %s." % chtext) - ircbot.reconnect() - else: - self.caller.msg("You don't have permission to force-reload the IRC bot.")
- - -# RSS connection -
[docs]class CmdRSS2Chan(COMMAND_DEFAULT_CLASS): - """ - link an evennia channel to an external RSS feed - - Usage: - rss2chan[/switches] <evennia_channel> = <rss_url> - - Switches: - /disconnect - this will stop the feed and remove the connection to the - channel. - /remove - " - /list - show all rss->evennia mappings - - Example: - rss2chan rsschan = http://code.google.com/feeds/p/evennia/updates/basic - - This creates an RSS reader that connects to a given RSS feed url. Updates - will be echoed as a title and news link to the given channel. The rate of - updating is set with the RSS_UPDATE_INTERVAL variable in settings (default - is every 10 minutes). - - When disconnecting you need to supply both the channel and url again so as - to identify the connection uniquely. - """ - - key = "rss2chan" - switch_options = ("disconnect", "remove", "list") - locks = "cmd:serversetting(RSS_ENABLED) and pperm(Developer)" - help_category = "Comms" - -
[docs] def func(self): - """Setup the rss-channel mapping""" - - # checking we have all we need - if not settings.RSS_ENABLED: - string = """RSS is not enabled. You need to activate it in game/settings.py.""" - self.msg(string) - return - try: - import feedparser - - assert feedparser # to avoid checker error of not being used - except ImportError: - string = ( - "RSS requires python-feedparser (https://pypi.python.org/pypi/feedparser)." - " Install before continuing." - ) - self.msg(string) - return - - if "list" in self.switches: - # show all connections - rssbots = [ - bot - for bot in AccountDB.objects.filter(db_is_bot=True, username__startswith="rssbot-") - ] - if rssbots: - table = self.styled_table( - "|wdbid|n", - "|wupdate rate|n", - "|wev-channel", - "|wRSS feed URL|n", - border="cells", - maxwidth=_DEFAULT_WIDTH, - ) - for rssbot in rssbots: - table.add_row( - rssbot.id, rssbot.db.rss_rate, rssbot.db.ev_channel, rssbot.db.rss_url - ) - self.msg(table) - else: - self.msg("No rss bots found.") - return - - if "disconnect" in self.switches or "remove" in self.switches or "delete" in self.switches: - botname = "rssbot-%s" % self.lhs - matches = AccountDB.objects.filter(db_is_bot=True, db_key=botname) - if not matches: - # try dbref match - matches = AccountDB.objects.filter(db_is_bot=True, id=self.args.lstrip("#")) - if matches: - matches[0].delete() - self.msg("RSS connection destroyed.") - else: - self.msg("RSS connection/bot could not be removed, does it exist?") - return - - if not self.args or not self.rhs: - string = "Usage: rss2chan[/switches] <evennia_channel> = <rss url>" - self.msg(string) - return - channel = self.lhs - url = self.rhs - - botname = "rssbot-%s" % url - bot = AccountDB.objects.filter(username__iexact=botname) - if bot: - # re-use existing bot - bot = bot[0] - if not bot.is_bot: - self.msg("Account '%s' already exists and is not a bot." % botname) - return - else: - # create a new bot - bot = create.create_account(botname, None, None, typeclass=bots.RSSBot) - bot.start(ev_channel=channel, rss_url=url, rss_rate=10) - self.msg("RSS reporter created. Fetching RSS.")
- - -
[docs]class CmdGrapevine2Chan(COMMAND_DEFAULT_CLASS): - """ - Link an Evennia channel to an exteral Grapevine channel - - Usage: - grapevine2chan[/switches] <evennia_channel> = <grapevine_channel> - grapevine2chan/disconnect <connection #id> - - Switches: - /list - (or no switch): show existing grapevine <-> Evennia - mappings and available grapevine chans - /remove - alias to disconnect - /delete - alias to disconnect - - Example: - grapevine2chan mygrapevine = gossip - - This creates a link between an in-game Evennia channel and an external - Grapevine channel. The game must be registered with the Grapevine network - (register at https://grapevine.haus) and the GRAPEVINE_* auth information - must be added to game settings. - """ - - key = "grapevine2chan" - switch_options = ("disconnect", "remove", "delete", "list") - locks = "cmd:serversetting(GRAPEVINE_ENABLED) and pperm(Developer)" - help_category = "Comms" - -
[docs] def func(self): - """Setup the Grapevine channel mapping""" - - if not settings.GRAPEVINE_ENABLED: - self.msg("Set GRAPEVINE_ENABLED=True in settings to enable.") - return - - if "list" in self.switches: - # show all connections - gwbots = [ - bot - for bot in AccountDB.objects.filter( - db_is_bot=True, username__startswith="grapevinebot-" - ) - ] - if gwbots: - table = self.styled_table( - "|wdbid|n", - "|wev-channel", - "|wgw-channel|n", - border="cells", - maxwidth=_DEFAULT_WIDTH, - ) - for gwbot in gwbots: - table.add_row(gwbot.id, gwbot.db.ev_channel, gwbot.db.grapevine_channel) - self.msg(table) - else: - self.msg("No grapevine bots found.") - return - - if "disconnect" in self.switches or "remove" in self.switches or "delete" in self.switches: - botname = "grapevinebot-%s" % self.lhs - matches = AccountDB.objects.filter(db_is_bot=True, db_key=botname) - - if not matches: - # try dbref match - matches = AccountDB.objects.filter(db_is_bot=True, id=self.args.lstrip("#")) - if matches: - matches[0].delete() - self.msg("Grapevine connection destroyed.") - else: - self.msg("Grapevine connection/bot could not be removed, does it exist?") - return - - if not self.args or not self.rhs: - string = "Usage: grapevine2chan[/switches] <evennia_channel> = <grapevine_channel>" - self.msg(string) - return - - channel = self.lhs - grapevine_channel = self.rhs - - botname = "grapewinebot-%s-%s" % (channel, grapevine_channel) - bot = AccountDB.objects.filter(username__iexact=botname) - if bot: - # re-use existing bot - bot = bot[0] - if not bot.is_bot: - self.msg("Account '%s' already exists and is not a bot." % botname) - return - else: - self.msg("Reusing bot '%s' (%s)" % (botname, bot.dbref)) - else: - # create a new bot - bot = create.create_account(botname, None, None, typeclass=bots.GrapevineBot) - - bot.start(ev_channel=channel, grapevine_channel=grapevine_channel) - self.msg(f"Grapevine connection created {channel} <-> {grapevine_channel}.")
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/commands/default/general.html b/docs/0.9.5/_modules/evennia/commands/default/general.html deleted file mode 100644 index c34ced0898..0000000000 --- a/docs/0.9.5/_modules/evennia/commands/default/general.html +++ /dev/null @@ -1,844 +0,0 @@ - - - - - - - - evennia.commands.default.general — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.commands.default.general

-"""
-General Character commands usually available to all characters
-"""
-import re
-from django.conf import settings
-from evennia.utils import utils
-from evennia.typeclasses.attributes import NickTemplateInvalid
-
-COMMAND_DEFAULT_CLASS = utils.class_from_module(settings.COMMAND_DEFAULT_CLASS)
-
-# limit symbol import for API
-__all__ = (
-    "CmdHome",
-    "CmdLook",
-    "CmdNick",
-    "CmdInventory",
-    "CmdSetDesc",
-    "CmdGet",
-    "CmdDrop",
-    "CmdGive",
-    "CmdSay",
-    "CmdWhisper",
-    "CmdPose",
-    "CmdAccess",
-)
-
-
-
[docs]class CmdHome(COMMAND_DEFAULT_CLASS): - """ - move to your character's home location - - Usage: - home - - Teleports you to your home location. - """ - - key = "home" - locks = "cmd:perm(home) or perm(Builder)" - arg_regex = r"$" - -
[docs] def func(self): - """Implement the command""" - caller = self.caller - home = caller.home - if not home: - caller.msg("You have no home!") - elif home == caller.location: - caller.msg("You are already home!") - else: - caller.msg("There's no place like home ...") - caller.move_to(home)
- - -
[docs]class CmdLook(COMMAND_DEFAULT_CLASS): - """ - look at location or object - - Usage: - look - look <obj> - look *<account> - - Observes your location or objects in your vicinity. - """ - - key = "look" - aliases = ["l", "ls"] - locks = "cmd:all()" - arg_regex = r"\s|$" - -
[docs] def func(self): - """ - Handle the looking. - """ - caller = self.caller - if not self.args: - target = caller.location - if not target: - caller.msg("You have no location to look at!") - return - else: - target = caller.search(self.args) - if not target: - return - desc = caller.at_look(target) - # add the type=look to the outputfunc to make it - # easy to separate this output in client. - self.msg(text=(desc, {"type": "look"}), options=None)
- - -
[docs]class CmdNick(COMMAND_DEFAULT_CLASS): - """ - define a personal alias/nick by defining a string to - match and replace it with another on the fly - - Usage: - nick[/switches] <string> [= [replacement_string]] - nick[/switches] <template> = <replacement_template> - nick/delete <string> or number - nicks - - Switches: - inputline - replace on the inputline (default) - object - replace on object-lookup - account - replace on account-lookup - list - show all defined aliases (also "nicks" works) - delete - remove nick by index in /list - clearall - clear all nicks - - Examples: - nick hi = say Hello, I'm Sarah! - nick/object tom = the tall man - nick build $1 $2 = create/drop $1;$2 - nick tell $1 $2=page $1=$2 - nick tm?$1=page tallman=$1 - nick tm\=$1=page tallman=$1 - - A 'nick' is a personal string replacement. Use $1, $2, ... to catch arguments. - Put the last $-marker without an ending space to catch all remaining text. You - can also use unix-glob matching for the left-hand side <string>: - - * - matches everything - ? - matches 0 or 1 single characters - [abcd] - matches these chars in any order - [!abcd] - matches everything not among these chars - \= - escape literal '=' you want in your <string> - - Note that no objects are actually renamed or changed by this command - your nicks - are only available to you. If you want to permanently add keywords to an object - for everyone to use, you need build privileges and the alias command. - - """ - - key = "nick" - switch_options = ("inputline", "object", "account", "list", "delete", "clearall") - aliases = ["nickname", "nicks"] - locks = "cmd:all()" - -
[docs] def parse(self): - """ - Support escaping of = with \= - """ - super(CmdNick, self).parse() - args = (self.lhs or "") + (" = %s" % self.rhs if self.rhs else "") - parts = re.split(r"(?<!\\)=", args, 1) - self.rhs = None - if len(parts) < 2: - self.lhs = parts[0].strip() - else: - self.lhs, self.rhs = [part.strip() for part in parts] - self.lhs = self.lhs.replace("\=", "=")
- -
[docs] def func(self): - """Create the nickname""" - - def _cy(string): - "add color to the special markers" - return re.sub(r"(\$[0-9]+|\*|\?|\[.+?\])", r"|Y\1|n", string) - - caller = self.caller - switches = self.switches - nicktypes = [switch for switch in switches if switch in ("object", "account", "inputline")] - specified_nicktype = bool(nicktypes) - nicktypes = nicktypes if specified_nicktype else ["inputline"] - - nicklist = ( - utils.make_iter(caller.nicks.get(category="inputline", return_obj=True) or []) - + utils.make_iter(caller.nicks.get(category="object", return_obj=True) or []) - + utils.make_iter(caller.nicks.get(category="account", return_obj=True) or []) - ) - - if "list" in switches or self.cmdstring in ("nicks",): - - if not nicklist: - string = "|wNo nicks defined.|n" - else: - table = self.styled_table("#", "Type", "Nick match", "Replacement") - for inum, nickobj in enumerate(nicklist): - _, _, nickvalue, replacement = nickobj.value - table.add_row( - str(inum + 1), nickobj.db_category, _cy(nickvalue), _cy(replacement) - ) - string = "|wDefined Nicks:|n\n%s" % table - caller.msg(string) - return - - if "clearall" in switches: - caller.nicks.clear() - caller.account.nicks.clear() - caller.msg("Cleared all nicks.") - return - - if "delete" in switches or "del" in switches: - if not self.args or not self.lhs: - caller.msg("usage nick/delete <nick> or <#num> ('nicks' for list)") - return - # see if a number was given - arg = self.args.lstrip("#") - oldnicks = [] - if arg.isdigit(): - # we are given a index in nicklist - delindex = int(arg) - if 0 < delindex <= len(nicklist): - oldnicks.append(nicklist[delindex - 1]) - else: - caller.msg("Not a valid nick index. See 'nicks' for a list.") - return - else: - if not specified_nicktype: - nicktypes = ("object", "account", "inputline") - for nicktype in nicktypes: - oldnicks.append(caller.nicks.get(arg, category=nicktype, return_obj=True)) - - oldnicks = [oldnick for oldnick in oldnicks if oldnick] - if oldnicks: - for oldnick in oldnicks: - nicktype = oldnick.category - nicktypestr = "%s-nick" % nicktype.capitalize() - _, _, old_nickstring, old_replstring = oldnick.value - caller.nicks.remove(old_nickstring, category=nicktype) - caller.msg( - "%s removed: '|w%s|n' -> |w%s|n." - % (nicktypestr, old_nickstring, old_replstring) - ) - else: - caller.msg("No matching nicks to remove.") - return - - if not self.rhs and self.lhs: - # check what a nick is set to - strings = [] - if not specified_nicktype: - nicktypes = ("object", "account", "inputline") - for nicktype in nicktypes: - nicks = [ - nick - for nick in utils.make_iter( - caller.nicks.get(category=nicktype, return_obj=True) - ) - if nick - ] - for nick in nicks: - _, _, nick, repl = nick.value - if nick.startswith(self.lhs): - strings.append( - "{}-nick: '{}' -> '{}'".format(nicktype.capitalize(), nick, repl) - ) - if strings: - caller.msg("\n".join(strings)) - else: - caller.msg("No nicks found matching '{}'".format(self.lhs)) - return - - if not self.rhs and self.lhs: - # check what a nick is set to - strings = [] - if not specified_nicktype: - nicktypes = ("object", "account", "inputline") - for nicktype in nicktypes: - if nicktype == "account": - obj = account - else: - obj = caller - nicks = utils.make_iter(obj.nicks.get(category=nicktype, return_obj=True)) - for nick in nicks: - _, _, nick, repl = nick.value - if nick.startswith(self.lhs): - strings.append( - "{}-nick: '{}' -> '{}'".format(nicktype.capitalize(), nick, repl) - ) - if strings: - caller.msg("\n".join(strings)) - else: - caller.msg("No nicks found matching '{}'".format(self.lhs)) - return - - if not self.rhs and self.lhs: - # check what a nick is set to - strings = [] - if not specified_nicktype: - nicktypes = ("object", "account", "inputline") - for nicktype in nicktypes: - if nicktype == "account": - obj = account - else: - obj = caller - nicks = utils.make_iter(obj.nicks.get(category=nicktype, return_obj=True)) - for nick in nicks: - _, _, nick, repl = nick.value - if nick.startswith(self.lhs): - strings.append( - "{}-nick: '{}' -> '{}'".format(nicktype.capitalize(), nick, repl) - ) - if strings: - caller.msg("\n".join(strings)) - else: - caller.msg("No nicks found matching '{}'".format(self.lhs)) - return - - if not self.args or not self.lhs: - caller.msg("Usage: nick[/switches] nickname = [realname]") - return - - # setting new nicks - - nickstring = self.lhs - replstring = self.rhs - - if replstring == nickstring: - caller.msg("No point in setting nick same as the string to replace...") - return - - # check so we have a suitable nick type - errstring = "" - string = "" - for nicktype in nicktypes: - nicktypestr = "%s-nick" % nicktype.capitalize() - old_nickstring = None - old_replstring = None - - oldnick = caller.nicks.get(key=nickstring, category=nicktype, return_obj=True) - if oldnick: - _, _, old_nickstring, old_replstring = oldnick.value - if replstring: - # creating new nick - errstring = "" - if oldnick: - if replstring == old_replstring: - string += "\nIdentical %s already set." % nicktypestr.lower() - else: - string += "\n%s '|w%s|n' updated to map to '|w%s|n'." % ( - nicktypestr, - old_nickstring, - replstring, - ) - else: - string += "\n%s '|w%s|n' mapped to '|w%s|n'." % ( - nicktypestr, - nickstring, - replstring, - ) - try: - caller.nicks.add(nickstring, replstring, category=nicktype) - except NickTemplateInvalid: - caller.msg( - "You must use the same $-markers both in the nick and in the replacement." - ) - return - elif old_nickstring and old_replstring: - # just looking at the nick - string += "\n%s '|w%s|n' maps to '|w%s|n'." % ( - nicktypestr, - old_nickstring, - old_replstring, - ) - errstring = "" - string = errstring if errstring else string - caller.msg(_cy(string))
- - -
[docs]class CmdInventory(COMMAND_DEFAULT_CLASS): - """ - view inventory - - Usage: - inventory - inv - - Shows your inventory. - """ - - key = "inventory" - aliases = ["inv", "i"] - locks = "cmd:all()" - arg_regex = r"$" - -
[docs] def func(self): - """check inventory""" - items = self.caller.contents - if not items: - string = "You are not carrying anything." - else: - from evennia.utils.ansi import raw as raw_ansi - table = self.styled_table(border="header") - for item in items: - table.add_row(f"|C{item.name}|n", - "{}|n".format(utils.crop(raw_ansi(item.db.desc or ""), width=50) or "")) - string = f"|wYou are carrying:\n{table}" - self.caller.msg(string)
- - -
[docs]class CmdGet(COMMAND_DEFAULT_CLASS): - """ - pick up something - - Usage: - get <obj> - - Picks up an object from your location and puts it in - your inventory. - """ - - key = "get" - aliases = "grab" - locks = "cmd:all();view:perm(Developer);read:perm(Developer)" - arg_regex = r"\s|$" - -
[docs] def func(self): - """implements the command.""" - - caller = self.caller - - if not self.args: - caller.msg("Get what?") - return - obj = caller.search(self.args, location=caller.location) - if not obj: - return - if caller == obj: - caller.msg("You can't get yourself.") - return - if not obj.access(caller, "get"): - if obj.db.get_err_msg: - caller.msg(obj.db.get_err_msg) - else: - caller.msg("You can't get that.") - return - - # calling at_pre_get hook method - if not obj.at_pre_get(caller): - return - - success = obj.move_to(caller, quiet=True) - if not success: - caller.msg("This can't be picked up.") - else: - caller.msg("You pick up %s." % obj.name) - caller.location.msg_contents( - "%s picks up %s." % (caller.name, obj.name), exclude=caller - ) - # calling at_get hook method - obj.at_get(caller)
- - -
[docs]class CmdDrop(COMMAND_DEFAULT_CLASS): - """ - drop something - - Usage: - drop <obj> - - Lets you drop an object from your inventory into the - location you are currently in. - """ - - key = "drop" - locks = "cmd:all()" - arg_regex = r"\s|$" - -
[docs] def func(self): - """Implement command""" - - caller = self.caller - if not self.args: - caller.msg("Drop what?") - return - - # Because the DROP command by definition looks for items - # in inventory, call the search function using location = caller - obj = caller.search( - self.args, - location=caller, - nofound_string="You aren't carrying %s." % self.args, - multimatch_string="You carry more than one %s:" % self.args, - ) - if not obj: - return - - # Call the object script's at_pre_drop() method. - if not obj.at_pre_drop(caller): - return - - success = obj.move_to(caller.location, quiet=True) - if not success: - caller.msg("This couldn't be dropped.") - else: - caller.msg("You drop %s." % (obj.name,)) - caller.location.msg_contents("%s drops %s." % (caller.name, obj.name), exclude=caller) - # Call the object script's at_drop() method. - obj.at_drop(caller)
- - -
[docs]class CmdGive(COMMAND_DEFAULT_CLASS): - """ - give away something to someone - - Usage: - give <inventory obj> <to||=> <target> - - Gives an items from your inventory to another character, - placing it in their inventory. - """ - - key = "give" - rhs_split = ("=", " to ") # Prefer = delimiter, but allow " to " usage. - locks = "cmd:all()" - arg_regex = r"\s|$" - -
[docs] def func(self): - """Implement give""" - - caller = self.caller - if not self.args or not self.rhs: - caller.msg("Usage: give <inventory object> = <target>") - return - to_give = caller.search( - self.lhs, - location=caller, - nofound_string="You aren't carrying %s." % self.lhs, - multimatch_string="You carry more than one %s:" % self.lhs, - ) - target = caller.search(self.rhs) - if not (to_give and target): - return - if target == caller: - caller.msg("You keep %s to yourself." % to_give.key) - return - if not to_give.location == caller: - caller.msg("You are not holding %s." % to_give.key) - return - - # calling at_pre_give hook method - if not to_give.at_pre_give(caller, target): - return - - # give object - success = to_give.move_to(target, quiet=True) - if not success: - caller.msg("This could not be given.") - else: - caller.msg("You give %s to %s." % (to_give.key, target.key)) - target.msg("%s gives you %s." % (caller.key, to_give.key)) - # Call the object script's at_give() method. - to_give.at_give(caller, target)
- - -
[docs]class CmdSetDesc(COMMAND_DEFAULT_CLASS): - """ - describe yourself - - Usage: - setdesc <description> - - Add a description to yourself. This - will be visible to people when they - look at you. - """ - - key = "setdesc" - locks = "cmd:all()" - arg_regex = r"\s|$" - -
[docs] def func(self): - """add the description""" - - if not self.args: - self.caller.msg("You must add a description.") - return - - self.caller.db.desc = self.args.strip() - self.caller.msg("You set your description.")
- - -
[docs]class CmdSay(COMMAND_DEFAULT_CLASS): - """ - speak as your character - - Usage: - say <message> - - Talk to those in your current location. - """ - - key = "say" - aliases = ['"', "'"] - locks = "cmd:all()" - - # don't require a space after `say/'/"` - arg_regex = None - -
[docs] def func(self): - """Run the say command""" - - caller = self.caller - - if not self.args: - caller.msg("Say what?") - return - - speech = self.args - - # Calling the at_pre_say hook on the character - speech = caller.at_pre_say(speech) - - # If speech is empty, stop here - if not speech: - return - - # Call the at_post_say hook on the character - caller.at_say(speech, msg_self=True)
- - -
[docs]class CmdWhisper(COMMAND_DEFAULT_CLASS): - """ - Speak privately as your character to another - - Usage: - whisper <character> = <message> - whisper <char1>, <char2> = <message> - - Talk privately to one or more characters in your current location, without - others in the room being informed. - """ - - key = "whisper" - locks = "cmd:all()" - -
[docs] def func(self): - """Run the whisper command""" - - caller = self.caller - - if not self.lhs or not self.rhs: - caller.msg("Usage: whisper <character> = <message>") - return - - receivers = [recv.strip() for recv in self.lhs.split(",")] - - receivers = [caller.search(receiver) for receiver in set(receivers)] - receivers = [recv for recv in receivers if recv] - - speech = self.rhs - # If the speech is empty, abort the command - if not speech or not receivers: - return - - # Call a hook to change the speech before whispering - speech = caller.at_pre_say(speech, whisper=True, receivers=receivers) - - # no need for self-message if we are whispering to ourselves (for some reason) - msg_self = None if caller in receivers else True - caller.at_say(speech, msg_self=msg_self, receivers=receivers, whisper=True)
- - -
[docs]class CmdPose(COMMAND_DEFAULT_CLASS): - """ - strike a pose - - Usage: - pose <pose text> - pose's <pose text> - - Example: - pose is standing by the wall, smiling. - -> others will see: - Tom is standing by the wall, smiling. - - Describe an action being taken. The pose text will - automatically begin with your name. - """ - - key = "pose" - aliases = [":", "emote"] - locks = "cmd:all()" - arg_regex = "" - - # we want to be able to pose without whitespace between - # the command/alias and the pose (e.g. :pose) - arg_regex = None - -
[docs] def parse(self): - """ - Custom parse the cases where the emote - starts with some special letter, such - as 's, at which we don't want to separate - the caller's name and the emote with a - space. - """ - args = self.args - if args and not args[0] in ["'", ",", ":"]: - args = " %s" % args.strip() - self.args = args
- -
[docs] def func(self): - """Hook function""" - if not self.args: - msg = "What do you want to do?" - self.caller.msg(msg) - else: - msg = "%s%s" % (self.caller.name, self.args) - self.caller.location.msg_contents(text=(msg, {"type": "pose"}), from_obj=self.caller)
- - -
[docs]class CmdAccess(COMMAND_DEFAULT_CLASS): - """ - show your current game access - - Usage: - access - - This command shows you the permission hierarchy and - which permission groups you are a member of. - """ - - key = "access" - aliases = ["groups", "hierarchy"] - locks = "cmd:all()" - arg_regex = r"$" - -
[docs] def func(self): - """Load the permission groups""" - - caller = self.caller - hierarchy_full = settings.PERMISSION_HIERARCHY - string = "\n|wPermission Hierarchy|n (climbing):\n %s" % ", ".join(hierarchy_full) - - if self.caller.account.is_superuser: - cperms = "<Superuser>" - pperms = "<Superuser>" - else: - cperms = ", ".join(caller.permissions.all()) - pperms = ", ".join(caller.account.permissions.all()) - - string += "\n|wYour access|n:" - string += "\nCharacter |c%s|n: %s" % (caller.key, cperms) - if hasattr(caller, "account"): - string += "\nAccount |c%s|n: %s" % (caller.account.key, pperms) - caller.msg(string)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/commands/default/help.html b/docs/0.9.5/_modules/evennia/commands/default/help.html deleted file mode 100644 index 6c1c6d5540..0000000000 --- a/docs/0.9.5/_modules/evennia/commands/default/help.html +++ /dev/null @@ -1,1086 +0,0 @@ - - - - - - - - evennia.commands.default.help — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.commands.default.help

-"""
-The help command. The basic idea is that help texts for commands are best
-written by those that write the commands - the developers. So command-help is
-all auto-loaded and searched from the current command set. The normal,
-database-tied help system is used for collaborative creation of other help
-topics such as RP help or game-world aides. Help entries can also be created
-outside the game in modules given by ``settings.FILE_HELP_ENTRY_MODULES``.
-
-"""
-
-import re
-from itertools import chain
-from dataclasses import dataclass
-from django.conf import settings
-from collections import defaultdict
-from evennia.utils.utils import dedent
-from evennia.help.models import HelpEntry
-from evennia.utils import create, evmore
-from evennia.utils.ansi import ANSIString
-from evennia.help.filehelp import FILE_HELP_ENTRIES
-from evennia.utils.eveditor import EvEditor
-from evennia.utils.utils import (
-    class_from_module,
-    inherits_from,
-    format_grid, pad
-)
-from evennia.help.utils import help_search_with_index, parse_entry_for_subcategories
-
-CMD_IGNORE_PREFIXES = settings.CMD_IGNORE_PREFIXES
-COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
-HELP_MORE_ENABLED = settings.HELP_MORE_ENABLED
-DEFAULT_HELP_CATEGORY = settings.DEFAULT_HELP_CATEGORY
-HELP_CLICKABLE_TOPICS = settings.HELP_CLICKABLE_TOPICS
-
-# limit symbol import for API
-__all__ = ("CmdHelp", "CmdSetHelp")
-
-@dataclass
-class HelpCategory:
-    """
-    Mock 'help entry' to search categories with the same code.
-
-    """
-    key: str
-
-    @property
-    def search_index_entry(self):
-        return {
-            "key": self.key,
-            "aliases": "",
-            "category": self.key,
-            "no_prefix": "",
-            "tags": "",
-            "text": "",
-        }
-
-    def __hash__(self):
-        return hash(id(self))
-
-
-
[docs]class CmdHelp(COMMAND_DEFAULT_CLASS): - """ - Get help. - - Usage: - help - help <topic, command or category> - help <topic>/<subtopic> - help <topic>/<subtopic>/<subsubtopic> ... - - Use the 'help' command alone to see an index of all help topics, organized - by category.eSome big topics may offer additional sub-topics. - - """ - - key = "help" - aliases = ["?"] - locks = "cmd:all()" - arg_regex = r"\s|$" - - # this is a special cmdhandler flag that makes the cmdhandler also pack - # the current cmdset with the call to self.func(). - return_cmdset = True - - # Help messages are wrapped in an EvMore call (unless using the webclient - # with separate help popups) If you want to avoid this, simply add - # 'HELP_MORE_ENABLED = False' in your settings/conf/settings.py - help_more = HELP_MORE_ENABLED - - # colors for the help index - index_type_separator_clr = "|w" - index_category_clr = "|W" - index_topic_clr = "|G" - - # suggestion cutoff, between 0 and 1 (1 => perfect match) - suggestion_cutoff = 0.6 - - # number of suggestions (set to 0 to remove suggestions from help) - suggestion_maxnum = 5 - - # separator between subtopics: - subtopic_separator_char = r"/" - - # should topics disply their help entry when clicked - clickable_topics = HELP_CLICKABLE_TOPICS - -
[docs] def msg_help(self, text): - """ - messages text to the caller, adding an extra oob argument to indicate - that this is a help command result and could be rendered in a separate - help window - """ - if type(self).help_more: - usemore = True - - if self.session and self.session.protocol_key in ("websocket", "ajax/comet",): - try: - options = self.account.db._saved_webclient_options - if options and options["helppopup"]: - usemore = False - except KeyError: - pass - - if usemore: - evmore.msg(self.caller, text, session=self.session) - return - - self.msg(text=(text, {"type": "help"}))
- -
[docs] def format_help_entry(self, topic="", help_text="", aliases=None, suggested=None, - subtopics=None, click_topics=True): - """This visually formats the help entry. - This method can be overriden to customize the way a help - entry is displayed. - - Args: - title (str, optional): The title of the help entry. - help_text (str, optional): Text of the help entry. - aliases (list, optional): List of help-aliases (displayed in header). - suggested (list, optional): Strings suggested reading (based on title). - subtopics (list, optional): A list of strings - the subcategories available - for this entry. - click_topics (bool, optional): Should help topics be clickable. Default is True. - - Returns: - help_message (str): Help entry formated for console. - - """ - separator = "|C" + "-" * self.client_width() + "|n" - start = f"{separator}\n" - - title = f"|CHelp for |w{topic}|n" if topic else "|rNo help found|n" - - if aliases: - aliases = ( - " |C(aliases: {}|C)|n".format("|C,|n ".join(f"|w{ali}|n" for ali in aliases)) - ) - else: - aliases = '' - - help_text = "\n" + dedent(help_text.strip('\n')) if help_text else "" - - if subtopics: - if click_topics: - subtopics = [ - f"|lchelp {topic}/{subtop}|lt|w{topic}/{subtop}|n|le" - for subtop in subtopics - ] - else: - subtopics = [f"|w{topic}/{subtop}|n" for subtop in subtopics] - subtopics = ( - "\n|CSubtopics:|n\n {}".format( - "\n ".join(format_grid(subtopics, width=self.client_width()))) - ) - else: - subtopics = '' - - if suggested: - suggested = sorted(suggested) - if click_topics: - suggested = [f"|lchelp {sug}|lt|w{sug}|n|le" for sug in suggested] - else: - suggested = [f"|w{sug}|n" for sug in suggested] - suggested = ( - "\n|COther topic suggestions:|n\n{}".format( - "\n ".join(format_grid(suggested, width=self.client_width()))) - ) - else: - suggested = '' - - end = start - - partorder = (start, title + aliases, help_text, subtopics, suggested, end) - - return "\n".join(part.rstrip() for part in partorder if part)
- -
[docs] def format_help_index(self, cmd_help_dict=None, db_help_dict=None, title_lone_category=False, - click_topics=True): - """Output a category-ordered g for displaying the main help, grouped by - category. - - Args: - cmd_help_dict (dict): A dict `{"category": [topic, topic, ...]}` for - command-based help. - db_help_dict (dict): A dict `{"category": [topic, topic], ...]}` for - database-based help. - title_lone_category (bool, optional): If a lone category should - be titled with the category name or not. While pointless in a - general index, the title should probably show when explicitly - listing the category itself. - click_topics (bool, optional): If help-topics are clickable or not - (for webclient or telnet clients with MXP support). - Returns: - str: The help index organized into a grid. - - Notes: - The input are the pre-loaded help files for commands and database-helpfiles - respectively. You can override this method to return a custom display of the list of - commands and topics. - - """ - def _group_by_category(help_dict): - grid = [] - verbatim_elements = [] - - if len(help_dict) == 1 and not title_lone_category: - # don't list categories if there is only one - for category in help_dict: - # gather and sort the entries from the help dictionary - entries = sorted(set(help_dict.get(category, []))) - - # make the help topics clickable - if click_topics: - entries = [ - f'|lchelp {entry}|lt{entry}|le' for entry in entries - ] - - # add the entries to the grid - grid.extend(entries) - else: - # list the categories - for category in sorted(set(list(help_dict.keys()))): - category_str = f"-- {category.title()} " - grid.append( - ANSIString( - self.index_category_clr + category_str - + "-" * (width - len(category_str)) - + self.index_topic_clr - ) - ) - verbatim_elements.append(len(grid) - 1) - - # gather and sort the entries from the help dictionary - entries = sorted(set(help_dict.get(category, []))) - - # make the help topics clickable - if click_topics: - entries = [ - f'|lchelp {entry}|lt{entry}|le' for entry in entries - ] - - # add the entries to the grid - grid.extend(entries) - - return grid, verbatim_elements - - help_index = "" - width = self.client_width() - grid = [] - verbatim_elements = [] - cmd_grid, db_grid = "", "" - - if any(cmd_help_dict.values()): - # get the command-help entries by-category - sep1 = (self.index_type_separator_clr - + pad("Commands", width=width, fillchar='-') - + self.index_topic_clr) - grid, verbatim_elements = _group_by_category(cmd_help_dict) - gridrows = format_grid(grid, width, sep=" ", verbatim_elements=verbatim_elements) - cmd_grid = ANSIString("\n").join(gridrows) if gridrows else "" - - if any(db_help_dict.values()): - # get db-based help entries by-category - sep2 = (self.index_type_separator_clr - + pad("Game & World", width=width, fillchar='-') - + self.index_topic_clr) - grid, verbatim_elements = _group_by_category(db_help_dict) - gridrows = format_grid(grid, width, sep=" ", verbatim_elements=verbatim_elements) - db_grid = ANSIString("\n").join(gridrows) if gridrows else "" - - # only show the main separators if there are actually both cmd and db-based help - if cmd_grid and db_grid: - help_index = f"{sep1}\n{cmd_grid}\n{sep2}\n{db_grid}" - else: - help_index = f"{cmd_grid}{db_grid}" - - return help_index
- -
[docs] def can_read_topic(self, cmd_or_topic, caller): - """ - Helper method. If this return True, the given help topic - be viewable in the help listing. Note that even if this returns False, - the entry will still be visible in the help index unless `should_list_topic` - is also returning False. - - Args: - cmd_or_topic (Command, HelpEntry or FileHelpEntry): The topic/command to test. - caller: the caller checking for access. - - Returns: - bool: If command can be viewed or not. - - Notes: - This uses the 'read' lock. If no 'read' lock is defined, the topic is assumed readable - by all. - - """ - if inherits_from(cmd_or_topic, "evennia.commands.command.Command"): - return cmd_or_topic.auto_help and cmd_or_topic.access(caller, 'read', default=True) - else: - return cmd_or_topic.access(caller, 'read', default=True)
- -
[docs] def can_list_topic(self, cmd_or_topic, caller): - """ - Should the specified command appear in the help table? - - This method only checks whether a specified command should appear in the table of - topics/commands. The command can be used by the caller (see the 'should_show_help' method) - and the command will still be available, for instance, if a character type 'help name of the - command'. However, if you return False, the specified command will not appear in the table. - This is sometimes useful to "hide" commands in the table, but still access them through the - help system. - - Args: - cmd_or_topic (Command, HelpEntry or FileHelpEntry): The topic/command to test. - caller: the caller checking for access. - - Returns: - bool: If command should be listed or not. - - Notes: - The `.auto_help` propery is checked for commands. For all help entries, - the 'view' lock will be checked, and if no such lock is defined, the 'read' - lock will be used. If neither lock is defined, the help entry is assumed to be - accessible to all. - - """ - if hasattr(cmd_or_topic, "auto_help") and not cmd_or_topic.auto_help: - return False - - has_view = ( - "view:" in cmd_or_topic.locks - if inherits_from(cmd_or_topic, "evennia.commands.command.Command") - else cmd_or_topic.locks.get("view") - ) - - if has_view: - return cmd_or_topic.access(caller, 'view', default=True) - else: - # no explicit 'view' lock - use the 'read' lock - return cmd_or_topic.access(caller, 'read', default=True)
- -
[docs] def collect_topics(self, caller, mode='list'): - """ - Collect help topics from all sources (cmd/db/file). - - Args: - caller (Object or Account): The user of the Command. - mode (str): One of 'list' or 'query', where the first means we are collecting to view - the help index and the second because of wanting to search for a specific help - entry/cmd to read. This determines which access should be checked. - - Returns: - tuple: A tuple of three dicts containing the different types of help entries - in the order cmd-help, db-help, file-help: - `({key: cmd,...}, {key: dbentry,...}, {key: fileentry,...}` - - """ - # start with cmd-help - cmdset = self.cmdset - # removing doublets in cmdset, caused by cmdhandler - # having to allow doublet commands to manage exits etc. - cmdset.make_unique(caller) - # retrieve all available commands and database / file-help topics. - # also check the 'cmd:' lock here - cmd_help_topics = [cmd for cmd in cmdset if cmd and cmd.access(caller, 'cmd')] - # get all file-based help entries, checking perms - file_help_topics = { - topic.key.lower().strip(): topic - for topic in FILE_HELP_ENTRIES.all() - } - # get db-based help entries, checking perms - db_help_topics = { - topic.key.lower().strip(): topic - for topic in HelpEntry.objects.all() - } - if mode == 'list': - # check the view lock for all help entries/commands and determine key - cmd_help_topics = { - cmd.auto_help_display_key - if hasattr(cmd, "auto_help_display_key") else cmd.key: cmd - for cmd in cmd_help_topics if self.can_list_topic(cmd, caller)} - db_help_topics = { - key: entry for key, entry in db_help_topics.items() - if self.can_list_topic(entry, caller) - } - file_help_topics = { - key: entry for key, entry in file_help_topics.items() - if self.can_list_topic(entry, caller)} - else: - # query - check the read lock on entries - cmd_help_topics = { - cmd.auto_help_display_key - if hasattr(cmd, "auto_help_display_key") else cmd.key: cmd - for cmd in cmd_help_topics if self.can_read_topic(cmd, caller)} - db_help_topics = { - key: entry for key, entry in db_help_topics.items() - if self.can_read_topic(entry, caller) - } - file_help_topics = { - key: entry for key, entry in file_help_topics.items() - if self.can_read_topic(entry, caller)} - - return cmd_help_topics, db_help_topics, file_help_topics
- - - -
[docs] def parse(self): - """ - input is a string containing the command or topic to match. - - The allowed syntax is - :: - - help <topic>[/<subtopic>[/<subtopic>[/...]]] - - The database/command query is always for `<topic>`, and any subtopics - is then parsed from there. If a `<topic>` has spaces in it, it is - always matched before assuming the space begins a subtopic. - - """ - # parse the query - - if self.args: - self.subtopics = [part.strip().lower() - for part in self.args.split(self.subtopic_separator_char)] - self.topic = self.subtopics.pop(0) - else: - self.topic = "" - self.subtopics = []
- -
[docs] def strip_cmd_prefix(self, key, all_keys): - """ - Conditional strip of a command prefix, such as @ in @desc. By default - this will be hidden unless there is a duplicate without the prefix - in the full command set (such as @open and open). - - Args: - key (str): Command key to analyze. - all_cmds (list): All command-keys (and potentially aliases). - - Returns: - str: Potentially modified key to use in help display. - - """ - if key and key[0] in CMD_IGNORE_PREFIXES and key[1:] not in all_keys: - # filter out e.g. `@` prefixes from display if there is duplicate - # with the prefix in the set (such as @open/open) - return key[1:] - return key
- - -
[docs] def func(self): - """ - Run the dynamic help entry creator. - """ - caller = self.caller - query, subtopics, cmdset = self.topic, self.subtopics, self.cmdset - clickable_topics = self.clickable_topics - - if not query: - # list all available help entries, grouped by category. We want to - # build dictionaries {category: [topic, topic, ...], ...} - - cmd_help_topics, db_help_topics, file_help_topics = \ - self.collect_topics(caller, mode='list') - - # db-topics override file-based ones - file_db_help_topics = {**file_help_topics, **db_help_topics} - - # group by category (cmds are listed separately) - cmd_help_by_category = defaultdict(list) - file_db_help_by_category = defaultdict(list) - - # get a collection of all keys + aliases to be able to strip prefixes like @ - key_and_aliases = set(chain(*(cmd._keyaliases for cmd in cmd_help_topics.values()))) - - for key, cmd in cmd_help_topics.items(): - key = self.strip_cmd_prefix(key, key_and_aliases) - cmd_help_by_category[cmd.help_category].append(key) - for key, entry in file_db_help_topics.items(): - file_db_help_by_category[entry.help_category].append(key) - - # generate the index and display - output = self.format_help_index(cmd_help_by_category, - file_db_help_by_category, - click_topics=clickable_topics) - self.msg_help(output) - - return - - # search for a specific entry. We need to check for 'read' access here before - # building the set of possibilities. - cmd_help_topics, db_help_topics, file_help_topics = \ - self.collect_topics(caller, mode='query') - - # get a collection of all keys + aliases to be able to strip prefixes like @ - key_and_aliases = set( - chain(*(cmd._keyaliases for cmd in cmd_help_topics.values()))) - - # db-help topics takes priority over file-help - file_db_help_topics = {**file_help_topics, **db_help_topics} - - # commands take priority over the other types - all_topics = {**file_db_help_topics, **cmd_help_topics} - - # get all categories - all_categories = list(set( - HelpCategory(topic.help_category) for topic in all_topics.values())) - - # all available help options - will be searched in order. We also check # the - # read-permission here. - entries = list(all_topics.values()) + all_categories - - # lunr search fields/boosts - match, suggestions = self.do_search(query, entries) - - if not match: - # no topic matches found. Only give suggestions. - help_text = f"There is no help topic matching '{query}'." - - if not suggestions: - # we don't even have a good suggestion. Run a second search, - # doing a full-text search in the actual texts of the help - # entries - - search_fields = [ - {"field_name": "text", "boost": 1}, - ] - - for match_query in [query, f"{query}*", f"*{query}"]: - _, suggestions = help_search_with_index( - match_query, entries, - suggestion_maxnum=self.suggestion_maxnum, - fields=search_fields - ) - if suggestions: - help_text += ( - "\n... But matches where found within the help " - "texts of the suggestions below.") - suggestions = [self.strip_cmd_prefix(sugg, key_and_aliases) - for sugg in suggestions] - break - - output = self.format_help_entry( - topic=None, # this will give a no-match style title - help_text=help_text, - suggested=suggestions, - click_topics=clickable_topics - ) - - self.msg_help(output) - return - - if isinstance(match, HelpCategory): - # no subtopics for categories - these are just lists of topics - category = match.key - category_lower = category.lower() - cmds_in_category = [key for key, cmd in cmd_help_topics.items() - if category_lower == cmd.help_category] - topics_in_category = [key for key, topic in file_db_help_topics.items() - if category_lower == topic.help_category] - output = self.format_help_index({category: cmds_in_category}, - {category: topics_in_category}, - title_lone_category=True, - click_topics=clickable_topics) - self.msg_help(output) - return - - if inherits_from(match, "evennia.commands.command.Command"): - # a command match - topic = match.key - help_text = match.get_help(caller, cmdset) - aliases = match.aliases - suggested = suggestions[1:] - else: - # a database (or file-help) match - topic = match.key - help_text = match.entrytext - aliases = match.aliases if isinstance(match.aliases, list) else match.aliases.all() - suggested = suggestions[1:] - - # parse for subtopics. The subtopic_map is a dict with the current topic/subtopic - # text is stored under a `None` key and all other keys are subtopic titles pointing - # to nested dicts. - - subtopic_map = parse_entry_for_subcategories(help_text) - help_text = subtopic_map[None] - subtopic_index = [subtopic for subtopic in subtopic_map if subtopic is not None] - - if subtopics: - # if we asked for subtopics, parse the found topic_text to see if any match. - # the subtopics is a list describing the path through the subtopic_map. - - for subtopic_query in subtopics: - - if subtopic_query not in subtopic_map: - # exact match failed. Try startswith-match - fuzzy_match = False - for key in subtopic_map: - if key and key.startswith(subtopic_query): - subtopic_query = key - fuzzy_match = True - break - - if not fuzzy_match: - # startswith failed - try an 'in' match - for key in subtopic_map: - if key and subtopic_query in key: - subtopic_query = key - fuzzy_match = True - break - - if not fuzzy_match: - # no match found - give up - checked_topic = topic + f"/{subtopic_query}" - output = self.format_help_entry( - topic=topic, - help_text=f"No help entry found for '{checked_topic}'", - subtopics=subtopic_index, - click_topics=clickable_topics - ) - self.msg_help(output) - return - - # if we get here we have an exact or fuzzy match - - subtopic_map = subtopic_map.pop(subtopic_query) - subtopic_index = [subtopic for subtopic in subtopic_map if subtopic is not None] - # keep stepping down into the tree, append path to show position - topic = topic + f"/{subtopic_query}" - - # we reached the bottom of the topic tree - help_text = subtopic_map[None] - - topic = self.strip_cmd_prefix(topic, key_and_aliases) - if subtopics: - aliases = None - else: - aliases = [self.strip_cmd_prefix(alias, key_and_aliases) for alias in aliases] - suggested = [self.strip_cmd_prefix(sugg, key_and_aliases) for sugg in suggested] - - output = self.format_help_entry( - topic=topic, - help_text=help_text, - aliases=aliases, - subtopics=subtopic_index, - suggested=suggested, - click_topics=clickable_topics - ) - - self.msg_help(output)
- - -def _loadhelp(caller): - entry = caller.db._editing_help - if entry: - return entry.entrytext - else: - return "" - - -def _savehelp(caller, buffer): - entry = caller.db._editing_help - caller.msg("Saved help entry.") - if entry: - entry.entrytext = buffer - - -def _quithelp(caller): - caller.msg("Closing the editor.") - del caller.db._editing_help - - -
[docs]class CmdSetHelp(CmdHelp): - """ - Edit the help database. - - Usage: - sethelp[/switches] <topic>[[;alias;alias][,category[,locks]] [= <text>] - - Switches: - edit - open a line editor to edit the topic's help text. - replace - overwrite existing help topic. - append - add text to the end of existing topic with a newline between. - extend - as append, but don't add a newline. - delete - remove help topic. - - Examples: - sethelp lore = In the beginning was ... - sethelp/append pickpocketing,Thievery = This steals ... - sethelp/replace pickpocketing, ,attr(is_thief) = This steals ... - sethelp/edit thievery - - If not assigning a category, the `settings.DEFAULT_HELP_CATEGORY` category - will be used. If no lockstring is specified, everyone will be able to read - the help entry. Sub-topics are embedded in the help text. - - Note that this cannot modify command-help entries - these are modified - in-code, outside the game. - - # SUBTOPICS - - ## Adding subtopics - - Subtopics helps to break up a long help entry into sub-sections. Users can - access subtopics with |whelp topic/subtopic/...|n Subtopics are created and - stored together with the main topic. - - To start adding subtopics, add the text '# SUBTOPICS' on a new line at the - end of your help text. After this you can now add any number of subtopics, - each starting with '## <subtopic-name>' on a line, followed by the - help-text of that subtopic. - Use '### <subsub-name>' to add a sub-subtopic and so on. Max depth is 5. A - subtopic's title is case-insensitive and can consist of multiple words - - the user will be able to enter a partial match to access it. - - For example: - - | Main help text for <topic> - | - | # SUBTOPICS - | - | ## about - | - | Text for the '<topic>/about' subtopic' - | - | ### more about-info - | - | Text for the '<topic>/about/more about-info sub-subtopic - | - | ## extra - | - | Text for the '<topic>/extra' subtopic - - """ - - key = "sethelp" - aliases = [] - switch_options = ("edit", "replace", "append", "extend", "delete") - locks = "cmd:perm(Helper)" - help_category = "Building" - arg_regex = None - -
[docs] def parse(self): - """We want to use the default parser rather than the CmdHelp.parse""" - return COMMAND_DEFAULT_CLASS.parse(self)
- -
[docs] def func(self): - """Implement the function""" - - switches = self.switches - lhslist = self.lhslist - - if not self.args: - self.msg( - "Usage: sethelp[/switches] <topic>[;alias;alias][,category[,locks,..] = <text>" - ) - return - - nlist = len(lhslist) - topicstr = lhslist[0] if nlist > 0 else "" - if not topicstr: - self.msg("You have to define a topic!") - return - topicstrlist = topicstr.split(";") - topicstr, aliases = ( - topicstrlist[0], - topicstrlist[1:] if len(topicstr) > 1 else [], - ) - aliastxt = ("(aliases: %s)" % ", ".join(aliases)) if aliases else "" - old_entry = None - - # check if we have an old entry with the same name - - cmd_help_topics, db_help_topics, file_help_topics = \ - self.collect_topics(self.caller, mode='query') - # db-help topics takes priority over file-help - file_db_help_topics = {**file_help_topics, **db_help_topics} - # commands take priority over the other types - all_topics = {**file_db_help_topics, **cmd_help_topics} - # get all categories - all_categories = list(set( - HelpCategory(topic.help_category) for topic in all_topics.values())) - # all available help options - will be searched in order. We also check # the - # read-permission here. - entries = list(all_topics.values()) + all_categories - - # default setup - category = lhslist[1] if nlist > 1 else DEFAULT_HELP_CATEGORY - lockstring = ",".join(lhslist[2:]) if nlist > 2 else "read:all()" - - # search for existing entries of this or other types - old_entry = None - for querystr in topicstrlist: - match, _ = self.do_search(querystr, entries) - if match: - warning = None - if isinstance(match, HelpCategory): - warning = (f"'{querystr}' matches (or partially matches) the name of " - "help-category '{match.key}'. If you continue, your help entry will " - "take precedence and the category (or part of its name) *may* not " - "be usable for grouping help entries anymore.") - elif inherits_from(match, "evennia.commands.command.Command"): - warning = (f"'{querystr}' matches (or partially matches) the key/alias of " - "Command '{match.key}'. Command-help take precedence over other " - "help entries so your help *may* be impossible to reach for those " - "with access to that command.") - elif inherits_from(match, "evennia.help.filehelp.FileHelpEntry"): - warning = (f"'{querystr}' matches (or partially matches) the name/alias of the " - f"file-based help topic '{match.key}'. File-help entries cannot be " - "modified from in-game (they are files on-disk). If you continue, " - "your help entry may shadow the file-based one's name partly or " - "completely.") - if warning: - # show a warning for a clashing help-entry type. Even if user accepts this - # we don't break here since we may need to show warnings for other inputs. - # We don't count this as an old-entry hit because we can't edit these - # types of entries. - self.msg(f"|rWarning:\n|r{warning}|n") - repl = yield("|wDo you still want to continue? Y/[N]?|n") - if repl.lower() not in ('y', 'yes'): - self.msg("Aborted.") - return - else: - # a db-based help entry - this is OK - old_entry = match - category = lhslist[1] if nlist > 1 else old_entry.help_category - lockstring = ",".join(lhslist[2:]) if nlist > 2 else old_entry.locks.get() - break - - category = category.lower() - - if "edit" in switches: - # open the line editor to edit the helptext. No = is needed. - if old_entry: - topicstr = old_entry.key - if self.rhs: - # we assume append here. - old_entry.entrytext += "\n%s" % self.rhs - helpentry = old_entry - else: - helpentry = create.create_help_entry( - topicstr, self.rhs, category=category, locks=lockstring, aliases=aliases, - ) - self.caller.db._editing_help = helpentry - - EvEditor( - self.caller, - loadfunc=_loadhelp, - savefunc=_savehelp, - quitfunc=_quithelp, - key="topic {}".format(topicstr), - persistent=True, - ) - return - - if "append" in switches or "merge" in switches or "extend" in switches: - # merge/append operations - if not old_entry: - self.msg("Could not find topic '%s'. You must give an exact name." % topicstr) - return - if not self.rhs: - self.msg("You must supply text to append/merge.") - return - if "merge" in switches: - old_entry.entrytext += " " + self.rhs - else: - old_entry.entrytext += "\n%s" % self.rhs - old_entry.aliases.add(aliases) - self.msg("Entry updated:\n%s%s" % (old_entry.entrytext, aliastxt)) - return - - if "delete" in switches or "del" in switches: - # delete the help entry - if not old_entry: - self.msg("Could not find topic '%s'%s." % (topicstr, aliastxt)) - return - old_entry.delete() - self.msg("Deleted help entry '%s'%s." % (topicstr, aliastxt)) - return - - # at this point it means we want to add a new help entry. - if not self.rhs: - self.msg("You must supply a help text to add.") - return - if old_entry: - if "replace" in switches: - # overwrite old entry - old_entry.key = topicstr - old_entry.entrytext = self.rhs - old_entry.help_category = category - old_entry.locks.clear() - old_entry.locks.add(lockstring) - old_entry.aliases.add(aliases) - old_entry.save() - self.msg("Overwrote the old topic '%s'%s." % (topicstr, aliastxt)) - else: - self.msg( - f"Topic '{topicstr}'{aliastxt} already exists. Use /edit to open in editor, or " - "/replace, /append and /merge to modify it directly." - ) - else: - # no old entry. Create a new one. - new_entry = create.create_help_entry( - topicstr, self.rhs, category=category, locks=lockstring, aliases=aliases - ) - if new_entry: - self.msg(f"Topic '{topicstr}'{aliastxt} was successfully created.") - if "edit" in switches: - # open the line editor to edit the helptext - self.caller.db._editing_help = new_entry - EvEditor( - self.caller, - loadfunc=_loadhelp, - savefunc=_savehelp, - quitfunc=_quithelp, - key="topic {}".format(new_entry.key), - persistent=True, - ) - return - else: - self.msg( - f"Error when creating topic '{topicstr}'{aliastxt}! Contact an admin." - )
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/commands/default/muxcommand.html b/docs/0.9.5/_modules/evennia/commands/default/muxcommand.html deleted file mode 100644 index 0c0cfe163c..0000000000 --- a/docs/0.9.5/_modules/evennia/commands/default/muxcommand.html +++ /dev/null @@ -1,375 +0,0 @@ - - - - - - - - evennia.commands.default.muxcommand — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.commands.default.muxcommand

-"""
-The command template for the default MUX-style command set. There
-is also an Account/OOC version that makes sure caller is an Account object.
-"""
-
-from evennia.utils import utils
-from evennia.commands.command import Command
-
-# limit symbol import for API
-__all__ = ("MuxCommand", "MuxAccountCommand")
-
-
-
[docs]class MuxCommand(Command): - """ - This sets up the basis for a MUX command. The idea - is that most other Mux-related commands should just - inherit from this and don't have to implement much - parsing of their own unless they do something particularly - advanced. - - Note that the class's __doc__ string (this text) is - used by Evennia to create the automatic help entry for - the command, so make sure to document consistently here. - """ - -
[docs] def has_perm(self, srcobj): - """ - This is called by the cmdhandler to determine - if srcobj is allowed to execute this command. - We just show it here for completeness - we - are satisfied using the default check in Command. - """ - return super().has_perm(srcobj)
- -
[docs] def at_pre_cmd(self): - """ - This hook is called before self.parse() on all commands - """ - pass
- -
[docs] def at_post_cmd(self): - """ - This hook is called after the command has finished executing - (after self.func()). - """ - pass
- -
[docs] def parse(self): - """ - This method is called by the cmdhandler once the command name - has been identified. It creates a new set of member variables - that can be later accessed from self.func() (see below) - - The following variables are available for our use when entering this - method (from the command definition, and assigned on the fly by the - cmdhandler): - self.key - the name of this command ('look') - self.aliases - the aliases of this cmd ('l') - self.permissions - permission string for this command - self.help_category - overall category of command - - self.caller - the object calling this command - self.cmdstring - the actual command name used to call this - (this allows you to know which alias was used, - for example) - self.args - the raw input; everything following self.cmdstring. - self.cmdset - the cmdset from which this command was picked. Not - often used (useful for commands like 'help' or to - list all available commands etc) - self.obj - the object on which this command was defined. It is often - the same as self.caller. - - A MUX command has the following possible syntax: - - name[ with several words][/switch[/switch..]] arg1[,arg2,...] [[=|,] arg[,..]] - - The 'name[ with several words]' part is already dealt with by the - cmdhandler at this point, and stored in self.cmdname (we don't use - it here). The rest of the command is stored in self.args, which can - start with the switch indicator /. - - Optional variables to aid in parsing, if set: - self.switch_options - (tuple of valid /switches expected by this - command (without the /)) - self.rhs_split - Alternate string delimiter or tuple of strings - to separate left/right hand sides. tuple form - gives priority split to first string delimiter. - - This parser breaks self.args into its constituents and stores them in the - following variables: - self.switches = [list of /switches (without the /)] - self.raw = This is the raw argument input, including switches - self.args = This is re-defined to be everything *except* the switches - self.lhs = Everything to the left of = (lhs:'left-hand side'). If - no = is found, this is identical to self.args. - self.rhs: Everything to the right of = (rhs:'right-hand side'). - If no '=' is found, this is None. - self.lhslist - [self.lhs split into a list by comma] - self.rhslist - [list of self.rhs split into a list by comma] - self.arglist = [list of space-separated args (stripped, including '=' if it exists)] - - All args and list members are stripped of excess whitespace around the - strings, but case is preserved. - """ - raw = self.args - args = raw.strip() - # Without explicitly setting these attributes, they assume default values: - if not hasattr(self, "switch_options"): - self.switch_options = None - if not hasattr(self, "rhs_split"): - self.rhs_split = "=" - if not hasattr(self, "account_caller"): - self.account_caller = False - - # split out switches - switches, delimiters = [], self.rhs_split - if self.switch_options: - self.switch_options = [opt.lower() for opt in self.switch_options] - if args and len(args) > 1 and raw[0] == "/": - # we have a switch, or a set of switches. These end with a space. - switches = args[1:].split(None, 1) - if len(switches) > 1: - switches, args = switches - switches = switches.split("/") - else: - args = "" - switches = switches[0].split("/") - # If user-provides switches, parse them with parser switch options. - if switches and self.switch_options: - valid_switches, unused_switches, extra_switches = [], [], [] - for element in switches: - option_check = [opt for opt in self.switch_options if opt == element] - if not option_check: - option_check = [ - opt for opt in self.switch_options if opt.startswith(element) - ] - match_count = len(option_check) - if match_count > 1: - extra_switches.extend( - option_check - ) # Either the option provided is ambiguous, - elif match_count == 1: - valid_switches.extend(option_check) # or it is a valid option abbreviation, - elif match_count == 0: - unused_switches.append(element) # or an extraneous option to be ignored. - if extra_switches: # User provided switches - self.msg( - "|g%s|n: |wAmbiguous switch supplied: Did you mean /|C%s|w?" - % (self.cmdstring, " |nor /|C".join(extra_switches)) - ) - if unused_switches: - plural = "" if len(unused_switches) == 1 else "es" - self.msg( - '|g%s|n: |wExtra switch%s "/|C%s|w" ignored.' - % (self.cmdstring, plural, "|n, /|C".join(unused_switches)) - ) - switches = valid_switches # Only include valid_switches in command function call - arglist = [arg.strip() for arg in args.split()] - - # check for arg1, arg2, ... = argA, argB, ... constructs - lhs, rhs = args.strip(), None - if lhs: - if delimiters and hasattr(delimiters, "__iter__"): # If delimiter is iterable, - best_split = delimiters[0] # (default to first delimiter) - for this_split in delimiters: # try each delimiter - if this_split in lhs: # to find first successful split - best_split = this_split # to be the best split. - break - else: - best_split = delimiters - # Parse to separate left into left/right sides using best_split delimiter string - if best_split in lhs: - lhs, rhs = lhs.split(best_split, 1) - # Trim user-injected whitespace - rhs = rhs.strip() if rhs is not None else None - lhs = lhs.strip() - # Further split left/right sides by comma delimiter - lhslist = [arg.strip() for arg in lhs.split(",")] if lhs is not None else [] - rhslist = [arg.strip() for arg in rhs.split(",")] if rhs is not None else [] - # save to object properties: - self.raw = raw - self.switches = switches - self.args = args.strip() - self.arglist = arglist - self.lhs = lhs - self.lhslist = lhslist - self.rhs = rhs - self.rhslist = rhslist - - # if the class has the account_caller property set on itself, we make - # sure that self.caller is always the account if possible. We also create - # a special property "character" for the puppeted object, if any. This - # is convenient for commands defined on the Account only. - if self.account_caller: - if utils.inherits_from(self.caller, "evennia.objects.objects.DefaultObject"): - # caller is an Object/Character - self.character = self.caller - self.caller = self.caller.account - elif utils.inherits_from(self.caller, "evennia.accounts.accounts.DefaultAccount"): - # caller was already an Account - self.character = self.caller.get_puppet(self.session) - else: - self.character = None
- -
[docs] def get_command_info(self): - """ - Update of parent class's get_command_info() for MuxCommand. - """ - variables = "\n".join( - " |w{}|n ({}): {}".format(key, type(val), val) for key, val in self.__dict__.items() - ) - string = f""" -Command {self} has no defined `func()` - showing on-command variables: No child func() defined for {self} - available variables: -{variables} - """ - self.caller.msg(string) - # a simple test command to show the available properties - string = "-" * 50 - string += "\n|w%s|n - Command variables from evennia:\n" % self.key - string += "-" * 50 - string += "\nname of cmd (self.key): |w%s|n\n" % self.key - string += "cmd aliases (self.aliases): |w%s|n\n" % self.aliases - string += "cmd locks (self.locks): |w%s|n\n" % self.locks - string += "help category (self.help_category): |w%s|n\n" % self.help_category - string += "object calling (self.caller): |w%s|n\n" % self.caller - string += "object storing cmdset (self.obj): |w%s|n\n" % self.obj - string += "command string given (self.cmdstring): |w%s|n\n" % self.cmdstring - # show cmdset.key instead of cmdset to shorten output - string += utils.fill("current cmdset (self.cmdset): |w%s|n\n" % self.cmdset) - string += "\n" + "-" * 50 - string += "\nVariables from MuxCommand baseclass\n" - string += "-" * 50 - string += "\nraw argument (self.raw): |w%s|n \n" % self.raw - string += "cmd args (self.args): |w%s|n\n" % self.args - string += "cmd switches (self.switches): |w%s|n\n" % self.switches - string += "cmd options (self.switch_options): |w%s|n\n" % self.switch_options - string += "cmd parse left/right using (self.rhs_split): |w%s|n\n" % self.rhs_split - string += "space-separated arg list (self.arglist): |w%s|n\n" % self.arglist - string += "lhs, left-hand side of '=' (self.lhs): |w%s|n\n" % self.lhs - string += "lhs, comma separated (self.lhslist): |w%s|n\n" % self.lhslist - string += "rhs, right-hand side of '=' (self.rhs): |w%s|n\n" % self.rhs - string += "rhs, comma separated (self.rhslist): |w%s|n\n" % self.rhslist - string += "-" * 50 - self.caller.msg(string)
- -
[docs] def func(self): - """ - This is the hook function that actually does all the work. It is called - by the cmdhandler right after self.parser() finishes, and so has access - to all the variables defined therein. - """ - self.get_command_info()
- - -
[docs]class MuxAccountCommand(MuxCommand): - """ - This is an on-Account version of the MuxCommand. Since these commands sit - on Accounts rather than on Characters/Objects, we need to check - this in the parser. - - Account commands are available also when puppeting a Character, it's - just that they are applied with a lower priority and are always - available, also when disconnected from a character (i.e. "ooc"). - - This class makes sure that caller is always an Account object, while - creating a new property "character" that is set only if a - character is actually attached to this Account and Session. - """ - - account_caller = True # Using MuxAccountCommand explicitly defaults the caller to an account
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/commands/default/syscommands.html b/docs/0.9.5/_modules/evennia/commands/default/syscommands.html deleted file mode 100644 index 325b41ee6e..0000000000 --- a/docs/0.9.5/_modules/evennia/commands/default/syscommands.html +++ /dev/null @@ -1,210 +0,0 @@ - - - - - - - - evennia.commands.default.syscommands — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.commands.default.syscommands

-"""
-System commands
-
-These are the default commands called by the system commandhandler
-when various exceptions occur. If one of these commands are not
-implemented and part of the current cmdset, the engine falls back
-to a default solution instead.
-
-Some system commands are shown in this module
-as a REFERENCE only (they are not all added to Evennia's
-default cmdset since they don't currently do anything differently from the
-default backup systems hard-wired in the engine).
-
-Overloading these commands in a cmdset can be used to create
-interesting effects. An example is using the NoMatch system command
-to implement a line-editor where you don't have to start each
-line with a command (if there is no match to a known command,
-the line is just added to the editor buffer).
-"""
-
-from evennia.comms.models import ChannelDB
-from evennia.utils import create
-from evennia.utils.utils import at_search_result
-
-# The command keys the engine is calling
-# (the actual names all start with __)
-from evennia.commands.cmdhandler import CMD_NOINPUT
-from evennia.commands.cmdhandler import CMD_NOMATCH
-from evennia.commands.cmdhandler import CMD_MULTIMATCH
-from evennia.utils import utils
-
-from django.conf import settings
-
-COMMAND_DEFAULT_CLASS = utils.class_from_module(settings.COMMAND_DEFAULT_CLASS)
-
-# Command called when there is no input at line
-# (i.e. an lone return key)
-
-
-
[docs]class SystemNoInput(COMMAND_DEFAULT_CLASS): - """ - This is called when there is no input given - """ - - key = CMD_NOINPUT - locks = "cmd:all()" - -
[docs] def func(self): - "Do nothing." - pass
- - -# -# Command called when there was no match to the -# command name -# -
[docs]class SystemNoMatch(COMMAND_DEFAULT_CLASS): - """ - No command was found matching the given input. - """ - - key = CMD_NOMATCH - locks = "cmd:all()" - -
[docs] def func(self): - """ - This is given the failed raw string as input. - """ - self.msg("Huh?")
- - -# -# Command called when there were multiple matches to the command. -# -
[docs]class SystemMultimatch(COMMAND_DEFAULT_CLASS): - """ - Multiple command matches. - - The cmdhandler adds a special attribute 'matches' to this - system command. - - matches = [(cmdname, args, cmdobj, cmdlen, mratio, raw_cmdname) , (cmdname, ...), ...] - - Here, `cmdname` is the command's name and `args` the rest of the incoming string, - without said command name. `cmdobj` is the Command instance, the cmdlen is - the same as len(cmdname) and mratio is a measure of how big a part of the - full input string the cmdname takes up - an exact match would be 1.0. Finally, - the `raw_cmdname` is the cmdname unmodified by eventual prefix-stripping. - - """ - - key = CMD_MULTIMATCH - locks = "cmd:all()" - -
[docs] def func(self): - """ - Handle multiple-matches by using the at_search_result default handler. - - """ - # this was set by the cmdparser and is a tuple - # (cmdname, args, cmdobj, cmdlen, mratio, raw_cmdname). See - # evennia.commands.cmdparse.create_match for more details. - matches = self.matches - # at_search_result will itself msg the multimatch options to the caller. - at_search_result([match[2] for match in matches], self.caller, query=matches[0][0])
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/commands/default/system.html b/docs/0.9.5/_modules/evennia/commands/default/system.html deleted file mode 100644 index 4e06451943..0000000000 --- a/docs/0.9.5/_modules/evennia/commands/default/system.html +++ /dev/null @@ -1,1260 +0,0 @@ - - - - - - - - evennia.commands.default.system — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.commands.default.system

-"""
-
-System commands
-
-"""
-
-
-import code
-import traceback
-import os
-import datetime
-import sys
-import django
-import twisted
-import time
-
-from django.conf import settings
-from evennia.server.sessionhandler import SESSIONS
-from evennia.accounts.models import AccountDB
-from evennia.utils import logger, utils, gametime, search
-from evennia.utils.eveditor import EvEditor
-from evennia.utils.evtable import EvTable
-from evennia.utils.evmenu import ask_yes_no
-from evennia.utils.utils import class_from_module, iter_to_str
-from evennia.scripts.taskhandler import TaskHandlerTask
-
-COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
-_TASK_HANDLER = None
-_BROADCAST_SERVER_RESTART_MESSAGES = settings.BROADCAST_SERVER_RESTART_MESSAGES
-
-# delayed imports
-_RESOURCE = None
-_IDMAPPER = None
-
-# limit symbol import for API
-__all__ = (
-    "CmdAccounts",
-    "CmdReload",
-    "CmdReset",
-    "CmdShutdown",
-    "CmdPy",
-    "CmdService",
-    "CmdAbout",
-    "CmdTime",
-    "CmdServerLoad",
-    "CmdTasks",
-    "CmdTickers",
-)
-
-
-
[docs]class CmdReload(COMMAND_DEFAULT_CLASS): - """ - reload the server - - Usage: - reload [reason] - - This restarts the server. The Portal is not - affected. Non-persistent scripts will survive a reload (use - reset to purge) and at_reload() hooks will be called. - """ - - key = "@reload" - aliases = ["@restart"] - locks = "cmd:perm(reload) or perm(Developer)" - help_category = "System" - -
[docs] def func(self): - """ - Reload the system. - """ - reason = "" - if self.args: - reason = "(Reason: %s) " % self.args.rstrip(".") - if _BROADCAST_SERVER_RESTART_MESSAGES: - SESSIONS.announce_all(" Server restart initiated %s..." % reason) - SESSIONS.portal_restart_server()
- - -
[docs]class CmdReset(COMMAND_DEFAULT_CLASS): - """ - reset and reboot the server - - Usage: - reset - - Notes: - For normal updating you are recommended to use reload rather - than this command. Use shutdown for a complete stop of - everything. - - This emulates a cold reboot of the Server component of Evennia. - The difference to shutdown is that the Server will auto-reboot - and that it does not affect the Portal, so no users will be - disconnected. Contrary to reload however, all shutdown hooks will - be called and any non-database saved scripts, ndb-attributes, - cmdsets etc will be wiped. - - """ - - key = "@reset" - aliases = ["@reboot"] - locks = "cmd:perm(reload) or perm(Developer)" - help_category = "System" - -
[docs] def func(self): - """ - Reload the system. - """ - SESSIONS.announce_all(" Server resetting/restarting ...") - SESSIONS.portal_reset_server()
- - -
[docs]class CmdShutdown(COMMAND_DEFAULT_CLASS): - - """ - stop the server completely - - Usage: - shutdown [announcement] - - Gracefully shut down both Server and Portal. - """ - - key = "@shutdown" - locks = "cmd:perm(shutdown) or perm(Developer)" - help_category = "System" - -
[docs] def func(self): - """Define function""" - # Only allow shutdown if caller has session - if not self.caller.sessions.get(): - return - self.msg("Shutting down server ...") - announcement = "\nServer is being SHUT DOWN!\n" - if self.args: - announcement += "%s\n" % self.args - logger.log_info("Server shutdown by %s." % self.caller.name) - SESSIONS.announce_all(announcement) - SESSIONS.portal_shutdown()
- - -def _py_load(caller): - return "" - - -def _py_code(caller, buf): - """ - Execute the buffer. - """ - measure_time = caller.db._py_measure_time - client_raw = caller.db._py_clientraw - string = "Executing code%s ..." % (" (measure timing)" if measure_time else "") - caller.msg(string) - _run_code_snippet( - caller, buf, mode="exec", measure_time=measure_time, client_raw=client_raw, show_input=False - ) - return True - - -def _py_quit(caller): - del caller.db._py_measure_time - caller.msg("Exited the code editor.") - - -def _run_code_snippet( - caller, pycode, mode="eval", measure_time=False, client_raw=False, show_input=True -): - """ - Run code and try to display information to the caller. - - Args: - caller (Object): The caller. - pycode (str): The Python code to run. - measure_time (bool, optional): Should we measure the time of execution? - client_raw (bool, optional): Should we turn off all client-specific escaping? - show_input (bookl, optional): Should we display the input? - - """ - # Try to retrieve the session - session = caller - if hasattr(caller, "sessions"): - sessions = caller.sessions.all() - - available_vars = evennia_local_vars(caller) - - if show_input: - for session in sessions: - try: - caller.msg(">>> %s" % pycode, session=session, options={"raw": True}) - except TypeError: - caller.msg(">>> %s" % pycode, options={"raw": True}) - - try: - # reroute standard output to game client console - old_stdout = sys.stdout - old_stderr = sys.stderr - - class FakeStd: - def __init__(self, caller): - self.caller = caller - - def write(self, string): - self.caller.msg(string.rsplit("\n", 1)[0]) - - fake_std = FakeStd(caller) - sys.stdout = fake_std - sys.stderr = fake_std - - try: - pycode_compiled = compile(pycode, "", mode) - except Exception: - mode = "exec" - pycode_compiled = compile(pycode, "", mode) - - duration = "" - if measure_time: - t0 = time.time() - ret = eval(pycode_compiled, {}, available_vars) - t1 = time.time() - duration = " (runtime ~ %.4f ms)" % ((t1 - t0) * 1000) - caller.msg(duration) - else: - ret = eval(pycode_compiled, {}, available_vars) - - except Exception: - errlist = traceback.format_exc().split("\n") - if len(errlist) > 4: - errlist = errlist[4:] - ret = "\n".join("%s" % line for line in errlist if line) - finally: - # return to old stdout - sys.stdout = old_stdout - sys.stderr = old_stderr - - if ret is None: - return - elif isinstance(ret, tuple): - # we must convert here to allow msg to pass it (a tuple is confused - # with a outputfunc structure) - ret = str(ret) - - for session in sessions: - try: - caller.msg(ret, session=session, options={"raw": True, "client_raw": client_raw}) - except TypeError: - caller.msg(ret, options={"raw": True, "client_raw": client_raw}) - - -def evennia_local_vars(caller): - """Return Evennia local variables usable in the py command as a dictionary.""" - import evennia - - return { - "self": caller, - "me": caller, - "here": getattr(caller, "location", None), - "evennia": evennia, - "ev": evennia, - "inherits_from": utils.inherits_from, - } - - -class EvenniaPythonConsole(code.InteractiveConsole): - - """Evennia wrapper around a Python interactive console.""" - - def __init__(self, caller): - super().__init__(evennia_local_vars(caller)) - self.caller = caller - - def write(self, string): - """Don't send to stderr, send to self.caller.""" - self.caller.msg(string) - - def push(self, line): - """Push some code, whether complete or not.""" - old_stdout = sys.stdout - old_stderr = sys.stderr - - class FakeStd: - def __init__(self, caller): - self.caller = caller - - def write(self, string): - self.caller.msg(string.split("\n", 1)[0]) - - fake_std = FakeStd(self.caller) - sys.stdout = fake_std - sys.stderr = fake_std - result = None - try: - result = super().push(line) - finally: - sys.stdout = old_stdout - sys.stderr = old_stderr - return result - - -
[docs]class CmdPy(COMMAND_DEFAULT_CLASS): - """ - execute a snippet of python code - - Usage: - py [cmd] - py/edit - py/time <cmd> - py/clientraw <cmd> - py/noecho - - Switches: - time - output an approximate execution time for <cmd> - edit - open a code editor for multi-line code experimentation - clientraw - turn off all client-specific escaping. Note that this may - lead to different output depending on prototocol (such as angular brackets - being parsed as HTML in the webclient but not in telnet clients) - noecho - in Python console mode, turn off the input echo (e.g. if your client - does this for you already) - - Without argument, open a Python console in-game. This is a full console, - accepting multi-line Python code for testing and debugging. Type `exit()` to - return to the game. If Evennia is reloaded, the console will be closed. - - Enter a line of instruction after the 'py' command to execute it - immediately. Separate multiple commands by ';' or open the code editor - using the /edit switch (all lines added in editor will be executed - immediately when closing or using the execute command in the editor). - - A few variables are made available for convenience in order to offer access - to the system (you can import more at execution time). - - Available variables in py environment: - self, me : caller - here : caller.location - evennia : the evennia API - inherits_from(obj, parent) : check object inheritance - - You can explore The evennia API from inside the game by calling - the `__doc__` property on entities: - py evennia.__doc__ - py evennia.managers.__doc__ - - |rNote: In the wrong hands this command is a severe security risk. It - should only be accessible by trusted server admins/superusers.|n - - """ - - key = "@py" - aliases = ["@!"] - switch_options = ("time", "edit", "clientraw", "noecho") - locks = "cmd:perm(py) or perm(Developer)" - help_category = "System" - arg_regex = "" - -
[docs] def func(self): - """hook function""" - - caller = self.caller - pycode = self.args - - noecho = "noecho" in self.switches - - if "edit" in self.switches: - caller.db._py_measure_time = "time" in self.switches - caller.db._py_clientraw = "clientraw" in self.switches - EvEditor( - self.caller, - loadfunc=_py_load, - savefunc=_py_code, - quitfunc=_py_quit, - key="Python exec: :w or :!", - persistent=True, - codefunc=_py_code, - ) - return - - if not pycode: - # Run in interactive mode - console = EvenniaPythonConsole(self.caller) - banner = ( - "|gEvennia Interactive Python mode{echomode}\n" - "Python {version} on {platform}".format( - echomode=" (no echoing of prompts)" if noecho else "", - version=sys.version, - platform=sys.platform, - ) - ) - self.msg(banner) - line = "" - main_prompt = "|x[py mode - quit() to exit]|n" - prompt = main_prompt - while line.lower() not in ("exit", "exit()"): - try: - line = yield (prompt) - if noecho: - prompt = "..." if console.push(line) else main_prompt - else: - if line: - self.caller.msg(f">>> {line}") - prompt = line if console.push(line) else main_prompt - except SystemExit: - break - self.msg("|gClosing the Python console.|n") - return - - _run_code_snippet( - caller, - self.args, - measure_time="time" in self.switches, - client_raw="clientraw" in self.switches, - )
- - -
[docs]class CmdAccounts(COMMAND_DEFAULT_CLASS): - """ - Manage registered accounts - - Usage: - accounts [nr] - accounts/delete <name or #id> [: reason] - - Switches: - delete - delete an account from the server - - By default, lists statistics about the Accounts registered with the game. - It will list the <nr> amount of latest registered accounts - If not given, <nr> defaults to 10. - """ - - key = "@accounts" - aliases = ["@account"] - switch_options = ("delete",) - locks = "cmd:perm(listaccounts) or perm(Admin)" - help_category = "System" - -
[docs] def func(self): - """List the accounts""" - - caller = self.caller - args = self.args - - if "delete" in self.switches: - account = getattr(caller, "account") - if not account or not account.check_permstring("Developer"): - caller.msg("You are not allowed to delete accounts.") - return - if not args: - caller.msg("Usage: accounts/delete <name or #id> [: reason]") - return - reason = "" - if ":" in args: - args, reason = [arg.strip() for arg in args.split(":", 1)] - # We use account_search since we want to be sure to find also accounts - # that lack characters. - accounts = search.account_search(args) - if not accounts: - self.msg("Could not find an account by that name.") - return - if len(accounts) > 1: - string = "There were multiple matches:\n" - string += "\n".join(" %s %s" % (account.id, account.key) for account in accounts) - self.msg(string) - return - account = accounts.first() - if not account.access(caller, "delete"): - self.msg("You don't have the permissions to delete that account.") - return - username = account.username - # ask for confirmation - confirm = ( - "It is often better to block access to an account rather than to delete it. " - "|yAre you sure you want to permanently delete " - "account '|n{}|y'|n yes/[no]?".format(username) - ) - answer = yield (confirm) - if answer.lower() not in ("y", "yes"): - caller.msg("Canceled deletion.") - return - - # Boot the account then delete it. - self.msg("Informing and disconnecting account ...") - string = "\nYour account '%s' is being *permanently* deleted.\n" % username - if reason: - string += " Reason given:\n '%s'" % reason - account.msg(string) - logger.log_sec( - "Account Deleted: %s (Reason: %s, Caller: %s, IP: %s)." - % (account, reason, caller, self.session.address) - ) - account.delete() - self.msg("Account %s was successfully deleted." % username) - return - - # No switches, default to displaying a list of accounts. - if self.args and self.args.isdigit(): - nlim = int(self.args) - else: - nlim = 10 - - naccounts = AccountDB.objects.count() - - # typeclass table - dbtotals = AccountDB.objects.object_totals() - typetable = self.styled_table( - "|wtypeclass|n", "|wcount|n", "|w%%|n", border="cells", align="l" - ) - for path, count in dbtotals.items(): - typetable.add_row(path, count, "%.2f" % ((float(count) / naccounts) * 100)) - # last N table - plyrs = AccountDB.objects.all().order_by("db_date_created")[max(0, naccounts - nlim) :] - latesttable = self.styled_table( - "|wcreated|n", "|wdbref|n", "|wname|n", "|wtypeclass|n", border="cells", align="l" - ) - for ply in plyrs: - latesttable.add_row( - utils.datetime_format(ply.date_created), ply.dbref, ply.key, ply.path - ) - - string = "\n|wAccount typeclass distribution:|n\n%s" % typetable - string += "\n|wLast %s Accounts created:|n\n%s" % (min(naccounts, nlim), latesttable) - caller.msg(string)
- - -
[docs]class CmdService(COMMAND_DEFAULT_CLASS): - """ - manage system services - - Usage: - service[/switch] <service> - - Switches: - list - shows all available services (default) - start - activates or reactivate a service - stop - stops/inactivate a service (can often be restarted) - delete - tries to permanently remove a service - - Service management system. Allows for the listing, - starting, and stopping of services. If no switches - are given, services will be listed. Note that to operate on the - service you have to supply the full (green or red) name as given - in the list. - """ - - key = "@service" - aliases = ["@services"] - switch_options = ("list", "start", "stop", "delete") - locks = "cmd:perm(service) or perm(Developer)" - help_category = "System" - -
[docs] def func(self): - """Implement command""" - - caller = self.caller - switches = self.switches - - if switches and switches[0] not in ("list", "start", "stop", "delete"): - caller.msg("Usage: service/<list|start|stop|delete> [servicename]") - return - - # get all services - service_collection = SESSIONS.server.services - - if not switches or switches[0] == "list": - # Just display the list of installed services and their - # status, then exit. - table = self.styled_table( - "|wService|n (use services/start|stop|delete)", "|wstatus", align="l" - ) - for service in service_collection.services: - table.add_row(service.name, service.running and "|gRunning" or "|rNot Running") - caller.msg(str(table)) - return - - # Get the service to start / stop - - try: - service = service_collection.getServiceNamed(self.args) - except Exception: - string = "Invalid service name. This command is case-sensitive. " - string += "See service/list for valid service name (enter the full name exactly)." - caller.msg(string) - return - - if switches[0] in ("stop", "delete"): - # Stopping/killing a service gracefully closes it and disconnects - # any connections (if applicable). - - delmode = switches[0] == "delete" - if not service.running: - caller.msg("That service is not currently running.") - return - if service.name[:7] == "Evennia": - if delmode: - caller.msg("You cannot remove a core Evennia service (named 'Evennia*').") - return - string = ("|RYou seem to be shutting down a core Evennia " - "service (named 'Evennia*').\nNote that stopping " - "some TCP port services will *not* disconnect users " - "*already* connected on those ports, but *may* " - "instead cause spurious errors for them.\nTo safely " - "and permanently remove ports, change settings file " - "and restart the server.|n\n") - caller.msg(string) - - if delmode: - service.stopService() - service_collection.removeService(service) - caller.msg("|gStopped and removed service '%s'.|n" % self.args) - else: - caller.msg(f"Stopping service '{self.args}'...") - try: - service.stopService() - except Exception as err: - caller.msg(f"|rErrors were reported when stopping this service{err}.\n" - "If there are remaining problems, try reloading " - "or rebooting the server.") - caller.msg("|g... Stopped service '%s'.|n" % self.args) - return - - if switches[0] == "start": - # Attempt to start a service. - if service.running: - caller.msg("That service is already running.") - return - caller.msg(f"Starting service '{self.args}' ...") - try: - service.startService() - except Exception as err: - caller.msg(f"|rErrors were reported when starting this service{err}.\n" - "If there are remaining problems, try reloading the server, changing the " - "settings if it's a non-standard service.|n") - caller.msg("|gService started.|n")
- - -
[docs]class CmdAbout(COMMAND_DEFAULT_CLASS): - """ - show Evennia info - - Usage: - about - - Display info about the game engine. - """ - - key = "@about" - aliases = "@version" - locks = "cmd:all()" - help_category = "System" - -
[docs] def func(self): - """Display information about server or target""" - - string = """ - |cEvennia|n MU* development system - - |wEvennia version|n: {version} - |wOS|n: {os} - |wPython|n: {python} - |wTwisted|n: {twisted} - |wDjango|n: {django} - - |wHomepage|n https://evennia.com - |wCode|n https://github.com/evennia/evennia - |wDemo|n https://demo.evennia.com - |wGame listing|n https://games.evennia.com - |wChat|n https://discord.gg/AJJpcRUhtF - |wForum|n https://github.com/evennia/evennia/discussions - |wLicence|n https://opensource.org/licenses/BSD-3-Clause - |wMaintainer|n (2010-) Griatch (griatch AT gmail DOT com) - |wMaintainer|n (2006-10) Greg Taylor - - """.format( - version=utils.get_evennia_version(), - os=os.name, - python=sys.version.split()[0], - twisted=twisted.version.short(), - django=django.get_version(), - ) - self.caller.msg(string)
- - -
[docs]class CmdTime(COMMAND_DEFAULT_CLASS): - """ - show server time statistics - - Usage: - time - - List Server time statistics such as uptime - and the current time stamp. - """ - - key = "@time" - aliases = "@uptime" - locks = "cmd:perm(time) or perm(Player)" - help_category = "System" - -
[docs] def func(self): - """Show server time data in a table.""" - table1 = self.styled_table("|wServer time", "", align="l", width=78) - table1.add_row("Current uptime", utils.time_format(gametime.uptime(), 3)) - table1.add_row("Portal uptime", utils.time_format(gametime.portal_uptime(), 3)) - table1.add_row("Total runtime", utils.time_format(gametime.runtime(), 2)) - table1.add_row("First start", datetime.datetime.fromtimestamp(gametime.server_epoch())) - table1.add_row("Current time", datetime.datetime.now()) - table1.reformat_column(0, width=30) - table2 = self.styled_table( - "|wIn-Game time", - "|wReal time x %g" % gametime.TIMEFACTOR, - align="l", - width=78, - border_top=0, - ) - epochtxt = "Epoch (%s)" % ("from settings" if settings.TIME_GAME_EPOCH else "server start") - table2.add_row(epochtxt, datetime.datetime.fromtimestamp(gametime.game_epoch())) - table2.add_row("Total time passed:", utils.time_format(gametime.gametime(), 2)) - table2.add_row( - "Current time ", datetime.datetime.fromtimestamp(gametime.gametime(absolute=True)) - ) - table2.reformat_column(0, width=30) - self.caller.msg(str(table1) + "\n" + str(table2))
- - -
[docs]class CmdServerLoad(COMMAND_DEFAULT_CLASS): - """ - show server load and memory statistics - - Usage: - server[/mem] - - Switches: - mem - return only a string of the current memory usage - flushmem - flush the idmapper cache - - This command shows server load statistics and dynamic memory - usage. It also allows to flush the cache of accessed database - objects. - - Some Important statistics in the table: - - |wServer load|n is an average of processor usage. It's usually - between 0 (no usage) and 1 (100% usage), but may also be - temporarily higher if your computer has multiple CPU cores. - - The |wResident/Virtual memory|n displays the total memory used by - the server process. - - Evennia |wcaches|n all retrieved database entities when they are - loaded by use of the idmapper functionality. This allows Evennia - to maintain the same instances of an entity and allowing - non-persistent storage schemes. The total amount of cached objects - are displayed plus a breakdown of database object types. - - The |wflushmem|n switch allows to flush the object cache. Please - note that due to how Python's memory management works, releasing - caches may not show you a lower Residual/Virtual memory footprint, - the released memory will instead be re-used by the program. - - """ - - key = "@server" - aliases = ["@serverload"] - switch_options = ("mem", "flushmem") - locks = "cmd:perm(list) or perm(Developer)" - help_category = "System" - -
[docs] def func(self): - """Show list.""" - - global _IDMAPPER - if not _IDMAPPER: - from evennia.utils.idmapper import models as _IDMAPPER - - if "flushmem" in self.switches: - # flush the cache - prev, _ = _IDMAPPER.cache_size() - nflushed = _IDMAPPER.flush_cache() - now, _ = _IDMAPPER.cache_size() - string = ( - "The Idmapper cache freed |w{idmapper}|n database objects.\n" - "The Python garbage collector freed |w{gc}|n Python instances total." - ) - self.caller.msg(string.format(idmapper=(prev - now), gc=nflushed)) - return - - # display active processes - - os_windows = os.name == "nt" - pid = os.getpid() - - if os_windows: - # Windows requires the psutil module to even get paltry - # statistics like this (it's pretty much worthless, - # unfortunately, since it's not specific to the process) /rant - try: - import psutil - - has_psutil = True - except ImportError: - has_psutil = False - - if has_psutil: - loadavg = psutil.cpu_percent() - _mem = psutil.virtual_memory() - rmem = _mem.used / (1000.0 * 1000) - pmem = _mem.percent - - if "mem" in self.switches: - string = "Total computer memory usage: |w%g|n MB (%g%%)" - self.caller.msg(string % (rmem, pmem)) - return - # Display table - loadtable = self.styled_table("property", "statistic", align="l") - loadtable.add_row("Total CPU load", "%g %%" % loadavg) - loadtable.add_row("Total computer memory usage", "%g MB (%g%%)" % (rmem, pmem)) - loadtable.add_row("Process ID", "%g" % pid), - else: - loadtable = ( - "Not available on Windows without 'psutil' library " - "(install with |wpip install psutil|n)." - ) - - else: - # Linux / BSD (OSX) - proper pid-based statistics - - global _RESOURCE - if not _RESOURCE: - import resource as _RESOURCE - - loadavg = os.getloadavg()[0] - rmem = ( - float(os.popen("ps -p %d -o %s | tail -1" % (pid, "rss")).read()) / 1000.0 - ) # resident memory - vmem = ( - float(os.popen("ps -p %d -o %s | tail -1" % (pid, "vsz")).read()) / 1000.0 - ) # virtual memory - pmem = float( - os.popen("ps -p %d -o %s | tail -1" % (pid, "%mem")).read() - ) # % of resident memory to total - rusage = _RESOURCE.getrusage(_RESOURCE.RUSAGE_SELF) - - if "mem" in self.switches: - string = "Memory usage: RMEM: |w%g|n MB (%g%%), VMEM (res+swap+cache): |w%g|n MB." - self.caller.msg(string % (rmem, pmem, vmem)) - return - - loadtable = self.styled_table("property", "statistic", align="l") - loadtable.add_row("Server load (1 min)", "%g" % loadavg) - loadtable.add_row("Process ID", "%g" % pid), - loadtable.add_row("Memory usage", "%g MB (%g%%)" % (rmem, pmem)) - loadtable.add_row("Virtual address space", "") - loadtable.add_row("|x(resident+swap+caching)|n", "%g MB" % vmem) - loadtable.add_row( - "CPU time used (total)", - "%s (%gs)" % (utils.time_format(rusage.ru_utime), rusage.ru_utime), - ) - loadtable.add_row( - "CPU time used (user)", - "%s (%gs)" % (utils.time_format(rusage.ru_stime), rusage.ru_stime), - ) - loadtable.add_row( - "Page faults", - "%g hard, %g soft, %g swapouts" - % (rusage.ru_majflt, rusage.ru_minflt, rusage.ru_nswap), - ) - loadtable.add_row( - "Disk I/O", "%g reads, %g writes" % (rusage.ru_inblock, rusage.ru_oublock) - ) - loadtable.add_row("Network I/O", "%g in, %g out" % (rusage.ru_msgrcv, rusage.ru_msgsnd)) - loadtable.add_row( - "Context switching", - "%g vol, %g forced, %g signals" - % (rusage.ru_nvcsw, rusage.ru_nivcsw, rusage.ru_nsignals), - ) - - # os-generic - - string = "|wServer CPU and Memory load:|n\n%s" % loadtable - - # object cache count (note that sys.getsiseof is not called so this works for pypy too. - total_num, cachedict = _IDMAPPER.cache_size() - sorted_cache = sorted( - [(key, num) for key, num in cachedict.items() if num > 0], - key=lambda tup: tup[1], - reverse=True, - ) - memtable = self.styled_table("entity name", "number", "idmapper %", align="l") - for tup in sorted_cache: - memtable.add_row(tup[0], "%i" % tup[1], "%.2f" % (float(tup[1]) / total_num * 100)) - - string += "\n|w Entity idmapper cache:|n %i items\n%s" % (total_num, memtable) - - # return to caller - self.caller.msg(string)
- - -
[docs]class CmdTickers(COMMAND_DEFAULT_CLASS): - """ - View running tickers - - Usage: - tickers - - Note: Tickers are created, stopped and manipulated in Python code - using the TickerHandler. This is merely a convenience function for - inspecting the current status. - - """ - - key = "@tickers" - help_category = "System" - locks = "cmd:perm(tickers) or perm(Builder)" - -
[docs] def func(self): - from evennia import TICKER_HANDLER - - all_subs = TICKER_HANDLER.all_display() - if not all_subs: - self.caller.msg("No tickers are currently active.") - return - table = self.styled_table("interval (s)", "object", "path/methodname", "idstring", "db") - for sub in all_subs: - table.add_row( - sub[3], - "%s%s" - % ( - sub[0] or "[None]", - sub[0] and " (#%s)" % (sub[0].id if hasattr(sub[0], "id") else "") or "", - ), - sub[1] if sub[1] else sub[2], - sub[4] or "[Unset]", - "*" if sub[5] else "-", - ) - self.caller.msg("|wActive tickers|n:\n" + str(table))
- - -
[docs]class CmdTasks(COMMAND_DEFAULT_CLASS): - """ - Display or terminate active tasks (delays). - - Usage: - tasks[/switch] [task_id or function_name] - - Switches: - pause - Pause the callback of a task. - unpause - Process all callbacks made since pause() was called. - do_task - Execute the task (call its callback). - call - Call the callback of this task. - remove - Remove a task without executing it. - cancel - Stop a task from automatically executing. - - Notes: - A task is a single use method of delaying the call of a function. Calls are created - in code, using `evennia.utils.delay`. - See |luhttps://www.evennia.com/docs/latest/Command-Duration.html|ltthe docs|le for help. - - By default, tasks that are canceled and never called are cleaned up after one minute. - - Examples: - - `tasks/cancel move_callback` - Cancels all movement delays from the slow_exit contrib. - In this example slow exits creates it's tasks with - `utils.delay(move_delay, move_callback)` - - `tasks/cancel 2` - Cancel task id 2. - - """ - - key = "@tasks" - aliases = ["@delays", "@task"] - switch_options = ("pause", "unpause", "do_task", "call", "remove", "cancel") - locks = "perm(Developer)" - help_category = "System" - -
[docs] @staticmethod - def coll_date_func(task): - """Replace regex characters in date string and collect deferred function name.""" - t_comp_date = str(task[0]).replace('-', '/') - t_func_name = str(task[1]).split(' ') - t_func_mem_ref = t_func_name[3] if len(t_func_name) >= 4 else None - return t_comp_date, t_func_mem_ref
- -
[docs] def do_task_action(self, *args, **kwargs): - """ - Process the action of a tasks command. - - This exists to gain support with yes or no function from EvMenu. - """ - task_id = self.task_id - - # get a reference of the global task handler - global _TASK_HANDLER - if _TASK_HANDLER is None: - from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER - - # verify manipulating the correct task - task_args = _TASK_HANDLER.tasks.get(task_id, False) - if not task_args: # check if the task is still active - self.msg('Task completed while waiting for input.') - return - else: - # make certain a task with matching IDs has not been created - t_comp_date, t_func_mem_ref = self.coll_date_func(task_args) - if self.t_comp_date != t_comp_date or self.t_func_mem_ref != t_func_mem_ref: - self.msg('Task completed while waiting for input.') - return - - # Do the action requested by command caller - action_return = self.task_action() - self.msg(f'{self.action_request} request completed.') - self.msg(f'The task function {self.action_request} returned: {action_return}')
- -
[docs] def func(self): - # get a reference of the global task handler - global _TASK_HANDLER - if _TASK_HANDLER is None: - from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER - # handle no tasks active. - if not _TASK_HANDLER.tasks: - self.msg('There are no active tasks.') - if self.switches or self.args: - self.msg('Likely the task has completed and been removed.') - return - - # handle caller's request to manipulate a task(s) - if self.switches and self.lhs: - - # find if the argument is a task id or function name - action_request = self.switches[0] - try: - arg_is_id = int(self.lhslist[0]) - except ValueError: - arg_is_id = False - - # if the argument is a task id, proccess the action on a single task - if arg_is_id: - - err_arg_msg = 'Switch and task ID are required when manipulating a task.' - task_comp_msg = 'Task completed while processing request.' - - # handle missing arguments or switches - if not self.switches and self.lhs: - self.msg(err_arg_msg) - return - - # create a handle for the task - task_id = arg_is_id - task = TaskHandlerTask(task_id) - - # handle task no longer existing - if not task.exists(): - self.msg(f'Task {task_id} does not exist.') - return - - # get a reference of the function caller requested - switch_action = getattr(task, action_request, False) - if not switch_action: - self.msg(f'{self.switches[0]}, is not an acceptable task action or ' \ - f'{task_comp_msg.lower()}') - - # verify manipulating the correct task - if task_id in _TASK_HANDLER.tasks: - task_args = _TASK_HANDLER.tasks.get(task_id, False) - if not task_args: # check if the task is still active - self.msg(task_comp_msg) - return - else: - t_comp_date, t_func_mem_ref = self.coll_date_func(task_args) - t_func_name = str(task_args[1]).split(' ') - t_func_name = t_func_name[1] if len(t_func_name) >= 2 else None - - if task.exists(): # make certain the task has not been called yet. - prompt = (f'{action_request.capitalize()} task {task_id} with completion date ' - f'{t_comp_date} ({t_func_name}) {{options}}?') - no_msg = f'No {action_request} processed.' - # record variables for use in do_task_action method - self.task_id = task_id - self.t_comp_date = t_comp_date - self.t_func_mem_ref = t_func_mem_ref - self.task_action = switch_action - self.action_request = action_request - ask_yes_no(self.caller, - prompt=prompt, - yes_action=self.do_task_action, - no_action=no_msg, - default="Y", - allow_abort=True) - return True - else: - self.msg(task_comp_msg) - return - - # the argument is not a task id, process the action on all task deferring the function - # specified as an argument - else: - - name_match_found = False - arg_func_name = self.lhslist[0].lower() - - # repack tasks into a new dictionary - current_tasks = {} - for task_id, task_args in _TASK_HANDLER.tasks.items(): - current_tasks.update({task_id: task_args}) - - # call requested action on all tasks with the function name - for task_id, task_args in current_tasks.items(): - t_func_name = str(task_args[1]).split(' ') - t_func_name = t_func_name[1] if len(t_func_name) >= 2 else None - # skip this task if it is not for the function desired - if arg_func_name != t_func_name: - continue - name_match_found = True - task = TaskHandlerTask(task_id) - switch_action = getattr(task, action_request, False) - if switch_action: - action_return = switch_action() - self.msg(f'Task action {action_request} completed on task ID {task_id}.') - self.msg(f'The task function {action_request} returned: {action_return}') - - # provide a message if not tasks of the function name was found - if not name_match_found: - self.msg(f'No tasks deferring function name {arg_func_name} found.') - return - return True - - # check if an maleformed request was created - elif self.switches or self.lhs: - self.msg('Task command misformed.') - self.msg('Proper format tasks[/switch] [function name or task id]') - return - - # No task manupilation requested, build a table of tasks and display it - # get the width of screen in characters - width = self.client_width() - # create table header and list to hold tasks data and actions - tasks_header = ('Task ID', 'Completion Date', 'Function', 'Arguments', 'KWARGS', - 'persistent') - # empty list of lists, the size of the header - tasks_list = [list() for i in range(len(tasks_header))] - for task_id, task in _TASK_HANDLER.tasks.items(): - # collect data from the task - t_comp_date, t_func_mem_ref = self.coll_date_func(task) - t_func_name = str(task[1]).split(' ') - t_func_name = t_func_name[1] if len(t_func_name) >= 2 else None - t_args = str(task[2]) - t_kwargs = str(task[3]) - t_pers = str(task[4]) - # add task data to the tasks list - task_data = (task_id, t_comp_date, t_func_name, t_args, t_kwargs, t_pers) - for i in range(len(tasks_header)): - tasks_list[i].append(task_data[i]) - # create and display the table - tasks_table = EvTable(*tasks_header, table=tasks_list, maxwidth=width, border='cells', - align='center') - actions = (f'/{switch}' for switch in self.switch_options) - helptxt = f"\nActions: {iter_to_str(actions)}" - self.msg(str(tasks_table) + helptxt)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/commands/default/tests.html b/docs/0.9.5/_modules/evennia/commands/default/tests.html deleted file mode 100644 index 35a4c326ef..0000000000 --- a/docs/0.9.5/_modules/evennia/commands/default/tests.html +++ /dev/null @@ -1,2122 +0,0 @@ - - - - - - - - evennia.commands.default.tests — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.commands.default.tests

-# -*- coding: utf-8 -*-
-"""
- ** OBS - this is not a normal command module! **
- ** You cannot import anything in this module as a command! **
-
-This is part of the Evennia unittest framework, for testing the
-stability and integrity of the codebase during updates. This module
-test the default command set. It is instantiated by the
-evennia/objects/tests.py module, which in turn is run by as part of the
-main test suite started with
- > python game/manage.py test.
-
-"""
-import datetime
-from anything import Anything
-
-from parameterized import parameterized
-from django.conf import settings
-from twisted.internet import task
-from unittest.mock import patch, Mock, MagicMock
-
-from evennia import DefaultRoom, DefaultExit, ObjectDB
-from evennia.commands.default.cmdset_character import CharacterCmdSet
-from evennia.utils.test_resources import BaseEvenniaTest, BaseEvenniaCommandTest, EvenniaCommandTest  # noqa
-from evennia.commands.default import (
-    help as help_module,
-    general,
-    system,
-    admin,
-    account,
-    building,
-    batchprocess,
-    comms,
-    unloggedin,
-    syscommands,
-)
-from evennia.commands.default.muxcommand import MuxCommand
-from evennia.commands.command import Command, InterruptCommand
-from evennia.commands import cmdparser
-from evennia.commands.cmdset import CmdSet
-from evennia.utils import utils, gametime, create
-from evennia.server.sessionhandler import SESSIONS
-from evennia import search_object
-from evennia import DefaultObject, DefaultCharacter
-from evennia.prototypes import prototypes as protlib
-
-# ------------------------------------------------------------
-# Command testing
-# ------------------------------------------------------------
-
-
-
[docs]class TestGeneral(BaseEvenniaCommandTest): -
[docs] def test_look(self): - rid = self.room1.id - self.call(general.CmdLook(), "here", "Room(#{})\nroom_desc".format(rid))
- -
[docs] def test_home(self): - self.call(general.CmdHome(), "", "You are already home")
- -
[docs] def test_inventory(self): - self.call(general.CmdInventory(), "", "You are not carrying anything.")
- -
[docs] def test_pose(self): - self.call(general.CmdPose(), "looks around", "Char looks around")
- -
[docs] def test_nick(self): - self.call( - general.CmdNick(), - "testalias = testaliasedstring1", - "Inputline-nick 'testalias' mapped to 'testaliasedstring1'.", - ) - self.call( - general.CmdNick(), - "/account testalias = testaliasedstring2", - "Account-nick 'testalias' mapped to 'testaliasedstring2'.", - ) - self.call( - general.CmdNick(), - "/object testalias = testaliasedstring3", - "Object-nick 'testalias' mapped to 'testaliasedstring3'.", - ) - self.assertEqual("testaliasedstring1", self.char1.nicks.get("testalias")) - self.assertEqual( - "testaliasedstring2", self.char1.nicks.get("testalias", category="account") - ) - self.assertEqual(None, self.char1.account.nicks.get("testalias", category="account")) - self.assertEqual("testaliasedstring3", self.char1.nicks.get("testalias", category="object"))
- -
[docs] def test_get_and_drop(self): - self.call(general.CmdGet(), "Obj", "You pick up Obj.") - self.call(general.CmdDrop(), "Obj", "You drop Obj.")
- -
[docs] def test_give(self): - self.call(general.CmdGive(), "Obj to Char2", "You aren't carrying Obj.") - self.call(general.CmdGive(), "Obj = Char2", "You aren't carrying Obj.") - self.call(general.CmdGet(), "Obj", "You pick up Obj.") - self.call(general.CmdGive(), "Obj to Char2", "You give") - self.call(general.CmdGive(), "Obj = Char", "You give", caller=self.char2)
- -
[docs] def test_mux_command(self): - class CmdTest(MuxCommand): - key = "test" - switch_options = ("test", "testswitch", "testswitch2") - - def func(self): - self.msg("Switches matched: {}".format(self.switches)) - - self.call( - CmdTest(), - "/test/testswitch/testswitch2", - "Switches matched: ['test', 'testswitch', 'testswitch2']", - ) - self.call(CmdTest(), "/test", "Switches matched: ['test']") - self.call(CmdTest(), "/test/testswitch", "Switches matched: ['test', 'testswitch']") - self.call( - CmdTest(), "/testswitch/testswitch2", "Switches matched: ['testswitch', 'testswitch2']" - ) - self.call(CmdTest(), "/testswitch", "Switches matched: ['testswitch']") - self.call(CmdTest(), "/testswitch2", "Switches matched: ['testswitch2']") - self.call( - CmdTest(), - "/t", - "test: Ambiguous switch supplied: " - "Did you mean /test or /testswitch or /testswitch2?|Switches matched: []", - ) - self.call( - CmdTest(), - "/tests", - "test: Ambiguous switch supplied: " - "Did you mean /testswitch or /testswitch2?|Switches matched: []", - )
- -
[docs] def test_say(self): - self.call(general.CmdSay(), "Testing", 'You say, "Testing"')
- -
[docs] def test_whisper(self): - self.call( - general.CmdWhisper(), - "Obj = Testing", - 'You whisper to Obj, "Testing"', - caller=self.char2, - )
- -
[docs] def test_access(self): - self.call(general.CmdAccess(), "", "Permission Hierarchy (climbing):")
- - -
[docs]class TestHelp(BaseEvenniaCommandTest): - - maxDiff = None - -
[docs] def setUp(self): - super().setUp() - # we need to set up a logger here since lunr takes over the logger otherwise - import logging - - logging.basicConfig(level=logging.ERROR)
- -
[docs] def tearDown(self): - super().tearDown() - import logging - - logging.disable(level=logging.ERROR)
- -
[docs] def test_help(self): - self.call(help_module.CmdHelp(), "", "Commands", cmdset=CharacterCmdSet())
- -
[docs] def test_set_help(self): - self.call( - help_module.CmdSetHelp(), - "testhelp, General = This is a test", - "Topic 'testhelp' was successfully created.", - cmdset=CharacterCmdSet() - ) - self.call(help_module.CmdHelp(), "testhelp", "Help for testhelp", cmdset=CharacterCmdSet())
- - @parameterized.expand([ - ("test", # main help entry - "Help for test\n\n" - "Main help text\n\n" - "Subtopics:\n" - " test/creating extra stuff" - " test/something else" - " test/more" - ), - ("test/creating extra stuff", # subtopic, full match - "Help for test/creating extra stuff\n\n" - "Help on creating extra stuff.\n\n" - "Subtopics:\n" - " test/creating extra stuff/subsubtopic\n" - ), - ("test/creating", # startswith-match - "Help for test/creating extra stuff\n\n" - "Help on creating extra stuff.\n\n" - "Subtopics:\n" - " test/creating extra stuff/subsubtopic\n" - ), - ("test/extra", # partial match - "Help for test/creating extra stuff\n\n" - "Help on creating extra stuff.\n\n" - "Subtopics:\n" - " test/creating extra stuff/subsubtopic\n" - ), - ("test/extra/subsubtopic", # partial subsub-match - "Help for test/creating extra stuff/subsubtopic\n\n" - "A subsubtopic text" - ), - ("test/creating extra/subsub", # partial subsub-match - "Help for test/creating extra stuff/subsubtopic\n\n" - "A subsubtopic text" - ), - ("test/Something else", # case - "Help for test/something else\n\n" - "Something else" - ), - ("test/More", # case - "Help for test/more\n\n" - "Another text\n\n" - "Subtopics:\n" - " test/more/second-more" - ), - ("test/More/Second-more", - "Help for test/more/second-more\n\n" - "The Second More text.\n\n" - "Subtopics:\n" - " test/more/second-more/more again" - " test/more/second-more/third more" - ), - ("test/More/-more", # partial match - "Help for test/more/second-more\n\n" - "The Second More text.\n\n" - "Subtopics:\n" - " test/more/second-more/more again" - " test/more/second-more/third more" - ), - ("test/more/second/more again", - "Help for test/more/second-more/more again\n\n" - "Even more text.\n" - ), - ("test/more/second/third", - "Help for test/more/second-more/third more\n\n" - "Third more text\n" - ), - ]) - def test_subtopic_fetch(self, helparg, expected): - """ - Check retrieval of subtopics. - - """ - class TestCmd(Command): - """ - Main help text - - # SUBTOPICS - - ## creating extra stuff - - Help on creating extra stuff. - - ### subsubtopic - - A subsubtopic text - - ## Something else - - Something else - - ## More - - Another text - - ### Second-More - - The Second More text. - - #### More again - - Even more text. - - #### Third more - - Third more text - - """ - key = "test" - - class TestCmdSet(CmdSet): - def at_cmdset_creation(self): - self.add(TestCmd()) - self.add(help_module.CmdHelp()) - - self.call(help_module.CmdHelp(), - helparg, - expected, - cmdset=TestCmdSet())
- - -
[docs]class TestSystem(BaseEvenniaCommandTest): -
[docs] def test_py(self): - # we are not testing CmdReload, CmdReset and CmdShutdown, CmdService or CmdTime - # since the server is not running during these tests. - self.call(system.CmdPy(), "1+2", ">>> 1+2|3") - self.call(system.CmdPy(), "/clientraw 1+2", ">>> 1+2|3")
- -
[docs] def test_scripts(self): - self.call(building.CmdScripts(), "", "dbref ")
- -
[docs] def test_objects(self): - self.call(building.CmdObjects(), "", "Object subtype totals")
- -
[docs] def test_about(self): - self.call(system.CmdAbout(), "", None)
- -
[docs] def test_server_load(self): - self.call(system.CmdServerLoad(), "", "Server CPU and Memory load:")
- -_TASK_HANDLER = None - -
[docs]def func_test_cmd_tasks(): - return 'success'
- -
[docs]class TestCmdTasks(BaseEvenniaCommandTest): - -
[docs] def setUp(self): - super().setUp() - # get a reference of TASK_HANDLER - self.timedelay = 5 - global _TASK_HANDLER - if _TASK_HANDLER is None: - from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER - _TASK_HANDLER.clock = task.Clock() - self.task_handler = _TASK_HANDLER - self.task_handler.clear() - self.task = self.task_handler.add(self.timedelay, func_test_cmd_tasks) - task_args = self.task_handler.tasks.get(self.task.get_id(), False)
- - -
[docs] def tearDown(self): - super().tearDown() - self.task_handler.clear()
- -
[docs] def test_no_tasks(self): - self.task_handler.clear() - self.call(system.CmdTasks(), '', 'There are no active tasks.')
- -
[docs] def test_active_task(self): - cmd_result = self.call(system.CmdTasks(), '') - for ptrn in ('Task ID', 'Completion', 'Date', 'Function', 'KWARGS', 'persisten', - '1', r'\d+/\d+/\d+', r'\d+\:', r'\d+\:\d+', r'\:\d+', 'func_test', '{}', - 'False'): - self.assertRegex(cmd_result, ptrn)
- -
[docs] def test_persistent_task(self): - self.task_handler.clear() - self.task_handler.add(self.timedelay, func_test_cmd_tasks, persistent=True) - cmd_result = self.call(system.CmdTasks(), '') - self.assertRegex(cmd_result, 'True')
- -
[docs] def test_pause_unpause(self): - # test pause - args = f'/pause {self.task.get_id()}' - wanted_msg = 'Pause task 1 with completion date' - cmd_result = self.call(system.CmdTasks(), args, wanted_msg) - self.assertRegex(cmd_result, ' \(func_test_cmd_tasks\) ') - self.char1.execute_cmd('y') - self.assertTrue(self.task.paused) - self.task_handler.clock.advance(self.timedelay + 1) - # test unpause - args = f'/unpause {self.task.get_id()}' - self.assertTrue(self.task.exists()) - wanted_msg = 'Unpause task 1 with completion date' - cmd_result = self.call(system.CmdTasks(), args, wanted_msg) - self.assertRegex(cmd_result, ' \(func_test_cmd_tasks\) ') - self.char1.execute_cmd('y') - # verify task continues after unpause - self.task_handler.clock.advance(1) - self.assertFalse(self.task.exists())
- -
[docs] def test_do_task(self): - args = f'/do_task {self.task.get_id()}' - wanted_msg = 'Do_task task 1 with completion date' - cmd_result = self.call(system.CmdTasks(), args, wanted_msg) - self.assertRegex(cmd_result, ' \(func_test_cmd_tasks\) ') - self.char1.execute_cmd('y') - self.assertFalse(self.task.exists())
- -
[docs] def test_remove(self): - args = f'/remove {self.task.get_id()}' - wanted_msg = 'Remove task 1 with completion date' - cmd_result = self.call(system.CmdTasks(), args, wanted_msg) - self.assertRegex(cmd_result, ' \(func_test_cmd_tasks\) ') - self.char1.execute_cmd('y') - self.assertFalse(self.task.exists())
- -
[docs] def test_call(self): - args = f'/call {self.task.get_id()}' - wanted_msg = 'Call task 1 with completion date' - cmd_result = self.call(system.CmdTasks(), args, wanted_msg) - self.assertRegex(cmd_result, ' \(func_test_cmd_tasks\) ') - self.char1.execute_cmd('y') - # make certain the task is still active - self.assertTrue(self.task.active()) - # go past delay time, the task should call do_task and remove itself after calling. - self.task_handler.clock.advance(self.timedelay + 1) - self.assertFalse(self.task.exists())
- -
[docs] def test_cancel(self): - args = f'/cancel {self.task.get_id()}' - wanted_msg = 'Cancel task 1 with completion date' - cmd_result = self.call(system.CmdTasks(), args, wanted_msg) - self.assertRegex(cmd_result, ' \(func_test_cmd_tasks\) ') - self.char1.execute_cmd('y') - self.assertTrue(self.task.exists()) - self.assertFalse(self.task.active())
- -
[docs] def test_func_name_manipulation(self): - self.task_handler.add(self.timedelay, func_test_cmd_tasks) # add an extra task - args = f'/remove func_test_cmd_tasks' - wanted_msg = 'Task action remove completed on task ID 1.|The task function remove returned: True|' \ - 'Task action remove completed on task ID 2.|The task function remove returned: True' - self.call(system.CmdTasks(), args, wanted_msg) - self.assertFalse(self.task_handler.tasks) # no tasks should exist.
- -
[docs] def test_wrong_func_name(self): - args = f'/remove intentional_fail' - wanted_msg = 'No tasks deferring function name intentional_fail found.' - self.call(system.CmdTasks(), args, wanted_msg) - self.assertTrue(self.task.active())
- -
[docs] def test_no_input(self): - args = f'/cancel {self.task.get_id()}' - self.call(system.CmdTasks(), args) - # task should complete since no input was received - self.task_handler.clock.advance(self.timedelay + 1) - self.assertFalse(self.task.exists())
- -
[docs] def test_responce_of_yes(self): - self.call(system.CmdTasks(), f'/cancel {self.task.get_id()}') - self.char1.msg = Mock() - self.char1.execute_cmd('y') - text = '' - for _, _, kwargs in self.char1.msg.mock_calls: - text += kwargs.get('text', '') - self.assertEqual(text, 'cancel request completed.The task function cancel returned: True') - self.assertTrue(self.task.exists())
- -
[docs] def test_task_complete_waiting_input(self): - """Test for task completing while waiting for input.""" - self.call(system.CmdTasks(), f'/cancel {self.task.get_id()}') - self.task_handler.clock.advance(self.timedelay + 1) - self.char1.msg = Mock() - self.char1.execute_cmd('y') - text = '' - for _, _, kwargs in self.char1.msg.mock_calls: - text += kwargs.get('text', '') - self.assertEqual(text, 'Task completed while waiting for input.') - self.assertFalse(self.task.exists())
- -
[docs] def test_new_task_waiting_input(self): - """ - Test task completing than a new task with the same ID being made while waitinf for input. - """ - self.assertTrue(self.task.get_id(), 1) - self.call(system.CmdTasks(), f'/cancel {self.task.get_id()}') - self.task_handler.clock.advance(self.timedelay + 1) - self.assertFalse(self.task.exists()) - self.task = self.task_handler.add(self.timedelay, func_test_cmd_tasks) - self.assertTrue(self.task.get_id(), 1) - self.char1.msg = Mock() - self.char1.execute_cmd('y') - text = '' - for _, _, kwargs in self.char1.msg.mock_calls: - text += kwargs.get('text', '') - self.assertEqual(text, 'Task completed while waiting for input.')
- -
[docs] def test_misformed_command(self): - wanted_msg = 'Task command misformed.|Proper format tasks[/switch] ' \ - '[function name or task id]' - self.call(system.CmdTasks(), f'/cancel', wanted_msg)
- - -
[docs]class TestAdmin(BaseEvenniaCommandTest): -
[docs] def test_emit(self): - self.call(admin.CmdEmit(), "Char2 = Test", "Emitted to Char2:\nTest")
- -
[docs] def test_perm(self): - self.call( - admin.CmdPerm(), - "Obj = Builder", - "Permission 'Builder' given to Obj (the Object/Character).", - ) - self.call( - admin.CmdPerm(), - "Char2 = Builder", - "Permission 'Builder' given to Char2 (the Object/Character).", - )
- -
[docs] def test_wall(self): - self.call(admin.CmdWall(), "Test", "Announcing to all connected sessions ...")
- -
[docs] def test_ban(self): - self.call(admin.CmdBan(), "Char", "Name-ban 'char' was added. Use unban to reinstate.")
- -
[docs] def test_force(self): - cid = self.char2.id - self.call( - admin.CmdForce(), - "Char2=say test", - 'Char2(#{}) says, "test"|You have forced Char2 to: say test'.format(cid), - )
- - -
[docs]class TestAccount(BaseEvenniaCommandTest): -
[docs] def test_ooc_look(self): - if settings.MULTISESSION_MODE < 2: - self.call( - account.CmdOOCLook(), "", "You are out-of-character (OOC).", caller=self.account - ) - if settings.MULTISESSION_MODE == 2: - self.call( - account.CmdOOCLook(), - "", - "Account TestAccount (you are OutofCharacter)", - caller=self.account, - )
- -
[docs] def test_ooc(self): - self.call(account.CmdOOC(), "", "You go OOC.", caller=self.account)
- -
[docs] def test_ic(self): - self.account.db._playable_characters = [self.char1] - self.account.unpuppet_object(self.session) - self.call( - account.CmdIC(), "Char", "You become Char.", caller=self.account, receiver=self.char1 - )
- -
[docs] def test_ic__other_object(self): - self.account.db._playable_characters = [self.obj1] - self.account.unpuppet_object(self.session) - self.call( - account.CmdIC(), "Obj", "You become Obj.", caller=self.account, receiver=self.obj1 - )
- -
[docs] def test_ic__nonaccess(self): - self.account.unpuppet_object(self.session) - self.call( - account.CmdIC(), - "Nonexistent", - "That is not a valid character choice.", - caller=self.account, - receiver=self.account, - )
- -
[docs] def test_password(self): - self.call( - account.CmdPassword(), - "testpassword = testpassword", - "Password changed.", - caller=self.account, - )
- -
[docs] def test_option(self): - self.call(account.CmdOption(), "", "Client settings", caller=self.account)
- -
[docs] def test_who(self): - self.call(account.CmdWho(), "", "Accounts:", caller=self.account)
- -
[docs] def test_quit(self): - self.call( - account.CmdQuit(), "", "Quitting. Hope to see you again, soon.", caller=self.account - )
- -
[docs] def test_sessions(self): - self.call(account.CmdSessions(), "", "Your current session(s):", caller=self.account)
- -
[docs] def test_color_test(self): - self.call(account.CmdColorTest(), "ansi", "ANSI colors:", caller=self.account)
- -
[docs] def test_char_create(self): - self.call( - account.CmdCharCreate(), - "Test1=Test char", - "Created new character Test1. Use ic Test1 to enter the game", - caller=self.account, - )
- -
[docs] def test_char_delete(self): - # Chardelete requires user input; this test is mainly to confirm - # whether permissions are being checked - - # Add char to account playable characters - self.account.db._playable_characters.append(self.char1) - - # Try deleting as Developer - self.call( - account.CmdCharDelete(), - "Char", - "This will permanently destroy 'Char'. This cannot be undone. Continue yes/[no]?", - caller=self.account, - ) - - # Downgrade permissions on account - self.account.permissions.add("Player") - self.account.permissions.remove("Developer") - - # Set lock on character object to prevent deletion - self.char1.locks.add("delete:none()") - - # Try deleting as Player - self.call( - account.CmdCharDelete(), - "Char", - "You do not have permission to delete this character.", - caller=self.account, - ) - - # Set lock on character object to allow self-delete - self.char1.locks.add("delete:pid(%i)" % self.account.id) - - # Try deleting as Player again - self.call( - account.CmdCharDelete(), - "Char", - "This will permanently destroy 'Char'. This cannot be undone. Continue yes/[no]?", - caller=self.account, - )
- -
[docs] def test_quell(self): - self.call( - account.CmdQuell(), - "", - "Quelling to current puppet's permissions (developer).", - caller=self.account, - )
- - -
[docs]class TestBuilding(BaseEvenniaCommandTest): -
[docs] def test_create(self): - name = settings.BASE_OBJECT_TYPECLASS.rsplit(".", 1)[1] - self.call( - building.CmdCreate(), - "/d TestObj1", # /d switch is abbreviated form of /drop - "You create a new %s: TestObj1." % name, - ) - self.call(building.CmdCreate(), "", "Usage: ") - self.call( - building.CmdCreate(), - "TestObj1;foo;bar", - "You create a new %s: TestObj1 (aliases: foo, bar)." % name, - )
- -
[docs] def test_examine(self): - self.call(building.CmdExamine(), "", "Name/key: Room") - self.call(building.CmdExamine(), "Obj", "Name/key: Obj") - self.call(building.CmdExamine(), "Obj", "Name/key: Obj") - self.call(building.CmdExamine(), "*TestAccount", "Name/key: TestAccount") - - self.char1.db.test = "testval" - self.call(building.CmdExamine(), "self/test", "Attribute Char/test [category=None]:\n\ntestval") - self.call(building.CmdExamine(), "NotFound", "Could not find 'NotFound'.") - self.call(building.CmdExamine(), "out", "Name/key: out") - - # escape inlinefuncs - self.char1.db.test2 = "this is a $random() value." - self.call( - building.CmdExamine(), - "self/test2", - "Attribute Char/test2 [category=None]:\n\nthis is a \$random() value." - ) - - self.room1.scripts.add(self.script.__class__) - self.call(building.CmdExamine(), "") - self.account.scripts.add(self.script.__class__) - self.call(building.CmdExamine(), "*TestAccount")
- -
[docs] def test_set_obj_alias(self): - oid = self.obj1.id - self.call(building.CmdSetObjAlias(), "Obj =", "Cleared aliases from Obj") - self.call( - building.CmdSetObjAlias(), - "Obj = TestObj1b", - "Alias(es) for 'Obj(#{})' set to 'testobj1b'.".format(oid), - ) - self.call(building.CmdSetObjAlias(), "", "Usage: ") - self.call(building.CmdSetObjAlias(), "NotFound =", "Could not find 'NotFound'.") - - self.call(building.CmdSetObjAlias(), "Obj", "Aliases for Obj(#{}): 'testobj1b'".format(oid)) - self.call(building.CmdSetObjAlias(), "Obj2 =", "Cleared aliases from Obj2") - self.call(building.CmdSetObjAlias(), "Obj2 =", "No aliases to clear.")
- -
[docs] def test_copy(self): - self.call( - building.CmdCopy(), - "Obj = TestObj2;TestObj2b, TestObj3;TestObj3b", - "Copied Obj to 'TestObj3' (aliases: ['TestObj3b']", - ) - self.call(building.CmdCopy(), "", "Usage: ") - self.call(building.CmdCopy(), "Obj", "Identical copy of Obj, named 'Obj_copy' was created.") - self.call(building.CmdCopy(), "NotFound = Foo", "Could not find 'NotFound'.")
- -
[docs] def test_attribute_commands(self): - self.call(building.CmdSetAttribute(), "", "Usage: ") - self.call( - building.CmdSetAttribute(), - 'Obj/test1="value1"', - "Created attribute Obj/test1 [category:None] = value1", - ) - self.call( - building.CmdSetAttribute(), - 'Obj2/test2="value2"', - "Created attribute Obj2/test2 [category:None] = value2", - ) - self.call(building.CmdSetAttribute(), - "Obj2/test2", "Attribute Obj2/test2 [category:None] = value2") - self.call(building.CmdSetAttribute(), - "Obj2/NotFound", "Attribute Obj2/notfound [category:None] does not exist.") - - with patch("evennia.commands.default.building.EvEditor") as mock_ed: - self.call(building.CmdSetAttribute(), "/edit Obj2/test3") - mock_ed.assert_called_with(self.char1, Anything, Anything, key="Obj2/test3") - - self.call( - building.CmdSetAttribute(), - 'Obj2/test3="value3"', - "Created attribute Obj2/test3 [category:None] = value3", - ) - self.call( - building.CmdSetAttribute(), - "Obj2/test3 = ", - "Deleted attribute Obj2/test3 [category:None].", - ) - self.call( - building.CmdSetAttribute(), - "Obj2/test4:Foo = 'Bar'", - "Created attribute Obj2/test4 [category:Foo] = Bar", - ) - self.call( - building.CmdCpAttr(), - "/copy Obj2/test2 = Obj2/test3", - '@cpattr: Extra switch "/copy" ignored.|\nCopied Obj2.test2 -> Obj2.test3. ' - "(value: 'value2')", - ) - self.call(building.CmdMvAttr(), "", "Usage: ") - self.call(building.CmdMvAttr(), "Obj2/test2 = Obj/test3", "Moved Obj2.test2 -> Obj.test3") - self.call(building.CmdCpAttr(), "", "Usage: ") - self.call(building.CmdCpAttr(), "Obj/test1 = Obj2/test3", "Copied Obj.test1 -> Obj2.test3") - - self.call(building.CmdWipe(), "", "Usage: ") - self.call(building.CmdWipe(), "Obj2/test2/test3", "Wiped attributes test2,test3 on Obj2.") - self.call(building.CmdWipe(), "Obj2", "Wiped all attributes on Obj2.")
- -
[docs] def test_nested_attribute_commands(self): - # list - adding white space proves real parsing - self.call( - building.CmdSetAttribute(), - "Obj/test1=[1,2]", "Created attribute Obj/test1 [category:None] = [1, 2]" - ) - self.call(building.CmdSetAttribute(), - "Obj/test1", - "Attribute Obj/test1 [category:None] = [1, 2]") - self.call(building.CmdSetAttribute(), - "Obj/test1[0]", - "Attribute Obj/test1[0] [category:None] = 1") - self.call(building.CmdSetAttribute(), - "Obj/test1[1]", - "Attribute Obj/test1[1] [category:None] = 2") - self.call( - building.CmdSetAttribute(), - "Obj/test1[0] = 99", - "Modified attribute Obj/test1 [category:None] = [99, 2]", - ) - self.call( - building.CmdSetAttribute(), - "Obj/test1[0]", - "Attribute Obj/test1[0] [category:None] = 99" - ) - # list delete - self.call( - building.CmdSetAttribute(), - "Obj/test1[0] =", - "Deleted attribute Obj/test1[0] [category:None].", - ) - self.call( - building.CmdSetAttribute(), - "Obj/test1[0]", - "Attribute Obj/test1[0] [category:None] = 2" - ) - self.call( - building.CmdSetAttribute(), - "Obj/test1[1]", - "Attribute Obj/test1[1] [category:None] does not exist. (Nested lookups attempted)", - ) - # Delete non-existent - self.call( - building.CmdSetAttribute(), - "Obj/test1[5] =", - "No attribute Obj/test1[5] [category: None] was found to " - "delete. (Nested lookups attempted)" - ) - # Append - self.call( - building.CmdSetAttribute(), - "Obj/test1[+] = 42", - "Modified attribute Obj/test1 [category:None] = [2, 42]", - ) - self.call( - building.CmdSetAttribute(), - "Obj/test1[+0] = -1", - "Modified attribute Obj/test1 [category:None] = [-1, 2, 42]", - ) - - # dict - removing white space proves real parsing - self.call( - building.CmdSetAttribute(), - "Obj/test2={ 'one': 1, 'two': 2 }", - "Created attribute Obj/test2 [category:None] = {'one': 1, 'two': 2}", - ) - self.call( - building.CmdSetAttribute(), - "Obj/test2", "Attribute Obj/test2 [category:None] = {'one': 1, 'two': 2}" - ) - self.call( - building.CmdSetAttribute(), - "Obj/test2['one']", - "Attribute Obj/test2['one'] [category:None] = 1" - ) - self.call( - building.CmdSetAttribute(), - "Obj/test2['one]", - "Attribute Obj/test2['one] [category:None] = 1" - ) - self.call( - building.CmdSetAttribute(), - "Obj/test2['one']=99", - "Modified attribute Obj/test2 [category:None] = {'one': 99, 'two': 2}", - ) - self.call( - building.CmdSetAttribute(), - "Obj/test2['one']", - "Attribute Obj/test2['one'] [category:None] = 99" - ) - self.call( - building.CmdSetAttribute(), - "Obj/test2['two']", - "Attribute Obj/test2['two'] [category:None] = 2" - ) - self.call( - building.CmdSetAttribute(), - "Obj/test2[+'three']", - "Attribute Obj/test2[+'three'] [category:None] does not exist. (Nested lookups attempted)" - ) - self.call( - building.CmdSetAttribute(), - "Obj/test2[+'three'] = 3", - "Modified attribute Obj/test2 [category:None] = {'one': 99, 'two': 2, \"+'three'\": 3}", - ) - self.call( - building.CmdSetAttribute(), - "Obj/test2[+'three'] =", - "Deleted attribute Obj/test2[+'three'] [category:None]." - ) - self.call( - building.CmdSetAttribute(), - "Obj/test2['three']=3", - "Modified attribute Obj/test2 [category:None] = {'one': 99, 'two': 2, 'three': 3}", - ) - # Dict delete - self.call( - building.CmdSetAttribute(), - "Obj/test2['two'] =", - "Deleted attribute Obj/test2['two'] [category:None].", - ) - self.call( - building.CmdSetAttribute(), - "Obj/test2['two']", - "Attribute Obj/test2['two'] [category:None] does not exist. (Nested lookups attempted)" - ) - self.call( - building.CmdSetAttribute(), - "Obj/test2", - "Attribute Obj/test2 [category:None] = {'one': 99, 'three': 3}" - ) - self.call( - building.CmdSetAttribute(), - "Obj/test2[0]", - "Attribute Obj/test2[0] [category:None] does not exist. (Nested lookups attempted)" - ) - self.call( - building.CmdSetAttribute(), - "Obj/test2['five'] =", - "No attribute Obj/test2['five'] [category: None] " - "was found to delete. (Nested lookups attempted)" - ) - self.call( - building.CmdSetAttribute(), - "Obj/test2[+]=42", - "Modified attribute Obj/test2 [category:None] = {'one': 99, 'three': 3, '+': 42}", - ) - self.call( - building.CmdSetAttribute(), - "Obj/test2[+1]=33", - "Modified attribute Obj/test2 [category:None] = " - "{'one': 99, 'three': 3, '+': 42, '+1': 33}", - ) - - # tuple - self.call( - building.CmdSetAttribute(), - "Obj/tup = (1,2)", - "Created attribute Obj/tup [category:None] = (1, 2)" - ) - self.call( - building.CmdSetAttribute(), - "Obj/tup[1] = 99", - "'tuple' object does not support item assignment - (1, 2)", - ) - self.call( - building.CmdSetAttribute(), - "Obj/tup[+] = 99", - "'tuple' object does not support item assignment - (1, 2)", - ) - self.call( - building.CmdSetAttribute(), - "Obj/tup[+1] = 99", - "'tuple' object does not support item assignment - (1, 2)", - ) - self.call( - building.CmdSetAttribute(), - # Special case for tuple, could have a better message - "Obj/tup[1] = ", - "No attribute Obj/tup[1] [category: None] " - "was found to delete. (Nested lookups attempted)" - ) - - # Deaper nesting - self.call( - building.CmdSetAttribute(), - "Obj/test3=[{'one': 1}]", - "Created attribute Obj/test3 [category:None] = [{'one': 1}]", - ) - self.call( - building.CmdSetAttribute(), - "Obj/test3[0]['one']", - "Attribute Obj/test3[0]['one'] [category:None] = 1" - ) - self.call( - building.CmdSetAttribute(), - "Obj/test3[0]", - "Attribute Obj/test3[0] [category:None] = {'one': 1}" - ) - self.call( - building.CmdSetAttribute(), - "Obj/test3[0]['one'] =", - "Deleted attribute Obj/test3[0]['one'] [category:None]." - ) - self.call( - building.CmdSetAttribute(), - "Obj/test3[0]", - "Attribute Obj/test3[0] [category:None] = {}") - self.call( - building.CmdSetAttribute(), - "Obj/test3", - "Attribute Obj/test3 [category:None] = [{}]" - ) - - # Naughty keys - self.call( - building.CmdSetAttribute(), - "Obj/test4[0]='foo'", - "Created attribute Obj/test4[0] [category:None] = foo", - ) - self.call( - building.CmdSetAttribute(), - "Obj/test4[0]", - "Attribute Obj/test4[0] [category:None] = foo") - self.call( - building.CmdSetAttribute(), - "Obj/test4=[{'one': 1}]", - "Created attribute Obj/test4 [category:None] = [{'one': 1}]", - ) - self.call( - building.CmdSetAttribute(), - "Obj/test4[0]['one']", - "Attribute Obj/test4[0]['one'] [category:None] = 1" - ) - # Prefer nested items - self.call( - building.CmdSetAttribute(), - "Obj/test4[0]", - "Attribute Obj/test4[0] [category:None] = {'one': 1}" - ) - self.call( - building.CmdSetAttribute(), - "Obj/test4[0]['one']", - "Attribute Obj/test4[0]['one'] [category:None] = 1" - ) - # Restored access - self.call( - building.CmdWipe(), - "Obj/test4", - "Wiped attributes test4 on Obj.") - self.call( - building.CmdSetAttribute(), - "Obj/test4[0]", - "Attribute Obj/test4[0] [category:None] = foo") - self.call( - building.CmdSetAttribute(), - "Obj/test4[0]['one']", - "Attribute Obj/test4[0]['one'] [category:None] does not exist. (Nested lookups attempted)" - )
- -
[docs] def test_split_nested_attr(self): - split_nested_attr = building.CmdSetAttribute().split_nested_attr - test_cases = { - "test1": [("test1", [])], - 'test2["dict"]': [("test2", ["dict"]), ('test2["dict"]', [])], - # Quotes not actually required - "test3[dict]": [("test3", ["dict"]), ("test3[dict]", [])], - 'test4["dict]': [("test4", ["dict"]), ('test4["dict]', [])], - # duplicate keys don't cause issues - "test5[0][0]": [("test5", [0, 0]), ("test5[0]", [0]), ("test5[0][0]", [])], - # String ints preserved - 'test6["0"][0]': [("test6", ["0", 0]), ('test6["0"]', [0]), ('test6["0"][0]', [])], - # Unmatched [] - "test7[dict": [("test7[dict", [])], - } - - for attr, result in test_cases.items(): - self.assertEqual(list(split_nested_attr(attr)), result)
- -
[docs] def test_do_nested_lookup(self): - do_nested_lookup = building.CmdSetAttribute().do_nested_lookup - not_found = building.CmdSetAttribute.not_found - - def do_test_single(value, key, result): - self.assertEqual(do_nested_lookup(value, key), result) - - def do_test_multi(value, keys, result): - self.assertEqual(do_nested_lookup(value, *keys), result) - - do_test_single([], "test1", not_found) - do_test_single([1], "test2", not_found) - do_test_single([], 0, not_found) - do_test_single([], "0", not_found) - do_test_single([1], 2, not_found) - do_test_single([1], 0, 1) - do_test_single([1], "0", not_found) # str key is str not int - do_test_single({}, "test3", not_found) - do_test_single({}, 0, not_found) - do_test_single({"foo": "bar"}, "foo", "bar") - - do_test_multi({"one": [1, 2, 3]}, ("one", 0), 1) - do_test_multi([{}, {"two": 2}, 3], (1, "two"), 2)
- -
[docs] def test_name(self): - self.call(building.CmdName(), "", "Usage: ") - self.call(building.CmdName(), "Obj2=Obj3", "Object's name changed to 'Obj3'.") - self.call( - building.CmdName(), - "*TestAccount=TestAccountRenamed", - "Account's name changed to 'TestAccountRenamed'.", - ) - self.call(building.CmdName(), "*NotFound=TestAccountRenamed", "Could not find '*NotFound'") - self.call( - building.CmdName(), "Obj3=Obj4;foo;bar", "Object's name changed to 'Obj4' (foo, bar)." - ) - self.call(building.CmdName(), "Obj4=", "No names or aliases defined!")
- -
[docs] def test_desc(self): - oid = self.obj2.id - self.call( - building.CmdDesc(), "Obj2=TestDesc", "The description was set on Obj2(#{}).".format(oid) - ) - self.call(building.CmdDesc(), "", "Usage: ") - - with patch("evennia.commands.default.building.EvEditor") as mock_ed: - self.call(building.CmdDesc(), "/edit") - mock_ed.assert_called_with( - self.char1, - key="desc", - loadfunc=building._desc_load, - quitfunc=building._desc_quit, - savefunc=building._desc_save, - persistent=True, - )
- -
[docs] def test_empty_desc(self): - """ - empty desc sets desc as '' - """ - oid = self.obj2.id - o2d = self.obj2.db.desc - r1d = self.room1.db.desc - self.call(building.CmdDesc(), "Obj2=", "The description was set on Obj2(#{}).".format(oid)) - assert self.obj2.db.desc == "" and self.obj2.db.desc != o2d - assert self.room1.db.desc == r1d
- -
[docs] def test_desc_default_to_room(self): - """no rhs changes room's desc""" - rid = self.room1.id - o2d = self.obj2.db.desc - r1d = self.room1.db.desc - self.call(building.CmdDesc(), "Obj2", "The description was set on Room(#{}).".format(rid)) - assert self.obj2.db.desc == o2d - assert self.room1.db.desc == "Obj2" and self.room1.db.desc != r1d
- -
[docs] def test_destroy(self): - confirm = building.CmdDestroy.confirm - building.CmdDestroy.confirm = False - self.call(building.CmdDestroy(), "", "Usage: ") - self.call(building.CmdDestroy(), "Obj", "Obj was destroyed.") - self.call(building.CmdDestroy(), "Obj", "Obj2 was destroyed.") - self.call( - building.CmdDestroy(), - "Obj", - "Could not find 'Obj'.| (Objects to destroy " - "must either be local or specified with a unique #dbref.)", - ) - settings.DEFAULT_HOME = f"#{self.room1.dbid}" - self.call( - building.CmdDestroy(), settings.DEFAULT_HOME, "You are trying to delete" - ) # DEFAULT_HOME should not be deleted - self.char2.location = self.room2 - charid = self.char2.id - room1id = self.room1.id - room2id = self.room2.id - self.call( - building.CmdDestroy(), - self.room2.dbref, - "Char2(#{}) arrives to Room(#{}) from Room2(#{}).|Room2 was destroyed.".format( - charid, room1id, room2id - ), - ) - building.CmdDestroy.confirm = confirm
- -
[docs] def test_destroy_sequence(self): - confirm = building.CmdDestroy.confirm - building.CmdDestroy.confirm = False - self.call( - building.CmdDestroy(), - "{}-{}".format(self.obj1.dbref, self.obj2.dbref), - "Obj was destroyed.\nObj2 was destroyed.", - )
- -
[docs] def test_dig(self): - self.call(building.CmdDig(), "TestRoom1=testroom;tr,back;b", "Created room TestRoom1") - self.call(building.CmdDig(), "", "Usage: ")
- -
[docs] def test_tunnel(self): - self.call(building.CmdTunnel(), "n = TestRoom2;test2", "Created room TestRoom2") - self.call(building.CmdTunnel(), "", "Usage: ") - self.call(building.CmdTunnel(), "foo = TestRoom2;test2", "tunnel can only understand the") - self.call(building.CmdTunnel(), "/tel e = TestRoom3;test3", "Created room TestRoom3") - DefaultRoom.objects.get_family(db_key="TestRoom3") - exits = DefaultExit.objects.filter_family(db_key__in=("east", "west")) - self.assertEqual(len(exits), 2)
- -
[docs] def test_tunnel_exit_typeclass(self): - self.call( - building.CmdTunnel(), - "n:evennia.objects.objects.DefaultExit = TestRoom3", - "Created room TestRoom3", - )
- -
[docs] def test_exit_commands(self): - self.call( - building.CmdOpen(), "TestExit1=Room2", "Created new Exit 'TestExit1' from Room to Room2" - ) - self.call(building.CmdLink(), "TestExit1=Room", "Link created TestExit1 -> Room (one way).") - self.call(building.CmdUnLink(), "", "Usage: ") - self.call(building.CmdLink(), "NotFound", "Could not find 'NotFound'.") - self.call(building.CmdLink(), "TestExit", "TestExit1 is an exit to Room.") - self.call(building.CmdLink(), "Obj", "Obj is not an exit. Its home location is Room.") - self.call( - building.CmdUnLink(), "TestExit1", "Former exit TestExit1 no longer links anywhere." - ) - - self.char1.location = self.room2 - self.call( - building.CmdOpen(), "TestExit2=Room", "Created new Exit 'TestExit2' from Room2 to Room." - ) - self.call( - building.CmdOpen(), - "TestExit2=Room", - "Exit TestExit2 already exists. It already points to the correct place.", - ) - - # ensure it matches locally first - self.call( - building.CmdLink(), "TestExit=Room2", "Link created TestExit2 -> Room2 (one way)." - ) - self.call( - building.CmdLink(), - "/twoway TestExit={}".format(self.exit.dbref), - "Link created TestExit2 (in Room2) <-> out (in Room) (two-way).", - ) - self.call( - building.CmdLink(), - "/twoway TestExit={}".format(self.room1.dbref), - "To create a two-way link, TestExit2 and Room must both have a location ", - ) - self.call( - building.CmdLink(), - "/twoway {}={}".format(self.exit.dbref, self.exit.dbref), - "Cannot link an object to itself.", - ) - self.call(building.CmdLink(), "", "Usage: ") - # ensure can still match globally when not a local name - self.call(building.CmdLink(), "TestExit1=Room2", "Note: TestExit1") - self.call( - building.CmdLink(), "TestExit1=", "Former exit TestExit1 no longer links anywhere." - )
- -
[docs] def test_set_home(self): - self.call( - building.CmdSetHome(), "Obj = Room2", "Home location of Obj was changed from Room" - ) - self.call(building.CmdSetHome(), "", "Usage: ") - self.call(building.CmdSetHome(), "self", "Char's current home is Room") - self.call(building.CmdSetHome(), "Obj", "Obj's current home is Room2") - self.obj1.home = None - self.call(building.CmdSetHome(), "Obj = Room2", "Home location of Obj was set to Room")
- -
[docs] def test_list_cmdsets(self): - self.call(building.CmdListCmdSets(), "", - "<CmdSetHandler> stack:\n <CmdSet DefaultCharacter, Union, perm, prio 0>:") - self.call(building.CmdListCmdSets(), "NotFound", "Could not find 'NotFound'")
- -
[docs] def test_typeclass(self): - self.call(building.CmdTypeclass(), "", "Usage: ") - self.call( - building.CmdTypeclass(), - "Obj = evennia.objects.objects.DefaultExit", - "Obj changed typeclass from evennia.objects.objects.DefaultObject " - "to evennia.objects.objects.DefaultExit.", - ) - self.call( - building.CmdTypeclass(), - "Obj2 = evennia.objects.objects.DefaultExit", - "Obj2 changed typeclass from evennia.objects.objects.DefaultObject " - "to evennia.objects.objects.DefaultExit.", - cmdstring="swap", - ) - self.call(building.CmdTypeclass(), "/list Obj", "Core typeclasses") - self.call( - building.CmdTypeclass(), - "/show Obj", - "Obj's current typeclass is 'evennia.objects.objects.DefaultExit'", - ) - self.call( - building.CmdTypeclass(), - "Obj = evennia.objects.objects.DefaultExit", - "Obj already has the typeclass 'evennia.objects.objects.DefaultExit'. Use /force to override.", - ) - self.call( - building.CmdTypeclass(), - "/force Obj = evennia.objects.objects.DefaultExit", - "Obj updated its existing typeclass ", - ) - self.call(building.CmdTypeclass(), "Obj = evennia.objects.objects.DefaultObject") - self.call( - building.CmdTypeclass(), - "/show Obj", - "Obj's current typeclass is 'evennia.objects.objects.DefaultObject'", - ) - self.call( - building.CmdTypeclass(), - "Obj", - "Obj updated its existing typeclass (evennia.objects.objects.DefaultObject).\n" - "Only the at_object_creation hook was run (update mode). Attributes set before swap were not removed.", - cmdstring="update", - ) - self.call( - building.CmdTypeclass(), - "/reset/force Obj=evennia.objects.objects.DefaultObject", - "Obj updated its existing typeclass (evennia.objects.objects.DefaultObject).\n" - "All object creation hooks were run. All old attributes where deleted before the swap.", - ) - - from evennia.prototypes.prototypes import homogenize_prototype - - test_prototype = [ - homogenize_prototype( - { - "prototype_key": "testkey", - "prototype_tags": [], - "typeclass": "typeclasses.objects.Object", - "key": "replaced_obj", - "attrs": [("foo", "bar", None, ""), ("desc", "protdesc", None, "")], - } - ) - ] - with patch( - "evennia.commands.default.building.protlib.search_prototype", - new=MagicMock(return_value=test_prototype), - ) as mprot: - self.call( - building.CmdTypeclass(), - "/prototype Obj=testkey", - "replaced_obj changed typeclass from " - "evennia.objects.objects.DefaultObject to " - "typeclasses.objects.Object.\nAll object creation hooks were " - "run. Attributes set before swap were not removed. Prototype " - "'replaced_obj' was successfully applied over the object type.", - ) - assert self.obj1.db.desc == "protdesc"
- -
[docs] def test_lock(self): - self.call(building.CmdLock(), "", "Usage: ") - self.call(building.CmdLock(), "Obj = test:all()", "Added lock 'test:all()' to Obj.") - self.call( - building.CmdLock(), - "*TestAccount = test:all()", - "Added lock 'test:all()' to TestAccount", - ) - self.call(building.CmdLock(), "Obj/notfound", "Obj has no lock of access type 'notfound'.") - self.call(building.CmdLock(), "Obj/test", "test:all()") - self.call( - building.CmdLock(), - "/view Obj = edit:false()", - "Switch(es) view can not be used with a lock assignment. " - "Use e.g. lock/del objname/locktype instead.", - ) - self.call(building.CmdLock(), "Obj = control:false()") - self.call(building.CmdLock(), "Obj = edit:false()") - self.call(building.CmdLock(), "Obj/test", "You are not allowed to do that.") - self.obj1.locks.add("control:true()") - self.call(building.CmdLock(), "Obj", "call:true()") # etc - self.call(building.CmdLock(), "*TestAccount", "boot:perm(Admin)") # etc
- -
[docs] def test_find(self): - rid2 = self.room2.id - rmax = rid2 + 100 - self.call(building.CmdFind(), "", "Usage: ") - self.call(building.CmdFind(), "oom2", "One Match") - self.call(building.CmdFind(), "oom2 = 1-{}".format(rmax), "One Match") - self.call(building.CmdFind(), "oom2 = 1 {}".format(rmax), "One Match") # space works too - self.call(building.CmdFind(), "Char2", "One Match", cmdstring="locate") - self.call( - building.CmdFind(), - "/ex Char2", # /ex is an ambiguous switch - "locate: Ambiguous switch supplied: Did you mean /exit or /exact?|", - cmdstring="locate", - ) - self.call(building.CmdFind(), "Char2", "One Match", cmdstring="locate") - self.call( - building.CmdFind(), "/l Char2", "One Match", cmdstring="find" - ) # /l switch is abbreviated form of /loc - self.call(building.CmdFind(), "Char2", "One Match", cmdstring="find") - self.call(building.CmdFind(), "/startswith Room2", "One Match") - - self.call(building.CmdFind(), self.char1.dbref, "Exact dbref match") - self.call(building.CmdFind(), "*TestAccount", "Match") - - self.call(building.CmdFind(), "/char Obj", "No Matches") - self.call(building.CmdFind(), "/room Obj", "No Matches") - self.call(building.CmdFind(), "/exit Obj", "No Matches") - self.call(building.CmdFind(), "/exact Obj", "One Match") - - # Test multitype filtering - with patch( - "evennia.commands.default.building.CHAR_TYPECLASS", - "evennia.objects.objects.DefaultCharacter", - ): - self.call(building.CmdFind(), "/char/room Obj", "No Matches") - self.call(building.CmdFind(), "/char/room/exit Char", "2 Matches") - self.call(building.CmdFind(), "/char/room/exit/startswith Cha", "2 Matches") - - # Test null search - self.call(building.CmdFind(), "=", "Usage: ") - - # Test bogus dbref range with no search term - self.call(building.CmdFind(), "= obj", "Invalid dbref range provided (not a number).") - self.call(building.CmdFind(), "= #1a", "Invalid dbref range provided (not a number).") - - # Test valid dbref ranges with no search term - id1 = self.obj1.id - id2 = self.obj2.id - maxid = ObjectDB.objects.latest("id").id - maxdiff = maxid - id1 + 1 - mdiff = id2 - id1 + 1 - - self.call(building.CmdFind(), f"=#{id1}", f"{maxdiff} Matches(#{id1}-#{maxid}") - self.call(building.CmdFind(), f"={id1}-{id2}", f"{mdiff} Matches(#{id1}-#{id2}):") - self.call(building.CmdFind(), f"={id1} - {id2}", f"{mdiff} Matches(#{id1}-#{id2}):") - self.call(building.CmdFind(), f"={id1}- #{id2}", f"{mdiff} Matches(#{id1}-#{id2}):") - self.call(building.CmdFind(), f"={id1}-#{id2}", f"{mdiff} Matches(#{id1}-#{id2}):") - self.call(building.CmdFind(), f"=#{id1}-{id2}", f"{mdiff} Matches(#{id1}-#{id2}):")
- -
[docs] def test_script(self): - self.call(building.CmdScripts(), "Obj", "No scripts defined on Obj") - self.call( - building.CmdScripts(), - "Obj = scripts.scripts.DefaultScript", - "Script scripts.scripts.DefaultScript successfully added" - ) - self.call( - building.CmdScripts(), - "evennia.Dummy", - "Global Script NOT Created " - ) - self.call( - building.CmdScripts(), - "evennia.scripts.scripts.DoNothing", - "Global Script Created - sys_do_nothing " - ) - self.call(building.CmdScripts(), "Obj ", "dbref ") - - self.call( - building.CmdScripts(), "/start Obj", "Script on Obj Started " - ) # we allow running start again; this should still happen - self.call(building.CmdScripts(), "/stop Obj", "Script on Obj Stopped - ") - - self.call( - building.CmdScripts(), "Obj = scripts.scripts.DefaultScript", - "Script scripts.scripts.DefaultScript successfully added", - inputs=["Y"] - ) - self.call( - building.CmdScripts(), - "/start Obj = scripts.scripts.DefaultScript", - "Script on Obj Started ", - inputs=["Y"] - ) - self.call( - building.CmdScripts(), - "/stop Obj = scripts.scripts.DefaultScript", - "Script on Obj Stopped ", - inputs=["Y"] - ) - self.call( - building.CmdScripts(), - "/delete Obj = scripts.scripts.DefaultScript", - "Script on Obj Deleted ", - inputs=["Y"] - ) - self.call( - building.CmdScripts(), - "/delete evennia.scripts.scripts.DoNothing", - "Global Script Deleted -" - )
- -
[docs] def test_script_multi_delete(self): - - script1 = create.create_script() - script2 = create.create_script() - script3 = create.create_script() - - self.call( - building.CmdScripts(), - "/delete #{}-#{}".format(script1.id, script3.id), - f"Global Script Deleted - #{script1.id} (evennia.scripts.scripts.DefaultScript)|" - f"Global Script Deleted - #{script2.id} (evennia.scripts.scripts.DefaultScript)|" - f"Global Script Deleted - #{script3.id} (evennia.scripts.scripts.DefaultScript)", - inputs=["y"] - ) - self.assertFalse(script1.pk) - self.assertFalse(script2.pk) - self.assertFalse(script3.pk)
- -
[docs] def test_teleport(self): - oid = self.obj1.id - rid = self.room1.id - rid2 = self.room2.id - self.call(building.CmdTeleport(), "", "Usage: ") - self.call(building.CmdTeleport(), "Obj = Room", "Obj is already at Room.") - self.call( - building.CmdTeleport(), - "Obj = NotFound", - "Could not find 'NotFound'.|Destination not found.", - ) - self.call( - building.CmdTeleport(), - "Obj = Room2", - "Obj(#{}) is leaving Room(#{}), heading for Room2(#{}).|Teleported Obj -> Room2.".format( - oid, rid, rid2 - ), - ) - self.call(building.CmdTeleport(), "NotFound = Room", "Could not find 'NotFound'.") - self.call( - building.CmdTeleport(), "Obj = Obj", "You can't teleport an object inside of itself!" - ) - - self.call(building.CmdTeleport(), "/tonone Obj2", "Teleported Obj2 -> None-location.") - self.call(building.CmdTeleport(), "/quiet Room2", "Room2(#{})".format(rid2)) - self.call( - building.CmdTeleport(), - "/t", # /t switch is abbreviated form of /tonone - "Cannot teleport a puppeted object (Char, puppeted by TestAccount", - ) - self.call( - building.CmdTeleport(), - "/l Room2", # /l switch is abbreviated form of /loc - "Destination has no location.", - ) - self.call( - building.CmdTeleport(), - "/q me to Room2", # /q switch is abbreviated form of /quiet - "Char is already at Room2.", - )
- -
[docs] def test_tag(self): - self.call(building.CmdTag(), "", "Usage: ") - - self.call(building.CmdTag(), "Obj = testtag") - self.call(building.CmdTag(), "Obj = testtag2") - self.call(building.CmdTag(), "Obj = testtag2:category1") - self.call(building.CmdTag(), "Obj = testtag3") - - self.call( - building.CmdTag(), - "Obj", - "Tags on Obj: 'testtag', 'testtag2', " "'testtag2' (category: category1), 'testtag3'", - ) - - self.call(building.CmdTag(), "/search NotFound", "No objects found with tag 'NotFound'.") - self.call(building.CmdTag(), "/search testtag", "Found 1 object with tag 'testtag':") - self.call(building.CmdTag(), "/search testtag2", "Found 1 object with tag 'testtag2':") - self.call( - building.CmdTag(), - "/search testtag2:category1", - "Found 1 object with tag 'testtag2' (category: 'category1'):", - ) - - self.call(building.CmdTag(), "/del Obj = testtag3", "Removed tag 'testtag3' from Obj.") - self.call( - building.CmdTag(), - "/del Obj", - "Cleared all tags from Obj: testtag, testtag2, testtag2 (category: category1)", - )
- -
[docs] def test_spawn(self): - def get_object(commandTest, obj_key): - # A helper function to get a spawned object and - # check that it exists in the process. - query = search_object(obj_key) - commandTest.assertIsNotNone(query) - commandTest.assertTrue(bool(query)) - obj = query[0] - commandTest.assertIsNotNone(obj) - return obj - - # Tests "spawn" without any arguments. - self.call(building.CmdSpawn(), " ", "Usage: spawn") - - # Tests "spawn <prototype_dictionary>" without specifying location. - - self.call( - building.CmdSpawn(), - "/save {'prototype_key': 'testprot', 'key':'Test Char', " - "'typeclass':'evennia.objects.objects.DefaultCharacter'}", - "Saved prototype: testprot", - inputs=["y"], - ) - - self.call( - building.CmdSpawn(), - "/save testprot2 = {'key':'Test Char', " - "'typeclass':'evennia.objects.objects.DefaultCharacter'}", - "(Replacing `prototype_key` in prototype with given key.)|Saved prototype: testprot2", - inputs=["y"], - ) - - self.call(building.CmdSpawn(), "/search ", "Key ") - self.call(building.CmdSpawn(), "/search test;test2", "No prototypes found.") - - self.call( - building.CmdSpawn(), - "/save {'key':'Test Char', " "'typeclass':'evennia.objects.objects.DefaultCharacter'}", - "A prototype_key must be given, either as `prototype_key = <prototype>` or as " - "a key 'prototype_key' inside the prototype structure.", - ) - - self.call(building.CmdSpawn(), "/list", "Key ") - self.call(building.CmdSpawn(), "testprot", "Spawned Test Char") - - # Tests that the spawned object's location is the same as the character's location, since - # we did not specify it. - testchar = get_object(self, "Test Char") - self.assertEqual(testchar.location, self.char1.location) - testchar.delete() - - # Test "spawn <prototype_dictionary>" with a location other than the character's. - spawnLoc = self.room2 - if spawnLoc == self.char1.location: - # Just to make sure we use a different location, in case someone changes - # char1's default location in the future... - spawnLoc = self.room1 - - self.call( - building.CmdSpawn(), - "{'prototype_key':'GOBLIN', 'typeclass':'evennia.objects.objects.DefaultCharacter', " - "'key':'goblin', 'location':'%s'}" % spawnLoc.dbref, - "Spawned goblin", - ) - goblin = get_object(self, "goblin") - # Tests that the spawned object's type is a DefaultCharacter. - self.assertIsInstance(goblin, DefaultCharacter) - self.assertEqual(goblin.location, spawnLoc) - - goblin.delete() - - # create prototype - protlib.create_prototype( - { - "key": "Ball", - "typeclass": "evennia.objects.objects.DefaultCharacter", - "prototype_key": "testball", - } - ) - - # Tests "spawn <prototype_name>" - self.call(building.CmdSpawn(), "testball", "Spawned Ball") - - ball = get_object(self, "Ball") - self.assertEqual(ball.location, self.char1.location) - self.assertIsInstance(ball, DefaultObject) - ball.delete() - - # Tests "spawn/n ..." without specifying a location. - # Location should be "None". - self.call( - building.CmdSpawn(), "/n 'BALL'", "Spawned Ball" - ) # /n switch is abbreviated form of /noloc - ball = get_object(self, "Ball") - self.assertIsNone(ball.location) - ball.delete() - - self.call( - building.CmdSpawn(), - "/noloc {'prototype_parent':'TESTBALL', 'prototype_key': 'testball', 'location':'%s'}" - % spawnLoc.dbref, - "Error: Prototype testball tries to parent itself.", - ) - - # Tests "spawn/noloc ...", but DO specify a location. - # Location should be the specified location. - self.call( - building.CmdSpawn(), - "/noloc {'prototype_parent':'TESTBALL', 'key': 'Ball', 'prototype_key': 'foo', 'location':'%s'}" - % spawnLoc.dbref, - "Spawned Ball", - ) - ball = get_object(self, "Ball") - self.assertEqual(ball.location, spawnLoc) - ball.delete() - - # test calling spawn with an invalid prototype. - self.call(building.CmdSpawn(), "'NO_EXIST'", "No prototype named 'NO_EXIST' was found.") - - # Test listing commands - self.call(building.CmdSpawn(), "/list", "Key ") - - # spawn/edit (missing prototype) - # brings up olc menu - msg = self.call(building.CmdSpawn(), "/edit") - assert "Prototype wizard" in msg - - # spawn/edit with valid prototype - # brings up olc menu loaded with prototype - msg = self.call(building.CmdSpawn(), "/edit testball") - assert "Prototype wizard" in msg - assert hasattr(self.char1.ndb._menutree, "olc_prototype") - assert ( - dict == type(self.char1.ndb._menutree.olc_prototype) - and "prototype_key" in self.char1.ndb._menutree.olc_prototype - and "key" in self.char1.ndb._menutree.olc_prototype - and "testball" == self.char1.ndb._menutree.olc_prototype["prototype_key"] - and "Ball" == self.char1.ndb._menutree.olc_prototype["key"] - ) - assert "Ball" in msg and "testball" in msg - - # spawn/edit with valid prototype (synomym) - msg = self.call(building.CmdSpawn(), "/edit BALL") - assert "Prototype wizard" in msg - assert "Ball" in msg and "testball" in msg - - # spawn/edit with invalid prototype - msg = self.call( - building.CmdSpawn(), "/edit NO_EXISTS", "No prototype named 'NO_EXISTS' was found." - ) - - # spawn/examine (missing prototype) - # lists all prototypes that exist - self.call(building.CmdSpawn(), "/examine", "You need to specify a prototype-key to show.") - - # spawn/examine with valid prototype - # prints the prototype - msg = self.call(building.CmdSpawn(), "/examine BALL") - assert "Ball" in msg and "testball" in msg - - # spawn/examine with invalid prototype - # shows error - self.call( - building.CmdSpawn(), "/examine NO_EXISTS", "No prototype named 'NO_EXISTS' was found." - )
- - -import evennia.commands.default.comms as cmd_comms # noqa -from evennia.utils.create import create_channel # noqa -from evennia.comms.comms import DefaultChannel # noqa - - -
[docs]@patch("evennia.commands.default.comms.CHANNEL_DEFAULT_TYPECLASS", DefaultChannel) -class TestCommsChannel(BaseEvenniaCommandTest): - """ - Test the central `channel` command. - - """ -
[docs] def setUp(self): - super().setUp() - self.channel = create_channel( - key="testchannel", - desc="A test channel") - self.channel.connect(self.char1) - self.cmdchannel = cmd_comms.CmdChannel - self.cmdchannel.account_caller = False
- -
[docs] def tearDown(self): - if self.channel.pk: - self.channel.delete()
- - # test channel command -
[docs] def test_channel__noarg(self): - self.call( - self.cmdchannel(), - "", - "Channel subscriptions" - )
- -
[docs] def test_channel__msg(self): - self.channel.msg = Mock() - self.call( - self.cmdchannel(), - "testchannel = Test message", - "" - ) - self.channel.msg.assert_called_with("Test message", senders=self.char1)
- -
[docs] def test_channel__list(self): - self.call( - self.cmdchannel(), - "/list", - "Channel subscriptions" - )
- -
[docs] def test_channel__all(self): - self.call( - self.cmdchannel(), - "/all", - "Available channels" - )
- -
[docs] def test_channel__history(self): - with patch("evennia.commands.default.comms.tail_log_file") as mock_tail: - self.call( - self.cmdchannel(), - "/history testchannel", - "" - ) - mock_tail.assert_called()
- -
[docs] def test_channel__sub(self): - self.channel.disconnect(self.char1) - - self.call( - self.cmdchannel(), - "/sub testchannel", - "You are now subscribed" - ) - self.assertTrue(self.char1 in self.channel.subscriptions.all()) - self.assertEqual(self.char1.nicks.nickreplace("testchannel Hello"), "channel testchannel = Hello")
- -
[docs] def test_channel__unsub(self): - self.call( - self.cmdchannel(), - "/unsub testchannel", - "You un-subscribed" - ) - self.assertFalse(self.char1 in self.channel.subscriptions.all())
- -
[docs] def test_channel__alias__unalias(self): - """Add and then remove a channel alias""" - - # add alias - self.call( - self.cmdchannel(), - "/alias testchannel = foo", - "Added/updated your alias 'foo' for channel testchannel." - ) - self.assertEqual( - self.char1.nicks.nickreplace('foo Hello'), "channel testchannel = Hello") - - # use alias - self.channel.msg = Mock() - self.call( - self.cmdchannel(), - "foo = test message", - "") - self.channel.msg.assert_called_with("test message", senders=self.char1) - - # remove alias - self.call( - self.cmdchannel(), - "/unalias foo", - "Removed your channel alias 'foo'" - ) - self.assertEqual(self.char1.nicks.get('foo $1', category="channel"), None)
- -
[docs] def test_channel__mute(self): - self.call( - self.cmdchannel(), - "/mute testchannel", - "Muted channel testchannel" - ) - self.assertTrue(self.char1 in self.channel.mutelist)
- -
[docs] def test_channel__unmute(self): - self.channel.mute(self.char1) - - self.call( - self.cmdchannel(), - "/unmute testchannel = Char1", - "Un-muted channel testchannel" - ) - self.assertFalse(self.char1 in self.channel.mutelist)
- -
[docs] def test_channel__create(self): - self.call( - self.cmdchannel(), - "/create testchannel2", - "Created (and joined) new channel" - )
- -
[docs] def test_channel__destroy(self): - self.channel.msg = Mock() - self.call( - self.cmdchannel(), - "/destroy testchannel = delete reason", - "Are you sure you want to delete channel ", - inputs=['Yes'] - ) - self.channel.msg.assert_called_with( - "delete reason", bypass_mute=True, senders=self.char1)
- -
[docs] def test_channel__desc(self): - self.call( - self.cmdchannel(), - "/desc testchannel = Another description", - "Updated channel description." - )
- -
[docs] def test_channel__lock(self): - self.call( - self.cmdchannel(), - "/lock testchannel = foo:false()", - "Added/updated lock on channel" - ) - self.assertEqual(self.channel.locks.get('foo'), 'foo:false()')
- -
[docs] def test_channel__unlock(self): - self.channel.locks.add("foo:true()") - self.call( - self.cmdchannel(), - "/unlock testchannel = foo", - "Removed lock from channel" - ) - self.assertEqual(self.channel.locks.get('foo'), '')
- -
[docs] def test_channel__boot(self): - self.channel.connect(self.char2) - self.assertTrue(self.char2 in self.channel.subscriptions.all()) - self.channel.msg = Mock() - self.char2.msg = Mock() - - self.call( - self.cmdchannel(), - "/boot testchannel = Char2 : Booting from channel!", - "Are you sure ", - inputs=["Yes"] - ) - self.channel.msg.assert_called_with( - "Char2 was booted from channel by Char. Reason: Booting from channel!") - self.char2.msg.assert_called_with( - "You were booted from channel testchannel by Char. Reason: Booting from channel!")
- -
[docs] def test_channel__ban__unban(self): - """Test first ban and then unban""" - - # ban - self.channel.connect(self.char2) - self.assertTrue(self.char2 in self.channel.subscriptions.all()) - self.channel.msg = Mock() - self.char2.msg = Mock() - - self.call( - self.cmdchannel(), - "/ban testchannel = Char2 : Banning from channel!", - "Are you sure ", - inputs=["Yes"] - ) - self.channel.msg.assert_called_with( - "Char2 was booted from channel by Char. Reason: Banning from channel!") - self.char2.msg.assert_called_with( - "You were booted from channel testchannel by Char. Reason: Banning from channel!") - self.assertTrue(self.char2 in self.channel.banlist) - - # unban - - self.call( - self.cmdchannel(), - "/unban testchannel = Char2", - "Un-banned Char2 from channel testchannel" - ) - self.assertFalse(self.char2 in self.channel.banlist)
- -
[docs] def test_channel__who(self): - self.call( - self.cmdchannel(), - "/who testchannel", - "Subscribed to testchannel:\nChar" - )
- - -from evennia.commands.default import comms # noqa - - -
[docs]class TestComms(BaseEvenniaCommandTest): - -
[docs] def test_page(self): - self.call( - comms.CmdPage(), - "TestAccount2 = Test", - "TestAccount2 is offline. They will see your message if they list their pages later." - "|You paged TestAccount2 with: 'Test'.", - receiver=self.account, - )
- - -
[docs]class TestBatchProcess(BaseEvenniaCommandTest): - """ - Test the batch processor. - - """ - # there is some sort of issue with the mock; it needs to loaded once to work - from evennia.contrib.tutorials.red_button import red_button # noqa - -
[docs] @patch("evennia.contrib.tutorials.red_button.red_button.repeat") - @patch("evennia.contrib.tutorials.red_button.red_button.delay") - def test_batch_commands(self, mock_tutorials, mock_repeat): - # cannot test batchcode here, it must run inside the server process - self.call( - batchprocess.CmdBatchCommands(), - "batchprocessor.example_batch_cmds", - "Running Batch-command processor - Automatic mode for batchprocessor.example_batch_cmds", - ) - # we make sure to delete the button again here to stop the running reactor - confirm = building.CmdDestroy.confirm - building.CmdDestroy.confirm = False - self.call(building.CmdDestroy(), "button", "button was destroyed.") - building.CmdDestroy.confirm = confirm - mock_repeat.assert_called()
- - -
[docs]class CmdInterrupt(Command): - - key = "interrupt" - -
[docs] def parse(self): - raise InterruptCommand
- -
[docs] def func(self): - self.msg("in func")
- - -
[docs]class TestInterruptCommand(BaseEvenniaCommandTest): -
[docs] def test_interrupt_command(self): - ret = self.call(CmdInterrupt(), "") - self.assertEqual(ret, "")
- - -
[docs]class TestUnconnectedCommand(BaseEvenniaCommandTest): -
[docs] def test_info_command(self): - # instead of using SERVER_START_TIME (0), we use 86400 because Windows won't let us use anything lower - gametime.SERVER_START_TIME = 86400 - expected = ( - "## BEGIN INFO 1.1\nName: %s\nUptime: %s\nConnected: %d\nVersion: Evennia %s\n## END INFO" - % ( - settings.SERVERNAME, - datetime.datetime.fromtimestamp(gametime.SERVER_START_TIME).ctime(), - SESSIONS.account_count(), - utils.get_evennia_version(), - ) - ) - self.call(unloggedin.CmdUnconnectedInfo(), "", expected) - del gametime.SERVER_START_TIME
- - -# Test syscommands - - -
[docs]class TestSystemCommands(BaseEvenniaCommandTest): -
[docs] def test_simple_defaults(self): - self.call(syscommands.SystemNoInput(), "") - self.call(syscommands.SystemNoMatch(), "Huh?")
- -
[docs] def test_multimatch(self): - # set up fake matches and store on command instance - cmdset = CmdSet() - cmdset.add(general.CmdLook()) - cmdset.add(general.CmdLook()) - matches = cmdparser.build_matches("look", cmdset) - - multimatch = syscommands.SystemMultimatch() - multimatch.matches = matches - - self.call(multimatch, "look", "")
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/commands/default/unloggedin.html b/docs/0.9.5/_modules/evennia/commands/default/unloggedin.html deleted file mode 100644 index 822e09c037..0000000000 --- a/docs/0.9.5/_modules/evennia/commands/default/unloggedin.html +++ /dev/null @@ -1,619 +0,0 @@ - - - - - - - - evennia.commands.default.unloggedin — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.commands.default.unloggedin

-"""
-Commands that are available from the connect screen.
-"""
-import re
-import datetime
-from codecs import lookup as codecs_lookup
-from django.conf import settings
-from evennia.comms.models import ChannelDB
-from evennia.server.sessionhandler import SESSIONS
-
-from evennia.utils import class_from_module, create, logger, utils, gametime
-from evennia.commands.cmdhandler import CMD_LOGINSTART
-
-COMMAND_DEFAULT_CLASS = utils.class_from_module(settings.COMMAND_DEFAULT_CLASS)
-
-# limit symbol import for API
-__all__ = (
-    "CmdUnconnectedConnect",
-    "CmdUnconnectedCreate",
-    "CmdUnconnectedQuit",
-    "CmdUnconnectedLook",
-    "CmdUnconnectedHelp",
-    "CmdUnconnectedEncoding",
-    "CmdUnconnectedInfo",
-    "CmdUnconnectedScreenreader",
-)
-
-MULTISESSION_MODE = settings.MULTISESSION_MODE
-CONNECTION_SCREEN_MODULE = settings.CONNECTION_SCREEN_MODULE
-
-
-def create_guest_account(session):
-    """
-    Creates a guest account/character for this session, if one is available.
-
-    Args:
-        session (Session): the session which will use the guest account/character.
-
-    Returns:
-        GUEST_ENABLED (boolean), account (Account):
-            the boolean is whether guest accounts are enabled at all.
-            the Account which was created from an available guest name.
-    """
-    enabled = settings.GUEST_ENABLED
-    address = session.address
-
-    # Get account class
-    Guest = class_from_module(settings.BASE_GUEST_TYPECLASS)
-
-    # Get an available guest account
-    # authenticate() handles its own throttling
-    account, errors = Guest.authenticate(ip=address)
-    if account:
-        return enabled, account
-    else:
-        session.msg("|R%s|n" % "\n".join(errors))
-        return enabled, None
-
-
-def create_normal_account(session, name, password):
-    """
-    Creates an account with the given name and password.
-
-    Args:
-        session (Session): the session which is requesting to create an account.
-        name (str): the name that the account wants to use for login.
-        password (str): the password desired by this account, for login.
-
-    Returns:
-        account (Account): the account which was created from the name and password.
-    """
-    # Get account class
-    Account = class_from_module(settings.BASE_ACCOUNT_TYPECLASS)
-
-    address = session.address
-
-    # Match account name and check password
-    # authenticate() handles all its own throttling
-    account, errors = Account.authenticate(
-        username=name, password=password, ip=address, session=session
-    )
-    if not account:
-        # No accountname or password match
-        session.msg("|R%s|n" % "\n".join(errors))
-        return None
-
-    return account
-
-
-
[docs]class CmdUnconnectedConnect(COMMAND_DEFAULT_CLASS): - """ - connect to the game - - Usage (at login screen): - connect accountname password - connect "account name" "pass word" - - Use the create command to first create an account before logging in. - - If you have spaces in your name, enclose it in double quotes. - """ - - key = "connect" - aliases = ["conn", "con", "co"] - locks = "cmd:all()" # not really needed - arg_regex = r"\s.*?|$" - -
[docs] def func(self): - """ - Uses the Django admin api. Note that unlogged-in commands - have a unique position in that their func() receives - a session object instead of a source_object like all - other types of logged-in commands (this is because - there is no object yet before the account has logged in) - """ - session = self.caller - address = session.address - - args = self.args - # extract double quote parts - parts = [part.strip() for part in re.split(r"\"", args) if part.strip()] - if len(parts) == 1: - # this was (hopefully) due to no double quotes being found, or a guest login - parts = parts[0].split(None, 1) - - # Guest login - if len(parts) == 1 and parts[0].lower() == "guest": - # Get Guest typeclass - Guest = class_from_module(settings.BASE_GUEST_TYPECLASS) - - account, errors = Guest.authenticate(ip=address) - if account: - session.sessionhandler.login(session, account) - return - else: - session.msg("|R%s|n" % "\n".join(errors)) - return - - if len(parts) != 2: - session.msg("\n\r Usage (without <>): connect <name> <password>") - return - - # Get account class - Account = class_from_module(settings.BASE_ACCOUNT_TYPECLASS) - - name, password = parts - account, errors = Account.authenticate( - username=name, password=password, ip=address, session=session - ) - if account: - session.sessionhandler.login(session, account) - else: - session.msg("|R%s|n" % "\n".join(errors))
- - -
[docs]class CmdUnconnectedCreate(COMMAND_DEFAULT_CLASS): - """ - create a new account account - - Usage (at login screen): - create <accountname> <password> - create "account name" "pass word" - - This creates a new account account. - - If you have spaces in your name, enclose it in double quotes. - """ - - key = "create" - aliases = ["cre", "cr"] - locks = "cmd:all()" - arg_regex = r"\s.*?|$" - -
[docs] def func(self): - """Do checks and create account""" - - session = self.caller - args = self.args.strip() - - address = session.address - - # Get account class - Account = class_from_module(settings.BASE_ACCOUNT_TYPECLASS) - - # extract double quoted parts - parts = [part.strip() for part in re.split(r"\"", args) if part.strip()] - if len(parts) == 1: - # this was (hopefully) due to no quotes being found - parts = parts[0].split(None, 1) - if len(parts) != 2: - string = ( - "\n Usage (without <>): create <name> <password>" - "\nIf <name> or <password> contains spaces, enclose it in double quotes." - ) - session.msg(string) - return - - username, password = parts - - # pre-normalize username so the user know what they get - non_normalized_username = username - username = Account.normalize_username(username) - if non_normalized_username != username: - session.msg("Note: your username was normalized to strip spaces and remove characters " - "that could be visually confusing.") - - # have the user verify their new account was what they intended - answer = yield(f"You want to create an account '{username}' with password '{password}'." - "\nIs this what you intended? [Y]/N?") - if answer.lower() in ('n', 'no'): - session.msg("Aborted. If your user name contains spaces, surround it by quotes.") - return - - # everything's ok. Create the new account account. - account, errors = Account.create( - username=username, password=password, ip=address, session=session - ) - if account: - # tell the caller everything went well. - string = "A new account '%s' was created. Welcome!" - if " " in username: - string += ( - "\n\nYou can now log in with the command 'connect \"%s\" <your password>'." - ) - else: - string += "\n\nYou can now log with the command 'connect %s <your password>'." - session.msg(string % (username, username)) - else: - session.msg("|R%s|n" % "\n".join(errors))
- - -
[docs]class CmdUnconnectedQuit(COMMAND_DEFAULT_CLASS): - """ - quit when in unlogged-in state - - Usage: - quit - - We maintain a different version of the quit command - here for unconnected accounts for the sake of simplicity. The logged in - version is a bit more complicated. - """ - - key = "quit" - aliases = ["q", "qu"] - locks = "cmd:all()" - -
[docs] def func(self): - """Simply close the connection.""" - session = self.caller - session.sessionhandler.disconnect(session, "Good bye! Disconnecting.")
- - -
[docs]class CmdUnconnectedLook(COMMAND_DEFAULT_CLASS): - """ - look when in unlogged-in state - - Usage: - look - - This is an unconnected version of the look command for simplicity. - - This is called by the server and kicks everything in gear. - All it does is display the connect screen. - """ - - key = CMD_LOGINSTART - aliases = ["look", "l"] - locks = "cmd:all()" - -
[docs] def func(self): - """Show the connect screen.""" - - callables = utils.callables_from_module(CONNECTION_SCREEN_MODULE) - if "connection_screen" in callables: - connection_screen = callables["connection_screen"]() - else: - connection_screen = utils.random_string_from_module(CONNECTION_SCREEN_MODULE) - if not connection_screen: - connection_screen = "No connection screen found. Please contact an admin." - self.caller.msg(connection_screen)
- - -
[docs]class CmdUnconnectedHelp(COMMAND_DEFAULT_CLASS): - """ - get help when in unconnected-in state - - Usage: - help - - This is an unconnected version of the help command, - for simplicity. It shows a pane of info. - """ - - key = "help" - aliases = ["h", "?"] - locks = "cmd:all()" - -
[docs] def func(self): - """Shows help""" - - string = """ -You are not yet logged into the game. Commands available at this point: - - |wcreate|n - create a new account - |wconnect|n - connect with an existing account - |wlook|n - re-show the connection screen - |whelp|n - show this help - |wencoding|n - change the text encoding to match your client - |wscreenreader|n - make the server more suitable for use with screen readers - |wquit|n - abort the connection - -First create an account e.g. with |wcreate Anna c67jHL8p|n -(If you have spaces in your name, use double quotes: |wcreate "Anna the Barbarian" c67jHL8p|n -Next you can connect to the game: |wconnect Anna c67jHL8p|n - -You can use the |wlook|n command if you want to see the connect screen again. - -""" - - if settings.STAFF_CONTACT_EMAIL: - string += "For support, please contact: %s" % settings.STAFF_CONTACT_EMAIL - self.caller.msg(string)
- - -
[docs]class CmdUnconnectedEncoding(COMMAND_DEFAULT_CLASS): - """ - set which text encoding to use in unconnected-in state - - Usage: - encoding/switches [<encoding>] - - Switches: - clear - clear your custom encoding - - - This sets the text encoding for communicating with Evennia. This is mostly - an issue only if you want to use non-ASCII characters (i.e. letters/symbols - not found in English). If you see that your characters look strange (or you - get encoding errors), you should use this command to set the server - encoding to be the same used in your client program. - - Common encodings are utf-8 (default), latin-1, ISO-8859-1 etc. - - If you don't submit an encoding, the current encoding will be displayed - instead. - """ - - key = "encoding" - aliases = "encode" - locks = "cmd:all()" - -
[docs] def func(self): - """ - Sets the encoding. - """ - - if self.session is None: - return - - sync = False - if "clear" in self.switches: - # remove customization - old_encoding = self.session.protocol_flags.get("ENCODING", None) - if old_encoding: - string = "Your custom text encoding ('%s') was cleared." % old_encoding - else: - string = "No custom encoding was set." - self.session.protocol_flags["ENCODING"] = "utf-8" - sync = True - elif not self.args: - # just list the encodings supported - pencoding = self.session.protocol_flags.get("ENCODING", None) - string = "" - if pencoding: - string += ( - "Default encoding: |g%s|n (change with |wencoding <encoding>|n)" % pencoding - ) - encodings = settings.ENCODINGS - if encodings: - string += ( - "\nServer's alternative encodings (tested in this order):\n |g%s|n" - % ", ".join(encodings) - ) - if not string: - string = "No encodings found." - else: - # change encoding - old_encoding = self.session.protocol_flags.get("ENCODING", None) - encoding = self.args - try: - codecs_lookup(encoding) - except LookupError: - string = ( - "|rThe encoding '|w%s|r' is invalid. Keeping the previous encoding '|w%s|r'.|n" - % (encoding, old_encoding) - ) - else: - self.session.protocol_flags["ENCODING"] = encoding - string = "Your custom text encoding was changed from '|w%s|n' to '|w%s|n'." % ( - old_encoding, - encoding, - ) - sync = True - if sync: - self.session.sessionhandler.session_portal_sync(self.session) - self.caller.msg(string.strip())
- - -
[docs]class CmdUnconnectedScreenreader(COMMAND_DEFAULT_CLASS): - """ - Activate screenreader mode. - - Usage: - screenreader - - Used to flip screenreader mode on and off before logging in (when - logged in, use option screenreader on). - """ - - key = "screenreader" - -
[docs] def func(self): - """Flips screenreader setting.""" - new_setting = not self.session.protocol_flags.get("SCREENREADER", False) - self.session.protocol_flags["SCREENREADER"] = new_setting - string = "Screenreader mode turned |w%s|n." % ("on" if new_setting else "off") - self.caller.msg(string) - self.session.sessionhandler.session_portal_sync(self.session)
- - -
[docs]class CmdUnconnectedInfo(COMMAND_DEFAULT_CLASS): - """ - Provides MUDINFO output, so that Evennia games can be added to Mudconnector - and Mudstats. Sadly, the MUDINFO specification seems to have dropped off the - face of the net, but it is still used by some crawlers. This implementation - was created by looking at the MUDINFO implementation in MUX2, TinyMUSH, Rhost, - and PennMUSH. - """ - - key = "info" - locks = "cmd:all()" - -
[docs] def func(self): - self.caller.msg( - "## BEGIN INFO 1.1\nName: %s\nUptime: %s\nConnected: %d\nVersion: Evennia %s\n## END INFO" - % ( - settings.SERVERNAME, - datetime.datetime.fromtimestamp(gametime.SERVER_START_TIME).ctime(), - SESSIONS.account_count(), - utils.get_evennia_version(), - ) - )
- - -def _create_account(session, accountname, password, permissions, typeclass=None, email=None): - """ - Helper function, creates an account of the specified typeclass. - """ - try: - new_account = create.create_account( - accountname, email, password, permissions=permissions, typeclass=typeclass - ) - - except Exception as e: - session.msg( - "There was an error creating the Account:\n%s\n If this problem persists, contact an admin." - % e - ) - logger.log_trace() - return False - - # This needs to be set so the engine knows this account is - # logging in for the first time. (so it knows to call the right - # hooks during login later) - new_account.db.FIRST_LOGIN = True - - # join the new account to the public channel - pchannel = ChannelDB.objects.get_channel(settings.DEFAULT_CHANNELS[0]["key"]) - if not pchannel or not pchannel.connect(new_account): - string = "New account '%s' could not connect to public channel!" % new_account.key - logger.log_err(string) - return new_account - - -def _create_character(session, new_account, typeclass, home, permissions): - """ - Helper function, creates a character based on an account's name. - This is meant for Guest and MULTISESSION_MODE < 2 situations. - """ - try: - new_character = create.create_object( - typeclass, key=new_account.key, home=home, permissions=permissions - ) - # set playable character list - new_account.db._playable_characters.append(new_character) - - # allow only the character itself and the account to puppet this character (and Developers). - new_character.locks.add( - "puppet:id(%i) or pid(%i) or perm(Developer) or pperm(Developer)" - % (new_character.id, new_account.id) - ) - - # If no description is set, set a default description - if not new_character.db.desc: - new_character.db.desc = "This is a character." - # We need to set this to have ic auto-connect to this character - new_account.db._last_puppet = new_character - except Exception as e: - session.msg( - "There was an error creating the Character:\n%s\n If this problem persists, contact an admin." - % e - ) - logger.log_trace() -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/comms/comms.html b/docs/0.9.5/_modules/evennia/comms/comms.html deleted file mode 100644 index 8b81a9175f..0000000000 --- a/docs/0.9.5/_modules/evennia/comms/comms.html +++ /dev/null @@ -1,960 +0,0 @@ - - - - - - - - evennia.comms.comms — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.comms.comms

-"""
-Base typeclass for in-game Channels.
-
-"""
-from django.contrib.contenttypes.models import ContentType
-from django.urls import reverse
-from django.utils.text import slugify
-
-from evennia.typeclasses.models import TypeclassBase
-from evennia.comms.models import ChannelDB
-from evennia.comms.managers import ChannelManager
-from evennia.utils import create, logger
-from evennia.utils.utils import make_iter
-
-
-
[docs]class DefaultChannel(ChannelDB, metaclass=TypeclassBase): - """ - This is the base class for all Channel Comms. Inherit from this to - create different types of communication channels. - - Class-level variables: - - `send_to_online_only` (bool, default True) - if set, will only try to - send to subscribers that are actually active. This is a useful optimization. - - `log_file` (str, default `"channel_{channelname}.log"`). This is the - log file to which the channel history will be saved. The `{channelname}` tag - will be replaced by the key of the Channel. If an Attribute 'log_file' - is set, this will be used instead. If this is None and no Attribute is found, - no history will be saved. - - `channel_prefix_string` (str, default `"[{channelname} ]"`) - this is used - as a simple template to get the channel prefix with `.channel_prefix()`. - - """ - - objects = ChannelManager() - - # channel configuration - - # only send to characters/accounts who has an active session (this is a - # good optimization since people can still recover history separately). - send_to_online_only = True - # store log in log file. `channel_key tag will be replace with key of channel. - # Will use log_file Attribute first, if given - log_file = "channel_{channelname}.log" - # which prefix to use when showing were a message is coming from. Set to - # None to disable and set this later. - channel_prefix_string = "[{channelname}] " - - # default nick-alias replacements (default using the 'channel' command) - channel_msg_nick_pattern = r"{alias}\s*?|{alias}\s+?(?P<arg1>.+?)" - channel_msg_nick_replacement = "channel {channelname} = $1" - -
[docs] def at_first_save(self): - """ - Called by the typeclass system the very first time the channel - is saved to the database. Generally, don't overload this but - the hooks called by this method. - - """ - self.basetype_setup() - self.at_channel_creation() - if hasattr(self, "_createdict"): - # this is only set if the channel was created - # with the utils.create.create_channel function. - cdict = self._createdict - if not cdict.get("key"): - if not self.db_key: - self.db_key = "#i" % self.dbid - elif cdict["key"] and self.key != cdict["key"]: - self.key = cdict["key"] - if cdict.get("aliases"): - self.aliases.add(cdict["aliases"]) - if cdict.get("locks"): - self.locks.add(cdict["locks"]) - if cdict.get("keep_log"): - self.attributes.add("keep_log", cdict["keep_log"]) - if cdict.get("desc"): - self.attributes.add("desc", cdict["desc"]) - if cdict.get("tags"): - self.tags.batch_add(*cdict["tags"])
- -
[docs] def basetype_setup(self): - self.locks.add("send:all();listen:all();control:perm(Admin)") - - # make sure we don't have access to a same-named old channel's history. - log_file = self.get_log_filename() - logger.rotate_log_file(log_file, num_lines_to_append=0)
- -
[docs] def at_channel_creation(self): - """ - Called once, when the channel is first created. - - """ - pass
- - # helper methods, for easy overloading - - _log_file = None - -
[docs] def get_log_filename(self): - """ - File name to use for channel log. - - Returns: - str: The filename to use (this is always assumed to be inside - settings.LOG_DIR) - - """ - if not self._log_file: - self._log_file = self.attributes.get( - "log_file", self.log_file.format(channelname=self.key.lower())) - return self._log_file
- -
[docs] def set_log_filename(self, filename): - """ - Set a custom log filename. - - Args: - filename (str): The filename to set. This is a path starting from - inside the settings.LOG_DIR location. - - """ - self.attributes.add("log_file", filename)
- -
[docs] def has_connection(self, subscriber): - """ - Checks so this account is actually listening - to this channel. - - Args: - subscriber (Account or Object): Entity to check. - - Returns: - has_sub (bool): Whether the subscriber is subscribing to - this channel or not. - - Notes: - This will first try Account subscribers and only try Object - if the Account fails. - - """ - has_sub = self.subscriptions.has(subscriber) - if not has_sub and hasattr(subscriber, "account"): - # it's common to send an Object when we - # by default only allow Accounts to subscribe. - has_sub = self.subscriptions.has(subscriber.account) - return has_sub
- - @property - def mutelist(self): - return self.db.mute_list or [] - - @property - def banlist(self): - return self.db.ban_list or [] - - @property - def wholist(self): - subs = self.subscriptions.all() - muted = list(self.mutelist) - listening = [ob for ob in subs if ob.is_connected and ob not in muted] - if subs: - # display listening subscribers in bold - string = ", ".join( - [ - account.key if account not in listening else "|w%s|n" % account.key - for account in subs - ] - ) - else: - string = "<None>" - return string - -
[docs] def mute(self, subscriber, **kwargs): - """ - Adds an entity to the list of muted subscribers. - A muted subscriber will no longer see channel messages, - but may use channel commands. - - Args: - subscriber (Object or Account): Subscriber to mute. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Returns: - bool: True if muting was successful, False if we were already - muted. - - """ - mutelist = self.mutelist - if subscriber not in mutelist: - mutelist.append(subscriber) - self.db.mute_list = mutelist - return True - return False
- -
[docs] def unmute(self, subscriber, **kwargs): - """ - Removes an entity from the list of muted subscribers. A muted subscriber - will no longer see channel messages, but may use channel commands. - - Args: - subscriber (Object or Account): The subscriber to unmute. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Returns: - bool: True if unmuting was successful, False if we were already - unmuted. - - """ - mutelist = self.mutelist - if subscriber in mutelist: - mutelist.remove(subscriber) - return True - return False
- -
[docs] def ban(self, target, **kwargs): - """ - Ban a given user from connecting to the channel. This will not stop - users already connected, so the user must be booted for this to take - effect. - - Args: - target (Object or Account): The entity to unmute. This need not - be a subscriber. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Returns: - bool: True if banning was successful, False if target was already - banned. - """ - banlist = self.banlist - if target not in banlist: - banlist.append(target) - self.db.ban_list = banlist - return True - return False
- -
[docs] def unban(self, target, **kwargs): - """ - Un-Ban a given user. This will not reconnect them - they will still - have to reconnect and set up aliases anew. - - Args: - target (Object or Account): The entity to unmute. This need not - be a subscriber. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Returns: - bool: True if unbanning was successful, False if target was not - previously banned. - """ - banlist = list(self.banlist) - if target in banlist: - banlist = [banned for banned in banlist if banned != target] - self.db.ban_list = banlist - return True - return False
- -
[docs] def connect(self, subscriber, **kwargs): - """ - Connect the user to this channel. This checks access. - - Args: - subscriber (Account or Object): the entity to subscribe - to this channel. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Returns: - success (bool): Whether or not the addition was - successful. - - """ - # check access - if subscriber in self.banlist or not self.access(subscriber, "listen"): - return False - # pre-join hook - connect = self.pre_join_channel(subscriber) - if not connect: - return False - # subscribe - self.subscriptions.add(subscriber) - # unmute - self.unmute(subscriber) - # post-join hook - self.post_join_channel(subscriber) - return True
- -
[docs] def disconnect(self, subscriber, **kwargs): - """ - Disconnect entity from this channel. - - Args: - subscriber (Account of Object): the - entity to disconnect. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Returns: - success (bool): Whether or not the removal was - successful. - - """ - # pre-disconnect hook - disconnect = self.pre_leave_channel(subscriber) - if not disconnect: - return False - # disconnect - self.subscriptions.remove(subscriber) - # unmute - self.unmute(subscriber) - # post-disconnect hook - self.post_leave_channel(subscriber) - return True
- -
[docs] def access( - self, - accessing_obj, - access_type="listen", - default=False, - no_superuser_bypass=False, - **kwargs, - ): - """ - Determines if another object has permission to access. - - Args: - accessing_obj (Object): Object trying to access this one. - access_type (str, optional): Type of access sought. - default (bool, optional): What to return if no lock of access_type was found - no_superuser_bypass (bool, optional): Turns off superuser - lock bypass. Be careful with this one. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Returns: - return (bool): Result of lock check. - - """ - return self.locks.check( - accessing_obj, - access_type=access_type, - default=default, - no_superuser_bypass=no_superuser_bypass, - )
- -
[docs] @classmethod - def create(cls, key, creator=None, *args, **kwargs): - """ - Creates a basic Channel with default parameters, unless otherwise - specified or extended. - - Provides a friendlier interface to the utils.create_channel() function. - - Args: - key (str): This must be unique. - creator (Account or Object): Entity to associate with this channel - (used for tracking) - - Keyword Args: - aliases (list of str): List of alternative (likely shorter) keynames. - description (str): A description of the channel, for use in listings. - locks (str): Lockstring. - keep_log (bool): Log channel throughput. - typeclass (str or class): The typeclass of the Channel (not - often used). - ip (str): IP address of creator (for object auditing). - - Returns: - channel (Channel): A newly created Channel. - errors (list): A list of errors in string form, if any. - - """ - errors = [] - obj = None - ip = kwargs.pop("ip", "") - - try: - kwargs["desc"] = kwargs.pop("description", "") - kwargs["typeclass"] = kwargs.get("typeclass", cls) - obj = create.create_channel(key, *args, **kwargs) - - # Record creator id and creation IP - if ip: - obj.db.creator_ip = ip - if creator: - obj.db.creator_id = creator.id - - except Exception as exc: - errors.append("An error occurred while creating this '%s' object." % key) - logger.log_err(exc) - - return obj, errors
- -
[docs] def delete(self): - """ - Deletes channel. - - Returns: - bool: If deletion was successful. Only time it can fail would be - if channel was already deleted. Even if it were to fail, all subscribers - will be disconnected. - - """ - self.attributes.clear() - self.aliases.clear() - for subscriber in self.subscriptions.all(): - self.disconnect(subscriber) - if not self.pk: - return False - super().delete() - return True
- -
[docs] def channel_prefix(self): - """ - Hook method. How the channel should prefix itself for users. - - Returns: - str: The channel prefix. - - """ - return self.channel_prefix_string.format(channelname=self.key)
- -
[docs] def add_user_channel_alias(self, user, alias, **kwargs): - """ - Add a personal user-alias for this channel to a given subscriber. - - Args: - user (Object or Account): The one to alias this channel. - alias (str): The desired alias. - - Note: - This is tightly coupled to the default `channel` command. If you - change that, you need to change this as well. - - We add two nicks - one is a plain `alias -> channel.key` that - users need to be able to reference this channel easily. The other - is a templated nick to easily be able to send messages to the - channel without needing to give the full `channel` command. The - structure of this nick is given by `self.channel_msg_nick_pattern` - and `self.channel_msg_nick_replacement`. By default it maps - `alias <msg> -> channel <channelname> = <msg>`, so that you can - for example just write `pub Hello` to send a message. - - The alias created is `alias $1 -> channel channel = $1`, to allow - for sending to channel using the main channel command. - - """ - chan_key = self.key.lower() - - # the message-pattern allows us to type the channel on its own without - # needing to use the `channel` command explicitly. - msg_nick_pattern = self.channel_msg_nick_pattern.format(alias=alias) - msg_nick_replacement = self.channel_msg_nick_replacement.format(channelname=chan_key) - user.nicks.add(msg_nick_pattern, msg_nick_replacement, category="inputline", - pattern_is_regex=True, **kwargs) - - if chan_key != alias: - # this allows for using the alias for general channel lookups - user.nicks.add(alias, chan_key, category="channel", **kwargs)
- -
[docs] @classmethod - def remove_user_channel_alias(cls, user, alias, **kwargs): - """ - Remove a personal channel alias from a user. - - Args: - user (Object or Account): The user to remove an alias from. - alias (str): The alias to remove. - **kwargs: Unused by default. Can be used to pass extra variables - into a custom implementation. - - Notes: - The channel-alias actually consists of two aliases - one - channel-based one for searching channels with the alias and one - inputline one for doing the 'channelalias msg' - call. - - This is a classmethod because it doesn't actually operate on the - channel instance. - - It sits on the channel because the nick structure for this is - pretty complex and needs to be located in a central place (rather - on, say, the channel command). - - """ - user.nicks.remove(alias, category="channel", **kwargs) - msg_nick_pattern = cls.channel_msg_nick_pattern.format(alias=alias) - user.nicks.remove(msg_nick_pattern, category="inputline", **kwargs)
- -
[docs] def at_pre_msg(self, message, **kwargs): - """ - Called before the starting of sending the message to a receiver. This - is called before any hooks on the receiver itself. If this returns - None/False, the sending will be aborted. - - Args: - message (str): The message to send. - **kwargs (any): Keywords passed on from `.msg`. This includes - `senders`. - - Returns: - str, False or None: Any custom changes made to the message. If - falsy, no message will be sent. - - """ - return message
- -
[docs] def msg(self, message, senders=None, bypass_mute=False, **kwargs): - """ - Send message to channel, causing it to be distributed to all non-muted - subscribed users of that channel. - - Args: - message (str): The message to send. - senders (Object, Account or list, optional): If not given, there is - no way to associate one or more senders with the message (like - a broadcast message or similar). - bypass_mute (bool, optional): If set, always send, regardless of - individual mute-state of subscriber. This can be used for - global announcements or warnings/alerts. - **kwargs (any): This will be passed on to all hooks. Use `no_prefix` - to exclude the channel prefix. - - Notes: - The call hook calling sequence is: - - - `msg = channel.at_pre_msg(message, **kwargs)` (aborts for all if return None) - - `msg = receiver.at_pre_channel_msg(msg, channel, **kwargs)` (aborts for receiver if return None) - - `receiver.at_channel_msg(msg, channel, **kwargs)` - - `receiver.at_post_channel_msg(msg, channel, **kwargs)`` - Called after all receivers are processed: - - `channel.at_post_all_msg(message, **kwargs)` - - (where the senders/bypass_mute are embedded into **kwargs for - later access in hooks) - - """ - senders = make_iter(senders) if senders else [] - if self.send_to_online_only: - receivers = self.subscriptions.online() - else: - receivers = self.subscriptions.all() - if not bypass_mute: - receivers = [receiver for receiver in receivers if receiver not in self.mutelist] - - send_kwargs = {'senders': senders, 'bypass_mute': bypass_mute, **kwargs} - - # pre-send hook - message = self.at_pre_msg(message, **send_kwargs) - if message in (None, False): - return - - for receiver in receivers: - # send to each individual subscriber - - try: - recv_message = receiver.at_pre_channel_msg(message, self, **send_kwargs) - if recv_message in (None, False): - return - - receiver.channel_msg(recv_message, self, **send_kwargs) - - receiver.at_post_channel_msg(recv_message, self, **send_kwargs) - - except Exception: - logger.log_trace(f"Error sending channel message to {receiver}.") - - # post-send hook - self.at_post_msg(message, **send_kwargs)
- -
[docs] def at_post_msg(self, message, **kwargs): - """ - This is called after sending to *all* valid recipients. It is normally - used for logging/channel history. - - Args: - message (str): The message sent. - **kwargs (any): Keywords passed on from `msg`, including `senders`. - - """ - # save channel history to log file - log_file = self.get_log_filename() - if log_file: - senders = ",".join(sender.key for sender in kwargs.get("senders", [])) - senders = f"{senders}: " if senders else "" - message = f"{senders}{message}" - logger.log_file(message, log_file)
- -
[docs] def pre_join_channel(self, joiner, **kwargs): - """ - Hook method. Runs right before a channel is joined. If this - returns a false value, channel joining is aborted. - - Args: - joiner (object): The joining object. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Returns: - should_join (bool): If `False`, channel joining is aborted. - - """ - return True
- -
[docs] def post_join_channel(self, joiner, **kwargs): - """ - Hook method. Runs right after an object or account joins a channel. - - Args: - joiner (object): The joining object. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Notes: - By default this adds the needed channel nicks to the joiner. - - """ - key_and_aliases = [self.key.lower()] + [alias.lower() for alias in self.aliases.all()] - for key_or_alias in key_and_aliases: - self.add_user_channel_alias(joiner, key_or_alias, **kwargs)
- -
[docs] def pre_leave_channel(self, leaver, **kwargs): - """ - Hook method. Runs right before a user leaves a channel. If this returns a false - value, leaving the channel will be aborted. - - Args: - leaver (object): The leaving object. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Returns: - should_leave (bool): If `False`, channel parting is aborted. - - """ - return True
- -
[docs] def post_leave_channel(self, leaver, **kwargs): - """ - Hook method. Runs right after an object or account leaves a channel. - - Args: - leaver (object): The leaving object. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - """ - chan_key = self.key.lower() - key_or_aliases = [self.key.lower()] + [alias.lower() for alias in self.aliases.all()] - nicktuples = leaver.nicks.get(category="channel", return_tuple=True, return_list=True) - key_or_aliases += [tup[2] for tup in nicktuples if tup[3].lower() == chan_key] - for key_or_alias in key_or_aliases: - self.remove_user_channel_alias(leaver, key_or_alias, **kwargs)
- -
[docs] def at_init(self): - """ - Hook method. This is always called whenever this channel is - initiated -- that is, whenever it its typeclass is cached from - memory. This happens on-demand first time the channel is used - or activated in some way after being created but also after - each server restart or reload. - - """ - pass
- - # - # Web/Django methods - # - -
[docs] def web_get_admin_url(self): - """ - Returns the URI path for the Django Admin page for this object. - - ex. Account#1 = '/admin/accounts/accountdb/1/change/' - - Returns: - path (str): URI path to Django Admin page for object. - - """ - content_type = ContentType.objects.get_for_model(self.__class__) - return reverse( - "admin:%s_%s_change" % (content_type.app_label, content_type.model), args=(self.id,) - )
- -
[docs] @classmethod - def web_get_create_url(cls): - """ - Returns the URI path for a View that allows users to create new - instances of this object. - - ex. Chargen = '/characters/create/' - - For this to work, the developer must have defined a named view somewhere - in urls.py that follows the format 'modelname-action', so in this case - a named view of 'channel-create' would be referenced by this method. - - ex. - url(r'channels/create/', ChannelCreateView.as_view(), name='channel-create') - - If no View has been created and defined in urls.py, returns an - HTML anchor. - - This method is naive and simply returns a path. Securing access to - the actual view and limiting who can create new objects is the - developer's responsibility. - - Returns: - path (str): URI path to object creation page, if defined. - - """ - try: - return reverse("%s-create" % slugify(cls._meta.verbose_name)) - except Exception: - return "#"
- -
[docs] def web_get_detail_url(self): - """ - Returns the URI path for a View that allows users to view details for - this object. - - ex. Oscar (Character) = '/characters/oscar/1/' - - For this to work, the developer must have defined a named view somewhere - in urls.py that follows the format 'modelname-action', so in this case - a named view of 'channel-detail' would be referenced by this method. - - ex. - :: - - url(r'channels/(?P<slug>[\w\d\-]+)/$', - ChannelDetailView.as_view(), name='channel-detail') - - If no View has been created and defined in urls.py, returns an - HTML anchor. - - This method is naive and simply returns a path. Securing access to - the actual view and limiting who can view this object is the developer's - responsibility. - - Returns: - path (str): URI path to object detail page, if defined. - - """ - try: - return reverse( - "%s-detail" % slugify(self._meta.verbose_name), - kwargs={"slug": slugify(self.db_key)}, - ) - except Exception: - return "#"
- -
[docs] def web_get_update_url(self): - """ - Returns the URI path for a View that allows users to update this - object. - - ex. Oscar (Character) = '/characters/oscar/1/change/' - - For this to work, the developer must have defined a named view somewhere - in urls.py that follows the format 'modelname-action', so in this case - a named view of 'channel-update' would be referenced by this method. - - ex. - :: - - url(r'channels/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$', - ChannelUpdateView.as_view(), name='channel-update') - - If no View has been created and defined in urls.py, returns an - HTML anchor. - - This method is naive and simply returns a path. Securing access to - the actual view and limiting who can modify objects is the developer's - responsibility. - - Returns: - path (str): URI path to object update page, if defined. - - """ - try: - return reverse( - "%s-update" % slugify(self._meta.verbose_name), - kwargs={"slug": slugify(self.db_key)}, - ) - except Exception: - return "#"
- -
[docs] def web_get_delete_url(self): - """ - Returns the URI path for a View that allows users to delete this object. - - ex. Oscar (Character) = '/characters/oscar/1/delete/' - - For this to work, the developer must have defined a named view somewhere - in urls.py that follows the format 'modelname-action', so in this case - a named view of 'channel-delete' would be referenced by this method. - - ex. - url(r'channels/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/delete/$', - ChannelDeleteView.as_view(), name='channel-delete') - - If no View has been created and defined in urls.py, returns an - HTML anchor. - - This method is naive and simply returns a path. Securing access to - the actual view and limiting who can delete this object is the developer's - responsibility. - - Returns: - path (str): URI path to object deletion page, if defined. - - """ - try: - return reverse( - "%s-delete" % slugify(self._meta.verbose_name), - kwargs={"slug": slugify(self.db_key)}, - ) - except Exception: - return "#"
- - # Used by Django Sites/Admin - get_absolute_url = web_get_detail_url - - # TODO Evennia 1.0+ removed hooks. Remove in 1.1. -
[docs] def message_transform(self, *args, **kwargs): - raise RuntimeError("Channel.message_transform is no longer used in 1.0+. " - "Use Account/Object.at_pre_channel_msg instead.")
- -
[docs] def distribute_message(self, msgobj, online=False, **kwargs): - raise RuntimeError("Channel.distribute_message is no longer used in 1.0+.")
- -
[docs] def format_senders(self, senders=None, **kwargs): - raise RuntimeError("Channel.format_senders is no longer used in 1.0+. " - "Use Account/Object.at_pre_channel_msg instead.")
- -
[docs] def pose_transform(self, msgobj, sender_string, **kwargs): - raise RuntimeError("Channel.pose_transform is no longer used in 1.0+. " - "Use Account/Object.at_pre_channel_msg instead.")
- -
[docs] def format_external(self, msgobj, senders, emit=False, **kwargs): - raise RuntimeError("Channel.format_external is no longer used in 1.0+. " - "Use Account/Object.at_pre_channel_msg instead.")
- -
[docs] def format_message(self, msgobj, emit=False, **kwargs): - raise RuntimeError("Channel.format_message is no longer used in 1.0+. " - "Use Account/Object.at_pre_channel_msg instead.")
- -
[docs] def pre_send_message(self, msg, **kwargs): - raise RuntimeError("Channel.pre_send_message was renamed to Channel.at_pre_msg.")
- -
[docs] def post_send_message(self, msg, **kwargs): - raise RuntimeError("Channel.post_send_message was renamed to Channel.at_post_msg.")
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/comms/managers.html b/docs/0.9.5/_modules/evennia/comms/managers.html deleted file mode 100644 index 029240d36e..0000000000 --- a/docs/0.9.5/_modules/evennia/comms/managers.html +++ /dev/null @@ -1,609 +0,0 @@ - - - - - - - - evennia.comms.managers — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.comms.managers

-"""
-These managers define helper methods for accessing the database from
-Comm system components.
-
-"""
-
-
-from django.conf import settings
-from django.db.models import Q
-from evennia.typeclasses.managers import TypedObjectManager, TypeclassManager
-from evennia.server import signals
-from evennia.utils import logger
-from evennia.utils.utils import dbref, make_iter, class_from_module
-
-_GA = object.__getattribute__
-_AccountDB = None
-_ObjectDB = None
-_ChannelDB = None
-_ScriptDB = None
-_SESSIONS = None
-
-# error class
-
-
-
[docs]class CommError(Exception): - """ - Raised by comm system, to allow feedback to player when caught. - """ - - pass
- - -# -# helper functions -# - - -
[docs]def identify_object(inp): - """ - Helper function. Identifies if an object is an account or an object; - return its database model - - Args: - inp (any): Entity to be idtified. - - Returns: - identified (tuple): This is a tuple with (`inp`, identifier) - where `identifier` is one of "account", "object", "channel", - "string", "dbref" or None. - - """ - if hasattr(inp, "__dbclass__"): - clsname = inp.__dbclass__.__name__ - if clsname == "AccountDB": - return inp, "account" - elif clsname == "ObjectDB": - return inp, "object" - elif clsname == "ChannelDB": - return inp, "channel" - elif clsname == "ScriptDB": - return inp, "script" - if isinstance(inp, str): - return inp, "string" - elif dbref(inp): - return dbref(inp), "dbref" - else: - return inp, None
- - -
[docs]def to_object(inp, objtype="account"): - """ - Locates the object related to the given accountname or channel key. - If input was already the correct object, return it. - - Args: - inp (any): The input object/string - objtype (str): Either 'account' or 'channel'. - - Returns: - obj (object): The correct object related to `inp`. - - """ - obj, typ = identify_object(inp) - if typ == objtype: - return obj - if objtype == "account": - if typ == "object": - return obj.account - if typ == "string": - return _AccountDB.objects.get(user_username__iexact=obj) - if typ == "dbref": - return _AccountDB.objects.get(id=obj) - logger.log_err("%s %s %s %s %s" % (objtype, inp, obj, typ, type(inp))) - raise CommError() - elif objtype == "object": - if typ == "account": - return obj.obj - if typ == "string": - return _ObjectDB.objects.get(db_key__iexact=obj) - if typ == "dbref": - return _ObjectDB.objects.get(id=obj) - logger.log_err("%s %s %s %s %s" % (objtype, inp, obj, typ, type(inp))) - raise CommError() - elif objtype == "channel": - if typ == "string": - return _ChannelDB.objects.get(db_key__iexact=obj) - if typ == "dbref": - return _ChannelDB.objects.get(id=obj) - logger.log_err("%s %s %s %s %s" % (objtype, inp, obj, typ, type(inp))) - raise CommError() - elif objtype == "script": - if typ == "string": - return _ScriptDB.objects.get(db_key__iexact=obj) - if typ == "dbref": - return _ScriptDB.objects.get(id=obj) - logger.log_err("%s %s %s %s %s" % (objtype, inp, obj, typ, type(inp))) - raise CommError() - - # an unknown - return None
- - -# -# Msg manager -# - - -
[docs]class MsgManager(TypedObjectManager): - """ - This MsgManager implements methods for searching and manipulating - Messages directly from the database. - - These methods will all return database objects (or QuerySets) - directly. - - A Message represents one unit of communication, be it over a - Channel or via some form of in-game mail system. Like an e-mail, - it always has a sender and can have any number of receivers (some - of which may be Channels). - - """ - -
[docs] def identify_object(self, inp): - """ - Wrapper to identify_object if accessing via the manager directly. - - Args: - inp (any): Entity to be idtified. - - Returns: - identified (tuple): This is a tuple with (`inp`, identifier) - where `identifier` is one of "account", "object", "channel", - "string", "dbref" or None. - - """ - return identify_object(inp)
- -
[docs] def get_message_by_id(self, idnum): - """ - Retrieve message by its id. - - Args: - idnum (int or str): The dbref to retrieve. - - Returns: - message (Msg): The message. - - """ - try: - return self.get(id=self.dbref(idnum, reqhash=False)) - except Exception: - return None
- -
[docs] def get_messages_by_sender(self, sender): - """ - Get all messages sent by one entity - this could be either a - account or an object - - Args: - sender (Account or Object): The sender of the message. - - Returns: - QuerySet: Matching messages. - - Raises: - CommError: For incorrect sender types. - - """ - obj, typ = identify_object(sender) - if typ == "account": - return self.filter(db_sender_accounts=obj).exclude(db_hide_from_accounts=obj) - elif typ == "object": - return self.filter(db_sender_objects=obj).exclude(db_hide_from_objects=obj) - elif typ == "script": - return self.filter(db_sender_scripts=obj) - else: - raise CommError
- -
[docs] def get_messages_by_receiver(self, recipient): - """ - Get all messages sent to one given recipient. - - Args: - recipient (Object, Account or Channel): The recipient of the messages to search for. - - Returns: - Queryset: Matching messages. - - Raises: - CommError: If the `recipient` is not of a valid type. - - """ - obj, typ = identify_object(recipient) - if typ == "account": - return self.filter(db_receivers_accounts=obj).exclude(db_hide_from_accounts=obj) - elif typ == "object": - return self.filter(db_receivers_objects=obj).exclude(db_hide_from_objects=obj) - elif typ == 'script': - return self.filter(db_receivers_scripts=obj) - else: - raise CommError
- -
[docs] def search_message(self, sender=None, receiver=None, freetext=None, dbref=None): - """ - Search the message database for particular messages. At least - one of the arguments must be given to do a search. - - Args: - sender (Object, Account or Script, optional): Get messages sent by a particular sender. - receiver (Object, Account or Channel, optional): Get messages - received by a certain account,object or channel - freetext (str): Search for a text string in a message. NOTE: - This can potentially be slow, so make sure to supply one of - the other arguments to limit the search. - dbref (int): The exact database id of the message. This will override - all other search criteria since it's unique and - always gives only one match. - - Returns: - Queryset: Iterable with 0, 1 or more matches. - - """ - # unique msg id - if dbref: - return self.objects.filter(id=dbref) - - # We use Q objects to gradually build up the query - this way we only - # need to do one database lookup at the end rather than gradually - # refining with multiple filter:s. Django Note: Q objects can be - # combined with & and | (=AND,OR). ~ negates the queryset - - # filter by sender (we need __pk to avoid an error with empty Q() objects) - sender, styp = identify_object(sender) - if sender: - spk = sender.pk - if styp == "account": - sender_restrict = Q(db_sender_accounts__pk=spk) & ~Q(db_hide_from_accounts__pk=spk) - elif styp == "object": - sender_restrict = Q(db_sender_objects__pk=spk) & ~Q(db_hide_from_objects__pk=spk) - elif styp == 'script': - sender_restrict = Q(db_sender_scripts__pk=spk) - else: - sender_restrict = Q() - # filter by receiver - receiver, rtyp = identify_object(receiver) - if receiver: - rpk = receiver.pk - if rtyp == "account": - receiver_restrict = ( - Q(db_receivers_accounts__pk=rpk) & ~Q(db_hide_from_accounts__pk=rpk)) - elif rtyp == "object": - receiver_restrict = Q(db_receivers_objects__pk=rpk) & ~Q(db_hide_from_objects__pk=rpk) - elif rtyp == 'script': - receiver_restrict = Q(db_receivers_scripts__pk=rpk) - elif rtyp == "channel": - raise DeprecationWarning( - "Msg.objects.search don't accept channel recipients since " - "Channels no longer accepts Msg objects.") - else: - receiver_restrict = Q() - # filter by full text - if freetext: - fulltext_restrict = Q(db_header__icontains=freetext) | Q(db_message__icontains=freetext) - else: - fulltext_restrict = Q() - # execute the query - return self.filter(sender_restrict & receiver_restrict & fulltext_restrict)
- - # back-compatibility alias - message_search = search_message - -
[docs] def create_message(self, senderobj, message, receivers=None, locks=None, tags=None, - header=None, **kwargs): - """ - Create a new communication Msg. Msgs represent a unit of - database-persistent communication between entites. - - Args: - senderobj (Object, Account, Script, str or list): The entity (or - entities) sending the Msg. If a `str`, this is the id-string - for an external sender type. - message (str): Text with the message. Eventual headers, titles - etc should all be included in this text string. Formatting - will be retained. - receivers (Object, Account, Script, str or list): An Account/Object to send - to, or a list of them. If a string, it's an identifier for an external - receiver. - locks (str): Lock definition string. - tags (list): A list of tags or tuples `(tag, category)`. - header (str): Mime-type or other optional information for the message - - Notes: - The Comm system is created to be very open-ended, so it's fully - possible to let a message both go several receivers at the same time, - it's up to the command definitions to limit this as desired. - - """ - if 'channels' in kwargs: - raise DeprecationWarning( - "create_message() does not accept 'channel' kwarg anymore " - "- channels no longer accept Msg objects." - ) - - if not message: - # we don't allow empty messages. - return None - new_message = self.model(db_message=message) - new_message.save() - for sender in make_iter(senderobj): - new_message.senders = sender - new_message.header = header - for receiver in make_iter(receivers): - new_message.receivers = receiver - if locks: - new_message.locks.add(locks) - if tags: - new_message.tags.batch_add(*tags) - - new_message.save() - return new_message
- -# -# Channel manager -# - - -
[docs]class ChannelDBManager(TypedObjectManager): - """ - This ChannelManager implements methods for searching and - manipulating Channels directly from the database. - - These methods will all return database objects (or QuerySets) - directly. - - A Channel is an in-game venue for communication. It's essentially - representation of a re-sender: Users sends Messages to the - Channel, and the Channel re-sends those messages to all users - subscribed to the Channel. - - """ - -
[docs] def get_all_channels(self): - """ - Get all channels. - - Returns: - channels (list): All channels in game. - - """ - return self.all()
- -
[docs] def get_channel(self, channelkey): - """ - Return the channel object if given its key. - Also searches its aliases. - - Args: - channelkey (str): Channel key to search for. - - Returns: - channel (Channel or None): A channel match. - - """ - dbref = self.dbref(channelkey) - if dbref: - try: - return self.get(id=dbref) - except self.model.DoesNotExist: - pass - results = self.filter( - Q(db_key__iexact=channelkey) - | Q(db_tags__db_tagtype__iexact="alias", db_tags__db_key__iexact=channelkey) - ).distinct() - return results[0] if results else None
- -
[docs] def get_subscriptions(self, subscriber): - """ - Return all channels a given entity is subscribed to. - - Args: - subscriber (Object or Account): The one subscribing. - - Returns: - subscriptions (list): Channel subscribed to. - - """ - clsname = subscriber.__dbclass__.__name__ - if clsname == "AccountDB": - return subscriber.account_subscription_set.all() - if clsname == "ObjectDB": - return subscriber.object_subscription_set.all() - return []
- -
[docs] def search_channel(self, ostring, exact=True): - """ - Search the channel database for a particular channel. - - Args: - ostring (str): The key or database id of the channel. - exact (bool, optional): Require an exact (but not - case sensitive) match. - - Returns: - Queryset: Iterable with 0, 1 or more matches. - - """ - dbref = self.dbref(ostring) - if dbref: - dbref_match = self.search_dbref(dbref) - if dbref_match: - return dbref_match - - if exact: - channels = self.filter( - Q(db_key__iexact=ostring) - | Q(db_tags__db_tagtype__iexact="alias", db_tags__db_key__iexact=ostring) - ).distinct() - else: - channels = self.filter( - Q(db_key__icontains=ostring) - | Q(db_tags__db_tagtype__iexact="alias", db_tags__db_key__icontains=ostring) - ).distinct() - return channels
- -
[docs] def create_channel( - self, key, aliases=None, desc=None, locks=None, keep_log=True, typeclass=None, tags=None - ): - """ - Create A communication Channel. A Channel serves as a central hub - for distributing Msgs to groups of people without specifying the - receivers explicitly. Instead accounts may 'connect' to the channel - and follow the flow of messages. By default the channel allows - access to all old messages, but this can be turned off with the - keep_log switch. - - Args: - key (str): This must be unique. - - Keyword Args: - aliases (list of str): List of alternative (likely shorter) keynames. - desc (str): A description of the channel, for use in listings. - locks (str): Lockstring. - keep_log (bool): Log channel throughput. - typeclass (str or class): The typeclass of the Channel (not - often used). - tags (list): A list of tags or tuples `(tag, category)`. - - Returns: - channel (Channel): A newly created channel. - - """ - typeclass = typeclass if typeclass else settings.BASE_CHANNEL_TYPECLASS - - if isinstance(typeclass, str): - # a path is given. Load the actual typeclass - typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS) - - # create new instance - new_channel = typeclass(db_key=key) - - # store call signature for the signal - new_channel._createdict = dict( - key=key, aliases=aliases, desc=desc, locks=locks, keep_log=keep_log, tags=tags - ) - - # this will trigger the save signal which in turn calls the - # at_first_save hook on the typeclass, where the _createdict can be - # used. - new_channel.save() - - signals.SIGNAL_CHANNEL_POST_CREATE.send(sender=new_channel) - - return new_channel
- - # back-compatibility alias - channel_search = search_channel
- - -
[docs]class ChannelManager(ChannelDBManager, TypeclassManager): - """ - Wrapper to group the typeclass manager to a consistent name. - """ - - pass
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/comms/models.html b/docs/0.9.5/_modules/evennia/comms/models.html deleted file mode 100644 index 5957c40c91..0000000000 --- a/docs/0.9.5/_modules/evennia/comms/models.html +++ /dev/null @@ -1,818 +0,0 @@ - - - - - - - - evennia.comms.models — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.comms.models

-"""
-Models for the in-game communication system.
-
-The comm system could take the form of channels, but can also be
-adopted for storing tells or in-game mail.
-
-The comsystem's main component is the Message (Msg), which carries the
-actual information between two parties.  Msgs are stored in the
-database and usually not deleted.  A Msg always have one sender (a
-user), but can have any number targets, both users and channels.
-
-For non-persistent (and slightly faster) use one can also use the
-TempMsg, which mimics the Msg API but without actually saving to the
-database.
-
-Channels are central objects that act as targets for Msgs. Accounts can
-connect to channels by use of a ChannelConnect object (this object is
-necessary to easily be able to delete connections on the fly).
-
-"""
-from django.conf import settings
-from django.utils import timezone
-from django.db import models
-from evennia.typeclasses.models import TypedObject
-from evennia.typeclasses.tags import Tag, TagHandler
-from evennia.utils.idmapper.models import SharedMemoryModel
-from evennia.comms import managers
-from evennia.locks.lockhandler import LockHandler
-from evennia.utils.utils import crop, make_iter, lazy_property
-
-__all__ = ("Msg", "TempMsg", "ChannelDB", "SubscriptionHandler")
-
-
-_GA = object.__getattribute__
-_SA = object.__setattr__
-_DA = object.__delattr__
-
-
-# ------------------------------------------------------------
-#
-# Msg
-#
-# ------------------------------------------------------------
-
-
-
[docs]class Msg(SharedMemoryModel): - """ - A single message. This model describes all ooc messages - sent in-game, both to channels and between accounts. - - The Msg class defines the following database fields (all - accessed via specific handler methods): - - - db_sender_accounts: Account senders - - db_sender_objects: Object senders - - db_sender_scripts: Script senders - - db_sender_external: External sender (defined as string name) - - db_receivers_accounts: Receiving accounts - - db_receivers_objects: Receiving objects - - db_receivers_scripts: Receiveing scripts - - db_receiver_external: External sender (defined as string name) - - db_header: Header text - - db_message: The actual message text - - db_date_created: time message was created / sent - - db_hide_from_sender: bool if message should be hidden from sender - - db_hide_from_receivers: list of receiver objects to hide message from - - db_lock_storage: Internal storage of lock strings. - - """ - - # - # Msg database model setup - # - # - # These databse fields are all set using their corresponding properties, - # named same as the field, but withtout the db_* prefix. - - db_sender_accounts = models.ManyToManyField( - "accounts.AccountDB", - related_name="sender_account_set", - blank=True, - verbose_name="Senders (Accounts)", - db_index=True, - ) - - db_sender_objects = models.ManyToManyField( - "objects.ObjectDB", - related_name="sender_object_set", - blank=True, - verbose_name="Senders (Objects)", - db_index=True, - ) - db_sender_scripts = models.ManyToManyField( - "scripts.ScriptDB", - related_name="sender_script_set", - blank=True, - verbose_name="Senders (Scripts)", - db_index=True, - ) - db_sender_external = models.CharField( - "external sender", - max_length=255, - null=True, - blank=True, - db_index=True, - help_text="Identifier for single external sender, for use with senders " - "not represented by a regular database model." - ) - - db_receivers_accounts = models.ManyToManyField( - "accounts.AccountDB", - related_name="receiver_account_set", - blank=True, - verbose_name="Receivers (Accounts)", - help_text="account receivers", - ) - - db_receivers_objects = models.ManyToManyField( - "objects.ObjectDB", - related_name="receiver_object_set", - blank=True, - verbose_name="Receivers (Objects)", - help_text="object receivers", - ) - db_receivers_scripts = models.ManyToManyField( - "scripts.ScriptDB", - related_name="receiver_script_set", - blank=True, - verbose_name="Receivers (Scripts)", - help_text="script_receivers", - ) - - db_receiver_external = models.CharField( - "external receiver", - max_length=1024, - null=True, - blank=True, - db_index=True, - help_text="Identifier for single external receiver, for use with recievers " - "not represented by a regular database model." - ) - - # header could be used for meta-info about the message if your system needs - # it, or as a separate store for the mail subject line maybe. - db_header = models.TextField("header", null=True, blank=True) - # the message body itself - db_message = models.TextField("message") - # send date - db_date_created = models.DateTimeField( - "date sent", editable=False, auto_now_add=True, db_index=True - ) - # lock storage - db_lock_storage = models.TextField( - "locks", blank=True, help_text="access locks on this message." - ) - - # these can be used to filter/hide a given message from supplied objects/accounts - db_hide_from_accounts = models.ManyToManyField( - "accounts.AccountDB", related_name="hide_from_accounts_set", blank=True - ) - - db_hide_from_objects = models.ManyToManyField( - "objects.ObjectDB", related_name="hide_from_objects_set", blank=True - ) - - db_tags = models.ManyToManyField( - Tag, - blank=True, - help_text="tags on this message. Tags are simple string markers to " - "identify, group and alias messages.", - ) - - # Database manager - objects = managers.MsgManager() - _is_deleted = False - - class Meta(object): - "Define Django meta options" - verbose_name = "Msg" - -
[docs] @lazy_property - def locks(self): - return LockHandler(self)
- -
[docs] @lazy_property - def tags(self): - return TagHandler(self)
- - # Wrapper properties to easily set database fields. These are - # @property decorators that allows to access these fields using - # normal python operations (without having to remember to save() - # etc). So e.g. a property 'attr' has a get/set/del decorator - # defined that allows the user to do self.attr = value, - # value = self.attr and del self.attr respectively (where self - # is the object in question). - - @property - def senders(self): - "Getter. Allows for value = self.senders" - return ( - list(self.db_sender_accounts.all()) - + list(self.db_sender_objects.all()) - + list(self.db_sender_scripts.all()) - + ([self.db_sender_external] if self.db_sender_external else []) - ) - - @senders.setter - def senders(self, senders): - "Setter. Allows for self.sender = value" - - if isinstance(senders, str): - self.db_sender_external = senders - self.save(update_fields=["db_sender_external"]) - return - - for sender in make_iter(senders): - if not sender: - continue - if not hasattr(sender, "__dbclass__"): - raise ValueError("This is a not a typeclassed object!") - clsname = sender.__dbclass__.__name__ - if clsname == "ObjectDB": - self.db_sender_objects.add(sender) - elif clsname == "AccountDB": - self.db_sender_accounts.add(sender) - elif clsname == "ScriptDB": - self.db_sender_scripts.add(sender) - - @senders.deleter - def senders(self): - "Deleter. Clears all senders" - self.db_sender_accounts.clear() - self.db_sender_objects.clear() - self.db_sender_scripts.clear() - self.db_sender_external = "" - self.save() - -
[docs] def remove_sender(self, senders): - """ - Remove a single sender or a list of senders. - - Args: - senders (Account, Object, str or list): Senders to remove. - If a string, removes the external sender. - - """ - if isinstance(senders, str): - self.db_sender_external = "" - self.save(update_fields=["db_sender_external"]) - return - - for sender in make_iter(senders): - if not sender: - continue - if not hasattr(sender, "__dbclass__"): - raise ValueError("This is a not a typeclassed object!") - clsname = sender.__dbclass__.__name__ - if clsname == "ObjectDB": - self.db_sender_objects.remove(sender) - elif clsname == "AccountDB": - self.db_sender_accounts.remove(sender) - elif clsname == "ScriptDB": - self.db_sender_accounts.remove(sender)
- - @property - def receivers(self): - """ - Getter. Allows for value = self.receivers. - Returns four lists of receivers: accounts, objects, scripts and - external_receivers. - - """ - return ( - list(self.db_receivers_accounts.all()) - + list(self.db_receivers_objects.all()) - + list(self.db_receivers_scripts.all()) - + ([self.db_receiver_external] if self.db_receiver_external else []) - ) - - @receivers.setter - def receivers(self, receivers): - """ - Setter. Allows for self.receivers = value. This appends a new receiver - to the message. If a string, replaces an external receiver. - - """ - if isinstance(receivers, str): - self.db_receiver_external = receivers - self.save(update_fields=['db_receiver_external']) - return - - for receiver in make_iter(receivers): - if not receiver: - continue - if not hasattr(receiver, "__dbclass__"): - raise ValueError("This is a not a typeclassed object!") - clsname = receiver.__dbclass__.__name__ - if clsname == "ObjectDB": - self.db_receivers_objects.add(receiver) - elif clsname == "AccountDB": - self.db_receivers_accounts.add(receiver) - elif clsname == "ScriptDB": - self.db_receivers_scripts.add(receiver) - - @receivers.deleter - def receivers(self): - "Deleter. Clears all receivers" - self.db_receivers_accounts.clear() - self.db_receivers_objects.clear() - self.db_receivers_scripts.clear() - self.db_receiver_external = "" - self.save() - -
[docs] def remove_receiver(self, receivers): - """ - Remove a single receiver, a list of receivers, or a single extral receiver. - - Args: - receivers (Account, Object, Script, list or str): Receiver - to remove. A string removes the external receiver. - - """ - if isinstance(receivers, str): - self.db_receiver_external = "" - self.save(update_fields="db_receiver_external") - return - - for receiver in make_iter(receivers): - if not receiver: - continue - elif not hasattr(receiver, "__dbclass__"): - raise ValueError("This is a not a typeclassed object!") - clsname = receiver.__dbclass__.__name__ - if clsname == "ObjectDB": - self.db_receivers_objects.remove(receiver) - elif clsname == "AccountDB": - self.db_receivers_accounts.remove(receiver) - elif clsname == "ScriptDB": - self.db_receivers_scripts.remove(receiver)
- - @property - def hide_from(self): - """ - Getter. Allows for value = self.hide_from. - Returns two lists of accounts and objects. - - """ - return ( - self.db_hide_from_accounts.all(), - self.db_hide_from_objects.all(), - ) - - @hide_from.setter - def hide_from(self, hiders): - """ - Setter. Allows for self.hide_from = value. Will append to hiders. - - """ - for hider in make_iter(hiders): - if not hider: - continue - if not hasattr(hider, "__dbclass__"): - raise ValueError("This is a not a typeclassed object!") - clsname = hider.__dbclass__.__name__ - if clsname == "AccountDB": - self.db_hide_from_accounts.add(hider.__dbclass__) - elif clsname == "ObjectDB": - self.db_hide_from_objects.add(hider.__dbclass__) - - @hide_from.deleter - def hide_from(self): - """ - Deleter. Allows for del self.hide_from_senders - - """ - self.db_hide_from_accounts.clear() - self.db_hide_from_objects.clear() - self.save() - - # - # Msg class methods - # - - def __str__(self): - """ - This handles what is shown when e.g. printing the message. - - """ - senders = ",".join(getattr(obj, "key", str(obj)) for obj in self.senders) - receivers = ",".join(getattr(obj, "key", str(obj)) for obj in self.receivers) - return "%s->%s: %s" % (senders, receivers, crop(self.message, width=40)) - -
[docs] def access(self, accessing_obj, access_type="read", default=False): - """ - Checks lock access. - - Args: - accessing_obj (Object or Account): The object trying to gain access. - access_type (str, optional): The type of lock access to check. - default (bool): Fallback to use if `access_type` lock is not defined. - - Returns: - result (bool): If access was granted or not. - - """ - return self.locks.check(accessing_obj, access_type=access_type, default=default)
- - -# ------------------------------------------------------------ -# -# TempMsg -# -# ------------------------------------------------------------ - - -
[docs]class TempMsg: - """ - This is a non-persistent object for sending temporary messages that will not be stored. It - mimics the "real" Msg object, but doesn't require sender to be given. - - """ - -
[docs] def __init__( - self, - senders=None, - receivers=None, - message="", - header="", - type="", - lockstring="", - hide_from=None, - ): - """ - Creates the temp message. - - Args: - senders (any or list, optional): Senders of the message. - receivers (Account, Object, Script or list, optional): Receivers of this message. - message (str, optional): Message to send. - header (str, optional): Header of message. - type (str, optional): Message class, if any. - lockstring (str, optional): Lock for the message. - hide_from (Account, Object, or list, optional): Entities to hide this message from. - - """ - self.senders = senders and make_iter(senders) or [] - self.receivers = receivers and make_iter(receivers) or [] - self.type = type - self.header = header - self.message = message - self.lock_storage = lockstring - self.hide_from = hide_from and make_iter(hide_from) or [] - self.date_created = timezone.now()
- -
[docs] @lazy_property - def locks(self): - return LockHandler(self)
- - def __str__(self): - """ - This handles what is shown when e.g. printing the message. - - """ - senders = ",".join(obj.key for obj in self.senders) - receivers = ",".join(obj.key for obj in self.receivers) - return "%s->%s: %s" % (senders, receivers, crop(self.message, width=40)) - -
[docs] def remove_sender(self, sender): - """ - Remove a sender or a list of senders. - - Args: - sender (Object, Account, str or list): Senders to remove. - - """ - for o in make_iter(sender): - try: - self.senders.remove(o) - except ValueError: - pass # nothing to remove
- -
[docs] def remove_receiver(self, receiver): - """ - Remove a receiver or a list of receivers - - Args: - receiver (Object, Account, Script, str or list): Receivers to remove. - - """ - - for o in make_iter(receiver): - try: - self.senders.remove(o) - except ValueError: - pass # nothing to remove
- -
[docs] def access(self, accessing_obj, access_type="read", default=False): - """ - Checks lock access. - - Args: - accessing_obj (Object or Account): The object trying to gain access. - access_type (str, optional): The type of lock access to check. - default (bool): Fallback to use if `access_type` lock is not defined. - - Returns: - result (bool): If access was granted or not. - - """ - return self.locks.check(accessing_obj, access_type=access_type, default=default)
- - -# ------------------------------------------------------------ -# -# Channel -# -# ------------------------------------------------------------ - - -
[docs]class SubscriptionHandler(object): - """ - This handler manages subscriptions to the - channel and hides away which type of entity is - subscribing (Account or Object) - - """ - -
[docs] def __init__(self, obj): - """ - Initialize the handler - - Attr: - obj (ChannelDB): The channel the handler sits on. - - """ - self.obj = obj - self._cache = None
- - def _recache(self): - self._cache = { - account: True - for account in self.obj.db_account_subscriptions.all() - if hasattr(account, "pk") and account.pk - } - self._cache.update( - { - obj: True - for obj in self.obj.db_object_subscriptions.all() - if hasattr(obj, "pk") and obj.pk - } - ) - -
[docs] def has(self, entity): - """ - Check if the given entity subscribe to this channel - - Args: - entity (str, Account or Object): The entity to return. If - a string, it assumed to be the key or the #dbref - of the entity. - - Returns: - subscriber (Account, Object or None): The given - subscriber. - - """ - if self._cache is None: - self._recache() - return entity in self._cache
- -
[docs] def add(self, entity): - """ - Subscribe an entity to this channel. - - Args: - entity (Account, Object or list): The entity or - list of entities to subscribe to this channel. - - Note: - No access-checking is done here, this must have - been done before calling this method. Also - no hooks will be called. - - """ - for subscriber in make_iter(entity): - if subscriber: - clsname = subscriber.__dbclass__.__name__ - # chooses the right type - if clsname == "ObjectDB": - self.obj.db_object_subscriptions.add(subscriber) - elif clsname == "AccountDB": - self.obj.db_account_subscriptions.add(subscriber) - self._recache()
- -
[docs] def remove(self, entity): - """ - Remove a subscriber from the channel. - - Args: - entity (Account, Object or list): The entity or - entities to un-subscribe from the channel. - - """ - for subscriber in make_iter(entity): - if subscriber: - clsname = subscriber.__dbclass__.__name__ - # chooses the right type - if clsname == "AccountDB": - self.obj.db_account_subscriptions.remove(entity) - elif clsname == "ObjectDB": - self.obj.db_object_subscriptions.remove(entity) - self._recache()
- -
[docs] def all(self): - """ - Get all subscriptions to this channel. - - Returns: - subscribers (list): The subscribers. This - may be a mix of Accounts and Objects! - - """ - if self._cache is None: - self._recache() - return self._cache
- - get = all # alias - -
[docs] def online(self): - """ - Get all online accounts from our cache - Returns: - subscribers (list): Subscribers who are online or - are puppeted by an online account. - """ - subs = [] - recache_needed = False - for obj in self.all(): - from django.core.exceptions import ObjectDoesNotExist - - try: - if hasattr(obj, "account") and obj.account: - obj = obj.account - if not obj.is_connected: - continue - except ObjectDoesNotExist: - # a subscribed object has already been deleted. Mark that we need a recache and - # ignore it - recache_needed = True - continue - subs.append(obj) - if recache_needed: - self._recache() - return subs
- -
[docs] def clear(self): - """ - Remove all subscribers from channel. - - """ - self.obj.db_account_subscriptions.clear() - self.obj.db_object_subscriptions.clear() - self._cache = None
- - -
[docs]class ChannelDB(TypedObject): - """ - This is the basis of a comm channel, only implementing - the very basics of distributing messages. - - The Channel class defines the following database fields - beyond the ones inherited from TypedObject: - - - db_account_subscriptions: The Account subscriptions. - - db_object_subscriptions: The Object subscriptions. - - """ - - db_account_subscriptions = models.ManyToManyField( - "accounts.AccountDB", - related_name="account_subscription_set", - blank=True, - verbose_name="account subscriptions", - db_index=True, - ) - - db_object_subscriptions = models.ManyToManyField( - "objects.ObjectDB", - related_name="object_subscription_set", - blank=True, - verbose_name="object subscriptions", - db_index=True, - ) - - # Database manager - objects = managers.ChannelDBManager() - - __settingclasspath__ = settings.BASE_CHANNEL_TYPECLASS - __defaultclasspath__ = "evennia.comms.comms.DefaultChannel" - __applabel__ = "comms" - - class Meta: - "Define Django meta options" - verbose_name = "Channel" - verbose_name_plural = "Channels" - - def __str__(self): - "Echoes the text representation of the channel." - return "Channel '%s' (%s)" % (self.key, self.db.desc) - -
[docs] @lazy_property - def subscriptions(self): - return SubscriptionHandler(self)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/help/manager.html b/docs/0.9.5/_modules/evennia/help/manager.html deleted file mode 100644 index e448f62e81..0000000000 --- a/docs/0.9.5/_modules/evennia/help/manager.html +++ /dev/null @@ -1,305 +0,0 @@ - - - - - - - - evennia.help.manager — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.help.manager

-"""
-Custom manager for HelpEntry objects.
-"""
-from django.db import IntegrityError
-from evennia.utils import logger, utils
-from evennia.typeclasses.managers import TypedObjectManager
-from evennia.utils.utils import make_iter
-from evennia.server import signals
-
-__all__ = ("HelpEntryManager",)
-
-
-
[docs]class HelpEntryManager(TypedObjectManager): - """ - This HelpEntryManager implements methods for searching - and manipulating HelpEntries directly from the database. - - These methods will all return database objects - (or QuerySets) directly. - - Evennia-specific: - find_topicmatch - find_apropos - find_topicsuggestions - find_topics_with_category - all_to_category - search_help (equivalent to evennia.search_helpentry) - - """ - -
[docs] def find_topicmatch(self, topicstr, exact=False): - """ - Searches for matching topics or aliases based on player's - input. - - Args: - topcistr (str): Help topic to search for. - exact (bool, optional): Require exact match - (non-case-sensitive). If `False` (default), match - sub-parts of the string. - - Returns: - matches (HelpEntries): Query results. - - """ - dbref = utils.dbref(topicstr) - if dbref: - return self.filter(id=dbref) - topics = self.filter(db_key__iexact=topicstr) - if not topics: - topics = self.get_by_alias(topicstr) - if not topics and not exact: - topics = self.filter(db_key__istartswith=topicstr) - if not topics: - topics = self.filter(db_key__icontains=topicstr) - return topics
- -
[docs] def find_apropos(self, topicstr): - """ - Do a very loose search, returning all help entries containing - the search criterion in their titles. - - Args: - topicstr (str): Search criterion. - - Returns: - matches (HelpEntries): Query results. - - """ - return self.filter(db_key__icontains=topicstr)
- -
[docs] def find_topicsuggestions(self, topicstr): - """ - Do a fuzzy match, preferably within the category of the - current topic. - - Args: - topicstr (str): Search criterion. - - Returns: - matches (Helpentries): Query results. - - """ - return self.filter(db_key__icontains=topicstr).exclude(db_key__iexact=topicstr)
- -
[docs] def find_topics_with_category(self, help_category): - """ - Search topics having a particular category. - - Args: - help_category (str): Category query criterion. - - Returns: - matches (HelpEntries): Query results. - - """ - return self.filter(db_help_category__iexact=help_category)
- -
[docs] def get_all_topics(self): - """ - Get all topics. - - Returns: - all (HelpEntries): All topics. - - """ - return self.all()
- -
[docs] def get_all_categories(self): - """ - Return all defined category names with at least one topic in - them. - - Returns: - matches (list): Unique list of category names across all - topics. - - """ - return list(set(topic.help_category for topic in self.all()))
- -
[docs] def all_to_category(self, default_category): - """ - Shifts all help entries in database to default_category. This - action cannot be reverted. It is used primarily by the engine - when importing a default help database, making sure this ends - up in one easily separated category. - - Args: - default_category (str): Category to move entries to. - - """ - topics = self.all() - for topic in topics: - topic.help_category = default_category - topic.save() - string = "Help database moved to category {default_category}".format( - default_category=default_category - ) - logger.log_info(string)
- -
[docs] def search_help(self, ostring, help_category=None): - """ - Retrieve a search entry object. - - Args: - ostring (str): The help topic to look for. - category (str): Limit the search to a particular help topic - - Returns: - Queryset: An iterable with 0, 1 or more matches. - - """ - ostring = ostring.strip().lower() - if help_category: - return self.filter(db_key__iexact=ostring, db_help_category__iexact=help_category) - else: - return self.filter(db_key__iexact=ostring)
- -
[docs] def create_help(self, key, entrytext, category="General", locks=None, aliases=None, tags=None): - """ - Create a static help entry in the help database. Note that Command - help entries are dynamic and directly taken from the __doc__ - entries of the command. The database-stored help entries are - intended for more general help on the game, more extensive info, - in-game setting information and so on. - - Args: - key (str): The name of the help entry. - entrytext (str): The body of te help entry - category (str, optional): The help category of the entry. - locks (str, optional): A lockstring to restrict access. - aliases (list of str, optional): List of alternative (likely shorter) keynames. - tags (lst, optional): List of tags or tuples `(tag, category)`. - - Returns: - help (HelpEntry): A newly created help entry. - - """ - try: - new_help = self.model() - new_help.key = key - new_help.entrytext = entrytext - new_help.help_category = category - if locks: - new_help.locks.add(locks) - if aliases: - new_help.aliases.add(make_iter(aliases)) - if tags: - new_help.tags.batch_add(*tags) - new_help.save() - return new_help - except IntegrityError: - string = "Could not add help entry: key '%s' already exists." % key - logger.log_err(string) - return None - except Exception: - logger.log_trace() - return None - - signals.SIGNAL_HELPENTRY_POST_CREATE.send(sender=new_help)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/help/models.html b/docs/0.9.5/_modules/evennia/help/models.html deleted file mode 100644 index 56df215eaa..0000000000 --- a/docs/0.9.5/_modules/evennia/help/models.html +++ /dev/null @@ -1,413 +0,0 @@ - - - - - - - - evennia.help.models — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.help.models

-"""
-Models for the help system.
-
-The database-tied help system is only half of Evennia's help
-functionality, the other one being the auto-generated command help
-that is created on the fly from each command's `__doc__` string. The
-persistent database system defined here is intended for all other
-forms of help that do not concern commands, like information about the
-game world, policy info, rules and similar.
-
-"""
-from django.contrib.contenttypes.models import ContentType
-from django.db import models
-from django.urls import reverse
-from django.utils.text import slugify
-
-from evennia.utils.idmapper.models import SharedMemoryModel
-from evennia.help.manager import HelpEntryManager
-from evennia.typeclasses.models import Tag, TagHandler, AliasHandler
-from evennia.locks.lockhandler import LockHandler
-from evennia.utils.utils import lazy_property
-
-__all__ = ("HelpEntry",)
-
-
-# ------------------------------------------------------------
-#
-# HelpEntry
-#
-# ------------------------------------------------------------
-
-
-
[docs]class HelpEntry(SharedMemoryModel): - """ - A generic help entry. - - An HelpEntry object has the following properties defined: - key - main name of entry - help_category - which category entry belongs to (defaults to General) - entrytext - the actual help text - permissions - perm strings - - Method: - access - - """ - - # - # HelpEntry Database Model setup - # - # - # These database fields are all set using their corresponding properties, - # named same as the field, but withtout the db_* prefix. - - # title of the help entry - db_key = models.CharField( - "help key", max_length=255, unique=True, help_text="key to search for" - ) - - # help category - db_help_category = models.CharField( - "help category", - max_length=255, - default="General", - help_text="organizes help entries in lists", - ) - - # the actual help entry text, in any formatting. - db_entrytext = models.TextField( - "help entry", blank=True, help_text="the main body of help text" - ) - # lock string storage - db_lock_storage = models.TextField("locks", blank=True, help_text="normally view:all().") - # tags are primarily used for permissions - db_tags = models.ManyToManyField( - Tag, - blank=True, - help_text="tags on this object. Tags are simple string markers to " - "identify, group and alias objects.", - ) - # Creation date. This is not changed once the object is created. - db_date_created = models.DateTimeField("creation date", editable=False, auto_now=True) - - # Database manager - objects = HelpEntryManager() - _is_deleted = False - - # lazy-loaded handlers - -
[docs] @lazy_property - def locks(self): - return LockHandler(self)
- -
[docs] @lazy_property - def tags(self): - return TagHandler(self)
- -
[docs] @lazy_property - def aliases(self): - return AliasHandler(self)
- - class Meta: - "Define Django meta options" - verbose_name = "Help Entry" - verbose_name_plural = "Help Entries" - - # - # - # HelpEntry main class methods - # - # - def __str__(self): - return str(self.key) - - def __repr__(self): - return f"<HelpEntry {self.key}>" - -
[docs] def access(self, accessing_obj, access_type="read", default=True): - """ - Determines if another object has permission to access this help entry. - - Accesses used by default: - 'read' - read the help entry itself. - 'view' - see help entry in help index. - - Args: - accessing_obj (Object or Account): Entity trying to access this one. - access_type (str): type of access sought. - default (bool): What to return if no lock of `access_type` was found. - - """ - return self.locks.check(accessing_obj, access_type=access_type, default=default)
- - @property - def search_index_entry(self): - """ - Property for easily retaining a search index entry for this object. - """ - return { - "key": self.db_key, - "aliases": " ".join(self.aliases.all()), - "no_prefix": "", - "category": self.db_help_category, - "text": self.db_entrytext, - "tags": " ".join(str(tag) for tag in self.tags.all()), - } - - # - # Web/Django methods - # - -
[docs] def web_get_admin_url(self): - """ - Returns the URI path for the Django Admin page for this object. - - ex. Account#1 = '/admin/accounts/accountdb/1/change/' - - Returns: - path (str): URI path to Django Admin page for object. - - """ - content_type = ContentType.objects.get_for_model(self.__class__) - return reverse( - "admin:%s_%s_change" % (content_type.app_label, content_type.model), args=(self.id,) - )
- -
[docs] @classmethod - def web_get_create_url(cls): - """ - Returns the URI path for a View that allows users to create new - instances of this object. - - ex. Chargen = '/characters/create/' - - For this to work, the developer must have defined a named view somewhere - in urls.py that follows the format 'modelname-action', so in this case - a named view of 'character-create' would be referenced by this method. - - ex. - :: - - url(r'characters/create/', ChargenView.as_view(), name='character-create') - - If no View has been created and defined in urls.py, returns an - HTML anchor. - - This method is naive and simply returns a path. Securing access to - the actual view and limiting who can create new objects is the - developer's responsibility. - - Returns: - path (str): URI path to object creation page, if defined. - - """ - try: - return reverse("%s-create" % slugify(cls._meta.verbose_name)) - except Exception: - return "#"
- -
[docs] def web_get_detail_url(self): - """ - Returns the URI path for a View that allows users to view details for - this object. - - ex. Oscar (Character) = '/characters/oscar/1/' - - For this to work, the developer must have defined a named view somewhere - in urls.py that follows the format 'modelname-action', so in this case - a named view of 'character-detail' would be referenced by this method. - - ex. - :: - url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$', - CharDetailView.as_view(), name='character-detail') - - If no View has been created and defined in urls.py, returns an - HTML anchor. - - This method is naive and simply returns a path. Securing access to - the actual view and limiting who can view this object is the developer's - responsibility. - - Returns: - path (str): URI path to object detail page, if defined. - - """ - - try: - return reverse( - "%s-detail" % slugify(self._meta.verbose_name), - kwargs={"category": slugify(self.db_help_category), "topic": slugify(self.db_key)}, - ) - except Exception: - return "#"
- -
[docs] def web_get_update_url(self): - """ - Returns the URI path for a View that allows users to update this - object. - - ex. Oscar (Character) = '/characters/oscar/1/change/' - - For this to work, the developer must have defined a named view somewhere - in urls.py that follows the format 'modelname-action', so in this case - a named view of 'character-update' would be referenced by this method. - - ex. - :: - - url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$', - CharUpdateView.as_view(), name='character-update') - - If no View has been created and defined in urls.py, returns an - HTML anchor. - - This method is naive and simply returns a path. Securing access to - the actual view and limiting who can modify objects is the developer's - responsibility. - - Returns: - path (str): URI path to object update page, if defined. - - """ - try: - return reverse( - "%s-update" % slugify(self._meta.verbose_name), - kwargs={"category": slugify(self.db_help_category), "topic": slugify(self.db_key)}, - ) - except Exception: - return "#"
- -
[docs] def web_get_delete_url(self): - """ - Returns the URI path for a View that allows users to delete this object. - - ex. Oscar (Character) = '/characters/oscar/1/delete/' - - For this to work, the developer must have defined a named view somewhere - in urls.py that follows the format 'modelname-action', so in this case - a named view of 'character-detail' would be referenced by this method. - - ex. - :: - - url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/delete/$', - CharDeleteView.as_view(), name='character-delete') - - If no View has been created and defined in urls.py, returns an - HTML anchor. - - This method is naive and simply returns a path. Securing access to - the actual view and limiting who can delete this object is the developer's - responsibility. - - Returns: - path (str): URI path to object deletion page, if defined. - - """ - try: - return reverse( - "%s-delete" % slugify(self._meta.verbose_name), - kwargs={"category": slugify(self.db_help_category), "topic": slugify(self.db_key)}, - ) - except Exception: - return "#"
- - # Used by Django Sites/Admin - get_absolute_url = web_get_detail_url
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/locks/lockfuncs.html b/docs/0.9.5/_modules/evennia/locks/lockfuncs.html deleted file mode 100644 index 8a02727621..0000000000 --- a/docs/0.9.5/_modules/evennia/locks/lockfuncs.html +++ /dev/null @@ -1,735 +0,0 @@ - - - - - - - - evennia.locks.lockfuncs — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.locks.lockfuncs

-"""
-This module provides a set of permission lock functions for use
-with Evennia's permissions system.
-
-To call these locks, make sure this module is included in the
-settings tuple `PERMISSION_FUNC_MODULES` then define a lock on the form
-'<access_type>:func(args)' and add it to the object's lockhandler.
-Run the `access()` method of the handler to execute the lock check.
-
-Note that `accessing_obj` and `accessed_obj` can be any object type
-with a lock variable/field, so be careful to not expect
-a certain object type.
-
-"""
-
-
-from ast import literal_eval
-from django.conf import settings
-from evennia.utils import utils
-
-_PERMISSION_HIERARCHY = [pe.lower() for pe in settings.PERMISSION_HIERARCHY]
-# also accept different plural forms
-_PERMISSION_HIERARCHY_PLURAL = [
-    pe + "s" if not pe.endswith("s") else pe for pe in _PERMISSION_HIERARCHY
-]
-
-
-def _to_account(accessing_obj):
-    "Helper function. Makes sure an accessing object is an account object"
-    if utils.inherits_from(accessing_obj, "evennia.objects.objects.DefaultObject"):
-        # an object. Convert to account.
-        accessing_obj = accessing_obj.account
-    return accessing_obj
-
-
-# lock functions
-
-
-
[docs]def true(*args, **kwargs): - """ - Always returns True. - - """ - return True
- -
[docs]def all(*args, **kwargs): - return True
- - -
[docs]def false(*args, **kwargs): - """ - Always returns False - - """ - return False
- - -
[docs]def none(*args, **kwargs): - return False
- - -
[docs]def superuser(*args, **kwargs): - return False
- - -
[docs]def self(accessing_obj, accessed_obj, *args, **kwargs): - """ - Check if accessing_obj is the same as accessed_obj - - Usage: - self() - - This can be used to lock specifically only to - the same object that the lock is defined on. - """ - return accessing_obj == accessed_obj
- - -
[docs]def perm(accessing_obj, accessed_obj, *args, **kwargs): - """ - The basic permission-checker. Ignores case. - - Usage: - perm(<permission>) - - where <permission> is the permission accessing_obj must - have in order to pass the lock. - - If the given permission is part of settings.PERMISSION_HIERARCHY, - permission is also granted to all ranks higher up in the hierarchy. - - If accessing_object is an Object controlled by an Account, the - permissions of the Account is used unless the Attribute _quell - is set to True on the Object. In this case however, the - LOWEST hieararcy-permission of the Account/Object-pair will be used - (this is order to avoid Accounts potentially escalating their own permissions - by use of a higher-level Object) - - For non-hierarchical permissions, a puppeted object's account is checked first, - followed by the puppet (unless quelled, when only puppet's access is checked). - - """ - # this allows the perm_above lockfunc to make use of this function too - try: - permission = args[0].lower() - perms_object = accessing_obj.permissions.all() - except (AttributeError, IndexError): - return False - - gtmode = kwargs.pop("_greater_than", False) - is_quell = False - - account = ( - utils.inherits_from(accessing_obj, "evennia.objects.objects.DefaultObject") - and accessing_obj.account - ) - # check object perms (note that accessing_obj could be an Account too) - perms_account = [] - if account: - perms_account = account.permissions.all() - is_quell = account.attributes.get("_quell") - - # Check hirarchy matches; handle both singular/plural forms in hierarchy - hpos_target = None - if permission in _PERMISSION_HIERARCHY: - hpos_target = _PERMISSION_HIERARCHY.index(permission) - if permission.endswith("s") and permission[:-1] in _PERMISSION_HIERARCHY: - hpos_target = _PERMISSION_HIERARCHY.index(permission[:-1]) - if hpos_target is not None: - # hieratchy match - hpos_account = -1 - hpos_object = -1 - - if account: - # we have an account puppeting this object. We must check what perms it has - perms_account_single = [p[:-1] if p.endswith("s") else p for p in perms_account] - hpos_account = [ - hpos - for hpos, hperm in enumerate(_PERMISSION_HIERARCHY) - if hperm in perms_account_single - ] - hpos_account = hpos_account and hpos_account[-1] or -1 - - if not account or is_quell: - # only get the object-level perms if there is no account or quelling - perms_object_single = [p[:-1] if p.endswith("s") else p for p in perms_object] - hpos_object = [ - hpos - for hpos, hperm in enumerate(_PERMISSION_HIERARCHY) - if hperm in perms_object_single - ] - hpos_object = hpos_object and hpos_object[-1] or -1 - - if account and is_quell: - # quell mode: use smallest perm from account and object - if gtmode: - return hpos_target < min(hpos_account, hpos_object) - else: - return hpos_target <= min(hpos_account, hpos_object) - elif account: - # use account perm - if gtmode: - return hpos_target < hpos_account - else: - return hpos_target <= hpos_account - else: - # use object perm - if gtmode: - return hpos_target < hpos_object - else: - return hpos_target <= hpos_object - else: - # no hierarchy match - check direct matches - if account: - # account exists - if is_quell and permission in perms_object: - # if quelled, first check object - return True - elif permission in perms_account: - # unquelled - check account - return True - else: - # no account-pass, check object pass - return permission in perms_object - - elif permission in perms_object: - return True - - return False
- - -
[docs]def perm_above(accessing_obj, accessed_obj, *args, **kwargs): - """ - Only allow objects with a permission *higher* in the permission - hierarchy than the one given. If there is no such higher rank, - it's assumed we refer to superuser. If no hierarchy is defined, - this function has no meaning and returns False. - """ - kwargs["_greater_than"] = True - return perm(accessing_obj, accessed_obj, *args, **kwargs)
- - -
[docs]def pperm(accessing_obj, accessed_obj, *args, **kwargs): - """ - The basic permission-checker only for Account objects. Ignores case. - - Usage: - pperm(<permission>) - - where <permission> is the permission accessing_obj must - have in order to pass the lock. If the given permission - is part of _PERMISSION_HIERARCHY, permission is also granted - to all ranks higher up in the hierarchy. - """ - return perm(_to_account(accessing_obj), accessed_obj, *args, **kwargs)
- - -
[docs]def pperm_above(accessing_obj, accessed_obj, *args, **kwargs): - """ - Only allow Account objects with a permission *higher* in the permission - hierarchy than the one given. If there is no such higher rank, - it's assumed we refer to superuser. If no hierarchy is defined, - this function has no meaning and returns False. - """ - return perm_above(_to_account(accessing_obj), accessed_obj, *args, **kwargs)
- - -
[docs]def dbref(accessing_obj, accessed_obj, *args, **kwargs): - """ - Usage: - dbref(3) - - This lock type checks if the checking object - has a particular dbref. Note that this only - works for checking objects that are stored - in the database (e.g. not for commands) - """ - if not args: - return False - try: - dbr = int(args[0].strip().strip("#")) - except ValueError: - return False - if hasattr(accessing_obj, "dbid"): - return dbr == accessing_obj.dbid - return False
- - -
[docs]def pdbref(accessing_obj, accessed_obj, *args, **kwargs): - """ - Same as dbref, but making sure accessing_obj is an account. - """ - return dbref(_to_account(accessing_obj), accessed_obj, *args, **kwargs)
- - -
[docs]def id(accessing_obj, accessed_obj, *args, **kwargs): - "Alias to dbref" - return dbref(accessing_obj, accessed_obj, *args, **kwargs)
- - -
[docs]def pid(accessing_obj, accessed_obj, *args, **kwargs): - "Alias to dbref, for Accounts" - return dbref(_to_account(accessing_obj), accessed_obj, *args, **kwargs)
- - -# this is more efficient than multiple if ... elif statments -CF_MAPPING = { - "eq": lambda val1, val2: val1 == val2 or str(val1) == str(val2) or float(val1) == float(val2), - "gt": lambda val1, val2: float(val1) > float(val2), - "lt": lambda val1, val2: float(val1) < float(val2), - "ge": lambda val1, val2: float(val1) >= float(val2), - "le": lambda val1, val2: float(val1) <= float(val2), - "ne": lambda val1, val2: float(val1) != float(val2), - "default": lambda val1, val2: False, -} - - -
[docs]def attr(accessing_obj, accessed_obj, *args, **kwargs): - """ - Usage: - attr(attrname) - attr(attrname, value) - attr(attrname, value, compare=type) - - where compare's type is one of (eq,gt,lt,ge,le,ne) and signifies - how the value should be compared with one on accessing_obj (so - compare=gt means the accessing_obj must have a value greater than - the one given). - - Searches attributes *and* properties stored on the accessing_obj. - if accessing_obj has a property "obj", then this is used as - accessing_obj (this makes this usable for Commands too) - - The first form works like a flag - if the attribute/property - exists on the object, the value is checked for True/False. The - second form also requires that the value of the attribute/property - matches. Note that all retrieved values will be converted to - strings before doing the comparison. - """ - # deal with arguments - if not args: - return False - attrname = args[0].strip() - value = None - if len(args) > 1: - value = args[1].strip() - compare = "eq" - if kwargs: - compare = kwargs.get("compare", "eq") - - def valcompare(val1, val2, typ="eq"): - "compare based on type" - try: - return CF_MAPPING.get(typ, CF_MAPPING["default"])(val1, val2) - except Exception: - # this might happen if we try to compare two things that - # cannot be compared - return False - - if hasattr(accessing_obj, "obj"): - # NOTE: this is relevant for Commands. It may clash with scripts - # (they have Attributes and .obj) , but are scripts really - # used so that one ever wants to check the property on the - # Script rather than on its owner? - accessing_obj = accessing_obj.obj - - # first, look for normal properties on the object trying to gain access - if hasattr(accessing_obj, attrname): - if value: - return valcompare(str(getattr(accessing_obj, attrname)), value, compare) - # will return Fail on False value etc - return bool(getattr(accessing_obj, attrname)) - # check attributes, if they exist - if hasattr(accessing_obj, "attributes") and accessing_obj.attributes.has(attrname): - if value: - return hasattr(accessing_obj, "attributes") and valcompare( - accessing_obj.attributes.get(attrname), value, compare - ) - # fails on False/None values - return bool(accessing_obj.attributes.get(attrname)) - return False
- - -
[docs]def objattr(accessing_obj, accessed_obj, *args, **kwargs): - """ - Usage: - objattr(attrname) - objattr(attrname, value) - objattr(attrname, value, compare=type) - - Works like attr, except it looks for an attribute on - accessed_obj instead. - - """ - return attr(accessed_obj, accessed_obj, *args, **kwargs)
- - -
[docs]def locattr(accessing_obj, accessed_obj, *args, **kwargs): - """ - Usage: - locattr(attrname) - locattr(attrname, value) - locattr(attrname, value, compare=type) - - Works like attr, except it looks for an attribute on - accessing_obj.location, if such an entity exists. - - if accessing_obj has a property ".obj" (such as is the case for a - Command), then accessing_obj.obj.location is used instead. - - """ - if hasattr(accessing_obj, "obj"): - accessing_obj = accessing_obj.obj - if hasattr(accessing_obj, "location"): - return attr(accessing_obj.location, accessed_obj, *args, **kwargs) - return False
- - -
[docs]def objlocattr(accessing_obj, accessed_obj, *args, **kwargs): - """ - Usage: - locattr(attrname) - locattr(attrname, value) - locattr(attrname, value, compare=type) - - Works like attr, except it looks for an attribute on - accessed_obj.location, if such an entity exists. - - if accessed_obj has a property ".obj" (such as is the case for a - Command), then accessing_obj.obj.location is used instead. - - """ - if hasattr(accessed_obj, "obj"): - accessed_obj = accessed_obj.obj - if hasattr(accessed_obj, "location"): - return attr(accessed_obj.location, accessed_obj, *args, **kwargs) - return False
- - -
[docs]def attr_eq(accessing_obj, accessed_obj, *args, **kwargs): - """ - Usage: - attr_gt(attrname, 54) - """ - return attr(accessing_obj, accessed_obj, *args, **kwargs)
- - -
[docs]def attr_gt(accessing_obj, accessed_obj, *args, **kwargs): - """ - Usage: - attr_gt(attrname, 54) - - Only true if access_obj's attribute > the value given. - """ - return attr(accessing_obj, accessed_obj, *args, **{"compare": "gt"})
- - -
[docs]def attr_ge(accessing_obj, accessed_obj, *args, **kwargs): - """ - Usage: - attr_gt(attrname, 54) - - Only true if access_obj's attribute >= the value given. - """ - return attr(accessing_obj, accessed_obj, *args, **{"compare": "ge"})
- - -
[docs]def attr_lt(accessing_obj, accessed_obj, *args, **kwargs): - """ - Usage: - attr_gt(attrname, 54) - - Only true if access_obj's attribute < the value given. - """ - return attr(accessing_obj, accessed_obj, *args, **{"compare": "lt"})
- - -
[docs]def attr_le(accessing_obj, accessed_obj, *args, **kwargs): - """ - Usage: - attr_gt(attrname, 54) - - Only true if access_obj's attribute <= the value given. - """ - return attr(accessing_obj, accessed_obj, *args, **{"compare": "le"})
- - -
[docs]def attr_ne(accessing_obj, accessed_obj, *args, **kwargs): - """ - Usage: - attr_gt(attrname, 54) - - Only true if access_obj's attribute != the value given. - """ - return attr(accessing_obj, accessed_obj, *args, **{"compare": "ne"})
- - -
[docs]def tag(accessing_obj, accessed_obj, *args, **kwargs): - """ - Usage: - tag(tagkey) - tag(tagkey, category) - - Only true if accessing_obj has the specified tag and optional - category. - If accessing_obj has the ".obj" property (such as is the case for - a command), then accessing_obj.obj is used instead. - """ - if hasattr(accessing_obj, "obj"): - accessing_obj = accessing_obj.obj - tagkey = args[0] if args else None - category = args[1] if len(args) > 1 else None - return bool(accessing_obj.tags.get(tagkey, category=category))
- - -
[docs]def objtag(accessing_obj, accessed_obj, *args, **kwargs): - """ - Usage: - objtag(tagkey) - objtag(tagkey, category) - - Only true if accessed_obj has the specified tag and optional - category. - """ - tagkey = args[0] if args else None - category = args[1] if len(args) > 1 else None - return bool(accessed_obj.tags.get(tagkey, category=category))
- - -
[docs]def inside(accessing_obj, accessed_obj, *args, **kwargs): - """ - Usage: - inside() - - True if accessing_obj is 'inside' accessing_obj. Note that this only checks - one level down. So if if the lock is on a room, you will pass but not your - inventory (since their location is you, not the locked object). If you - want also nested objects to pass the lock, use the `insiderecursive` - lockfunc. - """ - if hasattr(accessed_obj, "obj"): - accessed_obj = accessed_obj.obj - return accessing_obj.location == accessed_obj
- - -
[docs]def inside_rec(accessing_obj, accessed_obj, *args, **kwargs): - """ - Usage: - inside_rec() - - True if accessing_obj is inside the accessed obj, at up to 10 levels - of recursion (so if this lock is on a room, then an object inside a box - in your inventory will also pass the lock). - """ - - def _recursive_inside(obj, accessed_obj, lvl=1): - if obj.location: - if obj.location == accessed_obj: - return True - elif lvl >= 10: - # avoid infinite recursions - return False - else: - return _recursive_inside(obj.location, accessed_obj, lvl + 1) - return False - - return _recursive_inside(accessing_obj, accessed_obj)
- - -
[docs]def holds(accessing_obj, accessed_obj, *args, **kwargs): - """ - Usage: - holds() checks if accessed_obj or accessed_obj.obj - is held by accessing_obj - holds(key/dbref) checks if accessing_obj holds an object - with given key/dbref - holds(attrname, value) checks if accessing_obj holds an - object with the given attrname and value - - This is passed if accessed_obj is carried by accessing_obj (that is, - accessed_obj.location == accessing_obj), or if accessing_obj itself holds - an object matching the given key. - """ - try: - # commands and scripts don't have contents, so we are usually looking - # for the contents of their .obj property instead (i.e. the object the - # command/script is attached to). - contents = accessing_obj.contents - except AttributeError: - try: - contents = accessing_obj.obj.contents - except AttributeError: - return False - - def check_holds(objid): - # helper function. Compares both dbrefs and keys/aliases. - objid = str(objid) - dbref = utils.dbref(objid, reqhash=False) - if dbref and any((True for obj in contents if obj.dbid == dbref)): - return True - objid = objid.lower() - return any( - ( - True - for obj in contents - if obj.key.lower() == objid or objid in [al.lower() for al in obj.aliases.all()] - ) - ) - - if not args: - # holds() - check if accessed_obj or accessed_obj.obj is held by accessing_obj - try: - if check_holds(accessed_obj.dbid): - return True - except Exception: - # we need to catch any trouble here - pass - return hasattr(accessed_obj, "obj") and check_holds(accessed_obj.obj.dbid) - if len(args) == 1: - # command is holds(dbref/key) - check if given objname/dbref is held by accessing_ob - return check_holds(args[0]) - elif len(args) > 1: - # command is holds(attrname, value) check if any held object has the given attribute and value - for obj in contents: - if obj.attributes.get(args[0]) == args[1]: - return True - return False
- - -
[docs]def has_account(accessing_obj, accessed_obj, *args, **kwargs): - """ - Only returns true if accessing_obj has_account is true, that is, - this is an account-controlled object. It fails on actual accounts! - - This is a useful lock for traverse-locking Exits to restrain NPC - mobiles from moving outside their areas. - """ - return hasattr(accessing_obj, "has_account") and accessing_obj.has_account
- - -
[docs]def serversetting(accessing_obj, accessed_obj, *args, **kwargs): - """ - Only returns true if the Evennia settings exists, alternatively has - a certain value. - - Usage: - serversetting(IRC_ENABLED) - serversetting(BASE_SCRIPT_PATH, ['types']) - - A given True/False or integers will be converted properly. Note that - everything will enter this function as strings, so they have to be - unpacked to their real value. We only support basic properties. - """ - if not args or not args[0]: - return False - if len(args) < 2: - setting = args[0] - val = "True" - else: - setting, val = args[0], args[1] - # convert - try: - val = literal_eval(val) - except Exception: - # we swallow errors here, lockfuncs has noone to report to - return False - - if setting in settings._wrapped.__dict__: - return settings._wrapped.__dict__[setting] == val - return False
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/locks/lockhandler.html b/docs/0.9.5/_modules/evennia/locks/lockhandler.html deleted file mode 100644 index ba5cebd1cd..0000000000 --- a/docs/0.9.5/_modules/evennia/locks/lockhandler.html +++ /dev/null @@ -1,886 +0,0 @@ - - - - - - - - evennia.locks.lockhandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.locks.lockhandler

-"""
-A *lock* defines access to a particular subsystem or property of
-Evennia. For example, the "owner" property can be impmemented as a
-lock. Or the disability to lift an object or to ban users.
-
-
-A lock consists of three parts:
-
- - access_type - this defines what kind of access this lock regulates. This
-   just a string.
- - function call - this is one or many calls to functions that will determine
-   if the lock is passed or not.
- - lock function(s). These are regular python functions with a special
-   set of allowed arguments. They should always return a boolean depending
-   on if they allow access or not.
-
-A lock function is defined by existing in one of the modules
-listed by settings.LOCK_FUNC_MODULES. It should also always
-take four arguments looking like this:
-
-   funcname(accessing_obj, accessed_obj, *args, **kwargs):
-        [...]
-
-The accessing object is the object wanting to gain access.
-The accessed object is the object this lock resides on
-args and kwargs will hold optional arguments and/or keyword arguments
-to the function as a list and a dictionary respectively.
-
-Example:
-
-   perm(accessing_obj, accessed_obj, *args, **kwargs):
-       "Checking if the object has a particular, desired permission"
-       if args:
-           desired_perm = args[0]
-           return desired_perm in accessing_obj.permissions.all()
-       return False
-
-Lock functions should most often be pretty general and ideally possible to
-re-use and combine in various ways to build clever locks.
-
-
-
-Lock definition ("Lock string")
-
-A lock definition is a string with a special syntax. It is added to
-each object's lockhandler, making that lock available from then on.
-
-The lock definition looks like this:
-
- 'access_type:[NOT] func1(args)[ AND|OR][NOT] func2() ...'
-
-That is, the access_type, a colon followed by calls to lock functions
-combined with AND or OR. NOT negates the result of the following call.
-
-Example:
-
- We want to limit who may edit a particular object (let's call this access_type
-for 'edit', it depends on what the command is looking for). We want this to
-only work for those with the Permission 'Builder'. So we use our lock
-function above and define it like this:
-
-  'edit:perm(Builder)'
-
-Here, the lock-function perm() will be called with the string
-'Builder' (accessing_obj and accessed_obj are added automatically,
-you only need to add the args/kwargs, if any).
-
-If we wanted to make sure the accessing object was BOTH a Builder and a
-GoodGuy, we could use AND:
-
-  'edit:perm(Builder) AND perm(GoodGuy)'
-
-To allow EITHER Builder and GoodGuys, we replace AND with OR. perm() is just
-one example, the lock function can do anything and compare any properties of
-the calling object to decide if the lock is passed or not.
-
-  'lift:attrib(very_strong) AND NOT attrib(bad_back)'
-
-To make these work, add the string to the lockhandler of the object you want
-to apply the lock to:
-
-  obj.lockhandler.add('edit:perm(Builder)')
-
-From then on, a command that wants to check for 'edit' access on this
-object would do something like this:
-
-  if not target_obj.lockhandler.has_perm(caller, 'edit'):
-      caller.msg("Sorry, you cannot edit that.")
-
-All objects also has a shortcut called 'access' that is recommended to
-use instead:
-
-  if not target_obj.access(caller, 'edit'):
-      caller.msg("Sorry, you cannot edit that.")
-
-
-Permissions
-
-Permissions are just text strings stored in a comma-separated list on
-typeclassed objects. The default perm() lock function uses them,
-taking into account settings.PERMISSION_HIERARCHY. Also, the
-restricted @perm command sets them, but otherwise they are identical
-to any other identifier you can use.
-
-"""
-
-import re
-from django.conf import settings
-from evennia.utils import logger, utils
-from django.utils.translation import gettext as _
-
-__all__ = ("LockHandler", "LockException")
-
-WARNING_LOG = settings.LOCKWARNING_LOG_FILE
-_LOCK_HANDLER = None
-
-
-#
-# Exception class. This will be raised
-# by errors in lock definitions.
-#
-
-
-
[docs]class LockException(Exception): - """ - Raised during an error in a lock. - - """ - - pass
- - -# -# Cached lock functions -# - -_LOCKFUNCS = {} - - -def _cache_lockfuncs(): - """ - Updates the cache. - - """ - global _LOCKFUNCS - _LOCKFUNCS = {} - for modulepath in settings.LOCK_FUNC_MODULES: - _LOCKFUNCS.update(utils.callables_from_module(modulepath)) - - -# -# pre-compiled regular expressions -# - - -_RE_FUNCS = re.compile(r"\w+\([^)]*\)") -_RE_SEPS = re.compile(r"(?<=[ )])AND(?=\s)|(?<=[ )])OR(?=\s)|(?<=[ )])NOT(?=\s)") -_RE_OK = re.compile(r"%s|and|or|not") - - -# -# -# Lock handler -# -# - - -
[docs]class LockHandler: - """ - This handler should be attached to all objects implementing - permission checks, under the property 'lockhandler'. - - """ - -
[docs] def __init__(self, obj): - """ - Loads and pre-caches all relevant locks and their functions. - - Args: - obj (object): The object on which the lockhandler is - defined. - - """ - if not _LOCKFUNCS: - _cache_lockfuncs() - self.obj = obj - self.locks = {} - try: - self.reset() - except LockException as err: - logger.log_trace(err)
- - def __str__(self): - return ";".join(self.locks[key][2] for key in sorted(self.locks)) - - def _log_error(self, message): - "Try to log errors back to object" - raise LockException(message) - - def _parse_lockstring(self, storage_lockstring): - """ - Helper function. This is normally only called when the - lockstring is cached and does preliminary checking. locks are - stored as a string - - atype:[NOT] lock()[[ AND|OR [NOT] lock()[...]];atype... - - Args: - storage_locksring (str): The lockstring to parse. - - """ - locks = {} - if not storage_lockstring: - return locks - duplicates = 0 - elist = [] # errors - wlist = [] # warnings - for raw_lockstring in storage_lockstring.split(";"): - if not raw_lockstring: - continue - lock_funcs = [] - try: - access_type, rhs = (part.strip() for part in raw_lockstring.split(":", 1)) - except ValueError: - logger.log_trace() - return locks - - # parse the lock functions and separators - funclist = _RE_FUNCS.findall(rhs) - evalstring = rhs - for pattern in ("AND", "OR", "NOT"): - evalstring = re.sub(r"\b%s\b" % pattern, pattern.lower(), evalstring) - nfuncs = len(funclist) - for funcstring in funclist: - funcname, rest = (part.strip().strip(")") for part in funcstring.split("(", 1)) - func = _LOCKFUNCS.get(funcname, None) - if not callable(func): - elist.append(_("Lock: lock-function '{lockfunc}' is not available.").format( - lockfunc=funcstring)) - continue - args = list(arg.strip() for arg in rest.split(",") if arg and "=" not in arg) - kwargs = dict( - [ - (part.strip() for part in arg.split("=", 1)) - for arg in rest.split(",") - if arg and "=" in arg - ] - ) - lock_funcs.append((func, args, kwargs)) - evalstring = evalstring.replace(funcstring, "%s") - if len(lock_funcs) < nfuncs: - continue - try: - # purge the eval string of any superfluous items, then test it - evalstring = " ".join(_RE_OK.findall(evalstring)) - eval(evalstring % tuple(True for func in funclist), {}, {}) - except Exception: - elist.append( - _("Lock: definition '{lock_string}' has syntax errors.").format( - lock_string=raw_lockstring - ) - ) - continue - if access_type in locks: - duplicates += 1 - wlist.append(_( - "LockHandler on {obj}: access type '{access_type}' " - "changed from '{source}' to '{goal}' ".format( - obj=self.obj, - access_type=access_type, - source=locks[access_type][2], - goal=raw_lockstring)) - ) - locks[access_type] = (evalstring, tuple(lock_funcs), raw_lockstring) - if wlist and WARNING_LOG: - # a warning text was set, it's not an error, so only report - logger.log_file("\n".join(wlist), WARNING_LOG) - if elist: - # an error text was set, raise exception. - raise LockException("\n".join(elist)) - # return the gathered locks in an easily executable form - return locks - - def _cache_locks(self, storage_lockstring): - """ - Store data - - """ - self.locks = self._parse_lockstring(storage_lockstring) - - def _save_locks(self): - """ - Store locks to obj - - """ - self.obj.lock_storage = ";".join([tup[2] for tup in self.locks.values()]) - -
[docs] def cache_lock_bypass(self, obj): - """ - We cache superuser bypass checks here for efficiency. This - needs to be re-run when an account is assigned to a character. - We need to grant access to superusers. We need to check both - directly on the object (accounts), through obj.account and using - the get_account() method (this sits on serversessions, in some - rare cases where a check is done before the login process has - yet been fully finalized) - - Args: - obj (object): This is checked for the `is_superuser` property. - - """ - self.lock_bypass = hasattr(obj, "is_superuser") and obj.is_superuser
- -
[docs] def add(self, lockstring, validate_only=False): - """ - Add a new lockstring to handler. - - Args: - lockstring (str or list): A string on the form - `"<access_type>:<functions>"`. Multiple access types - should be separated by semicolon (`;`). Alternatively, - a list with lockstrings. - validate_only (bool, optional): If True, validate the lockstring but - don't actually store it. - Returns: - success (bool): The outcome of the addition, `False` on - error. If `validate_only` is True, this will be a tuple - (bool, error), for pass/fail and a string error. - - """ - if isinstance(lockstring, str): - lockdefs = lockstring.split(";") - else: - lockdefs = [lockdef for locks in lockstring for lockdef in locks.split(";")] - lockstring = ";".join(lockdefs) - - err = "" - # sanity checks - for lockdef in lockdefs: - if ":" not in lockdef: - err = _("Lock: '{lockdef}' contains no colon (:).").format(lockdef=lockdef) - if validate_only: - return False, err - else: - self._log_error(err) - return False - access_type, rhs = [part.strip() for part in lockdef.split(":", 1)] - if not access_type: - err = _( - "Lock: '{lockdef}' has no access_type " "(left-side of colon is empty)." - ).format(lockdef=lockdef) - if validate_only: - return False, err - else: - self._log_error(err) - return False - if rhs.count("(") != rhs.count(")"): - err = _("Lock: '{lockdef}' has mismatched parentheses.").format(lockdef=lockdef) - if validate_only: - return False, err - else: - self._log_error(err) - return False - if not _RE_FUNCS.findall(rhs): - err = _("Lock: '{lockdef}' has no valid lock functions.").format(lockdef=lockdef) - if validate_only: - return False, err - else: - self._log_error(err) - return False - if validate_only: - return True, None - # get the lock string - storage_lockstring = self.obj.lock_storage - if storage_lockstring: - storage_lockstring = storage_lockstring + ";" + lockstring - else: - storage_lockstring = lockstring - # cache the locks will get rid of eventual doublets - self._cache_locks(storage_lockstring) - self._save_locks() - return True
- -
[docs] def validate(self, lockstring): - """ - Validate lockstring syntactically, without saving it. - - Args: - lockstring (str): Lockstring to validate. - Returns: - valid (bool): If validation passed or not. - - """ - return self.add(lockstring, validate_only=True)
- -
[docs] def replace(self, lockstring): - """ - Replaces the lockstring entirely. - - Args: - lockstring (str): The new lock definition. - - Return: - success (bool): False if an error occurred. - - Raises: - LockException: If a critical error occurred. - If so, the old string is recovered. - - """ - old_lockstring = str(self) - self.clear() - try: - return self.add(lockstring) - except LockException: - self.add(old_lockstring) - raise
- -
[docs] def get(self, access_type=None): - """ - Get the full lockstring or the lockstring of a particular - access type. - - Args: - access_type (str, optional): - - Returns: - lockstring (str): The matched lockstring, or the full - lockstring if no access_type was given. - """ - - if access_type: - return self.locks.get(access_type, ["", "", ""])[2] - return str(self)
- -
[docs] def all(self): - """ - Return all lockstrings - - Returns: - lockstrings (list): All separate lockstrings - - """ - return str(self).split(";")
- -
[docs] def remove(self, access_type): - """ - Remove a particular lock from the handler - - Args: - access_type (str): The type of lock to remove. - - Returns: - success (bool): If the access_type was not found - in the lock, this returns `False`. - - """ - if access_type in self.locks: - del self.locks[access_type] - self._save_locks() - return True - return False
- - delete = remove # alias for historical reasons - -
[docs] def clear(self): - """ - Remove all locks in the handler. - - """ - self.locks = {} - self.lock_storage = "" - self._save_locks()
- -
[docs] def reset(self): - """ - Set the reset flag, so the the lock will be re-cached at next - checking. This is usually called by @reload. - - """ - self._cache_locks(self.obj.lock_storage) - self.cache_lock_bypass(self.obj)
- -
[docs] def append(self, access_type, lockstring, op="or"): - """ - Append a lock definition to access_type if it doesn't already exist. - - Args: - access_type (str): Access type. - lockstring (str): A valid lockstring, without the operator to - link it to an eventual existing lockstring. - op (str): An operator 'and', 'or', 'and not', 'or not' used - for appending the lockstring to an existing access-type. - Note: - The most common use of this method is for use in commands where - the user can specify their own lockstrings. This method allows - the system to auto-add things like Admin-override access. - - """ - old_lockstring = self.get(access_type) - if not lockstring.strip().lower() in old_lockstring.lower(): - lockstring = "{old} {op} {new}".format( - old=old_lockstring, op=op, new=lockstring.strip() - ) - self.add(lockstring)
- -
[docs] def check(self, accessing_obj, access_type, default=False, no_superuser_bypass=False): - """ - Checks a lock of the correct type by passing execution off to - the lock function(s). - - Args: - accessing_obj (object): The object seeking access. - access_type (str): The type of access wanted. - default (bool, optional): If no suitable lock type is - found, default to this result. - no_superuser_bypass (bool): Don't use this unless you - really, really need to, it makes supersusers susceptible - to the lock check. - - Notes: - A lock is executed in the follwoing way: - - Parsing the lockstring, we (during cache) extract the valid - lock functions and store their function objects in the right - order along with their args/kwargs. These are now executed in - sequence, creating a list of True/False values. This is put - into the evalstring, which is a string of AND/OR/NOT entries - separated by placeholders where each function result should - go. We just put those results in and evaluate the string to - get a final, combined True/False value for the lockstring. - - The important bit with this solution is that the full - lockstring is never blindly evaluated, and thus there (should - be) no way to sneak in malign code in it. Only "safe" lock - functions (as defined by your settings) are executed. - - """ - try: - # check if the lock should be bypassed (e.g. superuser status) - if accessing_obj.locks.lock_bypass and not no_superuser_bypass: - return True - except AttributeError: - # happens before session is initiated. - if not no_superuser_bypass and ( - (hasattr(accessing_obj, "is_superuser") and accessing_obj.is_superuser) - or ( - hasattr(accessing_obj, "account") - and hasattr(accessing_obj.account, "is_superuser") - and accessing_obj.account.is_superuser - ) - or ( - hasattr(accessing_obj, "get_account") - and ( - not accessing_obj.get_account() or accessing_obj.get_account().is_superuser - ) - ) - ): - return True - - # no superuser or bypass -> normal lock operation - if access_type in self.locks: - # we have a lock, test it. - evalstring, func_tup, raw_string = self.locks[access_type] - # execute all lock funcs in the correct order, producing a tuple of True/False results. - true_false = tuple( - bool(tup[0](accessing_obj, self.obj, *tup[1], **tup[2])) for tup in func_tup - ) - # the True/False tuple goes into evalstring, which combines them - # with AND/OR/NOT in order to get the final result. - return eval(evalstring % true_false) - else: - return default
- - def _eval_access_type(self, accessing_obj, locks, access_type): - """ - Helper method for evaluating the access type using eval(). - - Args: - accessing_obj (object): Object seeking access. - locks (dict): The pre-parsed representation of all access-types. - access_type (str): An access-type key to evaluate. - - """ - evalstring, func_tup, raw_string = locks[access_type] - true_false = tuple(tup[0](accessing_obj, self.obj, *tup[1], **tup[2]) for tup in func_tup) - return eval(evalstring % true_false) - -
[docs] def check_lockstring( - self, accessing_obj, lockstring, no_superuser_bypass=False, default=False, access_type=None - ): - """ - Do a direct check against a lockstring ('atype:func()..'), - without any intermediary storage on the accessed object. - - Args: - accessing_obj (object or None): The object seeking access. - Importantly, this can be left unset if the lock functions - don't access it, no updating or storage of locks are made - against this object in this method. - lockstring (str): Lock string to check, on the form - `"access_type:lock_definition"` where the `access_type` - part can potentially be set to a dummy value to just check - a lock condition. - no_superuser_bypass (bool, optional): Force superusers to heed lock. - default (bool, optional): Fallback result to use if `access_type` is set - but no such `access_type` is found in the given `lockstring`. - access_type (str, bool): If set, only this access_type will be looked up - among the locks defined by `lockstring`. - - Return: - access (bool): If check is passed or not. - - """ - try: - if accessing_obj.locks.lock_bypass and not no_superuser_bypass: - return True - except AttributeError: - if no_superuser_bypass and ( - (hasattr(accessing_obj, "is_superuser") and accessing_obj.is_superuser) - or ( - hasattr(accessing_obj, "account") - and hasattr(accessing_obj.account, "is_superuser") - and accessing_obj.account.is_superuser - ) - or ( - hasattr(accessing_obj, "get_account") - and ( - not accessing_obj.get_account() or accessing_obj.get_account().is_superuser - ) - ) - ): - return True - if ":" not in lockstring: - lockstring = "%s:%s" % ("_dummy", lockstring) - - locks = self._parse_lockstring(lockstring) - - if access_type: - if access_type not in locks: - return default - else: - return self._eval_access_type(accessing_obj, locks, access_type) - else: - # if no access types was given and multiple locks were - # embedded in the lockstring we assume all must be true - return all( - self._eval_access_type(accessing_obj, locks, access_type) for access_type in locks - )
- - -# convenience access function - -# dummy to be able to call check_lockstring from the outside - - -class _ObjDummy: - lock_storage = "" - - -def check_lockstring( - accessing_obj, lockstring, no_superuser_bypass=False, default=False, access_type=None -): - """ - Do a direct check against a lockstring ('atype:func()..'), - without any intermediary storage on the accessed object. - - Args: - accessing_obj (object or None): The object seeking access. - Importantly, this can be left unset if the lock functions - don't access it, no updating or storage of locks are made - against this object in this method. - lockstring (str): Lock string to check, on the form - `"access_type:lock_definition"` where the `access_type` - part can potentially be set to a dummy value to just check - a lock condition. - no_superuser_bypass (bool, optional): Force superusers to heed lock. - default (bool, optional): Fallback result to use if `access_type` is set - but no such `access_type` is found in the given `lockstring`. - access_type (str, bool): If set, only this access_type will be looked up - among the locks defined by `lockstring`. - - Return: - access (bool): If check is passed or not. - - """ - global _LOCK_HANDLER - if not _LOCK_HANDLER: - _LOCK_HANDLER = LockHandler(_ObjDummy()) - return _LOCK_HANDLER.check_lockstring( - accessing_obj, - lockstring, - no_superuser_bypass=no_superuser_bypass, - default=default, - access_type=access_type, - ) - -def check_perm(obj, permission, no_superuser_bypass=False): - """ - Shortcut for checking if an object has the given `permission`. If the - permission is in `settings.PERMISSION_HIERARCHY`, the check passes - if the object has this permission or higher. - - This is equivalent to calling the perm() lockfunc, but without needing - an accessed object. - - Args: - obj (Object, Account): The object to check access. If this has a linked - Account, the account is checked instead (same rules as per perm()). - permission (str): The permission string to check. - no_superuser_bypass (bool, optional): If unset, the superuser - will always pass this check. - - """ - from evennia.locks.lockfuncs import perm - if not no_superuser_bypass and obj.is_superuser: - return True - return perm(obj, None, permission) - - -def validate_lockstring(lockstring): - """ - Validate so lockstring is on a valid form. - - Args: - lockstring (str): Lockstring to validate. - - Returns: - is_valid (bool): If the lockstring is valid or not. - error (str or None): A string describing the error, or None - if no error was found. - - """ - global _LOCK_HANDLER - if not _LOCK_HANDLER: - _LOCK_HANDLER = LockHandler(_ObjDummy()) - return _LOCK_HANDLER.validate(lockstring) - - -def get_all_lockfuncs(): - """ - Get a dict of available lock funcs. - - Returns: - lockfuncs (dict): Mapping {lockfuncname:func}. - - """ - if not _LOCKFUNCS: - _cache_lockfuncs() - return _LOCKFUNCS - - -def _test(): - # testing - - class TestObj(object): - pass - - import pdb - - obj1 = TestObj() - obj2 = TestObj() - - # obj1.lock_storage = "owner:dbref(#4);edit:dbref(#5) or perm(Admin);examine:perm(Builder);delete:perm(Admin);get:all()" - # obj1.lock_storage = "cmd:all();admin:id(1);listen:all();send:all()" - obj1.lock_storage = "listen:perm(Developer)" - - pdb.set_trace() - obj1.locks = LockHandler(obj1) - obj2.permissions.add("Developer") - obj2.id = 4 - - # obj1.locks.add("edit:attr(test)") - - print("comparing obj2.permissions (%s) vs obj1.locks (%s)" % (obj2.permissions, obj1.locks)) - print(obj1.locks.check(obj2, "owner")) - print(obj1.locks.check(obj2, "edit")) - print(obj1.locks.check(obj2, "examine")) - print(obj1.locks.check(obj2, "delete")) - print(obj1.locks.check(obj2, "get")) - print(obj1.locks.check(obj2, "listen")) -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/objects/manager.html b/docs/0.9.5/_modules/evennia/objects/manager.html deleted file mode 100644 index cbd5be6fe9..0000000000 --- a/docs/0.9.5/_modules/evennia/objects/manager.html +++ /dev/null @@ -1,839 +0,0 @@ - - - - - - - - evennia.objects.manager — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.objects.manager

-"""
-Custom manager for Objects.
-"""
-import re
-from django.db.models import Q
-from django.conf import settings
-from django.db.models.fields import exceptions
-from evennia.typeclasses.managers import TypedObjectManager, TypeclassManager
-from evennia.utils.utils import is_iter, make_iter, string_partial_matching
-from evennia.utils.utils import class_from_module, dbid_to_obj
-from evennia.server import signals
-
-
-__all__ = ("ObjectManager", "ObjectDBManager")
-_GA = object.__getattribute__
-
-# delayed import
-_ATTR = None
-
-_MULTIMATCH_REGEX = re.compile(settings.SEARCH_MULTIMATCH_REGEX, re.I + re.U)
-
-# Try to use a custom way to parse id-tagged multimatches.
-
-
-
[docs]class ObjectDBManager(TypedObjectManager): - """ - This ObjectManager implements methods for searching - and manipulating Objects directly from the database. - - Evennia-specific search methods (will return Typeclasses or - lists of Typeclasses, whereas Django-general methods will return - Querysets or database objects). - - dbref (converter) - dbref_search - get_dbref_range - object_totals - typeclass_search - get_object_with_account - get_objs_with_key_and_typeclass - get_objs_with_attr - get_objs_with_attr_match - get_objs_with_db_property - get_objs_with_db_property_match - get_objs_with_key_or_alias - get_contents - object_search (interface to many of the above methods, - equivalent to evennia.search_object) - copy_object - - """ - - # - # ObjectManager Get methods - # - - # account related - -
[docs] def get_object_with_account(self, ostring, exact=True, candidates=None): - """ - Search for an object based on its account's name or dbref. - - Args: - ostring (str or int): Search criterion or dbref. Searching - for an account is sometimes initiated by appending an `*` to - the beginning of the search criterion (e.g. in - local_and_global_search). This is stripped here. - exact (bool, optional): Require an exact account match. - candidates (list, optional): Only search among this list of possible - object candidates. - - Return: - match (query): Matching query. - - """ - ostring = str(ostring).lstrip("*") - # simplest case - search by dbref - dbref = self.dbref(ostring) - if dbref: - try: - return self.get(db_account__id=dbref) - except self.model.DoesNotExist: - pass - - # not a dbref. Search by name. - cand_restriction = ( - candidates is not None - and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) - or Q() - ) - if exact: - return self.filter(cand_restriction & Q(db_account__username__iexact=ostring)).order_by( - "id" - ) - else: # fuzzy matching - obj_cands = self.select_related().filter( - cand_restriction & Q(db_account__username__istartswith=ostring) - ) - acct_cands = [obj.account for obj in obj_cands] - - if obj_cands: - index_matches = string_partial_matching( - [acct.key for acct in acct_cands], ostring, ret_index=True - ) - acct_cands = [acct_cands[i].id for i in index_matches] - return obj_cands.filter(db_account__id__in=acct_cands).order_by("id")
- -
[docs] def get_objs_with_key_and_typeclass(self, oname, otypeclass_path, candidates=None): - """ - Returns objects based on simultaneous key and typeclass match. - - Args: - oname (str): Object key to search for - otypeclass_path (str): Full Python path to tyepclass to search for - candidates (list, optional): Only match among the given list of candidates. - - Returns: - matches (query): The matching objects. - """ - cand_restriction = ( - candidates is not None - and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) - or Q() - ) - return self.filter( - cand_restriction & Q(db_key__iexact=oname, db_typeclass_path__exact=otypeclass_path) - ).order_by("id")
- - # attr/property related - -
[docs] def get_objs_with_attr(self, attribute_name, candidates=None): - """ - Get objects based on having a certain Attribute defined. - - Args: - attribute_name (str): Attribute name to search for. - candidates (list, optional): Only match among the given list of object - candidates. - - Returns: - matches (query): All objects having the given attribute_name defined at all. - - """ - cand_restriction = ( - candidates is not None and Q(id__in=[obj.id for obj in candidates]) or Q() - ) - return self.filter(cand_restriction & Q(db_attributes__db_key=attribute_name)).order_by( - "id" - )
- -
[docs] def get_objs_with_attr_value( - self, attribute_name, attribute_value, candidates=None, typeclasses=None - ): - """ - Get all objects having the given attrname set to the given value. - - Args: - attribute_name (str): Attribute key to search for. - attribute_value (any): Attribute value to search for. This can also be database - objects. - candidates (list, optional): Candidate objects to limit search to. - typeclasses (list, optional): Python pats to restrict matches with. - - Returns: - Queryset: Iterable with 0, 1 or more matches fullfilling both the `attribute_name` and - `attribute_value` criterions. - - Notes: - This uses the Attribute's PickledField to transparently search the database by matching - the internal representation. This is reasonably effective but since Attribute values - cannot be indexed, searching by Attribute key is to be preferred whenever possible. - - """ - cand_restriction = ( - candidates is not None - and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) - or Q() - ) - type_restriction = typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q() - - results = self.filter( - cand_restriction - & type_restriction - & Q(db_attributes__db_key=attribute_name) - & Q(db_attributes__db_value=attribute_value) - ).order_by("id") - return results
- -
[docs] def get_objs_with_db_property(self, property_name, candidates=None): - """ - Get all objects having a given db field property. - - Args: - property_name (str): The name of the field to match for. - candidates (list, optional): Only search among th egiven candidates. - - Returns: - matches (list): The found matches. - - """ - property_name = "db_%s" % property_name.lstrip("db_") - cand_restriction = ( - candidates is not None - and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) - or Q() - ) - querykwargs = {property_name: None} - try: - return list(self.filter(cand_restriction).exclude(Q(**querykwargs)).order_by("id")) - except exceptions.FieldError: - return []
- -
[docs] def get_objs_with_db_property_value( - self, property_name, property_value, candidates=None, typeclasses=None - ): - """ - Get objects with a specific field name and value. - - Args: - property_name (str): Field name to search for. - property_value (any): Value required for field with `property_name` to have. - candidates (list, optional): List of objects to limit search to. - typeclasses (list, optional): List of typeclass-path strings to restrict matches with - - Returns: - Queryset: Iterable with 0, 1 or more matches. - - """ - if isinstance(property_name, str): - if not property_name.startswith("db_"): - property_name = "db_%s" % property_name - querykwargs = {property_name: property_value} - cand_restriction = ( - candidates is not None - and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) - or Q() - ) - type_restriction = typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q() - try: - return self.filter( - cand_restriction & type_restriction & Q(**querykwargs)).order_by("id") - except exceptions.FieldError: - return self.none() - except ValueError: - from evennia.utils import logger - - logger.log_err( - "The property '%s' does not support search criteria of the type %s." - % (property_name, type(property_value)) - ) - return self.none()
- -
[docs] def get_contents(self, location, excludeobj=None): - """ - Get all objects that has a location set to this one. - - Args: - location (Object): Where to get contents from. - excludeobj (Object or list, optional): One or more objects - to exclude from the match. - - Returns: - Queryset: Iterable with 0, 1 or more matches. - - """ - exclude_restriction = ( - Q(pk__in=[_GA(obj, "id") for obj in make_iter(excludeobj)]) if excludeobj else Q() - ) - return self.filter(db_location=location).exclude(exclude_restriction).order_by("id")
- -
[docs] def get_objs_with_key_or_alias(self, ostring, exact=True, candidates=None, typeclasses=None): - """ - Args: - ostring (str): A search criterion. - exact (bool, optional): Require exact match of ostring - (still case-insensitive). If `False`, will do fuzzy matching - using `evennia.utils.utils.string_partial_matching` algorithm. - candidates (list): Only match among these candidates. - typeclasses (list): Only match objects with typeclasses having thess path strings. - - Returns: - Queryset: An iterable with 0, 1 or more matches. - - """ - if not isinstance(ostring, str): - if hasattr(ostring, "key"): - ostring = ostring.key - else: - return self.none() - if is_iter(candidates) and not len(candidates): - # if candidates is an empty iterable there can be no matches - # Exit early. - return self.none() - - # build query objects - candidates_id = [_GA(obj, "id") for obj in make_iter(candidates) if obj] - cand_restriction = candidates is not None and Q(pk__in=candidates_id) or Q() - type_restriction = typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q() - if exact: - # exact match - do direct search - return ( - ( - self.filter( - cand_restriction - & type_restriction - & ( - Q(db_key__iexact=ostring) - | Q(db_tags__db_key__iexact=ostring) - & Q(db_tags__db_tagtype__iexact="alias") - ) - ) - ) - .distinct() - .order_by("id") - ) - elif candidates: - # fuzzy with candidates - search_candidates = ( - self.filter(cand_restriction & type_restriction).distinct().order_by("id") - ) - else: - # fuzzy without supplied candidates - we select our own candidates - search_candidates = ( - self.filter( - type_restriction - & (Q(db_key__istartswith=ostring) | Q(db_tags__db_key__istartswith=ostring)) - ) - .distinct() - .order_by("id") - ) - # fuzzy matching - key_strings = search_candidates.values_list("db_key", flat=True).order_by("id") - - match_ids = [] - index_matches = string_partial_matching(key_strings, ostring, ret_index=True) - if index_matches: - # a match by key - match_ids = [obj.id for ind, obj in enumerate(search_candidates) - if ind in index_matches] - else: - # match by alias rather than by key - search_candidates = search_candidates.filter( - db_tags__db_tagtype__iexact="alias", db_tags__db_key__icontains=ostring - ).distinct() - alias_strings = [] - alias_candidates = [] - # TODO create the alias_strings and alias_candidates lists more efficiently? - for candidate in search_candidates: - for alias in candidate.aliases.all(): - alias_strings.append(alias) - alias_candidates.append(candidate) - index_matches = string_partial_matching(alias_strings, ostring, ret_index=True) - if index_matches: - # it's possible to have multiple matches to the same Object, we must weed those out - match_ids = [alias_candidates[ind].id for ind in index_matches] - # TODO - not ideal to have to do a second lookup here, but we want to return a queryset - # rather than a list ... maybe the above queries can be improved. - return self.filter(id__in=match_ids)
- - # main search methods and helper functions - -
[docs] def search_object( - self, - searchdata, - attribute_name=None, - typeclass=None, - candidates=None, - exact=True, - use_dbref=True, - ): - """ - Search as an object globally or in a list of candidates and - return results. The result is always an Object. Always returns - a list. - - Args: - searchdata (str or Object): The entity to match for. This is - usually a key string but may also be an object itself. - By default (if no `attribute_name` is set), this will - search `object.key` and `object.aliases` in order. - Can also be on the form #dbref, which will (if - `exact=True`) be matched against primary key. - attribute_name (str): Use this named Attribute to - match searchdata against, instead of the defaults. If - this is the name of a database field (with or without - the `db_` prefix), that will be matched too. - typeclass (str or TypeClass): restrict matches to objects - having this typeclass. This will help speed up global - searches. - candidates (list): If supplied, search will - only be performed among the candidates in this list. A - common list of candidates is the contents of the - current location searched. - exact (bool): Match names/aliases exactly or partially. - Partial matching matches the beginning of words in the - names/aliases, using a matching routine to separate - multiple matches in names with multiple components (so - "bi sw" will match "Big sword"). Since this is more - expensive than exact matching, it is recommended to be - used together with the `candidates` keyword to limit the - number of possibilities. This value has no meaning if - searching for attributes/properties. - use_dbref (bool): If False, bypass direct lookup of a string - on the form #dbref and treat it like any string. - - Returns: - matches (list): Matching objects - - """ - - def _searcher(searchdata, candidates, typeclass, exact=False): - """ - Helper method for searching objects. `typeclass` is only used - for global searching (no candidates) - """ - if attribute_name: - # attribute/property search (always exact). - matches = self.get_objs_with_db_property_value( - attribute_name, searchdata, candidates=candidates, typeclasses=typeclass - ) - if matches: - return matches - return self.get_objs_with_attr_value( - attribute_name, searchdata, candidates=candidates, typeclasses=typeclass - ) - else: - # normal key/alias search - return self.get_objs_with_key_or_alias( - searchdata, exact=exact, candidates=candidates, typeclasses=typeclass - ) - - if not searchdata and searchdata != 0: - return self.none() - - if typeclass: - # typeclass may also be a list - typeclasses = make_iter(typeclass) - for i, typeclass in enumerate(make_iter(typeclasses)): - if callable(typeclass): - typeclasses[i] = "%s.%s" % (typeclass.__module__, typeclass.__name__) - else: - typeclasses[i] = "%s" % typeclass - typeclass = typeclasses - - if candidates is not None: - if not candidates: - # candidates is the empty list. This should mean no matches can ever be acquired. - return [] - # Convenience check to make sure candidates are really dbobjs - candidates = [cand for cand in make_iter(candidates) if cand] - if typeclass: - candidates = [ - cand for cand in candidates if _GA(cand, "db_typeclass_path") in typeclass - ] - - dbref = not attribute_name and exact and use_dbref and self.dbref(searchdata) - if dbref: - # Easiest case - dbref matching (always exact) - dbref_match = self.dbref_search(dbref) - if dbref_match: - dmatch = dbref_match[0] - if not candidates or dmatch in candidates: - return dbref_match - else: - return self.none() - - # Search through all possibilities. - match_number = None - # always run first check exact - we don't want partial matches - # if on the form of 1-keyword etc. - matches = _searcher(searchdata, candidates, typeclass, exact=True) - if not matches: - # no matches found - check if we are dealing with N-keyword - # query - if so, strip it. - match = _MULTIMATCH_REGEX.match(str(searchdata)) - match_number = None - if match: - # strips the number - match_number, searchdata = match.group("number"), match.group("name") - match_number = int(match_number) - 1 - if match_number is not None or not exact: - # run search again, with the exactness set by call - matches = _searcher(searchdata, candidates, typeclass, exact=exact) - - # deal with result - if len(matches) == 1 and match_number is not None and match_number != 0: - # this indicates trying to get a single match with a match-number - # targeting some higher-number match (like 2-box when there is only - # one box in the room). This leads to a no-match. - matches = self.none() - elif len(matches) > 1 and match_number is not None: - # multiple matches, but a number was given to separate them - if 0 <= match_number < len(matches): - # limit to one match (we still want a queryset back) - # TODO: Can we do this some other way and avoid a second lookup? - matches = self.filter(id=matches[match_number].id) - else: - # a number was given outside of range. This means a no-match. - matches = self.none() - - # return a list (possibly empty) - return matches
- - # alias for backwards compatibility - object_search = search_object - search = search_object - - # - # ObjectManager Copy method - -
[docs] def copy_object( - self, - original_object, - new_key=None, - new_location=None, - new_home=None, - new_permissions=None, - new_locks=None, - new_aliases=None, - new_destination=None, - ): - """ - Create and return a new object as a copy of the original object. All - will be identical to the original except for the arguments given - specifically to this method. Object contents will not be copied. - - Args: - original_object (Object): The object to make a copy from. - new_key (str, optional): Name of the copy, if different - from the original. - new_location (Object, optional): Alternate location. - new_home (Object, optional): Change the home location - new_aliases (list, optional): Give alternate object - aliases as a list of strings. - new_destination (Object, optional): Used only by exits. - - Returns: - copy (Object or None): The copy of `original_object`, - optionally modified as per the ingoing keyword - arguments. `None` if an error was encountered. - - """ - - # get all the object's stats - typeclass_path = original_object.typeclass_path - if not new_key: - new_key = original_object.key - if not new_location: - new_location = original_object.location - if not new_home: - new_home = original_object.home - if not new_aliases: - new_aliases = original_object.aliases.all() - if not new_locks: - new_locks = original_object.db_lock_storage - if not new_permissions: - new_permissions = original_object.permissions.all() - if not new_destination: - new_destination = original_object.destination - - # create new object - from evennia.utils import create - from evennia.scripts.models import ScriptDB - - new_object = create.create_object( - typeclass_path, - key=new_key, - location=new_location, - home=new_home, - permissions=new_permissions, - locks=new_locks, - aliases=new_aliases, - destination=new_destination, - ) - if not new_object: - return None - - # copy over all attributes from old to new. - attrs = ( - (a.key, a.value, a.category, a.lock_storage) for a in original_object.attributes.all() - ) - new_object.attributes.batch_add(*attrs) - - # copy over all cmdsets, if any - for icmdset, cmdset in enumerate(original_object.cmdset.all()): - if icmdset == 0: - new_object.cmdset.add_default(cmdset) - else: - new_object.cmdset.add(cmdset) - - # copy over all scripts, if any - for script in original_object.scripts.all(): - ScriptDB.objects.copy_script(script, new_obj=new_object) - - # copy over all tags, if any - tags = ( - (t.db_key, t.db_category, t.db_data) for t in original_object.tags.all(return_objs=True) - ) - new_object.tags.batch_add(*tags) - - return new_object
- -
[docs] def clear_all_sessids(self): - """ - Clear the db_sessid field of all objects having also the - db_account field set. - - """ - self.filter(db_sessid__isnull=False).update(db_sessid=None)
- -
[docs] def create_object( - self, - typeclass=None, - key=None, - location=None, - home=None, - permissions=None, - locks=None, - aliases=None, - tags=None, - destination=None, - report_to=None, - nohome=False, - attributes=None, - nattributes=None, - ): - """ - - Create a new in-game object. - - Keyword Args: - typeclass (class or str): Class or python path to a typeclass. - key (str): Name of the new object. If not set, a name of - `#dbref` will be set. - location (Object or str): Obj or #dbref to use as the location of the new object. - home (Object or str): Obj or #dbref to use as the object's home location. - permissions (list): A list of permission strings or tuples (permstring, category). - locks (str): one or more lockstrings, separated by semicolons. - aliases (list): A list of alternative keys or tuples (aliasstring, category). - tags (list): List of tag keys or tuples (tagkey, category) or (tagkey, category, data). - destination (Object or str): Obj or #dbref to use as an Exit's target. - report_to (Object): The object to return error messages to. - nohome (bool): This allows the creation of objects without a - default home location; only used when creating the default - location itself or during unittests. - attributes (list): Tuples on the form (key, value) or (key, value, category), - (key, value, lockstring) or (key, value, lockstring, default_access). - to set as Attributes on the new object. - nattributes (list): Non-persistent tuples on the form (key, value). Note that - adding this rarely makes sense since this data will not survive a reload. - - Returns: - object (Object): A newly created object of the given typeclass. - - Raises: - ObjectDB.DoesNotExist: If trying to create an Object with - `location` or `home` that can't be found. - - """ - typeclass = typeclass if typeclass else settings.BASE_OBJECT_TYPECLASS - - # convenience converters to avoid common usage mistake - permissions = make_iter(permissions) if permissions is not None else None - locks = make_iter(locks) if locks is not None else None - aliases = make_iter(aliases) if aliases is not None else None - tags = make_iter(tags) if tags is not None else None - attributes = make_iter(attributes) if attributes is not None else None - - if isinstance(typeclass, str): - # a path is given. Load the actual typeclass - typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS) - - # Setup input for the create command. We use ObjectDB as baseclass here - # to give us maximum freedom (the typeclasses will load - # correctly when each object is recovered). - - location = dbid_to_obj(location, self.model) - destination = dbid_to_obj(destination, self.model) - - if home: - home_obj_or_dbref = home - elif nohome: - home_obj_or_dbref = None - else: - home_obj_or_dbref = settings.DEFAULT_HOME - - try: - home = dbid_to_obj(home_obj_or_dbref, self.model) - except self.model.DoesNotExist: - if settings._TEST_ENVIRONMENT: - # this happens for databases where the #1 location is flushed during tests - home = None - else: - raise self.model.DoesNotExist( - f"settings.DEFAULT_HOME (= '{settings.DEFAULT_HOME}') does not exist, " - "or the setting is malformed." - ) - - # create new instance - new_object = typeclass( - db_key=key, - db_location=location, - db_destination=destination, - db_home=home, - db_typeclass_path=typeclass.path, - ) - # store the call signature for the signal - new_object._createdict = dict( - key=key, - location=location, - destination=destination, - home=home, - typeclass=typeclass.path, - permissions=permissions, - locks=locks, - aliases=aliases, - tags=tags, - report_to=report_to, - nohome=nohome, - attributes=attributes, - nattributes=nattributes, - ) - # this will trigger the save signal which in turn calls the - # at_first_save hook on the typeclass, where the _createdict can be - # used. - new_object.save() - - signals.SIGNAL_OBJECT_POST_CREATE.send(sender=new_object) - - return new_object
- - -
[docs]class ObjectManager(ObjectDBManager, TypeclassManager): - pass
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/objects/models.html b/docs/0.9.5/_modules/evennia/objects/models.html deleted file mode 100644 index d0b7555d45..0000000000 --- a/docs/0.9.5/_modules/evennia/objects/models.html +++ /dev/null @@ -1,497 +0,0 @@ - - - - - - - - evennia.objects.models — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.objects.models

-"""
-This module defines the database models for all in-game objects, that
-is, all objects that has an actual existence in-game.
-
-Each database object is 'decorated' with a 'typeclass', a normal
-python class that implements all the various logics needed by the game
-in question. Objects created of this class transparently communicate
-with its related database object for storing all attributes. The
-admin should usually not have to deal directly with this database
-object layer.
-
-Attributes are separate objects that store values persistently onto
-the database object. Like everything else, they can be accessed
-transparently through the decorating TypeClass.
-"""
-from collections import defaultdict
-from django.conf import settings
-from django.db import models
-from django.core.exceptions import ObjectDoesNotExist
-from django.core.validators import validate_comma_separated_integer_list
-
-from evennia.typeclasses.models import TypedObject
-from evennia.objects.manager import ObjectDBManager
-from evennia.utils import logger
-from evennia.utils.utils import make_iter, dbref, lazy_property
-
-
-
[docs]class ContentsHandler: - """ - Handles and caches the contents of an object to avoid excessive - lookups (this is done very often due to cmdhandler needing to look - for object-cmdsets). It is stored on the 'contents_cache' property - of the ObjectDB. - """ - -
[docs] def __init__(self, obj): - """ - Sets up the contents handler. - - Args: - obj (Object): The object on which the - handler is defined - - """ - self.obj = obj - self._pkcache = set() - self._idcache = obj.__class__.__instance_cache__ - self._typecache = defaultdict(set) - self.init()
- -
[docs] def load(self): - """ - Retrieves all objects from database. Used for initializing. - - Returns: - Objects (list of ObjectDB) - """ - return list(self.obj.locations_set.all())
- -
[docs] def init(self): - """ - Re-initialize the content cache - - """ - objects = self.load() - self._pkcache = {obj.pk for obj in objects} - for obj in objects: - for ctype in obj._content_types: - self._typecache[ctype].add(obj.pk)
- -
[docs] def get(self, exclude=None, content_type=None): - """ - Return the contents of the cache. - - Args: - exclude (Object or list of Object): object(s) to ignore - content_type (str or None): Filter list by a content-type. If None, don't filter. - - Returns: - objects (list): the Objects inside this location - - """ - if content_type is not None: - pks = self._typecache[content_type] - else: - pks = self._pkcache - if exclude: - pks = pks - {excl.pk for excl in make_iter(exclude)} - try: - return [self._idcache[pk] for pk in pks] - except KeyError: - # this can happen if the idmapper cache was cleared for an object - # in the contents cache. If so we need to re-initialize and try again. - self.init() - try: - return [self._idcache[pk] for pk in pks] - except KeyError: - # this means an actual failure of caching. Return real database match. - logger.log_err("contents cache failed for %s." % self.obj.key) - return self.load()
- -
[docs] def add(self, obj): - """ - Add a new object to this location - - Args: - obj (Object): object to add - - """ - self._pkcache.add(obj.pk) - for ctype in obj._content_types: - self._typecache[ctype].add(obj.pk)
- -
[docs] def remove(self, obj): - """ - Remove object from this location - - Args: - obj (Object): object to remove - - """ - try: - self._pkcache.remove(obj.pk) - except KeyError: - # not in pk cache, but can happen deletions happens - # remotely from out-of-thread. - pass - for ctype in obj._content_types: - if obj.pk in self._typecache[ctype]: - self._typecache[ctype].remove(obj.pk)
- -
[docs] def clear(self): - """ - Clear the contents cache and re-initialize - - """ - self._pkcache = {} - self._typecache = defaultdict(set) - self.init()
- - -# ------------------------------------------------------------- -# -# ObjectDB -# -# ------------------------------------------------------------- - - -
[docs]class ObjectDB(TypedObject): - """ - All objects in the game use the ObjectDB model to store - data in the database. This is handled transparently through - the typeclass system. - - Note that the base objectdb is very simple, with - few defined fields. Use attributes to extend your - type class with new database-stored variables. - - The TypedObject supplies the following (inherited) properties: - - - key - main name - - name - alias for key - - db_typeclass_path - the path to the decorating typeclass - - db_date_created - time stamp of object creation - - permissions - perm strings - - locks - lock definitions (handler) - - dbref - #id of object - - db - persistent attribute storage - - ndb - non-persistent attribute storage - - The ObjectDB adds the following properties: - - - account - optional connected account (always together with sessid) - - sessid - optional connection session id (always together with account) - - location - in-game location of object - - home - safety location for object (handler) - - scripts - scripts assigned to object (handler from typeclass) - - cmdset - active cmdset on object (handler from typeclass) - - aliases - aliases for this object (property) - - nicks - nicknames for *other* things in Evennia (handler) - - sessions - sessions connected to this object (see also account) - - has_account - bool if an active account is currently connected - - contents - other objects having this object as location - - exits - exits from this object - - """ - - # - # ObjectDB Database model setup - # - # - # inherited fields (from TypedObject): - # db_key (also 'name' works), db_typeclass_path, db_date_created, - # db_permissions - # - # These databse fields (including the inherited ones) should normally be - # managed by their corresponding wrapper properties, named same as the - # field, but without the db_* prefix (e.g. the db_key field is set with - # self.key instead). The wrappers are created at the metaclass level and - # will automatically save and cache the data more efficiently. - - # If this is a character object, the account is connected here. - db_account = models.ForeignKey( - "accounts.AccountDB", - null=True, - verbose_name="account", - on_delete=models.SET_NULL, - help_text="an Account connected to this object, if any.", - ) - - # the session id associated with this account, if any - db_sessid = models.CharField( - null=True, - max_length=32, - validators=[validate_comma_separated_integer_list], - verbose_name="session id", - help_text="csv list of session ids of connected Account, if any.", - ) - # The location in the game world. Since this one is likely - # to change often, we set this with the 'location' property - # to transparently handle Typeclassing. - db_location = models.ForeignKey( - "self", - related_name="locations_set", - db_index=True, - on_delete=models.SET_NULL, - blank=True, - null=True, - verbose_name="game location", - ) - # a safety location, this usually don't change much. - db_home = models.ForeignKey( - "self", - related_name="homes_set", - on_delete=models.SET_NULL, - blank=True, - null=True, - verbose_name="home location", - ) - # destination of this object - primarily used by exits. - db_destination = models.ForeignKey( - "self", - related_name="destinations_set", - db_index=True, - on_delete=models.SET_NULL, - blank=True, - null=True, - verbose_name="destination", - help_text="a destination, used only by exit objects.", - ) - # database storage of persistant cmdsets. - db_cmdset_storage = models.CharField( - "cmdset", - max_length=255, - null=True, - blank=True, - help_text="optional python path to a cmdset class.", - ) - - # Database manager - objects = ObjectDBManager() - - # defaults - __settingsclasspath__ = settings.BASE_OBJECT_TYPECLASS - __defaultclasspath__ = "evennia.objects.objects.DefaultObject" - __applabel__ = "objects" - -
[docs] @lazy_property - def contents_cache(self): - return ContentsHandler(self)
- - # cmdset_storage property handling - def __cmdset_storage_get(self): - """getter""" - storage = self.db_cmdset_storage - return [path.strip() for path in storage.split(",")] if storage else [] - - def __cmdset_storage_set(self, value): - """setter""" - self.db_cmdset_storage = ",".join(str(val).strip() for val in make_iter(value)) - self.save(update_fields=["db_cmdset_storage"]) - - def __cmdset_storage_del(self): - """deleter""" - self.db_cmdset_storage = None - self.save(update_fields=["db_cmdset_storage"]) - - cmdset_storage = property(__cmdset_storage_get, __cmdset_storage_set, __cmdset_storage_del) - - # location getsetter - def __location_get(self): - """Get location""" - return self.db_location - - def __location_set(self, location): - """Set location, checking for loops and allowing dbref""" - if isinstance(location, (str, int)): - # allow setting of #dbref - dbid = dbref(location, reqhash=False) - if dbid: - try: - location = ObjectDB.objects.get(id=dbid) - except ObjectDoesNotExist: - # maybe it is just a name that happens to look like a dbid - pass - try: - - def is_loc_loop(loc, depth=0): - """Recursively traverse target location, trying to catch a loop.""" - if depth > 10: - return None - elif loc == self: - raise RuntimeError - elif loc is None: - raise RuntimeWarning - return is_loc_loop(loc.db_location, depth + 1) - - try: - is_loc_loop(location) - except RuntimeWarning: - # we caught an infinite location loop! - # (location1 is in location2 which is in location1 ...) - pass - - # if we get to this point we are ready to change location - - old_location = self.db_location - - # this is checked in _db_db_location_post_save below - self._safe_contents_update = True - - # actually set the field (this will error if location is invalid) - self.db_location = location - self.save(update_fields=["db_location"]) - - # remove the safe flag - del self._safe_contents_update - - # update the contents cache - if old_location: - old_location.contents_cache.remove(self) - if self.db_location: - self.db_location.contents_cache.add(self) - - except RuntimeError: - errmsg = "Error: %s.location = %s creates a location loop." % (self.key, location) - raise RuntimeError(errmsg) - except Exception: - # raising here gives more info for now - raise - # errmsg = "Error (%s): %s is not a valid location." % (str(e), location) - # raise RuntimeError(errmsg) - return - - def __location_del(self): - """Cleanly delete the location reference""" - self.db_location = None - self.save(update_fields=["db_location"]) - - location = property(__location_get, __location_set, __location_del) - -
[docs] def at_db_location_postsave(self, new): - """ - This is called automatically after the location field was - saved, no matter how. It checks for a variable - _safe_contents_update to know if the save was triggered via - the location handler (which updates the contents cache) or - not. - - Args: - new (bool): Set if this location has not yet been saved before. - - """ - if not hasattr(self, "_safe_contents_update"): - # changed/set outside of the location handler - if new: - # if new, there is no previous location to worry about - if self.db_location: - self.db_location.contents_cache.add(self) - else: - # Since we cannot know at this point was old_location was, we - # trigger a full-on contents_cache update here. - logger.log_warn( - "db_location direct save triggered contents_cache.init() for all objects!" - ) - [o.contents_cache.init() for o in self.__dbclass__.get_all_cached_instances()]
- - class Meta: - """Define Django meta options""" - - verbose_name = "Object" - verbose_name_plural = "Objects"
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/objects/objects.html b/docs/0.9.5/_modules/evennia/objects/objects.html deleted file mode 100644 index cd262e0f77..0000000000 --- a/docs/0.9.5/_modules/evennia/objects/objects.html +++ /dev/null @@ -1,2967 +0,0 @@ - - - - - - - - evennia.objects.objects — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.objects.objects

-"""
-This module defines the basic `DefaultObject` and its children
-`DefaultCharacter`, `DefaultAccount`, `DefaultRoom` and `DefaultExit`.
-These are the (default) starting points for all in-game visible
-entities.
-
-This is the v1.0 develop version (for ref in doc building).
-
-"""
-import time
-from collections import defaultdict
-
-import inflect
-from django.conf import settings
-from django.utils.translation import gettext as _
-
-from evennia.commands import cmdset
-from evennia.commands.cmdsethandler import CmdSetHandler
-from evennia.objects.manager import ObjectManager
-from evennia.objects.models import ObjectDB
-from evennia.scripts.scripthandler import ScriptHandler
-from evennia.typeclasses.attributes import ModelAttributeBackend, NickHandler
-from evennia.typeclasses.models import TypeclassBase
-from evennia.utils import ansi, create, funcparser, logger, search
-from evennia.utils.utils import (class_from_module, is_iter, lazy_property,
-                                 list_to_string, make_iter, to_str,
-                                 variable_from_module)
-
-_INFLECT = inflect.engine()
-_MULTISESSION_MODE = settings.MULTISESSION_MODE
-
-_ScriptDB = None
-_SESSIONS = None
-_CMDHANDLER = None
-
-_AT_SEARCH_RESULT = variable_from_module(*settings.SEARCH_AT_RESULT.rsplit(".", 1))
-_COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
-# the sessid_max is based on the length of the db_sessid csv field (excluding commas)
-_SESSID_MAX = 16 if _MULTISESSION_MODE in (1, 3) else 1
-
-# init the actor-stance funcparser for msg_contents
-_MSG_CONTENTS_PARSER = funcparser.FuncParser(funcparser.ACTOR_STANCE_CALLABLES)
-
-
-
[docs]class ObjectSessionHandler: - """ - Handles the get/setting of the sessid comma-separated integer field - - """ - -
[docs] def __init__(self, obj): - """ - Initializes the handler. - - Args: - obj (Object): The object on which the handler is defined. - - """ - self.obj = obj - self._sessid_cache = [] - self._recache()
- - def _recache(self): - global _SESSIONS - if not _SESSIONS: - from evennia.server.sessionhandler import SESSIONS as _SESSIONS - self._sessid_cache = list( - set(int(val) for val in (self.obj.db_sessid or "").split(",") if val) - ) - if any(sessid for sessid in self._sessid_cache if sessid not in _SESSIONS): - # cache is out of sync with sessionhandler! Only retain the ones in the handler. - self._sessid_cache = [sessid for sessid in self._sessid_cache if sessid in _SESSIONS] - self.obj.db_sessid = ",".join(str(val) for val in self._sessid_cache) - self.obj.save(update_fields=["db_sessid"]) - -
[docs] def get(self, sessid=None): - """ - Get the sessions linked to this Object. - - Args: - sessid (int, optional): A specific session id. - - Returns: - sessions (list): The sessions connected to this object. If `sessid` is given, - this is a list of one (or zero) elements. - - Notes: - Aliased to `self.all()`. - - """ - global _SESSIONS - if not _SESSIONS: - from evennia.server.sessionhandler import SESSIONS as _SESSIONS - if sessid: - sessions = ( - [_SESSIONS[sessid] if sessid in _SESSIONS else None] - if sessid in self._sessid_cache - else [] - ) - else: - sessions = [ - _SESSIONS[ssid] if ssid in _SESSIONS else None for ssid in self._sessid_cache - ] - if None in sessions: - # this happens only if our cache has gone out of sync with the SessionHandler. - - return self.get(sessid=sessid) - return sessions
- -
[docs] def all(self): - """ - Alias to get(), returning all sessions. - - Returns: - sessions (list): All sessions. - - """ - return self.get()
- -
[docs] def add(self, session): - """ - Add session to handler. - - Args: - session (Session or int): Session or session id to add. - - Notes: - We will only add a session/sessid if this actually also exists - in the the core sessionhandler. - - """ - global _SESSIONS - if not _SESSIONS: - from evennia.server.sessionhandler import SESSIONS as _SESSIONS - try: - sessid = session.sessid - except AttributeError: - sessid = session - - sessid_cache = self._sessid_cache - if sessid in _SESSIONS and sessid not in sessid_cache: - if len(sessid_cache) >= _SESSID_MAX: - return - sessid_cache.append(sessid) - self.obj.db_sessid = ",".join(str(val) for val in sessid_cache) - self.obj.save(update_fields=["db_sessid"])
- -
[docs] def remove(self, session): - """ - Remove session from handler. - - Args: - session (Session or int): Session or session id to remove. - - """ - try: - sessid = session.sessid - except AttributeError: - sessid = session - - sessid_cache = self._sessid_cache - if sessid in sessid_cache: - sessid_cache.remove(sessid) - self.obj.db_sessid = ",".join(str(val) for val in sessid_cache) - self.obj.save(update_fields=["db_sessid"])
- -
[docs] def clear(self): - """ - Clear all handled sessids. - - """ - self._sessid_cache = [] - self.obj.db_sessid = None - self.obj.save(update_fields=["db_sessid"])
- -
[docs] def count(self): - """ - Get amount of sessions connected. - - Returns: - sesslen (int): Number of sessions handled. - - """ - return len(self._sessid_cache)
- - -# -# Base class to inherit from. - - -
[docs]class DefaultObject(ObjectDB, metaclass=TypeclassBase): - """ - This is the root typeclass object, representing all entities that - have an actual presence in-game. DefaultObjects generally have a - location. They can also be manipulated and looked at. Game - entities you define should inherit from DefaultObject at some distance. - - It is recommended to create children of this class using the - `evennia.create_object()` function rather than to initialize the class - directly - this will both set things up and efficiently save the object - without `obj.save()` having to be called explicitly. - - """ - - # Used for sorting / filtering in inventories / room contents. - _content_types = ("object",) - - # lockstring of newly created objects, for easy overloading. - # Will be formatted with the appropriate attributes. - lockstring = "control:id({account_id}) or perm(Admin);delete:id({account_id}) or perm(Admin)" - - objects = ObjectManager() - - # populated by `return_apperance` - appearance_template = ''' -{header} -|c{name}|n -{desc} -{exits}{characters}{things} -{footer} - ''' - - # on-object properties - -
[docs] @lazy_property - def cmdset(self): - return CmdSetHandler(self, True)
- -
[docs] @lazy_property - def scripts(self): - return ScriptHandler(self)
- -
[docs] @lazy_property - def nicks(self): - return NickHandler(self, ModelAttributeBackend)
- -
[docs] @lazy_property - def sessions(self): - return ObjectSessionHandler(self)
- - @property - def is_connected(self): - # we get an error for objects subscribed to channels without this - if self.account: # seems sane to pass on the account - return self.account.is_connected - else: - return False - - @property - def has_account(self): - """ - Convenience property for checking if an active account is - currently connected to this object. - - """ - return self.sessions.count() - - @property - def is_superuser(self): - """ - Check if user has an account, and if so, if it is a superuser. - - """ - return ( - self.db_account - and self.db_account.is_superuser - and not self.db_account.attributes.get("_quell") - ) - -
[docs] def contents_get(self, exclude=None, content_type=None): - """ - Returns the contents of this object, i.e. all - objects that has this object set as its location. - This should be publically available. - - Args: - exclude (Object): Object to exclude from returned - contents list - content_type (str): A content_type to filter by. None for no - filtering. - - Returns: - contents (list): List of contents of this Object. - - Notes: - Also available as the `contents` property, minus exclusion - and filtering. - - """ - return self.contents_cache.get(exclude=exclude, content_type=content_type)
- -
[docs] def contents_set(self, *args): - "You cannot replace this property" - raise AttributeError( - "{}.contents is read-only. Use obj.move_to or " - "obj.location to move an object here.".format(self.__class__) - )
- - contents = property(contents_get, contents_set, contents_set) - - @property - def exits(self): - """ - Returns all exits from this object, i.e. all objects at this - location having the property destination != `None`. - - """ - return [exi for exi in self.contents if exi.destination] - - # main methods - -
[docs] def get_display_name(self, looker=None, **kwargs): - """ - Displays the name of the object in a viewer-aware manner. - - Args: - looker (TypedObject): The object or account that is looking - at/getting inforamtion for this object. - - Returns: - name (str): A string containing the name of the object, - including the DBREF if this user is privileged to control - said object. - - Notes: - This function could be extended to change how object names - appear to users in character, but be wary. This function - does not change an object's keys or aliases when - searching, and is expected to produce something useful for - builders. - - """ - if looker and self.locks.check_lockstring(looker, "perm(Builder)"): - return "{}(#{})".format(self.name, self.id) - return self.name
- -
[docs] def get_numbered_name(self, count, looker, **kwargs): - """ - Return the numbered (singular, plural) forms of this object's key. This is by default called - by return_appearance and is used for grouping multiple same-named of this object. Note that - this will be called on *every* member of a group even though the plural name will be only - shown once. Also the singular display version, such as 'an apple', 'a tree' is determined - from this method. - - Args: - count (int): Number of objects of this type - looker (Object): Onlooker. Not used by default. - Keyword Args: - key (str): Optional key to pluralize, if given, use this instead of the object's key. - Returns: - singular (str): The singular form to display. - plural (str): The determined plural form of the key, including the count. - - """ - plural_category = "plural_key" - key = kwargs.get("key", self.key) - key = ansi.ANSIString(key) # this is needed to allow inflection of colored names - try: - plural = _INFLECT.plural(key, count) - plural = "{} {}".format(_INFLECT.number_to_words(count, threshold=12), plural) - except IndexError: - # this is raised by inflect if the input is not a proper noun - plural = key - singular = _INFLECT.an(key) - if not self.aliases.get(plural, category=plural_category): - # we need to wipe any old plurals/an/a in case key changed in the interrim - self.aliases.clear(category=plural_category) - self.aliases.add(plural, category=plural_category) - # save the singular form as an alias here too so we can display "an egg" and also - # look at 'an egg'. - self.aliases.add(singular, category=plural_category) - return singular, plural
- -
[docs] def search( - self, - searchdata, - global_search=False, - use_nicks=True, - typeclass=None, - location=None, - attribute_name=None, - quiet=False, - exact=False, - candidates=None, - nofound_string=None, - multimatch_string=None, - use_dbref=None, - stacked=0, - ): - """ - Returns an Object matching a search string/condition - - Perform a standard object search in the database, handling - multiple results and lack thereof gracefully. By default, only - objects in the current `location` of `self` or its inventory are searched for. - - Args: - searchdata (str or obj): Primary search criterion. Will be matched - against `object.key` (with `object.aliases` second) unless - the keyword attribute_name specifies otherwise. - - Special keywords: - - - `#<num>`: search by unique dbref. This is always a global search. - - `me,self`: self-reference to this object - - `<num>-<string>` - can be used to differentiate - between multiple same-named matches. The exact form of this input - is given by `settings.SEARCH_MULTIMATCH_REGEX`. - - global_search (bool): Search all objects globally. This overrules 'location' data. - use_nicks (bool): Use nickname-replace (nicktype "object") on `searchdata`. - typeclass (str or Typeclass, or list of either): Limit search only - to `Objects` with this typeclass. May be a list of typeclasses - for a broader search. - location (Object or list): Specify a location or multiple locations - to search. Note that this is used to query the *contents* of a - location and will not match for the location itself - - if you want that, don't set this or use `candidates` to specify - exactly which objects should be searched. If this nor candidates are - given, candidates will include caller's inventory, current location and - all objects in the current location. - attribute_name (str): Define which property to search. If set, no - key+alias search will be performed. This can be used - to search database fields (db_ will be automatically - prepended), and if that fails, it will try to return - objects having Attributes with this name and value - equal to searchdata. A special use is to search for - "key" here if you want to do a key-search without - including aliases. - quiet (bool): don't display default error messages - this tells the - search method that the user wants to handle all errors - themselves. It also changes the return value type, see - below. - exact (bool): if unset (default) - prefers to match to beginning of - string rather than not matching at all. If set, requires - exact matching of entire string. - candidates (list of objects): this is an optional custom list of objects - to search (filter) between. It is ignored if `global_search` - is given. If not set, this list will automatically be defined - to include the location, the contents of location and the - caller's contents (inventory). - nofound_string (str): optional custom string for not-found error message. - multimatch_string (str): optional custom string for multimatch error header. - use_dbref (bool or None, optional): If `True`, allow to enter e.g. a query "#123" - to find an object (globally) by its database-id 123. If `False`, the string "#123" - will be treated like a normal string. If `None` (default), the ability to query by - #dbref is turned on if `self` has the permission 'Builder' and is turned off - otherwise. - stacked (int, optional): If > 0, multimatches will be analyzed to determine if they - only contains identical objects; these are then assumed 'stacked' and no multi-match - error will be generated, instead `stacked` number of matches will be returned. If - `stacked` is larger than number of matches, returns that number of matches. If - the found stack is a mix of objects, return None and handle the multi-match - error depending on the value of `quiet`. - - Returns: - Object, None or list: Will return an `Object` or `None` if `quiet=False`. Will return - a `list` with 0, 1 or more matches if `quiet=True`. If `stacked` is a positive integer, - this list may contain all stacked identical matches. - - Notes: - To find Accounts, use eg. `evennia.account_search`. If - `quiet=False`, error messages will be handled by - `settings.SEARCH_AT_RESULT` and echoed automatically (on - error, return will be `None`). If `quiet=True`, the error - messaging is assumed to be handled by the caller. - - """ - is_string = isinstance(searchdata, str) - - if is_string: - # searchdata is a string; wrap some common self-references - if searchdata.lower() in ("here",): - return [self.location] if quiet else self.location - if searchdata.lower() in ("me", "self"): - return [self] if quiet else self - - if use_dbref is None: - use_dbref = self.locks.check_lockstring(self, "_dummy:perm(Builder)") - - if use_nicks: - # do nick-replacement on search - searchdata = self.nicks.nickreplace( - searchdata, categories=("object", "account"), include_account=True - ) - - if global_search or ( - is_string - and searchdata.startswith("#") - and len(searchdata) > 1 - and searchdata[1:].isdigit() - ): - # only allow exact matching if searching the entire database - # or unique #dbrefs - exact = True - candidates = None - - elif candidates is None: - # no custom candidates given - get them automatically - if location: - # location(s) were given - candidates = [] - for obj in make_iter(location): - candidates.extend(obj.contents) - else: - # local search. Candidates are taken from - # self.contents, self.location and - # self.location.contents - location = self.location - candidates = self.contents - if location: - candidates = candidates + [location] + location.contents - else: - # normally we don't need this since we are - # included in location.contents - candidates.append(self) - - results = ObjectDB.objects.object_search( - searchdata, - attribute_name=attribute_name, - typeclass=typeclass, - candidates=candidates, - exact=exact, - use_dbref=use_dbref, - ) - - nresults = len(results) - if stacked > 0 and nresults > 1: - # handle stacks, disable multimatch errors - nstack = nresults - if not exact: - # we re-run exact match agains one of the matches to - # make sure we were not catching partial matches not belonging - # to the stack - nstack = len(ObjectDB.objects.get_objs_with_key_or_alias( - results[0].key, - exact=True, - candidates=list(results), - typeclasses=[typeclass] if typeclass else None - )) - if nstack == nresults: - # a valid stack, return multiple results - return list(results)[:stacked] - - if quiet: - # don't auto-handle error messaging - return list(results) - - # handle error messages - return _AT_SEARCH_RESULT( - results, - self, - query=searchdata, - nofound_string=nofound_string, - multimatch_string=multimatch_string, - )
- -
[docs] def search_account(self, searchdata, quiet=False): - """ - Simple shortcut wrapper to search for accounts, not characters. - - Args: - searchdata (str): Search criterion - the key or dbref of the account - to search for. If this is "here" or "me", search - for the account connected to this object. - quiet (bool): Returns the results as a list rather than - echo eventual standard error messages. Default `False`. - - Returns: - result (Account, None or list): Just what is returned depends on - the `quiet` setting: - - `quiet=True`: No match or multumatch auto-echoes errors - to self.msg, then returns `None`. The esults are passed - through `settings.SEARCH_AT_RESULT` and - `settings.SEARCH_AT_MULTIMATCH_INPUT`. If there is a - unique match, this will be returned. - - `quiet=True`: No automatic error messaging is done, and - what is returned is always a list with 0, 1 or more - matching Accounts. - - """ - if isinstance(searchdata, str): - # searchdata is a string; wrap some common self-references - if searchdata.lower() in ("me", "self"): - return [self.account] if quiet else self.account - - results = search.search_account(searchdata) - - if quiet: - return results - return _AT_SEARCH_RESULT(results, self, query=searchdata)
- -
[docs] def execute_cmd(self, raw_string, session=None, **kwargs): - """ - Do something as this object. This is never called normally, - it's only used when wanting specifically to let an object be - the caller of a command. It makes use of nicks of eventual - connected accounts as well. - - Args: - raw_string (string): Raw command input - session (Session, optional): Session to - return results to - - Keyword Args: - Other keyword arguments will be added to the found command - object instace as variables before it executes. This is - unused by default Evennia but may be used to set flags and - change operating paramaters for commands at run-time. - - Returns: - defer (Deferred): This is an asynchronous Twisted object that - will not fire until the command has actually finished - executing. To overload this one needs to attach - callback functions to it, with addCallback(function). - This function will be called with an eventual return - value from the command execution. This return is not - used at all by Evennia by default, but might be useful - for coders intending to implement some sort of nested - command structure. - - """ - # break circular import issues - global _CMDHANDLER - if not _CMDHANDLER: - from evennia.commands.cmdhandler import cmdhandler as _CMDHANDLER - - # nick replacement - we require full-word matching. - # do text encoding conversion - raw_string = self.nicks.nickreplace( - raw_string, categories=("inputline", "channel"), include_account=True - ) - return _CMDHANDLER( - self, raw_string, callertype="object", session=session, **kwargs - )
- -
[docs] def msg(self, text=None, from_obj=None, session=None, options=None, **kwargs): - """ - Emits something to a session attached to the object. - - Args: - text (str or tuple, optional): The message to send. This - is treated internally like any send-command, so its - value can be a tuple if sending multiple arguments to - the `text` oob command. - from_obj (obj or list, optional): object that is sending. If - given, at_msg_send will be called. This value will be - passed on to the protocol. If iterable, will execute hook - on all entities in it. - session (Session or list, optional): Session or list of - Sessions to relay data to, if any. If set, will force send - to these sessions. If unset, who receives the message - depends on the MULTISESSION_MODE. - options (dict, optional): Message-specific option-value - pairs. These will be applied at the protocol level. - Keyword Args: - any (string or tuples): All kwarg keys not listed above - will be treated as send-command names and their arguments - (which can be a string or a tuple). - - Notes: - `at_msg_receive` will be called on this Object. - All extra kwargs will be passed on to the protocol. - - """ - # try send hooks - if from_obj: - for obj in make_iter(from_obj): - try: - obj.at_msg_send(text=text, to_obj=self, **kwargs) - except Exception: - logger.log_trace() - kwargs["options"] = options - try: - if not self.at_msg_receive(text=text, from_obj=from_obj, **kwargs): - # if at_msg_receive returns false, we abort message to this object - return - except Exception: - logger.log_trace() - - if text is not None: - if not (isinstance(text, str) or isinstance(text, tuple)): - # sanitize text before sending across the wire - try: - text = to_str(text) - except Exception: - text = repr(text) - kwargs["text"] = text - - # relay to session(s) - sessions = make_iter(session) if session else self.sessions.all() - for session in sessions: - session.data_out(**kwargs)
- -
[docs] def for_contents(self, func, exclude=None, **kwargs): - """ - Runs a function on every object contained within this one. - - Args: - func (callable): Function to call. This must have the - formal call sign func(obj, **kwargs), where obj is the - object currently being processed and `**kwargs` are - passed on from the call to `for_contents`. - exclude (list, optional): A list of object not to call the - function on. - - Keyword Args: - Keyword arguments will be passed to the function for all objects. - - """ - contents = self.contents - if exclude: - exclude = make_iter(exclude) - contents = [obj for obj in contents if obj not in exclude] - for obj in contents: - func(obj, **kwargs)
- -
[docs] def msg_contents(self, text=None, exclude=None, from_obj=None, mapping=None, **kwargs): - """ - Emits a message to all objects inside this object. - - Args: - text (str or tuple): Message to send. If a tuple, this should be - on the valid OOB outmessage form `(message, {kwargs})`, - where kwargs are optional data passed to the `text` - outputfunc. The message will be parsed for `{key}` formatting and - `$You/$you()/$You()`, `$obj(name)`, `$conj(verb)` and `$pron(pronoun, option)` - inline function callables. - The `name` is taken from the `mapping` kwarg {"name": object, ...}`. - The `mapping[key].get_display_name(looker=recipient)` will be called - for that key for every recipient of the string. - exclude (list, optional): A list of objects not to send to. - from_obj (Object, optional): An object designated as the - "sender" of the message. See `DefaultObject.msg()` for - more info. - mapping (dict, optional): A mapping of formatting keys - `{"key":<object>, "key2":<object2>,...}. - The keys must either match `{key}` or `$You(key)/$you(key)` markers - in the `text` string. If `<object>` doesn't have a `get_display_name` - method, it will be returned as a string. If not set, a key `you` will - be auto-added to point to `from_obj` if given, otherwise to `self`. - **kwargs: Keyword arguments will be passed on to `obj.msg()` for all - messaged objects. - - Notes: - For 'actor-stance' reporting (You say/Name says), use the - `$You()/$you()/$You(key)` and `$conj(verb)` (verb-conjugation) - inline callables. This will use the respective `get_display_name()` - for all onlookers except for `from_obj or self`, which will become - 'You/you'. If you use `$You/you(key)`, the key must be in `mapping`. - - For 'director-stance' reporting (Name says/Name says), use {key} - syntax directly. For both `{key}` and `You/you(key)`, - `mapping[key].get_display_name(looker=recipient)` may be called - depending on who the recipient is. - - Examples: - - Let's assume - - `player1.key -> "Player1"`, - `player1.get_display_name(looker=player2) -> "The First girl"` - - `player2.key -> "Player2"`, - `player2.get_display_name(looker=player1) -> "The Second girl"` - - Actor-stance: - :: - - char.location.msg_contents( - "$You() $conj(attack) $you(defender).", - mapping={"defender": player2}) - - - player1 will see `You attack The Second girl.` - - player2 will see 'The First girl attacks you.' - - Director-stance: - :: - - char.location.msg_contents( - "{attacker} attacks {defender}.", - mapping={"attacker:player1, "defender":player2}) - - - player1 will see: 'Player1 attacks The Second girl.' - - player2 will see: 'The First girl attacks Player2' - - """ - # we also accept an outcommand on the form (message, {kwargs}) - is_outcmd = text and is_iter(text) - inmessage = text[0] if is_outcmd else text - outkwargs = text[1] if is_outcmd and len(text) > 1 else {} - mapping = mapping or {} - you = from_obj or self - - if 'you' not in mapping: - mapping[you] = you - - contents = self.contents - if exclude: - exclude = make_iter(exclude) - contents = [obj for obj in contents if obj not in exclude] - - for receiver in contents: - - # actor-stance replacements - inmessage = _MSG_CONTENTS_PARSER.parse( - inmessage, raise_errors=True, return_string=True, - caller=you, receiver=receiver, mapping=mapping) - - # director-stance replacements - outmessage = inmessage.format( - **{key: obj.get_display_name(looker=receiver) - if hasattr(obj, "get_display_name") else str(obj) - for key, obj in mapping.items()}) - - receiver.msg(text=(outmessage, outkwargs), from_obj=from_obj, **kwargs)
- -
[docs] def move_to( - self, - destination, - quiet=False, - emit_to_obj=None, - use_destination=True, - to_none=False, - move_hooks=True, - **kwargs, - ): - """ - Moves this object to a new location. - - Args: - destination (Object): Reference to the object to move to. This - can also be an exit object, in which case the - destination property is used as destination. - quiet (bool): If true, turn off the calling of the emit hooks - (announce_move_to/from etc) - emit_to_obj (Object): object to receive error messages - use_destination (bool): Default is for objects to use the "destination" - property of destinations as the target to move to. Turning off this - keyword allows objects to move "inside" exit objects. - to_none (bool): Allow destination to be None. Note that no hooks are run when - moving to a None location. If you want to run hooks, run them manually - (and make sure they can manage None locations). - move_hooks (bool): If False, turn off the calling of move-related hooks - (at_pre/post_move etc) with quiet=True, this is as quiet a move - as can be done. - - Keyword Args: - Passed on to announce_move_to and announce_move_from hooks. - - Returns: - result (bool): True/False depending on if there were problems with the move. - This method may also return various error messages to the - `emit_to_obj`. - - Notes: - No access checks are done in this method, these should be handled before - calling `move_to`. - - The `DefaultObject` hooks called (if `move_hooks=True`) are, in order: - - 1. `self.at_pre_move(destination)` (if this returns False, move is aborted) - 2. `source_location.at_object_leave(self, destination)` - 3. `self.announce_move_from(destination)` - 4. (move happens here) - 5. `self.announce_move_to(source_location)` - 6. `destination.at_object_receive(self, source_location)` - 7. `self.at_post_move(source_location)` - - """ - def logerr(string="", err=None): - """Simple log helper method""" - logger.log_trace() - self.msg("%s%s" % (string, "" if err is None else " (%s)" % err)) - return - - errtxt = _("Couldn't perform move ({err}). Contact an admin.") - if not emit_to_obj: - emit_to_obj = self - - if not destination: - if to_none: - # immediately move to None. There can be no hooks called since - # there is no destination to call them with. - self.location = None - return True - emit_to_obj.msg(_("The destination doesn't exist.")) - return False - if destination.destination and use_destination: - # traverse exits - destination = destination.destination - # Before the move, call eventual pre-commands. - if move_hooks: - try: - if not self.at_pre_move(destination, **kwargs): - return False - except Exception as err: - logerr(errtxt.format(err="at_pre_move()"), err) - return False - - # Save the old location - source_location = self.location - - # Call hook on source location - if move_hooks and source_location: - try: - source_location.at_object_leave(self, destination, **kwargs) - except Exception as err: - logerr(errtxt.format(err="at_object_leave()"), err) - return False - - if not quiet: - # tell the old room we are leaving - try: - self.announce_move_from(destination, **kwargs) - except Exception as err: - logerr(errtxt.format(err="at_announce_move()"), err) - return False - - # Perform move - try: - self.location = destination - except Exception as err: - logerr(errtxt.format(err="location change"), err) - return False - - if not quiet: - # Tell the new room we are there. - try: - self.announce_move_to(source_location, **kwargs) - except Exception as err: - logerr(errtxt.format(err="announce_move_to()"), err) - return False - - if move_hooks: - # Perform eventual extra commands on the receiving location - # (the object has already arrived at this point) - try: - destination.at_object_receive(self, source_location, **kwargs) - except Exception as err: - logerr(errtxt.format(err="at_object_receive()"), err) - return False - - # Execute eventual extra commands on this object after moving it - # (usually calling 'look') - if move_hooks: - try: - self.at_post_move(source_location, **kwargs) - except Exception as err: - logerr(errtxt.format(err="at_post_move"), err) - return False - return True
- -
[docs] def clear_exits(self): - """ - Destroys all of the exits and any exits pointing to this - object as a destination. - - """ - for out_exit in [exi for exi in ObjectDB.objects.get_contents(self) if exi.db_destination]: - out_exit.delete() - for in_exit in ObjectDB.objects.filter(db_destination=self): - in_exit.delete()
- -
[docs] def clear_contents(self): - """ - Moves all objects (accounts/things) to their home location or - to default home. - - """ - # Gather up everything that thinks this is its location. - default_home_id = int(settings.DEFAULT_HOME.lstrip("#")) - try: - default_home = ObjectDB.objects.get(id=default_home_id) - if default_home.dbid == self.dbid: - # we are deleting default home! - default_home = None - except Exception: - string = _("Could not find default home '(#{dbid})'.") - logger.log_err(string.format(dbid=default_home_id)) - default_home = None - - for obj in self.contents: - home = obj.home - # Obviously, we can't send it back to here. - if not home or (home and home.dbid == self.dbid): - obj.home = default_home - home = default_home - - # If for some reason it's still None... - if not home: - obj.location = None - obj.msg(_("Something went wrong! You are dumped into nowhere. Contact an admin.")) - logger.log_err("Missing default home - '{name}(#{dbid})' now " - "has a null location.".format(name=obj.name, dbid=obj.dbid)) - return - - if obj.has_account: - if home: - string = "Your current location has ceased to exist," - string += " moving you to (#{dbid})." - obj.msg(_(string).format(dbid=home.dbid)) - else: - # Famous last words: The account should never see this. - string = "This place should not exist ... contact an admin." - obj.msg(_(string)) - obj.move_to(home)
- -
[docs] @classmethod - def create(cls, key, account=None, **kwargs): - """ - Creates a basic object with default parameters, unless otherwise - specified or extended. - - Provides a friendlier interface to the utils.create_object() function. - - Args: - key (str): Name of the new object. - account (Account): Account to attribute this object to. - - Keyword Args: - description (str): Brief description for this object. - ip (str): IP address of creator (for object auditing). - - Returns: - object (Object): A newly created object of the given typeclass. - errors (list): A list of errors in string form, if any. - - """ - errors = [] - obj = None - - # Get IP address of creator, if available - ip = kwargs.pop("ip", "") - - # If no typeclass supplied, use this class - kwargs["typeclass"] = kwargs.pop("typeclass", cls) - - # Set the supplied key as the name of the intended object - kwargs["key"] = key - - # Get a supplied description, if any - description = kwargs.pop("description", "") - - # Create a sane lockstring if one wasn't supplied - lockstring = kwargs.get("locks") - if account and not lockstring: - lockstring = cls.lockstring.format(account_id=account.id) - kwargs["locks"] = lockstring - - # Create object - try: - obj = create.create_object(**kwargs) - - # Record creator id and creation IP - if ip: - obj.db.creator_ip = ip - if account: - obj.db.creator_id = account.id - - # Set description if there is none, or update it if provided - if description or not obj.db.desc: - desc = description if description else "You see nothing special." - obj.db.desc = desc - - except Exception as e: - errors.append("An error occurred while creating this '%s' object." % key) - logger.log_err(e) - - return obj, errors
- -
[docs] def copy(self, new_key=None, **kwargs): - """ - Makes an identical copy of this object, identical except for a - new dbref in the database. If you want to customize the copy - by changing some settings, use ObjectDB.object.copy_object() - directly. - - Args: - new_key (string): New key/name of copied object. If new_key is not - specified, the copy will be named <old_key>_copy by default. - Returns: - copy (Object): A copy of this object. - - """ - - def find_clone_key(): - """ - Append 01, 02 etc to obj.key. Checks next higher number in the - same location, then adds the next number available - - returns the new clone name on the form keyXX - """ - key = self.key - num = sum( - 1 - for obj in self.location.contents - if obj.key.startswith(key) and obj.key.lstrip(key).isdigit() - ) - return "%s%03i" % (key, num) - - new_key = new_key or find_clone_key() - new_obj = ObjectDB.objects.copy_object(self, new_key=new_key, **kwargs) - self.at_object_post_copy(new_obj, **kwargs) - return new_obj
- -
[docs] def at_object_post_copy(self, new_obj, **kwargs): - """ - Called by DefaultObject.copy(). Meant to be overloaded. In case there's extra data not - covered by .copy(), this can be used to deal with it. - - Args: - new_obj (Object): The new Copy of this object. - - Returns: - None - """ - pass
- -
[docs] def delete(self): - """ - Deletes this object. Before deletion, this method makes sure - to move all contained objects to their respective home - locations, as well as clean up all exits to/from the object. - - Returns: - noerror (bool): Returns whether or not the delete completed - successfully or not. - - """ - global _ScriptDB - if not _ScriptDB: - from evennia.scripts.models import ScriptDB as _ScriptDB - - if not self.pk or not self.at_object_delete(): - # This object has already been deleted, - # or the pre-delete check return False - return False - - # See if we need to kick the account off. - - for session in self.sessions.all(): - session.msg(_("Your character {key} has been destroyed.").format(key=self.key)) - # no need to disconnect, Account just jumps to OOC mode. - # sever the connection (important!) - if self.account: - # Remove the object from playable characters list - if self in self.account.db._playable_characters: - self.account.db._playable_characters = [ - x for x in self.account.db._playable_characters if x != self - ] - for session in self.sessions.all(): - self.account.unpuppet_object(session) - - self.account = None - - for script in _ScriptDB.objects.get_all_scripts_on_obj(self): - script.delete() - - # Destroy any exits to and from this room, if any - self.clear_exits() - # Clear out any non-exit objects located within the object - self.clear_contents() - self.attributes.clear() - self.nicks.clear() - self.aliases.clear() - self.location = None # this updates contents_cache for our location - - # Perform the deletion of the object - super().delete() - return True
- -
[docs] def access( - self, accessing_obj, access_type="read", default=False, no_superuser_bypass=False, **kwargs - ): - """ - Determines if another object has permission to access this object - in whatever way. - - Args: - accessing_obj (Object): Object trying to access this one. - access_type (str, optional): Type of access sought. - default (bool, optional): What to return if no lock of access_type was found. - no_superuser_bypass (bool, optional): If `True`, don't skip - lock check for superuser (be careful with this one). - - Keyword Args: - Passed on to the at_access hook along with the result of the access check. - - """ - result = super().access( - accessing_obj, - access_type=access_type, - default=default, - no_superuser_bypass=no_superuser_bypass, - ) - self.at_access(result, accessing_obj, access_type, **kwargs) - return result
- - # - # Hook methods - # - -
[docs] def at_first_save(self): - """ - This is called by the typeclass system whenever an instance of - this class is saved for the first time. It is a generic hook - for calling the startup hooks for the various game entities. - When overloading you generally don't overload this but - overload the hooks called by this method. - - """ - self.basetype_setup() - self.at_object_creation() - - if hasattr(self, "_createdict"): - # this will only be set if the utils.create function - # was used to create the object. We want the create - # call's kwargs to override the values set by hooks. - cdict = self._createdict - updates = [] - if not cdict.get("key"): - if not self.db_key: - self.db_key = "#%i" % self.dbid - updates.append("db_key") - elif self.key != cdict.get("key"): - updates.append("db_key") - self.db_key = cdict["key"] - if cdict.get("location") and self.location != cdict["location"]: - self.db_location = cdict["location"] - updates.append("db_location") - if cdict.get("home") and self.home != cdict["home"]: - self.home = cdict["home"] - updates.append("db_home") - if cdict.get("destination") and self.destination != cdict["destination"]: - self.destination = cdict["destination"] - updates.append("db_destination") - if updates: - self.save(update_fields=updates) - - if cdict.get("permissions"): - self.permissions.batch_add(*cdict["permissions"]) - if cdict.get("locks"): - self.locks.add(cdict["locks"]) - if cdict.get("aliases"): - self.aliases.batch_add(*cdict["aliases"]) - if cdict.get("location"): - cdict["location"].at_object_receive(self, None) - self.at_post_move(None) - if cdict.get("tags"): - # this should be a list of tags, tuples (key, category) or (key, category, data) - self.tags.batch_add(*cdict["tags"]) - if cdict.get("attributes"): - # this should be tuples (key, val, ...) - self.attributes.batch_add(*cdict["attributes"]) - if cdict.get("nattributes"): - # this should be a dict of nattrname:value - for key, value in cdict["nattributes"]: - self.nattributes.add(key, value) - - del self._createdict - - self.basetype_posthook_setup()
- - # hooks called by the game engine # - -
[docs] def basetype_setup(self): - """ - This sets up the default properties of an Object, just before - the more general at_object_creation. - - You normally don't need to change this unless you change some - fundamental things like names of permission groups. - - """ - # the default security setup fallback for a generic - # object. Overload in child for a custom setup. Also creation - # commands may set this (create an item and you should be its - # controller, for example) - - self.locks.add( - ";".join( - [ - "control:perm(Developer)", # edit locks/permissions, delete - "examine:perm(Builder)", # examine properties - "view:all()", # look at object (visibility) - "edit:perm(Admin)", # edit properties/attributes - "delete:perm(Admin)", # delete object - "get:all()", # pick up object - "drop:holds()", # drop only that which you hold - "call:true()", # allow to call commands on this object - "tell:perm(Admin)", # allow emits to this object - "puppet:pperm(Developer)", - ] - ) - ) # lock down puppeting only to staff by default
- -
[docs] def basetype_posthook_setup(self): - """ - Called once, after basetype_setup and at_object_creation. This - should generally not be overloaded unless you are redefining - how a room/exit/object works. It allows for basetype-like - setup after the object is created. An example of this is - EXITs, who need to know keys, aliases, locks etc to set up - their exit-cmdsets. - - """ - pass
- -
[docs] def at_object_creation(self): - """ - Called once, when this object is first created. This is the - normal hook to overload for most object types. - - """ - pass
- -
[docs] def at_object_delete(self): - """ - Called just before the database object is persistently - delete()d from the database. If this method returns False, - deletion is aborted. - - """ - return True
- -
[docs] def at_init(self): - """ - This is always called whenever this object is initiated -- - that is, whenever it its typeclass is cached from memory. This - happens on-demand first time the object is used or activated - in some way after being created but also after each server - restart or reload. - - """ - pass
- -
[docs] def at_cmdset_get(self, **kwargs): - """ - Called just before cmdsets on this object are requested by the - command handler. If changes need to be done on the fly to the - cmdset before passing them on to the cmdhandler, this is the - place to do it. This is called also if the object currently - have no cmdsets. - - Keyword Args: - caller (Session, Object or Account): The caller requesting - this cmdset. - - """ - pass
- -
[docs] def at_pre_puppet(self, account, session=None, **kwargs): - """ - Called just before an Account connects to this object to puppet - it. - - Args: - account (Account): This is the connecting account. - session (Session): Session controlling the connection. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - """ - pass
- -
[docs] def at_post_puppet(self, **kwargs): - """ - Called just after puppeting has been completed and all - Account<->Object links have been established. - - Args: - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - Note: - You can use `self.account` and `self.sessions.get()` to get - account and sessions at this point; the last entry in the - list from `self.sessions.get()` is the latest Session - puppeting this Object. - - """ - self.msg(f"You become |w{self.key}|n.") - self.account.db._last_puppet = self
- -
[docs] def at_pre_unpuppet(self, **kwargs): - """ - Called just before beginning to un-connect a puppeting from - this Account. - - Args: - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - Note: - You can use `self.account` and `self.sessions.get()` to get - account and sessions at this point; the last entry in the - list from `self.sessions.get()` is the latest Session - puppeting this Object. - - """ - pass
- -
[docs] def at_post_unpuppet(self, account, session=None, **kwargs): - """ - Called just after the Account successfully disconnected from - this object, severing all connections. - - Args: - account (Account): The account object that just disconnected - from this object. - session (Session): Session id controlling the connection that - just disconnected. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - """ - pass
- -
[docs] def at_server_reload(self): - """ - This hook is called whenever the server is shutting down for - restart/reboot. If you want to, for example, save non-persistent - properties across a restart, this is the place to do it. - - """ - pass
- -
[docs] def at_server_shutdown(self): - """ - This hook is called whenever the server is shutting down fully - (i.e. not for a restart). - - """ - pass
- -
[docs] def at_access(self, result, accessing_obj, access_type, **kwargs): - """ - This is called with the result of an access call, along with - any kwargs used for that call. The return of this method does - not affect the result of the lock check. It can be used e.g. to - customize error messages in a central location or other effects - based on the access result. - - Args: - result (bool): The outcome of the access call. - accessing_obj (Object or Account): The entity trying to gain access. - access_type (str): The type of access that was requested. - - Keyword Args: - Not used by default, added for possible expandability in a - game. - - """ - pass
- - # hooks called when moving the object - -
[docs] def at_pre_move(self, destination, **kwargs): - """ - Called just before starting to move this object to - destination. - - Args: - destination (Object): The object we are moving to - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Returns: - shouldmove (bool): If we should move or not. - - Notes: - If this method returns False/None, the move is cancelled - before it is even started. - - """ - # return has_perm(self, destination, "can_move") - return True
- - # deprecated alias - at_before_move = at_pre_move - -
[docs] def announce_move_from(self, destination, msg=None, mapping=None, **kwargs): - """ - Called if the move is to be announced. This is - called while we are still standing in the old - location. - - Args: - destination (Object): The place we are going to. - msg (str, optional): a replacement message. - mapping (dict, optional): additional mapping objects. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - You can override this method and call its parent with a - message to simply change the default message. In the string, - you can use the following as mappings (between braces): - object: the object which is moving. - exit: the exit from which the object is moving (if found). - origin: the location of the object before the move. - destination: the location of the object after moving. - - """ - if not self.location: - return - if msg: - string = msg - else: - string = "{object} is leaving {origin}, heading for {destination}." - - location = self.location - exits = [ - o for o in location.contents if o.location is location and o.destination is destination - ] - if not mapping: - mapping = {} - - mapping.update( - { - "object": self, - "exit": exits[0] if exits else "somewhere", - "origin": location or "nowhere", - "destination": destination or "nowhere", - } - ) - - location.msg_contents(string, exclude=(self,), from_obj=self, mapping=mapping)
- -
[docs] def announce_move_to(self, source_location, msg=None, mapping=None, **kwargs): - """ - Called after the move if the move was not quiet. At this point - we are standing in the new location. - - Args: - source_location (Object): The place we came from - msg (str, optional): the replacement message if location. - mapping (dict, optional): additional mapping objects. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Notes: - You can override this method and call its parent with a - message to simply change the default message. In the string, - you can use the following as mappings (between braces): - object: the object which is moving. - exit: the exit from which the object is moving (if found). - origin: the location of the object before the move. - destination: the location of the object after moving. - - """ - - if not source_location and self.location.has_account: - # This was created from nowhere and added to an account's - # inventory; it's probably the result of a create command. - string = _("You now have {name} in your possession.").format( - name=self.get_display_name(self.location)) - self.location.msg(string) - return - - if source_location: - if msg: - string = msg - else: - string = _("{object} arrives to {destination} from {origin}.") - else: - string = _("{object} arrives to {destination}.") - - origin = source_location - destination = self.location - exits = [] - if origin: - exits = [ - o - for o in destination.contents - if o.location is destination and o.destination is origin - ] - - if not mapping: - mapping = {} - - mapping.update( - { - "object": self, - "exit": exits[0] if exits else "somewhere", - "origin": origin or "nowhere", - "destination": destination or "nowhere", - } - ) - - destination.msg_contents(string, exclude=(self,), from_obj=self, mapping=mapping)
- -
[docs] def at_post_move(self, source_location, **kwargs): - """ - Called after move has completed, regardless of quiet mode or - not. Allows changes to the object due to the location it is - now in. - - Args: - source_location (Object): Wwhere we came from. This may be `None`. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - """ - pass
- - # deprecated - at_after_move = at_post_move - -
[docs] def at_object_leave(self, moved_obj, target_location, **kwargs): - """ - Called just before an object leaves from inside this object - - Args: - moved_obj (Object): The object leaving - target_location (Object): Where `moved_obj` is going. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - """ - pass
- -
[docs] def at_object_receive(self, moved_obj, source_location, **kwargs): - """ - Called after an object has been moved into this object. - - Args: - moved_obj (Object): The object moved into this one - source_location (Object): Where `moved_object` came from. - Note that this could be `None`. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - """ - pass
- -
[docs] def at_traverse(self, traversing_object, target_location, **kwargs): - """ - This hook is responsible for handling the actual traversal, - normally by calling - `traversing_object.move_to(target_location)`. It is normally - only implemented by Exit objects. If it returns False (usually - because `move_to` returned False), `at_post_traverse` below - should not be called and instead `at_failed_traverse` should be - called. - - Args: - traversing_object (Object): Object traversing us. - target_location (Object): Where target is going. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - """ - pass
- -
[docs] def at_post_traverse(self, traversing_object, source_location, **kwargs): - """ - Called just after an object successfully used this object to - traverse to another object (i.e. this object is a type of - Exit) - - Args: - traversing_object (Object): The object traversing us. - source_location (Object): Where `traversing_object` came from. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Notes: - The target location should normally be available as `self.destination`. - """ - pass
- - # deprecated - at_after_traverse = at_post_traverse - -
[docs] def at_failed_traverse(self, traversing_object, **kwargs): - """ - This is called if an object fails to traverse this object for - some reason. - - Args: - traversing_object (Object): The object that failed traversing us. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Notes: - Using the default exits, this hook will not be called if an - Attribute `err_traverse` is defined - this will in that case be - read for an error string instead. - - """ - pass
- -
[docs] def at_msg_receive(self, text=None, from_obj=None, **kwargs): - """ - This hook is called whenever someone sends a message to this - object using the `msg` method. - - Note that from_obj may be None if the sender did not include - itself as an argument to the obj.msg() call - so you have to - check for this. . - - Consider this a pre-processing method before msg is passed on - to the user session. If this method returns False, the msg - will not be passed on. - - Args: - text (str, optional): The message received. - from_obj (any, optional): The object sending the message. - - Keyword Args: - This includes any keywords sent to the `msg` method. - - Returns: - receive (bool): If this message should be received. - - Notes: - If this method returns False, the `msg` operation - will abort without sending the message. - - """ - return True
- -
[docs] def at_msg_send(self, text=None, to_obj=None, **kwargs): - """ - This is a hook that is called when *this* object sends a - message to another object with `obj.msg(text, to_obj=obj)`. - - Args: - text (str, optional): Text to send. - to_obj (any, optional): The object to send to. - - Keyword Args: - Keywords passed from msg() - - Notes: - Since this method is executed by `from_obj`, if no `from_obj` - was passed to `DefaultCharacter.msg` this hook will never - get called. - - """ - pass
- - # hooks called by the default cmdset. - -
[docs] def get_visible_contents(self, looker, **kwargs): - """ - Get all contents of this object that a looker can see (whatever that means, by default it - checks the 'view' lock), grouped by type. Helper method to return_appearance. - - Args: - looker (Object): The entity looking. - **kwargs (any): Passed from `return_appearance`. Unused by default. - - Returns: - dict: A dict of lists categorized by type. Byt default this - contains 'exits', 'characters' and 'things'. The elements of these - lists are the actual objects. - - """ - def filter_visible(obj_list): - return [obj for obj in obj_list if obj != looker and obj.access(looker, "view")] - - return { - "exits": filter_visible(self.contents_get(content_type="exit")), - "characters": filter_visible(self.contents_get(content_type="character")), - "things": filter_visible(self.contents_get(content_type="object")) - }
- -
[docs] def get_content_names(self, looker, **kwargs): - """ - Get the proper names for all contents of this object. Helper method - for return_appearance. - - Args: - looker (Object): The entity looking. - **kwargs (any): Passed from `return_appearance`. Passed into - `get_display_name` for each found entity. - - Returns: - dict: A dict of lists categorized by type. Byt default this - contains 'exits', 'characters' and 'things'. The elements - of these lists are strings - names of the objects that - can depend on the looker and also be grouped in the case - of multiple same-named things etc. - - Notes: - This method shouldn't add extra coloring to the names beyond what is - already given by the .get_display_name() (and the .name field) already. - Per-type coloring can be applied in `return_apperance`. - - """ - # a mapping {'exits': [...], 'characters': [...], 'things': [...]} - contents_map = self.get_visible_contents(looker, **kwargs) - - character_names = [char.get_display_name(looker, **kwargs) - for char in contents_map['characters']] - exit_names = [exi.get_display_name(looker, **kwargs) for exi in contents_map['exits']] - - # group all same-named things under one name - things = defaultdict(list) - for thing in contents_map['things']: - things[thing.get_display_name(looker, **kwargs)].append(thing) - - # pluralize same-named things - thing_names = [] - for thingname, thinglist in sorted(things.items()): - nthings = len(thinglist) - thing = thinglist[0] - singular, plural = thing.get_numbered_name(nthings, looker, key=thingname) - thing_names.append(singular if nthings == 1 else plural) - - return { - "exits": exit_names, - "characters": character_names, - "things": thing_names - }
- -
[docs] def return_appearance(self, looker, **kwargs): - """ - Main callback used by 'look' for the object to describe itself. - This formats a description. By default, this looks for the `appearance_template` - string set on this class and populates it with formatting keys - 'name', 'desc', 'exits', 'characters', 'things' as well as - (currently empty) 'header'/'footer'. - - Args: - looker (Object): Object doing the looking. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call. This is passed into the helper - methods and into `get_display_name` calls. - - Returns: - str: The description of this entity. By default this includes - the entity's name, description and any contents inside it. - - Notes: - To simply change the layout of how the object displays itself (like - adding some line decorations or change colors of different sections), - you can simply edit `.appearance_template`. You only need to override - this method (and/or its helpers) if you want to change what is passed - into the template or want the most control over output. - - """ - - if not looker: - return '' - - # ourselves - name = self.get_display_name(looker, **kwargs) - desc = self.db.desc or "You see nothing special." - - # contents - content_names_map = self.get_content_names(looker, **kwargs) - exits = list_to_string(content_names_map['exits']) - characters = list_to_string(content_names_map['characters']) - things = list_to_string(content_names_map['things']) - - # populate the appearance_template string. It's a good idea to strip it and - # let the client add any extra spaces instead. - return self.appearance_template.format( - header='', - name=name, - desc=desc, - exits=f"|wExits:|n {exits}" if exits else '', - characters=f"\n|wCharacters:|n {characters}" if characters else '', - things=f"\n|wYou see:|n {things}" if things else '', - footer='' - ).strip()
- -
[docs] def at_look(self, target, **kwargs): - """ - Called when this object performs a look. It allows to - customize just what this means. It will not itself - send any data. - - Args: - target (Object): The target being looked at. This is - commonly an object or the current location. It will - be checked for the "view" type access. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call. This will be passed into - return_appearance, get_display_name and at_desc but is not used - by default. - - Returns: - lookstring (str): A ready-processed look string - potentially ready to return to the looker. - - """ - if not target.access(self, "view"): - try: - return "Could not view '%s'." % target.get_display_name(self, **kwargs) - except AttributeError: - return "Could not view '%s'." % target.key - - description = target.return_appearance(self, **kwargs) - - # the target's at_desc() method. - # this must be the last reference to target so it may delete itself when acted on. - target.at_desc(looker=self, **kwargs) - - return description
- -
[docs] def at_desc(self, looker=None, **kwargs): - """ - This is called whenever someone looks at this object. - - Args: - looker (Object, optional): The object requesting the description. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - """ - pass
- -
[docs] def at_pre_get(self, getter, **kwargs): - """ - Called by the default `get` command before this object has been - picked up. - - Args: - getter (Object): The object about to get this object. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Returns: - shouldget (bool): If the object should be gotten or not. - - Notes: - If this method returns False/None, the getting is cancelled - before it is even started. - """ - return True
- - # deprecated - at_before_get = at_pre_get - -
[docs] def at_get(self, getter, **kwargs): - """ - Called by the default `get` command when this object has been - picked up. - - Args: - getter (Object): The object getting this object. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Notes: - This hook cannot stop the pickup from happening. Use - permissions or the at_pre_get() hook for that. - - """ - pass
- -
[docs] def at_pre_give(self, giver, getter, **kwargs): - """ - Called by the default `give` command before this object has been - given. - - Args: - giver (Object): The object about to give this object. - getter (Object): The object about to get this object. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Returns: - shouldgive (bool): If the object should be given or not. - - Notes: - If this method returns False/None, the giving is cancelled - before it is even started. - - """ - return True
- - # deprecated - at_before_give = at_pre_give - -
[docs] def at_give(self, giver, getter, **kwargs): - """ - Called by the default `give` command when this object has been - given. - - Args: - giver (Object): The object giving this object. - getter (Object): The object getting this object. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Notes: - This hook cannot stop the give from happening. Use - permissions or the at_pre_give() hook for that. - - """ - pass
- -
[docs] def at_pre_drop(self, dropper, **kwargs): - """ - Called by the default `drop` command before this object has been - dropped. - - Args: - dropper (Object): The object which will drop this object. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Returns: - shoulddrop (bool): If the object should be dropped or not. - - Notes: - If this method returns False/None, the dropping is cancelled - before it is even started. - - """ - if not self.locks.get("drop"): - # TODO: This if-statment will be removed in Evennia 1.0 - return True - if not self.access(dropper, "drop", default=False): - dropper.msg(f"You cannot drop {self.get_display_name(dropper)}") - return False - return True
- - # deprecated - at_before_drop = at_pre_drop - -
[docs] def at_drop(self, dropper, **kwargs): - """ - Called by the default `drop` command when this object has been - dropped. - - Args: - dropper (Object): The object which just dropped this object. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Notes: - This hook cannot stop the drop from happening. Use - permissions or the at_pre_drop() hook for that. - - """ - pass
- -
[docs] def at_pre_say(self, message, **kwargs): - """ - Before the object says something. - - This hook is by default used by the 'say' and 'whisper' - commands as used by this command it is called before the text - is said/whispered and can be used to customize the outgoing - text from the object. Returning `None` aborts the command. - - Args: - message (str): The suggested say/whisper text spoken by self. - Keyword Args: - whisper (bool): If True, this is a whisper rather than - a say. This is sent by the whisper command by default. - Other verbal commands could use this hook in similar - ways. - receivers (Object or iterable): If set, this is the target or targets for the - say/whisper. - - Returns: - message (str): The (possibly modified) text to be spoken. - - """ - return message
- - # deprecated - at_before_say = at_pre_say - -
[docs] def at_say( - self, - message, - msg_self=None, - msg_location=None, - receivers=None, - msg_receivers=None, - **kwargs, - ): - """ - Display the actual say (or whisper) of self. - - This hook should display the actual say/whisper of the object in its - location. It should both alert the object (self) and its - location that some text is spoken. The overriding of messages or - `mapping` allows for simple customization of the hook without - re-writing it completely. - - Args: - message (str): The message to convey. - msg_self (bool or str, optional): If boolean True, echo `message` to self. If a string, - return that message. If False or unset, don't echo to self. - msg_location (str, optional): The message to echo to self's location. - receivers (Object or iterable, optional): An eventual receiver or receivers of the - message (by default only used by whispers). - msg_receivers(str): Specific message to pass to the receiver(s). This will parsed - with the {receiver} placeholder replaced with the given receiver. - Keyword Args: - whisper (bool): If this is a whisper rather than a say. Kwargs - can be used by other verbal commands in a similar way. - mapping (dict): Pass an additional mapping to the message. - - Notes: - - - Messages can contain {} markers. These are substituted against the values - passed in the `mapping` argument. - - msg_self = 'You say: "{speech}"' - msg_location = '{object} says: "{speech}"' - msg_receivers = '{object} whispers: "{speech}"' - - Supported markers by default: - {self}: text to self-reference with (default 'You') - {speech}: the text spoken/whispered by self. - {object}: the object speaking. - {receiver}: replaced with a single receiver only for strings meant for a specific - receiver (otherwise 'None'). - {all_receivers}: comma-separated list of all receivers, - if more than one, otherwise same as receiver - {location}: the location where object is. - - """ - msg_type = "say" - if kwargs.get("whisper", False): - # whisper mode - msg_type = "whisper" - msg_self = ( - '{self} whisper to {all_receivers}, "|n{speech}|n"' - if msg_self is True else msg_self - ) - msg_receivers = msg_receivers or '{object} whispers: "|n{speech}|n"' - msg_location = None - else: - msg_self = '{self} say, "|n{speech}|n"' if msg_self is True else msg_self - msg_location = msg_location or '{object} says, "{speech}"' - msg_receivers = msg_receivers or message - - custom_mapping = kwargs.get("mapping", {}) - receivers = make_iter(receivers) if receivers else None - location = self.location - - if msg_self: - self_mapping = { - "self": "You", - "object": self.get_display_name(self), - "location": location.get_display_name(self) if location else None, - "receiver": None, - "all_receivers": ", ".join(recv.get_display_name(self) for recv in receivers) - if receivers - else None, - "speech": message, - } - self_mapping.update(custom_mapping) - self.msg(text=(msg_self.format(**self_mapping), {"type": msg_type}), from_obj=self) - - if receivers and msg_receivers: - receiver_mapping = { - "self": "You", - "object": None, - "location": None, - "receiver": None, - "all_receivers": None, - "speech": message, - } - for receiver in make_iter(receivers): - individual_mapping = { - "object": self.get_display_name(receiver), - "location": location.get_display_name(receiver), - "receiver": receiver.get_display_name(receiver), - "all_receivers": ", ".join(recv.get_display_name(recv) for recv in receivers) - if receivers - else None, - } - receiver_mapping.update(individual_mapping) - receiver_mapping.update(custom_mapping) - receiver.msg( - text=(msg_receivers.format(**receiver_mapping), {"type": msg_type}), - from_obj=self, - ) - - if self.location and msg_location: - location_mapping = { - "self": "You", - "object": self, - "location": location, - "all_receivers": ", ".join(str(recv) for recv in receivers) if receivers else None, - "receiver": None, - "speech": message, - } - location_mapping.update(custom_mapping) - exclude = [] - if msg_self: - exclude.append(self) - if receivers: - exclude.extend(receivers) - self.location.msg_contents( - text=(msg_location, {"type": msg_type}), - from_obj=self, - exclude=exclude, - mapping=location_mapping, - )
- - -# -# Base Character object -# - - -
[docs]class DefaultCharacter(DefaultObject): - """ - This implements an Object puppeted by a Session - that is, - a character avatar controlled by an account. - - """ - - # Tuple of types used for indexing inventory contents. Characters generally wouldn't be in - # anyone's inventory, but this also governs displays in room contents. - _content_types = ("character",) - # lockstring of newly created rooms, for easy overloading. - # Will be formatted with the appropriate attributes. - lockstring = ( - "puppet:id({character_id}) or pid({account_id}) or perm(Developer) or pperm(Developer);" - "delete:id({account_id}) or perm(Admin)" - ) - -
[docs] @classmethod - def create(cls, key, account=None, **kwargs): - """ - Creates a basic Character with default parameters, unless otherwise - specified or extended. - - Provides a friendlier interface to the utils.create_character() function. - - Args: - key (str): Name of the new Character. - account (obj, optional): Account to associate this Character with. - If unset supplying None-- it will - change the default lockset and skip creator attribution. - - Keyword Args: - description (str): Brief description for this object. - ip (str): IP address of creator (for object auditing). - All other kwargs will be passed into the create_object call. - - Returns: - character (Object): A newly created Character of the given typeclass. - errors (list): A list of errors in string form, if any. - - """ - errors = [] - obj = None - # Get IP address of creator, if available - ip = kwargs.pop("ip", "") - - # If no typeclass supplied, use this class - kwargs["typeclass"] = kwargs.pop("typeclass", cls) - - # Normalize to latin characters and validate, if necessary, the supplied key - key = cls.normalize_name(key) - - if not cls.validate_name(key): - errors.append(_("Invalid character name.")) - return obj, errors - - # Set the supplied key as the name of the intended object - kwargs["key"] = key - - # Get permissions - kwargs["permissions"] = kwargs.get("permissions", settings.PERMISSION_ACCOUNT_DEFAULT) - - # Get description if provided - description = kwargs.pop("description", "") - - # Get locks if provided - locks = kwargs.pop("locks", "") - - try: - # Check to make sure account does not have too many chars - if account: - if len(account.characters) >= settings.MAX_NR_CHARACTERS: - errors.append(_("There are too many characters associated with this account.")) - return obj, errors - - # Create the Character - obj = create.create_object(**kwargs) - - # Record creator id and creation IP - if ip: - obj.db.creator_ip = ip - if account: - obj.db.creator_id = account.id - if obj not in account.characters: - account.db._playable_characters.append(obj) - - # Add locks - if not locks and account: - # Allow only the character itself and the creator account to puppet this character - # (and Developers). - locks = cls.lockstring.format(**{"character_id": obj.id, "account_id": account.id}) - elif not locks and not account: - locks = cls.lockstring.format(**{"character_id": obj.id, "account_id": -1}) - - obj.locks.add(locks) - - # If no description is set, set a default description - if description or not obj.db.desc: - obj.db.desc = description if description else _("This is a character.") - - except Exception as e: - errors.append(f"An error occurred while creating object '{key} object.") - logger.log_err(e) - - return obj, errors
- -
[docs] @classmethod - def normalize_name(cls, name): - """ - Normalize the character name prior to creating. Note that this should be refactored to - support i18n for non-latin scripts, but as we (currently) have no bug reports requesting - better support of non-latin character sets, requiring character names to be latinified is an - acceptable option. - - Args: - name (str) : The name of the character - - Returns: - latin_name (str) : A valid name. - """ - - from evennia.utils.utils import latinify - - latin_name = latinify(name, default="X") - return latin_name
- -
[docs] @classmethod - def validate_name(cls, name): - """ Validate the character name prior to creating. Overload this function to add custom validators - - Args: - name (str) : The name of the character - Returns: - valid (bool) : True if character creation should continue; False if it should fail - - """ - - return True # Default validator does not perform any operations
- -
[docs] def basetype_setup(self): - """ - Setup character-specific security. - - You should normally not need to overload this, but if you do, - make sure to reproduce at least the two last commands in this - method (unless you want to fundamentally change how a - Character object works). - - """ - super().basetype_setup() - self.locks.add( - ";".join(["get:false()", "call:false()"]) # noone can pick up the character - ) # no commands can be called on character from outside - # add the default cmdset - self.cmdset.add_default(settings.CMDSET_CHARACTER, persistent=True)
- -
[docs] def at_post_move(self, source_location, **kwargs): - """ - We make sure to look around after a move. - - """ - if self.location.access(self, "view"): - self.msg(text=(self.at_look(self.location), {"type": "look"}))
- - # deprecated - at_after_move = at_post_move - -
[docs] def at_pre_puppet(self, account, session=None, **kwargs): - """ - Return the character from storage in None location in `at_post_unpuppet`. - Args: - account (Account): This is the connecting account. - session (Session): Session controlling the connection. - - """ - if ( - self.location is None - ): # Make sure character's location is never None before being puppeted. - # Return to last location (or home, which should always exist), - self.location = self.db.prelogout_location if self.db.prelogout_location else self.home - self.location.at_object_receive( - self, None - ) # and trigger the location's reception hook. - if self.location: # If the character is verified to be somewhere, - self.db.prelogout_location = self.location # save location again to be sure. - else: - account.msg( - _("|r{obj} has no location and no home is set.|n").format(obj=self), - session=session - ) # Note to set home.
- -
[docs] def at_post_puppet(self, **kwargs): - """ - Called just after puppeting has been completed and all - Account<->Object links have been established. - - Args: - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - Note: - You can use `self.account` and `self.sessions.get()` to get - account and sessions at this point; the last entry in the - list from `self.sessions.get()` is the latest Session - puppeting this Object. - - """ - self.msg(_("\nYou become |c{name}|n.\n").format(name=self.key)) - self.msg((self.at_look(self.location), {"type": "look"}), options=None) - - def message(obj, from_obj): - obj.msg(_("{name} has entered the game.").format(name=self.get_display_name(obj)), - from_obj=from_obj) - - self.location.for_contents(message, exclude=[self], from_obj=self)
- -
[docs] def at_post_unpuppet(self, account, session=None, **kwargs): - """ - We stove away the character when the account goes ooc/logs off, - otherwise the character object will remain in the room also - after the account logged off ("headless", so to say). - - Args: - account (Account): The account object that just disconnected - from this object. - session (Session): Session controlling the connection that - just disconnected. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - """ - if not self.sessions.count(): - # only remove this char from grid if no sessions control it anymore. - if self.location: - - def message(obj, from_obj): - obj.msg(_("{name} has left the game.").format(name=self.get_display_name(obj)), - from_obj=from_obj) - - self.location.for_contents(message, exclude=[self], from_obj=self) - self.db.prelogout_location = self.location - self.location = None
- - @property - def idle_time(self): - """ - Returns the idle time of the least idle session in seconds. If - no sessions are connected it returns nothing. - - """ - idle = [session.cmd_last_visible for session in self.sessions.all()] - if idle: - return time.time() - float(max(idle)) - return None - - @property - def connection_time(self): - """ - Returns the maximum connection time of all connected sessions - in seconds. Returns nothing if there are no sessions. - - """ - conn = [session.conn_time for session in self.sessions.all()] - if conn: - return time.time() - float(min(conn)) - return None
- - -# -# Base Room object - - -
[docs]class DefaultRoom(DefaultObject): - """ - This is the base room object. It's just like any Object except its - location is always `None`. - """ - - # A tuple of strings used for indexing this object inside an inventory. - # Generally, a room isn't expected to HAVE a location, but maybe in some games? - _content_types = ("room",) - - # lockstring of newly created rooms, for easy overloading. - # Will be formatted with the {id} of the creating object. - lockstring = ( - "control:id({id}) or perm(Admin); " - "delete:id({id}) or perm(Admin); " - "edit:id({id}) or perm(Admin)" - ) - -
[docs] @classmethod - def create(cls, key, account=None, **kwargs): - """ - Creates a basic Room with default parameters, unless otherwise - specified or extended. - - Provides a friendlier interface to the utils.create_object() function. - - Args: - key (str): Name of the new Room. - account (obj, optional): Account to associate this Room with. If - given, it will be given specific control/edit permissions to this - object (along with normal Admin perms). If not given, default - - Keyword Args: - description (str): Brief description for this object. - ip (str): IP address of creator (for object auditing). - - Returns: - room (Object): A newly created Room of the given typeclass. - errors (list): A list of errors in string form, if any. - - """ - errors = [] - obj = None - - # Get IP address of creator, if available - ip = kwargs.pop("ip", "") - - # If no typeclass supplied, use this class - kwargs["typeclass"] = kwargs.pop("typeclass", cls) - - # Set the supplied key as the name of the intended object - kwargs["key"] = key - - # Get who to send errors to - kwargs["report_to"] = kwargs.pop("report_to", account) - - # Get description, if provided - description = kwargs.pop("description", "") - - # get locks if provided - locks = kwargs.pop("locks", "") - - try: - # Create the Room - obj = create.create_object(**kwargs) - - # Add locks - if not locks and account: - locks = cls.lockstring.format(**{"id": account.id}) - elif not locks and not account: - locks = cls.lockstring.format(**{"id": obj.id}) - - obj.locks.add(locks) - - # Record creator id and creation IP - if ip: - obj.db.creator_ip = ip - if account: - obj.db.creator_id = account.id - - # If no description is set, set a default description - if description or not obj.db.desc: - obj.db.desc = description if description else _("This is a room.") - - except Exception as e: - errors.append("An error occurred while creating this '%s' object." % key) - logger.log_err(e) - - return obj, errors
- -
[docs] def basetype_setup(self): - """ - Simple room setup setting locks to make sure the room - cannot be picked up. - - """ - - super().basetype_setup() - self.locks.add( - ";".join(["get:false()", "puppet:false()"]) - ) # would be weird to puppet a room ... - self.location = None
- - -# -# Default Exit command, used by the base exit object -# - -
[docs]class ExitCommand(_COMMAND_DEFAULT_CLASS): - """ - This is a command that simply cause the caller to traverse - the object it is attached to. - - """ - - obj = None - -
[docs] def func(self): - """ - Default exit traverse if no syscommand is defined. - """ - - if self.obj.access(self.caller, "traverse"): - # we may traverse the exit. - self.obj.at_traverse(self.caller, self.obj.destination) - else: - # exit is locked - if self.obj.db.err_traverse: - # if exit has a better error message, let's use it. - self.caller.msg(self.obj.db.err_traverse) - else: - # No shorthand error message. Call hook. - self.obj.at_failed_traverse(self.caller)
- -
[docs] def get_extra_info(self, caller, **kwargs): - """ - Shows a bit of information on where the exit leads. - - Args: - caller (Object): The object (usually a character) that entered an ambiguous command. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Returns: - A string with identifying information to disambiguate the command, conventionally with a - preceding space. - - """ - if self.obj.destination: - return " (exit to %s)" % self.obj.destination.get_display_name(caller) - else: - return " (%s)" % self.obj.get_display_name(caller)
- - -# -# Base Exit object - - -
[docs]class DefaultExit(DefaultObject): - """ - This is the base exit object - it connects a location to another. - This is done by the exit assigning a "command" on itself with the - same name as the exit object (to do this we need to remember to - re-create the command when the object is cached since it must be - created dynamically depending on what the exit is called). This - command (which has a high priority) will thus allow us to traverse - exits simply by giving the exit-object's name on its own. - - """ - - _content_types = ("exit",) - exit_command = ExitCommand - priority = 101 - - # lockstring of newly created exits, for easy overloading. - # Will be formatted with the {id} of the creating object. - lockstring = ( - "control:id({id}) or perm(Admin); " - "delete:id({id}) or perm(Admin); " - "edit:id({id}) or perm(Admin)" - ) - - # Helper classes and methods to implement the Exit. These need not - # be overloaded unless one want to change the foundation for how - # Exits work. See the end of the class for hook methods to overload. - -
[docs] def create_exit_cmdset(self, exidbobj): - """ - Helper function for creating an exit command set + command. - - The command of this cmdset has the same name as the Exit - object and allows the exit to react when the account enter the - exit's name, triggering the movement between rooms. - - Args: - exidbobj (Object): The DefaultExit object to base the command on. - - """ - - # create an exit command. We give the properties here, - # to always trigger metaclass preparations - cmd = self.exit_command( - key=exidbobj.db_key.strip().lower(), - aliases=exidbobj.aliases.all(), - locks=str(exidbobj.locks), - auto_help=False, - destination=exidbobj.db_destination, - arg_regex=r"^$", - is_exit=True, - obj=exidbobj, - ) - # create a cmdset - exit_cmdset = cmdset.CmdSet(None) - exit_cmdset.key = "ExitCmdSet" - exit_cmdset.priority = self.priority - exit_cmdset.duplicates = True - # add command to cmdset - exit_cmdset.add(cmd) - return exit_cmdset
- - # Command hooks - -
[docs] @classmethod - def create(cls, key, source, dest, account=None, **kwargs): - """ - Creates a basic Exit with default parameters, unless otherwise - specified or extended. - - Provides a friendlier interface to the utils.create_object() function. - - Args: - key (str): Name of the new Exit, as it should appear from the - source room. - account (obj): Account to associate this Exit with. - source (Room): The room to create this exit in. - dest (Room): The room to which this exit should go. - - Keyword Args: - description (str): Brief description for this object. - ip (str): IP address of creator (for object auditing). - - Returns: - exit (Object): A newly created Room of the given typeclass. - errors (list): A list of errors in string form, if any. - - """ - errors = [] - obj = None - - # Get IP address of creator, if available - ip = kwargs.pop("ip", "") - - # If no typeclass supplied, use this class - kwargs["typeclass"] = kwargs.pop("typeclass", cls) - - # Set the supplied key as the name of the intended object - kwargs["key"] = key - - # Get who to send errors to - kwargs["report_to"] = kwargs.pop("report_to", account) - - # Set to/from rooms - kwargs["location"] = source - kwargs["destination"] = dest - - description = kwargs.pop("description", "") - - locks = kwargs.get("locks", "") - - try: - # Create the Exit - obj = create.create_object(**kwargs) - - # Set appropriate locks - if not locks and account: - locks = cls.lockstring.format(**{"id": account.id}) - elif not locks and not account: - locks = cls.lockstring.format(**{"id": obj.id}) - obj.locks.add(locks) - - # Record creator id and creation IP - if ip: - obj.db.creator_ip = ip - if account: - obj.db.creator_id = account.id - - # If no description is set, set a default description - if description or not obj.db.desc: - obj.db.desc = description if description else _("This is an exit.") - - except Exception as e: - errors.append("An error occurred while creating this '%s' object." % key) - logger.log_err(e) - - return obj, errors
- -
[docs] def basetype_setup(self): - """ - Setup exit-security - - You should normally not need to overload this - if you do make - sure you include all the functionality in this method. - - """ - super().basetype_setup() - - # setting default locks (overload these in at_object_creation() - self.locks.add( - ";".join( - [ - "puppet:false()", # would be weird to puppet an exit ... - "traverse:all()", # who can pass through exit by default - "get:false()", # noone can pick up the exit - ] - ) - ) - - # an exit should have a destination (this is replaced at creation time) - if self.location: - self.destination = self.location
- -
[docs] def at_cmdset_get(self, **kwargs): - """ - Called just before cmdsets on this object are requested by the - command handler. If changes need to be done on the fly to the - cmdset before passing them on to the cmdhandler, this is the - place to do it. This is called also if the object currently - has no cmdsets. - - Keyword Args: - force_init (bool): If `True`, force a re-build of the cmdset - (for example to update aliases). - - """ - - if "force_init" in kwargs or not self.cmdset.has_cmdset("ExitCmdSet", must_be_default=True): - # we are resetting, or no exit-cmdset was set. Create one dynamically. - self.cmdset.add_default(self.create_exit_cmdset(self), persistent=False)
- -
[docs] def at_init(self): - """ - This is called when this objects is re-loaded from cache. When - that happens, we make sure to remove any old ExitCmdSet cmdset - (this most commonly occurs when renaming an existing exit) - """ - self.cmdset.remove_default()
- -
[docs] def at_traverse(self, traversing_object, target_location, **kwargs): - """ - This implements the actual traversal. The traverse lock has - already been checked (in the Exit command) at this point. - - Args: - traversing_object (Object): Object traversing us. - target_location (Object): Where target is going. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - """ - source_location = traversing_object.location - if traversing_object.move_to(target_location): - self.at_post_traverse(traversing_object, source_location) - else: - if self.db.err_traverse: - # if exit has a better error message, let's use it. - traversing_object.msg(self.db.err_traverse) - else: - # No shorthand error message. Call hook. - self.at_failed_traverse(traversing_object)
- -
[docs] def at_failed_traverse(self, traversing_object, **kwargs): - """ - Overloads the default hook to implement a simple default error message. - - Args: - traversing_object (Object): The object that failed traversing us. - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - Notes: - Using the default exits, this hook will not be called if an - Attribute `err_traverse` is defined - this will in that case be - read for an error string instead. - - """ - traversing_object.msg(_("You cannot go there."))
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/prototypes/menus.html b/docs/0.9.5/_modules/evennia/prototypes/menus.html deleted file mode 100644 index 55aea3f377..0000000000 --- a/docs/0.9.5/_modules/evennia/prototypes/menus.html +++ /dev/null @@ -1,2863 +0,0 @@ - - - - - - - - evennia.prototypes.menus — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.prototypes.menus

-"""
-
-OLC Prototype menu nodes
-
-"""
-
-import json
-import re
-from random import choice
-from django.db.models import Q
-from django.conf import settings
-from evennia.objects.models import ObjectDB
-from evennia.utils.evmenu import EvMenu, list_node
-from evennia.utils import evmore
-from evennia.utils.ansi import strip_ansi
-from evennia.utils import utils
-from evennia.locks.lockhandler import get_all_lockfuncs
-from evennia.prototypes import prototypes as protlib
-from evennia.prototypes import spawner
-
-# ------------------------------------------------------------
-#
-# OLC Prototype design menu
-#
-# ------------------------------------------------------------
-
-_MENU_CROP_WIDTH = 15
-_MENU_ATTR_LITERAL_EVAL_ERROR = (
-    "|rCritical Python syntax error in your value. Only primitive Python structures are allowed.\n"
-    "You also need to use correct Python syntax. Remember especially to put quotes around all "
-    "strings inside lists and dicts.|n"
-)
-
-
-# Helper functions
-
-
-def _get_menu_prototype(caller):
-    """Return currently active menu prototype."""
-    prototype = None
-    if hasattr(caller.ndb._menutree, "olc_prototype"):
-        prototype = caller.ndb._menutree.olc_prototype
-    if not prototype:
-        caller.ndb._menutree.olc_prototype = prototype = {}
-        caller.ndb._menutree.olc_new = True
-    return prototype
-
-
-def _get_flat_menu_prototype(caller, refresh=False, validate=False):
-    """Return prototype where parent values are included"""
-    flat_prototype = None
-    if not refresh and hasattr(caller.ndb._menutree, "olc_flat_prototype"):
-        flat_prototype = caller.ndb._menutree.olc_flat_prototype
-    if not flat_prototype:
-        prot = _get_menu_prototype(caller)
-        caller.ndb._menutree.olc_flat_prototype = flat_prototype = spawner.flatten_prototype(
-            prot, validate=validate
-        )
-    return flat_prototype
-
-
-def _get_unchanged_inherited(caller, protname):
-    """Return prototype values inherited from parent(s), which are not replaced in child"""
-    prototype = _get_menu_prototype(caller)
-    if protname in prototype:
-        return protname[protname], False
-    else:
-        flattened = _get_flat_menu_prototype(caller)
-        if protname in flattened:
-            return protname[protname], True
-    return None, False
-
-
-def _set_menu_prototype(caller, prototype):
-    """Set the prototype with existing one"""
-    caller.ndb._menutree.olc_prototype = prototype
-    caller.ndb._menutree.olc_new = False
-    return prototype
-
-
-def _is_new_prototype(caller):
-    """Check if prototype is marked as new or was loaded from a saved one."""
-    return hasattr(caller.ndb._menutree, "olc_new")
-
-
-def _format_option_value(prop, required=False, prototype=None, cropper=None):
-    """
-    Format wizard option values.
-
-    Args:
-        prop (str): Name or value to format.
-        required (bool, optional): The option is required.
-        prototype (dict, optional): If given, `prop` will be considered a key in this prototype.
-        cropper (callable, optional): A function to crop the value to a certain width.
-
-    Returns:
-        value (str): The formatted value.
-    """
-    if prototype is not None:
-        prop = prototype.get(prop, "")
-
-    out = prop
-    if callable(prop):
-        if hasattr(prop, "__name__"):
-            out = "<{}>".format(prop.__name__)
-        else:
-            out = repr(prop)
-    if utils.is_iter(prop):
-        out = ", ".join(str(pr) for pr in prop)
-    if not out and required:
-        out = "|runset"
-    if out:
-        return " ({}|n)".format(cropper(out) if cropper else utils.crop(out, _MENU_CROP_WIDTH))
-    return ""
-
-
-def _set_prototype_value(caller, field, value, parse=True):
-    """Set prototype's field in a safe way."""
-    prototype = _get_menu_prototype(caller)
-    prototype[field] = value
-    caller.ndb._menutree.olc_prototype = prototype
-    return prototype
-
-
-def _set_property(caller, raw_string, **kwargs):
-    """
-    Add or update a property. To be called by the 'goto' option variable.
-
-    Args:
-        caller (Object, Account): The user of the wizard.
-        raw_string (str): Input from user on given node - the new value to set.
-
-    Keyword Args:
-        test_parse (bool): If set (default True), parse raw_string for protfuncs and obj-refs and
-            try to run result through literal_eval. The parser will be run in 'testing' mode and any
-            parsing errors will shown to the user. Note that this is just for testing, the original
-            given string will be what is inserted.
-        prop (str): Property name to edit with `raw_string`.
-        processor (callable): Converts `raw_string` to a form suitable for saving.
-        next_node (str): Where to redirect to after this has run.
-
-    Returns:
-        next_node (str): Next node to go to.
-
-    """
-    prop = kwargs.get("prop", "prototype_key")
-    processor = kwargs.get("processor", None)
-    next_node = kwargs.get("next_node", None)
-
-    if callable(processor):
-        try:
-            value = processor(raw_string)
-        except Exception as err:
-            caller.msg(
-                "Could not set {prop} to {value} ({err})".format(
-                    prop=prop.replace("_", "-").capitalize(), value=raw_string, err=str(err)
-                )
-            )
-            # this means we'll re-run the current node.
-            return None
-    else:
-        value = raw_string
-
-    if not value:
-        return next_node
-
-    prototype = _set_prototype_value(caller, prop, value)
-    caller.ndb._menutree.olc_prototype = prototype
-
-    try:
-        # TODO simple way to get rid of the u'' markers in list reprs, remove this when on py3.
-        repr_value = json.dumps(value)
-    except Exception:
-        repr_value = value
-
-    out = [" Set {prop} to {value} ({typ}).".format(prop=prop, value=repr_value, typ=type(value))]
-
-    if kwargs.get("test_parse", True):
-        out.append(" Simulating prototype-func parsing ...")
-        parsed_value = protlib.protfunc_parser(value, testing=True, prototype=prototype)
-        if parsed_value != value:
-            out.append(
-                " |g(Example-)value when parsed ({}):|n {}".format(type(parsed_value), parsed_value)
-            )
-        else:
-            out.append(" |gNo change when parsed.")
-
-    caller.msg("\n".join(out))
-
-    return next_node
-
-
-def _wizard_options(curr_node, prev_node, next_node, color="|W", search=False):
-    """Creates default navigation options available in the wizard."""
-    options = []
-    if prev_node:
-        options.append(
-            {
-                "key": ("|wB|Wack", "b"),
-                "desc": "{color}({node})|n".format(color=color, node=prev_node.replace("_", "-")),
-                "goto": "node_{}".format(prev_node),
-            }
-        )
-    if next_node:
-        options.append(
-            {
-                "key": ("|wF|Worward", "f"),
-                "desc": "{color}({node})|n".format(color=color, node=next_node.replace("_", "-")),
-                "goto": "node_{}".format(next_node),
-            }
-        )
-
-    options.append({"key": ("|wI|Wndex", "i"), "goto": "node_index"})
-
-    if curr_node:
-        options.append(
-            {
-                "key": ("|wV|Walidate prototype", "validate", "v"),
-                "goto": ("node_validate_prototype", {"back": curr_node}),
-            }
-        )
-        if search:
-            options.append(
-                {
-                    "key": ("|wSE|Warch objects", "search object", "search", "se"),
-                    "goto": ("node_search_object", {"back": curr_node}),
-                }
-            )
-
-    return options
-
-
-def _set_actioninfo(caller, string):
-    caller.ndb._menutree.actioninfo = string
-
-
-def _path_cropper(pythonpath):
-    "Crop path to only the last component"
-    return pythonpath.split(".")[-1]
-
-
-def _validate_prototype(prototype):
-    """Run validation on prototype"""
-
-    txt = protlib.prototype_to_str(prototype)
-    errors = "\n\n|g No validation errors found.|n (but errors could still happen at spawn-time)"
-    err = False
-    try:
-        # validate, don't spawn
-        spawner.spawn(prototype, only_validate=True)
-    except RuntimeError as exc:
-        errors = "\n\n|r{}|n".format(exc)
-        err = True
-    except RuntimeWarning as exc:
-        errors = "\n\n|y{}|n".format(exc)
-        err = True
-
-    text = txt + errors
-    return err, text
-
-
-def _format_protfuncs():
-    out = []
-    sorted_funcs = [
-        (key, func) for key, func in sorted(protlib.FUNC_PARSER.callables.items(), key=lambda tup: tup[0])
-    ]
-    for protfunc_name, protfunc in sorted_funcs:
-        out.append(
-            "- |c${name}|n - |W{docs}".format(
-                name=protfunc_name,
-                docs=utils.justify(protfunc.__doc__.strip(), align="l", indent=10).strip(),
-            )
-        )
-    return "\n       ".join(out)
-
-
-def _format_lockfuncs():
-    out = []
-    sorted_funcs = [
-        (key, func) for key, func in sorted(get_all_lockfuncs().items(), key=lambda tup: tup[0])
-    ]
-    for lockfunc_name, lockfunc in sorted_funcs:
-        doc = (lockfunc.__doc__ or "").strip()
-        out.append(
-            "- |c${name}|n - |W{docs}".format(
-                name=lockfunc_name, docs=utils.justify(doc, align="l", indent=10).strip()
-            )
-        )
-    return "\n".join(out)
-
-
-def _format_list_actions(*args, **kwargs):
-    """Create footer text for nodes with extra list actions
-
-    Args:
-        actions (str): Available actions. The first letter of the action name will be assumed
-            to be a shortcut.
-    Keyword Args:
-        prefix (str): Default prefix to use.
-    Returns:
-        string (str): Formatted footer for adding to the node text.
-
-    """
-    actions = []
-    prefix = kwargs.get("prefix", "|WSelect with |w<num>|W. Other actions:|n ")
-    for action in args:
-        actions.append("|w{}|n|W{} |w<num>|n".format(action[0], action[1:]))
-    return prefix + " |W|||n ".join(actions)
-
-
-def _get_current_value(caller, keyname, comparer=None, formatter=str, only_inherit=False):
-    """
-    Return current value, marking if value comes from parent or set in this prototype.
-
-    Args:
-        keyname (str): Name of prototoype key to get current value of.
-        comparer (callable, optional): This will be called as comparer(prototype_value,
-            flattened_value) and is expected to return the value to show as the current
-            or inherited one. If not given, a straight comparison is used and what is returned
-            depends on the only_inherit setting.
-        formatter (callable, optional)): This will be called with the result of comparer.
-        only_inherit (bool, optional): If a current value should only be shown if all
-            the values are inherited from the prototype parent (otherwise, show an empty string).
-    Returns:
-        current (str): The current value.
-
-    """
-
-    def _default_comparer(protval, flatval):
-        if only_inherit:
-            return "" if protval else flatval
-        else:
-            return protval if protval else flatval
-
-    if not callable(comparer):
-        comparer = _default_comparer
-
-    prot = _get_menu_prototype(caller)
-    flat_prot = _get_flat_menu_prototype(caller)
-
-    out = ""
-    if keyname in prot:
-        if keyname in flat_prot:
-            out = formatter(comparer(prot[keyname], flat_prot[keyname]))
-            if only_inherit:
-                if str(out).strip():
-                    return "|WCurrent|n {} |W(|binherited|W):|n {}".format(keyname, out)
-                return ""
-            else:
-                if out:
-                    return "|WCurrent|n {}|W:|n {}".format(keyname, out)
-                return "|W[No {} set]|n".format(keyname)
-        elif only_inherit:
-            return ""
-        else:
-            out = formatter(prot[keyname])
-            return "|WCurrent|n {}|W:|n {}".format(keyname, out)
-    elif keyname in flat_prot:
-        out = formatter(flat_prot[keyname])
-        if out:
-            return "|WCurrent|n {} |W(|n|binherited|W):|n {}".format(keyname, out)
-        else:
-            return ""
-    elif only_inherit:
-        return ""
-    else:
-        return "|W[No {} set]|n".format(keyname)
-
-
-def _default_parse(raw_inp, choices, *args):
-    """
-    Helper to parse default input to a node decorated with the node_list decorator on
-    the form l1, l 2, look 1, etc. Spaces are ignored, as is case.
-
-    Args:
-        raw_inp (str): Input from the user.
-        choices (list): List of available options on the node listing (list of strings).
-        args (tuples): The available actions, each specifed as a tuple (name, alias, ...)
-    Returns:
-        choice (str): A choice among the choices, or None if no match was found.
-        action (str): The action operating on the choice, or None.
-
-    """
-    raw_inp = raw_inp.lower().strip()
-    mapping = {t.lower(): tup[0] for tup in args for t in tup}
-    match = re.match(r"(%s)\s*?(\d+)$" % "|".join(mapping.keys()), raw_inp)
-    if match:
-        action = mapping.get(match.group(1), None)
-        num = int(match.group(2)) - 1
-        num = num if 0 <= num < len(choices) else None
-        if action is not None and num is not None:
-            return choices[num], action
-    return None, None
-
-
-# Menu nodes ------------------------------
-
-# helper nodes
-
-# validate prototype (available as option from all nodes)
-
-
-
[docs]def node_validate_prototype(caller, raw_string, **kwargs): - """General node to view and validate a protototype""" - prototype = _get_flat_menu_prototype(caller, refresh=True, validate=False) - prev_node = kwargs.get("back", "index") - - _, text = _validate_prototype(prototype) - - helptext = """ - The validator checks if the prototype's various values are on the expected form. It also tests - any $protfuncs. - - """ - - text = (text, helptext) - - options = _wizard_options(None, prev_node, None) - options.append({"key": "_default", "goto": "node_" + prev_node}) - - return text, options
- - -# node examine_entity - - -
[docs]def node_examine_entity(caller, raw_string, **kwargs): - """ - General node to view a text and then return to previous node. Kwargs should contain "text" for - the text to show and 'back" pointing to the node to return to. - """ - text = kwargs.get("text", "Nothing was found here.") - helptext = "Use |wback|n to return to the previous node." - prev_node = kwargs.get("back", "index") - - text = (text, helptext) - - options = _wizard_options(None, prev_node, None) - options.append({"key": "_default", "goto": "node_" + prev_node}) - - return text, options
- - -# node object_search - - -def _search_object(caller): - "update search term based on query stored on menu; store match too" - try: - searchstring = caller.ndb._menutree.olc_search_object_term.strip() - caller.ndb._menutree.olc_search_object_matches = [] - except AttributeError: - return [] - - if not searchstring: - caller.msg("Must specify a search criterion.") - return [] - - is_dbref = utils.dbref(searchstring) - is_account = searchstring.startswith("*") - - if is_dbref or is_account: - - if is_dbref: - # a dbref search - results = caller.search(searchstring, global_search=True, quiet=True) - else: - # an account search - searchstring = searchstring.lstrip("*") - results = caller.search_account(searchstring, quiet=True) - else: - keyquery = Q(db_key__istartswith=searchstring) - aliasquery = Q( - db_tags__db_key__istartswith=searchstring, db_tags__db_tagtype__iexact="alias" - ) - results = ObjectDB.objects.filter(keyquery | aliasquery).distinct() - - caller.msg("Searching for '{}' ...".format(searchstring)) - caller.ndb._menutree.olc_search_object_matches = results - return ["{}(#{})".format(obj.key, obj.id) for obj in results] - - -def _object_search_select(caller, obj_entry, **kwargs): - choices = kwargs["available_choices"] - num = choices.index(obj_entry) - matches = caller.ndb._menutree.olc_search_object_matches - obj = matches[num] - - if not obj.access(caller, "examine"): - caller.msg("|rYou don't have 'examine' access on this object.|n") - del caller.ndb._menutree.olc_search_object_term - return "node_search_object" - - prot = spawner.prototype_from_object(obj) - txt = protlib.prototype_to_str(prot) - return "node_examine_entity", {"text": txt, "back": "search_object"} - - -def _object_search_actions(caller, raw_inp, **kwargs): - "All this does is to queue a search query" - choices = kwargs["available_choices"] - obj_entry, action = _default_parse( - raw_inp, choices, ("examine", "e"), ("create prototype from object", "create", "c") - ) - - raw_inp = raw_inp.strip() - - if obj_entry: - - num = choices.index(obj_entry) - matches = caller.ndb._menutree.olc_search_object_matches - obj = matches[num] - prot = spawner.prototype_from_object(obj) - - if action == "examine": - - if not obj.access(caller, "examine"): - caller.msg("\n|rYou don't have 'examine' access on this object.|n") - del caller.ndb._menutree.olc_search_object_term - return "node_search_object" - - txt = protlib.prototype_to_str(prot) - return "node_examine_entity", {"text": txt, "back": "search_object"} - else: - # load prototype - - if not obj.access(caller, "edit"): - caller.msg("|rYou don't have access to do this with this object.|n") - del caller.ndb._menutree.olc_search_object_term - return "node_search_object" - - _set_menu_prototype(caller, prot) - caller.msg("Created prototype from object.") - return "node_index" - elif raw_inp: - caller.ndb._menutree.olc_search_object_term = raw_inp - return "node_search_object", kwargs - else: - # empty input - exit back to previous node - prev_node = "node_" + kwargs.get("back", "index") - return prev_node - - -@list_node(_search_object, _object_search_select) -def node_search_object(caller, raw_inp, **kwargs): - """ - Node for searching for an existing object. - """ - try: - matches = caller.ndb._menutree.olc_search_object_matches - except AttributeError: - matches = [] - nmatches = len(matches) - prev_node = kwargs.get("back", "index") - - if matches: - text = """ - Found {num} match{post}. - - (|RWarning: creating a prototype will |roverwrite|r |Rthe current prototype!)|n""".format( - num=nmatches, post="es" if nmatches > 1 else "" - ) - _set_actioninfo( - caller, - _format_list_actions("examine", "create prototype from object", prefix="Actions: "), - ) - else: - text = "Enter search criterion." - - helptext = """ - You can search objects by specifying partial key, alias or its exact #dbref. Use *query to - search for an Account instead. - - Once having found any matches you can choose to examine it or use |ccreate prototype from - object|n. If doing the latter, a prototype will be calculated from the selected object and - loaded as the new 'current' prototype. This is useful for having a base to build from but be - careful you are not throwing away any existing, unsaved, prototype work! - """ - - text = (text, helptext) - - options = _wizard_options(None, prev_node, None) - options.append({"key": "_default", "goto": (_object_search_actions, {"back": prev_node})}) - - return text, options - - -# main index (start page) node - - -
[docs]def node_index(caller): - prototype = _get_menu_prototype(caller) - - text = """ - |c --- Prototype wizard --- |n - %s - - A |cprototype|n is a 'template' for |wspawning|n an in-game entity. A field of the prototype - can either be hard-coded, left empty or scripted using |w$protfuncs|n - for example to - randomize the value every time a new entity is spawned. The fields whose names start with - 'Prototype-' are not fields on the object itself but are used for prototype-inheritance, or - when saving and loading. - - Select prototype field to edit. If you are unsure, start from [|w1|n]. Enter [|wh|n]elp at - any menu node for more info. - - """ - helptxt = """ - |c- prototypes |n - - A prototype is really just a Python dictionary. When spawning, this dictionary is essentially - passed into `|wevennia.utils.create.create_object(**prototype)|n` to create a new object. By - using different prototypes you can customize instances of objects without having to do code - changes to their typeclass (something which requires code access). The classical example is - to spawn goblins with different names, looks, equipment and skill, each based on the same - `Goblin` typeclass. - - At any time you can [|wV|n]alidate that the prototype works correctly and use it to - [|wSP|n]awn a new entity. You can also [|wSA|n]ve|n your work, [|wLO|n]oad an existing - prototype to [|wSE|n]arch for existing objects to use as a base. Use [|wL|n]ook to re-show a - menu node. [|wQ|n]uit will always exit the menu and [|wH|n]elp will show context-sensitive - help. - - - |c- $protfuncs |n - - Prototype-functions (protfuncs) allow for limited scripting within a prototype. These are - entered as a string $funcname(arg, arg, ...) and are evaluated |wat the time of spawning|n - only. They can also be nested for combined effects. - - {pfuncs} - """.format( - pfuncs=_format_protfuncs() - ) - - # If a prototype is being edited, show its key and - # prototype_key under the title - loaded_prototype = "" - if "prototype_key" in prototype or "key" in prototype: - loaded_prototype = " --- Editing: |y{}({})|n --- ".format( - prototype.get("key", ""), prototype.get("prototype_key", "") - ) - text = text % (loaded_prototype) - - text = (text, helptxt) - - options = [] - options.append( - { - "desc": "|WPrototype-Key|n|n{}".format( - _format_option_value("Key", "prototype_key" not in prototype, prototype, None) - ), - "goto": "node_prototype_key", - } - ) - for key in ( - "Prototype_Parent", - "Typeclass", - "Key", - "Aliases", - "Attrs", - "Tags", - "Locks", - "Permissions", - "Location", - "Home", - "Destination", - ): - required = False - cropper = None - if key in ("Prototype_Parent", "Typeclass"): - required = ("prototype_parent" not in prototype) and ("typeclass" not in prototype) - if key == "Typeclass": - cropper = _path_cropper - options.append( - { - "desc": "{}{}|n{}".format( - "|W" if key == "Prototype_Parent" else "|w", - key.replace("_", "-"), - _format_option_value(key, required, prototype, cropper=cropper), - ), - "goto": "node_{}".format(key.lower()), - } - ) - required = False - for key in ("Desc", "Tags", "Locks"): - options.append( - { - "desc": "|WPrototype-{}|n|n{}".format( - key, _format_option_value(key, required, prototype, None) - ), - "goto": "node_prototype_{}".format(key.lower()), - } - ) - - options.extend( - ( - {"key": ("|wV|Walidate prototype", "validate", "v"), "goto": "node_validate_prototype"}, - {"key": ("|wSA|Wve prototype", "save", "sa"), "goto": "node_prototype_save"}, - {"key": ("|wSP|Wawn prototype", "spawn", "sp"), "goto": "node_prototype_spawn"}, - {"key": ("|wLO|Wad prototype", "load", "lo"), "goto": "node_prototype_load"}, - {"key": ("|wSE|Warch objects|n", "search", "se"), "goto": "node_search_object"}, - ) - ) - - return text, options
- - -# prototype_key node - - -def _check_prototype_key(caller, key): - old_prototype = protlib.search_prototype(key) - olc_new = _is_new_prototype(caller) - key = key.strip().lower() - if old_prototype: - old_prototype = old_prototype[0] - # we are starting a new prototype that matches an existing - if not caller.locks.check_lockstring( - caller, old_prototype["prototype_locks"], access_type="edit" - ): - # return to the node_prototype_key to try another key - caller.msg( - "Prototype '{key}' already exists and you don't " - "have permission to edit it.".format(key=key) - ) - return "node_prototype_key" - elif olc_new: - # we are selecting an existing prototype to edit. Reset to index. - del caller.ndb._menutree.olc_new - caller.ndb._menutree.olc_prototype = old_prototype - caller.msg("Prototype already exists. Reloading.") - return "node_index" - - return _set_property(caller, key, prop="prototype_key") - - -
[docs]def node_prototype_key(caller): - - text = """ - The |cPrototype-Key|n uniquely identifies the prototype and is |wmandatory|n. It is used to - find and use the prototype to spawn new entities. It is not case sensitive. - - (To set a new value, just write it and press enter) - - {current}""".format( - current=_get_current_value(caller, "prototype_key") - ) - - helptext = """ - The prototype-key is not itself used when spawnng the new object, but is only used for - managing, storing and loading the prototype. It must be globally unique, so existing keys - will be checked before a new key is accepted. If an existing key is picked, the existing - prototype will be loaded. - """ - - options = _wizard_options("prototype_key", "index", "prototype_parent") - options.append({"key": "_default", "goto": _check_prototype_key}) - - text = (text, helptext) - return text, options
- - -# prototype_parents node - - -def _all_prototype_parents(caller): - """Return prototype_key of all available prototypes for listing in menu""" - return [ - prototype["prototype_key"] - for prototype in protlib.search_prototype() - if "prototype_key" in prototype - ] - - -def _prototype_parent_actions(caller, raw_inp, **kwargs): - """Parse the default Convert prototype to a string representation for closer inspection""" - choices = kwargs.get("available_choices", []) - prototype_parent, action = _default_parse( - raw_inp, choices, ("examine", "e", "l"), ("add", "a"), ("remove", "r", "delete", "d") - ) - - if prototype_parent: - # a selection of parent was made - prototype_parent = protlib.search_prototype(key=prototype_parent)[0] - prototype_parent_key = prototype_parent["prototype_key"] - - # which action to apply on the selection - if action == "examine": - # examine the prototype - txt = protlib.prototype_to_str(prototype_parent) - kwargs["text"] = txt - kwargs["back"] = "prototype_parent" - return "node_examine_entity", kwargs - elif action == "add": - # add/append parent - prot = _get_menu_prototype(caller) - current_prot_parent = prot.get("prototype_parent", None) - if current_prot_parent: - current_prot_parent = utils.make_iter(current_prot_parent) - if prototype_parent_key in current_prot_parent: - caller.msg("Prototype_parent {} is already used.".format(prototype_parent_key)) - return "node_prototype_parent" - else: - current_prot_parent.append(prototype_parent_key) - caller.msg("Add prototype parent for multi-inheritance.") - else: - current_prot_parent = prototype_parent_key - try: - if prototype_parent: - spawner.flatten_prototype(prototype_parent, validate=True) - else: - raise RuntimeError("Not found.") - except RuntimeError as err: - caller.msg( - "Selected prototype-parent {} " - "caused Error(s):\n|r{}|n".format(prototype_parent, err) - ) - return "node_prototype_parent" - _set_prototype_value(caller, "prototype_parent", current_prot_parent) - _get_flat_menu_prototype(caller, refresh=True) - elif action == "remove": - # remove prototype parent - prot = _get_menu_prototype(caller) - current_prot_parent = prot.get("prototype_parent", None) - if current_prot_parent: - current_prot_parent = utils.make_iter(current_prot_parent) - try: - current_prot_parent.remove(prototype_parent_key) - _set_prototype_value(caller, "prototype_parent", current_prot_parent) - _get_flat_menu_prototype(caller, refresh=True) - caller.msg("Removed prototype parent {}.".format(prototype_parent_key)) - except ValueError: - caller.msg( - "|rPrototype-parent {} could not be removed.".format(prototype_parent_key) - ) - return "node_prototype_parent" - - -def _prototype_parent_select(caller, new_parent): - - ret = None - prototype_parent = protlib.search_prototype(new_parent) - try: - if prototype_parent: - spawner.flatten_prototype(prototype_parent[0], validate=True) - else: - raise RuntimeError("Not found.") - except RuntimeError as err: - caller.msg( - "Selected prototype-parent {} " "caused Error(s):\n|r{}|n".format(new_parent, err) - ) - else: - ret = _set_property( - caller, - new_parent, - prop="prototype_parent", - processor=str, - next_node="node_prototype_parent", - ) - _get_flat_menu_prototype(caller, refresh=True) - caller.msg("Selected prototype parent |c{}|n.".format(new_parent)) - return ret - - -@list_node(_all_prototype_parents, _prototype_parent_select) -def node_prototype_parent(caller): - prototype = _get_menu_prototype(caller) - - prot_parent_keys = prototype.get("prototype_parent") - - text = """ - The |cPrototype Parent|n allows you to |winherit|n prototype values from another named - prototype (given as that prototype's |wprototype_key|n). If not changing these values in - the current prototype, the parent's value will be used. Pick the available prototypes below. - - Note that somewhere in the prototype's parentage, a |ctypeclass|n must be specified. If no - parent is given, this prototype must define the typeclass (next menu node). - - {current} - """ - helptext = """ - Prototypes can inherit from one another. Changes in the child replace any values set in a - parent. The |wtypeclass|n key must exist |wsomewhere|n in the parent chain for the - prototype to be valid. - """ - - _set_actioninfo(caller, _format_list_actions("examine", "add", "remove")) - - ptexts = [] - if prot_parent_keys: - for pkey in utils.make_iter(prot_parent_keys): - prot_parent = protlib.search_prototype(pkey) - if prot_parent: - prot_parent = prot_parent[0] - ptexts.append( - "|c -- {pkey} -- |n\n{prot}".format( - pkey=pkey, prot=protlib.prototype_to_str(prot_parent) - ) - ) - else: - ptexts.append("Prototype parent |r{pkey} was not found.".format(pkey=pkey)) - - if not ptexts: - ptexts.append("[No prototype_parent set]") - - text = text.format(current="\n\n".join(ptexts)) - - text = (text, helptext) - - options = _wizard_options("prototype_parent", "prototype_key", "typeclass", color="|W") - options.append({"key": "_default", "goto": _prototype_parent_actions}) - - return text, options - - -# typeclasses node - - -def _all_typeclasses(caller): - """Get name of available typeclasses.""" - return list( - name - for name in sorted(utils.get_all_typeclasses("evennia.objects.models.ObjectDB").keys()) - if name != "evennia.objects.models.ObjectDB" - ) - - -def _typeclass_actions(caller, raw_inp, **kwargs): - """Parse actions for typeclass listing""" - - choices = kwargs.get("available_choices", []) - typeclass_path, action = _default_parse( - raw_inp, choices, ("examine", "e", "l"), ("remove", "r", "delete", "d") - ) - - if typeclass_path: - if action == "examine": - typeclass = utils.get_all_typeclasses().get(typeclass_path) - if typeclass: - docstr = [] - for line in typeclass.__doc__.split("\n"): - if line.strip(): - docstr.append(line) - elif docstr: - break - docstr = "\n".join(docstr) if docstr else "<empty>" - txt = ( - "Typeclass |c{typeclass_path}|n; " - "First paragraph of docstring:\n\n{docstring}".format( - typeclass_path=typeclass_path, docstring=docstr - ) - ) - else: - txt = "This is typeclass |y{}|n.".format(typeclass) - return "node_examine_entity", {"text": txt, "back": "typeclass"} - elif action == "remove": - prototype = _get_menu_prototype(caller) - old_typeclass = prototype.pop("typeclass", None) - if old_typeclass: - _set_menu_prototype(caller, prototype) - caller.msg("Cleared typeclass {}.".format(old_typeclass)) - else: - caller.msg("No typeclass to remove.") - return "node_typeclass" - - -def _typeclass_select(caller, typeclass, **kwargs): - """Select typeclass from list and add it to prototype. Return next node to go to.""" - ret = _set_property(caller, typeclass, prop="typeclass", processor=str) - caller.msg("Selected typeclass |c{}|n.".format(typeclass)) - return ret - - -@list_node(_all_typeclasses, _typeclass_select) -def node_typeclass(caller): - text = """ - The |cTypeclass|n defines what 'type' of object this is - the actual working code to use. - - All spawned objects must have a typeclass. If not given here, the typeclass must be set in - one of the prototype's |cparents|n. - - {current} - """.format( - current=_get_current_value(caller, "typeclass"), - actions="|WSelect with |w<num>|W. Other actions: " - "|we|Wxamine |w<num>|W, |wr|Wemove selection", - ) - - helptext = """ - A |nTypeclass|n is specified by the actual python-path to the class definition in the - Evennia code structure. - - Which |cAttributes|n, |cLocks|n and other properties have special - effects or expects certain values depend greatly on the code in play. - """ - - text = (text, helptext) - - options = _wizard_options("typeclass", "prototype_parent", "key", color="|W") - options.append({"key": "_default", "goto": _typeclass_actions}) - return text, options - - -# key node - - -
[docs]def node_key(caller): - text = """ - The |cKey|n is the given name of the object to spawn. This will retain the given case. - - {current} - """.format( - current=_get_current_value(caller, "key") - ) - - helptext = """ - The key should often not be identical for every spawned object. Using a randomising - $protfunc can be used, for example |c$choice(Alan, Tom, John)|n will give one of the three - names every time an object of this prototype is spawned. - - |c$protfuncs|n - {pfuncs} - """.format( - pfuncs=_format_protfuncs() - ) - - text = (text, helptext) - - options = _wizard_options("key", "typeclass", "aliases") - options.append( - { - "key": "_default", - "goto": (_set_property, dict(prop="key", processor=lambda s: s.strip())), - } - ) - return text, options
- - -# aliases node - - -def _all_aliases(caller): - "Get aliases in prototype" - prototype = _get_menu_prototype(caller) - return prototype.get("aliases", []) - - -def _aliases_select(caller, alias): - "Add numbers as aliases" - aliases = _all_aliases(caller) - try: - ind = str(aliases.index(alias) + 1) - if ind not in aliases: - aliases.append(ind) - _set_prototype_value(caller, "aliases", aliases) - caller.msg("Added alias '{}'.".format(ind)) - except (IndexError, ValueError) as err: - caller.msg("Error: {}".format(err)) - - return "node_aliases" - - -def _aliases_actions(caller, raw_inp, **kwargs): - """Parse actions for aliases listing""" - choices = kwargs.get("available_choices", []) - alias, action = _default_parse(raw_inp, choices, ("remove", "r", "delete", "d")) - - aliases = _all_aliases(caller) - if alias and action == "remove": - try: - aliases.remove(alias) - _set_prototype_value(caller, "aliases", aliases) - caller.msg("Removed alias '{}'.".format(alias)) - except ValueError: - caller.msg("No matching alias found to remove.") - else: - # if not a valid remove, add as a new alias - alias = raw_inp.lower().strip() - if alias and alias not in aliases: - aliases.append(alias) - _set_prototype_value(caller, "aliases", aliases) - caller.msg("Added alias '{}'.".format(alias)) - else: - caller.msg("Alias '{}' was already set.".format(alias)) - return "node_aliases" - - -@list_node(_all_aliases, _aliases_select) -def node_aliases(caller): - - text = """ - |cAliases|n are alternative ways to address an object, next to its |cKey|n. Aliases are not - case sensitive. - - {current} - """.format( - current=_get_current_value( - caller, - "aliases", - comparer=lambda propval, flatval: [al for al in flatval if al not in propval], - formatter=lambda lst: "\n" + ", ".join(lst), - only_inherit=True, - ) - ) - _set_actioninfo( - caller, _format_list_actions("remove", prefix="|w<text>|W to add new alias. Other action: ") - ) - - helptext = """ - Aliases are fixed alternative identifiers and are stored with the new object. - - |c$protfuncs|n - - {pfuncs} - """.format( - pfuncs=_format_protfuncs() - ) - - text = (text, helptext) - - options = _wizard_options("aliases", "key", "attrs") - options.append({"key": "_default", "goto": _aliases_actions}) - return text, options - - -# attributes node - - -def _caller_attrs(caller): - prototype = _get_menu_prototype(caller) - attrs = [ - "{}={}".format(tup[0], utils.crop(utils.to_str(tup[1]), width=10)) - for tup in prototype.get("attrs", []) - ] - return attrs - - -def _get_tup_by_attrname(caller, attrname): - prototype = _get_menu_prototype(caller) - attrs = prototype.get("attrs", []) - try: - inp = [tup[0] for tup in attrs].index(attrname) - return attrs[inp] - except ValueError: - return None - - -def _display_attribute(attr_tuple): - """Pretty-print attribute tuple""" - attrkey, value, category, locks = attr_tuple - value = protlib.protfunc_parser(value) - typ = type(value) - out = "{attrkey} |c=|n {value} |W({typ}{category}{locks})|n".format( - attrkey=attrkey, - value=value, - typ=typ, - category=", category={}".format(category) if category else "", - locks=", locks={}".format(";".join(locks)) if any(locks) else "", - ) - - return out - - -def _add_attr(caller, attr_string, **kwargs): - """ - Add new attribute, parsing input. - - Args: - caller (Object): Caller of menu. - attr_string (str): Input from user - attr is entered on these forms - attr = value - attr;category = value - attr;category;lockstring = value - Keyword Args: - delete (str): If this is set, attr_string is - considered the name of the attribute to delete and - no further parsing happens. - Returns: - result (str): Result string of action. - """ - attrname = "" - value = "" - category = None - locks = "" - - if "delete" in kwargs: - attrname = attr_string.lower().strip() - elif "=" in attr_string: - attrname, value = (part.strip() for part in attr_string.split("=", 1)) - attrname = attrname.lower() - nameparts = attrname.split(";", 2) - nparts = len(nameparts) - if nparts == 2: - attrname, category = nameparts - elif nparts > 2: - attrname, category, locks = nameparts - attr_tuple = (attrname, value, category, str(locks)) - - if attrname: - prot = _get_menu_prototype(caller) - attrs = prot.get("attrs", []) - - if "delete" in kwargs: - try: - ind = [tup[0] for tup in attrs].index(attrname) - del attrs[ind] - _set_prototype_value(caller, "attrs", attrs) - return "Removed Attribute '{}'".format(attrname) - except IndexError: - return "Attribute to delete not found." - - try: - # replace existing attribute with the same name in the prototype - ind = [tup[0] for tup in attrs].index(attrname) - attrs[ind] = attr_tuple - text = "Edited Attribute '{}'.".format(attrname) - except ValueError: - attrs.append(attr_tuple) - text = "Added Attribute " + _display_attribute(attr_tuple) - - _set_prototype_value(caller, "attrs", attrs) - else: - text = "Attribute must be given as 'attrname[;category;locks] = <value>'." - - return text - - -def _attr_select(caller, attrstr): - attrname, _ = attrstr.split("=", 1) - attrname = attrname.strip() - - attr_tup = _get_tup_by_attrname(caller, attrname) - if attr_tup: - return ("node_examine_entity", {"text": _display_attribute(attr_tup), "back": "attrs"}) - else: - caller.msg("Attribute not found.") - return "node_attrs" - - -def _attrs_actions(caller, raw_inp, **kwargs): - """Parse actions for attribute listing""" - choices = kwargs.get("available_choices", []) - attrstr, action = _default_parse( - raw_inp, choices, ("examine", "e"), ("remove", "r", "delete", "d") - ) - if attrstr is None: - attrstr = raw_inp - try: - attrname, _ = attrstr.split("=", 1) - except ValueError: - caller.msg("|rNeed to enter the attribute on the form attrname=value.|n") - return "node_attrs" - - attrname = attrname.strip() - attr_tup = _get_tup_by_attrname(caller, attrname) - - if action and attr_tup: - if action == "examine": - return ("node_examine_entity", {"text": _display_attribute(attr_tup), "back": "attrs"}) - elif action == "remove": - res = _add_attr(caller, attrname, delete=True) - caller.msg(res) - else: - res = _add_attr(caller, raw_inp) - caller.msg(res) - return "node_attrs" - - -@list_node(_caller_attrs, _attr_select) -def node_attrs(caller): - def _currentcmp(propval, flatval): - "match by key + category" - cmp1 = [(tup[0].lower(), tup[2].lower() if tup[2] else None) for tup in propval] - return [ - tup - for tup in flatval - if (tup[0].lower(), tup[2].lower() if tup[2] else None) not in cmp1 - ] - - text = """ - |cAttributes|n are custom properties of the object. Enter attributes on one of these forms: - - attrname=value - attrname;category=value - attrname;category;lockstring=value - - To give an attribute without a category but with a lockstring, leave that spot empty - (attrname;;lockstring=value). Attribute values can have embedded $protfuncs. - - {current} - """.format( - current=_get_current_value( - caller, - "attrs", - comparer=_currentcmp, - formatter=lambda lst: "\n" + "\n".join(_display_attribute(tup) for tup in lst), - only_inherit=True, - ) - ) - _set_actioninfo(caller, _format_list_actions("examine", "remove", prefix="Actions: ")) - - helptext = """ - Most commonly, Attributes don't need any categories or locks. If using locks, the lock-types - 'attredit' and 'attrread' are used to limit editing and viewing of the Attribute. Putting - the lock-type `attrcreate` in the |clocks|n prototype key can be used to restrict builders - from adding new Attributes. - - |c$protfuncs - - {pfuncs} - """.format( - pfuncs=_format_protfuncs() - ) - - text = (text, helptext) - - options = _wizard_options("attrs", "aliases", "tags") - options.append({"key": "_default", "goto": _attrs_actions}) - return text, options - - -# tags node - - -def _caller_tags(caller): - prototype = _get_menu_prototype(caller) - tags = [tup[0] for tup in prototype.get("tags", [])] - return tags - - -def _get_tup_by_tagname(caller, tagname): - prototype = _get_menu_prototype(caller) - tags = prototype.get("tags", []) - try: - inp = [tup[0] for tup in tags].index(tagname) - return tags[inp] - except ValueError: - return None - - -def _display_tag(tag_tuple): - """Pretty-print tag tuple""" - tagkey, category, data = tag_tuple - out = "Tag: '{tagkey}' (category: {category}{dat})".format( - tagkey=tagkey, category=category, dat=", data: {}".format(data) if data else "" - ) - return out - - -def _add_tag(caller, tag_string, **kwargs): - """ - Add tags to the system, parsing input - - Args: - caller (Object): Caller of menu. - tag_string (str): Input from user on one of these forms - tagname - tagname;category - tagname;category;data - - Keyword Args: - delete (str): If this is set, tag_string is considered - the name of the tag to delete. - - Returns: - result (str): Result string of action. - - """ - tag = tag_string.strip().lower() - category = None - data = "" - - if "delete" in kwargs: - tag = tag_string.lower().strip() - else: - nameparts = tag.split(";", 2) - ntuple = len(nameparts) - if ntuple == 2: - tag, category = nameparts - elif ntuple > 2: - tag, category, data = nameparts[:3] - - tag_tuple = (tag.lower(), category.lower() if category else None, data) - - if tag: - prot = _get_menu_prototype(caller) - tags = prot.get("tags", []) - - old_tag = _get_tup_by_tagname(caller, tag) - - if "delete" in kwargs: - - if old_tag: - tags.pop(tags.index(old_tag)) - text = "Removed Tag '{}'.".format(tag) - else: - text = "Found no Tag to remove." - elif not old_tag: - # a fresh, new tag - tags.append(tag_tuple) - text = "Added Tag '{}'".format(tag) - else: - # old tag exists; editing a tag means replacing old with new - ind = tags.index(old_tag) - tags[ind] = tag_tuple - text = "Edited Tag '{}'".format(tag) - - _set_prototype_value(caller, "tags", tags) - else: - text = "Tag must be given as 'tag[;category;data]'." - - return text - - -def _tag_select(caller, tagname): - tag_tup = _get_tup_by_tagname(caller, tagname) - if tag_tup: - return "node_examine_entity", {"text": _display_tag(tag_tup), "back": "attrs"} - else: - caller.msg("Tag not found.") - return "node_attrs" - - -def _tags_actions(caller, raw_inp, **kwargs): - """Parse actions for tags listing""" - choices = kwargs.get("available_choices", []) - tagname, action = _default_parse( - raw_inp, choices, ("examine", "e"), ("remove", "r", "delete", "d") - ) - - if tagname is None: - tagname = raw_inp.lower().strip() - - tag_tup = _get_tup_by_tagname(caller, tagname) - - if tag_tup: - if action == "examine": - return ("node_examine_entity", {"text": _display_tag(tag_tup), "back": "tags"}) - elif action == "remove": - res = _add_tag(caller, tagname, delete=True) - caller.msg(res) - else: - res = _add_tag(caller, raw_inp) - caller.msg(res) - return "node_tags" - - -@list_node(_caller_tags, _tag_select) -def node_tags(caller): - def _currentcmp(propval, flatval): - "match by key + category" - cmp1 = [(tup[0].lower(), tup[1].lower() if tup[2] else None) for tup in propval] - return [ - tup - for tup in flatval - if (tup[0].lower(), tup[1].lower() if tup[1] else None) not in cmp1 - ] - - text = """ - |cTags|n are used to group objects so they can quickly be found later. Enter tags on one of - the following forms: - tagname - tagname;category - tagname;category;data - - {current} - """.format( - current=_get_current_value( - caller, - "tags", - comparer=_currentcmp, - formatter=lambda lst: "\n" + "\n".join(_display_tag(tup) for tup in lst), - only_inherit=True, - ) - ) - _set_actioninfo(caller, _format_list_actions("examine", "remove", prefix="Actions: ")) - - helptext = """ - Tags are shared between all objects with that tag. So the 'data' field (which is not - commonly used) can only hold eventual info about the Tag itself, not about the individual - object on which it sits. - - All objects created with this prototype will automatically get assigned a tag named the same - as the |cprototype_key|n and with a category "{tag_category}". This allows the spawner to - optionally update previously spawned objects when their prototype changes. - """.format( - tag_category=protlib.PROTOTYPE_TAG_CATEGORY - ) - - text = (text, helptext) - options = _wizard_options("tags", "attrs", "locks") - options.append({"key": "_default", "goto": _tags_actions}) - return text, options - - -# locks node - - -def _caller_locks(caller): - locks = _get_menu_prototype(caller).get("locks", "") - return [lck for lck in locks.split(";") if lck] - - -def _locks_display(caller, lock): - return lock - - -def _lock_select(caller, lockstr): - return ("node_examine_entity", {"text": _locks_display(caller, lockstr), "back": "locks"}) - - -def _lock_add(caller, lock, **kwargs): - locks = _caller_locks(caller) - - try: - locktype, lockdef = lock.split(":", 1) - except ValueError: - return "Lockstring lacks ':'." - - locktype = locktype.strip().lower() - - if "delete" in kwargs: - try: - ind = locks.index(lock) - locks.pop(ind) - _set_prototype_value(caller, "locks", ";".join(locks), parse=False) - ret = "Lock {} deleted.".format(lock) - except ValueError: - ret = "No lock found to delete." - return ret - try: - locktypes = [lck.split(":", 1)[0].strip().lower() for lck in locks] - ind = locktypes.index(locktype) - locks[ind] = lock - ret = "Lock with locktype '{}' updated.".format(locktype) - except ValueError: - locks.append(lock) - ret = "Added lock '{}'.".format(lock) - _set_prototype_value(caller, "locks", ";".join(locks)) - return ret - - -def _locks_actions(caller, raw_inp, **kwargs): - choices = kwargs.get("available_choices", []) - lock, action = _default_parse( - raw_inp, choices, ("examine", "e"), ("remove", "r", "delete", "d") - ) - - if lock: - if action == "examine": - return ("node_examine_entity", {"text": _locks_display(caller, lock), "back": "locks"}) - elif action == "remove": - ret = _lock_add(caller, lock, delete=True) - caller.msg(ret) - else: - ret = _lock_add(caller, raw_inp) - caller.msg(ret) - - return "node_locks" - - -@list_node(_caller_locks, _lock_select) -def node_locks(caller): - def _currentcmp(propval, flatval): - "match by locktype" - cmp1 = [lck.split(":", 1)[0] for lck in propval.split(";")] - return ";".join(lstr for lstr in flatval.split(";") if lstr.split(":", 1)[0] not in cmp1) - - text = """ - The |cLock string|n defines limitations for accessing various properties of the object once - it's spawned. The string should be on one of the following forms: - - locktype:[NOT] lockfunc(args) - locktype: [NOT] lockfunc(args) [AND|OR|NOT] lockfunc(args) [AND|OR|NOT] ... - - {current}{action} - """.format( - current=_get_current_value( - caller, - "locks", - comparer=_currentcmp, - formatter=lambda lockstr: "\n".join( - _locks_display(caller, lstr) for lstr in lockstr.split(";") - ), - only_inherit=True, - ), - action=_format_list_actions("examine", "remove", prefix="Actions: "), - ) - - helptext = """ - Here is an example of two lock strings: - - edit:false() - call:tag(Foo) OR perm(Builder) - - Above locks limit two things, 'edit' and 'call'. Which lock types are actually checked - depend on the typeclass of the object being spawned. Here 'edit' is never allowed by anyone - while 'call' is allowed to all accessors with a |ctag|n 'Foo' OR which has the - |cPermission|n 'Builder'. - - |cAvailable lockfuncs:|n - - {lfuncs} - """.format( - lfuncs=_format_lockfuncs() - ) - - text = (text, helptext) - - options = _wizard_options("locks", "tags", "permissions") - options.append({"key": "_default", "goto": _locks_actions}) - - return text, options - - -# permissions node - - -def _caller_permissions(caller): - prototype = _get_menu_prototype(caller) - perms = prototype.get("permissions", []) - return perms - - -def _display_perm(caller, permission, only_hierarchy=False): - hierarchy = settings.PERMISSION_HIERARCHY - perm_low = permission.lower() - txt = "" - if perm_low in [prm.lower() for prm in hierarchy]: - txt = "Permission (in hieararchy): {}".format( - ", ".join( - [ - "|w[{}]|n".format(prm) if prm.lower() == perm_low else "|W{}|n".format(prm) - for prm in hierarchy - ] - ) - ) - elif not only_hierarchy: - txt = "Permission: '{}'".format(permission) - return txt - - -def _permission_select(caller, permission, **kwargs): - return ( - "node_examine_entity", - {"text": _display_perm(caller, permission), "back": "permissions"}, - ) - - -def _add_perm(caller, perm, **kwargs): - if perm: - perm_low = perm.lower() - perms = _caller_permissions(caller) - perms_low = [prm.lower() for prm in perms] - if "delete" in kwargs: - try: - ind = perms_low.index(perm_low) - del perms[ind] - text = "Removed Permission '{}'.".format(perm) - except ValueError: - text = "Found no Permission to remove." - else: - if perm_low in perms_low: - text = "Permission already set." - else: - perms.append(perm) - _set_prototype_value(caller, "permissions", perms) - text = "Added Permission '{}'".format(perm) - return text - - -def _permissions_actions(caller, raw_inp, **kwargs): - """Parse actions for permission listing""" - choices = kwargs.get("available_choices", []) - perm, action = _default_parse( - raw_inp, choices, ("examine", "e"), ("remove", "r", "delete", "d") - ) - - if perm: - if action == "examine": - return ( - "node_examine_entity", - {"text": _display_perm(caller, perm), "back": "permissions"}, - ) - elif action == "remove": - res = _add_perm(caller, perm, delete=True) - caller.msg(res) - else: - res = _add_perm(caller, raw_inp.strip()) - caller.msg(res) - return "node_permissions" - - -@list_node(_caller_permissions, _permission_select) -def node_permissions(caller): - def _currentcmp(pval, fval): - cmp1 = [perm.lower() for perm in pval] - return [perm for perm in fval if perm.lower() not in cmp1] - - text = """ - |cPermissions|n are simple strings used to grant access to this object. A permission is used - when a |clock|n is checked that contains the |wperm|n or |wpperm|n lock functions. Certain - permissions belong in the |cpermission hierarchy|n together with the |Wperm()|n lock - function. - - {current} - """.format( - current=_get_current_value( - caller, - "permissions", - comparer=_currentcmp, - formatter=lambda lst: "\n" + "\n".join(prm for prm in lst), - only_inherit=True, - ) - ) - _set_actioninfo(caller, _format_list_actions("examine", "remove", prefix="Actions: ")) - - helptext = """ - Any string can act as a permission as long as a lock is set to look for it. Depending on the - lock, having a permission could even be negative (i.e. the lock is only passed if you - |wdon't|n have the 'permission'). The most common permissions are the hierarchical - permissions: - - {permissions}. - - For example, a |clock|n string like "edit:perm(Builder)" will grant access to accessors - having the |cpermission|n "Builder" or higher. - """.format( - permissions=", ".join(settings.PERMISSION_HIERARCHY) - ) - - text = (text, helptext) - - options = _wizard_options("permissions", "locks", "location") - options.append({"key": "_default", "goto": _permissions_actions}) - - return text, options - - -# location node - - -
[docs]def node_location(caller): - - text = """ - The |cLocation|n of this object in the world. If not given, the object will spawn in the - inventory of |c{caller}|n by default. - - {current} - """.format( - caller=caller.key, current=_get_current_value(caller, "location") - ) - - helptext = """ - You get the most control by not specifying the location - you can then teleport the spawned - objects as needed later. Setting the location may be useful for quickly populating a given - location. One could also consider randomizing the location using a $protfunc. - - |c$protfuncs|n - {pfuncs} - """.format( - pfuncs=_format_protfuncs() - ) - - text = (text, helptext) - - options = _wizard_options("location", "permissions", "home", search=True) - options.append( - { - "key": "_default", - "goto": (_set_property, dict(prop="location", processor=lambda s: s.strip())), - } - ) - return text, options
- - -# home node - - -
[docs]def node_home(caller): - - text = """ - The |cHome|n location of an object is often only used as a backup - this is where the object - will be moved to if its location is deleted. The home location can also be used as an actual - home for characters to quickly move back to. - - If unset, the global home default (|w{default}|n) will be used. - - {current} - """.format( - default=settings.DEFAULT_HOME, current=_get_current_value(caller, "home") - ) - helptext = """ - The home can be given as a #dbref but can also be specified using the protfunc - '$obj(name)'. Use |wSE|nearch to find objects in the database. - - The home location is commonly not used except as a backup; using the global default is often - enough. - - |c$protfuncs|n - {pfuncs} - """.format( - pfuncs=_format_protfuncs() - ) - - text = (text, helptext) - - options = _wizard_options("home", "location", "destination", search=True) - options.append( - { - "key": "_default", - "goto": (_set_property, dict(prop="home", processor=lambda s: s.strip())), - } - ) - return text, options
- - -# destination node - - -
[docs]def node_destination(caller): - - text = """ - The object's |cDestination|n is generally only used by Exit-like objects to designate where - the exit 'leads to'. It's usually unset for all other types of objects. - - {current} - """.format( - current=_get_current_value(caller, "destination") - ) - - helptext = """ - The destination can be given as a #dbref but can also be specified using the protfunc - '$obj(name)'. Use |wSEearch to find objects in the database. - - |c$protfuncs|n - {pfuncs} - """.format( - pfuncs=_format_protfuncs() - ) - - text = (text, helptext) - - options = _wizard_options("destination", "home", "prototype_desc", search=True) - options.append( - { - "key": "_default", - "goto": (_set_property, dict(prop="destination", processor=lambda s: s.strip())), - } - ) - return text, options
- - -# prototype_desc node - - -
[docs]def node_prototype_desc(caller): - - text = """ - The |cPrototype-Description|n briefly describes the prototype when it's viewed in listings. - - {current} - """.format( - current=_get_current_value(caller, "prototype_desc") - ) - - helptext = """ - Giving a brief description helps you and others to locate the prototype for use later. - """ - - text = (text, helptext) - - options = _wizard_options("prototype_desc", "prototype_key", "prototype_tags") - options.append( - { - "key": "_default", - "goto": ( - _set_property, - dict( - prop="prototype_desc", - processor=lambda s: s.strip(), - next_node="node_prototype_desc", - ), - ), - } - ) - - return text, options
- - -# prototype_tags node - - -def _caller_prototype_tags(caller): - prototype = _get_menu_prototype(caller) - tags = prototype.get("prototype_tags", []) - tags = [tag[0] if isinstance(tag, tuple) else tag for tag in tags] - return tags - - -def _add_prototype_tag(caller, tag_string, **kwargs): - """ - Add prototype_tags to the system. We only support straight tags, no - categories (category is assigned automatically). - - Args: - caller (Object): Caller of menu. - tag_string (str): Input from user - only tagname - - Keyword Args: - delete (str): If this is set, tag_string is considered - the name of the tag to delete. - - Returns: - result (str): Result string of action. - - """ - tag = tag_string.strip().lower() - - if tag: - tags = _caller_prototype_tags(caller) - exists = tag in tags - - if "delete" in kwargs: - if exists: - tags.pop(tags.index(tag)) - text = "Removed Prototype-Tag '{}'.".format(tag) - else: - text = "Found no Prototype-Tag to remove." - elif not exists: - # a fresh, new tag - tags.append(tag) - text = "Added Prototype-Tag '{}'.".format(tag) - else: - text = "Prototype-Tag already added." - - _set_prototype_value(caller, "prototype_tags", tags) - else: - text = "No Prototype-Tag specified." - - return text - - -def _prototype_tag_select(caller, tagname): - caller.msg("Prototype-Tag: {}".format(tagname)) - return "node_prototype_tags" - - -def _prototype_tags_actions(caller, raw_inp, **kwargs): - """Parse actions for tags listing""" - choices = kwargs.get("available_choices", []) - tagname, action = _default_parse(raw_inp, choices, ("remove", "r", "delete", "d")) - - if tagname: - if action == "remove": - res = _add_prototype_tag(caller, tagname, delete=True) - caller.msg(res) - else: - res = _add_prototype_tag(caller, raw_inp.lower().strip()) - caller.msg(res) - return "node_prototype_tags" - - -@list_node(_caller_prototype_tags, _prototype_tag_select) -def node_prototype_tags(caller): - - text = """ - |cPrototype-Tags|n can be used to classify and find prototypes in listings Tag names are not - case-sensitive and can have not have a custom category. - - {current} - """.format( - current=_get_current_value( - caller, - "prototype_tags", - formatter=lambda lst: ", ".join(tg for tg in lst), - only_inherit=True, - ) - ) - _set_actioninfo( - caller, _format_list_actions("remove", prefix="|w<text>|n|W to add Tag. Other Action:|n ") - ) - helptext = """ - Using prototype-tags is a good way to organize and group large numbers of prototypes by - genre, type etc. Under the hood, prototypes' tags will all be stored with the category - '{tagmetacategory}'. - """.format( - tagmetacategory=protlib._PROTOTYPE_TAG_META_CATEGORY - ) - - text = (text, helptext) - - options = _wizard_options("prototype_tags", "prototype_desc", "prototype_locks") - options.append({"key": "_default", "goto": _prototype_tags_actions}) - - return text, options - - -# prototype_locks node - - -def _caller_prototype_locks(caller): - locks = _get_menu_prototype(caller).get("prototype_locks", "") - return [lck for lck in locks.split(";") if lck] - - -def _prototype_lock_select(caller, lockstr): - return ( - "node_examine_entity", - {"text": _locks_display(caller, lockstr), "back": "prototype_locks"}, - ) - - -def _prototype_lock_add(caller, lock, **kwargs): - locks = _caller_prototype_locks(caller) - - try: - locktype, lockdef = lock.split(":", 1) - except ValueError: - return "Lockstring lacks ':'." - - locktype = locktype.strip().lower() - - if "delete" in kwargs: - try: - ind = locks.index(lock) - locks.pop(ind) - _set_prototype_value(caller, "prototype_locks", ";".join(locks), parse=False) - ret = "Prototype-lock {} deleted.".format(lock) - except ValueError: - ret = "No Prototype-lock found to delete." - return ret - try: - locktypes = [lck.split(":", 1)[0].strip().lower() for lck in locks] - ind = locktypes.index(locktype) - locks[ind] = lock - ret = "Prototype-lock with locktype '{}' updated.".format(locktype) - except ValueError: - locks.append(lock) - ret = "Added Prototype-lock '{}'.".format(lock) - _set_prototype_value(caller, "prototype_locks", ";".join(locks)) - return ret - - -def _prototype_locks_actions(caller, raw_inp, **kwargs): - choices = kwargs.get("available_choices", []) - lock, action = _default_parse( - raw_inp, choices, ("examine", "e"), ("remove", "r", "delete", "d") - ) - - if lock: - if action == "examine": - return ("node_examine_entity", {"text": _locks_display(caller, lock), "back": "locks"}) - elif action == "remove": - ret = _prototype_lock_add(caller, lock.strip(), delete=True) - caller.msg(ret) - else: - ret = _prototype_lock_add(caller, raw_inp.strip()) - caller.msg(ret) - - return "node_prototype_locks" - - -@list_node(_caller_prototype_locks, _prototype_lock_select) -def node_prototype_locks(caller): - - text = """ - |cPrototype-Locks|n are used to limit access to this prototype when someone else is trying - to access it. By default any prototype can be edited only by the creator and by Admins while - they can be used by anyone with access to the spawn command. There are two valid lock types - the prototype access tools look for: - - - 'edit': Who can edit the prototype. - - 'spawn': Who can spawn new objects with this prototype. - - If unsure, keep the open defaults. - - {current} - """.format( - current=_get_current_value( - caller, - "prototype_locks", - formatter=lambda lstring: "\n".join( - _locks_display(caller, lstr) for lstr in lstring.split(";") - ), - only_inherit=True, - ) - ) - _set_actioninfo(caller, _format_list_actions("examine", "remove", prefix="Actions: ")) - - helptext = """ - Prototype locks can be used to vary access for different tiers of builders. It also allows - developers to produce 'base prototypes' only meant for builders to inherit and expand on - rather than tweak in-place. - """ - - text = (text, helptext) - - options = _wizard_options("prototype_locks", "prototype_tags", "index") - options.append({"key": "_default", "goto": _prototype_locks_actions}) - - return text, options - - -# update existing objects node - - -def _apply_diff(caller, **kwargs): - """update existing objects""" - prototype = kwargs["prototype"] - objects = kwargs["objects"] - back_node = kwargs["back_node"] - diff = kwargs.get("diff", None) - num_changed = spawner.batch_update_objects_with_prototype(prototype, diff=diff, objects=objects, - caller=caller) - caller.msg("|g{num} objects were updated successfully.|n".format(num=num_changed)) - return back_node - - -def _keep_diff(caller, **kwargs): - """Change to KEEP setting for a given section of a diff""" - # from evennia import set_trace;set_trace(term_size=(182, 50)) - path = kwargs["path"] - diff = kwargs["diff"] - tmp = diff - for key in path[:-1]: - tmp = tmp[key] - tmp[path[-1]] = tuple(list(tmp[path[-1]][:-1]) + ["KEEP"]) - - -def _format_diff_text_and_options(diff, minimal=True, **kwargs): - """ - Reformat the diff in a way suitable for the olc menu. - - Args: - diff (dict): A diff as produced by `prototype_diff`. - minimal (bool, optional): Don't show KEEPs. - - Keyword Args: - any (any): Forwarded into the generated options as arguments to the callable. - - Returns: - texts (list): List of texts. - options (list): List of options dict. - - """ - valid_instructions = ("KEEP", "REMOVE", "ADD", "UPDATE") - - def _visualize(obj, rootname, get_name=False): - if utils.is_iter(obj): - if not obj: - return str(obj) - if get_name: - return obj[0] if obj[0] else "<unset>" - if rootname == "attrs": - return "{} |W=|n {} |W(category:|n {}|W, locks:|n {}|W)|n".format(*obj) - elif rootname == "tags": - return "{} |W(category:|n {}|W)|n".format(obj[0], obj[1]) - - return "{}".format(obj) - - def _parse_diffpart(diffpart, optnum, *args): - typ = type(diffpart) - texts = [] - options = [] - if typ == tuple and len(diffpart) == 3 and diffpart[2] in valid_instructions: - rootname = args[0] - old, new, instruction = diffpart - if instruction == "KEEP": - if not minimal: - texts.append(" |gKEEP|W:|n {old}".format(old=_visualize(old, rootname))) - else: - # instructions we should be able to revert by a menu choice - vold = _visualize(old, rootname) - vnew = _visualize(new, rootname) - vsep = "" if len(vold) < 78 else "\n" - - if instruction == "ADD": - texts.append( - " |c[{optnum}] |yADD|n: {new}".format( - optnum=optnum, new=_visualize(new, rootname) - ) - ) - elif instruction == "REMOVE" and not new: - if rootname == "tags" and old[1] == protlib.PROTOTYPE_TAG_CATEGORY: - # special exception for the prototype-tag mechanism - # this is added post-spawn automatically and should - # not be listed as REMOVE. - return texts, options, optnum - - texts.append( - " |c[{optnum}] |rREMOVE|n: {old}".format( - optnum=optnum, old=_visualize(old, rootname) - ) - ) - else: - vinst = "|y{}|n".format(instruction) - texts.append( - " |c[{num}] {inst}|W:|n {old} |W->|n{sep} {new}".format( - inst=vinst, num=optnum, old=vold, sep=vsep, new=vnew - ) - ) - options.append( - { - "key": str(optnum), - "desc": "|gKEEP|n ({}) {}".format( - rootname, _visualize(old, args[-1], get_name=True) - ), - "goto": (_keep_diff, dict((("path", args), ("diff", diff)), **kwargs)), - } - ) - optnum += 1 - else: - for key in sorted(list(diffpart.keys())): - subdiffpart = diffpart[key] - text, option, optnum = _parse_diffpart(subdiffpart, optnum, *(args + (key,))) - texts.extend(text) - options.extend(option) - return texts, options, optnum - - texts = [] - options = [] - # we use this to allow for skipping full KEEP instructions - optnum = 1 - - for root_key in sorted(diff): - diffpart = diff[root_key] - text, option, optnum = _parse_diffpart(diffpart, optnum, root_key) - heading = "- |w{}:|n ".format(root_key) - if text: - text = [heading + text[0]] + text[1:] - else: - text = [heading] - - texts.extend(text) - options.extend(option) - - return texts, options - - -
[docs]def node_apply_diff(caller, **kwargs): - """Offer options for updating objects""" - - def _keep_option(keyname, prototype, base_obj, obj_prototype, diff, objects, back_node): - """helper returning an option dict""" - options = { - "desc": "Keep {} as-is".format(keyname), - "goto": ( - _keep_diff, - { - "key": keyname, - "prototype": prototype, - "base_obj": base_obj, - "obj_prototype": obj_prototype, - "diff": diff, - "objects": objects, - "back_node": back_node, - }, - ), - } - return options - - prototype = kwargs.get("prototype", None) - update_objects = kwargs.get("objects", None) - back_node = kwargs.get("back_node", "node_index") - obj_prototype = kwargs.get("obj_prototype", None) - base_obj = kwargs.get("base_obj", None) - diff = kwargs.get("diff", None) - custom_location = kwargs.get("custom_location", None) - - if not update_objects: - text = "There are no existing objects to update." - options = {"key": "_default", "goto": back_node} - return text, options - - if not diff: - # use one random object as a reference to calculate a diff - base_obj = choice(update_objects) - - diff, obj_prototype = spawner.prototype_diff_from_object(prototype, base_obj) - - helptext = """ - This will go through all existing objects and apply the changes you accept. - - Be careful with this operation! The upgrade mechanism will try to automatically estimate - what changes need to be applied. But the estimate is |wonly based on the analysis of one - randomly selected object|n among all objects spawned by this prototype. If that object - happens to be unusual in some way the estimate will be off and may lead to unexpected - results for other objects. Always test your objects carefully after an upgrade and consider - being conservative (switch to KEEP) for things you are unsure of. For complex upgrades it - may be better to get help from an administrator with access to the `@py` command for doing - this manually. - - Note that the `location` will never be auto-adjusted because it's so rare to want to - homogenize the location of all object instances.""" - - if not custom_location: - diff.pop("location", None) - - txt, options = _format_diff_text_and_options( - diff, objects=update_objects, base_obj=base_obj, prototype=prototype - ) - - if options: - text = [ - "Suggested changes to {} objects. ".format(len(update_objects)), - "Showing random example obj to change: {name} ({dbref}))\n".format( - name=base_obj.key, dbref=base_obj.dbref - ), - ] + txt - options.extend( - [ - { - "key": ("|wu|Wpdate {} objects".format(len(update_objects)), "update", "u"), - "desc": "Update {} objects".format(len(update_objects)), - "goto": ( - _apply_diff, - { - "prototype": prototype, - "objects": update_objects, - "back_node": back_node, - "diff": diff, - "base_obj": base_obj, - }, - ), - }, - { - "key": ("|wr|Weset changes", "reset", "r"), - "goto": ( - "node_apply_diff", - {"prototype": prototype, "back_node": back_node, "objects": update_objects}, - ), - }, - ] - ) - else: - text = [ - "Analyzed a random sample object (out of {}) - " - "found no changes to apply.".format(len(update_objects)) - ] - - options.extend(_wizard_options("update_objects", back_node[5:], None)) - options.append({"key": "_default", "goto": back_node}) - - text = "\n".join(text) - text = (text, helptext) - - return text, options
- - -# prototype save node - - -
[docs]def node_prototype_save(caller, **kwargs): - """Save prototype to disk """ - # these are only set if we selected 'yes' to save on a previous pass - prototype = kwargs.get("prototype", None) - # set to True/False if answered, None if first pass - accept_save = kwargs.get("accept_save", None) - - if accept_save and prototype: - # we already validated and accepted the save, so this node acts as a goto callback and - # should now only return the next node - prototype_key = prototype.get("prototype_key") - try: - protlib.save_prototype(prototype) - except Exception as exc: - text = "|rCould not save:|n {}\n(press Return to continue)".format(exc) - options = {"key": "_default", "goto": "node_index"} - return text, options - - spawned_objects = protlib.search_objects_with_prototype(prototype_key) - nspawned = spawned_objects.count() - - text = ["|gPrototype saved.|n"] - - if nspawned: - text.append( - "\nDo you want to update {} object(s) " - "already using this prototype?".format(nspawned) - ) - options = ( - { - "key": ("|wY|Wes|n", "yes", "y"), - "desc": "Go to updating screen", - "goto": ( - "node_apply_diff", - { - "accept_update": True, - "objects": spawned_objects, - "prototype": prototype, - "back_node": "node_prototype_save", - }, - ), - }, - {"key": ("[|wN|Wo|n]", "n"), "desc": "Return to index", "goto": "node_index"}, - {"key": "_default", "goto": "node_index"}, - ) - else: - text.append("(press Return to continue)") - options = {"key": "_default", "goto": "node_index"} - - text = "\n".join(text) - - helptext = """ - Updating objects means that the spawner will find all objects previously created by this - prototype. You will be presented with a list of the changes the system will try to apply to - each of these objects and you can choose to customize that change if needed. If you have - done a lot of manual changes to your objects after spawning, you might want to update those - objects manually instead. - """ - - text = (text, helptext) - - return text, options - - # not validated yet - prototype = _get_menu_prototype(caller) - error, text = _validate_prototype(prototype) - - text = [text] - - if error: - # abort save - text.append( - "\n|yValidation errors were found. They need to be corrected before this prototype " - "can be saved (or used to spawn).|n" - ) - options = _wizard_options("prototype_save", "index", None) - options.append({"key": "_default", "goto": "node_index"}) - return "\n".join(text), options - - prototype_key = prototype["prototype_key"] - if protlib.search_prototype(prototype_key): - text.append( - "\nDo you want to save/overwrite the existing prototype '{name}'?".format( - name=prototype_key - ) - ) - else: - text.append("\nDo you want to save the prototype as '{name}'?".format(name=prototype_key)) - - text = "\n".join(text) - - helptext = """ - Saving the prototype makes it available for use later. It can also be used to inherit from, - by name. Depending on |cprototype-locks|n it also makes the prototype usable and/or - editable by others. Consider setting good |cPrototype-tags|n and to give a useful, brief - |cPrototype-desc|n to make the prototype easy to find later. - - """ - - text = (text, helptext) - - options = ( - { - "key": ("[|wY|Wes|n]", "yes", "y"), - "desc": "Save prototype", - "goto": ("node_prototype_save", {"accept_save": True, "prototype": prototype}), - }, - {"key": ("|wN|Wo|n", "n"), "desc": "Abort and return to Index", "goto": "node_index"}, - { - "key": "_default", - "goto": ("node_prototype_save", {"accept_save": True, "prototype": prototype}), - }, - ) - - return text, options
- - -# spawning node - - -def _spawn(caller, **kwargs): - """Spawn prototype""" - prototype = kwargs["prototype"].copy() - new_location = kwargs.get("location", None) - if new_location: - prototype["location"] = new_location - if not prototype.get("location"): - prototype["location"] = caller - - obj = spawner.spawn(prototype, caller=caller) - if obj: - obj = obj[0] - text = "|gNew instance|n {key} ({dbref}) |gspawned at location |n{loc}|n|g.|n".format( - key=obj.key, dbref=obj.dbref, loc=prototype["location"] - ) - else: - text = "|rError: Spawner did not return a new instance.|n" - return "node_examine_entity", {"text": text, "back": "prototype_spawn"} - - -
[docs]def node_prototype_spawn(caller, **kwargs): - """Submenu for spawning the prototype""" - - prototype = _get_menu_prototype(caller) - - already_validated = kwargs.get("already_validated", False) - - if already_validated: - error, text = None, [] - else: - error, text = _validate_prototype(prototype) - text = [text] - - if error: - text.append("\n|rPrototype validation failed. Correct the errors before spawning.|n") - options = _wizard_options("prototype_spawn", "index", None) - return "\n".join(text), options - - text = "\n".join(text) - - helptext = """ - Spawning is the act of instantiating a prototype into an actual object. As a new object is - spawned, every $protfunc in the prototype is called anew. Since this is a common thing to - do, you may also temporarily change the |clocation|n of this prototype to bypass whatever - value is set in the prototype. - - """ - text = (text, helptext) - - # show spawn submenu options - options = [] - prototype_key = prototype["prototype_key"] - location = prototype.get("location", None) - - if location: - options.append( - { - "desc": "Spawn in prototype's defined location ({loc})".format(loc=location), - "goto": ( - _spawn, - dict(prototype=prototype, location=location, custom_location=True), - ), - } - ) - caller_loc = caller.location - if location != caller_loc: - options.append( - { - "desc": "Spawn in {caller}'s location ({loc})".format( - caller=caller, loc=caller_loc - ), - "goto": (_spawn, dict(prototype=prototype, location=caller_loc)), - } - ) - if location != caller_loc != caller: - options.append( - { - "desc": "Spawn in {caller}'s inventory".format(caller=caller), - "goto": (_spawn, dict(prototype=prototype, location=caller)), - } - ) - - spawned_objects = protlib.search_objects_with_prototype(prototype_key) - nspawned = spawned_objects.count() - if spawned_objects: - options.append( - { - "desc": "Update {num} existing objects with this prototype".format(num=nspawned), - "goto": ( - "node_apply_diff", - { - "objects": list(spawned_objects), - "prototype": prototype, - "back_node": "node_prototype_spawn", - }, - ), - } - ) - options.extend(_wizard_options("prototype_spawn", "index", None)) - options.append({"key": "_default", "goto": "node_index"}) - - return text, options
- - -# prototype load node - - -def _prototype_load_select(caller, prototype_key, **kwargs): - matches = protlib.search_prototype(key=prototype_key) - if matches: - prototype = matches[0] - _set_menu_prototype(caller, prototype) - return ( - "node_examine_entity", - { - "text": "|gLoaded prototype {}.|n".format(prototype["prototype_key"]), - "back": "index", - }, - ) - else: - caller.msg("|rFailed to load prototype '{}'.".format(prototype_key)) - return None - - -def _prototype_load_actions(caller, raw_inp, **kwargs): - """Parse the default Convert prototype to a string representation for closer inspection""" - choices = kwargs.get("available_choices", []) - prototype, action = _default_parse( - raw_inp, choices, ("examine", "e", "l"), ("delete", "del", "d") - ) - - if prototype: - - # which action to apply on the selection - if action == "examine": - # examine the prototype - prototype = protlib.search_prototype(key=prototype)[0] - txt = protlib.prototype_to_str(prototype) - return "node_examine_entity", {"text": txt, "back": "prototype_load"} - elif action == "delete": - # delete prototype from disk - try: - protlib.delete_prototype(prototype, caller=caller) - except protlib.PermissionError as err: - txt = "|rDeletion error:|n {}".format(err) - else: - txt = "|gPrototype {} was deleted.|n".format(prototype) - return "node_examine_entity", {"text": txt, "back": "prototype_load"} - - return "node_prototype_load" - - -@list_node(_all_prototype_parents, _prototype_load_select) -def node_prototype_load(caller, **kwargs): - """Load prototype""" - - text = """ - Select a prototype to load. This will replace any prototype currently being edited! - """ - _set_actioninfo(caller, _format_list_actions("examine", "delete")) - - helptext = """ - Loading a prototype will load it and return you to the main index. It can be a good idea - to examine the prototype before loading it. - """ - - text = (text, helptext) - - options = _wizard_options("prototype_load", "index", None) - options.append({"key": "_default", "goto": _prototype_load_actions}) - - return text, options - - -# EvMenu definition, formatting and access functions - - -
[docs]class OLCMenu(EvMenu): - """ - A custom EvMenu with a different formatting for the options. - - """ - -
[docs] def nodetext_formatter(self, nodetext): - """ - Format the node text itself. - - """ - return super(OLCMenu, self).nodetext_formatter(nodetext)
- -
[docs] def options_formatter(self, optionlist): - """ - Split the options into two blocks - olc options and normal options - - """ - olc_keys = ( - "index", - "forward", - "back", - "previous", - "next", - "validate prototype", - "save prototype", - "load prototype", - "spawn prototype", - "search objects", - ) - actioninfo = self.actioninfo + "\n" if hasattr(self, "actioninfo") else "" - self.actioninfo = "" # important, or this could bleed over to other nodes - olc_options = [] - other_options = [] - for key, desc in optionlist: - raw_key = strip_ansi(key).lower() - if raw_key in olc_keys: - desc = " {}".format(desc) if desc else "" - olc_options.append("|lc{}|lt{}|le{}".format(raw_key, key, desc)) - else: - other_options.append((key, desc)) - - olc_options = ( - actioninfo + " |W|||n ".join(olc_options) + " |W|||n " + "|wQ|Wuit" - if olc_options - else "" - ) - other_options = super(OLCMenu, self).options_formatter(other_options) - sep = "\n\n" if olc_options and other_options else "" - - return "{}{}{}".format(olc_options, sep, other_options)
- -
[docs] def helptext_formatter(self, helptext): - """ - Show help text - """ - return "|c --- Help ---|n\n" + utils.dedent(helptext)
- -
[docs] def display_helptext(self): - evmore.msg(self.caller, self.helptext, session=self._session, exit_cmd="look")
- - -
[docs]def start_olc(caller, session=None, prototype=None): - """ - Start menu-driven olc system for prototypes. - - Args: - caller (Object or Account): The entity starting the menu. - session (Session, optional): The individual session to get data. - prototype (dict, optional): Given when editing an existing - prototype rather than creating a new one. - - """ - menudata = { - "node_index": node_index, - "node_validate_prototype": node_validate_prototype, - "node_examine_entity": node_examine_entity, - "node_search_object": node_search_object, - "node_prototype_key": node_prototype_key, - "node_prototype_parent": node_prototype_parent, - "node_typeclass": node_typeclass, - "node_key": node_key, - "node_aliases": node_aliases, - "node_attrs": node_attrs, - "node_tags": node_tags, - "node_locks": node_locks, - "node_permissions": node_permissions, - "node_location": node_location, - "node_home": node_home, - "node_destination": node_destination, - "node_apply_diff": node_apply_diff, - "node_prototype_desc": node_prototype_desc, - "node_prototype_tags": node_prototype_tags, - "node_prototype_locks": node_prototype_locks, - "node_prototype_load": node_prototype_load, - "node_prototype_save": node_prototype_save, - "node_prototype_spawn": node_prototype_spawn, - } - OLCMenu( - caller, - menudata, - startnode="node_index", - session=session, - olc_prototype=prototype, - debug=True, - )
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/prototypes/protfuncs.html b/docs/0.9.5/_modules/evennia/prototypes/protfuncs.html deleted file mode 100644 index 7140756794..0000000000 --- a/docs/0.9.5/_modules/evennia/prototypes/protfuncs.html +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - - - evennia.prototypes.protfuncs — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.prototypes.protfuncs

-"""
-Protfuncs are FuncParser-callables that can be embedded in a prototype to
-provide custom logic without having access to Python. The protfunc is parsed at
-the time of spawning, using the creating object's session as input. If the
-protfunc returns a non-string, this is what will be added to the prototype.
-
-In the prototype dict, the protfunc is specified as a string inside the prototype, e.g.:
-
-    { ...
-
-    "key": "$funcname(args, kwargs)"
-
-    ...  }
-
-Available protfuncs are either all callables in one of the modules of `settings.PROT_FUNC_MODULES`
-or all callables added to a dict FUNCPARSER_CALLABLES in such a module.
-
-    def funcname (*args, **kwargs)
-
-At spawn-time the spawner passes the following extra kwargs into each callable (in addition to
-what is added in the call itself):
-
-    - session (Session): The Session of the entity spawning using this prototype.
-    - prototype (dict): The dict this protfunc is a part of.
-    - current_key (str): The active key this value belongs to in the prototype.
-
-Any traceback raised by this function will be handled at the time of spawning and abort the spawn
-before any object is created/updated. It must otherwise return the value to store for the specified
-prototype key (this value must be possible to serialize in an Attribute).
-
-"""
-
-from evennia.utils import funcparser
-
-
-
[docs]def protfunc_callable_protkey(*args, **kwargs): - """ - Usage: $protkey(keyname) - Returns the value of another key in this prototoype. Will raise an error if - the key is not found in this prototype. - - """ - if not args: - return "" - - prototype = kwargs.get("prototype", {}) - fieldname = args[0] - prot_value = None - if fieldname in prototype: - prot_value = prototype[fieldname] - else: - # check if it's an attribute - for attrtuple in prototype.get('attrs', []): - if attrtuple[0] == fieldname: - prot_value = attrtuple[1] - break - else: - raise AttributeError(f"{fieldname} not found in prototype\n{prototype}\n" - "(neither as prototype-field or as an Attribute") - if callable(prot_value): - raise RuntimeError(f"Error in prototype\n{prototype}\n$protkey can only reference static " - f"values/attributes (found {prot_value})") - try: - return funcparser.funcparser_callable_eval(prot_value, **kwargs) - except funcparser.ParsingError: - return prot_value
- - -# this is picked up by FuncParser -FUNCPARSER_CALLABLES = { - "protkey": protfunc_callable_protkey, - **funcparser.FUNCPARSER_CALLABLES, - **funcparser.SEARCHING_CALLABLES, -} -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/prototypes/prototypes.html b/docs/0.9.5/_modules/evennia/prototypes/prototypes.html deleted file mode 100644 index 9f67a7ac09..0000000000 --- a/docs/0.9.5/_modules/evennia/prototypes/prototypes.html +++ /dev/null @@ -1,1241 +0,0 @@ - - - - - - - - evennia.prototypes.prototypes — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.prototypes.prototypes

-"""
-
-Handling storage of prototypes, both database-based ones (DBPrototypes) and those defined in modules
-(Read-only prototypes). Also contains utility functions, formatters and manager functions.
-
-"""
-
-import hashlib
-import time
-from django.conf import settings
-from django.db.models import Q
-from django.core.paginator import Paginator
-from django.utils.translation import gettext as _
-from evennia.scripts.scripts import DefaultScript
-from evennia.objects.models import ObjectDB
-from evennia.typeclasses.attributes import Attribute
-from evennia.utils.create import create_script
-from evennia.utils.evmore import EvMore
-from evennia.utils.utils import (
-    all_from_module,
-    variable_from_module,
-    make_iter,
-    is_iter,
-    dbid_to_obj,
-    justify,
-    class_from_module,
-)
-from evennia.locks.lockhandler import validate_lockstring, check_lockstring
-from evennia.utils import logger
-from evennia.utils.funcparser import FuncParser
-from evennia.utils import dbserialize
-from evennia.utils.evtable import EvTable
-
-_MODULE_PROTOTYPE_MODULES = {}
-_MODULE_PROTOTYPES = {}
-_PROTOTYPE_META_NAMES = (
-    "prototype_key",
-    "prototype_desc",
-    "prototype_tags",
-    "prototype_locks",
-    "prototype_parent",
-)
-_PROTOTYPE_RESERVED_KEYS = _PROTOTYPE_META_NAMES + (
-    "key",
-    "aliases",
-    "typeclass",
-    "location",
-    "home",
-    "destination",
-    "permissions",
-    "locks",
-    "tags",
-    "attrs",
-)
-_ERRSTR = _("Error")
-_WARNSTR = _("Warning")
-PROTOTYPE_TAG_CATEGORY = "from_prototype"
-_PROTOTYPE_TAG_META_CATEGORY = "db_prototype"
-
-_PROTOTYPE_FALLBACK_LOCK = "spawn:all();edit:all()"
-
-
-# the protfunc parser
-FUNC_PARSER = FuncParser(settings.PROT_FUNC_MODULES)
-
-
-
[docs]class PermissionError(RuntimeError): - pass
- - -
[docs]class ValidationError(RuntimeError): - """ - Raised on prototype validation errors - """ - - pass
- - -
[docs]def homogenize_prototype(prototype, custom_keys=None): - """ - Homogenize the more free-form prototype supported pre Evennia 0.7 into the stricter form. - - Args: - prototype (dict): Prototype. - custom_keys (list, optional): Custom keys which should not be interpreted as attrs, beyond - the default reserved keys. - - Returns: - homogenized (dict): Prototype where all non-identified keys grouped as attributes and other - homogenizations like adding missing prototype_keys and setting a default typeclass. - - """ - if not prototype or isinstance(prototype, str): - return prototype - - reserved = _PROTOTYPE_RESERVED_KEYS + (custom_keys or ()) - - # correct cases of setting None for certain values - for protkey in prototype: - if prototype[protkey] is None: - if protkey in ("attrs", "tags", "prototype_tags"): - prototype[protkey] = [] - elif protkey in ("prototype_key", "prototype_desc"): - prototype[protkey] = "" - - homogenized = {} - homogenized_tags = [] - homogenized_attrs = [] - homogenized_parents = [] - - for key, val in prototype.items(): - if key in reserved: - # check all reserved keys - if key == "tags": - # tags must be on form [(tag, category, data), ...] - tags = make_iter(prototype.get("tags", [])) - for tag in tags: - if not is_iter(tag): - homogenized_tags.append((tag, None, None)) - elif tag: - ntag = len(tag) - if ntag == 1: - homogenized_tags.append((tag[0], None, None)) - elif ntag == 2: - homogenized_tags.append((tag[0], tag[1], None)) - else: - homogenized_tags.append(tag[:3]) - - elif key == "attrs": - attrs = list(prototype.get("attrs", [])) # break reference - for attr in attrs: - # attrs must be on form [(key, value, category, lockstr)] - if not is_iter(attr): - logger.log_error("Prototype's 'attr' field must " - f"be a list of tuples: {prototype}") - elif attr: - nattr = len(attr) - if nattr == 1: - # we assume a None-value - homogenized_attrs.append((attr[0], None, None, "")) - elif nattr == 2: - homogenized_attrs.append((attr[0], attr[1], None, "")) - elif nattr == 3: - homogenized_attrs.append((attr[0], attr[1], attr[2], "")) - else: - homogenized_attrs.append(attr[:4]) - - elif key == "prototype_parent": - # homogenize any prototype-parents embedded directly as dicts - protparents = prototype.get('prototype_parent', []) - if isinstance(protparents, dict): - protparents = [protparents] - for parent in make_iter(protparents): - if isinstance(parent, dict): - # recursively homogenize directly embedded prototype parents - homogenized_parents.append( - homogenize_prototype(parent, custom_keys=custom_keys)) - else: - # normal prototype-parent names are added as-is - homogenized_parents.append(parent) - - else: - # another reserved key - homogenized[key] = val - else: - # unreserved keys -> attrs - homogenized_attrs.append((key, val, None, "")) - if homogenized_attrs: - homogenized["attrs"] = homogenized_attrs - if homogenized_tags: - homogenized["tags"] = homogenized_tags - if homogenized_parents: - homogenized['prototype_parent'] = homogenized_parents - - # add required missing parts that had defaults before - - homogenized["prototype_key"] = homogenized.get( - "prototype_key", - # assign a random hash as key - "prototype-{}".format(hashlib.md5(bytes(str(time.time()), "utf-8")).hexdigest()[:7]), - ) - homogenized["prototype_tags"] = homogenized.get("prototype_tags", []) - homogenized["prototype_locks"] = homogenized.get("prototype_lock", _PROTOTYPE_FALLBACK_LOCK) - homogenized["prototype_desc"] = homogenized.get("prototype_desc", "") - if "typeclass" not in prototype and "prototype_parent" not in prototype: - homogenized["typeclass"] = settings.BASE_OBJECT_TYPECLASS - - return homogenized
- - -# module/dict-based prototypes - -
[docs]def load_module_prototypes(*mod_or_prototypes, override=True): - """ - Load module prototypes. Also prototype-dicts passed directly to this function are considered - 'module' prototypes (they are impossible to change) but will have a module of None. - - Args: - *mod_or_prototypes (module or dict): Each arg should be a separate module or - prototype-dict to load. If none are given, `settings.PROTOTYPE_MODULES` will be used. - override (bool, optional): If prototypes should override existing ones already loaded. - Disabling this can allow for injecting prototypes into the system dynamically while - still allowing same prototype-keys to be overridden from settings (even though settings - is usually loaded before dynamic loading). - - Note: - This is called (without arguments) by `evennia.__init__` as Evennia initializes. It's - important to do this late so as to not interfere with evennia initialization. But it can - also be used later to add more prototypes to the library on the fly. This is requried - before a module-based prototype can be accessed by prototype-key. - - """ - global _MODULE_PROTOTYPE_MODULES, _MODULE_PROTOTYPES - - def _prototypes_from_module(mod): - """ - Load prototypes from a module, first by looking for a global list PROTOTYPE_LIST (a list of - dict-prototypes), and if not found, assuming all global-level dicts in the module are - prototypes. - - Args: - mod (module): The module to load from.evennia - - Returns: - list: A list of tuples `(prototype_key, prototype-dict)` where the prototype - has been homogenized. - - """ - prots = [] - prototype_list = variable_from_module(mod, "PROTOTYPE_LIST") - if prototype_list: - # found mod.PROTOTYPE_LIST - this should be a list of valid - # prototype dicts that must have 'prototype_key' set. - for prot in prototype_list: - if not isinstance(prot, dict): - logger.log_err(f"Prototype read from {mod}.PROTOTYPE_LIST " - f"is not a dict (skipping): {prot}") - continue - elif "prototype_key" not in prot: - logger.log_err(f"Prototype read from {mod}.PROTOTYPE_LIST " - f"is missing the 'prototype_key' (skipping): {prot}") - continue - prots.append((prot["prototype_key"], homogenize_prototype(prot))) - else: - # load all global dicts in module as prototypes. If the prototype_key - # is not given, the variable name will be used. - for variable_name, prot in all_from_module(mod).items(): - if isinstance(prot, dict): - if "prototype_key" not in prot: - prot["prototype_key"] = variable_name.lower() - prots.append((prot["prototype_key"], homogenize_prototype(prot))) - return prots - - def _cleanup_prototype(prototype_key, prototype, mod=None): - """ - We need to handle externally determined prototype-keys and to make sure - the prototype contains all needed meta information. - - Args: - prototype_key (str): The determined name of the prototype. - prototype (dict): The prototype itself. - mod (module, optional): The module the prototype was loaded from, if any. - - Returns: - dict: The cleaned up prototype. - - """ - actual_prot_key = prototype.get("prototype_key", prototype_key).lower() - prototype.update( - { - "prototype_key": actual_prot_key, - "prototype_desc": ( - prototype["prototype_desc"] if "prototype_desc" in prototype else (mod or "N/A")), - "prototype_locks": ( - prototype["prototype_locks"] - if "prototype_locks" in prototype - else "use:all();edit:false()" - ), - "prototype_tags": list( - set(list(make_iter(prototype.get("prototype_tags", []))) + ["module"]) - ), - } - ) - return prototype - - if not mod_or_prototypes: - # in principle this means PROTOTYPE_MODULES could also contain prototypes, but that is - # rarely useful ... - mod_or_prototypes = settings.PROTOTYPE_MODULES - - for mod_or_dict in mod_or_prototypes: - - if isinstance(mod_or_dict, dict): - # a single prototype; we must make sure it has its key - prototype_key = mod_or_dict.get('prototype_key') - if not prototype_key: - raise ValidationError(f"The prototype {mod_or_prototype} does not contain a 'prototype_key'") - prots = [(prototype_key, mod_or_dict)] - mod = None - else: - # a module (or path to module). This can contain many prototypes; they can be keyed by - # variable-name too - prots = _prototypes_from_module(mod_or_dict) - mod = repr(mod_or_dict) - - # store all found prototypes - for prototype_key, prot in prots: - prototype = _cleanup_prototype(prototype_key, prot, mod=mod) - # the key can change since in-proto key is given prio over variable-name-based keys - actual_prototype_key = prototype['prototype_key'] - - if actual_prototype_key in _MODULE_PROTOTYPES and not override: - # don't override - useful to still let settings replace dynamic inserts - continue - - # make sure the prototype contains all meta info - _MODULE_PROTOTYPES[actual_prototype_key] = prototype - # track module path for display purposes - _MODULE_PROTOTYPE_MODULES[actual_prototype_key.lower()] = mod
- - -# Db-based prototypes - - -
[docs]class DbPrototype(DefaultScript): - """ - This stores a single prototype, in an Attribute `prototype`. - - """ - -
[docs] def at_script_creation(self): - self.key = "empty prototype" # prototype_key - self.desc = "A prototype" # prototype_desc (.tags are used for prototype_tags) - self.db.prototype = {} # actual prototype
- - @property - def prototype(self): - "Make sure to decouple from db!" - return dbserialize.deserialize(self.attributes.get("prototype", {})) - - @prototype.setter - def prototype(self, prototype): - self.attributes.add("prototype", prototype)
- - -# Prototype manager functions - - -
[docs]def save_prototype(prototype): - """ - Create/Store a prototype persistently. - - Args: - prototype (dict): The prototype to save. A `prototype_key` key is - required. - - Returns: - prototype (dict or None): The prototype stored using the given kwargs, None if deleting. - - Raises: - prototypes.ValidationError: If prototype does not validate. - - Note: - No edit/spawn locks will be checked here - if this function is called the caller - is expected to have valid permissions. - - """ - in_prototype = prototype - in_prototype = homogenize_prototype(in_prototype) - - def _to_batchtuple(inp, *args): - "build tuple suitable for batch-creation" - if is_iter(inp): - # already a tuple/list, use as-is - return inp - return (inp,) + args - - prototype_key = in_prototype.get("prototype_key") - if not prototype_key: - raise ValidationError(_("Prototype requires a prototype_key")) - - prototype_key = str(prototype_key).lower() - - # we can't edit a prototype defined in a module - if prototype_key in _MODULE_PROTOTYPES: - mod = _MODULE_PROTOTYPE_MODULES.get(prototype_key) - if mod: - err = _("{protkey} is a read-only prototype (defined as code in {module}).") - else: - err = _("{protkey} is a read-only prototype (passed directly as a dict).") - raise PermissionError(err.format(protkey=prototype_key, module=mod)) - - # make sure meta properties are included with defaults - in_prototype["prototype_desc"] = in_prototype.get( - "prototype_desc", prototype.get("prototype_desc", "") - ) - prototype_locks = in_prototype.get( - "prototype_locks", prototype.get("prototype_locks", _PROTOTYPE_FALLBACK_LOCK) - ) - is_valid, err = validate_lockstring(prototype_locks) - if not is_valid: - raise ValidationError("Lock error: {}".format(err)) - in_prototype["prototype_locks"] = prototype_locks - - prototype_tags = [ - _to_batchtuple(tag, _PROTOTYPE_TAG_META_CATEGORY) - for tag in make_iter( - in_prototype.get("prototype_tags", prototype.get("prototype_tags", [])) - ) - ] - in_prototype["prototype_tags"] = prototype_tags - - stored_prototype = DbPrototype.objects.filter(db_key=prototype_key) - if stored_prototype: - # edit existing prototype - stored_prototype = stored_prototype[0] - stored_prototype.desc = in_prototype["prototype_desc"] - if prototype_tags: - stored_prototype.tags.clear(category=PROTOTYPE_TAG_CATEGORY) - stored_prototype.tags.batch_add(*in_prototype["prototype_tags"]) - stored_prototype.locks.add(in_prototype["prototype_locks"]) - stored_prototype.attributes.add("prototype", in_prototype) - else: - # create a new prototype - stored_prototype = create_script( - DbPrototype, - key=prototype_key, - desc=in_prototype["prototype_desc"], - persistent=True, - locks=prototype_locks, - tags=in_prototype["prototype_tags"], - attributes=[("prototype", in_prototype)], - ) - return stored_prototype.prototype
- - -create_prototype = save_prototype # alias - - -
[docs]def delete_prototype(prototype_key, caller=None): - """ - Delete a stored prototype - - Args: - key (str): The persistent prototype to delete. - caller (Account or Object, optionsl): Caller aiming to delete a prototype. - Note that no locks will be checked if`caller` is not passed. - Returns: - success (bool): If deletion worked or not. - Raises: - PermissionError: If 'edit' lock was not passed or deletion failed for some other reason. - - """ - if prototype_key in _MODULE_PROTOTYPES: - mod = _MODULE_PROTOTYPE_MODULES.get(prototype_key) - if mod: - err = _("{protkey} is a read-only prototype (defined as code in {module}).") - else: - err = _("{protkey} is a read-only prototype (passed directly as a dict).") - raise PermissionError(err.format(protkey=prototype_key, module=mod)) - - stored_prototype = DbPrototype.objects.filter(db_key__iexact=prototype_key) - - if not stored_prototype: - raise PermissionError(_("Prototype {prototype_key} was not found.").format( - prototype_key=prototype_key)) - - stored_prototype = stored_prototype[0] - if caller: - if not stored_prototype.access(caller, "edit"): - raise PermissionError( - _("{caller} needs explicit 'edit' permissions to " - "delete prototype {prototype_key}.").format( - caller=caller, prototype_key=prototype_key) - ) - stored_prototype.delete() - return True
- - -
[docs]def search_prototype(key=None, tags=None, require_single=False, return_iterators=False, - no_db=False): - """ - Find prototypes based on key and/or tags, or all prototypes. - - Keyword Args: - key (str): An exact or partial key to query for. - tags (str or list): Tag key or keys to query for. These - will always be applied with the 'db_protototype' - tag category. - require_single (bool): If set, raise KeyError if the result - was not found or if there are multiple matches. - return_iterators (bool): Optimized return for large numbers of db-prototypes. - If set, separate returns of module based prototypes and paginate - the db-prototype return. - no_db (bool): Optimization. If set, skip querying for database-generated prototypes and only - include module-based prototypes. This can lead to a dramatic speedup since - module-prototypes are static and require no db-lookup. - - Return: - matches (list): Default return, all found prototype dicts. Empty list if - no match was found. Note that if neither `key` nor `tags` - were given, *all* available prototypes will be returned. - list, queryset: If `return_iterators` are found, this is a list of - module-based prototypes followed by a *paginated* queryset of - db-prototypes. - - Raises: - KeyError: If `require_single` is True and there are 0 or >1 matches. - - Note: - The available prototypes is a combination of those supplied in - PROTOTYPE_MODULES and those stored in the database. Note that if - tags are given and the prototype has no tags defined, it will not - be found as a match. - - """ - # This will load the prototypes the first time they are searched - if not _MODULE_PROTOTYPE_MODULES: - load_module_prototypes() - - # prototype keys are always in lowecase - if key: - key = key.lower() - - # search module prototypes - - mod_matches = {} - if tags: - # use tags to limit selection - tagset = set(tags) - mod_matches = { - prototype_key: prototype - for prototype_key, prototype in _MODULE_PROTOTYPES.items() - if tagset.intersection(prototype.get("prototype_tags", [])) - } - else: - mod_matches = _MODULE_PROTOTYPES - - allow_fuzzy = True - if key: - if key in mod_matches: - # exact match - module_prototypes = [mod_matches[key].copy()] - allow_fuzzy = False - else: - # fuzzy matching - module_prototypes = [ - prototype - for prototype_key, prototype in mod_matches.items() - if key in prototype_key - ] - else: - # note - we return a copy of the prototype dict, otherwise using this with e.g. - # prototype_from_object will modify the base prototype for every object - module_prototypes = [match.copy() for match in mod_matches.values()] - - if no_db: - db_matches = [] - else: - # search db-stored prototypes - if tags: - # exact match on tag(s) - tags = make_iter(tags) - tag_categories = ["db_prototype" for _ in tags] - db_matches = DbPrototype.objects.get_by_tag(tags, tag_categories) - else: - db_matches = DbPrototype.objects.all() - - if key: - # exact or partial match on key - exact_match = db_matches.filter(Q(db_key__iexact=key)).order_by("db_key") - if not exact_match and allow_fuzzy: - # try with partial match instead - db_matches = db_matches.filter(Q(db_key__icontains=key)).order_by("db_key") - else: - db_matches = exact_match - - # convert to prototype - db_ids = db_matches.values_list("id", flat=True) - db_matches = ( - Attribute.objects.filter(scriptdb__pk__in=db_ids, db_key="prototype") - .values_list("db_value", flat=True) - .order_by("scriptdb__db_key") - ) - - if key and require_single: - nmodules = len(module_prototypes) - ndbprots = db_matches.count() if db_matches else 0 - if nmodules + ndbprots != 1: - raise KeyError(_( - "Found {num} matching prototypes among {module_prototypes}.").format( - num=nmodules + ndbprots, - module_prototypes=module_prototypes) - ) - - if return_iterators: - # trying to get the entire set of prototypes - we must paginate - # the result instead of trying to fetch the entire set at once - return db_matches, module_prototypes - else: - # full fetch, no pagination (compatibility mode) - return list(db_matches) + module_prototypes
- - -
[docs]def search_objects_with_prototype(prototype_key): - """ - Retrieve all object instances created by a given prototype. - - Args: - prototype_key (str): The exact (and unique) prototype identifier to query for. - - Returns: - matches (Queryset): All matching objects spawned from this prototype. - - """ - return ObjectDB.objects.get_by_tag(key=prototype_key, category=PROTOTYPE_TAG_CATEGORY)
- - -
[docs]class PrototypeEvMore(EvMore): - """ - Listing 1000+ prototypes can be very slow. So we customize EvMore to - display an EvTable per paginated page rather than to try creating an - EvTable for the entire dataset and then paginate it. - - """ - -
[docs] def __init__(self, caller, *args, session=None, **kwargs): - """ - Store some extra properties on the EvMore class - - """ - self.show_non_use = kwargs.pop("show_non_use", False) - self.show_non_edit = kwargs.pop("show_non_edit", False) - super().__init__(caller, *args, session=session, **kwargs)
- -
[docs] def init_pages(self, inp): - """ - This will be initialized with a tuple (mod_prototype_list, paginated_db_query) - and we must handle these separately since they cannot be paginated in the same - way. We will build the prototypes so that the db-prototypes come first (they - are likely the most volatile), followed by the mod-prototypes. - - """ - dbprot_query, modprot_list = inp - # set the number of entries per page to half the reported height of the screen - # to account for long descs etc - dbprot_paged = Paginator(dbprot_query, max(1, int(self.height / 2))) - - # we separate the different types of data, so we track how many pages there are - # of each. - n_mod = len(modprot_list) - self._npages_mod = n_mod // self.height + (0 if n_mod % self.height == 0 else 1) - self._db_count = dbprot_paged.count - self._npages_db = dbprot_paged.num_pages if self._db_count > 0 else 0 - # total number of pages - self._npages = self._npages_mod + self._npages_db - self._data = (dbprot_paged, modprot_list) - self._paginator = self.prototype_paginator
- -
[docs] def prototype_paginator(self, pageno): - """ - The listing is separated in db/mod prototypes, so we need to figure out which - one to pick based on the page number. Also, pageno starts from 0. - - """ - dbprot_pages, modprot_list = self._data - - if self._db_count and pageno < self._npages_db: - return dbprot_pages.page(pageno + 1) - else: - # get the correct slice, adjusted for the db-prototypes - pageno = max(0, pageno - self._npages_db) - return modprot_list[pageno * self.height: pageno * self.height + self.height]
- -
[docs] def page_formatter(self, page): - """ - Input is a queryset page from django.Paginator - - """ - caller = self._caller - - # get use-permissions of readonly attributes (edit is always False) - table = EvTable( - "|wKey|n", - "|wSpawn/Edit|n", - "|wTags|n", - "|wDesc|n", - border="tablecols", - crop=True, - width=self.width, - ) - - for prototype in page: - lock_use = caller.locks.check_lockstring( - caller, prototype.get("prototype_locks", ""), access_type="spawn", default=True - ) - if not self.show_non_use and not lock_use: - continue - if prototype.get("prototype_key", "") in _MODULE_PROTOTYPES: - lock_edit = False - else: - lock_edit = caller.locks.check_lockstring( - caller, prototype.get("prototype_locks", ""), access_type="edit", default=True - ) - if not self.show_non_edit and not lock_edit: - continue - ptags = [] - for ptag in prototype.get("prototype_tags", []): - if is_iter(ptag): - if len(ptag) > 1: - ptags.append("{}".format(ptag[0])) - else: - ptags.append(ptag[0]) - else: - ptags.append(str(ptag)) - - table.add_row( - prototype.get("prototype_key", "<unset>"), - "{}/{}".format("Y" if lock_use else "N", "Y" if lock_edit else "N"), - ", ".join(list(set(ptags))), - prototype.get("prototype_desc", "<unset>"), - ) - - return str(table)
- - -
[docs]def list_prototypes( - caller, key=None, tags=None, show_non_use=False, show_non_edit=True, session=None -): - """ - Collate a list of found prototypes based on search criteria and access. - - Args: - caller (Account or Object): The object requesting the list. - key (str, optional): Exact or partial prototype key to query for. - tags (str or list, optional): Tag key or keys to query for. - show_non_use (bool, optional): Show also prototypes the caller may not use. - show_non_edit (bool, optional): Show also prototypes the caller may not edit. - session (Session, optional): If given, this is used for display formatting. - Returns: - PrototypeEvMore: An EvMore subclass optimized for prototype listings. - None: If no matches were found. In this case the caller has already been notified. - - """ - # this allows us to pass lists of empty strings - tags = [tag for tag in make_iter(tags) if tag] - - dbprot_query, modprot_list = search_prototype(key, tags, return_iterators=True) - - if not dbprot_query and not modprot_list: - caller.msg(_("No prototypes found."), session=session) - return None - - # get specific prototype (one value or exception) - return PrototypeEvMore( - caller, - (dbprot_query, modprot_list), - session=session, - show_non_use=show_non_use, - show_non_edit=show_non_edit, - )
- - -
[docs]def validate_prototype( - prototype, protkey=None, protparents=None, is_prototype_base=True, strict=True, _flags=None -): - """ - Run validation on a prototype, checking for inifinite regress. - - Args: - prototype (dict): Prototype to validate. - protkey (str, optional): The name of the prototype definition. If not given, the prototype - dict needs to have the `prototype_key` field set. - protpartents (dict, optional): The available prototype parent library. If - note given this will be determined from settings/database. - is_prototype_base (bool, optional): We are trying to create a new object *based on this - object*. This means we can't allow 'mixin'-style prototypes without typeclass/parent - etc. - strict (bool, optional): If unset, don't require needed keys, only check against infinite - recursion etc. - _flags (dict, optional): Internal work dict that should not be set externally. - Raises: - RuntimeError: If prototype has invalid structure. - RuntimeWarning: If prototype has issues that would make it unsuitable to build an object - with (it may still be useful as a mix-in prototype). - - """ - assert isinstance(prototype, dict) - - if _flags is None: - _flags = {"visited": [], "depth": 0, "typeclass": False, "errors": [], "warnings": []} - - if not protparents: - protparents = { - prototype.get("prototype_key", "").lower(): prototype - for prototype in search_prototype() - } - - protkey = protkey and protkey.lower() or prototype.get("prototype_key", None) - - if strict and not bool(protkey): - _flags["errors"].append(_("Prototype lacks a 'prototype_key'.")) - protkey = "[UNSET]" - - typeclass = prototype.get("typeclass") - prototype_parent = prototype.get("prototype_parent", []) - - if strict and not (typeclass or prototype_parent): - if is_prototype_base: - _flags["errors"].append( - _("Prototype {protkey} requires `typeclass` " "or 'prototype_parent'.").format( - protkey=protkey) - ) - else: - _flags["warnings"].append( - _("Prototype {protkey} can only be used as a mixin since it lacks " - "'typeclass' or 'prototype_parent' keys.").format(protkey=protkey) - ) - - if strict and typeclass: - try: - class_from_module(typeclass) - except ImportError as err: - _flags["errors"].append( - _("{err}: Prototype {protkey} is based on typeclass {typeclass}, " - "which could not be imported!").format( - err=err, protkey=protkey, typeclass=typeclass) - ) - - if prototype_parent and isinstance(prototype_parent, dict): - # the protparent is already embedded as a dict; - prototype_parent = [prototype_parent] - - # recursively traverse prototype_parent chain - for protstring in make_iter(prototype_parent): - if isinstance(protstring, dict): - # an already embedded prototype_parent - protparent = protstring - protstring = None - else: - protstring = protstring.lower() - if protkey is not None and protstring == protkey: - _flags["errors"].append(_("Prototype {protkey} tries to parent itself.").format( - protkey=protkey)) - protparent = protparents.get(protstring) - if not protparent: - _flags["errors"].append( - _("Prototype {protkey}'s `prototype_parent` (named '{parent}') " - "was not found.").format(protkey=protkey, parent=protstring) - ) - - # check for infinite recursion - if id(prototype) in _flags["visited"]: - _flags["errors"].append( - _("{protkey} has infinite nesting of prototypes.").format( - protkey=protkey or prototype) - ) - - if _flags["errors"]: - raise RuntimeError(f"{_ERRSTR}: " + f"\n{_ERRSTR}: ".join(_flags["errors"])) - _flags["visited"].append(id(prototype)) - _flags["depth"] += 1 - - # next step of recursive validation - validate_prototype( - protparent, protstring, protparents, is_prototype_base=is_prototype_base, _flags=_flags - ) - - _flags["visited"].pop() - _flags["depth"] -= 1 - - if typeclass and not _flags["typeclass"]: - _flags["typeclass"] = typeclass - - # if we get back to the current level without a typeclass it's an error. - if strict and is_prototype_base and _flags["depth"] <= 0 and not _flags["typeclass"]: - _flags["errors"].append( - _("Prototype {protkey} has no `typeclass` defined anywhere in its parent\n " - "chain. Add `typeclass`, or a `prototype_parent` pointing to a " - "prototype with a typeclass.").format(protkey=protkey) - ) - - if _flags["depth"] <= 0: - if _flags["errors"]: - raise RuntimeError(f"{_ERRSTR}:_" + f"\n{_ERRSTR}: ".join(_flags["errors"])) - if _flags["warnings"]: - raise RuntimeWarning(f"{_WARNSTR}: " + f"\n{_WARNSTR}: ".join(_flags["warnings"])) - - # make sure prototype_locks are set to defaults - prototype_locks = [ - lstring.split(":", 1) - for lstring in prototype.get("prototype_locks", "").split(";") - if ":" in lstring - ] - locktypes = [tup[0].strip() for tup in prototype_locks] - if "spawn" not in locktypes: - prototype_locks.append(("spawn", "all()")) - if "edit" not in locktypes: - prototype_locks.append(("edit", "all()")) - prototype_locks = ";".join(":".join(tup) for tup in prototype_locks) - prototype["prototype_locks"] = prototype_locks
- - -
[docs]def protfunc_parser(value, available_functions=None, testing=False, stacktrace=False, - caller=None, **kwargs): - """ - Parse a prototype value string for a protfunc and process it. - - Available protfuncs are specified as callables in one of the modules of - `settings.PROTFUNC_MODULES`, or specified on the command line. - - Args: - value (any): The value to test for a parseable protfunc. Only strings will be parsed for - protfuncs, all other types are returned as-is. - available_functions (dict, optional): Mapping of name:protfunction to use for this parsing. - If not set, use default sources. - stacktrace (bool, optional): If set, print the stack parsing process of the protfunc-parser. - - Keyword Args: - session (Session): Passed to protfunc. Session of the entity spawning the prototype. - protototype (dict): Passed to protfunc. The dict this protfunc is a part of. - current_key(str): Passed to protfunc. The key in the prototype that will hold this value. - caller (Object or Account): This is necessary for certain protfuncs that perform object - searches and have to check permissions. - any (any): Passed on to the protfunc. - - Returns: - any: A structure to replace the string on the prototype leve. Note - that FunctionParser functions $funcname(*args, **kwargs) can return any - data type to insert into the prototype. - - """ - if not isinstance(value, str): - return value - - result = FUNC_PARSER.parse(value, raise_errors=True, return_str=False, caller=caller, **kwargs) - - return result
- - -# Various prototype utilities - - -
[docs]def format_available_protfuncs(): - """ - Get all protfuncs in a pretty-formatted form. - - Args: - clr (str, optional): What coloration tag to use. - """ - out = [] - for protfunc_name, protfunc in FUNC_PARSER.callables.items(): - out.append( - "- |c${name}|n - |W{docs}".format( - name=protfunc_name, docs=protfunc.__doc__.strip().replace("\n", "") - ) - ) - return justify("\n".join(out), indent=8)
- - -
[docs]def prototype_to_str(prototype): - """ - Format a prototype to a nice string representation. - - Args: - prototype (dict): The prototype. - """ - - prototype = homogenize_prototype(prototype) - - header = """ -|cprototype-key:|n {prototype_key}, |c-tags:|n {prototype_tags}, |c-locks:|n {prototype_locks}|n -|c-desc|n: {prototype_desc} -|cprototype-parent:|n {prototype_parent} - \n""".format( - prototype_key=prototype.get("prototype_key", "|r[UNSET](required)|n"), - prototype_tags=prototype.get("prototype_tags", "|wNone|n"), - prototype_locks=prototype.get("prototype_locks", "|wNone|n"), - prototype_desc=prototype.get("prototype_desc", "|wNone|n"), - prototype_parent=prototype.get("prototype_parent", "|wNone|n"), - ) - key = aliases = attrs = tags = locks = permissions = location = home = destination = "" - if "key" in prototype: - key = prototype["key"] - key = "|ckey:|n {key}".format(key=key) - if "aliases" in prototype: - aliases = prototype["aliases"] - aliases = "|caliases:|n {aliases}".format(aliases=", ".join(aliases)) - if "attrs" in prototype: - attrs = prototype["attrs"] - out = [] - for (attrkey, value, category, locks) in attrs: - locks = locks if isinstance(locks, str) else ", ".join(lock for lock in locks if lock) - category = "|ccategory:|n {}".format(category) if category else "" - cat_locks = "" - if category or locks: - cat_locks = " (|ccategory:|n {category}, ".format( - category=category if category else "|wNone|n" - ) - out.append( - "{attrkey}{cat_locks}{locks} |c=|n {value}".format( - attrkey=attrkey, - cat_locks=cat_locks, - locks=" |w(locks:|n {locks})".format(locks=locks) if locks else "", - value=value, - ) - ) - attrs = "|cattrs:|n\n {attrs}".format(attrs="\n ".join(out)) - if "tags" in prototype: - tags = prototype["tags"] - out = [] - for (tagkey, category, data) in tags: - out.append( - "{tagkey} (category: {category}{dat})".format( - tagkey=tagkey, category=category, dat=", data: {}".format(data) if data else "" - ) - ) - tags = "|ctags:|n\n {tags}".format(tags=", ".join(out)) - if "locks" in prototype: - locks = prototype["locks"] - locks = "|clocks:|n\n {locks}".format(locks=locks) - if "permissions" in prototype: - permissions = prototype["permissions"] - permissions = "|cpermissions:|n {perms}".format(perms=", ".join(permissions)) - if "location" in prototype: - location = prototype["location"] - location = "|clocation:|n {location}".format(location=location) - if "home" in prototype: - home = prototype["home"] - home = "|chome:|n {home}".format(home=home) - if "destination" in prototype: - destination = prototype["destination"] - destination = "|cdestination:|n {destination}".format(destination=destination) - - body = "\n".join( - part - for part in (key, aliases, attrs, tags, locks, permissions, location, home, destination) - if part - ) - - return header.lstrip() + body.strip()
- - -
[docs]def check_permission(prototype_key, action, default=True): - """ - Helper function to check access to actions on given prototype. - - Args: - prototype_key (str): The prototype to affect. - action (str): One of "spawn" or "edit". - default (str): If action is unknown or prototype has no locks - - Returns: - passes (bool): If permission for action is granted or not. - - """ - if action == "edit": - if prototype_key in _MODULE_PROTOTYPES: - mod = _MODULE_PROTOTYPE_MODULES.get(prototype_key) - if mod: - err = _("{protkey} is a read-only prototype (defined as code in {module}).") - else: - err = _("{protkey} is a read-only prototype (passed directly as a dict).") - logger.log_err(err.format(protkey=prototype_key, module=mod)) - return False - - prototype = search_prototype(key=prototype_key) - if not prototype: - logger.log_err("Prototype {} not found.".format(prototype_key)) - return False - - lockstring = prototype.get("prototype_locks") - - if lockstring: - return check_lockstring(None, lockstring, default=default, access_type=action) - return default
- - -
[docs]def init_spawn_value(value, validator=None, caller=None, prototype=None): - """ - Analyze the prototype value and produce a value useful at the point of spawning. - - Args: - value (any): This can be: - callable - will be called as callable() - (callable, (args,)) - will be called as callable(*args) - other - will be assigned depending on the variable type - validator (callable, optional): If given, this will be called with the value to - check and guarantee the outcome is of a given type. - caller (Object or Account): This is necessary for certain protfuncs that perform object - searches and have to check permissions. - prototype (dict): Prototype this is to be used for. Necessary for certain protfuncs. - - Returns: - any (any): The (potentially pre-processed value to use for this prototype key) - - """ - validator = validator if validator else lambda o: o - if callable(value): - value = validator(value()) - elif value and isinstance(value, (list, tuple)) and callable(value[0]): - # a structure (callable, (args, )) - args = value[1:] - value = validator(value[0](*make_iter(args))) - else: - value = validator(value) - result = protfunc_parser(value, caller=caller, prototype=prototype) - if result != value: - return validator(result) - return result
- - -
[docs]def value_to_obj_or_any(value): - "Convert value(s) to Object if possible, otherwise keep original value" - stype = type(value) - if is_iter(value): - if stype == dict: - return { - value_to_obj_or_any(key): value_to_obj_or_any(val) for key, val in value.items() - } - else: - return stype([value_to_obj_or_any(val) for val in value]) - obj = dbid_to_obj(value, ObjectDB) - return obj if obj is not None else value
- - -
[docs]def value_to_obj(value, force=True): - "Always convert value(s) to Object, or None" - stype = type(value) - if is_iter(value): - if stype == dict: - return {value_to_obj_or_any(key): value_to_obj_or_any(val) - for key, val in value.items()} - else: - return stype([value_to_obj_or_any(val) for val in value]) - return dbid_to_obj(value, ObjectDB)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/prototypes/spawner.html b/docs/0.9.5/_modules/evennia/prototypes/spawner.html deleted file mode 100644 index 801d772ee4..0000000000 --- a/docs/0.9.5/_modules/evennia/prototypes/spawner.html +++ /dev/null @@ -1,1141 +0,0 @@ - - - - - - - - evennia.prototypes.spawner — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.prototypes.spawner

-"""
-Spawner
-
-The spawner takes input files containing object definitions in
-dictionary forms. These use a prototype architecture to define
-unique objects without having to make a Typeclass for each.
-
-There  main function is `spawn(*prototype)`, where the `prototype`
-is a dictionary like this:
-
-```python
-from evennia.prototypes import prototypes, spawner
-
-prot = {
- "prototype_key": "goblin",
- "typeclass": "types.objects.Monster",
- "key": "goblin grunt",
- "health": lambda: randint(20,30),
- "resists": ["cold", "poison"],
- "attacks": ["fists"],
- "weaknesses": ["fire", "light"]
- "tags": ["mob", "evil", ('greenskin','mob')]
- "attrs": [("weapon", "sword")]
-}
-# spawn something with the prototype
-goblin = spawner.spawn(prot)
-
-# make this into a db-saved prototype (optional)
-prot = prototypes.create_prototype(prot)
-
-```
-
-Possible keywords are:
-    prototype_key (str):  name of this prototype. This is used when storing prototypes and should
-        be unique. This should always be defined but for prototypes defined in modules, the
-        variable holding the prototype dict will become the prototype_key if it's not explicitly
-        given.
-    prototype_desc (str, optional): describes prototype in listings
-    prototype_locks (str, optional): locks for restricting access to this prototype. Locktypes
-        supported are 'edit' and 'use'.
-    prototype_tags(list, optional): List of tags or tuples (tag, category) used to group prototype
-        in listings
-    prototype_parent (str, tuple or callable, optional): name (prototype_key) of eventual parent
-        prototype, or a list of parents, for multiple left-to-right inheritance.
-    prototype: Deprecated. Same meaning as 'parent'.
-
-    typeclass (str or callable, optional): if not set, will use typeclass of parent prototype or use
-        `settings.BASE_OBJECT_TYPECLASS`
-    key (str or callable, optional): the name of the spawned object. If not given this will set to a
-        random hash
-    location (obj, str or callable, optional): location of the object - a valid object or #dbref
-    home (obj, str or callable, optional): valid object or #dbref
-    destination (obj, str or callable, optional): only valid for exits (object or #dbref)
-
-    permissions (str, list or callable, optional): which permissions for spawned object to have
-    locks (str or callable, optional): lock-string for the spawned object
-    aliases (str, list or callable, optional): Aliases for the spawned object
-    exec (str or callable, optional): this is a string of python code to execute or a list of such
-        codes.  This can be used e.g. to trigger custom handlers on the object. The execution
-        namespace contains 'evennia' for the library and 'obj'. All default spawn commands limit
-        this functionality to Developer/superusers. Usually it's better to use callables or
-        prototypefuncs instead of this.
-    tags (str, tuple, list or callable, optional): string or list of strings or tuples
-        `(tagstr, category)`. Plain strings will be result in tags with no category (default tags).
-    attrs (tuple, list or callable, optional): tuple or list of tuples of Attributes to add. This
-        form allows more complex Attributes to be set. Tuples at least specify `(key, value)`
-        but can also specify up to `(key, value, category, lockstring)`. If you want to specify a
-        lockstring but not a category, set the category to `None`.
-    ndb_<name> (any): value of a nattribute (ndb_ is stripped) - this is of limited use.
-    other (any): any other name is interpreted as the key of an Attribute with
-        its value. Such Attributes have no categories.
-
-Each value can also be a callable that takes no arguments. It should
-return the value to enter into the field and will be called every time
-the prototype is used to spawn an object. Note, if you want to store
-a callable in an Attribute, embed it in a tuple to the `args` keyword.
-
-By specifying the "prototype_parent" key, the prototype becomes a child of
-the given prototype, inheritng all prototype slots it does not explicitly
-define itself, while overloading those that it does specify.
-
-```python
-import random
-
-
-{
- "prototype_key": "goblin_wizard",
- "prototype_parent": "GOBLIN",
- "key": "goblin wizard",
- "spells": ["fire ball", "lighting bolt"]
- }
-
-GOBLIN_ARCHER = {
- "prototype_parent": "GOBLIN",
- "key": "goblin archer",
- "attack_skill": (random, (5, 10))"
- "attacks": ["short bow"]
-}
-```
-
-One can also have multiple prototypes. These are inherited from the
-left, with the ones further to the right taking precedence.
-
-```python
-ARCHWIZARD = {
- "attack": ["archwizard staff", "eye of doom"]
-
-GOBLIN_ARCHWIZARD = {
- "key" : "goblin archwizard"
- "prototype_parent": ("GOBLIN_WIZARD", "ARCHWIZARD"),
-}
-```
-
-The *goblin archwizard* will have some different attacks, but will
-otherwise have the same spells as a *goblin wizard* who in turn shares
-many traits with a normal *goblin*.
-
-
-Storage mechanism:
-
-This sets up a central storage for prototypes. The idea is to make these
-available in a repository for buildiers to use. Each prototype is stored
-in a Script so that it can be tagged for quick sorting/finding and locked for limiting
-access.
-
-This system also takes into consideration prototypes defined and stored in modules.
-Such prototypes are considered 'read-only' to the system and can only be modified
-in code. To replace a default prototype, add the same-name prototype in a
-custom module read later in the settings.PROTOTYPE_MODULES list. To remove a default
-prototype, override its name with an empty dict.
-
-
-"""
-
-
-import copy
-import hashlib
-import time
-
-from django.conf import settings
-from django.utils.translation import gettext as _
-
-import evennia
-from evennia.objects.models import ObjectDB
-from evennia.utils import logger
-from evennia.utils.utils import make_iter, is_iter
-from evennia.prototypes import prototypes as protlib
-from evennia.prototypes.prototypes import (
-    value_to_obj,
-    value_to_obj_or_any,
-    init_spawn_value,
-    PROTOTYPE_TAG_CATEGORY,
-)
-
-
-_CREATE_OBJECT_KWARGS = ("key", "location", "home", "destination")
-_PROTOTYPE_META_NAMES = ("prototype_key", "prototype_desc", "prototype_tags",
-                         "prototype_locks", "prototype_parent")
-_PROTOTYPE_ROOT_NAMES = (
-    "typeclass",
-    "key",
-    "aliases",
-    "attrs",
-    "tags",
-    "locks",
-    "permissions",
-    "location",
-    "home",
-    "destination",
-)
-_NON_CREATE_KWARGS = _CREATE_OBJECT_KWARGS + _PROTOTYPE_META_NAMES
-
-
-
[docs]class Unset: - """ - Helper class representing a non-set diff element. - - """ - - def __bool__(self): - return False - - def __str__(self): - return "<Unset>"
- - -# Helper - - -def _get_prototype(inprot, protparents, uninherited=None, _workprot=None): - """ - Recursively traverse a prototype dictionary, including multiple - inheritance. Use validate_prototype before this, we don't check - for infinite recursion here. - - Args: - inprot (dict): Prototype dict (the individual prototype, with no inheritance included). - protparents (dict): Available protparents, keyed by prototype_key. - uninherited (dict): Parts of prototype to not inherit. - _workprot (dict, optional): Work dict for the recursive algorithm. - - Returns: - merged (dict): A prototype where parent's have been merged as needed (the - `prototype_parent` key is removed). - - """ - - def _inherit_tags(old_tags, new_tags): - old = {(tup[0], tup[1]): tup for tup in old_tags} - new = {(tup[0], tup[1]): tup for tup in new_tags} - old.update(new) - return list(old.values()) - - def _inherit_attrs(old_attrs, new_attrs): - old = {(tup[0], tup[2]): tup for tup in old_attrs} - new = {(tup[0], tup[2]): tup for tup in new_attrs} - old.update(new) - return list(old.values()) - - _workprot = {} if _workprot is None else _workprot - if "prototype_parent" in inprot: - # move backwards through the inheritance - - prototype_parents = inprot["prototype_parent"] - if isinstance(prototype_parents, dict): - # protparent already embedded as-is - prototype_parents = [prototype_parents] - - for prototype in make_iter(prototype_parents): - if isinstance(prototype, dict): - # protparent already embedded as-is - parent_prototype = prototype - else: - # protparent given by-name - parent_prototype = protparents.get(prototype.lower(), {}) - - # Build the prot dictionary in reverse order, overloading - new_prot = _get_prototype( - parent_prototype, protparents, _workprot=_workprot - ) - - # attrs, tags have internal structure that should be inherited separately - new_prot["attrs"] = _inherit_attrs( - _workprot.get("attrs", {}), new_prot.get("attrs", []) - ) - new_prot["tags"] = _inherit_tags(_workprot.get("tags", []), new_prot.get("tags", [])) - - _workprot.update(new_prot) - # the inprot represents a higher level (a child prot), which should override parents - - inprot["attrs"] = _inherit_attrs(_workprot.get("attrs", []), inprot.get("attrs", [])) - inprot["tags"] = _inherit_tags(_workprot.get("tags", []), inprot.get("tags", [])) - _workprot.update(inprot) - if uninherited: - # put back the parts that should not be inherited - _workprot.update(uninherited) - _workprot.pop("prototype_parent", None) # we don't need this for spawning - return _workprot - - -
[docs]def flatten_prototype(prototype, validate=False, no_db=False): - """ - Produce a 'flattened' prototype, where all prototype parents in the inheritance tree have been - merged into a final prototype. - - Args: - prototype (dict): Prototype to flatten. Its `prototype_parent` field will be parsed. - validate (bool, optional): Validate for valid keys etc. - no_db (bool, optional): Don't search db-based prototypes. This can speed up - searching dramatically since module-based prototypes are static. - - Returns: - flattened (dict): The final, flattened prototype. - - """ - - if prototype: - prototype = protlib.homogenize_prototype(prototype) - protparents = {prot["prototype_key"].lower(): prot - for prot in protlib.search_prototype(no_db=no_db)} - protlib.validate_prototype( - prototype, None, protparents, is_prototype_base=validate, strict=validate - ) - return _get_prototype( - prototype, protparents, uninherited={"prototype_key": prototype.get("prototype_key")} - ) - return {}
- - -# obj-related prototype functions - - -
[docs]def prototype_from_object(obj): - """ - Guess a minimal prototype from an existing object. - - Args: - obj (Object): An object to analyze. - - Returns: - prototype (dict): A prototype estimating the current state of the object. - - """ - # first, check if this object already has a prototype - - prot = obj.tags.get(category=PROTOTYPE_TAG_CATEGORY, return_list=True) - if prot: - prot = protlib.search_prototype(prot[0]) - - if not prot or len(prot) > 1: - # no unambiguous prototype found - build new prototype - prot = {} - prot["prototype_key"] = "From-Object-{}-{}".format( - obj.key, hashlib.md5(bytes(str(time.time()), "utf-8")).hexdigest()[:7] - ) - prot["prototype_desc"] = "Built from {}".format(str(obj)) - prot["prototype_locks"] = "spawn:all();edit:all()" - prot["prototype_tags"] = [] - else: - prot = prot[0] - - prot["key"] = obj.db_key or hashlib.md5(bytes(str(time.time()), "utf-8")).hexdigest()[:6] - prot["typeclass"] = obj.db_typeclass_path - - location = obj.db_location - if location: - prot["location"] = location.dbref - home = obj.db_home - if home: - prot["home"] = home.dbref - destination = obj.db_destination - if destination: - prot["destination"] = destination.dbref - locks = obj.locks.all() - if locks: - prot["locks"] = ";".join(locks) - perms = obj.permissions.get(return_list=True) - if perms: - prot["permissions"] = make_iter(perms) - aliases = obj.aliases.get(return_list=True) - if aliases: - prot["aliases"] = aliases - tags = sorted( - [(tag.db_key, tag.db_category, tag.db_data) for tag in obj.tags.all(return_objs=True)], - key=lambda tup: (str(tup[0]), tup[1] or '', tup[2] or '') - ) - if tags: - prot["tags"] = tags - attrs = sorted( - [ - (attr.key, attr.value, attr.category, ";".join(attr.locks.all())) - for attr in obj.attributes.all() - ], - key=lambda tup: (str(tup[0]), tup[1] or '', tup[2] or '', tup[3]) - ) - if attrs: - prot["attrs"] = attrs - - return prot
- - -
[docs]def prototype_diff(prototype1, prototype2, maxdepth=2, homogenize=False, implicit_keep=False): - """ - A 'detailed' diff specifies differences down to individual sub-sections - of the prototype, like individual attributes, permissions etc. It is used - by the menu to allow a user to customize what should be kept. - - Args: - prototype1 (dict): Original prototype. - prototype2 (dict): Comparison prototype. - maxdepth (int, optional): The maximum depth into the diff we go before treating the elements - of iterables as individual entities to compare. This is important since a single - attr/tag (for example) are represented by a tuple. - homogenize (bool, optional): Auto-homogenize both prototypes for the best comparison. - This is most useful for displaying. - implicit_keep (bool, optional): If set, the resulting diff will assume KEEP unless the new - prototype explicitly change them. That is, if a key exists in `prototype1` and - not in `prototype2`, it will not be REMOVEd but set to KEEP instead. This is - particularly useful for auto-generated prototypes when updating objects. - - Returns: - diff (dict): A structure detailing how to convert prototype1 to prototype2. All - nested structures are dicts with keys matching either the prototype's matching - key or the first element in the tuple describing the prototype value (so for - a tag tuple `(tagname, category)` the second-level key in the diff would be tagname). - The the bottom level of the diff consist of tuples `(old, new, instruction)`, where - instruction can be one of "REMOVE", "ADD", "UPDATE" or "KEEP". - - """ - _unset = Unset() - - def _recursive_diff(old, new, depth=0): - - old_type = type(old) - new_type = type(new) - - if old_type == new_type and not (old or new): - # both old and new are unset, like [] or None - return (None, None, "KEEP") - if old_type != new_type: - if old and not new: - if depth < maxdepth and old_type == dict: - return {key: (part, None, "REMOVE") for key, part in old.items()} - elif depth < maxdepth and is_iter(old): - return { - part[0] if is_iter(part) else part: (part, None, "REMOVE") for part in old - } - if isinstance(new, Unset) and implicit_keep: - # the new does not define any change, use implicit-keep - return (old, None, "KEEP") - return (old, new, "REMOVE") - elif not old and new: - if depth < maxdepth and new_type == dict: - return {key: (None, part, "ADD") for key, part in new.items()} - elif depth < maxdepth and is_iter(new): - return {part[0] if is_iter(part) else part: (None, part, "ADD") for part in new} - return (old, new, "ADD") - else: - # this condition should not occur in a standard diff - return (old, new, "UPDATE") - elif depth < maxdepth and new_type == dict: - all_keys = set(list(old.keys()) + list(new.keys())) - return { - key: _recursive_diff(old.get(key, _unset), new.get(key, _unset), depth=depth + 1) - for key in all_keys - } - elif depth < maxdepth and is_iter(new): - old_map = {part[0] if is_iter(part) else part: part for part in old} - new_map = {part[0] if is_iter(part) else part: part for part in new} - all_keys = set(list(old_map.keys()) + list(new_map.keys())) - return { - key: _recursive_diff( - old_map.get(key, _unset), new_map.get(key, _unset), depth=depth + 1 - ) - for key in all_keys - } - elif old != new: - return (old, new, "UPDATE") - else: - return (old, new, "KEEP") - - prot1 = protlib.homogenize_prototype(prototype1) if homogenize else prototype1 - prot2 = protlib.homogenize_prototype(prototype2) if homogenize else prototype2 - - diff = _recursive_diff(prot1, prot2) - - return diff
- - -
[docs]def flatten_diff(diff): - """ - For spawning, a 'detailed' diff is not necessary, rather we just want instructions on how to - handle each root key. - - Args: - diff (dict): Diff produced by `prototype_diff` and - possibly modified by the user. Note that also a pre-flattened diff will come out - unchanged by this function. - - Returns: - flattened_diff (dict): A flat structure detailing how to operate on each - root component of the prototype. - - Notes: - The flattened diff has the following possible instructions: - UPDATE, REPLACE, REMOVE - Many of the detailed diff's values can hold nested structures with their own - individual instructions. A detailed diff can have the following instructions: - REMOVE, ADD, UPDATE, KEEP - Here's how they are translated: - - All REMOVE -> REMOVE - - All ADD|UPDATE -> UPDATE - - All KEEP -> KEEP - - Mix KEEP, UPDATE, ADD -> UPDATE - - Mix REMOVE, KEEP, UPDATE, ADD -> REPLACE - """ - - valid_instructions = ("KEEP", "REMOVE", "ADD", "UPDATE") - - def _get_all_nested_diff_instructions(diffpart): - "Started for each root key, returns all instructions nested under it" - out = [] - typ = type(diffpart) - if typ == tuple and len(diffpart) == 3 and diffpart[2] in valid_instructions: - out = [diffpart[2]] - elif typ == dict: - # all other are dicts - for val in diffpart.values(): - out.extend(_get_all_nested_diff_instructions(val)) - else: - raise RuntimeError( - _("Diff contains non-dicts that are not on the " - "form (old, new, action_to_take): {diffpart}").format(diffpart) - ) - return out - - flat_diff = {} - - # flatten diff based on rules - for rootkey, diffpart in diff.items(): - insts = _get_all_nested_diff_instructions(diffpart) - if all(inst == "KEEP" for inst in insts): - rootinst = "KEEP" - elif all(inst in ("ADD", "UPDATE") for inst in insts): - rootinst = "UPDATE" - elif all(inst == "REMOVE" for inst in insts): - rootinst = "REMOVE" - elif "REMOVE" in insts: - rootinst = "REPLACE" - else: - rootinst = "UPDATE" - - flat_diff[rootkey] = rootinst - - return flat_diff
- - -
[docs]def prototype_diff_from_object(prototype, obj, implicit_keep=True): - """ - Get a simple diff for a prototype compared to an object which may or may not already have a - prototype (or has one but changed locally). For more complex migratations a manual diff may be - needed. - - Args: - prototype (dict): New prototype. - obj (Object): Object to compare prototype against. - - Returns: - diff (dict): Mapping for every prototype key: {"keyname": "REMOVE|UPDATE|KEEP", ...} - obj_prototype (dict): The prototype calculated for the given object. The diff is how to - convert this prototype into the new prototype. - implicit_keep (bool, optional): This is usually what one wants for object updating. When - set, this means the prototype diff will assume KEEP on differences - between the object-generated prototype and that which is not explicitly set in the - new prototype. This means e.g. that even though the object has a location, and the - prototype does not specify the location, it will not be unset. - - Notes: - The `diff` is on the following form: - - {"key": (old, new, "KEEP|REPLACE|UPDATE|REMOVE"), - "attrs": {"attrkey": (old, new, "KEEP|REPLACE|UPDATE|REMOVE"), - "attrkey": (old, new, "KEEP|REPLACE|UPDATE|REMOVE"), ...}, - "aliases": {"aliasname": (old, new, "KEEP...", ...}, - ... } - - """ - obj_prototype = prototype_from_object(obj) - diff = prototype_diff( - obj_prototype, protlib.homogenize_prototype(prototype), implicit_keep=implicit_keep - ) - return diff, obj_prototype
- - -
[docs]def format_diff(diff, minimal=True): - """ - Reformat a diff for presentation. This is a shortened version - of the olc _format_diff_text_and_options without the options. - - Args: - diff (dict): A diff as produced by `prototype_diff`. - minimal (bool, optional): Only show changes (remove KEEPs) - - Returns: - texts (str): The formatted text. - - """ - - valid_instructions = ("KEEP", "REMOVE", "ADD", "UPDATE") - - def _visualize(obj, rootname, get_name=False): - if is_iter(obj): - if not obj: - return str(obj) - if get_name: - return obj[0] if obj[0] else "<unset>" - if rootname == "attrs": - return "{} |w=|n {} |w(category:|n |n{}|w, locks:|n {}|w)|n".format(*obj) - elif rootname == "tags": - return "{} |w(category:|n {}|w)|n".format(obj[0], obj[1]) - return "{}".format(obj) - - def _parse_diffpart(diffpart, rootname): - typ = type(diffpart) - texts = [] - if typ == tuple and len(diffpart) == 3 and diffpart[2] in valid_instructions: - old, new, instruction = diffpart - if instruction == "KEEP": - if not minimal: - texts.append(" |gKEEP|n: {old}".format(old=_visualize(old, rootname))) - elif instruction == "ADD": - texts.append(" |yADD|n: {new}".format(new=_visualize(new, rootname))) - elif instruction == "REMOVE" and not new: - texts.append(" |rREMOVE|n: {old}".format(old=_visualize(old, rootname))) - else: - vold = _visualize(old, rootname) - vnew = _visualize(new, rootname) - vsep = "" if len(vold) < 78 else "\n" - vinst = " |rREMOVE|n" if instruction == "REMOVE" else "|y{}|n".format(instruction) - varrow = "|r->|n" if instruction == "REMOVE" else "|y->|n" - texts.append( - " {inst}|W:|n {old} |W{varrow}|n{sep} {new}".format( - inst=vinst, old=vold, varrow=varrow, sep=vsep, new=vnew - ) - ) - else: - for key in sorted(list(diffpart.keys())): - subdiffpart = diffpart[key] - text = _parse_diffpart(subdiffpart, rootname) - texts.extend(text) - return texts - - texts = [] - - for root_key in sorted(diff): - diffpart = diff[root_key] - text = _parse_diffpart(diffpart, root_key) - if text or not minimal: - heading = "- |w{}:|n\n".format(root_key) - if text: - text = [heading + text[0]] + text[1:] - else: - text = [heading] - - texts.extend(text) - - return "\n ".join(line for line in texts if line)
- - -
[docs]def batch_update_objects_with_prototype(prototype, diff=None, objects=None, - exact=False, caller=None): - """ - Update existing objects with the latest version of the prototype. - - Args: - prototype (str or dict): Either the `prototype_key` to use or the - prototype dict itself. - diff (dict, optional): This a diff structure that describes how to update the protototype. - If not given this will be constructed from the first object found. - objects (list, optional): List of objects to update. If not given, query for these - objects using the prototype's `prototype_key`. - exact (bool, optional): By default (`False`), keys not explicitly in the prototype will - not be applied to the object, but will be retained as-is. This is usually what is - expected - for example, one usually do not want to remove the object's location even - if it's not set in the prototype. With `exact=True`, all un-specified properties of the - objects will be removed if they exist. This will lead to a more accurate 1:1 correlation - between the object and the prototype but is usually impractical. - caller (Object or Account, optional): This may be used by protfuncs to do permission checks. - Returns: - changed (int): The number of objects that had changes applied to them. - - """ - prototype = protlib.homogenize_prototype(prototype) - - if isinstance(prototype, str): - new_prototype = protlib.search_prototype(prototype) - else: - new_prototype = prototype - - prototype_key = new_prototype["prototype_key"] - - if not objects: - objects = ObjectDB.objects.get_by_tag(prototype_key, category=PROTOTYPE_TAG_CATEGORY) - - if not objects: - return 0 - - if not diff: - diff, _ = prototype_diff_from_object(new_prototype, objects[0]) - - # make sure the diff is flattened - diff = flatten_diff(diff) - - changed = 0 - for obj in objects: - do_save = False - - old_prot_key = obj.tags.get(category=PROTOTYPE_TAG_CATEGORY, return_list=True) - old_prot_key = old_prot_key[0] if old_prot_key else None - - try: - for key, directive in diff.items(): - - if key not in new_prototype and not exact: - # we don't update the object if the prototype does not actually - # contain the key (the diff will report REMOVE but we ignore it - # since exact=False) - continue - - if directive in ("UPDATE", "REPLACE"): - - if key in _PROTOTYPE_META_NAMES: - # prototype meta keys are not stored on-object - continue - - val = new_prototype[key] - do_save = True - - def _init(val, typ): - return init_spawn_value(val, str, caller=caller, prototype=new_prototype) - - if key == "key": - obj.db_key = _init(val, str) - elif key == "typeclass": - obj.db_typeclass_path = _init(val, str) - elif key == "location": - obj.db_location = _init(val, value_to_obj) - elif key == "home": - obj.db_home = _init(val, value_to_obj) - elif key == "destination": - obj.db_destination = _init(val, value_to_obj) - elif key == "locks": - if directive == "REPLACE": - obj.locks.clear() - obj.locks.add(_init(val, str)) - elif key == "permissions": - if directive == "REPLACE": - obj.permissions.clear() - obj.permissions.batch_add(*(_init(perm, str) for perm in val)) - elif key == "aliases": - if directive == "REPLACE": - obj.aliases.clear() - obj.aliases.batch_add(*(_init(alias, str) for alias in val)) - elif key == "tags": - if directive == "REPLACE": - obj.tags.clear() - obj.tags.batch_add( - *( - (_init(ttag, str), tcategory, tdata) - for ttag, tcategory, tdata in val - ) - ) - elif key == "attrs": - if directive == "REPLACE": - obj.attributes.clear() - obj.attributes.batch_add( - *( - ( - _init(akey, str), - _init(aval, value_to_obj), - acategory, - alocks, - ) - for akey, aval, acategory, alocks in val - ) - ) - elif key == "exec": - # we don't auto-rerun exec statements, it would be huge security risk! - pass - else: - obj.attributes.add(key, _init(val, value_to_obj)) - elif directive == "REMOVE": - do_save = True - if key == "key": - obj.db_key = "" - elif key == "typeclass": - # fall back to default - obj.db_typeclass_path = settings.BASE_OBJECT_TYPECLASS - elif key == "location": - obj.db_location = None - elif key == "home": - obj.db_home = None - elif key == "destination": - obj.db_destination = None - elif key == "locks": - obj.locks.clear() - elif key == "permissions": - obj.permissions.clear() - elif key == "aliases": - obj.aliases.clear() - elif key == "tags": - obj.tags.clear() - elif key == "attrs": - obj.attributes.clear() - elif key == "exec": - # we don't auto-rerun exec statements, it would be huge security risk! - pass - else: - obj.attributes.remove(key) - except Exception: - logger.log_trace(f"Failed to apply prototype '{prototype_key}' to {obj}.") - finally: - # we must always make sure to re-add the prototype tag - obj.tags.clear(category=PROTOTYPE_TAG_CATEGORY) - obj.tags.add(prototype_key, category=PROTOTYPE_TAG_CATEGORY) - - if do_save: - changed += 1 - obj.save() - - return changed
- - -
[docs]def batch_create_object(*objparams): - """ - This is a cut-down version of the create_object() function, - optimized for speed. It does NOT check and convert various input - so make sure the spawned Typeclass works before using this! - - Args: - objsparams (tuple): Each paremter tuple will create one object instance using the parameters - within. - The parameters should be given in the following order: - - `create_kwargs` (dict): For use as new_obj = `ObjectDB(**create_kwargs)`. - - `permissions` (str): Permission string used with `new_obj.batch_add(permission)`. - - `lockstring` (str): Lockstring used with `new_obj.locks.add(lockstring)`. - - `aliases` (list): A list of alias strings for - adding with `new_object.aliases.batch_add(*aliases)`. - - `nattributes` (list): list of tuples `(key, value)` to be loop-added to - add with `new_obj.nattributes.add(*tuple)`. - - `attributes` (list): list of tuples `(key, value[,category[,lockstring]])` for - adding with `new_obj.attributes.batch_add(*attributes)`. - - `tags` (list): list of tuples `(key, category)` for adding - with `new_obj.tags.batch_add(*tags)`. - - `execs` (list): Code strings to execute together with the creation - of each object. They will be executed with `evennia` and `obj` - (the newly created object) available in the namespace. Execution - will happend after all other properties have been assigned and - is intended for calling custom handlers etc. - - Returns: - objects (list): A list of created objects - - Notes: - The `exec` list will execute arbitrary python code so don't allow this to be available to - unprivileged users! - - """ - - # bulk create all objects in one go - - # unfortunately this doesn't work since bulk_create doesn't creates pks; - # the result would be duplicate objects at the next stage, so we comment - # it out for now: - # dbobjs = _ObjectDB.objects.bulk_create(dbobjs) - - objs = [] - for objparam in objparams: - - obj = ObjectDB(**objparam[0]) - - # setup - obj._createdict = { - "permissions": make_iter(objparam[1]), - "locks": objparam[2], - "aliases": make_iter(objparam[3]), - "nattributes": objparam[4], - "attributes": objparam[5], - "tags": make_iter(objparam[6]), - } - # this triggers all hooks - obj.save() - # run eventual extra code - for code in objparam[7]: - if code: - exec(code, {}, {"evennia": evennia, "obj": obj}) - objs.append(obj) - return objs
- - -# Spawner mechanism - - -
[docs]def spawn(*prototypes, caller=None, **kwargs): - """ - Spawn a number of prototyped objects. - - Args: - prototypes (str or dict): Each argument should either be a - prototype_key (will be used to find the prototype) or a full prototype - dictionary. These will be batched-spawned as one object each. - Keyword Args: - caller (Object or Account, optional): This may be used by protfuncs to do access checks. - prototype_modules (str or list): A python-path to a prototype - module, or a list of such paths. These will be used to build - the global protparents dictionary accessible by the input - prototypes. If not given, it will instead look for modules - defined by settings.PROTOTYPE_MODULES. - prototype_parents (dict): A dictionary holding a custom - prototype-parent dictionary. Will overload same-named - prototypes from prototype_modules. - return_parents (bool): Return a dict of the entire prototype-parent tree - available to this prototype (no object creation happens). This is a - merged result between the globally found protparents and whatever - custom `prototype_parents` are given to this function. - only_validate (bool): Only run validation of prototype/parents - (no object creation) and return the create-kwargs. - - Returns: - object (Object, dict or list): Spawned object(s). If `only_validate` is given, return - a list of the creation kwargs to build the object(s) without actually creating it. If - `return_parents` is set, instead return dict of prototype parents. - - """ - # search string (=prototype_key) from input - prototypes = [ - protlib.search_prototype(prot, require_single=True)[0] if isinstance(prot, str) else prot - for prot in prototypes - ] - - # get available protparents - protparents = {prot["prototype_key"].lower(): prot for prot in protlib.search_prototype()} - - if not kwargs.get("only_validate"): - # homogenization to be more lenient about prototype format when entering the prototype - # manually - prototypes = [protlib.homogenize_prototype(prot) for prot in prototypes] - - # overload module's protparents with specifically given protparents - # we allow prototype_key to be the key of the protparent dict, to allow for module-level - # prototype imports. We need to insert prototype_key in this case - for key, protparent in kwargs.get("prototype_parents", {}).items(): - key = str(key).lower() - protparent["prototype_key"] = str(protparent.get("prototype_key", key)).lower() - protparents[key] = protlib.homogenize_prototype(protparent) - - if "return_parents" in kwargs: - # only return the parents - return copy.deepcopy(protparents) - - objsparams = [] - for prototype in prototypes: - - protlib.validate_prototype(prototype, None, protparents, is_prototype_base=True) - prot = _get_prototype( - prototype, protparents, uninherited={"prototype_key": prototype.get("prototype_key")} - ) - if not prot: - continue - - # extract the keyword args we need to create the object itself. If we get a callable, - # call that to get the value (don't catch errors) - create_kwargs = {} - # we must always add a key, so if not given we use a shortened md5 hash. There is a (small) - # chance this is not unique but it should usually not be a problem. - val = prot.pop( - "key", - "Spawned-{}".format(hashlib.md5(bytes(str(time.time()), "utf-8")).hexdigest()[:6]), - ) - create_kwargs["db_key"] = init_spawn_value(val, str, caller=caller, prototype=prototype) - - val = prot.pop("location", None) - create_kwargs["db_location"] = init_spawn_value( - val, value_to_obj, caller=caller, prototype=prototype) - - val = prot.pop("home", None) - if val: - create_kwargs["db_home"] = init_spawn_value(val, value_to_obj, caller=caller, - prototype=prototype) - else: - try: - create_kwargs["db_home"] = init_spawn_value( - settings.DEFAULT_HOME, value_to_obj, caller=caller, prototype=prototype) - except ObjectDB.DoesNotExist: - # settings.DEFAULT_HOME not existing is common for unittests - pass - - val = prot.pop("destination", None) - create_kwargs["db_destination"] = init_spawn_value(val, value_to_obj, caller=caller, - prototype=prototype) - - val = prot.pop("typeclass", settings.BASE_OBJECT_TYPECLASS) - create_kwargs["db_typeclass_path"] = init_spawn_value(val, str, caller=caller, - prototype=prototype) - - # extract calls to handlers - val = prot.pop("permissions", []) - permission_string = init_spawn_value(val, make_iter, caller=caller, prototype=prototype) - val = prot.pop("locks", "") - lock_string = init_spawn_value(val, str, caller=caller, prototype=prototype) - val = prot.pop("aliases", []) - alias_string = init_spawn_value(val, make_iter, caller=caller, prototype=prototype) - - val = prot.pop("tags", []) - tags = [] - for (tag, category, *data) in val: - tags.append((init_spawn_value(tag, str, caller=caller, prototype=prototype), - category, data[0] if data else None)) - - prototype_key = prototype.get("prototype_key", None) - if prototype_key: - # we make sure to add a tag identifying which prototype created this object - tags.append((prototype_key, PROTOTYPE_TAG_CATEGORY)) - - val = prot.pop("exec", "") - execs = init_spawn_value(val, make_iter, caller=caller, prototype=prototype) - - # extract ndb assignments - nattributes = dict( - (key.split("_", 1)[1], init_spawn_value(val, value_to_obj, caller=caller, - prototype=prototype)) - for key, val in prot.items() - if key.startswith("ndb_") - ) - - # the rest are attribute tuples (attrname, value, category, locks) - val = make_iter(prot.pop("attrs", [])) - attributes = [] - for (attrname, value, *rest) in val: - attributes.append( - (attrname, init_spawn_value(value, caller=caller, prototype=prototype), - rest[0] if rest else None, rest[1] if len(rest) > 1 else None)) - - simple_attributes = [] - for key, value in ( - (key, value) for key, value in prot.items() if not (key.startswith("ndb_")) - ): - # we don't support categories, nor locks for simple attributes - if key in _PROTOTYPE_META_NAMES: - continue - else: - simple_attributes.append( - (key, init_spawn_value(value, value_to_obj_or_any, caller=caller, - prototype=prototype), None, None) - ) - - attributes = attributes + simple_attributes - attributes = [tup for tup in attributes if not tup[0] in _NON_CREATE_KWARGS] - - # pack for call into _batch_create_object - objsparams.append( - ( - create_kwargs, - permission_string, - lock_string, - alias_string, - nattributes, - attributes, - tags, - execs, - ) - ) - - if kwargs.get("only_validate"): - return objsparams - return batch_create_object(*objsparams)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/scripts/manager.html b/docs/0.9.5/_modules/evennia/scripts/manager.html deleted file mode 100644 index 685e5c512b..0000000000 --- a/docs/0.9.5/_modules/evennia/scripts/manager.html +++ /dev/null @@ -1,432 +0,0 @@ - - - - - - - - evennia.scripts.manager — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.scripts.manager

-"""
-The custom manager for Scripts.
-"""
-
-from django.conf import settings
-from django.db.models import Q
-from evennia.typeclasses.managers import TypedObjectManager, TypeclassManager
-from evennia.utils.utils import make_iter, class_from_module, dbid_to_obj
-from evennia.server import signals
-
-__all__ = ("ScriptManager", "ScriptDBManager")
-_GA = object.__getattribute__
-
-_ObjectDB = None
-_AccountDB = None
-
-
-VALIDATE_ITERATION = 0
-
-
-
[docs]class ScriptDBManager(TypedObjectManager): - """ - This Scriptmanager implements methods for searching - and manipulating Scripts directly from the database. - - Evennia-specific search methods (will return Typeclasses or - lists of Typeclasses, whereas Django-general methods will return - Querysets or database objects). - - dbref (converter) - dbref_search - get_dbref_range - object_totals - typeclass_search - get_all_scripts_on_obj - get_all_scripts - delete_script - remove_non_persistent - validate - script_search (equivalent to evennia.search_script) - copy_script - - """ - -
[docs] def get_all_scripts_on_obj(self, obj, key=None): - """ - Find all Scripts related to a particular object. - - Args: - obj (Object): Object whose Scripts we are looking for. - key (str, optional): Script identifier - can be given as a - dbref or name string. If given, only scripts matching the - key on the object will be returned. - Returns: - matches (list): Matching scripts. - - """ - if not obj: - return [] - account = _GA(_GA(obj, "__dbclass__"), "__name__") == "AccountDB" - if key: - dbref = self.dbref(key) - if dbref or dbref == 0: - if account: - return self.filter(db_account=obj, id=dbref) - else: - return self.filter(db_obj=obj, id=dbref) - elif account: - return self.filter(db_account=obj, db_key=key) - else: - return self.filter(db_obj=obj, db_key=key) - elif account: - return self.filter(db_account=obj) - else: - return self.filter(db_obj=obj)
- -
[docs] def get_all_scripts(self, key=None): - """ - Get all scripts in the database. - - Args: - key (str or int, optional): Restrict result to only those - with matching key or dbref. - - Returns: - scripts (list): All scripts found, or those matching `key`. - - """ - if key: - dbref = self.dbref(key) - if dbref: - return self.filter(id=dbref) - return self.filter(db_key__iexact=key.strip()) - return self.all()
- -
[docs] def delete_script(self, dbref): - """ - This stops and deletes a specific script directly from the - script database. - - Args: - dbref (int): Database unique id. - - Notes: - This might be needed for global scripts not tied to a - specific game object - - """ - scripts = self.get_id(dbref) - for script in make_iter(scripts): - script.stop() - script.delete()
- -
[docs] def update_scripts_after_server_start(self): - """ - Update/sync/restart/delete scripts after server shutdown/restart. - - """ - for script in self.filter(db_is_active=True, db_persistent=False): - script._stop_task() - - for script in self.filter(db_is_active=True): - script._unpause_task(auto_unpause=True) - script.at_server_start() - - for script in self.filter(db_is_active=False): - script.at_server_start()
- -
[docs] def search_script(self, ostring, obj=None, only_timed=False, typeclass=None): - """ - Search for a particular script. - - Args: - ostring (str): Search criterion - a script dbef or key. - obj (Object, optional): Limit search to scripts defined on - this object - only_timed (bool): Limit search only to scripts that run - on a timer. - typeclass (class or str): Typeclass or path to typeclass. - - Returns: - Queryset: An iterable with 0, 1 or more results. - - """ - - ostring = ostring.strip() - - dbref = self.dbref(ostring) - if dbref: - # this is a dbref, try to find the script directly - dbref_match = self.dbref_search(dbref) - if dbref_match: - dmatch = dbref_match[0] - if not (obj and obj != dmatch.obj) or (only_timed and dmatch.interval): - return dbref_match - - if typeclass: - if callable(typeclass): - typeclass = "%s.%s" % (typeclass.__module__, typeclass.__name__) - else: - typeclass = "%s" % typeclass - - # not a dbref; normal search - obj_restriction = obj and Q(db_obj=obj) or Q() - timed_restriction = only_timed and Q(db_interval__gt=0) or Q() - typeclass_restriction = typeclass and Q(db_typeclass_path=typeclass) or Q() - scripts = self.filter( - timed_restriction & obj_restriction & typeclass_restriction & Q(db_key__iexact=ostring) - ) - return scripts
- - # back-compatibility alias - script_search = search_script - -
[docs] def copy_script(self, original_script, new_key=None, new_obj=None, new_locks=None): - """ - Make an identical copy of the original_script. - - Args: - original_script (Script): The Script to copy. - new_key (str, optional): Rename the copy. - new_obj (Object, optional): Place copy on different Object. - new_locks (str, optional): Give copy different locks from - the original. - - Returns: - script_copy (Script): A new Script instance, copied from - the original. - """ - typeclass = original_script.typeclass_path - new_key = new_key if new_key is not None else original_script.key - new_obj = new_obj if new_obj is not None else original_script.obj - new_locks = new_locks if new_locks is not None else original_script.db_lock_storage - - from evennia.utils import create - - new_script = create.create_script( - typeclass, key=new_key, obj=new_obj, locks=new_locks, autostart=True - ) - return new_script
- -
[docs] def create_script( - self, - typeclass=None, - key=None, - obj=None, - account=None, - locks=None, - interval=None, - start_delay=None, - repeats=None, - persistent=None, - autostart=True, - report_to=None, - desc=None, - tags=None, - attributes=None, - ): - """ - Create a new script. All scripts are a combination of a database - object that communicates with the database, and an typeclass that - 'decorates' the database object into being different types of - scripts. It's behaviour is similar to the game objects except - scripts has a time component and are more limited in scope. - - Keyword Args: - typeclass (class or str): Class or python path to a typeclass. - key (str): Name of the new object. If not set, a name of - #dbref will be set. - obj (Object): The entity on which this Script sits. If this - is `None`, we are creating a "global" script. - account (Account): The account on which this Script sits. It is - exclusiv to `obj`. - locks (str): one or more lockstrings, separated by semicolons. - interval (int): The triggering interval for this Script, in - seconds. If unset, the Script will not have a timing - component. - start_delay (bool): If `True`, will wait `interval` seconds - before triggering the first time. - repeats (int): The number of times to trigger before stopping. - If unset, will repeat indefinitely. - persistent (bool): If this Script survives a server shutdown - or not (all Scripts will survive a reload). - autostart (bool): If this Script will start immediately when - created or if the `start` method must be called explicitly. - report_to (Object): The object to return error messages to. - desc (str): Optional description of script - tags (list): List of tags or tuples (tag, category). - attributes (list): List if tuples (key, value) or (key, value, category) - (key, value, lockstring) or (key, value, lockstring, default_access). - - Returns: - script (obj): An instance of the script created - - See evennia.scripts.manager for methods to manipulate existing - scripts in the database. - - """ - global _ObjectDB, _AccountDB - if not _ObjectDB: - from evennia.objects.models import ObjectDB as _ObjectDB - from evennia.accounts.models import AccountDB as _AccountDB - - typeclass = typeclass if typeclass else settings.BASE_SCRIPT_TYPECLASS - - if isinstance(typeclass, str): - # a path is given. Load the actual typeclass - typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS) - - # validate input - kwarg = {} - if key: - kwarg["db_key"] = key - if account: - kwarg["db_account"] = dbid_to_obj(account, _AccountDB) - if obj: - kwarg["db_obj"] = dbid_to_obj(obj, _ObjectDB) - if interval: - kwarg["db_interval"] = max(0, interval) - if start_delay: - kwarg["db_start_delay"] = start_delay - if repeats: - kwarg["db_repeats"] = max(0, repeats) - if persistent: - kwarg["db_persistent"] = persistent - if desc: - kwarg["db_desc"] = desc - tags = make_iter(tags) if tags is not None else None - attributes = make_iter(attributes) if attributes is not None else None - - # create new instance - new_script = typeclass(**kwarg) - - # store the call signature for the signal - new_script._createdict = dict( - key=key, - obj=obj, - account=account, - locks=locks, - interval=interval, - start_delay=start_delay, - repeats=repeats, - persistent=persistent, - autostart=autostart, - report_to=report_to, - desc=desc, - tags=tags, - attributes=attributes, - ) - # this will trigger the save signal which in turn calls the - # at_first_save hook on the typeclass, where the _createdict - # can be used. - new_script.save() - - if not new_script.id: - # this happens in the case of having a repeating script with `repeats=1` and - # `start_delay=False` - the script will run once and immediately stop before - # save is over. - return None - - signals.SIGNAL_SCRIPT_POST_CREATE.send(sender=new_script) - - return new_script
- - -
[docs]class ScriptManager(ScriptDBManager, TypeclassManager): - pass
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/scripts/models.html b/docs/0.9.5/_modules/evennia/scripts/models.html deleted file mode 100644 index 6e015e75a2..0000000000 --- a/docs/0.9.5/_modules/evennia/scripts/models.html +++ /dev/null @@ -1,286 +0,0 @@ - - - - - - - - evennia.scripts.models — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.scripts.models

-"""
-Scripts are entities that perform some sort of action, either only
-once or repeatedly. They can be directly linked to a particular
-Evennia Object or be stand-alonw (in the latter case it is considered
-a 'global' script). Scripts can indicate both actions related to the
-game world as well as pure behind-the-scenes events and effects.
-Everything that has a time component in the game (i.e. is not
-hard-coded at startup or directly created/controlled by players) is
-handled by Scripts.
-
-Scripts have to check for themselves that they should be applied at a
-particular moment of time; this is handled by the is_valid() hook.
-Scripts can also implement at_start and at_end hooks for preparing and
-cleaning whatever effect they have had on the game object.
-
-Common examples of uses of Scripts:
-
-- Load the default cmdset to the account object's cmdhandler
-  when logging in.
-- Switch to a different state, such as entering a text editor,
-  start combat or enter a dark room.
-- Merge a new cmdset with the default one for changing which
-  commands are available at a particular time
-- Give the account/object a time-limited bonus/effect
-
-"""
-from django.conf import settings
-from django.db import models
-from django.core.exceptions import ObjectDoesNotExist
-from evennia.typeclasses.models import TypedObject
-from evennia.scripts.manager import ScriptDBManager
-from evennia.utils.utils import dbref, to_str
-
-__all__ = ("ScriptDB",)
-_GA = object.__getattribute__
-_SA = object.__setattr__
-
-
-# ------------------------------------------------------------
-#
-# ScriptDB
-#
-# ------------------------------------------------------------
-
-
-
[docs]class ScriptDB(TypedObject): - """ - The Script database representation. - - The TypedObject supplies the following (inherited) properties: - key - main name - name - alias for key - typeclass_path - the path to the decorating typeclass - typeclass - auto-linked typeclass - date_created - time stamp of object creation - permissions - perm strings - dbref - #id of object - db - persistent attribute storage - ndb - non-persistent attribute storage - - The ScriptDB adds the following properties: - desc - optional description of script - obj - the object the script is linked to, if any - account - the account the script is linked to (exclusive with obj) - interval - how often script should run - start_delay - if the script should start repeating right away - repeats - how many times the script should repeat - persistent - if script should survive a server reboot - is_active - bool if script is currently running - - """ - - # - # ScriptDB Database Model setup - # - # These database fields are all set using their corresponding properties, - # named same as the field, but withtou the db_* prefix. - - # inherited fields (from TypedObject): - # db_key, db_typeclass_path, db_date_created, db_permissions - - # optional description. - db_desc = models.CharField("desc", max_length=255, blank=True) - # A reference to the database object affected by this Script, if any. - db_obj = models.ForeignKey( - "objects.ObjectDB", - null=True, - blank=True, - on_delete=models.CASCADE, - verbose_name="scripted object", - help_text="the object to store this script on, if not a global script.", - ) - db_account = models.ForeignKey( - "accounts.AccountDB", - null=True, - blank=True, - on_delete=models.CASCADE, - verbose_name="scripted account", - help_text="the account to store this script on (should not be set if db_obj is set)", - ) - - # how often to run Script (secs). -1 means there is no timer - db_interval = models.IntegerField( - "interval", default=-1, help_text="how often to repeat script, in seconds. <= 0 means off." - ) - # start script right away or wait interval seconds first - db_start_delay = models.BooleanField( - "start delay", default=False, help_text="pause interval seconds before starting." - ) - # how many times this script is to be repeated, if interval!=0. - db_repeats = models.IntegerField("number of repeats", default=0, help_text="0 means off.") - # defines if this script should survive a reboot or not - db_persistent = models.BooleanField("survive server reboot", default=True) - # defines if this script has already been started in this session - db_is_active = models.BooleanField("script active", default=False) - - # Database manager - objects = ScriptDBManager() - - # defaults - __settingsclasspath__ = settings.BASE_SCRIPT_TYPECLASS - __defaultclasspath__ = "evennia.scripts.scripts.DefaultScript" - __applabel__ = "scripts" - - class Meta(object): - "Define Django meta options" - verbose_name = "Script" - - # - # - # ScriptDB class properties - # - # - - # obj property - def __get_obj(self): - """ - Property wrapper that homogenizes access to either the - db_account or db_obj field, using the same object property - name. - - """ - obj = _GA(self, "db_account") - if not obj: - obj = _GA(self, "db_obj") - return obj - - def __set_obj(self, value): - """ - Set account or obj to their right database field. If - a dbref is given, assume ObjectDB. - - """ - try: - value = _GA(value, "dbobj") - except AttributeError: - # deprecated ... - pass - if isinstance(value, (str, int)): - from evennia.objects.models import ObjectDB - - value = to_str(value) - if value.isdigit() or value.startswith("#"): - dbid = dbref(value, reqhash=False) - if dbid: - try: - value = ObjectDB.objects.get(id=dbid) - except ObjectDoesNotExist: - # maybe it is just a name that happens to look like a dbid - pass - if value.__class__.__name__ == "AccountDB": - fname = "db_account" - _SA(self, fname, value) - else: - fname = "db_obj" - _SA(self, fname, value) - # saving the field - _GA(self, "save")(update_fields=[fname]) - - obj = property(__get_obj, __set_obj) - object = property(__get_obj, __set_obj)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/scripts/monitorhandler.html b/docs/0.9.5/_modules/evennia/scripts/monitorhandler.html deleted file mode 100644 index 1242944848..0000000000 --- a/docs/0.9.5/_modules/evennia/scripts/monitorhandler.html +++ /dev/null @@ -1,330 +0,0 @@ - - - - - - - - evennia.scripts.monitorhandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.scripts.monitorhandler

-"""
-Monitors - catch changes to model fields and Attributes.
-
-The MONITOR_HANDLER singleton from this module offers the following
-functionality:
-
-- Field-monitor - track a object's specific database field and perform
-    an action whenever that field *changes* for whatever reason.
-- Attribute-monitor tracks an object's specific Attribute and perform
-    an action whenever that Attribute *changes* for whatever reason.
-
-"""
-import inspect
-
-from collections import defaultdict
-from evennia.server.models import ServerConfig
-from evennia.utils.dbserialize import dbserialize, dbunserialize
-from evennia.utils import logger
-from evennia.utils import variable_from_module
-
-_SA = object.__setattr__
-_GA = object.__getattribute__
-_DA = object.__delattr__
-
-
-
[docs]class MonitorHandler(object): - """ - This is a resource singleton that allows for registering - callbacks for when a field or Attribute is updated (saved). - - """ - -
[docs] def __init__(self): - """ - Initialize the handler. - - """ - self.savekey = "_monitorhandler_save" - self.monitors = defaultdict(lambda: defaultdict(dict))
- -
[docs] def save(self): - """ - Store our monitors to the database. This is called - by the server process. - - Since dbserialize can't handle defaultdicts, we convert to an - intermediary save format ((obj,fieldname, idstring, callback, kwargs), ...) - - """ - savedata = [] - if self.monitors: - for obj in self.monitors: - for fieldname in self.monitors[obj]: - for idstring, (callback, persistent, kwargs) in self.monitors[obj][ - fieldname - ].items(): - path = "%s.%s" % (callback.__module__, callback.__name__) - savedata.append((obj, fieldname, idstring, path, persistent, kwargs)) - savedata = dbserialize(savedata) - ServerConfig.objects.conf(key=self.savekey, value=savedata)
- -
[docs] def restore(self, server_reload=True): - """ - Restore our monitors after a reload. This is called - by the server process. - - Args: - server_reload (bool, optional): If this is False, it means - the server went through a cold reboot and all - non-persistent tickers must be killed. - - """ - self.monitors = defaultdict(lambda: defaultdict(dict)) - restored_monitors = ServerConfig.objects.conf(key=self.savekey) - if restored_monitors: - restored_monitors = dbunserialize(restored_monitors) - for (obj, fieldname, idstring, path, persistent, kwargs) in restored_monitors: - try: - if not server_reload and not persistent: - # this monitor will not be restarted - continue - if "session" in kwargs and not kwargs["session"]: - # the session was removed because it no longer - # exists. Don't restart the monitor. - continue - modname, varname = path.rsplit(".", 1) - callback = variable_from_module(modname, varname) - - if obj and hasattr(obj, fieldname): - self.monitors[obj][fieldname][idstring] = (callback, persistent, kwargs) - except Exception: - continue - # make sure to clean data from database - ServerConfig.objects.conf(key=self.savekey, delete=True)
- - def _attr_category_fieldname(self, fieldname, category): - """ - Modify the saved fieldname to make sure to differentiate between Attributes - with different categories. - - """ - return f"{fieldname}[{category}]" if category else fieldname - -
[docs] def at_update(self, obj, fieldname): - """ - Called by the field/attribute as it saves. - - """ - # if this an Attribute with a category we should differentiate - fieldname = self._attr_category_fieldname( - fieldname, obj.db_category - if fieldname == "db_value" and hasattr(obj, "db_category") else None - ) - - to_delete = [] - if obj in self.monitors and fieldname in self.monitors[obj]: - for idstring, (callback, persistent, kwargs) in self.monitors[obj][fieldname].items(): - try: - callback(obj=obj, fieldname=fieldname, **kwargs) - except Exception: - to_delete.append((obj, fieldname, idstring)) - logger.log_trace("Monitor callback was removed.") - # we cleanup non-found monitors (has to be done after loop) - for (obj, fieldname, idstring) in to_delete: - del self.monitors[obj][fieldname][idstring]
- -
[docs] def add(self, obj, fieldname, callback, idstring="", persistent=False, - category=None, **kwargs): - """ - Add monitoring to a given field or Attribute. A field must - be specified with the full db_* name or it will be assumed - to be an Attribute (so `db_key`, not just `key`). - - Args: - obj (Typeclassed Entity): The entity on which to monitor a - field or Attribute. - fieldname (str): Name of field (db_*) or Attribute to monitor. - callback (callable): A callable on the form `callable(**kwargs), - where kwargs holds keys fieldname and obj. - idstring (str, optional): An id to separate this monitor from other monitors - of the same field and object. - persistent (bool, optional): If False, the monitor will survive - a server reload but not a cold restart. This is default. - category (str, optional): This is only used if `fieldname` refers to - an Attribute (i.e. it does not start with `db_`). You must specify this - if you want to target an Attribute with a category. - - Keyword Args: - session (Session): If this keyword is given, the monitorhandler will - correctly analyze it and remove the monitor if after a reload/reboot - the session is no longer valid. - any (any): Any other kwargs are passed on to the callback. Remember that - all kwargs must be possible to pickle! - - """ - if not fieldname.startswith("db_") or not hasattr(obj, fieldname): - # an Attribute - we track its db_value field - obj = obj.attributes.get(fieldname, return_obj=True) - if not obj: - return - fieldname = self._attr_category_fieldname("db_value", category) - - # we try to serialize this data to test it's valid. Otherwise we won't accept it. - try: - if not inspect.isfunction(callback): - raise TypeError("callback is not a function.") - dbserialize((obj, fieldname, callback, idstring, persistent, kwargs)) - except Exception: - err = "Invalid monitor definition: \n" " (%s, %s, %s, %s, %s, %s)" % ( - obj, - fieldname, - callback, - idstring, - persistent, - kwargs, - ) - logger.log_trace(err) - else: - self.monitors[obj][fieldname][idstring] = (callback, persistent, kwargs)
- -
[docs] def remove(self, obj, fieldname, idstring="", category=None): - """ - Remove a monitor. - """ - if not fieldname.startswith("db_") or not hasattr(obj, fieldname): - obj = obj.attributes.get(fieldname, return_obj=True) - if not obj: - return - fieldname = self._attr_category_fieldname("db_value", category) - - idstring_dict = self.monitors[obj][fieldname] - if idstring in idstring_dict: - del self.monitors[obj][fieldname][idstring]
- -
[docs] def clear(self): - """ - Delete all monitors. - """ - self.monitors = defaultdict(lambda: defaultdict(dict))
- -
[docs] def all(self, obj=None): - """ - List all monitors or all monitors of a given object. - - Args: - obj (Object): The object on which to list all monitors. - - Returns: - monitors (list): The handled monitors. - - """ - output = [] - objs = [obj] if obj else self.monitors - - for obj in objs: - for fieldname in self.monitors[obj]: - for idstring, (callback, persistent, kwargs) in self.monitors[obj][ - fieldname - ].items(): - output.append((obj, fieldname, idstring, persistent, kwargs)) - return output
- - -# access object -MONITOR_HANDLER = MonitorHandler() -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/scripts/scripthandler.html b/docs/0.9.5/_modules/evennia/scripts/scripthandler.html deleted file mode 100644 index 1d2dc8f0ec..0000000000 --- a/docs/0.9.5/_modules/evennia/scripts/scripthandler.html +++ /dev/null @@ -1,260 +0,0 @@ - - - - - - - - evennia.scripts.scripthandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.scripts.scripthandler

-"""
-The script handler makes sure to check through all stored scripts to
-make sure they are still relevant. A scripthandler is automatically
-added to all game objects. You access it through the property
-`scripts` on the game object.
-
-"""
-from evennia.scripts.models import ScriptDB
-from evennia.utils import create
-from evennia.utils import logger
-
-from django.utils.translation import gettext as _
-
-
-
[docs]class ScriptHandler(object): - """ - Implements the handler. This sits on each game object. - - """ - -
[docs] def __init__(self, obj): - """ - Set up internal state. - - Args: - obj (Object): A reference to the object this handler is - attached to. - - """ - self.obj = obj
- - def __str__(self): - """ - List the scripts tied to this object. - - """ - scripts = ScriptDB.objects.get_all_scripts_on_obj(self.obj) - string = "" - for script in scripts: - interval = "inf" - next_repeat = "inf" - repeats = "inf" - if script.interval > 0: - interval = script.interval - if script.repeats: - repeats = script.repeats - try: - next_repeat = script.time_until_next_repeat() - except Exception: - next_repeat = "?" - string += _("\n '{key}' ({next_repeat}/{interval}, {repeats} repeats): {desc}").format( - key=script.key, next_repeat=next_repeat, - interval=interval, - repeats=repeats, - desc=script.desc) - return string.strip() - -
[docs] def add(self, scriptclass, key=None, autostart=True): - """ - Add a script to this object. - - Args: - scriptclass (Scriptclass, Script or str): Either a class - object inheriting from DefaultScript, an instantiated - script object or a python path to such a class object. - key (str, optional): Identifier for the script (often set - in script definition and listings) - autostart (bool, optional): Start the script upon adding it. - - """ - if self.obj.__dbclass__.__name__ == "AccountDB": - # we add to an Account, not an Object - script = create.create_script( - scriptclass, key=key, account=self.obj, autostart=autostart - ) - else: - # the normal - adding to an Object. We wait to autostart so we can differentiate - # a failing creation from a script that immediately starts/stops. - script = create.create_script(scriptclass, key=key, obj=self.obj, autostart=False) - if not script: - logger.log_err("Script %s failed to be created/started." % scriptclass) - return False - if autostart: - script.start() - if not script.id: - # this can happen if the script has repeats=1 or calls stop() in at_repeat. - logger.log_info( - "Script %s started and then immediately stopped; " - "it could probably be a normal function." % scriptclass - ) - return True
- -
[docs] def start(self, key): - """ - Find scripts and force-start them - - Args: - key (str): The script's key or dbref. - - Returns: - nr_started (int): The number of started scripts found. - - """ - scripts = ScriptDB.objects.get_all_scripts_on_obj(self.obj, key=key) - num = 0 - for script in scripts: - script.start() - num += 1 - return num
- -
[docs] def get(self, key): - """ - Search scripts on this object. - - Args: - key (str): Search criterion, the script's key or dbref. - - Returns: - scripts (list): The found scripts matching `key`. - - """ - return list(ScriptDB.objects.get_all_scripts_on_obj(self.obj, key=key))
- -
[docs] def delete(self, key=None): - """ - Forcibly delete a script from this object. - - Args: - key (str, optional): A script key or the path to a script (in the - latter case all scripts with this path will be deleted!) - If no key is given, delete *all* scripts on the object! - - """ - delscripts = ScriptDB.objects.get_all_scripts_on_obj(self.obj, key=key) - if not delscripts: - delscripts = [ - script - for script in ScriptDB.objects.get_all_scripts_on_obj(self.obj) - if script.path == key - ] - num = 0 - for script in delscripts: - script.delete() - num += 1 - return num
- - # alias to delete - stop = delete - -
[docs] def all(self): - """ - Get all scripts stored in this handler. - - """ - return ScriptDB.objects.get_all_scripts_on_obj(self.obj)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/scripts/scripts.html b/docs/0.9.5/_modules/evennia/scripts/scripts.html deleted file mode 100644 index 00093b083b..0000000000 --- a/docs/0.9.5/_modules/evennia/scripts/scripts.html +++ /dev/null @@ -1,915 +0,0 @@ - - - - - - - - evennia.scripts.scripts — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.scripts.scripts

-"""
-This module defines Scripts, out-of-character entities that can store
-data both on themselves and on other objects while also having the
-ability to run timers.
-
-"""
-
-from twisted.internet.defer import Deferred, maybeDeferred
-from twisted.internet.task import LoopingCall
-from django.utils.translation import gettext as _
-from evennia.typeclasses.models import TypeclassBase
-from evennia.scripts.models import ScriptDB
-from evennia.scripts.manager import ScriptManager
-from evennia.utils import create, logger
-
-__all__ = ["DefaultScript", "DoNothing", "Store"]
-
-
-class ExtendedLoopingCall(LoopingCall):
-    """
-    Custom child of LoopingCall that can start at a delay different than
-    `self.interval` and self.count=0. This allows it to support pausing
-    by resuming at a later period.
-
-    """
-
-    start_delay = None
-    callcount = 0
-
-    def start(self, interval, now=True, start_delay=None, count_start=0):
-        """
-        Start running function every interval seconds.
-
-        This overloads the LoopingCall default by offering the
-        start_delay keyword and ability to repeat.
-
-        Args:
-            interval (int): Repeat interval in seconds.
-            now (bool, optional): Whether to start immediately or after
-                `start_delay` seconds.
-            start_delay (int, optional): This only applies is `now=False`. It gives
-                number of seconds to wait before starting. If `None`, use
-                `interval` as this value instead. Internally, this is used as a
-                way to start with a variable start time after a pause.
-            count_start (int): Number of repeats to start at. The  count
-                goes up every time the system repeats. This is used to
-                implement something repeating `N` number of times etc.
-
-        Raises:
-            AssertError: if trying to start a task which is already running.
-            ValueError: If interval is set to an invalid value < 0.
-
-        Notes:
-            As opposed to Twisted's inbuilt count mechanism, this
-            system will count also if force_repeat() was called rather
-            than just the number of `interval` seconds since the start.
-            This allows us to force-step through a limited number of
-            steps if we want.
-
-        """
-        assert not self.running, "Tried to start an already running ExtendedLoopingCall."
-        if interval < 0:
-            raise ValueError("interval must be >= 0")
-        self.running = True
-        deferred = self._deferred = Deferred()
-        self.starttime = self.clock.seconds()
-        self.interval = interval
-        self._runAtStart = now
-        self.callcount = max(0, count_start)
-        self.start_delay = start_delay if start_delay is None else max(0, start_delay)
-
-        if now:
-            # run immediately
-            self()
-        elif start_delay is not None and start_delay >= 0:
-            # start after some time: for this to work we need to
-            # trick _scheduleFrom by temporarily setting a different
-            # self.interval for it to check.
-            real_interval, self.interval = self.interval, start_delay
-            self._scheduleFrom(self.starttime)
-            # re-set the actual interval (this will be picked up
-            # next time it runs
-            self.interval = real_interval
-        else:
-            self._scheduleFrom(self.starttime)
-        return deferred
-
-    def __call__(self):
-        """
-        Tick one step. We update callcount (tracks number of calls) as
-        well as null start_delay (needed in order to correctly
-        estimate next_call_time at all times).
-
-        """
-        self.callcount += 1
-        if self.start_delay:
-            self.start_delay = None
-            self.starttime = self.clock.seconds()
-        if self._deferred:
-            LoopingCall.__call__(self)
-
-    def force_repeat(self):
-        """
-        Force-fire the callback
-
-        Raises:
-            AssertionError: When trying to force a task that is not
-                running.
-
-        """
-        assert self.running, "Tried to fire an ExtendedLoopingCall that was not running."
-        self.call.cancel()
-        self.call = None
-        self.starttime = self.clock.seconds()
-        self()
-
-    def next_call_time(self):
-        """
-        Get the next call time. This also takes the eventual effect
-        of start_delay into account.
-
-        Returns:
-            int or None: The time in seconds until the next call. This
-                takes `start_delay` into account. Returns `None` if
-                the task is not running.
-
-        """
-        if self.running and self.interval > 0:
-            total_runtime = self.clock.seconds() - self.starttime
-            interval = self.start_delay or self.interval
-            return max(0, interval - (total_runtime % self.interval))
-
-
-class ScriptBase(ScriptDB, metaclass=TypeclassBase):
-    """
-    Base class for scripts. Don't inherit from this, inherit from the
-    class `DefaultScript` below instead.
-
-    This handles the timer-component of the Script.
-
-    """
-
-    objects = ScriptManager()
-
-    def __str__(self):
-        return "<{cls} {key}>".format(cls=self.__class__.__name__, key=self.key)
-
-    def __repr__(self):
-        return str(self)
-
-    def at_idmapper_flush(self):
-        """
-        If we're flushing this object, make sure the LoopingCall is gone too.
-        """
-        ret = super().at_idmapper_flush()
-        if ret and self.ndb._task:
-            self.ndb._pause_task(auto_pause=True)
-        # TODO - restart anew ?
-        return ret
-
-    def _start_task(
-        self,
-        interval=None,
-        start_delay=None,
-        repeats=None,
-        force_restart=False,
-        auto_unpause=False,
-        **kwargs,
-    ):
-        """
-        Start/Unpause task runner, optionally with new values. If given, this will
-        update the Script's fields.
-
-        Keyword Args:
-            interval (int): How often to tick the task, in seconds. If this is <= 0,
-                no task will start and properties will not be updated on the Script.
-            start_delay (int): If the start should be delayed.
-            repeats (int): How many repeats. 0 for infinite repeats.
-            force_restart (bool): If set, always create a new task running even if an
-                old one already was running. Otherwise this will only happen if
-                new script properties were passed.
-            auto_unpause (bool): This is an automatic unpaused (used e.g by Evennia after
-                a reload) and should not un-pause manually paused Script timers.
-        Note:
-            If setting the `start-delay` of a *paused* Script, the Script will
-            restart exactly after that new start-delay, ignoring the time it
-            was paused at. If only changing the `interval`, the Script will
-            come out of pause comparing the time it spent in the *old* interval
-            with the *new* interval in order to determine when next to fire.
-
-        Examples:
-            - Script previously had an interval of 10s and was paused 5s into that interval.
-              Script is now restarted with a 20s interval. It will next fire after 15s.
-            - Same Script is restarted with a 3s interval. It will fire immediately.
-
-        """
-        if self.pk is None:
-            # script object already deleted from db - don't start a new timer
-            raise ScriptDB.DoesNotExist
-
-        # handle setting/updating fields
-        update_fields = []
-        old_interval = self.db_interval
-        if interval is not None:
-            self.db_interval = interval
-            update_fields.append("db_interval")
-        if start_delay is not None:
-            self.db_start_delay = start_delay
-            update_fields.append("db_start_delay")
-        if repeats is not None:
-            self.db_repeats = repeats
-            update_fields.append("db_repeats")
-
-        # validate interval
-        if self.db_interval and self.db_interval > 0:
-            if not self.is_active:
-                self.db_is_active = True
-                update_fields.append("db_is_active")
-        else:
-            # no point in starting a task with no interval.
-            return
-
-        restart = bool(update_fields) or force_restart
-        self.save(update_fields=update_fields)
-
-        if self.ndb._task and self.ndb._task.running:
-            if restart:
-                # a change needed/forced; stop/remove old task
-                self._stop_task()
-            else:
-                # task alreaady running and no changes needed
-                return
-
-        if not self.ndb._task:
-            # we should have a fresh task after this point
-            self.ndb._task = ExtendedLoopingCall(self._step_task)
-
-        self._unpause_task(
-            interval=interval,
-            start_delay=start_delay,
-            auto_unpause=auto_unpause,
-            old_interval=old_interval,
-        )
-
-        if not self.ndb._task.running:
-            # if not unpausing started it, start script anew with the new values
-            self.ndb._task.start(self.db_interval, now=not self.db_start_delay)
-
-        self.at_start(**kwargs)
-
-    def _pause_task(self, auto_pause=False, **kwargs):
-        """
-        Pause task where it is, saving the current status.
-
-        Args:
-            auto_pause (str):
-
-        """
-        if not self.db._paused_time:
-            # only allow pause if not already paused
-            task = self.ndb._task
-            if task:
-                self.db._paused_time = task.next_call_time()
-                self.db._paused_callcount = task.callcount
-                self.db._manually_paused = not auto_pause
-                if task.running:
-                    task.stop()
-            self.ndb._task = None
-
-            self.at_pause(auto_pause=auto_pause, **kwargs)
-
-    def _unpause_task(
-        self, interval=None, start_delay=None, auto_unpause=False, old_interval=0, **kwargs
-    ):
-        """
-        Unpause task from paused status. This is used for auto-paused tasks, such
-        as tasks paused on a server reload.
-
-        Args:
-            interval (int): How often to tick the task, in seconds.
-            start_delay (int): If the start should be delayed.
-            auto_unpause (bool): If set, this will only unpause scripts that were unpaused
-                automatically (useful during a system reload/shutdown).
-            old_interval (int): The old Script interval (or current one if nothing changed). Used
-                to recalculate the unpause startup interval.
-
-        """
-        paused_time = self.db._paused_time
-        if paused_time:
-            if auto_unpause and self.db._manually_paused:
-                # this was manually paused.
-                return
-
-            # task was paused. This will use the new values as needed.
-            callcount = self.db._paused_callcount or 0
-            if start_delay is None and interval is not None:
-                # adjust start-delay based on how far we were into previous interval
-                start_delay = max(0, interval - (old_interval - paused_time))
-            else:
-                start_delay = paused_time
-
-            if not self.ndb._task:
-                self.ndb._task = ExtendedLoopingCall(self._step_task)
-
-            self.ndb._task.start(
-                self.db_interval, now=False, start_delay=start_delay, count_start=callcount
-            )
-            self.db._paused_time = None
-            self.db._paused_callcount = None
-            self.db._manually_paused = None
-
-            self.at_start(**kwargs)
-
-    def _stop_task(self, **kwargs):
-        """
-        Stop task runner and delete the task.
-
-        """
-        task = self.ndb._task
-        if task and task.running:
-            task.stop()
-        self.ndb._task = None
-        self.db_is_active = False
-
-        # make sure this is not confused as a paused script
-        self.db._paused_time = None
-        self.db._paused_callcount = None
-        self.db._manually_paused = None
-
-        self.save(update_fields=["db_is_active"])
-        self.at_stop(**kwargs)
-
-    def _step_errback(self, e):
-        """
-        Callback for runner errors
-
-        """
-        cname = self.__class__.__name__
-        estring = _(
-            "Script {key}(#{dbid}) of type '{name}': at_repeat() error '{err}'.".format(
-                key=self.key, dbid=self.dbid, name=cname, err=e.getErrorMessage()
-            )
-        )
-        try:
-            self.db_obj.msg(estring)
-        except Exception:
-            # we must not crash inside the errback, even if db_obj is None.
-            pass
-        logger.log_err(estring)
-
-    def _step_callback(self):
-        """
-        Step task runner. No try..except needed due to defer wrap.
-
-        """
-        if not self.ndb._task:
-            # if there is no task, we have no business using this method
-            return
-
-        if not self.is_valid():
-            self.stop()
-            return
-
-        # call hook
-        self.at_repeat()
-
-        # check repeats
-        if self.ndb._task:
-            # we need to check for the task in case stop() was called
-            # inside at_repeat() and it already went away.
-            callcount = self.ndb._task.callcount
-            maxcount = self.db_repeats
-            if maxcount > 0 and maxcount <= callcount:
-                self.stop()
-
-    def _step_task(self):
-        """
-        Step task. This groups error handling.
-        """
-        try:
-            return maybeDeferred(self._step_callback).addErrback(self._step_errback)
-        except Exception:
-            logger.log_trace()
-        return None
-
-    # Access methods / hooks
-
-    def at_first_save(self, **kwargs):
-        """
-        This is called after very first time this object is saved.
-        Generally, you don't need to overload this, but only the hooks
-        called by this method.
-
-        Args:
-            **kwargs (dict): Arbitrary, optional arguments for users
-                overriding the call (unused by default).
-
-        """
-        self.at_script_creation()
-
-        if hasattr(self, "_createdict"):
-            # this will only be set if the utils.create_script
-            # function was used to create the object. We want
-            # the create call's kwargs to override the values
-            # set by hooks.
-            cdict = self._createdict
-            updates = []
-            if not cdict.get("key"):
-                if not self.db_key:
-                    self.db_key = "#%i" % self.dbid
-                    updates.append("db_key")
-            elif self.db_key != cdict["key"]:
-                self.db_key = cdict["key"]
-                updates.append("db_key")
-            if cdict.get("interval") and self.interval != cdict["interval"]:
-                self.db_interval = max(0, cdict["interval"])
-                updates.append("db_interval")
-            if cdict.get("start_delay") and self.start_delay != cdict["start_delay"]:
-                self.db_start_delay = cdict["start_delay"]
-                updates.append("db_start_delay")
-            if cdict.get("repeats") and self.repeats != cdict["repeats"]:
-                self.db_repeats = max(0, cdict["repeats"])
-                updates.append("db_repeats")
-            if cdict.get("persistent") and self.persistent != cdict["persistent"]:
-                self.db_persistent = cdict["persistent"]
-                updates.append("db_persistent")
-            if cdict.get("desc") and self.desc != cdict["desc"]:
-                self.db_desc = cdict["desc"]
-                updates.append("db_desc")
-            if updates:
-                self.save(update_fields=updates)
-
-            if cdict.get("permissions"):
-                self.permissions.batch_add(*cdict["permissions"])
-            if cdict.get("locks"):
-                self.locks.add(cdict["locks"])
-            if cdict.get("tags"):
-                # this should be a list of tags, tuples (key, category) or (key, category, data)
-                self.tags.batch_add(*cdict["tags"])
-            if cdict.get("attributes"):
-                # this should be tuples (key, val, ...)
-                self.attributes.batch_add(*cdict["attributes"])
-            if cdict.get("nattributes"):
-                # this should be a dict of nattrname:value
-                for key, value in cdict["nattributes"]:
-                    self.nattributes.add(key, value)
-
-            if cdict.get("autostart"):
-                # autostart the script
-                self._start_task(force_restart=True)
-
-    def delete(self, stop_task=True):
-        """
-        Delete the Script. Normally stops any timer task. This fires at_script_delete before
-        deletion.
-
-        Args:
-            stop_task (bool, optional): If unset, the task will not be stopped
-                when this method is called. The main reason for setting this to False
-                is if wanting to delete the script from the at_stop method - setting
-                this will then avoid an infinite recursion.
-
-        Returns:
-            bool: If deletion was successful or not. Only time this can fail would be if
-                the script was already previously deleted, or `at_script_delete` returns
-                False.
-
-        """
-        if not self.pk or not self.at_script_delete():
-            return False
-        if stop_task:
-            self._stop_task()
-        super().delete()
-        return True
-
-    def at_script_creation(self):
-        """
-        Should be overridden in child.
-
-        """
-        pass
-
-    def at_script_delete(self):
-        """
-        Called when script is deleted, before the script timer stops.
-
-        Returns:
-            bool: If False, deletion is aborted.
-
-        """
-        return True
-
-    def is_valid(self):
-        """
-        If returning False, `at_repeat` will not be called and timer will stop
-        updating.
-        """
-        return True
-
-    def at_repeat(self, **kwargs):
-        """
-        Called repeatedly every `interval` seconds, once `.start()` has
-        been called on the Script at least once.
-
-        Args:
-            **kwargs (dict): Arbitrary, optional arguments for users
-                overriding the call (unused by default).
-
-        """
-        pass
-
-    def at_start(self, **kwargs):
-        pass
-
-    def at_pause(self, **kwargs):
-        pass
-
-    def at_stop(self, **kwargs):
-        pass
-
-    def start(self, interval=None, start_delay=None, repeats=None, **kwargs):
-        """
-        Start/Unpause timer component, optionally with new values. If given,
-        this will update the Script's fields. This will start `at_repeat` being
-        called every `interval` seconds.
-
-        Keyword Args:
-            interval (int): How often to fire `at_repeat` in seconds.
-            start_delay (int): If the start of ticking should be delayed.
-            repeats (int): How many repeats. 0 for infinite repeats.
-            **kwargs: Optional (default unused) kwargs passed on into the `at_start` hook.
-
-        Notes:
-            If setting the `start-delay` of a *paused* Script, the Script will
-            restart exactly after that new start-delay, ignoring the time it
-            was paused at. If only changing the `interval`, the Script will
-            come out of pause comparing the time it spent in the *old* interval
-            with the *new* interval in order to determine when next to fire.
-
-        Examples:
-            - Script previously had an interval of 10s and was paused 5s into that interval.
-              Script is now restarted with a 20s interval. It will next fire after 15s.
-            - Same Script is restarted with a 3s interval. It will fire immediately.
-
-        """
-        self._start_task(interval=interval, start_delay=start_delay, repeats=repeats, **kwargs)
-
-    # legacy alias
-    update = start
-
-    def stop(self, **kwargs):
-        """
-        Stop the Script's timer component. This will not delete the Sctipt,
-        just stop the regular firing of `at_repeat`. Running `.start()` will
-        start the timer anew, optionally with new settings..
-
-        Args:
-            **kwargs: Optional (default unused) kwargs passed on into the `at_stop` hook.
-
-        """
-        self._stop_task(**kwargs)
-
-    def pause(self, **kwargs):
-        """
-        Manually the Script's timer component manually.
-
-        Args:
-            **kwargs: Optional (default unused) kwargs passed on into the `at_pause` hook.
-
-        """
-        self._pause_task(manual_pause=True, **kwargs)
-
-    def unpause(self, **kwargs):
-        """
-        Manually unpause a Paused Script.
-
-        Args:
-            **kwargs: Optional (default unused) kwargs passed on into the `at_start` hook.
-
-        """
-        self._unpause_task(**kwargs)
-
-    def time_until_next_repeat(self):
-        """
-        Get time until the script fires it `at_repeat` hook again.
-
-        Returns:
-            int or None: Time in seconds until the script runs again.
-                If not a timed script, return `None`.
-
-        Notes:
-            This hook is not used in any way by the script's stepping
-            system; it's only here for the user to be able to check in
-            on their scripts and when they will next be run.
-
-        """
-        task = self.ndb._task
-        if task:
-            try:
-                return int(round(task.next_call_time()))
-            except TypeError:
-                pass
-        return None
-
-    def remaining_repeats(self):
-        """
-        Get the number of returning repeats for limited Scripts.
-
-        Returns:
-            int or None: The number of repeats remaining until the Script
-                stops. Returns `None` if it has unlimited repeats.
-
-        """
-        task = self.ndb._task
-        if task:
-            return max(0, self.db_repeats - task.callcount)
-        return None
-
-    def reset_callcount(self, value=0):
-        """
-        Reset the count of the number of calls done.
-
-        Args:
-            value (int, optional): The repeat value to reset to. Default
-                is to set it all the way back to 0.
-
-        Notes:
-            This is only useful if repeats != 0.
-
-        """
-        task = self.ndb._task
-        if task:
-            task.callcount = max(0, int(value))
-
-    def force_repeat(self):
-        """
-        Fire a premature triggering of the script callback. This
-        will reset the timer and count down repeats as if the script
-        had fired normally.
-        """
-        task = self.ndb._task
-        if task:
-            task.force_repeat()
-
-
-
[docs]class DefaultScript(ScriptBase): - """ - This is the base TypeClass for all Scripts. Scripts describe - events, timers and states in game, they can have a time component - or describe a state that changes under certain conditions. - - """ - -
[docs] @classmethod - def create(cls, key, **kwargs): - """ - Provides a passthrough interface to the utils.create_script() function. - - Args: - key (str): Name of the new object. - - Returns: - object (Object): A newly created object of the given typeclass. - errors (list): A list of errors in string form, if any. - - """ - errors = [] - obj = None - - kwargs["key"] = key - - # If no typeclass supplied, use this class - kwargs["typeclass"] = kwargs.pop("typeclass", cls) - - try: - obj = create.create_script(**kwargs) - except Exception: - logger.log_trace() - errors.append("The script '%s' encountered errors and could not be created." % key) - - return obj, errors
- -
[docs] def at_script_creation(self): - """ - Only called once, when script is first created. - - """ - pass
- -
[docs] def is_valid(self): - """ - Is called to check if the script's timer is valid to run at this time. - Should return a boolean. If False, the timer will be stopped. - - """ - return True
- -
[docs] def at_start(self, **kwargs): - """ - Called whenever the script timer is started, which for persistent - timed scripts is at least once every server start. It will also be - called when starting again after a pause (including after a - server reload). - - Args: - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - """ - pass
- -
[docs] def at_repeat(self, **kwargs): - """ - Called repeatedly if this Script is set to repeat regularly. - - Args: - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - """ - pass
- -
[docs] def at_pause(self, manual_pause=True, **kwargs): - """ - Called when this script's timer pauses. - - Args: - manual_pause (bool): If set, pausing was done by a direct call. The - non-manual pause indicates the script was paused as part of - the server reload. - - """ - pass
- -
[docs] def at_stop(self, **kwargs): - """ - Called whenever when it's time for this script's timer to stop (either - because is_valid returned False, it ran out of iterations or it was manuallys - stopped. - - Args: - **kwargs (dict): Arbitrary, optional arguments for users - overriding the call (unused by default). - - """ - pass
- -
[docs] def at_script_delete(self): - """ - Called when the Script is deleted, before stopping the timer. - - Returns: - bool: If False, the deletion is aborted. - - """ - return True
- -
[docs] def at_server_reload(self): - """ - This hook is called whenever the server is shutting down for - restart/reboot. If you want to, for example, save - non-persistent properties across a restart, this is the place - to do it. - """ - pass
- -
[docs] def at_server_shutdown(self): - """ - This hook is called whenever the server is shutting down fully - (i.e. not for a restart). - """ - pass
- -
[docs] def at_server_start(self): - """ - This hook is called after the server has started. It can be used to add - post-startup setup for Scripts without a timer component (for which at_start - could be used). - - """ - pass
- - -# Some useful default Script types used by Evennia. - - -
[docs]class DoNothing(DefaultScript): - """ - A script that does nothing. Used as default fallback. - """ - -
[docs] def at_script_creation(self): - """ - Setup the script - """ - self.key = "sys_do_nothing" - self.desc = "This is an empty placeholder script."
- - -
[docs]class Store(DefaultScript): - """ - Simple storage script - """ - -
[docs] def at_script_creation(self): - """ - Setup the script - """ - self.key = "sys_storage" - self.desc = "This is a generic storage container."
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/scripts/taskhandler.html b/docs/0.9.5/_modules/evennia/scripts/taskhandler.html deleted file mode 100644 index 27a94a8588..0000000000 --- a/docs/0.9.5/_modules/evennia/scripts/taskhandler.html +++ /dev/null @@ -1,715 +0,0 @@ - - - - - - - - evennia.scripts.taskhandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.scripts.taskhandler

-"""
-Module containing the task handler for Evennia deferred tasks, persistent or not.
-"""
-
-from datetime import datetime, timedelta
-
-from twisted.internet import reactor
-from pickle import PickleError
-from twisted.internet.task import deferLater
-from twisted.internet.defer import CancelledError as DefCancelledError
-from evennia.server.models import ServerConfig
-from evennia.utils.logger import log_err
-from evennia.utils.dbserialize import dbserialize, dbunserialize
-
-TASK_HANDLER = None
-
-
-
[docs]def handle_error(*args, **kwargs): - """Handle errors within deferred objects.""" - for arg in args: - # suppress cancel errors - if arg.type == DefCancelledError: - continue - raise arg
- - -
[docs]class TaskHandlerTask: - """An object to represent a single TaskHandler task. - - Instance Attributes: - task_id (int): the global id for this task - deferred (deferred): a reference to this task's deferred - Property Attributes: - paused (bool): check if the deferred instance of a task has been paused. - called(self): A task attribute to check if the deferred instance of a task has been called. - - Methods: - pause(): Pause the callback of a task. - unpause(): Process all callbacks made since pause() was called. - do_task(): Execute the task (call its callback). - call(): Call the callback of this task. - remove(): Remove a task without executing it. - cancel(): Stop a task from automatically executing. - active(): Check if a task is active (has not been called yet). - exists(): Check if a task exists. - get_id(): Returns the global id for this task. For use with - - """ - -
[docs] def __init__(self, task_id): - self.task_id = task_id - self.deferred = TASK_HANDLER.get_deferred(task_id)
- -
[docs] def get_deferred(self): - """Return the instance of the deferred the task id is using. - - Returns: - bool or deferred: An instance of a deferred or False if there is no task with the id. - None is returned if there is no deferred affiliated with this id. - - """ - return TASK_HANDLER.get_deferred(self.task_id)
- -
[docs] def pause(self): - """ - Pause the callback of a task. - To resume use `TaskHandlerTask.unpause`. - - """ - d = self.deferred - if d: - d.pause()
- -
[docs] def unpause(self): - """ - Unpause a task, run the task if it has passed delay time. - - """ - d = self.deferred - if d: - d.unpause()
- - @property - def paused(self): - """ - A task attribute to check if the deferred instance of a task has been paused. - - This exists to mock usage of a twisted deferred object. - - Returns: - bool or None: True if the task was properly paused. None if the task does not have - a deferred instance. - - """ - d = self.deferred - if d: - return d.paused - else: - return None - -
[docs] def do_task(self): - """ - Execute the task (call its callback). - If calling before timedelay, cancel the deferred instance affliated to this task. - Remove the task from the dictionary of current tasks on a successful - callback. - - Returns: - bool or any: Set to `False` if the task does not exist in task - handler. Otherwise it will be the return of the task's callback. - - """ - return TASK_HANDLER.do_task(self.task_id)
- -
[docs] def call(self): - """ - Call the callback of a task. - Leave the task unaffected otherwise. - This does not use the task's deferred instance. - The only requirement is that the task exist in task handler. - - Returns: - bool or any: Set to `False` if the task does not exist in task - handler. Otherwise it will be the return of the task's callback. - - """ - return TASK_HANDLER.call_task(self.task_id)
- -
[docs] def remove(self): - """Remove a task without executing it. - Deletes the instance of the task's deferred. - - Args: - task_id (int): an existing task ID. - - Returns: - bool: True if the removal completed successfully. - - """ - return TASK_HANDLER.remove(self.task_id)
- -
[docs] def cancel(self): - """Stop a task from automatically executing. - This will not remove the task. - - Returns: - bool: True if the cancel completed successfully. - False if the cancel did not complete successfully. - - """ - return TASK_HANDLER.cancel(self.task_id)
- -
[docs] def active(self): - """Check if a task is active (has not been called yet). - - Returns: - bool: True if a task is active (has not been called yet). False if - it is not (has been called) or if the task does not exist. - - """ - return TASK_HANDLER.active(self.task_id)
- - @property - def called(self): - """ - A task attribute to check if the deferred instance of a task has been called. - - This exists to mock usage of a twisted deferred object. - It will not set to True if Task.call has been called. This only happens if - task's deferred instance calls the callback. - - Returns: - bool: True if the deferred instance of this task has called the callback. - False if the deferred instnace of this task has not called the callback. - - """ - d = self.deferred - if d: - return d.called - else: - return None - -
[docs] def exists(self): - """ - Check if a task exists. - Most task handler methods check for existence for you. - - Returns: - bool: True the task exists False if it does not. - - """ - return TASK_HANDLER.exists(self.task_id)
- -
[docs] def get_id(self): - """ - Returns the global id for this task. For use with - `evennia.scripts.taskhandler.TASK_HANDLER`. - - Returns: - task_id (int): global task id for this task. - - """ - return self.task_id
- - -
[docs]class TaskHandler(object): - - """A light singleton wrapper allowing to access permanent tasks. - - When `utils.delay` is called, the task handler is used to create - the task. - - Task handler will automatically remove uncalled but canceled from task - handler. By default this will not occur until a canceled task - has been uncalled for 60 second after the time it should have been called. - To adjust this time use TASK_HANDLER.stale_timeout. If stale_timeout is 0 - stale tasks will not be automatically removed. - This is not done on a timer. I is done as new tasks are added or the load method is called. - - """ - -
[docs] def __init__(self): - self.tasks = {} - self.to_save = {} - self.clock = reactor - # number of seconds before an uncalled canceled task is removed from TaskHandler - self.stale_timeout = 60 - self._now = False # used in unit testing to manually set now time
- -
[docs] def load(self): - """Load from the ServerConfig. - - This should be automatically called when Evennia starts. - It populates `self.tasks` according to the ServerConfig. - - """ - to_save = False - value = ServerConfig.objects.conf("delayed_tasks", default={}) - if isinstance(value, str): - tasks = dbunserialize(value) - else: - tasks = value - - # At this point, `tasks` contains a dictionary of still-serialized tasks - for task_id, value in tasks.items(): - date, callback, args, kwargs = dbunserialize(value) - if isinstance(callback, tuple): - # `callback` can be an object and name for instance methods - obj, method = callback - if obj is None: - to_save = True - continue - - callback = getattr(obj, method) - self.tasks[task_id] = (date, callback, args, kwargs, True, None) - - if self.stale_timeout > 0: # cleanup stale tasks. - self.clean_stale_tasks() - if to_save: - self.save()
- -
[docs] def clean_stale_tasks(self): - """remove uncalled but canceled from task handler. - - By default this will not occur until a canceled task - has been uncalled for 60 second after the time it should have been called. - To adjust this time use TASK_HANDLER.stale_timeout. - - """ - clean_ids = [] - for task_id, (date, callback, args, kwargs, persistent, _) in self.tasks.items(): - if not self.active(task_id): - stale_date = date + timedelta(seconds=self.stale_timeout) - # if a now time is provided use it (intended for unit testing) - now = self._now if self._now else datetime.now() - # the task was canceled more than stale_timeout seconds ago - if now > stale_date: - clean_ids.append(task_id) - for task_id in clean_ids: - self.remove(task_id) - return True
- -
[docs] def save(self): - """ - Save the tasks in ServerConfig. - - """ - - for task_id, (date, callback, args, kwargs, persistent, _) in self.tasks.items(): - if task_id in self.to_save: - continue - if not persistent: - continue - - safe_callback = callback - if getattr(callback, "__self__", None): - # `callback` is an instance method - obj = callback.__self__ - name = callback.__name__ - safe_callback = (obj, name) - - # Check if callback can be pickled. args and kwargs have been checked - try: - dbserialize(safe_callback) - except (TypeError, AttributeError, PickleError) as err: - raise ValueError( - "the specified callback {callback} cannot be pickled. " - "It must be a top-level function in a module or an " - "instance method ({err}).".format(callback=callback, err=err) - ) - - self.to_save[task_id] = dbserialize((date, safe_callback, args, kwargs)) - - ServerConfig.objects.conf("delayed_tasks", self.to_save)
- -
[docs] def add(self, timedelay, callback, *args, **kwargs): - """ - Add a new task. - - If the persistent kwarg is truthy: - The callback, args and values for kwarg will be serialized. Type - and attribute errors during the serialization will be logged, - but will not throw exceptions. - For persistent tasks do not use memory references in the callback - function or arguments. After a restart those memory references are no - longer accurate. - - Args: - timedelay (int or float): time in seconds before calling the callback. - callback (function or instance method): the callback itself - any (any): any additional positional arguments to send to the callback - *args: positional arguments to pass to callback. - **kwargs: keyword arguments to pass to callback. - - persistent (bool, optional): persist the task (stores it). - Persistent key and value is removed from kwargs it will - not be passed to callback. - - Returns: - TaskHandlerTask: An object to represent a task. - Reference evennia.scripts.taskhandler.TaskHandlerTask for complete details. - - """ - # set the completion time - # Only used on persistent tasks after a restart - now = datetime.now() - delta = timedelta(seconds=timedelay) - comp_time = now + delta - # get an open task id - used_ids = list(self.tasks.keys()) - task_id = 1 - while task_id in used_ids: - task_id += 1 - - # record the task to the tasks dictionary - persistent = kwargs.get("persistent", False) - if "persistent" in kwargs: - del kwargs["persistent"] - if persistent: - safe_args = [] - safe_kwargs = {} - - # Check that args and kwargs contain picklable information - for arg in args: - try: - dbserialize(arg) - except (TypeError, AttributeError, PickleError): - log_err( - "The positional argument {} cannot be " - "pickled and will not be present in the arguments " - "fed to the callback {}".format(arg, callback) - ) - else: - safe_args.append(arg) - - for key, value in kwargs.items(): - try: - dbserialize(value) - except (TypeError, AttributeError, PickleError): - log_err( - "The {} keyword argument {} cannot be " - "pickled and will not be present in the arguments " - "fed to the callback {}".format(key, value, callback) - ) - else: - safe_kwargs[key] = value - - self.tasks[task_id] = (comp_time, callback, safe_args, safe_kwargs, persistent, None) - self.save() - else: # this is a non-persitent task - self.tasks[task_id] = (comp_time, callback, args, kwargs, persistent, None) - - # defer the task - callback = self.do_task - args = [task_id] - kwargs = {} - d = deferLater(self.clock, timedelay, callback, *args, **kwargs) - d.addErrback(handle_error) - - # some tasks may complete before the deferred can be added - if task_id in self.tasks: - task = self.tasks.get(task_id) - task = list(task) - task[4] = persistent - task[5] = d - self.tasks[task_id] = task - else: # the task already completed - return False - if self.stale_timeout > 0: - self.clean_stale_tasks() - return TaskHandlerTask(task_id)
- -
[docs] def exists(self, task_id): - """ - Check if a task exists. - Most task handler methods check for existence for you. - - Args: - task_id (int): an existing task ID. - - Returns: - bool: True the task exists False if it does not. - - """ - if task_id in self.tasks: - return True - else: - return False
- -
[docs] def active(self, task_id): - """ - Check if a task is active (has not been called yet). - - Args: - task_id (int): an existing task ID. - - Returns: - bool: True if a task is active (has not been called yet). False if - it is not (has been called) or if the task does not exist. - - """ - if task_id in self.tasks: - # if the task has not been run, cancel it - deferred = self.get_deferred(task_id) - return not (deferred and deferred.called) - else: - return False
- -
[docs] def cancel(self, task_id): - """ - Stop a task from automatically executing. - This will not remove the task. - - Args: - task_id (int): an existing task ID. - - Returns: - bool: True if the cancel completed successfully. - False if the cancel did not complete successfully. - - """ - if task_id in self.tasks: - # if the task has not been run, cancel it - d = self.get_deferred(task_id) - if d: # it is remotely possible for a task to not have a deferred - if d.called: - return False - else: # the callback has not been called yet. - d.cancel() - return True - else: # this task has no deferred instance - return False - else: - return False
- -
[docs] def remove(self, task_id): - """ - Remove a task without executing it. - Deletes the instance of the task's deferred. - - Args: - task_id (int): an existing task ID. - - Returns: - bool: True if the removal completed successfully. - - """ - d = None - # delete the task from the tasks dictionary - if task_id in self.tasks: - # if the task has not been run, cancel it - self.cancel(task_id) - del self.tasks[task_id] # delete the task from the tasks dictionary - # remove the task from the persistent dictionary and ServerConfig - if task_id in self.to_save: - del self.to_save[task_id] - self.save() # remove from ServerConfig.objects - # delete the instance of the deferred - if d: - del d - return True
- -
[docs] def clear(self, save=True, cancel=True): - """ - Clear all tasks. By default tasks are canceled and removed from the database as well. - - Args: - save=True (bool): Should changes to persistent tasks be saved to database. - cancel=True (bool): Cancel scheduled tasks before removing it from task handler. - - Returns: - True (bool): if the removal completed successfully. - - """ - if self.tasks: - for task_id in self.tasks.keys(): - if cancel: - self.cancel(task_id) - self.tasks = {} - if self.to_save: - self.to_save = {} - if save: - self.save() - return True
- -
[docs] def call_task(self, task_id): - """ - Call the callback of a task. - Leave the task unaffected otherwise. - This does not use the task's deferred instance. - The only requirement is that the task exist in task handler. - - Args: - task_id (int): an existing task ID. - - Returns: - bool or any: Set to `False` if the task does not exist in task - handler. Otherwise it will be the return of the task's callback. - - """ - if task_id in self.tasks: - date, callback, args, kwargs, persistent, d = self.tasks.get(task_id) - else: # the task does not exist - return False - return callback(*args, **kwargs)
- -
[docs] def do_task(self, task_id): - """ - Execute the task (call its callback). - If calling before timedelay cancel the deferred instance affliated to this task. - Remove the task from the dictionary of current tasks on a successful - callback. - - Args: - task_id (int): a valid task ID. - - Returns: - bool or any: Set to `False` if the task does not exist in task - handler. Otherwise it will be the return of the task's callback. - - """ - callback_return = False - if task_id in self.tasks: - date, callback, args, kwargs, persistent, d = self.tasks.get(task_id) - else: # the task does not exist - return False - if d: # it is remotely possible for a task to not have a deferred - if not d.called: # the task's deferred has not been called yet - d.cancel() # cancel the automated callback - else: # this task has no deferred, and should not be called - return False - callback_return = callback(*args, **kwargs) - self.remove(task_id) - return callback_return
- -
[docs] def get_deferred(self, task_id): - """ - Return the instance of the deferred the task id is using. - - Args: - task_id (int): a valid task ID. - - Returns: - bool or deferred: An instance of a deferred or False if there is no task with the id. - None is returned if there is no deferred affiliated with this id. - - """ - if task_id in self.tasks: - return self.tasks[task_id][5] - else: - return None
- -
[docs] def create_delays(self): - """ - Create the delayed tasks for the persistent tasks. - This method should be automatically called when Evennia starts. - - """ - now = datetime.now() - for task_id, (date, callback, args, kwargs, _, _) in self.tasks.items(): - self.tasks[task_id] = date, callback, args, kwargs, True, None - seconds = max(0, (date - now).total_seconds()) - d = deferLater(self.clock, seconds, self.do_task, task_id) - d.addErrback(handle_error) - # some tasks may complete before the deferred can be added - if self.tasks.get(task_id, False): - self.tasks[task_id] = date, callback, args, kwargs, True, d
- - -# Create the soft singleton -TASK_HANDLER = TaskHandler() -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/scripts/tickerhandler.html b/docs/0.9.5/_modules/evennia/scripts/tickerhandler.html deleted file mode 100644 index 283dd85d2d..0000000000 --- a/docs/0.9.5/_modules/evennia/scripts/tickerhandler.html +++ /dev/null @@ -1,748 +0,0 @@ - - - - - - - - evennia.scripts.tickerhandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.scripts.tickerhandler

-"""
-TickerHandler
-
-This implements an efficient Ticker which uses a subscription
-model to 'tick' subscribed objects at regular intervals.
-
-The ticker mechanism is used by importing and accessing
-the instantiated TICKER_HANDLER instance in this module. This
-instance is run by the server; it will save its status across
-server reloads and be started automaticall on boot.
-
-Example:
-
-```python
-    from evennia.scripts.tickerhandler import TICKER_HANDLER
-
-    # call tick myobj.at_tick(*args, **kwargs) every 15 seconds
-    TICKER_HANDLER.add(15, myobj.at_tick, *args, **kwargs)
-```
-
-You supply the interval to tick and a callable to call regularly with
-any extra args/kwargs. The callable should either be a stand-alone
-function in a module *or* the method on a *typeclassed* entity (that
-is, on an object that can be safely and stably returned from the
-database).  Functions that are dynamically created or sits on
-in-memory objects cannot be used by the tickerhandler (there is no way
-to reference them safely across reboots and saves).
-
-The handler will transparently set
-up and add new timers behind the scenes to tick at given intervals,
-using a TickerPool - all callables with the same interval will share
-the interval ticker.
-
-To remove:
-
-```python
-    TICKER_HANDLER.remove(15, myobj.at_tick)
-```
-
-Both interval and callable must be given since a single object can be subscribed
-to many different tickers at the same time. You can also supply `idstring`
-as an identifying string if you ever want to tick the callable at the same interval
-but with different arguments (args/kwargs are not used for identifying the ticker). There
-is also `persistent=False` if you don't want to make a ticker that don't survive a reload.
-If either or both `idstring` or `persistent` has been changed from their defaults, they
-must be supplied to the `TICKER_HANDLER.remove` call to properly identify the ticker
-to remove.
-
-The TickerHandler's functionality can be overloaded by modifying the
-Ticker class and then changing TickerPool and TickerHandler to use the
-custom classes
-
-```python
-class MyTicker(Ticker):
-    # [doing custom stuff]
-
-class MyTickerPool(TickerPool):
-    ticker_class = MyTicker
-class MyTickerHandler(TickerHandler):
-    ticker_pool_class = MyTickerPool
-```
-
-If one wants to duplicate TICKER_HANDLER's auto-saving feature in
-a  custom handler one can make a custom `AT_STARTSTOP_MODULE` entry to
-call the handler's `save()` and `restore()` methods when the server reboots.
-
-"""
-import inspect
-
-from twisted.internet.defer import inlineCallbacks
-from django.core.exceptions import ObjectDoesNotExist
-from evennia.scripts.scripts import ExtendedLoopingCall
-from evennia.server.models import ServerConfig
-from evennia.utils.logger import log_trace, log_err
-from evennia.utils.dbserialize import dbserialize, dbunserialize, pack_dbobj
-from evennia.utils import variable_from_module, inherits_from
-
-_GA = object.__getattribute__
-_SA = object.__setattr__
-
-
-_ERROR_ADD_TICKER = """TickerHandler: Tried to add an invalid ticker:
-{store_key}
-Ticker was not added."""
-
-_ERROR_ADD_TICKER_SUB_SECOND = """You are trying to add a ticker running faster
-than once per second. This is not supported and also probably not useful:
-Spamming messages to the user faster than once per second serves no purpose in
-a text-game, and if you want to update some property, consider doing so
-on-demand rather than using a ticker.
-"""
-
-
[docs]class Ticker(object): - """ - Represents a repeatedly running task that calls - hooks repeatedly. Overload `_callback` to change the - way it operates. - """ - - @inlineCallbacks - def _callback(self): - """ - This will be called repeatedly every `self.interval` seconds. - `self.subscriptions` contain tuples of (obj, args, kwargs) for - each subscribing object. - - If overloading, this callback is expected to handle all - subscriptions when it is triggered. It should not return - anything and should not traceback on poorly designed hooks. - The callback should ideally work under @inlineCallbacks so it - can yield appropriately. - - The _hook_key, which is passed down through the handler via - kwargs is used here to identify which hook method to call. - - """ - self._to_add = [] - self._to_remove = [] - self._is_ticking = True - for store_key, (args, kwargs) in self.subscriptions.items(): - callback = yield kwargs.pop("_callback", "at_tick") - obj = yield kwargs.pop("_obj", None) - try: - if callable(callback): - # call directly - yield callback(*args, **kwargs) - continue - # try object method - if not obj or not obj.pk: - # object was deleted between calls - self._to_remove.append(store_key) - continue - else: - yield _GA(obj, callback)(*args, **kwargs) - except ObjectDoesNotExist: - log_trace("Removing ticker.") - self._to_remove.append(store_key) - except Exception: - log_trace() - finally: - # make sure to re-store - kwargs["_callback"] = callback - kwargs["_obj"] = obj - # cleanup - we do this here to avoid changing the subscription dict while it loops - self._is_ticking = False - for store_key in self._to_remove: - self.remove(store_key) - for store_key, (args, kwargs) in self._to_add: - self.add(store_key, *args, **kwargs) - self._to_remove = [] - self._to_add = [] - -
[docs] def __init__(self, interval): - """ - Set up the ticker - - Args: - interval (int): The stepping interval. - - """ - self.interval = interval - self.subscriptions = {} - self._is_ticking = False - self._to_remove = [] - self._to_add = [] - # set up a twisted asynchronous repeat call - self.task = ExtendedLoopingCall(self._callback)
- -
[docs] def validate(self, start_delay=None): - """ - Start/stop the task depending on how many subscribers we have - using it. - - Args: - start_delay (int): Time to way before starting. - - """ - subs = self.subscriptions - if self.task.running: - if not subs: - self.task.stop() - elif subs: - self.task.start(self.interval, now=False, start_delay=start_delay)
- -
[docs] def add(self, store_key, *args, **kwargs): - """ - Sign up a subscriber to this ticker. - Args: - store_key (str): Unique storage hash for this ticker subscription. - args (any, optional): Arguments to call the hook method with. - - Keyword Args: - _start_delay (int): If set, this will be - used to delay the start of the trigger instead of - `interval`. - - """ - if self._is_ticking: - # protects the subscription dict from - # updating while it is looping - self._to_add.append((store_key, (args, kwargs))) - else: - start_delay = kwargs.pop("_start_delay", None) - self.subscriptions[store_key] = (args, kwargs) - self.validate(start_delay=start_delay)
- -
[docs] def remove(self, store_key): - """ - Unsubscribe object from this ticker - - Args: - store_key (str): Unique store key. - - """ - if self._is_ticking: - # this protects the subscription dict from - # updating while it is looping - self._to_remove.append(store_key) - else: - self.subscriptions.pop(store_key, False) - self.validate()
- -
[docs] def stop(self): - """ - Kill the Task, regardless of subscriptions. - - """ - self.subscriptions = {} - self.validate()
- - -
[docs]class TickerPool(object): - """ - This maintains a pool of - `evennia.scripts.scripts.ExtendedLoopingCall` tasks for calling - subscribed objects at given times. - - """ - - ticker_class = Ticker - -
[docs] def __init__(self): - """ - Initialize the pool. - - """ - self.tickers = {}
- -
[docs] def add(self, store_key, *args, **kwargs): - """ - Add new ticker subscriber. - - Args: - store_key (str): Unique storage hash. - args (any, optional): Arguments to send to the hook method. - - """ - _, _, _, interval, _, _ = store_key - if not interval: - log_err(_ERROR_ADD_TICKER.format(store_key=store_key)) - return - - if interval not in self.tickers: - self.tickers[interval] = self.ticker_class(interval) - self.tickers[interval].add(store_key, *args, **kwargs)
- -
[docs] def remove(self, store_key): - """ - Remove subscription from pool. - - Args: - store_key (str): Unique storage hash to remove - - """ - _, _, _, interval, _, _ = store_key - if interval in self.tickers: - self.tickers[interval].remove(store_key) - if not self.tickers[interval]: - del self.tickers[interval]
- -
[docs] def stop(self, interval=None): - """ - Stop all scripts in pool. This is done at server reload since - restoring the pool will automatically re-populate the pool. - - Args: - interval (int, optional): Only stop tickers with this - interval. - - """ - if interval and interval in self.tickers: - self.tickers[interval].stop() - else: - for ticker in self.tickers.values(): - ticker.stop()
- - -
[docs]class TickerHandler(object): - """ - The Tickerhandler maintains a pool of tasks for subscribing - objects to various tick rates. The pool maintains creation - instructions and and re-applies them at a server restart. - - """ - - ticker_pool_class = TickerPool - -
[docs] def __init__(self, save_name="ticker_storage"): - """ - Initialize handler - - save_name (str, optional): The name of the ServerConfig - instance to store the handler state persistently. - - """ - self.ticker_storage = {} - self.save_name = save_name - self.ticker_pool = self.ticker_pool_class()
- - def _get_callback(self, callback): - """ - Analyze callback and determine its consituents - - Args: - callback (function or method): This is either a stand-alone - function or class method on a typeclassed entitye (that is, - an entity that can be saved to the database). - Returns: - ret (tuple): This is a tuple of the form `(obj, path, callfunc)`, - where `obj` is the database object the callback is defined on - if it's a method (otherwise `None`) and vice-versa, `path` is - the python-path to the stand-alone function (`None` if a method). - The `callfunc` is either the name of the method to call or the - callable function object itself. - Raises: - TypeError: If the callback is of an unsupported type. - - """ - outobj, outpath, outcallfunc = None, None, None - if callable(callback): - if inspect.ismethod(callback): - outobj = callback.__self__ - outcallfunc = callback.__func__.__name__ - elif inspect.isfunction(callback): - outpath = "%s.%s" % (callback.__module__, callback.__name__) - outcallfunc = callback - else: - raise TypeError(f"{callback} is not a method or function.") - else: - raise TypeError(f"{callback} is not a callable function or method.") - - if outobj and not inherits_from(outobj, "evennia.typeclasses.models.TypedObject"): - raise TypeError( - f"{callback} is a method on a normal object - it must " - "be either a method on a typeclass, or a stand-alone function." - ) - - return outobj, outpath, outcallfunc - - def _store_key(self, obj, path, interval, callfunc, idstring="", persistent=True): - """ - Tries to create a store_key for the object. - - Args: - obj (Object, tuple or None): Subscribing object if any. If a tuple, this is - a packed_obj tuple from dbserialize. - path (str or None): Python-path to callable, if any. - interval (int): Ticker interval. Floats will be converted to - nearest lower integer value. - callfunc (callable or str): This is either the callable function or - the name of the method to call. Note that the callable is never - stored in the key; that is uniquely identified with the python-path. - idstring (str, optional): Additional separator between - different subscription types. - persistent (bool, optional): If this ticker should survive a system - shutdown or not. - - Returns: - store_key (tuple): A tuple `(packed_obj, methodname, outpath, interval, - idstring, persistent)` that uniquely identifies the - ticker. Here, `packed_obj` is the unique string representation of the - object or `None`. The `methodname` is the string name of the method on - `packed_obj` to call, or `None` if `packed_obj` is unset. `path` is - the Python-path to a non-method callable, or `None`. Finally, `interval` - `idstring` and `persistent` are integers, strings and bools respectively. - - """ - if interval < 1: - raise RuntimeError(_ERROR_ADD_TICKER_SUB_SECOND) - - interval = int(interval) - persistent = bool(persistent) - packed_obj = pack_dbobj(obj) - methodname = callfunc if callfunc and isinstance(callfunc, str) else None - outpath = path if path and isinstance(path, str) else None - return (packed_obj, methodname, outpath, interval, idstring, persistent) - -
[docs] def save(self): - """ - Save ticker_storage as a serialized string into a temporary - ServerConf field. Whereas saving is done on the fly, if called - by server when it shuts down, the current timer of each ticker - will be saved so it can start over from that point. - - """ - if self.ticker_storage: - # get the current times so the tickers can be restarted with a delay later - start_delays = dict( - (interval, ticker.task.next_call_time()) - for interval, ticker in self.ticker_pool.tickers.items() - ) - - # remove any subscriptions that lost its object in the interim - to_save = { - store_key: (args, kwargs) - for store_key, (args, kwargs) in self.ticker_storage.items() - if ( - ( - store_key[1] - and ("_obj" in kwargs and kwargs["_obj"].pk) - and hasattr(kwargs["_obj"], store_key[1]) - ) - or store_key[2] # a valid method with existing obj - ) - } # a path given - - # update the timers for the tickers - for store_key, (args, kwargs) in to_save.items(): - interval = store_key[1] - # this is a mutable, so it's updated in-place in ticker_storage - kwargs["_start_delay"] = start_delays.get(interval, None) - ServerConfig.objects.conf(key=self.save_name, value=dbserialize(to_save)) - else: - # make sure we have nothing lingering in the database - ServerConfig.objects.conf(key=self.save_name, delete=True)
- -
[docs] def restore(self, server_reload=True): - """ - Restore ticker_storage from database and re-initialize the - handler from storage. This is triggered by the server at - restart. - - Args: - server_reload (bool, optional): If this is False, it means - the server went through a cold reboot and all - non-persistent tickers must be killed. - - """ - # load stored command instructions and use them to re-initialize handler - restored_tickers = ServerConfig.objects.conf(key=self.save_name) - if restored_tickers: - # the dbunserialize will convert all serialized dbobjs to real objects - - restored_tickers = dbunserialize(restored_tickers) - self.ticker_storage = {} - for store_key, (args, kwargs) in restored_tickers.items(): - try: - # at this point obj is the actual object (or None) due to how - # the dbunserialize works - obj, callfunc, path, interval, idstring, persistent = store_key - if not persistent and not server_reload: - # this ticker will not be restarted - continue - if isinstance(callfunc, str) and not obj: - # methods must have an existing object - continue - # we must rebuild the store_key here since obj must not be - # stored as the object itself for the store_key to be hashable. - store_key = self._store_key(obj, path, interval, callfunc, idstring, persistent) - - if obj and callfunc: - kwargs["_callback"] = callfunc - kwargs["_obj"] = obj - elif path: - modname, varname = path.rsplit(".", 1) - callback = variable_from_module(modname, varname) - kwargs["_callback"] = callback - kwargs["_obj"] = None - else: - # Neither object nor path - discard this ticker - log_err("Tickerhandler: Removing malformed ticker: %s" % str(store_key)) - continue - except Exception: - # this suggests a malformed save or missing objects - log_trace("Tickerhandler: Removing malformed ticker: %s" % str(store_key)) - continue - # if we get here we should create a new ticker - self.ticker_storage[store_key] = (args, kwargs) - self.ticker_pool.add(store_key, *args, **kwargs)
- -
[docs] def add(self, interval=60, callback=None, idstring="", persistent=True, *args, **kwargs): - """ - Add subscription to tickerhandler - - Args: - interval (int, optional): Interval in seconds between calling - `callable(*args, **kwargs)` - callable (callable function or method, optional): This - should either be a stand-alone function or a method on a - typeclassed entity (that is, one that can be saved to the - database). - idstring (str, optional): Identifier for separating - this ticker-subscription from others with the same - interval. Allows for managing multiple calls with - the same time interval and callback. - persistent (bool, optional): A ticker will always survive - a server reload. If this is unset, the ticker will be - deleted by a server shutdown. - args, kwargs (optional): These will be passed into the - callback every time it is called. This must be data possible - to pickle! - - Returns: - store_key (tuple): The immutable store-key for this ticker. This can - be stored and passed into `.remove(store_key=store_key)` later to - easily stop this ticker later. - - Notes: - The callback will be identified by type and stored either as - as combination of serialized database object + methodname or - as a python-path to the module + funcname. These strings will - be combined iwth `interval` and `idstring` to define a - unique storage key for saving. These must thus all be supplied - when wanting to modify/remove the ticker later. - - """ - obj, path, callfunc = self._get_callback(callback) - store_key = self._store_key(obj, path, interval, callfunc, idstring, persistent) - kwargs["_obj"] = obj - kwargs["_callback"] = callfunc # either method-name or callable - self.ticker_storage[store_key] = (args, kwargs) - self.ticker_pool.add(store_key, *args, **kwargs) - self.save() - return store_key
- -
[docs] def remove(self, interval=60, callback=None, idstring="", persistent=True, store_key=None): - """ - Remove ticker subscription from handler. - - Args: - interval (int, optional): Interval of ticker to remove. - callback (callable function or method): Either a function or - the method of a typeclassed object. - idstring (str, optional): Identifier id of ticker to remove. - persistent (bool, optional): Whether this ticker is persistent or not. - store_key (str, optional): If given, all other kwargs are ignored and only - this is used to identify the ticker. - - Raises: - KeyError: If no matching ticker was found to remove. - - Notes: - The store-key is normally built from the interval/callback/idstring/persistent values; - but if the `store_key` is explicitly given, this is used instead. - - """ - if isinstance(callback, int): - raise RuntimeError( - "TICKER_HANDLER.remove has changed: " - "the interval is now the first argument, callback the second." - ) - if not store_key: - obj, path, callfunc = self._get_callback(callback) - store_key = self._store_key(obj, path, interval, callfunc, idstring, persistent) - to_remove = self.ticker_storage.pop(store_key, None) - if to_remove: - self.ticker_pool.remove(store_key) - self.save() - else: - raise KeyError(f"No Ticker was found matching the store-key {store_key}.")
- -
[docs] def clear(self, interval=None): - """ - Stop/remove tickers from handler. - - Args: - interval (int): Only stop tickers with this interval. - - Notes: - This is the only supported way to kill tickers related to - non-db objects. - - """ - self.ticker_pool.stop(interval) - if interval: - self.ticker_storage = dict( - (store_key, store_key) - for store_key in self.ticker_storage - if store_key[1] != interval - ) - else: - self.ticker_storage = {} - self.save()
- -
[docs] def all(self, interval=None): - """ - Get all subscriptions. - - Args: - interval (int): Limit match to tickers with this interval. - - Returns: - tickers (list): If `interval` was given, this is a list of - tickers using that interval. - tickerpool_layout (dict): If `interval` was *not* given, - this is a dict {interval1: [ticker1, ticker2, ...], ...} - - """ - if interval is None: - # return dict of all, ordered by interval - return dict( - (interval, ticker.subscriptions) - for interval, ticker in self.ticker_pool.tickers.items() - ) - else: - # get individual interval - ticker = self.ticker_pool.tickers.get(interval, None) - if ticker: - return {interval: ticker.subscriptions} - return None
- -
[docs] def all_display(self): - """ - Get all tickers on an easily displayable form. - - Returns: - tickers (dict): A list of all storekeys - - """ - store_keys = [] - for ticker in self.ticker_pool.tickers.values(): - for ( - (objtup, callfunc, path, interval, idstring, persistent), - (args, kwargs), - ) in ticker.subscriptions.items(): - store_keys.append( - (kwargs.get("_obj", None), callfunc, path, interval, idstring, persistent) - ) - return store_keys
- - -# main tickerhandler -TICKER_HANDLER = TickerHandler() -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/amp_client.html b/docs/0.9.5/_modules/evennia/server/amp_client.html deleted file mode 100644 index 51994d4203..0000000000 --- a/docs/0.9.5/_modules/evennia/server/amp_client.html +++ /dev/null @@ -1,357 +0,0 @@ - - - - - - - - evennia.server.amp_client — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.amp_client

-"""
-The Evennia Server service acts as an AMP-client when talking to the
-Portal. This module sets up the Client-side communication.
-
-"""
-
-import os
-from django.conf import settings
-from evennia.server.portal import amp
-from twisted.internet import protocol
-from evennia.utils import logger
-from evennia.utils.utils import class_from_module
-
-
-
[docs]class AMPClientFactory(protocol.ReconnectingClientFactory): - """ - This factory creates an instance of an AMP client connection. This handles communication from - the be the Evennia 'Server' service to the 'Portal'. The client will try to auto-reconnect on a - connection error. - - """ - - # Initial reconnect delay in seconds. - initialDelay = 1 - factor = 1.5 - maxDelay = 1 - noisy = False - -
[docs] def __init__(self, server): - """ - Initializes the client factory. - - Args: - server (server): server instance. - - """ - self.server = server - self.protocol = class_from_module(settings.AMP_CLIENT_PROTOCOL_CLASS) - self.maxDelay = 10 - # not really used unless connecting to multiple servers, but - # avoids having to check for its existence on the protocol - self.broadcasts = []
- -
[docs] def startedConnecting(self, connector): - """ - Called when starting to try to connect to the Portal AMP server. - - Args: - connector (Connector): Twisted Connector instance representing - this connection. - - """ - pass
- -
[docs] def buildProtocol(self, addr): - """ - Creates an AMPProtocol instance when connecting to the AMP server. - - Args: - addr (str): Connection address. Not used. - - """ - self.resetDelay() - self.server.amp_protocol = AMPServerClientProtocol() - self.server.amp_protocol.factory = self - return self.server.amp_protocol
- -
[docs] def clientConnectionLost(self, connector, reason): - """ - Called when the AMP connection to the MUD server is lost. - - Args: - connector (Connector): Twisted Connector instance representing - this connection. - reason (str): Eventual text describing why connection was lost. - - """ - logger.log_info("Server disconnected from the portal.") - protocol.ReconnectingClientFactory.clientConnectionLost(self, connector, reason)
- -
[docs] def clientConnectionFailed(self, connector, reason): - """ - Called when an AMP connection attempt to the MUD server fails. - - Args: - connector (Connector): Twisted Connector instance representing - this connection. - reason (str): Eventual text describing why connection failed. - - """ - logger.log_msg("Attempting to reconnect to Portal ...") - protocol.ReconnectingClientFactory.clientConnectionFailed(self, connector, reason)
- - -
[docs]class AMPServerClientProtocol(amp.AMPMultiConnectionProtocol): - """ - This protocol describes the Server service (acting as an AMP-client)'s communication with the - Portal (which acts as the AMP-server) - - """ - - # sending AMP data - -
[docs] def connectionMade(self): - """ - Called when a new connection is established. - - """ - # print("AMPClient new connection {}".format(self)) - info_dict = self.factory.server.get_info_dict() - super(AMPServerClientProtocol, self).connectionMade() - # first thing we do is to request the Portal to sync all sessions - # back with the Server side. We also need the startup mode (reload, reset, shutdown) - self.send_AdminServer2Portal( - amp.DUMMYSESSION, operation=amp.PSYNC, spid=os.getpid(), info_dict=info_dict - ) - # run the intial setup if needed - self.factory.server.run_initial_setup()
- -
[docs] def data_to_portal(self, command, sessid, **kwargs): - """ - Send data across the wire to the Portal - - Args: - command (AMP Command): A protocol send command. - sessid (int): A unique Session id. - kwargs (any): Any data to pickle into the command. - - Returns: - deferred (deferred or None): A deferred with an errback. - - Notes: - Data will be sent across the wire pickled as a tuple - (sessid, kwargs). - - """ - # print("server data_to_portal: {}, {}, {}".format(command, sessid, kwargs)) - return self.callRemote(command, packed_data=amp.dumps((sessid, kwargs))).addErrback( - self.errback, command.key - )
- -
[docs] def send_MsgServer2Portal(self, session, **kwargs): - """ - Access method - executed on the Server for sending data - to Portal. - - Args: - session (Session): Unique Session. - kwargs (any, optiona): Extra data. - - """ - return self.data_to_portal(amp.MsgServer2Portal, session.sessid, **kwargs)
- -
[docs] def send_AdminServer2Portal(self, session, operation="", **kwargs): - """ - Administrative access method called by the Server to send an - instruction to the Portal. - - Args: - session (Session): Session. - operation (char, optional): Identifier for the server - operation, as defined by the global variables in - `evennia/server/amp.py`. - kwargs (dict, optional): Data going into the adminstrative. - - """ - return self.data_to_portal( - amp.AdminServer2Portal, session.sessid, operation=operation, **kwargs - )
- - # receiving AMP data - -
[docs] @amp.MsgStatus.responder - def server_receive_status(self, question): - return {"status": "OK"}
- - @amp.MsgPortal2Server.responder - @amp.catch_traceback - def server_receive_msgportal2server(self, packed_data): - """ - Receives message arriving to server. This method is executed - on the Server. - - Args: - packed_data (str): Data to receive (a pickled tuple (sessid,kwargs)) - - """ - sessid, kwargs = self.data_in(packed_data) - session = self.factory.server.sessions.get(sessid, None) - if session: - self.factory.server.sessions.data_in(session, **kwargs) - return {} - - @amp.AdminPortal2Server.responder - @amp.catch_traceback - def server_receive_adminportal2server(self, packed_data): - """ - Receives admin data from the Portal (allows the portal to - perform admin operations on the server). This is executed on - the Server. - - Args: - packed_data (str): Incoming, pickled data. - - """ - sessid, kwargs = self.data_in(packed_data) - operation = kwargs.pop("operation", "") - server_sessionhandler = self.factory.server.sessions - - if operation == amp.PCONN: # portal_session_connect - # create a new session and sync it - server_sessionhandler.portal_connect(kwargs.get("sessiondata")) - - elif operation == amp.PCONNSYNC: # portal_session_sync - server_sessionhandler.portal_session_sync(kwargs.get("sessiondata")) - - elif operation == amp.PDISCONN: # portal_session_disconnect - # session closed from portal sid - session = server_sessionhandler.get(sessid) - if session: - server_sessionhandler.portal_disconnect(session) - - elif operation == amp.PDISCONNALL: # portal_disconnect_all - # portal orders all sessions to close - server_sessionhandler.portal_disconnect_all() - - elif operation == amp.PSYNC: # portal_session_sync - # force a resync of sessions from the portal side. This happens on - # first server-connect. - server_restart_mode = kwargs.get("server_restart_mode", "shutdown") - self.factory.server.run_init_hooks(server_restart_mode) - server_sessionhandler.portal_sessions_sync(kwargs.get("sessiondata")) - server_sessionhandler.portal_start_time = kwargs.get("portal_start_time") - - elif operation == amp.SRELOAD: # server reload - # shut down in reload mode - server_sessionhandler.all_sessions_portal_sync() - server_sessionhandler.server.shutdown(mode="reload") - - elif operation == amp.SRESET: - # shut down in reset mode - server_sessionhandler.all_sessions_portal_sync() - server_sessionhandler.server.shutdown(mode="reset") - - elif operation == amp.SSHUTD: # server shutdown - # shutdown in stop mode - server_sessionhandler.server.shutdown(mode="shutdown") - - else: - raise Exception("operation %(op)s not recognized." % {"op": operation}) - - return {}
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/connection_wizard.html b/docs/0.9.5/_modules/evennia/server/connection_wizard.html deleted file mode 100644 index 7240c4c96a..0000000000 --- a/docs/0.9.5/_modules/evennia/server/connection_wizard.html +++ /dev/null @@ -1,626 +0,0 @@ - - - - - - - - evennia.server.connection_wizard — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.connection_wizard

-"""
-Link Evennia to external resources (wizard plugin for evennia_launcher)
-
-"""
-import sys
-from os import path
-import pprint
-from django.conf import settings
-from evennia.utils.utils import list_to_string, mod_import
-
-
-
[docs]class ConnectionWizard(object): -
[docs] def __init__(self): - self.data = {} - self.prev_node = None
- -
[docs] def display(self, text): - "Show text" - print(text)
- -
[docs] def ask_continue(self): - "'Press return to continue'-prompt" - input(" (Press return to continue)")
- -
[docs] def ask_node(self, options, prompt="Enter choice: ", default=None): - """ - Retrieve options and jump to different menu nodes - - Args: - options (dict): Node options on the form {key: (desc, callback), } - prompt (str, optional): Question to ask - default (str, optional): Default value to use if user hits return. - - """ - - opt_txt = "\n".join(f" {key}: {desc}" for key, (desc, _, _) in options.items()) - self.display(opt_txt + "\n") - - while True: - resp = input(prompt).strip() - - if not resp: - if default: - resp = str(default) - - if resp.lower() in options: - # self.display(f" Selected '{resp}'.") - desc, callback, kwargs = options[resp.lower()] - callback(self, **kwargs) - elif resp.lower() in ("quit", "q"): - sys.exit() - elif resp: - # input, but nothing was recognized - self.display(" Choose one of: {}".format(list_to_string(list(options))))
- -
[docs] def ask_yesno(self, prompt, default="yes"): - """ - Ask a yes/no question inline. - - Keyword Args: - prompt (str): The prompt to ask. - default (str): "yes" or "no", used if pressing return. - Returns: - reply (str): Either 'yes' or 'no'. - - """ - prompt = prompt + (" [Y]/N? " if default == "yes" else " Y/[N]? ") - - while True: - resp = input(prompt).lstrip().lower() - if not resp: - resp = default.lower() - if resp in ("yes", "y"): - self.display(" Answered Yes.") - return "yes" - elif resp in ("no", "n"): - self.display(" Answered No.") - return "no" - elif resp.lower() in ("quit", "q"): - sys.exit()
- -
[docs] def ask_choice(self, prompt=" > ", options=None, default=None): - """ - Ask multiple-choice question, get response inline. - - Keyword Args: - prompt (str): Input prompt. - options (list): List of options. Will be indexable by sequence number 1... - default (int): The list index+1 of the default choice, if any - Returns: - reply (str): The answered reply. - - """ - opt_txt = "\n".join(f" {ind + 1}: {desc}" for ind, desc in enumerate(options)) - self.display(opt_txt + "\n") - - while True: - resp = input(prompt).strip() - - if not resp: - if default: - return options[int(default)] - if resp.lower() in ("quit", "q"): - sys.exit() - if resp.isdigit(): - resp = int(resp) - 1 - if 0 <= resp < len(options): - selection = options[resp] - self.display(f" Selected '{selection}'.") - return selection - self.display(" Select one of the given options.")
- -
[docs] def ask_input(self, prompt=" > ", default=None, validator=None): - """ - Get arbitrary input inline. - - Keyword Args: - prompt (str): The display prompt. - default (str): If empty input, use this. - validator (callable): If given, the input will be passed - into this callable. It should return True unless validation - fails (and is expected to echo why if so). - - Returns: - inp (str): The input given, or default. - - """ - while True: - resp = input(prompt).strip() - - if not resp and default: - resp = str(default) - - if resp.lower() in ("q", "quit"): - sys.exit() - - if resp.lower() == "none": - resp = "" - - if validator and not validator(resp): - continue - - ok = input("\n Leave blank? [Y]/N: ") - if ok.lower() in ("n", "no"): - continue - elif ok.lower() in ("q", "quit"): - sys.exit() - return resp - - if validator and not validator(resp): - continue - - self.display(resp) - ok = input("\n Is this correct? [Y]/N: ") - if ok.lower() in ("n", "no"): - continue - elif ok.lower() in ("q", "quit"): - sys.exit() - return resp
- - -
[docs]def node_start(wizard): - text = """ - This wizard helps to attach your Evennia server to external networks. It - will save to a file `server/conf/connection_settings.py` that will be - imported from the bottom of your game settings file. Once generated you can - also modify that file directly. - - Make sure you have at least started the game once before continuing! - - Use `quit` at any time to abort and throw away unsaved changes. - """ - options = { - "1": ( - "Add your game to the Evennia game index (also for closed-dev games)", - node_game_index_start, - {}, - ), - "2": ("MSSP setup (for mud-list crawlers)", node_mssp_start, {}), - # "3": ("Add Grapevine listing", - # node_grapevine_start, {}), - # "4": ("Add IRC link", - # "node_irc_start", {}), - # "5" ("Add RSS feed", - # "node_rss_start", {}), - "s": ("View and (optionally) Save created settings", node_view_and_apply_settings, {}), - "q": ("Quit", lambda *args: sys.exit(), {}), - } - - wizard.display(text) - wizard.ask_node(options)
- - -# Evennia game index - - -
[docs]def node_game_index_start(wizard, **kwargs): - text = """ - The Evennia game index (http://games.evennia.com) lists both active Evennia - games as well as games in various stages of development. - - You can put up your game in the index also if you are not (yet) open for - players. If so, put 'None' for the connection details - you are just telling - us that you are out there, making us excited about your upcoming game! - - Please check the listing online first to see that your exact game name is - not colliding with an existing game-name in the list (be nice!). - """ - - wizard.display(text) - if wizard.ask_yesno("Continue adding/editing an Index entry?") == "yes": - node_game_index_fields(wizard) - else: - node_start(wizard)
- - -
[docs]def node_game_index_fields(wizard, status=None): - - # reset the listing if needed - if not hasattr(wizard, "game_index_listing"): - wizard.game_index_listing = settings.GAME_INDEX_LISTING - - # game status - - status_default = wizard.game_index_listing["game_status"] - text = f""" - What is the status of your game? - - pre-alpha: a game in its very early stages, mostly unfinished or unstarted - - alpha: a working concept, probably lots of bugs and incomplete features - - beta: a working game, but expect bugs and changing features - - launched: a full, working game (that may still be expanded upon and improved later) - - Current value (return to keep): - {status_default} - """ - - options = ["pre-alpha", "alpha", "beta", "launched"] - - wizard.display(text) - wizard.game_index_listing["game_status"] = wizard.ask_choice("Select one: ", options) - - # game name - - name_default = settings.SERVERNAME - text = f""" - Your game's name should usually be the same as `settings.SERVERNAME`, but - you can set it to something else here if you want. - - Current value: - {name_default} - """ - - def name_validator(inp): - tmax = 80 - tlen = len(inp) - if tlen > tmax: - print(f"The name must be shorter than {tmax} characters (was {tlen}).") - wizard.ask_continue() - return False - return True - - wizard.display(text) - wizard.game_index_listing["game_name"] = wizard.ask_input( - default=name_default, validator=name_validator - ) - - # short desc - - sdesc_default = wizard.game_index_listing.get("short_description", None) - - text = f""" - Enter a short description of your game. Make it snappy and interesting! - This should be at most one or two sentences (255 characters) to display by - '{settings.SERVERNAME}' in the main game list. Line breaks will be ignored. - - Current value: - {sdesc_default} - """ - - def sdesc_validator(inp): - tmax = 255 - tlen = len(inp) - if tlen > tmax: - print(f"The short desc must be shorter than {tmax} characters (was {tlen}).") - wizard.ask_continue() - return False - return True - - wizard.display(text) - wizard.game_index_listing["short_description"] = wizard.ask_input( - default=sdesc_default, validator=sdesc_validator - ) - - # long desc - - long_default = wizard.game_index_listing.get("long_description", None) - - text = f""" - Enter a longer, full-length description. This will be shown when clicking - on your game's listing. You can use \\n to create line breaks and may use - Markdown formatting like *bold*, _italic_, [linkname](http://link) etc. - - Current value: - {long_default} - """ - - wizard.display(text) - wizard.game_index_listing["long_description"] = wizard.ask_input(default=long_default) - - # listing contact - - listing_default = wizard.game_index_listing.get("listing_contact", None) - text = f""" - Enter a listing email-contact. This will not be visible in the listing, but - allows us to get in touch with you should there be some listing issue (like - a name collision) or some bug with the listing (us actually using this is - likely to be somewhere between super-rarely and never). - - Current value: - {listing_default} - """ - - def contact_validator(inp): - if not inp or "@" not in inp: - print("This should be an email and cannot be blank.") - wizard.ask_continue() - return False - return True - - wizard.display(text) - wizard.game_index_listing["listing_contact"] = wizard.ask_input( - default=listing_default, validator=contact_validator - ) - - # telnet hostname - - hostname_default = wizard.game_index_listing.get("telnet_hostname", None) - text = f""" - Enter the hostname to which third-party telnet mud clients can connect to - your game. This would be the name of the server your game is hosted on, - like `coolgame.games.com`, or `mygreatgame.se`. - - Write 'None' if you are not offering public telnet connections at this time. - - Current value: - {hostname_default} - """ - - wizard.display(text) - wizard.game_index_listing["telnet_hostname"] = wizard.ask_input(default=hostname_default) - - # telnet port - - port_default = wizard.game_index_listing.get("telnet_port", None) - text = f""" - Enter the main telnet port. The Evennia default is 4000. You can change - this with the TELNET_PORTS server setting. - - Write 'None' if you are not offering public telnet connections at this time. - - Current value: - {port_default} - """ - - wizard.display(text) - wizard.game_index_listing["telnet_port"] = wizard.ask_input(default=port_default) - - # website - - website_default = wizard.game_index_listing.get("game_website", None) - text = f""" - Evennia is its own web server and runs your game's website. Enter the - URL of the website here, like http://yourwebsite.com, here. - - Write 'None' if you are not offering a publicly visible website at this time. - - Current value: - {website_default} - """ - - wizard.display(text) - wizard.game_index_listing["game_website"] = wizard.ask_input(default=website_default) - - # webclient - - webclient_default = wizard.game_index_listing.get("web_client_url", None) - text = f""" - Evennia offers its own native webclient. Normally it will be found from the - game homepage at something like http://yourwebsite.com/webclient. Enter - your specific URL here (when clicking this link you should launch into the - web client) - - Write 'None' if you don't want to list a publicly accessible webclient. - - Current value: - {webclient_default} - """ - - wizard.display(text) - wizard.game_index_listing["web_client_url"] = wizard.ask_input(default=webclient_default) - - if not ( - wizard.game_index_listing.get("web_client_url") - or (wizard.game_index_listing.get("telnet_host")) - ): - wizard.display( - "\nNote: You have not specified any connection options. This means " - "your game \nwill be marked as being in 'closed development' in " - "the index." - ) - - wizard.display("\nDon't forget to inspect and save your changes.") - - node_start(wizard)
- - -# MSSP - - -
[docs]def node_mssp_start(wizard): - - mssp_module = mod_import(settings.MSSP_META_MODULE or "server.conf.mssp") - try: - filename = mssp_module.__file__ - except AttributeError: - filename = "server/conf/mssp.py" - - text = f""" - MSSP (Mud Server Status Protocol) has a vast amount of options so it must - be modified outside this wizard by directly editing its config file here: - - '{filename}' - - MSSP allows traditional online MUD-listing sites/crawlers to continuously - monitor your game and list information about it. Some of this, like active - player-count, Evennia will automatically add for you, whereas most fields - you need to set manually. - - To use MSSP you should generally have a publicly open game that external - players can connect to. You also need to register at a MUD listing site to - tell them to crawl your game. - """ - - wizard.display(text) - wizard.ask_continue() - node_start(wizard)
- - -# Admin - - -def _save_changes(wizard): - """ - Perform the save - """ - - # add import statement to settings file - import_stanza = "from .connection_settings import *" - setting_module = mod_import("server.conf.settings") - with open(setting_module.__file__, "r+") as f: - txt = f.read() # moves pointer to end of file - if import_stanza not in txt: - # add to the end of the file - f.write( - "\n\n" - "try:\n" - " # Created by the `evennia connections` wizard\n" - f" {import_stanza}\n" - "except ImportError:\n" - " pass" - ) - - connect_settings_file = path.join(settings.GAME_DIR, "server", "conf", "connection_settings.py") - with open(connect_settings_file, "w") as f: - f.write( - "# This file is auto-generated by the `evennia connections` wizard.\n" - "# Don't edit manually, your changes will be overwritten.\n\n" - ) - - f.write(wizard.save_output) - wizard.display(f"saving to {connect_settings_file} ...") - - -
[docs]def node_view_and_apply_settings(wizard): - """ - Inspect and save the data gathered in the other nodes - - """ - pp = pprint.PrettyPrinter(indent=4) - saves = False - - # game index - game_index_save_text = "" - game_index_listing = ( - wizard.game_index_listing if hasattr(wizard, "game_index_listing") else None - ) - if not game_index_listing and settings.GAME_INDEX_ENABLED: - game_index_listing = settings.GAME_INDEX_LISTING - if game_index_listing: - game_index_save_text = ( - "GAME_INDEX_ENABLED = True\n" - "GAME_INDEX_LISTING = \\\n" + pp.pformat(game_index_listing) - ) - saves = True - else: - game_index_save_text = "# No Game Index settings found." - - # potentially add other wizards in the future - text = game_index_save_text - - wizard.display(f"Settings to save:\n\n{text}") - - if saves: - if wizard.ask_yesno("\nDo you want to save these settings?") == "yes": - wizard.save_output = text - _save_changes(wizard) - wizard.display("... saved!\nThe changes will apply after you reload your server.") - else: - wizard.display("... cancelled.") - wizard.ask_continue() - node_start(wizard)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/deprecations.html b/docs/0.9.5/_modules/evennia/server/deprecations.html deleted file mode 100644 index fc3c4152fa..0000000000 --- a/docs/0.9.5/_modules/evennia/server/deprecations.html +++ /dev/null @@ -1,268 +0,0 @@ - - - - - - - - evennia.server.deprecations — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.deprecations

-"""
-This module contains historical deprecations that the Evennia launcher
-checks for.
-
-These all print to the terminal.
-"""
-import os
-
-
[docs]def check_errors(settings): - """ - Check for deprecations that are critical errors and should stop - the launcher. - - Args: - settings (Settings): The Django settings file - - Raises: - DeprecationWarning if a critical deprecation is found. - - """ - deprstring = ( - "settings.%s should be renamed to %s. If defaults are used, " - "their path/classname must be updated " - "(see evennia/settings_default.py)." - ) - if hasattr(settings, "CMDSET_DEFAULT"): - raise DeprecationWarning(deprstring % ("CMDSET_DEFAULT", "CMDSET_CHARACTER")) - if hasattr(settings, "CMDSET_OOC"): - raise DeprecationWarning(deprstring % ("CMDSET_OOC", "CMDSET_ACCOUNT")) - if settings.WEBSERVER_ENABLED and not isinstance(settings.WEBSERVER_PORTS[0], tuple): - raise DeprecationWarning( - "settings.WEBSERVER_PORTS must be on the form " "[(proxyport, serverport), ...]" - ) - if hasattr(settings, "BASE_COMM_TYPECLASS"): - raise DeprecationWarning(deprstring % ("BASE_COMM_TYPECLASS", "BASE_CHANNEL_TYPECLASS")) - if hasattr(settings, "COMM_TYPECLASS_PATHS"): - raise DeprecationWarning(deprstring % ("COMM_TYPECLASS_PATHS", "CHANNEL_TYPECLASS_PATHS")) - if hasattr(settings, "CHARACTER_DEFAULT_HOME"): - raise DeprecationWarning( - "settings.CHARACTER_DEFAULT_HOME should be renamed to " - "DEFAULT_HOME. See also settings.START_LOCATION " - "(see evennia/settings_default.py)." - ) - deprstring = ( - "settings.%s is now merged into settings.TYPECLASS_PATHS. " "Update your settings file." - ) - if hasattr(settings, "OBJECT_TYPECLASS_PATHS"): - raise DeprecationWarning(deprstring % "OBJECT_TYPECLASS_PATHS") - if hasattr(settings, "SCRIPT_TYPECLASS_PATHS"): - raise DeprecationWarning(deprstring % "SCRIPT_TYPECLASS_PATHS") - if hasattr(settings, "ACCOUNT_TYPECLASS_PATHS"): - raise DeprecationWarning(deprstring % "ACCOUNT_TYPECLASS_PATHS") - if hasattr(settings, "CHANNEL_TYPECLASS_PATHS"): - raise DeprecationWarning(deprstring % "CHANNEL_TYPECLASS_PATHS") - if hasattr(settings, "SEARCH_MULTIMATCH_SEPARATOR"): - raise DeprecationWarning( - "settings.SEARCH_MULTIMATCH_SEPARATOR was replaced by " - "SEARCH_MULTIMATCH_REGEX and SEARCH_MULTIMATCH_TEMPLATE. " - "Update your settings file (see evennia/settings_default.py " - "for more info)." - ) - depstring = ( - "settings.{} was renamed to {}. Update your settings file (the FuncParser " - "replaces and generalizes that which inlinefuncs used to do).") - if hasattr(settings, "INLINEFUNC_ENABLED"): - raise DeprecationWarning(depstring.format( - "settings.INLINEFUNC_ENABLED", "FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED")) - if hasattr(settings, "INLINEFUNC_STACK_MAXSIZE"): - raise DeprecationWarning(depstring.format( - "settings.INLINEFUNC_STACK_MAXSIZE", "FUNCPARSER_MAX_NESTING")) - if hasattr(settings, "INLINEFUNC_MODULES"): - raise DeprecationWarning(depstring.format( - "settings.INLINEFUNC_MODULES", "FUNCPARSER_OUTGOING_MESSAGES_MODULES")) - if hasattr(settings, "PROTFUNC_MODULES"): - raise DeprecationWarning(depstring.format( - "settings.PROTFUNC_MODULES", "FUNCPARSER_PROTOTYPE_VALUE_MODULES")) - - gametime_deprecation = ( - "The settings TIME_SEC_PER_MIN, TIME_MIN_PER_HOUR," - "TIME_HOUR_PER_DAY, TIME_DAY_PER_WEEK, \n" - "TIME_WEEK_PER_MONTH and TIME_MONTH_PER_YEAR " - "are no longer supported. Remove them from your " - "settings file to continue.\nIf you want to use " - "and manipulate these time units, the tools from utils.gametime " - "are now found in contrib/convert_gametime.py instead." - ) - if any( - hasattr(settings, value) - for value in ( - "TIME_SEC_PER_MIN", - "TIME_MIN_PER_HOUR", - "TIME_HOUR_PER_DAY", - "TIME_DAY_PER_WEEK", - "TIME_WEEK_PER_MONTH", - "TIME_MONTH_PER_YEAR", - ) - ): - raise DeprecationWarning(gametime_deprecation) - - game_directory_deprecation = ( - "The setting GAME_DIRECTORY_LISTING was removed. It must be " - "renamed to GAME_INDEX_LISTING instead." - ) - if hasattr(settings, "GAME_DIRECTORY_LISTING"): - raise DeprecationWarning(game_directory_deprecation) - - chan_connectinfo = settings.CHANNEL_CONNECTINFO - if chan_connectinfo is not None and not isinstance(chan_connectinfo, dict): - raise DeprecationWarning( - "settings.CHANNEL_CONNECTINFO has changed. It " - "must now be either None or a dict " - "specifying the properties of the channel to create." - ) - if hasattr(settings, "CYCLE_LOGFILES"): - raise DeprecationWarning( - "settings.CYCLE_LOGFILES is unused and should be removed. " - "Use PORTAL/SERVER_LOG_DAY_ROTATION and PORTAL/SERVER_LOG_MAX_SIZE " - "to control log cycling." - ) - if hasattr(settings, "CHANNEL_COMMAND_CLASS") or hasattr(settings, "CHANNEL_HANDLER_CLASS"): - raise DeprecationWarning( - "settings.CHANNEL_HANDLER_CLASS and CHANNEL COMMAND_CLASS are " - "unused and should be removed. The ChannelHandler is no more; " - "channels are now handled by aliasing the default 'channel' command.") - - template_overrides_dir = os.path.join(settings.GAME_DIR, "web", "template_overrides") - static_overrides_dir = os.path.join(settings.GAME_DIR, "web", "static_overrides") - if os.path.exists(template_overrides_dir): - raise DeprecationWarning( - f"The template_overrides directory ({template_overrides_dir}) has changed name.\n" - " - Rename your existing `template_overrides` folder to `templates` instead." - ) - if os.path.exists(static_overrides_dir): - raise DeprecationWarning( - f"The static_overrides directory ({static_overrides_dir}) has changed name.\n" - " 1. Delete any existing `web/static` folder and all its contents (this " - "was auto-generated)\n" - " 2. Rename your existing `static_overrides` folder to `static` instead." - )
- - -
[docs]def check_warnings(settings): - """ - Check conditions and deprecations that should produce warnings but which - does not stop launch. - """ - if settings.DEBUG: - print(" [Devel: settings.DEBUG is True. Important to turn off in production.]") - if settings.IN_GAME_ERRORS: - print(" [Devel: settings.IN_GAME_ERRORS is True. Turn off in production.]") - if settings.ALLOWED_HOSTS == ["*"]: - print(" [Devel: settings.ALLOWED_HOSTS set to '*' (all). Limit in production.]") - if settings.SERVER_HOSTNAME == "localhost": - print(" [Devel: settings.SERVER_HOSTNAME is set to 'localhost'. " - "Update to the actual hostname in production.]") - - for dbentry in settings.DATABASES.values(): - if "psycopg" in dbentry.get("ENGINE", ""): - print( - 'Deprecation: postgresql_psycopg2 backend is deprecated". ' - "Switch settings.DATABASES to use " - '"ENGINE": "django.db.backends.postgresql instead"' - )
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/evennia_launcher.html b/docs/0.9.5/_modules/evennia/server/evennia_launcher.html deleted file mode 100644 index 4dc1cca7f8..0000000000 --- a/docs/0.9.5/_modules/evennia/server/evennia_launcher.html +++ /dev/null @@ -1,2459 +0,0 @@ - - - - - - - - evennia.server.evennia_launcher — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.evennia_launcher

-#!/usr/bin/python
-"""
-Evennia launcher program
-
-This is the start point for running Evennia.
-
-Sets the appropriate environmental variables for managing an Evennia game. It will start and connect
-to the Portal, through which the Server is also controlled. This pprogram
-
-Run the script with the -h flag to see usage information.
-
-"""
-
-import os
-import sys
-import re
-import signal
-import shutil
-import importlib
-import pickle
-from distutils.version import LooseVersion
-from argparse import ArgumentParser
-import argparse
-from subprocess import Popen, check_output, call, CalledProcessError, STDOUT
-
-from twisted.protocols import amp
-from twisted.internet import reactor, endpoints
-import django
-from django.core.management import execute_from_command_line
-from django.db.utils import ProgrammingError
-
-# Signal processing
-SIG = signal.SIGINT
-CTRL_C_EVENT = 0  # Windows SIGINT-like signal
-
-# Set up the main python paths to Evennia
-EVENNIA_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-import evennia  # noqa
-
-EVENNIA_LIB = os.path.join(os.path.dirname(os.path.abspath(evennia.__file__)))
-EVENNIA_SERVER = os.path.join(EVENNIA_LIB, "server")
-EVENNIA_TEMPLATE = os.path.join(EVENNIA_LIB, "game_template")
-EVENNIA_PROFILING = os.path.join(EVENNIA_SERVER, "profiling")
-EVENNIA_DUMMYRUNNER = os.path.join(EVENNIA_PROFILING, "dummyrunner.py")
-
-TWISTED_BINARY = "twistd"
-
-# Game directory structure
-SETTINGFILE = "settings.py"
-SERVERDIR = "server"
-CONFDIR = os.path.join(SERVERDIR, "conf")
-SETTINGS_PATH = os.path.join(CONFDIR, SETTINGFILE)
-SETTINGS_DOTPATH = "server.conf.settings"
-CURRENT_DIR = os.getcwd()
-GAMEDIR = CURRENT_DIR
-
-# Operational setup
-
-SERVER_LOGFILE = None
-PORTAL_LOGFILE = None
-HTTP_LOGFILE = None
-
-SERVER_PIDFILE = None
-PORTAL_PIDFILE = None
-
-SERVER_PY_FILE = None
-PORTAL_PY_FILE = None
-
-SPROFILER_LOGFILE = None
-PPROFILER_LOGFILE = None
-
-TEST_MODE = False
-ENFORCED_SETTING = False
-
-REACTOR_RUN = False
-NO_REACTOR_STOP = False
-
-# communication constants
-
-AMP_PORT = None
-AMP_HOST = None
-AMP_INTERFACE = None
-AMP_CONNECTION = None
-
-SRELOAD = chr(14)  # server reloading (have portal start a new server)
-SSTART = chr(15)  # server start
-PSHUTD = chr(16)  # portal (+server) shutdown
-SSHUTD = chr(17)  # server-only shutdown
-PSTATUS = chr(18)  # ping server or portal status
-SRESET = chr(19)  # shutdown server in reset mode
-
-# requirements
-PYTHON_MIN = "3.7"
-TWISTED_MIN = "20.3.0"
-DJANGO_MIN = "3.2.0"
-DJANGO_LT = "4.0"
-
-try:
-    sys.path[1] = EVENNIA_ROOT
-except IndexError:
-    sys.path.append(EVENNIA_ROOT)
-
-# ------------------------------------------------------------
-#
-# Messages
-#
-# ------------------------------------------------------------
-
-CREATED_NEW_GAMEDIR = """
-    Welcome to Evennia!
-    Created a new Evennia game directory '{gamedir}'.
-
-    You can now optionally edit your new settings file
-    at {settings_path}. If you don't, the defaults
-    will work out of the box. When ready to continue, 'cd' to your
-    game directory and run:
-
-       evennia migrate
-
-    This initializes the database. To start the server for the first
-    time, run:
-
-       evennia start
-
-    Make sure to create a superuser when asked for it (the email is optional)
-    You should now be able to connect to your server on 'localhost', port 4000
-    using a telnet/mud client or http://localhost:4001 using your web browser.
-    If things don't work, check the log with `evennia --log`. Also make sure
-    ports are open.
-
-    (Finally, why not run `evennia connections` and make the world aware of
-    your new Evennia project!)
-    """
-
-ERROR_INPUT = """
-    Command
-      {args} {kwargs}
-    raised an error: '{traceback}'.
-"""
-
-ERROR_NO_ALT_GAMEDIR = """
-    The path '{gamedir}' could not be found.
-"""
-
-ERROR_NO_GAMEDIR = """
-    ERROR: No Evennia settings file was found. Evennia looks for the
-    file in your game directory as ./server/conf/settings.py.
-
-    You must run this command from somewhere inside a valid game
-    directory first created with
-
-        evennia --init mygamename
-
-    If you are in a game directory but is missing a settings.py file,
-    it may be because you have git-cloned an existing game directory.
-    The settings.py file is not cloned by git (it's in .gitignore)
-    since it can contain sensitive and/or server-specific information.
-    You can create a new, empty settings file with
-
-        evennia --initsettings
-
-    If cloning the settings file is not a problem you could manually
-    copy over the old settings file or remove its entry in .gitignore
-
-    """
-
-WARNING_MOVING_SUPERUSER = """
-    WARNING: Evennia expects an Account superuser with id=1. No such
-    Account was found. However, another superuser ('{other_key}',
-    id={other_id}) was found in the database. If you just created this
-    superuser and still see this text it is probably due to the
-    database being flushed recently - in this case the database's
-    internal auto-counter might just start from some value higher than
-    one.
-
-    We will fix this by assigning the id 1 to Account '{other_key}'.
-    Please confirm this is acceptable before continuing.
-    """
-
-WARNING_RUNSERVER = """
-    WARNING: There is no need to run the Django development
-    webserver to test out Evennia web features (the web client
-    will in fact not work since the Django test server knows
-    nothing about MUDs).  Instead, just start Evennia with the
-    webserver component active (this is the default).
-    """
-
-ERROR_SETTINGS = """
-    ERROR: There was an error importing Evennia's config file
-    {settingspath}.
-    There is usually one of three reasons for this:
-        1) You are not running this command from your game directory.
-           Change directory to your game directory and try again (or
-           create a new game directory using evennia --init <dirname>)
-        2) The settings file contains a syntax error. If you see a
-           traceback above, review it, resolve the problem and try again.
-        3) Django is not correctly installed. This usually shows as
-           errors mentioning 'DJANGO_SETTINGS_MODULE'. If you run a
-           virtual machine, it might be worth to restart it to see if
-           this resolves the issue.
-    """.format(
-    settingspath=SETTINGS_PATH
-)
-
-ERROR_INITSETTINGS = """
-    ERROR: 'evennia --initsettings' must be called from the root of
-    your game directory, since it tries to (re)create the new
-    settings.py file in a subfolder server/conf/.
-    """
-
-RECREATED_SETTINGS = """
-    (Re)created an empty settings file in server/conf/settings.py.
-
-    Note that if you were using an existing database, the password
-    salt of this new settings file will be different from the old one.
-    This means that any existing accounts may not be able to log in to
-    their accounts with their old passwords.
-    """
-
-ERROR_INITMISSING = """
-    ERROR: 'evennia --initmissing' must be called from the root of
-    your game directory, since it tries to create any missing files
-    in the server/ subfolder.
-    """
-
-RECREATED_MISSING = """
-    (Re)created any missing directories or files.  Evennia should
-    be ready to run now!
-    """
-
-ERROR_DATABASE = """
-    ERROR: Your database does not exist or is not set up correctly.
-    (error was '{traceback}')
-
-    If you think your database should work, make sure you are running your
-    commands from inside your game directory. If this error persists, run
-
-       evennia migrate
-
-    to initialize/update the database according to your settings.
-    """
-
-ERROR_WINDOWS_WIN32API = """
-    ERROR: Unable to import win32api, which Twisted requires to run.
-    You may download it from:
-
-    http://sourceforge.net/projects/pywin32/files/pywin32/
-
-    If you are running in a virtual environment, browse to the
-    location of the latest win32api exe file for your computer and
-    Python version and copy the url to it; then paste it into a call
-    to easy_install:
-
-        easy_install http://<url to win32api exe>
-    """
-
-INFO_WINDOWS_BATFILE = """
-    INFO: Since you are running Windows, a file 'twistd.bat' was
-    created for you. This is a simple batch file that tries to call
-    the twisted executable. Evennia determined this to be:
-
-       {twistd_path}
-
-    If you run into errors at startup you might need to edit
-    twistd.bat to point to the actual location of the Twisted
-    executable (usually called twistd.py) on your machine.
-
-    This procedure is only done once. Run `evennia` again when you
-    are ready to start the server.
-    """
-
-CMDLINE_HELP = """Starts, initializes, manages and operates the Evennia MU* server.
-Most standard django management commands are also accepted."""
-
-
-VERSION_INFO = """
-    Evennia {version}
-    OS: {os}
-    Python: {python}
-    Twisted: {twisted}
-    Django: {django}{about}
-    """
-
-ABOUT_INFO = """
-    Evennia MUD/MUX/MU* development system
-
-    Licence: BSD 3-Clause Licence
-    Web: http://www.evennia.com
-    Chat: https://discord.gg/AJJpcRUhtF
-    Forum: http://www.evennia.com/discussions
-    Maintainer (2006-10): Greg Taylor
-    Maintainer (2010-):   Griatch (griatch AT gmail DOT com)
-
-    Use -h for command line options.
-    """
-
-HELP_ENTRY = """
-    Evennia has two processes, the 'Server' and the 'Portal'.
-    External users connect to the Portal while the Server runs the
-    game/database. Restarting the Server will refresh code but not
-    disconnect users.
-
-    To start a new game, use 'evennia --init mygame'.
-    For more ways to operate and manage Evennia, see 'evennia -h'.
-
-    If you want to add unit tests to your game, see
-        https://github.com/evennia/evennia/wiki/Unit-Testing
-
-    Evennia's manual is found here:
-        https://github.com/evennia/evennia/wiki
-    """
-
-MENU = """
-    +----Evennia Launcher-------------------------------------------+
-    {gameinfo}
-    +--- Common operations -----------------------------------------+
-    |  1) Start                       (also restart stopped Server) |
-    |  2) Reload               (stop/start Server in 'reload' mode) |
-    |  3) Stop                         (shutdown Portal and Server) |
-    |  4) Reboot                            (shutdown then restart) |
-    +--- Other operations ------------------------------------------+
-    |  5) Reset              (stop/start Server in 'shutdown' mode) |
-    |  6) Stop Server only                                          |
-    |  7) Kill Server only            (send kill signal to process) |
-    |  8) Kill Portal + Server                                      |
-    +--- Information -----------------------------------------------+
-    |  9) Tail log files      (quickly see errors - Ctrl-C to exit) |
-    | 10) Status                                                    |
-    | 11) Port info                                                 |
-    +--- Testing ---------------------------------------------------+
-    | 12) Test gamedir             (run gamedir test suite, if any) |
-    | 13) Test Evennia                     (run Evennia test suite) |
-    +---------------------------------------------------------------+
-    |  h) Help               i) About info                q) Abort  |
-    +---------------------------------------------------------------+"""
-
-ERROR_AMP_UNCONFIGURED = """
-    Can't find server info for connecting. Either run this command from
-    the game dir (it will then use the game's settings file) or specify
-    the path to your game's settings file manually with the --settings
-    option.
-    """
-
-ERROR_LOGDIR_MISSING = """
-    ERROR: One or more log-file directory locations could not be
-    found:
-
-    {logfiles}
-
-    This is simple to fix: Just manually create the missing log
-    directory (or directories) and re-launch the server (the log files
-    will be created automatically).
-
-    (Explanation: Evennia creates the log directory automatically when
-    initializing a new game directory. This error usually happens if
-    you used git to clone a pre-created game directory - since log
-    files are in .gitignore they will not be cloned, which leads to
-    the log directory also not being created.)
-    """
-
-ERROR_PYTHON_VERSION = """
-    ERROR: Python {pversion} used. Evennia requires version
-    {python_min} or higher.
-    """
-
-ERROR_TWISTED_VERSION = """
-    ERROR: Twisted {tversion} found. Evennia requires
-    version {twisted_min} or higher.
-    """
-
-ERROR_NOTWISTED = """
-    ERROR: Twisted does not seem to be installed.
-    """
-
-ERROR_DJANGO_MIN = """
-    ERROR: Django {dversion} found. Evennia requires at least version {django_min} (but
-    no higher than {django_lt}).
-
-    If you are using a virtualenv, use the command `pip install --upgrade -e evennia` where
-    `evennia` is the folder to where you cloned the Evennia library. If not
-    in a virtualenv you can install django with for example `pip install --upgrade django`
-    or with `pip install django=={django_min}` to get a specific version.
-
-    It's also a good idea to run `evennia migrate` after this upgrade. Ignore
-    any warnings and don't run `makemigrate` even if told to.
-    """
-
-NOTE_DJANGO_NEW = """
-    NOTE: Django {dversion} found. This is newer than Evennia's
-    recommended version ({django_rec}). It might work, but is new
-    enough to not be fully tested yet. Report any issues.
-    """
-
-ERROR_NODJANGO = """
-    ERROR: Django does not seem to be installed.
-    """
-
-NOTE_KEYBOARDINTERRUPT = """
-    STOP: Caught keyboard interrupt while in interactive mode.
-    """
-
-NOTE_TEST_DEFAULT = """
-    TESTING: Using Evennia's default settings file (evennia.settings_default).
-    (use 'evennia test --settings settings.py .' to run only your custom game tests)
-    """
-
-NOTE_TEST_CUSTOM = """
-    TESTING: Using specified settings file '{settings_dotpath}'.
-
-    OBS: Evennia's full test suite may not pass if the settings are very
-    different from the default (use 'evennia test evennia' to run core tests)
-    """
-
-PROCESS_ERROR = """
-    {component} process error: {traceback}.
-    """
-
-PORTAL_INFO = """{servername} Portal {version}
-    external ports:
-        {telnet}
-        {telnet_ssl}
-        {ssh}
-        {webserver_proxy}
-        {webclient}
-    internal_ports (to Server):
-        {webserver_internal}
-        {amp}
-"""
-
-
-SERVER_INFO = """{servername} Server {version}
-    internal ports (to Portal):
-        {webserver}
-        {amp}
-    {irc_rss}
-    {info}
-    {errors}"""
-
-
-ARG_OPTIONS = """Actions on installed server. One of:
- start       - launch server+portal if not running
- reload      - restart server in 'reload' mode
- stop        - shutdown server+portal
- reboot      - shutdown server+portal, then start again
- reset       - restart server in 'shutdown' mode
- istart      - start server in foreground (until reload)
- ipstart     - start portal in foreground
- sstop       - stop only server
- kill        - send kill signal to portal+server (force)
- skill       - send kill signal only to server
- status      - show server and portal run state
- info        - show server and portal port info
- menu        - show a menu of options
- connections - show connection wizard
-Others, like migrate, test and shell is passed on to Django."""
-
-# ------------------------------------------------------------
-#
-# Private helper functions
-#
-# ------------------------------------------------------------
-
-
-def _is_windows():
-    return os.name == "nt"
-
-
-def _file_names_compact(filepath1, filepath2):
-    "Compact the output of filenames with same base dir"
-    dirname1 = os.path.dirname(filepath1)
-    dirname2 = os.path.dirname(filepath2)
-    if dirname1 == dirname2:
-        name2 = os.path.basename(filepath2)
-        return "{} and {}".format(filepath1, name2)
-    else:
-        return "{} and {}".format(filepath1, filepath2)
-
-
-def _print_info(portal_info_dict, server_info_dict):
-    """
-    Format info dicts from the Portal/Server for display
-
-    """
-    ind = " " * 8
-
-    def _prepare_dict(dct):
-        out = {}
-        for key, value in dct.items():
-            if isinstance(value, list):
-                value = "\n{}".format(ind).join(str(val) for val in value)
-            out[key] = value
-        return out
-
-    def _strip_empty_lines(string):
-        return "\n".join(line for line in string.split("\n") if line.strip())
-
-    pstr, sstr = "", ""
-    if portal_info_dict:
-        pdict = _prepare_dict(portal_info_dict)
-        pstr = _strip_empty_lines(PORTAL_INFO.format(**pdict))
-
-    if server_info_dict:
-        sdict = _prepare_dict(server_info_dict)
-        sstr = _strip_empty_lines(SERVER_INFO.format(**sdict))
-
-    info = pstr + ("\n\n" + sstr if sstr else "")
-    maxwidth = max(len(line) for line in info.split("\n"))
-    top_border = "-" * (maxwidth - 11) + " Evennia " + "---"
-    border = "-" * (maxwidth + 1)
-    print(top_border + "\n" + info + "\n" + border)
-
-
-def _parse_status(response):
-    "Unpack the status information"
-    return pickle.loads(response["status"])
-
-
-def _get_twistd_cmdline(pprofiler, sprofiler):
-    """
-    Compile the command line for starting a Twisted application using the 'twistd' executable.
-
-    """
-    portal_cmd = [TWISTED_BINARY, "--python={}".format(PORTAL_PY_FILE)]
-    server_cmd = [TWISTED_BINARY, "--python={}".format(SERVER_PY_FILE)]
-
-    if os.name != "nt":
-        # PID files only for UNIX
-        portal_cmd.append("--pidfile={}".format(PORTAL_PIDFILE))
-        server_cmd.append("--pidfile={}".format(SERVER_PIDFILE))
-
-    if pprofiler:
-        portal_cmd.extend(
-            ["--savestats", "--profiler=cprofile", "--profile={}".format(PPROFILER_LOGFILE)]
-        )
-    if sprofiler:
-        server_cmd.extend(
-            ["--savestats", "--profiler=cprofile", "--profile={}".format(SPROFILER_LOGFILE)]
-        )
-
-    return portal_cmd, server_cmd
-
-
-def _reactor_stop():
-    if not NO_REACTOR_STOP:
-        reactor.stop()
-
-
-# ------------------------------------------------------------
-#
-#  Protocol Evennia launcher - Portal/Server communication
-#
-# ------------------------------------------------------------
-
-
-
[docs]class MsgStatus(amp.Command): - """ - Ping between AMP services - - """ - - key = "MsgStatus" - arguments = [(b"status", amp.String())] - errors = {Exception: b"EXCEPTION"} - response = [(b"status", amp.String())]
- - -
[docs]class MsgLauncher2Portal(amp.Command): - """ - Message Launcher -> Portal - - """ - - key = "MsgLauncher2Portal" - arguments = [(b"operation", amp.String()), (b"arguments", amp.String())] - errors = {Exception: b"EXCEPTION"} - response = []
- - -
[docs]class AMPLauncherProtocol(amp.AMP): - """ - Defines callbacks to the launcher - - """ - -
[docs] def __init__(self): - self.on_status = []
- -
[docs] def wait_for_status(self, callback): - """ - Register a waiter for a status return. - - """ - self.on_status.append(callback)
- -
[docs] @MsgStatus.responder - def receive_status_from_portal(self, status): - """ - Get a status signal from portal - fire next queued - callback - - """ - try: - callback = self.on_status.pop() - except IndexError: - pass - else: - status = pickle.loads(status) - callback(status) - return {"status": pickle.dumps(b"")}
- - -
[docs]def send_instruction(operation, arguments, callback=None, errback=None): - """ - Send instruction and handle the response. - - """ - global AMP_CONNECTION, REACTOR_RUN - - if None in (AMP_HOST, AMP_PORT, AMP_INTERFACE): - print(ERROR_AMP_UNCONFIGURED) - sys.exit() - - def _callback(result): - if callback: - callback(result) - - def _errback(fail): - if errback: - errback(fail) - - def _on_connect(prot): - """ - This fires with the protocol when connection is established. We - immediately send off the instruction - - """ - global AMP_CONNECTION - AMP_CONNECTION = prot - _send() - - def _on_connect_fail(fail): - "This is called if portal is not reachable." - errback(fail) - - def _send(): - if operation == PSTATUS: - return AMP_CONNECTION.callRemote(MsgStatus, status=b"").addCallbacks( - _callback, _errback - ) - else: - return AMP_CONNECTION.callRemote( - MsgLauncher2Portal, - operation=bytes(operation, "utf-8"), - arguments=pickle.dumps(arguments, pickle.HIGHEST_PROTOCOL), - ).addCallbacks(_callback, _errback) - - if AMP_CONNECTION: - # already connected - send right away - return _send() - else: - # we must connect first, send once connected - point = endpoints.TCP4ClientEndpoint(reactor, AMP_HOST, AMP_PORT) - deferred = endpoints.connectProtocol(point, AMPLauncherProtocol()) - deferred.addCallbacks(_on_connect, _on_connect_fail) - REACTOR_RUN = True - return deferred
- - -
[docs]def query_status(callback=None): - """ - Send status ping to portal - - """ - wmap = {True: "RUNNING", False: "NOT RUNNING"} - - def _callback(response): - if callback: - callback(response) - else: - pstatus, sstatus, ppid, spid, pinfo, sinfo = _parse_status(response) - print( - "Portal: {}{}\nServer: {}{}".format( - wmap[pstatus], - " (pid {})".format(get_pid(PORTAL_PIDFILE, ppid)) if pstatus else "", - wmap[sstatus], - " (pid {})".format(get_pid(SERVER_PIDFILE, spid)) if sstatus else "", - ) - ) - _reactor_stop() - - def _errback(fail): - pstatus, sstatus = False, False - print("Portal: {}\nServer: {}".format(wmap[pstatus], wmap[sstatus])) - _reactor_stop() - - send_instruction(PSTATUS, None, _callback, _errback)
- - -
[docs]def wait_for_status_reply(callback): - """ - Wait for an explicit STATUS signal to be sent back from Evennia. - """ - if AMP_CONNECTION: - AMP_CONNECTION.wait_for_status(callback) - else: - print("No Evennia connection established.")
- - -
[docs]def wait_for_status( - portal_running=True, server_running=True, callback=None, errback=None, rate=0.5, retries=20 -): - """ - Repeat the status ping until the desired state combination is achieved. - - Args: - portal_running (bool or None): Desired portal run-state. If None, any state - is accepted. - server_running (bool or None): Desired server run-state. If None, any state - is accepted. The portal must be running. - callback (callable): Will be called with portal_state, server_state when - condition is fulfilled. - errback (callable): Will be called with portal_state, server_state if the - request is timed out. - rate (float): How often to retry. - retries (int): How many times to retry before timing out and calling `errback`. - """ - - def _callback(response): - prun, srun, _, _, _, _ = _parse_status(response) - if (portal_running is None or prun == portal_running) and ( - server_running is None or srun == server_running - ): - # the correct state was achieved - if callback: - callback(prun, srun) - else: - _reactor_stop() - else: - if retries <= 0: - if errback: - errback(prun, srun) - else: - print("Connection to Evennia timed out. Try again.") - _reactor_stop() - else: - reactor.callLater( - rate, - wait_for_status, - portal_running, - server_running, - callback, - errback, - rate, - retries - 1, - ) - - def _errback(fail): - """ - Portal not running - """ - if not portal_running: - # this is what we want - if callback: - callback(portal_running, server_running) - else: - _reactor_stop() - else: - if retries <= 0: - if errback: - errback(portal_running, server_running) - else: - print("Connection to Evennia timed out. Try again.") - _reactor_stop() - else: - reactor.callLater( - rate, - wait_for_status, - portal_running, - server_running, - callback, - errback, - rate, - retries - 1, - ) - - return send_instruction(PSTATUS, None, _callback, _errback)
- - -# ------------------------------------------------------------ -# -# Operational functions -# -# ------------------------------------------------------------ - - -
[docs]def collectstatic(): - "Run the collectstatic django command" - django.core.management.call_command("collectstatic", interactive=False, verbosity=0)
- - -
[docs]def start_evennia(pprofiler=False, sprofiler=False): - """ - This will start Evennia anew by launching the Evennia Portal (which in turn - will start the Server) - - """ - portal_cmd, server_cmd = _get_twistd_cmdline(pprofiler, sprofiler) - - def _fail(fail): - print(fail) - _reactor_stop() - - def _server_started(response): - print("... Server started.\nEvennia running.") - if response: - _, _, _, _, pinfo, sinfo = response - _print_info(pinfo, sinfo) - _reactor_stop() - - def _portal_started(*args): - print( - "... Portal started.\nServer starting {} ...".format( - "(under cProfile)" if sprofiler else "" - ) - ) - wait_for_status_reply(_server_started) - send_instruction(SSTART, server_cmd) - - def _portal_running(response): - prun, srun, ppid, spid, _, _ = _parse_status(response) - print("Portal is already running as process {pid}. Not restarted.".format(pid=ppid)) - if srun: - print("Server is already running as process {pid}. Not restarted.".format(pid=spid)) - _reactor_stop() - else: - print("Server starting {}...".format("(under cProfile)" if sprofiler else "")) - send_instruction(SSTART, server_cmd, _server_started, _fail) - - def _portal_not_running(fail): - print("Portal starting {}...".format("(under cProfile)" if pprofiler else "")) - try: - if _is_windows(): - # Windows requires special care - create_no_window = 0x08000000 - Popen(portal_cmd, env=getenv(), bufsize=-1, creationflags=create_no_window) - else: - Popen(portal_cmd, env=getenv(), bufsize=-1) - except Exception as e: - print(PROCESS_ERROR.format(component="Portal", traceback=e)) - _reactor_stop() - wait_for_status(True, None, _portal_started) - - collectstatic() - send_instruction(PSTATUS, None, _portal_running, _portal_not_running)
- - -
[docs]def reload_evennia(sprofiler=False, reset=False): - """ - This will instruct the Portal to reboot the Server component. We - do this manually by telling the server to shutdown (in reload mode) - and wait for the portal to report back, at which point we start the - server again. This way we control the process exactly. - - """ - _, server_cmd = _get_twistd_cmdline(False, sprofiler) - - def _server_restarted(*args): - print("... Server re-started.") - _reactor_stop() - - def _server_reloaded(status): - print("... Server {}.".format("reset" if reset else "reloaded")) - _reactor_stop() - - def _server_stopped(status): - wait_for_status_reply(_server_reloaded) - send_instruction(SSTART, server_cmd) - - def _portal_running(response): - _, srun, _, _, _, _ = _parse_status(response) - if srun: - print("Server {}...".format("resetting" if reset else "reloading")) - wait_for_status_reply(_server_stopped) - send_instruction(SRESET if reset else SRELOAD, {}) - else: - print("Server down. Re-starting ...") - wait_for_status_reply(_server_restarted) - send_instruction(SSTART, server_cmd) - - def _portal_not_running(fail): - print("Evennia not running. Starting up ...") - start_evennia() - - collectstatic() - send_instruction(PSTATUS, None, _portal_running, _portal_not_running)
- - -
[docs]def stop_evennia(): - """ - This instructs the Portal to stop the Server and then itself. - - """ - - def _portal_stopped(*args): - print("... Portal stopped.\nEvennia shut down.") - _reactor_stop() - - def _server_stopped(*args): - print("... Server stopped.\nStopping Portal ...") - send_instruction(PSHUTD, {}) - wait_for_status(False, None, _portal_stopped) - - def _portal_running(response): - prun, srun, ppid, spid, _, _ = _parse_status(response) - if srun: - print("Server stopping ...") - send_instruction(SSHUTD, {}) - wait_for_status_reply(_server_stopped) - else: - print("Server already stopped.\nStopping Portal ...") - send_instruction(PSHUTD, {}) - wait_for_status(False, None, _portal_stopped) - - def _portal_not_running(fail): - print("Evennia not running.") - _reactor_stop() - - send_instruction(PSTATUS, None, _portal_running, _portal_not_running)
- - -
[docs]def reboot_evennia(pprofiler=False, sprofiler=False): - """ - This is essentially an evennia stop && evennia start except we make sure - the system has successfully shut down before starting it again. - - If evennia was not running, start it. - - """ - global AMP_CONNECTION - - def _portal_stopped(*args): - print("... Portal stopped. Evennia shut down. Rebooting ...") - global AMP_CONNECTION - AMP_CONNECTION = None - start_evennia(pprofiler, sprofiler) - - def _server_stopped(*args): - print("... Server stopped.\nStopping Portal ...") - send_instruction(PSHUTD, {}) - wait_for_status(False, None, _portal_stopped) - - def _portal_running(response): - prun, srun, ppid, spid, _, _ = _parse_status(response) - if srun: - print("Server stopping ...") - send_instruction(SSHUTD, {}) - wait_for_status_reply(_server_stopped) - else: - print("Server already stopped.\nStopping Portal ...") - send_instruction(PSHUTD, {}) - wait_for_status(False, None, _portal_stopped) - - def _portal_not_running(fail): - print("Evennia not running. Starting up ...") - start_evennia() - - collectstatic() - send_instruction(PSTATUS, None, _portal_running, _portal_not_running)
- - -
[docs]def start_only_server(): - """ - Tell portal to start server (debug) - """ - portal_cmd, server_cmd = _get_twistd_cmdline(False, False) - print("launcher: Sending to portal: SSTART + {}".format(server_cmd)) - collectstatic() - send_instruction(SSTART, server_cmd)
- - -
[docs]def start_server_interactive(): - """ - Start the Server under control of the launcher process (foreground) - - """ - - def _iserver(): - _, server_twistd_cmd = _get_twistd_cmdline(False, False) - server_twistd_cmd.append("--nodaemon") - print("Starting Server in interactive mode (stop with Ctrl-C)...") - try: - Popen(server_twistd_cmd, env=getenv(), stderr=STDOUT).wait() - except KeyboardInterrupt: - print("... Stopped Server with Ctrl-C.") - else: - print("... Server stopped (leaving interactive mode).") - - collectstatic() - stop_server_only(when_stopped=_iserver, interactive=True)
- - -
[docs]def start_portal_interactive(): - """ - Start the Portal under control of the launcher process (foreground) - - Notes: - In a normal start, the launcher waits for the Portal to start, then - tells it to start the Server. Since we can't do this here, we instead - start the Server first and then starts the Portal - the Server will - auto-reconnect to the Portal. To allow the Server to be reloaded, this - relies on a fixed server server-cmdline stored as a fallback on the - portal application in evennia/server/portal/portal.py. - - """ - - def _iportal(fail): - portal_twistd_cmd, server_twistd_cmd = _get_twistd_cmdline(False, False) - portal_twistd_cmd.append("--nodaemon") - - # starting Server first - it will auto-connect once Portal comes up - if _is_windows(): - # Windows requires special care - create_no_window = 0x08000000 - Popen(server_twistd_cmd, env=getenv(), bufsize=-1, creationflags=create_no_window) - else: - Popen(server_twistd_cmd, env=getenv(), bufsize=-1) - - print("Starting Portal in interactive mode (stop with Ctrl-C)...") - try: - Popen(portal_twistd_cmd, env=getenv(), stderr=STDOUT).wait() - except KeyboardInterrupt: - print("... Stopped Portal with Ctrl-C.") - else: - print("... Portal stopped (leaving interactive mode).") - - def _portal_running(response): - print("Evennia must be shut down completely before running Portal in interactive mode.") - _reactor_stop() - - send_instruction(PSTATUS, None, _portal_running, _iportal)
- - -
[docs]def stop_server_only(when_stopped=None, interactive=False): - """ - Only stop the Server-component of Evennia (this is not useful except for debug) - - Args: - when_stopped (callable): This will be called with no arguments when Server has stopped (or - if it had already stopped when this is called). - interactive (bool, optional): Set if this is called as part of the interactive reload - mechanism. - - """ - - def _server_stopped(*args): - if when_stopped: - when_stopped() - else: - print("... Server stopped.") - _reactor_stop() - - def _portal_running(response): - _, srun, _, _, _, _ = _parse_status(response) - if srun: - print("Server stopping ...") - wait_for_status_reply(_server_stopped) - if interactive: - send_instruction(SRELOAD, {}) - else: - send_instruction(SSHUTD, {}) - else: - if when_stopped: - when_stopped() - else: - print("Server is not running.") - _reactor_stop() - - def _portal_not_running(fail): - print("Evennia is not running.") - if interactive: - print("Start Evennia normally first, then use `istart` to switch to interactive mode.") - _reactor_stop() - - send_instruction(PSTATUS, None, _portal_running, _portal_not_running)
- - -
[docs]def query_info(): - """ - Display the info strings from the running Evennia - - """ - - def _got_status(status): - _, _, _, _, pinfo, sinfo = _parse_status(status) - _print_info(pinfo, sinfo) - _reactor_stop() - - def _portal_running(response): - query_status(_got_status) - - def _portal_not_running(fail): - print("Evennia is not running.") - - send_instruction(PSTATUS, None, _portal_running, _portal_not_running)
- - -
[docs]def tail_log_files(filename1, filename2, start_lines1=20, start_lines2=20, rate=1): - """ - Tail two logfiles interactively, combining their output to stdout - - When first starting, this will display the tail of the log files. After - that it will poll the log files repeatedly and display changes. - - Args: - filename1 (str): Path to first log file. - filename2 (str): Path to second log file. - start_lines1 (int): How many lines to show from existing first log. - start_lines2 (int): How many lines to show from existing second log. - rate (int, optional): How often to poll the log file. - - """ - global REACTOR_RUN - - def _file_changed(filename, prev_size): - "Get size of file in bytes, get diff compared with previous size" - try: - new_size = os.path.getsize(filename) - except FileNotFoundError: - return False, 0 - return new_size != prev_size, new_size - - def _get_new_lines(filehandle, old_linecount): - "count lines, get the ones not counted before" - - def _block(filehandle, size=65536): - "File block generator for quick traversal" - while True: - dat = filehandle.read(size) - if not dat: - break - yield dat - - # count number of lines in file - new_linecount = sum(blck.count("\n") for blck in _block(filehandle)) - - if new_linecount < old_linecount: - # this happens if the file was cycled or manually deleted/edited. - print( - " ** Log file {filename} has cycled or been edited. " - "Restarting log. ".format(filename=filehandle.name) - ) - new_linecount = 0 - old_linecount = 0 - - lines_to_get = max(0, new_linecount - old_linecount) - - if not lines_to_get: - return [], old_linecount - - lines_found = [] - buffer_size = 4098 - block_count = -1 - - while len(lines_found) < lines_to_get: - try: - # scan backwards in file, starting from the end - filehandle.seek(block_count * buffer_size, os.SEEK_END) - except IOError: - # file too small for current seek, include entire file - filehandle.seek(0) - lines_found = filehandle.readlines() - break - lines_found = filehandle.readlines() - block_count -= 1 - - # only actually return the new lines - return lines_found[-lines_to_get:], new_linecount - - def _tail_file(filename, file_size, line_count, max_lines=None): - """This will cycle repeatedly, printing new lines""" - - # poll for changes - has_changed, file_size = _file_changed(filename, file_size) - - if has_changed: - try: - with open(filename, "r") as filehandle: - new_lines, line_count = _get_new_lines(filehandle, line_count) - except IOError: - # the log file might not exist yet. Wait a little, then try again ... - pass - else: - if max_lines == 0: - # don't show any lines from old file - new_lines = [] - elif max_lines: - # show some lines from first startup - new_lines = new_lines[-max_lines:] - - # print to stdout without line break (log has its own line feeds) - sys.stdout.write("".join(new_lines)) - sys.stdout.flush() - - # set up the next poll - reactor.callLater(rate, _tail_file, filename, file_size, line_count, max_lines=100) - - reactor.callLater(0, _tail_file, filename1, 0, 0, max_lines=start_lines1) - reactor.callLater(0, _tail_file, filename2, 0, 0, max_lines=start_lines2) - - REACTOR_RUN = True
- - -# ------------------------------------------------------------ -# -# Environment setup -# -# ------------------------------------------------------------ - - -
[docs]def evennia_version(): - """ - Get the Evennia version info from the main package. - - """ - version = "Unknown" - try: - version = evennia.__version__ - except ImportError: - # even if evennia is not found, we should not crash here. - pass - try: - rev = ( - check_output("git rev-parse --short HEAD", shell=True, cwd=EVENNIA_ROOT, stderr=STDOUT) - .strip() - .decode() - ) - version = "%s (rev %s)" % (version, rev) - except (IOError, CalledProcessError, OSError): - # move on if git is not answering - pass - return version
- - -EVENNIA_VERSION = evennia_version() - - -
[docs]def check_main_evennia_dependencies(): - """ - Checks and imports the Evennia dependencies. This must be done - already before the paths are set up. - - Returns: - not_error (bool): True if no dependency error was found. - - """ - error = False - - # Python - pversion = ".".join(str(num) for num in sys.version_info if isinstance(num, int)) - if LooseVersion(pversion) < LooseVersion(PYTHON_MIN): - print(ERROR_PYTHON_VERSION.format(pversion=pversion, python_min=PYTHON_MIN)) - error = True - # Twisted - try: - import twisted - - tversion = twisted.version.short() - if LooseVersion(tversion) < LooseVersion(TWISTED_MIN): - print(ERROR_TWISTED_VERSION.format(tversion=tversion, twisted_min=TWISTED_MIN)) - error = True - except ImportError: - print(ERROR_NOTWISTED) - error = True - # Django - try: - dversion = ".".join(str(num) for num in django.VERSION if isinstance(num, int)) - # only the main version (1.5, not 1.5.4.0) - dversion_main = ".".join(dversion.split(".")[:2]) - if LooseVersion(dversion) < LooseVersion(DJANGO_MIN): - print( - ERROR_DJANGO_MIN.format( - dversion=dversion_main, django_min=DJANGO_MIN, django_lt=DJANGO_LT - ) - ) - error = True - elif LooseVersion(DJANGO_LT) <= LooseVersion(dversion_main): - print(NOTE_DJANGO_NEW.format(dversion=dversion_main, django_rec=DJANGO_LT)) - except ImportError: - print(ERROR_NODJANGO) - error = True - if error: - sys.exit() - - # return True/False if error was reported or not - return not error
- - -
[docs]def set_gamedir(path): - """ - Set GAMEDIR based on path, by figuring out where the setting file - is inside the directory tree. This allows for running the launcher - from elsewhere than the top of the gamedir folder. - - """ - global GAMEDIR - - Ndepth = 10 - settings_path = os.path.join("server", "conf", "settings.py") - os.chdir(GAMEDIR) - for i in range(Ndepth): - gpath = os.getcwd() - if "server" in os.listdir(gpath): - if os.path.isfile(settings_path): - GAMEDIR = gpath - return - os.chdir(os.pardir) - print(ERROR_NO_GAMEDIR) - sys.exit()
- - -
[docs]def create_secret_key(): - """ - Randomly create the secret key for the settings file - - """ - import random - import string - - secret_key = list( - (string.ascii_letters + string.digits + string.punctuation) - .replace("\\", "") - .replace("'", '"') - .replace("{", "_") - .replace("}", "-") - ) - random.shuffle(secret_key) - secret_key = "".join(secret_key[:40]) - return secret_key
- - -
[docs]def create_settings_file(init=True, secret_settings=False): - """ - Uses the template settings file to build a working settings file. - - Args: - init (bool): This is part of the normal evennia --init - operation. If false, this function will copy a fresh - template file in (asking if it already exists). - secret_settings (bool, optional): If False, create settings.py, otherwise - create the secret_settings.py file. - - """ - if secret_settings: - settings_path = os.path.join(GAMEDIR, "server", "conf", "secret_settings.py") - setting_dict = {"secret_key": "'%s'" % create_secret_key()} - else: - settings_path = os.path.join(GAMEDIR, "server", "conf", "settings.py") - setting_dict = { - "settings_default": os.path.join(EVENNIA_LIB, "settings_default.py"), - "servername": '"%s"' % GAMEDIR.rsplit(os.path.sep, 1)[1], - "secret_key": "'%s'" % create_secret_key(), - } - - if not init: - # if not --init mode, settings file may already exist from before - if os.path.exists(settings_path): - inp = input("%s already exists. Do you want to reset it? y/[N]> " % settings_path) - if not inp.lower() == "y": - print("Aborted.") - sys.exit() - else: - print("Reset the settings file.") - - if secret_settings: - default_settings_path = os.path.join( - EVENNIA_TEMPLATE, "server", "conf", "secret_settings.py" - ) - else: - default_settings_path = os.path.join(EVENNIA_TEMPLATE, "server", "conf", "settings.py") - shutil.copy(default_settings_path, settings_path) - - with open(settings_path, "r") as f: - settings_string = f.read() - - settings_string = settings_string.format(**setting_dict) - - with open(settings_path, "w") as f: - f.write(settings_string)
- - -
[docs]def create_game_directory(dirname): - """ - Initialize a new game directory named dirname - at the current path. This means copying the - template directory from evennia's root. - - Args: - dirname (str): The directory name to create. - - """ - global GAMEDIR - GAMEDIR = os.path.abspath(os.path.join(CURRENT_DIR, dirname)) - if os.path.exists(GAMEDIR): - print("Cannot create new Evennia game dir: '%s' already exists." % dirname) - sys.exit() - # copy template directory - shutil.copytree(EVENNIA_TEMPLATE, GAMEDIR) - # rename gitignore to .gitignore - os.rename(os.path.join(GAMEDIR, "gitignore"), os.path.join(GAMEDIR, ".gitignore")) - - # pre-build settings file in the new GAMEDIR - create_settings_file() - create_settings_file(secret_settings=True)
- - -
[docs]def create_superuser(): - """ - Create the superuser account - - """ - print( - "\nCreate a superuser below. The superuser is Account #1, the 'owner' " - "account of the server. Email is optional and can be empty.\n" - ) - from os import environ - - username = environ.get("EVENNIA_SUPERUSER_USERNAME") - email = environ.get("EVENNIA_SUPERUSER_EMAIL") - password = environ.get("EVENNIA_SUPERUSER_PASSWORD") - - if (username is not None) and (password is not None) and len(password) > 0: - from evennia.accounts.models import AccountDB - superuser = AccountDB.objects.create_superuser(username, email, password) - superuser.save() - else: - django.core.management.call_command("createsuperuser", interactive=True)
- - -
[docs]def check_database(always_return=False): - """ - Check so the database exists. - - Args: - always_return (bool, optional): If set, will always return True/False - also on critical errors. No output will be printed. - Returns: - exists (bool): `True` if the database exists, otherwise `False`. - - - """ - # Check so a database exists and is accessible - from django.db import connection - - tables = connection.introspection.get_table_list(connection.cursor()) - if not tables or not isinstance(tables[0], str): # django 1.8+ - tables = [tableinfo.name for tableinfo in tables] - if tables and "accounts_accountdb" in tables: - # database exists and seems set up. Initialize evennia. - evennia._init() - # Try to get Account#1 - from evennia.accounts.models import AccountDB - - try: - AccountDB.objects.get(id=1) - except (django.db.utils.OperationalError, ProgrammingError) as e: - if always_return: - return False - print(ERROR_DATABASE.format(traceback=e)) - sys.exit() - except AccountDB.DoesNotExist: - # no superuser yet. We need to create it. - - other_superuser = AccountDB.objects.filter(is_superuser=True) - if other_superuser: - # Another superuser was found, but not with id=1. This may - # happen if using flush (the auto-id starts at a higher - # value). Wwe copy this superuser into id=1. To do - # this we must deepcopy it, delete it then save the copy - # with the new id. This allows us to avoid the UNIQUE - # constraint on usernames. - other = other_superuser[0] - other_id = other.id - other_key = other.username - print(WARNING_MOVING_SUPERUSER.format(other_key=other_key, other_id=other_id)) - res = "" - while res.upper() != "Y": - # ask for permission - res = eval(input("Continue [Y]/N: ")) - if res.upper() == "N": - sys.exit() - elif not res: - break - # continue with the - from copy import deepcopy - - new = deepcopy(other) - other.delete() - new.id = 1 - new.save() - else: - create_superuser() - check_database(always_return=always_return) - return True
- - -
[docs]def getenv(): - """ - Get current environment and add PYTHONPATH. - - Returns: - env (dict): Environment global dict. - - """ - sep = ";" if _is_windows() else ":" - env = os.environ.copy() - env["PYTHONPATH"] = sep.join(sys.path) - return env
- - -
[docs]def get_pid(pidfile, default=None): - """ - Get the PID (Process ID) by trying to access an PID file. - - Args: - pidfile (str): The path of the pid file. - default (int, optional): What to return if file does not exist. - - Returns: - pid (str): The process id or `default`. - - """ - if os.path.exists(pidfile): - with open(pidfile, "r") as f: - pid = f.read() - return pid - return default
- - -
[docs]def del_pid(pidfile): - """ - The pidfile should normally be removed after a process has - finished, but when sending certain signals they remain, so we need - to clean them manually. - - Args: - pidfile (str): The path of the pid file. - - """ - if os.path.exists(pidfile): - os.remove(pidfile)
- - -
[docs]def kill(pidfile, component="Server", callback=None, errback=None, killsignal=SIG): - """ - Send a kill signal to a process based on PID. A customized - success/error message will be returned. If clean=True, the system - will attempt to manually remove the pid file. On Windows, no arguments - are useful since Windows has no ability to direct signals except to all - children of a console. - - Args: - pidfile (str): The path of the pidfile to get the PID from. This is ignored - on Windows. - component (str, optional): Usually one of 'Server' or 'Portal'. This is - ignored on Windows. - errback (callable, optional): Called if signal failed to send. This - is ignored on Windows. - callback (callable, optional): Called if kill signal was sent successfully. - This is ignored on Windows. - killsignal (int, optional): Signal identifier for signal to send. This is - ignored on Windows. - - """ - if _is_windows(): - # Windows signal sending is very limited. - from win32api import GenerateConsoleCtrlEvent, SetConsoleCtrlHandler - - try: - # Windows can only send a SIGINT-like signal to - # *every* process spawned off the same console, so we must - # avoid killing ourselves here. - SetConsoleCtrlHandler(None, True) - GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0) - except KeyboardInterrupt: - # We must catch and ignore the interrupt sent. - pass - print("Sent kill signal to all spawned processes") - - else: - # Linux/Unix/Mac can send kill signal directly to specific PIDs. - pid = get_pid(pidfile) - if pid: - if _is_windows(): - os.remove(pidfile) - try: - os.kill(int(pid), killsignal) - except OSError: - print( - "{component} ({pid}) cannot be stopped. " - "The PID file '{pidfile}' seems stale. " - "Try removing it manually.".format( - component=component, pid=pid, pidfile=pidfile - ) - ) - return - if callback: - callback() - else: - print("Sent kill signal to {component}.".format(component=component)) - return - if errback: - errback() - else: - print( - "Could not send kill signal - {component} does " - "not appear to be running.".format(component=component) - )
- - -
[docs]def show_version_info(about=False): - """ - Display version info. - - Args: - about (bool): Include ABOUT info as well as version numbers. - - Returns: - version_info (str): A complete version info string. - - """ - import sys - import twisted - - return VERSION_INFO.format( - version=EVENNIA_VERSION, - about=ABOUT_INFO if about else "", - os=os.name, - python=sys.version.split()[0], - twisted=twisted.version.short(), - django=django.get_version(), - )
- - -
[docs]def error_check_python_modules(show_warnings=False): - """ - Import settings modules in settings. This will raise exceptions on - pure python-syntax issues which are hard to catch gracefully with - exceptions in the engine (since they are formatting errors in the - python source files themselves). Best they fail already here - before we get any further. - - Keyword Args: - show_warnings (bool): If non-fatal warning messages should be shown. - - """ - - from django.conf import settings - - def _imp(path, split=True): - "helper method" - mod, fromlist = path, "None" - if split: - mod, fromlist = path.rsplit(".", 1) - __import__(mod, fromlist=[fromlist]) - - # check the historical deprecations - from evennia.server import deprecations - - try: - deprecations.check_errors(settings) - except DeprecationWarning as err: - print(err) - sys.exit() - - if show_warnings: - deprecations.check_warnings(settings) - - # core modules - _imp(settings.COMMAND_PARSER) - _imp(settings.SEARCH_AT_RESULT) - _imp(settings.CONNECTION_SCREEN_MODULE) - # imp(settings.AT_INITIAL_SETUP_HOOK_MODULE, split=False) - for path in settings.LOCK_FUNC_MODULES: - _imp(path, split=False) - - from evennia.commands import cmdsethandler - - if not cmdsethandler.import_cmdset(settings.CMDSET_UNLOGGEDIN, None): - print("Warning: CMDSET_UNLOGGED failed to load!") - if not cmdsethandler.import_cmdset(settings.CMDSET_CHARACTER, None): - print("Warning: CMDSET_CHARACTER failed to load") - if not cmdsethandler.import_cmdset(settings.CMDSET_ACCOUNT, None): - print("Warning: CMDSET_ACCOUNT failed to load") - # typeclasses - _imp(settings.BASE_ACCOUNT_TYPECLASS) - _imp(settings.BASE_OBJECT_TYPECLASS) - _imp(settings.BASE_CHARACTER_TYPECLASS) - _imp(settings.BASE_ROOM_TYPECLASS) - _imp(settings.BASE_EXIT_TYPECLASS) - _imp(settings.BASE_SCRIPT_TYPECLASS)
- - -# ------------------------------------------------------------ -# -# Options -# -# ------------------------------------------------------------ - - -
[docs]def init_game_directory(path, check_db=True, need_gamedir=True): - """ - Try to analyze the given path to find settings.py - this defines - the game directory and also sets PYTHONPATH as well as the django - path. - - Args: - path (str): Path to new game directory, including its name. - check_db (bool, optional): Check if the databae exists. - need_gamedir (bool, optional): set to False if Evennia doesn't require to - be run in a valid game directory. - - """ - # set the GAMEDIR path - if need_gamedir: - set_gamedir(path) - - # Add gamedir to python path - sys.path.insert(0, GAMEDIR) - - if TEST_MODE or not need_gamedir: - if ENFORCED_SETTING: - print(NOTE_TEST_CUSTOM.format(settings_dotpath=SETTINGS_DOTPATH)) - os.environ["DJANGO_SETTINGS_MODULE"] = SETTINGS_DOTPATH - else: - print(NOTE_TEST_DEFAULT) - os.environ["DJANGO_SETTINGS_MODULE"] = "evennia.settings_default" - else: - os.environ["DJANGO_SETTINGS_MODULE"] = SETTINGS_DOTPATH - - # required since django1.7 - django.setup() - - # test existence of the settings module - try: - from django.conf import settings - except Exception as ex: - if not str(ex).startswith("No module named"): - import traceback - - print(traceback.format_exc().strip()) - print(ERROR_SETTINGS) - sys.exit() - - # this will both check the database and initialize the evennia dir. - if check_db: - check_database() - - # if we don't have to check the game directory, return right away - if not need_gamedir: - return - - # set up the Evennia executables and log file locations - global AMP_PORT, AMP_HOST, AMP_INTERFACE - global SERVER_PY_FILE, PORTAL_PY_FILE - global SERVER_LOGFILE, PORTAL_LOGFILE, HTTP_LOGFILE - global SERVER_PIDFILE, PORTAL_PIDFILE - global SPROFILER_LOGFILE, PPROFILER_LOGFILE - global EVENNIA_VERSION - - AMP_PORT = settings.AMP_PORT - AMP_HOST = settings.AMP_HOST - AMP_INTERFACE = settings.AMP_INTERFACE - - SERVER_PY_FILE = os.path.join(EVENNIA_LIB, "server", "server.py") - PORTAL_PY_FILE = os.path.join(EVENNIA_LIB, "server", "portal", "portal.py") - - SERVER_PIDFILE = os.path.join(GAMEDIR, SERVERDIR, "server.pid") - PORTAL_PIDFILE = os.path.join(GAMEDIR, SERVERDIR, "portal.pid") - - SPROFILER_LOGFILE = os.path.join(GAMEDIR, SERVERDIR, "logs", "server.prof") - PPROFILER_LOGFILE = os.path.join(GAMEDIR, SERVERDIR, "logs", "portal.prof") - - SERVER_LOGFILE = settings.SERVER_LOG_FILE - PORTAL_LOGFILE = settings.PORTAL_LOG_FILE - HTTP_LOGFILE = settings.HTTP_LOG_FILE - - # verify existence of log file dir (this can be missing e.g. - # if the game dir itself was cloned since log files are in .gitignore) - logdirs = [ - logfile.rsplit(os.path.sep, 1) for logfile in (SERVER_LOGFILE, PORTAL_LOGFILE, HTTP_LOGFILE) - ] - if not all(os.path.isdir(pathtup[0]) for pathtup in logdirs): - errstr = "\n ".join( - "%s (log file %s)" % (pathtup[0], pathtup[1]) - for pathtup in logdirs - if not os.path.isdir(pathtup[0]) - ) - print(ERROR_LOGDIR_MISSING.format(logfiles=errstr)) - sys.exit() - - if _is_windows(): - # We need to handle Windows twisted separately. We create a - # batchfile in game/server, linking to the actual binary - - global TWISTED_BINARY - # Windows requires us to use the absolute path for the bat file. - server_path = os.path.dirname(os.path.abspath(__file__)) - TWISTED_BINARY = os.path.join(server_path, "twistd.bat") - - # add path so system can find the batfile - sys.path.insert(1, os.path.join(GAMEDIR, SERVERDIR)) - - try: - importlib.import_module("win32api") - except ImportError: - print(ERROR_WINDOWS_WIN32API) - sys.exit() - - batpath = os.path.join(EVENNIA_SERVER, TWISTED_BINARY) - if not os.path.exists(batpath): - # Test for executable twisted batch file. This calls the - # twistd.py executable that is usually not found on the - # path in Windows. It's not enough to locate - # scripts.twistd, what we want is the executable script - # C:\PythonXX/Scripts/twistd.py. Alas we cannot hardcode - # this location since we don't know if user has Python in - # a non-standard location. So we try to figure it out. - twistd = importlib.import_module("twisted.scripts.twistd") - twistd_dir = os.path.dirname(twistd.__file__) - - # note that we hope the twistd package won't change here, since we - # try to get to the executable by relative path. - # Update: In 2016, it seems Twisted 16 has changed the name of - # of its executable from 'twistd.py' to 'twistd.exe'. - twistd_path = os.path.abspath( - os.path.join( - twistd_dir, os.pardir, os.pardir, os.pardir, os.pardir, "scripts", "twistd.exe" - ) - ) - - with open(batpath, "w") as bat_file: - # build a custom bat file for windows - bat_file.write('@"%s" %%*' % twistd_path) - - print(INFO_WINDOWS_BATFILE.format(twistd_path=twistd_path))
- - -
[docs]def run_dummyrunner(number_of_dummies): - """ - Start an instance of the dummyrunner - - Args: - number_of_dummies (int): The number of dummy accounts to start. - - Notes: - The dummy accounts' behavior can be customized by adding a - `dummyrunner_settings.py` config file in the game's conf/ - directory. - - """ - number_of_dummies = str(int(number_of_dummies)) if number_of_dummies else 1 - cmdstr = [sys.executable, EVENNIA_DUMMYRUNNER, "-N", number_of_dummies] - config_file = os.path.join(SETTINGS_PATH, "dummyrunner_settings.py") - if os.path.exists(config_file): - cmdstr.extend(["--config", config_file]) - try: - call(cmdstr, env=getenv()) - except KeyboardInterrupt: - # this signals the dummyrunner to stop cleanly and should - # not lead to a traceback here. - pass
- - -
[docs]def run_connect_wizard(): - """ - Run the linking wizard, for adding new external connections. - - """ - from .connection_wizard import ConnectionWizard, node_start - - wizard = ConnectionWizard() - node_start(wizard)
- - -
[docs]def list_settings(keys): - """ - Display the server settings. We only display the Evennia specific - settings here. The result will be printed to the terminal. - - Args: - keys (str or list): Setting key or keys to inspect. - - """ - from importlib import import_module - from evennia.utils import evtable - - evsettings = import_module(SETTINGS_DOTPATH) - if len(keys) == 1 and keys[0].upper() == "ALL": - # show a list of all keys - # a specific key - table = evtable.EvTable() - confs = [key for key in sorted(evsettings.__dict__) if key.isupper()] - for i in range(0, len(confs), 4): - table.add_row(*confs[i : i + 4]) - else: - # a specific key - table = evtable.EvTable(width=131) - keys = [key.upper() for key in keys] - confs = dict((key, var) for key, var in evsettings.__dict__.items() if key in keys) - for key, val in confs.items(): - table.add_row(key, str(val)) - print(table)
- - -
[docs]def run_custom_commands(option, *args): - """ - Inject a custom option into the evennia launcher command chain. - - Args: - option (str): Incoming option - the first argument after `evennia` on - the command line. - *args: All args will passed to a found callable.__dict__ - - Returns: - bool: If a custom command was found and handled the option. - - Notes: - Provide new commands in settings with - - CUSTOM_EVENNIA_LAUNCHER_COMMANDS = {"mycmd": "path.to.callable", ...} - - The callable will be passed any `*args` given on the command line and is expected to - handle/validate the input correctly. Use like any other evennia command option on - in the terminal/console, for example: - - evennia mycmd foo bar - - """ - from django.conf import settings - import importlib - - try: - # a dict of {option: callable(*args), ...} - custom_commands = settings.EXTRA_LAUNCHER_COMMANDS - except AttributeError: - return False - cmdpath = custom_commands.get(option) - if cmdpath: - modpath, *cmdname = cmdpath.rsplit('.', 1) - if cmdname: - cmdname = cmdname[0] - mod = importlib.import_module(modpath) - command = mod.__dict__.get(cmdname) - if command: - command(*args) - return True - return False
- - -
[docs]def run_menu(): - """ - This launches an interactive menu. - - """ - while True: - # menu loop - gamedir = "/{}".format(os.path.basename(GAMEDIR)) - leninfo = len(gamedir) - line = "|" + " " * (61 - leninfo) + gamedir + " " * 2 + "|" - - print(MENU.format(gameinfo=line)) - inp = input(" option > ") - - # quitting and help - if inp.lower() == "q": - return - elif inp.lower() == "h": - print(HELP_ENTRY) - eval(input("press <return> to continue ...")) - continue - elif inp.lower() in ("v", "i", "a"): - print(show_version_info(about=True)) - eval(input("press <return> to continue ...")) - continue - - # options - try: - inp = int(inp) - except ValueError: - print("Not a valid option.") - continue - if inp == 1: - start_evennia(False, False) - elif inp == 2: - reload_evennia(False, False) - elif inp == 3: - stop_evennia() - elif inp == 4: - reboot_evennia(False, False) - elif inp == 5: - reload_evennia(False, True) - elif inp == 6: - stop_server_only() - elif inp == 7: - if _is_windows(): - print("This option is not supported on Windows.") - else: - kill(SERVER_PIDFILE, "Server") - elif inp == 8: - if _is_windows(): - print("This option is not supported on Windows.") - else: - kill(SERVER_PIDFILE, "Server") - kill(PORTAL_PIDFILE, "Portal") - elif inp == 9: - if not SERVER_LOGFILE: - init_game_directory(CURRENT_DIR, check_db=False) - tail_log_files(PORTAL_LOGFILE, SERVER_LOGFILE, 20, 20) - print( - " Tailing logfiles {} (Ctrl-C to exit) ...".format( - _file_names_compact(SERVER_LOGFILE, PORTAL_LOGFILE) - ) - ) - elif inp == 10: - query_status() - elif inp == 11: - query_info() - elif inp == 12: - print("Running 'evennia --settings settings.py test .' ...") - Popen( - [sys.executable, __file__, "--settings", "settings.py", "test", "."], env=getenv() - ).wait() - elif inp == 13: - print("Running 'evennia test evennia' ...") - Popen([sys.executable, __file__, "test", "evennia"], env=getenv()).wait() - else: - print("Not a valid option.") - continue - return
- - -
[docs]def main(): - """ - Run the evennia launcher main program. - - """ - # set up argument parser - - parser = ArgumentParser(description=CMDLINE_HELP, formatter_class=argparse.RawTextHelpFormatter) - parser.add_argument( - "--gamedir", - nargs=1, - action="store", - dest="altgamedir", - metavar="<path>", - help="location of gamedir (default: current location)", - ) - parser.add_argument( - "--init", - action="store", - dest="init", - metavar="<gamename>", - help="creates a new gamedir 'name' at current location", - ) - parser.add_argument( - "--log", - "-l", - action="store_true", - dest="tail_log", - default=False, - help="tail the portal and server logfiles and print to stdout", - ) - parser.add_argument( - "--list", - nargs="+", - action="store", - dest="listsetting", - metavar="all|<key>", - help=("list settings, use 'all' to list all available keys"), - ) - parser.add_argument( - "--settings", - nargs=1, - action="store", - dest="altsettings", - default=None, - metavar="<path>", - help=( - "start evennia with alternative settings file from\n" - " gamedir/server/conf/. (default is settings.py)" - ), - ) - parser.add_argument( - "--initsettings", - action="store_true", - dest="initsettings", - default=False, - help="create a new, empty settings file as\n gamedir/server/conf/settings.py", - ) - parser.add_argument( - "--initmissing", - action="store_true", - dest="initmissing", - default=False, - help="checks for missing secret_settings or server logs\n directory, and adds them if needed", - ) - parser.add_argument( - "--profiler", - action="store_true", - dest="profiler", - default=False, - help="start given server component under the Python profiler", - ) - parser.add_argument( - "--dummyrunner", - nargs=1, - action="store", - dest="dummyrunner", - metavar="<N>", - help="test a server by connecting <N> dummy accounts to it", - ) - parser.add_argument( - "-v", - "--version", - action="store_true", - dest="show_version", - default=False, - help="show version info", - ) - - parser.add_argument("operation", nargs="?", default="noop", help=ARG_OPTIONS) - parser.epilog = ( - "Common Django-admin commands are shell, dbshell, test and migrate.\n" - "See the Django documentation for more management commands." - ) - - args, unknown_args = parser.parse_known_args() - - # handle arguments - option = args.operation - - # make sure we have everything - check_main_evennia_dependencies() - - if not args: - # show help pane - print(CMDLINE_HELP) - sys.exit() - - if args.altgamedir: - # use alternative gamedir path - global GAMEDIR - altgamedir = args.altgamedir[0] - if not os.path.isdir(altgamedir) and not args.init: - print(ERROR_NO_ALT_GAMEDIR.format(gamedir=altgamedir)) - sys.exit() - GAMEDIR = altgamedir - - if args.init: - # initialization of game directory - create_game_directory(args.init) - print( - CREATED_NEW_GAMEDIR.format( - gamedir=args.init, settings_path=os.path.join(args.init, SETTINGS_PATH) - ) - ) - sys.exit() - - if args.show_version: - # show the version info - print(show_version_info(option == "help")) - sys.exit() - - if args.altsettings: - # use alternative settings file - global SETTINGSFILE, SETTINGS_DOTPATH, ENFORCED_SETTING - sfile = args.altsettings[0] - SETTINGSFILE = sfile - ENFORCED_SETTING = True - SETTINGS_DOTPATH = "server.conf.%s" % sfile.rstrip(".py") - print("Using settings file '%s' (%s)." % (SETTINGSFILE, SETTINGS_DOTPATH)) - - if args.initsettings: - # create new settings file - try: - create_settings_file(init=False) - print(RECREATED_SETTINGS) - except IOError: - print(ERROR_INITSETTINGS) - sys.exit() - - if args.initmissing: - created = False - try: - log_path = os.path.join(SERVERDIR, "logs") - if not os.path.exists(log_path): - os.makedirs(log_path) - print(f" ... Created missing log dir {log_path}.") - created = True - - settings_path = os.path.join(CONFDIR, "secret_settings.py") - if not os.path.exists(settings_path): - create_settings_file(init=False, secret_settings=True) - print(f" ... Created missing secret_settings.py file as {settings_path}.") - created = True - - if created: - print(RECREATED_MISSING) - else: - print(" ... No missing resources to create/init. You are good to go.") - except IOError: - print(ERROR_INITMISSING) - sys.exit() - - if args.tail_log: - # set up for tailing the log files - global NO_REACTOR_STOP - NO_REACTOR_STOP = True - if not SERVER_LOGFILE: - init_game_directory(CURRENT_DIR, check_db=False) - - # adjust how many lines we show from existing logs - start_lines1, start_lines2 = 20, 20 - if option not in ("reload", "reset", "noop"): - start_lines1, start_lines2 = 0, 0 - - tail_log_files(PORTAL_LOGFILE, SERVER_LOGFILE, start_lines1, start_lines2) - print( - " Tailing logfiles {} (Ctrl-C to exit) ...".format( - _file_names_compact(SERVER_LOGFILE, PORTAL_LOGFILE) - ) - ) - if args.dummyrunner: - # launch the dummy runner - init_game_directory(CURRENT_DIR, check_db=True) - run_dummyrunner(args.dummyrunner[0]) - elif args.listsetting: - # display all current server settings - init_game_directory(CURRENT_DIR, check_db=False) - list_settings(args.listsetting) - elif option == "menu": - # launch menu for operation - init_game_directory(CURRENT_DIR, check_db=True) - run_menu() - elif option in ( - "status", - "info", - "start", - "istart", - "ipstart", - "reload", - "restart", - "reboot", - "reset", - "stop", - "sstop", - "kill", - "skill", - "sstart", - "connections", - ): - # operate the server directly - if not SERVER_LOGFILE: - init_game_directory(CURRENT_DIR, check_db=True) - if option == "status": - query_status() - elif option == "info": - query_info() - elif option == "start": - init_game_directory(CURRENT_DIR, check_db=True) - error_check_python_modules(show_warnings=args.tail_log) - start_evennia(args.profiler, args.profiler) - elif option == "istart": - init_game_directory(CURRENT_DIR, check_db=True) - error_check_python_modules(show_warnings=args.tail_log) - start_server_interactive() - elif option == "ipstart": - start_portal_interactive() - elif option in ("reload", "restart"): - reload_evennia(args.profiler) - elif option == "reboot": - reboot_evennia(args.profiler, args.profiler) - elif option == "reset": - reload_evennia(args.profiler, reset=True) - elif option == "stop": - stop_evennia() - elif option == "sstop": - stop_server_only() - elif option == "sstart": - start_only_server() - elif option == "kill": - if _is_windows(): - print("This option is not supported on Windows.") - else: - kill(SERVER_PIDFILE, "Server") - kill(PORTAL_PIDFILE, "Portal") - elif option == "skill": - if _is_windows(): - print("This option is not supported on Windows.") - else: - kill(SERVER_PIDFILE, "Server") - elif option == "connections": - run_connect_wizard() - - elif option != "noop": - # pass-through to django manager, but set things up first - check_db = False - need_gamedir = True - - # handle special django commands - if option in ("runserver", "testserver"): - # we don't want the django test-webserver - print(WARNING_RUNSERVER) - if option in ("makemessages", "compilemessages"): - # some commands don't require the presence of a game directory to work - need_gamedir = False - if option in ("shell", "check", "makemigrations", "createsuperuser", "shell_plus"): - # some django commands requires the database to exist, - # or evennia._init to have run before they work right. - check_db = True - if option == "test": - global TEST_MODE - TEST_MODE = True - - init_game_directory(CURRENT_DIR, check_db=check_db, need_gamedir=need_gamedir) - - if option == "migrate": - # we need to bypass some checks here for the first db creation - if not check_database(always_return=True): - django.core.management.call_command(*([option] + unknown_args)) - sys.exit(0) - - if run_custom_commands(option, *unknown_args): - # run any custom commands - sys.exit() - - # pass on to the core django manager - re-parse the entire input line - # but keep 'evennia' as the name instead of django-admin. This is - # an exit condition. - sys.argv[0] = re.sub(r"(-script\.pyw?|\.exe)?$", "", sys.argv[0]) - sys.exit(execute_from_command_line(sys.argv)) - - elif not args.tail_log: - # no input; print evennia info (don't pring if we're tailing log) - print(ABOUT_INFO) - - if REACTOR_RUN: - reactor.run()
- - -if __name__ == "__main__": - # start Evennia from the command line - main() -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/game_index_client/client.html b/docs/0.9.5/_modules/evennia/server/game_index_client/client.html deleted file mode 100644 index 68b6b781d5..0000000000 --- a/docs/0.9.5/_modules/evennia/server/game_index_client/client.html +++ /dev/null @@ -1,284 +0,0 @@ - - - - - - - - evennia.server.game_index_client.client — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.game_index_client.client

-"""
-The client for sending data to the Evennia Game Index
-
-"""
-import urllib.request, urllib.parse, urllib.error
-import platform
-import warnings
-
-import django
-from django.conf import settings
-from twisted.internet import defer
-from twisted.internet import protocol
-from twisted.internet import reactor
-from twisted.internet.defer import inlineCallbacks
-from twisted.web.client import Agent, _HTTP11ClientFactory, HTTPConnectionPool
-from twisted.web.http_headers import Headers
-from twisted.web.iweb import IBodyProducer
-from zope.interface import implementer
-
-from evennia.accounts.models import AccountDB
-from evennia.server.sessionhandler import SESSIONS
-from evennia.utils import get_evennia_version, logger
-
-_EGI_HOST = "http://evennia-game-index.appspot.com"
-_EGI_REPORT_PATH = "/api/v1/game/check_in"
-
-
-
[docs]class EvenniaGameIndexClient(object): - """ - This client class is used for gathering and sending game details to the - Evennia Game Index. Since EGI is in the early goings, this isn't - incredibly configurable as far as to what is being sent. - """ - -
[docs] def __init__(self, on_bad_request=None): - """ - :param on_bad_request: Optional callable to trigger when a bad request - was sent. This is almost always going to be due to bad config. - """ - self.report_host = _EGI_HOST - self.report_path = _EGI_REPORT_PATH - self.report_url = self.report_host + self.report_path - self.logged_first_connect = False - - self._on_bad_request = on_bad_request - # Oh, the humanity. Silence the factory start/stop messages. - self._conn_pool = HTTPConnectionPool(reactor) - self._conn_pool._factory = QuietHTTP11ClientFactory
- -
[docs] @inlineCallbacks - def send_game_details(self): - """ - This is where the magic happens. Send details about the game to the - Evennia Game Index. - """ - status_code, response_body = yield self._form_and_send_request() - if status_code == 200: - if not self.logged_first_connect: - logger.log_infomsg("Successfully sent game details to Evennia Game Index.") - self.logged_first_connect = True - return - # At this point, either EGD is having issues or the payload we sent - # is improperly formed (probably due to mis-configuration). - logger.log_errmsg( - "Failed to send game details to Evennia Game Index. HTTP " - "status code was %s. Message was: %s" % (status_code, response_body) - ) - - if status_code == 400 and self._on_bad_request: - # Improperly formed request. Defer to the callback as far as what - # to do. Probably not a great idea to continue attempting to send - # to EGD, though. - self._on_bad_request()
- - def _form_and_send_request(self): - """ - Build the request to send to the index. - - """ - agent = Agent(reactor, pool=self._conn_pool) - headers = { - b"User-Agent": [b"Evennia Game Index Client"], - b"Content-Type": [b"application/x-www-form-urlencoded"], - } - egi_config = settings.GAME_INDEX_LISTING - # We are using `or` statements below with dict.get() to avoid sending - # stringified 'None' values to the server. - try: - values = { - # Game listing stuff - "game_name": egi_config.get("game_name", settings.SERVERNAME), - "game_status": egi_config["game_status"], - "game_website": egi_config.get("game_website", ""), - "short_description": egi_config["short_description"], - "long_description": egi_config.get("long_description", ""), - "listing_contact": egi_config["listing_contact"], - # How to play - "telnet_hostname": egi_config.get("telnet_hostname", ""), - "telnet_port": egi_config.get("telnet_port", ""), - "web_client_url": egi_config.get("web_client_url", ""), - # Game stats - "connected_account_count": SESSIONS.account_count(), - "total_account_count": AccountDB.objects.num_total_accounts() or 0, - # System info - "evennia_version": get_evennia_version(), - "python_version": platform.python_version(), - "django_version": django.get_version(), - "server_platform": platform.platform(), - } - except KeyError as err: - raise KeyError(f"Error loading GAME_INDEX_LISTING: {err}") - - data = urllib.parse.urlencode(values) - - d = agent.request( - b"POST", - bytes(self.report_url, "utf-8"), - headers=Headers(headers), - bodyProducer=StringProducer(data), - ) - - d.addCallback(self.handle_egd_response) - return d - -
[docs] def handle_egd_response(self, response): - if 200 <= response.code < 300: - d = defer.succeed((response.code, "OK")) - else: - # Go through the horrifying process of getting the response body - # out of Twisted's plumbing. - d = defer.Deferred() - response.deliverBody(SimpleResponseReceiver(response.code, d)) - return d
- - -
[docs]class SimpleResponseReceiver(protocol.Protocol): - """ - Used for pulling the response body out of an HTTP response. - """ - -
[docs] def __init__(self, status_code, d): - self.status_code = status_code - self.buf = "" - self.d = d
- -
[docs] def dataReceived(self, data): - self.buf += data
- -
[docs] def connectionLost(self, reason=protocol.connectionDone): - self.d.callback((self.status_code, self.buf))
- - -
[docs]@implementer(IBodyProducer) -class StringProducer(object): - """ - Used for feeding a request body to the tx HTTP client. - """ - -
[docs] def __init__(self, body): - self.body = bytes(body, "utf-8") - self.length = len(body)
- -
[docs] def startProducing(self, consumer): - consumer.write(self.body) - return defer.succeed(None)
- -
[docs] def pauseProducing(self): - pass
- -
[docs] def stopProducing(self): - pass
- - -
[docs]class QuietHTTP11ClientFactory(_HTTP11ClientFactory): - """ - Silences the obnoxious factory start/stop messages in the default client. - """ - - noisy = False
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/game_index_client/service.html b/docs/0.9.5/_modules/evennia/server/game_index_client/service.html deleted file mode 100644 index c5af1fbc5e..0000000000 --- a/docs/0.9.5/_modules/evennia/server/game_index_client/service.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - evennia.server.game_index_client.service — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.game_index_client.service

-"""
-Service for integrating the Evennia Game Index client into Evennia.
-
-"""
-from twisted.internet import reactor
-from twisted.internet.task import LoopingCall
-from twisted.application.service import Service
-
-from evennia.utils import logger
-from .client import EvenniaGameIndexClient
-
-# How many seconds to wait before triggering the first EGI check-in.
-_FIRST_UPDATE_DELAY = 10
-# How often to sync to the server
-_CLIENT_UPDATE_RATE = 60 * 30
-
-
-
[docs]class EvenniaGameIndexService(Service): - """ - Twisted Service that contains a LoopingCall for regularly sending game details - to the Evennia Game Index. - - """ - - # We didn't stick the Evennia prefix on here because it'd get marked as - # a core system service. - name = "GameIndexClient" - -
[docs] def __init__(self): - self.client = EvenniaGameIndexClient(on_bad_request=self._die_on_bad_request) - self.loop = LoopingCall(self.client.send_game_details)
- -
[docs] def startService(self): - super().startService() - # Check to make sure that the client is configured. - # Start the loop, but only after a short delay. This allows the - # portal and the server time to sync up as far as total player counts. - # Prevents always reporting a count of 0. - reactor.callLater(_FIRST_UPDATE_DELAY, self.loop.start, _CLIENT_UPDATE_RATE)
- -
[docs] def stopService(self): - if self.running == 0: - # reload errors if we've stopped this service. - return - super().stopService() - if self.loop.running: - self.loop.stop()
- - def _die_on_bad_request(self): - """ - If it becomes apparent that our configuration is generating improperly - formed messages to EGI, we don't want to keep sending bad messages. - Stop the service so we're not wasting resources. - """ - logger.log_infomsg( - "Shutting down Evennia Game Index client service due to " "invalid configuration." - ) - self.stopService()
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/initial_setup.html b/docs/0.9.5/_modules/evennia/server/initial_setup.html deleted file mode 100644 index 5d5c49c5a4..0000000000 --- a/docs/0.9.5/_modules/evennia/server/initial_setup.html +++ /dev/null @@ -1,328 +0,0 @@ - - - - - - - - evennia.server.initial_setup — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.initial_setup

-"""
-This module handles initial database propagation, which is only run the first time the game starts.
-It will create some default objects (notably give #1 its evennia-specific properties, and create the
-Limbo room). It will also hooks, and then perform an initial restart.
-
-Everything starts at handle_setup()
-"""
-
-
-import time
-from django.conf import settings
-from django.utils.translation import gettext as _
-from evennia.accounts.models import AccountDB
-from evennia.server.models import ServerConfig
-from evennia.utils import create, logger
-
-
-ERROR_NO_SUPERUSER = """
-    No superuser exists yet. The superuser is the 'owner' account on
-    the Evennia server. Create a new superuser using the command
-
-       evennia createsuperuser
-
-    Follow the prompts, then restart the server.
-    """
-
-
-LIMBO_DESC = _("""
-Welcome to your new |wEvennia|n-based game! Visit https://www.evennia.com if you need
-help, want to contribute, report issues or just join the community.
-As Account #1 you can create a demo/tutorial area with '|wbatchcommand tutorial_world.build|n'.
-""")
-
-
-WARNING_POSTGRESQL_FIX = """
-    PostgreSQL-psycopg2 compatibility fix:
-    The in-game channels {chan1}, {chan2} and {chan3} were created,
-    but the superuser was not yet connected to them. Please use in
-    game commands to connect Account #1 to those channels when first
-    logging in.
-"""
-
-
-def _get_superuser_account():
-    """
-    Get the superuser (created at the command line) and don't take no for an answer.
-
-    Returns:
-        Account: The first superuser (User #1).
-
-    Raises:
-        AccountDB.DoesNotExist: If the superuser couldn't be found.
-
-    """
-    try:
-        superuser = AccountDB.objects.get(id=1)
-    except AccountDB.DoesNotExist:
-        raise AccountDB.DoesNotExist(ERROR_NO_SUPERUSER)
-    return superuser
-
-
-
[docs]def create_objects(): - """ - Creates the #1 account and Limbo room. - - """ - - logger.log_info("Initial setup: Creating objects (Account #1 and Limbo room) ...") - - # Set the initial User's account object's username on the #1 object. - # This object is pure django and only holds name, email and password. - superuser = _get_superuser_account() - from evennia.objects.models import ObjectDB - - # Create an Account 'user profile' object to hold eventual - # mud-specific settings for the AccountDB object. - account_typeclass = settings.BASE_ACCOUNT_TYPECLASS - - # run all creation hooks on superuser (we must do so manually - # since the manage.py command does not) - superuser.swap_typeclass(account_typeclass, clean_attributes=True) - superuser.basetype_setup() - superuser.at_account_creation() - superuser.locks.add( - "examine:perm(Developer);edit:false();delete:false();boot:false();msg:all()" - ) - # this is necessary for quelling to work correctly. - superuser.permissions.add("Developer") - - # Limbo is the default "nowhere" starting room - - # Create the in-game god-character for account #1 and set - # it to exist in Limbo. - character_typeclass = settings.BASE_CHARACTER_TYPECLASS - try: - superuser_character = ObjectDB.objects.get(id=1) - except ObjectDB.DoesNotExist: - superuser_character = create.create_object( - character_typeclass, key=superuser.username, nohome=True) - - superuser_character.db_typeclass_path = character_typeclass - superuser_character.db.desc = _("This is User #1.") - superuser_character.locks.add( - "examine:perm(Developer);edit:false();delete:false();boot:false();msg:all();puppet:false()" - ) - # we set this low so that quelling is more useful - superuser_character.permissions.add("Player") - superuser_character.save() - - superuser.attributes.add("_first_login", True) - superuser.attributes.add("_last_puppet", superuser_character) - - try: - superuser.db._playable_characters.append(superuser_character) - except AttributeError: - superuser.db_playable_characters = [superuser_character] - - room_typeclass = settings.BASE_ROOM_TYPECLASS - try: - limbo_obj = ObjectDB.objects.get(id=2) - except ObjectDB.DoesNotExist: - limbo_obj = create.create_object(room_typeclass, _("Limbo"), nohome=True) - - limbo_obj.db_typeclass_path = room_typeclass - limbo_obj.db.desc = LIMBO_DESC.strip() - limbo_obj.save() - - # Now that Limbo exists, try to set the user up in Limbo (unless - # the creation hooks already fixed this). - if not superuser_character.location: - superuser_character.location = limbo_obj - if not superuser_character.home: - superuser_character.home = limbo_obj
- -
[docs]def at_initial_setup(): - """ - Custom hook for users to overload some or all parts of the initial - setup. Called very last in the sequence. It tries to import and - srun a module settings.AT_INITIAL_SETUP_HOOK_MODULE and will fail - silently if this does not exist or fails to load. - - """ - modname = settings.AT_INITIAL_SETUP_HOOK_MODULE - if not modname: - return - try: - mod = __import__(modname, fromlist=[None]) - except (ImportError, ValueError): - return - logger.log_info("Initial setup: Running at_initial_setup() hook.") - if mod.__dict__.get("at_initial_setup", None): - mod.at_initial_setup()
- - -
[docs]def collectstatic(): - """ - Run collectstatic to make sure all web assets are loaded. - - """ - from django.core.management import call_command - - logger.log_info("Initial setup: Gathering static resources using 'collectstatic'") - call_command("collectstatic", "--noinput")
- - -
[docs]def reset_server(): - """ - We end the initialization by resetting the server. This makes sure - the first login is the same as all the following ones, - particularly it cleans all caches for the special objects. It - also checks so the warm-reset mechanism works as it should. - - """ - ServerConfig.objects.conf("server_epoch", time.time()) - from evennia.server.sessionhandler import SESSIONS - - logger.log_info("Initial setup complete. Restarting Server once.") - SESSIONS.portal_reset_server()
- - -
[docs]def handle_setup(last_step=None): - """ - Main logic for the module. It allows for restarting the - initialization at any point if one of the modules should crash. - - Args: - last_step (str, None): The last stored successful step, for starting - over on errors. None if starting from scratch. If this is 'done', - the function will exit immediately. - - """ - if last_step in('done', -1): - # this means we don't need to handle setup since - # it already ran sucessfully once. -1 is the legacy - # value for existing databases. - return - - # setup sequence - setup_sequence = { - 'create_objects': create_objects, - 'at_initial_setup': at_initial_setup, - 'collectstatic': collectstatic, - 'done': reset_server, - } - - # determine the sequence so we can skip ahead - steps = list(setup_sequence) - steps = steps[steps.index(last_step) + 1 if last_step is not None else 0:] - - # step through queue from last completed function. Once completed, - # the 'done' key should be set. - for stepname in steps: - try: - setup_sequence[stepname]() - except Exception: - # we re-raise to make sure to stop startup - raise - else: - # save the step - ServerConfig.objects.conf("last_initial_setup_step", stepname) - if stepname == 'done': - # always exit on 'done' - break
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/inputfuncs.html b/docs/0.9.5/_modules/evennia/server/inputfuncs.html deleted file mode 100644 index d047249602..0000000000 --- a/docs/0.9.5/_modules/evennia/server/inputfuncs.html +++ /dev/null @@ -1,759 +0,0 @@ - - - - - - - - evennia.server.inputfuncs — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.inputfuncs

-"""
-Functions for processing input commands.
-
-All global functions in this module whose name does not start with "_"
-is considered an inputfunc. Each function must have the following
-callsign (where inputfunc name is always lower-case, no matter what the
-OOB input name looked like):
-
-    inputfunc(session, *args, **kwargs)
-
-Where "options" is always one of the kwargs, containing eventual
-protocol-options.
-There is one special function, the "default" function, which is called
-on a no-match. It has this callsign:
-
-    default(session, cmdname, *args, **kwargs)
-
-Evennia knows which modules to use for inputfuncs by
-settings.INPUT_FUNC_MODULES.
-
-"""
-
-import importlib
-from codecs import lookup as codecs_lookup
-from django.conf import settings
-from evennia.commands.cmdhandler import cmdhandler
-from evennia.accounts.models import AccountDB
-from evennia.utils.logger import log_err
-from evennia.utils.utils import to_str
-
-BrowserSessionStore = importlib.import_module(settings.SESSION_ENGINE).SessionStore
-
-
-# always let "idle" work since we use this in the webclient
-_IDLE_COMMAND = settings.IDLE_COMMAND
-_IDLE_COMMAND = (_IDLE_COMMAND,) if _IDLE_COMMAND == "idle" else (_IDLE_COMMAND, "idle")
-_GA = object.__getattribute__
-_SA = object.__setattr__
-
-
-_STRIP_INCOMING_MXP = settings.MXP_ENABLED and settings.MXP_OUTGOING_ONLY
-_STRIP_MXP = None
-
-
-
-def _NA(o):
-    return "N/A"
-
-
-def _maybe_strip_incoming_mxp(txt):
-    global _STRIP_MXP
-    if _STRIP_INCOMING_MXP:
-        if not _STRIP_MXP:
-            from evennia.utils.ansi import strip_mxp as _STRIP_MXP
-        return _STRIP_MXP(txt)
-    return txt
-
-
-_ERROR_INPUT = "Inputfunc {name}({session}): Wrong/unrecognized input: {inp}"
-
-
-# All global functions are inputfuncs available to process inputs
-
-
-
[docs]def text(session, *args, **kwargs): - """ - Main text input from the client. This will execute a command - string on the server. - - Args: - session (Session): The active Session to receive the input. - text (str): First arg is used as text-command input. Other - arguments are ignored. - - """ - - # from evennia.server.profiling.timetrace import timetrace - # text = timetrace(text, "ServerSession.data_in") - - txt = args[0] if args else None - - # explicitly check for None since text can be an empty string, which is - # also valid - if txt is None: - return - # this is treated as a command input - # handle the 'idle' command - if txt.strip() in _IDLE_COMMAND: - session.update_session_counters(idle=True) - return - - txt = _maybe_strip_incoming_mxp(txt) - - if session.account: - # nick replacement - puppet = session.puppet - if puppet: - txt = puppet.nicks.nickreplace( - txt, categories=("inputline"), include_account=True - ) - else: - txt = session.account.nicks.nickreplace( - txt, categories=("inputline"), include_account=False - ) - kwargs.pop("options", None) - cmdhandler(session, txt, callertype="session", session=session, **kwargs) - session.update_session_counters()
- - -
[docs]def bot_data_in(session, *args, **kwargs): - """ - Text input from the IRC and RSS bots. - This will trigger the execute_cmd method on the bots in-game counterpart. - - Args: - session (Session): The active Session to receive the input. - text (str): First arg is text input. Other arguments are ignored. - - """ - - txt = args[0] if args else None - - # Explicitly check for None since text can be an empty string, which is - # also valid - if txt is None: - return - # this is treated as a command input - # handle the 'idle' command - if txt.strip() in _IDLE_COMMAND: - session.update_session_counters(idle=True) - return - - txt = _maybe_strip_incoming_mxp(txt) - - kwargs.pop("options", None) - # Trigger the execute_cmd method of the corresponding bot. - session.account.execute_cmd(session=session, txt=txt, **kwargs) - session.update_session_counters()
- - -
[docs]def echo(session, *args, **kwargs): - """ - Echo test function - """ - if _STRIP_INCOMING_MXP: - txt = strip_mxp(txt) - - session.data_out(text="Echo returns: %s" % args)
- - -
[docs]def default(session, cmdname, *args, **kwargs): - """ - Default catch-function. This is like all other input functions except - it will get `cmdname` as the first argument. - - """ - err = ( - "Session {sessid}: Input command not recognized:\n" - " name: '{cmdname}'\n" - " args, kwargs: {args}, {kwargs}".format( - sessid=session.sessid, cmdname=cmdname, args=args, kwargs=kwargs - ) - ) - if session.protocol_flags.get("INPUTDEBUG", False): - session.msg(err) - log_err(err)
- - -_CLIENT_OPTIONS = ( - "ANSI", - "XTERM256", - "MXP", - "UTF-8", - "SCREENREADER", - "ENCODING", - "MCCP", - "SCREENHEIGHT", - "SCREENWIDTH", - "INPUTDEBUG", - "RAW", - "NOCOLOR", - "NOGOAHEAD", - "LOCALECHO", -) - - -
[docs]def client_options(session, *args, **kwargs): - """ - This allows the client an OOB way to inform us about its name and capabilities. - This will be integrated into the session settings - - Keyword Args: - get (bool): If this is true, return the settings as a dict - (ignore all other kwargs). - client (str): A client identifier, like "mushclient". - version (str): A client version - ansi (bool): Supports ansi colors - xterm256 (bool): Supports xterm256 colors or not - mxp (bool): Supports MXP or not - utf-8 (bool): Supports UTF-8 or not - screenreader (bool): Screen-reader mode on/off - mccp (bool): MCCP compression on/off - screenheight (int): Screen height in lines - screenwidth (int): Screen width in characters - inputdebug (bool): Debug input functions - nocolor (bool): Strip color - raw (bool): Turn off parsing - localecho (bool): Turn on server-side echo (for clients not supporting it) - - """ - old_flags = session.protocol_flags - if not kwargs or kwargs.get("get", False): - # return current settings - options = dict((key, old_flags[key]) for key in old_flags if key.upper() in _CLIENT_OPTIONS) - session.msg(client_options=options) - return - - def validate_encoding(val): - # helper: change encoding - try: - codecs_lookup(val) - except LookupError: - raise RuntimeError("The encoding '|w%s|n' is invalid. " % val) - return val - - def validate_size(val): - return {0: int(val)} - - def validate_bool(val): - if isinstance(val, str): - return True if val.lower() in ("true", "on", "1") else False - return bool(val) - - flags = {} - for key, value in kwargs.items(): - key = key.lower() - if key == "client": - flags["CLIENTNAME"] = to_str(value) - elif key == "version": - if "CLIENTNAME" in flags: - flags["CLIENTNAME"] = "%s %s" % (flags["CLIENTNAME"], to_str(value)) - elif key == "ENCODING": - flags["ENCODING"] = validate_encoding(value) - elif key == "ansi": - flags["ANSI"] = validate_bool(value) - elif key == "xterm256": - flags["XTERM256"] = validate_bool(value) - elif key == "mxp": - flags["MXP"] = validate_bool(value) - elif key == "utf-8": - flags["UTF-8"] = validate_bool(value) - elif key == "screenreader": - flags["SCREENREADER"] = validate_bool(value) - elif key == "mccp": - flags["MCCP"] = validate_bool(value) - elif key == "screenheight": - flags["SCREENHEIGHT"] = validate_size(value) - elif key == "screenwidth": - flags["SCREENWIDTH"] = validate_size(value) - elif key == "inputdebug": - flags["INPUTDEBUG"] = validate_bool(value) - elif key == "nocolor": - flags["NOCOLOR"] = validate_bool(value) - elif key == "raw": - flags["RAW"] = validate_bool(value) - elif key == "nogoahead": - flags["NOGOAHEAD"] = validate_bool(value) - elif key == "localecho": - flags["LOCALECHO"] = validate_bool(value) - elif key in ( - "Char 1", - "Char.Skills 1", - "Char.Items 1", - "Room 1", - "IRE.Rift 1", - "IRE.Composer 1", - ): - # ignore mudlet's default send (aimed at IRE games) - pass - elif key not in ("options", "cmdid"): - err = _ERROR_INPUT.format(name="client_settings", session=session, inp=key) - session.msg(text=err) - - session.protocol_flags.update(flags) - # we must update the protocol flags on the portal session copy as well - session.sessionhandler.session_portal_partial_sync({session.sessid: {"protocol_flags": flags}})
- - -
[docs]def get_client_options(session, *args, **kwargs): - """ - Alias wrapper for getting options. - """ - client_options(session, get=True)
- - -
[docs]def get_inputfuncs(session, *args, **kwargs): - """ - Get the keys of all available inputfuncs. Note that we don't get - it from this module alone since multiple modules could be added. - So we get it from the sessionhandler. - """ - inputfuncsdict = dict( - (key, func.__doc__) for key, func in session.sessionhandler.get_inputfuncs().items() - ) - session.msg(get_inputfuncs=inputfuncsdict)
- - -
[docs]def login(session, *args, **kwargs): - """ - Peform a login. This only works if session is currently not logged - in. This will also automatically throttle too quick attempts. - - Keyword Args: - name (str): Account name - password (str): Plain-text password - - """ - if not session.logged_in and "name" in kwargs and "password" in kwargs: - from evennia.commands.default.unloggedin import create_normal_account - - account = create_normal_account(session, kwargs["name"], kwargs["password"]) - if account: - session.sessionhandler.login(session, account)
- - -_gettable = { - "name": lambda obj: obj.key, - "key": lambda obj: obj.key, - "location": lambda obj: obj.location.key if obj.location else "None", - "servername": lambda obj: settings.SERVERNAME, -} - - -
[docs]def get_value(session, *args, **kwargs): - """ - Return the value of a given attribute or db_property on the - session's current account or character. - - Keyword Args: - name (str): Name of info value to return. Only names - in the _gettable dictionary earlier in this module - are accepted. - - """ - name = kwargs.get("name", "") - obj = session.puppet or session.account - if name in _gettable: - session.msg(get_value={"name": name, "value": _gettable[name](obj)})
- - -def _testrepeat(**kwargs): - """ - This is a test function for using with the repeat - inputfunc. - - Keyword Args: - session (Session): Session to return to. - """ - import time - - kwargs["session"].msg(repeat="Repeat called: %s" % time.time()) - - -_repeatable = {"test1": _testrepeat, "test2": _testrepeat} # example only # " - - -
[docs]def repeat(session, *args, **kwargs): - """ - Call a named function repeatedly. Note that - this is meant as an example of limiting the number of - possible call functions. - - Keyword Args: - callback (str): The function to call. Only functions - from the _repeatable dictionary earlier in this - module are available. - interval (int): How often to call function (s). - Defaults to once every 60 seconds with a minimum - of 5 seconds. - stop (bool): Stop a previously assigned ticker with - the above settings. - - """ - from evennia.scripts.tickerhandler import TICKER_HANDLER - - name = kwargs.get("callback", "") - interval = max(5, int(kwargs.get("interval", 60))) - - if name in _repeatable: - if kwargs.get("stop", False): - TICKER_HANDLER.remove( - interval, _repeatable[name], idstring=session.sessid, persistent=False - ) - else: - TICKER_HANDLER.add( - interval, - _repeatable[name], - idstring=session.sessid, - persistent=False, - session=session, - ) - else: - session.msg("Allowed repeating functions are: %s" % (", ".join(_repeatable)))
- - -
[docs]def unrepeat(session, *args, **kwargs): - "Wrapper for OOB use" - kwargs["stop"] = True - repeat(session, *args, **kwargs)
- - -_monitorable = {"name": "db_key", "location": "db_location", "desc": "desc"} - - -def _on_monitor_change(**kwargs): - fieldname = kwargs["fieldname"] - obj = kwargs["obj"] - name = kwargs["name"] - session = kwargs["session"] - outputfunc_name = kwargs["outputfunc_name"] - - # the session may be None if the char quits and someone - # else then edits the object - - if session: - callsign = {outputfunc_name: {"name": name, "value": _GA(obj, fieldname)}} - session.msg(**callsign) - - -
[docs]def monitor(session, *args, **kwargs): - """ - Adds monitoring to a given property or Attribute. - - Keyword Args: - name (str): The name of the property or Attribute - to report. No db_* prefix is needed. Only names - in the _monitorable dict earlier in this module - are accepted. - stop (bool): Stop monitoring the above name. - outputfunc_name (str, optional): Change the name of - the outputfunc name. This is used e.g. by MSDP which - has its own specific output format. - - """ - from evennia.scripts.monitorhandler import MONITOR_HANDLER - - name = kwargs.get("name", None) - outputfunc_name = kwargs("outputfunc_name", "monitor") - if name and name in _monitorable and session.puppet: - field_name = _monitorable[name] - obj = session.puppet - if kwargs.get("stop", False): - MONITOR_HANDLER.remove(obj, field_name, idstring=session.sessid) - else: - # the handler will add fieldname and obj to the kwargs automatically - MONITOR_HANDLER.add( - obj, - field_name, - _on_monitor_change, - idstring=session.sessid, - persistent=False, - name=name, - session=session, - outputfunc_name=outputfunc_name, - )
- - -
[docs]def unmonitor(session, *args, **kwargs): - """ - Wrapper for turning off monitoring - """ - kwargs["stop"] = True - monitor(session, *args, **kwargs)
- - -
[docs]def monitored(session, *args, **kwargs): - """ - Report on what is being monitored - - """ - from evennia.scripts.monitorhandler import MONITOR_HANDLER - - obj = session.puppet - monitors = MONITOR_HANDLER.all(obj=obj) - session.msg(monitored=(monitors, {}))
- - -def _on_webclient_options_change(**kwargs): - """ - Called when the webclient options stored on the account changes. - Inform the interested clients of this change. - """ - session = kwargs["session"] - obj = kwargs["obj"] - fieldname = kwargs["fieldname"] - clientoptions = _GA(obj, fieldname) - - # the session may be None if the char quits and someone - # else then edits the object - if session: - session.msg(webclient_options=clientoptions) - - -
[docs]def webclient_options(session, *args, **kwargs): - """ - Handles retrieving and changing of options related to the webclient. - - If kwargs is empty (or contains just a "cmdid"), the saved options will be - sent back to the session. - A monitor handler will be created to inform the client of any future options - that changes. - - If kwargs is not empty, the key/values stored in there will be persisted - to the account object. - - Keyword Args: - <option name>: an option to save - """ - account = session.account - - clientoptions = account.db._saved_webclient_options - if not clientoptions: - # No saved options for this account, copy and save the default. - account.db._saved_webclient_options = settings.WEBCLIENT_OPTIONS.copy() - # Get the _SaverDict created by the database. - clientoptions = account.db._saved_webclient_options - - # The webclient adds a cmdid to every kwargs, but we don't need it. - try: - del kwargs["cmdid"] - except KeyError: - pass - - if not kwargs: - # No kwargs: we are getting the stored options - # Convert clientoptions to regular dict for sending. - session.msg(webclient_options=dict(clientoptions)) - - # Create a monitor. If a monitor already exists then it will replace - # the previous one since it would use the same idstring - from evennia.scripts.monitorhandler import MONITOR_HANDLER - - MONITOR_HANDLER.add( - account, - "_saved_webclient_options", - _on_webclient_options_change, - idstring=session.sessid, - persistent=False, - session=session, - ) - else: - # kwargs provided: persist them to the account object. - clientoptions.update(kwargs)
- - -# OOB protocol-specific aliases and wrappers - -# GMCP aliases -hello = client_options -supports_set = client_options - - -# MSDP aliases (some of the the generic MSDP commands defined in the MSDP spec are prefixed -# by msdp_ at the protocol level) -# See https://tintin.sourceforge.io/protocols/msdp/ - - -
[docs]def msdp_list(session, *args, **kwargs): - """ - MSDP LIST command - - """ - from evennia.scripts.monitorhandler import MONITOR_HANDLER - - args_lower = [arg.lower() for arg in args] - if "commands" in args_lower: - inputfuncs = [ - key[5:] if key.startswith("msdp_") else key - for key in session.sessionhandler.get_inputfuncs().keys() - ] - session.msg(commands=(inputfuncs, {})) - if "lists" in args_lower: - session.msg( - lists=( - [ - "commands", - "lists", - "configurable_variables", - "reportable_variables", - "reported_variables", - "sendable_variables", - ], - {}, - ) - ) - if "configurable_variables" in args_lower: - session.msg(configurable_variables=(_CLIENT_OPTIONS, {})) - if "reportable_variables" in args_lower: - session.msg(reportable_variables=(_monitorable, {})) - if "reported_variables" in args_lower: - obj = session.puppet - monitor_infos = MONITOR_HANDLER.all(obj=obj) - fieldnames = [tup[1] for tup in monitor_infos] - session.msg(reported_variables=(fieldnames, {})) - if "sendable_variables" in args_lower: - session.msg(sendable_variables=(_monitorable, {}))
- - -
[docs]def msdp_report(session, *args, **kwargs): - """ - MSDP REPORT command - - """ - kwargs["outputfunc_name":"report"] - monitor(session, *args, **kwargs)
- - -
[docs]def msdp_unreport(session, *args, **kwargs): - """ - MSDP UNREPORT command - - """ - unmonitor(session, *args, **kwargs)
- - -
[docs]def msdp_send(session, *args, **kwargs): - """ - MSDP SEND command - """ - out = {} - for varname in args: - if varname.lower() in _monitorable: - out[varname] = _monitorable[varname.lower()] - session.msg(send=((), out))
- - -# client specific - - -def _not_implemented(session, *args, **kwargs): - """ - Dummy used to swallow missing-inputfunc errors for - common clients. - """ - pass - - -# GMCP External.Discord.Hello is sent by Mudlet as a greeting -# (see https://wiki.mudlet.org/w/Manual:Technical_Manual) -external_discord_hello = _not_implemented - - -# GMCP Client.Gui is sent by Mudlet for gui setup. -client_gui = _not_implemented -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/manager.html b/docs/0.9.5/_modules/evennia/server/manager.html deleted file mode 100644 index 9f3c2a6bc8..0000000000 --- a/docs/0.9.5/_modules/evennia/server/manager.html +++ /dev/null @@ -1,158 +0,0 @@ - - - - - - - - evennia.server.manager — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.manager

-"""
-Custom manager for ServerConfig objects.
-"""
-from django.db import models
-
-
-
[docs]class ServerConfigManager(models.Manager): - """ - This ServerConfigManager implements methods for searching and - manipulating ServerConfigs directly from the database. - - These methods will all return database objects (or QuerySets) - directly. - - ServerConfigs are used to store certain persistent settings for - the server at run-time. - - """ - -
[docs] def conf(self, key=None, value=None, delete=False, default=None): - """ - Add, retrieve and manipulate config values. - - Args: - key (str, optional): Name of config. - value (str, optional): Data to store in this config value. - delete (bool, optional): If `True`, delete config with `key`. - default (str, optional): Use when retrieving a config value - by a key that does not exist. - Returns: - all (list): If `key` was not given - all stored config values. - value (str): If `key` was given, this is the stored value, or - `default` if no matching `key` was found. - - """ - if not key: - return self.all() - elif delete is True: - for conf in self.filter(db_key=key): - conf.delete() - elif value is not None: - conf = self.filter(db_key=key) - if conf: - conf = conf[0] - else: - conf = self.model(db_key=key) - conf.value = value # this will pickle - else: - conf = self.filter(db_key=key) - if not conf: - return default - return conf[0].value - return None
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/models.html b/docs/0.9.5/_modules/evennia/server/models.html deleted file mode 100644 index 001e9d7076..0000000000 --- a/docs/0.9.5/_modules/evennia/server/models.html +++ /dev/null @@ -1,238 +0,0 @@ - - - - - - - - evennia.server.models — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.models

-"""
-
-Server Configuration flags
-
-This holds persistent server configuration flags.
-
-Config values should usually be set through the
-manager's conf() method.
-
-"""
-from django.db import models
-
-from evennia.utils.idmapper.models import WeakSharedMemoryModel
-from evennia.utils import logger, utils
-from evennia.utils.dbserialize import to_pickle, from_pickle
-from evennia.server.manager import ServerConfigManager
-from evennia.utils import picklefield
-
-
-# ------------------------------------------------------------
-#
-# ServerConfig
-#
-# ------------------------------------------------------------
-
-
-
[docs]class ServerConfig(WeakSharedMemoryModel): - """ - On-the fly storage of global settings. - - Properties defined on ServerConfig: - - - key: Main identifier - - value: Value stored in key. This is a pickled storage. - - """ - - # - # ServerConfig database model setup - # - # - # These database fields are all set using their corresponding properties, - # named same as the field, but without the db_* prefix. - - # main name of the database entry - db_key = models.CharField(max_length=64, unique=True) - # config value - # db_value = models.BinaryField(blank=True) - - db_value = picklefield.PickledObjectField( - "value", - null=True, - help_text="The data returned when the config value is accessed. Must be " - "written as a Python literal if editing through the admin " - "interface. Attribute values which are not Python literals " - "cannot be edited through the admin interface.", - ) - - objects = ServerConfigManager() - _is_deleted = False - - # Wrapper properties to easily set database fields. These are - # @property decorators that allows to access these fields using - # normal python operations (without having to remember to save() - # etc). So e.g. a property 'attr' has a get/set/del decorator - # defined that allows the user to do self.attr = value, - # value = self.attr and del self.attr respectively (where self - # is the object in question). - - # key property (wraps db_key) - # @property - def __key_get(self): - "Getter. Allows for value = self.key" - return self.db_key - - # @key.setter - def __key_set(self, value): - "Setter. Allows for self.key = value" - self.db_key = value - self.save() - - # @key.deleter - def __key_del(self): - "Deleter. Allows for del self.key. Deletes entry." - self.delete() - - key = property(__key_get, __key_set, __key_del) - - # value property (wraps db_value) - # @property - def __value_get(self): - "Getter. Allows for value = self.value" - return from_pickle(self.db_value, db_obj=self) - - # @value.setter - def __value_set(self, value): - "Setter. Allows for self.value = value" - if utils.has_parent("django.db.models.base.Model", value): - # we have to protect against storing db objects. - logger.log_err("ServerConfig cannot store db objects! (%s)" % value) - return - self.db_value = to_pickle(value) - self.save() - - # @value.deleter - def __value_del(self): - "Deleter. Allows for del self.value. Deletes entry." - self.delete() - - value = property(__value_get, __value_set, __value_del) - - class Meta: - "Define Django meta options" - verbose_name = "Server Config value" - verbose_name_plural = "Server Config values" - - # - # ServerConfig other methods - # - def __repr__(self): - return "<{} {}>".format(self.__class__.__name__, self.key) - -
[docs] def store(self, key, value): - """ - Wrap the storage. - - Args: - key (str): The name of this store. - value (str): The data to store with this `key`. - - """ - self.key = key - self.value = value
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/amp.html b/docs/0.9.5/_modules/evennia/server/portal/amp.html deleted file mode 100644 index 29f5a866d2..0000000000 --- a/docs/0.9.5/_modules/evennia/server/portal/amp.html +++ /dev/null @@ -1,653 +0,0 @@ - - - - - - - - evennia.server.portal.amp — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.portal.amp

-"""
-The AMP (Asynchronous Message Protocol)-communication commands and constants used by Evennia.
-
-This module acts as a central place for AMP-servers and -clients to get commands to use.
-
-"""
-
-from functools import wraps
-import time
-from twisted.protocols import amp
-from collections import defaultdict, namedtuple
-from io import BytesIO
-from itertools import count
-import zlib  # Used in Compressed class
-import pickle
-
-from twisted.internet.defer import DeferredList, Deferred
-from evennia.utils.utils import variable_from_module
-
-# delayed import
-_LOGGER = None
-
-# communication bits
-# (chr(9) and chr(10) are \t and \n, so skipping them)
-
-PCONN = chr(1)  # portal session connect
-PDISCONN = chr(2)  # portal session disconnect
-PSYNC = chr(3)  # portal session sync
-SLOGIN = chr(4)  # server session login
-SDISCONN = chr(5)  # server session disconnect
-SDISCONNALL = chr(6)  # server session disconnect all
-SSHUTD = chr(7)  # server shutdown
-SSYNC = chr(8)  # server session sync
-SCONN = chr(11)  # server creating new connection (for irc bots and etc)
-PCONNSYNC = chr(12)  # portal post-syncing a session
-PDISCONNALL = chr(13)  # portal session disconnect all
-SRELOAD = chr(14)  # server shutdown in reload mode
-SSTART = chr(15)  # server start (portal must already be running anyway)
-PSHUTD = chr(16)  # portal (+server) shutdown
-SSHUTD = chr(17)  # server shutdown
-PSTATUS = chr(18)  # ping server or portal status
-SRESET = chr(19)  # server shutdown in reset mode
-
-NUL = b"\x00"
-NULNUL = b"\x00\x00"
-
-AMP_MAXLEN = amp.MAX_VALUE_LENGTH  # max allowed data length in AMP protocol (cannot be changed)
-
-# amp internal
-ASK = b'_ask'
-ANSWER = b'_answer'
-ERROR = b'_error'
-ERROR_CODE = b'_error_code'
-ERROR_DESCRIPTION = b'_error_description'
-UNKNOWN_ERROR_CODE = b'UNKNOWN'
-
-# buffers
-_SENDBATCH = defaultdict(list)
-_MSGBUFFER = defaultdict(list)
-
-# resources
-
-DUMMYSESSION = namedtuple("DummySession", ["sessid"])(0)
-
-
-_HTTP_WARNING = bytes(
-    """
-HTTP/1.1 200 OK
-Content-Type: text/html
-
-<html>
-  <body>
-    This is Evennia's internal AMP port. It handles communication
-    between Evennia's different processes.
-    <p>
-        <h3>This port should NOT be publicly visible.</h3>
-    </p>
-  </body>
-</html>""".strip(),
-    "utf-8",
-)
-
-
-# Helper functions for pickling.
-
-
-
[docs]def dumps(data): - return pickle.dumps(data, pickle.HIGHEST_PROTOCOL)
- - -
[docs]def loads(data): - return pickle.loads(data)
- - -def _get_logger(): - """ - Delay import of logger until absolutely necessary - - """ - global _LOGGER - if not _LOGGER: - from evennia.utils import logger as _LOGGER - return _LOGGER - - -@wraps -def catch_traceback(func): - """ - Helper decorator - - """ - - def decorator(*args, **kwargs): - try: - func(*args, **kwargs) - except Exception as err: - _get_logger().log_trace() - raise # make sure the error is visible on the other side of the connection too - print(err) - - return decorator - - -# AMP Communication Command types - - -
[docs]class Compressed(amp.String): - """ - This is a custom AMP command Argument that both handles too-long - sends as well as uses zlib for compression across the wire. The - batch-grouping of too-long sends is borrowed from the "mediumbox" - recipy at twisted-hacks's ~glyph/+junk/amphacks/mediumbox. - - """ - -
[docs] def fromBox(self, name, strings, objects, proto): - """ - Converts from box string representation to python. We read back too-long batched data and - put it back together here. - - """ - - value = BytesIO() - value.write(self.fromStringProto(strings.get(name), proto)) - for counter in count(2): - # count from 2 upwards - chunk = strings.get(b"%s.%d" % (name, counter)) - if chunk is None: - break - value.write(self.fromStringProto(chunk, proto)) - objects[str(name, "utf-8")] = value.getvalue()
- -
[docs] def toBox(self, name, strings, objects, proto): - """ - Convert from python object to string box representation. - we break up too-long data snippets into multiple batches here. - - """ - - # print("toBox: name={}, strings={}, objects={}, proto{}".format(name, strings, objects, proto)) - - value = BytesIO(objects[str(name, "utf-8")]) - strings[name] = self.toStringProto(value.read(AMP_MAXLEN), proto) - - # print("toBox strings[name] = {}".format(strings[name])) - - for counter in count(2): - chunk = value.read(AMP_MAXLEN) - if not chunk: - break - strings[b"%s.%d" % (name, counter)] = self.toStringProto(chunk, proto)
- -
[docs] def toString(self, inObject): - """ - Convert to send as a bytestring on the wire, with compression. - - Note: In Py3 this is really a byte stream. - - """ - return zlib.compress(super(Compressed, self).toString(inObject), 9)
- -
[docs] def fromString(self, inString): - """ - Convert (decompress) from the string-representation on the wire to Python. - - """ - return super(Compressed, self).fromString(zlib.decompress(inString))
- - -
[docs]class MsgLauncher2Portal(amp.Command): - """ - Message Launcher -> Portal - - """ - - key = "MsgLauncher2Portal" - arguments = [(b"operation", amp.String()), (b"arguments", amp.String())] - errors = {Exception: b"EXCEPTION"} - response = []
- - -
[docs]class MsgPortal2Server(amp.Command): - """ - Message Portal -> Server - - """ - - key = b"MsgPortal2Server" - arguments = [(b"packed_data", Compressed())] - errors = {Exception: b"EXCEPTION"} - response = []
- - -
[docs]class MsgServer2Portal(amp.Command): - """ - Message Server -> Portal - - """ - - key = "MsgServer2Portal" - arguments = [(b"packed_data", Compressed())] - errors = {Exception: b"EXCEPTION"} - response = []
- - -
[docs]class AdminPortal2Server(amp.Command): - """ - Administration Portal -> Server - - Sent when the portal needs to perform admin operations on the - server, such as when a new session connects or resyncs - - """ - - key = "AdminPortal2Server" - arguments = [(b"packed_data", Compressed())] - errors = {Exception: b"EXCEPTION"} - response = []
- - -
[docs]class AdminServer2Portal(amp.Command): - """ - Administration Server -> Portal - - Sent when the server needs to perform admin operations on the - portal. - - """ - - key = "AdminServer2Portal" - arguments = [(b"packed_data", Compressed())] - errors = {Exception: b"EXCEPTION"} - response = []
- - -
[docs]class MsgStatus(amp.Command): - """ - Check Status between AMP services - - """ - - key = "MsgStatus" - arguments = [(b"status", amp.String())] - errors = {Exception: b"EXCEPTION"} - response = [(b"status", amp.String())]
- - -
[docs]class FunctionCall(amp.Command): - """ - Bidirectional Server <-> Portal - - Sent when either process needs to call an arbitrary function in - the other. This does not use the batch-send functionality. - - """ - - key = "FunctionCall" - arguments = [ - (b"module", amp.String()), - (b"function", amp.String()), - (b"args", amp.String()), - (b"kwargs", amp.String()), - ] - errors = {Exception: b"EXCEPTION"} - response = [(b"result", amp.String())]
- - -# ------------------------------------------------------------- -# Core AMP protocol for communication Server <-> Portal -# ------------------------------------------------------------- - - -
[docs]class AMPMultiConnectionProtocol(amp.AMP): - """ - AMP protocol that safely handle multiple connections to the same - server without dropping old ones - new clients will receive - all server returns (broadcast). Will also correctly handle - erroneous HTTP requests on the port and return a HTTP error response. - - """ - - # helper methods - -
[docs] def __init__(self, *args, **kwargs): - """ - Initialize protocol with some things that need to be in place - already before connecting both on portal and server. - - """ - self.send_batch_counter = 0 - self.send_reset_time = time.time() - self.send_mode = True - self.send_task = None - self.multibatches = 0 - # later twisted amp has its own __init__ - super(AMPMultiConnectionProtocol, self).__init__(*args, **kwargs)
- - def _commandReceived(self, box): - """ - This overrides the default Twisted AMP error handling which is not - passing enough of the traceback through to the other side. Instead we - add a specific log of the problem on the erroring side. - - """ - def formatAnswer(answerBox): - answerBox[ANSWER] = box[ASK] - return answerBox - - def formatError(error): - if error.check(amp.RemoteAmpError): - code = error.value.errorCode - desc = error.value.description - - # Evennia extra logging - desc += " (error logged on other side)" - _get_logger().log_err(f"AMP caught exception ({desc}):\n{error.value}") - - if isinstance(desc, str): - desc = desc.encode("utf-8", "replace") - if error.value.fatal: - errorBox = amp.QuitBox() - else: - errorBox = amp.AmpBox() - else: - errorBox = amp.QuitBox() - _get_logger().log_err(error) # server-side logging if unhandled error - code = UNKNOWN_ERROR_CODE - desc = b"Unknown Error" - errorBox[ERROR] = box[ASK] - errorBox[ERROR_DESCRIPTION] = desc - errorBox[ERROR_CODE] = code - return errorBox - deferred = self.dispatchCommand(box) - if ASK in box: - deferred.addCallbacks(formatAnswer, formatError) - deferred.addCallback(self._safeEmit) - deferred.addErrback(self.unhandledError) - -
[docs] def dataReceived(self, data): - """ - Handle non-AMP messages, such as HTTP communication. - - """ - # print("dataReceived: {}".format(data)) - if data[:1] == NUL: - # an AMP communication - if data[-2:] != NULNUL: - # an incomplete AMP box means more batches are forthcoming. - self.multibatches += 1 - try: - super(AMPMultiConnectionProtocol, self).dataReceived(data) - except KeyError: - _get_logger().log_trace( - "Discarded incoming partial (packed) data (len {})".format(len(data)) - ) - elif self.multibatches: - # invalid AMP, but we have a pending multi-batch that is not yet complete - if data[-2:] == NULNUL: - # end of existing multibatch - self.multibatches = max(0, self.multibatches - 1) - try: - super(AMPMultiConnectionProtocol, self).dataReceived(data) - except KeyError: - _get_logger().log_trace( - "Discarded incoming multi-batch (packed) data (len {})".format(len(data)) - ) - else: - # not an AMP communication, return warning - self.transport.write(_HTTP_WARNING) - self.transport.loseConnection() - print("HTTP received (the AMP port should not receive http, only AMP!) %s" % data)
- -
[docs] def makeConnection(self, transport): - """ - Swallow connection log message here. Copied from original - in the amp protocol. - - """ - # copied from original, removing the log message - if not self._ampInitialized: - amp.AMP.__init__(self) - self._transportPeer = transport.getPeer() - self._transportHost = transport.getHost() - amp.BinaryBoxProtocol.makeConnection(self, transport)
- -
[docs] def connectionMade(self): - """ - This is called when an AMP connection is (re-)established. AMP calls it on both sides. - - """ - # print("connectionMade: {}".format(self)) - self.factory.broadcasts.append(self)
- -
[docs] def connectionLost(self, reason): - """ - We swallow connection errors here. The reason is that during a - normal reload/shutdown there will almost always be cases where - either the portal or server shuts down before a message has - returned its (empty) return, triggering a connectionLost error - that is irrelevant. If a true connection error happens, the - portal will continuously try to reconnect, showing the problem - that way. - - """ - # print("ConnectionLost: {}: {}".format(self, reason)) - try: - self.factory.broadcasts.remove(self) - except ValueError: - pass
- - # Error handling - -
[docs] def errback(self, err, info): - """ - Error callback. - Handles errors to avoid dropping connections on server tracebacks. - - Args: - err (Failure): Deferred error instance. - info (str): Error string. - - """ - err.trap(Exception) - _get_logger().log_err( - "AMP Error from {info}: {trcbck} {err}".format( - info=info, trcbck=err.getTraceback(), err=err.getErrorMessage() - ) - )
- -
[docs] def data_in(self, packed_data): - """ - Process incoming packed data. - - Args: - packed_data (bytes): Pickled data. - Returns: - unpaced_data (any): Unpickled package - - """ - msg = loads(packed_data) - return msg
- -
[docs] def broadcast(self, command, sessid, **kwargs): - """ - Send data across the wire to all connections. - - Args: - command (AMP Command): A protocol send command. - sessid (int): A unique Session id. - - Returns: - deferred (deferred or None): A deferred with an errback. - - Notes: - Data will be sent across the wire pickled as a tuple - (sessid, kwargs). - - """ - deferreds = [] - # print("broadcast: {} {}: {}".format(command, sessid, kwargs)) - - for protcl in self.factory.broadcasts: - deferreds.append( - protcl.callRemote(command, **kwargs).addErrback(self.errback, command.key) - ) - - return DeferredList(deferreds)
- - # generic function send/recvs - -
[docs] def send_FunctionCall(self, modulepath, functionname, *args, **kwargs): - """ - Access method called by either process. This will call an arbitrary - function on the other process (On Portal if calling from Server and - vice versa). - - Inputs: - modulepath (str) - python path to module holding function to call - functionname (str) - name of function in given module - *args, **kwargs will be used as arguments/keyword args for the - remote function call - Returns: - A deferred that fires with the return value of the remote - function call - - """ - return ( - self.callRemote( - FunctionCall, - module=modulepath, - function=functionname, - args=dumps(args), - kwargs=dumps(kwargs), - ) - .addCallback(lambda r: loads(r["result"])) - .addErrback(self.errback, "FunctionCall") - )
- -
[docs] @FunctionCall.responder - @catch_traceback - def receive_functioncall(self, module, function, func_args, func_kwargs): - """ - This allows Portal- and Server-process to call an arbitrary - function in the other process. It is intended for use by - plugin modules. - - Args: - module (str or module): The module containing the - `function` to call. - function (str): The name of the function to call in - `module`. - func_args (str): Pickled args tuple for use in `function` call. - func_kwargs (str): Pickled kwargs dict for use in `function` call. - - """ - args = loads(func_args) - kwargs = loads(func_kwargs) - - # call the function (don't catch tracebacks here) - result = variable_from_module(module, function)(*args, **kwargs) - - if isinstance(result, Deferred): - # if result is a deferred, attach handler to properly - # wrap the return value - result.addCallback(lambda r: {"result": dumps(r)}) - return result - else: - return {"result": dumps(result)}
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/amp_server.html b/docs/0.9.5/_modules/evennia/server/portal/amp_server.html deleted file mode 100644 index 3d553763ed..0000000000 --- a/docs/0.9.5/_modules/evennia/server/portal/amp_server.html +++ /dev/null @@ -1,590 +0,0 @@ - - - - - - - - evennia.server.portal.amp_server — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.portal.amp_server

-"""
-The Evennia Portal service acts as an AMP-server, handling AMP
-communication to the AMP clients connecting to it (by default
-these are the Evennia Server and the evennia launcher).
-
-"""
-import os
-import sys
-from twisted.internet import protocol
-from evennia.server.portal import amp
-from django.conf import settings
-from subprocess import Popen, STDOUT
-from evennia.utils import logger
-from evennia.utils.utils import class_from_module
-
-
-def _is_windows():
-    return os.name == "nt"
-
-
-
[docs]def getenv(): - """ - Get current environment and add PYTHONPATH. - - Returns: - env (dict): Environment global dict. - - """ - sep = ";" if _is_windows() else ":" - env = os.environ.copy() - env["PYTHONPATH"] = sep.join(sys.path) - return env
- - -
[docs]class AMPServerFactory(protocol.ServerFactory): - - """ - This factory creates AMP Server connection. This acts as the 'Portal'-side communication to the - 'Server' process. - - """ - - noisy = False - -
[docs] def logPrefix(self): - """ - How this is named in logs - - """ - return "AMP"
- -
[docs] def __init__(self, portal): - """ - Initialize the factory. This is called as the Portal service starts. - - Args: - portal (Portal): The Evennia Portal service instance. - protocol (Protocol): The protocol the factory creates - instances of. - - """ - self.portal = portal - self.protocol = class_from_module(settings.AMP_SERVER_PROTOCOL_CLASS) - self.broadcasts = [] - self.server_connection = None - self.launcher_connection = None - self.disconnect_callbacks = {} - self.server_connect_callbacks = []
- -
[docs] def buildProtocol(self, addr): - """ - Start a new connection, and store it on the service object. - - Args: - addr (str): Connection address. Not used. - - Returns: - protocol (Protocol): The created protocol. - - """ - self.portal.amp_protocol = self.protocol() - self.portal.amp_protocol.factory = self - return self.portal.amp_protocol
- - -
[docs]class AMPServerProtocol(amp.AMPMultiConnectionProtocol): - """ - Protocol subclass for the AMP-server run by the Portal. - - """ - -
[docs] def connectionLost(self, reason): - """ - Set up a simple callback mechanism to let the amp-server wait for a connection to close. - - """ - # wipe broadcast and data memory - super(AMPServerProtocol, self).connectionLost(reason) - if self.factory.server_connection == self: - self.factory.server_connection = None - self.factory.portal.server_info_dict = {} - if self.factory.launcher_connection == self: - self.factory.launcher_connection = None - - callback, args, kwargs = self.factory.disconnect_callbacks.pop(self, (None, None, None)) - if callback: - try: - callback(*args, **kwargs) - except Exception: - logger.log_trace()
- -
[docs] def get_status(self): - """ - Return status for the Evennia infrastructure. - - Returns: - status (tuple): The portal/server status and pids - (portal_live, server_live, portal_PID, server_PID). - - """ - server_connected = bool( - self.factory.server_connection and self.factory.server_connection.transport.connected - ) - portal_info_dict = self.factory.portal.get_info_dict() - server_info_dict = self.factory.portal.server_info_dict - server_pid = self.factory.portal.server_process_id - portal_pid = os.getpid() - return (True, server_connected, portal_pid, server_pid, portal_info_dict, server_info_dict)
- -
[docs] def data_to_server(self, command, sessid, **kwargs): - """ - Send data across the wire to the Server. - - Args: - command (AMP Command): A protocol send command. - sessid (int): A unique Session id. - kwargs (any): Data to send. This will be pickled. - - Returns: - deferred (deferred or None): A deferred with an errback. - - Notes: - Data will be sent across the wire pickled as a tuple - (sessid, kwargs). - - """ - # print("portal data_to_server: {}, {}, {}".format(command, sessid, kwargs)) - if self.factory.server_connection: - return self.factory.server_connection.callRemote( - command, packed_data=amp.dumps((sessid, kwargs)) - ).addErrback(self.errback, command.key) - else: - # if no server connection is available, broadcast - return self.broadcast(command, sessid, packed_data=amp.dumps((sessid, kwargs)))
- -
[docs] def start_server(self, server_twistd_cmd): - """ - (Re-)Launch the Evennia server. - - Args: - server_twisted_cmd (list): The server start instruction - to pass to POpen to start the server. - - """ - # start the Server - print("Portal starting server ... ") - process = None - with open(settings.SERVER_LOG_FILE, "a") as logfile: - # we link stdout to a file in order to catch - # eventual errors happening before the Server has - # opened its logger. - try: - if _is_windows(): - # Windows requires special care - create_no_window = 0x08000000 - process = Popen( - server_twistd_cmd, - env=getenv(), - bufsize=-1, - stdout=logfile, - stderr=STDOUT, - creationflags=create_no_window, - ) - - else: - process = Popen( - server_twistd_cmd, env=getenv(), bufsize=-1, stdout=logfile, stderr=STDOUT - ) - except Exception: - logger.log_trace() - - self.factory.portal.server_twistd_cmd = server_twistd_cmd - logfile.flush() - if process and not _is_windows(): - # avoid zombie-process on Unix/BSD - process.wait() - return
- -
[docs] def wait_for_disconnect(self, callback, *args, **kwargs): - """ - Add a callback for when this connection is lost. - - Args: - callback (callable): Will be called with *args, **kwargs - once this protocol is disconnected. - - """ - self.factory.disconnect_callbacks[self] = (callback, args, kwargs)
- -
[docs] def wait_for_server_connect(self, callback, *args, **kwargs): - """ - Add a callback for when the Server is sure to have connected. - - Args: - callback (callable): Will be called with *args, **kwargs - once the Server handshake with Portal is complete. - - """ - self.factory.server_connect_callbacks.append((callback, args, kwargs))
- -
[docs] def stop_server(self, mode="shutdown"): - """ - Shut down server in one or more modes. - - Args: - mode (str): One of 'shutdown', 'reload' or 'reset'. - - """ - if mode == "reload": - self.send_AdminPortal2Server(amp.DUMMYSESSION, operation=amp.SRELOAD) - elif mode == "reset": - self.send_AdminPortal2Server(amp.DUMMYSESSION, operation=amp.SRESET) - elif mode == "shutdown": - self.send_AdminPortal2Server(amp.DUMMYSESSION, operation=amp.SSHUTD) - self.factory.portal.server_restart_mode = mode
- - # sending amp data - -
[docs] def send_Status2Launcher(self): - """ - Send a status stanza to the launcher. - - """ - # print("send status to launcher") - # print("self.get_status(): {}".format(self.get_status())) - if self.factory.launcher_connection: - self.factory.launcher_connection.callRemote( - amp.MsgStatus, status=amp.dumps(self.get_status()) - ).addErrback(self.errback, amp.MsgStatus.key)
- -
[docs] def send_MsgPortal2Server(self, session, **kwargs): - """ - Access method called by the Portal and executed on the Portal. - - Args: - session (session): Session - kwargs (any, optional): Optional data. - - Returns: - deferred (Deferred): Asynchronous return. - - """ - return self.data_to_server(amp.MsgPortal2Server, session.sessid, **kwargs)
- -
[docs] def send_AdminPortal2Server(self, session, operation="", **kwargs): - """ - Send Admin instructions from the Portal to the Server. - Executed on the Portal. - - Args: - session (Session): Session. - operation (char, optional): Identifier for the server operation, as defined by the - global variables in `evennia/server/amp.py`. - data (str or dict, optional): Data used in the administrative operation. - - """ - return self.data_to_server( - amp.AdminPortal2Server, session.sessid, operation=operation, **kwargs - )
- - # receive amp data - - @amp.MsgStatus.responder - @amp.catch_traceback - def portal_receive_status(self, status): - """ - Returns run-status for the server/portal. - - Args: - status (str): Not used. - Returns: - status (dict): The status is a tuple - (portal_running, server_running, portal_pid, server_pid). - - """ - # print('Received PSTATUS request') - return {"status": amp.dumps(self.get_status())} - - @amp.MsgLauncher2Portal.responder - @amp.catch_traceback - def portal_receive_launcher2portal(self, operation, arguments): - """ - Receives message arriving from evennia_launcher. - This method is executed on the Portal. - - Args: - operation (str): The action to perform. - arguments (str): Possible argument to the instruction, or the empty string. - - Returns: - result (dict): The result back to the launcher. - - Notes: - This is the entrypoint for controlling the entire Evennia system from the evennia - launcher. It can obviously only accessed when the Portal is already up and running. - - """ - # Since the launcher command uses amp.String() we need to convert from byte here. - operation = str(operation, "utf-8") - self.factory.launcher_connection = self - _, server_connected, _, _, _, _ = self.get_status() - - # logger.log_msg("Evennia Launcher->Portal operation %s:%s received" % (ord(operation), arguments)) - - # logger.log_msg("operation == amp.SSTART: {}: {}".format(operation == amp.SSTART, amp.loads(arguments))) - - if operation == amp.SSTART: # portal start #15 - # first, check if server is already running - if not server_connected: - self.wait_for_server_connect(self.send_Status2Launcher) - self.start_server(amp.loads(arguments)) - - elif operation == amp.SRELOAD: # reload server #14 - if server_connected: - # We let the launcher restart us once they get the signal - self.factory.server_connection.wait_for_disconnect(self.send_Status2Launcher) - self.stop_server(mode="reload") - else: - self.wait_for_server_connect(self.send_Status2Launcher) - self.start_server(amp.loads(arguments)) - - elif operation == amp.SRESET: # reload server #19 - if server_connected: - self.factory.server_connection.wait_for_disconnect(self.send_Status2Launcher) - self.stop_server(mode="reset") - else: - self.wait_for_server_connect(self.send_Status2Launcher) - self.start_server(amp.loads(arguments)) - - elif operation == amp.SSHUTD: # server-only shutdown #17 - if server_connected: - self.factory.server_connection.wait_for_disconnect(self.send_Status2Launcher) - self.stop_server(mode="shutdown") - - elif operation == amp.PSHUTD: # portal + server shutdown #16 - if server_connected: - self.factory.server_connection.wait_for_disconnect(self.factory.portal.shutdown) - else: - self.factory.portal.shutdown() - - else: - logger.log_err("Operation {} not recognized".format(operation)) - raise Exception("operation %(op)s not recognized." % {"op": operation}) - - return {} - - @amp.MsgServer2Portal.responder - @amp.catch_traceback - def portal_receive_server2portal(self, packed_data): - """ - Receives message arriving to Portal from Server. - This method is executed on the Portal. - - Args: - packed_data (str): Pickled data (sessid, kwargs) coming over the wire. - - """ - try: - sessid, kwargs = self.data_in(packed_data) - session = self.factory.portal.sessions.get(sessid, None) - if session: - self.factory.portal.sessions.data_out(session, **kwargs) - except Exception: - logger.log_trace("packed_data len {}".format(len(packed_data))) - return {} - - @amp.AdminServer2Portal.responder - @amp.catch_traceback - def portal_receive_adminserver2portal(self, packed_data): - """ - - Receives and handles admin operations sent to the Portal - This is executed on the Portal. - - Args: - packed_data (str): Data received, a pickled tuple (sessid, kwargs). - - """ - self.factory.server_connection = self - - sessid, kwargs = self.data_in(packed_data) - - # logger.log_msg("Evennia Server->Portal admin data %s:%s received" % (sessid, kwargs)) - - operation = kwargs.pop("operation") - portal_sessionhandler = self.factory.portal.sessions - - if operation == amp.SLOGIN: # server_session_login - # a session has authenticated; sync it. - session = portal_sessionhandler.get(sessid) - if session: - portal_sessionhandler.server_logged_in(session, kwargs.get("sessiondata")) - - elif operation == amp.SDISCONN: # server_session_disconnect - # the server is ordering to disconnect the session - session = portal_sessionhandler.get(sessid) - if session: - portal_sessionhandler.server_disconnect(session, reason=kwargs.get("reason")) - - elif operation == amp.SDISCONNALL: # server_session_disconnect_all - # server orders all sessions to disconnect - portal_sessionhandler.server_disconnect_all(reason=kwargs.get("reason")) - - elif operation == amp.SRELOAD: # server reload - self.factory.server_connection.wait_for_disconnect( - self.start_server, self.factory.portal.server_twistd_cmd - ) - self.stop_server(mode="reload") - - elif operation == amp.SRESET: # server reset - self.factory.server_connection.wait_for_disconnect( - self.start_server, self.factory.portal.server_twistd_cmd - ) - self.stop_server(mode="reset") - - elif operation == amp.SSHUTD: # server-only shutdown - self.stop_server(mode="shutdown") - - elif operation == amp.PSHUTD: # full server+server shutdown - self.factory.server_connection.wait_for_disconnect(self.factory.portal.shutdown) - self.stop_server(mode="shutdown") - - elif operation == amp.PSYNC: # portal sync - # Server has (re-)connected and wants the session data from portal - self.factory.portal.server_info_dict = kwargs.get("info_dict", {}) - self.factory.portal.server_process_id = kwargs.get("spid", None) - # this defaults to 'shutdown' or whatever value set in server_stop - server_restart_mode = self.factory.portal.server_restart_mode - - sessdata = self.factory.portal.sessions.get_all_sync_data() - self.send_AdminPortal2Server( - amp.DUMMYSESSION, - amp.PSYNC, - server_restart_mode=server_restart_mode, - sessiondata=sessdata, - portal_start_time=self.factory.portal.start_time, - ) - self.factory.portal.sessions.at_server_connection() - - if self.factory.server_connection: - # this is an indication the server has successfully connected, so - # we trigger any callbacks (usually to tell the launcher server is up) - for callback, args, kwargs in self.factory.server_connect_callbacks: - try: - callback(*args, **kwargs) - except Exception: - logger.log_trace() - self.factory.server_connect_callbacks = [] - - elif operation == amp.SSYNC: # server_session_sync - # server wants to save session data to the portal, - # maybe because it's about to shut down. - portal_sessionhandler.server_session_sync( - kwargs.get("sessiondata"), kwargs.get("clean", True) - ) - - # set a flag in case we are about to shut down soon - self.factory.server_restart_mode = True - - elif operation == amp.SCONN: # server_force_connection (for irc/etc) - portal_sessionhandler.server_connect(**kwargs) - - else: - raise Exception("operation %(op)s not recognized." % {"op": operation}) - return {}
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/grapevine.html b/docs/0.9.5/_modules/evennia/server/portal/grapevine.html deleted file mode 100644 index f7804789ed..0000000000 --- a/docs/0.9.5/_modules/evennia/server/portal/grapevine.html +++ /dev/null @@ -1,464 +0,0 @@ - - - - - - - - evennia.server.portal.grapevine — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.portal.grapevine

-"""
-Grapevine network connection
-
-This is an implementation of the Grapevine Websocket protocol v 1.0.0 as
-outlined here: https://grapevine.haus/docs
-
-This will allow the linked game to transfer status as well as connects
-the grapevine client to in-game channels.
-
-"""
-
-import json
-from twisted.internet import protocol
-from django.conf import settings
-from evennia.server.session import Session
-from evennia.utils import get_evennia_version
-from evennia.utils.logger import log_info, log_err
-from autobahn.twisted.websocket import WebSocketClientProtocol, WebSocketClientFactory, connectWS
-
-# There is only one at this time
-GRAPEVINE_URI = "wss://grapevine.haus/socket"
-
-GRAPEVINE_CLIENT_ID = settings.GRAPEVINE_CLIENT_ID
-GRAPEVINE_CLIENT_SECRET = settings.GRAPEVINE_CLIENT_SECRET
-GRAPEVINE_CHANNELS = settings.GRAPEVINE_CHANNELS
-
-# defined error codes
-CLOSE_NORMAL = 1000
-GRAPEVINE_AUTH_ERROR = 4000
-GRAPEVINE_HEARTBEAT_FAILURE = 4001
-
-
-
[docs]class RestartingWebsocketServerFactory(WebSocketClientFactory, protocol.ReconnectingClientFactory): - """ - A variant of the websocket-factory that auto-reconnects. - - """ - - initialDelay = 1 - factor = 1.5 - maxDelay = 60 - -
[docs] def __init__(self, sessionhandler, *args, **kwargs): - - self.uid = kwargs.pop("uid") - self.channel = kwargs.pop("grapevine_channel") - self.sessionhandler = sessionhandler - - # self.noisy = False - self.port = None - self.bot = None - - WebSocketClientFactory.__init__(self, GRAPEVINE_URI, *args, **kwargs)
- -
[docs] def buildProtocol(self, addr): - """ - Build new instance of protocol - - Args: - addr (str): Not used, using factory/settings data - - """ - protocol = GrapevineClient() - protocol.factory = self - protocol.channel = self.channel - protocol.sessionhandler = self.sessionhandler - return protocol
- -
[docs] def startedConnecting(self, connector): - """ - Tracks reconnections for debugging. - - Args: - connector (Connector): Represents the connection. - - """ - log_info("(re)connecting to grapevine channel '%s'" % self.channel)
- -
[docs] def clientConnectionFailed(self, connector, reason): - """ - Called when Client failed to connect. - - Args: - connector (Connection): Represents the connection. - reason (str): The reason for the failure. - - """ - protocol.ReconnectingClientFactory.clientConnectionLost(self, connector, reason)
- -
[docs] def clientConnectionLost(self, connector, reason): - """ - Called when Client loses connection. - - Args: - connector (Connection): Represents the connection. - reason (str): The reason for the failure. - - """ - if not (self.bot or (self.bot and self.bot.stopping)): - self.retry(connector)
- -
[docs] def reconnect(self): - """ - Force a reconnection of the bot protocol. This requires - de-registering the session and then reattaching a new one, - otherwise you end up with an ever growing number of bot - sessions. - - """ - self.bot.stopping = True - self.bot.transport.loseConnection() - self.sessionhandler.server_disconnect(self.bot) - self.start()
- -
[docs] def start(self): - "Connect protocol to remote server" - - try: - from twisted.internet import ssl - except ImportError: - log_err("To use Grapevine, The PyOpenSSL module must be installed.") - else: - context_factory = ssl.ClientContextFactory() if self.isSecure else None - connectWS(self, context_factory)
- # service.name = "websocket/grapevine" - # self.sessionhandler.portal.services.addService(service) - - -
[docs]class GrapevineClient(WebSocketClientProtocol, Session): - """ - Implements the grapevine client - """ - -
[docs] def __init__(self): - WebSocketClientProtocol.__init__(self) - Session.__init__(self) - self.restart_downtime = None
- -
[docs] def at_login(self): - pass
- -
[docs] def onOpen(self): - """ - Called when connection is established. - - """ - self.restart_downtime = None - self.restart_task = None - - self.stopping = False - self.factory.bot = self - - self.init_session("grapevine", GRAPEVINE_URI, self.factory.sessionhandler) - self.uid = int(self.factory.uid) - self.logged_in = True - self.sessionhandler.connect(self) - - self.send_authenticate()
- -
[docs] def onMessage(self, payload, isBinary): - """ - Callback fired when a complete WebSocket message was received. - - Args: - payload (bytes): The WebSocket message received. - isBinary (bool): Flag indicating whether payload is binary or - UTF-8 encoded text. - - """ - if not isBinary: - data = json.loads(str(payload, "utf-8")) - self.data_in(data=data) - self.retry_task = None
- -
[docs] def onClose(self, wasClean, code=None, reason=None): - """ - This is executed when the connection is lost for whatever - reason. it can also be called directly, from the disconnect - method. - - Args: - wasClean (bool): ``True`` if the WebSocket was closed cleanly. - code (int or None): Close status as sent by the WebSocket peer. - reason (str or None): Close reason as sent by the WebSocket peer. - - """ - self.disconnect(reason) - - if code == GRAPEVINE_HEARTBEAT_FAILURE: - log_err("Grapevine connection lost (Heartbeat error)") - elif code == GRAPEVINE_AUTH_ERROR: - log_err("Grapevine connection lost (Auth error)") - elif self.restart_downtime: - # server previously warned us about downtime and told us to be - # ready to reconnect. - log_info("Grapevine connection lost (Server restart).")
- - def _send_json(self, data): - """ - Send (json-) data to client. - - Args: - data (str): Text to send. - - """ - return self.sendMessage(json.dumps(data).encode("utf-8")) - -
[docs] def disconnect(self, reason=None): - """ - Generic hook for the engine to call in order to - disconnect this protocol. - - Args: - reason (str or None): Motivation for the disconnection. - - """ - self.sessionhandler.disconnect(self) - # autobahn-python: 1000 for a normal close, 3000-4999 for app. specific, - # in case anyone wants to expose this functionality later. - # - # sendClose() under autobahn/websocket/interfaces.py - self.sendClose(CLOSE_NORMAL, reason)
- - # send_* method are automatically callable through .msg(heartbeat={}) etc - -
[docs] def send_authenticate(self, *args, **kwargs): - """ - Send grapevine authentication. This should be send immediately upon connection. - - """ - data = { - "event": "authenticate", - "payload": { - "client_id": GRAPEVINE_CLIENT_ID, - "client_secret": GRAPEVINE_CLIENT_SECRET, - "supports": ["channels"], - "channels": GRAPEVINE_CHANNELS, - "version": "1.0.0", - "user_agent": get_evennia_version("pretty"), - }, - } - # override on-the-fly - data.update(kwargs) - - self._send_json(data)
- -
[docs] def send_heartbeat(self, *args, **kwargs): - """ - Send heartbeat to remote grapevine server. - - """ - # pass along all connected players - data = {"event": "heartbeat", "payload": {}} - sessions = self.sessionhandler.get_sessions(include_unloggedin=False) - data["payload"]["players"] = [ - sess.account.key for sess in sessions if hasattr(sess, "account") - ] - - self._send_json(data)
- -
[docs] def send_subscribe(self, channelname, *args, **kwargs): - """ - Subscribe to new grapevine channel - - Use with session.msg(subscribe="channelname") - """ - data = {"event": "channels/subscribe", "payload": {"channel": channelname}} - self._send_json(data)
- -
[docs] def send_unsubscribe(self, channelname, *args, **kwargs): - """ - Un-subscribe to a grapevine channel - - Use with session.msg(unsubscribe="channelname") - """ - data = {"event": "channels/unsubscribe", "payload": {"channel": channelname}} - self._send_json(data)
- -
[docs] def send_channel(self, text, channel, sender, *args, **kwargs): - """ - Send text type Evennia -> grapevine - - This is the channels/send message type - - Use with session.msg(channel=(message, channel, sender)) - - """ - - data = { - "event": "channels/send", - "payload": {"message": text, "channel": channel, "name": sender}, - } - self._send_json(data)
- -
[docs] def send_default(self, *args, **kwargs): - """ - Ignore other outputfuncs - - """ - pass
- -
[docs] def data_in(self, data, **kwargs): - """ - Send data grapevine -> Evennia - - Keyword Args: - data (dict): Converted json data. - - """ - event = data["event"] - if event == "authenticate": - # server replies to our auth handshake - if data["status"] != "success": - log_err("Grapevine authentication failed.") - self.disconnect() - else: - log_info("Connected and authenticated to Grapevine network.") - elif event == "heartbeat": - # server sends heartbeat - we have to send one back - self.send_heartbeat() - elif event == "restart": - # set the expected downtime - self.restart_downtime = data["payload"]["downtime"] - elif event == "channels/subscribe": - # subscription verification - if data.get("status", "success") == "failure": - err = data.get("error", "N/A") - self.sessionhandler.data_in( - bot_data_in=((f"Grapevine error: {err}"), {"event": event}) - ) - elif event == "channels/unsubscribe": - # unsubscribe-verification - pass - elif event == "channels/broadcast": - # incoming broadcast from network - payload = data["payload"] - - # print("channels/broadcast:", payload["channel"], self.channel) - if str(payload["channel"]) != self.channel: - # only echo from channels this particular bot actually listens to - return - else: - # correct channel - self.sessionhandler.data_in( - self, - bot_data_in=( - str(payload["message"]), - { - "event": event, - "grapevine_channel": str(payload["channel"]), - "sender": str(payload["name"]), - "game": str(payload["game"]), - }, - ), - ) - elif event == "channels/send": - pass - else: - self.sessionhandler.data_in(self, bot_data_in=("", kwargs))
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/irc.html b/docs/0.9.5/_modules/evennia/server/portal/irc.html deleted file mode 100644 index f4165054ba..0000000000 --- a/docs/0.9.5/_modules/evennia/server/portal/irc.html +++ /dev/null @@ -1,583 +0,0 @@ - - - - - - - - evennia.server.portal.irc — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.portal.irc

-"""
-This connects to an IRC network/channel and launches an 'bot' onto it.
-The bot then pipes what is being said between the IRC channel and one or
-more Evennia channels.
-"""
-
-import re
-from twisted.application import internet
-from twisted.words.protocols import irc
-from twisted.internet import protocol, reactor
-from evennia.server.session import Session
-from evennia.utils import logger, utils, ansi
-
-
-# IRC colors
-
-IRC_BOLD = "\002"
-IRC_COLOR = "\003"
-IRC_RESET = "\017"
-IRC_ITALIC = "\026"
-IRC_INVERT = "\x16"
-IRC_NORMAL = "99"
-IRC_UNDERLINE = "37"
-
-IRC_WHITE = "0"
-IRC_BLACK = "1"
-IRC_DBLUE = "2"
-IRC_DGREEN = "3"
-IRC_RED = "4"
-IRC_DRED = "5"
-IRC_DMAGENTA = "6"
-IRC_DYELLOW = "7"
-IRC_YELLOW = "8"
-IRC_GREEN = "9"
-IRC_DCYAN = "10"
-IRC_CYAN = "11"
-IRC_BLUE = "12"
-IRC_MAGENTA = "13"
-IRC_DGREY = "14"
-IRC_GREY = "15"
-
-# obsolete test:
-
-# test evennia->irc:
-# |rred |ggreen |yyellow |bblue |mmagenta |ccyan |wwhite |xdgrey
-# |Rdred |Gdgreen |Ydyellow |Bdblue |Mdmagenta |Cdcyan |Wlgrey |Xblack
-# |[rredbg |[ggreenbg |[yyellowbg |[bbluebg |[mmagentabg |[ccyanbg |[wlgreybg |[xblackbg
-
-# test irc->evennia
-# Use Ctrl+C <num> to produce mIRC colors in e.g. irssi
-
-IRC_COLOR_MAP = dict(
-    (
-        (r"|n", IRC_COLOR + IRC_NORMAL),  # normal mode
-        (r"|H", IRC_RESET),  # un-highlight
-        (r"|/", "\n"),  # line break
-        (r"|t", "    "),  # tab
-        (r"|-", "    "),  # fixed tab
-        (r"|_", " "),  # space
-        (r"|*", IRC_INVERT),  # invert
-        (r"|^", ""),  # blinking text
-        (r"|h", IRC_BOLD),  # highlight, use bold instead
-        (r"|r", IRC_COLOR + IRC_RED),
-        (r"|g", IRC_COLOR + IRC_GREEN),
-        (r"|y", IRC_COLOR + IRC_YELLOW),
-        (r"|b", IRC_COLOR + IRC_BLUE),
-        (r"|m", IRC_COLOR + IRC_MAGENTA),
-        (r"|c", IRC_COLOR + IRC_CYAN),
-        (r"|w", IRC_COLOR + IRC_WHITE),  # pure white
-        (r"|x", IRC_COLOR + IRC_DGREY),  # dark grey
-        (r"|R", IRC_COLOR + IRC_DRED),
-        (r"|G", IRC_COLOR + IRC_DGREEN),
-        (r"|Y", IRC_COLOR + IRC_DYELLOW),
-        (r"|B", IRC_COLOR + IRC_DBLUE),
-        (r"|M", IRC_COLOR + IRC_DMAGENTA),
-        (r"|C", IRC_COLOR + IRC_DCYAN),
-        (r"|W", IRC_COLOR + IRC_GREY),  # light grey
-        (r"|X", IRC_COLOR + IRC_BLACK),  # pure black
-        (r"|[r", IRC_COLOR + IRC_NORMAL + "," + IRC_DRED),
-        (r"|[g", IRC_COLOR + IRC_NORMAL + "," + IRC_DGREEN),
-        (r"|[y", IRC_COLOR + IRC_NORMAL + "," + IRC_DYELLOW),
-        (r"|[b", IRC_COLOR + IRC_NORMAL + "," + IRC_DBLUE),
-        (r"|[m", IRC_COLOR + IRC_NORMAL + "," + IRC_DMAGENTA),
-        (r"|[c", IRC_COLOR + IRC_NORMAL + "," + IRC_DCYAN),
-        (r"|[w", IRC_COLOR + IRC_NORMAL + "," + IRC_GREY),  # light grey background
-        (r"|[x", IRC_COLOR + IRC_NORMAL + "," + IRC_BLACK),  # pure black background
-    )
-)
-# ansi->irc
-RE_ANSI_COLOR = re.compile(r"|".join([re.escape(key) for key in IRC_COLOR_MAP.keys()]), re.DOTALL)
-RE_MXP = re.compile(r"\|lc(.*?)\|lt(.*?)\|le", re.DOTALL)
-RE_ANSI_ESCAPES = re.compile(r"(%s)" % "|".join(("{{", "%%", "\\\\")), re.DOTALL)
-# irc->ansi
-_CLR_LIST = [
-    re.escape(val) for val in sorted(IRC_COLOR_MAP.values(), key=len, reverse=True) if val.strip()
-]
-_CLR_LIST = _CLR_LIST[-2:] + _CLR_LIST[:-2]
-RE_IRC_COLOR = re.compile(r"|".join(_CLR_LIST), re.DOTALL)
-ANSI_COLOR_MAP = dict((tup[1], tup[0]) for tup in IRC_COLOR_MAP.items() if tup[1].strip())
-
-
-
[docs]def parse_ansi_to_irc(string): - """ - Parse |-type syntax and replace with IRC color markers - - Args: - string (str): String to parse for ANSI colors. - - Returns: - parsed_string (str): String with replaced ANSI colors. - - """ - - def _sub_to_irc(ansi_match): - return IRC_COLOR_MAP.get(ansi_match.group(), "") - - in_string = utils.to_str(string) - parsed_string = [] - parts = RE_ANSI_ESCAPES.split(in_string) + [" "] - for part, sep in zip(parts[::2], parts[1::2]): - pstring = RE_ANSI_COLOR.sub(_sub_to_irc, part) - parsed_string.append("%s%s" % (pstring, sep[0].strip())) - # strip mxp - parsed_string = RE_MXP.sub(r"\2", "".join(parsed_string)) - return parsed_string
- - -
[docs]def parse_irc_to_ansi(string): - """ - Parse IRC mIRC color syntax and replace with Evennia ANSI color markers - - Args: - string (str): String to parse for IRC colors. - - Returns: - parsed_string (str): String with replaced IRC colors. - - """ - - def _sub_to_ansi(irc_match): - return ANSI_COLOR_MAP.get(irc_match.group(), "") - - in_string = utils.to_str(string) - pstring = RE_IRC_COLOR.sub(_sub_to_ansi, in_string) - return pstring
- - -# IRC bot - - -
[docs]class IRCBot(irc.IRCClient, Session): - """ - An IRC bot that tracks activity in a channel as well - as sends text to it when prompted - - """ - - lineRate = 1 - - # assigned by factory at creation - - nickname = None - logger = None - factory = None - channel = None - sourceURL = "http://code.evennia.com" - -
[docs] def signedOn(self): - """ - This is called when we successfully connect to the network. We - make sure to now register with the game as a full session. - - """ - self.join(self.channel) - self.stopping = False - self.factory.bot = self - address = "%s@%s" % (self.channel, self.network) - self.init_session("ircbot", address, self.factory.sessionhandler) - # we link back to our bot and log in - self.uid = int(self.factory.uid) - self.logged_in = True - self.factory.sessionhandler.connect(self) - logger.log_info( - "IRC bot '%s' connected to %s at %s:%s." - % (self.nickname, self.channel, self.network, self.port) - )
- -
[docs] def disconnect(self, reason=""): - """ - Called by sessionhandler to disconnect this protocol. - - Args: - reason (str): Motivation for the disconnect. - - """ - self.sessionhandler.disconnect(self) - self.stopping = True - self.transport.loseConnection()
- -
[docs] def at_login(self): - pass
- -
[docs] def privmsg(self, user, channel, msg): - """ - Called when the connected channel receives a message. - - Args: - user (str): User name sending the message. - channel (str): Channel name seeing the message. - msg (str): The message arriving from channel. - - """ - if channel == self.nickname: - # private message - user = user.split("!", 1)[0] - self.data_in(text=msg, type="privmsg", user=user, channel=channel) - elif not msg.startswith("***"): - # channel message - user = user.split("!", 1)[0] - user = ansi.raw(user) - self.data_in(text=msg, type="msg", user=user, channel=channel)
- -
[docs] def action(self, user, channel, msg): - """ - Called when an action is detected in channel. - - Args: - user (str): User name sending the message. - channel (str): Channel name seeing the message. - msg (str): The message arriving from channel. - - """ - if not msg.startswith("**"): - user = user.split("!", 1)[0] - self.data_in(text=msg, type="action", user=user, channel=channel)
- -
[docs] def get_nicklist(self): - """ - Retrieve name list from the channel. The return - is handled by the catch methods below. - - """ - if not self.nicklist: - self.sendLine("NAMES %s" % self.channel)
- -
[docs] def irc_RPL_NAMREPLY(self, prefix, params): - """"Handles IRC NAME request returns (nicklist)""" - channel = params[2].lower() - if channel != self.channel.lower(): - return - self.nicklist += params[3].split(" ")
- -
[docs] def irc_RPL_ENDOFNAMES(self, prefix, params): - """Called when the nicklist has finished being returned.""" - channel = params[1].lower() - if channel != self.channel.lower(): - return - self.data_in( - text="", type="nicklist", user="server", channel=channel, nicklist=self.nicklist - ) - self.nicklist = []
- -
[docs] def pong(self, user, time): - """ - Called with the return timing from a PING. - - Args: - user (str): Name of user - time (float): Ping time in secs. - - """ - self.data_in(text="", type="ping", user="server", channel=self.channel, timing=time)
- -
[docs] def data_in(self, text=None, **kwargs): - """ - Data IRC -> Server. - - Keyword Args: - text (str): Ingoing text. - kwargs (any): Other data from protocol. - - """ - self.sessionhandler.data_in(self, bot_data_in=[parse_irc_to_ansi(text), kwargs])
- -
[docs] def send_channel(self, *args, **kwargs): - """ - Send channel text to IRC channel (visible to all). Note that - we don't handle the "text" send (it's rerouted to send_default - which does nothing) - this is because the IRC bot is a normal - session and would otherwise report anything that happens to it - to the IRC channel (such as it seeing server reload messages). - - Args: - text (str): Outgoing text - - """ - text = args[0] if args else "" - if text: - text = parse_ansi_to_irc(text) - self.say(self.channel, text)
- -
[docs] def send_privmsg(self, *args, **kwargs): - """ - Send message only to specific user. - - Args: - text (str): Outgoing text. - - Keyword Args: - user (str): the nick to send - privately to. - - """ - text = args[0] if args else "" - user = kwargs.get("user", None) - if text and user: - text = parse_ansi_to_irc(text) - self.msg(user, text)
- -
[docs] def send_request_nicklist(self, *args, **kwargs): - """ - Send a request for the channel nicklist. The return (handled - by `self.irc_RPL_ENDOFNAMES`) will be sent back as a message - with type `nicklist'. - """ - self.get_nicklist()
- -
[docs] def send_ping(self, *args, **kwargs): - """ - Send a ping. The return (handled by `self.pong`) will be sent - back as a message of type 'ping'. - """ - self.ping(self.nickname)
- -
[docs] def send_reconnect(self, *args, **kwargs): - """ - The server instructs us to rebuild the connection by force, - probably because the client silently lost connection. - """ - self.factory.reconnect()
- -
[docs] def send_default(self, *args, **kwargs): - """ - Ignore other types of sends. - - """ - pass
- - -
[docs]class IRCBotFactory(protocol.ReconnectingClientFactory): - """ - Creates instances of IRCBot, connecting with a staggered - increase in delay - - """ - - # scaling reconnect time - initialDelay = 1 - factor = 1.5 - maxDelay = 60 - -
[docs] def __init__( - self, - sessionhandler, - uid=None, - botname=None, - channel=None, - network=None, - port=None, - ssl=None, - ): - """ - Storing some important protocol properties. - - Args: - sessionhandler (SessionHandler): Reference to the main Sessionhandler. - - Keyword Args: - uid (int): Bot user id. - botname (str): Bot name (seen in IRC channel). - channel (str): IRC channel to connect to. - network (str): Network address to connect to. - port (str): Port of the network. - ssl (bool): Indicates SSL connection. - - """ - self.sessionhandler = sessionhandler - self.uid = uid - self.nickname = str(botname) - self.channel = str(channel) - self.network = str(network) - self.port = port - self.ssl = ssl - self.bot = None - self.nicklists = {}
- -
[docs] def buildProtocol(self, addr): - """ - Build the protocol and assign it some properties. - - Args: - addr (str): Not used; using factory data. - - """ - protocol = IRCBot() - protocol.factory = self - protocol.nickname = self.nickname - protocol.channel = self.channel - protocol.network = self.network - protocol.port = self.port - protocol.ssl = self.ssl - protocol.nicklist = [] - return protocol
- -
[docs] def startedConnecting(self, connector): - """ - Tracks reconnections for debugging. - - Args: - connector (Connector): Represents the connection. - - """ - logger.log_info("(re)connecting to %s" % self.channel)
- -
[docs] def clientConnectionFailed(self, connector, reason): - """ - Called when Client failed to connect. - - Args: - connector (Connection): Represents the connection. - reason (str): The reason for the failure. - - """ - self.retry(connector)
- -
[docs] def clientConnectionLost(self, connector, reason): - """ - Called when Client loses connection. - - Args: - connector (Connection): Represents the connection. - reason (str): The reason for the failure. - - """ - if not (self.bot or (self.bot and self.bot.stopping)): - self.retry(connector)
- -
[docs] def reconnect(self): - """ - Force a reconnection of the bot protocol. This requires - de-registering the session and then reattaching a new one, - otherwise you end up with an ever growing number of bot - sessions. - - """ - self.bot.stopping = True - self.bot.transport.loseConnection() - self.sessionhandler.server_disconnect(self.bot) - self.start()
- -
[docs] def start(self): - """ - Connect session to sessionhandler. - - """ - if self.port: - if self.ssl: - try: - from twisted.internet import ssl - - service = reactor.connectSSL( - self.network, int(self.port), self, ssl.ClientContextFactory() - ) - except ImportError: - logger.log_err("To use SSL, the PyOpenSSL module must be installed.") - else: - service = internet.TCPClient(self.network, int(self.port), self) - self.sessionhandler.portal.services.addService(service)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/mccp.html b/docs/0.9.5/_modules/evennia/server/portal/mccp.html deleted file mode 100644 index 39d28462f1..0000000000 --- a/docs/0.9.5/_modules/evennia/server/portal/mccp.html +++ /dev/null @@ -1,194 +0,0 @@ - - - - - - - - evennia.server.portal.mccp — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.portal.mccp

-"""
-
-MCCP - Mud Client Compression Protocol
-
-This implements the MCCP v2 telnet protocol as per
-http://tintin.sourceforge.net/mccp/. MCCP allows for the server to
-compress data when sending to supporting clients, reducing bandwidth
-by 70-90%.. The compression is done using Python's builtin zlib
-library. If the client doesn't support MCCP, server sends uncompressed
-as normal.  Note: On modern hardware you are not likely to notice the
-effect of MCCP unless you have extremely heavy traffic or sits on a
-terribly slow connection.
-
-This protocol is implemented by the telnet protocol importing
-mccp_compress and calling it from its write methods.
-"""
-import zlib
-
-# negotiations for v1 and v2 of the protocol
-MCCP = bytes([86])  # b"\x56"
-FLUSH = zlib.Z_SYNC_FLUSH
-
-
-
[docs]def mccp_compress(protocol, data): - """ - Handles zlib compression, if applicable. - - Args: - data (str): Incoming data to compress. - - Returns: - stream (binary): Zlib-compressed data. - - """ - if hasattr(protocol, "zlib"): - return protocol.zlib.compress(data) + protocol.zlib.flush(FLUSH) - return data
- - -
[docs]class Mccp: - """ - Implements the MCCP protocol. Add this to a - variable on the telnet protocol to set it up. - - """ - -
[docs] def __init__(self, protocol): - """ - initialize MCCP by storing protocol on - ourselves and calling the client to see if - it supports MCCP. Sets callbacks to - start zlib compression in that case. - - Args: - protocol (Protocol): The active protocol instance. - - """ - - self.protocol = protocol - self.protocol.protocol_flags["MCCP"] = False - # ask if client will mccp, connect callbacks to handle answer - self.protocol.will(MCCP).addCallbacks(self.do_mccp, self.no_mccp)
- -
[docs] def no_mccp(self, option): - """ - Called if client doesn't support mccp or chooses to turn it off. - - Args: - option (Option): Option dict (not used). - - """ - if hasattr(self.protocol, "zlib"): - del self.protocol.zlib - self.protocol.protocol_flags["MCCP"] = False - self.protocol.handshake_done()
- -
[docs] def do_mccp(self, option): - """ - The client supports MCCP. Set things up by - creating a zlib compression stream. - - Args: - option (Option): Option dict (not used). - - """ - self.protocol.protocol_flags["MCCP"] = True - self.protocol.requestNegotiation(MCCP, b"") - self.protocol.zlib = zlib.compressobj(9) - self.protocol.handshake_done()
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/mssp.html b/docs/0.9.5/_modules/evennia/server/portal/mssp.html deleted file mode 100644 index 5ee8274a82..0000000000 --- a/docs/0.9.5/_modules/evennia/server/portal/mssp.html +++ /dev/null @@ -1,239 +0,0 @@ - - - - - - - - evennia.server.portal.mssp — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.portal.mssp

-"""
-
-MSSP - Mud Server Status Protocol
-
-This implements the MSSP telnet protocol as per
-http://tintin.sourceforge.net/mssp/.  MSSP allows web portals and
-listings to have their crawlers find the mud and automatically
-extract relevant information about it, such as genre, how many
-active players and so on.
-
-
-"""
-from django.conf import settings
-from evennia.utils import utils
-
-MSSP = bytes([70])  # b"\x46"
-MSSP_VAR = bytes([1])  # b"\x01"
-MSSP_VAL = bytes([2])  # b"\x02"
-
-# try to get the customized mssp info, if it exists.
-MSSPTable_CUSTOM = utils.variable_from_module(settings.MSSP_META_MODULE, "MSSPTable", default={})
-
-
-
[docs]class Mssp: - """ - Implements the MSSP protocol. Add this to a variable on the telnet - protocol to set it up. - - """ - -
[docs] def __init__(self, protocol): - """ - initialize MSSP by storing protocol on ourselves and calling - the client to see if it supports MSSP. - - Args: - protocol (Protocol): The active protocol instance. - - """ - self.protocol = protocol - self.protocol.will(MSSP).addCallbacks(self.do_mssp, self.no_mssp)
- -
[docs] def get_player_count(self): - """ - Get number of logged-in players. - - Returns: - count (int): The number of players in the MUD. - - """ - return str(self.protocol.sessionhandler.count_loggedin())
- -
[docs] def get_uptime(self): - """ - Get how long the portal has been online (reloads are not counted). - - Returns: - uptime (int): Number of seconds of uptime. - - """ - return str(self.protocol.sessionhandler.uptime)
- -
[docs] def no_mssp(self, option): - """ - Called when mssp is not requested. This is the normal - operation. - - Args: - option (Option): Not used. - - """ - self.protocol.handshake_done()
- -
[docs] def do_mssp(self, option): - """ - Negotiate all the information. - - Args: - option (Option): Not used. - - """ - - self.mssp_table = { - # Required fields - "NAME": settings.SERVERNAME, - "PLAYERS": self.get_player_count, - "UPTIME": self.get_uptime, - "PORT": list( - str(port) for port in reversed(settings.TELNET_PORTS) - ), # most important port should be last in list - # Evennia auto-filled - "CRAWL DELAY": "-1", - "CODEBASE": utils.get_evennia_version(mode="pretty"), - "FAMILY": "Custom", - "ANSI": "1", - "GMCP": "1" if settings.TELNET_OOB_ENABLED else "0", - "ATCP": "0", - "MCCP": "1", - "MCP": "0", - "MSDP": "1" if settings.TELNET_OOB_ENABLED else "0", - "MSP": "0", - "MXP": "1", - "PUEBLO": "0", - "SSL": "1" if settings.SSL_ENABLED else "0", - "UTF-8": "1", - "ZMP": "0", - "VT100": "1", - "XTERM 256 COLORS": "1", - } - - # update the static table with the custom one - if MSSPTable_CUSTOM: - self.mssp_table.update(MSSPTable_CUSTOM) - - varlist = b"" - for variable, value in self.mssp_table.items(): - if callable(value): - value = value() - if utils.is_iter(value): - for partval in value: - varlist += ( - MSSP_VAR - + bytes(str(variable), "utf-8") - + MSSP_VAL - + bytes(str(partval), "utf-8") - ) - else: - varlist += ( - MSSP_VAR + bytes(str(variable), "utf-8") + MSSP_VAL + bytes(str(value), "utf-8") - ) - - # send to crawler by subnegotiation - self.protocol.requestNegotiation(MSSP, varlist) - self.protocol.handshake_done()
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/mxp.html b/docs/0.9.5/_modules/evennia/server/portal/mxp.html deleted file mode 100644 index 85872c9440..0000000000 --- a/docs/0.9.5/_modules/evennia/server/portal/mxp.html +++ /dev/null @@ -1,196 +0,0 @@ - - - - - - - - evennia.server.portal.mxp — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.portal.mxp

-"""
-MXP - Mud eXtension Protocol.
-
-Partial implementation of the MXP protocol.
-The MXP protocol allows more advanced formatting options for telnet clients
-that supports it (mudlet, zmud, mushclient are a few)
-
-This only implements the SEND tag.
-
-More information can be found on the following links:
-http://www.zuggsoft.com/zmud/mxp.htm
-http://www.mushclient.com/mushclient/mxp.htm
-http://www.gammon.com.au/mushclient/addingservermxp.htm
-
-"""
-import re
-from django.conf import settings
-
-LINKS_SUB = re.compile(r"\|lc(.*?)\|lt(.*?)\|le", re.DOTALL)
-URL_SUB = re.compile(r"\|lu(.*?)\|lt(.*?)\|le", re.DOTALL)
-
-# MXP Telnet option
-MXP = bytes([91])  # b"\x5b"
-
-MXP_TEMPSECURE = "\x1B[4z"
-MXP_SEND = MXP_TEMPSECURE + '<SEND HREF="\\1">' + "\\2" + MXP_TEMPSECURE + "</SEND>"
-MXP_URL = MXP_TEMPSECURE + '<A HREF="\\1">' + "\\2" + MXP_TEMPSECURE + "</A>"
-
-
-
[docs]def mxp_parse(text): - """ - Replaces links to the correct format for MXP. - - Args: - text (str): The text to parse. - - Returns: - parsed (str): The parsed text. - - """ - text = text.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;") - - text = LINKS_SUB.sub(MXP_SEND, text) - text = URL_SUB.sub(MXP_URL, text) - return text
- - -
[docs]class Mxp: - """ - Implements the MXP protocol. - - """ - -
[docs] def __init__(self, protocol): - """ - Initializes the protocol by checking if the client supports it. - - Args: - protocol (Protocol): The active protocol instance. - - """ - self.protocol = protocol - self.protocol.protocol_flags["MXP"] = False - if settings.MXP_ENABLED: - self.protocol.will(MXP).addCallbacks(self.do_mxp, self.no_mxp)
- -
[docs] def no_mxp(self, option): - """ - Called when the Client reports to not support MXP. - - Args: - option (Option): Not used. - - """ - self.protocol.protocol_flags["MXP"] = False - self.protocol.handshake_done()
- -
[docs] def do_mxp(self, option): - """ - Called when the Client reports to support MXP. - - Args: - option (Option): Not used. - - """ - if settings.MXP_ENABLED: - self.protocol.protocol_flags["MXP"] = True - self.protocol.requestNegotiation(MXP, b"") - else: - self.protocol.wont(MXP) - self.protocol.handshake_done()
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/naws.html b/docs/0.9.5/_modules/evennia/server/portal/naws.html deleted file mode 100644 index 595034d9c5..0000000000 --- a/docs/0.9.5/_modules/evennia/server/portal/naws.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - - - evennia.server.portal.naws — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.portal.naws

-"""
-
-NAWS - Negotiate About Window Size
-
-This implements the NAWS telnet option as per
-https://www.ietf.org/rfc/rfc1073.txt
-
-NAWS allows telnet clients to report their current window size to the
-client and update it when the size changes
-
-"""
-from codecs import encode as codecs_encode
-from django.conf import settings
-
-NAWS = bytes([31])  # b"\x1f"
-IS = bytes([0])  # b"\x00"
-
-# default taken from telnet specification
-DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
-DEFAULT_HEIGHT = settings.CLIENT_DEFAULT_HEIGHT
-
-# try to get the customized mssp info, if it exists.
-
-
-
[docs]class Naws: - """ - Implements the NAWS protocol. Add this to a variable on the telnet - protocol to set it up. - - """ - -
[docs] def __init__(self, protocol): - """ - initialize NAWS by storing protocol on ourselves and calling - the client to see if it supports NAWS. - - Args: - protocol (Protocol): The active protocol instance. - - """ - self.naws_step = 0 - self.protocol = protocol - self.protocol.protocol_flags["SCREENWIDTH"] = { - 0: DEFAULT_WIDTH - } # windowID (0 is root):width - self.protocol.protocol_flags["SCREENHEIGHT"] = {0: DEFAULT_HEIGHT} # windowID:width - self.protocol.negotiationMap[NAWS] = self.negotiate_sizes - self.protocol.do(NAWS).addCallbacks(self.do_naws, self.no_naws)
- -
[docs] def no_naws(self, option): - """ - Called when client is not reporting NAWS. This is the normal - operation. - - Args: - option (Option): Not used. - - """ - self.protocol.handshake_done()
- -
[docs] def do_naws(self, option): - """ - Client wants to negotiate all the NAWS information. - - Args: - option (Option): Not used. - - """ - self.protocol.handshake_done()
- -
[docs] def negotiate_sizes(self, options): - """ - Step through the NAWS handshake. - - Args: - option (list): The incoming NAWS options. - - """ - if len(options) == 4: - # NAWS is negotiated with 16bit words - width = options[0] + options[1] - self.protocol.protocol_flags["SCREENWIDTH"][0] = int(codecs_encode(width, "hex"), 16) - height = options[2] + options[3] - self.protocol.protocol_flags["SCREENHEIGHT"][0] = int(codecs_encode(height, "hex"), 16)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/portal.html b/docs/0.9.5/_modules/evennia/server/portal/portal.html deleted file mode 100644 index 4e5b44646b..0000000000 --- a/docs/0.9.5/_modules/evennia/server/portal/portal.html +++ /dev/null @@ -1,550 +0,0 @@ - - - - - - - - evennia.server.portal.portal — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.portal.portal

-"""
-This module implements the main Evennia server process, the core of
-the game engine.
-
-This module should be started with the 'twistd' executable since it
-sets up all the networking features.  (this is done automatically
-by game/evennia.py).
-
-"""
-import sys
-import os
-import time
-
-from os.path import dirname, abspath
-from twisted.application import internet, service
-from twisted.internet.task import LoopingCall
-from twisted.internet import protocol, reactor
-from twisted.python.log import ILogObserver
-
-import django
-
-django.setup()
-from django.conf import settings
-from django.db import connection
-
-import evennia
-
-evennia._init()
-
-from evennia.utils.utils import get_evennia_version, mod_import, make_iter, class_from_module
-from evennia.server.portal.portalsessionhandler import PORTAL_SESSIONS
-from evennia.utils import logger
-from evennia.server.webserver import EvenniaReverseProxyResource
-
-
-# we don't need a connection to the database so close it right away
-try:
-    connection.close()
-except Exception:
-    pass
-
-PORTAL_SERVICES_PLUGIN_MODULES = [
-    mod_import(module) for module in make_iter(settings.PORTAL_SERVICES_PLUGIN_MODULES)
-]
-LOCKDOWN_MODE = settings.LOCKDOWN_MODE
-
-# -------------------------------------------------------------
-# Evennia Portal settings
-# -------------------------------------------------------------
-
-VERSION = get_evennia_version()
-
-SERVERNAME = settings.SERVERNAME
-
-PORTAL_RESTART = os.path.join(settings.GAME_DIR, "server", "portal.restart")
-
-TELNET_PORTS = settings.TELNET_PORTS
-SSL_PORTS = settings.SSL_PORTS
-SSH_PORTS = settings.SSH_PORTS
-WEBSERVER_PORTS = settings.WEBSERVER_PORTS
-WEBSOCKET_CLIENT_PORT = settings.WEBSOCKET_CLIENT_PORT
-
-TELNET_INTERFACES = ["127.0.0.1"] if LOCKDOWN_MODE else settings.TELNET_INTERFACES
-SSL_INTERFACES = ["127.0.0.1"] if LOCKDOWN_MODE else settings.SSL_INTERFACES
-SSH_INTERFACES = ["127.0.0.1"] if LOCKDOWN_MODE else settings.SSH_INTERFACES
-WEBSERVER_INTERFACES = ["127.0.0.1"] if LOCKDOWN_MODE else settings.WEBSERVER_INTERFACES
-WEBSOCKET_CLIENT_INTERFACE = "127.0.0.1" if LOCKDOWN_MODE else settings.WEBSOCKET_CLIENT_INTERFACE
-WEBSOCKET_CLIENT_URL = settings.WEBSOCKET_CLIENT_URL
-
-TELNET_ENABLED = settings.TELNET_ENABLED and TELNET_PORTS and TELNET_INTERFACES
-SSL_ENABLED = settings.SSL_ENABLED and SSL_PORTS and SSL_INTERFACES
-SSH_ENABLED = settings.SSH_ENABLED and SSH_PORTS and SSH_INTERFACES
-WEBSERVER_ENABLED = settings.WEBSERVER_ENABLED and WEBSERVER_PORTS and WEBSERVER_INTERFACES
-WEBCLIENT_ENABLED = settings.WEBCLIENT_ENABLED
-WEBSOCKET_CLIENT_ENABLED = (
-    settings.WEBSOCKET_CLIENT_ENABLED and WEBSOCKET_CLIENT_PORT and WEBSOCKET_CLIENT_INTERFACE
-)
-
-AMP_HOST = settings.AMP_HOST
-AMP_PORT = settings.AMP_PORT
-AMP_INTERFACE = settings.AMP_INTERFACE
-AMP_ENABLED = AMP_HOST and AMP_PORT and AMP_INTERFACE
-
-INFO_DICT = {
-    "servername": SERVERNAME,
-    "version": VERSION,
-    "errors": "",
-    "info": "",
-    "lockdown_mode": "",
-    "amp": "",
-    "telnet": [],
-    "telnet_ssl": [],
-    "ssh": [],
-    "webclient": [],
-    "webserver_proxy": [],
-    "webserver_internal": [],
-}
-
-try:
-    WEB_PLUGINS_MODULE = mod_import(settings.WEB_PLUGINS_MODULE)
-except ImportError:
-    WEB_PLUGINS_MODULE = None
-    INFO_DICT["errors"] = (
-        "WARNING: settings.WEB_PLUGINS_MODULE not found - "
-        "copy 'evennia/game_template/server/conf/web_plugins.py to "
-        "mygame/server/conf."
-    )
-
-
-_MAINTENANCE_COUNT = 0
-
-
-def _portal_maintenance():
-    """
-    Repeated maintenance tasks for the portal.
-
-    """
-    global _MAINTENANCE_COUNT
-
-    _MAINTENANCE_COUNT += 1
-
-    if _MAINTENANCE_COUNT % (60 * 7) == 0:
-        # drop database connection every 7 hrs to avoid default timeouts on MySQL
-        # (see https://github.com/evennia/evennia/issues/1376)
-        connection.close()
-
-
-# -------------------------------------------------------------
-# Portal Service object
-# -------------------------------------------------------------
-
-
-
[docs]class Portal(object): - - """ - The main Portal server handler. This object sets up the database - and tracks and interlinks all the twisted network services that - make up Portal. - - """ - -
[docs] def __init__(self, application): - """ - Setup the server. - - Args: - application (Application): An instantiated Twisted application - - """ - sys.path.append(".") - - # create a store of services - self.services = service.MultiService() - self.services.setServiceParent(application) - self.amp_protocol = None # set by amp factory - self.sessions = PORTAL_SESSIONS - self.sessions.portal = self - self.process_id = os.getpid() - - self.server_process_id = None - self.server_restart_mode = "shutdown" - self.server_info_dict = {} - - self.start_time = time.time() - - self.maintenance_task = LoopingCall(_portal_maintenance) - self.maintenance_task.start(60, now=True) # call every minute - - # in non-interactive portal mode, this gets overwritten by - # cmdline sent by the evennia launcher - self.server_twistd_cmd = self._get_backup_server_twistd_cmd() - - # set a callback if the server is killed abruptly, - # by Ctrl-C, reboot etc. - reactor.addSystemEventTrigger( - "before", "shutdown", self.shutdown, _reactor_stopping=True, _stop_server=True - )
- - def _get_backup_server_twistd_cmd(self): - """ - For interactive Portal mode there is no way to get the server cmdline from the launcher, so - we need to guess it here (it's very likely to not change) - - Returns: - server_twistd_cmd (list): An instruction for starting the server, to pass to Popen. - - """ - server_twistd_cmd = [ - "twistd", - "--python={}".format(os.path.join(dirname(dirname(abspath(__file__))), "server.py")), - ] - if os.name != "nt": - gamedir = os.getcwd() - server_twistd_cmd.append( - "--pidfile={}".format(os.path.join(gamedir, "server", "server.pid")) - ) - return server_twistd_cmd - -
[docs] def get_info_dict(self): - """ - Return the Portal info, for display. - - """ - return INFO_DICT
- -
[docs] def shutdown(self, _reactor_stopping=False, _stop_server=False): - """ - Shuts down the server from inside it. - - Args: - _reactor_stopping (bool, optional): This is set if server - is already in the process of shutting down; in this case - we don't need to stop it again. - _stop_server (bool, optional): Only used in portal-interactive mode; - makes sure to stop the Server cleanly. - - Note that restarting (regardless of the setting) will not work - if the Portal is currently running in daemon mode. In that - case it always needs to be restarted manually. - - """ - if _reactor_stopping and hasattr(self, "shutdown_complete"): - # we get here due to us calling reactor.stop below. No need - # to do the shutdown procedure again. - return - - self.sessions.disconnect_all() - if _stop_server: - self.amp_protocol.stop_server(mode="shutdown") - if not _reactor_stopping: - # shutting down the reactor will trigger another signal. We set - # a flag to avoid loops. - self.shutdown_complete = True - reactor.callLater(0, reactor.stop)
- - -# ------------------------------------------------------------- -# -# Start the Portal proxy server and add all active services -# -# ------------------------------------------------------------- - - -# twistd requires us to define the variable 'application' so it knows -# what to execute from. -application = service.Application("Portal") - -# custom logging - -if "--nodaemon" not in sys.argv: - logfile = logger.WeeklyLogFile( - os.path.basename(settings.PORTAL_LOG_FILE), - os.path.dirname(settings.PORTAL_LOG_FILE), - day_rotation=settings.PORTAL_LOG_DAY_ROTATION, - max_size=settings.PORTAL_LOG_MAX_SIZE, - ) - application.setComponent(ILogObserver, logger.PortalLogObserver(logfile).emit) - -# The main Portal server program. This sets up the database -# and is where we store all the other services. -PORTAL = Portal(application) - -if LOCKDOWN_MODE: - - INFO_DICT["lockdown_mode"] = " LOCKDOWN_MODE active: Only local connections." - -if AMP_ENABLED: - - # The AMP protocol handles the communication between - # the portal and the mud server. Only reason to ever deactivate - # it would be during testing and debugging. - - from evennia.server.portal import amp_server - - INFO_DICT["amp"] = "amp: %s" % AMP_PORT - - factory = amp_server.AMPServerFactory(PORTAL) - amp_service = internet.TCPServer(AMP_PORT, factory, interface=AMP_INTERFACE) - amp_service.setName("PortalAMPServer") - PORTAL.services.addService(amp_service) - - -# We group all the various services under the same twisted app. -# These will gradually be started as they are initialized below. - -if TELNET_ENABLED: - - # Start telnet game connections - - from evennia.server.portal import telnet - - _telnet_protocol = class_from_module(settings.TELNET_PROTOCOL_CLASS) - - for interface in TELNET_INTERFACES: - ifacestr = "" - if interface not in ("0.0.0.0", "::") or len(TELNET_INTERFACES) > 1: - ifacestr = "-%s" % interface - for port in TELNET_PORTS: - pstring = "%s:%s" % (ifacestr, port) - factory = telnet.TelnetServerFactory() - factory.noisy = False - factory.protocol = _telnet_protocol - factory.sessionhandler = PORTAL_SESSIONS - telnet_service = internet.TCPServer(port, factory, interface=interface) - telnet_service.setName("EvenniaTelnet%s" % pstring) - PORTAL.services.addService(telnet_service) - - INFO_DICT["telnet"].append("telnet%s: %s" % (ifacestr, port)) - - -if SSL_ENABLED: - - # Start Telnet+SSL game connection (requires PyOpenSSL). - - from evennia.server.portal import telnet_ssl - - _ssl_protocol = class_from_module(settings.SSL_PROTOCOL_CLASS) - - for interface in SSL_INTERFACES: - ifacestr = "" - if interface not in ("0.0.0.0", "::") or len(SSL_INTERFACES) > 1: - ifacestr = "-%s" % interface - for port in SSL_PORTS: - pstring = "%s:%s" % (ifacestr, port) - factory = protocol.ServerFactory() - factory.noisy = False - factory.sessionhandler = PORTAL_SESSIONS - factory.protocol = _ssl_protocol - - ssl_context = telnet_ssl.getSSLContext() - if ssl_context: - ssl_service = internet.SSLServer( - port, factory, telnet_ssl.getSSLContext(), interface=interface - ) - ssl_service.setName("EvenniaSSL%s" % pstring) - PORTAL.services.addService(ssl_service) - - INFO_DICT["telnet_ssl"].append("telnet+ssl%s: %s" % (ifacestr, port)) - else: - INFO_DICT["telnet_ssl"].append( - "telnet+ssl%s: %s (deactivated - keys/cert unset)" % (ifacestr, port) - ) - - -if SSH_ENABLED: - - # Start SSH game connections. Will create a keypair in - # evennia/game if necessary. - - from evennia.server.portal import ssh - - _ssh_protocol = class_from_module(settings.SSH_PROTOCOL_CLASS) - - for interface in SSH_INTERFACES: - ifacestr = "" - if interface not in ("0.0.0.0", "::") or len(SSH_INTERFACES) > 1: - ifacestr = "-%s" % interface - for port in SSH_PORTS: - pstring = "%s:%s" % (ifacestr, port) - factory = ssh.makeFactory( - {"protocolFactory": _ssh_protocol, - "protocolArgs": (), "sessions": PORTAL_SESSIONS} - ) - factory.noisy = False - ssh_service = internet.TCPServer(port, factory, interface=interface) - ssh_service.setName("EvenniaSSH%s" % pstring) - PORTAL.services.addService(ssh_service) - - INFO_DICT["ssh"].append("ssh%s: %s" % (ifacestr, port)) - - -if WEBSERVER_ENABLED: - from evennia.server.webserver import Website - - # Start a reverse proxy to relay data to the Server-side webserver - - websocket_started = False - _websocket_protocol = class_from_module(settings.WEBSOCKET_PROTOCOL_CLASS) - for interface in WEBSERVER_INTERFACES: - ifacestr = "" - if interface not in ("0.0.0.0", "::") or len(WEBSERVER_INTERFACES) > 1: - ifacestr = "-%s" % interface - for proxyport, serverport in WEBSERVER_PORTS: - web_root = EvenniaReverseProxyResource("127.0.0.1", serverport, "") - webclientstr = "" - if WEBCLIENT_ENABLED: - # create ajax client processes at /webclientdata - from evennia.server.portal import webclient_ajax - - ajax_webclient = webclient_ajax.AjaxWebClient() - ajax_webclient.sessionhandler = PORTAL_SESSIONS - web_root.putChild(b"webclientdata", ajax_webclient) - webclientstr = "webclient (ajax only)" - - if WEBSOCKET_CLIENT_ENABLED and not websocket_started: - # start websocket client port for the webclient - # we only support one websocket client - from evennia.server.portal import webclient # noqa - from autobahn.twisted.websocket import WebSocketServerFactory - - w_interface = WEBSOCKET_CLIENT_INTERFACE - w_ifacestr = "" - if w_interface not in ("0.0.0.0", "::") or len(WEBSERVER_INTERFACES) > 1: - w_ifacestr = "-%s" % w_interface - port = WEBSOCKET_CLIENT_PORT - -
[docs] class Websocket(WebSocketServerFactory): - "Only here for better naming in logs" - pass
- - factory = Websocket() - factory.noisy = False - factory.protocol = _websocket_protocol - factory.sessionhandler = PORTAL_SESSIONS - websocket_service = internet.TCPServer(port, factory, interface=w_interface) - websocket_service.setName("EvenniaWebSocket%s:%s" % (w_ifacestr, port)) - PORTAL.services.addService(websocket_service) - websocket_started = True - webclientstr = "webclient-websocket%s: %s" % (w_ifacestr, port) - INFO_DICT["webclient"].append(webclientstr) - - if WEB_PLUGINS_MODULE: - try: - web_root = WEB_PLUGINS_MODULE.at_webproxy_root_creation(web_root) - except Exception: - # Legacy user has not added an at_webproxy_root_creation function in existing - # web plugins file - INFO_DICT["errors"] = ( - "WARNING: WEB_PLUGINS_MODULE is enabled but at_webproxy_root_creation() " - "not found copy 'evennia/game_template/server/conf/web_plugins.py to " - "mygame/server/conf." - ) - web_root = Website(web_root, logPath=settings.HTTP_LOG_FILE) - web_root.is_portal = True - proxy_service = internet.TCPServer(proxyport, web_root, interface=interface) - proxy_service.setName("EvenniaWebProxy%s:%s" % (ifacestr, proxyport)) - PORTAL.services.addService(proxy_service) - INFO_DICT["webserver_proxy"].append("webserver-proxy%s: %s" % (ifacestr, proxyport)) - INFO_DICT["webserver_internal"].append("webserver: %s" % serverport) - - -for plugin_module in PORTAL_SERVICES_PLUGIN_MODULES: - # external plugin services to start - if plugin_module: - plugin_module.start_plugin_services(PORTAL) -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/portalsessionhandler.html b/docs/0.9.5/_modules/evennia/server/portal/portalsessionhandler.html deleted file mode 100644 index e25252734a..0000000000 --- a/docs/0.9.5/_modules/evennia/server/portal/portalsessionhandler.html +++ /dev/null @@ -1,592 +0,0 @@ - - - - - - - - evennia.server.portal.portalsessionhandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.portal.portalsessionhandler

-"""
-Sessionhandler for portal sessions.
-
-"""
-
-
-import time
-from collections import deque, namedtuple
-from twisted.internet import reactor
-from django.conf import settings
-from evennia.server.sessionhandler import SessionHandler
-from evennia.server.portal.amp import PCONN, PDISCONN, PCONNSYNC, PDISCONNALL
-from evennia.utils.logger import log_trace
-from evennia.utils.utils import class_from_module
-from django.utils.translation import gettext as _
-
-# module import
-_MOD_IMPORT = None
-
-# global throttles
-_MAX_CONNECTION_RATE = float(settings.MAX_CONNECTION_RATE)
-# per-session throttles
-_MAX_COMMAND_RATE = float(settings.MAX_COMMAND_RATE)
-_MAX_CHAR_LIMIT = int(settings.MAX_CHAR_LIMIT)
-
-_MIN_TIME_BETWEEN_CONNECTS = 1.0 / float(_MAX_CONNECTION_RATE)
-_MIN_TIME_BETWEEN_COMMANDS = 1.0 / float(_MAX_COMMAND_RATE)
-
-_ERROR_COMMAND_OVERFLOW = settings.COMMAND_RATE_WARNING
-_ERROR_MAX_CHAR = settings.MAX_CHAR_LIMIT_WARNING
-
-_CONNECTION_QUEUE = deque()
-
-DUMMYSESSION = namedtuple("DummySession", ["sessid"])(0)
-
-# -------------------------------------------------------------
-# Portal-SessionHandler class
-# -------------------------------------------------------------
-
-DOS_PROTECTION_MSG = _("{servername} DoS protection is active."
-                       "You are queued to connect in {num} seconds ...")
-
-
-
[docs]class PortalSessionHandler(SessionHandler): - """ - This object holds the sessions connected to the portal at any time. - It is synced with the server's equivalent SessionHandler over the AMP - connection. - - Sessions register with the handler using the connect() method. This - will assign a new unique sessionid to the session and send that sessid - to the server using the AMP connection. - - """ - -
[docs] def __init__(self, *args, **kwargs): - """ - Init the handler - - """ - super().__init__(*args, **kwargs) - self.portal = None - self.latest_sessid = 0 - self.uptime = time.time() - self.connection_time = 0 - - self.connection_last = self.uptime - self.connection_task = None
- -
[docs] def at_server_connection(self): - """ - Called when the Portal establishes connection with the Server. - At this point, the AMP connection is already established. - - """ - self.connection_time = time.time()
- -
[docs] def generate_sessid(self): - """ - Simply generates a sessid that's guaranteed to be unique for this Portal run. - - Returns: - sessid - - """ - self.latest_sessid += 1 - if self.latest_sessid in self: - return self.generate_sessid() - return self.latest_sessid
- -
[docs] def connect(self, session): - """ - Called by protocol at first connect. This adds a not-yet - authenticated session using an ever-increasing counter for - sessid. - - Args: - session (PortalSession): The Session connecting. - - Notes: - We implement a throttling mechanism here to limit the speed at - which new connections are accepted - this is both a stop - against DoS attacks as well as helps using the Dummyrunner - tester with a large number of connector dummies. - - """ - global _CONNECTION_QUEUE - - if session: - # assign if we are first-connectors - if not session.sessid: - # if the session already has a sessid (e.g. being inherited in the - # case of a webclient auto-reconnect), keep it - session.sessid = self.generate_sessid() - session.server_connected = False - _CONNECTION_QUEUE.appendleft(session) - if len(_CONNECTION_QUEUE) > 1: - session.data_out( - text=( - (DOS_PROTECTION_MSG.format( - servername=settings.SERVERNAME, - num=len(_CONNECTION_QUEUE) * _MIN_TIME_BETWEEN_CONNECTS),), - {}, - ) - ) - now = time.time() - if ( - now - self.connection_last < _MIN_TIME_BETWEEN_CONNECTS - ) or not self.portal.amp_protocol: - if not session or not self.connection_task: - self.connection_task = reactor.callLater( - _MIN_TIME_BETWEEN_CONNECTS, self.connect, None - ) - self.connection_last = now - return - elif not session: - if _CONNECTION_QUEUE: - # keep launching tasks until queue is empty - self.connection_task = reactor.callLater( - _MIN_TIME_BETWEEN_CONNECTS, self.connect, None - ) - else: - self.connection_task = None - self.connection_last = now - - if _CONNECTION_QUEUE: - # sync with server-side - session = _CONNECTION_QUEUE.pop() - sessdata = session.get_sync_data() - - self[session.sessid] = session - session.server_connected = True - self.portal.amp_protocol.send_AdminPortal2Server( - session, operation=PCONN, sessiondata=sessdata - )
- -
[docs] def sync(self, session): - """ - Called by the protocol of an already connected session. This - can be used to sync the session info in a delayed manner, such - as when negotiation and handshakes are delayed. - - Args: - session (PortalSession): Session to sync. - - """ - if session.sessid and session.server_connected: - # only use if session already has sessid and has already connected - # once to the server - if so we must re-sync woth the server, otherwise - # we skip this step. - sessdata = session.get_sync_data() - if self.portal.amp_protocol: - # we only send sessdata that should not have changed - # at the server level at this point - sessdata = dict( - (key, val) - for key, val in sessdata.items() - if key - in ( - "protocol_key", - "address", - "sessid", - "csessid", - "conn_time", - "protocol_flags", - "server_data", - ) - ) - self.portal.amp_protocol.send_AdminPortal2Server( - session, operation=PCONNSYNC, sessiondata=sessdata - )
- -
[docs] def disconnect(self, session): - """ - Called from portal when the connection is closed from the - portal side. - - Args: - session (PortalSession): Session to disconnect. - delete (bool, optional): Delete the session from - the handler. Only time to not do this is when - this is called from a loop, such as from - self.disconnect_all(). - - """ - global _CONNECTION_QUEUE - if session in _CONNECTION_QUEUE: - # connection was already dropped before we had time - # to forward this to the Server, so now we just remove it. - _CONNECTION_QUEUE.remove(session) - return - - if session.sessid in self and not hasattr(self, "_disconnect_all"): - # if this was called directly from the protocol, the - # connection is already dead and we just need to cleanup - del self[session.sessid] - - # Tell the Server to disconnect its version of the Session as well. - self.portal.amp_protocol.send_AdminPortal2Server(session, operation=PDISCONN)
- -
[docs] def disconnect_all(self): - """ - Disconnect all sessions, informing the Server. - - """ - - def _callback(result, sessionhandler): - # we set a watchdog to stop self.disconnect from deleting - # sessions while we are looping over them. - sessionhandler._disconnect_all = True - for session in sessionhandler.values(): - session.disconnect() - del sessionhandler._disconnect_all - - # inform Server; wait until finished sending before we continue - # removing all the sessions. - self.portal.amp_protocol.send_AdminPortal2Server( - DUMMYSESSION, operation=PDISCONNALL - ).addCallback(_callback, self)
- -
[docs] def server_connect(self, protocol_path="", config=dict()): - """ - Called by server to force the initialization of a new protocol - instance. Server wants this instance to get a unique sessid and to be - connected back as normal. This is used to initiate irc/rss etc - connections. - - Args: - protocol_path (str): Full python path to the class factory - for the protocol used, eg - 'evennia.server.portal.irc.IRCClientFactory' - config (dict): Dictionary of configuration options, fed as - `**kwarg` to protocol class `__init__` method. - - Raises: - RuntimeError: If The correct factory class is not found. - - Notes: - The called protocol class must have a method start() - that calls the portalsession.connect() as a normal protocol. - - """ - global _MOD_IMPORT - if not _MOD_IMPORT: - from evennia.utils.utils import variable_from_module as _MOD_IMPORT - path, clsname = protocol_path.rsplit(".", 1) - cls = _MOD_IMPORT(path, clsname) - if not cls: - raise RuntimeError("ServerConnect: protocol factory '%s' not found." % protocol_path) - protocol = cls(self, **config) - protocol.start()
- -
[docs] def server_disconnect(self, session, reason=""): - """ - Called by server to force a disconnect by sessid. - - Args: - session (portalsession): Session to disconnect. - reason (str, optional): Motivation for disconnect. - - """ - if session: - session.disconnect(reason) - if session.sessid in self: - # in case sess.disconnect doesn't delete it - del self[session.sessid] - del session
- -
[docs] def server_disconnect_all(self, reason=""): - """ - Called by server when forcing a clean disconnect for everyone. - - Args: - reason (str, optional): Motivation for disconnect. - - """ - for session in list(self.values()): - session.disconnect(reason) - del session - self.clear()
- -
[docs] def server_logged_in(self, session, data): - """ - The server tells us that the session has been authenticated. - Update it. Called by the Server. - - Args: - session (Session): Session logging in. - data (dict): The session sync data. - - """ - session.load_sync_data(data) - session.at_login()
- -
[docs] def server_session_sync(self, serversessions, clean=True): - """ - Server wants to save data to the portal, maybe because it's - about to shut down. We don't overwrite any sessions here, just - update them in-place. - - Args: - serversessions (dict): This is a dictionary - - `{sessid:{property:value},...}` describing - the properties to sync on all sessions. - clean (bool): If True, remove any Portal sessions that are - not included in serversessions. - """ - to_save = [sessid for sessid in serversessions if sessid in self] - # save protocols - for sessid in to_save: - self[sessid].load_sync_data(serversessions[sessid]) - if clean: - # disconnect out-of-sync missing protocols - to_delete = [sessid for sessid in self if sessid not in to_save] - for sessid in to_delete: - self.server_disconnect(sessid)
- -
[docs] def count_loggedin(self, include_unloggedin=False): - """ - Count loggedin connections, alternatively count all connections. - - Args: - include_unloggedin (bool): Also count sessions that have - not yet authenticated. - - Returns: - count (int): Number of sessions. - - """ - return len(self.get_sessions(include_unloggedin=include_unloggedin))
- -
[docs] def sessions_from_csessid(self, csessid): - """ - Given a session id, retrieve the session (this is primarily - intended to be called by web clients) - - Args: - csessid (int): Session id. - - Returns: - session (list): The matching session, if found. - - """ - return [ - sess - for sess in self.get_sessions(include_unloggedin=True) - if hasattr(sess, "csessid") and sess.csessid and sess.csessid == csessid - ]
- -
[docs] def announce_all(self, message): - """ - Send message to all connected sessions. - - Args: - message (str): Message to relay. - - Notes: - This will create an on-the fly text-type - send command. - - """ - for session in self.values(): - self.data_out(session, text=[[message], {}])
- -
[docs] def data_in(self, session, **kwargs): - """ - Called by portal sessions for relaying data coming - in from the protocol to the server. - - Args: - session (PortalSession): Session receiving data. - - Keyword Args: - kwargs (any): Other data from protocol. - - Notes: - Data is serialized before passed on. - - """ - try: - text = kwargs["text"] - if (_MAX_CHAR_LIMIT > 0) and len(text) > _MAX_CHAR_LIMIT: - if session: - self.data_out(session, text=[[_ERROR_MAX_CHAR], {}]) - return - except Exception: - # if there is a problem to send, we continue - pass - if session: - now = time.time() - - try: - command_counter_reset = session.command_counter_reset - except AttributeError: - command_counter_reset = session.command_counter_reset = now - session.command_counter = 0 - - # global command-rate limit - if max(0, now - command_counter_reset) > 1.0: - # more than a second since resetting the counter. Refresh. - session.command_counter_reset = now - session.command_counter = 0 - - session.command_counter += 1 - - if session.command_counter * _MIN_TIME_BETWEEN_COMMANDS > 1.0: - self.data_out(session, text=[[_ERROR_COMMAND_OVERFLOW], {}]) - return - - if not self.portal.amp_protocol: - # this can happen if someone connects before AMP connection - # was established (usually on first start) - reactor.callLater(1.0, self.data_in, session, **kwargs) - return - - # scrub data - kwargs = self.clean_senddata(session, kwargs) - - # relay data to Server - session.cmd_last = now - self.portal.amp_protocol.send_MsgPortal2Server(session, **kwargs) - - # eventual local echo (text input only) - if 'text' in kwargs and session.protocol_flags.get('LOCALECHO', False): - self.data_out(session, text=kwargs['text'])
- -
[docs] def data_out(self, session, **kwargs): - """ - Called by server for having the portal relay messages and data - to the correct session protocol. - - Args: - session (Session): Session sending data. - - Keyword Args: - kwargs (any): Each key is a command instruction to the - protocol on the form key = [[args],{kwargs}]. This will - call a method send_<key> on the protocol. If no such - method exixts, it sends the data to a method send_default. - - """ - # from evennia.server.profiling.timetrace import timetrace # DEBUG - # text = timetrace(text, "portalsessionhandler.data_out") # DEBUG - - # distribute outgoing data to the correct session methods. - if session: - for cmdname, (cmdargs, cmdkwargs) in kwargs.items(): - funcname = "send_%s" % cmdname.strip().lower() - if hasattr(session, funcname): - # better to use hassattr here over try..except - # - avoids hiding AttributeErrors in the call. - try: - getattr(session, funcname)(*cmdargs, **cmdkwargs) - except Exception: - log_trace() - else: - try: - # note that send_default always takes cmdname - # as arg too. - session.send_default(cmdname, *cmdargs, **cmdkwargs) - except Exception: - log_trace()
- - -_PORTAL_SESSION_HANDLER_CLASS = class_from_module(settings.PORTAL_SESSION_HANDLER_CLASS) -PORTAL_SESSIONS = _PORTAL_SESSION_HANDLER_CLASS() -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/rss.html b/docs/0.9.5/_modules/evennia/server/portal/rss.html deleted file mode 100644 index a19b1d3c44..0000000000 --- a/docs/0.9.5/_modules/evennia/server/portal/rss.html +++ /dev/null @@ -1,269 +0,0 @@ - - - - - - - - evennia.server.portal.rss — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.portal.rss

-"""
-RSS parser for Evennia
-
-This connects an RSS feed to an in-game Evennia channel, sending messages
-to the channel whenever the feed updates.
-
-"""
-from twisted.internet import task, threads
-from django.conf import settings
-from evennia.server.session import Session
-from evennia.utils import logger
-
-RSS_ENABLED = settings.RSS_ENABLED
-# RETAG = re.compile(r'<[^>]*?>')
-
-if RSS_ENABLED:
-    try:
-        import feedparser
-    except ImportError:
-        raise ImportError(
-            "RSS requires python-feedparser to be installed. Install or set RSS_ENABLED=False."
-        )
-
-
-
[docs]class RSSReader(Session): - """ - A simple RSS reader using the feedparser module. - - """ - -
[docs] def __init__(self, factory, url, rate): - """ - Initialize the reader. - - Args: - factory (RSSFactory): The protocol factory. - url (str): The RSS url. - rate (int): The seconds between RSS lookups. - - """ - self.url = url - self.rate = rate - self.factory = factory - self.old_entries = {}
- -
[docs] def get_new(self): - """ - Returns list of new items. - - """ - feed = feedparser.parse(self.url) - new_entries = [] - for entry in feed["entries"]: - idval = entry["id"] + entry.get("updated", "") - if idval not in self.old_entries: - self.old_entries[idval] = entry - new_entries.append(entry) - return new_entries
- -
[docs] def disconnect(self, reason=None): - """ - Disconnect from feed. - - Args: - reason (str, optional): Motivation for the disconnect. - - """ - if self.factory.task and self.factory.task.running: - self.factory.task.stop() - self.sessionhandler.disconnect(self)
- - def _callback(self, new_entries, init): - """ - Called when RSS returns. - - Args: - new_entries (list): List of new RSS entries since last. - init (bool): If this is a startup operation (at which - point all entries are considered new). - - """ - if not init: - # for initialization we just ignore old entries - for entry in reversed(new_entries): - self.data_in(entry) - -
[docs] def data_in(self, text=None, **kwargs): - """ - Data RSS -> Evennia. - - Keyword Args: - text (str): Incoming text - kwargs (any): Options from protocol. - - """ - self.sessionhandler.data_in(self, bot_data_in=text, **kwargs)
- - def _errback(self, fail): - "Report error" - logger.log_err("RSS feed error: %s" % fail.value) - -
[docs] def update(self, init=False): - """ - Request the latest version of feed. - - Args: - init (bool, optional): If this is an initialization call - or not (during init, all entries are conidered new). - - Notes: - This call is done in a separate thread to avoid blocking - on slow connections. - - """ - return ( - threads.deferToThread(self.get_new) - .addCallback(self._callback, init) - .addErrback(self._errback) - )
- - -
[docs]class RSSBotFactory(object): - """ - Initializes new bots. - """ - -
[docs] def __init__(self, sessionhandler, uid=None, url=None, rate=None): - """ - Initialize the bot. - - Args: - sessionhandler (PortalSessionHandler): The main sessionhandler object. - uid (int): User id for the bot. - url (str): The RSS URL. - rate (int): How often for the RSS to request the latest RSS entries. - - """ - self.sessionhandler = sessionhandler - self.url = url - self.rate = rate - self.uid = uid - self.bot = RSSReader(self, url, rate) - self.task = None
- -
[docs] def start(self): - """ - Called by portalsessionhandler. Starts the bot. - - """ - - def errback(fail): - logger.log_err(fail.value) - - # set up session and connect it to sessionhandler - self.bot.init_session("rssbot", self.url, self.sessionhandler) - self.bot.uid = self.uid - self.bot.logged_in = True - self.sessionhandler.connect(self.bot) - - # start repeater task - self.bot.update(init=True) - self.task = task.LoopingCall(self.bot.update) - if self.rate: - self.task.start(self.rate, now=False).addErrback(errback)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/ssh.html b/docs/0.9.5/_modules/evennia/server/portal/ssh.html deleted file mode 100644 index 9200951cc8..0000000000 --- a/docs/0.9.5/_modules/evennia/server/portal/ssh.html +++ /dev/null @@ -1,633 +0,0 @@ - - - - - - - - evennia.server.portal.ssh — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.portal.ssh

-"""
-This module implements the ssh (Secure SHell) protocol for encrypted
-connections.
-
-This depends on a generic session module that implements the actual
-login procedure of the game, tracks sessions etc.
-
-Using standard ssh client,
-
-"""
-
-import os
-import re
-
-from twisted.cred.checkers import credentials
-from twisted.cred.portal import Portal
-from twisted.conch.interfaces import IConchUser
-
-_SSH_IMPORT_ERROR = """
-ERROR: Missing crypto library for SSH. Install it with
-
-       pip install cryptography pyasn1 bcrypt
-
-(On older Twisted versions you may have to do 'pip install pycrypto pyasn1' instead).
-
-If you get a compilation error you must install a C compiler and the
-SSL dev headers (On Debian-derived systems this is the gcc and libssl-dev
-packages).
-"""
-
-try:
-    from twisted.conch.ssh.keys import Key
-except ImportError:
-    raise ImportError(_SSH_IMPORT_ERROR)
-
-from twisted.conch.ssh.userauth import SSHUserAuthServer
-from twisted.conch.ssh import common
-from twisted.conch.insults import insults
-from twisted.conch.manhole_ssh import TerminalRealm, _Glue, ConchFactory
-from twisted.conch.manhole import Manhole, recvline
-from twisted.internet import defer, protocol
-from twisted.conch import interfaces as iconch
-from twisted.python import components
-from django.conf import settings
-
-from evennia.accounts.models import AccountDB
-from evennia.utils import ansi
-from evennia.utils.utils import to_str, class_from_module
-
-_RE_N = re.compile(r"\|n$")
-_RE_SCREENREADER_REGEX = re.compile(
-    r"%s" % settings.SCREENREADER_REGEX_STRIP, re.DOTALL + re.MULTILINE
-)
-_GAME_DIR = settings.GAME_DIR
-_PRIVATE_KEY_FILE = os.path.join(_GAME_DIR, "server", "ssh-private.key")
-_PUBLIC_KEY_FILE = os.path.join(_GAME_DIR, "server", "ssh-public.key")
-_KEY_LENGTH = 2048
-
-CTRL_C = "\x03"
-CTRL_D = "\x04"
-CTRL_BACKSLASH = "\x1c"
-CTRL_L = "\x0c"
-
-_NO_AUTOGEN = f"""
-Evennia could not generate SSH private- and public keys ({{err}})
-Using conch default keys instead.
-
-If this error persists, create the keys manually (using the tools for your OS)
-and put them here:
-    {_PRIVATE_KEY_FILE}
-    {_PUBLIC_KEY_FILE}
-"""
-
-_BASE_SESSION_CLASS = class_from_module(settings.BASE_SESSION_CLASS)
-
-
-# not used atm
-
[docs]class SSHServerFactory(protocol.ServerFactory): - """ - This is only to name this better in logs - - """ - noisy = False - -
[docs] def logPrefix(self): - return "SSH"
- - -
[docs]class SshProtocol(Manhole, _BASE_SESSION_CLASS): - """ - Each account connecting over ssh gets this protocol assigned to - them. All communication between game and account goes through - here. - - """ - - noisy = False - -
[docs] def __init__(self, starttuple): - """ - For setting up the account. If account is not None then we'll - login automatically. - - Args: - starttuple (tuple): A (account, factory) tuple. - - """ - self.protocol_key = "ssh" - self.authenticated_account = starttuple[0] - # obs must not be called self.factory, that gets overwritten! - self.cfactory = starttuple[1]
- -
[docs] def terminalSize(self, width, height): - """ - Initialize the terminal and connect to the new session. - - Args: - width (int): Width of terminal. - height (int): Height of terminal. - - """ - # Clear the previous input line, redraw it at the new - # cursor position - self.terminal.eraseDisplay() - self.terminal.cursorHome() - self.width = width - self.height = height - - # initialize the session - client_address = self.getClientAddress() - client_address = client_address.host if client_address else None - self.init_session("ssh", client_address, self.cfactory.sessionhandler) - - # since we might have authenticated already, we might set this here. - if self.authenticated_account: - self.logged_in = True - self.uid = self.authenticated_account.id - self.sessionhandler.connect(self)
- -
[docs] def connectionMade(self): - """ - This is called when the connection is first established. - - """ - recvline.HistoricRecvLine.connectionMade(self) - self.keyHandlers[CTRL_C] = self.handle_INT - self.keyHandlers[CTRL_D] = self.handle_EOF - self.keyHandlers[CTRL_L] = self.handle_FF - self.keyHandlers[CTRL_BACKSLASH] = self.handle_QUIT
- - # initalize - -
[docs] def handle_INT(self): - """ - Handle ^C as an interrupt keystroke by resetting the current - input variables to their initial state. - - """ - self.lineBuffer = [] - self.lineBufferIndex = 0 - - self.terminal.nextLine() - self.terminal.write("KeyboardInterrupt") - self.terminal.nextLine()
- -
[docs] def handle_EOF(self): - """ - Handles EOF generally used to exit. - - """ - if self.lineBuffer: - self.terminal.write("\a") - else: - self.handle_QUIT()
- -
[docs] def handle_FF(self): - """ - Handle a 'form feed' byte - generally used to request a screen - refresh/redraw. - - """ - self.terminal.eraseDisplay() - self.terminal.cursorHome()
- -
[docs] def handle_QUIT(self): - """ - Quit, end, and lose the connection. - - """ - self.terminal.loseConnection()
- -
[docs] def connectionLost(self, reason=None): - """ - This is executed when the connection is lost for whatever - reason. It can also be called directly, from the disconnect - method. - - Args: - reason (str): Motivation for loosing connection. - - """ - insults.TerminalProtocol.connectionLost(self, reason) - self.sessionhandler.disconnect(self) - self.terminal.loseConnection()
- -
[docs] def getClientAddress(self): - """ - Get client address. - - Returns: - address_and_port (tuple): The client's address and port in - a tuple. For example `('127.0.0.1', 41917)`. - - """ - return self.terminal.transport.getPeer()
- -
[docs] def lineReceived(self, string): - """ - Communication User -> Evennia. Any line return indicates a - command for the purpose of the MUD. So we take the user input - and pass it on to the game engine. - - Args: - string (str): Input text. - - """ - self.sessionhandler.data_in(self, text=string)
- -
[docs] def sendLine(self, string): - """ - Communication Evennia -> User. Any string sent should - already have been properly formatted and processed before - reaching this point. - - Args: - string (str): Output text. - - """ - for line in string.split("\n"): - # the telnet-specific method for sending - self.terminal.write(line) - self.terminal.nextLine()
- - # session-general method hooks - -
[docs] def at_login(self): - """ - Called when this session gets authenticated by the server. - """ - pass
- -
[docs] def disconnect(self, reason="Connection closed. Goodbye for now."): - """ - Disconnect from server. - - Args: - reason (str): Motivation for disconnect. - - """ - if reason: - self.data_out(text=((reason,), {})) - self.connectionLost(reason)
- -
[docs] def data_out(self, **kwargs): - """ - Data Evennia -> User - - Keyword Args: - kwargs (any): Options to the protocol. - - """ - self.sessionhandler.data_out(self, **kwargs)
- -
[docs] def send_text(self, *args, **kwargs): - """ - Send text data. This is an in-band telnet operation. - - Args: - text (str): The first argument is always the text string to send. No other arguments - are considered. - Keyword Args: - options (dict): Send-option flags (booleans) - - - mxp: enforce mxp link support. - - ansi: enforce no ansi colors. - - xterm256: enforce xterm256 colors, regardless of ttype setting. - - nocolor: strip all colors. - - raw: pass string through without any ansi processing - (i.e. include evennia ansi markers but do not - convert them into ansi tokens) - - echo: turn on/off line echo on the client. turn - off line echo for client, for example for password. - note that it must be actively turned back on again! - - """ - # print "telnet.send_text", args,kwargs # DEBUG - text = args[0] if args else "" - if text is None: - return - text = to_str(text) - - # handle arguments - options = kwargs.get("options", {}) - flags = self.protocol_flags - xterm256 = options.get("xterm256", flags.get("XTERM256", True)) - useansi = options.get("ansi", flags.get("ANSI", True)) - raw = options.get("raw", flags.get("RAW", False)) - nocolor = options.get("nocolor", flags.get("NOCOLOR") or not (xterm256 or useansi)) - # echo = options.get("echo", None) # DEBUG - screenreader = options.get("screenreader", flags.get("SCREENREADER", False)) - - if screenreader: - # screenreader mode cleans up output - text = ansi.parse_ansi(text, strip_ansi=True, xterm256=False, mxp=False) - text = _RE_SCREENREADER_REGEX.sub("", text) - - if raw: - # no processing - self.sendLine(text) - return - else: - # we need to make sure to kill the color at the end in order - # to match the webclient output. - linetosend = ansi.parse_ansi( - _RE_N.sub("", text) + ("||n" if text.endswith("|") else "|n"), - strip_ansi=nocolor, - xterm256=xterm256, - mxp=False, - ) - self.sendLine(linetosend)
- -
[docs] def send_prompt(self, *args, **kwargs): - self.send_text(*args, **kwargs)
- -
[docs] def send_default(self, *args, **kwargs): - pass
- - -
[docs]class ExtraInfoAuthServer(SSHUserAuthServer): - - noisy = False - -
[docs] def auth_password(self, packet): - """ - Password authentication. - - Used mostly for setting up the transport so we can query - username and password later. - - Args: - packet (Packet): Auth packet. - - """ - password = common.getNS(packet[1:])[0] - c = credentials.UsernamePassword(self.user, password) - c.transport = self.transport - return self.portal.login(c, None, IConchUser).addErrback(self._ebPassword)
- - -
[docs]class AccountDBPasswordChecker(object): - """ - Checks the django db for the correct credentials for - username/password otherwise it returns the account or None which is - useful for the Realm. - - """ - - noisy = False - credentialInterfaces = (credentials.IUsernamePassword,) - -
[docs] def __init__(self, factory): - """ - Initialize the factory. - - Args: - factory (SSHFactory): Checker factory. - - """ - self.factory = factory - super().__init__()
- -
[docs] def requestAvatarId(self, c): - """ - Generic credentials. - - """ - up = credentials.IUsernamePassword(c, None) - username = up.username - password = up.password - account = AccountDB.objects.get_account_from_name(username) - res = (None, self.factory) - if account and account.check_password(password): - res = (account, self.factory) - return defer.succeed(res)
- - -
[docs]class PassAvatarIdTerminalRealm(TerminalRealm): - """ - Returns an avatar that passes the avatarId through to the - protocol. This is probably not the best way to do it. - - """ - - noisy = False - - def _getAvatar(self, avatarId): - comp = components.Componentized() - user = self.userFactory(comp, avatarId) - sess = self.sessionFactory(comp) - - sess.transportFactory = self.transportFactory - sess.chainedProtocolFactory = lambda: self.chainedProtocolFactory(avatarId) - - comp.setComponent(iconch.IConchUser, user) - comp.setComponent(iconch.ISession, sess) - - return user
- - -
[docs]class TerminalSessionTransport_getPeer(object): - """ - Taken from twisted's TerminalSessionTransport which doesn't - provide getPeer to the transport. This one does. - - """ - - noisy = False - -
[docs] def __init__(self, proto, chainedProtocol, avatar, width, height): - self.proto = proto - self.avatar = avatar - self.chainedProtocol = chainedProtocol - - session = self.proto.session - - self.proto.makeConnection( - _Glue( - write=self.chainedProtocol.dataReceived, - loseConnection=lambda: avatar.conn.sendClose(session), - name="SSH Proto Transport", - ) - ) - - def loseConnection(): - self.proto.loseConnection() - - def getPeer(): - return session.conn.transport.transport.getPeer() - - self.chainedProtocol.makeConnection( - _Glue( - getPeer=getPeer, - write=self.proto.write, - loseConnection=loseConnection, - name="Chained Proto Transport", - ) - ) - - self.chainedProtocol.terminalProtocol.terminalSize(width, height)
- - -
[docs]def getKeyPair(pubkeyfile, privkeyfile): - """ - This function looks for RSA keypair files in the current directory. If they - do not exist, the keypair is created. - """ - - if not (os.path.exists(pubkeyfile) and os.path.exists(privkeyfile)): - # No keypair exists. Generate a new RSA keypair - from cryptography.hazmat.backends import default_backend - from cryptography.hazmat.primitives.asymmetric import rsa - - rsa_key = Key( - rsa.generate_private_key( - public_exponent=65537, key_size=_KEY_LENGTH, backend=default_backend() - ) - ) - public_key_string = rsa_key.public().toString(type="OPENSSH").decode() - private_key_string = rsa_key.toString(type="OPENSSH").decode() - - # save keys for the future. - with open(privkeyfile, "wt") as pfile: - pfile.write(private_key_string) - print("Created SSH private key in '{}'".format(_PRIVATE_KEY_FILE)) - with open(pubkeyfile, "wt") as pfile: - pfile.write(public_key_string) - print("Created SSH public key in '{}'".format(_PUBLIC_KEY_FILE)) - else: - with open(pubkeyfile) as pfile: - public_key_string = pfile.read() - with open(privkeyfile) as pfile: - private_key_string = pfile.read() - - return Key.fromString(public_key_string), Key.fromString(private_key_string)
- - -
[docs]def makeFactory(configdict): - """ - Creates the ssh server factory. - """ - - def chainProtocolFactory(username=None): - return insults.ServerProtocol( - configdict["protocolFactory"], - *configdict.get("protocolConfigdict", (username,)), - **configdict.get("protocolKwArgs", {}), - ) - - rlm = PassAvatarIdTerminalRealm() - rlm.transportFactory = TerminalSessionTransport_getPeer - rlm.chainedProtocolFactory = chainProtocolFactory - factory = ConchFactory(Portal(rlm)) - factory.sessionhandler = configdict["sessions"] - - try: - # create/get RSA keypair - publicKey, privateKey = getKeyPair(_PUBLIC_KEY_FILE, _PRIVATE_KEY_FILE) - factory.publicKeys = {b"ssh-rsa": publicKey} - factory.privateKeys = {b"ssh-rsa": privateKey} - except Exception as err: - print(_NO_AUTOGEN.format(err=err)) - - factory.services = factory.services.copy() - factory.services["ssh-userauth"] = ExtraInfoAuthServer - - factory.portal.registerChecker(AccountDBPasswordChecker(factory)) - - return factory
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/ssl.html b/docs/0.9.5/_modules/evennia/server/portal/ssl.html deleted file mode 100644 index 7403c73557..0000000000 --- a/docs/0.9.5/_modules/evennia/server/portal/ssl.html +++ /dev/null @@ -1,225 +0,0 @@ - - - - - - - - evennia.server.portal.ssl — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.portal.ssl

-"""
-This is a simple context factory for auto-creating
-SSL keys and certificates.
-
-"""
-import os
-import sys
-
-try:
-    import OpenSSL
-    from twisted.internet import ssl as twisted_ssl
-except ImportError as error:
-    errstr = """
-    {err}
-    SSL requires the PyOpenSSL library:
-        pip install pyopenssl
-    """
-    raise ImportError(errstr.format(err=error))
-
-from django.conf import settings
-from evennia.utils.utils import class_from_module
-
-_GAME_DIR = settings.GAME_DIR
-
-# messages
-
-NO_AUTOGEN = """
-
-{err}
-Evennia could not auto-generate the SSL private key. If this error
-persists, create {keyfile} yourself using third-party tools.
-"""
-
-NO_AUTOCERT = """
-
-{err}
-Evennia's SSL context factory could not automatically, create an SSL
-certificate {certfile}.
-
-A private key {keyfile} was already created. Please create {certfile}
-manually using the commands valid  for your operating system, for
-example (linux, using the openssl program):
-    {exestring}
-"""
-
-_TELNET_PROTOCOL_CLASS = class_from_module(settings.TELNET_PROTOCOL_CLASS)
-
-
-
[docs]class SSLProtocol(_TELNET_PROTOCOL_CLASS): - """ - Communication is the same as telnet, except data transfer - is done with encryption. - - """ - -
[docs] def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.protocol_name = "ssl"
- - -
[docs]def verify_SSL_key_and_cert(keyfile, certfile): - """ - This function looks for RSA key and certificate in the current - directory. If files ssl.key and ssl.cert does not exist, they - are created. - - """ - - if not (os.path.exists(keyfile) and os.path.exists(certfile)): - # key/cert does not exist. Create. - import subprocess - from Crypto.PublicKey import RSA - from twisted.conch.ssh.keys import Key - - print(" Creating SSL key and certificate ... ", end=" ") - - try: - # create the RSA key and store it. - KEY_LENGTH = 2048 - rsa_key = Key(RSA.generate(KEY_LENGTH)) - key_string = rsa_key.toString(type="OPENSSH") - with open(keyfile, "w+b") as fil: - fil.write(key_string) - except Exception as err: - print(NO_AUTOGEN.format(err=err, keyfile=keyfile)) - sys.exit(5) - - # try to create the certificate - CERT_EXPIRE = 365 * 20 # twenty years validity - # default: - # openssl req -new -x509 -key ssl.key -out ssl.cert -days 7300 - exestring = "openssl req -new -x509 -key %s -out %s -days %s" % ( - keyfile, - certfile, - CERT_EXPIRE, - ) - try: - subprocess.call(exestring) - except OSError as err: - raise OSError( - NO_AUTOCERT.format(err=err, certfile=certfile, keyfile=keyfile, exestring=exestring) - ) - print("done.")
- - -
[docs]def getSSLContext(): - """ - This is called by the portal when creating the SSL context - server-side. - - Returns: - ssl_context (tuple): A key and certificate that is either - existing previously or or created on the fly. - - """ - keyfile = os.path.join(_GAME_DIR, "server", "ssl.key") - certfile = os.path.join(_GAME_DIR, "server", "ssl.cert") - - verify_SSL_key_and_cert(keyfile, certfile) - return twisted_ssl.DefaultOpenSSLContextFactory(keyfile, certfile)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/suppress_ga.html b/docs/0.9.5/_modules/evennia/server/portal/suppress_ga.html deleted file mode 100644 index 969e323a81..0000000000 --- a/docs/0.9.5/_modules/evennia/server/portal/suppress_ga.html +++ /dev/null @@ -1,173 +0,0 @@ - - - - - - - - evennia.server.portal.suppress_ga — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.portal.suppress_ga

-"""
-
-SUPPRESS-GO-AHEAD
-
-This supports suppressing or activating Evennia
-the GO-AHEAD telnet operation after every server reply.
-If the client sends no explicit DONT SUPRESS GO-AHEAD,
-Evennia will default to supressing it since many clients
-will fail to use it and has no knowledge of this standard.
-
-It is set as the NOGOAHEAD protocol_flag option.
-
-http://www.faqs.org/rfcs/rfc858.html
-
-"""
-
-SUPPRESS_GA = bytes([3])  # b"\x03"
-
-# default taken from telnet specification
-
-# try to get the customized mssp info, if it exists.
-
-
-
[docs]class SuppressGA: - """ - Implements the SUPRESS-GO-AHEAD protocol. Add this to a variable on the telnet - protocol to set it up. - - """ - -
[docs] def __init__(self, protocol): - """ - Initialize suppression of GO-AHEADs. - - Args: - protocol (Protocol): The active protocol instance. - - """ - self.protocol = protocol - - self.protocol.protocol_flags["NOGOAHEAD"] = True - self.protocol.protocol_flags[ - "NOPROMPTGOAHEAD" - ] = True # Used to send a GA after a prompt line only, set in TTYPE (per client) - # tell the client that we prefer to suppress GA ... - self.protocol.will(SUPPRESS_GA).addCallbacks(self.will_suppress_ga, self.wont_suppress_ga)
- -
[docs] def wont_suppress_ga(self, option): - """ - Called when client requests to not suppress GA. - - Args: - option (Option): Not used. - - """ - self.protocol.protocol_flags["NOGOAHEAD"] = False - self.protocol.handshake_done()
- -
[docs] def will_suppress_ga(self, option): - """ - Client will suppress GA - - Args: - option (Option): Not used. - - """ - self.protocol.protocol_flags["NOGOAHEAD"] = True - self.protocol.handshake_done()
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/telnet.html b/docs/0.9.5/_modules/evennia/server/portal/telnet.html deleted file mode 100644 index 651270c58d..0000000000 --- a/docs/0.9.5/_modules/evennia/server/portal/telnet.html +++ /dev/null @@ -1,615 +0,0 @@ - - - - - - - - evennia.server.portal.telnet — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.portal.telnet

-"""
-This module implements the telnet protocol.
-
-This depends on a generic session module that implements
-the actual login procedure of the game, tracks
-sessions etc.
-
-"""
-
-import re
-from twisted.internet import protocol
-from twisted.internet.task import LoopingCall
-from twisted.conch.telnet import Telnet, StatefulTelnetProtocol
-from twisted.conch.telnet import (
-    IAC,
-    NOP,
-    LINEMODE,
-    GA,
-    WILL,
-    WONT,
-    ECHO,
-    NULL,
-    MODE,
-    LINEMODE_EDIT,
-    LINEMODE_TRAPSIG,
-)
-from django.conf import settings
-from evennia.server.portal import ttype, mssp, telnet_oob, naws, suppress_ga
-from evennia.server.portal.mccp import Mccp, mccp_compress, MCCP
-from evennia.server.portal.mxp import Mxp, mxp_parse
-from evennia.utils import ansi
-from evennia.utils.utils import to_bytes, class_from_module
-
-_RE_N = re.compile(r"\|n$")
-_RE_LEND = re.compile(br"\n$|\r$|\r\n$|\r\x00$|", re.MULTILINE)
-_RE_LINEBREAK = re.compile(br"\n\r|\r\n|\n|\r", re.DOTALL + re.MULTILINE)
-_RE_SCREENREADER_REGEX = re.compile(
-    r"%s" % settings.SCREENREADER_REGEX_STRIP, re.DOTALL + re.MULTILINE
-)
-_IDLE_COMMAND = str.encode(settings.IDLE_COMMAND + "\n")
-
-# identify HTTP indata
-_HTTP_REGEX = re.compile(
-    b"(GET|HEAD|POST|PUT|DELETE|TRACE|OPTIONS|CONNECT|PATCH) (.*? HTTP/[0-9]\.[0-9])", re.I
-)
-
-_HTTP_WARNING = bytes(
-    """
-    This is Evennia's Telnet port and cannot be used for regular HTTP traffic.
-    Use a telnet client to connect here and point your browser to the server's
-    dedicated web port instead.
-
-    """.strip(),
-    "utf-8",
-)
-
-
-_BASE_SESSION_CLASS = class_from_module(settings.BASE_SESSION_CLASS)
-
-
-
[docs]class TelnetServerFactory(protocol.ServerFactory): - """ - This exists only to name this better in logs. - - """ - noisy = False - -
[docs] def logPrefix(self): - return "Telnet"
- - -
[docs]class TelnetProtocol(Telnet, StatefulTelnetProtocol, _BASE_SESSION_CLASS): - """ - Each player connecting over telnet (ie using most traditional mud - clients) gets a telnet protocol instance assigned to them. All - communication between game and player goes through here. - - """ - -
[docs] def __init__(self, *args, **kwargs): - self.protocol_key = "telnet" - super().__init__(*args, **kwargs)
- -
[docs] def dataReceived(self, data): - """ - Unused by default, but a good place to put debug printouts - of incoming data. - - """ - # print(f"telnet dataReceived: {data}") - try: - super().dataReceived(data) - except ValueError as err: - from evennia.utils import logger - logger.log_err(f"Malformed telnet input: {err}")
- -
[docs] def connectionMade(self): - """ - This is called when the connection is first established. - - """ - # important in order to work normally with standard telnet - self.do(LINEMODE).addErrback(self._wont_linemode) - # initialize the session - self.line_buffer = b"" - client_address = self.transport.client - client_address = client_address[0] if client_address else None - # this number is counted down for every handshake that completes. - # when it reaches 0 the portal/server syncs their data - self.handshakes = 8 # suppress-go-ahead, naws, ttype, mccp, mssp, msdp, gmcp, mxp - - self.init_session(self.protocol_key, client_address, self.factory.sessionhandler) - self.protocol_flags["ENCODING"] = settings.ENCODINGS[0] if settings.ENCODINGS else "utf-8" - # add this new connection to sessionhandler so - # the Server becomes aware of it. - self.sessionhandler.connect(self) - # change encoding to ENCODINGS[0] which reflects Telnet default encoding - - # suppress go-ahead - self.sga = suppress_ga.SuppressGA(self) - # negotiate client size - self.naws = naws.Naws(self) - # negotiate ttype (client info) - # Obs: mudlet ttype does not seem to work if we start mccp before ttype. /Griatch - self.ttype = ttype.Ttype(self) - # negotiate mccp (data compression) - turn this off for wireshark analysis - self.mccp = Mccp(self) - # negotiate mssp (crawler communication) - self.mssp = mssp.Mssp(self) - # oob communication (MSDP, GMCP) - two handshake calls! - self.oob = telnet_oob.TelnetOOB(self) - # mxp support - self.mxp = Mxp(self) - - from evennia.utils.utils import delay - - # timeout the handshakes in case the client doesn't reply at all - self._handshake_delay = delay(2, callback=self.handshake_done, timeout=True) - - # TCP/IP keepalive watches for dead links - self.transport.setTcpKeepAlive(1) - # The TCP/IP keepalive is not enough for some networks; - # we have to complement it with a NOP keep-alive. - self.protocol_flags["NOPKEEPALIVE"] = True - self.nop_keep_alive = None - self.toggle_nop_keepalive()
- - def _wont_linemode(self, *args): - """ - Client refuses do(linemode). This is common for MUD-specific - clients, but we must ask for the sake of raw telnet. We ignore - this error. - - """ - pass - - def _send_nop_keepalive(self): - """ - Send NOP keepalive unless flag is set - - """ - if self.protocol_flags.get("NOPKEEPALIVE"): - self._write(IAC + NOP) - -
[docs] def toggle_nop_keepalive(self): - """ - Allow to toggle the NOP keepalive for those sad clients that - can't even handle a NOP instruction. This is turned off by the - protocol_flag NOPKEEPALIVE (settable e.g. by the default - `option` command). - - """ - if self.nop_keep_alive and self.nop_keep_alive.running: - self.nop_keep_alive.stop() - else: - self.nop_keep_alive = LoopingCall(self._send_nop_keepalive) - self.nop_keep_alive.start(30, now=False)
- -
[docs] def handshake_done(self, timeout=False): - """ - This is called by all telnet extensions once they are finished. - When all have reported, a sync with the server is performed. - The system will force-call this sync after a small time to handle - clients that don't reply to handshakes at all. - - """ - if timeout: - if self.handshakes > 0: - self.handshakes = 0 - self.sessionhandler.sync(self) - else: - self.handshakes -= 1 - if self.handshakes <= 0: - # do the sync - self.sessionhandler.sync(self)
- -
[docs] def at_login(self): - """ - Called when this session gets authenticated by the server. - - """ - pass
- -
[docs] def enableRemote(self, option): - """ - This sets up the remote-activated options we allow for this protocol. - - Args: - option (char): The telnet option to enable. - - Returns: - enable (bool): If this option should be enabled. - - """ - if option == LINEMODE: - # make sure to activate line mode with local editing for all clients - self.requestNegotiation( - LINEMODE, MODE + bytes(chr(ord(LINEMODE_EDIT) + ord(LINEMODE_TRAPSIG)), "ascii") - ) - return True - else: - return ( - option == ttype.TTYPE - or option == naws.NAWS - or option == MCCP - or option == mssp.MSSP - or option == suppress_ga.SUPPRESS_GA - )
- -
[docs] def disableRemote(self, option): - return ( - option == LINEMODE - or option == ttype.TTYPE - or option == naws.NAWS - or option == MCCP - or option == mssp.MSSP - or option == suppress_ga.SUPPRESS_GA - )
- -
[docs] def enableLocal(self, option): - """ - Call to allow the activation of options for this protocol - - Args: - option (char): The telnet option to enable locally. - - Returns: - enable (bool): If this option should be enabled. - - """ - return ( - option == LINEMODE - or option == MCCP - or option == ECHO - or option == suppress_ga.SUPPRESS_GA - )
- -
[docs] def disableLocal(self, option): - """ - Disable a given option locally. - - Args: - option (char): The telnet option to disable locally. - - """ - if option == LINEMODE: - return True - if option == ECHO: - return True - if option == MCCP: - self.mccp.no_mccp(option) - return True - else: - try: - return super().disableLocal(option) - except Exception: - from evennia.utils import logger - - logger.log_trace()
- -
[docs] def connectionLost(self, reason): - """ - this is executed when the connection is lost for whatever - reason. it can also be called directly, from the disconnect - method - - Args: - reason (str): Motivation for losing connection. - - """ - self.sessionhandler.disconnect(self) - self.transport.loseConnection()
- -
[docs] def applicationDataReceived(self, data): - """ - Telnet method called when non-telnet-command data is coming in - over the telnet connection. We pass it on to the game engine - directly. - - Args: - data (str): Incoming data. - - """ - if not data: - data = [data] - elif data.strip() == NULL: - # this is an ancient type of keepalive used by some - # legacy clients. There should never be a reason to send a - # lone NULL character so this seems to be a safe thing to - # support for backwards compatibility. It also stops the - # NULL from continuously popping up as an unknown command. - data = [_IDLE_COMMAND] - else: - data = _RE_LINEBREAK.split(data) - - if len(data) > 2 and _HTTP_REGEX.match(data[0]): - # guard against HTTP request on the Telnet port; we - # block and kill the connection. - self.transport.write(_HTTP_WARNING) - self.transport.loseConnection() - return - - if self.line_buffer and len(data) > 1: - # buffer exists, it is terminated by the first line feed - data[0] = self.line_buffer + data[0] - self.line_buffer = b"" - # if the last data split is empty, it means all splits have - # line breaks, if not, it is unterminated and must be - # buffered. - self.line_buffer += data.pop() - # send all data chunks - for dat in data: - self.data_in(text=dat + b"\n")
- - def _write(self, data): - """ - Hook overloading the one used in plain telnet - - """ - data = data.replace(b"\n", b"\r\n").replace(b"\r\r\n", b"\r\n") - super()._write(mccp_compress(self, data)) - -
[docs] def sendLine(self, line): - """ - Hook overloading the one used by linereceiver. - - Args: - line (str): Line to send. - - """ - line = to_bytes(line, self) - # escape IAC in line mode, and correctly add \r\n (the TELNET end-of-line) - line = line.replace(IAC, IAC + IAC) - line = line.replace(b"\n", b"\r\n") - if not line.endswith(b"\r\n") and self.protocol_flags.get("FORCEDENDLINE", True): - line += b"\r\n" - if not self.protocol_flags.get("NOGOAHEAD", True): - line += IAC + GA - return self.transport.write(mccp_compress(self, line))
- - # Session hooks - -
[docs] def disconnect(self, reason=""): - """ - Generic hook for the engine to call in order to - disconnect this protocol. - - Args: - reason (str, optional): Reason for disconnecting. - - """ - self.data_out(text=((reason,), {})) - self.connectionLost(reason)
- -
[docs] def data_in(self, **kwargs): - """ - Data User -> Evennia - - Keyword Args: - kwargs (any): Options from the protocol. - - """ - # from evennia.server.profiling.timetrace import timetrace # DEBUG - # text = timetrace(text, "telnet.data_in") # DEBUG - - self.sessionhandler.data_in(self, **kwargs)
- -
[docs] def data_out(self, **kwargs): - """ - Data Evennia -> User - - Keyword Args: - kwargs (any): Options to the protocol - - """ - self.sessionhandler.data_out(self, **kwargs)
- - # send_* methods - -
[docs] def send_text(self, *args, **kwargs): - """ - Send text data. This is an in-band telnet operation. - - Args: - text (str): The first argument is always the text string to send. No other arguments - are considered. - Keyword Args: - options (dict): Send-option flags - - - mxp: Enforce MXP link support. - - ansi: Enforce no ANSI colors. - - xterm256: Enforce xterm256 colors, regardless of TTYPE. - - noxterm256: Enforce no xterm256 color support, regardless of TTYPE. - - nocolor: Strip all Color, regardless of ansi/xterm256 setting. - - raw: Pass string through without any ansi processing - (i.e. include Evennia ansi markers but do not - convert them into ansi tokens) - - echo: Turn on/off line echo on the client. Turn - off line echo for client, for example for password. - Note that it must be actively turned back on again! - - """ - text = args[0] if args else "" - if text is None: - return - - # handle arguments - options = kwargs.get("options", {}) - flags = self.protocol_flags - xterm256 = options.get( - "xterm256", flags.get("XTERM256", False) if flags.get("TTYPE", False) else True - ) - useansi = options.get( - "ansi", flags.get("ANSI", False) if flags.get("TTYPE", False) else True - ) - raw = options.get("raw", flags.get("RAW", False)) - nocolor = options.get("nocolor", flags.get("NOCOLOR") or not (xterm256 or useansi)) - echo = options.get("echo", None) - mxp = options.get("mxp", flags.get("MXP", False)) - screenreader = options.get("screenreader", flags.get("SCREENREADER", False)) - - if screenreader: - # screenreader mode cleans up output - text = ansi.parse_ansi(text, strip_ansi=True, xterm256=False, mxp=False) - text = _RE_SCREENREADER_REGEX.sub("", text) - - if options.get("send_prompt"): - # send a prompt instead. - prompt = text - if not raw: - # processing - prompt = ansi.parse_ansi( - _RE_N.sub("", prompt) + ("||n" if prompt.endswith("|") else "|n"), - strip_ansi=nocolor, - xterm256=xterm256, - ) - if mxp: - prompt = mxp_parse(prompt) - prompt = to_bytes(prompt, self) - prompt = prompt.replace(IAC, IAC + IAC).replace(b"\n", b"\r\n") - if not self.protocol_flags.get("NOPROMPTGOAHEAD", - self.protocol_flags.get("NOGOAHEAD", True)): - prompt += IAC + GA - self.transport.write(mccp_compress(self, prompt)) - else: - if echo is not None: - # turn on/off echo. Note that this is a bit turned around since we use - # echo as if we are "turning off the client's echo" when telnet really - # handles it the other way around. - if echo: - # by telling the client that WE WON'T echo, the client knows - # that IT should echo. This is the expected behavior from - # our perspective. - self.transport.write(mccp_compress(self, IAC + WONT + ECHO)) - else: - # by telling the client that WE WILL echo, the client can - # safely turn OFF its OWN echo. - self.transport.write(mccp_compress(self, IAC + WILL + ECHO)) - if raw: - # no processing - self.sendLine(text) - return - else: - # we need to make sure to kill the color at the end in order - # to match the webclient output. - linetosend = ansi.parse_ansi( - _RE_N.sub("", text) + ("||n" if text.endswith("|") else "|n"), - strip_ansi=nocolor, - xterm256=xterm256, - mxp=mxp, - ) - if mxp: - linetosend = mxp_parse(linetosend) - self.sendLine(linetosend)
- -
[docs] def send_prompt(self, *args, **kwargs): - """ - Send a prompt - a text without a line end. See send_text for argument options. - - """ - kwargs["options"].update({"send_prompt": True}) - self.send_text(*args, **kwargs)
- -
[docs] def send_default(self, cmdname, *args, **kwargs): - """ - Send other oob data - - """ - if not cmdname == "options": - self.oob.data_out(cmdname, *args, **kwargs)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/telnet_oob.html b/docs/0.9.5/_modules/evennia/server/portal/telnet_oob.html deleted file mode 100644 index 801fbddb15..0000000000 --- a/docs/0.9.5/_modules/evennia/server/portal/telnet_oob.html +++ /dev/null @@ -1,552 +0,0 @@ - - - - - - - - evennia.server.portal.telnet_oob — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.portal.telnet_oob

-"""
-
-Telnet OOB (Out of band communication)
-
-OOB protocols allow for asynchronous communication between Evennia and
-compliant telnet clients. The "text" type of send command will always
-be sent "in-band", appearing in the client's main text output. OOB
-commands, by contrast, can have many forms and it is up to the client
-how and if they are handled.  Examples of OOB instructions could be to
-instruct the client to play sounds or to update a graphical health
-bar.
-
-Note that in Evennia's Web client, all send commands are "OOB
-commands", (including the "text" one), there is no equivalence to
-MSDP/GMCP for the webclient since it doesn't need it.
-
-This implements the following telnet OOB communication protocols:
-
-- MSDP (Mud Server Data Protocol), as per http://tintin.sourceforge.net/msdp/
-- GMCP (Generic Mud Communication Protocol) as per
-  http://www.ironrealms.com/rapture/manual/files/FeatGMCP-txt.html#Generic_MUD_Communication_Protocol%28GMCP%29
-
-----
-
-"""
-import re
-import json
-from evennia.utils.utils import is_iter
-
-# General Telnet
-from twisted.conch.telnet import IAC, SB, SE
-
-# MSDP-relevant telnet cmd/opt-codes
-MSDP = bytes([69])
-MSDP_VAR = bytes([1])
-MSDP_VAL = bytes([2])
-MSDP_TABLE_OPEN = bytes([3])
-MSDP_TABLE_CLOSE = bytes([4])
-
-MSDP_ARRAY_OPEN = bytes([5])
-MSDP_ARRAY_CLOSE = bytes([6])
-
-# GMCP
-GMCP = bytes([201])
-
-
-# pre-compiled regexes
-# returns 2-tuple
-msdp_regex_table = re.compile(
-    br"%s\s*(\w*?)\s*%s\s*%s(.*?)%s" % (MSDP_VAR, MSDP_VAL, MSDP_TABLE_OPEN, MSDP_TABLE_CLOSE)
-)
-# returns 2-tuple
-msdp_regex_array = re.compile(
-    br"%s\s*(\w*?)\s*%s\s*%s(.*?)%s" % (MSDP_VAR, MSDP_VAL, MSDP_ARRAY_OPEN, MSDP_ARRAY_CLOSE)
-)
-msdp_regex_var = re.compile(br"%s" % MSDP_VAR)
-msdp_regex_val = re.compile(br"%s" % MSDP_VAL)
-
-EVENNIA_TO_GMCP = {
-    "client_options": "Core.Supports.Get",
-    "get_inputfuncs": "Core.Commands.Get",
-    "get_value": "Char.Value.Get",
-    "repeat": "Char.Repeat.Update",
-    "monitor": "Char.Monitor.Update",
-}
-
-
-# MSDP/GMCP communication handler
-
-
-
[docs]class TelnetOOB: - """ - Implements the MSDP and GMCP protocols. - """ - -
[docs] def __init__(self, protocol): - """ - Initiates by storing the protocol on itself and trying to - determine if the client supports MSDP. - - Args: - protocol (Protocol): The active protocol. - - """ - self.protocol = protocol - self.protocol.protocol_flags["OOB"] = False - self.MSDP = False - self.GMCP = False - # ask for the available protocols and assign decoders - # (note that handshake_done() will be called twice!) - self.protocol.negotiationMap[MSDP] = self.decode_msdp - self.protocol.negotiationMap[GMCP] = self.decode_gmcp - self.protocol.will(MSDP).addCallbacks(self.do_msdp, self.no_msdp) - self.protocol.will(GMCP).addCallbacks(self.do_gmcp, self.no_gmcp) - self.oob_reported = {}
- -
[docs] def no_msdp(self, option): - """ - Client reports No msdp supported or wanted. - - Args: - option (Option): Not used. - - """ - # no msdp, check GMCP - self.protocol.handshake_done()
- -
[docs] def do_msdp(self, option): - """ - Client reports that it supports msdp. - - Args: - option (Option): Not used. - - """ - self.MSDP = True - self.protocol.protocol_flags["OOB"] = True - self.protocol.handshake_done()
- -
[docs] def no_gmcp(self, option): - """ - If this is reached, it means neither MSDP nor GMCP is - supported. - - Args: - option (Option): Not used. - - """ - self.protocol.handshake_done()
- -
[docs] def do_gmcp(self, option): - """ - Called when client confirms that it can do MSDP or GMCP. - - Args: - option (Option): Not used. - - """ - self.GMCP = True - self.protocol.protocol_flags["OOB"] = True - self.protocol.handshake_done()
- - # encoders - -
[docs] def encode_msdp(self, cmdname, *args, **kwargs): - """ - Encode into a valid MSDP command. - - Args: - cmdname (str): Name of send instruction. - args, kwargs (any): Arguments to OOB command. - - Notes: - The output of this encoding will be - MSDP structures on these forms: - :: - - [cmdname, [], {}] -> VAR cmdname VAL "" - [cmdname, [arg], {}] -> VAR cmdname VAL arg - [cmdname, [args],{}] -> VAR cmdname VAL ARRAYOPEN VAL arg VAL arg ... ARRAYCLOSE - [cmdname, [], {kwargs}] -> VAR cmdname VAL TABLEOPEN VAR key VAL val ... TABLECLOSE - [cmdname, [args], {kwargs}] -> VAR cmdname VAL ARRAYOPEN VAL arg VAL arg ... ARRAYCLOSE - VAR cmdname VAL TABLEOPEN VAR key VAL val ... TABLECLOSE - - Further nesting is not supported, so if an array argument - consists of an array (for example), that array will be - json-converted to a string. - - """ - msdp_cmdname = "{msdp_var}{msdp_cmdname}{msdp_val}".format( - msdp_var=MSDP_VAR.decode(), msdp_cmdname=cmdname, msdp_val=MSDP_VAL.decode() - ) - - if not (args or kwargs): - return msdp_cmdname.encode() - - # print("encode_msdp in:", cmdname, args, kwargs) # DEBUG - - msdp_args = "" - if args: - msdp_args = msdp_cmdname - if len(args) == 1: - msdp_args += args[0] - else: - msdp_args += ( - "{msdp_array_open}" - "{msdp_args}" - "{msdp_array_close}".format( - msdp_array_open=MSDP_ARRAY_OPEN.decode(), - msdp_array_close=MSDP_ARRAY_CLOSE.decode(), - msdp_args="".join("%s%s" % (MSDP_VAL.decode(), val) for val in args), - ) - ) - - msdp_kwargs = "" - if kwargs: - msdp_kwargs = msdp_cmdname - msdp_kwargs += ( - "{msdp_table_open}" - "{msdp_kwargs}" - "{msdp_table_close}".format( - msdp_table_open=MSDP_TABLE_OPEN.decode(), - msdp_table_close=MSDP_TABLE_CLOSE.decode(), - msdp_kwargs="".join( - "%s%s%s%s" % (MSDP_VAR.decode(), key, MSDP_VAL.decode(), val) - for key, val in kwargs.items() - ), - ) - ) - - msdp_string = msdp_args + msdp_kwargs - - # print("msdp_string:", msdp_string) # DEBUG - return msdp_string.encode()
- -
[docs] def encode_gmcp(self, cmdname, *args, **kwargs): - """ - Encode into GMCP messages. - - Args: - cmdname (str): GMCP OOB command name. - args, kwargs (any): Arguments to OOB command. - - Notes: - GMCP messages will be outgoing on the following - form (the non-JSON cmdname at the start is what - IRE games use, supposedly, and what clients appear - to have adopted). A cmdname without Package will end - up in the Core package, while Core package names will - be stripped on the Evennia side. - :: - - [cmd_name, [], {}] -> Cmd.Name - [cmd_name, [arg], {}] -> Cmd.Name arg - [cmd_name, [args],{}] -> Cmd.Name [args] - [cmd_name, [], {kwargs}] -> Cmd.Name {kwargs} - [cmdname, [args, {kwargs}] -> Core.Cmdname [[args],{kwargs}] - - For more flexibility with certain clients, if `cmd_name` is capitalized, - Evennia will leave its current capitalization (So CMD_nAmE would be sent - as CMD.nAmE but cMD_Name would be Cmd.Name) - - Notes: - There are also a few default mappings between evennia outputcmds and GMCP: - :: - - client_options -> Core.Supports.Get - get_inputfuncs -> Core.Commands.Get - get_value -> Char.Value.Get - repeat -> Char.Repeat.Update - monitor -> Char.Monitor.Update - - """ - - if cmdname in EVENNIA_TO_GMCP: - gmcp_cmdname = EVENNIA_TO_GMCP[cmdname] - elif "_" in cmdname: - if cmdname.istitle(): - # leave without capitalization - gmcp_cmdname = ".".join(word for word in cmdname.split("_")) - else: - gmcp_cmdname = ".".join(word.capitalize() for word in cmdname.split("_")) - else: - gmcp_cmdname = "Core.%s" % (cmdname if cmdname.istitle() else cmdname.capitalize()) - - if not (args or kwargs): - gmcp_string = gmcp_cmdname - elif args: - if len(args) == 1: - args = args[0] - if kwargs: - gmcp_string = "%s %s" % (gmcp_cmdname, json.dumps([args, kwargs])) - else: - gmcp_string = "%s %s" % (gmcp_cmdname, json.dumps(args)) - else: # only kwargs - gmcp_string = "%s %s" % (gmcp_cmdname, json.dumps(kwargs)) - - # print("gmcp string", gmcp_string) # DEBUG - return gmcp_string.encode()
- -
[docs] def decode_msdp(self, data): - """ - Decodes incoming MSDP data. - - Args: - data (str or list): MSDP data. - - Notes: - Clients should always send MSDP data on - one of the following forms: - :: - - cmdname '' -> [cmdname, [], {}] - cmdname val -> [cmdname, [val], {}] - cmdname array -> [cmdname, [array], {}] - cmdname table -> [cmdname, [], {table}] - cmdname array cmdname table -> [cmdname, [array], {table}] - - Observe that all MSDP_VARS are used to identify cmdnames, - so if there are multiple arrays with the same cmdname - given, they will be merged into one argument array, same - for tables. Different MSDP_VARS (outside tables) will be - identified as separate cmdnames. - - """ - if isinstance(data, list): - data = b"".join(data) - - # print("decode_msdp in:", data) # DEBUG - - tables = {} - arrays = {} - variables = {} - - # decode tables - for key, table in msdp_regex_table.findall(data): - key = key.decode() - tables[key] = {} if key not in tables else tables[key] - for varval in msdp_regex_var.split(table)[1:]: - var, val = msdp_regex_val.split(varval, 1) - var, val = var.decode(), val.decode() - if var: - tables[key][var] = val - - # decode arrays from all that was not a table - data_no_tables = msdp_regex_table.sub(b"", data) - for key, array in msdp_regex_array.findall(data_no_tables): - key = key.decode() - arrays[key] = [] if key not in arrays else arrays[key] - parts = msdp_regex_val.split(array) - parts = [part.decode() for part in parts] - if len(parts) == 2: - arrays[key].append(parts[1]) - elif len(parts) > 1: - arrays[key].extend(parts[1:]) - - # decode remainders from all that were not tables or arrays - data_no_tables_or_arrays = msdp_regex_array.sub(b"", data_no_tables) - for varval in msdp_regex_var.split(data_no_tables_or_arrays): - # get remaining varvals after cleaning away tables/arrays. If mathcing - # an existing key in arrays, it will be added as an argument to that command, - # otherwise it will be treated as a command without argument. - parts = msdp_regex_val.split(varval) - parts = [part.decode() for part in parts] - if len(parts) == 2: - variables[parts[0]] = parts[1] - elif len(parts) > 1: - variables[parts[0]] = parts[1:] - - cmds = {} - # merge matching table/array/variables together - for key, table in tables.items(): - args, kwargs = [], table - if key in arrays: - args.extend(arrays.pop(key)) - if key in variables: - args.append(variables.pop(key)) - cmds[key] = [args, kwargs] - - for key, arr in arrays.items(): - args, kwargs = arr, {} - if key in variables: - args.append(variables.pop(key)) - cmds[key] = [args, kwargs] - - for key, var in variables.items(): - cmds[key] = [[var], {}] - - # remap the 'generic msdp commands' to avoid colliding with builtins etc - # by prepending "msdp_" - lower_case = {key.lower(): key for key in cmds} - for remap in ("list", "report", "reset", "send", "unreport"): - if remap in lower_case: - cmds["msdp_{}".format(remap)] = cmds.pop(lower_case[remap]) - - # print("msdp data in:", cmds) # DEBUG - self.protocol.data_in(**cmds)
- -
[docs] def decode_gmcp(self, data): - """ - Decodes incoming GMCP data on the form 'varname <structure>'. - - Args: - data (str or list): GMCP data. - - Notes: - Clients send data on the form "Module.Submodule.Cmdname <structure>". - We assume the structure is valid JSON. - - The following is parsed into Evennia's formal structure: - :: - - Core.Name -> [name, [], {}] - Core.Name string -> [name, [string], {}] - Core.Name [arg, arg,...] -> [name, [args], {}] - Core.Name {key:arg, key:arg, ...} -> [name, [], {kwargs}] - Core.Name [[args], {kwargs}] -> [name, [args], {kwargs}] - - """ - if isinstance(data, list): - data = b"".join(data) - - # print("decode_gmcp in:", data) # DEBUG - if data: - try: - cmdname, structure = data.split(None, 1) - except ValueError: - cmdname, structure = data, b"" - cmdname = cmdname.replace(b".", b"_") - try: - structure = json.loads(structure) - except ValueError: - # maybe the structure is not json-serialized at all - pass - args, kwargs = [], {} - if is_iter(structure): - if isinstance(structure, dict): - kwargs = {key: value for key, value in structure.items() if key} - else: - args = list(structure) - else: - args = (structure,) - if cmdname.lower().startswith(b"core_"): - # if Core.cmdname, then use cmdname - cmdname = cmdname[5:] - self.protocol.data_in(**{cmdname.lower().decode(): [args, kwargs]})
- - # access methods - -
[docs] def data_out(self, cmdname, *args, **kwargs): - """ - Return a MSDP- or GMCP-valid subnegotiation across the protocol. - - Args: - cmdname (str): OOB-command name. - args, kwargs (any): Arguments to OOB command. - - """ - kwargs.pop("options", None) - - if self.MSDP: - encoded_oob = self.encode_msdp(cmdname, *args, **kwargs) - self.protocol._write(IAC + SB + MSDP + encoded_oob + IAC + SE) - - if self.GMCP: - encoded_oob = self.encode_gmcp(cmdname, *args, **kwargs) - self.protocol._write(IAC + SB + GMCP + encoded_oob + IAC + SE)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/telnet_ssl.html b/docs/0.9.5/_modules/evennia/server/portal/telnet_ssl.html deleted file mode 100644 index 8bfe9fe920..0000000000 --- a/docs/0.9.5/_modules/evennia/server/portal/telnet_ssl.html +++ /dev/null @@ -1,257 +0,0 @@ - - - - - - - - evennia.server.portal.telnet_ssl — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.portal.telnet_ssl

-"""
-This allows for running the telnet communication over an encrypted SSL tunnel. To use it, requires a
-client supporting Telnet SSL.
-
-The protocol will try to automatically create the private key and certificate on the server side
-when starting and will warn if this was not possible. These will appear as files ssl.key and
-ssl.cert in mygame/server/.
-
-"""
-import os
-
-try:
-    from OpenSSL import crypto
-    from twisted.internet import ssl as twisted_ssl
-except ImportError as error:
-    errstr = """
-    {err}
-    Telnet-SSL requires the PyOpenSSL library and dependencies:
-
-        pip install pyopenssl pycrypto enum pyasn1 service_identity
-
-    Stop and start Evennia again. If no certificate can be generated, you'll
-    get a suggestion for a (linux) command to generate this locally.
-
-    """
-    raise ImportError(errstr.format(err=error))
-
-from django.conf import settings
-from evennia.server.portal.telnet import TelnetProtocol
-
-_GAME_DIR = settings.GAME_DIR
-
-_PRIVATE_KEY_LENGTH = 2048
-_PRIVATE_KEY_FILE = os.path.join(_GAME_DIR, "server", "ssl.key")
-_PUBLIC_KEY_FILE = os.path.join(_GAME_DIR, "server", "ssl-public.key")
-_CERTIFICATE_FILE = os.path.join(_GAME_DIR, "server", "ssl.cert")
-_CERTIFICATE_EXPIRE = 365 * 24 * 60 * 60 * 20  # 20 years
-_CERTIFICATE_ISSUER = {
-    "C": "EV",
-    "ST": "Evennia",
-    "L": "Evennia",
-    "O": "Evennia Security",
-    "OU": "Evennia Department",
-    "CN": "evennia",
-}
-
-# messages
-
-NO_AUTOGEN = f"""
-Evennia could not auto-generate the SSL private- and public keys ({{err}}).
-If this error persists, create them manually (using the tools for your OS). The files
-should be placed and named like this:
-    {_PRIVATE_KEY_FILE}
-    {_PUBLIC_KEY_FILE}
-"""
-
-NO_AUTOCERT = """
-Evennia's could not auto-generate the SSL certificate ({{err}}).
-The private key already exists here:
-    {_PRIVATE_KEY_FILE}
-If this error persists, create the certificate manually (using the private key and
-the tools for your OS). The file should be placed and named like this:
-    {_CERTIFICATE_FILE}
-"""
-
-
-
[docs]class SSLProtocol(TelnetProtocol): - """ - Communication is the same as telnet, except data transfer - is done with encryption set up by the portal at start time. - - """ - -
[docs] def __init__(self, *args, **kwargs): - super(SSLProtocol, self).__init__(*args, **kwargs) - self.protocol_key = "telnet/ssl"
- - -
[docs]def verify_or_create_SSL_key_and_cert(keyfile, certfile): - """ - Verify or create new key/certificate files. - - Args: - keyfile (str): Path to ssl.key file. - certfile (str): Parth to ssl.cert file. - - Notes: - If files don't already exist, they are created. - - """ - - if not (os.path.exists(keyfile) and os.path.exists(certfile)): - # key/cert does not exist. Create. - try: - # generate the keypair - keypair = crypto.PKey() - keypair.generate_key(crypto.TYPE_RSA, _PRIVATE_KEY_LENGTH) - - with open(_PRIVATE_KEY_FILE, "wt") as pfile: - pfile.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, keypair).decode("utf-8")) - print("Created SSL private key in '{}'.".format(_PRIVATE_KEY_FILE)) - - with open(_PUBLIC_KEY_FILE, "wt") as pfile: - pfile.write(crypto.dump_publickey(crypto.FILETYPE_PEM, keypair).decode("utf-8")) - print("Created SSL public key in '{}'.".format(_PUBLIC_KEY_FILE)) - - except Exception as err: - print(NO_AUTOGEN.format(err=err)) - return False - - else: - - try: - # create certificate - cert = crypto.X509() - subj = cert.get_subject() - for key, value in _CERTIFICATE_ISSUER.items(): - setattr(subj, key, value) - cert.set_issuer(subj) - - cert.set_serial_number(1000) - cert.gmtime_adj_notBefore(0) - cert.gmtime_adj_notAfter(_CERTIFICATE_EXPIRE) - cert.set_pubkey(keypair) - cert.sign(keypair, "sha1") - - with open(_CERTIFICATE_FILE, "wt") as cfile: - cfile.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode("utf-8")) - print("Created SSL certificate in '{}'.".format(_CERTIFICATE_FILE)) - - except Exception as err: - print(NO_AUTOCERT.format(err=err)) - return False - - return True
- - -
[docs]def getSSLContext(): - """ - This is called by the portal when creating the SSL context - server-side. - - Returns: - ssl_context (tuple): A key and certificate that is either - existing previously or created on the fly. - - """ - - if verify_or_create_SSL_key_and_cert(_PRIVATE_KEY_FILE, _CERTIFICATE_FILE): - return twisted_ssl.DefaultOpenSSLContextFactory(_PRIVATE_KEY_FILE, _CERTIFICATE_FILE) - else: - return None
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/tests.html b/docs/0.9.5/_modules/evennia/server/portal/tests.html deleted file mode 100644 index c2fb7e7a17..0000000000 --- a/docs/0.9.5/_modules/evennia/server/portal/tests.html +++ /dev/null @@ -1,426 +0,0 @@ - - - - - - - - evennia.server.portal.tests — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.portal.tests

-try:
-    from django.utils.unittest import TestCase
-except ImportError:
-    from django.test import TestCase
-
-try:
-    from django.utils import unittest
-except ImportError:
-    import unittest
-
-import sys
-import string
-import mock
-import pickle
-import json
-
-from mock import Mock, MagicMock
-from evennia.server.portal import irc
-from evennia.utils.test_resources import BaseEvenniaTest
-
-from twisted.conch.telnet import IAC, WILL, DONT, SB, SE, NAWS, DO
-from twisted.test import proto_helpers
-from twisted.trial.unittest import TestCase as TwistedTestCase
-from twisted.internet.base import DelayedCall
-
-from .telnet import TelnetServerFactory, TelnetProtocol
-from .portal import PORTAL_SESSIONS
-from .suppress_ga import SUPPRESS_GA
-from .naws import DEFAULT_HEIGHT, DEFAULT_WIDTH
-from .ttype import TTYPE, IS
-from .mccp import MCCP
-from .mssp import MSSP
-from .mxp import MXP
-from .telnet_oob import MSDP, MSDP_VAL, MSDP_VAR
-
-from .amp import AMPMultiConnectionProtocol, MsgServer2Portal, MsgPortal2Server, AMP_MAXLEN
-from .amp_server import AMPServerFactory
-
-from autobahn.twisted.websocket import WebSocketServerFactory
-from .webclient import WebSocketClient
-
-
-
[docs]class TestAMPServer(TwistedTestCase): - """ - Test AMP communication - """ - -
[docs] def setUp(self): - super(TestAMPServer, self).setUp() - portal = Mock() - factory = AMPServerFactory(portal) - self.proto = factory.buildProtocol(("localhost", 0)) - self.transport = MagicMock() # proto_helpers.StringTransport() - self.transport.client = ["localhost"] - self.transport.write = MagicMock()
- -
[docs] def test_amp_out(self): - self.proto.makeConnection(self.transport) - - self.proto.data_to_server(MsgServer2Portal, 1, test=2) - - if pickle.HIGHEST_PROTOCOL == 5: - # Python 3.8+ - byte_out = ( - b"\x00\x04_ask\x00\x011\x00\x08_command\x00\x10MsgServer2Portal\x00\x0b" - b"packed_data\x00 x\xdak`\x9d*\xc8\x00\x01\xde\x8c\xb5SzXJR" - b"\x8bK\xa6x3\x15\xb7M\xd1\x03\x00VU\x07u\x00\x00" - ) - elif pickle.HIGHEST_PROTOCOL == 4: - # Python 3.7 - byte_out = ( - b"\x00\x04_ask\x00\x011\x00\x08_command\x00\x10MsgServer2Portal\x00\x0b" - b"packed_data\x00 x\xdak`\x99*\xc8\x00\x01\xde\x8c\xb5SzXJR" - b"\x8bK\xa6x3\x15\xb7M\xd1\x03\x00V:\x07t\x00\x00" - ) - self.transport.write.assert_called_with(byte_out) - with mock.patch("evennia.server.portal.amp.amp.AMP.dataReceived") as mocked_amprecv: - self.proto.dataReceived(byte_out) - mocked_amprecv.assert_called_with(byte_out)
- -
[docs] def test_amp_in(self): - self.proto.makeConnection(self.transport) - - self.proto.data_to_server(MsgPortal2Server, 1, test=2) - if pickle.HIGHEST_PROTOCOL == 5: - # Python 3.8+ - byte_out = ( - b"\x00\x04_ask\x00\x011\x00\x08_command\x00\x10MsgPortal2Server\x00\x0b" - b"packed_data\x00 x\xdak`\x9d*\xc8\x00\x01\xde\x8c\xb5SzXJR" - b"\x8bK\xa6x3\x15\xb7M\xd1\x03\x00VU\x07u\x00\x00" - ) - elif pickle.HIGHEST_PROTOCOL == 4: - # Python 3.7 - byte_out = ( - b"\x00\x04_ask\x00\x011\x00\x08_command\x00\x10MsgPortal2Server\x00\x0b" - b"packed_data\x00 x\xdak`\x99*\xc8\x00\x01\xde\x8c\xb5SzXJR" - b"\x8bK\xa6x3\x15\xb7M\xd1\x03\x00V:\x07t\x00\x00" - ) - self.transport.write.assert_called_with(byte_out) - with mock.patch("evennia.server.portal.amp.amp.AMP.dataReceived") as mocked_amprecv: - self.proto.dataReceived(byte_out) - mocked_amprecv.assert_called_with(byte_out)
- -
[docs] def test_large_msg(self): - """ - Send message larger than AMP_MAXLEN - should be split into several - """ - self.proto.makeConnection(self.transport) - outstr = "test" * AMP_MAXLEN - self.proto.data_to_server(MsgServer2Portal, 1, test=outstr) - - if pickle.HIGHEST_PROTOCOL == 5: - # Python 3.8+ - self.transport.write.assert_called_with( - b"\x00\x04_ask\x00\x011\x00\x08_command\x00\x10MsgServer2Portal\x00\x0bpacked_data" - b"\x00wx\xda\xed\xc6\xc1\t\x80 \x00@Q#=5Z\x0b\xb8\x80\x13\xe85h\x80\x8e\xbam`Dc\xf4><\xf8g" - b"\x1a[\xf8\xda\x97\xa3_\xb1\x95\xdaz\xbe\xe7\x1a\xde\x03\x00\x00\x00\x00\x00\x00\x00" - b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x1f\x1eP\x1d\x02\r\x00\rpacked_data.2" - b"\x00Zx\xda\xed\xc3\x01\r\x00\x00\x08\xc0\xa0\xb4&\xf0\xfdg\x10a\xa3" - b"\xd9RUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU\xf5\xfb\x03m\xe0\x06" - b"\x1d\x00\rpacked_data.3\x00Zx\xda\xed\xc3\x01\r\x00\x00\x08\xc0\xa0\xb4&\xf0\xfdg\x10a" - b"\xa3fSUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU\xf5\xfb\x03n\x1c" - b"\x06\x1e\x00\rpacked_data.4\x00Zx\xda\xed\xc3\x01\t\x00\x00\x0c\x03\xa0\xb4O\xb0\xf5gA" - b"\xae`\xda\x8b\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - b"\xaa\xaa\xaa\xdf\x0fnI\x06,\x00\rpacked_data.5\x00\x18x\xdaK-.)I\xc5\x8e\xa7\xb22@\xc0" - b"\x94\xe2\xb6)z\x00Z\x1e\x0e\xb6\x00\x00" - ) - elif pickle.HIGHEST_PROTOCOL == 4: - # Python 3.7 - self.transport.write.assert_called_with( - b"\x00\x04_ask\x00\x011\x00\x08_command\x00\x10MsgServer2Portal\x00\x0bpacked_data" - b"\x00wx\xda\xed\xc6\xc1\t\x80 \x00@Q#o\x8e\xd6\x02-\xe0\x04z\r\x1a\xa0\xa3m+$\xd2" - b"\x18\xbe\x0f\x0f\xfe\x1d\xdf\x14\xfe\x8e\xedjO\xac\xb9\xd4v\xf6o\x0f\xf3\x00\x00" - b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - b"\x00X\xc3\x00P\x10\x02\x0c\x00\rpacked_data.2\x00Zx\xda\xed\xc3\x01\r\x00\x00\x08" - b"\xc0\xa0\xb4&\xf0\xfdg\x10a\xa3\xd9RUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU" - b"\xf5\xfb\x03m\xe0\x06\x1d\x00\rpacked_data.3\x00Zx\xda\xed\xc3\x01\r\x00\x00\x08" - b"\xc0\xa0\xb4&\xf0\xfdg\x10a\xa3fSUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU" - b"\xf5\xfb\x03n\x1c\x06\x1e\x00\rpacked_data.4\x00Zx\xda\xed\xc3\x01\t\x00\x00\x0c" - b"\x03\xa0\xb4O\xb0\xf5gA\xae`\xda\x8b\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - b"\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xdf\x0fnI\x06,\x00\rpacked_data.5" - b"\x00\x18x\xdaK-.)I\xc5\x8e\xa7\xb22@\xc0\x94\xe2\xb6)z\x00Z\x1e\x0e\xb6\x00\x00" - )
- - -
[docs]class TestIRC(TestCase): -
[docs] def test_plain_ansi(self): - """ - Test that printable characters do not get mangled. - """ - irc_ansi = irc.parse_ansi_to_irc(string.printable) - ansi_irc = irc.parse_irc_to_ansi(string.printable) - self.assertEqual(irc_ansi, string.printable) - self.assertEqual(ansi_irc, string.printable)
- -
[docs] def test_bold(self): - s_irc = "\x02thisisatest" - s_eve = r"|hthisisatest" - self.assertEqual(irc.parse_ansi_to_irc(s_eve), s_irc) - self.assertEqual(s_eve, irc.parse_irc_to_ansi(s_irc))
- -
[docs] def test_italic(self): - s_irc = "\x02thisisatest" - s_eve = r"|hthisisatest" - self.assertEqual(irc.parse_ansi_to_irc(s_eve), s_irc)
- -
[docs] def test_colors(self): - color_map = ( - ("\0030", r"|w"), - ("\0031", r"|X"), - ("\0032", r"|B"), - ("\0033", r"|G"), - ("\0034", r"|r"), - ("\0035", r"|R"), - ("\0036", r"|M"), - ("\0037", r"|Y"), - ("\0038", r"|y"), - ("\0039", r"|g"), - ("\00310", r"|C"), - ("\00311", r"|c"), - ("\00312", r"|b"), - ("\00313", r"|m"), - ("\00314", r"|x"), - ("\00315", r"|W"), - ("\00399,5", r"|[r"), - ("\00399,3", r"|[g"), - ("\00399,7", r"|[y"), - ("\00399,2", r"|[b"), - ("\00399,6", r"|[m"), - ("\00399,10", r"|[c"), - ("\00399,15", r"|[w"), - ("\00399,1", r"|[x"), - ) - - for m in color_map: - self.assertEqual(irc.parse_irc_to_ansi(m[0]), m[1]) - self.assertEqual(m[0], irc.parse_ansi_to_irc(m[1]))
- -
[docs] def test_identity(self): - """ - Test that the composition of the function and - its inverse gives the correct string. - """ - - s = r"|wthis|Xis|gis|Ma|C|complex|*string" - - self.assertEqual(irc.parse_irc_to_ansi(irc.parse_ansi_to_irc(s)), s)
- - -
[docs]class TestTelnet(TwistedTestCase): -
[docs] def setUp(self): - super(TestTelnet, self).setUp() - factory = TelnetServerFactory() - factory.protocol = TelnetProtocol - factory.sessionhandler = PORTAL_SESSIONS - factory.sessionhandler.portal = Mock() - self.proto = factory.buildProtocol(("localhost", 0)) - self.transport = proto_helpers.StringTransport() - self.addCleanup(factory.sessionhandler.disconnect_all)
- -
[docs] @mock.patch("evennia.server.portal.portalsessionhandler.reactor", new=MagicMock()) - def test_mudlet_ttype(self): - self.transport.client = ["localhost"] - self.transport.setTcpKeepAlive = Mock() - d = self.proto.makeConnection(self.transport) - # test suppress_ga - self.assertTrue(self.proto.protocol_flags["NOGOAHEAD"]) - self.proto.dataReceived(IAC + DONT + SUPPRESS_GA) - self.assertFalse(self.proto.protocol_flags["NOGOAHEAD"]) - self.assertEqual(self.proto.handshakes, 7) - # test naws - self.assertEqual(self.proto.protocol_flags["SCREENWIDTH"], {0: DEFAULT_WIDTH}) - self.assertEqual(self.proto.protocol_flags["SCREENHEIGHT"], {0: DEFAULT_HEIGHT}) - self.proto.dataReceived(IAC + WILL + NAWS) - self.proto.dataReceived(b"".join([IAC, SB, NAWS, b"", b"x", b"", b"d", IAC, SE])) - self.assertEqual(self.proto.protocol_flags["SCREENWIDTH"][0], 78) - self.assertEqual(self.proto.protocol_flags["SCREENHEIGHT"][0], 45) - self.assertEqual(self.proto.handshakes, 6) - # test ttype - self.assertFalse(self.proto.protocol_flags["TTYPE"]) - self.assertTrue(self.proto.protocol_flags["ANSI"]) - self.proto.dataReceived(IAC + WILL + TTYPE) - self.proto.dataReceived(b"".join([IAC, SB, TTYPE, IS, b"MUDLET", IAC, SE])) - self.assertTrue(self.proto.protocol_flags["XTERM256"]) - self.assertEqual(self.proto.protocol_flags["CLIENTNAME"], "MUDLET") - self.assertTrue(self.proto.protocol_flags["FORCEDENDLINE"]) - self.assertTrue(self.proto.protocol_flags["NOGOAHEAD"]) - self.assertFalse(self.proto.protocol_flags["NOPROMPTGOAHEAD"]) - self.proto.dataReceived(b"".join([IAC, SB, TTYPE, IS, b"XTERM", IAC, SE])) - self.proto.dataReceived(b"".join([IAC, SB, TTYPE, IS, b"MTTS 137", IAC, SE])) - self.assertEqual(self.proto.handshakes, 5) - # test mccp - self.proto.dataReceived(IAC + DONT + MCCP) - self.assertFalse(self.proto.protocol_flags["MCCP"]) - self.assertEqual(self.proto.handshakes, 4) - # test mssp - self.proto.dataReceived(IAC + DONT + MSSP) - self.assertEqual(self.proto.handshakes, 3) - # test oob - self.proto.dataReceived(IAC + DO + MSDP) - self.proto.dataReceived( - b"".join([IAC, SB, MSDP, MSDP_VAR, b"LIST", MSDP_VAL, b"COMMANDS", IAC, SE]) - ) - self.assertTrue(self.proto.protocol_flags["OOB"]) - self.assertEqual(self.proto.handshakes, 2) - # test mxp - self.proto.dataReceived(IAC + DONT + MXP) - self.assertFalse(self.proto.protocol_flags["MXP"]) - self.assertEqual(self.proto.handshakes, 1) - # clean up to prevent Unclean reactor - self.proto.nop_keep_alive.stop() - self.proto._handshake_delay.cancel() - return d
- - -
[docs]class TestWebSocket(BaseEvenniaTest): -
[docs] def setUp(self): - super().setUp() - self.proto = WebSocketClient() - self.proto.factory = WebSocketServerFactory() - self.proto.factory.sessionhandler = PORTAL_SESSIONS - self.proto.sessionhandler = PORTAL_SESSIONS - self.proto.sessionhandler.portal = Mock() - self.proto.transport = proto_helpers.StringTransport() - # self.proto.transport = proto_helpers.FakeDatagramTransport() - self.proto.transport.client = ["localhost"] - self.proto.transport.setTcpKeepAlive = Mock() - self.proto.state = MagicMock() - self.addCleanup(self.proto.factory.sessionhandler.disconnect_all) - DelayedCall.debug = True
- -
[docs] def tearDown(self): - super().tearDown()
- -
[docs] @mock.patch("evennia.server.portal.portalsessionhandler.reactor", new=MagicMock()) - def test_data_in(self): - self.proto.sessionhandler.data_in = MagicMock() - self.proto.onOpen() - msg = json.dumps(["logged_in", (), {}]).encode() - self.proto.onMessage(msg, isBinary=False) - self.proto.sessionhandler.data_in.assert_called_with(self.proto, logged_in=[[], {}]) - sendStr = "You can get anything you want at Alice's Restaurant." - msg = json.dumps(["text", (sendStr,), {}]).encode() - self.proto.onMessage(msg, isBinary=False) - self.proto.sessionhandler.data_in.assert_called_with(self.proto, text=[[sendStr], {}])
- -
[docs] @mock.patch("evennia.server.portal.portalsessionhandler.reactor", new=MagicMock()) - def test_data_out(self): - self.proto.onOpen() - self.proto.sendLine = MagicMock() - msg = json.dumps(["logged_in", (), {}]) - self.proto.sessionhandler.data_out(self.proto, text=[["Excepting Alice"], {}]) - self.proto.sendLine.assert_called_with(json.dumps(["text", ["Excepting Alice"], {}]))
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/ttype.html b/docs/0.9.5/_modules/evennia/server/portal/ttype.html deleted file mode 100644 index b8196bfeed..0000000000 --- a/docs/0.9.5/_modules/evennia/server/portal/ttype.html +++ /dev/null @@ -1,292 +0,0 @@ - - - - - - - - evennia.server.portal.ttype — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.portal.ttype

-"""
-TTYPE (MTTS) - Mud Terminal Type Standard
-
-This module implements the TTYPE telnet protocol as per
-http://tintin.sourceforge.net/mtts/. It allows the server to ask the
-client about its capabilities. If the client also supports TTYPE, it
-will return with information such as its name, if it supports colour
-etc. If the client does not support TTYPE, this will be ignored.
-
-All data will be stored on the protocol's protocol_flags dictionary,
-under the 'TTYPE' key.
-
-"""
-
-# telnet option codes
-TTYPE = bytes([24])  # b"\x18"
-IS = bytes([0])  # b"\x00"
-SEND = bytes([1])  # b"\x01"
-
-# terminal capabilities and their codes
-MTTS = [
-    (128, "PROXY"),
-    (64, "SCREENREADER"),
-    (32, "OSC_COLOR_PALETTE"),
-    (16, "MOUSE_TRACKING"),
-    (8, "XTERM256"),
-    (4, "UTF-8"),
-    (2, "VT100"),
-    (1, "ANSI"),
-]
-
-
-
[docs]class Ttype: - """ - Handles ttype negotiations. Called and initiated by the - telnet protocol. - - """ - -
[docs] def __init__(self, protocol): - """ - Initialize ttype by storing protocol on ourselves and calling - the client to see if it supporst ttype. - - Args: - protocol (Protocol): The protocol instance. - - Notes: - The `self.ttype_step` indicates how far in the data - retrieval we've gotten. - - """ - self.ttype_step = 0 - self.protocol = protocol - # we set FORCEDENDLINE for clients not supporting ttype - self.protocol.protocol_flags["FORCEDENDLINE"] = True - self.protocol.protocol_flags["TTYPE"] = False - # is it a safe bet to assume ANSI is always supported? - self.protocol.protocol_flags["ANSI"] = True - # setup protocol to handle ttype initialization and negotiation - self.protocol.negotiationMap[TTYPE] = self.will_ttype - # ask if client will ttype, connect callback if it does. - self.protocol.do(TTYPE).addCallbacks(self.will_ttype, self.wont_ttype)
- -
[docs] def wont_ttype(self, option): - """ - Callback if ttype is not supported by client. - - Args: - option (Option): Not used. - - """ - self.protocol.protocol_flags["TTYPE"] = False - self.protocol.handshake_done()
- -
[docs] def will_ttype(self, option): - """ - Handles negotiation of the ttype protocol once the client has - confirmed that it will respond with the ttype protocol. - - Args: - option (Option): Not used. - - Notes: - The negotiation proceeds in several steps, each returning a - certain piece of information about the client. All data is - stored on protocol.protocol_flags under the TTYPE key. - - """ - options = self.protocol.protocol_flags - - if options and options.get("TTYPE", False) or self.ttype_step > 3: - return - - try: - option = b"".join(option).lstrip(IS).decode() - except TypeError: - # option is not on a suitable form for joining - pass - - if self.ttype_step == 0: - # just start the request chain - self.protocol.requestNegotiation(TTYPE, SEND) - - elif self.ttype_step == 1: - # this is supposed to be the name of the client/terminal. - # For clients not supporting the extended TTYPE - # definition, subsequent calls will just repeat-return this. - try: - clientname = option.upper() - except AttributeError: - # malformed option (not a string) - clientname = "UNKNOWN" - - # use name to identify support for xterm256. Many of these - # only support after a certain version, but all support - # it since at least 4 years. We assume recent client here for now. - xterm256 = False - if clientname.startswith("MUDLET"): - # supports xterm256 stably since 1.1 (2010?) - xterm256 = clientname.split("MUDLET", 1)[1].strip() >= "1.1" - # Mudlet likes GA's on a prompt line for the prompt trigger to - # match, if it's not wanting NOGOAHEAD. - if not self.protocol.protocol_flags["NOGOAHEAD"]: - self.protocol.protocol_flags["NOGOAHEAD"] = True - self.protocol.protocol_flags["NOPROMPTGOAHEAD"] = False - - if ( - clientname.startswith("XTERM") - or clientname.endswith("-256COLOR") - or clientname - in ( - "ATLANTIS", # > 0.9.9.0 (aug 2009) - "CMUD", # > 3.04 (mar 2009) - "KILDCLIENT", # > 2.2.0 (sep 2005) - "MUDLET", # > beta 15 (sep 2009) - "MUSHCLIENT", # > 4.02 (apr 2007) - "PUTTY", # > 0.58 (apr 2005) - "BEIP", # > 2.00.206 (late 2009) (BeipMu) - "POTATO", # > 2.00 (maybe earlier) - "TINYFUGUE", # > 4.x (maybe earlier) - ) - ): - xterm256 = True - - # all clients supporting TTYPE at all seem to support ANSI - self.protocol.protocol_flags["ANSI"] = True - self.protocol.protocol_flags["XTERM256"] = xterm256 - self.protocol.protocol_flags["CLIENTNAME"] = clientname - self.protocol.requestNegotiation(TTYPE, SEND) - - elif self.ttype_step == 2: - # this is a term capabilities flag - term = option - tupper = term.upper() - # identify xterm256 based on flag - xterm256 = ( - tupper.endswith("-256COLOR") - or tupper.endswith("XTERM") # Apple Terminal, old Tintin - and not tupper.endswith("-COLOR") # old Tintin, Putty - ) - if xterm256: - self.protocol.protocol_flags["ANSI"] = True - self.protocol.protocol_flags["XTERM256"] = xterm256 - self.protocol.protocol_flags["TERM"] = term - # request next information - self.protocol.requestNegotiation(TTYPE, SEND) - - elif self.ttype_step == 3: - # the MTTS bitstring identifying term capabilities - if option.startswith("MTTS"): - option = option[4:].strip() - if option.isdigit(): - # a number - determine the actual capabilities - option = int(option) - support = dict( - (capability, True) for bitval, capability in MTTS if option & bitval > 0 - ) - self.protocol.protocol_flags.update(support) - else: - # some clients send erroneous MTTS as a string. Add directly. - self.protocol.protocol_flags[option.upper()] = True - - self.protocol.protocol_flags["TTYPE"] = True - # we must sync ttype once it'd done - self.protocol.handshake_done() - self.ttype_step += 1
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/webclient.html b/docs/0.9.5/_modules/evennia/server/portal/webclient.html deleted file mode 100644 index 06b9aa527e..0000000000 --- a/docs/0.9.5/_modules/evennia/server/portal/webclient.html +++ /dev/null @@ -1,421 +0,0 @@ - - - - - - - - evennia.server.portal.webclient — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.portal.webclient

-"""
-Webclient based on websockets.
-
-This implements a webclient with WebSockets (http://en.wikipedia.org/wiki/WebSocket)
-by use of the autobahn-python package's implementation (https://github.com/crossbario/autobahn-python).
-It is used together with evennia/web/media/javascript/evennia_websocket_webclient.js.
-
-All data coming into the webclient is in the form of valid JSON on the form
-
-`["inputfunc_name", [args], {kwarg}]`
-
-which represents an "inputfunc" to be called on the Evennia side with *args, **kwargs.
-The most common inputfunc is "text", which takes just the text input
-from the command line and interprets it as an Evennia Command: `["text", ["look"], {}]`
-
-"""
-import re
-import json
-import html
-from django.conf import settings
-from evennia.utils.utils import mod_import, class_from_module
-from evennia.utils.ansi import parse_ansi
-from evennia.utils.text2html import parse_html
-from autobahn.twisted.websocket import WebSocketServerProtocol
-from autobahn.exception import Disconnected
-
-_RE_SCREENREADER_REGEX = re.compile(
-    r"%s" % settings.SCREENREADER_REGEX_STRIP, re.DOTALL + re.MULTILINE
-)
-_CLIENT_SESSIONS = mod_import(settings.SESSION_ENGINE).SessionStore
-_UPSTREAM_IPS = settings.UPSTREAM_IPS
-
-# Status Code 1000: Normal Closure
-#   called when the connection was closed through JavaScript
-CLOSE_NORMAL = WebSocketServerProtocol.CLOSE_STATUS_CODE_NORMAL
-
-# Status Code 1001: Going Away
-#   called when the browser is navigating away from the page
-GOING_AWAY = WebSocketServerProtocol.CLOSE_STATUS_CODE_GOING_AWAY
-
-_BASE_SESSION_CLASS = class_from_module(settings.BASE_SESSION_CLASS)
-
-
-
[docs]class WebSocketClient(WebSocketServerProtocol, _BASE_SESSION_CLASS): - """ - Implements the server-side of the Websocket connection. - - """ - - # nonce value, used to prevent the webclient from erasing the - # webclient_authenticated_uid value of csession on disconnect - nonce = 0 - -
[docs] def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.protocol_key = "webclient/websocket" - self.browserstr = ""
- -
[docs] def get_client_session(self): - """ - Get the Client browser session (used for auto-login based on browser session) - - Returns: - csession (ClientSession): This is a django-specific internal representation - of the browser session. - - """ - try: - # client will connect with wsurl?csessid&browserid - webarg = self.http_request_uri.split("?", 1)[1] - except IndexError: - # this may happen for custom webclients not caring for the - # browser session. - self.csessid = None - return None - except AttributeError: - from evennia.utils import logger - - self.csessid = None - logger.log_trace(str(self)) - return None - - self.csessid, *browserstr = webarg.split("&", 1) - if browserstr: - self.browserstr = str(browserstr[0]) - - if self.csessid: - return _CLIENT_SESSIONS(session_key=self.csessid)
- -
[docs] def onOpen(self): - """ - This is called when the WebSocket connection is fully established. - - """ - client_address = self.transport.client - client_address = client_address[0] if client_address else None - - if client_address in _UPSTREAM_IPS and "x-forwarded-for" in self.http_headers: - addresses = [x.strip() for x in self.http_headers["x-forwarded-for"].split(",")] - addresses.reverse() - - for addr in addresses: - if addr not in _UPSTREAM_IPS: - client_address = addr - break - - self.init_session("websocket", client_address, self.factory.sessionhandler) - - csession = self.get_client_session() # this sets self.csessid - csessid = self.csessid - uid = csession and csession.get("webclient_authenticated_uid", None) - nonce = csession and csession.get("webclient_authenticated_nonce", 0) - if uid: - # the client session is already logged in. - self.uid = uid - self.nonce = nonce - self.logged_in = True - - for old_session in self.sessionhandler.sessions_from_csessid(csessid): - if ( - hasattr(old_session, "websocket_close_code") - and old_session.websocket_close_code != CLOSE_NORMAL - ): - # if we have old sessions with the same csession, they are remnants - self.sessid = old_session.sessid - self.sessionhandler.disconnect(old_session) - - browserstr = f":{self.browserstr}" if self.browserstr else "" - self.protocol_flags["CLIENTNAME"] = f"Evennia Webclient (websocket{browserstr})" - self.protocol_flags["UTF-8"] = True - self.protocol_flags["OOB"] = True - - # watch for dead links - self.transport.setTcpKeepAlive(1) - # actually do the connection - self.sessionhandler.connect(self)
- -
[docs] def disconnect(self, reason=None): - """ - Generic hook for the engine to call in order to - disconnect this protocol. - - Args: - reason (str or None): Motivation for the disconnection. - - """ - csession = self.get_client_session() - - if csession: - # if the nonce is different, webclient_authenticated_uid has been - # set *before* this disconnect (disconnect called after a new client - # connects, which occurs in some 'fast' browsers like Google Chrome - # and Mobile Safari) - if csession.get("webclient_authenticated_nonce", 0) == self.nonce: - csession["webclient_authenticated_uid"] = None - csession["webclient_authenticated_nonce"] = 0 - csession.save() - self.logged_in = False - - self.sessionhandler.disconnect(self) - # autobahn-python: - # 1000 for a normal close, 1001 if the browser window is closed, - # 3000-4999 for app. specific, - # in case anyone wants to expose this functionality later. - # - # sendClose() under autobahn/websocket/interfaces.py - self.sendClose(CLOSE_NORMAL, reason)
- -
[docs] def onClose(self, wasClean, code=None, reason=None): - """ - This is executed when the connection is lost for whatever - reason. it can also be called directly, from the disconnect - method. - - Args: - wasClean (bool): ``True`` if the WebSocket was closed cleanly. - code (int or None): Close status as sent by the WebSocket peer. - reason (str or None): Close reason as sent by the WebSocket peer. - - """ - if code == CLOSE_NORMAL or code == GOING_AWAY: - self.disconnect(reason) - else: - self.websocket_close_code = code
- -
[docs] def onMessage(self, payload, isBinary): - """ - Callback fired when a complete WebSocket message was received. - - Args: - payload (bytes): The WebSocket message received. - isBinary (bool): Flag indicating whether payload is binary or - UTF-8 encoded text. - - """ - cmdarray = json.loads(str(payload, "utf-8")) - if cmdarray: - self.data_in(**{cmdarray[0]: [cmdarray[1], cmdarray[2]]})
- -
[docs] def sendLine(self, line): - """ - Send data to client. - - Args: - line (str): Text to send. - - """ - try: - return self.sendMessage(line.encode()) - except Disconnected: - # this can happen on an unclean close of certain browsers. - # it means this link is actually already closed. - self.disconnect(reason="Browser already closed.")
- -
[docs] def at_login(self): - csession = self.get_client_session() - if csession: - csession["webclient_authenticated_uid"] = self.uid - csession.save()
- -
[docs] def data_in(self, **kwargs): - """ - Data User > Evennia. - - Args: - text (str): Incoming text. - kwargs (any): Options from protocol. - - Notes: - At initilization, the client will send the special - 'csessid' command to identify its browser session hash - with the Evennia side. - - The websocket client will also pass 'websocket_close' command - to report that the client has been closed and that the - session should be disconnected. - - Both those commands are parsed and extracted already at - this point. - - """ - if "websocket_close" in kwargs: - self.disconnect() - return - - self.sessionhandler.data_in(self, **kwargs)
- -
[docs] def send_text(self, *args, **kwargs): - """ - Send text data. This will pre-process the text for - color-replacement, conversion to html etc. - - Args: - text (str): Text to send. - - Keyword Args: - options (dict): Options-dict with the following keys understood: - - raw (bool): No parsing at all (leave ansi-to-html markers unparsed). - - nocolor (bool): Clean out all color. - - screenreader (bool): Use Screenreader mode. - - send_prompt (bool): Send a prompt with parsed html - - """ - if args: - args = list(args) - text = args[0] - if text is None: - return - else: - return - - flags = self.protocol_flags - - options = kwargs.pop("options", {}) - raw = options.get("raw", flags.get("RAW", False)) - client_raw = options.get("client_raw", False) - nocolor = options.get("nocolor", flags.get("NOCOLOR", False)) - screenreader = options.get("screenreader", flags.get("SCREENREADER", False)) - prompt = options.get("send_prompt", False) - - if screenreader: - # screenreader mode cleans up output - text = parse_ansi(text, strip_ansi=True, xterm256=False, mxp=False) - text = _RE_SCREENREADER_REGEX.sub("", text) - cmd = "prompt" if prompt else "text" - if raw: - if client_raw: - args[0] = text - else: - args[0] = html.escape(text) # escape html! - else: - args[0] = parse_html(text, strip_ansi=nocolor) - - # send to client on required form [cmdname, args, kwargs] - self.sendLine(json.dumps([cmd, args, kwargs]))
- -
[docs] def send_prompt(self, *args, **kwargs): - kwargs["options"].update({"send_prompt": True}) - self.send_text(*args, **kwargs)
- -
[docs] def send_default(self, cmdname, *args, **kwargs): - """ - Data Evennia -> User. - - Args: - cmdname (str): The first argument will always be the oob cmd name. - *args (any): Remaining args will be arguments for `cmd`. - - Keyword Args: - options (dict): These are ignored for oob commands. Use command - arguments (which can hold dicts) to send instructions to the - client instead. - - """ - if not cmdname == "options": - self.sendLine(json.dumps([cmdname, args, kwargs]))
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/portal/webclient_ajax.html b/docs/0.9.5/_modules/evennia/server/portal/webclient_ajax.html deleted file mode 100644 index 887fb5d6ac..0000000000 --- a/docs/0.9.5/_modules/evennia/server/portal/webclient_ajax.html +++ /dev/null @@ -1,596 +0,0 @@ - - - - - - - - evennia.server.portal.webclient_ajax — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.portal.webclient_ajax

-"""
-AJAX/COMET fallback webclient
-
-The AJAX/COMET web client consists of two components running on
-twisted and django. They are both a part of the Evennia website url
-tree (so the testing website might be located on
-http://localhost:4001/, whereas the webclient can be found on
-http://localhost:4001/webclient.)
-
-/webclient - this url is handled through django's template
-             system and serves the html page for the client
-             itself along with its javascript chat program.
-/webclientdata - this url is called by the ajax chat using
-                 POST requests (long-polling when necessary)
-                 The WebClient resource in this module will
-                 handle these requests and act as a gateway
-                 to sessions connected over the webclient.
-
-"""
-import json
-import re
-import time
-import html
-
-from twisted.web import server, resource
-from twisted.internet.task import LoopingCall
-from django.utils.functional import Promise
-from django.conf import settings
-from evennia.utils.ansi import parse_ansi
-from evennia.utils import utils
-from evennia.utils.utils import to_bytes
-from evennia.utils.text2html import parse_html
-from evennia.server import session
-
-_CLIENT_SESSIONS = utils.mod_import(settings.SESSION_ENGINE).SessionStore
-_RE_SCREENREADER_REGEX = re.compile(
-    r"%s" % settings.SCREENREADER_REGEX_STRIP, re.DOTALL + re.MULTILINE
-)
-_SERVERNAME = settings.SERVERNAME
-_KEEPALIVE = 30  # how often to check keepalive
-
-
-# defining a simple json encoder for returning
-# django data to the client. Might need to
-# extend this if one wants to send more
-# complex database objects too.
-
-
-
[docs]class LazyEncoder(json.JSONEncoder): -
[docs] def default(self, obj): - if isinstance(obj, Promise): - return str(obj) - return super().default(obj)
- - -
[docs]def jsonify(obj): - return to_bytes(json.dumps(obj, ensure_ascii=False, cls=LazyEncoder))
- - -# -# AjaxWebClient resource - this is called by the ajax client -# using POST requests to /webclientdata. -# - - -
[docs]class AjaxWebClient(resource.Resource): - """ - An ajax/comet long-polling transport - - """ - - isLeaf = True - allowedMethods = ("POST",) - -
[docs] def __init__(self): - self.requests = {} - self.databuffer = {} - - self.last_alive = {} - self.keep_alive = None
- - def _responseFailed(self, failure, csessid, request): - "callback if a request is lost/timed out" - try: - del self.requests[csessid] - except KeyError: - # nothing left to delete - pass - - def _keepalive(self): - """ - Callback for checking the connection is still alive. - """ - now = time.time() - to_remove = [] - keep_alives = ( - (csessid, remove) - for csessid, (t, remove) in self.last_alive.items() - if now - t > _KEEPALIVE - ) - for csessid, remove in keep_alives: - if remove: - # keepalive timeout. Line is dead. - to_remove.append(csessid) - else: - # normal timeout - send keepalive - self.last_alive[csessid] = (now, True) - self.lineSend(csessid, ["ajax_keepalive", [], {}]) - # remove timed-out sessions - for csessid in to_remove: - sessions = self.sessionhandler.sessions_from_csessid(csessid) - for sess in sessions: - sess.disconnect() - self.last_alive.pop(csessid, None) - if not self.last_alive: - # no more ajax clients. Stop the keepalive - self.keep_alive.stop() - self.keep_alive = None - -
[docs] def get_client_sessid(self, request): - """ - Helper to get the client session id out of the request. - - Args: - request (Request): Incoming request object. - Returns: - csessid (int): The client-session id. - - """ - return html.escape(request.args[b"csessid"][0].decode("utf-8"))
- -
[docs] def get_browserstr(self, request): - """ - Get browser-string out of the request. - - Args: - request (Request): Incoming request object. - Returns: - str: The browser name. - - - """ - return html.escape(request.args[b"browserstr"][0].decode("utf-8"))
- -
[docs] def at_login(self): - """ - Called when this session gets authenticated by the server. - """ - pass
- -
[docs] def lineSend(self, csessid, data): - """ - This adds the data to the buffer and/or sends it to the client - as soon as possible. - - Args: - csessid (int): Session id. - data (list): A send structure [cmdname, [args], {kwargs}]. - - """ - request = self.requests.get(csessid) - if request: - # we have a request waiting. Return immediately. - request.write(jsonify(data)) - request.finish() - del self.requests[csessid] - else: - # no waiting request. Store data in buffer - dataentries = self.databuffer.get(csessid, []) - dataentries.append(jsonify(data)) - self.databuffer[csessid] = dataentries
- -
[docs] def client_disconnect(self, csessid): - """ - Disconnect session with given csessid. - - Args: - csessid (int): Session id. - - """ - if csessid in self.requests: - self.requests[csessid].finish() - del self.requests[csessid] - if csessid in self.databuffer: - del self.databuffer[csessid]
- -
[docs] def mode_init(self, request): - """ - This is called by render_POST when the client requests an init - mode operation (at startup) - - Args: - request (Request): Incoming request. - - """ - csessid = self.get_client_sessid(request) - browserstr = self.get_browserstr(request) - - remote_addr = request.getClientIP() - - if remote_addr in settings.UPSTREAM_IPS and request.getHeader("x-forwarded-for"): - addresses = [x.strip() for x in request.getHeader("x-forwarded-for").split(",")] - addresses.reverse() - - for addr in addresses: - if addr not in settings.UPSTREAM_IPS: - remote_addr = addr - break - - host_string = "%s (%s:%s)" % ( - _SERVERNAME, - request.getRequestHostname(), - request.getHost().port, - ) - - sess = AjaxWebClientSession() - sess.client = self - sess.init_session("ajax/comet", remote_addr, self.sessionhandler) - - sess.csessid = csessid - sess.browserstr = browserstr - csession = _CLIENT_SESSIONS(session_key=sess.csessid) - uid = csession and csession.get("webclient_authenticated_uid", False) - if uid: - # the client session is already logged in - sess.uid = uid - sess.logged_in = True - - # watch for dead links - self.last_alive[csessid] = (time.time(), False) - if not self.keep_alive: - # the keepalive is not running; start it. - self.keep_alive = LoopingCall(self._keepalive) - self.keep_alive.start(_KEEPALIVE, now=False) - - browserstr = f":{browserstr}" if browserstr else "" - sess.protocol_flags["CLIENTNAME"] = f"Evennia Webclient (ajax{browserstr})" - sess.protocol_flags["UTF-8"] = True - sess.protocol_flags["OOB"] = True - - # actually do the connection - sess.sessionhandler.connect(sess) - - return jsonify({"msg": host_string, "csessid": csessid})
- -
[docs] def mode_keepalive(self, request): - """ - This is called by render_POST when the - client is replying to the keepalive. - - Args: - request (Request): Incoming request. - - """ - csessid = self.get_client_sessid(request) - self.last_alive[csessid] = (time.time(), False) - return b'""'
- -
[docs] def mode_input(self, request): - """ - This is called by render_POST when the client - is sending data to the server. - - Args: - request (Request): Incoming request. - - """ - csessid = self.get_client_sessid(request) - self.last_alive[csessid] = (time.time(), False) - cmdarray = json.loads(request.args.get(b"data")[0]) - for sess in self.sessionhandler.sessions_from_csessid(csessid): - sess.data_in(**{cmdarray[0]: [cmdarray[1], cmdarray[2]]}) - return b'""'
- -
[docs] def mode_receive(self, request): - """ - This is called by render_POST when the client is telling us - that it is ready to receive data as soon as it is available. - This is the basis of a long-polling (comet) mechanism: the - server will wait to reply until data is available. - - Args: - request (Request): Incoming request. - - """ - csessid = html.escape(request.args[b"csessid"][0].decode("utf-8")) - self.last_alive[csessid] = (time.time(), False) - - dataentries = self.databuffer.get(csessid) - if dataentries: - # we have data that could not be sent earlier (because client was not - # ready to receive it). Return this buffered data immediately - return dataentries.pop(0) - else: - # we have no data to send. End the old request and start - # a new long-polling one - request.notifyFinish().addErrback(self._responseFailed, csessid, request) - if csessid in self.requests: - self.requests[csessid].finish() # Clear any stale request. - self.requests[csessid] = request - return server.NOT_DONE_YET
- -
[docs] def mode_close(self, request): - """ - This is called by render_POST when the client is signalling - that it is about to be closed. - - Args: - request (Request): Incoming request. - - """ - csessid = self.get_client_sessid(request) - try: - sess = self.sessionhandler.sessions_from_csessid(csessid)[0] - sess.sessionhandler.disconnect(sess) - except IndexError: - self.client_disconnect(csessid) - return b'""'
- -
[docs] def render_POST(self, request): - """ - This function is what Twisted calls with POST requests coming - in from the ajax client. The requests should be tagged with - different modes depending on what needs to be done, such as - initializing or sending/receving data through the request. It - uses a long-polling mechanism to avoid sending data unless - there is actual data available. - - Args: - request (Request): Incoming request. - - """ - dmode = request.args.get(b"mode", [b"None"])[0].decode("utf-8") - - if dmode == "init": - # startup. Setup the server. - return self.mode_init(request) - elif dmode == "input": - # input from the client to the server - return self.mode_input(request) - elif dmode == "receive": - # the client is waiting to receive data. - return self.mode_receive(request) - elif dmode == "close": - # the client is closing - return self.mode_close(request) - elif dmode == "keepalive": - # A reply to our keepalive request - all is well - return self.mode_keepalive(request) - else: - # This should not happen if client sends valid data. - return b'""'
- - -# -# A session type handling communication over the -# web client interface. -# - - -
[docs]class AjaxWebClientSession(session.Session): - """ - This represents a session running in an AjaxWebclient. - """ - -
[docs] def __init__(self, *args, **kwargs): - self.protocol_key = "webclient/ajax" - super().__init__(*args, **kwargs)
- -
[docs] def get_client_session(self): - """ - Get the Client browser session (used for auto-login based on browser session) - - Returns: - csession (ClientSession): This is a django-specific internal representation - of the browser session. - - """ - if self.csessid: - return _CLIENT_SESSIONS(session_key=self.csessid)
- -
[docs] def disconnect(self, reason="Server disconnected."): - """ - Disconnect from server. - - Args: - reason (str): Motivation for the disconnect. - """ - csession = self.get_client_session() - - if csession: - csession["webclient_authenticated_uid"] = None - csession.save() - self.logged_in = False - self.client.lineSend(self.csessid, ["connection_close", [reason], {}]) - self.client.client_disconnect(self.csessid) - self.sessionhandler.disconnect(self)
- -
[docs] def at_login(self): - csession = self.get_client_session() - if csession: - csession["webclient_authenticated_uid"] = self.uid - csession.save()
- -
[docs] def data_in(self, **kwargs): - """ - Data User -> Evennia - - Keyword Args: - kwargs (any): Incoming data. - - """ - self.sessionhandler.data_in(self, **kwargs)
- -
[docs] def data_out(self, **kwargs): - """ - Data Evennia -> User - - Keyword Args: - kwargs (any): Options to the protocol - """ - self.sessionhandler.data_out(self, **kwargs)
- -
[docs] def send_text(self, *args, **kwargs): - """ - Send text data. This will pre-process the text for - color-replacement, conversion to html etc. - - Args: - text (str): Text to send. - - Keyword Args: - options (dict): Options-dict with the following keys understood: - - raw (bool): No parsing at all (leave ansi-to-html markers unparsed). - - nocolor (bool): Remove all color. - - screenreader (bool): Use Screenreader mode. - - send_prompt (bool): Send a prompt with parsed html - - """ - if args: - args = list(args) - text = args[0] - if text is None: - return - else: - return - - flags = self.protocol_flags - text = utils.to_str(text) - - options = kwargs.pop("options", {}) - raw = options.get("raw", flags.get("RAW", False)) - xterm256 = options.get("xterm256", flags.get("XTERM256", True)) - useansi = options.get("ansi", flags.get("ANSI", True)) - nocolor = options.get("nocolor", flags.get("NOCOLOR") or not (xterm256 or useansi)) - screenreader = options.get("screenreader", flags.get("SCREENREADER", False)) - prompt = options.get("send_prompt", False) - - if screenreader: - # screenreader mode cleans up output - text = parse_ansi(text, strip_ansi=True, xterm256=False, mxp=False) - text = _RE_SCREENREADER_REGEX.sub("", text) - cmd = "prompt" if prompt else "text" - if raw: - args[0] = text - else: - args[0] = parse_html(text, strip_ansi=nocolor) - - # send to client on required form [cmdname, args, kwargs] - self.client.lineSend(self.csessid, [cmd, args, kwargs])
- -
[docs] def send_prompt(self, *args, **kwargs): - kwargs["options"].update({"send_prompt": True}) - self.send_text(*args, **kwargs)
- -
[docs] def send_default(self, cmdname, *args, **kwargs): - """ - Data Evennia -> User. - - Args: - cmdname (str): The first argument will always be the oob cmd name. - *args (any): Remaining args will be arguments for `cmd`. - - Keyword Args: - options (dict): These are ignored for oob commands. Use command - arguments (which can hold dicts) to send instructions to the - client instead. - - """ - if not cmdname == "options": - self.client.lineSend(self.csessid, [cmdname, args, kwargs])
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/profiling/dummyrunner.html b/docs/0.9.5/_modules/evennia/server/profiling/dummyrunner.html deleted file mode 100644 index 991763bb7d..0000000000 --- a/docs/0.9.5/_modules/evennia/server/profiling/dummyrunner.html +++ /dev/null @@ -1,731 +0,0 @@ - - - - - - - - evennia.server.profiling.dummyrunner — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.profiling.dummyrunner

-"""
-Dummy client runner
-
-This module implements a stand-alone launcher for stress-testing
-an Evennia game. It will launch any number of fake clients. These
-clients will log into the server and start doing random operations.
-Customizing and weighing these operations differently depends on
-which type of game is tested. The module contains a testing module
-for plain Evennia.
-
-Please note that you shouldn't run this on a production server!
-Launch the program without any arguments or options to see a
-full step-by-step setup help.
-
-Basically (for testing default Evennia):
-
- - Use an empty/testing database.
- - set PERMISSION_ACCOUNT_DEFAULT = "Builder"
- - start server, eventually with profiling active
- - launch this client runner
-
-If you want to customize the runner's client actions
-(because you changed the cmdset or needs to better
-match your use cases or add more actions), you can
-change which actions by adding a path to
-
-   DUMMYRUNNER_ACTIONS_MODULE = <path.to.your.module>
-
-in your settings. See utils.dummyrunner_actions.py
-for instructions on how to define this module.
-
-"""
-
-
-import sys
-import time
-import random
-from argparse import ArgumentParser
-from twisted.conch import telnet
-from twisted.internet import reactor, protocol
-from twisted.internet.task import LoopingCall
-
-import django
-django.setup()
-import evennia  # noqa
-evennia._init()
-
-from django.conf import settings  # noqa
-from evennia.utils import mod_import, time_format  # noqa
-from evennia.commands.command import Command  # noqa
-from evennia.commands.cmdset import CmdSet  # noqa
-from evennia.utils.ansi import strip_ansi  # noqa
-
-# Load the dummyrunner settings module
-
-DUMMYRUNNER_SETTINGS = mod_import(settings.DUMMYRUNNER_SETTINGS_MODULE)
-if not DUMMYRUNNER_SETTINGS:
-    raise IOError(
-        "Error: Dummyrunner could not find settings file at %s"
-        % settings.DUMMYRUNNER_SETTINGS_MODULE
-    )
-IDMAPPER_CACHE_MAXSIZE = settings.IDMAPPER_CACHE_MAXSIZE
-
-DATESTRING = "%Y%m%d%H%M%S"
-CLIENTS = []
-
-# Settings
-
-# number of clients to launch if no input is given on command line
-NCLIENTS = 1
-# time between each 'tick', in seconds, if not set on command
-# line. All launched clients will be called upon to possibly do an
-# action with this frequency.
-TIMESTEP = DUMMYRUNNER_SETTINGS.TIMESTEP
-# chance of a client performing an action, per timestep. This helps to
-# spread out usage randomly, like it would be in reality.
-CHANCE_OF_ACTION = DUMMYRUNNER_SETTINGS.CHANCE_OF_ACTION
-# spread out the login action separately, having many accounts create accounts
-# and connect simultaneously is generally unlikely.
-CHANCE_OF_LOGIN = DUMMYRUNNER_SETTINGS.CHANCE_OF_LOGIN
-# Port to use, if not specified on command line
-TELNET_PORT = DUMMYRUNNER_SETTINGS.TELNET_PORT or settings.TELNET_PORTS[0]
-#
-NCONNECTED = 0  # client has received a connection
-NLOGIN_SCREEN = 0  # client has seen the login screen (server responded)
-NLOGGING_IN = 0  # client starting login procedure
-NLOGGED_IN = 0  # client has authenticated and logged in
-
-# time when all clients have logged_in
-TIME_ALL_LOGIN = 0
-# actions since all logged in
-TOTAL_ACTIONS = 0
-TOTAL_LAG_MEASURES = 0
-# lag per 30s for all logged in
-TOTAL_LAG = 0
-TOTAL_LAG_IN = 0
-TOTAL_LAG_OUT = 0
-
-
-INFO_STARTING = """
-    Dummyrunner starting using {nclients} dummy account(s). If you don't see
-    any connection messages, make sure that the Evennia server is
-    running.
-
-    TELNET_PORT = {port}
-    IDMAPPER_CACHE_MAXSIZE = {idmapper_cache_size} MB
-    TIMESTEP = {timestep} (rate {rate}/s)
-    CHANCE_OF_LOGIN = {chance_of_login}% per time step
-    CHANCE_OF_ACTION = {chance_of_action}% per time step
-    -> avg rate (per client, after login): {avg_rate} cmds/s
-    -> total avg rate (after login): {avg_rate_total} cmds/s
-
-    Use Ctrl-C (or Cmd-C) to stop/disconnect all clients.
-
-    """
-
-ERROR_NO_MIXIN = """
-    Error: Evennia is not set up for dummyrunner. Before starting the
-    server, make sure to include the following at *the end* of your
-    settings file (remove when not using dummyrunner!):
-
-        from evennia.server.profiling.settings_mixin import *
-
-    This will change the settings in the following way:
-        - change PERMISSION_ACCOUNT_DEFAULT to 'Developer' to allow clients
-          to test all commands
-        - change PASSWORD_HASHERS to use a faster (but less safe) algorithm
-          when creating large numbers of accounts at the same time
-        - set LOGIN_THROTTLE/CREATION_THROTTLE=None to disable it
-
-    If you don't want to use the custom settings of the mixin for some
-    reason, you can change their values manually after the import, or
-    add DUMMYRUNNER_MIXIN=True to your settings file to avoid this
-    error completely.
-
-    Warning: Don't run dummyrunner on a production database! It will
-    create a lot of spammy objects and accounts!
-    """
-
-
-ERROR_FEW_ACTIONS = """
-    Dummyrunner settings error: The ACTIONS tuple is too short: it must
-    contain at least login- and logout functions.
-    """
-
-
-HELPTEXT = """
-DO NOT RUN THIS ON A PRODUCTION SERVER! USE A CLEAN/TESTING DATABASE!
-
-This stand-alone program launches dummy telnet clients against a
-running Evennia server. The idea is to mimic real accounts logging in
-and repeatedly doing resource-heavy commands so as to stress test the
-game. It uses the default command set to log in and issue commands, so
-if that was customized, some of the functionality will not be tested
-(it will not fail, the commands will just not be recognized).  The
-running clients will create new objects and rooms all over the place
-as part of their running, so using a clean/testing database is
-strongly recommended.
-
-Setup:
-  1) setup a fresh/clean database (if using sqlite, just safe-copy
-     away your real evennia.db3 file and create a new one with
-     `evennia migrate`)
-  2) in server/conf/settings.py, add
-
-        PERMISSION_ACCOUNT_DEFAULT="Builder"
-
-     This is so that the dummy accounts can test building operations.
-     You can also customize the dummyrunner by modifying a setting
-     file specified by DUMMYRUNNER_SETTINGS_MODULE
-
-  3) Start Evennia like normal, optionally with profiling (--profile)
-  4) Run this dummy runner via the evennia launcher:
-
-        evennia --dummyrunner <nr_of_clients>
-
-  5) Log on and determine if game remains responsive despite the
-     heavier load. Note that if you activated profiling, there is a
-     considerate additional overhead from the profiler too so you
-     should usually not consider game responsivity when using the
-     profiler at the same time.
-  6) If you use profiling, let the game run long enough to gather
-     data, then stop the server cleanly using evennia stop or @shutdown.
-     @shutdown. The profile appears as
-     server/logs/server.prof/portal.prof (see Python's manual on
-     cProfiler).
-
-Notes:
-
-The dummyrunner tends to create a lot of accounts all at once, which is
-a very heavy operation. This is not a realistic use-case - what you want
-to test is performance during run. A large
-number of clients here may lock up the client until all have been
-created. It may be better to connect multiple dummyrunners instead of
-starting one single one with a lot of accounts. Exactly what this number
-is depends on your computer power. So start with 10-20 clients and increase
-until you see the initial login slows things too much.
-
-"""
-
-
-
[docs]class CmdDummyRunnerEchoResponse(Command): - """ - Dummyrunner command measuring the round-about response time - from sending to receiving a result. - - Usage: - dummyrunner_echo_response <timestamp> - - Responds with - dummyrunner_echo_response:<timestamp>,<current_time> - - The dummyrunner will send this and then compare the send time - with the receive time on both ends. - - """ - key = "dummyrunner_echo_response" - -
[docs] def func(self): - # returns (dummy_client_timestamp,current_time) - self.msg(f"dummyrunner_echo_response:{self.args},{time.time()}") - if self.caller.account.is_superuser: - print(f"cmddummyrunner lag in: {time.time() - float(self.args)}s")
- - -
[docs]class DummyRunnerCmdSet(CmdSet): - """ - Dummyrunner injected cmdset. - - """ -
[docs] def at_cmdset_creation(self): - self.add(CmdDummyRunnerEchoResponse())
- -# ------------------------------------------------------------ -# Helper functions -# ------------------------------------------------------------ - - -ICOUNT = 0 - - -
[docs]def idcounter(): - """ - Makes unique ids. - - Returns: - str: A globally unique id. - - """ - global ICOUNT - ICOUNT += 1 - return str("{:03d}".format(ICOUNT))
- - -GCOUNT = 0 - - -
[docs]def gidcounter(): - """ - Makes globally unique ids. - - Returns: - count (int); A globally unique counter. - - """ - global GCOUNT - GCOUNT += 1 - return "%s_%s" % (time.strftime(DATESTRING), GCOUNT)
- - -
[docs]def makeiter(obj): - """ - Makes everything iterable. - - Args: - obj (any): Object to turn iterable. - - Returns: - iterable (iterable): An iterable object. - """ - return obj if hasattr(obj, "__iter__") else [obj]
- - -# ------------------------------------------------------------ -# Client classes -# ------------------------------------------------------------ - -
[docs]class DummyClient(telnet.StatefulTelnetProtocol): - """ - Handles connection to a running Evennia server, - mimicking a real account by sending commands on - a timer. - - """ - -
[docs] def report(self, text, clientkey): - pad = " " * (25 - len(text)) - tim = round(time.time() - self.connection_timestamp) - print(f"{text} {clientkey}{pad}\t" - f"conn: {NCONNECTED} -> " - f"welcome screen: {NLOGIN_SCREEN} -> " - f"authing: {NLOGGING_IN} -> " - f"loggedin/tot: {NLOGGED_IN}/{NCLIENTS} (after {tim}s)")
- -
[docs] def connectionMade(self): - """ - Called when connection is first established. - - """ - global NCONNECTED - # public properties - self.cid = idcounter() - self.key = f"Dummy-{self.cid}" - self.gid = f"{time.strftime(DATESTRING)}_{self.cid}" - self.istep = 0 - self.exits = [] # exit names created - self.objs = [] # obj names created - self.connection_timestamp = time.time() - self.connection_attempt = 0 - self.action_started = 0 - - self._connected = False - self._loggedin = False - self._logging_out = False - self._ready = False - self._report = "" - self._cmdlist = [] # already stepping in a cmd definition - self._login = self.factory.actions[0] - self._logout = self.factory.actions[1] - self._actions = self.factory.actions[2:] - - reactor.addSystemEventTrigger("before", "shutdown", self.logout) - - NCONNECTED += 1 - self.report("-> connected", self.key) - - reactor.callLater(30, self._retry_welcome_screen)
- - def _retry_welcome_screen(self): - if not self._connected and not self._ready: - # we have connected but not received anything for 30s. - # (unclear why this would be - overload?) - # try sending a look to get something to start with - self.report("?? retrying welcome screen", self.key) - self.sendLine(bytes("look", 'utf-8')) - # make sure to check again later - reactor.callLater(30, self._retry_welcome_screen) - - def _print_statistics(self): - global TIME_ALL_LOGIN, TOTAL_ACTIONS - global TOTAL_LAG, TOTAL_LAG_MEASURES, TOTAL_LAG_IN, TOTAL_LAG_OUT - - tim = time.time() - TIME_ALL_LOGIN - avgrate = round(TOTAL_ACTIONS / tim) - lag = TOTAL_LAG / (TOTAL_LAG_MEASURES or 1) - lag_in = TOTAL_LAG_IN / (TOTAL_LAG_MEASURES or 1) - lag_out = TOTAL_LAG_OUT / (TOTAL_LAG_MEASURES or 1) - - TOTAL_ACTIONS = 0 - TOTAL_LAG = 0 - TOTAL_LAG_IN = 0 - TOTAL_LAG_OUT = 0 - TOTAL_LAG_MEASURES = 0 - TIME_ALL_LOGIN = time.time() - - print(f".. running 30s average: ~{avgrate} actions/s " - f"lag: {lag:.2}s (in: {lag_in:.2}s, out: {lag_out:.2}s)") - - reactor.callLater(30, self._print_statistics) - -
[docs] def dataReceived(self, data): - """ - Called when data comes in over the protocol. We wait to start - stepping until the server actually responds - - Args: - data (str): Incoming data. - - """ - global NLOGIN_SCREEN, NLOGGED_IN, NLOGGING_IN, NCONNECTED - global TOTAL_ACTIONS, TIME_ALL_LOGIN - global TOTAL_LAG, TOTAL_LAG_MEASURES, TOTAL_LAG_IN, TOTAL_LAG_OUT - - if not data.startswith(b"\xff"): - # regular text, not a telnet command - - if NCLIENTS == 1: - print("dummy-client sees:", str(data, "utf-8")) - - if not self._connected: - # waiting for connection - # wait until we actually get text back (not just telnet - # negotiation) - # start client tick - d = LoopingCall(self.step) - df = max(abs(TIMESTEP * 0.001), min(TIMESTEP/10, 0.5)) - # dither next attempt with random time - timestep = TIMESTEP + (-df + (random.random() * df)) - d.start(timestep, now=True).addErrback(self.error) - self.connection_attempt += 1 - - self._connected = True - NLOGIN_SCREEN += 1 - NCONNECTED -= 1 - self.report("<- server sent login screen", self.key) - - elif self._loggedin: - if not self._ready: - # logged in, ready to run - NLOGGED_IN += 1 - NLOGGING_IN -= 1 - self._ready = True - self.report("== logged in", self.key) - if NLOGGED_IN == NCLIENTS and not TIME_ALL_LOGIN: - # all are logged in! We can start collecting statistics - print(".. All clients connected and logged in!") - TIME_ALL_LOGIN = time.time() - reactor.callLater(30, self._print_statistics) - - elif TIME_ALL_LOGIN: - TOTAL_ACTIONS += 1 - - try: - data = strip_ansi(str(data, "utf-8").strip()) - if data.startswith("dummyrunner_echo_response:"): - # handle special lag-measuring command. This returns - # dummyrunner_echo_response:<starttime>,<midpointtime> - now = time.time() - _, data = data.split(":", 1) - start_time, mid_time = (float(part) for part in data.split(",", 1)) - lag_in = mid_time - start_time - lag_out = now - mid_time - total_lag = now - start_time # full round-about time - - TOTAL_LAG += total_lag - TOTAL_LAG_IN += lag_in - TOTAL_LAG_OUT += lag_out - TOTAL_LAG_MEASURES += 1 - except Exception: - pass
- -
[docs] def connectionLost(self, reason): - """ - Called when loosing the connection. - - Args: - reason (str): Reason for loosing connection. - - """ - if not self._logging_out: - self.report("XX lost connection", self.key)
- -
[docs] def error(self, err): - """ - Error callback. - - Args: - err (Failure): Error instance. - """ - print(err)
- -
[docs] def counter(self): - """ - Produces a unique id, also between clients. - - Returns: - counter (int): A unique counter. - - """ - return gidcounter()
- -
[docs] def logout(self): - """ - Causes the client to log out of the server. Triggered by ctrl-c signal. - - """ - self._logging_out = True - cmd = self._logout(self)[0] - self.report(f"-> logout/disconnect ({self.istep} actions)", self.key) - self.sendLine(bytes(cmd, 'utf-8'))
- -
[docs] def step(self): - """ - Perform a step. This is called repeatedly by the runner and - causes the client to issue commands to the server. This holds - all "intelligence" of the dummy client. - - """ - global NLOGGING_IN, NLOGIN_SCREEN - - rand = random.random() - - if not self._cmdlist: - # no commands ready. Load some. - - if not self._loggedin: - if rand < CHANCE_OF_LOGIN or NLOGGING_IN < 10: - # lower rate of logins, but not below 1 / s - # get the login commands - self._cmdlist = list(makeiter(self._login(self))) - NLOGGING_IN += 1 # this is for book-keeping - NLOGIN_SCREEN -= 1 - self.report("-> create/login", self.key) - self._loggedin = True - else: - # no login yet, so cmdlist not yet set - return - else: - # we always pick a cumulatively random function - crand = random.random() - cfunc = [func for (cprob, func) in self._actions if cprob >= crand][0] - self._cmdlist = list(makeiter(cfunc(self))) - - # at this point we always have a list of commands - if rand < CHANCE_OF_ACTION: - # send to the game - cmd = str(self._cmdlist.pop(0)) - - if cmd.startswith("dummyrunner_echo_response"): - # we need to set the timer element as close to - # the send as possible - cmd = cmd.format(timestamp=time.time()) - - self.sendLine(bytes(cmd, 'utf-8')) - self.action_started = time.time() - self.istep += 1 - - if NCLIENTS == 1: - print(f"dummy-client sent: {cmd}")
- - -
[docs]class DummyFactory(protocol.ReconnectingClientFactory): - protocol = DummyClient - initialDelay = 1 - maxDelay = 1 - noisy = False - -
[docs] def __init__(self, actions): - "Setup the factory base (shared by all clients)" - self.actions = actions
- - -# ------------------------------------------------------------ -# Access method: -# Starts clients and connects them to a running server. -# ------------------------------------------------------------ - - -
[docs]def start_all_dummy_clients(nclients): - """ - Initialize all clients, connect them and start to step them - - Args: - nclients (int): Number of dummy clients to connect. - - """ - global NCLIENTS - NCLIENTS = int(nclients) - actions = DUMMYRUNNER_SETTINGS.ACTIONS - - if len(actions) < 2: - print(ERROR_FEW_ACTIONS) - return - - # make sure the probabilities add up to 1 - pratio = 1.0 / sum(tup[0] for tup in actions[2:]) - flogin, flogout, probs, cfuncs = ( - actions[0], - actions[1], - [tup[0] * pratio for tup in actions[2:]], - [tup[1] for tup in actions[2:]], - ) - # create cumulative probabilies for the random actions - cprobs = [sum(v for i, v in enumerate(probs) if i <= k) for k in range(len(probs))] - # rebuild a new, optimized action structure - actions = (flogin, flogout) + tuple(zip(cprobs, cfuncs)) - - # setting up all clients (they are automatically started) - factory = DummyFactory(actions) - for i in range(NCLIENTS): - reactor.connectTCP("127.0.0.1", TELNET_PORT, factory) - # start reactor - reactor.run()
- - -# ------------------------------------------------------------ -# Command line interface -# ------------------------------------------------------------ - - -if __name__ == "__main__": - - try: - settings.DUMMYRUNNER_MIXIN - except AttributeError: - print(ERROR_NO_MIXIN) - sys.exit() - - # parsing command line with default vals - parser = ArgumentParser(description=HELPTEXT) - parser.add_argument( - "-N", nargs=1, default=1, dest="nclients", help="Number of clients to start" - ) - - args = parser.parse_args() - nclients = int(args.nclients[0]) - - print(INFO_STARTING.format( - nclients=nclients, - port=TELNET_PORT, - idmapper_cache_size=IDMAPPER_CACHE_MAXSIZE, - timestep=TIMESTEP, - rate=1/TIMESTEP, - chance_of_login=CHANCE_OF_LOGIN * 100, - chance_of_action=CHANCE_OF_ACTION * 100, - avg_rate=(1 / TIMESTEP) * CHANCE_OF_ACTION, - avg_rate_total=(1 / TIMESTEP) * CHANCE_OF_ACTION * nclients - )) - - # run the dummyrunner - TIME_START = t0 = time.time() - start_all_dummy_clients(nclients=nclients) - ttot = time.time() - t0 - - # output runtime - print("... dummy client runner stopped after %s." % time_format(ttot, style=3)) -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/profiling/dummyrunner_settings.html b/docs/0.9.5/_modules/evennia/server/profiling/dummyrunner_settings.html deleted file mode 100644 index 38e9ca48c0..0000000000 --- a/docs/0.9.5/_modules/evennia/server/profiling/dummyrunner_settings.html +++ /dev/null @@ -1,442 +0,0 @@ - - - - - - - - evennia.server.profiling.dummyrunner_settings — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.profiling.dummyrunner_settings

-"""
-Settings and actions for the dummyrunner
-
-This module defines dummyrunner settings and sets up
-the actions available to dummy accounts.
-
-The settings are global variables:
-
-- TIMESTEP - time in seconds between each 'tick'. 1 is a good start.
-- CHANCE_OF_ACTION - chance 0-1 of action happening. Default is 0.5.
-- CHANCE_OF_LOGIN - chance 0-1 of login happening. 0.01 is a good number.
-- TELNET_PORT - port to use, defaults to settings.TELNET_PORT
-- ACTIONS - see below
-
-ACTIONS is a tuple
-
-```python
-(login_func, logout_func, (0.3, func1), (0.1, func2) ... )
-
-```
-
-where the first entry is the function to call on first connect, with a
-chance of occurring given by CHANCE_OF_LOGIN. This function is usually
-responsible for logging in the account. The second entry is always
-called when the dummyrunner disconnects from the server and should
-thus issue a logout command. The other entries are tuples (chance,
-func). They are picked randomly, their commonality based on the
-cumulative chance given (the chance is normalized between all options
-so if will still work also if the given chances don't add up to 1).
-
-The PROFILE variable define pre-made ACTION tuples for convenience.
-
-Each function should return an iterable of one or more command-call
-strings (like "look here"), so each can group multiple command operations.
-
-An action-function is called with a "client" argument which is a
-reference to the dummy client currently performing the action.
-
-The client object has the following relevant properties and methods:
-
-- key - an optional client key. This is only used for dummyrunner output.
-  Default is "Dummy-<cid>"
-- cid - client id
-- gid - globally unique id, hashed with time stamp
-- istep - the current step
-- exits - an empty list. Can be used to store exit names
-- objs - an empty list. Can be used to store object names
-- counter() - returns a unique increasing id, hashed with time stamp
-  to make it unique also between dummyrunner instances.
-
-The return should either be a single command string or a tuple of
-command strings. This list of commands will always be executed every
-TIMESTEP with a chance given by CHANCE_OF_ACTION by in the order given
-(no randomness) and allows for setting up a more complex chain of
-commands (such as creating an account and logging in).
-
-----
-
-"""
-import random
-import string
-
-# Dummy runner settings
-
-# Time between each dummyrunner "tick", in seconds. Each dummy
-# will be called with this frequency.
-TIMESTEP = 1
-# TIMESTEP = 0.025  # 40/s
-
-# Chance of a dummy actually performing an action on a given tick.
-# This spreads out usage randomly, like it would be in reality.
-CHANCE_OF_ACTION = 0.5
-
-# Chance of a currently unlogged-in dummy performing its login
-# action every tick. This emulates not all accounts logging in
-# at exactly the same time.
-CHANCE_OF_LOGIN = 0.01
-
-# Which telnet port to connect to. If set to None, uses the first
-# default telnet port of the running server.
-TELNET_PORT = None
-
-
-# Setup actions tuple
-
-# some convenient templates
-
-DUMMY_NAME = "Dummy_{gid}"
-DUMMY_PWD = (''.join(random.choice(string.ascii_letters + string.digits)
-                     for _ in range(20)) + "-{gid}")
-START_ROOM = "testing_room_start_{gid}"
-ROOM_TEMPLATE = "testing_room_%s"
-EXIT_TEMPLATE = "exit_%s"
-OBJ_TEMPLATE = "testing_obj_%s"
-TOBJ_TEMPLATE = "testing_button_%s"
-TOBJ_TYPECLASS = "contrib.tutorial_examples.red_button.RedButton"
-
-
-# action function definitions (pick and choose from
-# these to build a client "usage profile"
-
-# login/logout
-
-
[docs]def c_login(client): - "logins to the game" - # we always use a new client name - cname = DUMMY_NAME.format(gid=client.gid) - cpwd = DUMMY_PWD.format(gid=client.gid) - room_name = START_ROOM.format(gid=client.gid) - - # we assign the dummyrunner cmdsert to ourselves so # we can use special commands - add_cmdset = ( - "py from evennia.server.profiling.dummyrunner import DummyRunnerCmdSet;" - "self.cmdset.add(DummyRunnerCmdSet, persistent=False)" - ) - - # create character, log in, then immediately dig a new location and - # teleport it (to keep the login room clean) - cmds = ( - f"create {cname} {cpwd}", - f"yes", # to confirm creation - f"connect {cname} {cpwd}", - f"dig {room_name}", - f"teleport {room_name}", - add_cmdset, - ) - return cmds
- - -
[docs]def c_login_nodig(client): - "logins, don't dig its own room" - cname = DUMMY_NAME.format(gid=client.gid) - cpwd = DUMMY_PWD.format(gid=client.gid) - cmds = ( - f"create {cname} {cpwd}", - f"connect {cname} {cpwd}" - ) - return cmds
- - -
[docs]def c_logout(client): - "logouts of the game" - return ("quit",)
- - -# random commands - - -
[docs]def c_looks(client): - "looks at various objects" - cmds = ["look %s" % obj for obj in client.objs] - if not cmds: - cmds = ["look %s" % exi for exi in client.exits] - if not cmds: - cmds = ("look",) - return cmds
- - -
[docs]def c_examines(client): - "examines various objects" - cmds = ["examine %s" % obj for obj in client.objs] - if not cmds: - cmds = ["examine %s" % exi for exi in client.exits] - if not cmds: - cmds = ("examine me",) - return cmds
- - -
[docs]def c_idles(client): - "idles" - cmds = ("idle", "idle") - return cmds
- - -
[docs]def c_help(client): - "reads help files" - cmds = ("help", "dummyrunner_echo_response",) - return cmds
- - -
[docs]def c_digs(client): - "digs a new room, storing exit names on client" - roomname = ROOM_TEMPLATE % client.counter() - exitname1 = EXIT_TEMPLATE % client.counter() - exitname2 = EXIT_TEMPLATE % client.counter() - client.exits.extend([exitname1, exitname2]) - return ("dig/tel %s = %s, %s" % (roomname, exitname1, exitname2),)
- - -
[docs]def c_creates_obj(client): - "creates normal objects, storing their name on client" - objname = OBJ_TEMPLATE % client.counter() - client.objs.append(objname) - cmds = ( - "create %s" % objname, - 'desc %s = "this is a test object' % objname, - "set %s/testattr = this is a test attribute value." % objname, - "set %s/testattr2 = this is a second test attribute." % objname, - ) - return cmds
- - -
[docs]def c_creates_button(client): - "creates example button, storing name on client" - objname = TOBJ_TEMPLATE % client.counter() - client.objs.append(objname) - cmds = ("create %s:%s" % (objname, TOBJ_TYPECLASS), "desc %s = test red button!" % objname) - return cmds
- - -
[docs]def c_socialize(client): - "socializechats on channel" - cmds = ( - "pub Hello!", - "say Yo!", - "emote stands looking around.", - ) - return cmds
- - -
[docs]def c_moves(client): - "moves to a previously created room, using the stored exits" - cmds = client.exits # try all exits - finally one will work - return ("look",) if not cmds else cmds
- - -
[docs]def c_moves_n(client): - "move through north exit if available" - return ("north",)
- - -
[docs]def c_moves_s(client): - "move through south exit if available" - return ("south",)
- - -
[docs]def c_measure_lag(client): - """ - Special dummyrunner command, injected in c_login. It measures - response time. Including this in the ACTION tuple will give more - dummyrunner output about just how fast commands are being processed. - - The dummyrunner will treat this special and inject the - {timestamp} just before sending. - - """ - return ("dummyrunner_echo_response {timestamp}",)
- - -# Action profile (required) - -# Some pre-made profiles to test. To make your own, just assign a tuple to ACTIONS. -# -# idler - does nothing after logging in -# looker - just looks around -# normal_player - moves around, reads help, looks around (digs rarely) (spammy) -# normal_builder - digs now and then, examines, creates objects, moves -# heavy_builder - digs and creates a lot, moves and examines -# socializing_builder - builds a lot, creates help entries, moves, chat (spammy) -# only_digger - extreme builder that only digs room after room - -PROFILE = "looker" - - -if PROFILE == 'idler': - ACTIONS = ( - c_login, - c_logout, - (0.9, c_idles), - (0.1, c_measure_lag), - ) -elif PROFILE == 'looker': - ACTIONS = ( - c_login, - c_logout, - (0.8, c_looks), - (0.2, c_measure_lag) - ) -elif PROFILE == 'normal_player': - ACTIONS = ( - c_login, - c_logout, - (0.01, c_digs), - (0.29, c_looks), - (0.2, c_help), - (0.3, c_moves), - (0.05, c_socialize), - (0.1, c_measure_lag) - ) -elif PROFILE == 'normal_builder': - ACTIONS = ( - c_login, - c_logout, - (0.5, c_looks), - (0.08, c_examines), - (0.1, c_help), - (0.01, c_digs), - (0.01, c_creates_obj), - (0.2, c_moves), - (0.1, c_measure_lag) - ) -elif PROFILE == 'heavy_builder': - ACTIONS = ( - c_login, - c_logout, - (0.1, c_looks), - (0.1, c_examines), - (0.2, c_help), - (0.1, c_digs), - (0.1, c_creates_obj), - (0.2, c_moves), - (0.1, c_measure_lag) - ) -elif PROFILE == 'socializing_builder': - ACTIONS = ( - c_login, - c_logout, - (0.1, c_socialize), - (0.1, c_looks), - (0.1, c_help), - (0.1, c_creates_obj), - (0.2, c_digs), - (0.3, c_moves), - (0.1, c_measure_lag) - ) -elif PROFILE == 'only_digger': - ACTIONS = ( - c_login, - c_logout, - (0.9, c_digs), - (0.1, c_measure_lag) - ) - -else: - print("No dummyrunner ACTION profile defined.") - import sys - sys.exit() -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/profiling/memplot.html b/docs/0.9.5/_modules/evennia/server/profiling/memplot.html deleted file mode 100644 index 6237e38126..0000000000 --- a/docs/0.9.5/_modules/evennia/server/profiling/memplot.html +++ /dev/null @@ -1,221 +0,0 @@ - - - - - - - - evennia.server.profiling.memplot — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.profiling.memplot

-"""
-Script that saves memory and idmapper data over time.
-
-Data will be saved to game/logs/memoryusage.log. Note that
-the script will append to this file if it already exists.
-
-Call this module directly to plot the log (requires matplotlib and numpy).
-"""
-
-import os
-import sys
-import time
-
-# TODO!
-# sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
-# os.environ['DJANGO_SETTINGS_MODULE'] = 'game.settings'
-import evennia
-from evennia.utils.idmapper import models as _idmapper
-
-LOGFILE = "logs/memoryusage.log"
-INTERVAL = 30  # log every 30 seconds
-
-
-
[docs]class Memplot(evennia.DefaultScript): - """ - Describes a memory plotting action. - - """ - -
[docs] def at_script_creation(self): - "Called at script creation" - self.key = "memplot" - self.desc = "Save server memory stats to file" - self.start_delay = False - self.persistent = True - self.interval = INTERVAL - self.db.starttime = time.time()
- -
[docs] def at_repeat(self): - "Regularly save memory statistics." - pid = os.getpid() - rmem = ( - float(os.popen("ps -p %d -o %s | tail -1" % (pid, "rss")).read()) / 1000.0 - ) # resident memory - vmem = ( - float(os.popen("ps -p %d -o %s | tail -1" % (pid, "vsz")).read()) / 1000.0 - ) # virtual memory - total_num, cachedict = _idmapper.cache_size() - t0 = (time.time() - self.db.starttime) / 60.0 # save in minutes - - with open(LOGFILE, "a") as f: - f.write("%s, %s, %s, %s\n" % (t0, rmem, vmem, int(total_num)))
- - -if __name__ == "__main__": - - # plot output from the file - - from matplotlib import pyplot as pp - import numpy - - data = numpy.genfromtxt("../../../game/" + LOGFILE, delimiter=",") - secs = data[:, 0] - rmem = data[:, 1] - vmem = data[:, 2] - nobj = data[:, 3] - - # calculate derivative of obj creation - # oderiv = (0.5*(nobj[2:] - nobj[:-2]) / (secs[2:] - secs[:-2])).copy() - # oderiv = (0.5*(rmem[2:] - rmem[:-2]) / (secs[2:] - secs[:-2])).copy() - - fig = pp.figure() - ax1 = fig.add_subplot(111) - ax1.set_title("1000 bots (normal accounts with light building)") - ax1.set_xlabel("Time (mins)") - ax1.set_ylabel("Memory usage (MB)") - ax1.plot(secs, rmem, "r", label="RMEM", lw=2) - ax1.plot(secs, vmem, "b", label="VMEM", lw=2) - ax1.legend(loc="upper left") - - ax2 = ax1.twinx() - ax2.plot(secs, nobj, "g--", label="objs in cache", lw=2) - # ax2.plot(secs[:-2], oderiv/60.0, "g--", label="Objs/second", lw=2) - # ax2.plot(secs[:-2], oderiv, "g--", label="Objs/second", lw=2) - ax2.set_ylabel("Number of objects") - ax2.legend(loc="lower right") - ax2.annotate("First 500 bots\nconnecting", xy=(10, 4000)) - ax2.annotate("Next 500 bots\nconnecting", xy=(350, 10000)) - # ax2.annotate("@reload", xy=(185,600)) - - # # plot mem vs cachesize - # nobj, rmem, vmem = nobj[:262].copy(), rmem[:262].copy(), vmem[:262].copy() - # - # fig = pp.figure() - # ax1 = fig.add_subplot(111) - # ax1.set_title("Memory usage per cache size") - # ax1.set_xlabel("Cache size (number of objects)") - # ax1.set_ylabel("Memory usage (MB)") - # ax1.plot(nobj, rmem, "r", label="RMEM", lw=2) - # ax1.plot(nobj, vmem, "b", label="VMEM", lw=2) - # - - # empirical estimate of memory usage: rmem = 35.0 + 0.0157 * Ncache - # Ncache = int((rmem - 35.0) / 0.0157) (rmem in MB) - # - # rderiv_aver = 0.0157 - # fig = pp.figure() - # ax1 = fig.add_subplot(111) - # ax1.set_title("Relation between memory and cache size") - # ax1.set_xlabel("Memory usage (MB)") - # ax1.set_ylabel("Idmapper Cache Size (number of objects)") - # rmem = numpy.linspace(35, 2000, 2000) - # nobjs = numpy.array([int((mem - 35.0) / 0.0157) for mem in rmem]) - # ax1.plot(rmem, nobjs, "r", lw=2) - - pp.show() -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/profiling/test_queries.html b/docs/0.9.5/_modules/evennia/server/profiling/test_queries.html deleted file mode 100644 index 33ab31f3a0..0000000000 --- a/docs/0.9.5/_modules/evennia/server/profiling/test_queries.html +++ /dev/null @@ -1,148 +0,0 @@ - - - - - - - - evennia.server.profiling.test_queries — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.profiling.test_queries

-"""
-This is a little routine for viewing the sql queries that are executed by a given
-query as well as count them for optimization testing.
-
-"""
-
-import sys
-import os
-
-# sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
-# os.environ["DJANGO_SETTINGS_MODULE"] = "game.settings"
-from django.db import connection
-
-
-
[docs]def count_queries(exec_string, setup_string): - """ - Display queries done by exec_string. Use setup_string - to setup the environment to test. - """ - - exec(setup_string) - - num_queries_old = len(connection.queries) - exec(exec_string) - nqueries = len(connection.queries) - num_queries_old - - for query in connection.queries[-nqueries if nqueries else 1 :]: - print(query["time"], query["sql"]) - print("Number of queries: %s" % nqueries)
- - -if __name__ == "__main__": - - # setup tests here - - setup_string = """ -from evennia.objects.models import ObjectDB -g = ObjectDB.objects.get(db_key="Griatch") -""" - exec_string = """ -g.tags.all() -""" - count_queries(exec_string, setup_string) -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/profiling/tests.html b/docs/0.9.5/_modules/evennia/server/profiling/tests.html deleted file mode 100644 index ec4b8c18fb..0000000000 --- a/docs/0.9.5/_modules/evennia/server/profiling/tests.html +++ /dev/null @@ -1,264 +0,0 @@ - - - - - - - - evennia.server.profiling.tests — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.profiling.tests

-from django.test import TestCase
-from mock import Mock, patch, mock_open
-from anything import Something
-from .dummyrunner_settings import (
-    c_creates_button,
-    c_creates_obj,
-    c_digs,
-    c_examines,
-    c_help,
-    c_idles,
-    c_login,
-    c_login_nodig,
-    c_logout,
-    c_looks,
-    c_moves,
-    c_moves_n,
-    c_moves_s,
-    c_socialize,
-)
-
-try:
-    import memplot
-except ImportError:
-    memplot = Mock()
-
-
-
[docs]class TestDummyrunnerSettings(TestCase): -
[docs] def setUp(self): - self.client = Mock() - self.client.cid = 1 - self.client.counter = Mock(return_value=1) - self.client.gid = "20171025161153-1" - self.client.name = "Dummy_%s" % self.client.gid - self.client.password = Something, - self.client.start_room = "testing_room_start_%s" % self.client.gid - self.client.objs = [] - self.client.exits = []
- -
[docs] def clear_client_lists(self): - self.client.objs = [] - self.client.exits = []
- -
[docs] def test_c_login(self): - self.assertEqual( - c_login(self.client), - ( - Something, # create - 'yes', # confirm creation - Something, # connect - "dig %s" % self.client.start_room, - "teleport %s" % self.client.start_room, - "py from evennia.server.profiling.dummyrunner import DummyRunnerCmdSet;" - "self.cmdset.add(DummyRunnerCmdSet, persistent=False)" - ), - )
- -
[docs] def test_c_login_no_dig(self): - cmd1, cmd2 = c_login_nodig(self.client) - self.assertTrue(cmd1.startswith("create " + self.client.name + " ")) - self.assertTrue(cmd2.startswith("connect " + self.client.name + " "))
- -
[docs] def test_c_logout(self): - self.assertEqual(c_logout(self.client), ("quit",))
- -
[docs] def perception_method_tests(self, func, verb, alone_suffix=""): - self.assertEqual(func(self.client), ("%s%s" % (verb, alone_suffix),)) - self.client.exits = ["exit1", "exit2"] - self.assertEqual(func(self.client), ["%s exit1" % verb, "%s exit2" % verb]) - self.client.objs = ["foo", "bar"] - self.assertEqual(func(self.client), ["%s foo" % verb, "%s bar" % verb]) - self.clear_client_lists()
- -
[docs] def test_c_looks(self): - self.perception_method_tests(c_looks, "look")
- -
[docs] def test_c_examines(self): - self.perception_method_tests(c_examines, "examine", " me")
- -
[docs] def test_idles(self): - self.assertEqual(c_idles(self.client), ("idle", "idle"))
- -
[docs] def test_c_help(self): - self.assertEqual( - c_help(self.client), - ("help", "dummyrunner_echo_response"), - )
- -
[docs] def test_c_digs(self): - self.assertEqual(c_digs(self.client), ("dig/tel testing_room_1 = exit_1, exit_1", )) - self.assertEqual(self.client.exits, ["exit_1", "exit_1"]) - self.clear_client_lists()
- -
[docs] def test_c_creates_obj(self): - objname = "testing_obj_1" - self.assertEqual( - c_creates_obj(self.client), - ( - "create %s" % objname, - 'desc %s = "this is a test object' % objname, - "set %s/testattr = this is a test attribute value." % objname, - "set %s/testattr2 = this is a second test attribute." % objname, - ), - ) - self.assertEqual(self.client.objs, [objname]) - self.clear_client_lists()
- -
[docs] def test_c_creates_button(self): - objname = "testing_button_1" - typeclass_name = "contrib.tutorial_examples.red_button.RedButton" - self.assertEqual( - c_creates_button(self.client), - ("create %s:%s" % (objname, typeclass_name), "desc %s = test red button!" % objname), - ) - self.assertEqual(self.client.objs, [objname]) - self.clear_client_lists()
- -
[docs] def test_c_socialize(self): - self.assertEqual( - c_socialize(self.client), - ( - "pub Hello!", - "say Yo!", - "emote stands looking around.", - ), - )
- -
[docs] def test_c_moves(self): - self.assertEqual(c_moves(self.client), ("look",)) - self.client.exits = ["south", "north"] - self.assertEqual(c_moves(self.client), ["south", "north"]) - self.clear_client_lists()
- -
[docs] def test_c_move_n(self): - self.assertEqual(c_moves_n(self.client), ("north",))
- -
[docs] def test_c_move_s(self): - self.assertEqual(c_moves_s(self.client), ("south",))
- - -
[docs]class TestMemPlot(TestCase): -
[docs] @patch.object(memplot, "_idmapper") - @patch.object(memplot, "os") - @patch.object(memplot, "open", new_callable=mock_open, create=True) - @patch.object(memplot, "time") - @patch("evennia.utils.idmapper.models.SharedMemoryModel.flush_from_cache", new=Mock()) - def test_memplot(self, mock_time, mocked_open, mocked_os, mocked_idmapper): - if isinstance(memplot, Mock): - return - from evennia.utils.create import create_script - - mocked_idmapper.cache_size.return_value = (9, 5000) - mock_time.time = Mock(return_value=6000.0) - script = create_script(memplot.Memplot) - script.db.starttime = 0.0 - mocked_os.popen.read.return_value = 5000.0 - script.at_repeat() - handle = mocked_open() - handle.write.assert_called_with("100.0, 0.001, 0.001, 9\n") - script.stop()
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/profiling/timetrace.html b/docs/0.9.5/_modules/evennia/server/profiling/timetrace.html deleted file mode 100644 index b97cfff46f..0000000000 --- a/docs/0.9.5/_modules/evennia/server/profiling/timetrace.html +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - - - evennia.server.profiling.timetrace — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.profiling.timetrace

-"""
-Trace a message through the messaging system
-"""
-
-import time
-
-
-
[docs]def timetrace(message, idstring, tracemessage="TEST_MESSAGE", final=False): - """ - Trace a message with time stamps. - - Args: - message (str): The actual message coming through - idstring (str): An identifier string specifying where this trace is happening. - tracemessage (str): The start of the message to tag. - This message will get attached time stamp. - final (bool): This is the final leg in the path - include total time in message - - """ - if message.startswith(tracemessage): - # the message is on the form TEST_MESSAGE tlast t0 - # where t0 is the initial starting time and last is the time - # saved at the last stop. - try: - prefix, tlast, t0 = message.split(None, 2) - tlast, t0 = float(tlast), float(t0) - except (IndexError, ValueError): - t0 = time.time() - tlast = t0 - t1 = t0 - else: - t1 = time.time() - # print to log (important!) - print("** timetrace (%s): dT=%fs, total=%fs." % (idstring, t1 - tlast, t1 - t0)) - - if final: - message = " **** %s (total %f) **** " % (tracemessage, t1 - t0) - else: - message = "%s %f %f" % (tracemessage, t1, t0) - return message
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/server.html b/docs/0.9.5/_modules/evennia/server/server.html deleted file mode 100644 index d0b14e5b80..0000000000 --- a/docs/0.9.5/_modules/evennia/server/server.html +++ /dev/null @@ -1,857 +0,0 @@ - - - - - - - - evennia.server.server — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.server

-"""
-This module implements the main Evennia server process, the core of the game
-engine.
-
-This module should be started with the 'twistd' executable since it sets up all
-the networking features.  (this is done automatically by
-evennia/server/server_runner.py).
-
-"""
-import time
-import sys
-import os
-import traceback
-
-from twisted.web import static
-from twisted.application import internet, service
-from twisted.internet import reactor, defer
-from twisted.internet.task import LoopingCall
-from twisted.python.log import ILogObserver
-
-import django
-
-django.setup()
-
-import evennia
-import importlib
-
-evennia._init()
-
-from django.db import connection
-from django.db.utils import OperationalError
-from django.conf import settings
-
-from evennia.accounts.models import AccountDB
-from evennia.scripts.models import ScriptDB
-from evennia.server.models import ServerConfig
-
-from evennia.utils.utils import get_evennia_version, mod_import, make_iter
-from evennia.utils import logger
-from evennia.server.sessionhandler import SESSIONS
-
-from django.utils.translation import gettext as _
-
-_SA = object.__setattr__
-
-# a file with a flag telling the server to restart after shutdown or not.
-SERVER_RESTART = os.path.join(settings.GAME_DIR, "server", "server.restart")
-
-# module containing hook methods called during start_stop
-SERVER_STARTSTOP_MODULE = mod_import(settings.AT_SERVER_STARTSTOP_MODULE)
-
-# modules containing plugin services
-SERVER_SERVICES_PLUGIN_MODULES = make_iter(settings.SERVER_SERVICES_PLUGIN_MODULES)
-
-
-# ------------------------------------------------------------
-# Evennia Server settings
-# ------------------------------------------------------------
-
-SERVERNAME = settings.SERVERNAME
-VERSION = get_evennia_version()
-
-AMP_ENABLED = True
-AMP_HOST = settings.AMP_HOST
-AMP_PORT = settings.AMP_PORT
-AMP_INTERFACE = settings.AMP_INTERFACE
-
-WEBSERVER_PORTS = settings.WEBSERVER_PORTS
-WEBSERVER_INTERFACES = settings.WEBSERVER_INTERFACES
-
-GUEST_ENABLED = settings.GUEST_ENABLED
-
-# server-channel mappings
-WEBSERVER_ENABLED = settings.WEBSERVER_ENABLED and WEBSERVER_PORTS and WEBSERVER_INTERFACES
-IRC_ENABLED = settings.IRC_ENABLED
-RSS_ENABLED = settings.RSS_ENABLED
-GRAPEVINE_ENABLED = settings.GRAPEVINE_ENABLED
-WEBCLIENT_ENABLED = settings.WEBCLIENT_ENABLED
-GAME_INDEX_ENABLED = settings.GAME_INDEX_ENABLED
-
-INFO_DICT = {
-    "servername": SERVERNAME,
-    "version": VERSION,
-    "amp": "",
-    "errors": "",
-    "info": "",
-    "webserver": "",
-    "irc_rss": "",
-}
-
-try:
-    WEB_PLUGINS_MODULE = mod_import(settings.WEB_PLUGINS_MODULE)
-except ImportError:
-    WEB_PLUGINS_MODULE = None
-    INFO_DICT["errors"] = (
-        "WARNING: settings.WEB_PLUGINS_MODULE not found - "
-        "copy 'evennia/game_template/server/conf/web_plugins.py to mygame/server/conf."
-    )
-
-
-# Maintenance function - this is called repeatedly by the server
-
-_MAINTENANCE_COUNT = 0
-_FLUSH_CACHE = None
-_IDMAPPER_CACHE_MAXSIZE = settings.IDMAPPER_CACHE_MAXSIZE
-_GAMETIME_MODULE = None
-
-_IDLE_TIMEOUT = settings.IDLE_TIMEOUT
-_LAST_SERVER_TIME_SNAPSHOT = 0
-
-
-def _server_maintenance():
-    """
-    This maintenance function handles repeated checks and updates that
-    the server needs to do. It is called every minute.
-    """
-    global EVENNIA, _MAINTENANCE_COUNT, _FLUSH_CACHE, _GAMETIME_MODULE
-    global _LAST_SERVER_TIME_SNAPSHOT
-
-    if not _FLUSH_CACHE:
-        from evennia.utils.idmapper.models import conditional_flush as _FLUSH_CACHE
-    if not _GAMETIME_MODULE:
-        from evennia.utils import gametime as _GAMETIME_MODULE
-
-    _MAINTENANCE_COUNT += 1
-
-    now = time.time()
-    if _MAINTENANCE_COUNT == 1:
-        # first call after a reload
-        _GAMETIME_MODULE.SERVER_START_TIME = now
-        _GAMETIME_MODULE.SERVER_RUNTIME = ServerConfig.objects.conf("runtime", default=0.0)
-        _LAST_SERVER_TIME_SNAPSHOT = now
-    else:
-        # adjust the runtime not with 60s but with the actual elapsed time
-        # in case this may varies slightly from 60s.
-        _GAMETIME_MODULE.SERVER_RUNTIME += now - _LAST_SERVER_TIME_SNAPSHOT
-    _LAST_SERVER_TIME_SNAPSHOT = now
-
-    # update game time and save it across reloads
-    _GAMETIME_MODULE.SERVER_RUNTIME_LAST_UPDATED = now
-    ServerConfig.objects.conf("runtime", _GAMETIME_MODULE.SERVER_RUNTIME)
-
-    if _MAINTENANCE_COUNT % 5 == 0:
-        # check cache size every 5 minutes
-        _FLUSH_CACHE(_IDMAPPER_CACHE_MAXSIZE)
-    if _MAINTENANCE_COUNT % (60 * 7) == 0:
-        # drop database connection every 7 hrs to avoid default timeouts on MySQL
-        # (see https://github.com/evennia/evennia/issues/1376)
-        connection.close()
-
-    # handle idle timeouts
-    if _IDLE_TIMEOUT > 0:
-        reason = _("idle timeout exceeded")
-        to_disconnect = []
-        for session in (
-            sess for sess in SESSIONS.values() if (now - sess.cmd_last) > _IDLE_TIMEOUT
-        ):
-            if not session.account or not session.account.access(
-                session.account, "noidletimeout", default=False
-            ):
-                to_disconnect.append(session)
-
-        for session in to_disconnect:
-            SESSIONS.disconnect(session, reason=reason)
-
-
-# ------------------------------------------------------------
-# Evennia Main Server object
-# ------------------------------------------------------------
-
-
-
[docs]class Evennia: - - """ - The main Evennia server handler. This object sets up the database and - tracks and interlinks all the twisted network services that make up - evennia. - - """ - -
[docs] def __init__(self, application): - """ - Setup the server. - - application - an instantiated Twisted application - - """ - sys.path.insert(1, ".") - - # create a store of services - self.services = service.MultiService() - self.services.setServiceParent(application) - self.amp_protocol = None # set by amp factory - self.sessions = SESSIONS - self.sessions.server = self - self.process_id = os.getpid() - - # Database-specific startup optimizations. - self.sqlite3_prep() - - self.start_time = time.time() - - # wrap the SIGINT handler to make sure we empty the threadpool - # even when we reload and we have long-running requests in queue. - # this is necessary over using Twisted's signal handler. - # (see https://github.com/evennia/evennia/issues/1128) - def _wrap_sigint_handler(*args): - from twisted.internet.defer import Deferred - - if hasattr(self, "web_root"): - d = self.web_root.empty_threadpool() - d.addCallback(lambda _: self.shutdown("reload", _reactor_stopping=True)) - else: - d = Deferred(lambda _: self.shutdown("reload", _reactor_stopping=True)) - d.addCallback(lambda _: reactor.stop()) - reactor.callLater(1, d.callback, None) - - reactor.sigInt = _wrap_sigint_handler
- - # Server startup methods - -
[docs] def sqlite3_prep(self): - """ - Optimize some SQLite stuff at startup since we - can't save it to the database. - """ - if ( - ".".join(str(i) for i in django.VERSION) < "1.2" - and settings.DATABASES.get("default", {}).get("ENGINE") == "sqlite3" - ) or ( - hasattr(settings, "DATABASES") - and settings.DATABASES.get("default", {}).get("ENGINE", None) - == "django.db.backends.sqlite3" - ): - cursor = connection.cursor() - cursor.execute("PRAGMA cache_size=10000") - cursor.execute("PRAGMA synchronous=OFF") - cursor.execute("PRAGMA count_changes=OFF") - cursor.execute("PRAGMA temp_store=2")
- -
[docs] def update_defaults(self): - """ - We make sure to store the most important object defaults here, so - we can catch if they change and update them on-objects automatically. - This allows for changing default cmdset locations and default - typeclasses in the settings file and have them auto-update all - already existing objects. - - """ - global INFO_DICT - - # setting names - settings_names = ( - "CMDSET_CHARACTER", - "CMDSET_ACCOUNT", - "BASE_ACCOUNT_TYPECLASS", - "BASE_OBJECT_TYPECLASS", - "BASE_CHARACTER_TYPECLASS", - "BASE_ROOM_TYPECLASS", - "BASE_EXIT_TYPECLASS", - "BASE_SCRIPT_TYPECLASS", - "BASE_CHANNEL_TYPECLASS", - ) - # get previous and current settings so they can be compared - settings_compare = list( - zip( - [ServerConfig.objects.conf(name) for name in settings_names], - [settings.__getattr__(name) for name in settings_names], - ) - ) - mismatches = [ - i for i, tup in enumerate(settings_compare) if tup[0] and tup[1] and tup[0] != tup[1] - ] - if len( - mismatches - ): # can't use any() since mismatches may be [0] which reads as False for any() - # we have a changed default. Import relevant objects and - # run the update - from evennia.objects.models import ObjectDB - from evennia.comms.models import ChannelDB - - # from evennia.accounts.models import AccountDB - for i, prev, curr in ( - (i, tup[0], tup[1]) for i, tup in enumerate(settings_compare) if i in mismatches - ): - # update the database - INFO_DICT["info"] = ( - " %s:\n '%s' changed to '%s'. Updating unchanged entries in database ..." - % (settings_names[i], prev, curr) - ) - if i == 0: - ObjectDB.objects.filter(db_cmdset_storage__exact=prev).update( - db_cmdset_storage=curr - ) - if i == 1: - AccountDB.objects.filter(db_cmdset_storage__exact=prev).update( - db_cmdset_storage=curr - ) - if i == 2: - AccountDB.objects.filter(db_typeclass_path__exact=prev).update( - db_typeclass_path=curr - ) - if i in (3, 4, 5, 6): - ObjectDB.objects.filter(db_typeclass_path__exact=prev).update( - db_typeclass_path=curr - ) - if i == 7: - ScriptDB.objects.filter(db_typeclass_path__exact=prev).update( - db_typeclass_path=curr - ) - if i == 8: - ChannelDB.objects.filter(db_typeclass_path__exact=prev).update( - db_typeclass_path=curr - ) - # store the new default and clean caches - ServerConfig.objects.conf(settings_names[i], curr) - ObjectDB.flush_instance_cache() - AccountDB.flush_instance_cache() - ScriptDB.flush_instance_cache() - ChannelDB.flush_instance_cache() - # if this is the first start we might not have a "previous" - # setup saved. Store it now. - [ - ServerConfig.objects.conf(settings_names[i], tup[1]) - for i, tup in enumerate(settings_compare) - if not tup[0] - ]
- -
[docs] def run_initial_setup(self): - """ - This is triggered by the amp protocol when the connection - to the portal has been established. - This attempts to run the initial_setup script of the server. - It returns if this is not the first time the server starts. - Once finished the last_initial_setup_step is set to 'done' - - """ - global INFO_DICT - initial_setup = importlib.import_module(settings.INITIAL_SETUP_MODULE) - last_initial_setup_step = ServerConfig.objects.conf("last_initial_setup_step") - try: - if not last_initial_setup_step: - # None is only returned if the config does not exist, - # i.e. this is an empty DB that needs populating. - INFO_DICT["info"] = " Server started for the first time. Setting defaults." - initial_setup.handle_setup() - elif last_initial_setup_step not in ('done', -1): - # last step crashed, so we weill resume from this step. - # modules and setup will resume from this step, retrying - # the last failed module. When all are finished, the step - # is set to 'done' to show it does not need to be run again. - INFO_DICT["info"] = " Resuming initial setup from step '{last}'.".format( - last=last_initial_setup_step - ) - initial_setup.handle_setup(last_initial_setup_step) - except Exception: - # stop server if this happens. - print(traceback.format_exc()) - print("Error in initial setup. Stopping Server + Portal.") - self.sessions.portal_shutdown()
- -
[docs] def create_default_channels(self): - """ - check so default channels exist on every restart, create if not. - - """ - - from evennia.comms.models import ChannelDB - from evennia.accounts.models import AccountDB - from evennia.utils.create import create_channel - - superuser = AccountDB.objects.get(id=1) - # mudinfo - mudinfo_chan = settings.CHANNEL_MUDINFO - if mudinfo_chan: - if not ChannelDB.objects.filter(db_key=mudinfo_chan["key"]): - channel = create_channel(**mudinfo_chan) - channel.connect(superuser) - # connectinfo - connectinfo_chan = settings.CHANNEL_MUDINFO - if connectinfo_chan: - if not ChannelDB.objects.filter(db_key=mudinfo_chan["key"]): - channel = create_channel(**connectinfo_chan) - # default channels - for chan_info in settings.DEFAULT_CHANNELS: - if not ChannelDB.objects.filter(db_key=chan_info["key"]): - channel = create_channel(**chan_info) - channel.connect(superuser)
- -
[docs] def run_init_hooks(self, mode): - """ - Called by the amp client once receiving sync back from Portal - - Args: - mode (str): One of shutdown, reload or reset - - """ - from evennia.objects.models import ObjectDB - - # start server time and maintenance task - self.maintenance_task = LoopingCall(_server_maintenance) - self.maintenance_task.start(60, now=True) # call every minute - - # update eventual changed defaults - self.update_defaults() - - [o.at_init() for o in ObjectDB.get_all_cached_instances()] - [p.at_init() for p in AccountDB.get_all_cached_instances()] - - # call correct server hook based on start file value - if mode == "reload": - logger.log_msg("Server successfully reloaded.") - self.at_server_reload_start() - elif mode == "reset": - # only run hook, don't purge sessions - self.at_server_cold_start() - logger.log_msg("Evennia Server successfully restarted in 'reset' mode.") - elif mode == "shutdown": - self.at_server_cold_start() - # clear eventual lingering session storages - ObjectDB.objects.clear_all_sessids() - logger.log_msg("Evennia Server successfully started.") - - # always call this regardless of start type - self.at_server_start()
- -
[docs] @defer.inlineCallbacks - def shutdown(self, mode="reload", _reactor_stopping=False): - """ - Shuts down the server from inside it. - - mode - sets the server restart mode. - - 'reload' - server restarts, no "persistent" scripts - are stopped, at_reload hooks called. - - 'reset' - server restarts, non-persistent scripts stopped, - at_shutdown hooks called but sessions will not - be disconnected. - - 'shutdown' - like reset, but server will not auto-restart. - _reactor_stopping - this is set if server is stopped by a kill - command OR this method was already called - once - in both cases the reactor is - dead/stopping already. - """ - if _reactor_stopping and hasattr(self, "shutdown_complete"): - # this means we have already passed through this method - # once; we don't need to run the shutdown procedure again. - defer.returnValue(None) - - from evennia.objects.models import ObjectDB - from evennia.server.models import ServerConfig - from evennia.utils import gametime as _GAMETIME_MODULE - - if mode == "reload": - # call restart hooks - ServerConfig.objects.conf("server_restart_mode", "reload") - yield [o.at_server_reload() for o in ObjectDB.get_all_cached_instances()] - yield [p.at_server_reload() for p in AccountDB.get_all_cached_instances()] - yield [ - (s._pause_task(auto_pause=True), s.at_server_reload()) - for s in ScriptDB.get_all_cached_instances() - if s.id and s.is_active - ] - yield self.sessions.all_sessions_portal_sync() - self.at_server_reload_stop() - # only save monitor state on reload, not on shutdown/reset - from evennia.scripts.monitorhandler import MONITOR_HANDLER - - MONITOR_HANDLER.save() - else: - if mode == "reset": - # like shutdown but don't unset the is_connected flag and don't disconnect sessions - yield [o.at_server_shutdown() for o in ObjectDB.get_all_cached_instances()] - yield [p.at_server_shutdown() for p in AccountDB.get_all_cached_instances()] - if self.amp_protocol: - yield self.sessions.all_sessions_portal_sync() - else: # shutdown - yield [_SA(p, "is_connected", False) for p in AccountDB.get_all_cached_instances()] - yield [o.at_server_shutdown() for o in ObjectDB.get_all_cached_instances()] - yield [ - (p.unpuppet_all(), p.at_server_shutdown()) - for p in AccountDB.get_all_cached_instances() - ] - yield ObjectDB.objects.clear_all_sessids() - yield [ - (s._pause_task(auto_pause=True), s.at_server_shutdown()) - for s in ScriptDB.get_all_cached_instances() - if s.id and s.is_active - ] - ServerConfig.objects.conf("server_restart_mode", "reset") - self.at_server_cold_stop() - - # tickerhandler state should always be saved. - from evennia.scripts.tickerhandler import TICKER_HANDLER - - TICKER_HANDLER.save() - - # always called, also for a reload - self.at_server_stop() - - if hasattr(self, "web_root"): # not set very first start - yield self.web_root.empty_threadpool() - - if not _reactor_stopping: - # kill the server - self.shutdown_complete = True - reactor.callLater(1, reactor.stop) - - # we make sure the proper gametime is saved as late as possible - ServerConfig.objects.conf("runtime", _GAMETIME_MODULE.runtime())
- -
[docs] def get_info_dict(self): - """ - Return the server info, for display. - - """ - return INFO_DICT
- - # server start/stop hooks - -
[docs] def at_server_start(self): - """ - This is called every time the server starts up, regardless of - how it was shut down. - - """ - if SERVER_STARTSTOP_MODULE: - SERVER_STARTSTOP_MODULE.at_server_start()
- -
[docs] def at_server_stop(self): - """ - This is called just before a server is shut down, regardless - of it is fore a reload, reset or shutdown. - - """ - if SERVER_STARTSTOP_MODULE: - SERVER_STARTSTOP_MODULE.at_server_stop()
- -
[docs] def at_server_reload_start(self): - """ - This is called only when server starts back up after a reload. - - """ - if SERVER_STARTSTOP_MODULE: - SERVER_STARTSTOP_MODULE.at_server_reload_start()
- -
[docs] def at_post_portal_sync(self, mode): - """ - This is called just after the portal has finished syncing back data to the server - after reconnecting. - - Args: - mode (str): One of 'reload', 'reset' or 'shutdown'. - - """ - - from evennia.scripts.monitorhandler import MONITOR_HANDLER - - MONITOR_HANDLER.restore(mode == "reload") - - from evennia.scripts.tickerhandler import TICKER_HANDLER - - TICKER_HANDLER.restore(mode == "reload") - - # Un-pause all scripts, stop non-persistent timers - ScriptDB.objects.update_scripts_after_server_start() - - # start the task handler - from evennia.scripts.taskhandler import TASK_HANDLER - - TASK_HANDLER.load() - TASK_HANDLER.create_delays() - - # create/update channels - self.create_default_channels() - - # delete the temporary setting - ServerConfig.objects.conf("server_restart_mode", delete=True)
- -
[docs] def at_server_reload_stop(self): - """ - This is called only time the server stops before a reload. - - """ - if SERVER_STARTSTOP_MODULE: - SERVER_STARTSTOP_MODULE.at_server_reload_stop()
- -
[docs] def at_server_cold_start(self): - """ - This is called only when the server starts "cold", i.e. after a - shutdown or a reset. - - """ - # We need to do this just in case the server was killed in a way where - # the normal cleanup operations did not have time to run. - from evennia.objects.models import ObjectDB - - ObjectDB.objects.clear_all_sessids() - - # Remove non-persistent scripts - from evennia.scripts.models import ScriptDB - - for script in ScriptDB.objects.filter(db_persistent=False): - script._stop_task() - - if GUEST_ENABLED: - for guest in AccountDB.objects.all().filter( - db_typeclass_path=settings.BASE_GUEST_TYPECLASS - ): - for character in guest.db._playable_characters: - if character: - character.delete() - guest.delete() - if SERVER_STARTSTOP_MODULE: - SERVER_STARTSTOP_MODULE.at_server_cold_start()
- -
[docs] def at_server_cold_stop(self): - """ - This is called only when the server goes down due to a shutdown or reset. - - """ - if SERVER_STARTSTOP_MODULE: - SERVER_STARTSTOP_MODULE.at_server_cold_stop()
- - -# ------------------------------------------------------------ -# -# Start the Evennia game server and add all active services -# -# ------------------------------------------------------------ - - -# Tell the system the server is starting up; some things are not available yet -try: - ServerConfig.objects.conf("server_starting_mode", True) -except OperationalError: - print("Server server_starting_mode couldn't be set - database not set up.") - - -# twistd requires us to define the variable 'application' so it knows -# what to execute from. -application = service.Application("Evennia") - -if "--nodaemon" not in sys.argv: - # custom logging, but only if we are not running in interactive mode - logfile = logger.WeeklyLogFile( - os.path.basename(settings.SERVER_LOG_FILE), - os.path.dirname(settings.SERVER_LOG_FILE), - day_rotation=settings.SERVER_LOG_DAY_ROTATION, - max_size=settings.SERVER_LOG_MAX_SIZE, - ) - application.setComponent(ILogObserver, logger.ServerLogObserver(logfile).emit) - -# The main evennia server program. This sets up the database -# and is where we store all the other services. -EVENNIA = Evennia(application) - -if AMP_ENABLED: - - # The AMP protocol handles the communication between - # the portal and the mud server. Only reason to ever deactivate - # it would be during testing and debugging. - - ifacestr = "" - if AMP_INTERFACE != "127.0.0.1": - ifacestr = "-%s" % AMP_INTERFACE - - INFO_DICT["amp"] = "amp %s: %s" % (ifacestr, AMP_PORT) - - from evennia.server import amp_client - - factory = amp_client.AMPClientFactory(EVENNIA) - amp_service = internet.TCPClient(AMP_HOST, AMP_PORT, factory) - amp_service.setName("ServerAMPClient") - EVENNIA.services.addService(amp_service) - -if WEBSERVER_ENABLED: - - # Start a django-compatible webserver. - - from evennia.server.webserver import ( - DjangoWebRoot, - WSGIWebServer, - Website, - LockableThreadPool, - PrivateStaticRoot, - ) - - # start a thread pool and define the root url (/) as a wsgi resource - # recognized by Django - threads = LockableThreadPool( - minthreads=max(1, settings.WEBSERVER_THREADPOOL_LIMITS[0]), - maxthreads=max(1, settings.WEBSERVER_THREADPOOL_LIMITS[1]), - ) - - web_root = DjangoWebRoot(threads) - # point our media resources to url /media - web_root.putChild(b"media", PrivateStaticRoot(settings.MEDIA_ROOT)) - # point our static resources to url /static - web_root.putChild(b"static", PrivateStaticRoot(settings.STATIC_ROOT)) - EVENNIA.web_root = web_root - - if WEB_PLUGINS_MODULE: - # custom overloads - web_root = WEB_PLUGINS_MODULE.at_webserver_root_creation(web_root) - - web_site = Website(web_root, logPath=settings.HTTP_LOG_FILE) - web_site.is_portal = False - - INFO_DICT["webserver"] = "" - for proxyport, serverport in WEBSERVER_PORTS: - # create the webserver (we only need the port for this) - webserver = WSGIWebServer(threads, serverport, web_site, interface="127.0.0.1") - webserver.setName("EvenniaWebServer%s" % serverport) - EVENNIA.services.addService(webserver) - - INFO_DICT["webserver"] += "webserver: %s" % serverport - -ENABLED = [] -if IRC_ENABLED: - # IRC channel connections - ENABLED.append("irc") - -if RSS_ENABLED: - # RSS feed channel connections - ENABLED.append("rss") - -if GRAPEVINE_ENABLED: - # Grapevine channel connections - ENABLED.append("grapevine") - -if GAME_INDEX_ENABLED: - from evennia.server.game_index_client.service import EvenniaGameIndexService - - egi_service = EvenniaGameIndexService() - EVENNIA.services.addService(egi_service) - -if ENABLED: - INFO_DICT["irc_rss"] = ", ".join(ENABLED) + " enabled." - -for plugin_module in SERVER_SERVICES_PLUGIN_MODULES: - # external plugin protocols - load here - plugin_module = mod_import(plugin_module) - if plugin_module: - plugin_module.start_plugin_services(EVENNIA) - else: - print(f"Could not load plugin module {plugin_module}") - -# clear server startup mode -try: - ServerConfig.objects.conf("server_starting_mode", delete=True) -except OperationalError: - print("Server server_starting_mode couldn't unset - db not set up.") -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/serversession.html b/docs/0.9.5/_modules/evennia/server/serversession.html deleted file mode 100644 index de813c203d..0000000000 --- a/docs/0.9.5/_modules/evennia/server/serversession.html +++ /dev/null @@ -1,542 +0,0 @@ - - - - - - - - evennia.server.serversession — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.serversession

-"""
-This defines a the Server's generic session object. This object represents
-a connection to the outside world but don't know any details about how the
-connection actually happens (so it's the same for telnet, web, ssh etc).
-
-It is stored on the Server side (as opposed to protocol-specific sessions which
-are stored on the Portal side)
-"""
-import time
-from django.utils import timezone
-from django.conf import settings
-from evennia.comms.models import ChannelDB
-from evennia.utils import logger
-from evennia.utils.utils import make_iter, lazy_property, class_from_module
-from evennia.commands.cmdsethandler import CmdSetHandler
-from evennia.scripts.monitorhandler import MONITOR_HANDLER
-from evennia.typeclasses.attributes import AttributeHandler, InMemoryAttributeBackend, DbHolder
-
-_GA = object.__getattribute__
-_SA = object.__setattr__
-_ObjectDB = None
-_ANSI = None
-
-_BASE_SESSION_CLASS = class_from_module(settings.BASE_SESSION_CLASS)
-
-
-# -------------------------------------------------------------
-# Server Session
-# -------------------------------------------------------------
-
-
-
[docs]class ServerSession(_BASE_SESSION_CLASS): - """ - This class represents an account's session and is a template for - individual protocols to communicate with Evennia. - - Each account gets a session assigned to them whenever they connect - to the game server. All communication between game and account goes - through their session. - - """ - -
[docs] def __init__(self): - """ - Initiate to avoid AttributeErrors down the line - - """ - self.puppet = None - self.account = None - self.cmdset_storage_string = "" - self.cmdset = CmdSetHandler(self, True)
- - def __cmdset_storage_get(self): - return [path.strip() for path in self.cmdset_storage_string.split(",")] - - def __cmdset_storage_set(self, value): - self.cmdset_storage_string = ",".join(str(val).strip() for val in make_iter(value)) - - cmdset_storage = property(__cmdset_storage_get, __cmdset_storage_set) - - @property - def id(self): - return self.sessid - -
[docs] def at_sync(self): - """ - This is called whenever a session has been resynced with the - portal. At this point all relevant attributes have already - been set and self.account been assigned (if applicable). - - Since this is often called after a server restart we need to - set up the session as it was. - - """ - global _ObjectDB - if not _ObjectDB: - from evennia.objects.models import ObjectDB as _ObjectDB - - super(ServerSession, self).at_sync() - if not self.logged_in: - # assign the unloggedin-command set. - self.cmdset_storage = settings.CMDSET_UNLOGGEDIN - - self.cmdset.update(init_mode=True) - - if self.puid: - # reconnect puppet (puid is only set if we are coming - # back from a server reload). This does all the steps - # done in the default @ic command but without any - # hooks, echoes or access checks. - obj = _ObjectDB.objects.get(id=self.puid) - obj.sessions.add(self) - obj.account = self.account - self.puid = obj.id - self.puppet = obj - # obj.scripts.validate() - obj.locks.cache_lock_bypass(obj)
- -
[docs] def at_login(self, account): - """ - Hook called by sessionhandler when the session becomes authenticated. - - Args: - account (Account): The account associated with the session. - - """ - self.account = account - self.uid = self.account.id - self.uname = self.account.username - self.logged_in = True - self.conn_time = time.time() - self.puid = None - self.puppet = None - self.cmdset_storage = settings.CMDSET_SESSION - - # Update account's last login time. - self.account.last_login = timezone.now() - self.account.save() - - # add the session-level cmdset - self.cmdset = CmdSetHandler(self, True)
- -
[docs] def at_disconnect(self, reason=None): - """ - Hook called by sessionhandler when disconnecting this session. - - """ - if self.logged_in: - account = self.account - if self.puppet: - account.unpuppet_object(self) - uaccount = account - uaccount.last_login = timezone.now() - uaccount.save() - # calling account hook - account.at_disconnect(reason) - self.logged_in = False - if not self.sessionhandler.sessions_from_account(account): - # no more sessions connected to this account - account.is_connected = False - # this may be used to e.g. delete account after disconnection etc - account.at_post_disconnect() - # remove any webclient settings monitors associated with this - # session - MONITOR_HANDLER.remove(account, "_saved_webclient_options", self.sessid)
- -
[docs] def get_account(self): - """ - Get the account associated with this session - - Returns: - account (Account): The associated Account. - - """ - return self.logged_in and self.account
- -
[docs] def get_puppet(self): - """ - Get the in-game character associated with this session. - - Returns: - puppet (Object): The puppeted object, if any. - - """ - return self.logged_in and self.puppet
- - get_character = get_puppet - -
[docs] def get_puppet_or_account(self): - """ - Get puppet or account. - - Returns: - controller (Object or Account): The puppet if one exists, - otherwise return the account. - - """ - if self.logged_in: - return self.puppet if self.puppet else self.account - return None
- -
[docs] def log(self, message, channel=True): - """ - Emits session info to the appropriate outputs and info channels. - - Args: - message (str): The message to log. - channel (bool, optional): Log to the CHANNEL_CONNECTINFO channel - in addition to the server log. - - """ - cchan = channel and settings.CHANNEL_CONNECTINFO - if cchan: - try: - cchan = ChannelDB.objects.get_channel(cchan["key"]) - cchan.msg("[%s]: %s" % (cchan.key, message)) - except Exception: - logger.log_trace() - logger.log_info(message)
- -
[docs] def get_client_size(self): - """ - Return eventual eventual width and height reported by the - client. Note that this currently only deals with a single - client window (windowID==0) as in a traditional telnet session. - - """ - flags = self.protocol_flags - print("session flags:", flags) - width = flags.get("SCREENWIDTH", {}).get(0, settings.CLIENT_DEFAULT_WIDTH) - height = flags.get("SCREENHEIGHT", {}).get(0, settings.CLIENT_DEFAULT_HEIGHT) - return width, height
- -
[docs] def update_session_counters(self, idle=False): - """ - Hit this when the user enters a command in order to update - idle timers and command counters. - - """ - # Idle time used for timeout calcs. - self.cmd_last = time.time() - - # Store the timestamp of the user's last command. - if not idle: - # Increment the user's command counter. - self.cmd_total += 1 - # Account-visible idle time, not used in idle timeout calcs. - self.cmd_last_visible = self.cmd_last
- -
[docs] def update_flags(self, **kwargs): - """ - Update the protocol_flags and sync them with Portal. - - Keyword Args: - protocol_flag (any): A key and value to set in the - protocol_flags dictionary. - - Notes: - Since protocols can vary, no checking is done - as to the existene of the flag or not. The input - data should have been validated before this call. - - """ - if kwargs: - self.protocol_flags.update(kwargs) - self.sessionhandler.session_portal_sync(self)
- -
[docs] def data_out(self, **kwargs): - """ - Sending data from Evennia->Client - - Keyword Args: - text (str or tuple) - any (str or tuple): Send-commands identified - by their keys. Or "options", carrying options - for the protocol(s). - - """ - self.sessionhandler.data_out(self, **kwargs)
- -
[docs] def data_in(self, **kwargs): - """ - Receiving data from the client, sending it off to - the respective inputfuncs. - - Keyword Args: - kwargs (any): Incoming data from protocol on - the form `{"commandname": ((args), {kwargs}),...}` - Notes: - This method is here in order to give the user - a single place to catch and possibly process all incoming data from - the client. It should usually always end by sending - this data off to `self.sessionhandler.call_inputfuncs(self, **kwargs)`. - """ - self.sessionhandler.call_inputfuncs(self, **kwargs)
- -
[docs] def msg(self, text=None, **kwargs): - """ - Wrapper to mimic msg() functionality of Objects and Accounts. - - Args: - text (str): String input. - - Keyword Args: - any (str or tuple): Send-commands identified - by their keys. Or "options", carrying options - for the protocol(s). - - """ - # this can happen if this is triggered e.g. a command.msg - # that auto-adds the session, we'd get a kwarg collision. - kwargs.pop("session", None) - kwargs.pop("from_obj", None) - if text is not None: - self.data_out(text=text, **kwargs) - else: - self.data_out(**kwargs)
- -
[docs] def execute_cmd(self, raw_string, session=None, **kwargs): - """ - Do something as this object. This method is normally never - called directly, instead incoming command instructions are - sent to the appropriate inputfunc already at the sessionhandler - level. This method allows Python code to inject commands into - this stream, and will lead to the text inputfunc be called. - - Args: - raw_string (string): Raw command input - session (Session): This is here to make API consistent with - Account/Object.execute_cmd. If given, data is passed to - that Session, otherwise use self. - Keyword Args: - Other keyword arguments will be added to the found command - object instace as variables before it executes. This is - unused by default Evennia but may be used to set flags and - change operating paramaters for commands at run-time. - - """ - # inject instruction into input stream - kwargs["text"] = ((raw_string,), {}) - self.sessionhandler.data_in(session or self, **kwargs)
- - def __eq__(self, other): - """ - Handle session comparisons - - """ - try: - return self.address == other.address - except AttributeError: - return False - - def __hash__(self): - """ - Python 3 requires that any class which implements __eq__ must also - implement __hash__ and that the corresponding hashes for equivalent - instances are themselves equivalent. - - """ - return hash(self.address) - - def __ne__(self, other): - try: - return self.address != other.address - except AttributeError: - return True - - def __str__(self): - """ - String representation of the user session class. We use - this a lot in the server logs. - - """ - symbol = "" - if self.logged_in and hasattr(self, "account") and self.account: - symbol = "(#%s)" % self.account.id - try: - if hasattr(self.address, "__iter__"): - address = ":".join([str(part) for part in self.address]) - else: - address = self.address - except Exception: - address = self.address - return "%s%s@%s" % (self.uname, symbol, address) - - def __repr__(self): - return "%s" % str(self) - - # Dummy API hooks for use during non-loggedin operation - -
[docs] def at_cmdset_get(self, **kwargs): - """ - A dummy hook all objects with cmdsets need to have - - """ - - pass
- - # Mock db/ndb properties for allowing easy storage on the session - # (note that no databse is involved at all here. session.db.attr = - # value just saves a normal property in memory, just like ndb). - -
[docs] @lazy_property - def nattributes(self): - return AttributeHandler(self, InMemoryAttributeBackend)
- -
[docs] @lazy_property - def attributes(self): - return self.nattributes
- - # @property -
[docs] def ndb_get(self): - """ - A non-persistent store (ndb: NonDataBase). Everything stored - to this is guaranteed to be cleared when a server is shutdown. - Syntax is same as for the _get_db_holder() method and - property, e.g. obj.ndb.attr = value etc. - - """ - try: - return self._ndb_holder - except AttributeError: - self._ndb_holder = DbHolder(self, "nattrhandler", manager_name="nattributes") - return self._ndb_holder
- - # @ndb.setter -
[docs] def ndb_set(self, value): - """ - Stop accidentally replacing the db object - - Args: - value (any): A value to store in the ndb. - - """ - string = "Cannot assign directly to ndb object! " - string += "Use ndb.attr=value instead." - raise Exception(string)
- - # @ndb.deleter -
[docs] def ndb_del(self): - """ - Stop accidental deletion. - - """ - raise Exception("Cannot delete the ndb object!")
- - ndb = property(ndb_get, ndb_set, ndb_del) - db = property(ndb_get, ndb_set, ndb_del) - - # Mock access method for the session (there is no lock info - # at this stage, so we just present a uniform API) -
[docs] def access(self, *args, **kwargs): - """ - Dummy method to mimic the logged-in API. - - """ - return True
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/session.html b/docs/0.9.5/_modules/evennia/server/session.html deleted file mode 100644 index 12af53b9ac..0000000000 --- a/docs/0.9.5/_modules/evennia/server/session.html +++ /dev/null @@ -1,280 +0,0 @@ - - - - - - - - evennia.server.session — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.session

-"""
-This module defines a generic session class. All connection instances
-(both on Portal and Server side) should inherit from this class.
-
-"""
-from django.conf import settings
-
-import time
-
-# ------------------------------------------------------------
-# Server Session
-# ------------------------------------------------------------
-
-
-
[docs]class Session: - """ - This class represents a player's session and is a template for - both portal- and server-side sessions. - - Each connection will see two session instances created: - - 1. A Portal session. This is customized for the respective connection - protocols that Evennia supports, like Telnet, SSH etc. The Portal - session must call init_session() as part of its initialization. The - respective hook methods should be connected to the methods unique - for the respective protocol so that there is a unified interface - to Evennia. - 2. A Server session. This is the same for all connected accounts, - regardless of how they connect. - - The Portal and Server have their own respective sessionhandlers. These - are synced whenever new connections happen or the Server restarts etc, - which means much of the same information must be stored in both places - e.g. the portal can re-sync with the server when the server reboots. - - """ - -
[docs] def init_session(self, protocol_key, address, sessionhandler): - """ - Initialize the Session. This should be called by the protocol when - a new session is established. - - Args: - protocol_key (str): By default, one of 'telnet', 'telnet/ssl', 'ssh', - 'webclient/websocket' or 'webclient/ajax'. - address (str): Client address. - sessionhandler (SessionHandler): Reference to the - main sessionhandler instance. - - """ - # This is currently 'telnet', 'ssh', 'ssl' or 'web' - self.protocol_key = protocol_key - # Protocol address tied to this session - self.address = address - - # suid is used by some protocols, it's a hex key. - self.suid = None - - # unique id for this session - self.sessid = 0 # no sessid yet - # client session id, if given by the client - self.csessid = None - # database id for the user connected to this session - self.uid = None - # user name, for easier tracking of sessions - self.uname = None - # if user has authenticated already or not - self.logged_in = False - - # database id of puppeted object (if any) - self.puid = None - - # session time statistics - self.conn_time = time.time() - self.cmd_last_visible = self.conn_time - self.cmd_last = self.conn_time - self.cmd_total = 0 - - self.protocol_flags = { - "ENCODING": "utf-8", - "SCREENREADER": False, - "INPUTDEBUG": False, - "RAW": False, - "NOCOLOR": False, - "LOCALECHO": False, - } - self.server_data = {} - - # map of input data to session methods - self.datamap = {} - - # a back-reference to the relevant sessionhandler this - # session is stored in. - self.sessionhandler = sessionhandler
- -
[docs] def get_sync_data(self): - """ - Get all data relevant to sync the session. - - Args: - syncdata (dict): All syncdata values, based on - the keys given by self._attrs_to_sync. - - """ - return { - attr: getattr(self, attr) for attr in settings.SESSION_SYNC_ATTRS if hasattr(self, attr) - }
- -
[docs] def load_sync_data(self, sessdata): - """ - Takes a session dictionary, as created by get_sync_data, and - loads it into the correct properties of the session. - - Args: - sessdata (dict): Session data dictionary. - - """ - for propname, value in sessdata.items(): - if ( - propname == "protocol_flags" - and isinstance(value, dict) - and hasattr(self, "protocol_flags") - and isinstance(self.protocol_flags, dict) - ): - # special handling to allow partial update of protocol flags - self.protocol_flags.update(value) - else: - setattr(self, propname, value)
- -
[docs] def at_sync(self): - """ - Called after a session has been fully synced (including - secondary operations such as setting self.account based - on uid etc). - - """ - if self.account: - self.protocol_flags.update( - self.account.attributes.get("_saved_protocol_flags", None) or {} - )
- - # access hooks - -
[docs] def disconnect(self, reason=None): - """ - generic hook called from the outside to disconnect this session - should be connected to the protocols actual disconnect mechanism. - - Args: - reason (str): Eventual text motivating the disconnect. - - """ - pass
- -
[docs] def data_out(self, **kwargs): - """ - Generic hook for sending data out through the protocol. Server - protocols can use this right away. Portal sessions - should overload this to format/handle the outgoing data as needed. - - Keyword Args: - kwargs (any): Other data to the protocol. - - """ - pass
- -
[docs] def data_in(self, **kwargs): - """ - Hook for protocols to send incoming data to the engine. - - Keyword Args: - kwargs (any): Other data from the protocol. - - """ - pass
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/sessionhandler.html b/docs/0.9.5/_modules/evennia/server/sessionhandler.html deleted file mode 100644 index 0c6673b220..0000000000 --- a/docs/0.9.5/_modules/evennia/server/sessionhandler.html +++ /dev/null @@ -1,973 +0,0 @@ - - - - - - - - evennia.server.sessionhandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.sessionhandler

-"""
-This module defines handlers for storing sessions when handles
-sessions of users connecting to the server.
-
-There are two similar but separate stores of sessions:
-
-- ServerSessionHandler - this stores generic game sessions
-     for the game. These sessions has no knowledge about
-     how they are connected to the world.
-- PortalSessionHandler - this stores sessions created by
-     twisted protocols. These are dumb connectors that
-     handle network communication but holds no game info.
-
-"""
-import time
-
-from django.conf import settings
-from evennia.commands.cmdhandler import CMD_LOGINSTART
-from evennia.utils.logger import log_trace
-from evennia.utils.utils import (
-    is_iter,
-    make_iter,
-    delay,
-    callables_from_module,
-    class_from_module,
-)
-from evennia.server.portal import amp
-from evennia.server.signals import SIGNAL_ACCOUNT_POST_LOGIN, SIGNAL_ACCOUNT_POST_LOGOUT
-from evennia.server.signals import SIGNAL_ACCOUNT_POST_FIRST_LOGIN, SIGNAL_ACCOUNT_POST_LAST_LOGOUT
-from codecs import decode as codecs_decode
-from django.utils.translation import gettext as _
-
-_FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED = settings.FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED
-_BROADCAST_SERVER_RESTART_MESSAGES = settings.BROADCAST_SERVER_RESTART_MESSAGES
-
-# delayed imports
-_AccountDB = None
-_ServerSession = None
-_ServerConfig = None
-_ScriptDB = None
-_OOB_HANDLER = None
-
-_ERR_BAD_UTF8 = _("Your client sent an incorrect UTF-8 sequence.")
-
-
-
[docs]class DummySession(object): - sessid = 0
- - -DUMMYSESSION = DummySession() - -_SERVERNAME = settings.SERVERNAME -_MULTISESSION_MODE = settings.MULTISESSION_MODE -_IDLE_TIMEOUT = settings.IDLE_TIMEOUT -_DELAY_CMD_LOGINSTART = settings.DELAY_CMD_LOGINSTART -_MAX_SERVER_COMMANDS_PER_SECOND = 100.0 -_MAX_SESSION_COMMANDS_PER_SECOND = 5.0 -_MODEL_MAP = None -_FUNCPARSER = None - - -# input handlers - -_INPUT_FUNCS = {} -for modname in make_iter(settings.INPUT_FUNC_MODULES): - _INPUT_FUNCS.update(callables_from_module(modname)) - - -
[docs]def delayed_import(): - """ - Helper method for delayed import of all needed entities. - - """ - global _ServerSession, _AccountDB, _ServerConfig, _ScriptDB - if not _ServerSession: - # we allow optional arbitrary serversession class for overloading - _ServerSession = class_from_module(settings.SERVER_SESSION_CLASS) - if not _AccountDB: - from evennia.accounts.models import AccountDB as _AccountDB - if not _ServerConfig: - from evennia.server.models import ServerConfig as _ServerConfig - if not _ScriptDB: - from evennia.scripts.models import ScriptDB as _ScriptDB - # including once to avoid warnings in Python syntax checkers - assert _ServerSession, "ServerSession class could not load" - assert _AccountDB, "AccountDB class could not load" - assert _ServerConfig, "ServerConfig class could not load" - assert _ScriptDB, "ScriptDB class c ould not load"
- - -# ----------------------------------------------------------- -# SessionHandler base class -# ------------------------------------------------------------ - - -
[docs]class SessionHandler(dict): - """ - This handler holds a stack of sessions. - - """ - - def __getitem__(self, key): - """ - Clean out None-sessions automatically. - - """ - if None in self: - del self[None] - return super().__getitem__(key) - -
[docs] def get(self, key, default=None): - """ - Clean out None-sessions automatically. - - """ - if None in self: - del self[None] - return super().get(key, default)
- - def __setitem__(self, key, value): - """ - Don't assign None sessions" - - """ - if key is not None: - super().__setitem__(key, value) - - def __contains__(self, key): - """ - None-keys are not accepted. - - """ - return False if key is None else super().__contains__(key) - -
[docs] def get_sessions(self, include_unloggedin=False): - """ - Returns the connected session objects. - - Args: - include_unloggedin (bool, optional): Also list Sessions - that have not yet authenticated. - - Returns: - sessions (list): A list of `Session` objects. - - """ - if include_unloggedin: - return list(self.values()) - else: - return [session for session in self.values() if session.logged_in]
- -
[docs] def get_all_sync_data(self): - """ - Create a dictionary of sessdata dicts representing all - sessions in store. - - Returns: - syncdata (dict): A dict of sync data. - - """ - return dict((sessid, sess.get_sync_data()) for sessid, sess in self.items())
- -
[docs] def clean_senddata(self, session, kwargs): - """ - Clean up data for sending across the AMP wire. Also apply the - FuncParser using callables from `settings.FUNCPARSER_OUTGOING_MESSAGES_MODULES`. - - Args: - session (Session): The relevant session instance. - kwargs (dict) Each keyword represents a send-instruction, with the keyword itself being - the name of the instruction (like "text"). Suitable values for each keyword are: - - arg -> [[arg], {}] - - [args] -> [[args], {}] - - {kwargs} -> [[], {kwargs}] - - [args, {kwargs}] -> [[arg], {kwargs}] - - [[args], {kwargs}] -> [[args], {kwargs}] - - Returns: - kwargs (dict): A cleaned dictionary of cmdname:[[args],{kwargs}] pairs, - where the keys, args and kwargs have all been converted to - send-safe entities (strings or numbers), and funcparser parsing has been - applied. - - """ - global _FUNCPARSER - if not _FUNCPARSER: - from evennia.utils.funcparser import FuncParser - _FUNCPARSER = FuncParser(settings.FUNCPARSER_OUTGOING_MESSAGES_MODULES, - raise_errors=True) - - options = kwargs.pop("options", None) or {} - raw = options.get("raw", False) - strip_inlinefunc = options.get("strip_inlinefunc", False) - - def _utf8(data): - if isinstance(data, bytes): - try: - data = codecs_decode(data, session.protocol_flags["ENCODING"]) - except LookupError: - # wrong encoding set on the session. Set it to a safe one - session.protocol_flags["ENCODING"] = "utf-8" - data = codecs_decode(data, "utf-8") - except UnicodeDecodeError: - # incorrect unicode sequence - session.sendLine(_ERR_BAD_UTF8) - data = "" - - return data - - def _validate(data): - """ - Helper function to convert data to AMP-safe (picketable) values" - - """ - if isinstance(data, dict): - newdict = {} - for key, part in data.items(): - newdict[key] = _validate(part) - return newdict - elif is_iter(data): - return [_validate(part) for part in data] - elif isinstance(data, (str, bytes)): - data = _utf8(data) - - if (_FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED - and not raw and isinstance(self, ServerSessionHandler)): - # only apply funcparser on the outgoing path (sessionhandler->) - # data = parse_inlinefunc(data, strip=strip_inlinefunc, session=session) - data = _FUNCPARSER.parse(data, strip=strip_inlinefunc, session=session) - - return str(data) - elif ( - hasattr(data, "id") - and hasattr(data, "db_date_created") - and hasattr(data, "__dbclass__") - ): - # convert database-object to their string representation. - return _validate(str(data)) - else: - return data - - rkwargs = {} - for key, data in kwargs.items(): - key = _validate(key) - if not data: - if key == "text": - # we don't allow sending text = None, this must mean - # that the text command is not to be used. - continue - rkwargs[key] = [[], {}] - elif isinstance(data, dict): - rkwargs[key] = [[], _validate(data)] - elif is_iter(data): - data = tuple(data) - if isinstance(data[-1], dict): - if len(data) == 2: - if is_iter(data[0]): - rkwargs[key] = [_validate(data[0]), _validate(data[1])] - else: - rkwargs[key] = [[_validate(data[0])], _validate(data[1])] - else: - rkwargs[key] = [_validate(data[:-1]), _validate(data[-1])] - else: - rkwargs[key] = [_validate(data), {}] - else: - rkwargs[key] = [[_validate(data)], {}] - rkwargs[key][1]["options"] = options - return rkwargs
- - -# ------------------------------------------------------------ -# Server-SessionHandler class -# ------------------------------------------------------------ - - -
[docs]class ServerSessionHandler(SessionHandler): - """ - This object holds the stack of sessions active in the game at any time. - - A session register with the handler in two steps, first by registering itself with the connect() - method. This indicates an non-authenticated session. Whenever the session is authenticated the - session together with the related account is sent to the login() method. - - """ - - # AMP communication methods - -
[docs] def __init__(self, *args, **kwargs): - """ - Init the handler. - - """ - super().__init__(*args, **kwargs) - self.server = None # set at server initialization - self.server_data = {"servername": _SERVERNAME} - # will be set on psync - self.portal_start_time = 0.0
- - def _run_cmd_login(self, session): - """ - Launch the CMD_LOGINSTART command. This is wrapped - for delays. - - """ - if not session.logged_in: - self.data_in(session, text=[[CMD_LOGINSTART], {}]) - -
[docs] def portal_connect(self, portalsessiondata): - """ - Called by Portal when a new session has connected. - Creates a new, unlogged-in game session. - - Args: - portalsessiondata (dict): a dictionary of all property:value - keys defining the session and which is marked to be - synced. - - """ - delayed_import() - global _ServerSession, _AccountDB, _ScriptDB - - sess = _ServerSession() - sess.sessionhandler = self - sess.load_sync_data(portalsessiondata) - sess.at_sync() - # validate all scripts - # _ScriptDB.objects.validate() - self[sess.sessid] = sess - - if sess.logged_in and sess.uid: - # Session is already logged in. This can happen in the - # case of auto-authenticating protocols like SSH or - # webclient's session sharing - account = _AccountDB.objects.get_account_from_uid(sess.uid) - if account: - # this will set account.is_connected too - self.login(sess, account, force=True) - return - else: - sess.logged_in = False - sess.uid = None - - # show the first login command, may delay slightly to allow - # the handshakes to finish. - delay(_DELAY_CMD_LOGINSTART, self._run_cmd_login, sess)
- -
[docs] def portal_session_sync(self, portalsessiondata): - """ - Called by Portal when it wants to update a single session (e.g. - because of all negotiation protocols have finally replied) - - Args: - portalsessiondata (dict): a dictionary of all property:value - keys defining the session and which is marked to be - synced. - - """ - sessid = portalsessiondata.get("sessid") - session = self.get(sessid) - if session: - # since some of the session properties may have had - # a chance to change already before the portal gets here - # the portal doesn't send all sessiondata but only - # ones which should only be changed from portal (like - # protocol_flags etc) - session.load_sync_data(portalsessiondata)
- -
[docs] def portal_sessions_sync(self, portalsessionsdata): - """ - Syncing all session ids of the portal with the ones of the - server. This is instantiated by the portal when reconnecting. - - Args: - portalsessionsdata (dict): A dictionary - `{sessid: {property:value},...}` defining each session and - the properties in it which should be synced. - - """ - delayed_import() - global _ServerSession, _AccountDB, _ServerConfig, _ScriptDB - - for sess in list(self.values()): - # we delete the old session to make sure to catch eventual - # lingering references. - del sess - - for sessid, sessdict in portalsessionsdata.items(): - sess = _ServerSession() - sess.sessionhandler = self - sess.load_sync_data(sessdict) - if sess.uid: - sess.account = _AccountDB.objects.get_account_from_uid(sess.uid) - self[sessid] = sess - sess.at_sync() - - mode = "reload" - - # tell the server hook we synced - self.server.at_post_portal_sync(mode) - # announce the reconnection - if _BROADCAST_SERVER_RESTART_MESSAGES: - self.announce_all(_(" ... Server restarted."))
- -
[docs] def portal_disconnect(self, session): - """ - Called from Portal when Portal session closed from the portal - side. There is no message to report in this case. - - Args: - session (Session): The Session to disconnect - - """ - # disconnect us without calling Portal since - # Portal already knows. - self.disconnect(session, reason="", sync_portal=False)
- -
[docs] def portal_disconnect_all(self): - """ - Called from Portal when Portal is closing down. All - Sessions should die. The Portal should not be informed. - - """ - # set a watchdog to avoid self.disconnect from deleting - # the session while we are looping over them - self._disconnect_all = True - for session in self.values(): - session.disconnect() - del self._disconnect_all
- - # server-side access methods - -
[docs] def start_bot_session(self, protocol_path, configdict): - """ - This method allows the server-side to force the Portal to - create a new bot session. - - Args: - protocol_path (str): The full python path to the bot's - class. - configdict (dict): This dict will be used to configure - the bot (this depends on the bot protocol). - - Examples: - start_bot_session("evennia.server.portal.irc.IRCClient", - {"uid":1, "botname":"evbot", "channel":"#evennia", - "network:"irc.freenode.net", "port": 6667}) - - Notes: - The new session will use the supplied account-bot uid to - initiate an already logged-in connection. The Portal will - treat this as a normal connection and henceforth so will - the Server. - - """ - self.server.amp_protocol.send_AdminServer2Portal( - DUMMYSESSION, operation=amp.SCONN, protocol_path=protocol_path, config=configdict - )
- -
[docs] def portal_restart_server(self): - """ - Called by server when reloading. We tell the portal to start a new server instance. - - """ - self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=amp.SRELOAD)
- -
[docs] def portal_reset_server(self): - """ - Called by server when reloading. We tell the portal to start a new server instance. - - """ - self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=amp.SRESET)
- -
[docs] def portal_shutdown(self): - """ - Called by server when it's time to shut down (the portal will shut us down and then shut - itself down) - - """ - self.server.amp_protocol.send_AdminServer2Portal(DUMMYSESSION, operation=amp.PSHUTD)
- -
[docs] def login(self, session, account, force=False, testmode=False): - """ - Log in the previously unloggedin session and the account we by now should know is connected - to it. After this point we assume the session to be logged in one way or another. - - Args: - session (Session): The Session to authenticate. - account (Account): The Account identified as associated with this Session. - force (bool): Login also if the session thinks it's already logged in - (this can happen for auto-authenticating protocols) - testmode (bool, optional): This is used by unittesting for - faking login without any AMP being actually active. - - """ - if session.logged_in and not force: - # don't log in a session that is already logged in. - return - - account.is_connected = True - - # sets up and assigns all properties on the session - session.at_login(account) - - # account init - account.at_init() - - # Check if this is the first time the *account* logs in - if account.db.FIRST_LOGIN: - account.at_first_login() - del account.db.FIRST_LOGIN - - account.at_pre_login() - - if _MULTISESSION_MODE == 0: - # disconnect all previous sessions. - self.disconnect_duplicate_sessions(session) - - nsess = len(self.sessions_from_account(account)) - string = "Logged in: {account} {address} ({nsessions} session(s) total)" - string = string.format(account=account, address=session.address, nsessions=nsess) - session.log(string) - session.logged_in = True - # sync the portal to the session - if not testmode: - self.server.amp_protocol.send_AdminServer2Portal( - session, operation=amp.SLOGIN, sessiondata={"logged_in": True, "uid": session.uid} - ) - account.at_post_login(session=session) - if nsess < 2: - SIGNAL_ACCOUNT_POST_FIRST_LOGIN.send(sender=account, session=session) - SIGNAL_ACCOUNT_POST_LOGIN.send(sender=account, session=session)
- -
[docs] def disconnect(self, session, reason="", sync_portal=True): - """ - Called from server side to remove session and inform portal - of this fact. - - Args: - session (Session): The Session to disconnect. - reason (str, optional): A motivation for the disconnect. - sync_portal (bool, optional): Sync the disconnect to - Portal side. This should be done unless this was - called by self.portal_disconnect(). - - """ - session = self.get(session.sessid) - if not session: - return - - if hasattr(session, "account") and session.account: - # only log accounts logging off - nsess = len(self.sessions_from_account(session.account)) - 1 - sreason = " ({})".format(reason) if reason else "" - string = "Logged out: {account} {address} ({nsessions} sessions(s) remaining){reason}" - string = string.format( - reason=sreason, account=session.account, address=session.address, nsessions=nsess - ) - session.log(string) - - if nsess == 0: - SIGNAL_ACCOUNT_POST_LAST_LOGOUT.send(sender=session.account, session=session) - - session.at_disconnect(reason) - SIGNAL_ACCOUNT_POST_LOGOUT.send(sender=session.account, session=session) - sessid = session.sessid - if sessid in self and not hasattr(self, "_disconnect_all"): - del self[sessid] - if sync_portal: - # inform portal that session should be closed. - self.server.amp_protocol.send_AdminServer2Portal( - session, operation=amp.SDISCONN, reason=reason - )
- -
[docs] def all_sessions_portal_sync(self): - """ - This is called by the server when it reboots. It syncs all session data - to the portal. Returns a deferred! - - """ - sessdata = self.get_all_sync_data() - return self.server.amp_protocol.send_AdminServer2Portal( - DUMMYSESSION, operation=amp.SSYNC, sessiondata=sessdata - )
- -
[docs] def session_portal_sync(self, session): - """ - This is called by the server when it wants to sync a single session - with the Portal for whatever reason. Returns a deferred! - - """ - sessdata = {session.sessid: session.get_sync_data()} - return self.server.amp_protocol.send_AdminServer2Portal( - DUMMYSESSION, operation=amp.SSYNC, sessiondata=sessdata, clean=False - )
- -
[docs] def session_portal_partial_sync(self, session_data): - """ - Call to make a partial update of the session, such as only a particular property. - - Args: - session_data (dict): Store `{sessid: {property:value}, ...}` defining one or - more sessions in detail. - - """ - return self.server.amp_protocol.send_AdminServer2Portal( - DUMMYSESSION, operation=amp.SSYNC, sessiondata=session_data, clean=False - )
- -
[docs] def disconnect_all_sessions(self, reason="You have been disconnected."): - """ - Cleanly disconnect all of the connected sessions. - - Args: - reason (str, optional): The reason for the disconnection. - - """ - - for session in self: - del session - # tell portal to disconnect all sessions - self.server.amp_protocol.send_AdminServer2Portal( - DUMMYSESSION, operation=amp.SDISCONNALL, reason=reason - )
- -
[docs] def disconnect_duplicate_sessions( - self, curr_session, reason=_("Logged in from elsewhere. Disconnecting.") - ): - """ - Disconnects any existing sessions with the same user. - - args: - curr_session (Session): Disconnect all Sessions matching this one. - reason (str, optional): A motivation for disconnecting. - - """ - uid = curr_session.uid - # we can't compare sessions directly since this will compare addresses and - # mean connecting from the same host would not catch duplicates - sid = id(curr_session) - doublet_sessions = [ - sess for sess in self.values() - if sess.logged_in and sess.uid == uid and id(sess) != sid - ] - - for session in doublet_sessions: - self.disconnect(session, reason)
- -
[docs] def validate_sessions(self): - """ - Check all currently connected sessions (logged in and not) and - see if any are dead or idle. - - """ - tcurr = time.time() - reason = _("Idle timeout exceeded, disconnecting.") - for session in ( - session - for session in self.values() - if session.logged_in - and _IDLE_TIMEOUT > 0 - and (tcurr - session.cmd_last) > _IDLE_TIMEOUT - ): - self.disconnect(session, reason=reason)
- -
[docs] def account_count(self): - """ - Get the number of connected accounts (not sessions since a - account may have more than one session depending on settings). - Only logged-in accounts are counted here. - - Returns: - naccount (int): Number of connected accounts - - """ - return len(set(session.uid for session in self.values() if session.logged_in))
- -
[docs] def all_connected_accounts(self): - """ - Get a unique list of connected and logged-in Accounts. - - Returns: - accounts (list): All conected Accounts (which may be fewer than the - amount of Sessions due to multi-playing). - - """ - return list( - set( - session.account - for session in self.values() - if session.logged_in and session.account - ) - )
- -
[docs] def session_from_sessid(self, sessid): - """ - Get session based on sessid, or None if not found - - Args: - sessid (int or list): Session id(s). - - Return: - sessions (Session or list): Session(s) found. This - is a list if input was a list. - - """ - if is_iter(sessid): - return [self.get(sid) for sid in sessid if sid in self] - return self.get(sessid)
- -
[docs] def session_from_account(self, account, sessid): - """ - Given an account and a session id, return the actual session - object. - - Args: - account (Account): The Account to get the Session from. - sessid (int or list): Session id(s). - - Returns: - sessions (Session or list): Session(s) found. - - """ - sessions = [ - self[sid] - for sid in make_iter(sessid) - if sid in self and self[sid].logged_in and account.uid == self[sid].uid - ] - return sessions[0] if len(sessions) == 1 else sessions
- -
[docs] def sessions_from_account(self, account): - """ - Given an account, return all matching sessions. - - Args: - account (Account): Account to get sessions from. - - Returns: - sessions (list): All Sessions associated with this account. - - """ - uid = account.uid - return [session for session in self.values() if session.logged_in and session.uid == uid]
- -
[docs] def sessions_from_puppet(self, puppet): - """ - Given a puppeted object, return all controlling sessions. - - Args: - puppet (Object): Object puppeted - - Returns. - sessions (Session or list): Can be more than one of Object is controlled by more than - one Session (MULTISESSION_MODE > 1). - - """ - sessions = puppet.sessid.get() - return sessions[0] if len(sessions) == 1 else sessions
- - sessions_from_character = sessions_from_puppet - -
[docs] def sessions_from_csessid(self, csessid): - """ - Given a client identification hash (for session types that offer them) - return all sessions with a matching hash. - - Args - csessid (str): The session hash. - - Returns: - sessions (list): The sessions with matching .csessid, if any. - - """ - if csessid: - return [] - return [ - session for session in self.values() if session.csessid and session.csessid == csessid - ]
- -
[docs] def announce_all(self, message): - """ - Send message to all connected sessions - - Args: - message (str): Message to send. - - """ - for session in self.values(): - self.data_out(session, text=message)
- -
[docs] def data_out(self, session, **kwargs): - """ - Sending data Server -> Portal - - Args: - session (Session): Session to relay to. - text (str, optional): text data to return - - Notes: - The outdata will be scrubbed for sending across - the wire here. - """ - # clean output for sending - kwargs = self.clean_senddata(session, kwargs) - - # send across AMP - self.server.amp_protocol.send_MsgServer2Portal(session, **kwargs)
- -
[docs] def get_inputfuncs(self): - """ - Get all registered inputfuncs (access function) - - Returns: - inputfuncs (dict): A dict of {key:inputfunc,...} - """ - return _INPUT_FUNCS
- -
[docs] def data_in(self, session, **kwargs): - """ - We let the data take a "detour" to session.data_in - so the user can override and see it all in one place. - That method is responsible to in turn always call - this class' `sessionhandler.call_inputfunc` with the - (possibly processed) data. - - """ - if session: - session.data_in(**kwargs)
- -
[docs] def call_inputfuncs(self, session, **kwargs): - """ - Split incoming data into its inputfunc counterparts. This should be - called by the `serversession.data_in` as - `sessionhandler.call_inputfunc(self, **kwargs)`. - - We also intercept OOB communication here. - - Args: - sessions (Session): Session. - - Keyword Args: - any (tuple): Incoming data from protocol, each - on the form `commandname=((args), {kwargs})`. - - """ - - # distribute incoming data to the correct receiving methods. - if session: - input_debug = session.protocol_flags.get("INPUTDEBUG", False) - for cmdname, (cmdargs, cmdkwargs) in kwargs.items(): - cname = cmdname.strip().lower() - try: - cmdkwargs.pop("options", None) - if cname in _INPUT_FUNCS: - _INPUT_FUNCS[cname](session, *cmdargs, **cmdkwargs) - else: - _INPUT_FUNCS["default"](session, cname, *cmdargs, **cmdkwargs) - except Exception as err: - if input_debug: - session.msg(err) - log_trace()
- - -# import class from settings -_SESSION_HANDLER_CLASS = class_from_module(settings.SERVER_SESSION_HANDLER_CLASS) - -# Instantiate class. These globals are used to provide singleton-like behavior. -SESSION_HANDLER = _SESSION_HANDLER_CLASS() -SESSIONS = SESSION_HANDLER # legacy -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/throttle.html b/docs/0.9.5/_modules/evennia/server/throttle.html deleted file mode 100644 index 44bf13c673..0000000000 --- a/docs/0.9.5/_modules/evennia/server/throttle.html +++ /dev/null @@ -1,328 +0,0 @@ - - - - - - - - evennia.server.throttle — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.throttle

-from django.core.cache import caches
-from collections import deque
-from evennia.utils import logger
-import time
-from django.utils.translation import gettext as _
-
-
-
[docs]class Throttle: - """ - Keeps a running count of failed actions per IP address. - - Available methods indicate whether or not the number of failures exceeds a - particular threshold. - - This version of the throttle is usable by both the terminal server as well - as the web server, imposes limits on memory consumption by using deques - with length limits instead of open-ended lists, and uses native Django - caches for automatic key eviction and persistence configurability. - """ - - error_msg = _("Too many failed attempts; you must wait a few minutes before trying again.") - -
[docs] def __init__(self, **kwargs): - """ - Allows setting of throttle parameters. - - Keyword Args: - name (str): Name of this throttle. - limit (int): Max number of failures before imposing limiter. If `None`, - the throttle is disabled. - timeout (int): number of timeout seconds after - max number of tries has been reached. - cache_size (int): Max number of attempts to record per IP within a - rolling window; this is NOT the same as the limit after which - the throttle is imposed! - """ - try: - self.storage = caches['throttle'] - except Exception: - logger.log_trace("Throttle: Errors encountered; using default cache.") - self.storage = caches['default'] - - self.name = kwargs.get('name', 'undefined-throttle') - self.limit = kwargs.get("limit", 5) - self.cache_size = kwargs.get('cache_size', self.limit) - self.timeout = kwargs.get("timeout", 5 * 60)
- -
[docs] def get_cache_key(self, *args, **kwargs): - """ - Creates a 'prefixed' key containing arbitrary terms to prevent key - collisions in the same namespace. - - """ - return '-'.join((self.name, *args))
- -
[docs] def touch(self, key, *args, **kwargs): - """ - Refreshes the timeout on a given key and ensures it is recorded in the - key register. - - Args: - key(str): Key of entry to renew. - - """ - cache_key = self.get_cache_key(key) - if self.storage.touch(cache_key, self.timeout): - self.record_key(key)
- -
[docs] def get(self, ip=None): - """ - Convenience function that returns the storage table, or part of. - - Args: - ip (str, optional): IP address of requestor - - Returns: - storage (dict): When no IP is provided, returns a dict of all - current IPs being tracked and the timestamps of their recent - failures. - timestamps (deque): When an IP is provided, returns a deque of - timestamps of recent failures only for that IP. - - """ - if ip: - cache_key = self.get_cache_key(str(ip)) - return self.storage.get(cache_key, deque(maxlen=self.cache_size)) - else: - keys_key = self.get_cache_key('keys') - keys = self.storage.get_or_set(keys_key, set(), self.timeout) - data = self.storage.get_many((self.get_cache_key(x) for x in keys)) - - found_keys = set(data.keys()) - if len(keys) != len(found_keys): - self.storage.set(keys_key, found_keys, self.timeout) - - return data
- -
[docs] def update(self, ip, failmsg="Exceeded threshold."): - """ - Store the time of the latest failure. - - Args: - ip (str): IP address of requestor - failmsg (str, optional): Message to display in logs upon activation - of throttle. - - Returns: - None - - """ - cache_key = self.get_cache_key(ip) - - # Get current status - previously_throttled = self.check(ip) - - # Get previous failures, if any - entries = self.storage.get(cache_key, []) - entries.append(time.time()) - - # Store updated record - self.storage.set(cache_key, deque(entries, maxlen=self.cache_size), self.timeout) - - # See if this update caused a change in status - currently_throttled = self.check(ip) - - # If this makes it engage, log a single activation event - if not previously_throttled and currently_throttled: - logger.log_sec( - f"Throttle Activated: {failmsg} (IP: {ip}, " - f"{self.limit} hits in {self.timeout} seconds.)" - ) - - self.record_ip(ip)
- -
[docs] def remove(self, ip, *args, **kwargs): - """ - Clears data stored for an IP from the throttle. - - Args: - ip(str): IP to clear. - - """ - exists = self.get(ip) - if not exists: - return False - - cache_key = self.get_cache_key(ip) - self.storage.delete(cache_key) - self.unrecord_ip(ip) - - # Return True if NOT exists - return not bool(self.get(ip))
- -
[docs] def record_ip(self, ip, *args, **kwargs): - """ - Tracks keys as they are added to the cache (since there is no way to - get a list of keys after-the-fact). - - Args: - ip(str): IP being added to cache. This should be the original - IP, not the cache-prefixed key. - - """ - keys_key = self.get_cache_key('keys') - keys = self.storage.get(keys_key, set()) - keys.add(ip) - self.storage.set(keys_key, keys, self.timeout) - return True
- -
[docs] def unrecord_ip(self, ip, *args, **kwargs): - """ - Forces removal of a key from the key registry. - - Args: - ip(str): IP to remove from list of keys. - - """ - keys_key = self.get_cache_key('keys') - keys = self.storage.get(keys_key, set()) - try: - keys.remove(ip) - self.storage.set(keys_key, keys, self.timeout) - return True - except KeyError: - return False
- -
[docs] def check(self, ip): - """ - This will check the session's address against the - storage dictionary to check they haven't spammed too many - fails recently. - - Args: - ip (str): IP address of requestor - - Returns: - throttled (bool): True if throttling is active, - False otherwise. - - """ - if self.limit is None: - # throttle is disabled - return False - - now = time.time() - ip = str(ip) - - cache_key = self.get_cache_key(ip) - - # checking mode - latest_fails = self.storage.get(cache_key) - if latest_fails and len(latest_fails) >= self.limit: - # too many fails recently - if now - latest_fails[-1] < self.timeout: - # too soon - timeout in play - self.touch(cache_key) - return True - else: - # timeout has passed. clear faillist - self.remove(ip) - return False - else: - return False
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/validators.html b/docs/0.9.5/_modules/evennia/server/validators.html deleted file mode 100644 index d1fe1e651e..0000000000 --- a/docs/0.9.5/_modules/evennia/server/validators.html +++ /dev/null @@ -1,195 +0,0 @@ - - - - - - - - evennia.server.validators — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.validators

-from django.conf import settings
-from django.core.exceptions import ValidationError
-from django.utils.translation import gettext as _
-from evennia.accounts.models import AccountDB
-import re
-
-
-
[docs]class EvenniaUsernameAvailabilityValidator: - """ - Checks to make sure a given username is not taken or otherwise reserved. - """ - - def __call__(self, username): - """ - Validates a username to make sure it is not in use or reserved. - - Args: - username (str): Username to validate - - Returns: - None (None): None if password successfully validated, - raises ValidationError otherwise. - - """ - - # Check guest list - if settings.GUEST_LIST and username.lower() in ( - guest.lower() for guest in settings.GUEST_LIST - ): - raise ValidationError( - _("Sorry, that username is reserved."), code="evennia_username_reserved" - ) - - # Check database - exists = AccountDB.objects.filter(username__iexact=username).exists() - if exists: - raise ValidationError( - _("Sorry, that username is already taken."), code="evennia_username_taken" - )
- - -
[docs]class EvenniaPasswordValidator: -
[docs] def __init__( - self, - regex=r"^[\w. @+\-',]+$", - policy="Password should contain a mix of letters, " - "spaces, digits and @/./+/-/_/'/, only.", - ): - """ - Constructs a standard Django password validator. - - Args: - regex (str): Regex pattern of valid characters to allow. - policy (str): Brief explanation of what the defined regex permits. - - """ - self.regex = regex - self.policy = policy
- -
[docs] def validate(self, password, user=None): - """ - Validates a password string to make sure it meets predefined Evennia - acceptable character policy. - - Args: - password (str): Password to validate - user (None): Unused argument but required by Django - - Returns: - None (None): None if password successfully validated, - raises ValidationError otherwise. - - """ - # Check complexity - if not re.findall(self.regex, password): - raise ValidationError(_(self.policy), code="evennia_password_policy")
- -
[docs] def get_help_text(self): - """ - Returns a user-facing explanation of the password policy defined - by this validator. - - Returns: - text (str): Explanation of password policy. - - """ - return _( - "{policy} From a terminal client, you can also use a phrase of multiple words if " - "you enclose the password in double quotes.".format(policy=self.policy) - )
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/server/webserver.html b/docs/0.9.5/_modules/evennia/server/webserver.html deleted file mode 100644 index 19d3a27db6..0000000000 --- a/docs/0.9.5/_modules/evennia/server/webserver.html +++ /dev/null @@ -1,405 +0,0 @@ - - - - - - - - evennia.server.webserver — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.server.webserver

-"""
-This implements resources for Twisted webservers using the WSGI
-interface of Django. This alleviates the need of running e.g. an
-Apache server to serve Evennia's web presence (although you could do
-that too if desired).
-
-The actual servers are started inside server.py as part of the Evennia
-application.
-
-(Lots of thanks to http://github.com/clemesha/twisted-wsgi-django for
-a great example/aid on how to do this.)
-
-
-"""
-import urllib.parse
-from urllib.parse import quote as urlquote
-from twisted.web import resource, http, server, static
-from twisted.internet import reactor
-from twisted.application import internet
-from twisted.web.proxy import ReverseProxyResource
-from twisted.web.server import NOT_DONE_YET
-from twisted.python import threadpool
-from twisted.internet import defer
-
-from twisted.web.wsgi import WSGIResource
-from django.conf import settings
-from django.core.wsgi import get_wsgi_application
-
-
-from evennia.utils import logger
-
-_UPSTREAM_IPS = settings.UPSTREAM_IPS
-_DEBUG = settings.DEBUG
-
-
-
[docs]class LockableThreadPool(threadpool.ThreadPool): - """ - Threadpool that can be locked from accepting new requests. - """ - -
[docs] def __init__(self, *args, **kwargs): - self._accept_new = True - threadpool.ThreadPool.__init__(self, *args, **kwargs)
- -
[docs] def lock(self): - self._accept_new = False
- -
[docs] def callInThread(self, func, *args, **kwargs): - """ - called in the main reactor thread. Makes sure the pool - is not locked before continuing. - """ - if self._accept_new: - threadpool.ThreadPool.callInThread(self, func, *args, **kwargs)
- - -# -# X-Forwarded-For Handler -# - - -
[docs]class HTTPChannelWithXForwardedFor(http.HTTPChannel): - """ - HTTP xforward class - - """ - -
[docs] def allHeadersReceived(self): - """ - Check to see if this is a reverse proxied connection. - - """ - if self.requests: - CLIENT = 0 - http.HTTPChannel.allHeadersReceived(self) - req = self.requests[-1] - client_ip, port = self.transport.client - proxy_chain = req.getHeader("X-FORWARDED-FOR") - if proxy_chain and client_ip in _UPSTREAM_IPS: - forwarded = proxy_chain.split(", ", 1)[CLIENT] - self.transport.client = (forwarded, port)
- - -# Monkey-patch Twisted to handle X-Forwarded-For. - -http.HTTPFactory.protocol = HTTPChannelWithXForwardedFor - - -
[docs]class EvenniaReverseProxyResource(ReverseProxyResource): -
[docs] def getChild(self, path, request): - """ - Create and return a proxy resource with the same proxy configuration - as this one, except that its path also contains the segment given by - path at the end. - - Args: - path (str): Url path. - request (Request object): Incoming request. - - Return: - resource (EvenniaReverseProxyResource): A proxy resource. - - """ - request.notifyFinish().addErrback( - lambda f: 0 - # lambda f: logger.log_trace("%s\nCaught errback in webserver.py" % f) - ) - return EvenniaReverseProxyResource( - self.host, self.port, self.path + "/" + urlquote(path, safe=""), self.reactor - )
- -
[docs] def render(self, request): - """ - Render a request by forwarding it to the proxied server. - - Args: - request (Request): Incoming request. - - Returns: - not_done (char): Indicator to note request not yet finished. - - """ - # RFC 2616 tells us that we can omit the port if it's the default port, - # but we have to provide it otherwise - request.content.seek(0, 0) - qs = urllib.parse.urlparse(request.uri)[4] - if qs: - rest = self.path + "?" + qs.decode() - else: - rest = self.path - rest = rest.encode() - clientFactory = self.proxyClientFactoryClass( - request.method, - rest, - request.clientproto, - request.getAllHeaders(), - request.content.read(), - request, - ) - clientFactory.noisy = False - self.reactor.connectTCP(self.host, self.port, clientFactory) - # don't trigger traceback if connection is lost before request finish. - request.notifyFinish().addErrback(lambda f: 0) - # request.notifyFinish().addErrback( - # lambda f:logger.log_trace("Caught errback in webserver.py: %s" % f) - return NOT_DONE_YET
- - -# -# Website server resource -# - - -
[docs]class DjangoWebRoot(resource.Resource): - """ - This creates a web root (/) that Django - understands by tweaking the way - child instances are recognized. - """ - -
[docs] def __init__(self, pool): - """ - Setup the django+twisted resource. - - Args: - pool (ThreadPool): The twisted threadpool. - - """ - self.pool = pool - self._echo_log = True - self._pending_requests = {} - super().__init__() - self.wsgi_resource = WSGIResource(reactor, pool, get_wsgi_application())
- -
[docs] def empty_threadpool(self): - """ - Converts our _pending_requests list of deferreds into a DeferredList - - Returns: - deflist (DeferredList): Contains all deferreds of pending requests. - - """ - self.pool.lock() - if self._pending_requests and self._echo_log: - self._echo_log = False # just to avoid multiple echoes - msg = "Webserver waiting for %i requests ... " - logger.log_info(msg % len(self._pending_requests)) - return defer.DeferredList(self._pending_requests, consumeErrors=True)
- - def _decrement_requests(self, *args, **kwargs): - self._pending_requests.pop(kwargs.get("deferred", None), None) - -
[docs] def getChild(self, path, request): - """ - To make things work we nudge the url tree to make this the - root. - - Args: - path (str): Url path. - request (Request object): Incoming request. - - Notes: - We make sure to save the request queue so - that we can safely kill the threadpool - on a server reload. - - """ - path0 = request.prepath.pop(0) - request.postpath.insert(0, path0) - - request.notifyFinish().addErrback( - lambda f: 0 - # lambda f: logger.log_trace("%s\nCaught errback in webserver.py:" % f) - ) - - deferred = request.notifyFinish() - self._pending_requests[deferred] = deferred - deferred.addBoth(self._decrement_requests, deferred=deferred) - - return self.wsgi_resource
- - -# -# Site with deactivateable logging -# - - -
[docs]class Website(server.Site): - """ - This class will only log http requests if settings.DEBUG is True. - """ - - noisy = False - -
[docs] def logPrefix(self): - "How to be named in logs" - if hasattr(self, "is_portal") and self.is_portal: - return "Webserver-proxy" - return "Webserver"
- -
[docs] def log(self, request): - """Conditional logging""" - if _DEBUG: - server.Site.log(self, request)
- - -# -# Threaded Webserver -# - - -
[docs]class WSGIWebServer(internet.TCPServer): - """ - This is a WSGI webserver. It makes sure to start - the threadpool after the service itself started, - so as to register correctly with the twisted daemon. - - call with WSGIWebServer(threadpool, port, wsgi_resource) - - """ - -
[docs] def __init__(self, pool, *args, **kwargs): - """ - This just stores the threadpool. - - Args: - pool (ThreadPool): The twisted threadpool. - args, kwargs (any): Passed on to the TCPServer. - - """ - self.pool = pool - super().__init__(*args, **kwargs)
- -
[docs] def startService(self): - """ - Start the pool after the service starts. - - """ - super().startService() - self.pool.start()
- -
[docs] def stopService(self): - """ - Safely stop the pool after the service stops. - - """ - super().stopService() - self.pool.stop()
- - -
[docs]class PrivateStaticRoot(static.File): - """ - This overrides the default static file resource so as to not make the - directory listings public (that is, if you go to /media or /static you - won't see an index of all static/media files on the server). - - """ - -
[docs] def directoryListing(self): - return resource.ForbiddenResource()
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/typeclasses/attributes.html b/docs/0.9.5/_modules/evennia/typeclasses/attributes.html deleted file mode 100644 index 564a18e193..0000000000 --- a/docs/0.9.5/_modules/evennia/typeclasses/attributes.html +++ /dev/null @@ -1,1788 +0,0 @@ - - - - - - - - evennia.typeclasses.attributes — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.typeclasses.attributes

-"""
-Attributes are arbitrary data stored on objects. Attributes supports
-both pure-string values and pickled arbitrary data.
-
-Attributes are also used to implement Nicks. This module also contains
-the Attribute- and NickHandlers as well as the `NAttributeHandler`,
-which is a non-db version of Attributes.
-
-
-"""
-import re
-import fnmatch
-
-from collections import defaultdict
-
-from django.db import models
-from django.conf import settings
-from django.utils.encoding import smart_str
-
-from evennia.locks.lockhandler import LockHandler
-from evennia.utils.idmapper.models import SharedMemoryModel
-from evennia.utils.dbserialize import to_pickle, from_pickle
-from evennia.utils.picklefield import PickledObjectField
-from evennia.utils.utils import lazy_property, to_str, make_iter, is_iter
-
-_TYPECLASS_AGGRESSIVE_CACHE = settings.TYPECLASS_AGGRESSIVE_CACHE
-
-# -------------------------------------------------------------
-#
-#   Attributes
-#
-# -------------------------------------------------------------
-
-
-
[docs]class IAttribute: - """ - Attributes are things that are specific to different types of objects. For - example, a drink container needs to store its fill level, whereas an exit - needs to store its open/closed/locked/unlocked state. These are done via - attributes, rather than making different classes for each object type and - storing them directly. The added benefit is that we can add/remove - attributes on the fly as we like. - - The Attribute class defines the following properties: - - key (str): Primary identifier. - - lock_storage (str): Perm strings. - - model (str): A string defining the model this is connected to. This - is a natural_key, like "objects.objectdb" - - date_created (datetime): When the attribute was created. - - value (any): The data stored in the attribute, in pickled form - using wrappers to be able to store/retrieve models. - - strvalue (str): String-only data. This data is not pickled and - is thus faster to search for in the database. - - category (str): Optional character string for grouping the - Attribute. - - This class is an API/Interface/Abstract base class; do not instantiate it directly. - """ - -
[docs] @lazy_property - def locks(self): - return LockHandler(self)
- - key = property(lambda self: self.db_key) - strvalue = property(lambda self: self.db_strvalue) - category = property(lambda self: self.db_category) - model = property(lambda self: self.db_model) - attrtype = property(lambda self: self.db_attrtype) - date_created = property(lambda self: self.db_date_created) - - def __lock_storage_get(self): - return self.db_lock_storage - - def __lock_storage_set(self, value): - self.db_lock_storage = value - - def __lock_storage_del(self): - self.db_lock_storage = "" - - lock_storage = property(__lock_storage_get, __lock_storage_set, __lock_storage_del) - -
[docs] def access(self, accessing_obj, access_type="read", default=False, **kwargs): - """ - Determines if another object has permission to access. - - Args: - accessing_obj (object): Entity trying to access this one. - access_type (str, optional): Type of access sought, see - the lock documentation. - default (bool, optional): What result to return if no lock - of access_type was found. The default, `False`, means a lockdown - policy, only allowing explicit access. - kwargs (any, optional): Not used; here to make the API consistent with - other access calls. - - Returns: - result (bool): If the lock was passed or not. - - """ - result = self.locks.check(accessing_obj, access_type=access_type, default=default) - return result
- - # - # - # Attribute methods - # - # - - def __str__(self): - return smart_str("%s(%s)" % (self.db_key, self.id)) - - def __repr__(self): - return "%s(%s)" % (self.db_key, self.id)
- - -
[docs]class InMemoryAttribute(IAttribute): - """ - This Attribute is used purely for NAttributes/NAttributeHandler. It has no database backend. - - """ - - # Primary Key has no meaning for an InMemoryAttribute. This merely serves to satisfy other code. - -
[docs] def __init__(self, pk, **kwargs): - """ - Create an Attribute that exists only in Memory. - - Args: - pk (int): This is a fake 'primary key' / id-field. It doesn't actually have to be - unique, but is fed an incrementing number from the InMemoryBackend by default. This - is needed only so Attributes can be sorted. Some parts of the API also see the lack - of a .pk field as a sign that the Attribute was deleted. - **kwargs: Other keyword arguments are used to construct the actual Attribute. - - """ - self.id = pk - self.pk = pk - - # Copy all kwargs to local properties. We use db_ for compatability here. - for key, value in kwargs.items(): - # Value and locks are special. We must call the wrappers. - if key == "value": - self.value = value - elif key == "lock_storage": - self.lock_storage = value - else: - setattr(self, f"db_{key}", value)
- - # value property (wraps db_value) - def __value_get(self): - return self.db_value - - def __value_set(self, new_value): - self.db_value = new_value - - def __value_del(self): - pass - - value = property(__value_get, __value_set, __value_del)
- - -
[docs]class AttributeProperty: - """ - Attribute property descriptor. Allows for specifying Attributes as Django-like 'fields' - on the class level. Note that while one can set a lock on the Attribute, - there is no way to *check* said lock when accessing via the property - use - the full AttributeHandler if you need to do access checks. - - Example: - :: - - class Character(DefaultCharacter): - foo = AttributeProperty(default="Bar") - - """ - attrhandler_name = "attributes" - -
[docs] def __init__(self, default=None, category=None, strattr=False, lockstring="", - autocreate=False): - """ - Initialize an Attribute as a property descriptor. - - Keyword Args: - default (any): A default value if the attr is not set. - category (str): The attribute's category. If unset, use class default. - strattr (bool): If set, this Attribute *must* be a simple string, and will be - stored more efficiently. - lockstring (str): This is not itself useful with the property, but only if - using the full AttributeHandler.get(accessing_obj=...) to access the - Attribute. - autocreate (bool): If an un-found Attr should lead to auto-creating the - Attribute (with the default value). If `False`, the property will - return the default value until it has been explicitly set. This means - less database accesses, but also means the property will have no - corresponding Attribute if wanting to access it directly via the - AttributeHandler (it will also not show up in `examine`). - - """ - self._default = default - self._category = category - self._strattr = strattr - self._lockstring = lockstring - self._autocreate = autocreate - self._key = ""
- - def __set_name__(self, cls, name): - """ - Called when descriptor is first assigned to the class. It is called with - the name of the field. - - """ - self._key = name - - def __get__(self, instance, owner): - """ - Called when the attrkey is retrieved from the instance. - - """ - value = self._default - try: - value = ( - getattr(instance, self.attrhandler_name) - .get(key=self._key, - default=self._default, - category=self._category, - strattr=self._strattr, - raise_exception=self._autocreate) - ) - except AttributeError: - if self._autocreate: - # attribute didn't exist and autocreate is set - self.__set__(instance, self._default) - else: - raise - finally: - return value - - def __set__(self, instance, value): - """ - Called when assigning to the property (and when auto-creating an Attribute). - - """ - ( - getattr(instance, self.attrhandler_name) - .add(self._key, - value, - category=self._category, - lockstring=self._lockstring, - strattr=self._strattr) - ) - - def __delete__(self, instance): - """ - Called when running `del` on the field. Will remove/clear the Attribute. - - """ - ( - getattr(instance, self.attrhandler_name) - .remove(key=self._key, - category=self._category) - )
- - -
[docs]class NAttributeProperty(AttributeProperty): - """ - NAttribute property descriptor. Allows for specifying NAttributes as Django-like 'fields' - on the class level. - - Example: - :: - - class Character(DefaultCharacter): - foo = NAttributeProperty(default="Bar") - - """ - attrhandler_name = "nattributes"
- - -
[docs]class Attribute(IAttribute, SharedMemoryModel): - """ - This attribute is stored via Django. Most Attributes will be using this class. - - """ - - # - # Attribute Database Model setup - # - # These database fields are all set using their corresponding properties, - # named same as the field, but without the db_* prefix. - db_key = models.CharField("key", max_length=255, db_index=True) - db_value = PickledObjectField( - "value", - null=True, - help_text="The data returned when the attribute is accessed. Must be " - "written as a Python literal if editing through the admin " - "interface. Attribute values which are not Python literals " - "cannot be edited through the admin interface.", - ) - db_strvalue = models.TextField( - "strvalue", null=True, blank=True, help_text="String-specific storage for quick look-up" - ) - db_category = models.CharField( - "category", - max_length=128, - db_index=True, - blank=True, - null=True, - help_text="Optional categorization of attribute.", - ) - # Lock storage - db_lock_storage = models.TextField( - "locks", blank=True, help_text="Lockstrings for this object are stored here." - ) - db_model = models.CharField( - "model", - max_length=32, - db_index=True, - blank=True, - null=True, - help_text="Which model of object this attribute is attached to (A " - "natural key like 'objects.objectdb'). You should not change " - "this value unless you know what you are doing.", - ) - # subclass of Attribute (None or nick) - db_attrtype = models.CharField( - "attrtype", - max_length=16, - db_index=True, - blank=True, - null=True, - help_text="Subclass of Attribute (None or nick)", - ) - # time stamp - db_date_created = models.DateTimeField("date_created", editable=False, auto_now_add=True) - - # Database manager - # objects = managers.AttributeManager() - - class Meta: - "Define Django meta options" - verbose_name = "Attribute" - - # Wrapper properties to easily set database fields. These are - # @property decorators that allows to access these fields using - # normal python operations (without having to remember to save() - # etc). So e.g. a property 'attr' has a get/set/del decorator - # defined that allows the user to do self.attr = value, - # value = self.attr and del self.attr respectively (where self - # is the object in question). - - # lock_storage wrapper. Overloaded for saving to database. - def __lock_storage_get(self): - return self.db_lock_storage - - def __lock_storage_set(self, value): - self.db_lock_storage = value - self.save(update_fields=["db_lock_storage"]) - - def __lock_storage_del(self): - self.db_lock_storage = '' - self.save(update_fields=["db_lock_storage"]) - - lock_storage = property(__lock_storage_get, __lock_storage_set, __lock_storage_del) - - # value property (wraps db_value) - @property - def value(self): - """ - Getter. Allows for `value = self.value`. - We cannot cache here since it makes certain cases (such - as storing a dbobj which is then deleted elsewhere) out-of-sync. - The overhead of unpickling seems hard to avoid. - """ - return from_pickle(self.db_value, db_obj=self) - - @value.setter - def value(self, new_value): - """ - Setter. Allows for self.value = value. We cannot cache here, - see self.__value_get. - """ - self.db_value = to_pickle(new_value) - self.save(update_fields=["db_value"]) - - @value.deleter - def value(self): - """Deleter. Allows for del attr.value. This removes the entire attribute.""" - self.delete()
- -# -# Handlers making use of the Attribute model -# - - -
[docs]class IAttributeBackend: - """ - Abstract interface for the backends used by the Attribute Handler. - - All Backends must implement this base class. - """ - - _attrcreate = "attrcreate" - _attredit = "attredit" - _attrread = "attrread" - _attrclass = None - -
[docs] def __init__(self, handler, attrtype): - self.handler = handler - self.obj = handler.obj - self._attrtype = attrtype - self._objid = handler.obj.id - self._cache = {} - # store category names fully cached - self._catcache = {} - # full cache was run on all attributes - self._cache_complete = False
- -
[docs] def query_all(self): - """ - Fetch all Attributes from this object. - - Returns: - attrlist (list): A list of Attribute objects. - """ - raise NotImplementedError()
- -
[docs] def query_key(self, key, category): - """ - - Args: - key (str): The key of the Attribute being searched for. - category (str or None): The category of the desired Attribute. - - Returns: - attribute (IAttribute): A single Attribute. - """ - raise NotImplementedError()
- -
[docs] def query_category(self, category): - """ - Returns every matching Attribute as a list, given a category. - - This method calls up whatever storage the backend uses. - - Args: - category (str or None): The category to query. - - Returns: - attrs (list): The discovered Attributes. - """ - raise NotImplementedError()
- - def _full_cache(self): - """Cache all attributes of this object""" - if not _TYPECLASS_AGGRESSIVE_CACHE: - return - attrs = self.query_all() - self._cache = { - f"{to_str(attr.key).lower()}-{attr.category.lower() if attr.category else None}": attr - for attr in attrs - } - self._cache_complete = True - - def _get_cache_key(self, key, category): - """ - Fetch cache key. - - Args: - key (str): The key of the Attribute being searched for. - category (str or None): The category of the desired Attribute. - - Returns: - attribute (IAttribute): A single Attribute. - """ - cachekey = "%s-%s" % (key, category) - cachefound = False - try: - attr = _TYPECLASS_AGGRESSIVE_CACHE and self._cache[cachekey] - cachefound = True - except KeyError: - attr = None - - if attr and (not hasattr(attr, "pk") and attr.pk is None): - # clear out Attributes deleted from elsewhere. We must search this anew. - attr = None - cachefound = False - del self._cache[cachekey] - if cachefound and _TYPECLASS_AGGRESSIVE_CACHE: - if attr: - return [attr] # return cached entity - else: - return [] # no such attribute: return an empty list - else: - conn = self.query_key(key, category) - if conn: - attr = conn[0].attribute - if _TYPECLASS_AGGRESSIVE_CACHE: - self._cache[cachekey] = attr - return [attr] if attr.pk else [] - else: - # There is no such attribute. We will explicitly save that - # in our cache to avoid firing another query if we try to - # retrieve that (non-existent) attribute again. - if _TYPECLASS_AGGRESSIVE_CACHE: - self._cache[cachekey] = None - return [] - - def _get_cache_category(self, category): - """ - Retrieves Attribute list (by category) from cache. - - Args: - category (str or None): The category to query. - - Returns: - attrs (list): The discovered Attributes. - """ - catkey = "-%s" % category - if _TYPECLASS_AGGRESSIVE_CACHE and catkey in self._catcache: - return [attr for key, attr in self._cache.items() if key.endswith(catkey) and attr] - else: - # we have to query to make this category up-date in the cache - attrs = self.query_category(category) - if _TYPECLASS_AGGRESSIVE_CACHE: - for attr in attrs: - if attr.pk: - cachekey = "%s-%s" % (attr.key, category) - self._cache[cachekey] = attr - # mark category cache as up-to-date - self._catcache[catkey] = True - return attrs - - def _get_cache(self, key=None, category=None): - """ - Retrieve from cache or database (always caches) - - Args: - key (str, optional): Attribute key to query for - category (str, optional): Attribiute category - - Returns: - args (list): Returns a list of zero or more matches - found from cache or database. - Notes: - When given a category only, a search for all objects - of that cateogory is done and the category *name* is - stored. This tells the system on subsequent calls that the - list of cached attributes of this category is up-to-date - and that the cache can be queried for category matches - without missing any. - The TYPECLASS_AGGRESSIVE_CACHE=False setting will turn off - caching, causing each attribute access to trigger a - database lookup. - - """ - key = key.strip().lower() if key else None - category = category.strip().lower() if category is not None else None - if key: - return self._get_cache_key(key, category) - return self._get_cache_category(category) - -
[docs] def get(self, key=None, category=None): - """ - Frontend for .get_cache. Retrieves Attribute(s). - - Args: - key (str, optional): Attribute key to query for - category (str, optional): Attribiute category - - Returns: - args (list): Returns a list of zero or more matches - found from cache or database. - """ - return self._get_cache(key, category)
- - def _set_cache(self, key, category, attr_obj): - """ - Update cache. - - Args: - key (str): A cleaned key string - category (str or None): A cleaned category name - attr_obj (IAttribute): The newly saved attribute - - """ - if not _TYPECLASS_AGGRESSIVE_CACHE: - return - if not key: # don't allow an empty key in cache - return - cachekey = "%s-%s" % (key, category) - catkey = "-%s" % category - self._cache[cachekey] = attr_obj - # mark that the category cache is no longer up-to-date - self._catcache.pop(catkey, None) - self._cache_complete = False - - def _delete_cache(self, key, category): - """ - Remove attribute from cache - - Args: - key (str): A cleaned key string - category (str or None): A cleaned category name - - """ - catkey = "-%s" % category - if key: - cachekey = "%s-%s" % (key, category) - self._cache.pop(cachekey, None) - else: - self._cache = { - key: attrobj - for key, attrobj in list(self._cache.items()) - if not key.endswith(catkey) - } - # mark that the category cache is no longer up-to-date - self._catcache.pop(catkey, None) - self._cache_complete = False - -
[docs] def reset_cache(self): - """ - Reset cache from the outside. - """ - self._cache_complete = False - self._cache = {} - self._catcache = {}
- -
[docs] def do_create_attribute(self, key, category, lockstring, value, strvalue): - """ - Does the hard work of actually creating Attributes, whatever is needed. - - Args: - key (str): The Attribute's key. - category (str or None): The Attribute's category, or None - lockstring (str): Any locks for the Attribute. - value (obj): The Value of the Attribute. - strvalue (bool): Signifies if this is a strvalue Attribute. Value MUST be a string or - this will lead to Trouble. Ignored for InMemory attributes. - - Returns: - attr (IAttribute): The new Attribute. - """ - raise NotImplementedError()
- -
[docs] def create_attribute(self, key, category, lockstring, value, strvalue=False, cache=True): - """ - Creates Attribute (using the class specified for the backend), (optionally) caches it, and - returns it. - - This MUST actively save the Attribute to whatever database backend is used, AND - call self.set_cache(key, category, new_attrobj) - - Args: - key (str): The Attribute's key. - category (str or None): The Attribute's category, or None - lockstring (str): Any locks for the Attribute. - value (obj): The Value of the Attribute. - strvalue (bool): Signifies if this is a strvalue Attribute. Value MUST be a string or - this will lead to Trouble. Ignored for InMemory attributes. - cache (bool): Whether to cache the new Attribute - - Returns: - attr (IAttribute): The new Attribute. - """ - attr = self.do_create_attribute(key, category, lockstring, value, strvalue) - if cache: - self._set_cache(key, category, attr) - return attr
- -
[docs] def do_update_attribute(self, attr, value): - """ - Simply sets a new Value to an Attribute. - - Args: - attr (IAttribute): The Attribute being changed. - value (obj): The Value for the Attribute. - - """ - raise NotImplementedError()
- -
[docs] def do_batch_update_attribute(self, attr_obj, category, lock_storage, new_value, strvalue): - """ - Called opnly by batch add. For the database backend, this is a method - of updating that can alter category and lock-storage. - - Args: - attr_obj (IAttribute): The Attribute being altered. - category (str or None): The attribute's (new) category. - lock_storage (str): The attribute's new locks. - new_value (obj): The Attribute's new value. - strvalue (bool): Signifies if this is a strvalue Attribute. Value MUST be a string or - this will lead to Trouble. Ignored for InMemory attributes. - """ - raise NotImplementedError()
- -
[docs] def do_batch_finish(self, attr_objs): - """ - Called after batch_add completed. Used for handling database operations - and/or caching complications. - - Args: - attr_objs (list of IAttribute): The Attributes created/updated thus far. - - """ - raise NotImplementedError()
- -
[docs] def batch_add(self, *args, **kwargs): - """ - Batch-version of `.add()`. This is more efficient than repeat-calling - `.add` when having many Attributes to add. - - Args: - *args (tuple): Tuples of varying length representing the - Attribute to add to this object. Supported tuples are - - - (key, value) - - (key, value, category) - - (key, value, category, lockstring) - - (key, value, category, lockstring, default_access) - - Raises: - RuntimeError: If trying to pass a non-iterable as argument. - - Notes: - The indata tuple order matters, so if you want a lockstring but no - category, set the category to `None`. This method does not have the - ability to check editing permissions and is mainly used internally. - It does not use the normal `self.add` but applies the Attributes - directly to the database. - - """ - new_attrobjs = [] - strattr = kwargs.get("strattr", False) - for tup in args: - if not is_iter(tup) or len(tup) < 2: - raise RuntimeError("batch_add requires iterables as arguments (got %r)." % tup) - ntup = len(tup) - keystr = str(tup[0]).strip().lower() - new_value = tup[1] - category = str(tup[2]).strip().lower() if ntup > 2 and tup[2] is not None else None - lockstring = tup[3] if ntup > 3 else "" - - attr_objs = self._get_cache(keystr, category) - - if attr_objs: - attr_obj = attr_objs[0] - # update an existing attribute object - self.do_batch_update_attribute(attr_obj, category, lockstring, new_value, strattr) - else: - new_attr = self.do_create_attribute( - keystr, category, lockstring, new_value, strvalue=strattr - ) - new_attrobjs.append(new_attr) - if new_attrobjs: - self.do_batch_finish(new_attrobjs)
- -
[docs] def do_delete_attribute(self, attr): - """ - Does the hard work of actually deleting things. - - Args: - attr (IAttribute): The attribute to delete. - """ - raise NotImplementedError()
- -
[docs] def delete_attribute(self, attr): - """ - Given an Attribute, deletes it. Also remove it from cache. - - Args: - attr (IAttribute): The attribute to delete. - """ - if not attr: - return - self._delete_cache(attr.key, attr.category) - self.do_delete_attribute(attr)
- -
[docs] def update_attribute(self, attr, value): - """ - Simply updates an Attribute. - - Args: - attr (IAttribute): The attribute to delete. - value (obj): The new value. - """ - self.do_update_attribute(attr, value)
- -
[docs] def do_batch_delete(self, attribute_list): - """ - Given a list of attributes, deletes them all. - The default implementation is fine, but this is overridable since some databases may allow - for a better method. - - Args: - attribute_list (list of IAttribute): - """ - for attribute in attribute_list: - self.delete_attribute(attribute)
- -
[docs] def clear_attributes(self, category, accessing_obj, default_access): - """ - Remove all Attributes on this object. - - Args: - category (str, optional): If given, clear only Attributes - of this category. - accessing_obj (object, optional): If given, check the - `attredit` lock on each Attribute before continuing. - default_access (bool, optional): Use this permission as - fallback if `access_obj` is given but there is no lock of - type `attredit` on the Attribute in question. - - """ - category = category.strip().lower() if category is not None else None - - if not self._cache_complete: - self._full_cache() - - if category is not None: - attrs = [attr for attr in self._cache.values() if attr.category == category] - else: - attrs = self._cache.values() - - if accessing_obj: - self.do_batch_delete( - [ - attr - for attr in attrs - if attr.access(accessing_obj, self._attredit, default=default_access) - ] - ) - else: - # have to cast the results to a list or we'll get a RuntimeError for removing from the - # dict we're iterating - self.do_batch_delete(list(attrs)) - self.reset_cache()
- -
[docs] def get_all_attributes(self): - """ - Simply returns all Attributes of this object, sorted by their IDs. - - Returns: - attributes (list of IAttribute) - """ - if _TYPECLASS_AGGRESSIVE_CACHE: - if not self._cache_complete: - self._full_cache() - return sorted([attr for attr in self._cache.values() if attr], key=lambda o: o.id) - else: - return sorted([attr for attr in self.query_all() if attr], key=lambda o: o.id)
- - -
[docs]class InMemoryAttributeBackend(IAttributeBackend): - """ - This Backend for Attributes stores NOTHING in the database. Everything is kept in memory, and - normally lost on a crash, reload, shared memory flush, etc. It generates IDs for the Attributes - it manages, but these are of little importance beyond sorting and satisfying the caching logic - to know an Attribute hasn't been deleted out from under the cache's nose. - - """ - - _attrclass = InMemoryAttribute - -
[docs] def __init__(self, handler, attrtype): - super().__init__(handler, attrtype) - self._storage = dict() - self._category_storage = defaultdict(list) - self._id_counter = 0
- - def _next_id(self): - """ - Increments the internal ID counter and returns the new value. - - Returns: - next_id (int): A simple integer. - """ - self._id_counter += 1 - return self._id_counter - -
[docs] def query_all(self): - return self._storage.values()
- -
[docs] def query_key(self, key, category): - found = self._storage.get((key, category), None) - if found: - return [found] - return []
- -
[docs] def query_category(self, category): - if category is None: - return self._storage.values() - return self._category_storage.get(category, [])
- -
[docs] def do_create_attribute(self, key, category, lockstring, value, strvalue): - """ - See parent class. - - strvalue has no meaning for InMemory attributes. - - """ - new_attr = self._attrclass( - pk=self._next_id(), key=key, category=category, lock_storage=lockstring, value=value - ) - self._storage[(key, category)] = new_attr - self._category_storage[category].append(new_attr) - return new_attr
- -
[docs] def do_update_attribute(self, attr, value): - attr.value = value
- -
[docs] def do_batch_update_attribute(self, attr_obj, category, lock_storage, new_value, strvalue): - """ - No need to bother saving anything. Just set some values. - """ - attr_obj.db_category = category - attr_obj.db_lock_storage = lock_storage if lock_storage else "" - attr_obj.value = new_value
- -
[docs] def do_batch_finish(self, attr_objs): - """ - Nothing to do here for In-Memory. - - Args: - attr_objs (list of IAttribute): The Attributes created/updated thus far. - """ - pass
- -
[docs] def do_delete_attribute(self, attr): - """ - Removes the Attribute from local storage. Once it's out of the cache, garbage collection - will handle the rest. - - Args: - attr (IAttribute): The attribute to delete. - """ - del self._storage[(attr.key, attr.category)] - self._category_storage[attr.category].remove(attr)
- - -
[docs]class ModelAttributeBackend(IAttributeBackend): - """ - Uses Django models for storing Attributes. - """ - - _attrclass = Attribute - _m2m_fieldname = "db_attributes" - -
[docs] def __init__(self, handler, attrtype): - super().__init__(handler, attrtype) - self._model = to_str(handler.obj.__dbclass__.__name__.lower())
- -
[docs] def query_all(self): - query = { - "%s__id" % self._model: self._objid, - "attribute__db_model__iexact": self._model, - "attribute__db_attrtype": self._attrtype, - } - return [ - conn.attribute - for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query) - ]
- -
[docs] def query_key(self, key, category): - query = { - "%s__id" % self._model: self._objid, - "attribute__db_model__iexact": self._model, - "attribute__db_attrtype": self._attrtype, - "attribute__db_key__iexact": key.lower(), - "attribute__db_category__iexact": category.lower() if category else None, - } - if not self.obj.pk: - return [] - return getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query)
- -
[docs] def query_category(self, category): - query = { - "%s__id" % self._model: self._objid, - "attribute__db_model__iexact": self._model, - "attribute__db_attrtype": self._attrtype, - "attribute__db_category__iexact": category.lower() if category else None, - } - return [ - conn.attribute - for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query) - ]
- -
[docs] def do_create_attribute(self, key, category, lockstring, value, strvalue): - kwargs = { - "db_key": key, - "db_category": category, - "db_model": self._model, - "db_lock_storage": lockstring if lockstring else "", - "db_attrtype": self._attrtype, - } - if strvalue: - kwargs["db_value"] = None - kwargs["db_strvalue"] = value - else: - kwargs["db_value"] = to_pickle(value) - kwargs["db_strvalue"] = None - new_attr = self._attrclass(**kwargs) - new_attr.save() - getattr(self.obj, self._m2m_fieldname).add(new_attr) - self._set_cache(key, category, new_attr) - return new_attr
- -
[docs] def do_update_attribute(self, attr, value): - attr.value = value
- -
[docs] def do_batch_update_attribute(self, attr_obj, category, lock_storage, new_value, strvalue): - attr_obj.db_category = category - attr_obj.db_lock_storage = lock_storage if lock_storage else "" - if strvalue: - # store as a simple string (will not notify OOB handlers) - attr_obj.db_strvalue = new_value - attr_obj.value = None - else: - # store normally (this will also notify OOB handlers) - attr_obj.value = new_value - attr_obj.db_strvalue = None - attr_obj.save(update_fields=["db_strvalue", "db_value", "db_category", "db_lock_storage"])
- -
[docs] def do_batch_finish(self, attr_objs): - # Add new objects to m2m field all at once - getattr(self.obj, self._m2m_fieldname).add(*attr_objs)
- -
[docs] def do_delete_attribute(self, attr): - try: - attr.delete() - except AssertionError: - # This could happen if the Attribute has already been deleted. - pass
- - -
[docs]class AttributeHandler: - """ - Handler for adding Attributes to the object. - """ - - _attrcreate = "attrcreate" - _attredit = "attredit" - _attrread = "attrread" - _attrtype = None - -
[docs] def __init__(self, obj, backend_class): - """ - Setup the AttributeHandler. - - Args: - obj (TypedObject): An Account, Object, Channel, ServerSession (not technically a typed - object), etc. backend_class (IAttributeBackend class): The class of the backend to - use. - """ - self.obj = obj - self.backend = backend_class(self, self._attrtype)
- -
[docs] def has(self, key=None, category=None): - """ - Checks if the given Attribute (or list of Attributes) exists on - the object. - - Args: - key (str or iterable): The Attribute key or keys to check for. - If `None`, search by category. - category (str or None): Limit the check to Attributes with this - category (note, that `None` is the default category). - - Returns: - has_attribute (bool or list): If the Attribute exists on - this object or not. If `key` was given as an iterable then - the return is a list of booleans. - - """ - ret = [] - category = category.strip().lower() if category is not None else None - for keystr in make_iter(key): - keystr = key.strip().lower() - ret.extend(bool(attr) for attr in self.backend.get(keystr, category)) - return ret[0] if len(ret) == 1 else ret
- -
[docs] def get( - self, - key=None, - default=None, - category=None, - return_obj=False, - strattr=False, - raise_exception=False, - accessing_obj=None, - default_access=True, - return_list=False, - ): - """ - Get the Attribute. - - Args: - key (str or list, optional): the attribute identifier or - multiple attributes to get. if a list of keys, the - method will return a list. - default (any, optional): The value to return if an - Attribute was not defined. If set, it will be returned in - a one-item list. - category (str, optional): the category within which to - retrieve attribute(s). - return_obj (bool, optional): If set, the return is not the value of the - Attribute but the Attribute object itself. - strattr (bool, optional): Return the `strvalue` field of - the Attribute rather than the usual `value`, this is a - string-only value for quick database searches. - raise_exception (bool, optional): When an Attribute is not - found, the return from this is usually `default`. If this - is set, an exception is raised instead. - accessing_obj (object, optional): If set, an `attrread` - permission lock will be checked before returning each - looked-after Attribute. - default_access (bool, optional): If no `attrread` lock is set on - object, this determines if the lock should then be passed or not. - return_list (bool, optional): Always return a list, also if there is only - one or zero matches found. - - Returns: - result (any or list): One or more matches for keys and/or - categories. Each match will be the value of the found Attribute(s) - unless `return_obj` is True, at which point it will be the - attribute object itself or None. If `return_list` is True, this - will always be a list, regardless of the number of elements. - - Raises: - AttributeError: If `raise_exception` is set and no matching Attribute - was found matching `key`. - - """ - - ret = [] - for keystr in make_iter(key): - # it's okay to send a None key - attr_objs = self.backend.get(keystr, category) - if attr_objs: - ret.extend(attr_objs) - elif raise_exception: - raise AttributeError - elif return_obj: - ret.append(None) - - if accessing_obj: - # check 'attrread' locks - ret = [ - attr - for attr in ret - if attr.access(accessing_obj, self._attrread, default=default_access) - ] - if strattr: - ret = ret if return_obj else [attr.strvalue for attr in ret if attr] - else: - ret = ret if return_obj else [attr.value for attr in ret if attr] - - if return_list: - return ret if ret else [default] if default is not None else [] - return ret[0] if ret and len(ret) == 1 else ret or default
- -
[docs] def add( - self, - key, - value, - category=None, - lockstring="", - strattr=False, - accessing_obj=None, - default_access=True, - ): - """ - Add attribute to object, with optional `lockstring`. - - Args: - key (str): An Attribute name to add. - value (any or str): The value of the Attribute. If - `strattr` keyword is set, this *must* be a string. - category (str, optional): The category for the Attribute. - The default `None` is the normal category used. - lockstring (str, optional): A lock string limiting access - to the attribute. - strattr (bool, optional): Make this a string-only Attribute. - This is only ever useful for optimization purposes. - accessing_obj (object, optional): An entity to check for - the `attrcreate` access-type. If not passing, this method - will be exited. - default_access (bool, optional): What access to grant if - `accessing_obj` is given but no lock of the type - `attrcreate` is defined on the Attribute in question. - - """ - if accessing_obj and not self.obj.access( - accessing_obj, self._attrcreate, default=default_access - ): - # check create access - return - - if not key: - return - - category = category.strip().lower() if category is not None else None - keystr = key.strip().lower() - attr_obj = self.backend.get(key, category) - - if attr_obj: - # update an existing attribute object - attr_obj = attr_obj[0] - self.backend.update_attribute(attr_obj, value) - else: - # create a new Attribute (no OOB handlers can be notified) - self.backend.create_attribute(keystr, category, lockstring, value, strattr)
- -
[docs] def batch_add(self, *args, **kwargs): - """ - Batch-version of `add()`. This is more efficient than - repeat-calling add when having many Attributes to add. - - Args: - *args (tuple): Each argument should be a tuples (can be of varying - length) representing the Attribute to add to this object. - Supported tuples are - - - (key, value) - - (key, value, category) - - (key, value, category, lockstring) - - (key, value, category, lockstring, default_access) - - Keyword Args: - strattr (bool): If `True`, value must be a string. This - will save the value without pickling which is less - flexible but faster to search (not often used except - internally). - - Raises: - RuntimeError: If trying to pass a non-iterable as argument. - - Notes: - The indata tuple order matters, so if you want a lockstring - but no category, set the category to `None`. This method - does not have the ability to check editing permissions like - normal .add does, and is mainly used internally. It does not - use the normal self.add but apply the Attributes directly - to the database. - - """ - self.backend.batch_add(*args, **kwargs)
- -
[docs] def remove( - self, - key=None, - category=None, - raise_exception=False, - accessing_obj=None, - default_access=True, - ): - """ - Remove attribute or a list of attributes from object. - - Args: - key (str or list, optional): An Attribute key to remove or a list of keys. If - multiple keys, they must all be of the same `category`. If None and - category is not given, remove all Attributes. - category (str, optional): The category within which to - remove the Attribute. - raise_exception (bool, optional): If set, not finding the - Attribute to delete will raise an exception instead of - just quietly failing. - accessing_obj (object, optional): An object to check - against the `attredit` lock. If not given, the check will - be skipped. - default_access (bool, optional): The fallback access to - grant if `accessing_obj` is given but there is no - `attredit` lock set on the Attribute in question. - - Raises: - AttributeError: If `raise_exception` is set and no matching Attribute - was found matching `key`. - - Notes: - If neither key nor category is given, this acts as clear(). - - """ - - if key is None: - self.clear( - category=category, accessing_obj=accessing_obj, default_access=default_access - ) - return - - category = category.strip().lower() if category is not None else None - - for keystr in make_iter(key): - keystr = keystr.lower() - - attr_objs = self.backend.get(keystr, category) - for attr_obj in attr_objs: - if not ( - accessing_obj - and not attr_obj.access(accessing_obj, self._attredit, default=default_access) - ): - self.backend.delete_attribute(attr_obj) - if not attr_objs and raise_exception: - raise AttributeError
- -
[docs] def clear(self, category=None, accessing_obj=None, default_access=True): - """ - Remove all Attributes on this object. - - Args: - category (str, optional): If given, clear only Attributes - of this category. - accessing_obj (object, optional): If given, check the - `attredit` lock on each Attribute before continuing. - default_access (bool, optional): Use this permission as - fallback if `access_obj` is given but there is no lock of - type `attredit` on the Attribute in question. - - """ - self.backend.clear_attributes(category, accessing_obj, default_access)
- -
[docs] def all(self, accessing_obj=None, default_access=True): - """ - Return all Attribute objects on this object, regardless of category. - - Args: - accessing_obj (object, optional): Check the `attrread` - lock on each attribute before returning them. If not - given, this check is skipped. - default_access (bool, optional): Use this permission as a - fallback if `accessing_obj` is given but one or more - Attributes has no lock of type `attrread` defined on them. - - Returns: - Attributes (list): All the Attribute objects (note: Not - their values!) in the handler. - - """ - attrs = self.backend.get_all_attributes() - - if accessing_obj: - return [ - attr - for attr in attrs - if attr.access(accessing_obj, self._attrread, default=default_access) - ] - else: - return attrs
- -
[docs] def reset_cache(self): - self.backend.reset_cache()
- - -# DbHolders for .db and .ndb properties on Typeclasses. - -_GA = object.__getattribute__ -_SA = object.__setattr__ - - -
[docs]class DbHolder: - "Holder for allowing property access of attributes" - -
[docs] def __init__(self, obj, name, manager_name="attributes"): - _SA(self, name, _GA(obj, manager_name)) - _SA(self, "name", name)
- - def __getattribute__(self, attrname): - if attrname == "all": - # we allow to overload our default .all - attr = _GA(self, _GA(self, "name")).get("all") - return attr if attr else _GA(self, "all") - return _GA(self, _GA(self, "name")).get(attrname) - - def __setattr__(self, attrname, value): - _GA(self, _GA(self, "name")).add(attrname, value) - - def __delattr__(self, attrname): - _GA(self, _GA(self, "name")).remove(attrname) - -
[docs] def get_all(self): - return _GA(self, _GA(self, "name")).backend.get_all_attributes()
- - all = property(get_all)
- - -# -# Nick templating -# - -""" -This supports the use of replacement templates in nicks: - -This happens in two steps: - -1) The user supplies a template that is converted to a regex according - to the unix-like templating language. -2) This regex is tested against nicks depending on which nick replacement - strategy is considered (most commonly inputline). -3) If there is a template match and there are templating markers, - these are replaced with the arguments actually given. - -@desc $1 $2 $3 - -This will be converted to the following regex: - - \@desc (?P<1>\w+) (?P<2>\w+) $(?P<3>\w+) - -Supported template markers (through fnmatch) - * matches anything (non-greedy) -> .*? - ? matches any single character -> - [seq] matches any entry in sequence - [!seq] matches entries not in sequence -Custom arg markers - $N argument position (1-99) - -""" -_RE_OR = re.compile(r"(?<!\\)\|") -_RE_NICK_RE_ARG = re.compile(r"arg([1-9][0-9]?)") -_RE_NICK_ARG = re.compile(r"\\(\$)([1-9][0-9]?)") -_RE_NICK_RAW_ARG = re.compile(r"(\$)([1-9][0-9]?)") -_RE_NICK_SPACE = re.compile(r"\\ ") - - -
[docs]class NickTemplateInvalid(ValueError): - pass
- - -
[docs]def initialize_nick_templates(pattern, replacement, pattern_is_regex=False): - """ - Initialize the nick templates for matching and remapping a string. - - Args: - pattern (str): The pattern to be used for nick recognition. This will - be parsed for shell patterns into a regex, unless `pattern_is_regex` - is `True`, in which case it must be an already valid regex string. In - this case, instead of `$N`, numbered arguments must instead be given - as matching groups named as `argN`, such as `(?P<arg1>.+?)`. - replacement (str): The template to be used to replace the string - matched by the pattern. This can contain `$N` markers and is never - parsed into a regex. - pattern_is_regex (bool): If set, `pattern` is a full regex string - instead of containing shell patterns. - - Returns: - regex, template (str): Regex to match against strings and template - with markers ``{arg1}, {arg2}``, etc for replacement using the standard - `.format` method. - - Raises: - evennia.typecalasses.attributes.NickTemplateInvalid: If the in/out - template does not have a matching number of `$args`. - - Examples: - - `pattern` (shell syntax): `"grin $1"` - - `pattern` (regex): `"grin (?P<arg1.+?>)"` - - `replacement`: `"emote gives a wicked grin to $1"` - - """ - - # create the regex from the pattern - if pattern_is_regex: - # Note that for a regex we can't validate in the way we do for the shell - # pattern, since you may have complex OR statements or optional arguments. - - # Explicit regex given from the onset - this already contains argN - # groups. we need to split out any | - separated parts so we can - # attach the line-break/ending extras all regexes require. - pattern_regex_string = r"|".join( - or_part + r"(?:[\n\r]*?)\Z" - for or_part in _RE_OR.split(pattern)) - - else: - # Shell pattern syntax - convert $N to argN groups - # for the shell pattern we make sure we have matching $N on both sides - pattern_args = [match.group(1) for match in _RE_NICK_RAW_ARG.finditer(pattern)] - replacement_args = [ - match.group(1) for match in _RE_NICK_RAW_ARG.finditer(replacement)] - if set(pattern_args) != set(replacement_args): - # We don't have the same amount of argN/$N tags in input/output. - raise NickTemplateInvalid("Nicks: Both in/out-templates must contain the same $N tags.") - - # generate regex from shell pattern - pattern_regex_string = fnmatch.translate(pattern) - pattern_regex_string = _RE_NICK_SPACE.sub(r"\\s+", pattern_regex_string) - pattern_regex_string = _RE_NICK_ARG.sub( - lambda m: "(?P<arg%s>.+?)" % m.group(2), pattern_regex_string) - # we must account for a possible line break coming over the wire - pattern_regex_string = pattern_regex_string[:-2] + r"(?:[\n\r]*?)\Z" - - # map the replacement to match the arg1 group-names, to make replacement easy - replacement_string = _RE_NICK_RAW_ARG.sub(lambda m: "{arg%s}" % m.group(2), replacement) - - return pattern_regex_string, replacement_string
- - -
[docs]def parse_nick_template(string, template_regex, outtemplate): - """ - Parse a text using a template and map it to another template - - Args: - string (str): The input string to process - template_regex (regex): A template regex created with - initialize_nick_template. - outtemplate (str): The template to which to map the matches - produced by the template_regex. This should have $1, $2, - etc to match the template-regex. Un-found $N-markers (possible if - the regex has optional matching groups) are replaced with empty - strings. - - """ - match = template_regex.match(string) - if match: - matchdict = {key: value if value is not None else "" - for key, value in match.groupdict().items()} - return True, outtemplate.format(**matchdict) - return False, string
- - -
[docs]class NickHandler(AttributeHandler): - """ - Handles the addition and removal of Nicks. Nicks are special - versions of Attributes with an `_attrtype` hardcoded to `nick`. - They also always use the `strvalue` fields for their data. - - """ - - _attrtype = "nick" - -
[docs] def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._regex_cache = {}
- -
[docs] def has(self, key, category="inputline"): - """ - Args: - key (str or iterable): The Nick key or keys to check for. - category (str): Limit the check to Nicks with this - category (note, that `None` is the default category). - - Returns: - has_nick (bool or list): If the Nick exists on this object - or not. If `key` was given as an iterable then the return - is a list of booleans. - - """ - return super().has(key, category=category)
- -
[docs] def get(self, key=None, category="inputline", return_tuple=False, **kwargs): - """ - Get the replacement value matching the given key and category - - Args: - key (str or list, optional): the attribute identifier or - multiple attributes to get. if a list of keys, the - method will return a list. - category (str, optional): the category within which to - retrieve the nick. The "inputline" means replacing data - sent by the user. - return_tuple (bool, optional): return the full nick tuple rather - than just the replacement. For non-template nicks this is just - a string. - kwargs (any, optional): These are passed on to `AttributeHandler.get`. - - Returns: - str or tuple: The nick replacement string or nick tuple. - - """ - if return_tuple or "return_obj" in kwargs: - return super().get(key=key, category=category, **kwargs) - else: - retval = super().get(key=key, category=category, **kwargs) - if retval: - return ( - retval[3] - if isinstance(retval, tuple) - else [tup[3] for tup in make_iter(retval)] - ) - return None
- -
[docs] def add(self, pattern, replacement, category="inputline", pattern_is_regex=False, **kwargs): - """ - Add a new nick, a mapping pattern -> replacement. - - Args: - pattern (str): A pattern to match for. This will be parsed for - shell patterns using the `fnmatch` library and can contain - `$N`-markers to indicate the locations of arguments to catch. If - `pattern_is_regex=True`, this must instead be a valid regular - expression and the `$N`-markers must be named `argN` that matches - numbered regex groups (see examples). - replacement (str): The string (or template) to replace `key` with - (the "nickname"). This may contain `$N` markers to indicate where to - place the argument-matches - category (str, optional): the category within which to - retrieve the nick. The "inputline" means replacing data - sent by the user. - pattern_is_regex (bool): If `True`, the `pattern` will be parsed as a - raw regex string. Instead of using `$N` markers in this string, one - then must mark numbered arguments as a named regex-groupd named `argN`. - For example, `(?P<arg1>.+?)` will match the behavior of using `$1` - in the shell pattern. - **kwargs (any, optional): These are passed on to `AttributeHandler.get`. - - Notes: - For most cases, the shell-pattern is much shorter and easier. The - regex pattern form can be useful for more complex matchings though, - for example in order to add optional arguments, such as with - `(?P<argN>.*?)`. - - Example: - - pattern (default shell syntax): `"gr $1 at $2"` - - pattern (with pattern_is_regex=True): `r"gr (?P<arg1>.+?) at (?P<arg2>.+?)"` - - replacement: `"emote With a flourish, $1 grins at $2."` - - """ - nick_regex, nick_template = initialize_nick_templates( - pattern, replacement, pattern_is_regex=pattern_is_regex) - super().add(pattern, (nick_regex, nick_template, pattern, replacement), - category=category, **kwargs)
- -
[docs] def remove(self, key, category="inputline", **kwargs): - """ - Remove Nick with matching category. - - Args: - key (str): A key for the nick to match for. - category (str, optional): the category within which to - removethe nick. The "inputline" means replacing data - sent by the user. - kwargs (any, optional): These are passed on to `AttributeHandler.get`. - - """ - super().remove(key, category=category, **kwargs)
- -
[docs] def nickreplace(self, raw_string, categories=("inputline", "channel"), include_account=True): - """ - Apply nick replacement of entries in raw_string with nick replacement. - - Args: - raw_string (str): The string in which to perform nick - replacement. - categories (tuple, optional): Replacement categories in - which to perform the replacement, such as "inputline", - "channel" etc. - include_account (bool, optional): Also include replacement - with nicks stored on the Account level. - kwargs (any, optional): Not used. - - Returns: - string (str): A string with matching keys replaced with - their nick equivalents. - - """ - nicks = {} - for category in make_iter(categories): - nicks.update( - { - nick.key: nick - for nick in make_iter(self.get(category=category, return_obj=True)) - if nick and nick.key - } - ) - if include_account and self.obj.has_account: - for category in make_iter(categories): - nicks.update( - { - nick.key: nick - for nick in make_iter( - self.obj.account.nicks.get(category=category, return_obj=True) - ) - if nick and nick.key - } - ) - for key, nick in nicks.items(): - nick_regex, template, _, _ = nick.value - regex = self._regex_cache.get(nick_regex) - if not regex: - regex = re.compile(nick_regex, re.I + re.DOTALL + re.U) - self._regex_cache[nick_regex] = regex - - is_match, raw_string = parse_nick_template(raw_string.strip(), regex, template) - if is_match: - break - return raw_string
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/typeclasses/managers.html b/docs/0.9.5/_modules/evennia/typeclasses/managers.html deleted file mode 100644 index 8d1df0b33e..0000000000 --- a/docs/0.9.5/_modules/evennia/typeclasses/managers.html +++ /dev/null @@ -1,964 +0,0 @@ - - - - - - - - evennia.typeclasses.managers — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.typeclasses.managers

-"""
-This implements the common managers that are used by the
-abstract models in dbobjects.py (and which are thus shared by
-all Attributes and TypedObjects).
-
-"""
-import shlex
-from django.db.models import F, Q, Count, ExpressionWrapper, FloatField
-from django.db.models.functions import Cast
-from evennia.utils import idmapper
-from evennia.utils.utils import make_iter, variable_from_module
-from evennia.typeclasses.attributes import Attribute
-from evennia.typeclasses.tags import Tag
-
-__all__ = ("TypedObjectManager",)
-_GA = object.__getattribute__
-_Tag = None
-
-
-# Managers
-
-
-
[docs]class TypedObjectManager(idmapper.manager.SharedMemoryManager): - """ - Common ObjectManager for all dbobjects. - - """ - - # common methods for all typed managers. These are used - # in other methods. Returns querysets. - - # Attribute manager methods -
[docs] def get_attribute( - self, key=None, category=None, value=None, strvalue=None, obj=None, attrtype=None, **kwargs - ): - """ - Return Attribute objects by key, by category, by value, by strvalue, by - object (it is stored on) or with a combination of those criteria. - - Args: - key (str, optional): The attribute's key to search for - category (str, optional): The category of the attribute(s) to search for. - value (str, optional): The attribute value to search for. - Note that this is not a very efficient operation since it - will query for a pickled entity. Mutually exclusive to - `strvalue`. - strvalue (str, optional): The str-value to search for. - Most Attributes will not have strvalue set. This is - mutually exclusive to the `value` keyword and will take - precedence if given. - obj (Object, optional): On which object the Attribute to - search for is. - attrype (str, optional): An attribute-type to search for. - By default this is either `None` (normal Attributes) or - `"nick"`. - **kwargs (any): Currently unused. Reserved for future use. - - Returns: - list: The matching Attributes. - - """ - dbmodel = self.model.__dbclass__.__name__.lower() - query = [("attribute__db_attrtype", attrtype), ("attribute__db_model", dbmodel)] - if obj: - query.append(("%s__id" % self.model.__dbclass__.__name__.lower(), obj.id)) - if key: - query.append(("attribute__db_key", key)) - if category: - query.append(("attribute__db_category", category)) - if strvalue: - query.append(("attribute__db_strvalue", strvalue)) - if value: - # no reason to make strvalue/value mutually exclusive at this level - query.append(("attribute__db_value", value)) - return Attribute.objects.filter( - pk__in=self.model.db_attributes.through.objects.filter(**dict(query)).values_list( - "attribute_id", flat=True - ) - )
- -
[docs] def get_nick(self, key=None, category=None, value=None, strvalue=None, obj=None): - """ - Get a nick, in parallel to `get_attribute`. - - Args: - key (str, optional): The nicks's key to search for - category (str, optional): The category of the nicks(s) to search for. - value (str, optional): The attribute value to search for. Note that this - is not a very efficient operation since it will query for a pickled - entity. Mutually exclusive to `strvalue`. - strvalue (str, optional): The str-value to search for. Most Attributes - will not have strvalue set. This is mutually exclusive to the `value` - keyword and will take precedence if given. - obj (Object, optional): On which object the Attribute to search for is. - - Returns: - nicks (list): The matching Nicks. - - """ - return self.get_attribute( - key=key, category=category, value=value, strvalue=strvalue, obj=obj - )
- -
[docs] def get_by_attribute( - self, key=None, category=None, value=None, strvalue=None, attrtype=None, **kwargs - ): - """ - Return objects having attributes with the given key, category, - value, strvalue or combination of those criteria. - - Args: - key (str, optional): The attribute's key to search for - category (str, optional): The category of the attribute - to search for. - value (str, optional): The attribute value to search for. - Note that this is not a very efficient operation since it - will query for a pickled entity. Mutually exclusive to - `strvalue`. - strvalue (str, optional): The str-value to search for. - Most Attributes will not have strvalue set. This is - mutually exclusive to the `value` keyword and will take - precedence if given. - attrype (str, optional): An attribute-type to search for. - By default this is either `None` (normal Attributes) or - `"nick"`. - kwargs (any): Currently unused. Reserved for future use. - - Returns: - obj (list): Objects having the matching Attributes. - - """ - dbmodel = self.model.__dbclass__.__name__.lower() - query = [ - ("db_attributes__db_attrtype", attrtype), - ("db_attributes__db_model", dbmodel), - ] - if key: - query.append(("db_attributes__db_key", key)) - if category: - query.append(("db_attributes__db_category", category)) - if strvalue: - query.append(("db_attributes__db_strvalue", strvalue)) - elif value: - # strvalue and value are mutually exclusive - query.append(("db_attributes__db_value", value)) - return self.filter(**dict(query))
- -
[docs] def get_by_nick(self, key=None, nick=None, category="inputline"): - """ - Get object based on its key or nick. - - Args: - key (str, optional): The attribute's key to search for - nick (str, optional): The nickname to search for - category (str, optional): The category of the nick - to search for. - - Returns: - obj (list): Objects having the matching Nicks. - - """ - return self.get_by_attribute(key=key, category=category, strvalue=nick, attrtype="nick")
- - # Tag manager methods - -
[docs] def get_tag(self, key=None, category=None, obj=None, tagtype=None, global_search=False): - """ - Return Tag objects by key, by category, by object (it is - stored on) or with a combination of those criteria. - - Args: - key (str, optional): The Tag's key to search for - category (str, optional): The Tag of the attribute(s) - to search for. - obj (Object, optional): On which object the Tag to - search for is. - tagtype (str, optional): One of `None` (normal tags), - "alias" or "permission" - global_search (bool, optional): Include all possible tags, - not just tags on this object - - Returns: - tag (list): The matching Tags. - - """ - global _Tag - if not _Tag: - from evennia.typeclasses.models import Tag as _Tag - dbmodel = self.model.__dbclass__.__name__.lower() - if global_search: - # search all tags using the Tag model - query = [("db_tagtype", tagtype), ("db_model", dbmodel)] - if obj: - query.append(("id", obj.id)) - if key: - query.append(("db_key", key)) - if category: - query.append(("db_category", category)) - return _Tag.objects.filter(**dict(query)) - else: - # search only among tags stored on on this model - query = [("tag__db_tagtype", tagtype), ("tag__db_model", dbmodel)] - if obj: - query.append(("%s__id" % self.model.__name__.lower(), obj.id)) - if key: - query.append(("tag__db_key", key)) - if category: - query.append(("tag__db_category", category)) - return Tag.objects.filter( - pk__in=self.model.db_tags.through.objects.filter(**dict(query)).values_list( - "tag_id", flat=True - ) - )
- -
[docs] def get_permission(self, key=None, category=None, obj=None): - """ - Get a permission from the database. - - Args: - key (str, optional): The permission's identifier. - category (str, optional): The permission's category. - obj (object, optional): The object on which this Tag is set. - - Returns: - permission (list): Permission objects. - - """ - return self.get_tag(key=key, category=category, obj=obj, tagtype="permission")
- -
[docs] def get_alias(self, key=None, category=None, obj=None): - """ - Get an alias from the database. - - Args: - key (str, optional): The permission's identifier. - category (str, optional): The permission's category. - obj (object, optional): The object on which this Tag is set. - - Returns: - alias (list): Alias objects. - - """ - return self.get_tag(key=key, category=category, obj=obj, tagtype="alias")
- -
[docs] def get_by_tag(self, key=None, category=None, tagtype=None, **kwargs): - """ - Return objects having tags with a given key or category or combination of the two. - Also accepts multiple tags/category/tagtype - - Args: - key (str or list, optional): Tag key or list of keys. Not case sensitive. - category (str or list, optional): Tag category. Not case sensitive. - If `key` is a list, a single category can either apply to all - keys in that list or this must be a list matching the `key` - list element by element. If no `key` is given, all objects with - tags of this category are returned. - tagtype (str, optional): 'type' of Tag, by default - this is either `None` (a normal Tag), `alias` or - `permission`. This always apply to all queried tags. - - Keyword Args: - match (str): "all" (default) or "any"; determines whether the - target object must be tagged with ALL of the provided - tags/categories or ANY single one. ANY will perform a weighted - sort, so objects with more tag matches will outrank those with - fewer tag matches. - - Returns: - objects (list): Objects with matching tag. - - Raises: - IndexError: If `key` and `category` are both lists and `category` is shorter - than `key`. - - """ - if not (key or category): - return [] - - global _Tag - if not _Tag: - from evennia.typeclasses.models import Tag as _Tag - - anymatch = "any" == kwargs.get("match", "all").lower().strip() - - keys = make_iter(key) if key else [] - categories = make_iter(category) if category else [] - n_keys = len(keys) - n_categories = len(categories) - unique_categories = sorted(set(categories)) - n_unique_categories = len(unique_categories) - - dbmodel = self.model.__dbclass__.__name__.lower() - query = ( - self.filter(db_tags__db_tagtype__iexact=tagtype, db_tags__db_model__iexact=dbmodel) - .distinct() - .order_by("id") - ) - - if n_keys > 0: - # keys and/or categories given - if n_categories == 0: - categories = [None for _ in range(n_keys)] - elif n_categories == 1 and n_keys > 1: - cat = categories[0] - categories = [cat for _ in range(n_keys)] - elif 1 < n_categories < n_keys: - raise IndexError( - "get_by_tag needs a single category or a list of categories " - "the same length as the list of tags." - ) - clauses = Q() - for ikey, key in enumerate(keys): - # ANY mode; must match any one of the given tags/categories - clauses |= Q(db_key__iexact=key, db_category__iexact=categories[ikey]) - else: - # only one or more categories given - clauses = Q() - # ANY mode; must match any one of them - for category in unique_categories: - clauses |= Q(db_category__iexact=category) - - tags = _Tag.objects.filter(clauses) - query = query.filter(db_tags__in=tags).annotate( - matches=Count("db_tags__pk", filter=Q(db_tags__in=tags), distinct=True) - ) - - if anymatch: - # ANY: Match any single tag, ordered by weight - query = query.order_by("-matches") - else: - # Default ALL: Match all of the tags and optionally more - n_req_tags = n_keys if n_keys > 0 else n_unique_categories - query = query.filter(matches__gte=n_req_tags) - - return query
- -
[docs] def get_by_permission(self, key=None, category=None): - """ - Return objects having permissions with a given key or category or - combination of the two. - - Args: - key (str, optional): Permissions key. Not case sensitive. - category (str, optional): Permission category. Not case sensitive. - Returns: - objects (list): Objects with matching permission. - """ - return self.get_by_tag(key=key, category=category, tagtype="permission")
- -
[docs] def get_by_alias(self, key=None, category=None): - """ - Return objects having aliases with a given key or category or - combination of the two. - - Args: - key (str, optional): Alias key. Not case sensitive. - category (str, optional): Alias category. Not case sensitive. - Returns: - objects (list): Objects with matching alias. - """ - return self.get_by_tag(key=key, category=category, tagtype="alias")
- -
[docs] def create_tag(self, key=None, category=None, data=None, tagtype=None): - """ - Create a new Tag of the base type associated with this - object. This makes sure to create case-insensitive tags. - If the exact same tag configuration (key+category+tagtype+dbmodel) - exists on the model, a new tag will not be created, but an old - one returned. - - - Args: - key (str, optional): Tag key. Not case sensitive. - category (str, optional): Tag category. Not case sensitive. - data (str, optional): Extra information about the tag. - tagtype (str or None, optional): 'type' of Tag, by default - this is either `None` (a normal Tag), `alias` or - `permission`. - Notes: - The `data` field is not part of the uniqueness of the tag: - Setting `data` on an existing tag will overwrite the old - data field. It is intended only as a way to carry - information about the tag (like a help text), not to carry - any information about the tagged objects themselves. - - """ - data = str(data) if data is not None else None - # try to get old tag - - dbmodel = self.model.__dbclass__.__name__.lower() - tag = self.get_tag(key=key, category=category, tagtype=tagtype, global_search=True) - if tag and data is not None: - # get tag from list returned by get_tag - tag = tag[0] - # overload data on tag - tag.db_data = data - tag.save() - elif not tag: - # create a new tag - global _Tag - if not _Tag: - from evennia.typeclasses.models import Tag as _Tag - tag = _Tag.objects.create( - db_key=key.strip().lower() if key is not None else None, - db_category=category.strip().lower() if category and key is not None else None, - db_data=data, - db_model=dbmodel, - db_tagtype=tagtype.strip().lower() if tagtype is not None else None, - ) - tag.save() - return make_iter(tag)[0]
- -
[docs] def dbref(self, dbref, reqhash=True): - """ - Determing if input is a valid dbref. - - Args: - dbref (str or int): A possible dbref. - reqhash (bool, optional): If the "#" is required for this - to be considered a valid hash. - - Returns: - dbref (int or None): The integer part of the dbref. - - Notes: - Valid forms of dbref (database reference number) are - either a string '#N' or an integer N. - - """ - if reqhash and not (isinstance(dbref, str) and dbref.startswith("#")): - return None - if isinstance(dbref, str): - dbref = dbref.lstrip("#") - try: - if int(dbref) < 0: - return None - except Exception: - return None - return dbref
- -
[docs] def get_id(self, dbref): - """ - Find object with given dbref. - - Args: - dbref (str or int): The id to search for. - - Returns: - object (TypedObject): The matched object. - - """ - dbref = self.dbref(dbref, reqhash=False) - try: - return self.get(id=dbref) - except self.model.DoesNotExist: - pass - return None
- - - -
[docs] def get_dbref_range(self, min_dbref=None, max_dbref=None): - """ - Get objects within a certain range of dbrefs. - - Args: - min_dbref (int): Start of dbref range. - max_dbref (int): End of dbref range (inclusive) - - Returns: - objects (list): TypedObjects with dbrefs within - the given dbref ranges. - - """ - retval = super().all() - if min_dbref is not None: - retval = retval.filter(id__gte=self.dbref(min_dbref, reqhash=False)) - if max_dbref is not None: - retval = retval.filter(id__lte=self.dbref(max_dbref, reqhash=False)) - return retval
- -
[docs] def get_typeclass_totals(self, *args, **kwargs) -> object: - """ - Returns a queryset of typeclass composition statistics. - - Returns: - qs (Queryset): A queryset of dicts containing the typeclass (name), - the count of objects with that typeclass and a float representing - the percentage of objects associated with the typeclass. - - """ - return ( - self.values("db_typeclass_path") - .distinct() - .annotate( - # Get count of how many objects for each typeclass exist - count=Count("db_typeclass_path") - ) - .annotate( - # Rename db_typeclass_path field to something more human - typeclass=F("db_typeclass_path"), - # Calculate this class' percentage of total composition - percent=ExpressionWrapper( - ((F("count") / float(self.count())) * 100.0), output_field=FloatField(), - ), - ) - .values("typeclass", "count", "percent") - )
- -
[docs] def object_totals(self): - """ - Get info about database statistics. - - Returns: - census (dict): A dictionary `{typeclass_path: number, ...}` with - all the typeclasses active in-game as well as the number - of such objects defined (i.e. the number of database - object having that typeclass set on themselves). - - """ - stats = self.get_typeclass_totals().order_by("typeclass") - return {x.get("typeclass"): x.get("count") for x in stats}
- -
- - -class TypeclassManager(TypedObjectManager): - """ - Manager for the typeclasses. The main purpose of this manager is - to limit database queries to the given typeclass despite all - typeclasses technically being defined in the same core database - model. - - """ - - # object-manager methods - def smart_search(self, query): - """ - Search by supplying a string with optional extra search criteria to aid the query. - - Args: - query (str): A search criteria that accepts extra search criteria on the following - forms: - - [key|alias|#dbref...] - [tag==<tagstr>[:category]...] - [attr==<key>:<value>:category...] - - All three can be combined in the same query, separated by spaces. - - Returns: - matches (queryset): A queryset result matching all queries exactly. If wanting to use - spaces or ==, != in tags or attributes, enclose them in quotes. - - Example: - house = smart_search("key=foo alias=bar tag=house:building tag=magic attr=color:red") - - Note: - The flexibility of this method is limited by the input line format. Tag/attribute - matching only works for matching primitives. For even more complex queries, such as - 'in' operations or object field matching, use the full django query language. - - """ - # shlex splits by spaces unless escaped by quotes - querysplit = shlex.split(query) - queries, plustags, plusattrs, negtags, negattrs = [], [], [], [], [] - for ipart, part in enumerate(querysplit): - key, rest = part, "" - if ":" in part: - key, rest = part.split(":", 1) - # tags are on the form tag or tag:category - if key.startswith("tag=="): - plustags.append((key[5:], rest)) - continue - elif key.startswith("tag!="): - negtags.append((key[5:], rest)) - continue - # attrs are on the form attr:value or attr:value:category - elif rest: - value, category = rest, "" - if ":" in rest: - value, category = rest.split(":", 1) - if key.startswith("attr=="): - plusattrs.append((key[7:], value, category)) - continue - elif key.startswith("attr!="): - negattrs.append((key[7:], value, category)) - continue - # if we get here, we are entering a key search criterion which - # we assume is one word. - queries.append(part) - # build query from components - query = " ".join(queries) - # TODO - - def get(self, *args, **kwargs): - """ - Overload the standard get. This will limit itself to only - return the current typeclass. - - Args: - args (any): These are passed on as arguments to the default - django get method. - Keyword Args: - kwargs (any): These are passed on as normal arguments - to the default django get method - Returns: - object (object): The object found. - - Raises: - ObjectNotFound: The exact name of this exception depends - on the model base used. - - """ - kwargs.update({"db_typeclass_path": self.model.path}) - return super().get(**kwargs) - - def filter(self, *args, **kwargs): - """ - Overload of the standard filter function. This filter will - limit itself to only the current typeclass. - - Args: - args (any): These are passed on as arguments to the default - django filter method. - Keyword Args: - kwargs (any): These are passed on as normal arguments - to the default django filter method. - Returns: - objects (queryset): The objects found. - - """ - kwargs.update({"db_typeclass_path": self.model.path}) - return super().filter(*args, **kwargs) - - def all(self): - """ - Overload method to return all matches, filtering for typeclass. - - Returns: - objects (queryset): The objects found. - - """ - return super().all().filter(db_typeclass_path=self.model.path) - - def first(self): - """ - Overload method to return first match, filtering for typeclass. - - Returns: - object (object): The object found. - - Raises: - ObjectNotFound: The exact name of this exception depends - on the model base used. - - """ - return super().filter(db_typeclass_path=self.model.path).first() - - def last(self): - """ - Overload method to return last match, filtering for typeclass. - - Returns: - object (object): The object found. - - Raises: - ObjectNotFound: The exact name of this exception depends - on the model base used. - - """ - return super().filter(db_typeclass_path=self.model.path).last() - - def count(self): - """ - Overload method to return number of matches, filtering for typeclass. - - Returns: - integer : Number of objects found. - - """ - return super().filter(db_typeclass_path=self.model.path).count() - - def annotate(self, *args, **kwargs): - """ - Overload annotate method to filter on typeclass before annotating. - Args: - *args (any): Positional arguments passed along to queryset annotate method. - **kwargs (any): Keyword arguments passed along to queryset annotate method. - - Returns: - Annotated queryset. - """ - return ( - super(TypeclassManager, self) - .filter(db_typeclass_path=self.model.path) - .annotate(*args, **kwargs) - ) - - def values(self, *args, **kwargs): - """ - Overload values method to filter on typeclass first. - Args: - *args (any): Positional arguments passed along to values method. - **kwargs (any): Keyword arguments passed along to values method. - - Returns: - Queryset of values dictionaries, just filtered by typeclass first. - """ - return ( - super(TypeclassManager, self) - .filter(db_typeclass_path=self.model.path) - .values(*args, **kwargs) - ) - - def values_list(self, *args, **kwargs): - """ - Overload values method to filter on typeclass first. - Args: - *args (any): Positional arguments passed along to values_list method. - **kwargs (any): Keyword arguments passed along to values_list method. - - Returns: - Queryset of value_list tuples, just filtered by typeclass first. - """ - return ( - super(TypeclassManager, self) - .filter(db_typeclass_path=self.model.path) - .values_list(*args, **kwargs) - ) - - def _get_subclasses(self, cls): - """ - Recursively get all subclasses to a class. - - Args: - cls (classoject): A class to get subclasses from. - """ - all_subclasses = cls.__subclasses__() - for subclass in all_subclasses: - all_subclasses.extend(self._get_subclasses(subclass)) - return all_subclasses - - def get_family(self, *args, **kwargs): - """ - Variation of get that not only returns the current typeclass - but also all subclasses of that typeclass. - - Keyword Args: - kwargs (any): These are passed on as normal arguments - to the default django get method. - Returns: - objects (list): The objects found. - - Raises: - ObjectNotFound: The exact name of this exception depends - on the model base used. - - """ - paths = [self.model.path] + [ - "%s.%s" % (cls.__module__, cls.__name__) for cls in self._get_subclasses(self.model) - ] - kwargs.update({"db_typeclass_path__in": paths}) - return super().get(*args, **kwargs) - - def filter_family(self, *args, **kwargs): - """ - Variation of filter that allows results both from typeclass - and from subclasses of typeclass - - Args: - args (any): These are passed on as arguments to the default - django filter method. - Keyword Args: - kwargs (any): These are passed on as normal arguments - to the default django filter method. - Returns: - objects (list): The objects found. - - """ - # query, including all subclasses - paths = [self.model.path] + [ - "%s.%s" % (cls.__module__, cls.__name__) for cls in self._get_subclasses(self.model) - ] - kwargs.update({"db_typeclass_path__in": paths}) - return super().filter(*args, **kwargs) - - def all_family(self): - """ - Return all matches, allowing matches from all subclasses of - the typeclass. - - Returns: - objects (list): The objects found. - - """ - paths = [self.model.path] + [ - "%s.%s" % (cls.__module__, cls.__name__) for cls in self._get_subclasses(self.model) - ] - return super().all().filter(db_typeclass_path__in=paths) -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/typeclasses/models.html b/docs/0.9.5/_modules/evennia/typeclasses/models.html deleted file mode 100644 index 0ea11f9c3b..0000000000 --- a/docs/0.9.5/_modules/evennia/typeclasses/models.html +++ /dev/null @@ -1,1170 +0,0 @@ - - - - - - - - evennia.typeclasses.models — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.typeclasses.models

-"""
-This is the *abstract* django models for many of the database objects
-in Evennia. A django abstract (obs, not the same as a Python metaclass!) is
-a model which is not actually created in the database, but which only exists
-for other models to inherit from, to avoid code duplication. Any model can
-import and inherit from these classes.
-
-Attributes are database objects stored on other objects. The implementing
-class needs to supply a ForeignKey field attr_object pointing to the kind
-of object being mapped. Attributes storing iterables actually store special
-types of iterables named PackedList/PackedDict respectively. These make
-sure to save changes to them to database - this is criticial in order to
-allow for obj.db.mylist[2] = data. Also, all dbobjects are saved as
-dbrefs but are also aggressively cached.
-
-TypedObjects are objects 'decorated' with a typeclass - that is, the typeclass
-(which is a normal Python class implementing some special tricks with its
-get/set attribute methods, allows for the creation of all sorts of different
-objects all with the same database object underneath. Usually attributes are
-used to permanently store things not hard-coded as field on the database object.
-The admin should usually not have to deal directly  with the database object
-layer.
-
-This module also contains the Managers for the respective models; inherit from
-these to create custom managers.
-
-"""
-from django.db.models import signals
-
-from django.db.models.base import ModelBase
-from django.db import models
-from django.contrib.contenttypes.models import ContentType
-from django.core.exceptions import ObjectDoesNotExist
-from django.conf import settings
-from django.urls import reverse
-from django.utils.encoding import smart_str
-from django.utils.text import slugify
-
-from evennia.typeclasses.attributes import (
-    Attribute,
-    AttributeHandler,
-    ModelAttributeBackend,
-    InMemoryAttributeBackend,
-)
-from evennia.typeclasses.attributes import DbHolder
-from evennia.typeclasses.tags import Tag, TagHandler, AliasHandler, PermissionHandler
-
-from evennia.utils.idmapper.models import SharedMemoryModel, SharedMemoryModelBase
-from evennia.server.signals import SIGNAL_TYPED_OBJECT_POST_RENAME
-
-from evennia.typeclasses import managers
-from evennia.locks.lockhandler import LockHandler
-from evennia.utils.utils import is_iter, inherits_from, lazy_property, class_from_module
-from evennia.utils.logger import log_trace
-
-__all__ = ("TypedObject",)
-
-TICKER_HANDLER = None
-
-_PERMISSION_HIERARCHY = [p.lower() for p in settings.PERMISSION_HIERARCHY]
-_TYPECLASS_AGGRESSIVE_CACHE = settings.TYPECLASS_AGGRESSIVE_CACHE
-_GA = object.__getattribute__
-_SA = object.__setattr__
-
-
-# signal receivers. Connected in __new__
-
-
-def call_at_first_save(sender, instance, created, **kwargs):
-    """
-    Receives a signal just after the object is saved.
-
-    """
-    if created:
-        instance.at_first_save()
-
-
-def remove_attributes_on_delete(sender, instance, **kwargs):
-    """
-    Wipe object's Attributes when it's deleted
-
-    """
-    instance.db_attributes.all().delete()
-
-
-# ------------------------------------------------------------
-#
-# Typed Objects
-#
-# ------------------------------------------------------------
-
-
-#
-# Meta class for typeclasses
-#
-
-
-class TypeclassBase(SharedMemoryModelBase):
-    """
-    Metaclass which should be set for the root of model proxies
-    that don't define any new fields, like Object, Script etc. This
-    is the basis for the typeclassing system.
-
-    """
-
-    def __new__(cls, name, bases, attrs):
-        """
-        We must define our Typeclasses as proxies. We also store the
-        path directly on the class, this is required by managers.
-        """
-
-        # storage of stats
-        attrs["typename"] = name
-        attrs["path"] = "%s.%s" % (attrs["__module__"], name)
-
-        def _get_dbmodel(bases):
-            """Recursively get the dbmodel"""
-            if not hasattr(bases, "__iter__"):
-                bases = [bases]
-            for base in bases:
-                try:
-                    if base._meta.proxy or base._meta.abstract:
-                        for kls in base._meta.parents:
-                            return _get_dbmodel(kls)
-                except AttributeError:
-                    # this happens if trying to parse a non-typeclass mixin parent,
-                    # without a _meta
-                    continue
-                else:
-                    return base
-                return None
-
-        dbmodel = _get_dbmodel(bases)
-
-        if not dbmodel:
-            raise TypeError(f"{name} does not appear to inherit from a database model.")
-
-        # typeclass proxy setup
-        # first check explicit __applabel__ on the typeclass, then figure
-        # it out from the dbmodel
-        if "__applabel__" not in attrs:
-            # find the app-label in one of the bases, usually the dbmodel
-            attrs["__applabel__"] = dbmodel._meta.app_label
-
-        if "Meta" not in attrs:
-
-            class Meta:
-                proxy = True
-                app_label = attrs.get("__applabel__", "typeclasses")
-
-            attrs["Meta"] = Meta
-        attrs["Meta"].proxy = True
-
-        new_class = ModelBase.__new__(cls, name, bases, attrs)
-
-        # django doesn't support inheriting proxy models so we hack support for
-        # it here by injecting `proxy_for_model` to the actual dbmodel.
-        # Unfortunately we cannot also set the correct model_name, because this
-        # would block multiple-inheritance of typeclasses (Django doesn't allow
-        # multiple bases of the same model).
-        if dbmodel:
-            new_class._meta.proxy_for_model = dbmodel
-            # Maybe Django will eventually handle this in the future:
-            # new_class._meta.model_name = dbmodel._meta.model_name
-
-        # attach signals
-        signals.post_save.connect(call_at_first_save, sender=new_class)
-        signals.pre_delete.connect(remove_attributes_on_delete, sender=new_class)
-        return new_class
-
-
-#
-# Main TypedObject abstraction
-#
-
-
-
[docs]class TypedObject(SharedMemoryModel): - """ - Abstract Django model. - - This is the basis for a typed object. It also contains all the - mechanics for managing connected attributes. - - The TypedObject has the following properties: - - - key - main name - - name - alias for key - - typeclass_path - the path to the decorating typeclass - - typeclass - auto-linked typeclass - - date_created - time stamp of object creation - - permissions - perm strings - - dbref - #id of object - - db - persistent attribute storage - - ndb - non-persistent attribute storage - - """ - - # - # TypedObject Database Model setup - # - # - # These databse fields are all accessed and set using their corresponding - # properties, named same as the field, but without the db_* prefix - # (no separate save() call is needed) - - # Main identifier of the object, for searching. Is accessed with self.key - # or self.name - db_key = models.CharField("key", max_length=255, db_index=True) - # This is the python path to the type class this object is tied to. The - # typeclass is what defines what kind of Object this is) - db_typeclass_path = models.CharField( - "typeclass", - max_length=255, - null=True, - help_text="this defines what 'type' of entity this is. This variable holds " - "a Python path to a module with a valid Evennia Typeclass.", - db_index=True, - ) - # Creation date. This is not changed once the object is created. - db_date_created = models.DateTimeField("creation date", editable=False, auto_now_add=True) - # Lock storage - db_lock_storage = models.TextField( - "locks", - blank=True, - help_text="locks limit access to an entity. A lock is defined as a 'lock string' " - "on the form 'type:lockfunctions', defining what functionality is locked and " - "how to determine access. Not defining a lock means no access is granted.", - ) - # many2many relationships - db_attributes = models.ManyToManyField( - Attribute, - help_text="attributes on this object. An attribute can hold any pickle-able " - "python object (see docs for special cases).", - ) - db_tags = models.ManyToManyField( - Tag, - help_text="tags on this object. Tags are simple string markers to identify, " - "group and alias objects.", - ) - - # Database manager - objects = managers.TypedObjectManager() - - # quick on-object typeclass cache for speed - _cached_typeclass = None - - # typeclass mechanism - -
[docs] def set_class_from_typeclass(self, typeclass_path=None): - if typeclass_path: - try: - self.__class__ = class_from_module( - typeclass_path, defaultpaths=settings.TYPECLASS_PATHS - ) - except Exception: - log_trace() - try: - self.__class__ = class_from_module(self.__settingsclasspath__) - except Exception: - log_trace() - try: - self.__class__ = class_from_module(self.__defaultclasspath__) - except Exception: - log_trace() - self.__class__ = self._meta.concrete_model or self.__class__ - finally: - self.db_typeclass_path = typeclass_path - elif self.db_typeclass_path: - try: - self.__class__ = class_from_module(self.db_typeclass_path) - except Exception: - log_trace() - try: - self.__class__ = class_from_module(self.__defaultclasspath__) - except Exception: - log_trace() - self.__dbclass__ = self._meta.concrete_model or self.__class__ - else: - self.db_typeclass_path = "%s.%s" % (self.__module__, self.__class__.__name__) - # important to put this at the end since _meta is based on the set __class__ - try: - self.__dbclass__ = self._meta.concrete_model or self.__class__ - except AttributeError: - err_class = repr(self.__class__) - self.__class__ = class_from_module("evennia.objects.objects.DefaultObject") - self.__dbclass__ = class_from_module("evennia.objects.models.ObjectDB") - self.db_typeclass_path = "evennia.objects.objects.DefaultObject" - log_trace( - "Critical: Class %s of %s is not a valid typeclass!\nTemporarily falling back to %s." - % (err_class, self, self.__class__) - )
- -
[docs] def __init__(self, *args, **kwargs): - """ - The `__init__` method of typeclasses is the core operational - code of the typeclass system, where it dynamically re-applies - a class based on the db_typeclass_path database field rather - than use the one in the model. - - Args: - Passed through to parent. - - Keyword Args: - Passed through to parent. - - Notes: - The loading mechanism will attempt the following steps: - - 1. Attempt to load typeclass given on command line - 2. Attempt to load typeclass stored in db_typeclass_path - 3. Attempt to load `__settingsclasspath__`, which is by the - default classes defined to be the respective user-set - base typeclass settings, like `BASE_OBJECT_TYPECLASS`. - 4. Attempt to load `__defaultclasspath__`, which is the - base classes in the library, like DefaultObject etc. - 5. If everything else fails, use the database model. - - Normal operation is to load successfully at either step 1 - or 2 depending on how the class was called. Tracebacks - will be logged for every step the loader must take beyond - 2. - - """ - typeclass_path = kwargs.pop("typeclass", None) - super().__init__(*args, **kwargs) - self.set_class_from_typeclass(typeclass_path=typeclass_path)
- - # initialize all handlers in a lazy fashion -
[docs] @lazy_property - def attributes(self): - return AttributeHandler(self, ModelAttributeBackend)
- -
[docs] @lazy_property - def locks(self): - return LockHandler(self)
- -
[docs] @lazy_property - def tags(self): - return TagHandler(self)
- -
[docs] @lazy_property - def aliases(self): - return AliasHandler(self)
- -
[docs] @lazy_property - def permissions(self): - return PermissionHandler(self)
- -
[docs] @lazy_property - def nattributes(self): - return AttributeHandler(self, InMemoryAttributeBackend)
- -
[docs] class Meta: - """ - Django setup info. - """ - - abstract = True - verbose_name = "Evennia Database Object" - ordering = ["-db_date_created", "id", "db_typeclass_path", "db_key"]
- - # wrapper - # Wrapper properties to easily set database fields. These are - # @property decorators that allows to access these fields using - # normal python operations (without having to remember to save() - # etc). So e.g. a property 'attr' has a get/set/del decorator - # defined that allows the user to do self.attr = value, - # value = self.attr and del self.attr respectively (where self - # is the object in question). - - # name property (alias to self.key) - def __name_get(self): - return self.key - - def __name_set(self, value): - self.key = value - - def __name_del(self): - raise Exception("Cannot delete name") - - name = property(__name_get, __name_set, __name_del) - - # key property (overrides's the idmapper's db_key for the at_rename hook) - @property - def key(self): - return self.db_key - - @key.setter - def key(self, value): - oldname = str(self.db_key) - self.db_key = value - self.save(update_fields=["db_key"]) - self.at_rename(oldname, value) - SIGNAL_TYPED_OBJECT_POST_RENAME.send(sender=self, old_key=oldname, new_key=value) - - # - # - # TypedObject main class methods and properties - # - # - - def __eq__(self, other): - try: - return self.__dbclass__ == other.__dbclass__ and self.dbid == other.dbid - except AttributeError: - return False - - def __hash__(self): - # this is required to maintain hashing - return super().__hash__() - - def __str__(self): - return smart_str("%s" % self.db_key) - - def __repr__(self): - return "%s" % self.db_key - - # @property - def __dbid_get(self): - """ - Caches and returns the unique id of the object. - Use this instead of self.id, which is not cached. - """ - return self.id - - def __dbid_set(self, value): - raise Exception("dbid cannot be set!") - - def __dbid_del(self): - raise Exception("dbid cannot be deleted!") - - dbid = property(__dbid_get, __dbid_set, __dbid_del) - - # @property - def __dbref_get(self): - """ - Returns the object's dbref on the form #NN. - """ - return "#%s" % self.id - - def __dbref_set(self): - raise Exception("dbref cannot be set!") - - def __dbref_del(self): - raise Exception("dbref cannot be deleted!") - - dbref = property(__dbref_get, __dbref_set, __dbref_del) - -
[docs] def at_idmapper_flush(self): - """ - This is called when the idmapper cache is flushed and - allows customized actions when this happens. - - Returns: - do_flush (bool): If True, flush this object as normal. If - False, don't flush and expect this object to handle - the flushing on its own. - - Notes: - The default implementation relies on being able to clear - Django's Foreignkey cache on objects not affected by the - flush (notably objects with an NAttribute stored). We rely - on this cache being stored on the format "_<fieldname>_cache". - If Django were to change this name internally, we need to - update here (unlikely, but marking just in case). - - """ - if self.nattributes.all(): - # we can't flush this object if we have non-persistent - # attributes stored - those would get lost! Nevertheless - # we try to flush as many references as we can. - self.attributes.reset_cache() - self.tags.reset_cache() - # flush caches for all related fields - for field in self._meta.fields: - name = "_%s_cache" % field.name - if field.is_relation and name in self.__dict__: - # a foreignkey - remove its cache - del self.__dict__[name] - return False - # a normal flush - return True
- - # - # Object manipulation methods - # - -
[docs] @classmethod - def search(cls, query, **kwargs): - """ - Overridden by class children. This implements a common API. - - Args: - query (str): A search query. - **kwargs: Other search parameters. - - Returns: - list: A list of 0, 1 or more matches, only of this typeclass. - - """ - if cls.objects.dbref(query): - return [cls.objects.get_id(query)] - return list(cls.objects.filter(db_key__lower=query))
- -
[docs] def is_typeclass(self, typeclass, exact=False): - """ - Returns true if this object has this type OR has a typeclass - which is an subclass of the given typeclass. This operates on - the actually loaded typeclass (this is important since a - failing typeclass may instead have its default currently - loaded) typeclass - can be a class object or the python path - to such an object to match against. - - Args: - typeclass (str or class): A class or the full python path - to the class to check. - exact (bool, optional): Returns true only if the object's - type is exactly this typeclass, ignoring parents. - - Returns: - is_typeclass (bool): If this typeclass matches the given - typeclass. - - """ - if isinstance(typeclass, str): - typeclass = [typeclass] + [ - "%s.%s" % (prefix, typeclass) for prefix in settings.TYPECLASS_PATHS - ] - else: - typeclass = [typeclass.path] - - selfpath = self.path - if exact: - # check only exact match - return selfpath in typeclass - else: - # check parent chain - return any( - hasattr(cls, "path") and cls.path in typeclass for cls in self.__class__.mro() - )
- -
[docs] def swap_typeclass( - self, - new_typeclass, - clean_attributes=False, - run_start_hooks="all", - no_default=True, - clean_cmdsets=False, - ): - """ - This performs an in-situ swap of the typeclass. This means - that in-game, this object will suddenly be something else. - Account will not be affected. To 'move' an account to a different - object entirely (while retaining this object's type), use - self.account.swap_object(). - - Note that this might be an error prone operation if the - old/new typeclass was heavily customized - your code - might expect one and not the other, so be careful to - bug test your code if using this feature! Often its easiest - to create a new object and just swap the account over to - that one instead. - - Args: - new_typeclass (str or classobj): Type to switch to. - clean_attributes (bool or list, optional): Will delete all - attributes stored on this object (but not any of the - database fields such as name or location). You can't get - attributes back, but this is often the safest bet to make - sure nothing in the new typeclass clashes with the old - one. If you supply a list, only those named attributes - will be cleared. - run_start_hooks (str or None, optional): This is either None, - to not run any hooks, "all" to run all hooks defined by - at_first_start, or a string with space-separated hook-names to run - (for example 'at_object_creation'). This will - always be called without arguments. - no_default (bool, optiona): If set, the swapper will not - allow for swapping to a default typeclass in case the - given one fails for some reason. Instead the old one will - be preserved. - clean_cmdsets (bool, optional): Delete all cmdsets on the object. - - """ - - if not callable(new_typeclass): - # this is an actual class object - build the path - new_typeclass = class_from_module(new_typeclass, defaultpaths=settings.TYPECLASS_PATHS) - - # if we get to this point, the class is ok. - - if inherits_from(self, "evennia.scripts.models.ScriptDB"): - if self.interval > 0: - raise RuntimeError( - "Cannot use swap_typeclass on time-dependent " - "Script '%s'.\nStop and start a new Script of the " - "right type instead." % self.key - ) - - self.typeclass_path = new_typeclass.path - self.__class__ = new_typeclass - - if clean_attributes: - # Clean out old attributes - if is_iter(clean_attributes): - for attr in clean_attributes: - self.attributes.remove(attr) - for nattr in clean_attributes: - if hasattr(self.ndb, nattr): - self.nattributes.remove(nattr) - else: - self.attributes.clear() - self.nattributes.clear() - if clean_cmdsets: - # purge all cmdsets - self.cmdset.clear() - self.cmdset.remove_default() - - if run_start_hooks == "all": - # fake this call to mimic the first save - self.at_first_save() - elif run_start_hooks: - # a custom hook-name to call. - for start_hook in str(run_start_hooks).split(): - getattr(self, run_start_hooks)()
- - # - # Lock / permission methods - # - -
[docs] def access( - self, accessing_obj, access_type="read", default=False, no_superuser_bypass=False, **kwargs - ): - """ - Determines if another object has permission to access this one. - - Args: - accessing_obj (str): Object trying to access this one. - access_type (str, optional): Type of access sought. - default (bool, optional): What to return if no lock of - access_type was found - no_superuser_bypass (bool, optional): Turn off the - superuser lock bypass (be careful with this one). - - Keyword Args: - kwar (any): Ignored, but is there to make the api - consistent with the object-typeclass method access, which - use it to feed to its hook methods. - - """ - return self.locks.check( - accessing_obj, - access_type=access_type, - default=default, - no_superuser_bypass=no_superuser_bypass, - )
- -
[docs] def check_permstring(self, permstring): - """ - This explicitly checks if we hold particular permission - without involving any locks. - - Args: - permstring (str): The permission string to check against. - - Returns: - result (bool): If the permstring is passed or not. - - """ - if hasattr(self, "account"): - if ( - self.account - and self.account.is_superuser - and not self.account.attributes.get("_quell") - ): - return True - else: - if self.is_superuser and not self.attributes.get("_quell"): - return True - - if not permstring: - return False - perm = permstring.lower() - perms = [p.lower() for p in self.permissions.all()] - if perm in perms: - # simplest case - we have a direct match - return True - if perm in _PERMISSION_HIERARCHY: - # check if we have a higher hierarchy position - ppos = _PERMISSION_HIERARCHY.index(perm) - return any( - True - for hpos, hperm in enumerate(_PERMISSION_HIERARCHY) - if hperm in perms and hpos > ppos - ) - # we ignore pluralization (english only) - if perm.endswith("s"): - return self.check_permstring(perm[:-1]) - - return False
- - # - # Deletion methods - # - - def _deleted(self, *args, **kwargs): - """ - Scrambling method for already deleted objects - """ - raise ObjectDoesNotExist("This object was already deleted!") - -
[docs] def delete(self): - """ - Cleaning up handlers on the typeclass level - - """ - global TICKER_HANDLER - self.permissions.clear() - self.attributes.clear() - self.aliases.clear() - if hasattr(self, "nicks"): - self.nicks.clear() - # scrambling properties - self.delete = self._deleted - super().delete()
- - # - # Attribute storage - # - - @property - def db(self): - """ - Attribute handler wrapper. Allows for the syntax - - ```python - obj.db.attrname = value - # and - value = obj.db.attrname - # and - del obj.db.attrname - # and - all_attr = obj.db.all() - # (unless there is an attribute - # named 'all', in which case that will be returned instead). - ``` - - """ - try: - return self._db_holder - except AttributeError: - self._db_holder = DbHolder(self, "attributes") - return self._db_holder - - @db.setter - def db(self, value): - "Stop accidentally replacing the db object" - string = "Cannot assign directly to db object! " - string += "Use db.attr=value instead." - raise Exception(string) - - @db.deleter - def db(self): - "Stop accidental deletion." - raise Exception("Cannot delete the db object!") - - # - # Non-persistent (ndb) storage - # - - @property - def ndb(self): - """ - A non-attr_obj store (ndb: NonDataBase). Everything stored - to this is guaranteed to be cleared when a server is shutdown. - Syntax is same as for the _get_db_holder() method and - property, e.g. obj.ndb.attr = value etc. - """ - try: - return self._ndb_holder - except AttributeError: - self._ndb_holder = DbHolder(self, "nattrhandler", manager_name="nattributes") - return self._ndb_holder - - @ndb.setter - def ndb(self, value): - "Stop accidentally replacing the ndb object" - string = "Cannot assign directly to ndb object! " - string += "Use ndb.attr=value instead." - raise Exception(string) - - @ndb.deleter - def ndb(self): - "Stop accidental deletion." - raise Exception("Cannot delete the ndb object!") - -
[docs] def get_display_name(self, looker, **kwargs): - """ - Displays the name of the object in a viewer-aware manner. - - Args: - looker (TypedObject, optional): The object or account that is looking - at/getting inforamtion for this object. If not given, some - 'safe' minimum level should be returned. - - Returns: - name (str): A string containing the name of the object, - including the DBREF if this user is privileged to control - said object. - - Notes: - This function could be extended to change how object names - appear to users in character, but be wary. This function - does not change an object's keys or aliases when - searching, and is expected to produce something useful for - builders. - - """ - if self.access(looker, access_type="controls"): - return "{}(#{})".format(self.name, self.id) - return self.name
- -
[docs] def get_extra_info(self, looker, **kwargs): - """ - Used when an object is in a list of ambiguous objects as an - additional information tag. - - For instance, if you had potions which could have varying - levels of liquid left in them, you might want to display how - many drinks are left in each when selecting which to drop, but - not in your normal inventory listing. - - Args: - looker (TypedObject): The object or account that is looking - at/getting information for this object. - - Returns: - info (str): A string with disambiguating information, - conventionally with a leading space. - - """ - - if self.location == looker: - return " (carried)" - return ""
- -
[docs] def at_rename(self, oldname, newname): - """ - This Hook is called by @name on a successful rename. - - Args: - oldname (str): The instance's original name. - newname (str): The new name for the instance. - - """ - pass
- - # - # Web/Django methods - # - -
[docs] def web_get_admin_url(self): - """ - Returns the URI path for the Django Admin page for this object. - - ex. Account#1 = '/admin/accounts/accountdb/1/change/' - - Returns: - path (str): URI path to Django Admin page for object. - - """ - content_type = ContentType.objects.get_for_model(self.__class__) - return reverse( - "admin:%s_%s_change" % (content_type.app_label, content_type.model), args=(self.id,) - )
- -
[docs] @classmethod - def web_get_create_url(cls): - """ - Returns the URI path for a View that allows users to create new - instances of this object. - - ex. Chargen = '/characters/create/' - - For this to work, the developer must have defined a named view somewhere - in urls.py that follows the format 'modelname-action', so in this case - a named view of 'character-create' would be referenced by this method. - - ex. - url(r'characters/create/', ChargenView.as_view(), name='character-create') - - If no View has been created and defined in urls.py, returns an - HTML anchor. - - This method is naive and simply returns a path. Securing access to - the actual view and limiting who can create new objects is the - developer's responsibility. - - Returns: - path (str): URI path to object creation page, if defined. - - """ - try: - return reverse("%s-create" % slugify(cls._meta.verbose_name)) - except Exception: - return "#"
- -
[docs] def web_get_detail_url(self): - """ - Returns the URI path for a View that allows users to view details for - this object. - - Returns: - path (str): URI path to object detail page, if defined. - - Examples: - - ```python - Oscar (Character) = '/characters/oscar/1/' - ``` - - For this to work, the developer must have defined a named view somewhere - in urls.py that follows the format 'modelname-action', so in this case - a named view of 'character-detail' would be referenced by this method. - - - ```python - url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$', - CharDetailView.as_view(), name='character-detail') - ``` - - If no View has been created and defined in urls.py, returns an - HTML anchor. - - This method is naive and simply returns a path. Securing access to - the actual view and limiting who can view this object is the - developer's responsibility. - - """ - try: - return reverse( - "%s-detail" % slugify(self._meta.verbose_name), - kwargs={"pk": self.pk, "slug": slugify(self.name)}, - ) - except Exception: - return "#"
- -
[docs] def web_get_puppet_url(self): - """ - Returns the URI path for a View that allows users to puppet a specific - object. - - Returns: - str: URI path to object puppet page, if defined. - - Examples: - :: - - Oscar (Character) = '/characters/oscar/1/puppet/' - - For this to work, the developer must have defined a named view somewhere - in urls.py that follows the format 'modelname-action', so in this case - a named view of 'character-puppet' would be referenced by this method. - :: - - url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/puppet/$', - CharPuppetView.as_view(), name='character-puppet') - - If no View has been created and defined in urls.py, returns an - HTML anchor. - - This method is naive and simply returns a path. Securing access to - the actual view and limiting who can view this object is the developer's - responsibility. - - - """ - try: - return reverse( - "%s-puppet" % slugify(self._meta.verbose_name), - kwargs={"pk": self.pk, "slug": slugify(self.name)}, - ) - except Exception: - return "#"
- -
[docs] def web_get_update_url(self): - """ - Returns the URI path for a View that allows users to update this - object. - - Returns: - str: URI path to object update page, if defined. - - Examples: - - ```python - Oscar (Character) = '/characters/oscar/1/change/' - ``` - - For this to work, the developer must have defined a named view somewhere - in urls.py that follows the format 'modelname-action', so in this case - a named view of 'character-update' would be referenced by this method. - :: - - url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$', - CharUpdateView.as_view(), name='character-update') - - If no View has been created and defined in urls.py, returns an - HTML anchor. - - This method is naive and simply returns a path. Securing access to - the actual view and limiting who can modify objects is the developer's - responsibility. - - - """ - try: - return reverse( - "%s-update" % slugify(self._meta.verbose_name), - kwargs={"pk": self.pk, "slug": slugify(self.name)}, - ) - except Exception: - return "#"
- -
[docs] def web_get_delete_url(self): - """ - Returns the URI path for a View that allows users to delete this object. - - Returns: - path (str): URI path to object deletion page, if defined. - - Examples: - - ```python - Oscar (Character) = '/characters/oscar/1/delete/' - ``` - - For this to work, the developer must have defined a named view - somewhere in urls.py that follows the format 'modelname-action', so - in this case a named view of 'character-detail' would be referenced - by this method. - :: - - url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/delete/$', - CharDeleteView.as_view(), name='character-delete') - - If no View has been created and defined in urls.py, returns an HTML - anchor. - - This method is naive and simply returns a path. Securing access to - the actual view and limiting who can delete this object is the - developer's responsibility. - - - """ - try: - return reverse( - "%s-delete" % slugify(self._meta.verbose_name), - kwargs={"pk": self.pk, "slug": slugify(self.name)}, - ) - except Exception: - return "#"
- - # Used by Django Sites/Admin - get_absolute_url = web_get_detail_url
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/typeclasses/tags.html b/docs/0.9.5/_modules/evennia/typeclasses/tags.html deleted file mode 100644 index dadaa1693c..0000000000 --- a/docs/0.9.5/_modules/evennia/typeclasses/tags.html +++ /dev/null @@ -1,688 +0,0 @@ - - - - - - - - evennia.typeclasses.tags — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.typeclasses.tags

-"""
-Tags are entities that are attached to objects in the same way as
-Attributes. But contrary to Attributes, which are unique to an
-individual object, a single Tag can be attached to any number of
-objects at the same time.
-
-Tags are used for tagging, obviously, but the data structure is also
-used for storing Aliases and Permissions. This module contains the
-respective handlers.
-
-"""
-from collections import defaultdict
-
-from django.conf import settings
-from django.db import models
-from evennia.utils.utils import to_str, make_iter
-from evennia.locks.lockfuncs import perm as perm_lockfunc
-
-
-_TYPECLASS_AGGRESSIVE_CACHE = settings.TYPECLASS_AGGRESSIVE_CACHE
-
-# ------------------------------------------------------------
-#
-# Tags
-#
-# ------------------------------------------------------------
-
-
-
[docs]class Tag(models.Model): - """ - Tags are quick markers for objects in-game. An typeobject can have - any number of tags, stored via its db_tags property. Tagging - similar objects will make it easier to quickly locate the group - later (such as when implementing zones). The main advantage of - tagging as opposed to using tags is speed; a tag is very - limited in what data it can hold, and the tag key+category is - indexed for efficient lookup in the database. Tags are shared - between objects - a new tag is only created if the key+category - combination did not previously exist, making them unsuitable for - storing object-related data (for this a regular Attribute should be - used). - - The 'db_data' field is intended as a documentation field for the - tag itself, such as to document what this tag+category stands for - and display that in a web interface or similar. - - The main default use for Tags is to implement Aliases for objects. - this uses the 'aliases' tag category, which is also checked by the - default search functions of Evennia to allow quick searches by alias. - - """ - - db_key = models.CharField( - "key", max_length=255, null=True, help_text="tag identifier", db_index=True - ) - db_category = models.CharField( - "category", max_length=64, null=True, blank=True, help_text="tag category", db_index=True - ) - db_data = models.TextField( - "data", - null=True, - blank=True, - help_text="optional data field with extra information. This is not searched for.", - ) - # this is "objectdb" etc. Required behind the scenes - db_model = models.CharField( - "model", max_length=32, null=True, help_text="database model to Tag", db_index=True - ) - # this is None, alias or permission - db_tagtype = models.CharField( - "tagtype", - max_length=16, - null=True, - blank=True, - help_text="overall type of Tag", - db_index=True, - ) - - class Meta: - "Define Django meta options" - verbose_name = "Tag" - unique_together = (("db_key", "db_category", "db_tagtype", "db_model"),) - index_together = (("db_key", "db_category", "db_tagtype", "db_model"),) - - def __lt__(self, other): - return str(self) < str(other) - - def __str__(self): - return str( - "<Tag: %s%s>" - % (self.db_key, "(category:%s)" % self.db_category if self.db_category else "") - )
- - -# -# Handlers making use of the Tags model -# - - -
[docs]class TagHandler(object): - """ - Generic tag-handler. Accessed via TypedObject.tags. - - """ - - _m2m_fieldname = "db_tags" - _tagtype = None - -
[docs] def __init__(self, obj): - """ - Tags are stored internally in the TypedObject.db_tags m2m - field with an tag.db_model based on the obj the taghandler is - stored on and with a tagtype given by self.handlertype - - Args: - obj (object): The object on which the handler is set. - - """ - self.obj = obj - self._objid = obj.id - self._model = obj.__dbclass__.__name__.lower() - self._cache = {} - # store category names fully cached - self._catcache = {} - # full cache was run on all tags - self._cache_complete = False
- - def _query_all(self): - """ - Get all tags for this object. - - """ - query = { - "%s__id" % self._model: self._objid, - "tag__db_model": self._model, - "tag__db_tagtype": self._tagtype, - } - return [ - conn.tag - for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query) - ] - - def _fullcache(self): - """ - Cache all tags of this object. - - """ - if not _TYPECLASS_AGGRESSIVE_CACHE: - return - tags = self._query_all() - self._cache = dict( - ( - "%s-%s" - % ( - to_str(tag.db_key).lower(), - tag.db_category.lower() if tag.db_category else None, - ), - tag, - ) - for tag in tags - ) - self._cache_complete = True - - def _getcache(self, key=None, category=None): - """ - Retrieve from cache or database (always caches) - - Args: - key (str, optional): Tag key to query for - category (str, optional): Tag category - - Returns: - args (list): Returns a list of zero or more matches - found from cache or database. - Notes: - When given a category only, a search for all objects - of that category is done and a the category *name* is is - stored. This tells the system on subsequent calls that the - list of cached tags of this category is up-to-date - and that the cache can be queried for category matches - without missing any. - The TYPECLASS_AGGRESSIVE_CACHE=False setting will turn off - caching, causing each tag access to trigger a - database lookup. - - """ - key = key.strip().lower() if key else None - category = category.strip().lower() if category else None - if key: - cachekey = "%s-%s" % (key, category) - tag = _TYPECLASS_AGGRESSIVE_CACHE and self._cache.get(cachekey, None) - if tag and (not hasattr(tag, "pk") and tag.pk is None): - # clear out Tags deleted from elsewhere. We must search this anew. - tag = None - del self._cache[cachekey] - if tag: - return [tag] # return cached entity - else: - query = { - "%s__id" % self._model: self._objid, - "tag__db_model": self._model, - "tag__db_tagtype": self._tagtype, - "tag__db_key__iexact": key.lower(), - "tag__db_category__iexact": category.lower() if category else None, - } - conn = getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query) - if conn: - tag = conn[0].tag - if _TYPECLASS_AGGRESSIVE_CACHE: - self._cache[cachekey] = tag - return [tag] - else: - # only category given (even if it's None) - we can't - # assume the cache to be complete unless we have queried - # for this category before - catkey = "-%s" % category - if _TYPECLASS_AGGRESSIVE_CACHE and catkey in self._catcache: - return [tag for key, tag in self._cache.items() if key.endswith(catkey)] - else: - # we have to query to make this category up-date in the cache - query = { - "%s__id" % self._model: self._objid, - "tag__db_model": self._model, - "tag__db_tagtype": self._tagtype, - "tag__db_category__iexact": category.lower() if category else None, - } - tags = [ - conn.tag - for conn in getattr(self.obj, self._m2m_fieldname).through.objects.filter( - **query - ) - ] - if _TYPECLASS_AGGRESSIVE_CACHE: - for tag in tags: - cachekey = "%s-%s" % (tag.db_key, category) - self._cache[cachekey] = tag - # mark category cache as up-to-date - self._catcache[catkey] = True - return tags - return [] - - def _setcache(self, key, category, tag_obj): - """ - Update cache. - - Args: - key (str): A cleaned key string - category (str or None): A cleaned category name - tag_obj (tag): The newly saved tag - - """ - if not _TYPECLASS_AGGRESSIVE_CACHE: - return - if not key: # don't allow an empty key in cache - return - key, category = (key.strip().lower(), category.strip().lower() if category else category) - cachekey = "%s-%s" % (key, category) - catkey = "-%s" % category - self._cache[cachekey] = tag_obj - # mark that the category cache is no longer up-to-date - self._catcache.pop(catkey, None) - self._cache_complete = False - - def _delcache(self, key, category): - """ - Remove tag from cache - - Args: - key (str): A cleaned key string - category (str or None): A cleaned category name - - """ - key, category = (key.strip().lower(), category.strip().lower() if category else category) - catkey = "-%s" % category - if key: - cachekey = "%s-%s" % (key, category) - self._cache.pop(cachekey, None) - else: - [self._cache.pop(key, None) for key in self._cache if key.endswith(catkey)] - # mark that the category cache is no longer up-to-date - self._catcache.pop(catkey, None) - self._cache_complete = False - -
[docs] def reset_cache(self): - """ - Reset the cache from the outside. - - """ - self._cache_complete = False - self._cache = {} - self._catcache = {}
- -
[docs] def add(self, key=None, category=None, data=None): - """ - Add a new tag to the handler. - - Args: - key (str or list): The name of the tag to add. If a list, - add several Tags. - category (str, optional): Category of Tag. `None` is the default category. - data (str, optional): Info text about the tag(s) added. - This can not be used to store object-unique info but only - eventual info about the tag itself. - - Notes: - If the tag + category combination matches an already - existing Tag object, this will be re-used and no new Tag - will be created. - - """ - if not key: - return - if not self._cache_complete: - self._fullcache() - for tagstr in make_iter(key): - if not tagstr: - continue - tagstr = str(tagstr).strip().lower() - category = str(category).strip().lower() if category else category - data = str(data) if data is not None else None - # this will only create tag if no matches existed beforehand (it - # will overload data on an existing tag since that is not - # considered part of making the tag unique) - tagobj = self.obj.__class__.objects.create_tag( - key=tagstr, category=category, data=data, tagtype=self._tagtype - ) - getattr(self.obj, self._m2m_fieldname).add(tagobj) - self._setcache(tagstr, category, tagobj)
- -
[docs] def has(self, key=None, category=None, return_list=False): - """ - Checks if the given Tag (or list of Tags) exists on the object. - - Args: - key (str or iterable): The Tag key or tags to check for. - If `None`, search by category. - category (str, optional): Limit the check to Tags with this - category (note, that `None` is the default category). - - Returns: - has_tag (bool or list): If the Tag exists on this object or not. - If `tag` was given as an iterable then the return is a list of booleans. - - Raises: - ValueError: If neither `tag` nor `category` is given. - - """ - ret = [] - category = category.strip().lower() if category is not None else None - if key: - for tag_str in make_iter(key): - tag_str = tag_str.strip().lower() - ret.extend(bool(tag) for tag in self._getcache(tag_str, category)) - elif category: - ret.extend(bool(tag) for tag in self._getcache(category=category)) - else: - raise ValueError("Either tag or category must be provided.") - - if return_list: - return ret - - return ret[0] if len(ret) == 1 else ret
- -
[docs] def get(self, key=None, default=None, category=None, return_tagobj=False, return_list=False): - """ - Get the tag for the given key, category or combination of the two. - - Args: - key (str or list, optional): The tag or tags to retrieve. - default (any, optional): The value to return in case of no match. - category (str, optional): The Tag category to limit the - request to. Note that `None` is the valid, default - category. If no `key` is given, all tags of this category will be - returned. - return_tagobj (bool, optional): Return the Tag object itself - instead of a string representation of the Tag. - return_list (bool, optional): Always return a list, regardless - of number of matches. - - Returns: - tags (list): The matches, either string - representations of the tags or the Tag objects themselves - depending on `return_tagobj`. If 'default' is set, this - will be a list with the default value as its only element. - - """ - ret = [] - for keystr in make_iter(key): - # note - the _getcache call removes case sensitivity for us - ret.extend( - [ - tag if return_tagobj else to_str(tag.db_key) - for tag in self._getcache(keystr, category) - ] - ) - if return_list: - return ret if ret else [default] if default is not None else [] - return ret[0] if len(ret) == 1 else (ret if ret else default)
- -
[docs] def remove(self, key=None, category=None): - """ - Remove a tag from the handler based ond key and/or category. - - Args: - key (str or list, optional): The tag or tags to retrieve. - category (str, optional): The Tag category to limit the - request to. Note that `None` is the valid, default - category - Notes: - If neither key nor category is specified, this acts - as .clear(). - - """ - if not key: - # only category - self.clear(category=category) - return - - for key in make_iter(key): - if not (key or key.strip()): # we don't allow empty tags - continue - tagstr = key.strip().lower() - category = category.strip().lower() if category else category - - # This does not delete the tag object itself. Maybe it should do - # that when no objects reference the tag anymore (but how to check)? - # For now, tags are never deleted, only their connection to objects. - tagobj = getattr(self.obj, self._m2m_fieldname).filter( - db_key=tagstr, db_category=category, db_model=self._model, db_tagtype=self._tagtype - ) - if tagobj: - getattr(self.obj, self._m2m_fieldname).remove(tagobj[0]) - self._delcache(key, category)
- -
[docs] def clear(self, category=None): - """ - Remove all tags from the handler. - - Args: - category (str, optional): The Tag category to limit the - request to. Note that `None` is the valid, default - category. - - """ - if not self._cache_complete: - self._fullcache() - query = { - "%s__id" % self._model: self._objid, - "tag__db_model": self._model, - "tag__db_tagtype": self._tagtype, - } - if category: - query["tag__db_category"] = category.strip().lower() - getattr(self.obj, self._m2m_fieldname).through.objects.filter(**query).delete() - self._cache = {} - self._catcache = {} - self._cache_complete = False
- -
[docs] def all(self, return_key_and_category=False, return_objs=False): - """ - Get all tags in this handler, regardless of category. - - Args: - return_key_and_category (bool, optional): Return a list of - tuples `[(key, category), ...]`. - return_objs (bool, optional): Return tag objects. - - Returns: - tags (list): A list of tag keys `[tagkey, tagkey, ...]` or - a list of tuples `[(key, category), ...]` if - `return_key_and_category` is set. - - """ - if _TYPECLASS_AGGRESSIVE_CACHE: - if not self._cache_complete: - self._fullcache() - tags = sorted(self._cache.values()) - else: - tags = sorted(self._query_all()) - - if return_key_and_category: - # return tuple (key, category) - return [(to_str(tag.db_key), tag.db_category) for tag in tags] - elif return_objs: - return tags - else: - return [to_str(tag.db_key) for tag in tags]
- -
[docs] def batch_add(self, *args): - """ - Batch-add tags from a list of tuples. - - Args: - *args (tuple or str): Each argument should be a `tagstr` keys or tuple - `(keystr, category)` or `(keystr, category, data)`. It's possible to mix input - types. - - Notes: - This will generate a mimimal number of self.add calls, - based on the number of categories involved (including - `None`) (data is not unique and may be overwritten by the content - of a latter tuple with the same category). - - """ - keys = defaultdict(list) - data = {} - for tup in args: - tup = make_iter(tup) - nlen = len(tup) - if nlen == 1: # just a key - keys[None].append(tup[0]) - elif nlen == 2: - keys[tup[1]].append(tup[0]) - else: - keys[tup[1]].append(tup[0]) - data[tup[1]] = tup[2] # overwrite previous - for category, key in keys.items(): - self.add(key=key, category=category, data=data.get(category, None))
- - def __str__(self): - return ",".join(self.all())
- - -
[docs]class AliasHandler(TagHandler): - """ - A handler for the Alias Tag type. - - """ - - _tagtype = "alias"
- - -
[docs]class PermissionHandler(TagHandler): - """ - A handler for the Permission Tag type. - - """ - - _tagtype = "permission" - -
[docs] def check(self, *permissions, require_all=False): - """ - Straight-up check the provided permission against this handler. The check will pass if - - - any/all given permission exists on the handler (depending on if `require_all` is set). - - If handler sits on puppeted object and this is a hierarachical perm, the puppeting - Account's permission will also be included in the check, prioritizing the Account's perm - (this avoids escalation exploits by puppeting a too-high prio character) - - a permission is also considered to exist on the handler, if it is *lower* than - a permission on the handler and this is a 'hierarchical' permission given - in `settings.PERMISSION_HIERARCHY`. Example: If the 'Developer' hierarchical - perm perm is set on the handler, and we check for the 'Builder' perm, the - check will pass. - - Args: - *permissions (str): Any number of permissions to check. By default, - the permission is passed if any of these (or higher, if a - hierarchical permission defined in settings.PERMISSION_HIERARCHY) - exists in the handler. Permissions are not case-sensitive. - require_all (bool): If set, *all* provided permissions much pass - the check for the entire check to pass. By default only one - needs to pass. - - Returns: - bool: If the provided permission(s) pass the check on this handler. - - Example: - :: - can_enter = obj.permissions.check("Blacksmith", "Builder") - - Notes: - This works the same way as the `perms` lockfunc and could be - replicated with a lock check against the lockstring - - "locktype: perm(perm1) OR perm(perm2) OR ..." - - (using AND for the `require_all` condition). - - """ - if require_all: - return all(perm_lockfunc(self.obj, None, perm) for perm in permissions) - else: - return any(perm_lockfunc(self.obj, None, perm) for perm in permissions)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/ansi.html b/docs/0.9.5/_modules/evennia/utils/ansi.html deleted file mode 100644 index 75b16fa2e4..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/ansi.html +++ /dev/null @@ -1,1608 +0,0 @@ - - - - - - - - evennia.utils.ansi — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.utils.ansi

-"""
-ANSI - Gives colour to text.
-
-Use the codes defined in the *ANSIParser* class to apply colour to text. The
-`parse_ansi` function in this module parses text for markup and `strip_ansi`
-removes it.
-
-You should usually not need to call `parse_ansi` explicitly; it is run by
-Evennia just before returning data to/from the user. Alternative markup is
-possible by overriding the parser class (see also contrib/ for deprecated
-markup schemes).
-
-
-Supported standards:
-
-- ANSI 8 bright and 8 dark fg (foreground) colors
-- ANSI 8 dark bg (background) colors
-- 'ANSI' 8 bright bg colors 'faked' with xterm256 (bright bg not included in ANSI standard)
-- Xterm256 - 255 fg/bg colors + 26 greyscale fg/bg colors
-
-## Markup
-
-ANSI colors: `r` ed, `g` reen, `y` ellow, `b` lue, `m` agenta, `c` yan, `n` ormal (no color).
-Capital letters indicate the 'dark' variant.
-
-- `|r` fg bright red
-- `|R` fg dark red
-- `|[r` bg bright red
-- `|[R` bg dark red
-- `|[R|g` bg dark red, fg bright green
-
-```python
-"This is |rRed text|n and this is normal again."
-
-```
-
-Xterm256 colors are given as RGB (Red-Green-Blue), with values 0-5:
-
-- `|500` fg bright red
-- `|050` fg bright green
-- `|005` fg bright blue
-- `|110` fg dark brown
-- `|425` fg pink
-- `|[431` bg orange
-
-Xterm256 greyscale:
-
-- `|=a` fg black
-- `|=g` fg dark grey
-- `|=o` fg middle grey
-- `|=v` fg bright grey
-- `|=z` fg white
-- `|[=r` bg middle grey
-
-```python
-"This is |500Red text|n and this is normal again."
-"This is |[=jText on dark grey background"
-
-```
-
-----
-
-"""
-import functools
-
-import re
-from collections import OrderedDict
-
-from django.conf import settings
-
-from evennia.utils import utils
-from evennia.utils import logger
-
-from evennia.utils.utils import to_str
-
-MXP_ENABLED = settings.MXP_ENABLED
-
-
-# ANSI definitions
-
-ANSI_BEEP = "\07"
-ANSI_ESCAPE = "\033"
-ANSI_NORMAL = "\033[0m"
-
-ANSI_UNDERLINE = "\033[4m"
-ANSI_HILITE = "\033[1m"
-ANSI_UNHILITE = "\033[22m"
-ANSI_BLINK = "\033[5m"
-ANSI_INVERSE = "\033[7m"
-ANSI_INV_HILITE = "\033[1;7m"
-ANSI_INV_BLINK = "\033[7;5m"
-ANSI_BLINK_HILITE = "\033[1;5m"
-ANSI_INV_BLINK_HILITE = "\033[1;5;7m"
-
-# Foreground colors
-ANSI_BLACK = "\033[30m"
-ANSI_RED = "\033[31m"
-ANSI_GREEN = "\033[32m"
-ANSI_YELLOW = "\033[33m"
-ANSI_BLUE = "\033[34m"
-ANSI_MAGENTA = "\033[35m"
-ANSI_CYAN = "\033[36m"
-ANSI_WHITE = "\033[37m"
-
-# Background colors
-ANSI_BACK_BLACK = "\033[40m"
-ANSI_BACK_RED = "\033[41m"
-ANSI_BACK_GREEN = "\033[42m"
-ANSI_BACK_YELLOW = "\033[43m"
-ANSI_BACK_BLUE = "\033[44m"
-ANSI_BACK_MAGENTA = "\033[45m"
-ANSI_BACK_CYAN = "\033[46m"
-ANSI_BACK_WHITE = "\033[47m"
-
-# Formatting Characters
-ANSI_RETURN = "\r\n"
-ANSI_TAB = "\t"
-ANSI_SPACE = " "
-
-# Escapes
-ANSI_ESCAPES = ("{{", "\\\\", "\|\|")
-
-_PARSE_CACHE = OrderedDict()
-_PARSE_CACHE_SIZE = 10000
-
-_COLOR_NO_DEFAULT = settings.COLOR_NO_DEFAULT
-
-
-
[docs]class ANSIParser(object): - """ - A class that parses ANSI markup - to ANSI command sequences - - We also allow to escape colour codes - by prepending with an extra `|`. - - """ - - # Mapping using {r {n etc - - ansi_map = [ - # alternative |-format - (r"|n", ANSI_NORMAL), # reset - (r"|/", ANSI_RETURN), # line break - (r"|-", ANSI_TAB), # tab - (r"|>", ANSI_SPACE * 4), # indent (4 spaces) - (r"|_", ANSI_SPACE), # space - (r"|*", ANSI_INVERSE), # invert - (r"|^", ANSI_BLINK), # blinking text (very annoying and not supported by all clients) - (r"|u", ANSI_UNDERLINE), # underline - (r"|r", ANSI_HILITE + ANSI_RED), - (r"|g", ANSI_HILITE + ANSI_GREEN), - (r"|y", ANSI_HILITE + ANSI_YELLOW), - (r"|b", ANSI_HILITE + ANSI_BLUE), - (r"|m", ANSI_HILITE + ANSI_MAGENTA), - (r"|c", ANSI_HILITE + ANSI_CYAN), - (r"|w", ANSI_HILITE + ANSI_WHITE), # pure white - (r"|x", ANSI_HILITE + ANSI_BLACK), # dark grey - (r"|R", ANSI_UNHILITE + ANSI_RED), - (r"|G", ANSI_UNHILITE + ANSI_GREEN), - (r"|Y", ANSI_UNHILITE + ANSI_YELLOW), - (r"|B", ANSI_UNHILITE + ANSI_BLUE), - (r"|M", ANSI_UNHILITE + ANSI_MAGENTA), - (r"|C", ANSI_UNHILITE + ANSI_CYAN), - (r"|W", ANSI_UNHILITE + ANSI_WHITE), # light grey - (r"|X", ANSI_UNHILITE + ANSI_BLACK), # pure black - # hilight-able colors - (r"|h", ANSI_HILITE), - (r"|H", ANSI_UNHILITE), - (r"|!R", ANSI_RED), - (r"|!G", ANSI_GREEN), - (r"|!Y", ANSI_YELLOW), - (r"|!B", ANSI_BLUE), - (r"|!M", ANSI_MAGENTA), - (r"|!C", ANSI_CYAN), - (r"|!W", ANSI_WHITE), # light grey - (r"|!X", ANSI_BLACK), # pure black - # normal ANSI backgrounds - (r"|[R", ANSI_BACK_RED), - (r"|[G", ANSI_BACK_GREEN), - (r"|[Y", ANSI_BACK_YELLOW), - (r"|[B", ANSI_BACK_BLUE), - (r"|[M", ANSI_BACK_MAGENTA), - (r"|[C", ANSI_BACK_CYAN), - (r"|[W", ANSI_BACK_WHITE), # light grey background - (r"|[X", ANSI_BACK_BLACK), # pure black background - ] - - ansi_xterm256_bright_bg_map = [ - # "bright" ANSI backgrounds using xterm256 since ANSI - # standard does not support it (will - # fallback to dark ANSI background colors if xterm256 - # is not supported by client) - # |-style variations - (r"|[r", r"|[500"), - (r"|[g", r"|[050"), - (r"|[y", r"|[550"), - (r"|[b", r"|[005"), - (r"|[m", r"|[505"), - (r"|[c", r"|[055"), - (r"|[w", r"|[555"), # white background - (r"|[x", r"|[222"), - ] # dark grey background - - # xterm256. These are replaced directly by - # the sub_xterm256 method - - if settings.COLOR_NO_DEFAULT: - ansi_map = settings.COLOR_ANSI_EXTRA_MAP - xterm256_fg = settings.COLOR_XTERM256_EXTRA_FG - xterm256_bg = settings.COLOR_XTERM256_EXTRA_BG - xterm256_gfg = settings.COLOR_XTERM256_EXTRA_GFG - xterm256_gbg = settings.COLOR_XTERM256_EXTRA_GBG - ansi_xterm256_bright_bg_map = settings.COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP - else: - xterm256_fg = [r"\|([0-5])([0-5])([0-5])"] # |123 - foreground colour - xterm256_bg = [r"\|\[([0-5])([0-5])([0-5])"] # |[123 - background colour - xterm256_gfg = [r"\|=([a-z])"] # |=a - greyscale foreground - xterm256_gbg = [r"\|\[=([a-z])"] # |[=a - greyscale background - ansi_map += settings.COLOR_ANSI_EXTRA_MAP - xterm256_fg += settings.COLOR_XTERM256_EXTRA_FG - xterm256_bg += settings.COLOR_XTERM256_EXTRA_BG - xterm256_gfg += settings.COLOR_XTERM256_EXTRA_GFG - xterm256_gbg += settings.COLOR_XTERM256_EXTRA_GBG - ansi_xterm256_bright_bg_map += settings.COLOR_ANSI_XTERM256_BRIGHT_BG_EXTRA_MAP - - mxp_re = r"\|lc(.*?)\|lt(.*?)\|le" - mxp_url_re = r"\|lu(.*?)\|lt(.*?)\|le" - - # prepare regex matching - brightbg_sub = re.compile( - r"|".join([r"(?<!\|)%s" % re.escape(tup[0]) for tup in ansi_xterm256_bright_bg_map]), - re.DOTALL, - ) - xterm256_fg_sub = re.compile(r"|".join(xterm256_fg), re.DOTALL) - xterm256_bg_sub = re.compile(r"|".join(xterm256_bg), re.DOTALL) - xterm256_gfg_sub = re.compile(r"|".join(xterm256_gfg), re.DOTALL) - xterm256_gbg_sub = re.compile(r"|".join(xterm256_gbg), re.DOTALL) - - # xterm256_sub = re.compile(r"|".join([tup[0] for tup in xterm256_map]), re.DOTALL) - ansi_sub = re.compile(r"|".join([re.escape(tup[0]) for tup in ansi_map]), re.DOTALL) - mxp_sub = re.compile(mxp_re, re.DOTALL) - mxp_url_sub = re.compile(mxp_url_re, re.DOTALL) - - # used by regex replacer to correctly map ansi sequences - ansi_map_dict = dict(ansi_map) - ansi_xterm256_bright_bg_map_dict = dict(ansi_xterm256_bright_bg_map) - - # prepare matching ansi codes overall - ansi_re = r"\033\[[0-9;]+m" - ansi_regex = re.compile(ansi_re) - - # escapes - these double-chars will be replaced with a single - # instance of each - ansi_escapes = re.compile(r"(%s)" % "|".join(ANSI_ESCAPES), re.DOTALL) - - # tabs/linebreaks |/ and |- should be able to be cleaned - unsafe_tokens = re.compile(r"\|\/|\|-", re.DOTALL) - -
[docs] def sub_ansi(self, ansimatch): - """ - Replacer used by `re.sub` to replace ANSI - markers with correct ANSI sequences - - Args: - ansimatch (re.matchobject): The match. - - Returns: - processed (str): The processed match string. - - """ - return self.ansi_map_dict.get(ansimatch.group(), "")
- -
[docs] def sub_brightbg(self, ansimatch): - """ - Replacer used by `re.sub` to replace ANSI - bright background markers with Xterm256 replacement - - Args: - ansimatch (re.matchobject): The match. - - Returns: - processed (str): The processed match string. - - """ - return self.ansi_xterm256_bright_bg_map_dict.get(ansimatch.group(), "")
- -
[docs] def sub_xterm256(self, rgbmatch, use_xterm256=False, color_type="fg"): - """ - This is a replacer method called by `re.sub` with the matched - tag. It must return the correct ansi sequence. - - It checks `self.do_xterm256` to determine if conversion - to standard ANSI should be done or not. - - Args: - rgbmatch (re.matchobject): The match. - use_xterm256 (bool, optional): Don't convert 256-colors to 16. - color_type (str): One of 'fg', 'bg', 'gfg', 'gbg'. - - Returns: - processed (str): The processed match string. - - """ - if not rgbmatch: - return "" - - # get tag, stripping the initial marker - # rgbtag = rgbmatch.group()[1:] - - background = color_type in ("bg", "gbg") - grayscale = color_type in ("gfg", "gbg") - - if not grayscale: - # 6x6x6 color-cube (xterm indexes 16-231) - try: - red, green, blue = [int(val) for val in rgbmatch.groups() if val is not None] - except (IndexError, ValueError): - logger.log_trace() - return rgbmatch.group(0) - else: - # grayscale values (xterm indexes 0, 232-255, 15) for full spectrum - try: - letter = [val for val in rgbmatch.groups() if val is not None][0] - except IndexError: - logger.log_trace() - return rgbmatch.group(0) - - if letter == "a": - colval = 16 # pure black @ index 16 (first color cube entry) - elif letter == "z": - colval = 231 # pure white @ index 231 (last color cube entry) - else: - # letter in range [b..y] (exactly 24 values!) - colval = 134 + ord(letter) - - # ansi fallback logic expects r,g,b values in [0..5] range - gray = (ord(letter) - 97) / 5.0 - red, green, blue = gray, gray, gray - - if use_xterm256: - - if not grayscale: - colval = 16 + (red * 36) + (green * 6) + blue - - return "\033[%s8;5;%sm" % (3 + int(background), colval) - # replaced since some clients (like Potato) does not accept codes with leading zeroes, - # see issue #1024. - # return "\033[%s8;5;%s%s%sm" % (3 + int(background), colval // 100, (colval % 100) // 10, colval%10) # noqa - - else: - # xterm256 not supported, convert the rgb value to ansi instead - if red == green == blue and red < 3: - if background: - return ANSI_BACK_BLACK - elif red >= 1: - return ANSI_HILITE + ANSI_BLACK - else: - return ANSI_NORMAL + ANSI_BLACK - elif red == green == blue: - if background: - return ANSI_BACK_WHITE - elif red >= 4: - return ANSI_HILITE + ANSI_WHITE - else: - return ANSI_NORMAL + ANSI_WHITE - elif red > green and red > blue: - if background: - return ANSI_BACK_RED - elif red >= 3: - return ANSI_HILITE + ANSI_RED - else: - return ANSI_NORMAL + ANSI_RED - elif red == green and red > blue: - if background: - return ANSI_BACK_YELLOW - elif red >= 3: - return ANSI_HILITE + ANSI_YELLOW - else: - return ANSI_NORMAL + ANSI_YELLOW - elif red == blue and red > green: - if background: - return ANSI_BACK_MAGENTA - elif red >= 3: - return ANSI_HILITE + ANSI_MAGENTA - else: - return ANSI_NORMAL + ANSI_MAGENTA - elif green > blue: - if background: - return ANSI_BACK_GREEN - elif green >= 3: - return ANSI_HILITE + ANSI_GREEN - else: - return ANSI_NORMAL + ANSI_GREEN - elif green == blue: - if background: - return ANSI_BACK_CYAN - elif green >= 3: - return ANSI_HILITE + ANSI_CYAN - else: - return ANSI_NORMAL + ANSI_CYAN - else: # mostly blue - if background: - return ANSI_BACK_BLUE - elif blue >= 3: - return ANSI_HILITE + ANSI_BLUE - else: - return ANSI_NORMAL + ANSI_BLUE
- -
[docs] def strip_raw_codes(self, string): - """ - Strips raw ANSI codes from a string. - - Args: - string (str): The string to strip. - - Returns: - string (str): The processed string. - - """ - return self.ansi_regex.sub("", string)
- -
[docs] def strip_mxp(self, string): - """ - Strips all MXP codes from a string. - - Args: - string (str): The string to strip. - - Returns: - string (str): The processed string. - - """ - string = self.mxp_sub.sub(r"\2", string) - string = self.mxp_url_sub.sub(r"\1", string) # replace with url verbatim - return string
- -
[docs] def strip_unsafe_tokens(self, string): - """ - Strip explicitly ansi line breaks and tabs. - - """ - return self.unsafe_tokens.sub('', string)
- -
[docs] def parse_ansi(self, string, strip_ansi=False, xterm256=False, mxp=False): - """ - Parses a string, subbing color codes according to the stored - mapping. - - Args: - string (str): The string to parse. - strip_ansi (boolean, optional): Strip all found ansi markup. - xterm256 (boolean, optional): If actually using xterm256 or if - these values should be converted to 16-color ANSI. - mxp (boolean, optional): Parse MXP commands in string. - - Returns: - string (str): The parsed string. - - """ - if hasattr(string, "_raw_string"): - if strip_ansi: - return string.clean() - else: - return string.raw() - - if not string: - return "" - - # check cached parsings - global _PARSE_CACHE - cachekey = "%s-%s-%s-%s" % (string, strip_ansi, xterm256, mxp) - if cachekey in _PARSE_CACHE: - return _PARSE_CACHE[cachekey] - - # pre-convert bright colors to xterm256 color tags - string = self.brightbg_sub.sub(self.sub_brightbg, string) - - def do_xterm256_fg(part): - return self.sub_xterm256(part, xterm256, "fg") - - def do_xterm256_bg(part): - return self.sub_xterm256(part, xterm256, "bg") - - def do_xterm256_gfg(part): - return self.sub_xterm256(part, xterm256, "gfg") - - def do_xterm256_gbg(part): - return self.sub_xterm256(part, xterm256, "gbg") - - in_string = utils.to_str(string) - - # do string replacement - parsed_string = [] - parts = self.ansi_escapes.split(in_string) + [" "] - for part, sep in zip(parts[::2], parts[1::2]): - pstring = self.xterm256_fg_sub.sub(do_xterm256_fg, part) - pstring = self.xterm256_bg_sub.sub(do_xterm256_bg, pstring) - pstring = self.xterm256_gfg_sub.sub(do_xterm256_gfg, pstring) - pstring = self.xterm256_gbg_sub.sub(do_xterm256_gbg, pstring) - pstring = self.ansi_sub.sub(self.sub_ansi, pstring) - parsed_string.append("%s%s" % (pstring, sep[0].strip())) - parsed_string = "".join(parsed_string) - - if not mxp: - parsed_string = self.strip_mxp(parsed_string) - - if strip_ansi: - # remove all ansi codes (including those manually - # inserted in string) - return self.strip_raw_codes(parsed_string) - - # cache and crop old cache - _PARSE_CACHE[cachekey] = parsed_string - if len(_PARSE_CACHE) > _PARSE_CACHE_SIZE: - _PARSE_CACHE.popitem(last=False) - - return parsed_string
- - -ANSI_PARSER = ANSIParser() - - -# -# Access function -# - - -
[docs]def parse_ansi(string, strip_ansi=False, parser=ANSI_PARSER, xterm256=False, mxp=False): - """ - Parses a string, subbing color codes as needed. - - Args: - string (str): The string to parse. - strip_ansi (bool, optional): Strip all ANSI sequences. - parser (ansi.AnsiParser, optional): A parser instance to use. - xterm256 (bool, optional): Support xterm256 or not. - mxp (bool, optional): Support MXP markup or not. - - Returns: - string (str): The parsed string. - - """ - return parser.parse_ansi(string, strip_ansi=strip_ansi, xterm256=xterm256, mxp=mxp)
- - -
[docs]def strip_ansi(string, parser=ANSI_PARSER): - """ - Strip all ansi from the string. This handles the Evennia-specific - markup. - - Args: - string (str): The string to strip. - parser (ansi.AnsiParser, optional): The parser to use. - - Returns: - string (str): The stripped string. - - """ - return parser.parse_ansi(string, strip_ansi=True)
- - -
[docs]def strip_raw_ansi(string, parser=ANSI_PARSER): - """ - Remove raw ansi codes from string. This assumes pure - ANSI-bytecodes in the string. - - Args: - string (str): The string to parse. - parser (bool, optional): The parser to use. - - Returns: - string (str): the stripped string. - - """ - return parser.strip_raw_codes(string)
- - -
[docs]def strip_unsafe_tokens(string, parser=ANSI_PARSER): - """ - Strip markup that can be used to create visual exploits - (notably linebreaks and tags) - - """ - return parser.strip_unsafe_tokens(string)
- - -
[docs]def strip_mxp(string, parser=ANSI_PARSER): - """ - Strip MXP markup. - - """ - return parser.strip_mxp(string)
- - -
[docs]def raw(string): - """ - Escapes a string into a form which won't be colorized by the ansi - parser. - - Returns: - string (str): The raw, escaped string. - - """ - return string.replace("{", "{{").replace("|", "||")
- - -# ------------------------------------------------------------ -# -# ANSIString - ANSI-aware string class -# -# ------------------------------------------------------------ - - -def _spacing_preflight(func): - """ - This wrapper function is used to do some preflight checks on - functions used for padding ANSIStrings. - - """ - - @functools.wraps(func) - def wrapped(self, width=78, fillchar=None): - if fillchar is None: - fillchar = " " - if (len(fillchar) != 1) or (not isinstance(fillchar, str)): - raise TypeError("must be char, not %s" % type(fillchar)) - if not isinstance(width, int): - raise TypeError("integer argument expected, got %s" % type(width)) - _difference = width - len(self) - if _difference <= 0: - return self - return func(self, width, fillchar, _difference) - - return wrapped - - -def _query_super(func_name): - """ - Have the string class handle this with the cleaned string instead - of ANSIString. - - """ - - def wrapped(self, *args, **kwargs): - return getattr(self.clean(), func_name)(*args, **kwargs) - - return wrapped - - -def _on_raw(func_name): - """ - Like query_super, but makes the operation run on the raw string. - - """ - - def wrapped(self, *args, **kwargs): - args = list(args) - try: - string = args.pop(0) - if hasattr(string, "_raw_string"): - args.insert(0, string.raw()) - else: - args.insert(0, string) - except IndexError: - # just skip out if there are no more strings - pass - result = getattr(self._raw_string, func_name)(*args, **kwargs) - if isinstance(result, str): - return ANSIString(result, decoded=True) - return result - - return wrapped - - -def _transform(func_name): - """ - Some string functions, like those manipulating capital letters, - return a string the same length as the original. This function - allows us to do the same, replacing all the non-coded characters - with the resulting string. - - """ - - def wrapped(self, *args, **kwargs): - replacement_string = _query_super(func_name)(self, *args, **kwargs) - to_string = [] - char_counter = 0 - for index in range(0, len(self._raw_string)): - if index in self._code_indexes: - to_string.append(self._raw_string[index]) - elif index in self._char_indexes: - to_string.append(replacement_string[char_counter]) - char_counter += 1 - return ANSIString( - "".join(to_string), - decoded=True, - code_indexes=self._code_indexes, - char_indexes=self._char_indexes, - clean_string=replacement_string, - ) - - return wrapped - - -
[docs]class ANSIMeta(type): - """ - Many functions on ANSIString are just light wrappers around the string - base class. We apply them here, as part of the classes construction. - - """ - -
[docs] def __init__(cls, *args, **kwargs): - for func_name in [ - "count", - "startswith", - "endswith", - "find", - "index", - "isalnum", - "isalpha", - "isdigit", - "islower", - "isspace", - "istitle", - "isupper", - "rfind", - "rindex", - "__len__", - ]: - setattr(cls, func_name, _query_super(func_name)) - for func_name in ["__mod__", "expandtabs", "decode", "replace", "format", "encode"]: - setattr(cls, func_name, _on_raw(func_name)) - for func_name in ["capitalize", "translate", "lower", "upper", "swapcase"]: - setattr(cls, func_name, _transform(func_name)) - super().__init__(*args, **kwargs)
- - -
[docs]class ANSIString(str, metaclass=ANSIMeta): - """ - Unicode-like object that is aware of ANSI codes. - - This class can be used nearly identically to strings, in that it will - report string length, handle slices, etc, much like a string object - would. The methods should be used identically as string methods are. - - There is at least one exception to this (and there may be more, though - they have not come up yet). When using ''.join() or u''.join() on an - ANSIString, color information will get lost. You must use - ANSIString('').join() to preserve color information. - - This implementation isn't perfectly clean, as it doesn't really have an - understanding of what the codes mean in order to eliminate - redundant characters-- though cleaning up the strings might end up being - inefficient and slow without some C code when dealing with larger values. - Such enhancements could be made as an enhancement to ANSI_PARSER - if needed, however. - - If one is going to use ANSIString, one should generally avoid converting - away from it until one is about to send information on the wire. This is - because escape sequences in the string may otherwise already be decoded, - and taken literally the second time around. - - """ - - # A compiled Regex for the format mini-language: - # https://docs.python.org/3/library/string.html#formatspec - re_format = re.compile( - r"(?i)(?P<just>(?P<fill>.)?(?P<align>\<|\>|\=|\^))?(?P<sign>\+|\-| )?(?P<alt>\#)?" - r"(?P<zero>0)?(?P<width>\d+)?(?P<grouping>\_|\,)?(?:\.(?P<precision>\d+))?" - r"(?P<type>b|c|d|e|E|f|F|g|G|n|o|s|x|X|%)?" - ) - - def __new__(cls, *args, **kwargs): - """ - When creating a new ANSIString, you may use a custom parser that has - the same attributes as the standard one, and you may declare the - string to be handled as already decoded. It is important not to double - decode strings, as escapes can only be respected once. - - Internally, ANSIString can also passes itself precached code/character - indexes and clean strings to avoid doing extra work when combining - ANSIStrings. - - """ - string = args[0] - if not isinstance(string, str): - string = to_str(string) - parser = kwargs.get("parser", ANSI_PARSER) - decoded = kwargs.get("decoded", False) or hasattr(string, "_raw_string") - code_indexes = kwargs.pop("code_indexes", None) - char_indexes = kwargs.pop("char_indexes", None) - clean_string = kwargs.pop("clean_string", None) - # All True, or All False, not just one. - checks = [x is None for x in [code_indexes, char_indexes, clean_string]] - if not len(set(checks)) == 1: - raise ValueError( - "You must specify code_indexes, char_indexes, " - "and clean_string together, or not at all." - ) - if not all(checks): - decoded = True - if not decoded: - # Completely new ANSI String - clean_string = parser.parse_ansi(string, strip_ansi=True, mxp=MXP_ENABLED) - string = parser.parse_ansi(string, xterm256=True, mxp=MXP_ENABLED) - elif clean_string is not None: - # We have an explicit clean string. - pass - elif hasattr(string, "_clean_string"): - # It's already an ANSIString - clean_string = string._clean_string - code_indexes = string._code_indexes - char_indexes = string._char_indexes - string = string._raw_string - else: - # It's a string that has been pre-ansi decoded. - clean_string = parser.strip_raw_codes(string) - - if not isinstance(string, str): - string = string.decode("utf-8") - - ansi_string = super().__new__(ANSIString, to_str(clean_string)) - ansi_string._raw_string = string - ansi_string._clean_string = clean_string - ansi_string._code_indexes = code_indexes - ansi_string._char_indexes = char_indexes - return ansi_string - - def __str__(self): - return self._raw_string - - def __format__(self, format_spec): - """ - This magic method covers ANSIString's behavior within a str.format() or f-string. - - Current features supported: fill, align, width. - - Args: - format_spec (str): The format specification passed by f-string or str.format(). This is - a string such as "0<30" which would mean "left justify to 30, filling with zeros". - The full specification can be found at - https://docs.python.org/3/library/string.html#formatspec - - Returns: - ansi_str (str): The formatted ANSIString's .raw() form, for display. - - """ - # This calls the compiled regex stored on ANSIString's class to analyze the format spec. - # It returns a dictionary. - format_data = self.re_format.match(format_spec).groupdict() - clean = self.clean() - base_output = ANSIString(self.raw()) - align = format_data.get("align", "<") - fill = format_data.get("fill", " ") - - # Need to coerce width into an integer. We can be certain that it's numeric thanks to regex. - width = format_data.get("width", None) - if width is None: - width = len(clean) - else: - width = int(width) - - if align == "<": - base_output = self.ljust(width, fill) - elif align == ">": - base_output = self.rjust(width, fill) - elif align == "^": - base_output = self.center(width, fill) - elif align == "=": - pass - - # Return the raw string with ANSI markup, ready to be displayed. - return base_output.raw() - - def __repr__(self): - """ - Let's make the repr the command that would actually be used to - construct this object, for convenience and reference. - - """ - return "ANSIString(%s, decoded=True)" % repr(self._raw_string) - -
[docs] def __init__(self, *_, **kwargs): - """ - When the ANSIString is first initialized, a few internal variables - have to be set. - - The first is the parser. It is possible to replace Evennia's standard - ANSI parser with one of your own syntax if you wish, so long as it - implements the same interface. - - The second is the _raw_string. This is the original "dumb" string - with ansi escapes that ANSIString represents. - - The third thing to set is the _clean_string. This is a string that is - devoid of all ANSI Escapes. - - Finally, _code_indexes and _char_indexes are defined. These are lookup - tables for which characters in the raw string are related to ANSI - escapes, and which are for the readable text. - - """ - self.parser = kwargs.pop("parser", ANSI_PARSER) - super().__init__() - if self._code_indexes is None: - self._code_indexes, self._char_indexes = self._get_indexes()
- - @staticmethod - def _shifter(iterable, offset): - """ - Takes a list of integers, and produces a new one incrementing all - by a number. - - """ - if not offset: - return iterable - return [i + offset for i in iterable] - - @classmethod - def _adder(cls, first, second): - """ - Joins two ANSIStrings, preserving calculated info. - - """ - - raw_string = first._raw_string + second._raw_string - clean_string = first._clean_string + second._clean_string - code_indexes = first._code_indexes[:] - char_indexes = first._char_indexes[:] - code_indexes.extend(cls._shifter(second._code_indexes, len(first._raw_string))) - char_indexes.extend(cls._shifter(second._char_indexes, len(first._raw_string))) - return ANSIString( - raw_string, - code_indexes=code_indexes, - char_indexes=char_indexes, - clean_string=clean_string, - ) - - def __add__(self, other): - """ - We have to be careful when adding two strings not to reprocess things - that don't need to be reprocessed, lest we end up with escapes being - interpreted literally. - - """ - if not isinstance(other, str): - return NotImplemented - if not isinstance(other, ANSIString): - other = ANSIString(other) - return self._adder(self, other) - - def __radd__(self, other): - """ - Likewise, if we're on the other end. - - """ - if not isinstance(other, str): - return NotImplemented - if not isinstance(other, ANSIString): - other = ANSIString(other) - return self._adder(other, self) - - def __getslice__(self, i, j): - """ - This function is deprecated, so we just make it call the proper - function. - - """ - return self.__getitem__(slice(i, j)) - - def _slice(self, slc): - """ - This function takes a slice() object. - - Slices have to be handled specially. Not only are they able to specify - a start and end with [x:y], but many forget that they can also specify - an interval with [x:y:z]. As a result, not only do we have to track - the ANSI Escapes that have played before the start of the slice, we - must also replay any in these intervals, should they exist. - - Thankfully, slicing the _char_indexes table gives us the actual - indexes that need slicing in the raw string. We can check between - those indexes to figure out what escape characters need to be - replayed. - - """ - char_indexes = self._char_indexes - slice_indexes = char_indexes[slc] - # If it's the end of the string, we need to append final color codes. - if not slice_indexes: - # if we find no characters it may be because we are just outside - # of the interval, using an open-ended slice. We must replay all - # of the escape characters until/after this point. - if char_indexes: - if slc.start is None and slc.stop is None: - # a [:] slice of only escape characters - return ANSIString(self._raw_string[slc]) - if slc.start is None: - # this is a [:x] slice - return ANSIString(self._raw_string[:char_indexes[0]]) - if slc.stop is None: - # a [x:] slice - return ANSIString(self._raw_string[char_indexes[-1] + 1:]) - return ANSIString("") - try: - string = self[slc.start or 0]._raw_string - except IndexError: - return ANSIString("") - last_mark = slice_indexes[0] - # Check between the slice intervals for escape sequences. - i = None - for i in slice_indexes[1:]: - for index in range(last_mark, i): - if index in self._code_indexes: - string += self._raw_string[index] - last_mark = i - try: - string += self._raw_string[i] - except IndexError: - # raw_string not long enough - pass - if i is not None: - append_tail = self._get_interleving(char_indexes.index(i) + 1) - else: - append_tail = "" - return ANSIString(string + append_tail, decoded=True) - - def __getitem__(self, item): - """ - Gateway for slices and getting specific indexes in the ANSIString. If - this is a regexable ANSIString, it will get the data from the raw - string instead, bypassing ANSIString's intelligent escape skipping, - for reasons explained in the __new__ method's docstring. - - """ - if isinstance(item, slice): - # Slices must be handled specially. - return self._slice(item) - try: - self._char_indexes[item] - except IndexError: - raise IndexError("ANSIString Index out of range") - # Get character codes after the index as well. - if self._char_indexes[-1] == self._char_indexes[item]: - append_tail = self._get_interleving(item + 1) - else: - append_tail = "" - item = self._char_indexes[item] - - clean = self._raw_string[item] - result = "" - # Get the character they're after, and replay all escape sequences - # previous to it. - for index in range(0, item + 1): - if index in self._code_indexes: - result += self._raw_string[index] - return ANSIString(result + clean + append_tail, decoded=True) - -
[docs] def clean(self): - """ - Return a string object *without* the ANSI escapes. - - Returns: - clean_string (str): A unicode object with no ANSI escapes. - - """ - return self._clean_string
- -
[docs] def raw(self): - """ - Return a string object with the ANSI escapes. - - Returns: - raw (str): A unicode object *with* the raw ANSI escape sequences. - - """ - return self._raw_string
- -
[docs] def partition(self, sep, reverse=False): - """ - Splits once into three sections (with the separator being the middle section) - - We use the same techniques we used in split() to make sure each are - colored. - - Args: - sep (str): The separator to split the string on. - reverse (boolean): Whether to split the string on the last - occurrence of the separator rather than the first. - - Returns: - ANSIString: The part of the string before the separator - ANSIString: The separator itself - ANSIString: The part of the string after the separator. - - """ - if hasattr(sep, "_clean_string"): - sep = sep.clean() - if reverse: - parent_result = self._clean_string.rpartition(sep) - else: - parent_result = self._clean_string.partition(sep) - current_index = 0 - result = tuple() - for section in parent_result: - result += (self[current_index: current_index + len(section)],) - current_index += len(section) - return result
- - def _get_indexes(self): - """ - Two tables need to be made, one which contains the indexes of all - readable characters, and one which contains the indexes of all ANSI - escapes. It's important to remember that ANSI escapes require more - that one character at a time, though no readable character needs more - than one character, since the string base class abstracts that away - from us. However, several readable characters can be placed in a row. - - We must use regexes here to figure out where all the escape sequences - are hiding in the string. Then we use the ranges of their starts and - ends to create a final, comprehensive list of all indexes which are - dedicated to code, and all dedicated to text. - - It's possible that only one of these tables is actually needed, the - other assumed to be what isn't in the first. - - """ - - code_indexes = [] - for match in self.parser.ansi_regex.finditer(self._raw_string): - code_indexes.extend(list(range(match.start(), match.end()))) - if not code_indexes: - # Plain string, no ANSI codes. - return code_indexes, list(range(0, len(self._raw_string))) - # all indexes not occupied by ansi codes are normal characters - char_indexes = [i for i in range(len(self._raw_string)) if i not in code_indexes] - return code_indexes, char_indexes - - def _get_interleving(self, index): - """ - Get the code characters from the given slice end to the next - character. - - """ - try: - index = self._char_indexes[index - 1] - except IndexError: - return "" - s = "" - while True: - index += 1 - if index in self._char_indexes: - break - elif index in self._code_indexes: - s += self._raw_string[index] - else: - break - return s - - def __mul__(self, other): - """ - Multiplication method. Implemented for performance reasons. - - """ - if not isinstance(other, int): - return NotImplemented - raw_string = self._raw_string * other - clean_string = self._clean_string * other - code_indexes = self._code_indexes[:] - char_indexes = self._char_indexes[:] - for i in range(other): - code_indexes.extend(self._shifter(self._code_indexes, i * len(self._raw_string))) - char_indexes.extend(self._shifter(self._char_indexes, i * len(self._raw_string))) - return ANSIString( - raw_string, - code_indexes=code_indexes, - char_indexes=char_indexes, - clean_string=clean_string, - ) - - def __rmul__(self, other): - return self.__mul__(other) - -
[docs] def split(self, by=None, maxsplit=-1): - """ - Splits a string based on a separator. - - Stolen from PyPy's pure Python string implementation, tweaked for - ANSIString. - - PyPy is distributed under the MIT licence. - http://opensource.org/licenses/MIT - - Args: - by (str): A string to search for which will be used to split - the string. For instance, ',' for 'Hello,world' would - result in ['Hello', 'world'] - maxsplit (int): The maximum number of times to split the string. - For example, a maxsplit of 2 with a by of ',' on the string - 'Hello,world,test,string' would result in - ['Hello', 'world', 'test,string'] - Returns: - result (list of ANSIStrings): A list of ANSIStrings derived from - this string. - - """ - drop_spaces = by is None - if drop_spaces: - by = " " - - bylen = len(by) - if bylen == 0: - raise ValueError("empty separator") - - res = [] - start = 0 - while maxsplit != 0: - next = self._clean_string.find(by, start) - if next < 0: - break - # Get character codes after the index as well. - res.append(self[start:next]) - start = next + bylen - maxsplit -= 1 # NB. if it's already < 0, it stays < 0 - - res.append(self[start: len(self)]) - if drop_spaces: - return [part for part in res if part != ""] - return res
- -
[docs] def rsplit(self, by=None, maxsplit=-1): - """ - Like split, but starts from the end of the string rather than the - beginning. - - Stolen from PyPy's pure Python string implementation, tweaked for - ANSIString. - - PyPy is distributed under the MIT licence. - http://opensource.org/licenses/MIT - - Args: - by (str): A string to search for which will be used to split - the string. For instance, ',' for 'Hello,world' would - result in ['Hello', 'world'] - maxsplit (int): The maximum number of times to split the string. - For example, a maxsplit of 2 with a by of ',' on the string - 'Hello,world,test,string' would result in - ['Hello,world', 'test', 'string'] - Returns: - result (list of ANSIStrings): A list of ANSIStrings derived from - this string. - - """ - res = [] - end = len(self) - drop_spaces = by is None - if drop_spaces: - by = " " - bylen = len(by) - if bylen == 0: - raise ValueError("empty separator") - - while maxsplit != 0: - next = self._clean_string.rfind(by, 0, end) - if next < 0: - break - # Get character codes after the index as well. - res.append(self[next + bylen: end]) - end = next - maxsplit -= 1 # NB. if it's already < 0, it stays < 0 - - res.append(self[:end]) - res.reverse() - if drop_spaces: - return [part for part in res if part != ""] - return res
- -
[docs] def strip(self, chars=None): - """ - Strip from both ends, taking ANSI markers into account. - - Args: - chars (str, optional): A string containing individual characters - to strip off of both ends of the string. By default, any blank - spaces are trimmed. - Returns: - result (ANSIString): A new ANSIString with the ends trimmed of the - relevant characters. - - """ - clean = self._clean_string - raw = self._raw_string - - # count continuous sequence of chars from left and right - nlen = len(clean) - nlstripped = nlen - len(clean.lstrip(chars)) - nrstripped = nlen - len(clean.rstrip(chars)) - - # within the stripped regions, only retain parts of the raw - # string *not* matching the clean string (these are ansi/mxp tags) - lstripped = "" - ic, ir1 = 0, 0 - while nlstripped: - if ic >= nlstripped: - break - elif raw[ir1] != clean[ic]: - lstripped += raw[ir1] - else: - ic += 1 - ir1 += 1 - rstripped = "" - ic, ir2 = nlen - 1, len(raw) - 1 - while nrstripped: - if nlen - ic > nrstripped: - break - elif raw[ir2] != clean[ic]: - rstripped += raw[ir2] - else: - ic -= 1 - ir2 -= 1 - rstripped = rstripped[::-1] - return ANSIString(lstripped + raw[ir1: ir2 + 1] + rstripped)
- -
[docs] def lstrip(self, chars=None): - """ - Strip from the left, taking ANSI markers into account. - - Args: - chars (str, optional): A string containing individual characters - to strip off of the left end of the string. By default, any - blank spaces are trimmed. - Returns: - result (ANSIString): A new ANSIString with the left end trimmed of - the relevant characters. - - """ - clean = self._clean_string - raw = self._raw_string - - # count continuous sequence of chars from left and right - nlen = len(clean) - nlstripped = nlen - len(clean.lstrip(chars)) - # within the stripped regions, only retain parts of the raw - # string *not* matching the clean string (these are ansi/mxp tags) - lstripped = "" - ic, ir1 = 0, 0 - while nlstripped: - if ic >= nlstripped: - break - elif raw[ir1] != clean[ic]: - lstripped += raw[ir1] - else: - ic += 1 - ir1 += 1 - return ANSIString(lstripped + raw[ir1:])
- -
[docs] def rstrip(self, chars=None): - """ - Strip from the right, taking ANSI markers into account. - - Args: - chars (str, optional): A string containing individual characters - to strip off of the right end of the string. By default, any - blank spaces are trimmed. - Returns: - result (ANSIString): A new ANSIString with the right end trimmed of - the relevant characters. - - """ - clean = self._clean_string - raw = self._raw_string - nlen = len(clean) - nrstripped = nlen - len(clean.rstrip(chars)) - rstripped = "" - ic, ir2 = nlen - 1, len(raw) - 1 - while nrstripped: - if nlen - ic > nrstripped: - break - elif raw[ir2] != clean[ic]: - rstripped += raw[ir2] - else: - ic -= 1 - ir2 -= 1 - rstripped = rstripped[::-1] - return ANSIString(raw[: ir2 + 1] + rstripped)
- -
[docs] def join(self, iterable): - """ - Joins together strings in an iterable, using this string between each - one. - - NOTE: This should always be used for joining strings when ANSIStrings - are involved. Otherwise color information will be discarded by python, - due to details in the C implementation of strings. - - Args: - iterable (list of strings): A list of strings to join together - - Returns: - ANSIString: A single string with all of the iterable's - contents concatenated, with this string between each. - - Examples: - :: - - >>> ANSIString(', ').join(['up', 'right', 'left', 'down']) - ANSIString('up, right, left, down') - - """ - result = ANSIString("") - last_item = None - for item in iterable: - if last_item is not None: - result += self._raw_string - if not isinstance(item, ANSIString): - item = ANSIString(item) - result += item - last_item = item - return result
- - def _filler(self, char, amount): - """ - Generate a line of characters in a more efficient way than just adding - ANSIStrings. - - """ - if not isinstance(char, ANSIString): - line = char * amount - return ANSIString( - char * amount, - code_indexes=[], - char_indexes=list(range(0, len(line))), - clean_string=char, - ) - try: - start = char._code_indexes[0] - except IndexError: - start = None - end = char._char_indexes[0] - prefix = char._raw_string[start:end] - postfix = char._raw_string[end + 1:] - line = char._clean_string * amount - code_indexes = [i for i in range(0, len(prefix))] - length = len(prefix) + len(line) - code_indexes.extend([i for i in range(length, length + len(postfix))]) - char_indexes = self._shifter(list(range(0, len(line))), len(prefix)) - raw_string = prefix + line + postfix - return ANSIString( - raw_string, clean_string=line, char_indexes=char_indexes, code_indexes=code_indexes - ) - - # The following methods should not be called with the '_difference' argument explicitly. This is - # data provided by the wrapper _spacing_preflight. -
[docs] @_spacing_preflight - def center(self, width, fillchar, _difference): - """ - Center some text with some spaces padding both sides. - - Args: - width (int): The target width of the output string. - fillchar (str): A single character string to pad the output string - with. - Returns: - result (ANSIString): A string padded on both ends with fillchar. - - """ - remainder = _difference % 2 - _difference //= 2 - spacing = self._filler(fillchar, _difference) - result = spacing + self + spacing + self._filler(fillchar, remainder) - return result
- -
[docs] @_spacing_preflight - def ljust(self, width, fillchar, _difference): - """ - Left justify some text. - - Args: - width (int): The target width of the output string. - fillchar (str): A single character string to pad the output string - with. - Returns: - result (ANSIString): A string padded on the right with fillchar. - - """ - return self + self._filler(fillchar, _difference)
- -
[docs] @_spacing_preflight - def rjust(self, width, fillchar, _difference): - """ - Right justify some text. - - Args: - width (int): The target width of the output string. - fillchar (str): A single character string to pad the output string - with. - Returns: - result (ANSIString): A string padded on the left with fillchar. - - """ - return self._filler(fillchar, _difference) + self
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/batchprocessors.html b/docs/0.9.5/_modules/evennia/utils/batchprocessors.html deleted file mode 100644 index 152cdfbe92..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/batchprocessors.html +++ /dev/null @@ -1,544 +0,0 @@ - - - - - - - - evennia.utils.batchprocessors — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.utils.batchprocessors

-"""
-This module contains the core methods for the Batch-command- and
-Batch-code-processors respectively. In short, these are two different ways to
-build a game world using a normal text-editor without having to do so 'on the
-fly' in-game. They also serve as an automatic backup so you can quickly
-recreate a world also after a server reset. The functions in this module is
-meant to form the backbone of a system called and accessed through game
-commands.
-
-The Batch-command processor is the simplest. It simply runs a list of in-game
-commands in sequence by reading them from a text file. The advantage of this is
-that the builder only need to remember the normal in-game commands. They are
-also executing with full permission checks etc, making it relatively safe for
-builders to use. The drawback is that in-game there is really a
-builder-character walking around building things, and it can be important to
-create rooms and objects in the right order, so the character can move between
-them. Also objects that affects players (such as mobs, dark rooms etc) will
-affect the building character too, requiring extra care to turn off/on.
-
-The Batch-code processor is a more advanced system that accepts full
-Python code, executing in chunks. The advantage of this is much more
-power; practically anything imaginable can be coded and handled using
-the batch-code processor. There is no in-game character that moves and
-that can be affected by what is being built - the database is
-populated on the fly. The drawback is safety and entry threshold - the
-code is executed as would any server code, without mud-specific
-permission-checks, and you have full access to modifying objects
-etc. You also need to know Python and Evennia's API. Hence it's
-recommended that the batch-code processor is limited only to
-superusers or highly trusted staff.
-
-# Batch-command processor file syntax
-
-The batch-command processor accepts 'batchcommand files' e.g
-`batch.ev`, containing a sequence of valid Evennia commands in a
-simple format. The engine runs each command in sequence, as if they
-had been run at the game prompt.
-
-Each Evennia command must be delimited by a line comment to mark its
-end.
-
-::
-
-    look
-    # delimiting comment
-    create/drop box
-    # another required comment
-
-One can also inject another batchcmdfile:
-
-::
-
-    #INSERT path.batchcmdfile
-
-This way entire game worlds can be created and planned offline; it is
-especially useful in order to create long room descriptions where a
-real offline text editor is often much better than any online text
-editor or prompt.
-
-## Example of batch.ev file:
-
-::
-
-    # batch file
-    # all lines starting with # are comments; they also indicate
-    # that a command definition is over.
-
-    create box
-
-    # this comment ends the @create command.
-
-    set box/desc = A large box.
-
-    Inside are some scattered piles of clothing.
-
-
-    It seems the bottom of the box is a bit loose.
-
-    # Again, this comment indicates the @set command is over. Note how
-    # the description could be freely added. Excess whitespace on a line
-    # is ignored.  An empty line in the command definition is parsed as a \n
-    # (so two empty lines becomes a new paragraph).
-
-    teleport #221
-
-    # (Assuming #221 is a warehouse or something.)
-    # (remember, this comment ends the @teleport command! Don'f forget it)
-
-    # Example of importing another file at this point.
-    #IMPORT examples.batch
-
-    drop box
-
-    # Done, the box is in the warehouse! (this last comment is not necessary to
-    # close the drop command since it's the end of the file)
-
-An example batch file is `contrib/examples/batch_example.ev`.
-
-# Batch-code processor file syntax
-
-The Batch-code processor accepts full python modules (e.g. `batch.py`)
-that looks identical to normal Python files. The difference from
-importing and running any Python module is that the batch-code module
-is loaded as a file and executed directly, so changes to the file will
-apply immediately without a server @reload.
-
-Optionally, one can add some special commented tokens to split the
-execution of the code for the benefit of the batchprocessor's
-interactive- and debug-modes. This allows to conveniently step through
-the code and re-run sections of it easily during development.
-
-Code blocks are marked by commented tokens alone on a line:
-
-- `#HEADER` - This denotes code that should be pasted at the top of all
-  other code. Multiple HEADER statements - regardless of where
-  it exists in the file - is the same as one big block.
-  Observe that changes to variables made in one block is not
-  preserved between blocks!
-- `#CODE` - This designates a code block that will be executed like a
-  stand-alone piece of code together with any HEADER(s)
-  defined. It is mainly used as a way to mark stop points for
-  the interactive mode of the batchprocessor. If no CODE block
-  is defined in the module, the entire module (including HEADERS)
-  is assumed to be a CODE block.
-- `#INSERT path.filename` - This imports another batch_code.py file and
-  runs it in the given position. The inserted file will retain
-  its own HEADERs which will not be mixed with the headers of
-  this file.
-
-Importing works as normal. The following variables are automatically
-made available in the script namespace.
-
-- `caller` - The object executing the batchscript
-- `DEBUG` - This is a boolean marking if the batchprocessor is running
-            in debug mode. It can be checked to e.g. delete created objects
-            when running a CODE block multiple times during testing.
-            (avoids creating a slew of same-named db objects)
-
-## Example batch.py file
-
-::
-
-    #HEADER
-
-    from django.conf import settings
-    from evennia.utils import create
-    from types import basetypes
-
-    GOLD = 10
-
-    #CODE
-
-    obj = create.create_object(basetypes.Object)
-    obj2 = create.create_object(basetypes.Object)
-    obj.location = caller.location
-    obj.db.gold = GOLD
-    caller.msg("The object was created!")
-
-    if DEBUG:
-        obj.delete()
-        obj2.delete()
-
-    #INSERT another_batch_file
-
-    #CODE
-
-    script = create.create_script()
-
-"""
-import re
-import codecs
-import traceback
-import sys
-from django.conf import settings
-from evennia.utils import utils
-
-_ENCODINGS = settings.ENCODINGS
-_RE_INSERT = re.compile(r"^\#INSERT (.*)$", re.MULTILINE)
-_RE_CLEANBLOCK = re.compile(r"^\#.*?$|^\s*$", re.MULTILINE)
-_RE_CMD_SPLIT = re.compile(r"^\#.*?$", re.MULTILINE)
-_RE_CODE_OR_HEADER = re.compile(
-    r"((?:\A|^)#CODE|(?:/A|^)#HEADER|\A)(.*?)$(.*?)(?=^#CODE.*?$|^#HEADER.*?$|\Z)",
-    re.MULTILINE + re.DOTALL,
-)
-
-
-# -------------------------------------------------------------
-# Helper function
-# -------------------------------------------------------------
-
-
-
[docs]def read_batchfile(pythonpath, file_ending=".py"): - """ - This reads the contents of a batch-file. Filename is considered - to be a python path to a batch file relative the directory - specified in `settings.py`. - - file_ending specify which batchfile ending should be assumed (.ev - or .py). The ending should not be included in the python path. - - Args: - pythonpath (str): A dot-python path to a file. - file_ending (str): The file ending of this file (.ev or .py) - - Returns: - text (str): The text content of the batch file. - - Raises: - IOError: If problems reading file. - - """ - - # find all possible absolute paths - abspaths = utils.pypath_to_realpath(pythonpath, file_ending, settings.BASE_BATCHPROCESS_PATHS) - if not abspaths: - raise IOError("Absolute batchcmd paths could not be found.") - text = None - decoderr = [] - for abspath in abspaths: - # try different paths, until we get a match - # we read the file directly into string. - for file_encoding in _ENCODINGS: - # try different encodings, in order - try: - with codecs.open(abspath, "r", encoding=file_encoding) as fobj: - text = fobj.read() - except (ValueError, UnicodeDecodeError) as e: - # this means an encoding error; try another encoding - decoderr.append(str(e)) - continue - break - if not text and decoderr: - raise UnicodeDecodeError("\n".join(decoderr), bytearray(), 0, 0, "") - - return text
- - -# ------------------------------------------------------------- -# -# Batch-command processor -# -# ------------------------------------------------------------- - - -
[docs]class BatchCommandProcessor(object): - """ - This class implements a batch-command processor. - - """ - -
[docs] def parse_file(self, pythonpath): - """ - This parses the lines of a batch-command-file. - - Args: - pythonpath (str): The dot-python path to the file. - - Returns: - list: A list of all parsed commands with arguments, as strings. - - Notes: - Parsing follows the following rules: - - 1. A `#` at the beginning of a line marks the end of the command before - it. It is also a comment and any number of # can exist on - subsequent lines (but not inside comments). - 2. #INSERT at the beginning of a line imports another - batch-cmd file file and pastes it into the batch file as if - it was written there. - 3. Commands are placed alone at the beginning of a line and their - arguments are considered to be everything following (on any - number of lines) until the next comment line beginning with #. - 4. Newlines are ignored in command definitions - 5. A completely empty line in a command line definition is condered - a newline (so two empty lines is a paragraph). - 6. Excess spaces and indents inside arguments are stripped. - - """ - - text = "".join(read_batchfile(pythonpath, file_ending=".ev")) - - def replace_insert(match): - """Map replace entries""" - try: - path = match.group(1) - return "\n#\n".join(self.parse_file(path)) - except IOError: - raise IOError("#INSERT {} failed.".format(path)) - - text = _RE_INSERT.sub(replace_insert, text) - commands = _RE_CMD_SPLIT.split(text) - commands = [c.strip("\r\n") for c in commands] - commands = [c for c in commands if c] - - return commands
- - -# ------------------------------------------------------------- -# -# Batch-code processor -# -# ------------------------------------------------------------- - - -
[docs]def tb_filename(tb): - """Helper to get filename from traceback""" - return tb.tb_frame.f_code.co_filename
- - -
[docs]def tb_iter(tb): - """Traceback iterator.""" - while tb is not None: - yield tb - tb = tb.tb_next
- - -
[docs]class BatchCodeProcessor(object): - """ - This implements a batch-code processor - - """ - -
[docs] def parse_file(self, pythonpath): - """ - This parses the lines of a batch-code file - - Args: - pythonpath (str): The dot-python path to the file. - - Returns: - list: A list of all `#CODE` blocks, each with - prepended `#HEADER` block data. If no `#CODE` - blocks were found, this will be a list of one element - containing all code in the file (so a normal Python file). - - Notes: - Parsing is done according to the following rules: - - 1. Code before a #CODE/HEADER block are considered part of - the first code/header block or is the ONLY block if no - `#CODE/HEADER` blocks are defined. - 2. Lines starting with #HEADER starts a header block (ends other blocks) - 3. Lines starting with #CODE begins a code block (ends other blocks) - 4. Lines starting with #INSERT are on form #INSERT filename. Code from - this file are processed with their headers *separately* before - being inserted at the point of the #INSERT. - 5. Code after the last block is considered part of the last header/code - block - - - """ - - text = "".join(read_batchfile(pythonpath, file_ending=".py")) - - def replace_insert(match): - """Run parse_file on the import before sub:ing it into this file""" - path = match.group(1) - try: - return "# batchcode insert (%s):" % path + "\n".join(self.parse_file(path)) - except IOError as err: - raise IOError("#INSERT {} failed.".format(path)) - - # process and then insert code from all #INSERTS - text = _RE_INSERT.sub(replace_insert, text) - - headers = [] - codes = [] - for imatch, match in enumerate(list(_RE_CODE_OR_HEADER.finditer(text))): - mtype = match.group(1).strip() - # we need to handle things differently at the start of the file - if mtype: - istart, iend = match.span(3) - else: - istart, iend = match.start(2), match.end(3) - code = text[istart:iend] - if mtype == "#HEADER": - headers.append(code) - else: # either #CODE or matching from start of file - codes.append(code) - - # join all headers together to one - header = "# batchcode header:\n%s\n\n" % "\n\n".join(headers) if headers else "" - # add header to each code block - codes = ["%s# batchcode code:\n%s" % (header, code) for code in codes] - return codes
- -
[docs] def code_exec(self, code, extra_environ=None, debug=False): - """ - Execute a single code block, including imports and appending - global vars. - - Args: - code (str): Code to run. - extra_environ (dict): Environment variables to run with code. - debug (bool, optional): Set the DEBUG variable in the execution - namespace. - - Returns: - err (str or None): An error code or None (ok). - - """ - # define the execution environment - environdict = {"settings_module": settings, "DEBUG": debug} - for key, value in extra_environ.items(): - environdict[key] = value - - # initializing the django settings at the top of code - code = ( - "# batchcode evennia initialization: \n" - "try: settings_module.configure()\n" - "except RuntimeError: pass\n" - "finally: del settings_module\n\n%s" % code - ) - - # execute the block - try: - exec(code, environdict) - except Exception: - etype, value, tb = sys.exc_info() - - fname = tb_filename(tb) - for tb in tb_iter(tb): - if fname != tb_filename(tb): - break - lineno = tb.tb_lineno - 1 - err = "" - for iline, line in enumerate(code.split("\n")): - if iline == lineno: - err += "\n|w%02i|n: %s" % (iline + 1, line) - elif lineno - 5 < iline < lineno + 5: - err += "\n%02i: %s" % (iline + 1, line) - - err += "\n".join(traceback.format_exception(etype, value, tb)) - return err - return None
- - -BATCHCMD = BatchCommandProcessor() -BATCHCODE = BatchCodeProcessor() -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/containers.html b/docs/0.9.5/_modules/evennia/utils/containers.html deleted file mode 100644 index f770341672..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/containers.html +++ /dev/null @@ -1,351 +0,0 @@ - - - - - - - - evennia.utils.containers — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.utils.containers

-"""
-Containers
-
-Containers are storage classes usually initialized from a setting. They
-represent Singletons and acts as a convenient place to find resources (
-available as properties on the singleton)
-
-evennia.GLOBAL_SCRIPTS
-evennia.OPTION_CLASSES
-
-"""
-
-
-from pickle import dumps
-from django.conf import settings
-from evennia.utils.utils import class_from_module, callables_from_module
-from evennia.utils import logger
-
-
-SCRIPTDB = None
-
-
-
[docs]class Container: - """ - Base container class. A container is simply a storage object whose - properties can be acquired as a property on it. This is generally - considered a read-only affair. - - The container is initialized by a list of modules containing callables. - - """ - - storage_modules = [] - -
[docs] def __init__(self): - """ - Read data from module. - - """ - self.loaded_data = None
- -
[docs] def load_data(self): - """ - Delayed import to avoid eventual circular imports from inside - the storage modules. - - """ - if self.loaded_data is None: - self.loaded_data = {} - for module in self.storage_modules: - self.loaded_data.update(callables_from_module(module))
- - def __getattr__(self, key): - return self.get(key) - -
[docs] def get(self, key, default=None): - """ - Retrive data by key (in case of not knowing it beforehand). - - Args: - key (str): The name of the script. - default (any, optional): Value to return if key is not found. - - Returns: - any (any): The data loaded on this container. - - """ - self.load_data() - return self.loaded_data.get(key, default)
- -
[docs] def all(self): - """ - Get all stored data - - Returns: - scripts (list): All global script objects stored on the container. - - """ - self.load_data() - return list(self.loaded_data.values())
- - -
[docs]class OptionContainer(Container): - """ - Loads and stores the final list of OPTION CLASSES. - - Can access these as properties or dictionary-contents. - """ - - storage_modules = settings.OPTION_CLASS_MODULES
- - -
[docs]class GlobalScriptContainer(Container): - """ - Simple Handler object loaded by the Evennia API to contain and manage a - game's Global Scripts. This will list global Scripts created on their own - but will also auto-(re)create scripts defined in `settings.GLOBAL_SCRIPTS`. - - Example: - import evennia - evennia.GLOBAL_SCRIPTS.scriptname - - Note: - This does not use much of the BaseContainer since it's not loading - callables from settings but a custom dict of tuples. - - """ - -
[docs] def __init__(self): - """ - Note: We must delay loading of typeclasses since this module may get - initialized before Scripts are actually initialized. - - """ - self.typeclass_storage = None - self.loaded_data = { - key: {} if data is None else data for key, data in settings.GLOBAL_SCRIPTS.items() - }
- - def _get_scripts(self, key=None, default=None): - global SCRIPTDB - if not SCRIPTDB: - from evennia.scripts.models import ScriptDB as SCRIPTDB - if key: - try: - return SCRIPTDB.objects.get(db_key__exact=key, db_obj__isnull=True) - except SCRIPTDB.DoesNotExist: - return default - else: - return SCRIPTDB.objects.filter(db_obj__isnull=True) - - def _load_script(self, key): - self.load_data() - - typeclass = self.typeclass_storage[key] - script = typeclass.objects.filter( - db_key=key, db_account__isnull=True, db_obj__isnull=True).first() - - kwargs = {**self.loaded_data[key]} - kwargs['key'] = key - kwargs['persistent'] = kwargs.get('persistent', True) - - compare_hash = str(dumps(kwargs, protocol=4)) - - if script: - script_hash = script.attributes.get("global_script_settings", category="settings_hash") - if script_hash is None: - # legacy - store the hash anew and assume no change - script.attributes.add("global_script_settings", compare_hash, - category="settings_hash") - elif script_hash != compare_hash: - # wipe the old version and create anew - logger.log_info(f"GLOBAL_SCRIPTS: Settings changed for {key} ({typeclass}).") - script.stop() - script.delete() - script = None - - if not script: - logger.log_info(f"GLOBAL_SCRIPTS: (Re)creating {key} ({typeclass}).") - - script, errors = typeclass.create(**kwargs) - if errors: - logger.log_err("\n".join(errors)) - return None - - # store a hash representation of the setup - script.attributes.add("_global_script_settings", - compare_hash, category="settings_hash") - script.start() - - return script - -
[docs] def start(self): - """ - Called last in evennia.__init__ to initialize the container late - (after script typeclasses have finished loading). - - We include all global scripts in the handler and - make sure to auto-load time-based scripts. - - """ - # populate self.typeclass_storage - self.load_data() - - # start registered scripts - for key in self.loaded_data: - self._load_script(key)
- -
[docs] def load_data(self): - """ - This delayed import avoids trying to load Scripts before they are - initialized. - - """ - if self.typeclass_storage is None: - self.typeclass_storage = {} - for key, data in self.loaded_data.items(): - try: - typeclass = data.get("typeclass", settings.BASE_SCRIPT_TYPECLASS) - self.typeclass_storage[key] = class_from_module(typeclass) - except Exception: - logger.log_trace( - f"GlobalScriptContainer could not start import global script {key}.")
- -
[docs] def get(self, key, default=None): - """ - Retrive data by key (in case of not knowing it beforehand). Any - scripts that are in settings.GLOBAL_SCRIPTS that are not found - will be recreated on-demand. - - Args: - key (str): The name of the script. - default (any, optional): Value to return if key is not found - at all on this container (i.e it cannot be loaded at all). - - Returns: - any (any): The data loaded on this container. - """ - res = self._get_scripts(key) - if not res: - if key in self.loaded_data: - # recreate if we have the info - return self._load_script(key) or default - return default - return res
- -
[docs] def all(self): - """ - Get all global scripts. Note that this will not auto-start - scripts defined in settings. - - Returns: - scripts (list): All global script objects stored on the container. - - """ - self.typeclass_storage = None - self.load_data() - for key in self.loaded_data: - self._load_script(key) - return self._get_scripts(None)
- - -# Create all singletons - -GLOBAL_SCRIPTS = GlobalScriptContainer() -OPTION_CLASSES = OptionContainer() -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/dbserialize.html b/docs/0.9.5/_modules/evennia/utils/dbserialize.html deleted file mode 100644 index 01afb0210a..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/dbserialize.html +++ /dev/null @@ -1,865 +0,0 @@ - - - - - - - - evennia.utils.dbserialize — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.utils.dbserialize

-"""
-This module handles serialization of arbitrary python structural data,
-intended primarily to be stored in the database. It also supports
-storing Django model instances (which plain pickle cannot do).
-
-This serialization is used internally by the server, notably for
-storing data in Attributes and for piping data to process pools.
-
-The purpose of dbserialize is to handle all forms of data. For
-well-structured non-arbitrary exchange, such as communicating with a
-rich web client, a simpler JSON serialization makes more sense.
-
-This module also implements the `SaverList`, `SaverDict` and `SaverSet`
-classes. These are iterables that track their position in a nested
-structure and makes sure to send updates up to their root. This is
-used by Attributes - without it, one would not be able to update mutables
-in-situ, e.g `obj.db.mynestedlist[3][5] = 3` would never be saved and
-be out of sync with the database.
-
-"""
-from functools import update_wrapper
-from collections import deque, OrderedDict, defaultdict
-from collections.abc import MutableSequence, MutableSet, MutableMapping
-
-try:
-    from pickle import dumps, loads
-except ImportError:
-    from pickle import dumps, loads
-from django.core.exceptions import ObjectDoesNotExist
-from django.contrib.contenttypes.models import ContentType
-from django.utils.safestring import SafeString
-from evennia.utils.utils import uses_database, is_iter, to_bytes
-from evennia.utils import logger
-
-__all__ = ("to_pickle", "from_pickle", "do_pickle", "do_unpickle", "dbserialize", "dbunserialize")
-
-PICKLE_PROTOCOL = 2
-
-
-# message to send if editing an already deleted Attribute in a savermutable
-_ERROR_DELETED_ATTR = (
-    "{cls_name} {obj} has had its root Attribute deleted. "
-    "It must be cast to a {non_saver_name} before it can be modified further."
-)
-
-
-def _get_mysql_db_version():
-    """
-    This is a helper method for specifically getting the version
-    string of a MySQL database.
-
-    Returns:
-        mysql_version (str): The currently used mysql database
-            version.
-
-    """
-    from django.db import connection
-
-    conn = connection.cursor()
-    conn.execute("SELECT VERSION()")
-    version = conn.fetchone()
-    return version and str(version[0]) or ""
-
-
-# initialization and helpers
-
-
-_GA = object.__getattribute__
-_SA = object.__setattr__
-_FROM_MODEL_MAP = None
-_TO_MODEL_MAP = None
-_IGNORE_DATETIME_MODELS = None
-_SESSION_HANDLER = None
-
-
-def _IS_PACKED_DBOBJ(o):
-    return isinstance(o, tuple) and len(o) == 4 and o[0] == "__packed_dbobj__"
-
-
-def _IS_PACKED_SESSION(o):
-    return isinstance(o, tuple) and len(o) == 3 and o[0] == "__packed_session__"
-
-
-if uses_database("mysql") and _get_mysql_db_version() < "5.6.4":
-    # mysql <5.6.4 don't support millisecond precision
-    _DATESTRING = "%Y:%m:%d-%H:%M:%S:000000"
-else:
-    _DATESTRING = "%Y:%m:%d-%H:%M:%S:%f"
-
-
-def _TO_DATESTRING(obj):
-    """
-    Creates datestring hash.
-
-    Args:
-        obj (Object): Database object.
-
-    Returns:
-        datestring (str): A datestring hash.
-
-    """
-    try:
-        return _GA(obj, "db_date_created").strftime(_DATESTRING)
-    except AttributeError:
-        # this can happen if object is not yet saved - no datestring is then set
-        try:
-            obj.save()
-        except AttributeError:
-            # we have received a None object, for example due to an erroneous save.
-            return None
-        return _GA(obj, "db_date_created").strftime(_DATESTRING)
-
-
-def _init_globals():
-    """Lazy importing to avoid circular import issues"""
-    global _FROM_MODEL_MAP, _TO_MODEL_MAP, _SESSION_HANDLER, _IGNORE_DATETIME_MODELS
-    if not _FROM_MODEL_MAP:
-        _FROM_MODEL_MAP = defaultdict(str)
-        _FROM_MODEL_MAP.update(dict((c.model, c.natural_key()) for c in ContentType.objects.all()))
-    if not _TO_MODEL_MAP:
-        from django.conf import settings
-
-        _TO_MODEL_MAP = defaultdict(str)
-        _TO_MODEL_MAP.update(
-            dict((c.natural_key(), c.model_class()) for c in ContentType.objects.all())
-        )
-        _IGNORE_DATETIME_MODELS = []
-        for src_key, dst_key in settings.ATTRIBUTE_STORED_MODEL_RENAME:
-            _TO_MODEL_MAP[src_key] = _TO_MODEL_MAP.get(dst_key, None)
-            _IGNORE_DATETIME_MODELS.append(src_key)
-    if not _SESSION_HANDLER:
-        from evennia.server.sessionhandler import SESSION_HANDLER as _SESSION_HANDLER
-
-
-#
-# SaverList, SaverDict, SaverSet - Attribute-specific helper classes and functions
-#
-
-
-def _save(method):
-    """method decorator that saves data to Attribute"""
-
-    def save_wrapper(self, *args, **kwargs):
-        self.__doc__ = method.__doc__
-        ret = method(self, *args, **kwargs)
-        self._save_tree()
-        return ret
-
-    return update_wrapper(save_wrapper, method)
-
-
-class _SaverMutable(object):
-    """
-    Parent class for properly handling  of nested mutables in
-    an Attribute. If not used something like
-     obj.db.mylist[1][2] = "test" (allocation to a nested list)
-    will not save the updated value to the database.
-    """
-
-    def __init__(self, *args, **kwargs):
-        """store all properties for tracking the tree"""
-        self._parent = kwargs.pop("_parent", None)
-        self._db_obj = kwargs.pop("_db_obj", None)
-        self._data = None
-
-    def __bool__(self):
-        """Make sure to evaluate as False if empty"""
-        return bool(self._data)
-
-    def _save_tree(self):
-        """recursively traverse back up the tree, save when we reach the root"""
-        if self._parent:
-            self._parent._save_tree()
-        elif self._db_obj:
-            if not self._db_obj.pk:
-                cls_name = self.__class__.__name__
-                try:
-                    non_saver_name = cls_name.split("_Saver", 1)[1].lower()
-                except IndexError:
-                    non_saver_name = cls_name
-                raise ValueError(
-                    _ERROR_DELETED_ATTR.format(
-                        cls_name=cls_name, obj=self, non_saver_name=non_saver_name
-                    )
-                )
-            self._db_obj.value = self
-        else:
-            logger.log_err("_SaverMutable %s has no root Attribute to save to." % self)
-
-    def _convert_mutables(self, data):
-        """converts mutables to Saver* variants and assigns ._parent property"""
-
-        def process_tree(item, parent):
-            """recursively populate the tree, storing parents"""
-            dtype = type(item)
-            if dtype in (str, int, float, bool, tuple):
-                return item
-            elif dtype == list:
-                dat = _SaverList(_parent=parent)
-                dat._data.extend(process_tree(val, dat) for val in item)
-                return dat
-            elif dtype == dict:
-                dat = _SaverDict(_parent=parent)
-                dat._data.update((key, process_tree(val, dat)) for key, val in item.items())
-                return dat
-            elif dtype == set:
-                dat = _SaverSet(_parent=parent)
-                dat._data.update(process_tree(val, dat) for val in item)
-                return dat
-            return item
-
-        return process_tree(data, self)
-
-    def __repr__(self):
-        return self._data.__repr__()
-
-    def __len__(self):
-        return self._data.__len__()
-
-    def __iter__(self):
-        return self._data.__iter__()
-
-    def __getitem__(self, key):
-        return self._data.__getitem__(key)
-
-    def __eq__(self, other):
-        return self._data == other
-
-    def __ne__(self, other):
-        return self._data != other
-
-    def __lt__(self, other):
-        return self._data < other
-
-    def __gt__(self, other):
-        return self._data > other
-
-    @_save
-    def __setitem__(self, key, value):
-        self._data.__setitem__(key, self._convert_mutables(value))
-
-    @_save
-    def __delitem__(self, key):
-        self._data.__delitem__(key)
-
-
-class _SaverList(_SaverMutable, MutableSequence):
-    """
-    A list that saves itself to an Attribute when updated.
-    """
-
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-        self._data = list()
-
-    @_save
-    def __iadd__(self, otherlist):
-        self._data = self._data.__add__(otherlist)
-        return self._data
-
-    def __add__(self, otherlist):
-        return list(self._data) + otherlist
-
-    @_save
-    def insert(self, index, value):
-        self._data.insert(index, self._convert_mutables(value))
-
-    def __eq__(self, other):
-        try:
-            return list(self._data) == list(other)
-        except TypeError:
-            return False
-
-    def __ne__(self, other):
-        try:
-            return list(self._data) != list(other)
-        except TypeError:
-            return True
-
-    def index(self, value, *args):
-        return self._data.index(value, *args)
-
-    @_save
-    def sort(self, *, key=None, reverse=False):
-        self._data.sort(key=key, reverse=reverse)
-
-    def copy(self):
-        return self._data.copy()
-
-
-class _SaverDict(_SaverMutable, MutableMapping):
-    """
-    A dict that stores changes to an Attribute when updated
-    """
-
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-        self._data = dict()
-
-    def has_key(self, key):
-        return key in self._data
-
-    @_save
-    def update(self, *args, **kwargs):
-        self._data.update(*args, **kwargs)
-
-
-class _SaverSet(_SaverMutable, MutableSet):
-    """
-    A set that saves to an Attribute when updated
-    """
-
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-        self._data = set()
-
-    def __contains__(self, value):
-        return self._data.__contains__(value)
-
-    @_save
-    def add(self, value):
-        self._data.add(self._convert_mutables(value))
-
-    @_save
-    def discard(self, value):
-        self._data.discard(value)
-
-
-class _SaverOrderedDict(_SaverMutable, MutableMapping):
-    """
-    An ordereddict that can be saved and operated on.
-    """
-
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-        self._data = OrderedDict()
-
-    def has_key(self, key):
-        return key in self._data
-
-
-class _SaverDeque(_SaverMutable):
-    """
-    A deque that can be saved and operated on.
-    """
-
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-        self._data = deque()
-
-    @_save
-    def append(self, *args, **kwargs):
-        self._data.append(*args, **kwargs)
-
-    @_save
-    def appendleft(self, *args, **kwargs):
-        self._data.appendleft(*args, **kwargs)
-
-    @_save
-    def clear(self):
-        self._data.clear()
-
-    @_save
-    def extendleft(self, *args, **kwargs):
-        self._data.extendleft(*args, **kwargs)
-
-    # maxlen property
-    def _getmaxlen(self):
-        return self._data.maxlen
-
-    def _setmaxlen(self, value):
-        self._data.maxlen = value
-
-    def _delmaxlen(self):
-        del self._data.maxlen
-
-    maxlen = property(_getmaxlen, _setmaxlen, _delmaxlen)
-
-    @_save
-    def pop(self, *args, **kwargs):
-        return self._data.pop(*args, **kwargs)
-
-    @_save
-    def popleft(self, *args, **kwargs):
-        return self._data.popleft(*args, **kwargs)
-
-    @_save
-    def reverse(self):
-        self._data.reverse()
-
-    @_save
-    def rotate(self, *args):
-        self._data.rotate(*args)
-        
-    @_save
-    def remove(self, *args):
-        self._data.remove(*args)
-
-
-_DESERIALIZE_MAPPING = {
-    _SaverList.__name__: list,
-    _SaverDict.__name__: dict,
-    _SaverSet.__name__: set,
-    _SaverOrderedDict.__name__: OrderedDict,
-    _SaverDeque.__name__: deque,
-}
-
-
-def deserialize(obj):
-    """
-    Make sure to *fully* decouple a structure from the database, by turning all _Saver*-mutables
-    inside it back into their normal Python forms.
-
-    """
-
-    def _iter(obj):
-        typ = type(obj)
-        tname = typ.__name__
-        if tname in ("_SaverDict", "dict"):
-            return {_iter(key): _iter(val) for key, val in obj.items()}
-        elif tname in _DESERIALIZE_MAPPING:
-            return _DESERIALIZE_MAPPING[tname](_iter(val) for val in obj)
-        elif is_iter(obj):
-            return typ(_iter(val) for val in obj)
-        return obj
-
-    return _iter(obj)
-
-
-#
-# serialization helpers
-
-
-def pack_dbobj(item):
-    """
-    Check and convert django database objects to an internal representation.
-
-    Args:
-        item (any): A database entity to pack
-
-    Returns:
-        packed (any or tuple): Either returns the original input item
-            or the packing tuple `("__packed_dbobj__", key, creation_time, id)`.
-
-    """
-    _init_globals()
-    obj = item
-    natural_key = _FROM_MODEL_MAP[
-        hasattr(obj, "id")
-        and hasattr(obj, "db_date_created")
-        and hasattr(obj, "__dbclass__")
-        and obj.__dbclass__.__name__.lower()
-    ]
-    # build the internal representation as a tuple
-    #  ("__packed_dbobj__", key, creation_time, id)
-    return (
-        natural_key
-        and ("__packed_dbobj__", natural_key, _TO_DATESTRING(obj), _GA(obj, "id"))
-        or item
-    )
-
-
-def unpack_dbobj(item):
-    """
-    Check and convert internal representations back to Django database
-    models.
-
-    Args:
-        item (packed_dbobj): The fact that item is a packed dbobj
-            should be checked before this call.
-
-    Returns:
-        unpacked (any): Either the original input or converts the
-            internal store back to a database representation (its
-            typeclass is returned if applicable).
-
-    """
-    _init_globals()
-    try:
-        obj = item[3] and _TO_MODEL_MAP[item[1]].objects.get(id=item[3])
-    except ObjectDoesNotExist:
-        return None
-    except TypeError:
-        if hasattr(item, "pk"):
-            # this happens if item is already an obj
-            return item
-        return None
-    if item[1] in _IGNORE_DATETIME_MODELS:
-        # if we are replacing models we ignore the datatime
-        return obj
-    else:
-        # even if we got back a match, check the sanity of the date (some
-        # databases may 're-use' the id)
-        return _TO_DATESTRING(obj) == item[2] and obj or None
-
-
-def pack_session(item):
-    """
-    Handle the safe serializion of Sessions objects (these contain
-    hidden references to database objects (accounts, puppets) so they
-    can't be safely serialized).
-
-    Args:
-        item (Session)): This item must have all properties of a session
-            before entering this call.
-
-    Returns:
-        packed (tuple or None): A session-packed tuple on the form
-            `(__packed_session__, sessid, conn_time)`. If this sessid
-            does not match a session in the Session handler, None is returned.
-
-    """
-    _init_globals()
-    session = _SESSION_HANDLER.get(item.sessid)
-    if session and session.conn_time == item.conn_time:
-        # we require connection times to be identical for the Session
-        # to be accepted as actually being a session (sessids gets
-        # reused all the time).
-        return (
-            item.conn_time
-            and item.sessid
-            and ("__packed_session__", _GA(item, "sessid"), _GA(item, "conn_time"))
-        )
-    return None
-
-
-def unpack_session(item):
-    """
-    Check and convert internal representations back to Sessions.
-
-    Args:
-        item (packed_session): The fact that item is a packed session
-            should be checked before this call.
-
-    Returns:
-        unpacked (any): Either the original input or converts the
-            internal store back to a Session. If Session no longer
-            exists, None will be returned.
-    """
-    _init_globals()
-    session = _SESSION_HANDLER.get(item[1])
-    if session and session.conn_time == item[2]:
-        # we require connection times to be identical for the Session
-        # to be accepted as the same as the one stored (sessids gets
-        # reused all the time).
-        return session
-    return None
-
-
-#
-# Access methods
-
-
-
[docs]def to_pickle(data): - """ - This prepares data on arbitrary form to be pickled. It handles any - nested structure and returns data on a form that is safe to pickle - (including having converted any database models to their internal - representation). We also convert any Saver*-type objects back to - their normal representations, they are not pickle-safe. - - Args: - data (any): Data to pickle. - - Returns: - data (any): Pickled data. - - """ - - def process_item(item): - """Recursive processor and identification of data""" - dtype = type(item) - if dtype in (str, int, float, bool, bytes, SafeString): - return item - elif dtype == tuple: - return tuple(process_item(val) for val in item) - elif dtype in (list, _SaverList): - return [process_item(val) for val in item] - elif dtype in (dict, _SaverDict): - return dict((process_item(key), process_item(val)) for key, val in item.items()) - elif dtype in (set, _SaverSet): - return set(process_item(val) for val in item) - elif dtype in (OrderedDict, _SaverOrderedDict): - return OrderedDict((process_item(key), process_item(val)) for key, val in item.items()) - elif dtype in (deque, _SaverDeque): - return deque(process_item(val) for val in item) - - elif hasattr(item, "__iter__"): - # we try to conserve the iterable class, if not convert to list - try: - return item.__class__([process_item(val) for val in item]) - except (AttributeError, TypeError): - return [process_item(val) for val in item] - elif hasattr(item, "sessid") and hasattr(item, "conn_time"): - return pack_session(item) - try: - return pack_dbobj(item) - except TypeError: - return item - except Exception: - logger.log_err(f"The object {item} of type {type(item)} could not be stored.") - raise - - return process_item(data)
- - -# @transaction.autocommit -
[docs]def from_pickle(data, db_obj=None): - """ - This should be fed a just de-pickled data object. It will be converted back - to a form that may contain database objects again. Note that if a database - object was removed (or changed in-place) in the database, None will be - returned. - - Args: - data (any): Pickled data to unpickle. - db_obj (Atribute, any): This is the model instance (normally - an Attribute) that _Saver*-type iterables (_SaverList etc) - will save to when they update. It must have a 'value' property - that saves assigned data to the database. Skip if not - serializing onto a given object. If db_obj is given, this - function will convert lists, dicts and sets to their - _SaverList, _SaverDict and _SaverSet counterparts. - - Returns: - data (any): Unpickled data. - - """ - - def process_item(item): - """Recursive processor and identification of data""" - dtype = type(item) - if dtype in (str, int, float, bool, bytes, SafeString): - return item - elif _IS_PACKED_DBOBJ(item): - # this must be checked before tuple - return unpack_dbobj(item) - elif _IS_PACKED_SESSION(item): - return unpack_session(item) - elif dtype == tuple: - return tuple(process_item(val) for val in item) - elif dtype == dict: - return dict((process_item(key), process_item(val)) for key, val in item.items()) - elif dtype == set: - return set(process_item(val) for val in item) - elif dtype == OrderedDict: - return OrderedDict((process_item(key), process_item(val)) for key, val in item.items()) - elif dtype == deque: - return deque(process_item(val) for val in item) - elif hasattr(item, "__iter__"): - try: - # we try to conserve the iterable class if - # it accepts an iterator - return item.__class__(process_item(val) for val in item) - except (AttributeError, TypeError): - return [process_item(val) for val in item] - return item - - def process_tree(item, parent): - """Recursive processor, building a parent-tree from iterable data""" - dtype = type(item) - if dtype in (str, int, float, bool, bytes, SafeString): - return item - elif _IS_PACKED_DBOBJ(item): - # this must be checked before tuple - return unpack_dbobj(item) - elif dtype == tuple: - return tuple(process_tree(val, item) for val in item) - elif dtype == list: - dat = _SaverList(_parent=parent) - dat._data.extend(process_tree(val, dat) for val in item) - return dat - elif dtype == dict: - dat = _SaverDict(_parent=parent) - dat._data.update( - (process_item(key), process_tree(val, dat)) for key, val in item.items() - ) - return dat - elif dtype == set: - dat = _SaverSet(_parent=parent) - dat._data.update(set(process_tree(val, dat) for val in item)) - return dat - elif dtype == OrderedDict: - dat = _SaverOrderedDict(_parent=parent) - dat._data.update( - (process_item(key), process_tree(val, dat)) for key, val in item.items() - ) - return dat - elif dtype == deque: - dat = _SaverDeque(_parent=parent) - dat._data.extend(process_item(val) for val in item) - return dat - elif hasattr(item, "__iter__"): - try: - # we try to conserve the iterable class if it - # accepts an iterator - return item.__class__(process_tree(val, parent) for val in item) - except (AttributeError, TypeError): - dat = _SaverList(_parent=parent) - dat._data.extend(process_tree(val, dat) for val in item) - return dat - return item - - if db_obj: - # convert lists, dicts and sets to their Saved* counterparts. It - # is only relevant if the "root" is an iterable of the right type. - dtype = type(data) - if dtype == list: - dat = _SaverList(_db_obj=db_obj) - dat._data.extend(process_tree(val, dat) for val in data) - return dat - elif dtype == dict: - dat = _SaverDict(_db_obj=db_obj) - dat._data.update( - (process_item(key), process_tree(val, dat)) for key, val in data.items() - ) - return dat - elif dtype == set: - dat = _SaverSet(_db_obj=db_obj) - dat._data.update(process_tree(val, dat) for val in data) - return dat - elif dtype == OrderedDict: - dat = _SaverOrderedDict(_db_obj=db_obj) - dat._data.update( - (process_item(key), process_tree(val, dat)) for key, val in data.items() - ) - return dat - elif dtype == deque: - dat = _SaverDeque(_db_obj=db_obj) - dat._data.extend(process_item(val) for val in data) - return dat - return process_item(data)
- - -
[docs]def do_pickle(data): - """Perform pickle to string""" - try: - return dumps(data, protocol=PICKLE_PROTOCOL) - except Exception: - logger.log_err(f"Could not pickle data for storage: {data}") - raise
- - -
[docs]def do_unpickle(data): - """Retrieve pickle from pickled string""" - try: - return loads(to_bytes(data)) - except Exception: - logger.log_err(f"Could not unpickle data from storage: {data}") - raise
- - -
[docs]def dbserialize(data): - """Serialize to pickled form in one step""" - return do_pickle(to_pickle(data))
- - -
[docs]def dbunserialize(data, db_obj=None): - """Un-serialize in one step. See from_pickle for help db_obj.""" - return from_pickle(do_unpickle(data), db_obj=db_obj)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/eveditor.html b/docs/0.9.5/_modules/evennia/utils/eveditor.html deleted file mode 100644 index 06a5a7deac..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/eveditor.html +++ /dev/null @@ -1,1248 +0,0 @@ - - - - - - - - evennia.utils.eveditor — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.utils.eveditor

-"""
-EvEditor (Evennia Line Editor)
-
-This implements an advanced line editor for editing longer texts in-game. The
-editor mimics the command mechanisms of the "VI" editor (a famous line-by-line
-editor) as far as reasonable.
-
-Features of the editor:
-
-- undo/redo.
-- edit/replace on any line of the buffer.
-- search&replace text anywhere in buffer.
-- formatting of buffer, or selection, to certain width + indentations.
-- allow to echo the input or not, depending on your client.
-- in-built help
-
-To use the editor, just import EvEditor from this module and initialize it:
-
-```python
-from evennia.utils.eveditor import EvEditor
-
-# set up an editor to edit the caller's 'desc' Attribute
-def _loadfunc(caller):
-    return caller.db.desc
-
-def _savefunc(caller, buffer):
-    caller.db.desc = buffer.strip()
-    return True
-
-def _quitfunc(caller):
-    caller.msg("Custom quit message")
-
-# start the editor
-EvEditor(caller, loadfunc=None, savefunc=None, quitfunc=None, key="",
-         persistent=True, code=False)
-```
-
-The editor can also be used to format Python code and be made to
-survive a reload. See the `EvEditor` class for more details.
-
-"""
-import re
-
-from django.conf import settings
-from evennia import CmdSet
-from evennia.utils import is_iter, fill, dedent, logger, justify, to_str, utils
-from evennia.utils.ansi import raw
-from evennia.commands import cmdhandler
-from django.utils.translation import gettext as _
-
-# we use cmdhandler instead of evennia.syscmdkeys to
-# avoid some cases of loading before evennia init'd
-_CMD_NOMATCH = cmdhandler.CMD_NOMATCH
-_CMD_NOINPUT = cmdhandler.CMD_NOINPUT
-
-_RE_GROUP = re.compile(r"\".*?\"|\'.*?\'|\S*")
-_COMMAND_DEFAULT_CLASS = utils.class_from_module(settings.COMMAND_DEFAULT_CLASS)
-# use NAWS in the future?
-_DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
-
-# -------------------------------------------------------------
-#
-# texts
-#
-# -------------------------------------------------------------
-
-_HELP_TEXT = _("""
- <txt>  - any non-command is appended to the end of the buffer.
- :  <l> - view buffer or only line(s) <l>
- :: <l> - raw-view buffer or only line(s) <l>
- :::    - escape - enter ':' as the only character on the line.
- :h     - this help.
-
- :w     - save the buffer (don't quit)
- :wq    - save buffer and quit
- :q     - quit (will be asked to save if buffer was changed)
- :q!    - quit without saving, no questions asked
-
- :u     - (undo) step backwards in undo history
- :uu    - (redo) step forward in undo history
- :UU    - reset all changes back to initial state
-
- :dd <l>     - delete last line or line(s) <l>
- :dw <l> <w> - delete word or regex <w> in entire buffer or on line <l>
- :DD         - clear entire buffer
-
- :y  <l>        - yank (copy) line(s) <l> to the copy buffer
- :x  <l>        - cut line(s) <l> and store it in the copy buffer
- :p  <l>        - put (paste) previously copied line(s) directly after <l>
- :i  <l> <txt>  - insert new text <txt> at line <l>. Old line will move down
- :r  <l> <txt>  - replace line <l> with text <txt>
- :I  <l> <txt>  - insert text at the beginning of line <l>
- :A  <l> <txt>  - append text after the end of line <l>
-
- :s <l> <w> <txt> - search/replace word or regex <w> in buffer or on line <l>
-
- :j <l> <w> - justify buffer or line <l>. <w> is f, c, l or r. Default f (full)
- :f <l>     - flood-fill entire buffer or line <l>: Equivalent to :j left
- :fi <l>    - indent entire buffer or line <l>
- :fd <l>    - de-indent entire buffer or line <l>
-
- :echo - turn echoing of the input on/off (helpful for some clients)
-""")
-
-_HELP_LEGEND = _("""
-    Legend:
-    <l>   - line number, like '5' or range, like '3:7'.
-    <w>   - a single word, or multiple words with quotes around them.
-    <txt> - longer string, usually not needing quotes.
-""")
-
-_HELP_CODE = _("""
- :!    - Execute code buffer without saving
- :<    - Decrease the level of automatic indentation for the next lines
- :>    - Increase the level of automatic indentation for the next lines
- :=    - Switch automatic indentation on/off
-""".lstrip(
-    "\n"
-))
-
-_ERROR_LOADFUNC = _("""
-{error}
-
-|rBuffer load function error. Could not load initial data.|n
-""")
-
-_ERROR_SAVEFUNC = _("""
-{error}
-
-|rSave function returned an error. Buffer not saved.|n
-""")
-
-_ERROR_NO_SAVEFUNC = _("|rNo save function defined. Buffer cannot be saved.|n")
-
-_MSG_SAVE_NO_CHANGE = _("No changes need saving")
-_DEFAULT_NO_QUITFUNC = _("Exited editor.")
-
-_ERROR_QUITFUNC = _("""
-{error}
-
-|rQuit function gave an error. Skipping.|n
-""")
-
-_ERROR_PERSISTENT_SAVING = _("""
-{error}
-
-|rThe editor state could not be saved for persistent mode. Switching
-to non-persistent mode (which means the editor session won't survive
-an eventual server reload - so save often!)|n
-""")
-
-_TRACE_PERSISTENT_SAVING = _(
-    "EvEditor persistent-mode error. Commonly, this is because one or "
-    "more of the EvEditor callbacks could not be pickled, for example "
-    "because it's a class method or is defined inside another function."
-)
-
-
-_MSG_NO_UNDO = _("Nothing to undo.")
-_MSG_NO_REDO = _("Nothing to redo.")
-_MSG_UNDO = _("Undid one step.")
-_MSG_REDO = _("Redid one step.")
-
-# -------------------------------------------------------------
-#
-# Handle yes/no quit question
-#
-# -------------------------------------------------------------
-
-
-
[docs]class CmdSaveYesNo(_COMMAND_DEFAULT_CLASS): - """ - Save the editor state on quit. This catches - nomatches (defaults to Yes), and avoid saves only if - command was given specifically as "no" or "n". - """ - - key = _CMD_NOMATCH - aliases = _CMD_NOINPUT - locks = "cmd:all()" - help_cateogory = "LineEditor" - -
[docs] def func(self): - """ - Implement the yes/no choice. - - """ - # this is only called from inside the lineeditor - # so caller.ndb._lineditor must be set. - - self.caller.cmdset.remove(SaveYesNoCmdSet) - if self.raw_string.strip().lower() in ("no", "n"): - # answered no - self.caller.msg(self.caller.ndb._eveditor.quit()) - else: - # answered yes (default) - self.caller.ndb._eveditor.save_buffer() - self.caller.ndb._eveditor.quit()
- - -
[docs]class SaveYesNoCmdSet(CmdSet): - """ - Stores the yesno question - - """ - - key = "quitsave_yesno" - priority = 150 # override other cmdsets. - mergetype = "Replace" - -
[docs] def at_cmdset_creation(self): - """at cmdset creation""" - self.add(CmdSaveYesNo())
- - -# ------------------------------------------------------------- -# -# Editor commands -# -# ------------------------------------------------------------- - - -
[docs]class CmdEditorBase(_COMMAND_DEFAULT_CLASS): - """ - Base parent for editor commands - """ - - locks = "cmd:all()" - help_entry = "LineEditor" - - editor = None - -
[docs] def parse(self): - """ - Handles pre-parsing. Editor commands are on the form - - :: - - :cmd [li] [w] [txt] - - Where all arguments are optional. - - - `li` - line number (int), starting from 1. This could also - be a range given as <l>:<l>. - - `w` - word(s) (string), could be encased in quotes. - - `txt` - extra text (string), could be encased in quotes. - - """ - - editor = self.caller.ndb._eveditor - if not editor: - # this will completely replace the editor - _load_editor(self.caller) - editor = self.caller.ndb._eveditor - self.editor = editor - - linebuffer = self.editor.get_buffer().split("\n") - - nlines = len(linebuffer) - - # The regular expression will split the line by whitespaces, - # stripping extra whitespaces, except if the text is - # surrounded by single- or double quotes, in which case they - # will be kept together and extra whitespace preserved. You - # can input quotes on the line by alternating single and - # double quotes. - arglist = [part for part in _RE_GROUP.findall(self.args) if part] - temp = [] - for arg in arglist: - # we want to clean the quotes, but only one type, - # in case we are nesting. - if arg.startswith('"'): - arg.strip('"') - elif arg.startswith("'"): - arg.strip("'") - temp.append(arg) - arglist = temp - - # A dumb split, without grouping quotes - words = self.args.split() - - # current line number - cline = nlines - 1 - - # the first argument could also be a range of line numbers, on the - # form <lstart>:<lend>. Either of the ends could be missing, to - # mean start/end of buffer respectively. - - lstart, lend = cline, cline + 1 - linerange = False - if arglist and arglist[0].count(":") == 1: - part1, part2 = arglist[0].split(":") - if part1 and part1.isdigit(): - lstart = min(max(0, int(part1)) - 1, nlines) - linerange = True - if part2 and part2.isdigit(): - lend = min(lstart + 1, int(part2)) + 1 - linerange = True - elif arglist and arglist[0].isdigit(): - lstart = min(max(0, int(arglist[0]) - 1), nlines) - lend = lstart + 1 - linerange = True - if linerange: - arglist = arglist[1:] - - # nicer output formatting of the line range. - lstr = ( - "line %i" % (lstart + 1) - if not linerange or lstart + 1 == lend - else "lines %i-%i" % (lstart + 1, lend) - ) - - # arg1 and arg2 is whatever arguments. Line numbers or -ranges are - # never included here. - args = " ".join(arglist) - arg1, arg2 = "", "" - if len(arglist) > 1: - arg1, arg2 = arglist[0], " ".join(arglist[1:]) - else: - arg1 = " ".join(arglist) - - # store for use in func() - - self.linebuffer = linebuffer - self.nlines = nlines - self.arglist = arglist - self.cline = cline - self.lstart = lstart - self.lend = lend - self.linerange = linerange - self.lstr = lstr - self.words = words - self.args = args - self.arg1 = arg1 - self.arg2 = arg2
- - -def _load_editor(caller): - """ - Load persistent editor from storage. - - """ - saved_options = caller.attributes.get("_eveditor_saved") - saved_buffer, saved_undo = caller.attributes.get("_eveditor_buffer_temp", (None, None)) - unsaved = caller.attributes.get("_eveditor_unsaved", False) - indent = caller.attributes.get("_eveditor_indent", 0) - if saved_options: - eveditor = EvEditor(caller, **saved_options[0]) - if saved_buffer: - # we have to re-save the buffer data so we can handle subsequent restarts - caller.attributes.add("_eveditor_buffer_temp", (saved_buffer, saved_undo)) - setattr(eveditor, "_buffer", saved_buffer) - setattr(eveditor, "_undo_buffer", saved_undo) - setattr(eveditor, "_undo_pos", len(saved_undo) - 1) - setattr(eveditor, "_unsaved", unsaved) - setattr(eveditor, "_indent", indent) - for key, value in saved_options[1].items(): - setattr(eveditor, key, value) - else: - # something went wrong. Cleanup. - caller.cmdset.remove(EvEditorCmdSet) - - -
[docs]class CmdLineInput(CmdEditorBase): - """ - No command match - Inputs line of text into buffer. - - """ - - key = _CMD_NOMATCH - aliases = _CMD_NOINPUT - -
[docs] def func(self): - """ - Adds the line without any formatting changes. - - If the editor handles code, it might add automatic - indentation. - """ - caller = self.caller - editor = caller.ndb._eveditor - buf = editor.get_buffer() - - # add a line of text to buffer - line = self.raw_string.strip("\r\n") - if editor._codefunc and editor._indent >= 0: - # if automatic indentation is active, add spaces - line = editor.deduce_indent(line, buf) - buf = line if not buf else buf + "\n%s" % line - self.editor.update_buffer(buf) - if self.editor._echo_mode: - # need to do it here or we will be off one line - cline = len(self.editor.get_buffer().split("\n")) - if editor._codefunc: - # display the current level of identation - indent = editor._indent - if indent < 0: - indent = "off" - - self.caller.msg("|b%02i|||n (|g%s|n) %s" % (cline, indent, raw(line))) - else: - self.caller.msg("|b%02i|||n %s" % (cline, raw(self.args)))
- - -
[docs]class CmdEditorGroup(CmdEditorBase): - """ - Commands for the editor - """ - - key = ":editor_command_group" - aliases = [ - ":", - "::", - ":::", - ":h", - ":w", - ":wq", - ":q", - ":q!", - ":u", - ":uu", - ":UU", - ":dd", - ":dw", - ":DD", - ":y", - ":x", - ":p", - ":i", - ":j", - ":r", - ":I", - ":A", - ":s", - ":S", - ":f", - ":fi", - ":fd", - ":echo", - ":!", - ":<", - ":>", - ":=", - ] - arg_regex = r"\s.*?|$" - -
[docs] def func(self): - """ - This command handles all the in-editor :-style commands. Since - each command is small and very limited, this makes for a more - efficient presentation. - - """ - caller = self.caller - editor = caller.ndb._eveditor - - linebuffer = self.linebuffer - lstart, lend = self.lstart, self.lend - cmd = self.cmdstring - echo_mode = self.editor._echo_mode - - if cmd == ":": - # Echo buffer - if self.linerange: - buf = linebuffer[lstart:lend] - editor.display_buffer(buf=buf, offset=lstart) - else: - editor.display_buffer() - elif cmd == "::": - # Echo buffer without the line numbers and syntax parsing - if self.linerange: - buf = linebuffer[lstart:lend] - editor.display_buffer(buf=buf, offset=lstart, linenums=False, options={"raw": True}) - else: - editor.display_buffer(linenums=False, options={"raw": True}) - elif cmd == ":::": - # Insert single colon alone on a line - editor.update_buffer([":"] if lstart == 0 else linebuffer + [":"]) - if echo_mode: - caller.msg(_("Single ':' added to buffer.")) - elif cmd == ":h": - # help entry - editor.display_help() - elif cmd == ":w": - # save without quitting - editor.save_buffer() - elif cmd == ":wq": - # save and quit - editor.save_buffer() - editor.quit() - elif cmd == ":q": - # quit. If not saved, will ask - if self.editor._unsaved: - caller.cmdset.add(SaveYesNoCmdSet) - caller.msg(_("Save before quitting?") + " |lcyes|lt[Y]|le/|lcno|ltN|le") - else: - editor.quit() - elif cmd == ":q!": - # force quit, not checking saving - editor.quit() - elif cmd == ":u": - # undo - editor.update_undo(-1) - elif cmd == ":uu": - # redo - editor.update_undo(1) - elif cmd == ":UU": - # reset buffer - editor.update_buffer(editor._pristine_buffer) - caller.msg(_("Reverted all changes to the buffer back to original state.")) - elif cmd == ":dd": - # :dd <l> - delete line <l> - buf = linebuffer[:lstart] + linebuffer[lend:] - editor.update_buffer(buf) - caller.msg(_("Deleted {string}.").format(string=self.lstr)) - elif cmd == ":dw": - # :dw <w> - delete word in entire buffer - # :dw <l> <w> delete word only on line(s) <l> - if not self.arg1: - caller.msg(_("You must give a search word to delete.")) - else: - if not self.linerange: - lstart = 0 - lend = self.cline + 1 - caller.msg(_("Removed {arg1} for lines {l1}-{l2}.").format( - arg1=self.arg1, l1=lstart + 1, l2=lend + 1)) - else: - caller.msg(_("Removed {arg1} for {line}.").format( - arg1=self.arg1, line=self.lstr)) - sarea = "\n".join(linebuffer[lstart:lend]) - sarea = re.sub(r"%s" % self.arg1.strip("'").strip('"'), "", sarea, re.MULTILINE) - buf = linebuffer[:lstart] + sarea.split("\n") + linebuffer[lend:] - editor.update_buffer(buf) - elif cmd == ":DD": - # clear buffer - editor.update_buffer("") - - # Reset indentation level to 0 - if editor._codefunc: - if editor._indent >= 0: - editor._indent = 0 - if editor._persistent: - caller.attributes.add("_eveditor_indent", 0) - caller.msg(_("Cleared {nlines} lines from buffer.").format(nlines=self.nlines)) - elif cmd == ":y": - # :y <l> - yank line(s) to copy buffer - cbuf = linebuffer[lstart:lend] - editor._copy_buffer = cbuf - caller.msg(_("{line}, {cbuf} yanked.").format(line=self.lstr.capitalize(), cbuf=cbuf)) - elif cmd == ":x": - # :x <l> - cut line to copy buffer - cbuf = linebuffer[lstart:lend] - editor._copy_buffer = cbuf - buf = linebuffer[:lstart] + linebuffer[lend:] - editor.update_buffer(buf) - caller.msg(_("{line}, {cbuf} cut.").format(line=self.lstr.capitalize(), cbuf=cbuf)) - elif cmd == ":p": - # :p <l> paste line(s) from copy buffer - if not editor._copy_buffer: - caller.msg(_("Copy buffer is empty.")) - else: - buf = linebuffer[:lstart] + editor._copy_buffer + linebuffer[lstart:] - editor.update_buffer(buf) - caller.msg(_("Pasted buffer {cbuf} to {line}.").format( - cbuf=editor._copy_buffer, line=self.lstr)) - elif cmd == ":i": - # :i <l> <txt> - insert new line - new_lines = self.args.split("\n") - if not new_lines: - caller.msg(_("You need to enter a new line and where to insert it.")) - else: - buf = linebuffer[:lstart] + new_lines + linebuffer[lstart:] - editor.update_buffer(buf) - caller.msg(_("Inserted {num} new line(s) at {line}.").format( - num=len(new_lines), line=self.lstr)) - elif cmd == ":r": - # :r <l> <txt> - replace lines - new_lines = self.args.split("\n") - if not new_lines: - caller.msg(_("You need to enter a replacement string.")) - else: - buf = linebuffer[:lstart] + new_lines + linebuffer[lend:] - editor.update_buffer(buf) - caller.msg(_("Replaced {num} line(s) at {line}.").format( - num=len(new_lines), line=self.lstr)) - elif cmd == ":I": - # :I <l> <txt> - insert text at beginning of line(s) <l> - if not self.raw_string and not editor._codefunc: - caller.msg(_("You need to enter text to insert.")) - else: - buf = ( - linebuffer[:lstart] - + ["%s%s" % (self.args, line) for line in linebuffer[lstart:lend]] - + linebuffer[lend:] - ) - editor.update_buffer(buf) - caller.msg(_("Inserted text at beginning of {line}.").format(line=self.lstr)) - elif cmd == ":A": - # :A <l> <txt> - append text after end of line(s) - if not self.args: - caller.msg(_("You need to enter text to append.")) - else: - buf = ( - linebuffer[:lstart] - + ["%s%s" % (line, self.args) for line in linebuffer[lstart:lend]] - + linebuffer[lend:] - ) - editor.update_buffer(buf) - caller.msg(_("Appended text to end of {line}.").format(line=self.lstr)) - elif cmd == ":s": - # :s <li> <w> <txt> - search and replace words - # in entire buffer or on certain lines - if not self.arg1 or not self.arg2: - caller.msg(_("You must give a search word and something to replace it with.")) - else: - if not self.linerange: - lstart = 0 - lend = self.cline + 1 - caller.msg( - _("Search-replaced {arg1} -> {arg2} for lines {l1}-{l2}.").format( - arg1=self.arg1, arg2=self.arg2, l1=lstart + 1, l2=lend) - ) - else: - caller.msg( - _("Search-replaced {arg1} -> {arg2} for {line}.").format( - arg1=self.arg1, arg2=self.arg2, line=self.lstr) - ) - sarea = "\n".join(linebuffer[lstart:lend]) - - regex = r"%s|^%s(?=\s)|(?<=\s)%s(?=\s)|^%s$|(?<=\s)%s$" - regarg = self.arg1.strip("'").strip('"') - if " " in regarg: - regarg = regarg.replace(" ", " +") - sarea = re.sub( - regex % (regarg, regarg, regarg, regarg, regarg), - self.arg2.strip("'").strip('"'), - sarea, - re.MULTILINE, - ) - buf = linebuffer[:lstart] + sarea.split("\n") + linebuffer[lend:] - editor.update_buffer(buf) - elif cmd == ":f": - # :f <l> flood-fill buffer or <l> lines of buffer. - width = _DEFAULT_WIDTH - if not self.linerange: - lstart = 0 - lend = self.cline + 1 - caller.msg(_("Flood filled lines {l1}-{l2}.").format( - l1=lstart + 1, l2=lend)) - else: - caller.msg(_("Flood filled {line}.").format(line=self.lstr)) - fbuf = "\n".join(linebuffer[lstart:lend]) - fbuf = fill(fbuf, width=width) - buf = linebuffer[:lstart] + fbuf.split("\n") + linebuffer[lend:] - editor.update_buffer(buf) - elif cmd == ":j": - # :f <l> <w> justify buffer of <l> with <w> as align (one of - # f(ull), c(enter), r(ight) or l(left). Default is full. - align_map = { - "full": "f", - "f": "f", - "center": "c", - "c": "c", - "right": "r", - "r": "r", - "left": "l", - "l": "l", - } - align_name = {"f": "Full", "c": "Center", "l": "Left", "r": "Right"} - width = _DEFAULT_WIDTH - if self.arg1 and self.arg1.lower() not in align_map: - self.caller.msg( - _("Valid justifications are") - + " [f]ull (default), [c]enter, [r]right or [l]eft" - ) - return - align = align_map[self.arg1.lower()] if self.arg1 else "f" - if not self.linerange: - lstart = 0 - lend = self.cline + 1 - self.caller.msg(_("{align}-justified lines {l1}-{l2}.").format( - align=align_name[align], l1=lstart + 1, l2=lend)) - else: - self.caller.msg(_("{align}-justified {line}.").format( - align=align_name[align], line=self.lstr)) - jbuf = "\n".join(linebuffer[lstart:lend]) - jbuf = justify(jbuf, width=width, align=align) - buf = linebuffer[:lstart] + jbuf.split("\n") + linebuffer[lend:] - editor.update_buffer(buf) - elif cmd == ":fi": - # :fi <l> indent buffer or lines <l> of buffer. - indent = " " * 4 - if not self.linerange: - lstart = 0 - lend = self.cline + 1 - caller.msg(_("Indented lines {l1}-{l2}.").format(l1=lstart + 1, l2=lend)) - else: - caller.msg(_("Indented {line}.").format(line=self.lstr)) - fbuf = [indent + line for line in linebuffer[lstart:lend]] - buf = linebuffer[:lstart] + fbuf + linebuffer[lend:] - editor.update_buffer(buf) - elif cmd == ":fd": - # :fi <l> indent buffer or lines <l> of buffer. - if not self.linerange: - lstart = 0 - lend = self.cline + 1 - caller.msg(_("Removed left margin (dedented) lines {l1}-{l2}.").format( - l1=lstart + 1, l2=lend)) - else: - caller.msg(_("Removed left margin (dedented) {line}.").format(line=self.lstr)) - fbuf = "\n".join(linebuffer[lstart:lend]) - fbuf = dedent(fbuf) - buf = linebuffer[:lstart] + fbuf.split("\n") + linebuffer[lend:] - editor.update_buffer(buf) - elif cmd == ":echo": - # set echoing on/off - editor._echo_mode = not editor._echo_mode - caller.msg(_("Echo mode set to {mode}").format(mode=editor._echo_mode)) - elif cmd == ":!": - if editor._codefunc: - editor._codefunc(caller, editor._buffer) - else: - caller.msg(_("This command is only available in code editor mode.")) - elif cmd == ":<": - # :< - if editor._codefunc: - editor.decrease_indent() - indent = editor._indent - if indent >= 0: - caller.msg(_( - "Decreased indentation: new indentation is {indent}.").format( - indent=indent)) - else: - caller.msg(_("|rManual indentation is OFF.|n Use := to turn it on.")) - else: - caller.msg(_("This command is only available in code editor mode.")) - elif cmd == ":>": - # :> - if editor._codefunc: - editor.increase_indent() - indent = editor._indent - if indent >= 0: - caller.msg(_( - "Increased indentation: new indentation is {indent}.").format( - indent=indent)) - else: - caller.msg(_("|rManual indentation is OFF.|n Use := to turn it on.")) - else: - caller.msg(_("This command is only available in code editor mode.")) - elif cmd == ":=": - # := - if editor._codefunc: - editor.swap_autoindent() - indent = editor._indent - if indent >= 0: - caller.msg(_("Auto-indentation turned on.")) - else: - caller.msg(_("Auto-indentation turned off.")) - else: - caller.msg(_("This command is only available in code editor mode."))
- - -
[docs]class EvEditorCmdSet(CmdSet): - """CmdSet for the editor commands""" - - key = "editorcmdset" - mergetype = "Replace" - -
[docs] def at_cmdset_creation(self): - self.add(CmdLineInput()) - self.add(CmdEditorGroup())
- - -# ------------------------------------------------------------- -# -# Main Editor object -# -# ------------------------------------------------------------- - - -
[docs]class EvEditor: - """ - This defines a line editor object. It creates all relevant commands - and tracks the current state of the buffer. It also cleans up after - itself. - - """ - -
[docs] def __init__( - self, - caller, - loadfunc=None, - savefunc=None, - quitfunc=None, - key="", - persistent=False, - codefunc=False, - ): - """ - Launches a full in-game line editor, mimicking the functionality of VIM. - - Args: - caller (Object): Who is using the editor. - loadfunc (callable, optional): This will be called as - `loadfunc(caller)` when the editor is first started. Its - return will be used as the editor's starting buffer. - savefunc (callable, optional): This will be called as - `savefunc(caller, buffer)` when the save-command is given and - is used to actually determine where/how result is saved. - It should return `True` if save was successful and also - handle any feedback to the user. - quitfunc (callable, optional): This will optionally be - called as `quitfunc(caller)` when the editor is - exited. If defined, it should handle all wanted feedback - to the user. - quitfunc_args (tuple, optional): Optional tuple of arguments to - supply to `quitfunc`. - key (str, optional): An optional key for naming this - session and make it unique from other editing sessions. - persistent (bool, optional): Make the editor survive a reboot. Note - that if this is set, all callables must be possible to pickle - codefunc (bool, optional): If given, will run the editor in code mode. - This will be called as `codefunc(caller, buf)`. - - Notes: - In persistent mode, all the input callables (savefunc etc) - must be possible to be *pickled*, this excludes e.g. - callables that are class methods or functions defined - dynamically or as part of another function. In - non-persistent mode no such restrictions exist. - - - - """ - self._key = key - self._caller = caller - self._caller.ndb._eveditor = self - self._buffer = "" - self._unsaved = False - self._persistent = persistent - self._indent = 0 - - if loadfunc: - self._loadfunc = loadfunc - else: - self._loadfunc = lambda caller: self._buffer - self.load_buffer() - if savefunc: - self._savefunc = savefunc - else: - self._savefunc = lambda caller, buffer: caller.msg(_ERROR_NO_SAVEFUNC) - if quitfunc: - self._quitfunc = quitfunc - else: - self._quitfunc = lambda caller: caller.msg(_DEFAULT_NO_QUITFUNC) - self._codefunc = codefunc - - # store the original version - self._pristine_buffer = self._buffer - self._sep = "-" - - # undo operation buffer - self._undo_buffer = [self._buffer] - self._undo_pos = 0 - self._undo_max = 20 - - # copy buffer - self._copy_buffer = [] - - if persistent: - # save in tuple {kwargs, other options} - try: - caller.attributes.add( - "_eveditor_saved", - ( - dict( - loadfunc=loadfunc, - savefunc=savefunc, - quitfunc=quitfunc, - codefunc=codefunc, - key=key, - persistent=persistent, - ), - dict(_pristine_buffer=self._pristine_buffer, _sep=self._sep), - ), - ) - caller.attributes.add("_eveditor_buffer_temp", (self._buffer, self._undo_buffer)) - caller.attributes.add("_eveditor_unsaved", False) - caller.attributes.add("_eveditor_indent", 0) - except Exception as err: - caller.msg(_ERROR_PERSISTENT_SAVING.format(error=err)) - logger.log_trace(_TRACE_PERSISTENT_SAVING) - persistent = False - - # Create the commands we need - caller.cmdset.add(EvEditorCmdSet, persistent=persistent) - - # echo inserted text back to caller - self._echo_mode = True - - # show the buffer ui - self.display_buffer()
- -
[docs] def load_buffer(self): - """ - Load the buffer using the load function hook. - - """ - try: - self._buffer = self._loadfunc(self._caller) - if not isinstance(self._buffer, str): - self._caller.msg(f"|rBuffer is of type |w{type(self._buffer)})|r. " - "Continuing, it is converted to a string " - "(and will be saved as such)!|n") - self._buffer = to_str(self._buffer) - except Exception as e: - from evennia.utils import logger - - logger.log_trace() - self._caller.msg(_ERROR_LOADFUNC.format(error=e))
- -
[docs] def get_buffer(self): - """ - Return: - buffer (str): The current buffer. - - """ - return self._buffer
- -
[docs] def update_buffer(self, buf): - """ - This should be called when the buffer has been changed - somehow. It will handle unsaved flag and undo updating. - - Args: - buf (str): The text to update the buffer with. - - """ - if is_iter(buf): - buf = "\n".join(buf) - - if buf != self._buffer: - self._buffer = buf - self.update_undo() - self._unsaved = True - if self._persistent: - self._caller.attributes.add( - "_eveditor_buffer_temp", (self._buffer, self._undo_buffer) - ) - self._caller.attributes.add("_eveditor_unsaved", True) - self._caller.attributes.add("_eveditor_indent", self._indent)
- -
[docs] def quit(self): - """ - Cleanly exit the editor. - - """ - try: - self._quitfunc(self._caller) - except Exception as e: - self._caller.msg(_ERROR_QUITFUNC.format(error=e)) - self._caller.nattributes.remove("_eveditor") - self._caller.attributes.remove("_eveditor_buffer_temp") - self._caller.attributes.remove("_eveditor_saved") - self._caller.attributes.remove("_eveditor_unsaved") - self._caller.attributes.remove("_eveditor_indent") - self._caller.cmdset.remove(EvEditorCmdSet)
- -
[docs] def save_buffer(self): - """ - Saves the content of the buffer. - - """ - if self._unsaved or self._codefunc: - # always save code - this allows us to tie execution to - # saving if we want. - try: - if self._savefunc(self._caller, self._buffer): - # Save codes should return a true value to indicate - # save worked. The saving function is responsible for - # any status messages. - self._unsaved = False - except Exception as e: - self._caller.msg(_ERROR_SAVEFUNC.format(error=e)) - else: - self._caller.msg(_MSG_SAVE_NO_CHANGE)
- -
[docs] def update_undo(self, step=None): - """ - This updates the undo position. - - Args: - step (int, optional): The amount of steps - to progress the undo position to. This - may be a negative value for undo and - a positive value for redo. - - """ - if step and step < 0: - # undo - if self._undo_pos <= 0: - self._caller.msg(_MSG_NO_UNDO) - else: - self._undo_pos = max(0, self._undo_pos + step) - self._buffer = self._undo_buffer[self._undo_pos] - self._caller.msg(_MSG_UNDO) - elif step and step > 0: - # redo - if self._undo_pos >= len(self._undo_buffer) - 1 or self._undo_pos + 1 >= self._undo_max: - self._caller.msg(_MSG_NO_REDO) - else: - self._undo_pos = min( - self._undo_pos + step, min(len(self._undo_buffer), self._undo_max) - 1 - ) - self._buffer = self._undo_buffer[self._undo_pos] - self._caller.msg(_MSG_REDO) - if not self._undo_buffer or ( - self._undo_buffer and self._buffer != self._undo_buffer[self._undo_pos] - ): - # save undo state - self._undo_buffer = self._undo_buffer[: self._undo_pos + 1] + [self._buffer] - self._undo_pos = len(self._undo_buffer) - 1
- -
[docs] def display_buffer(self, buf=None, offset=0, linenums=True, options={"raw": False}): - """ - This displays the line editor buffer, or selected parts of it. - - Args: - buf (str, optional): The buffer or part of buffer to display. - offset (int, optional): If `buf` is set and is not the full buffer, - `offset` should define the actual starting line number, to - get the linenum display right. - linenums (bool, optional): Show line numbers in buffer. - options: raw (bool, optional): Tell protocol to not parse - formatting information. - - """ - if buf is None: - buf = self._buffer - if is_iter(buf): - buf = "\n".join(buf) - - lines = buf.split("\n") - nlines = len(lines) - nwords = len(buf.split()) - nchars = len(buf) - - sep = self._sep - header = ( - "|n" - + sep * 10 - + _("Line Editor [{name}]").format(name=self._key) - + sep * (_DEFAULT_WIDTH - 24 - len(self._key)) - ) - footer = ( - "|n" - + sep * 10 - + "[l:%02i w:%03i c:%04i]" % (nlines, nwords, nchars) - + sep * 12 - + _("(:h for help)") - + sep * (_DEFAULT_WIDTH - 54) - ) - if linenums: - main = "\n".join( - "|b%02i|||n %s" % (iline + 1 + offset, raw(line)) - for iline, line in enumerate(lines) - ) - else: - main = "\n".join([raw(line) for line in lines]) - string = "%s\n%s\n%s" % (header, main, footer) - self._caller.msg(string, options=options)
- -
[docs] def display_help(self): - """ - Shows the help entry for the editor. - - """ - string = self._sep * _DEFAULT_WIDTH + _HELP_TEXT - if self._codefunc: - string += _HELP_CODE - string += _HELP_LEGEND + self._sep * _DEFAULT_WIDTH - self._caller.msg(string)
- -
[docs] def deduce_indent(self, line, buffer): - """ - Try to deduce the level of indentation of the given line. - - """ - keywords = { - "elif ": ["if "], - "else:": ["if ", "try"], - "except": ["try:"], - "finally:": ["try:"], - } - opening_tags = ("if ", "try:", "for ", "while ") - - # If the line begins by one of the given keywords - indent = self._indent - if any(line.startswith(kw) for kw in keywords.keys()): - # Get the keyword and matching begin tags - keyword = [kw for kw in keywords if line.startswith(kw)][0] - begin_tags = keywords[keyword] - for oline in reversed(buffer.splitlines()): - if any(oline.lstrip(" ").startswith(tag) for tag in begin_tags): - # This line begins with a begin tag, takes the identation - indent = (len(oline) - len(oline.lstrip(" "))) / 4 - break - - self._indent = indent + 1 - if self._persistent: - self._caller.attributes.add("_eveditor_indent", self._indent) - elif any(line.startswith(kw) for kw in opening_tags): - self._indent = indent + 1 - if self._persistent: - self._caller.attributes.add("_eveditor_indent", self._indent) - - line = " " * 4 * indent + line - return line
- -
[docs] def decrease_indent(self): - """Decrease automatic indentation by 1 level.""" - if self._codefunc and self._indent > 0: - self._indent -= 1 - if self._persistent: - self._caller.attributes.add("_eveditor_indent", self._indent)
- -
[docs] def increase_indent(self): - """Increase automatic indentation by 1 level.""" - if self._codefunc and self._indent >= 0: - self._indent += 1 - if self._persistent: - self._caller.attributes.add("_eveditor_indent", self._indent)
- -
[docs] def swap_autoindent(self): - """Swap automatic indentation on or off.""" - if self._codefunc: - if self._indent >= 0: - self._indent = -1 - else: - self._indent = 0 - - if self._persistent: - self._caller.attributes.add("_eveditor_indent", self._indent)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/evform.html b/docs/0.9.5/_modules/evennia/utils/evform.html deleted file mode 100644 index de99093bc6..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/evform.html +++ /dev/null @@ -1,573 +0,0 @@ - - - - - - - - evennia.utils.evform — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.utils.evform

-# coding=utf-8
-"""
-EvForm - a way to create advanced ASCII forms
-
-This is intended for creating advanced ASCII game forms, such as a
-large pretty character sheet or info document.
-
-The system works on the basis of a readin template that is given in a
-separate Python file imported into the handler. This file contains
-some optional settings and a string mapping out the form. The template
-has markers in it to denounce fields to fill. The markers map the
-absolute size of the field and will be filled with an `evtable.EvCell`
-object when displaying the form.
-
-Example of input file `testform.py`:
-
-```python
-FORMCHAR = "x"
-TABLECHAR = "c"
-
-FORM = '''
-.------------------------------------------------.
-|                                                |
-|  Name: xxxxx1xxxxx    Player: xxxxxxx2xxxxxxx  |
-|        xxxxxxxxxxx                             |
-|                                                |
- >----------------------------------------------<
-|                                                |
-| Desc:  xxxxxxxxxxx    STR: x4x    DEX: x5x     |
-|        xxxxx3xxxxx    INT: x6x    STA: x7x     |
-|        xxxxxxxxxxx    LUC: x8x    MAG: x9x     |
-|                                                |
- >----------------------------------------------<
-|          |                                     |
-| cccccccc | ccccccccccccccccccccccccccccccccccc |
-| cccccccc | ccccccccccccccccccccccccccccccccccc |
-| cccAcccc | ccccccccccccccccccccccccccccccccccc |
-| cccccccc | ccccccccccccccccccccccccccccccccccc |
-| cccccccc | cccccccccccccccccBccccccccccccccccc |
-|          |                                     |
--------------------------------------------------
-'''
-```
-
-The first line of the `FORM` string is ignored. The forms and table
-markers must mark out complete, unbroken rectangles, each containing
-one embedded single-character identifier (so the smallest element
-possible is a 3-character wide form). The identifier can be any
-character except for the `FORM_CHAR` and `TABLE_CHAR` and some of the
-common ASCII-art elements, like space, `_` `|` `*` etc (see
-`INVALID_FORMCHARS` in this module). Form Rectangles can have any size,
-but must be separated from each other by at least one other
-character's width.
-
-
-Use as follows:
-
-```python
-    from evennia import EvForm, EvTable
-
-    # create a new form from the template
-    form = EvForm("path/to/testform.py")
-
-    (MudForm can also take a dictionary holding
-     the required keys FORMCHAR, TABLECHAR and FORM)
-
-    # add data to each tagged form cell
-    form.map(cells={1: "Tom the Bouncer",
-                    2: "Griatch",
-                    3: "A sturdy fellow",
-                    4: 12,
-                    5: 10,
-                    6:  5,
-                    7: 18,
-                    8: 10,
-                    9:  3})
-    # create the EvTables
-    tableA = EvTable("HP","MV","MP",
-                               table=[["**"], ["*****"], ["***"]],
-                               border="incols")
-    tableB = EvTable("Skill", "Value", "Exp",
-                               table=[["Shooting", "Herbalism", "Smithing"],
-                                      [12,14,9],["550/1200", "990/1400", "205/900"]],
-                               border="incols")
-    # add the tables to the proper ids in the form
-    form.map(tables={"A": tableA,
-                     "B": tableB})
-
-    print(form)
-```
-
-This produces the following result:
-
-::
-
-    .------------------------------------------------.
-    |                                                |
-    |  Name: Tom the        Player: Griatch          |
-    |        Bouncer                                 |
-    |                                                |
-     >----------------------------------------------<
-    |                                                |
-    | Desc:  A sturdy       STR: 12     DEX: 10      |
-    |        fellow         INT: 5      STA: 18      |
-    |                       LUC: 10     MAG: 3       |
-    |                                                |
-     >----------------------------------------------<
-    |          |                                     |
-    | HP|MV|MP | Skill      |Value      |Exp         |
-    | ~~+~~+~~ | ~~~~~~~~~~~+~~~~~~~~~~~+~~~~~~~~~~~ |
-    | **|**|** | Shooting   |12         |550/1200    |
-    |   |**|*  | Herbalism  |14         |990/1400    |
-    |   |* |   | Smithing   |9          |205/900     |
-    |          |                                     |
-     ------------------------------------------------
-
-The marked forms have been replaced with EvCells of text and with
-EvTables. The form can be updated by simply re-applying `form.map()`
-with the updated data.
-
-When working with the template ASCII file, you can use `form.reload()`
-to re-read the template and re-apply all existing mappings.
-
-Each component is restrained to the width and height specified by the
-template, so it will resize to fit (or crop text if the area is too
-small for it). If you try to fit a table into an area it cannot fit
-into (when including its borders and at least one line of text), the
-form will raise an error.
-
-----
-
-"""
-
-import re
-import copy
-from evennia.utils.evtable import EvCell, EvTable
-from evennia.utils.utils import all_from_module, to_str, is_iter
-from evennia.utils.ansi import ANSIString
-
-# non-valid form-identifying characters (which can thus be
-# used as separators between forms without being detected
-# as an identifier). These should be listed in regex form.
-
-INVALID_FORMCHARS = r"\s\/\|\\\*\_\-\#\<\>\~\^\:\;\.\,"
-# if there is an ansi-escape (||) we have to replace this with ||| to make sure
-# to properly escape down the line
-_ANSI_ESCAPE = re.compile(r"\|\|")
-
-
-def _to_rect(lines):
-    """
-    Forces all lines to be as long as the longest
-
-    Args:
-        lines (list): list of `ANSIString`s
-
-    Returns:
-        (list): list of `ANSIString`s of
-        same length as the longest input line
-
-    """
-    maxl = max(len(line) for line in lines)
-    return [line + " " * (maxl - len(line)) for line in lines]
-
-
-def _to_ansi(obj, regexable=False):
-    "convert to ANSIString"
-    if isinstance(obj, ANSIString):
-        return obj
-    elif isinstance(obj, str):
-        # since ansi will be parsed twice (here and in the normal ansi send), we have to
-        # escape the |-structure twice. TODO: This is tied to the default color-tag syntax
-        # which is not ideal for those wanting to replace/extend it ...
-        obj = _ANSI_ESCAPE.sub(r"||||", obj)
-    if isinstance(obj, dict):
-        return dict((key, _to_ansi(value, regexable=regexable)) for key, value in obj.items())
-    elif is_iter(obj):
-        return [_to_ansi(o) for o in obj]
-    else:
-        return ANSIString(obj, regexable=regexable)
-
-
-
[docs]class EvForm: - """ - This object is instantiated with a text file and parses - it for rectangular form fields. It can then be fed a - mapping so as to populate the fields with fixed-width - EvCell or Tables. - - """ - -
[docs] def __init__(self, filename=None, cells=None, tables=None, form=None, **kwargs): - """ - Initiate the form - - Keyword Args: - filename (str): Path to template file. - cells (dict): A dictionary mapping `{id: text}` - tables (dict): A dictionary mapping `{id: EvTable}`. - form (dict): A dictionary - `{"FORMCHAR":char, "TABLECHAR":char, "FORM":templatestring}`. - If this is given, filename is not read. - - Notes: - Other kwargs are fed as options to the EvCells and EvTables - (see `evtable.EvCell` and `evtable.EvTable` for more info). - - """ - self.filename = filename - self.input_form_dict = form - - self.cells_mapping = ( - dict((to_str(key), value) for key, value in cells.items()) if cells else {} - ) - self.tables_mapping = ( - dict((to_str(key), value) for key, value in tables.items()) if tables else {} - ) - - self.cellchar = "x" - self.tablechar = "c" - - self.raw_form = [] - self.form = [] - - # clean kwargs (these cannot be overridden) - kwargs.pop("enforce_size", None) - kwargs.pop("width", None) - kwargs.pop("height", None) - # table/cell options - self.options = kwargs - - self.reload()
- - def _parse_rectangles(self, cellchar, tablechar, form, **kwargs): - """ - Parse a form for rectangular formfields identified by formchar - enclosing an identifier. - - """ - - # update options given at creation with new input - this - # allows e.g. self.map() to add custom settings for individual - # cells/tables - custom_options = copy.copy(self.options) - custom_options.update(kwargs) - - nform = len(form) - - mapping = {} - cell_coords = {} - table_coords = {} - - # Locate the identifier tags and the horizontal end coords for all forms - re_cellchar = re.compile( - r"%s+([^%s%s]+)%s+" % (cellchar, INVALID_FORMCHARS, cellchar, cellchar) - ) - re_tablechar = re.compile( - r"%s+([^%s%s|+])%s+" % (tablechar, INVALID_FORMCHARS, tablechar, tablechar) - ) - for iy, line in enumerate(_to_ansi(form, regexable=True)): - # find cells - ix0 = 0 - while True: - match = re_cellchar.search(line, ix0) - if match: - # get the width of the rectangle directly from the match - cell_coords[match.group(1)] = [iy, match.start(), match.end()] - ix0 = match.end() - else: - break - # find tables - ix0 = 0 - while True: - match = re_tablechar.search(line, ix0) - if match: - # get the width of the rectangle directly from the match - table_coords[match.group(1)] = [iy, match.start(), match.end()] - ix0 = match.end() - else: - break - - # get rectangles and assign EvCells - for key, (iy, leftix, rightix) in cell_coords.items(): - # scan up to find top of rectangle - dy_up = 0 - if iy > 0: - for i in range(1, iy): - if all(form[iy - i][ix] == cellchar for ix in range(leftix, rightix)): - dy_up += 1 - else: - break - # find bottom edge of rectangle - dy_down = 0 - if iy < nform - 1: - for i in range(1, nform - iy - 1): - if all(form[iy + i][ix] == cellchar for ix in range(leftix, rightix)): - dy_down += 1 - else: - break - - # we have our rectangle. Calculate size of EvCell. - iyup = iy - dy_up - iydown = iy + dy_down - width = rightix - leftix - height = abs(iyup - iydown) + 1 - - # we have all the coordinates we need. Create EvCell. - data = self.cells_mapping.get(key, "") - # if key == "1": - - options = { - "pad_left": 0, - "pad_right": 0, - "pad_top": 0, - "pad_bottom": 0, - "align": "l", - "valign": "t", - "enforce_size": True, - } - options.update(custom_options) - # if key=="4": - - mapping[key] = ( - iyup, - leftix, - width, - height, - EvCell(data, width=width, height=height, **options), - ) - - # get rectangles and assign Tables - for key, (iy, leftix, rightix) in table_coords.items(): - - # scan up to find top of rectangle - dy_up = 0 - if iy > 0: - for i in range(1, iy): - if all(form[iy - i][ix] == tablechar for ix in range(leftix, rightix)): - dy_up += 1 - else: - break - # find bottom edge of rectangle - dy_down = 0 - if iy < nform - 1: - for i in range(1, nform - iy - 1): - if all(form[iy + i][ix] == tablechar for ix in range(leftix, rightix)): - dy_down += 1 - else: - break - - # we have our rectangle. Calculate size of Table. - iyup = iy - dy_up - iydown = iy + dy_down - width = rightix - leftix - height = abs(iyup - iydown) + 1 - - # we have all the coordinates we need. Create Table. - table = self.tables_mapping.get(key, None) - - options = { - "pad_left": 0, - "pad_right": 0, - "pad_top": 0, - "pad_bottom": 0, - "align": "l", - "valign": "t", - "enforce_size": True, - } - options.update(custom_options) - - if table: - table.reformat(width=width, height=height, **options) - else: - table = EvTable(width=width, height=height, **options) - mapping[key] = (iyup, leftix, width, height, table) - - return mapping - - def _populate_form(self, raw_form, mapping): - """ - Insert cell contents into form at given locations - - """ - form = copy.copy(raw_form) - for key, (iy0, ix0, width, height, cell_or_table) in mapping.items(): - # rect is a list of <height> lines, each <width> wide - rect = cell_or_table.get() - for il, rectline in enumerate(rect): - formline = form[iy0 + il] - # insert new content, replacing old - form[iy0 + il] = formline[:ix0] + rectline + formline[ix0 + width :] - return form - -
[docs] def map(self, cells=None, tables=None, **kwargs): - """ - Add mapping for form. - - Args: - cells (dict): A dictionary of {identifier:celltext} - tables (dict): A dictionary of {identifier:table} - - Notes: - kwargs will be forwarded to tables/cells. See - `evtable.EvCell` and `evtable.EvTable` for info. - - """ - # clean kwargs (these cannot be overridden) - kwargs.pop("enforce_size", None) - kwargs.pop("width", None) - kwargs.pop("height", None) - - new_cells = dict((to_str(key), value) for key, value in cells.items()) if cells else {} - new_tables = dict((to_str(key), value) for key, value in tables.items()) if tables else {} - - self.cells_mapping.update(new_cells) - self.tables_mapping.update(new_tables) - self.reload()
- -
[docs] def reload(self, filename=None, form=None, **kwargs): - """ - Creates the form from a stored file name. - - Args: - filename (str): The file to read from. - form (dict): A mapping for the form. - - Notes: - Kwargs are passed through to Cel creation. - - """ - # clean kwargs (these cannot be overridden) - kwargs.pop("enforce_size", None) - kwargs.pop("width", None) - kwargs.pop("height", None) - - if form or self.input_form_dict: - datadict = form if form else self.input_form_dict - self.input_form_dict = datadict - elif filename or self.filename: - filename = filename if filename else self.filename - datadict = all_from_module(filename) - self.filename = filename - else: - datadict = {} - - cellchar = to_str(datadict.get("FORMCHAR", "x")) - self.cellchar = to_str(cellchar[0] if len(cellchar) > 1 else cellchar) - tablechar = datadict.get("TABLECHAR", "c") - self.tablechar = tablechar[0] if len(tablechar) > 1 else tablechar - - # split into a list of list of lines. Form can be indexed with form[iy][ix] - raw_form = _to_ansi(datadict.get("FORM", "").split("\n")) - self.raw_form = _to_rect(raw_form) - - # strip first line - self.raw_form = self.raw_form[1:] if self.raw_form else self.raw_form - - self.options.update(kwargs) - - # parse and replace - self.mapping = self._parse_rectangles( - self.cellchar, self.tablechar, self.raw_form, **kwargs - ) - self.form = self._populate_form(self.raw_form, self.mapping)
- - def __str__(self): - "Prints the form" - return str(ANSIString("\n").join([line for line in self.form]))
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/evmenu.html b/docs/0.9.5/_modules/evennia/utils/evmenu.html deleted file mode 100644 index 836a839690..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/evmenu.html +++ /dev/null @@ -1,2230 +0,0 @@ - - - - - - - - evennia.utils.evmenu — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.utils.evmenu

-"""
-EvMenu
-
-This implements a full menu system for Evennia.
-
-To start the menu, just import the EvMenu class from this module.
-Example usage:
-
-```python
-
-    from evennia.utils.evmenu import EvMenu
-
-    EvMenu(caller, menu_module_path,
-         startnode="node1",
-         cmdset_mergetype="Replace", cmdset_priority=1,
-         auto_quit=True, cmd_on_exit="look", persistent=True)
-```
-
-Where `caller` is the Object to use the menu on - it will get a new
-cmdset while using the Menu. The menu_module_path is the python path
-to a python module containing function definitions.  By adjusting the
-keyword options of the Menu() initialization call you can start the
-menu at different places in the menu definition file, adjust if the
-menu command should overload the normal commands or not, etc.
-
-The `persistent` keyword will make the menu survive a server reboot.
-It is `False` by default. Note that if using persistent mode, every
-node and callback in the menu must be possible to be *pickled*, this
-excludes e.g. callables that are class methods or functions defined
-dynamically or as part of another function. In non-persistent mode
-no such restrictions exist.
-
-The menu is defined in a module (this can be the same module as the
-command definition too) with function definitions:
-
-```python
-
-    def node1(caller):
-        # (this is the start node if called like above)
-        # code
-        return text, options
-
-    def node_with_other_name(caller, input_string):
-        # code
-        return text, options
-
-    def another_node(caller, input_string, **kwargs):
-        # code
-        return text, options
-```
-
-Where caller is the object using the menu and input_string is the
-command entered by the user on the *previous* node (the command
-entered to get to this node). The node function code will only be
-executed once per node-visit and the system will accept nodes with
-both one or two arguments interchangeably. It also accepts nodes
-that takes `**kwargs`.
-
-The menu tree itself is available on the caller as
-`caller.ndb._evmenu`. This makes it a convenient place to store
-temporary state variables between nodes, since this NAttribute is
-deleted when the menu is exited.
-
-The return values must be given in the above order, but each can be
-returned as None as well. If the options are returned as None, the
-menu is immediately exited and the default "look" command is called.
-
-- `text` (str, tuple or None): Text shown at this node. If a tuple, the
-   second element in the tuple is a help text to display at this
-   node when the user enters the menu help command there.
-- `options` (tuple, dict or None): If `None`, this exits the menu.
-  If a single dict, this is a single-option node. If a tuple,
-  it should be a tuple of option dictionaries. Option dicts have the following keys:
-
-  - `key` (str or tuple, optional): What to enter to choose this option.
-    If a tuple, it must be a tuple of strings, where the first string is the
-    key which will be shown to the user and the others are aliases.
-    If unset, the options' number will be used. The special key `_default`
-    marks this option as the default fallback when no other option matches
-    the user input. There can only be one `_default` option per node. It
-    will not be displayed in the list.
-  - `desc` (str, optional): This describes what choosing the option will do.
-  - `goto` (str, tuple or callable): If string, should be the name of node to go to
-    when this option is selected. If a callable, it has the signature
-    `callable(caller[,raw_input][,**kwargs])`. If a tuple, the first element
-    is the callable and the second is a dict with the `**kwargs` to pass to
-    the callable. Those kwargs will also be passed into the next node if possible.
-    Such a callable should return either a str or a (str, dict), where the
-    string is the name of the next node to go to and the dict is the new,
-    (possibly modified) kwarg to pass into the next node. If the callable returns
-    None or the empty string, the current node will be revisited.
-  - `exec` (str, callable or tuple, optional): This takes the same input as `goto` above
-    and runs before it. If given a node name, the node will be executed but will not
-    be considered the next node. If node/callback returns str or (str, dict), these will
-    replace the `goto` step (`goto` callbacks will not fire), with the string being the
-    next node name and the optional dict acting as the kwargs-input for the next node.
-    If an exec callable returns the empty string (only), the current node is re-run.
-
-If `key` is not given, the option will automatically be identified by
-its number 1..N.
-
-Example:
-
-```python
-
-    # in menu_module.py
-
-    def node1(caller):
-        text = ("This is a node text",
-                "This is help text for this node")
-        options = ({"key": "testing",
-                    "desc": "Select this to go to node 2",
-                    "goto": ("node2", {"foo": "bar"}),
-                    "exec": "callback1"},
-                   {"desc": "Go to node 3.",
-                    "goto": "node3"})
-        return text, options
-
-    def callback1(caller):
-        # this is called when choosing the "testing" option in node1
-        # (before going to node2). If it returned a string, say 'node3',
-        # then the next node would be node3 instead of node2 as specified
-        # by the normal 'goto' option key above.
-        caller.msg("Callback called!")
-
-    def node2(caller, **kwargs):
-        text = '''
-            This is node 2. It only allows you to go back
-            to the original node1. This extra indent will
-            be stripped. We don't include a help text but
-            here are the variables passed to us: {}
-            '''.format(kwargs)
-        options = {"goto": "node1"}
-        return text, options
-
-    def node3(caller):
-        text = "This ends the menu since there are no options."
-        return text, None
-
-```
-
-When starting this menu with  `Menu(caller, "path.to.menu_module")`,
-the first node will look something like this:
-
-::
-
-    This is a node text
-    ______________________________________
-
-    testing: Select this to go to node 2
-    2: Go to node 3
-
-Where you can both enter "testing" and "1" to select the first option.
-If the client supports MXP, they may also mouse-click on "testing" to
-do the same. When making this selection, a function "callback1" in the
-same Using `help` will show the help text, otherwise a list of
-available commands while in menu mode.
-
-The menu tree is exited either by using the in-menu quit command or by
-reaching a node without any options.
-
-
-For a menu demo, import `CmdTestMenu` from this module and add it to
-your default cmdset. Run it with this module, like `testmenu evennia.utils.evmenu`.
-
-
-## Menu generation from template string
-
-In evmenu.py is a helper function `parse_menu_template` that parses a
-template-string and outputs a menu-tree dictionary suitable to pass into
-EvMenu:
-::
-
-    menutree = evmenu.parse_menu_template(caller, menu_template, goto_callables)
-    EvMenu(caller, menutree)
-
-For maximum flexibility you can inject normally-created nodes in the menu tree
-before passing it to EvMenu. If that's not needed, you can also create a menu
-in one step with:
-
-```python
-
-    evmenu.template2menu(caller, menu_template, goto_callables)
-
-```
-
-The `goto_callables` is a mapping `{"funcname": callable, ...}`, where each
-callable must be a module-global function on the form
-`funcname(caller, raw_string, **kwargs)` (like any goto-callable). The
-`menu_template` is a multi-line string on the following form:
-::
-
-    ## node start
-
-    This is the text of the start node.
-    The text area can have multiple lines, line breaks etc.
-
-    Each option below is one of these forms
-        key: desc -> gotostr_or_func
-        key: gotostr_or_func
-        >: gotostr_or_func
-        > glob/regex: gotostr_or_func
-
-    ## options
-
-        # comments are only allowed from beginning of line.
-        # Indenting is not necessary, but good for readability
-
-        1: Option number 1 -> node1
-        2: Option number 2 -> node2
-        next: This steps next -> go_back()
-        # the -> can be ignored if there is no desc
-        back: go_back(from_node=start)
-        abort: abort
-
-    ## node node1
-
-    Text for Node1. Enter a message!
-    <return> to go back.
-
-    ## options
-
-        # Starting the option-line with >
-        # allows to perform different actions depending on
-        # what is inserted.
-
-        # this catches everything starting with foo
-        > foo*: handle_foo_message()
-
-        # regex are also allowed (this catches number inputs)
-        > [0-9]+?: handle_numbers()
-
-        # this catches the empty return
-        >: start
-
-        # this catches everything else
-        > *: handle_message(from_node=node1)
-
-    ## node node2
-
-    Text for Node2. Just go back.
-
-    ## options
-
-        >: start
-
-    ## node abort
-
-    This exits the menu since there is no `## options` section.
-
-Each menu node is defined by a `# node <name>` containing the text of the node,
-followed by `## options` Also `## NODE` and `## OPTIONS` work. No python code
-logics is allowed in the template, this code is not evaluated but parsed. More
-advanced dynamic usage requires a full node-function (which can be added to the
-generated dict, as said).
-
-Adding `(..)` to a goto treats it as a callable and it must then be included in
-the `goto_callable` mapping. Only named keywords (or no args at all) are
-allowed, these will be added to the `**kwargs` going into the callable. Quoting
-strings is only needed if wanting to pass strippable spaces, otherwise the
-key:values will be converted to strings/numbers with literal_eval before passed
-into the callable.
-
-The \\> option takes a glob or regex to perform different actions depending
-on user input. Make sure to sort these in increasing order of generality since
-they will be tested in sequence.
-
-----
-
-"""
-
-import re
-import inspect
-
-from ast import literal_eval
-from fnmatch import fnmatch
-
-from inspect import isfunction, getargspec
-from django.conf import settings
-from evennia import Command, CmdSet
-from evennia.utils import logger
-from evennia.utils.evtable import EvTable
-from evennia.utils.ansi import strip_ansi
-from evennia.utils.utils import mod_import, make_iter, pad, to_str, m_len, is_iter, dedent, crop
-from evennia.commands import cmdhandler
-
-# i18n
-from django.utils.translation import gettext as _
-
-# read from protocol NAWS later?
-_MAX_TEXT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
-
-# we use cmdhandler instead of evennia.syscmdkeys to
-# avoid some cases of loading before evennia init'd
-_CMD_NOMATCH = cmdhandler.CMD_NOMATCH
-_CMD_NOINPUT = cmdhandler.CMD_NOINPUT
-
-# Return messages
-
-
-_ERR_NOT_IMPLEMENTED = _(
-    "Menu node '{nodename}' is either not implemented or caused an error. "
-    "Make another choice or try 'q' to abort."
-)
-_ERR_GENERAL = _("Error in menu node '{nodename}'.")
-_ERR_NO_OPTION_DESC = _("No description.")
-_HELP_FULL = _("Commands: <menu option>, help, quit")
-_HELP_NO_QUIT = _("Commands: <menu option>, help")
-_HELP_NO_OPTIONS = _("Commands: help, quit")
-_HELP_NO_OPTIONS_NO_QUIT = _("Commands: help")
-_HELP_NO_OPTION_MATCH = _("Choose an option or try 'help'.")
-
-_ERROR_PERSISTENT_SAVING = """
-{error}
-
-|rThe menu state could not be saved for persistent mode. Switching
-to non-persistent mode (which means the menu session won't survive
-an eventual server reload).|n
-"""
-
-_TRACE_PERSISTENT_SAVING = (
-    "EvMenu persistent-mode error. Commonly, this is because one or "
-    "more of the EvEditor callbacks could not be pickled, for example "
-    "because it's a class method or is defined inside another function."
-)
-
-
-
[docs]class EvMenuError(RuntimeError): - """ - Error raised by menu when facing internal errors. - - """ - - pass
- - -
[docs]class EvMenuGotoAbortMessage(RuntimeError): - """ - This can be raised by a goto-callable to abort the goto flow. The message - stored with the executable will be sent to the caller who will remain on - the current node. This can be used to pass single-line returns without - re-running the entire node with text and options. - - Example: - raise EvMenuGotoMessage("That makes no sense.") - - """
- - -# ------------------------------------------------------------- -# -# Menu command and command set -# -# ------------------------------------------------------------- - - -
[docs]class CmdEvMenuNode(Command): - """ - Menu options. - """ - - key = _CMD_NOINPUT - aliases = [_CMD_NOMATCH] - locks = "cmd:all()" - help_category = "Menu" - auto_help_display_key = "<menu commands>" - -
[docs] def get_help(self): - return "Menu commands are explained within the menu."
- -
[docs] def func(self): - """ - Implement all menu commands. - """ - - def _restore(caller): - # check if there is a saved menu available. - # this will re-start a completely new evmenu call. - saved_options = caller.attributes.get("_menutree_saved") - if saved_options: - startnode_tuple = caller.attributes.get("_menutree_saved_startnode") - try: - startnode, startnode_input = startnode_tuple - except ValueError: # old form of startnode store - startnode, startnode_input = startnode_tuple, "" - if startnode: - saved_options[2]["startnode"] = startnode - saved_options[2]["startnode_input"] = startnode_input - MenuClass = saved_options[0] - # this will create a completely new menu call - MenuClass(caller, *saved_options[1], **saved_options[2]) - return True - return None - - caller = self.caller - # we store Session on the menu since this can be hard to - # get in multisession environments if caller is an Account. - menu = caller.ndb._evmenu - if not menu: - if _restore(caller): - return - orig_caller = caller - caller = caller.account if hasattr(caller, "account") else None - menu = caller.ndb._evmenu if caller else None - if not menu: - if caller and _restore(caller): - return - caller = self.session - menu = caller.ndb._evmenu - if not menu: - # can't restore from a session - err = "Menu object not found as %s.ndb._evmenu!" % orig_caller - orig_caller.msg( - err - ) # don't give the session as a kwarg here, direct to original - raise EvMenuError(err) - # we must do this after the caller with the menu has been correctly identified since it - # can be either Account, Object or Session (in the latter case this info will be - # superfluous). - caller.ndb._evmenu._session = self.session - # we have a menu, use it. - menu.parse_input(self.raw_string)
- - -
[docs]class EvMenuCmdSet(CmdSet): - """ - The Menu cmdset replaces the current cmdset. - - """ - - key = "menu_cmdset" - priority = 1 - mergetype = "Replace" - no_objs = True - no_exits = True - no_channels = False - -
[docs] def at_cmdset_creation(self): - """ - Called when creating the set. - """ - self.add(CmdEvMenuNode())
- - -# ------------------------------------------------------------ -# -# Menu main class -# -# ------------------------------------------------------------- - - -
[docs]class EvMenu: - """ - This object represents an operational menu. It is initialized from - a menufile.py instruction. - - """ - - # convenient helpers for easy overloading - node_border_char = "_" - -
[docs] def __init__( - self, - caller, - menudata, - startnode="start", - cmdset_mergetype="Replace", - cmdset_priority=1, - auto_quit=True, - auto_look=True, - auto_help=True, - cmd_on_exit="look", - persistent=False, - startnode_input="", - session=None, - debug=False, - **kwargs, - ): - """ - Initialize the menu tree and start the caller onto the first node. - - Args: - caller (Object, Account or Session): The user of the menu. - menudata (str, module or dict): The full or relative path to the module - holding the menu tree data. All global functions in this module - whose name doesn't start with '_ ' will be parsed as menu nodes. - Also the module itself is accepted as input. Finally, a dictionary - menu tree can be given directly. This must then be a mapping - `{"nodekey":callable,...}` where `callable` must be called as - and return the data expected of a menu node. This allows for - dynamic menu creation. - startnode (str, optional): The starting node name in the menufile. - cmdset_mergetype (str, optional): 'Replace' (default) means the menu - commands will be exclusive - no other normal commands will - be usable while the user is in the menu. 'Union' means the - menu commands will be integrated with the existing commands - (it will merge with `merge_priority`), if so, make sure that - the menu's command names don't collide with existing commands - in an unexpected way. Also the CMD_NOMATCH and CMD_NOINPUT will - be overloaded by the menu cmdset. Other cmdser mergetypes - has little purpose for the menu. - cmdset_priority (int, optional): The merge priority for the - menu command set. The default (1) is usually enough for most - types of menus. - auto_quit (bool, optional): Allow user to use "q", "quit" or - "exit" to leave the menu at any point. Recommended during - development! - auto_look (bool, optional): Automatically make "looK" or "l" to - re-show the last node. Turning this off means you have to handle - re-showing nodes yourself, but may be useful if you need to - use "l" for some other purpose. - auto_help (bool, optional): Automatically make "help" or "h" show - the current help entry for the node. If turned off, eventual - help must be handled manually, but it may be useful if you - need 'h' for some other purpose, for example. - cmd_on_exit (callable, str or None, optional): When exiting the menu - (either by reaching a node with no options or by using the - in-built quit command (activated with `allow_quit`), this - callback function or command string will be executed. - The callback function takes two parameters, the caller then the - EvMenu object. This is called after cleanup is complete. - Set to None to not call any command. - persistent (bool, optional): Make the Menu persistent (i.e. it will - survive a reload. This will make the Menu cmdset persistent. Use - with caution - if your menu is buggy you may end up in a state - you can't get out of! Also note that persistent mode requires - that all formatters, menu nodes and callables are possible to - *pickle*. When the server is reloaded, the latest node shown will be completely - re-run with the same input arguments - so be careful if you are counting - up some persistent counter or similar - the counter may be run twice if - reload happens on the node that does that. Note that if `debug` is True, - this setting is ignored and assumed to be False. - startnode_input (str or (str, dict), optional): Send an input text to `startnode` as if - a user input text from a fictional previous node. If including the dict, this will - be passed as **kwargs to that node. When the server reloads, - the latest visited node will be re-run as `node(caller, raw_string, **kwargs)`. - session (Session, optional): This is useful when calling EvMenu from an account - in multisession mode > 2. Note that this session only really relevant - for the very first display of the first node - after that, EvMenu itself - will keep the session updated from the command input. So a persistent - menu will *not* be using this same session anymore after a reload. - debug (bool, optional): If set, the 'menudebug' command will be made available - by default in all nodes of the menu. This will print out the current state of - the menu. Deactivate for production use! When the debug flag is active, the - `persistent` flag is deactivated. - **kwargs: All kwargs will become initialization variables on `caller.ndb._menutree`, - to be available at run. - - Raises: - EvMenuError: If the start/end node is not found in menu tree. - - Notes: - While running, the menu is stored on the caller as `caller.ndb._evmenu`. Also - the current Session (from the Command, so this is still valid in multisession - environments) is available through `caller.ndb._evmenu._session`. The `_evmenu` - property is a good one for storing intermediary data on between nodes since it - will be automatically deleted when the menu closes. - - In persistent mode, all nodes, formatters and callbacks in the menu must be - possible to be *pickled*, this excludes e.g. callables that are class methods - or functions defined dynamically or as part of another function. In - non-persistent mode no such restrictions exist. - - """ - self._startnode = startnode - self._menutree = self._parse_menudata(menudata) - self._persistent = persistent if not debug else False - self._quitting = False - - if startnode not in self._menutree: - raise EvMenuError("Start node '%s' not in menu tree!" % startnode) - - # public variables made available to the command - - self.caller = caller - - # track EvMenu kwargs - self.auto_quit = auto_quit - self.auto_look = auto_look - self.auto_help = auto_help - self.debug_mode = debug - self._session = session - if isinstance(cmd_on_exit, str): - # At this point menu._session will have been replaced by the - # menu command to the actual session calling. - self.cmd_on_exit = lambda caller, menu: caller.execute_cmd( - cmd_on_exit, session=menu._session - ) - elif callable(cmd_on_exit): - self.cmd_on_exit = cmd_on_exit - else: - self.cmd_on_exit = None - # current menu state - self.default = None - self.nodetext = None - self.helptext = None - self.options = None - self.nodename = None - self.node_kwargs = {} - - # used for testing - self.test_options = {} - self.test_nodetext = "" - - # assign kwargs as initialization vars on ourselves. - reserved_clash = set( - ( - "_startnode", - "_menutree", - "_session", - "_persistent", - "cmd_on_exit", - "default", - "nodetext", - "helptext", - "options", - "cmdset_mergetype", - "auto_quit", - ) - ).intersection(set(kwargs.keys())) - if reserved_clash: - raise RuntimeError( - f"One or more of the EvMenu `**kwargs` ({list(reserved_clash)}) " - "is reserved by EvMenu for internal use." - ) - for key, val in kwargs.items(): - setattr(self, key, val) - - if self.caller.ndb._evmenu: - # an evmenu already exists - we try to close it cleanly. Note that this will - # not fire the previous menu's end node. - try: - self.caller.ndb._evmenu.close_menu() - except Exception: - pass - - # store ourself on the object - self.caller.ndb._evmenu = self - - # DEPRECATED - for backwards-compatibility - self.caller.ndb._menutree = self - - if persistent: - # save the menu to the database - calldict = { - "startnode": startnode, - "cmdset_mergetype": cmdset_mergetype, - "cmdset_priority": cmdset_priority, - "auto_quit": auto_quit, - "auto_look": auto_look, - "auto_help": auto_help, - "cmd_on_exit": cmd_on_exit, - "persistent": persistent, - } - calldict.update(kwargs) - try: - caller.attributes.add("_menutree_saved", (self.__class__, (menudata,), calldict)) - caller.attributes.add("_menutree_saved_startnode", (startnode, startnode_input)) - except Exception as err: - self.msg(_ERROR_PERSISTENT_SAVING.format(error=err)) - logger.log_trace(_TRACE_PERSISTENT_SAVING) - persistent = False - - # set up the menu command on the caller - menu_cmdset = EvMenuCmdSet() - menu_cmdset.mergetype = str(cmdset_mergetype).lower().capitalize() or "Replace" - menu_cmdset.priority = int(cmdset_priority) - self.caller.cmdset.add(menu_cmdset, persistent=persistent) - - reserved_startnode_kwargs = set(("nodename", "raw_string")) - startnode_kwargs = {} - if isinstance(startnode_input, (tuple, list)) and len(startnode_input) > 1: - startnode_input, startnode_kwargs = startnode_input[:2] - if not isinstance(startnode_kwargs, dict): - raise EvMenuError("startnode_input must be either a str or a tuple (str, dict).") - clashing_kwargs = reserved_startnode_kwargs.intersection(set(startnode_kwargs.keys())) - if clashing_kwargs: - raise RuntimeError( - f"Evmenu startnode_inputs includes kwargs {tuple(clashing_kwargs)} that " - "clashes with EvMenu's internal usage." - ) - - # start the menu - self.goto(self._startnode, startnode_input, **startnode_kwargs)
- - def _parse_menudata(self, menudata): - """ - Parse a menufile for node functions and store in dictionary - map. Alternatively, accept a pre-made mapping dictionary of - node functions. - - Args: - menudata (str, module or dict): The python.path to the menufile, - or the python module itself. If a dict, this should be a - mapping nodename:callable, where the callable must match - the criteria for a menu node. - - Returns: - menutree (dict): A {nodekey: func} - - """ - if isinstance(menudata, dict): - # This is assumed to be a pre-loaded menu tree. - return menudata - else: - # a python path of a module - module = mod_import(menudata) - return dict( - (key, func) - for key, func in module.__dict__.items() - if isfunction(func) and not key.startswith("_") - ) - - def _format_node(self, nodetext, optionlist): - """ - Format the node text + option section - - Args: - nodetext (str): The node text - optionlist (list): List of (key, desc) pairs. - - Returns: - string (str): The options section, including - all needed spaces. - - Notes: - This will adjust the columns of the options, first to use - a maxiumum of 4 rows (expanding in columns), then gradually - growing to make use of the screen space. - - """ - - # handle the node text - nodetext = self.nodetext_formatter(nodetext) - - # handle the options - optionstext = self.options_formatter(optionlist) - - # format the entire node - return self.node_formatter(nodetext, optionstext) - - def _safe_call(self, callback, raw_string, **kwargs): - """ - Call a node-like callable, with a variable number of raw_string, *args, **kwargs, all of - which should work also if not present (only `caller` is always required). Return its result. - - """ - try: - try: - nargs = len(getargspec(callback).args) - except TypeError: - raise EvMenuError("Callable {} doesn't accept any arguments!".format(callback)) - supports_kwargs = bool(getargspec(callback).keywords) - if nargs <= 0: - raise EvMenuError("Callable {} doesn't accept any arguments!".format(callback)) - - if supports_kwargs: - if nargs > 1: - ret = callback(self.caller, raw_string, **kwargs) - # callback accepting raw_string, **kwargs - else: - # callback accepting **kwargs - ret = callback(self.caller, **kwargs) - elif nargs > 1: - # callback accepting raw_string - ret = callback(self.caller, raw_string) - else: - # normal callback, only the caller as arg - ret = callback(self.caller) - except EvMenuError: - errmsg = _ERR_GENERAL.format(nodename=callback) - self.msg(errmsg) - logger.log_trace() - raise - - return ret - - def _execute_node(self, nodename, raw_string, **kwargs): - """ - Execute a node. - - Args: - nodename (str): Name of node. - raw_string (str): The raw default string entered on the - previous node (only used if the node accepts it as an - argument) - kwargs (any, optional): Optional kwargs for the node. - - Returns: - nodetext, options (tuple): The node text (a string or a - tuple and the options tuple, if any. - - """ - try: - node = self._menutree[nodename] - except KeyError: - self.msg(_ERR_NOT_IMPLEMENTED.format(nodename=nodename)) - raise EvMenuError - try: - kwargs["_current_nodename"] = nodename - ret = self._safe_call(node, raw_string, **kwargs) - if isinstance(ret, (tuple, list)) and len(ret) > 1: - nodetext, options = ret[:2] - else: - nodetext, options = ret, None - except KeyError: - self.msg(_ERR_NOT_IMPLEMENTED.format(nodename=nodename)) - logger.log_trace() - raise EvMenuError - except Exception: - self.msg(_ERR_GENERAL.format(nodename=nodename)) - logger.log_trace() - raise - - # store options to make them easier to test - self.test_options = options - self.test_nodetext = nodetext - - return nodetext, options - -
[docs] def msg(self, txt): - """ - This is a central point for sending return texts to the caller. It - allows for a central point to add custom messaging when creating custom - EvMenu overrides. - - Args: - txt (str): The text to send. - - Notes: - By default this will send to the same session provided to EvMenu - (if `session` kwarg was provided to `EvMenu.__init__`). It will - also send it with a `type=menu` for the benefit of OOB/webclient. - - """ - self.caller.msg(text=(txt, {"type": "menu"}), session=self._session)
- -
[docs] def run_exec(self, nodename, raw_string, **kwargs): - """ - NOTE: This is deprecated. Use `goto` directly instead. - - Run a function or node as a callback (with the 'exec' option key). - - Args: - nodename (callable or str): A callable to run as - `callable(caller, raw_string)`, or the Name of an existing - node to run as a callable. This may or may not return - a string. - raw_string (str): The raw default string entered on the - previous node (only used if the node accepts it as an - argument) - kwargs (any): These are optional kwargs passed into goto - - Returns: - new_goto (str or None): A replacement goto location string or - None (no replacement). - Notes: - Relying on exec callbacks to set the goto location is - very powerful but will easily lead to spaghetti structure and - hard-to-trace paths through the menu logic. So be careful with - relying on this. - - """ - try: - if callable(nodename): - # this is a direct callable - execute it directly - ret = self._safe_call(nodename, raw_string, **kwargs) - if isinstance(ret, (tuple, list)): - if not len(ret) > 1 or not isinstance(ret[1], dict): - raise EvMenuError( - "exec callable must return either None, str or (str, dict)" - ) - ret, kwargs = ret[:2] - else: - # nodename is a string; lookup as node and run as node in-place (don't goto it) - # execute the node - ret = self._execute_node(nodename, raw_string, **kwargs) - if isinstance(ret, (tuple, list)): - if not len(ret) > 1 and ret[1] and not isinstance(ret[1], dict): - raise EvMenuError("exec node must return either None, str or (str, dict)") - ret, kwargs = ret[:2] - except EvMenuError as err: - errmsg = "Error in exec '%s' (input: '%s'): %s" % (nodename, raw_string.rstrip(), err) - self.msg("|r%s|n" % errmsg) - logger.log_trace(errmsg) - return - - if isinstance(ret, str): - # only return a value if a string (a goto target), ignore all other returns - if not ret: - # an empty string - rerun the same node - return self.nodename - return ret, kwargs - return None
- -
[docs] def extract_goto_exec(self, nodename, option_dict): - """ - Helper: Get callables and their eventual kwargs. - - Args: - nodename (str): The current node name (used for error reporting). - option_dict (dict): The seleted option's dict. - - Returns: - goto (str, callable or None): The goto directive in the option. - goto_kwargs (dict): Kwargs for `goto` if the former is callable, otherwise empty. - execute (callable or None): Executable given by the `exec` directive. - exec_kwargs (dict): Kwargs for `execute` if it's callable, otherwise empty. - - """ - goto_kwargs, exec_kwargs = {}, {} - goto, execute = option_dict.get("goto", None), option_dict.get("exec", None) - if goto and isinstance(goto, (tuple, list)): - if len(goto) > 1: - goto, goto_kwargs = goto[:2] # ignore any extra arguments - if not hasattr(goto_kwargs, "__getitem__"): - # not a dict-like structure - raise EvMenuError( - "EvMenu node {}: goto kwargs is not a dict: {}".format( - nodename, goto_kwargs - ) - ) - else: - goto = goto[0] - if execute and isinstance(execute, (tuple, list)): - if len(execute) > 1: - execute, exec_kwargs = execute[:2] # ignore any extra arguments - if not hasattr(exec_kwargs, "__getitem__"): - # not a dict-like structure - raise EvMenuError( - "EvMenu node {}: exec kwargs is not a dict: {}".format( - nodename, goto_kwargs - ) - ) - else: - execute = execute[0] - return goto, goto_kwargs, execute, exec_kwargs
- -
[docs] def goto(self, nodename, raw_string, **kwargs): - """ - Run a node by name, optionally dynamically generating that name first. - - Args: - nodename (str or callable): Name of node or a callable - to be called as `function(caller, raw_string, **kwargs)` or - `function(caller, **kwargs)` to return the actual goto string or - a ("nodename", kwargs) tuple. - raw_string (str): The raw default string entered on the - previous node (only used if the node accepts it as an - argument) - **kwargs: Extra arguments to goto callables. - - """ - - if callable(nodename): - # run the "goto" callable, if possible - inp_nodename = nodename - nodename = self._safe_call(nodename, raw_string, **kwargs) - if isinstance(nodename, (tuple, list)): - if not len(nodename) > 1 or not isinstance(nodename[1], dict): - raise EvMenuError( - "{}: goto callable must return str or (str, dict)".format(inp_nodename) - ) - nodename, kwargs = nodename[:2] - if not nodename: - # no nodename return. Re-run current node - nodename = self.nodename - try: - # execute the found node, make use of the returns. - nodetext, options = self._execute_node(nodename, raw_string, **kwargs) - except EvMenuError: - return - - if self._persistent: - self.caller.attributes.add( - "_menutree_saved_startnode", (nodename, (raw_string, kwargs)) - ) - - # validation of the node return values - helptext = "" - if is_iter(nodetext): - if len(nodetext) > 1: - nodetext, helptext = nodetext[:2] - else: - nodetext = nodetext[0] - nodetext = "" if nodetext is None else str(nodetext) - options = [options] if isinstance(options, dict) else options - - # this will be displayed in the given order - display_options = [] - # this is used for lookup - self.options = {} - self.default = None - if options: - for inum, dic in enumerate(options): - # fix up the option dicts - keys = make_iter(dic.get("key")) - desc = dic.get("desc", dic.get("text", None)) - if "_default" in keys: - keys = [key for key in keys if key != "_default"] - goto, goto_kwargs, execute, exec_kwargs = self.extract_goto_exec(nodename, dic) - self.default = (goto, goto_kwargs, execute, exec_kwargs) - else: - # use the key (only) if set, otherwise use the running number - keys = list(make_iter(dic.get("key", str(inum + 1).strip()))) - goto, goto_kwargs, execute, exec_kwargs = self.extract_goto_exec(nodename, dic) - if keys: - display_options.append((keys[0], desc)) - for key in keys: - if goto or execute: - self.options[strip_ansi(key).strip().lower()] = ( - goto, - goto_kwargs, - execute, - exec_kwargs, - ) - - self.nodetext = self._format_node(nodetext, display_options) - self.node_kwargs = kwargs - self.nodename = nodename - - # handle the helptext - if helptext: - self.helptext = self.helptext_formatter(helptext) - elif options: - self.helptext = _HELP_FULL if self.auto_quit else _HELP_NO_QUIT - else: - self.helptext = _HELP_NO_OPTIONS if self.auto_quit else _HELP_NO_OPTIONS_NO_QUIT - - self.display_nodetext() - if not options: - self.close_menu()
- -
[docs] def run_exec_then_goto(self, runexec, goto, raw_string, runexec_kwargs=None, goto_kwargs=None): - """ - Call 'exec' callback and goto (which may also be a callable) in sequence. - - Args: - runexec (callable or str): Callback to run before goto. If - the callback returns a string, this is used to replace - the `goto` string/callable before being passed into the goto handler. - goto (str): The target node to go to next (may be replaced - by `runexec`).. - raw_string (str): The original user input. - runexec_kwargs (dict, optional): Optional kwargs for runexec. - goto_kwargs (dict, optional): Optional kwargs for goto. - - """ - if runexec: - # replace goto only if callback returns - goto, goto_kwargs = self.run_exec( - runexec, raw_string, **(runexec_kwargs if runexec_kwargs else {}) - ) or (goto, goto_kwargs) - if goto: - self.goto(goto, raw_string, **(goto_kwargs if goto_kwargs else {}))
- -
[docs] def close_menu(self): - """ - Shutdown menu; occurs when reaching the end node or using the quit command. - """ - if not self._quitting: - # avoid multiple calls from different sources - self._quitting = True - self.caller.cmdset.remove(EvMenuCmdSet) - del self.caller.ndb._evmenu - if self._persistent: - self.caller.attributes.remove("_menutree_saved") - self.caller.attributes.remove("_menutree_saved_startnode") - if self.cmd_on_exit is not None: - self.cmd_on_exit(self.caller, self) - # special for template-generated menues - del self.caller.db._evmenu_template_contents
- -
[docs] def print_debug_info(self, arg): - """ - Messages the caller with the current menu state, for debug purposes. - - Args: - arg (str): Arg to debug instruction, either nothing, 'full' or the name - of a property to inspect. - - """ - all_props = inspect.getmembers(self) - all_methods = [name for name, _ in inspect.getmembers(self, predicate=inspect.ismethod)] - all_builtins = [name for name, _ in inspect.getmembers(self, predicate=inspect.isbuiltin)] - props = { - prop: value - for prop, value in all_props - if prop not in all_methods and prop not in all_builtins and not prop.endswith("__") - } - - local = { - key: var - for key, var in locals().items() - if key not in all_props and not key.endswith("__") - } - - if arg: - if arg in props: - debugtxt = " |y* {}:|n\n{}".format(arg, props[arg]) - elif arg in local: - debugtxt = " |y* {}:|n\n{}".format(arg, local[arg]) - elif arg == "full": - debugtxt = ( - "|yMENU DEBUG full ... |n\n" - + "\n".join( - "|y *|n {}: {}".format(key, val) for key, val in sorted(props.items()) - ) - + "\n |yLOCAL VARS:|n\n" - + "\n".join( - "|y *|n {}: {}".format(key, val) for key, val in sorted(local.items()) - ) - + "\n |y... END MENU DEBUG|n" - ) - else: - debugtxt = "|yUsage: menudebug full|<name of property>|n" - else: - debugtxt = ( - "|yMENU DEBUG properties ... |n\n" - + "\n".join( - "|y *|n {}: {}".format(key, crop(to_str(val, force_string=True), width=50)) - for key, val in sorted(props.items()) - ) - + "\n |yLOCAL VARS:|n\n" - + "\n".join( - "|y *|n {}: {}".format(key, crop(to_str(val, force_string=True), width=50)) - for key, val in sorted(local.items()) - ) - + "\n |y... END MENU DEBUG|n" - ) - self.msg(debugtxt)
- -
[docs] def parse_input(self, raw_string): - """ - Parses the incoming string from the menu user. - - Args: - raw_string (str): The incoming, unmodified string - from the user. - Notes: - This method is expected to parse input and use the result - to relay execution to the relevant methods of the menu. It - should also report errors directly to the user. - - """ - cmd = strip_ansi(raw_string.strip().lower()) - - try: - if self.options and cmd in self.options: - # this will take precedence over the default commands - # below - goto, goto_kwargs, execfunc, exec_kwargs = self.options[cmd] - self.run_exec_then_goto(execfunc, goto, raw_string, exec_kwargs, goto_kwargs) - elif self.auto_look and cmd in ("look", "l"): - self.display_nodetext() - elif self.auto_help and cmd in ("help", "h"): - self.display_helptext() - elif self.auto_quit and cmd in ("quit", "q", "exit"): - self.close_menu() - elif self.debug_mode and cmd.startswith("menudebug"): - self.print_debug_info(cmd[9:].strip()) - elif self.default: - goto, goto_kwargs, execfunc, exec_kwargs = self.default - self.run_exec_then_goto(execfunc, goto, raw_string, exec_kwargs, goto_kwargs) - else: - self.msg(_HELP_NO_OPTION_MATCH) - except EvMenuGotoAbortMessage as err: - # custom interrupt from inside a goto callable - print the message and - # stay on the current node. - self.msg(str(err))
- -
[docs] def display_nodetext(self): - self.msg(self.nodetext)
- -
[docs] def display_helptext(self): - self.msg(self.helptext)
- - # formatters - override in a child class - -
[docs] def nodetext_formatter(self, nodetext): - """ - Format the node text itself. - - Args: - nodetext (str): The full node text (the text describing the node). - - Returns: - nodetext (str): The formatted node text. - - """ - return dedent(nodetext.strip("\n"), baseline_index=0).rstrip()
- -
[docs] def helptext_formatter(self, helptext): - """ - Format the node's help text - - Args: - helptext (str): The unformatted help text for the node. - - Returns: - helptext (str): The formatted help text. - - """ - return dedent(helptext.strip("\n"), baseline_index=0).rstrip()
- -
[docs] def options_formatter(self, optionlist): - """ - Formats the option block. - - Args: - optionlist (list): List of (key, description) tuples for every - option related to this node. - caller (Object, Account or None, optional): The caller of the node. - - Returns: - options (str): The formatted option display. - - """ - if not optionlist: - return "" - - # column separation distance - colsep = 4 - - nlist = len(optionlist) - - # get the widest option line in the table. - table_width_max = -1 - table = [] - for key, desc in optionlist: - if key or desc: - desc_string = ": %s" % desc if desc else "" - table_width_max = max( - table_width_max, - max(m_len(p) for p in key.split("\n")) - + max(m_len(p) for p in desc_string.split("\n")) - + colsep, - ) - raw_key = strip_ansi(key) - if raw_key != key: - # already decorations in key definition - table.append(" |lc%s|lt%s|le%s" % (raw_key, key, desc_string)) - else: - # add a default white color to key - table.append(" |lc%s|lt|w%s|n|le%s" % (raw_key, raw_key, desc_string)) - ncols = _MAX_TEXT_WIDTH // table_width_max # number of ncols - - if ncols < 0: - # no visible option at all - return "" - - ncols = ncols + 1 if ncols == 0 else ncols - # get the amount of rows needed (start with 4 rows) - nrows = 4 - while nrows * ncols < nlist: - nrows += 1 - ncols = nlist // nrows # number of full columns - nlastcol = nlist % nrows # number of elements in last column - - # get the final column count - ncols = ncols + 1 if nlastcol > 0 else ncols - if ncols > 1: - # only extend if longer than one column - table.extend([" " for i in range(nrows - nlastcol)]) - - # build the actual table grid - table = [table[icol * nrows: (icol * nrows) + nrows] for icol in range(0, ncols)] - - # adjust the width of each column - for icol in range(len(table)): - col_width = ( - max(max(m_len(p) for p in part.split("\n")) for part in table[icol]) + colsep - ) - table[icol] = [pad(part, width=col_width + colsep, align="l") for part in table[icol]] - - # format the table into columns - return str(EvTable(table=table, border="none"))
- -
[docs] def node_formatter(self, nodetext, optionstext): - """ - Formats the entirety of the node. - - Args: - nodetext (str): The node text as returned by `self.nodetext_formatter`. - optionstext (str): The options display as returned by `self.options_formatter`. - caller (Object, Account or None, optional): The caller of the node. - - Returns: - node (str): The formatted node to display. - - """ - sep = self.node_border_char - - if self._session: - screen_width = self._session.protocol_flags.get("SCREENWIDTH", {0: _MAX_TEXT_WIDTH})[0] - else: - screen_width = _MAX_TEXT_WIDTH - - nodetext_width_max = max(m_len(line) for line in nodetext.split("\n")) - options_width_max = max(m_len(line) for line in optionstext.split("\n")) - total_width = min(screen_width, max(options_width_max, nodetext_width_max)) - separator1 = sep * total_width + "\n\n" if nodetext_width_max else "" - separator2 = "\n" + sep * total_width + "\n\n" if total_width else "" - return separator1 + "|n" + nodetext + "|n" + separator2 + "|n" + optionstext
- - -# ----------------------------------------------------------- -# -# List node (decorator turning a node into a list with -# look/edit/add functionality for the elements) -# -# ----------------------------------------------------------- - - -
[docs]def list_node(option_generator, select=None, pagesize=10): - """ - Decorator for making an EvMenu node into a multi-page list node. Will add new options, - prepending those options added in the node. - - Args: - option_generator (callable or list): A list of strings indicating the options, or a callable - that is called as option_generator(caller) to produce such a list. - select (callable or str, optional): Node to redirect a selection to. Its `**kwargs` will - contain the `available_choices` list and `selection` will hold one of the elements in - that list. If a callable, it will be called as - `select(caller, menuchoice, **kwargs)` where menuchoice is the chosen option as a - string and `available_choices` is a kwarg mapping the option keys to the choices - offered by the option_generator. The callable whould return the name of the target node - to goto after this selection (or None to repeat the list-node). Note that if this is not - given, the decorated node must itself provide a way to continue from the node! - pagesize (int): How many options to show per page. - - Example: - - ```python - def select(caller, selection, available_choices=None, **kwargs): - ''' - This will be called by all auto-generated options except any 'extra_options' - you return from the node (those you need to handle normally). - - Args: - caller (Object or Account): User of the menu. - selection (str): What caller chose in the menu - available_choices (list): The keys of elements available on the *current listing - page*. - **kwargs: Kwargs passed on from the node. - Returns: - tuple, str or None: A tuple (nextnodename, **kwargs) or just nextnodename. Return - `None` to go back to the listnode. - ''' - - # (do something with `selection` here) - - return "nextnode", **kwargs - - @list_node(['foo', 'bar'], select) - def node_index(caller): - text = "describing the list" - - # optional extra options in addition to the list-options - extra_options = [] - - return text, extra_options - - ``` - - Notes: - All normal `goto` or `exec` callables returned from the decorated nodes - will, if they accept `**kwargs`, get a new kwarg 'available_choices' - injected. These are the ordered list of named options (descs) visible - on the current node page. - - """ - - def decorator(func): - def _select_parser(caller, raw_string, **kwargs): - """ - Parse the select action - - """ - available_choices = kwargs.pop("available_choices", []) - - try: - index = int(raw_string.strip()) - 1 - selection = available_choices[index] - except Exception: - caller.msg(_("|rInvalid choice.|n")) - else: - if callable(select): - try: - if bool(getargspec(select).keywords): - return select( - caller, selection, available_choices=available_choices, **kwargs) - else: - return select(caller, selection, **kwargs) - except Exception: - logger.log_trace("Error in EvMenu.list_node decorator:\n " - f"select-callable: {select}\n with args: ({caller}" - f"{selection}, {available_choices}, {kwargs}) raised " - "exception.") - elif select: - # we assume a string was given, we inject the result into the kwargs - # to pass on to the next node - kwargs["selection"] = selection - return str(select) - # this means the previous node will be re-run with these same kwargs - return None - - def _list_node(caller, raw_string, **kwargs): - - option_list = ( - option_generator(caller) if callable(option_generator) else option_generator - ) - - npages = 0 - page_index = 0 - page = [] - options = [] - - if option_list: - nall_options = len(option_list) - pages = [ - option_list[ind: ind + pagesize] for ind in range(0, nall_options, pagesize) - ] - npages = len(pages) - - page_index = max(0, min(npages - 1, kwargs.get("optionpage_index", 0))) - page = pages[page_index] - - text = "" - extra_text = None - - # dynamic, multi-page option list. Each selection leads to the `select` - # callback being called with a result from the available choices - options.extend( - [ - {"desc": opt, "goto": (_select_parser, {"available_choices": page, **kwargs})} - for opt in page - ] - ) - - if npages > 1: - # if the goto callable returns None, the same node is rerun, and - # kwargs not used by the callable are passed on to the node. This - # allows us to call ourselves over and over, using different kwargs. - options.append( - { - "key": (_("|Wcurrent|n"), "c"), - "desc": "|W({}/{})|n".format(page_index + 1, npages), - "goto": (lambda caller: None, {"optionpage_index": page_index}), - } - ) - if page_index > 0: - options.append( - { - "key": (_("|wp|Wrevious page|n"), "p"), - "goto": (lambda caller: None, {"optionpage_index": page_index - 1}), - } - ) - if page_index < npages - 1: - options.append( - { - "key": (_("|wn|Wext page|n"), "n"), - "goto": (lambda caller: None, {"optionpage_index": page_index + 1}), - } - ) - - # add data from the decorated node - - decorated_options = [] - supports_kwargs = bool(getargspec(func).keywords) - try: - if supports_kwargs: - text, decorated_options = func(caller, raw_string, **kwargs) - else: - text, decorated_options = func(caller, raw_string) - except TypeError: - try: - if supports_kwargs: - text, decorated_options = func(caller, **kwargs) - else: - text, decorated_options = func(caller) - except Exception: - raise - except Exception: - logger.log_trace() - else: - if isinstance(decorated_options, dict): - decorated_options = [decorated_options] - else: - decorated_options = make_iter(decorated_options) - - extra_options = [] - if isinstance(decorated_options, dict): - decorated_options = [decorated_options] - for eopt in decorated_options: - cback = ("goto" in eopt and "goto") or ("exec" in eopt and "exec") or None - if cback: - signature = eopt[cback] - if callable(signature): - # callable with no kwargs defined - eopt[cback] = (signature, {"available_choices": page}) - elif is_iter(signature): - if len(signature) > 1 and isinstance(signature[1], dict): - signature[1]["available_choices"] = page - eopt[cback] = signature - elif signature: - # a callable alone in a tuple (i.e. no previous kwargs) - eopt[cback] = (signature[0], {"available_choices": page}) - else: - # malformed input. - logger.log_err( - "EvMenu @list_node decorator found " - "malformed option to decorate: {}".format(eopt) - ) - extra_options.append(eopt) - - options.extend(extra_options) - text = text + "\n\n" + extra_text if extra_text else text - - return text, options - - return _list_node - - return decorator
- - -# ------------------------------------------------------------------------------------------------- -# -# Simple input shortcuts -# -# ------------------------------------------------------------------------------------------------- - - -
[docs]class CmdGetInput(Command): - """ - Enter your data and press return. - """ - - key = _CMD_NOMATCH - aliases = _CMD_NOINPUT - -
[docs] def func(self): - """This is called when user enters anything.""" - caller = self.caller - try: - getinput = caller.ndb._getinput - if not getinput and hasattr(caller, "account"): - getinput = caller.account.ndb._getinput - if getinput: - caller = caller.account - callback = getinput._callback - - caller.ndb._getinput._session = self.session - prompt = caller.ndb._getinput._prompt - args = caller.ndb._getinput._args - kwargs = caller.ndb._getinput._kwargs - result = self.raw_string.rstrip() # we strip the ending line break caused by sending - - ok = not callback(caller, prompt, result, *args, **kwargs) - if ok: - # only clear the state if the callback does not return - # anything - del caller.ndb._getinput - caller.cmdset.remove(InputCmdSet) - except Exception: - # make sure to clean up cmdset if something goes wrong - caller.msg("|rError in get_input. Choice not confirmed (report to admin)|n") - logger.log_trace("Error in get_input") - caller.cmdset.remove(InputCmdSet)
- - -
[docs]class InputCmdSet(CmdSet): - """ - This stores the input command - """ - - key = "input_cmdset" - priority = 1 - mergetype = "Replace" - no_objs = True - no_exits = True - no_channels = False - -
[docs] def at_cmdset_creation(self): - """called once at creation""" - self.add(CmdGetInput())
- - -class _Prompt: - """Dummy holder""" - - pass - - -
[docs]def get_input(caller, prompt, callback, session=None, *args, **kwargs): - """ - This is a helper function for easily request input from the caller. - - Args: - caller (Account or Object): The entity being asked the question. This - should usually be an object controlled by a user. - prompt (str): This text will be shown to the user, in order to let them - know their input is needed. - callback (callable): A function that will be called - when the user enters a reply. It must take three arguments: the - `caller`, the `prompt` text and the `result` of the input given by - the user. If the callback doesn't return anything or return False, - the input prompt will be cleaned up and exited. If returning True, - the prompt will remain and continue to accept input. - session (Session, optional): This allows to specify the - session to send the prompt to. It's usually only needed if `caller` - is an Account in multisession modes greater than 2. The session is - then updated by the command and is available (for example in - callbacks) through `caller.ndb.getinput._session`. - *args (any): Extra arguments to pass to `callback`. To utilise `*args` - (and `**kwargs`), a value for the `session` argument must also be - provided. - **kwargs (any): Extra kwargs to pass to `callback`. - - Raises: - RuntimeError: If the given callback is not callable. - - Notes: - The result value sent to the callback is raw and not processed in any - way. This means that you will get the ending line return character from - most types of client inputs. So make sure to strip that before doing a - comparison. - - When the prompt is running, a temporary object `caller.ndb._getinput` - is stored; this will be removed when the prompt finishes. - - If you need the specific Session of the caller (which may not be easy - to get if caller is an account in higher multisession modes), then it - is available in the callback through `caller.ndb._getinput._session`. - This is why the `session` is required as input. - - It's not recommended to 'chain' `get_input` into a sequence of - questions. This will result in the caller stacking ever more instances - of InputCmdSets. While they will all be cleared on concluding the - get_input chain, EvMenu should be considered for anything beyond a - single question. - - """ - if not callable(callback): - raise RuntimeError("get_input: input callback is not callable.") - caller.ndb._getinput = _Prompt() - caller.ndb._getinput._callback = callback - caller.ndb._getinput._prompt = prompt - caller.ndb._getinput._session = session - caller.ndb._getinput._args = args - caller.ndb._getinput._kwargs = kwargs - caller.cmdset.add(InputCmdSet, persistent=False) - caller.msg(prompt, session=session)
- - -
[docs]class CmdYesNoQuestion(Command): - """ - Handle a prompt for yes or no. Press [return] for the default choice. - - """ - - key = _CMD_NOINPUT - aliases = [_CMD_NOMATCH, "yes", "no", 'y', 'n', 'a', 'abort'] - arg_regex = r"^$" - - def _clean(self, caller): - del caller.ndb._yes_no_question - if not caller.cmdset.has(YesNoQuestionCmdSet) and hasattr(caller, "account"): - caller.account.cmdset.remove(YesNoQuestionCmdSet) - else: - caller.cmdset.remove(YesNoQuestionCmdSet) - -
[docs] def func(self): - """This is called when user enters anything.""" - caller = self.caller - try: - yes_no_question = caller.ndb._yes_no_question - if not yes_no_question and hasattr(caller, "account"): - yes_no_question = caller.account.ndb._yes_no_question - caller = caller.account - - if not yes_no_question: - self._clean(caller) - return - - inp = self.cmdname - - if inp == _CMD_NOINPUT: - raw = self.raw_cmdname.strip() - if not raw: - # use default - inp = yes_no_question.default - else: - inp = raw - - if inp in ('a', 'abort') and yes_no_question.allow_abort: - caller.msg(_("Aborted.")) - self._clean(caller) - return - - caller.ndb._yes_no_question.session = self.session - - args = yes_no_question.args - kwargs = yes_no_question.kwargs - kwargs['caller_session'] = self.session - - if inp in ('yes', 'y'): - yes_no_question.yes_callable(caller, *args, **kwargs) - elif inp in ('no', 'n'): - yes_no_question.no_callable(caller, *args, **kwargs) - else: - # invalid input. Resend prompt without cleaning - caller.msg(yes_no_question.prompt, session=self.session) - return - - # cleanup - self._clean(caller) - except Exception: - # make sure to clean up cmdset if something goes wrong - caller.msg(_("|rError in ask_yes_no. Choice not confirmed (report to admin)|n")) - logger.log_trace("Error in ask_yes_no") - self._clean(caller) - raise
- - -
[docs]class YesNoQuestionCmdSet(CmdSet): - """ - This stores the input command - """ - - key = "yes_no_question_cmdset" - priority = 1 - mergetype = "Replace" - no_objs = True - no_exits = True - no_channels = False - -
[docs] def at_cmdset_creation(self): - """called once at creation""" - self.add(CmdYesNoQuestion())
- - -
[docs]def ask_yes_no(caller, prompt="Yes or No {options}?", yes_action="Yes", no_action="No", - default=None, allow_abort=False, session=None, *args, **kwargs): - """ - A helper question for asking a simple yes/no question. This will cause - the system to pause and wait for input from the player. - - Args: - prompt (str): The yes/no question to ask. This takes an optional formatting - marker `{options}` which will be filled with 'Y/N', '[Y]/N' or - 'Y/[N]' depending on the setting of `default`. If `allow_abort` is set, - then the 'A(bort)' option will also be available. - yes_action (callable or str): If a callable, this will be called - with `(caller, *args, **kwargs)` when the Yes-choice is made. - If a string, this string will be echoed back to the caller. - no_action (callable or str): If a callable, this will be called - with `(caller, *args, **kwargs)` when the No-choice is made. - If a string, this string will be echoed back to the caller. - default (str optional): This is what the user will get if they just press the - return key without giving any input. One of 'N', 'Y', 'A' or `None` - for no default (an explicit choice must be given). If 'A' (abort) - is given, `allow_abort` kwarg is ignored and assumed set. - allow_abort (bool, optional): If set, the 'A(bort)' option is available - (a third option meaning neither yes or no but just exits the prompt). - session (Session, optional): This allows to specify the - session to send the prompt to. It's usually only needed if `caller` - is an Account in multisession modes greater than 2. The session is - then updated by the command and is available (for example in - callbacks) through `caller.ndb._yes_no_question.session`. - *args: Additional arguments passed on into callables. - **kwargs: Additional keyword args passed on into callables. - - Raises: - RuntimeError, FooError: If default and `allow_abort` clashes. - - Example: - :: - - # just returning strings - ask_yes_no(caller, "Are you happy {options}?", - "you answered yes", "you answered no") - # trigger callables - ask_yes_no(caller, "Are you sad {options}?", - _callable_yes, _callable_no, allow_abort=True) - - """ - def _callable_yes_txt(caller, *args, **kwargs): - yes_txt = kwargs['yes_txt'] - session = kwargs['caller_session'] - caller.msg(yes_txt, session=session) - - def _callable_no_txt(caller, *args, **kwargs): - no_txt = kwargs['no_txt'] - session = kwargs['caller_session'] - caller.msg(no_txt, session=session) - - if not callable(yes_action): - kwargs['yes_txt'] = str(yes_action) - yes_action = _callable_yes_txt - - if not callable(no_action): - kwargs['no_txt'] = str(no_action) - no_action = _callable_no_txt - - # prepare the prompt with options - options = "Y/N" - abort_txt = "/Abort" if allow_abort else "" - if default: - default = default.lower() - if default == "y": - options = "[Y]/N" - elif default == "n": - options = "Y/[N]" - elif default == "a": - allow_abort = True - abort_txt = "/[A]bort" - options += abort_txt - prompt = prompt.format(options=options) - - caller.ndb._yes_no_question = _Prompt() - caller.ndb._yes_no_question.prompt = prompt - caller.ndb._yes_no_question.session = session - caller.ndb._yes_no_question.prompt = prompt - caller.ndb._yes_no_question.default = default - caller.ndb._yes_no_question.allow_abort = allow_abort - caller.ndb._yes_no_question.yes_callable = yes_action - caller.ndb._yes_no_question.no_callable = no_action - caller.ndb._yes_no_question.args = args - caller.ndb._yes_no_question.kwargs = kwargs - - caller.cmdset.add(YesNoQuestionCmdSet) - caller.msg(prompt, session=session)
- - -# ------------------------------------------------------------- -# -# Menu generation from menu template string -# -# ------------------------------------------------------------- - -_RE_NODE = re.compile(r"##\s*?NODE\s+?(?P<nodename>\S[\S\s]*?)$", re.I + re.M) -_RE_OPTIONS_SEP = re.compile(r"##\s*?OPTIONS\s*?$", re.I + re.M) -_RE_CALLABLE = re.compile(r"\S+?\(\)", re.I + re.M) -_RE_CALLABLE = re.compile( - r"(?P<funcname>\S+?)(?:\((?P<kwargs>[\S\s]+?)\)|\(\))", re.I + re.M -) - -_HELP_NO_OPTION_MATCH = _("Choose an option or try 'help'.") - -_OPTION_INPUT_MARKER = ">" -_OPTION_ALIAS_MARKER = ";" -_OPTION_SEP_MARKER = ":" -_OPTION_CALL_MARKER = "->" -_OPTION_COMMENT_START = "#" - - -# Input/option/goto handler functions that allows for dynamically generated -# nodes read from the menu template. - -def _process_callable(caller, goto, goto_callables, raw_string, - current_nodename, kwargs): - """ - Central helper for parsing a goto-callable (`funcname(**kwargs)`) out of - the right-hand-side of the template options and map this to an actual - callable registered with the template generator. This involves parsing the - func-name and running literal-eval on its kwargs. - - """ - match = _RE_CALLABLE.match(goto) - if match: - gotofunc = match.group("funcname") - gotokwargs = match.group("kwargs") or "" - if gotofunc in goto_callables: - for kwarg in gotokwargs.split(","): - if kwarg and "=" in kwarg: - key, value = [part.strip() for part in kwarg.split("=", 1)] - if key in ("evmenu_goto", "evmenu_gotomap", "_current_nodename", - "evmenu_current_nodename", "evmenu_goto_callables"): - raise RuntimeError( - f"EvMenu template error: goto-callable '{goto}' uses a " - f"kwarg ({kwarg}) that is reserved for the EvMenu templating " - "system. Rename the kwarg.") - try: - key = literal_eval(key) - except ValueError: - pass - try: - value = literal_eval(value) - except ValueError: - pass - kwargs[key] = value - - goto = goto_callables[gotofunc](caller, raw_string, **kwargs) - if goto is None: - return goto, {"generated_nodename": current_nodename} - return goto, {"generated_nodename": goto} - - -def _generated_goto_func(caller, raw_string, **kwargs): - """ - This rerouter handles normal direct goto func call matches. - - key : ... -> goto_callable(**kwargs) - - """ - goto = kwargs["evmenu_goto"] - goto_callables = kwargs["evmenu_goto_callables"] - current_nodename = kwargs["evmenu_current_nodename"] - return _process_callable(caller, goto, goto_callables, raw_string, - current_nodename, kwargs) - - -def _generated_input_goto_func(caller, raw_string, **kwargs): - """ - This goto-func acts as a rerouter for >-type line parsing (by acting as the - _default option). The patterns discovered in the menu maps to different - *actual* goto-funcs. We map to those here. - - >pattern: ... -> goto_callable - - """ - gotomap = kwargs["evmenu_gotomap"] - goto_callables = kwargs["evmenu_goto_callables"] - current_nodename = kwargs["evmenu_current_nodename"] - raw_string = raw_string.strip("\n") # strip is necessary to catch empty return - - # start with glob patterns - for pattern, goto in gotomap.items(): - if fnmatch(raw_string.lower(), pattern): - return _process_callable(caller, goto, goto_callables, raw_string, - current_nodename, kwargs) - # no glob pattern match; try regex - for pattern, goto in gotomap.items(): - if pattern and re.match(pattern, raw_string.lower(), flags=re.I + re.M): - return _process_callable(caller, goto, goto_callables, raw_string, - current_nodename, kwargs) - # no match, show error - raise EvMenuGotoAbortMessage(_HELP_NO_OPTION_MATCH) - - -def _generated_node(caller, raw_string, **kwargs): - """ - Every node in the templated menu will be this node, but with dynamically - changing text/options. It must be a global function like this because - otherwise we could not make the templated-menu persistent. - - """ - text, options = caller.db._evmenu_template_contents[kwargs["_current_nodename"]] - return text, options - - -
[docs]def parse_menu_template(caller, menu_template, goto_callables=None): - """ - Parse menu-template string. The main function of the EvMenu templating system. - - Args: - caller (Object or Account): Entity using the menu. - menu_template (str): Menu described using the templating format. - goto_callables (dict, optional): Mapping between call-names and callables - on the form `callable(caller, raw_string, **kwargs)`. These are what is - available to use in the `menu_template` string. - - Returns: - dict: A `{"node": nodefunc}` menutree suitable to pass into EvMenu. - - """ - def _validate_kwarg(goto, kwarg): - """ - Validate goto-callable kwarg is on correct form. - """ - if "=" not in kwarg: - raise RuntimeError( - f"EvMenu template error: goto-callable '{goto}' has a " - f"non-kwarg argument ({kwarg}). All callables in the " - "template must have only keyword-arguments, or no " - "args at all.") - key, _ = [part.strip() for part in kwarg.split("=", 1)] - if key in ("evmenu_goto", "evmenu_gotomap", "_current_nodename", - "evmenu_current_nodename", "evmenu_goto_callables"): - raise RuntimeError( - f"EvMenu template error: goto-callable '{goto}' uses a " - f"kwarg ({kwarg}) that is reserved for the EvMenu templating " - "system. Rename the kwarg.") - - def _parse_options(nodename, optiontxt, goto_callables): - """ - Parse option section into option dict. - - """ - options = [] - optiontxt = optiontxt[0].strip() if optiontxt else "" - optionlist = [optline.strip() for optline in optiontxt.split("\n")] - inputparsemap = {} - - for inum, optline in enumerate(optionlist): - if optline.startswith(_OPTION_COMMENT_START) or _OPTION_SEP_MARKER not in optline: - # skip comments or invalid syntax - continue - key = "" - desc = "" - pattern = None - - key, goto = [part.strip() for part in optline.split(_OPTION_SEP_MARKER, 1)] - - # desc -> goto - if _OPTION_CALL_MARKER in goto: - desc, goto = [part.strip() for part in goto.split(_OPTION_CALL_MARKER, 1)] - - # validate callable - match = _RE_CALLABLE.match(goto) - if match: - kwargs = match.group("kwargs") - if kwargs: - for kwarg in kwargs.split(','): - _validate_kwarg(goto, kwarg) - - # parse key [;aliases|pattern] - key = [part.strip() for part in key.split(_OPTION_ALIAS_MARKER)] - if not key: - # fall back to this being the Nth option - key = [f"{inum + 1}"] - main_key = key[0] - - if main_key.startswith(_OPTION_INPUT_MARKER): - # if we have a pattern, build the arguments for _default later - pattern = main_key[len(_OPTION_INPUT_MARKER):].strip() - inputparsemap[pattern] = goto - else: - # a regular goto string/callable target - option = { - "key": key, - "goto": ( - _generated_goto_func, - { - "evmenu_goto": goto, - "evmenu_current_nodename": nodename, - "evmenu_goto_callables": goto_callables, - }, - ), - } - if desc: - option["desc"] = desc - options.append(option) - - if inputparsemap: - # if this exists we must create a _default entry too - options.append( - { - "key": "_default", - "goto": ( - _generated_input_goto_func, - { - "evmenu_gotomap": inputparsemap, - "evmenu_current_nodename": nodename, - "evmenu_goto_callables": goto_callables, - }, - ), - } - ) - - return options - - def _parse(caller, menu_template, goto_callables): - """ - Parse the menu string format into a node tree. - - """ - nodetree = {} - splits = _RE_NODE.split(menu_template) - splits = splits[1:] if splits else [] - - # from evennia import set_trace;set_trace(term_size=(140,120)) - content_map = {} - for node_ind in range(0, len(splits), 2): - nodename, nodetxt = splits[node_ind], splits[node_ind + 1] - text, *optiontxt = _RE_OPTIONS_SEP.split(nodetxt, maxsplit=2) - options = _parse_options(nodename, optiontxt, goto_callables) - content_map[nodename] = (text, options) - nodetree[nodename] = _generated_node - caller.db._evmenu_template_contents = content_map - - return nodetree - - return _parse(caller, menu_template, goto_callables)
- - -
[docs]def template2menu( - caller, - menu_template, - goto_callables=None, - startnode="start", - persistent=False, - **kwargs, -): - """ - Helper function to generate and start an EvMenu based on a menu template - string. This will internall call `parse_menu_template` and run a default - EvMenu with its results. - - Args: - caller (Object or Account): The entity using the menu. - menu_template (str): The menu-template string describing the content - and structure of the menu. It can also be the python-path to, or a module - containing a `MENU_TEMPLATE` global variable with the template. - goto_callables (dict, optional): Mapping of callable-names to - module-global objects to reference by name in the menu-template. - Must be on the form `callable(caller, raw_string, **kwargs)`. - startnode (str, optional): The name of the startnode, if not 'start'. - persistent (bool, optional): If the generated menu should be persistent. - **kwargs: All kwargs will be passed into EvMenu. - - Returns: - EvMenu: The generated EvMenu. - - """ - goto_callables = goto_callables or {} - menu_tree = parse_menu_template(caller, menu_template, goto_callables) - return EvMenu( - caller, - menu_tree, - persistent=persistent, - **kwargs, - )
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/evmore.html b/docs/0.9.5/_modules/evennia/utils/evmore.html deleted file mode 100644 index 77cfd82617..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/evmore.html +++ /dev/null @@ -1,658 +0,0 @@ - - - - - - - - evennia.utils.evmore — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.utils.evmore

-# -*- coding: utf-8 -*-
-"""
-EvMore - pager mechanism
-
-This is a pager for displaying long texts and allows stepping up and down in
-the text (the name comes from the traditional 'more' unix command).
-
-To use, simply pass the text through the EvMore object:
-
-
-```python
-
-    from evennia.utils.evmore import EvMore
-
-    text = some_long_text_output()
-    EvMore(caller, text, always_page=False, session=None, justify_kwargs=None, **kwargs)
-```
-
-One can also use the convenience function `msg` from this module to avoid
-having to set up the `EvMenu` object manually:
-
-```python
-
-    from evennia.utils import evmore
-
-    text = some_long_text_output()
-    evmore.msg(caller, text, always_page=False, session=None, justify_kwargs=None, **kwargs)
-```
-
-The `always_page` argument  decides if the pager is used also if the text is not long
-enough to need to scroll, `session` is used to determine which session to relay
-to and `justify_kwargs` are kwargs to pass to utils.utils.justify in order to
-change the formatting of the text. The remaining `**kwargs` will be passed on to
-the `caller.msg()` construct every time the page is updated.
-
-----
-
-"""
-from django.conf import settings
-from django.db.models.query import QuerySet
-from django.core.paginator import Paginator
-from evennia.commands.command import Command
-from evennia.commands.cmdset import CmdSet
-from evennia.commands import cmdhandler
-from evennia.utils.ansi import ANSIString
-from evennia.utils.utils import make_iter, inherits_from, justify, dedent
-from django.utils.translation import gettext as _
-
-_CMD_NOMATCH = cmdhandler.CMD_NOMATCH
-_CMD_NOINPUT = cmdhandler.CMD_NOINPUT
-
-# we need to use NAWS for this
-_SCREEN_WIDTH = settings.CLIENT_DEFAULT_WIDTH
-_SCREEN_HEIGHT = settings.CLIENT_DEFAULT_HEIGHT
-
-_EVTABLE = None
-
-_LBR = ANSIString("\n")
-
-# text
-
-_DISPLAY = """{text}
-(|wPage|n [{pageno}/{pagemax}] |wn|next|n || |wp|nrevious || |wt|nop || |we|nnd || |wq|nuit)"""
-
-
-
[docs]class CmdMore(Command): - """ - Manipulate the text paging. Catch no-input with aliases. - """ - - key = _CMD_NOINPUT - aliases = ["quit", "q", "abort", "a", "next", "n", "previous", "p", "top", "t", "end", "e"] - auto_help = False - -
[docs] def func(self): - """ - Implement the command - """ - more = self.caller.ndb._more - if not more and hasattr(self.caller, "account"): - more = self.caller.account.ndb._more - if not more: - self.caller.msg("Error in loading the pager. Contact an admin.") - return - - cmd = self.cmdstring - - if cmd in ("abort", "a", "q"): - more.page_quit() - elif cmd in ("previous", "p"): - more.page_back() - elif cmd in ("top", "t", "look", "l"): - more.page_top() - elif cmd in ("end", "e"): - more.page_end() - else: - # return or n, next - more.page_next()
- - -
[docs]class CmdMoreExit(Command): - """ - Any non-more command will exit the pager. - - """ - key = _CMD_NOMATCH - -
[docs] def func(self): - """ - Exit pager and re-fire the failed command. - - """ - more = self.caller.ndb._more - more.page_quit() - - # re-fire the command (in new cmdset) - self.caller.execute_cmd(self.raw_string)
- - -
[docs]class CmdSetMore(CmdSet): - """ - Stores the more command - """ - - key = "more_commands" - priority = 110 - mergetype = "Replace" - -
[docs] def at_cmdset_creation(self): - self.add(CmdMore()) - self.add(CmdMoreExit())
- - -# resources for handling queryset inputs -
[docs]def queryset_maxsize(qs): - return qs.count()
- - -
[docs]class EvMore(object): - """ - The main pager object - """ - -
[docs] def __init__( - self, - caller, - inp, - always_page=False, - session=None, - justify=False, - justify_kwargs=None, - exit_on_lastpage=False, - exit_cmd=None, - page_formatter=str, - **kwargs, - ): - - """ - Initialization of the EvMore pager. - - Args: - caller (Object or Account): Entity reading the text. - inp (str, EvTable, Paginator or iterator): The text or data to put under paging. - - - If a string, paginage normally. If this text contains - one or more `\\\\f` format symbol, automatic pagination and justification - are force-disabled and page-breaks will only happen after each `\\\\f`. - - If `EvTable`, the EvTable will be paginated with the same - setting on each page if it is too long. The table - decorations will be considered in the size of the page. - - Otherwise `inp` is converted to an iterator, where each step is - expected to be a line in the final display. Each line - will be run through `iter_callable`. - - always_page (bool, optional): If `False`, the - pager will only kick in if `inp` is too big - to fit the screen. - session (Session, optional): If given, this session will be used - to determine the screen width and will receive all output. - justify (bool, optional): If set, auto-justify long lines. This must be turned - off for fixed-width or formatted output, like tables. It's force-disabled - if `inp` is an EvTable. - justify_kwargs (dict, optional): Keywords for the justifiy function. Used only - if `justify` is True. If this is not set, default arguments will be used. - exit_on_lastpage (bool, optional): If reaching the last page without the - page being completely filled, exit pager immediately. If unset, - another move forward is required to exit. If set, the pager - exit message will not be shown. - exit_cmd (str, optional): If given, this command-string will be executed on - the caller when the more page exits. Note that this will be using whatever - cmdset the user had *before* the evmore pager was activated (so none of - the evmore commands will be available when this is run). - kwargs (any, optional): These will be passed on to the `caller.msg` method. - - Examples: - - ```python - super_long_text = " ... " - EvMore(caller, super_long_text) - ``` - Paginator - ```python - from django.core.paginator import Paginator - query = ObjectDB.objects.all() - pages = Paginator(query, 10) # 10 objs per page - EvMore(caller, pages) - ``` - Every page an EvTable - ```python - from evennia import EvTable - def _to_evtable(page): - table = ... # convert page to a table - return EvTable(*headers, table=table, ...) - EvMore(caller, pages, page_formatter=_to_evtable) - ``` - - """ - self._caller = caller - self._always_page = always_page - - if not session: - # if not supplied, use the first session to - # determine screen size - sessions = caller.sessions.get() - if not sessions: - return - session = sessions[0] - self._session = session - - self._justify = justify - self._justify_kwargs = justify_kwargs - self.exit_on_lastpage = exit_on_lastpage - self.exit_cmd = exit_cmd - self._exit_msg = _("|xExited pager.|n") - self._kwargs = kwargs - - self._data = None - - self._pages = [] - self._npos = 0 - - self._npages = 1 - self._paginator = self.paginator_index - self._page_formatter = str - - # set up individual pages for different sessions - height = max(4, session.protocol_flags.get("SCREENHEIGHT", {0: _SCREEN_HEIGHT})[0] - 4) - self.width = session.protocol_flags.get("SCREENWIDTH", {0: _SCREEN_WIDTH})[0] - # always limit number of chars to 10 000 per page - self.height = min(10000 // max(1, self.width), height) - - # does initial parsing of input - self.init_pages(inp) - - # kick things into gear - self.start()
- - # EvMore functional methods - -
[docs] def display(self, show_footer=True): - """ - Pretty-print the page. - """ - pos = 0 - text = "[no content]" - if self._npages > 0: - pos = self._npos - text = self.page_formatter(self.paginator(pos)) - if show_footer: - page = _DISPLAY.format(text=text, pageno=pos + 1, pagemax=self._npages) - else: - page = text - # check to make sure our session is still valid - sessions = self._caller.sessions.get() - if not sessions: - self.page_quit() - return - # this must be an 'is', not == check - if not any(ses for ses in sessions if self._session is ses): - self._session = sessions[0] - self._caller.msg(text=page, session=self._session, **self._kwargs)
- -
[docs] def page_top(self): - """ - Display the top page - """ - self._npos = 0 - self.display()
- -
[docs] def page_end(self): - """ - Display the bottom page. - """ - self._npos = self._npages - 1 - self.display()
- -
[docs] def page_next(self): - """ - Scroll the text to the next page. Quit if already at the end - of the page. - """ - if self._npos >= self._npages - 1: - # exit if we are already at the end - self.page_quit() - else: - self._npos += 1 - if self.exit_on_lastpage and self._npos >= (self._npages - 1): - self.display(show_footer=False) - self.page_quit(quiet=True) - else: - self.display()
- -
[docs] def page_back(self): - """ - Scroll the text back up, at the most to the top. - """ - self._npos = max(0, self._npos - 1) - self.display()
- -
[docs] def page_quit(self, quiet=False): - """ - Quit the pager - """ - del self._caller.ndb._more - if not quiet: - self._caller.msg(text=self._exit_msg, **self._kwargs) - self._caller.cmdset.remove(CmdSetMore) - if self.exit_cmd: - self._caller.execute_cmd(self.exit_cmd, session=self._session)
- -
[docs] def start(self): - """ - Starts the pagination - """ - if self._npages <= 1 and not self._always_page: - # no need for paging; just pass-through. - self.display(show_footer=False) - else: - # go into paging mode - # first pass on the msg kwargs - self._caller.ndb._more = self - self._caller.cmdset.add(CmdSetMore) - - # goto top of the text - self.page_top()
- - # default paginators - responsible for extracting a specific page number - -
[docs] def paginator_index(self, pageno): - """Paginate to specific, known index""" - return self._data[pageno]
- -
[docs] def paginator_slice(self, pageno): - """ - Paginate by slice. This is done with an eye on memory efficiency (usually for - querysets); to avoid fetching all objects at the same time. - - """ - return self._data[pageno * self.height: pageno * self.height + self.height]
- -
[docs] def paginator_django(self, pageno): - """ - Paginate using the django queryset Paginator API. Note that his is indexed from 1. - """ - return self._data.page(pageno + 1)
- - # default helpers to set up particular input types - -
[docs] def init_evtable(self, table): - """The input is an EvTable.""" - if table.height: - # enforced height of each paged table, plus space for evmore extras - self.height = table.height - 4 - - # convert table to string - text = str(table) - self._justify = False - self._justify_kwargs = None # enforce - self.init_str(text)
- -
[docs] def init_queryset(self, qs): - """The input is a queryset""" - nsize = qs.count() # we assume each will be a line - self._npages = nsize // self.height + (0 if nsize % self.height == 0 else 1) - self._data = qs
- -
[docs] def init_django_paginator(self, pages): - """ - The input is a django Paginator object. - """ - self._npages = pages.num_pages - self._data = pages
- -
[docs] def init_iterable(self, inp): - """The input is something other than a string - convert to iterable of strings""" - inp = make_iter(inp) - nsize = len(inp) - self._npages = nsize // self.height + (0 if nsize % self.height == 0 else 1) - self._data = inp
- -
[docs] def init_f_str(self, text): - """ - The input contains `\\f` markers. We use `\\f` to indicate the user wants to - enforce their line breaks on their own. If so, we do no automatic - line-breaking/justification at all. - - Args: - text (str): The string to format with f-markers. - - """ - self._data = text.split("\f") - self._npages = len(self._data)
- -
[docs] def init_str(self, text): - """The input is a string""" - - if self._justify: - # we must break very long lines into multiple ones. Note that this - # will also remove spurious whitespace. - justify_kwargs = self._justify_kwargs or {} - width = self._justify_kwargs.get("width", self.width) - justify_kwargs["width"] = width - justify_kwargs["align"] = self._justify_kwargs.get("align", "l") - justify_kwargs["indent"] = self._justify_kwargs.get("indent", 0) - - lines = [] - for line in text.split("\n"): - if len(line) > width: - lines.extend(justify(line, **justify_kwargs).split("\n")) - else: - lines.append(line) - else: - # no justification. Simple division by line - lines = text.split("\n") - - self._data = [ - _LBR.join(lines[i: i + self.height]) for i in range(0, len(lines), self.height) - ] - self._npages = len(self._data)
- - # Hooks for customizing input handling and formatting (override in a child class) - -
[docs] def init_pages(self, inp): - """ - Initialize the pagination. By default, will analyze input type to determine - how pagination automatically. - - Args: - inp (any): Incoming data to be paginated. By default, handles pagination of - strings, querysets, django.Paginator, EvTables and any iterables with strings. - - Notes: - If overridden, this method must perform the following actions: - - - read and re-store `self._data` (the incoming data set) if needed for pagination to - work. - - set `self._npages` to the total number of pages. Default is 1. - - set `self._paginator` to a callable that will take a page number 1...N and return - the data to display on that page (not any decorations or next/prev buttons). If only - wanting to change the paginator, override `self.paginator` instead. - - set `self._page_formatter` to a callable that will receive the page from - `self._paginator` and format it with one element per line. Default is `str`. Or - override `self.page_formatter` directly instead. - - By default, helper methods are called that perform these actions - depending on supported inputs. - - """ - if inherits_from(inp, "evennia.utils.evtable.EvTable"): - # an EvTable - self.init_evtable(inp) - self._paginator = self.paginator_index - elif isinstance(inp, QuerySet): - # a queryset - self.init_queryset(inp) - self._paginator = self.paginator_slice - elif isinstance(inp, Paginator): - self.init_django_paginator(inp) - self._paginator = self.paginator_django - elif not isinstance(inp, str): - # anything else not a str - self.init_iterable(inp) - self._paginator = self.paginator_slice - elif "\f" in inp: - # string with \f line-break markers in it - self.init_f_str(inp) - self._paginator = self.paginator_index - else: - # a string - self.init_str(inp) - self._paginator = self.paginator_index
- -
[docs] def paginator(self, pageno): - """ - Paginator. The data operated upon is in `self._data`. - - Args: - pageno (int): The page number to view, from 0...N-1 - Returns: - str: The page to display (without any decorations, those are added - by EvMore). - - """ - return self._paginator(pageno)
- -
[docs] def page_formatter(self, page): - """ - Page formatter. Every page passes through this method. Override - it to customize behvaior per-page. A common use is to generate a new - EvTable for every page (this is more efficient than to generate one huge - EvTable across many pages and feed it into EvMore all at once). - - Args: - page (any): A piece of data representing one page to display. This must - - Returns: - str: A ready-formatted page to display. Extra footer with help about - switching to the next/prev page will be added automatically - - """ - return self._page_formatter(page)
- - -# helper function - - -
[docs]def msg( - caller, - text="", - always_page=False, - session=None, - justify=False, - justify_kwargs=None, - exit_on_lastpage=True, - **kwargs, -): - """ - EvMore-supported version of msg, mimicking the normal msg method. - - """ - EvMore( - caller, - text, - always_page=always_page, - session=session, - justify=justify, - justify_kwargs=justify_kwargs, - exit_on_lastpage=exit_on_lastpage, - **kwargs, - )
- - -msg.__doc__ += dedent(EvMore.__init__.__doc__) -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/evtable.html b/docs/0.9.5/_modules/evennia/utils/evtable.html deleted file mode 100644 index df7caebf82..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/evtable.html +++ /dev/null @@ -1,1854 +0,0 @@ - - - - - - - - evennia.utils.evtable — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.utils.evtable

-"""
-This is an advanced ASCII table creator. It was inspired by Prettytable
-(https://code.google.com/p/prettytable/) but shares no code and is considerably
-more advanced, supporting auto-balancing of incomplete tables and ANSI colors among
-other things.
-
-Example usage:
-
-```python
-  from evennia.utils import evtable
-
-  table = evtable.EvTable("Heading1", "Heading2",
-                  table=[[1,2,3],[4,5,6],[7,8,9]], border="cells")
-  table.add_column("This is long data", "This is even longer data")
-  table.add_row("This is a single row")
-  print table
-```
-
-Result:
-
-::
-
-    +----------------------+----------+---+--------------------------+
-    |       Heading1       | Heading2 |   |                          |
-    +~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~~+~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~+
-    |           1          |     4    | 7 |     This is long data    |
-    +----------------------+----------+---+--------------------------+
-    |           2          |     5    | 8 | This is even longer data |
-    +----------------------+----------+---+--------------------------+
-    |           3          |     6    | 9 |                          |
-    +----------------------+----------+---+--------------------------+
-    | This is a single row |          |   |                          |
-    +----------------------+----------+---+--------------------------+
-
-As seen, the table will automatically expand with empty cells to make
-the table symmetric. Tables can be restricted to a given width:
-
-```python
-  table.reformat(width=50, align="l")
-```
-
-(We could just have added these keywords to the table creation call)
-
-This yields the following result:
-
-::
-
-    +-----------+------------+-----------+-----------+
-    | Heading1  | Heading2   |           |           |
-    +~~~~~~~~~~~+~~~~~~~~~~~~+~~~~~~~~~~~+~~~~~~~~~~~+
-    | 1         | 4          | 7         | This is   |
-    |           |            |           | long data |
-    +-----------+------------+-----------+-----------+
-    |           |            |           | This is   |
-    | 2         | 5          | 8         | even      |
-    |           |            |           | longer    |
-    |           |            |           | data      |
-    +-----------+------------+-----------+-----------+
-    | 3         | 6          | 9         |           |
-    +-----------+------------+-----------+-----------+
-    | This is a |            |           |           |
-    |  single   |            |           |           |
-    | row       |            |           |           |
-    +-----------+------------+-----------+-----------+
-
-
-Table-columns can be individually formatted. Note that if an
-individual column is set with a specific width, table auto-balancing
-will not affect this column (this may lead to the full table being too
-wide, so be careful mixing fixed-width columns with auto- balancing).
-Here we change the width and alignment of the column at index 3
-(Python starts from 0):
-
-```python
-
-table.reformat_column(3, width=30, align="r")
-print table
-```
-
-::
-
-    +-----------+-------+-----+-----------------------------+---------+
-    | Heading1  | Headi |     |                             |         |
-    |           | ng2   |     |                             |         |
-    +~~~~~~~~~~~+~~~~~~~+~~~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~+
-    | 1         | 4     | 7   |           This is long data | Test1   |
-    +-----------+-------+-----+-----------------------------+---------+
-    | 2         | 5     | 8   |    This is even longer data | Test3   |
-    +-----------+-------+-----+-----------------------------+---------+
-    | 3         | 6     | 9   |                             | Test4   |
-    +-----------+-------+-----+-----------------------------+---------+
-    | This is a |       |     |                             |         |
-    |  single   |       |     |                             |         |
-    | row       |       |     |                             |         |
-    +-----------+-------+-----+-----------------------------+---------+
-
-When adding new rows/columns their data can have its own alignments
-(left/center/right, top/center/bottom).
-
-If the height is restricted, cells will be restricted from expanding
-vertically. This will lead to text contents being cropped. Each cell
-can only shrink to a minimum width and height of 1.
-
-`EvTable` is intended to be used with `ANSIString` for supporting ANSI-coloured
-string types.
-
-When a cell is auto-wrapped across multiple lines, ANSI-reset sequences will be
-put at the end of each wrapped line. This means that the colour of a wrapped
-cell will not "bleed", but it also means that eventual colour outside the table
-will not transfer "across" a table, you need to re-set the color to have it
-appear on both sides of the table string.
-
-----
-
-"""
-
-from django.conf import settings
-from textwrap import TextWrapper
-from copy import deepcopy, copy
-from evennia.utils.utils import is_iter, display_len as d_len
-from evennia.utils.ansi import ANSIString
-
-_DEFAULT_WIDTH = settings.CLIENT_DEFAULT_WIDTH
-
-
-def _to_ansi(obj):
-    """
-    convert to ANSIString.
-
-    Args:
-        obj (str): Convert incoming text to
-            be ANSI aware ANSIStrings.
-    """
-    if is_iter(obj):
-        return [_to_ansi(o) for o in obj]
-    else:
-        return ANSIString(obj)
-
-
-_whitespace = "\t\n\x0b\x0c\r "
-
-
-
[docs]class ANSITextWrapper(TextWrapper): - """ - This is a wrapper work class for handling strings with ANSI tags - in it. It overloads the standard library `TextWrapper` class and - is used internally in `EvTable` and has no public methods. - - """ - - def _munge_whitespace(self, text): - """_munge_whitespace(text : string) -> string - - Munge whitespace in text: expand tabs and convert all other - whitespace characters to spaces. Eg. " foo\tbar\n\nbaz" - becomes " foo bar baz". - """ - return text - - # TODO: Ignore expand_tabs/replace_whitespace until ANSIString handles them. - # - don't remove this code. /Griatch - # if self.expand_tabs: - # text = text.expandtabs() - # if self.replace_whitespace: - # if isinstance(text, str): - # text = text.translate(self.whitespace_trans) - # return text - - def _split(self, text): - """_split(text : string) -> [string] - - Split the text to wrap into indivisible chunks. Chunks are - not quite the same as words; see _wrap_chunks() for full - details. As an example, the text - Look, goof-ball -- use the -b option! - breaks into the following chunks: - 'Look,', ' ', 'goof-', 'ball', ' ', '--', ' ', - 'use', ' ', 'the', ' ', '-b', ' ', 'option!' - if break_on_hyphens is True, or in: - 'Look,', ' ', 'goof-ball', ' ', '--', ' ', - 'use', ' ', 'the', ' ', '-b', ' ', option!' - otherwise. - """ - # NOTE-PYTHON3: The following code only roughly approximates what this - # function used to do. Regex splitting on ANSIStrings is - # dropping ANSI codes, so we're using ANSIString.split - # for the time being. - # - # A less hackier solution would be appreciated. - chunks = _to_ansi(text).split() - - chunks = [chunk + " " for chunk in chunks if chunk] # remove empty chunks - - if len(chunks) > 1: - chunks[-1] = chunks[-1][0:-1] - - return chunks - - def _wrap_chunks(self, chunks): - """_wrap_chunks(chunks : [string]) -> [string] - - Wrap a sequence of text chunks and return a list of lines of - length 'self.width' or less. (If 'break_long_words' is false, - some lines may be longer than this.) Chunks correspond roughly - to words and the whitespace between them: each chunk is - indivisible (modulo 'break_long_words'), but a line break can - come between any two chunks. Chunks should not have internal - whitespace; ie. a chunk is either all whitespace or a "word". - Whitespace chunks will be removed from the beginning and end of - lines, but apart from that whitespace is preserved. - """ - lines = [] - if self.width <= 0: - raise ValueError("invalid width %r (must be > 0)" % self.width) - - # Arrange in reverse order so items can be efficiently popped - # from a stack of chucks. - chunks.reverse() - - while chunks: - - # Start the list of chunks that will make up the current line. - # cur_len is just the length of all the chunks in cur_line. - cur_line = [] - cur_len = 0 - - # Figure out which static string will prefix this line. - if lines: - indent = self.subsequent_indent - else: - indent = self.initial_indent - - # Maximum width for this line. - width = self.width - d_len(indent) - - # First chunk on line is whitespace -- drop it, unless this - # is the very beginning of the text (ie. no lines started yet). - if self.drop_whitespace and chunks[-1].strip() == "" and lines: - del chunks[-1] - - while chunks: - ln = d_len(chunks[-1]) - - # Can at least squeeze this chunk onto the current line. - if cur_len + ln <= width: - cur_line.append(chunks.pop()) - cur_len += ln - - # Nope, this line is full. - else: - break - - # The current line is full, and the next chunk is too big to - # fit on *any* line (not just this one). - if chunks and d_len(chunks[-1]) > width: - self._handle_long_word(chunks, cur_line, cur_len, width) - - # If the last chunk on this line is all whitespace, drop it. - if self.drop_whitespace and cur_line and cur_line[-1].strip() == "": - del cur_line[-1] - - # Convert current line back to a string and store it in list - # of all lines (return value). - if cur_line: - ln = "" - for w in cur_line: # ANSI fix - ln += w # - lines.append(indent + ln) - return lines
- - -# -- Convenience interface --------------------------------------------- - - -
[docs]def wrap(text, width=_DEFAULT_WIDTH, **kwargs): - """ - Wrap a single paragraph of text, returning a list of wrapped lines. - - Reformat the single paragraph in 'text' so it fits in lines of no - more than 'width' columns, and return a list of wrapped lines. By - default, tabs in 'text' are expanded with string.expandtabs(), and - all other whitespace characters (including newline) are converted to - - Args: - text (str): Text to wrap. - width (int, optional): Width to wrap `text` to. - - Keyword Args: - See TextWrapper class for available keyword args to customize - wrapping behaviour. - - """ - w = ANSITextWrapper(width=width, **kwargs) - return w.wrap(text)
- - -
[docs]def fill(text, width=_DEFAULT_WIDTH, **kwargs): - """Fill a single paragraph of text, returning a new string. - - Reformat the single paragraph in 'text' to fit in lines of no more - than 'width' columns, and return a new string containing the entire - wrapped paragraph. As with wrap(), tabs are expanded and other - whitespace characters converted to space. - - Args: - text (str): Text to fill. - width (int, optional): Width of fill area. - - Keyword Args: - See TextWrapper class for available keyword args to customize - filling behaviour. - - """ - w = ANSITextWrapper(width=width, **kwargs) - return w.fill(text)
- - -# EvCell class (see further down for the EvTable itself) - - -
[docs]class EvCell: - """ - Holds a single data cell for the table. A cell has a certain width - and height and contains one or more lines of data. It can shrink - and resize as needed. - - """ - -
[docs] def __init__(self, data, **kwargs): - """ - Args: - data (str): The un-padded data of the entry. - - Keyword Args: - width (int): Desired width of cell. It will pad - to this size. - height (int): Desired height of cell. it will pad - to this size. - pad_width (int): General padding width. This can be overruled - by individual settings below. - pad_left (int): Number of extra pad characters on the left. - pad_right (int): Number of extra pad characters on the right. - pad_top (int): Number of extra pad lines top (will pad with `vpad_char`). - pad_bottom (int): Number of extra pad lines bottom (will pad with `vpad_char`). - pad_char (str)- pad character to use for padding. This is overruled - by individual settings below (default `" "`). - hpad_char (str): Pad character to use both for extra horizontal - padding (default `" "`). - vpad_char (str): Pad character to use for extra vertical padding - and for vertical fill (default `" "`). - fill_char (str): Character used to filling (expanding cells to - desired size). This can be overruled by individual settings below. - hfill_char (str): Character used for horizontal fill (default `" "`). - vfill_char (str): Character used for vertical fill (default `" "`). - align (str): Should be one of "l", "r" or "c" for left-, right- or center - horizontal alignment respectively. Default is left-aligned. - valign (str): Should be one of "t", "b" or "c" for top-, bottom and center - vertical alignment respectively. Default is centered. - border_width (int): General border width. This is overruled - by individual settings below. - border_left (int): Left border width. - border_right (int): Right border width. - border_top (int): Top border width. - border_bottom (int): Bottom border width. - border_char (str): This will use a single border char for all borders. - overruled by individual settings below. - border_left_char (str): Char used for left border. - border_right_char (str): Char used for right border. - border_top_char (str): Char used for top border. - border_bottom_char (str): Char user for bottom border. - corner_char (str): Character used when two borders cross. (default is ""). - This is overruled by individual settings below. - corner_top_left_char (str): Char used for "nw" corner. - corner_top_right_char (str): Char used for "ne" corner. - corner_bottom_left_char (str): Char used for "sw" corner. - corner_bottom_right_char (str): Char used for "se" corner. - crop_string (str): String to use when cropping sideways, default is `'[...]'`. - crop (bool): Crop contentof cell rather than expand vertically, default=`False`. - enforce_size (bool): If true, the width/height of the cell is - strictly enforced and extra text will be cropped rather than the - cell growing vertically. - - Raises: - Exception: for impossible cell size requirements where the - border width or height cannot fit, or the content is too - small. - - """ - - self.formatted = None - padwidth = kwargs.get("pad_width", None) - padwidth = int(padwidth) if padwidth is not None else None - self.pad_left = int(kwargs.get("pad_left", padwidth if padwidth is not None else 1)) - self.pad_right = int(kwargs.get("pad_right", padwidth if padwidth is not None else 1)) - self.pad_top = int(kwargs.get("pad_top", padwidth if padwidth is not None else 0)) - self.pad_bottom = int(kwargs.get("pad_bottom", padwidth if padwidth is not None else 0)) - - self.enforce_size = kwargs.get("enforce_size", False) - - # avoid multi-char pad_chars messing up counting - pad_char = kwargs.get("pad_char", " ") - pad_char = pad_char[0] if pad_char else " " - hpad_char = kwargs.get("hpad_char", pad_char) - self.hpad_char = hpad_char[0] if hpad_char else pad_char - vpad_char = kwargs.get("vpad_char", pad_char) - self.vpad_char = vpad_char[0] if vpad_char else pad_char - - fill_char = kwargs.get("fill_char", " ") - fill_char = fill_char[0] if fill_char else " " - hfill_char = kwargs.get("hfill_char", fill_char) - self.hfill_char = hfill_char[0] if hfill_char else " " - vfill_char = kwargs.get("vfill_char", fill_char) - self.vfill_char = vfill_char[0] if vfill_char else " " - - self.crop_string = kwargs.get("crop_string", "[...]") - - # borders and corners - borderwidth = kwargs.get("border_width", 0) - self.border_left = kwargs.get("border_left", borderwidth) - self.border_right = kwargs.get("border_right", borderwidth) - self.border_top = kwargs.get("border_top", borderwidth) - self.border_bottom = kwargs.get("border_bottom", borderwidth) - - borderchar = kwargs.get("border_char", None) - self.border_left_char = kwargs.get("border_left_char", borderchar if borderchar else "|") - self.border_right_char = kwargs.get( - "border_right_char", borderchar if borderchar else self.border_left_char - ) - self.border_top_char = kwargs.get("border_top_char", borderchar if borderchar else "-") - self.border_bottom_char = kwargs.get( - "border_bottom_char", borderchar if borderchar else self.border_top_char - ) - - corner_char = kwargs.get("corner_char", "+") - self.corner_top_left_char = kwargs.get("corner_top_left_char", corner_char) - self.corner_top_right_char = kwargs.get("corner_top_right_char", corner_char) - self.corner_bottom_left_char = kwargs.get("corner_bottom_left_char", corner_char) - self.corner_bottom_right_char = kwargs.get("corner_bottom_right_char", corner_char) - - # alignments - self.align = kwargs.get("align", "l") - self.valign = kwargs.get("valign", "c") - - self.data = self._split_lines(_to_ansi(data)) - self.raw_width = max(d_len(line) for line in self.data) - self.raw_height = len(self.data) - - # this is extra trimming required for cels in the middle of a table only - self.trim_horizontal = 0 - self.trim_vertical = 0 - - # width/height is given without left/right or top/bottom padding - if "width" in kwargs: - width = kwargs.pop("width") - self.width = ( - width - self.pad_left - self.pad_right - self.border_left - self.border_right - ) - if self.width <= 0 < self.raw_width: - raise Exception("Cell width too small - no space for data.") - else: - self.width = self.raw_width - if "height" in kwargs: - height = kwargs.pop("height") - self.height = ( - height - self.pad_top - self.pad_bottom - self.border_top - self.border_bottom - ) - if self.height <= 0 < self.raw_height: - raise Exception("Cell height too small - no space for data.") - else: - self.height = self.raw_height
- - # prepare data - # self.formatted = self._reformat() - - def _crop(self, text, width): - """ - Apply cropping of text. - - Args: - text (str): The text to crop. - width (int): The width to crop `text` to. - - """ - if d_len(text) > width: - crop_string = self.crop_string - return text[: width - d_len(crop_string)] + crop_string - return text - - def _reformat(self): - """ - Apply all EvCells' formatting operations. - - """ - data = self._border(self._pad(self._valign(self._align(self._fit_width(self.data))))) - return data - - def _split_lines(self, text): - """ - Simply split by linebreaks - - Args: - text (str): text to split. - - Returns: - split (list): split text. - """ - return text.split("\n") - - def _fit_width(self, data): - """ - Split too-long lines to fit the desired width of the Cell. - - Args: - data (str): Text to adjust to the cell's width. - - Returns: - adjusted data (str): The adjusted text. - - Notes: - This also updates `raw_width`. - - - """ - width = self.width - adjusted_data = [] - for line in data: - if 0 < width < d_len(line): - # replace_whitespace=False, expand_tabs=False is a - # fix for ANSIString not supporting expand_tabs/translate - adjusted_data.extend( - [ - ANSIString(part + ANSIString("|n")) - for part in wrap(line, width=width, drop_whitespace=False) - ] - ) - else: - adjusted_data.append(line) - if self.enforce_size: - # don't allow too high cells - excess = len(adjusted_data) - self.height - if excess > 0: - # too many lines. Crop and mark last line with crop_string - crop_string = self.crop_string - adjusted_data = adjusted_data[:-excess] - crop_string_length = len(crop_string) - if len(adjusted_data[-1]) > crop_string_length: - adjusted_data[-1] = adjusted_data[-1][:-crop_string_length] + crop_string - else: - adjusted_data[-1] += crop_string - elif excess < 0: - # too few lines. Fill to height. - adjusted_data.extend(["" for _ in range(excess)]) - - return adjusted_data - - def _center(self, text, width, pad_char): - """ - Horizontally center text on line of certain width, using padding. - - Args: - text (str): The text to center. - width (int): How wide the area is (in characters) where `text` - should be centered. - pad_char (str): Which padding character to use. - - Returns: - text (str): Centered text. - - """ - excess = width - d_len(text) - if excess <= 0: - return text - if excess % 2: - # uneven padding - narrowside = (excess // 2) * pad_char - widerside = narrowside + pad_char - if width % 2: - return narrowside + text + widerside - else: - return widerside + text + narrowside - else: - # even padding - same on both sides - side = (excess // 2) * pad_char - return side + text + side - - def _align(self, data): - """ - Align list of rows of cell. Whitespace characters will be stripped - if there is only one whitespace character - otherwise, it's assumed - the caller may be trying some manual formatting in the text. - - Args: - data (str): Text to align. - - Returns: - text (str): Aligned result. - - """ - align = self.align - hfill_char = self.hfill_char - width = self.width - if align == "l": - lines = [ - ( - line.lstrip(" ") + " " - if line.startswith(" ") and not line.startswith(" ") - else line - ) - + hfill_char * (width - d_len(line)) - for line in data - ] - return lines - elif align == "r": - return [ - hfill_char * (width - d_len(line)) - + ( - " " + line.rstrip(" ") - if line.endswith(" ") and not line.endswith(" ") - else line - ) - for line in data - ] - else: # center, 'c' - return [self._center(line, self.width, self.hfill_char) for line in data] - - def _valign(self, data): - """ - Align cell vertically - - Args: - data (str): Text to align. - - Returns: - text (str): Vertically aligned text. - - """ - valign = self.valign - height = self.height - cheight = len(data) - excess = height - cheight - padline = self.vfill_char * self.width - - if excess <= 0: - return data - # only care if we need to add new lines - if valign == "t": - return data + [padline for _ in range(excess)] - elif valign == "b": - return [padline for _ in range(excess)] + data - else: # center - narrowside = [padline for _ in range(excess // 2)] - widerside = narrowside + [padline] - if excess % 2: - # uneven padding - if height % 2: - return widerside + data + narrowside - else: - return narrowside + data + widerside - else: - # even padding, same on both sides - return narrowside + data + narrowside - - def _pad(self, data): - """ - Pad data with extra characters on all sides. - - Args: - data (str): Text to pad. - - Returns: - text (str): Padded text. - - """ - left = self.hpad_char * self.pad_left - right = self.hpad_char * self.pad_right - vfill = (self.width + self.pad_left + self.pad_right) * self.vpad_char - top = [vfill for _ in range(self.pad_top)] - bottom = [vfill for _ in range(self.pad_bottom)] - return top + [left + line + right for line in data] + bottom - - def _border(self, data): - """ - Add borders to the cell. - - Args: - data (str): Text to surround with borders. - - Return: - text (str): Text with borders. - - """ - - left = self.border_left_char * self.border_left + ANSIString("|n") - right = ANSIString("|n") + self.border_right_char * self.border_right - - cwidth = ( - self.width - + self.pad_left - + self.pad_right - + max(0, self.border_left - 1) - + max(0, self.border_right - 1) - ) - - vfill = self.corner_top_left_char if left else "" - vfill += cwidth * self.border_top_char - vfill += self.corner_top_right_char if right else "" - top = [vfill for _ in range(self.border_top)] - - vfill = self.corner_bottom_left_char if left else "" - vfill += cwidth * self.border_bottom_char - vfill += self.corner_bottom_right_char if right else "" - bottom = [vfill for _ in range(self.border_bottom)] - - return top + [left + line + right for line in data] + bottom - -
[docs] def get_min_height(self): - """ - Get the minimum possible height of cell, including at least - one line for data. - - Returns: - min_height (int): The mininum height of cell. - - """ - return self.pad_top + self.pad_bottom + self.border_bottom + self.border_top + 1
- -
[docs] def get_min_width(self): - """ - Get the minimum possible width of cell, including at least one - character-width for data. - - Returns: - min_width (int): The minimum width of cell. - - """ - return self.pad_left + self.pad_right + self.border_left + self.border_right + 1
- -
[docs] def get_height(self): - """ - Get natural height of cell, including padding. - - Returns: - natural_height (int): Height of cell. - - """ - return len(self.formatted) # if self.formatted else 0
- -
[docs] def get_width(self): - """ - Get natural width of cell, including padding. - - Returns: - natural_width (int): Width of cell. - - """ - return d_len(self.formatted[0]) # if self.formatted else 0
- -
[docs] def replace_data(self, data, **kwargs): - """ - Replace cell data. This causes a full reformat of the cell. - - Args: - data (str): Cell data. - - Notes: - The available keyword arguments are the same as for - `EvCell.__init__`. - - """ - self.data = self._split_lines(_to_ansi(data)) - self.raw_width = max(d_len(line) for line in self.data) - self.raw_height = len(self.data) - self.reformat(**kwargs)
- -
[docs] def reformat(self, **kwargs): - """ - Reformat the EvCell with new options - - Keyword Args: - The available keyword arguments are the same as for `EvCell.__init__`. - - Raises: - Exception: If the cells cannot shrink enough to accomodate - the options or the data given. - - """ - # keywords that require manipulation - padwidth = kwargs.get("pad_width", None) - padwidth = int(padwidth) if padwidth is not None else None - self.pad_left = int( - kwargs.pop("pad_left", padwidth if padwidth is not None else self.pad_left) - ) - self.pad_right = int( - kwargs.pop("pad_right", padwidth if padwidth is not None else self.pad_right) - ) - self.pad_top = int( - kwargs.pop("pad_top", padwidth if padwidth is not None else self.pad_top) - ) - self.pad_bottom = int( - kwargs.pop("pad_bottom", padwidth if padwidth is not None else self.pad_bottom) - ) - - self.enforce_size = kwargs.get("enforce_size", False) - - pad_char = kwargs.pop("pad_char", None) - hpad_char = kwargs.pop("hpad_char", pad_char) - self.hpad_char = hpad_char[0] if hpad_char else self.hpad_char - vpad_char = kwargs.pop("vpad_char", pad_char) - self.vpad_char = vpad_char[0] if vpad_char else self.vpad_char - - fillchar = kwargs.pop("fill_char", None) - hfill_char = kwargs.pop("hfill_char", fillchar) - self.hfill_char = hfill_char[0] if hfill_char else self.hfill_char - vfill_char = kwargs.pop("vfill_char", fillchar) - self.vfill_char = vfill_char[0] if vfill_char else self.vfill_char - - borderwidth = kwargs.get("border_width", None) - self.border_left = kwargs.pop( - "border_left", borderwidth if borderwidth is not None else self.border_left - ) - self.border_right = kwargs.pop( - "border_right", borderwidth if borderwidth is not None else self.border_right - ) - self.border_top = kwargs.pop( - "border_top", borderwidth if borderwidth is not None else self.border_top - ) - self.border_bottom = kwargs.pop( - "border_bottom", borderwidth if borderwidth is not None else self.border_bottom - ) - - borderchar = kwargs.get("border_char", None) - self.border_left_char = kwargs.pop( - "border_left_char", borderchar if borderchar else self.border_left_char - ) - self.border_right_char = kwargs.pop( - "border_right_char", borderchar if borderchar else self.border_right_char - ) - self.border_top_char = kwargs.pop( - "border_topchar", borderchar if borderchar else self.border_top_char - ) - self.border_bottom_char = kwargs.pop( - "border_bottom_char", borderchar if borderchar else self.border_bottom_char - ) - - corner_char = kwargs.get("corner_char", None) - self.corner_top_left_char = kwargs.pop( - "corner_top_left", corner_char if corner_char is not None else self.corner_top_left_char - ) - self.corner_top_right_char = kwargs.pop( - "corner_top_right", - corner_char if corner_char is not None else self.corner_top_right_char, - ) - self.corner_bottom_left_char = kwargs.pop( - "corner_bottom_left", - corner_char if corner_char is not None else self.corner_bottom_left_char, - ) - self.corner_bottom_right_char = kwargs.pop( - "corner_bottom_right", - corner_char if corner_char is not None else self.corner_bottom_right_char, - ) - - # this is used by the table to adjust size of cells with borders in the middle - # of the table - self.trim_horizontal = kwargs.pop("trim_horizontal", self.trim_horizontal) - self.trim_vertical = kwargs.pop("trim_vertical", self.trim_vertical) - - # fill all other properties - for key, value in kwargs.items(): - setattr(self, key, value) - - # Handle sizes - if "width" in kwargs: - width = kwargs.pop("width") - self.width = ( - width - - self.pad_left - - self.pad_right - - self.border_left - - self.border_right - + self.trim_horizontal - ) - # if self.width <= 0 and self.raw_width > 0: - if self.width <= 0 < self.raw_width: - raise Exception("Cell width too small, no room for data.") - if "height" in kwargs: - height = kwargs.pop("height") - self.height = ( - height - - self.pad_top - - self.pad_bottom - - self.border_top - - self.border_bottom - + self.trim_vertical - ) - if self.height <= 0 < self.raw_height: - raise Exception("Cell height too small, no room for data.") - - # reformat (to new sizes, padding, header and borders) - self.formatted = self._reformat()
- -
[docs] def get(self): - """ - Get data, padded and aligned in the form of a list of lines. - - """ - self.formatted = self._reformat() - return self.formatted
- - def __repr__(self): - self.formatted = self._reformat() - return str(ANSIString("<EvCel %s>" % self.formatted)) - - def __str__(self): - "returns cell contents on string form" - self.formatted = self._reformat() - return str(ANSIString("\n").join(self.formatted))
- - -# EvColumn class - - -
[docs]class EvColumn(object): - """ - This class holds a list of Cells to represent a column of a table. - It holds operations and settings that affect *all* cells in the - column. - - Columns are not intended to be used stand-alone; they should be - incorporated into an EvTable (like EvCells) - - """ - -
[docs] def __init__(self, *args, **kwargs): - """ - Args: - Text for each row in the column - - Keyword Args: - All `EvCell.__init_` keywords are available, these - settings will be persistently applied to every Cell in the - column. - - """ - self.options = kwargs # column-specific options - self.column = [EvCell(data, **kwargs) for data in args]
- - def _balance(self, **kwargs): - """ - Make sure to adjust the width of all cells so we form a - coherent and lined-up column. Will enforce column-specific - options to cells. - - Keyword Args: - Extra keywords to modify the column setting. Same keywords - as in `EvCell.__init__`. - - """ - col = self.column - # fixed options for the column will override those requested in the call! - # this is particularly relevant to things like width/height, to avoid - # fixed-widths columns from being auto-balanced - kwargs.update(self.options) - # use fixed width or adjust to the largest cell - if "width" not in kwargs: - [ - cell.reformat() for cell in col - ] # this is necessary to get initial widths of all cells - kwargs["width"] = max(cell.get_width() for cell in col) if col else 0 - [cell.reformat(**kwargs) for cell in col] - -
[docs] def add_rows(self, *args, **kwargs): - """ - Add new cells to column. They will be inserted as - a series of rows. It will inherit the options - of the rest of the column's cells (use update to change - options). - - Args: - Texts for the new cells - ypos (int, optional): Index position in table before which to insert the - new column. Uses Python indexing, so to insert at the top, - use `ypos=0`. If not given, data will be inserted at the end - of the column. - - Keyword Args: - Available keywods as per `EvCell.__init__`. - - """ - # column-level options override those in kwargs - options = {**kwargs, **self.options} - - ypos = kwargs.get("ypos", None) - if ypos is None or ypos > len(self.column): - # add to the end - self.column.extend([EvCell(data, **options) for data in args]) - else: - # insert cells before given index - ypos = min(len(self.column) - 1, max(0, int(ypos))) - new_cells = [EvCell(data, **options) for data in args] - self.column = self.column[:ypos] + new_cells + self.column[ypos:]
- # self._balance(**kwargs) - -
[docs] def reformat(self, **kwargs): - """ - Change the options for the column. - - Keyword Args: - Keywords as per `EvCell.__init__`. - - """ - self._balance(**kwargs)
- -
[docs] def reformat_cell(self, index, **kwargs): - """ - reformat cell at given index, keeping column options if - necessary. - - Args: - index (int): Index location of the cell in the column, - starting from 0 for the first row to Nrows-1. - - Keyword Args: - Keywords as per `EvCell.__init__`. - - """ - # column-level options take precedence here - kwargs.update(self.options) - self.column[index].reformat(**kwargs)
- - def __repr__(self): - return "<EvColumn\n %s>" % ("\n ".join([repr(cell) for cell in self.column])) - - def __len__(self): - return len(self.column) - - def __iter__(self): - return iter(self.column) - - def __getitem__(self, index): - return self.column[index] - - def __setitem__(self, index, value): - self.column[index] = value - - def __delitem__(self, index): - del self.column[index]
- - -# Main Evtable class - - -
[docs]class EvTable(object): - """ - The table class holds a list of EvColumns, each consisting of EvCells so - that the result is a 2D matrix. - """ - -
[docs] def __init__(self, *args, **kwargs): - """ - Args: - Header texts for the table. - - Keyword Args: - table (list of lists or list of `EvColumns`, optional): - This is used to build the table in a quick way. If not - given, the table will start out empty and `add_` methods - need to be used to add rows/columns. - header (bool, optional): `True`/`False` - turn off the - header texts (`*args`) being treated as a header (such as - not adding extra underlining) - pad_width (int, optional): How much empty space to pad your cells with - (default is 1) - border (str, optional)): The border style to use. This is one of - - `None` - No border drawing at all. - - "table" - only a border around the whole table. - - "tablecols" - table and column borders. (default) - - "header" - only border under header. - - "cols" - only vertical borders. - - "incols" - vertical borders, no outer edges. - - "rows" - only borders between rows. - - "cells" - border around all cells. - border_width (int, optional): Width of table borders, if border is active. - Note that widths wider than 1 may give artifacts in the corners. Default is 1. - corner_char (str, optional): Character to use in corners when border is active. - Default is `+`. - corner_top_left_char (str, optional): Character used for "nw" corner of table. - Defaults to `corner_char`. - corner_top_right_char (str, optional): Character used for "ne" corner of table. - Defaults to `corner_char`. - corner_bottom_left_char (str, optional): Character used for "sw" corner of table. - Defaults to `corner_char`. - corner_bottom_right_char (str, optional): Character used for "se" corner of table. - Defaults to `corner_char`. - pretty_corners (bool, optional): Use custom characters to - make the table corners look "rounded". Uses UTF-8 - characters. Defaults to `False` for maximum compatibility with various displays - that may occationally have issues with UTF-8 characters. - header_line_char (str, optional): Character to use for underlining - the header row (default is '~'). Requires `border` to not be `None`. - width (int, optional): Fixed width of table. If not set, - width is set by the total width of each column. This will - resize individual columns in the vertical direction to fit. - height (int, optional): Fixed height of table. Defaults to being unset. Width is - still given precedence. If given, table cells will crop text rather - than expand vertically. - evenwidth (bool, optional): Used with the `width` keyword. Adjusts columns to have as - even width as possible. This often looks best also for mixed-length tables. Default - is `False`. - maxwidth (int, optional): This will set a maximum width - of the table while allowing it to be smaller. Only if it grows wider than this - size will it be resized by expanding horizontally (or crop `height` is given). - This keyword has no meaning if `width` is set. - - Raises: - Exception: If given erroneous input or width settings for the data. - - Notes: - Beyond those table-specific keywords, the non-overlapping keywords - of `EvCell.__init__` are also available. These will be passed down - to every cell in the table. - - """ - # at this point table is a 2D grid - a list of columns - # x is the column position, y the row - table = kwargs.pop("table", []) - - # header is a list of texts. We merge it to the table's top - header = [_to_ansi(head) for head in args] - self.header = header != [] - if self.header: - if table: - excess = len(header) - len(table) - if excess > 0: - # header bigger than table - table.extend([] for _ in range(excess)) - elif excess < 0: - # too short header - header.extend(_to_ansi(["" for _ in range(abs(excess))])) - for ix, heading in enumerate(header): - table[ix].insert(0, heading) - else: - table = [[heading] for heading in header] - # even though we inserted the header, we can still turn off - # header border underling etc. We only allow this if a header - # was actually set - self.header = kwargs.pop("header", self.header) if self.header else False - hchar = kwargs.pop("header_line_char", "~") - self.header_line_char = hchar[0] if hchar else "~" - - border = kwargs.pop("border", "tablecols") - if border is None: - border = "none" - if border not in ( - "none", - "table", - "tablecols", - "header", - "incols", - "cols", - "rows", - "cells", - ): - raise Exception("Unsupported border type: '%s'" % border) - self.border = border - - # border settings are passed into Cell as well (so kwargs.get and not pop) - self.border_width = kwargs.get("border_width", 1) - self.corner_char = kwargs.get("corner_char", "+") - pcorners = kwargs.pop("pretty_corners", False) - self.corner_top_left_char = _to_ansi( - kwargs.pop("corner_top_left_char", "." if pcorners else self.corner_char) - ) - self.corner_top_right_char = _to_ansi( - kwargs.pop("corner_top_right_char", "." if pcorners else self.corner_char) - ) - self.corner_bottom_left_char = _to_ansi( - kwargs.pop("corner_bottom_left_char", " " if pcorners else self.corner_char) - ) - self.corner_bottom_right_char = _to_ansi( - kwargs.pop("corner_bottom_right_char", " " if pcorners else self.corner_char) - ) - - self.width = kwargs.pop("width", None) - self.height = kwargs.pop("height", None) - self.evenwidth = kwargs.pop("evenwidth", False) - self.maxwidth = kwargs.pop("maxwidth", None) - if self.maxwidth and self.width and self.maxwidth < self.width: - raise Exception("table maxwidth < table width!") - # size in cell cols/rows - self.ncols = len(table) - self.nrows = max(len(col) for col in table) if table else 0 - # size in characters (gets set when _balance is called) - self.nwidth = 0 - self.nheight = 0 - # save options - self.options = kwargs - - # use the temporary table to generate the table on the fly, as a list of EvColumns - self.table = [EvColumn(*col, **kwargs) for col in table] - - # this is the actual working table - self.worktable = None
- - # balance the table - # self._balance() - - def _cellborders(self, ix, iy, nx, ny, **kwargs): - """ - Adds borders to the table by adjusting the input kwarg to - instruct cells to build a border in the right positions. - - Args: - ix (int): x index positions in table. - iy (int): y index positions in table. - nx (int): x size of table. - ny (int): y size of table. - - Keyword Args: - Keywords as per `EvTable.__init__`. - - Returns: - table (str): string with the correct borders. - - Notes: - A copy of the kwarg is returned to the cell. This is method - is called by self._borders. - - """ - - ret = kwargs.copy() - - # handle the various border modes - border = self.border - header = self.header - - bwidth = self.border_width - headchar = self.header_line_char - - def corners(ret): - """Handle corners of table""" - if ix == 0 and iy == 0: - ret["corner_top_left_char"] = self.corner_top_left_char - if ix == nx and iy == 0: - ret["corner_top_right_char"] = self.corner_top_right_char - if ix == 0 and iy == ny: - ret["corner_bottom_left_char"] = self.corner_bottom_left_char - if ix == nx and iy == ny: - ret["corner_bottom_right_char"] = self.corner_bottom_right_char - return ret - - def left_edge(ret): - """add vertical border along left table edge""" - if ix == 0: - ret["border_left"] = bwidth - # ret["trim_horizontal"] = bwidth - return ret - - def top_edge(ret): - """add border along top table edge""" - if iy == 0: - ret["border_top"] = bwidth - # ret["trim_vertical"] = bwidth - return ret - - def right_edge(ret): - """add vertical border along right table edge""" - if ix == nx: # and 0 < iy < ny: - ret["border_right"] = bwidth - # ret["trim_horizontal"] = 0 - return ret - - def bottom_edge(ret): - """add border along bottom table edge""" - if iy == ny: - ret["border_bottom"] = bwidth - # ret["trim_vertical"] = bwidth - return ret - - def cols(ret): - """Adding vertical borders inside the table""" - if 0 <= ix < nx: - ret["border_right"] = bwidth - return ret - - def rows(ret): - """Adding horizontal borders inside the table""" - if 0 <= iy < ny: - ret["border_bottom"] = bwidth - return ret - - def head(ret): - """Add header underline""" - if iy == 0: - # put different bottom line for header - ret["border_bottom"] = bwidth - ret["border_bottom_char"] = headchar - return ret - - # use the helper functions to define various - # table "styles" - - if border in ("table", "tablecols", "cells"): - ret = bottom_edge(right_edge(top_edge(left_edge(corners(ret))))) - if border in ("cols", "tablecols", "cells"): - ret = cols(right_edge(left_edge(ret))) - if border in "incols": - ret = cols(ret) - if border in ("rows", "cells"): - ret = rows(bottom_edge(top_edge(ret))) - if header and border not in ("none", None): - ret = head(ret) - - return ret - - def _borders(self): - """ - Add borders to table. This is called from self._balance. - """ - nx, ny = self.ncols - 1, self.nrows - 1 - options = self.options - for ix, col in enumerate(self.worktable): - for iy, cell in enumerate(col): - col.reformat_cell(iy, **self._cellborders(ix, iy, nx, ny, **options)) - - def _balance(self): - """ - Balance the table. This means to make sure - all cells on the same row have the same height, - that all columns have the same number of rows - and that the table fits within the given width. - """ - - # we make all modifications on a working copy of the - # actual table. This allows us to add columns/rows - # and re-balance over and over without issue. - self.worktable = deepcopy(self.table) - # self._borders() - # return - options = copy(self.options) - - # balance number of rows to make a rectangular table - # column by column - ncols = len(self.worktable) - nrows = [len(col) for col in self.worktable] - nrowmax = max(nrows) if nrows else 0 - for icol, nrow in enumerate(nrows): - self.worktable[icol].reformat(**options) - if nrow < nrowmax: - # add more rows to too-short columns - empty_rows = ["" for _ in range(nrowmax - nrow)] - self.worktable[icol].add_rows(*empty_rows) - self.ncols = ncols - self.nrows = nrowmax - - # add borders - these add to the width/height, so we must do this before calculating - # width/height - self._borders() - - # equalize widths within each column - cwidths = [max(cell.get_width() for cell in col) for col in self.worktable] - - if self.width or self.maxwidth and self.maxwidth < sum(cwidths): - # we set a table width. Horizontal cells will be evenly distributed and - # expand vertically as needed (unless self.height is set, see below) - - # use fixed width, or set to maxwidth - width = self.width if self.width else self.maxwidth - - if ncols: - # get minimum possible cell widths for each row - cwidths_min = [max(cell.get_min_width() for cell in col) for col in self.worktable] - cwmin = sum(cwidths_min) - - # get which cols have separately set widths - these should be locked - # note that we need to remove cwidths_min for each lock to avoid counting - # it twice (in cwmin and in locked_cols) - locked_cols = { - icol: col.options["width"] - cwidths_min[icol] - for icol, col in enumerate(self.worktable) - if "width" in col.options - } - locked_width = sum(locked_cols.values()) - - excess = width - cwmin - locked_width - - if len(locked_cols) >= ncols and excess: - # we can't adjust the width at all - all columns are locked - raise Exception( - "Cannot balance table to width %s - " - "all columns have a set, fixed width summing to %s!" - % (self.width, sum(cwidths)) - ) - - if excess < 0: - # the locked cols makes it impossible - raise Exception( - "Cannot shrink table width to %s. " - "Minimum size (and/or fixed-width columns) " - "sets minimum at %s." % (self.width, cwmin + locked_width) - ) - - if self.evenwidth: - # make each column of equal width - # use cwidths as a work-array to track weights - cwidths = copy(cwidths_min) - correction = 0 - while correction < excess: - # flood-fill the minimum table starting with the smallest columns - ci = cwidths.index(min(cwidths)) - if ci in locked_cols: - # locked column, make sure it's not picked again - cwidths[ci] += 9999 - cwidths_min[ci] = locked_cols[ci] - else: - cwidths_min[ci] += 1 - correction += 1 - cwidths = cwidths_min - else: - # make each column expand more proportional to their data size - # we use cwidth as a work-array to track weights - correction = 0 - while correction < excess: - # fill wider columns first - ci = cwidths.index(max(cwidths)) - if ci in locked_cols: - # locked column, make sure it's not picked again - cwidths[ci] -= 9999 - cwidths_min[ci] = locked_cols[ci] - else: - cwidths_min[ci] += 1 - correction += 1 - # give a just changed col less prio next run - cwidths[ci] -= 3 - cwidths = cwidths_min - - # reformat worktable (for width align) - for ix, col in enumerate(self.worktable): - try: - col.reformat(width=cwidths[ix], **options) - except Exception: - raise - - # equalize heights for each row (we must do this here, since it may have changed to fit new - # widths) - cheights = [ - max(cell.get_height() for cell in (col[iy] for col in self.worktable)) - for iy in range(nrowmax) - ] - - if self.height: - # if we are fixing the table height, it means cells must crop text instead of resizing. - if nrowmax: - - # get minimum possible cell heights for each column - cheights_min = [ - max(cell.get_min_height() for cell in (col[iy] for col in self.worktable)) - for iy in range(nrowmax) - ] - chmin = sum(cheights_min) - - # get which cols have separately set heights - these should be locked - # note that we need to remove cheights_min for each lock to avoid counting - # it twice (in chmin and in locked_cols) - locked_cols = { - icol: col.options["height"] - cheights_min[icol] - for icol, col in enumerate(self.worktable) - if "height" in col.options - } - locked_height = sum(locked_cols.values()) - - excess = self.height - chmin - locked_height - - if chmin > self.height: - # we cannot shrink any more - raise Exception( - "Cannot shrink table height to %s. Minimum " - "size (and/or fixed-height rows) sets minimum at %s." - % (self.height, chmin + locked_height) - ) - - # Add all the excess at the end of the table - # Note: Older solutions tried to balance individual - # rows' vsize. This could lead to empty rows that - # looked like a bug. This solution instead - # adds empty rows at the end which is less sophisticated - # but much more visually consistent. - cheights_min[-1] += excess - cheights = cheights_min - - # we must tell cells to crop instead of expanding - options["enforce_size"] = True - - # reformat table (for vertical align) - for ix, col in enumerate(self.worktable): - for iy, cell in enumerate(col): - try: - col.reformat_cell(iy, height=cheights[iy], **options) - except Exception as e: - msg = "ix=%s, iy=%s, height=%s: %s" % (ix, iy, cheights[iy], e.message) - raise Exception("Error in vertical align:\n %s" % msg) - - # calculate actual table width/height in characters - self.cwidth = sum(cwidths) - self.cheight = sum(cheights) - - def _generate_lines(self): - """ - Generates lines across all columns - (each cell may contain multiple lines) - This will also balance the table. - """ - self._balance() - for iy in range(self.nrows): - cell_row = [col[iy] for col in self.worktable] - # this produces a list of lists, each of equal length - cell_data = [cell.get() for cell in cell_row] - cell_height = min(len(lines) for lines in cell_data) - for iline in range(cell_height): - yield ANSIString("").join(_to_ansi(celldata[iline] for celldata in cell_data)) - -
[docs] def add_header(self, *args, **kwargs): - """ - Add header to table. This is a number of texts to be put at - the top of the table. They will replace an existing header. - - Args: - args (str): These strings will be used as the header texts. - - Keyword Args: - Same keywords as per `EvTable.__init__`. Will be applied - to the new header's cells. - - """ - self.header = True - self.add_row(ypos=0, *args, **kwargs)
- -
[docs] def add_column(self, *args, **kwargs): - """ - Add a column to table. If there are more rows in new column - than there are rows in the current table, the table will - expand with empty rows in the other columns. If too few, the - new column with get new empty rows. All filling rows are added - to the end. - - Args: - args (`EvColumn` or multiple strings): Either a single EvColumn instance or - a number of data string arguments to be used to create a new column. - header (str, optional): The header text for the column - xpos (int, optional): Index position in table *before* which - to input new column. If not given, column will be added to the end - of the table. Uses Python indexing (so first column is `xpos=0`) - - Keyword Args: - Other keywords as per `Cell.__init__`. - - """ - # this will replace default options with new ones without changing default - options = dict(list(self.options.items()) + list(kwargs.items())) - - xpos = kwargs.get("xpos", None) - column = EvColumn(*args, **options) - wtable = self.ncols - htable = self.nrows - - header = kwargs.get("header", None) - if header: - column.add_rows(str(header), ypos=0, **options) - self.header = True - elif self.header: - # we have a header already. Offset - column.add_rows("", ypos=0, **options) - - # Calculate whether the new column needs to expand to the - # current table size, or if the table needs to expand to - # the column size. - # This needs to happen after the header rows have already been - # added to the column in order for the size calculations to match. - excess = len(column) - htable - if excess > 0: - # we need to add new rows to table - for col in self.table: - empty_rows = ["" for _ in range(excess)] - col.add_rows(*empty_rows, **options) - self.nrows += excess - elif excess < 0: - # we need to add new rows to new column - empty_rows = ["" for _ in range(abs(excess))] - column.add_rows(*empty_rows, **options) - self.nrows -= excess - - if xpos is None or xpos > wtable - 1: - # add to the end - self.table.append(column) - else: - # insert column - xpos = min(wtable - 1, max(0, int(xpos))) - self.table.insert(xpos, column) - self.ncols += 1
- # self._balance() - -
[docs] def add_row(self, *args, **kwargs): - """ - Add a row to table (not a header). If there are more cells in - the given row than there are cells in the current table the - table will be expanded with empty columns to match. These will - be added to the end of the table. In the same way, adding a - line with too few cells will lead to the last ones getting - padded. - - Args: - args (str): Any number of string argumnets to use as the - data in the row (one cell per argument). - ypos (int, optional): Index position in table before which to - input new row. If not given, will be added to the end of the table. - Uses Python indexing (so first row is `ypos=0`) - - Keyword Args: - Other keywords are as per `EvCell.__init__`. - - """ - # this will replace default options with new ones without changing default - row = list(args) - options = dict(list(self.options.items()) + list(kwargs.items())) - - ypos = kwargs.get("ypos", None) - wtable = self.ncols - htable = self.nrows - excess = len(row) - wtable - - if excess > 0: - # we need to add new empty columns to table - empty_rows = ["" for _ in range(htable)] - self.table.extend([EvColumn(*empty_rows, **options) for _ in range(excess)]) - self.ncols += excess - elif excess < 0: - # we need to add more cells to row - row.extend(["" for _ in range(abs(excess))]) - self.ncols -= excess - - if ypos is None or ypos > htable - 1: - # add new row to the end - for icol, col in enumerate(self.table): - col.add_rows(row[icol], **options) - else: - # insert row elsewhere - ypos = min(htable - 1, max(0, int(ypos))) - for icol, col in enumerate(self.table): - col.add_rows(row[icol], ypos=ypos, **options) - self.nrows += 1
- # self._balance() - -
[docs] def reformat(self, **kwargs): - """ - Force a re-shape of the entire table. - - Keyword Args: - Table options as per `EvTable.__init__`. - - """ - self.width = kwargs.pop("width", self.width) - self.height = kwargs.pop("height", self.height) - for key, value in kwargs.items(): - setattr(self, key, value) - - hchar = kwargs.pop("header_line_char", self.header_line_char) - - # border settings are also passed on into EvCells (so kwargs.get, not kwargs.pop) - self.header_line_char = hchar[0] if hchar else self.header_line_char - self.border_width = kwargs.get("border_width", self.border_width) - self.corner_char = kwargs.get("corner_char", self.corner_char) - self.header_line_char = kwargs.get("header_line_char", self.header_line_char) - - self.corner_top_left_char = _to_ansi(kwargs.pop("corner_top_left_char", self.corner_char)) - self.corner_top_right_char = _to_ansi(kwargs.pop("corner_top_right_char", self.corner_char)) - self.corner_bottom_left_char = _to_ansi( - kwargs.pop("corner_bottom_left_char", self.corner_char) - ) - self.corner_bottom_right_char = _to_ansi( - kwargs.pop("corner_bottom_right_char", self.corner_char) - ) - - self.options.update(kwargs)
- -
[docs] def reformat_column(self, index, **kwargs): - """ - Sends custom options to a specific column in the table. - - Args: - index (int): Which column to reformat. The column index is - given from 0 to Ncolumns-1. - - Keyword Args: - Column options as per `EvCell.__init__`. - - Raises: - Exception: if an invalid index is found. - - """ - if index > len(self.table): - raise Exception("Not a valid column index") - # we update the columns' options which means eventual width/height - # will be 'locked in' and withstand auto-balancing width/height from the table later - self.table[index].options.update(kwargs) - self.table[index].reformat(**kwargs)
- -
[docs] def get(self): - """ - Return lines of table as a list. - - Returns: - table_lines (list): The lines of the table, in order. - - """ - return [line for line in self._generate_lines()]
- - def __str__(self): - """print table (this also balances it)""" - # h = "12345678901234567890123456789012345678901234567890123456789012345678901234567890" - return str(str(ANSIString("\n").join([line for line in self._generate_lines()])))
- - -def _test(): - """Test""" - table = EvTable( - "|yHeading1|n", - "|gHeading2|n", - table=[[1, 2, 3], [4, 5, 6], [7, 8, 9]], - border="cells", - align="l", - ) - table.add_column("|rThis is long data|n", "|bThis is even longer data|n") - table.add_row("This is a single row") - print(str(table)) - table.reformat(width=50) - print(str(table)) - table.reformat_column(3, width=30, align="r") - print(str(table)) - return table - - -def _test2(): - table = EvTable("|yHeading1|n", "|B|[GHeading2|n", "Heading3") - for i in range(100): - table.add_row( - "This is col 0, row %i" % i, - "|gThis is col 1, row |w%i|n|g.|n" % i, - "This is col 2, row %i" % i, - ) - return table -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/gametime.html b/docs/0.9.5/_modules/evennia/utils/gametime.html deleted file mode 100644 index b73b3434bb..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/gametime.html +++ /dev/null @@ -1,390 +0,0 @@ - - - - - - - - evennia.utils.gametime — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.utils.gametime

-"""
-The gametime module handles the global passage of time in the mud.
-
-It also supplies some useful methods to convert between
-in-mud time and real-world time as well allows to get the
-total runtime of the server and the current uptime.
-
-"""
-
-import time
-from datetime import datetime, timedelta
-
-from django.db.utils import OperationalError
-from django.conf import settings
-from evennia import DefaultScript
-from evennia.server.models import ServerConfig
-from evennia.utils.create import create_script
-
-# Speed-up factor of the in-game time compared
-# to real time.
-
-TIMEFACTOR = settings.TIME_FACTOR
-IGNORE_DOWNTIMES = settings.TIME_IGNORE_DOWNTIMES
-
-
-# Only set if gametime_reset was called at some point.
-try:
-    GAME_TIME_OFFSET = ServerConfig.objects.conf("gametime_offset", default=0)
-except OperationalError:
-    # the db is not initialized
-    print("Gametime offset could not load - db not set up.")
-    GAME_TIME_OFFSET = 0
-
-# Common real-life time measure, in seconds.
-# You should not change this.
-
-# these are kept updated by the server maintenance loop
-SERVER_START_TIME = 0.0
-SERVER_RUNTIME_LAST_UPDATED = 0.0
-SERVER_RUNTIME = 0.0
-
-# note that these should not be accessed directly since they may
-# need further processing. Access from server_epoch() and game_epoch().
-_SERVER_EPOCH = None
-_GAME_EPOCH = None
-
-# Helper Script dealing in gametime (created by `schedule` function
-# below).
-
-
-
[docs]class TimeScript(DefaultScript): - """Gametime-sensitive script.""" - -
[docs] def at_script_creation(self): - """The script is created.""" - self.key = "unknown scr" - self.interval = 100 - self.start_delay = True - self.persistent = True
- -
[docs] def at_repeat(self): - """Call the callback and reset interval.""" - callback = self.db.callback - args = self.db.schedule_args or [] - kwargs = self.db.schedule_kwargs or {} - if callback: - callback(*args, **kwargs) - - seconds = real_seconds_until(**self.db.gametime) - self.restart(interval=seconds)
- - -# Access functions - - -
[docs]def runtime(): - """ - Get the total runtime of the server since first start (minus - downtimes) - - Args: - format (bool, optional): Format into a time representation. - - Returns: - time (float or tuple): The runtime or the same time split up - into time units. - - """ - return SERVER_RUNTIME + time.time() - SERVER_RUNTIME_LAST_UPDATED
- - -
[docs]def server_epoch(): - """ - Get the server epoch. We may need to calculate this on the fly. - - """ - global _SERVER_EPOCH - if not _SERVER_EPOCH: - _SERVER_EPOCH = ( - ServerConfig.objects.conf("server_epoch", default=None) or time.time() - runtime() - ) - return _SERVER_EPOCH
- - -
[docs]def uptime(): - """ - Get the current uptime of the server since last reload - - Args: - format (bool, optional): Format into time representation. - - Returns: - time (float or tuple): The uptime or the same time split up - into time units. - - """ - return time.time() - SERVER_START_TIME
- - -
[docs]def portal_uptime(): - """ - Get the current uptime of the portal. - - Returns: - time (float): The uptime of the portal. - """ - from evennia.server.sessionhandler import SESSIONS - - return time.time() - SESSIONS.portal_start_time
- - -
[docs]def game_epoch(): - """ - Get the game epoch. - - """ - game_epoch = settings.TIME_GAME_EPOCH - return game_epoch if game_epoch is not None else server_epoch()
- - -
[docs]def gametime(absolute=False): - """ - Get the total gametime of the server since first start (minus downtimes) - - Args: - absolute (bool, optional): Get the absolute game time, including - the epoch. This could be converted to an absolute in-game - date. - - Returns: - time (float): The gametime as a virtual timestamp. - - Notes: - If one is using a standard calendar, one could convert the unformatted - return to a date using Python's standard `datetime` module like this: - `datetime.datetime.fromtimestamp(gametime(absolute=True))` - - """ - epoch = game_epoch() if absolute else 0 - if IGNORE_DOWNTIMES: - gtime = epoch + (time.time() - server_epoch()) * TIMEFACTOR - else: - gtime = epoch + (runtime() - GAME_TIME_OFFSET) * TIMEFACTOR - return gtime
- - -
[docs]def real_seconds_until(sec=None, min=None, hour=None, day=None, month=None, year=None): - """ - Return the real seconds until game time. - - Args: - sec (int or None): number of absolute seconds. - min (int or None): number of absolute minutes. - hour (int or None): number of absolute hours. - day (int or None): number of absolute days. - month (int or None): number of absolute months. - year (int or None): number of absolute years. - - Returns: - The number of real seconds before the given game time is up. - - Example: - real_seconds_until(hour=5, min=10, sec=0) - - If the game time is 5:00, TIME_FACTOR is set to 2 and you ask - the number of seconds until it's 5:10, then this function should - return 300 (5 minutes). - - - """ - current = datetime.fromtimestamp(gametime(absolute=True)) - s_sec = sec if sec is not None else current.second - s_min = min if min is not None else current.minute - s_hour = hour if hour is not None else current.hour - s_day = day if day is not None else current.day - s_month = month if month is not None else current.month - s_year = year if year is not None else current.year - projected = datetime(s_year, s_month, s_day, s_hour, s_min, s_sec) - - if projected <= current: - # We increase one unit of time depending on parameters - if month is not None: - projected = projected.replace(year=s_year + 1) - elif day is not None: - try: - projected = projected.replace(month=s_month + 1) - except ValueError: - projected = projected.replace(month=1) - elif hour is not None: - projected += timedelta(days=1) - elif min is not None: - projected += timedelta(seconds=3600) - else: - projected += timedelta(seconds=60) - - # Get the number of gametime seconds between these two dates - seconds = (projected - current).total_seconds() - return seconds / TIMEFACTOR
- - -
[docs]def schedule( - callback, repeat=False, sec=None, min=None, hour=None, day=None, month=None, year=None, - *args, **kwargs -): - """ - Call a callback at a given in-game time. - - Args: - callback (function): The callback function that will be called. Note - that the callback must be a module-level function, since the script will - be persistent. The callable should be on form `callable(*args, **kwargs)` - where args/kwargs are passed into this schedule. - repeat (bool, optional): Defines if the callback should be called regularly - at the specified time. - sec (int or None): Number of absolute game seconds at which to run repeat. - min (int or None): Number of absolute minutes. - hour (int or None): Number of absolute hours. - day (int or None): Number of absolute days. - month (int or None): Number of absolute months. - year (int or None): Number of absolute years. - *args, **kwargs: Will be passed into the callable. These must be possible - to store in Attributes on the generated scheduling Script. - - Returns: - Script: The created Script handling the scheduling. - - Examples: - :: - - schedule(func, min=5, sec=0) # Will call 5 minutes past the next (in-game) hour. - schedule(func, hour=2, min=30, sec=0) # Will call the next (in-game) day at 02:30. - - """ - seconds = real_seconds_until(sec=sec, min=min, hour=hour, day=day, month=month, year=year) - script = create_script( - "evennia.utils.gametime.TimeScript", - key="TimeScript", - desc="A gametime-sensitive script", - interval=seconds, - start_delay=True, - repeats=-1 if repeat else 1, - ) - script.db.callback = callback - script.db.gametime = { - "sec": sec, - "min": min, - "hour": hour, - "day": day, - "month": month, - "year": year, - } - script.db.schedule_args = args - script.db.schedule_kwargs = kwargs - return script
- - -
[docs]def reset_gametime(): - """ - Resets the game time to make it start from the current time. Note that - the epoch set by `settings.TIME_GAME_EPOCH` will still apply. - - """ - global GAME_TIME_OFFSET - GAME_TIME_OFFSET = runtime() - ServerConfig.objects.conf("gametime_offset", GAME_TIME_OFFSET)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/idmapper/manager.html b/docs/0.9.5/_modules/evennia/utils/idmapper/manager.html deleted file mode 100644 index 11b3e1df44..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/idmapper/manager.html +++ /dev/null @@ -1,138 +0,0 @@ - - - - - - - - evennia.utils.idmapper.manager — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.utils.idmapper.manager

-"""
-IDmapper extension to the default manager.
-"""
-from django.db.models.manager import Manager
-
-
-
[docs]class SharedMemoryManager(Manager): - # TODO: improve on this implementation - # We need a way to handle reverse lookups so that this model can - # still use the singleton cache, but the active model isn't required - # to be a SharedMemoryModel. -
[docs] def get(self, *args, **kwargs): - """ - Data entity lookup. - """ - items = list(kwargs) - inst = None - if len(items) == 1: - # CL: support __exact - key = items[0] - if key.endswith("__exact"): - key = key[: -len("__exact")] - if key in ("pk", self.model._meta.pk.attname): - try: - inst = self.model.get_cached_instance(kwargs[items[0]]) - # we got the item from cache, but if this is a fk, check it's ours - if getattr(inst, str(self.field).split(".")[-1]) != self.instance: - inst = None - except Exception: - pass - if inst is None: - inst = super().get(*args, **kwargs) - return inst
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/idmapper/models.html b/docs/0.9.5/_modules/evennia/utils/idmapper/models.html deleted file mode 100644 index 4041f4e9e5..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/idmapper/models.html +++ /dev/null @@ -1,782 +0,0 @@ - - - - - - - - evennia.utils.idmapper.models — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.utils.idmapper.models

-"""
-Django ID mapper
-
-Modified for Evennia by making sure that no model references
-leave caching unexpectedly (no use of WeakRefs).
-
-Also adds `cache_size()` for monitoring the size of the cache.
-"""
-
-import os
-import threading
-import gc
-import time
-from weakref import WeakValueDictionary
-from twisted.internet.reactor import callFromThread
-from django.core.exceptions import ObjectDoesNotExist, FieldError
-from django.db.models.signals import post_save
-from django.db.models.base import Model, ModelBase
-from django.db.models.signals import pre_delete, post_migrate
-from django.db.utils import DatabaseError
-from evennia.utils import logger
-from evennia.utils.utils import dbref, get_evennia_pids, to_str
-
-from .manager import SharedMemoryManager
-
-AUTO_FLUSH_MIN_INTERVAL = 60.0 * 5  # at least 5 mins between cache flushes
-
-_GA = object.__getattribute__
-_SA = object.__setattr__
-_DA = object.__delattr__
-_MONITOR_HANDLER = None
-
-# References to db-updated objects are stored here so the
-# main process can be informed to re-cache itself.
-PROC_MODIFIED_COUNT = 0
-PROC_MODIFIED_OBJS = WeakValueDictionary()
-
-# get info about the current process and thread; determine if our
-# current pid is different from the server PID (i.e.  # if we are in a
-# subprocess or not)
-_SELF_PID = os.getpid()
-_SERVER_PID, _PORTAL_PID = get_evennia_pids()
-_IS_SUBPROCESS = (_SERVER_PID and _PORTAL_PID) and _SELF_PID not in (_SERVER_PID, _PORTAL_PID)
-_IS_MAIN_THREAD = threading.currentThread().getName() == "MainThread"
-
-
-
[docs]class SharedMemoryModelBase(ModelBase): - # CL: upstream had a __new__ method that skipped ModelBase's __new__ if - # SharedMemoryModelBase was not in the model class's ancestors. It's not - # clear what was the intended purpose, but skipping ModelBase.__new__ - # broke things; in particular, default manager inheritance. - - def __call__(cls, *args, **kwargs): - """ - this method will either create an instance (by calling the default implementation) - or try to retrieve one from the class-wide cache by inferring the pk value from - `args` and `kwargs`. If instance caching is enabled for this class, the cache is - populated whenever possible (ie when it is possible to infer the pk value). - - """ - - def new_instance(): - return super(SharedMemoryModelBase, cls).__call__(*args, **kwargs) - - instance_key = cls._get_cache_key(args, kwargs) - # depending on the arguments, we might not be able to infer the PK, so in that case we - # create a new instance - if instance_key is None: - return new_instance() - cached_instance = cls.get_cached_instance(instance_key) - if cached_instance is None: - cached_instance = new_instance() - cls.cache_instance(cached_instance, new=True) - return cached_instance - - def _prepare(cls): - """ - Prepare the cache, making sure that proxies of the same db base - share the same cache. - - """ - # the dbmodel is either the proxy base or ourselves - dbmodel = cls._meta.concrete_model if cls._meta.proxy else cls - cls.__dbclass__ = dbmodel - if not hasattr(dbmodel, "__instance_cache__"): - # we store __instance_cache__ only on the dbmodel base - dbmodel.__instance_cache__ = {} - super()._prepare() - - def __new__(cls, name, bases, attrs): - """ - Field shortcut creation: - - Takes field names `db_*` and creates property wrappers named - without the `db_` prefix. So db_key -> key - - This wrapper happens on the class level, so there is no - overhead when creating objects. If a class already has a - wrapper of the given name, the automatic creation is skipped. - - Notes: - Remember to document this auto-wrapping in the class - header, this could seem very much like magic to the user - otherwise. - """ - - attrs["typename"] = cls.__name__ - attrs["path"] = "%s.%s" % (attrs["__module__"], name) - attrs["_is_deleted"] = False - - # set up the typeclass handling only if a variable _is_typeclass is set on the class - def create_wrapper(cls, fieldname, wrappername, editable=True, foreignkey=False): - "Helper method to create property wrappers with unique names (must be in separate call)" - - def _get(cls, fname): - "Wrapper for getting database field" - if _GA(cls, "_is_deleted"): - raise ObjectDoesNotExist( - "Cannot access %s: Hosting object was already deleted." % fname - ) - return _GA(cls, fieldname) - - def _get_foreign(cls, fname): - "Wrapper for returning foreignkey fields" - if _GA(cls, "_is_deleted"): - raise ObjectDoesNotExist( - "Cannot access %s: Hosting object was already deleted." % fname - ) - return _GA(cls, fieldname) - - def _set_nonedit(cls, fname, value): - "Wrapper for blocking editing of field" - raise FieldError("Field %s cannot be edited." % fname) - - def _set(cls, fname, value): - "Wrapper for setting database field" - if _GA(cls, "_is_deleted"): - raise ObjectDoesNotExist( - "Cannot set %s to %s: Hosting object was already deleted!" % (fname, value) - ) - _SA(cls, fname, value) - # only use explicit update_fields in save if we actually have a - # primary key assigned already (won't be set when first creating object) - update_fields = ( - [fname] if _GA(cls, "_get_pk_val")(_GA(cls, "_meta")) is not None else None - ) - _GA(cls, "save")(update_fields=update_fields) - - def _set_foreign(cls, fname, value): - "Setter only used on foreign key relations, allows setting with #dbref" - if _GA(cls, "_is_deleted"): - raise ObjectDoesNotExist( - "Cannot set %s to %s: Hosting object was already deleted!" % (fname, value) - ) - if isinstance(value, (str, int)): - value = to_str(value) - if value.isdigit() or value.startswith("#"): - # we also allow setting using dbrefs, if so we try to load the matching - # object. (we assume the object is of the same type as the class holding - # the field, if not a custom handler must be used for that field) - dbid = dbref(value, reqhash=False) - if dbid: - model = _GA(cls, "_meta").get_field(fname).model - try: - value = model._default_manager.get(id=dbid) - except ObjectDoesNotExist: - # maybe it is just a name that happens to look like a dbid - pass - _SA(cls, fname, value) - # only use explicit update_fields in save if we actually have a - # primary key assigned already (won't be set when first creating object) - update_fields = ( - [fname] if _GA(cls, "_get_pk_val")(_GA(cls, "_meta")) is not None else None - ) - _GA(cls, "save")(update_fields=update_fields) - - def _del_nonedit(cls, fname): - "wrapper for not allowing deletion" - raise FieldError("Field %s cannot be edited." % fname) - - def _del(cls, fname): - "Wrapper for clearing database field - sets it to None" - _SA(cls, fname, None) - update_fields = ( - [fname] if _GA(cls, "_get_pk_val")(_GA(cls, "_meta")) is not None else None - ) - _GA(cls, "save")(update_fields=update_fields) - - # wrapper factories - if not editable: - - def fget(cls): - return _get(cls, fieldname) - - def fset(cls, val): - return _set_nonedit(cls, fieldname, val) - - elif foreignkey: - - def fget(cls): - return _get_foreign(cls, fieldname) - - def fset(cls, val): - return _set_foreign(cls, fieldname, val) - - else: - - def fget(cls): - return _get(cls, fieldname) - - def fset(cls, val): - return _set(cls, fieldname, val) - - def fdel(cls): - return _del(cls, fieldname) if editable else _del_nonedit(cls, fieldname) - - # set docstrings for auto-doc - fget.__doc__ = "A wrapper for getting database field `%s`." % fieldname - fset.__doc__ = "A wrapper for setting (and saving) database field `%s`." % fieldname - fdel.__doc__ = "A wrapper for deleting database field `%s`." % fieldname - # assigning - attrs[wrappername] = property(fget, fset, fdel) - # type(cls).__setattr__(cls, wrappername, property(fget, fset, fdel))#, doc)) - - # exclude some models that should not auto-create wrapper fields - if cls.__name__ in ("ServerConfig", "TypeNick"): - return - # dynamically create the wrapper properties for all fields not already handled - # (manytomanyfields are always handlers) - for fieldname, field in ( - (fname, field) - for fname, field in list(attrs.items()) - if fname.startswith("db_") and type(field).__name__ != "ManyToManyField" - ): - foreignkey = type(field).__name__ == "ForeignKey" - wrappername = "dbid" if fieldname == "id" else fieldname.replace("db_", "", 1) - if wrappername not in attrs: - # makes sure not to overload manually created wrappers on the model - create_wrapper( - cls, fieldname, wrappername, editable=field.editable, foreignkey=foreignkey - ) - - return super().__new__(cls, name, bases, attrs)
- - -
[docs]class SharedMemoryModel(Model, metaclass=SharedMemoryModelBase): - """ - Base class for idmapped objects. Inherit from `this`. - """ - - objects = SharedMemoryManager() - -
[docs] class Meta(object): - abstract = True
- - @classmethod - def _get_cache_key(cls, args, kwargs): - """ - This method is used by the caching subsystem to infer the PK - value from the constructor arguments. It is used to decide if - an instance has to be built or is already in the cache. - - """ - result = None - # Quick hack for my composites work for now. - if hasattr(cls._meta, "pks"): - pk = cls._meta.pks[0] - else: - pk = cls._meta.pk - # get the index of the pk in the class fields. this should be calculated *once*, but isn't - # atm - pk_position = cls._meta.fields.index(pk) - if len(args) > pk_position: - # if it's in the args, we can get it easily by index - result = args[pk_position] - elif pk.attname in kwargs: - # retrieve the pk value. Note that we use attname instead of name, to handle the case - # where the pk is a a ForeignKey. - result = kwargs[pk.attname] - elif pk.name != pk.attname and pk.name in kwargs: - # ok we couldn't find the value, but maybe it's a FK and we can find the corresponding - # object instead - result = kwargs[pk.name] - - if result is not None and isinstance(result, Model): - # if the pk value happens to be a model instance (which can happen wich a FK), we'd - # rather use its own pk as the key - result = result._get_pk_val() - return result - -
[docs] @classmethod - def get_cached_instance(cls, id): - """ - Method to retrieve a cached instance by pk value. Returns None - when not found (which will always be the case when caching is - disabled for this class). Please note that the lookup will be - done even when instance caching is disabled. - - """ - return cls.__dbclass__.__instance_cache__.get(id)
- -
[docs] @classmethod - def cache_instance(cls, instance, new=False): - """ - Method to store an instance in the cache. - - Args: - instance (Class instance): the instance to cache. - new (bool, optional): this is the first time this instance is - cached (i.e. this is not an update operation like after a - db save). - - """ - pk = instance._get_pk_val() - if pk is not None: - cls.__dbclass__.__instance_cache__[pk] = instance - if new: - try: - # trigger the at_init hook only - # at first initialization - instance.at_init() - except AttributeError: - # The at_init hook is not assigned to all entities - pass
- -
[docs] @classmethod - def get_all_cached_instances(cls): - """ - Return the objects so far cached by idmapper for this class. - - """ - return list(cls.__dbclass__.__instance_cache__.values())
- - @classmethod - def _flush_cached_by_key(cls, key, force=True): - """ - Remove the cached reference. - - """ - try: - if force or cls.at_idmapper_flush(): - del cls.__dbclass__.__instance_cache__[key] - else: - cls._dbclass__.__instance_cache__[key].refresh_from_db() - except KeyError: - # No need to remove if cache doesn't contain it already - pass - -
[docs] @classmethod - def flush_cached_instance(cls, instance, force=True): - """ - Method to flush an instance from the cache. The instance will - always be flushed from the cache, since this is most likely - called from delete(), and we want to make sure we don't cache - dead objects. - - """ - cls._flush_cached_by_key(instance._get_pk_val(), force=force)
- - # flush_cached_instance = classmethod(flush_cached_instance) - -
[docs] @classmethod - def flush_instance_cache(cls, force=False): - """ - This will clean safe objects from the cache. Use `force` - keyword to remove all objects, safe or not. - - """ - if force: - cls.__dbclass__.__instance_cache__ = {} - else: - cls.__dbclass__.__instance_cache__ = dict( - (key, obj) - for key, obj in cls.__dbclass__.__instance_cache__.items() - if not obj.at_idmapper_flush() - )
- - # flush_instance_cache = classmethod(flush_instance_cache) - - # per-instance methods - - def __eq__(self, other): - return super().__eq__(other) - - def __hash__(self): - # this is required to maintain hashing - return super().__hash__() - -
[docs] def at_idmapper_flush(self): - """ - This is called when the idmapper cache is flushed and - allows customized actions when this happens. - - Returns: - do_flush (bool): If True, flush this object as normal. If - False, don't flush and expect this object to handle - the flushing on its own. - """ - return True
- -
[docs] def flush_from_cache(self, force=False): - """ - Flush this instance from the instance cache. Use - `force` to override the result of at_idmapper_flush() for the object. - - """ - pk = self._get_pk_val() - if pk: - if force or self.at_idmapper_flush(): - self.__class__.__dbclass__.__instance_cache__.pop(pk, None)
- -
[docs] def delete(self, *args, **kwargs): - """ - Delete the object, clearing cache. - - """ - self.flush_from_cache() - self._is_deleted = True - super().delete(*args, **kwargs)
- -
[docs] def save(self, *args, **kwargs): - """ - Central database save operation. - - Notes: - Arguments as per Django documentation. - Calls `self.at_<fieldname>_postsave(new)` - (this is a wrapper set by oobhandler: - self._oob_at_<fieldname>_postsave()) - - """ - global _MONITOR_HANDLER - if not _MONITOR_HANDLER: - from evennia.scripts.monitorhandler import MONITOR_HANDLER as _MONITOR_HANDLER - - if _IS_SUBPROCESS: - # we keep a store of objects modified in subprocesses so - # we know to update their caches in the central process - global PROC_MODIFIED_COUNT, PROC_MODIFIED_OBJS - PROC_MODIFIED_COUNT += 1 - PROC_MODIFIED_OBJS[PROC_MODIFIED_COUNT] = self - - if _IS_MAIN_THREAD: - # in main thread - normal operation - try: - super().save(*args, **kwargs) - except DatabaseError: - # we handle the 'update_fields did not update any rows' error that - # may happen due to timing issues with attributes - ufields_removed = kwargs.pop("update_fields", None) - if ufields_removed: - super().save(*args, **kwargs) - else: - raise - else: - # in another thread; make sure to save in reactor thread - def _save_callback(cls, *args, **kwargs): - super().save(*args, **kwargs) - - callFromThread(_save_callback, self, *args, **kwargs) - - if not self.pk: - # this can happen if some of the startup methods immediately - # delete the object (an example are Scripts that start and die immediately) - return - - # update field-update hooks and eventual OOB watchers - new = False - if "update_fields" in kwargs and kwargs["update_fields"]: - # get field objects from their names - update_fields = ( - self._meta.get_field(fieldname) for fieldname in kwargs.get("update_fields") - ) - else: - # meta.fields are already field objects; get them all - new = True - update_fields = self._meta.fields - for field in update_fields: - fieldname = field.name - # trigger eventual monitors - _MONITOR_HANDLER.at_update(self, fieldname) - # if a hook is defined it must be named exactly on this form - hookname = "at_%s_postsave" % fieldname - if hasattr(self, hookname) and callable(_GA(self, hookname)): - _GA(self, hookname)(new) - - # # if a trackerhandler is set on this object, update it with the - # # fieldname and the new value - # fieldtracker = "_oob_at_%s_postsave" % fieldname - # if hasattr(self, fieldtracker): - # _GA(self, fieldtracker)(fieldname) - pass
- - -
[docs]class WeakSharedMemoryModelBase(SharedMemoryModelBase): - """ - Uses a WeakValue dictionary for caching instead of a regular one. - - """ - - def _prepare(cls): - super()._prepare() - cls.__dbclass__.__instance_cache__ = WeakValueDictionary()
- - -
[docs]class WeakSharedMemoryModel(SharedMemoryModel, metaclass=WeakSharedMemoryModelBase): - """ - Uses a WeakValue dictionary for caching instead of a regular one - - """ - -
[docs] class Meta(object): - abstract = True
- - -
[docs]def flush_cache(**kwargs): - """ - Flush idmapper cache. When doing so the cache will fire the - at_idmapper_flush hook to allow the object to optionally handle - its own flushing. - - Uses a signal so we make sure to catch cascades. - - """ - - def class_hierarchy(clslist): - """Recursively yield a class hierarchy""" - for cls in clslist: - subclass_list = cls.__subclasses__() - if subclass_list: - for subcls in class_hierarchy(subclass_list): - yield subcls - else: - yield cls - - for cls in class_hierarchy([SharedMemoryModel]): - cls.flush_instance_cache() - # run the python garbage collector - return gc.collect()
- - -# request_finished.connect(flush_cache) -post_migrate.connect(flush_cache) - - -
[docs]def flush_cached_instance(sender, instance, **kwargs): - """ - Flush the idmapper cache only for a given instance. - - """ - # XXX: Is this the best way to make sure we can flush? - if not hasattr(instance, "flush_cached_instance"): - return - sender.flush_cached_instance(instance, force=True)
- - -pre_delete.connect(flush_cached_instance) - - -
[docs]def update_cached_instance(sender, instance, **kwargs): - """ - Re-cache the given instance in the idmapper cache. - - """ - if not hasattr(instance, "cache_instance"): - return - sender.cache_instance(instance)
- - -post_save.connect(update_cached_instance) - - -LAST_FLUSH = None - - -
[docs]def conditional_flush(max_rmem, force=False): - """ - Flush the cache if the estimated memory usage exceeds `max_rmem`. - - The flusher has a timeout to avoid flushing over and over - in particular situations (this means that for some setups - the memory usage will exceed the requirement and a server with - more memory is probably required for the given game). - - Args: - max_rmem (int): memory-usage estimation-treshold after which - cache is flushed. - force (bool, optional): forces a flush, regardless of timeout. - Defaults to `False`. - - """ - global LAST_FLUSH - - def mem2cachesize(desired_rmem): - """ - Estimate the size of the idmapper cache based on the memory - desired. This is used to optionally cap the cache size. - - desired_rmem - memory in MB (minimum 50MB) - - The formula is empirically estimated from usage tests (Linux) - and is - Ncache = RMEM - 35.0 / 0.0157 - where RMEM is given in MB and Ncache is the size of the cache - for this memory usage. VMEM tends to be about 100MB higher - than RMEM for large memory usage. - """ - vmem = max(desired_rmem, 50.0) - Ncache = int(abs(float(vmem) - 35.0) / 0.0157) - return Ncache - - if not max_rmem: - # auto-flush is disabled - return - - now = time.time() - if not LAST_FLUSH: - # server is just starting - LAST_FLUSH = now - return - - if ((now - LAST_FLUSH) < AUTO_FLUSH_MIN_INTERVAL) and not force: - # too soon after last flush. - logger.log_warn( - "Warning: Idmapper flush called more than " - "once in %s min interval. Check memory usage." % (AUTO_FLUSH_MIN_INTERVAL / 60.0) - ) - return - - if os.name == "nt": - # we can't look for mem info in Windows at the moment - return - - # check actual memory usage - Ncache_max = mem2cachesize(max_rmem) - Ncache, _ = cache_size() - actual_rmem = ( - float(os.popen("ps -p %d -o %s | tail -1" % (os.getpid(), "rss")).read()) / 1000.0 - ) # resident memory - - if Ncache >= Ncache_max and actual_rmem > max_rmem * 0.9: - # flush cache when number of objects in cache is big enough and our - # actual memory use is within 10% of our set max - flush_cache() - LAST_FLUSH = now
- - -
[docs]def cache_size(mb=True): - """ - Calculate statistics about the cache. - - Note: we cannot get reliable memory statistics from the cache - - whereas we could do `getsizof` each object in cache, the result is - highly imprecise and for a large number of objects the result is - many times larger than the actual memory usage of the entire server; - Python is clearly reusing memory behind the scenes that we cannot - catch in an easy way here. Ideas are appreciated. /Griatch - - Returns: - total_num, {objclass:total_num, ...} - - """ - numtotal = [0] # use mutable to keep reference through recursion - classdict = {} - - def get_recurse(submodels): - for submodel in submodels: - subclasses = submodel.__subclasses__() - if not subclasses: - num = len(submodel.get_all_cached_instances()) - numtotal[0] += num - classdict[submodel.__dbclass__.__name__] = num - else: - get_recurse(subclasses) - - get_recurse(SharedMemoryModel.__subclasses__()) - return numtotal[0], classdict
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/idmapper/tests.html b/docs/0.9.5/_modules/evennia/utils/idmapper/tests.html deleted file mode 100644 index 16933073d6..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/idmapper/tests.html +++ /dev/null @@ -1,183 +0,0 @@ - - - - - - - - evennia.utils.idmapper.tests — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.utils.idmapper.tests

-from django.test import TestCase
-
-from .models import SharedMemoryModel
-from django.db import models
-
-
-
[docs]class Category(SharedMemoryModel): - name = models.CharField(max_length=32)
- - -
[docs]class RegularCategory(models.Model): - name = models.CharField(max_length=32)
- - -
[docs]class Article(SharedMemoryModel): - name = models.CharField(max_length=32) - category = models.ForeignKey(Category, on_delete=models.CASCADE) - category2 = models.ForeignKey(RegularCategory, on_delete=models.CASCADE)
- - -
[docs]class RegularArticle(models.Model): - name = models.CharField(max_length=32) - category = models.ForeignKey(Category, on_delete=models.CASCADE) - category2 = models.ForeignKey(RegularCategory, on_delete=models.CASCADE)
- - -
[docs]class SharedMemorysTest(TestCase): - # TODO: test for cross model relation (singleton to regular) - -
[docs] def setUp(self): - super().setUp() - n = 0 - category = Category.objects.create(name="Category %d" % (n,)) - regcategory = RegularCategory.objects.create(name="Category %d" % (n,)) - - for n in range(0, 10): - Article.objects.create( - name="Article %d" % (n,), category=category, category2=regcategory - ) - RegularArticle.objects.create( - name="Article %d" % (n,), category=category, category2=regcategory - )
- -
[docs] def testSharedMemoryReferences(self): - article_list = Article.objects.all().select_related("category") - last_article = article_list[0] - for article in article_list[1:]: - self.assertEqual(article.category is last_article.category, True) - last_article = article
- -
[docs] def testRegularReferences(self): - article_list = RegularArticle.objects.all().select_related("category") - last_article = article_list[0] - for article in article_list[1:]: - self.assertEqual(article.category2 is last_article.category2, False) - last_article = article
- -
[docs] def testMixedReferences(self): - article_list = RegularArticle.objects.all().select_related("category") - last_article = article_list[0] - for article in article_list[1:]: - self.assertEqual(article.category is last_article.category, True) - last_article = article
- - # article_list = Article.objects.all().select_related('category') - # last_article = article_list[0] - # for article in article_list[1:]: - # self.assertEquals(article.category2 is last_article.category2, False) - # last_article = article - -
[docs] def testObjectDeletion(self): - # This must execute first so its guaranteed to be in memory. - list(Article.objects.all().select_related("category")) - - article = Article.objects.all()[0:1].get() - pk = article.pk - article.delete() - self.assertEqual(pk not in Article.__instance_cache__, True)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/logger.html b/docs/0.9.5/_modules/evennia/utils/logger.html deleted file mode 100644 index 0871f2a231..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/logger.html +++ /dev/null @@ -1,701 +0,0 @@ - - - - - - - - evennia.utils.logger — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.utils.logger

-"""
-Logging facilities
-
-These are thin wrappers on top of Twisted's logging facilities; logs
-are all directed either to stdout (if Evennia is running in
-interactive mode) or to $GAME_DIR/server/logs.
-
-The log_file() function uses its own threading system to log to
-arbitrary files in $GAME_DIR/server/logs.
-
-Note: All logging functions have two aliases, log_type() and
-log_typemsg(). This is for historical, back-compatible reasons.
-
-"""
-
-
-import os
-import time
-from datetime import datetime
-from traceback import format_exc
-from twisted.python import log, logfile
-from twisted.python import util as twisted_util
-from twisted.internet.threads import deferToThread
-
-
-_LOGDIR = None
-_LOG_ROTATE_SIZE = None
-_TIMEZONE = None
-_CHANNEL_LOG_NUM_TAIL_LINES = None
-
-
-# logging overrides
-
-
-
[docs]def timeformat(when=None): - """ - This helper function will format the current time in the same - way as the twisted logger does, including time zone info. Only - difference from official logger is that we only use two digits - for the year and don't show timezone for CET times. - - Args: - when (int, optional): This is a time in POSIX seconds on the form - given by time.time(). If not given, this function will - use the current time. - - Returns: - timestring (str): A formatted string of the given time. - - """ - when = when if when else time.time() - - # time zone offset: UTC - the actual offset - tz_offset = datetime.utcfromtimestamp(when) - datetime.fromtimestamp(when) - tz_offset = tz_offset.days * 86400 + tz_offset.seconds - # correct given time to utc - when = datetime.utcfromtimestamp(when - tz_offset) - - if tz_offset == 0: - tz = "" - else: - tz_hour = abs(int(tz_offset // 3600)) - tz_mins = abs(int(tz_offset // 60 % 60)) - tz_sign = "-" if tz_offset >= 0 else "+" - tz = "%s%02d%s" % (tz_sign, tz_hour, (":%02d" % tz_mins if tz_mins else "")) - - return "%d-%02d-%02d %02d:%02d:%02d%s" % ( - when.year - 2000, - when.month, - when.day, - when.hour, - when.minute, - when.second, - tz, - )
- - -
[docs]class WeeklyLogFile(logfile.DailyLogFile): - """ - Log file that rotates once per week by default. Overrides key methods to change format. - - """ - -
[docs] def __init__(self, name, directory, defaultMode=None, day_rotation=7, max_size=1000000): - """ - Args: - name (str): Name of log file. - directory (str): Directory holding the file. - defaultMode (str): Permissions used to create file. Defaults to - current permissions of this file if it exists. - day_rotation (int): How often to rotate the file. - max_size (int): Max size of log file before rotation (regardless of - time). Defaults to 1M. - - """ - self.day_rotation = day_rotation - self.max_size = max_size - self.size = 0 - logfile.DailyLogFile.__init__(self, name, directory, defaultMode=defaultMode)
- - def _openFile(self): - logfile.DailyLogFile._openFile(self) - self.size = self._file.tell() - -
[docs] def shouldRotate(self): - """Rotate when the date has changed since last write""" - # all dates here are tuples (year, month, day) - now = self.toDate() - then = self.lastDate - return ( - now[0] > then[0] - or now[1] > then[1] - or now[2] > (then[2] + self.day_rotation) - or self.size >= self.max_size - )
- -
[docs] def suffix(self, tupledate): - """Return the suffix given a (year, month, day) tuple or unixtime. - Format changed to have 03 for march instead of 3 etc (retaining unix - file order) - - If we get duplicate suffixes in location (due to hitting size limit), - we append __1, __2 etc. - - Examples: - server.log.2020_01_29 - server.log.2020_01_29__1 - server.log.2020_01_29__2 - - """ - suffix = "" - copy_suffix = 0 - while True: - try: - suffix = "_".join(["{:02d}".format(part) for part in tupledate]) - except Exception: - # try taking a float unixtime - suffix = "_".join(["{:02d}".format(part) for part in self.toDate(tupledate)]) - - suffix += f"__{copy_suffix}" if copy_suffix else "" - - if os.path.exists(f"{self.path}.{suffix}"): - # Append a higher copy_suffix to try to break the tie (starting from 2) - copy_suffix += 1 - else: - break - return suffix
- -
[docs] def write(self, data): - """ - Write data to log file - - """ - logfile.BaseLogFile.write(self, data) - self.lastDate = max(self.lastDate, self.toDate()) - self.size += len(data)
- - -
[docs]class PortalLogObserver(log.FileLogObserver): - """ - Reformat logging - - """ - - timeFormat = None - prefix = " |Portal| " - -
[docs] def emit(self, eventDict): - """ - Copied from Twisted parent, to change logging output - - """ - text = log.textFromEventDict(eventDict) - if text is None: - return - - # timeStr = self.formatTime(eventDict["time"]) - timeStr = timeformat(eventDict["time"]) - fmtDict = {"text": text.replace("\n", "\n\t")} - - msgStr = log._safeFormat("%(text)s\n", fmtDict) - - twisted_util.untilConcludes(self.write, timeStr + "%s" % self.prefix + msgStr) - twisted_util.untilConcludes(self.flush)
- - -
[docs]class ServerLogObserver(PortalLogObserver): - prefix = " "
- - -
[docs]def log_msg(msg): - """ - Wrapper around log.msg call to catch any exceptions that might - occur in logging. If an exception is raised, we'll print to - stdout instead. - - Args: - msg: The message that was passed to log.msg - - """ - try: - log.msg(msg) - except Exception: - print("Exception raised while writing message to log. Original message: %s" % msg)
- - -
[docs]def log_trace(errmsg=None): - """ - Log a traceback to the log. This should be called from within an - exception. - - Args: - errmsg (str, optional): Adds an extra line with added info - at the end of the traceback in the log. - - """ - tracestring = format_exc() - try: - if tracestring: - for line in tracestring.splitlines(): - log.msg("[::] %s" % line) - if errmsg: - try: - errmsg = str(errmsg) - except Exception as e: - errmsg = str(e) - for line in errmsg.splitlines(): - log_msg("[EE] %s" % line) - except Exception: - log_msg("[EE] %s" % errmsg)
- - -log_tracemsg = log_trace - - -
[docs]def log_err(errmsg): - """ - Prints/logs an error message to the server log. - - Args: - errmsg (str): The message to be logged. - - """ - try: - errmsg = str(errmsg) - except Exception as e: - errmsg = str(e) - for line in errmsg.splitlines(): - log_msg("[EE] %s" % line)
- - # log.err('ERROR: %s' % (errmsg,)) - - -log_errmsg = log_err - - -
[docs]def log_server(servermsg): - """ - This is for the Portal to log captured Server stdout messages (it's - usually only used during startup, before Server log is open) - - """ - try: - servermsg = str(servermsg) - except Exception as e: - servermsg = str(e) - for line in servermsg.splitlines(): - log_msg("[Server] %s" % line)
- - -
[docs]def log_warn(warnmsg): - """ - Prints/logs any warnings that aren't critical but should be noted. - - Args: - warnmsg (str): The message to be logged. - - """ - try: - warnmsg = str(warnmsg) - except Exception as e: - warnmsg = str(e) - for line in warnmsg.splitlines(): - log_msg("[WW] %s" % line)
- - # log.msg('WARNING: %s' % (warnmsg,)) - - -log_warnmsg = log_warn - - -
[docs]def log_info(infomsg): - """ - Prints any generic debugging/informative info that should appear in the log. - - infomsg: (string) The message to be logged. - - """ - try: - infomsg = str(infomsg) - except Exception as e: - infomsg = str(e) - for line in infomsg.splitlines(): - log_msg("[..] %s" % line)
- - -log_infomsg = log_info - - -
[docs]def log_dep(depmsg): - """ - Prints a deprecation message. - - Args: - depmsg (str): The deprecation message to log. - - """ - try: - depmsg = str(depmsg) - except Exception as e: - depmsg = str(e) - for line in depmsg.splitlines(): - log_msg("[DP] %s" % line)
- - -log_depmsg = log_dep - - -
[docs]def log_sec(secmsg): - """ - Prints a security-related message. - - Args: - secmsg (str): The security message to log. - - """ - try: - secmsg = str(secmsg) - except Exception as e: - secmsg = str(e) - for line in secmsg.splitlines(): - log_msg("[SS] %s" % line)
- - -log_secmsg = log_sec - - -# Arbitrary file logger - - -
[docs]class EvenniaLogFile(logfile.LogFile): - """ - A rotating logfile based off Twisted's LogFile. It overrides - the LogFile's rotate method in order to append some of the last - lines of the previous log to the start of the new log, in order - to preserve a continuous chat history for channel log files. - - """ - - # we delay import of settings to keep logger module as free - # from django as possible. - global _CHANNEL_LOG_NUM_TAIL_LINES - if _CHANNEL_LOG_NUM_TAIL_LINES is None: - from django.conf import settings - - _CHANNEL_LOG_NUM_TAIL_LINES = settings.CHANNEL_LOG_NUM_TAIL_LINES - num_lines_to_append = _CHANNEL_LOG_NUM_TAIL_LINES - -
[docs] def rotate(self, num_lines_to_append=None): - """ - Rotates our log file and appends some number of lines from - the previous log to the start of the new one. - - """ - append_tail = (num_lines_to_append - if num_lines_to_append is not None - else self.num_lines_to_append) - if not append_tail: - logfile.LogFile.rotate(self) - return - lines = tail_log_file(self.path, 0, self.num_lines_to_append) - super().rotate() - for line in lines: - self.write(line)
- -
[docs] def seek(self, *args, **kwargs): - """ - Convenience method for accessing our _file attribute's seek method, - which is used in tail_log_function. - - Args: - *args: Same args as file.seek - **kwargs: Same kwargs as file.seek - - """ - return self._file.seek(*args, **kwargs)
- -
[docs] def readlines(self, *args, **kwargs): - """ - Convenience method for accessing our _file attribute's readlines method, - which is used in tail_log_function. - - Args: - *args: same args as file.readlines - **kwargs: same kwargs as file.readlines - - Returns: - lines (list): lines from our _file attribute. - - """ - lines = [] - for line in self._file.readlines(*args, **kwargs): - try: - lines.append(line.decode("utf-8")) - except UnicodeDecodeError: - try: - lines.append(str(line)) - except Exception: - lines.append("") - return lines
- - -_LOG_FILE_HANDLES = {} # holds open log handles -_LOG_FILE_HANDLE_COUNTS = {} -_LOG_FILE_HANDLE_RESET = 500 - - -def _open_log_file(filename): - """ - Helper to open the log file (always in the log dir) and cache its - handle. Will create a new file in the log dir if one didn't - exist. - - To avoid keeping the filehandle open indefinitely we reset it every - _LOG_FILE_HANDLE_RESET accesses. This may help resolve issues for very - long uptimes and heavy log use. - - """ - # we delay import of settings to keep logger module as free - # from django as possible. - global _LOG_FILE_HANDLES, _LOG_FILE_HANDLE_COUNTS, _LOGDIR, _LOG_ROTATE_SIZE - if not _LOGDIR: - from django.conf import settings - - _LOGDIR = settings.LOG_DIR - _LOG_ROTATE_SIZE = settings.CHANNEL_LOG_ROTATE_SIZE - - filename = os.path.join(_LOGDIR, filename) - if filename in _LOG_FILE_HANDLES: - _LOG_FILE_HANDLE_COUNTS[filename] += 1 - if _LOG_FILE_HANDLE_COUNTS[filename] > _LOG_FILE_HANDLE_RESET: - # close/refresh handle - _LOG_FILE_HANDLES[filename].close() - del _LOG_FILE_HANDLES[filename] - else: - # return cached handle - return _LOG_FILE_HANDLES[filename] - try: - filehandle = EvenniaLogFile.fromFullPath(filename, rotateLength=_LOG_ROTATE_SIZE) - # filehandle = open(filename, "a+") # append mode + reading - _LOG_FILE_HANDLES[filename] = filehandle - _LOG_FILE_HANDLE_COUNTS[filename] = 0 - return filehandle - except IOError: - log_trace() - return None - - -
[docs]def log_file(msg, filename="game.log"): - """ - Arbitrary file logger using threads. - - Args: - msg (str): String to append to logfile. - filename (str, optional): Defaults to 'game.log'. All logs - will appear in the logs directory and log entries will start - on new lines following datetime info. - - """ - - def callback(filehandle, msg): - """Writing to file and flushing result""" - msg = "\n%s [-] %s" % (timeformat(), msg.strip()) - filehandle.write(msg) - # since we don't close the handle, we need to flush - # manually or log file won't be written to until the - # write buffer is full. - filehandle.flush() - - def errback(failure): - """Catching errors to normal log""" - log_trace() - - # save to server/logs/ directory - filehandle = _open_log_file(filename) - if filehandle: - deferToThread(callback, filehandle, msg).addErrback(errback)
- - -
[docs]def log_file_exists(filename="game.log"): - """ - Determine if a log-file already exists. - - Args: - filename (str): The filename (within the log-dir). - - Returns: - bool: If the log file exists or not. - - """ - global _LOGDIR - if not _LOGDIR: - from django.conf import settings - _LOGDIR = settings.LOG_DIR - - filename = os.path.join(_LOGDIR, filename) - return os.path.exists(filename)
- - -
[docs]def rotate_log_file(filename="game.log", num_lines_to_append=None): - """ - Force-rotate a log-file, without - - Args: - filename (str): The log file, located in settings.LOG_DIR. - num_lines_to_append (int, optional): Include N number of - lines from previous file in new one. If `None`, use default. - Set to 0 to include no lines. - - """ - if log_file_exists(filename): - file_handle = _open_log_file(filename) - if file_handle: - file_handle.rotate(num_lines_to_append=num_lines_to_append)
- - -
[docs]def tail_log_file(filename, offset, nlines, callback=None): - """ - Return the tail of the log file. - - Args: - filename (str): The name of the log file, presumed to be in - the Evennia log dir. - offset (int): The line offset *from the end of the file* to start - reading from. 0 means to start at the latest entry. - nlines (int): How many lines to return, counting backwards - from the offset. If file is shorter, will get all lines. - callback (callable, optional): A function to manage the result of the - asynchronous file access. This will get a list of lines. If unset, - the tail will happen synchronously. - - Returns: - lines (deferred or list): This will be a deferred if `callable` is given, - otherwise it will be a list with The nline entries from the end of the file, or - all if the file is shorter than nlines. - - """ - - def seek_file(filehandle, offset, nlines, callback): - """step backwards in chunks and stop only when we have enough lines""" - lines_found = [] - buffer_size = 4098 - block_count = -1 - while len(lines_found) < (offset + nlines): - try: - # scan backwards in file, starting from the end - filehandle.seek(block_count * buffer_size, os.SEEK_END) - except IOError: - # file too small for this seek, take what we've got - filehandle.seek(0) - lines_found = filehandle.readlines() - break - lines_found = filehandle.readlines() - block_count -= 1 - # return the right number of lines - lines_found = lines_found[-nlines - offset: -offset if offset else None] - if callback: - callback(lines_found) - return None - else: - return lines_found - - def errback(failure): - """Catching errors to normal log""" - log_trace() - - filehandle = _open_log_file(filename) - if filehandle: - if callback: - return deferToThread(seek_file, filehandle, offset, nlines, callback).addErrback( - errback - ) - else: - return seek_file(filehandle, offset, nlines, callback) - else: - return None
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/optionclasses.html b/docs/0.9.5/_modules/evennia/utils/optionclasses.html deleted file mode 100644 index ec74740a4a..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/optionclasses.html +++ /dev/null @@ -1,428 +0,0 @@ - - - - - - - - evennia.utils.optionclasses — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.utils.optionclasses

-import datetime
-from evennia import logger
-from evennia.utils.ansi import strip_ansi
-from evennia.utils.validatorfuncs import _TZ_DICT
-from evennia.utils.utils import crop
-from evennia.utils import validatorfuncs
-
-
-
[docs]class BaseOption: - """ - Abstract Class to deal with encapsulating individual Options. An Option has - a name/key, a description to display in relevant commands and menus, and a - default value. It saves to the owner's Attributes using its Handler's save - category. - - Designed to be extremely overloadable as some options can be cantankerous. - - Properties: - valid: Shortcut to the loaded VALID_HANDLER. - validator_key (str): The key of the Validator this uses. - - """ - - def __str__(self): - return "<Option {key}: {value}>".format(key=self.key, value=crop(str(self.value), width=10)) - - def __repr__(self): - return str(self) - -
[docs] def __init__(self, handler, key, description, default): - """ - - Args: - handler (OptionHandler): The OptionHandler that 'owns' this Option. - key (str): The name this will be used for storage in a dictionary. - Must be unique per OptionHandler. - description (str): What this Option's text will show in commands and menus. - default: A default value for this Option. - - """ - self.handler = handler - self.key = key - self.default_value = default - self.description = description - - # Value Storage contains None until the Option is loaded. - self.value_storage = None - - # And it's not loaded until it's called upon to spit out its contents. - self.loaded = False
- - @property - def changed(self): - return self.value_storage != self.default_value - - @property - def default(self): - return self.default_value - - @property - def value(self): - if not self.loaded: - self.load() - if self.loaded: - return self.value_storage - else: - return self.default - - @value.setter - def value(self, value): - self.set(value) - -
[docs] def set(self, value, **kwargs): - """ - Takes user input and stores appropriately. This method allows for - passing extra instructions into the validator. - - Args: - value (str): The new value of this Option. - kwargs (any): Any kwargs will be passed into - `self.validate(value, **kwargs)` and `self.save(**kwargs)`. - - """ - final_value = self.validate(value, **kwargs) - self.value_storage = final_value - self.loaded = True - self.save(**kwargs)
- -
[docs] def load(self): - """ - Takes the provided save data, validates it, and gets this Option ready to use. - - Returns: - Boolean: Whether loading was successful. - - """ - loadfunc = self.handler.loadfunc - load_kwargs = self.handler.load_kwargs - - try: - self.value_storage = self.deserialize( - loadfunc(self.key, default=self.default_value, **load_kwargs) - ) - except Exception: - logger.log_trace() - return False - self.loaded = True - return True
- -
[docs] def save(self, **kwargs): - """ - Stores the current value using `.handler.save_handler(self.key, value, **kwargs)` - where `kwargs` are a combination of those passed into this function and - the ones specified by the `OptionHandler`. - - Keyword Args: - any (any): Not used by default. These are passed in from self.set - and allows the option to let the caller customize saving by - overriding or extend the default save kwargs - - """ - value = self.serialize() - save_kwargs = {**self.handler.save_kwargs, **kwargs} - savefunc = self.handler.savefunc - savefunc(self.key, value=value, **save_kwargs)
- -
[docs] def deserialize(self, save_data): - """ - Perform sanity-checking on the save data as it is loaded from storage. - This isn't the same as what validator-functions provide (those work on - user input). For example, save data might be a timedelta or a list or - some other object. - - Args: - save_data: The data to check. - - Returns: - any (any): Whatever the Option needs to track, like a string or a - datetime. The display hook is responsible for what is actually - displayed to user. - """ - return save_data
- -
[docs] def serialize(self): - """ - Serializes the save data for Attribute storage. - - Returns: - any (any): Whatever is best for storage. - - """ - return self.value_storage
- -
[docs] def validate(self, value, **kwargs): - """ - Validate user input, which is presumed to be a string. - - Args: - value (str): User input. - account (AccountDB): The Account that is performing the validation. - This is necessary because of other settings which may affect the - check, such as an Account's timezone affecting how their datetime - entries are processed. - Returns: - any (any): The results of the validation. - Raises: - ValidationError: If input value failed validation. - - """ - return validatorfuncs.text(value, option_key=self.key, **kwargs)
- -
[docs] def display(self, **kwargs): - """ - Renders the Option's value as something pretty to look at. - - Keyword Args: - any (any): These are options passed by the caller to potentially - customize display dynamically. - - Returns: - str: How the stored value should be projected to users (e.g. a raw - timedelta is pretty ugly). - - """ - return self.value
- - -# Option classes - - -
[docs]class Text(BaseOption): -
[docs] def deserialize(self, save_data): - got_data = str(save_data) - if not got_data: - raise ValueError(f"{self.key} expected Text data, got '{save_data}'") - return got_data
- - -
[docs]class Email(BaseOption): -
[docs] def validate(self, value, **kwargs): - return validatorfuncs.email(value, option_key=self.key, **kwargs)
- -
[docs] def deserialize(self, save_data): - got_data = str(save_data) - if not got_data: - raise ValueError(f"{self.key} expected String data, got '{save_data}'") - return got_data
- - -
[docs]class Boolean(BaseOption): -
[docs] def validate(self, value, **kwargs): - return validatorfuncs.boolean(value, option_key=self.key, **kwargs)
- -
[docs] def display(self, **kwargs): - if self.value: - return "1 - On/True" - return "0 - Off/False"
- -
[docs] def serialize(self): - return self.value
- -
[docs] def deserialize(self, save_data): - if not isinstance(save_data, bool): - raise ValueError(f"{self.key} expected Boolean, got '{save_data}'") - return save_data
- - -
[docs]class Color(BaseOption): -
[docs] def validate(self, value, **kwargs): - return validatorfuncs.color(value, option_key=self.key, **kwargs)
- -
[docs] def display(self, **kwargs): - return f"{self.value} - |{self.value}this|n"
- -
[docs] def deserialize(self, save_data): - if not save_data or len(strip_ansi(f"|{save_data}|n")) > 0: - raise ValueError(f"{self.key} expected Color Code, got '{save_data}'") - return save_data
- - -
[docs]class Timezone(BaseOption): -
[docs] def validate(self, value, **kwargs): - return validatorfuncs.timezone(value, option_key=self.key, **kwargs)
- - @property - def default(self): - return _TZ_DICT[self.default_value] - -
[docs] def deserialize(self, save_data): - if save_data not in _TZ_DICT: - raise ValueError(f"{self.key} expected Timezone Data, got '{save_data}'") - return _TZ_DICT[save_data]
- -
[docs] def serialize(self): - return str(self.value_storage)
- - -
[docs]class UnsignedInteger(BaseOption): - validator_key = "unsigned_integer" - -
[docs] def validate(self, value, **kwargs): - return validatorfuncs.unsigned_integer(value, option_key=self.key, **kwargs)
- -
[docs] def deserialize(self, save_data): - if isinstance(save_data, int) and save_data >= 0: - return save_data - raise ValueError(f"{self.key} expected Whole Number 0+, got '{save_data}'")
- - -
[docs]class SignedInteger(BaseOption): -
[docs] def validate(self, value, **kwargs): - return validatorfuncs.signed_integer(value, option_key=self.key, **kwargs)
- -
[docs] def deserialize(self, save_data): - if isinstance(save_data, int): - return save_data - raise ValueError(f"{self.key} expected Whole Number, got '{save_data}'")
- - -
[docs]class PositiveInteger(BaseOption): -
[docs] def validate(self, value, **kwargs): - return validatorfuncs.positive_integer(value, option_key=self.key, **kwargs)
- -
[docs] def deserialize(self, save_data): - if isinstance(save_data, int) and save_data > 0: - return save_data - raise ValueError(f"{self.key} expected Whole Number 1+, got '{save_data}'")
- - -
[docs]class Duration(BaseOption): -
[docs] def validate(self, value, **kwargs): - return validatorfuncs.duration(value, option_key=self.key, **kwargs)
- -
[docs] def deserialize(self, save_data): - if isinstance(save_data, int): - return datetime.timedelta(0, save_data, 0, 0, 0, 0, 0) - raise ValueError(f"{self.key} expected Timedelta in seconds, got '{save_data}'")
- -
[docs] def serialize(self): - return self.value_storage.seconds
- - -
[docs]class Datetime(BaseOption): -
[docs] def validate(self, value, **kwargs): - return validatorfuncs.datetime(value, option_key=self.key, **kwargs)
- -
[docs] def deserialize(self, save_data): - if isinstance(save_data, int): - return datetime.datetime.utcfromtimestamp(save_data) - raise ValueError(f"{self.key} expected UTC Datetime in EPOCH format, got '{save_data}'")
- -
[docs] def serialize(self): - return int(self.value_storage.strftime("%s"))
- - -
[docs]class Future(Datetime): -
[docs] def validate(self, value, **kwargs): - return validatorfuncs.future(value, option_key=self.key, **kwargs)
- - -
[docs]class Lock(Text): -
[docs] def validate(self, value, **kwargs): - return validatorfuncs.lock(value, option_key=self.key, **kwargs)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/optionhandler.html b/docs/0.9.5/_modules/evennia/utils/optionhandler.html deleted file mode 100644 index 11dcce0860..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/optionhandler.html +++ /dev/null @@ -1,289 +0,0 @@ - - - - - - - - evennia.utils.optionhandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.utils.optionhandler

-from evennia.utils.utils import string_partial_matching
-from evennia.utils.containers import OPTION_CLASSES
-from django.utils.translation import gettext as _
-
-_GA = object.__getattribute__
-_SA = object.__setattr__
-
-
-
[docs]class InMemorySaveHandler: - """ - Fallback SaveHandler, implementing a minimum of the required save mechanism - and storing data in memory. - - """ - -
[docs] def __init__(self): - self.storage = {}
- -
[docs] def add(self, key, value=None, **kwargs): - self.storage[key] = value
- -
[docs] def get(self, key, default=None, **kwargs): - return self.storage.get(key, default)
- - -
[docs]class OptionHandler: - """ - This is a generic Option handler. Retrieve options either as properties on - this handler or by using the .get method. - - This is used for Account.options but it could be used by Scripts or Objects - just as easily. All it needs to be provided is an options_dict. - - """ - -
[docs] def __init__( - self, - obj, - options_dict=None, - savefunc=None, - loadfunc=None, - save_kwargs=None, - load_kwargs=None, - ): - """ - Initialize an OptionHandler. - - Args: - obj (object): The object this handler sits on. This is usually a TypedObject. - options_dict (dict): A dictionary of option keys, where the values - are options. The format of those tuples is: ('key', "Description to - show", 'option_type', <default value>) - savefunc (callable): A callable for all options to call when saving itself. - It will be called as `savefunc(key, value, **save_kwargs)`. A common one - to pass would be AttributeHandler.add. - loadfunc (callable): A callable for all options to call when loading data into - itself. It will be called as `loadfunc(key, default=default, **load_kwargs)`. - A common one to pass would be AttributeHandler.get. - save_kwargs (any): Optional extra kwargs to pass into `savefunc` above. - load_kwargs (any): Optional extra kwargs to pass into `loadfunc` above. - - Notes: - Both loadfunc and savefunc must be specified. If only one is given, the other - will be ignored and in-memory storage will be used. - - """ - self.obj = obj - self.options_dict = {} if options_dict is None else options_dict - - if not savefunc and loadfunc: - self._in_memory_handler = InMemorySaveHandler() - savefunc = InMemorySaveHandler.add - loadfunc = InMemorySaveHandler.get - self.savefunc = savefunc - self.loadfunc = loadfunc - self.save_kwargs = {} if save_kwargs is None else save_kwargs - self.load_kwargs = {} if load_kwargs is None else load_kwargs - - # This dictionary stores the in-memory Options objects by their key for - # quick lookup. - self.options = {}
- - def __getattr__(self, key): - """ - Allow for obj.options.key - - """ - return self.get(key) - - def __setattr__(self, key, value): - """ - Allow for obj.options.key = value - - But we must be careful to avoid infinite loops! - - """ - try: - if key in _GA(self, "options_dict"): - _GA(self, "set")(key, value) - except AttributeError: - pass - _SA(self, key, value) - - def _load_option(self, key): - """ - Loads option on-demand if it has not been loaded yet. - - Args: - key (str): The option being loaded. - - Returns: - - """ - desc, clsname, default_val = self.options_dict[key] - loaded_option = OPTION_CLASSES.get(clsname)(self, key, desc, default_val) - # store the value for future easy access - self.options[key] = loaded_option - return loaded_option - -
[docs] def get(self, key, default=None, return_obj=False, raise_error=False): - """ - Retrieves an Option stored in the handler. Will load it if it doesn't exist. - - Args: - key (str): The option key to retrieve. - default (any): What to return if the option is defined. - return_obj (bool, optional): If True, returns the actual option - object instead of its value. - raise_error (bool, optional): Raise Exception if key is not found in options. - Returns: - option_value (any or Option): An option value the Option itself. - Raises: - KeyError: If option is not defined. - - """ - if key not in self.options_dict: - if raise_error: - raise KeyError(_("Option not found!")) - return default - # get the options or load/recache it - op_found = self.options.get(key) or self._load_option(key) - return op_found if return_obj else op_found.value
- -
[docs] def set(self, key, value, **kwargs): - """ - Change an individual option. - - Args: - key (str): The key of an option that can be changed. Allows partial matching. - value (str): The value that should be checked, coerced, and stored.: - kwargs (any, optional): These are passed into the Option's validation function, - save function and display function and allows to customize either. - - Returns: - value (any): Value stored in option, after validation. - - """ - if not key: - raise ValueError(_("Option field blank!")) - match = string_partial_matching(list(self.options_dict.keys()), key, ret_index=False) - if not match: - raise ValueError(_("Option not found!")) - if len(match) > 1: - raise ValueError(_("Multiple matches:") - + f"{', '.join(match)}. " - + _("Please be more specific.")) - match = match[0] - op = self.get(match, return_obj=True) - op.set(value, **kwargs) - return op.value
- -
[docs] def all(self, return_objs=False): - """ - Get all options defined on this handler. - - Args: - return_objs (bool, optional): Return the actual Option objects rather - than their values. - Returns: - all_options (dict): All options on this handler, either `{key: value}` - or `{key: <Option>}` if `return_objs` is `True`. - - """ - return [self.get(key, return_obj=return_objs) for key in self.options_dict]
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/picklefield.html b/docs/0.9.5/_modules/evennia/utils/picklefield.html deleted file mode 100644 index ab6a240921..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/picklefield.html +++ /dev/null @@ -1,407 +0,0 @@ - - - - - - - - evennia.utils.picklefield — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.utils.picklefield

-#
-#  Copyright (c) 2009-2010 Gintautas Miliauskas
-#
-#   Permission is hereby granted, free of charge, to any person
-#   obtaining a copy of this software and associated documentation
-#   files (the "Software"), to deal in the Software without
-#   restriction, including without limitation the rights to use,
-#   copy, modify, merge, publish, distribute, sublicense, and/or sell
-#   copies of the Software, and to permit persons to whom the
-#   Software is furnished to do so, subject to the following
-#   conditions:
-#
-#   The above copyright notice and this permission notice shall be
-#   included in all copies or substantial portions of the Software.
-#
-#   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-#   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-#   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-#   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-#   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-#   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-#   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-#   OTHER DEALINGS IN THE SOFTWARE.
-
-"""
-Pickle field implementation for Django.
-
-Modified for Evennia by Griatch and the Evennia community.
-
-"""
-from ast import literal_eval
-from datetime import datetime
-
-from copy import deepcopy, Error as CopyError
-from base64 import b64encode, b64decode
-from zlib import compress, decompress
-
-# import six # this is actually a pypy component, not in default syslib
-from django.core.exceptions import ValidationError
-from django.db import models
-
-from django.forms.fields import CharField
-from django.forms.widgets import Textarea
-
-from pickle import loads, dumps
-from django.utils.encoding import force_str
-from evennia.utils.dbserialize import pack_dbobj
-
-
-DEFAULT_PROTOCOL = 4
-
-
-
[docs]class PickledObject(str): - """ - A subclass of string so it can be told whether a string is a pickled - object or not (if the object is an instance of this class then it must - [well, should] be a pickled one). - - Only really useful for passing pre-encoded values to ``default`` - with ``dbsafe_encode``, not that doing so is necessary. If you - remove PickledObject and its references, you won't be able to pass - in pre-encoded values anymore, but you can always just pass in the - python objects themselves. - """
- - -class _ObjectWrapper(object): - """ - A class used to wrap object that have properties that may clash with the - ORM internals. - - For example, objects with the `prepare_database_save` property such as - `django.db.Model` subclasses won't work under certain conditions and the - same apply for trying to retrieve any `callable` object. - """ - - __slots__ = ("_obj",) - - def __init__(self, obj): - self._obj = obj - - -
[docs]def wrap_conflictual_object(obj): - if hasattr(obj, "prepare_database_save") or callable(obj): - obj = _ObjectWrapper(obj) - return obj
- - -
[docs]def dbsafe_encode(value, compress_object=False, pickle_protocol=DEFAULT_PROTOCOL): - # We use deepcopy() here to avoid a problem with cPickle, where dumps - # can generate different character streams for same lookup value if - # they are referenced differently. - # The reason this is important is because we do all of our lookups as - # simple string matches, thus the character streams must be the same - # for the lookups to work properly. See tests.py for more information. - try: - value = deepcopy(value) - except CopyError: - # this can happen on a manager query where the search query string is a - # database model. - value = pack_dbobj(value) - - value = dumps(value, protocol=pickle_protocol) - - if compress_object: - value = compress(value) - value = b64encode(value).decode() # decode bytes to str - return PickledObject(value)
- - -
[docs]def dbsafe_decode(value, compress_object=False): - value = value.encode() # encode str to bytes - value = b64decode(value) - if compress_object: - value = decompress(value) - return loads(value)
- - -
[docs]class PickledWidget(Textarea): - """ - This is responsible for outputting HTML representing a given field. - """ - -
[docs] def render(self, name, value, attrs=None, renderer=None): - """Display of the PickledField in django admin""" - - repr_value = repr(value) - - # analyze represented value to see how big the field should be - if attrs is not None: - attrs["name"] = name - else: - attrs = {"name": name} - attrs["cols"] = 30 - # adapt number of rows to number of lines in string - rows = 1 - if isinstance(value, str) and "\n" in repr_value: - rows = max(1, len(value.split("\n"))) - attrs["rows"] = rows - attrs = self.build_attrs(attrs) - - try: - # necessary to convert it back after repr(), otherwise validation errors will mutate it - value = literal_eval(repr_value) - except (ValueError, SyntaxError): - # we could not eval it, just show its prepresentation - value = repr_value - return super().render(name, value, attrs=attrs, renderer=renderer)
- -
[docs] def value_from_datadict(self, data, files, name): - dat = data.get(name) - # import evennia;evennia.set_trace() - return dat
- - -
[docs]class PickledFormField(CharField): - """ - This represents one input field for the form. - - """ - - widget = PickledWidget - default_error_messages = dict(CharField.default_error_messages) - default_error_messages["invalid"] = ( - "This is not a Python Literal. You can store things like strings, " - "integers, or floats, but you must do it by typing them as you would " - "type them in the Python Interpreter. For instance, strings must be " - "surrounded by quote marks. We have converted it to a string for your " - "convenience. If it is acceptable, please hit save again." - ) - -
[docs] def __init__(self, *args, **kwargs): - # This needs to fall through to literal_eval. - kwargs["required"] = False - super().__init__(*args, **kwargs)
- -
[docs] def clean(self, value): - value = super().clean(value) - - # handle empty input - try: - if not value.strip(): - # Field was left blank. Make this None. - value = "None" - except AttributeError: - pass - - # parse raw Python - try: - return literal_eval(value) - except (ValueError, SyntaxError): - pass - - # fall through to parsing the repr() of the data - try: - value = repr(value) - return literal_eval(value) - except (ValueError, SyntaxError): - raise ValidationError(self.error_messages["invalid"])
- - -
[docs]class PickledObjectField(models.Field): - """ - A field that will accept *any* python object and store it in the - database. PickledObjectField will optionally compress its values if - declared with the keyword argument ``compress=True``. - - Does not actually encode and compress ``None`` objects (although you - can still do lookups using None). This way, it is still possible to - use the ``isnull`` lookup type correctly. - """ - -
[docs] def __init__(self, *args, **kwargs): - self.compress = kwargs.pop("compress", False) - self.protocol = kwargs.pop("protocol", DEFAULT_PROTOCOL) - super().__init__(*args, **kwargs)
- -
[docs] def get_default(self): - """ - Returns the default value for this field. - - The default implementation on models.Field calls force_str - on the default, which means you can't set arbitrary Python - objects as the default. To fix this, we just return the value - without calling force_str on it. Note that if you set a - callable as a default, the field will still call it. It will - *not* try to pickle and encode it. - - """ - if self.has_default(): - if callable(self.default): - return self.default() - return self.default - # If the field doesn't have a default, then we punt to models.Field. - return super().get_default()
- -
[docs] def from_db_value(self, value, *args): - """ - B64decode and unpickle the object, optionally decompressing it. - - If an error is raised in de-pickling and we're sure the value is - a definite pickle, the error is allowed to propagate. If we - aren't sure if the value is a pickle or not, then we catch the - error and return the original value instead. - - """ - if value is not None: - try: - value = dbsafe_decode(value, self.compress) - except Exception: - # If the value is a definite pickle; and an error is raised in - # de-pickling it should be allowed to propogate. - if isinstance(value, PickledObject): - raise - else: - if isinstance(value, _ObjectWrapper): - return value._obj - return value
- -
[docs] def formfield(self, **kwargs): - return PickledFormField(**kwargs)
- -
[docs] def pre_save(self, model_instance, add): - value = super().pre_save(model_instance, add) - return wrap_conflictual_object(value)
- -
[docs] def get_db_prep_value(self, value, connection=None, prepared=False): - """ - Pickle and b64encode the object, optionally compressing it. - - The pickling protocol is specified explicitly (by default 2), - rather than as -1 or HIGHEST_PROTOCOL, because we don't want the - protocol to change over time. If it did, ``exact`` and ``in`` - lookups would likely fail, since pickle would now be generating - a different string. - - """ - if value is not None and not isinstance(value, PickledObject): - # We call force_str here explicitly, so that the encoded string - # isn't rejected by the postgresql backend. Alternatively, - # we could have just registered PickledObject with the psycopg - # marshaller (telling it to store it like it would a string), but - # since both of these methods result in the same value being stored, - # doing things this way is much easier. - value = force_str(dbsafe_encode(value, self.compress, self.protocol)) - return value
- -
[docs] def value_to_string(self, obj): - value = self.value_from_object(obj) - return self.get_db_prep_value(value)
- -
[docs] def get_internal_type(self): - return "TextField"
- -
[docs] def get_db_prep_lookup(self, lookup_type, value, connection=None, prepared=False): - if lookup_type not in ["exact", "in", "isnull"]: - raise TypeError("Lookup type %s is not supported." % lookup_type) - # The Field model already calls get_db_prep_value before doing the - # actual lookup, so all we need to do is limit the lookup types. - return super().get_db_prep_lookup( - lookup_type, value, connection=connection, prepared=prepared - )
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/search.html b/docs/0.9.5/_modules/evennia/utils/search.html deleted file mode 100644 index 042160342d..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/search.html +++ /dev/null @@ -1,469 +0,0 @@ - - - - - - - - evennia.utils.search — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.utils.search

-"""
-This is a convenient container gathering all the main
-search methods for the various database tables.
-
-It is intended to be used e.g. as
-
-> from evennia.utils import search
-> match = search.objects(...)
-
-Note that this is not intended to be a complete listing of all search
-methods! You need to refer to the respective manager to get all
-possible search methods. To get to the managers from your code, import
-the database model and call its 'objects' property.
-
-Also remember that all commands in this file return lists (also if
-there is only one match) unless noted otherwise.
-
-Example: To reach the search method 'get_object_with_account'
-         in evennia/objects/managers.py:
-
-> from evennia.objects.models import ObjectDB
-> match = Object.objects.get_object_with_account(...)
-
-
-"""
-
-# Import the manager methods to be wrapped
-
-from django.db.utils import OperationalError, ProgrammingError
-from django.contrib.contenttypes.models import ContentType
-
-# limit symbol import from API
-__all__ = (
-    "search_object",
-    "search_account",
-    "search_script",
-    "search_message",
-    "search_channel",
-    "search_help_entry",
-    "search_tag",
-    "search_script_tag",
-    "search_account_tag",
-    "search_channel_tag",
-)
-
-
-# import objects this way to avoid circular import problems
-try:
-    ObjectDB = ContentType.objects.get(app_label="objects", model="objectdb").model_class()
-    AccountDB = ContentType.objects.get(app_label="accounts", model="accountdb").model_class()
-    ScriptDB = ContentType.objects.get(app_label="scripts", model="scriptdb").model_class()
-    Msg = ContentType.objects.get(app_label="comms", model="msg").model_class()
-    ChannelDB = ContentType.objects.get(app_label="comms", model="channeldb").model_class()
-    HelpEntry = ContentType.objects.get(app_label="help", model="helpentry").model_class()
-    Tag = ContentType.objects.get(app_label="typeclasses", model="tag").model_class()
-except (OperationalError, ProgrammingError):
-    # this is a fallback used during tests/doc building
-    print("Database not available yet - using temporary fallback for search managers.")
-    from evennia.objects.models import ObjectDB
-    from evennia.accounts.models import AccountDB
-    from evennia.scripts.models import ScriptDB
-    from evennia.comms.models import Msg, ChannelDB
-    from evennia.help.models import HelpEntry
-    from evennia.typeclasses.tags import Tag  # noqa
-
-# -------------------------------------------------------------------
-# Search manager-wrappers
-# -------------------------------------------------------------------
-
-#
-# Search objects as a character
-#
-# NOTE: A more powerful wrapper of this method
-#  is reachable from within each command class
-#  by using self.caller.search()!
-#
-#    def object_search(self, ostring=None,
-#                      attribute_name=None,
-#                      typeclass=None,
-#                      candidates=None,
-#                      exact=True):
-#
-#        Search globally or in a list of candidates and return results.
-#        The result is always a list of Objects (or the empty list)
-#
-#        Arguments:
-#        ostring: (str) The string to compare names against. By default (if
-#                  not attribute_name is set), this will search object.key
-#                  and object.aliases in order. Can also be on the form #dbref,
-#                  which will, if exact=True be matched against primary key.
-#        attribute_name: (str): Use this named ObjectAttribute to match ostring
-#                        against, instead of the defaults.
-#        typeclass (str or TypeClass): restrict matches to objects having
-#                  this typeclass. This will help speed up global searches.
-#        candidates (list obj ObjectDBs): If supplied, search will only be
-#                  performed among the candidates in this list. A common list
-#                  of candidates is the contents of the current location.
-#        exact (bool): Match names/aliases exactly or partially. Partial
-#                  matching matches the beginning of words in the names/aliases,
-#                  using a matching routine to separate multiple matches in
-#                  names with multiple components (so "bi sw" will match
-#                  "Big sword"). Since this is more expensive than exact
-#                  matching, it is recommended to be used together with
-#                  the objlist keyword to limit the number of possibilities.
-#                  This keyword has no meaning if attribute_name is set.
-#
-#        Returns:
-#        A list of matching objects (or a list with one unique match)
-#    def object_search(self, ostring, caller=None,
-#                      candidates=None,
-#                      attribute_name=None):
-#
-search_object = ObjectDB.objects.search_object
-search_objects = search_object
-object_search = search_object
-objects = search_objects
-
-#
-# Search for accounts
-#
-# account_search(self, ostring)
-
-#     Searches for a particular account by name or
-#     database id.
-#
-#     ostring = a string or database id.
-#
-
-search_account = AccountDB.objects.search_account
-search_accounts = search_account
-account_search = search_account
-accounts = search_accounts
-
-#
-#   Searching for scripts
-#
-# script_search(self, ostring, obj=None, only_timed=False)
-#
-#     Search for a particular script.
-#
-#     ostring - search criterion - a script ID or key
-#     obj - limit search to scripts defined on this object
-#     only_timed - limit search only to scripts that run
-#                  on a timer.
-#
-
-search_script = ScriptDB.objects.search_script
-search_scripts = search_script
-script_search = search_script
-scripts = search_scripts
-#
-# Searching for communication messages
-#
-#
-# message_search(self, sender=None, receiver=None, channel=None, freetext=None)
-#
-#     Search the message database for particular messages. At least one
-#     of the arguments must be given to do a search.
-#
-#     sender - get messages sent by a particular account
-#     receiver - get messages received by a certain account
-#     channel - get messages sent to a particular channel
-#     freetext - Search for a text string in a message.
-#                NOTE: This can potentially be slow, so make sure to supply
-#                one of the other arguments to limit the search.
-#
-
-search_message = Msg.objects.search_message
-search_messages = search_message
-message_search = search_message
-messages = search_messages
-
-#
-# Search for Communication Channels
-#
-# channel_search(self, ostring)
-#
-#     Search the channel database for a particular channel.
-#
-#     ostring - the key or database id of the channel.
-#     exact -  requires an exact ostring match (not case sensitive)
-#
-
-search_channel = ChannelDB.objects.search_channel
-search_channels = search_channel
-channel_search = search_channel
-channels = search_channels
-
-#
-# Find help entry objects.
-#
-# search_help(self, ostring, help_category=None)
-#
-#     Retrieve a search entry object.
-#
-#     ostring - the help topic to look for
-#     category - limit the search to a particular help topic
-#
-
-search_help = HelpEntry.objects.search_help
-search_help_entry = search_help
-search_help_entries = search_help
-help_entry_search = search_help
-help_entries = search_help
-
-
-# Locate Attributes
-
-#    search_object_attribute(key, category, value, strvalue) (also search_attribute works)
-#    search_account_attribute(key, category, value, strvalue) (also search_attribute works)
-#    search_script_attribute(key, category, value, strvalue) (also search_attribute works)
-#    search_channel_attribute(key, category, value, strvalue) (also search_attribute works)
-
-# Note that these return the object attached to the Attribute,
-# not the attribute object itself (this is usually what you want)
-
-
-def search_object_attribute(
-    key=None, category=None, value=None, strvalue=None, attrtype=None, **kwargs
-):
-    return ObjectDB.objects.get_by_attribute(
-        key=key, category=category, value=value, strvalue=strvalue, attrtype=attrtype, **kwargs
-    )
-
-
-def search_account_attribute(
-    key=None, category=None, value=None, strvalue=None, attrtype=None, **kwargs
-):
-    return AccountDB.objects.get_by_attribute(
-        key=key, category=category, value=value, strvalue=strvalue, attrtype=attrtype, **kwargs
-    )
-
-
-def search_script_attribute(
-    key=None, category=None, value=None, strvalue=None, attrtype=None, **kwargs
-):
-    return ScriptDB.objects.get_by_attribute(
-        key=key, category=category, value=value, strvalue=strvalue, attrtype=attrtype, **kwargs
-    )
-
-
-def search_channel_attribute(
-    key=None, category=None, value=None, strvalue=None, attrtype=None, **kwargs
-):
-    return ChannelDB.objects.get_by_attribute(
-        key=key, category=category, value=value, strvalue=strvalue, attrtype=attrtype, **kwargs
-    )
-
-
-# search for attribute objects
-search_attribute_object = ObjectDB.objects.get_attribute
-
-# Locate Tags
-
-#    search_object_tag(key=None, category=None) (also search_tag works)
-#    search_account_tag(key=None, category=None)
-#    search_script_tag(key=None, category=None)
-#    search_channel_tag(key=None, category=None)
-
-# Note that this returns the object attached to the tag, not the tag
-# object itself (this is usually what you want)
-
-
-def search_object_by_tag(key=None, category=None, tagtype=None, **kwargs):
-    """
-    Find object based on tag or category.
-
-    Args:
-        key (str, optional): The tag key to search for.
-        category (str, optional): The category of tag
-            to search for. If not set, uncategorized
-            tags will be searched.
-        tagtype (str, optional): 'type' of Tag, by default
-            this is either `None` (a normal Tag), `alias` or
-            `permission`. This always apply to all queried tags.
-        kwargs (any): Other optional parameter that may be supported
-            by the manager method.
-
-    Returns:
-        matches (list): List of Objects with tags matching
-            the search criteria, or an empty list if no
-            matches were found.
-
-    """
-    return ObjectDB.objects.get_by_tag(key=key, category=category, tagtype=tagtype, **kwargs)
-
-
-search_tag = search_object_by_tag  # this is the most common case
-
-
-
[docs]def search_account_tag(key=None, category=None, tagtype=None, **kwargs): - """ - Find account based on tag or category. - - Args: - key (str, optional): The tag key to search for. - category (str, optional): The category of tag - to search for. If not set, uncategorized - tags will be searched. - tagtype (str, optional): 'type' of Tag, by default - this is either `None` (a normal Tag), `alias` or - `permission`. This always apply to all queried tags. - kwargs (any): Other optional parameter that may be supported - by the manager method. - - Returns: - matches (list): List of Accounts with tags matching - the search criteria, or an empty list if no - matches were found. - - """ - return AccountDB.objects.get_by_tag(key=key, category=category, tagtype=tagtype, **kwargs)
- - -
[docs]def search_script_tag(key=None, category=None, tagtype=None, **kwargs): - """ - Find script based on tag or category. - - Args: - key (str, optional): The tag key to search for. - category (str, optional): The category of tag - to search for. If not set, uncategorized - tags will be searched. - tagtype (str, optional): 'type' of Tag, by default - this is either `None` (a normal Tag), `alias` or - `permission`. This always apply to all queried tags. - kwargs (any): Other optional parameter that may be supported - by the manager method. - - Returns: - matches (list): List of Scripts with tags matching - the search criteria, or an empty list if no - matches were found. - - """ - return ScriptDB.objects.get_by_tag(key=key, category=category, tagtype=tagtype, **kwargs)
- - -
[docs]def search_channel_tag(key=None, category=None, tagtype=None, **kwargs): - """ - Find channel based on tag or category. - - Args: - key (str, optional): The tag key to search for. - category (str, optional): The category of tag - to search for. If not set, uncategorized - tags will be searched. - tagtype (str, optional): 'type' of Tag, by default - this is either `None` (a normal Tag), `alias` or - `permission`. This always apply to all queried tags. - kwargs (any): Other optional parameter that may be supported - by the manager method. - - Returns: - matches (list): List of Channels with tags matching - the search criteria, or an empty list if no - matches were found. - - """ - return ChannelDB.objects.get_by_tag(key=key, category=category, tagtype=tagtype, **kwargs)
- - -# search for tag objects (not the objects they are attached to -search_tag_object = ObjectDB.objects.get_tag -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/test_resources.html b/docs/0.9.5/_modules/evennia/utils/test_resources.html deleted file mode 100644 index 107d8bd177..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/test_resources.html +++ /dev/null @@ -1,693 +0,0 @@ - - - - - - - - evennia.utils.test_resources — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.utils.test_resources

-"""
-Various helper resources for writing unittests.
-
-Classes for testing Evennia core:
-
-- `BaseEvenniaTestCase` - no default objects, only enforced default settings
-- `BaseEvenniaTest` - all default objects, enforced default settings
-- `BaseEvenniaCommandTest` - for testing Commands, enforced default settings
-
-Classes for testing game folder content:
-
-- `EvenniaTestCase` - no default objects, using gamedir settings (identical to
-   standard Python TestCase)
-- `EvenniaTest` - all default objects, using gamedir settings
-- `EvenniaCommandTest` - for testing game folder commands, using gamedir settings
-
-Other:
-
-- `EvenniaTestMixin` - A class mixin for creating the test environment objects, for
-  making custom tests.
-- `EvenniaCommandMixin` - A class mixin that adds support for command testing with the .call()
-  helper. Used by the command-test classes, but can be used for making a customt test class.
-
-"""
-import sys
-import re
-import types
-from twisted.internet.defer import Deferred
-from django.conf import settings
-from django.test import TestCase, override_settings
-from mock import Mock, patch, MagicMock
-from evennia.objects.objects import DefaultObject, DefaultCharacter, DefaultRoom, DefaultExit
-from evennia.accounts.accounts import DefaultAccount
-from evennia.scripts.scripts import DefaultScript
-from evennia.server.serversession import ServerSession
-from evennia.server.sessionhandler import SESSIONS
-from evennia.utils import create
-from evennia.utils.idmapper.models import flush_cache
-from evennia.utils.utils import all_from_module, to_str
-from evennia.utils import ansi
-from evennia import settings_default
-from evennia.commands.default.muxcommand import MuxCommand
-from evennia.commands.command import InterruptCommand
-
-
-_RE_STRIP_EVMENU = re.compile(r"^\+|-+\+|\+-+|--+|\|(?:\s|$)", re.MULTILINE)
-
-
-# set up a 'pristine' setting, unaffected by any changes in mygame
-DEFAULT_SETTING_RESETS = dict(
-    CONNECTION_SCREEN_MODULE="evennia.game_template.server.conf.connection_screens",
-    AT_SERVER_STARTSTOP_MODULE="evennia.game_template.server.conf.at_server_startstop",
-    AT_SERVICES_PLUGINS_MODULES=["evennia.game_template.server.conf.server_services_plugins"],
-    PORTAL_SERVICES_PLUGIN_MODULES=["evennia.game_template.server.conf.portal_services_plugins"],
-    MSSP_META_MODULE="evennia.game_template.server.conf.mssp",
-    WEB_PLUGINS_MODULE="server.conf.web_plugins",
-    LOCK_FUNC_MODULES=("evennia.locks.lockfuncs", "evennia.game_template.server.conf.lockfuncs"),
-    INPUT_FUNC_MODULES=["evennia.server.inputfuncs",
-                        "evennia.game_template.server.conf.inputfuncs"],
-    PROTOTYPE_MODULES=["evennia.game_template.world.prototypes"],
-    CMDSET_UNLOGGEDIN="evennia.game_template.commands.default_cmdsets.UnloggedinCmdSet",
-    CMDSET_SESSION="evennia.game_template.commands.default_cmdsets.SessionCmdSet",
-    CMDSET_CHARACTER="evennia.game_template.commands.default_cmdsets.CharacterCmdSet",
-    CMDSET_ACCOUNT="evennia.game_template.commands.default_cmdsets.AccountCmdSet",
-    CMDSET_PATHS=["evennia.game_template.commands", "evennia", "evennia.contrib"],
-    TYPECLASS_PATHS=[
-        "evennia",
-        "evennia.contrib",
-        "evennia.contrib.game_systems",
-        "evennia.contrib.base_systems",
-        "evennia.contrib.full_systems",
-        "evennia.contrib.tutorials",
-        "evennia.contrib.utils"],
-    BASE_ACCOUNT_TYPECLASS="evennia.accounts.accounts.DefaultAccount",
-    BASE_OBJECT_TYPECLASS="evennia.objects.objects.DefaultObject",
-    BASE_CHARACTER_TYPECLASS="evennia.objects.objects.DefaultCharacter",
-    BASE_ROOM_TYPECLASS="evennia.objects.objects.DefaultRoom",
-    BASE_EXIT_TYPECLASS="evennia.objects.objects.DefaultExit",
-    BASE_CHANNEL_TYPECLASS="evennia.comms.comms.DefaultChannel",
-    BASE_SCRIPT_TYPECLASS="evennia.scripts.scripts.DefaultScript",
-    BASE_BATCHPROCESS_PATHS=["evennia.game_template.world",
-                             "evennia.contrib", "evennia.contrib.tutorials"],
-    FILE_HELP_ENTRY_MODULES=["evennia.game_template.world.help_entries"],
-    FUNCPARSER_OUTGOING_MESSAGES_MODULES=["evennia.utils.funcparser",
-                                          "evennia.game_template.server.conf.inlinefuncs"],
-    FUNCPARSER_PROTOTYPE_PARSING_MODULES=["evennia.prototypes.protfuncs",
-                                          "evennia.game_template.server.conf.prototypefuncs"],
-    BASE_GUEST_TYPECLASS="evennia.accounts.accounts.DefaultGuest",
-    # a special flag; test with settings._TEST_ENVIRONMENT to see if code runs in a test
-    _TEST_ENVIRONMENT=True,
-)
-
-DEFAULT_SETTINGS = {
-    **all_from_module(settings_default),
-    **DEFAULT_SETTING_RESETS
-}
-DEFAULT_SETTINGS.pop("DATABASES")  # we want different dbs tested in CI
-
-
-# mocking of evennia.utils.utils.delay
-
[docs]def mockdelay(timedelay, callback, *args, **kwargs): - callback(*args, **kwargs) - return Deferred()
- - -# mocking of twisted's deferLater -
[docs]def mockdeferLater(reactor, timedelay, callback, *args, **kwargs): - callback(*args, **kwargs) - return Deferred()
- - -
[docs]def unload_module(module): - """ - Reset import so one can mock global constants. - - Args: - module (module, object or str): The module will - be removed so it will have to be imported again. If given - an object, the module in which that object sits will be unloaded. A string - should directly give the module pathname to unload. - - Example: - - ```python - # (in a test method) - unload_module(foo) - with mock.patch("foo.GLOBALTHING", "mockval"): - import foo - ... # test code using foo.GLOBALTHING, now set to 'mockval' - ``` - - This allows for mocking constants global to the module, since - otherwise those would not be mocked (since a module is only - loaded once). - - """ - if isinstance(module, str): - modulename = module - elif hasattr(module, "__module__"): - modulename = module.__module__ - else: - modulename = module.__name__ - - if modulename in sys.modules: - del sys.modules[modulename]
- - -def _mock_deferlater(reactor, timedelay, callback, *args, **kwargs): - callback(*args, **kwargs) - return Deferred() - - -
[docs]class EvenniaTestMixin: - """ - Evennia test environment mixin - """ - account_typeclass = DefaultAccount - object_typeclass = DefaultObject - character_typeclass = DefaultCharacter - exit_typeclass = DefaultExit - room_typeclass = DefaultRoom - script_typeclass = DefaultScript - -
[docs] def create_accounts(self): - self.account = create.create_account( - "TestAccount", - email="test@test.com", - password="testpassword", - typeclass=self.account_typeclass, - ) - self.account2 = create.create_account( - "TestAccount2", - email="test@test.com", - password="testpassword", - typeclass=self.account_typeclass, - ) - self.account.permissions.add("Developer")
- -
[docs] def teardown_accounts(self): - if hasattr(self, "account"): - self.account.delete() - if hasattr(self, "account2"): - self.account2.delete()
- - # Set up fake prototype module for allowing tests to use named prototypes. -
[docs] @override_settings(PROTOTYPE_MODULES=["evennia.utils.tests.data.prototypes_example"], - DEFAULT_HOME="#1") - def create_rooms(self): - self.room1 = create.create_object(self.room_typeclass, key="Room", nohome=True) - self.room1.db.desc = "room_desc" - - self.room2 = create.create_object(self.room_typeclass, key="Room2") - self.exit = create.create_object( - self.exit_typeclass, key="out", location=self.room1, destination=self.room2 - )
- -
[docs] def create_objs(self): - self.obj1 = create.create_object( - self.object_typeclass, key="Obj", location=self.room1, home=self.room1 - ) - self.obj2 = create.create_object( - self.object_typeclass, key="Obj2", location=self.room1, home=self.room1 - )
- -
[docs] def create_chars(self): - self.char1 = create.create_object( - self.character_typeclass, key="Char", location=self.room1, home=self.room1 - ) - self.char1.permissions.add("Developer") - self.char2 = create.create_object( - self.character_typeclass, key="Char2", location=self.room1, home=self.room1 - ) - self.char1.account = self.account - self.account.db._last_puppet = self.char1 - self.char2.account = self.account2 - self.account2.db._last_puppet = self.char2
- -
[docs] def create_script(self): - self.script = create.create_script(self.script_typeclass, key="Script")
- -
[docs] def setup_session(self): - dummysession = ServerSession() - dummysession.init_session("telnet", ("localhost", "testmode"), SESSIONS) - dummysession.sessid = 1 - SESSIONS.portal_connect( - dummysession.get_sync_data() - ) # note that this creates a new Session! - session = SESSIONS.session_from_sessid(1) # the real session - SESSIONS.login(session, self.account, testmode=True) - self.session = session
- -
[docs] def teardown_session(self): - if hasattr(self, "sessions"): - del SESSIONS[self.session.sessid]
- -
[docs] @patch("evennia.scripts.taskhandler.deferLater", _mock_deferlater) - def setUp(self): - """ - Sets up testing environment - """ - self.backups = ( - SESSIONS.data_out, - SESSIONS.disconnect, - settings.DEFAULT_HOME, - settings.PROTOTYPE_MODULES, - ) - SESSIONS.data_out = Mock() - SESSIONS.disconnect = Mock() - - self.create_accounts() - self.create_rooms() - self.create_objs() - self.create_chars() - self.create_script() - self.setup_session()
- -
[docs] def tearDown(self): - flush_cache() - try: - SESSIONS.data_out = self.backups[0] - SESSIONS.disconnect = self.backups[1] - settings.DEFAULT_HOME = self.backups[2] - settings.PROTOTYPE_MODULES = self.backups[3] - except AttributeError as err: - raise AttributeError(f"{err}: Teardown error. If you overrode the `setUp()` method " - "in your test, make sure you also added `super().setUp()`!") - - del SESSIONS[self.session.sessid] - self.teardown_accounts() - super().tearDown()
- - -
[docs]@patch("evennia.server.portal.portal.LoopingCall", new=MagicMock()) -class EvenniaCommandTestMixin: - """ - Mixin to add to a test in order to provide the `.call` helper for - testing the execution and returns of a command. - - Tests a Command by running it and comparing what messages it sends with - expected values. This tests without actually spinning up the cmdhandler - for every test, which is more controlled. - - Example: - :: - - from commands.echo import CmdEcho - - class MyCommandTest(EvenniaTest, CommandTestMixin): - - def test_echo(self): - ''' - Test that the echo command really returns - what you pass into it. - ''' - self.call(MyCommand(), "hello world!", - "You hear your echo: 'Hello world!'") - - """ - - # formatting for .call's error message - _ERROR_FORMAT = """ -=========================== Wanted message =================================== -{expected_msg} -=========================== Returned message ================================= -{returned_msg} -============================================================================== -""".rstrip() - -
[docs] def call( - self, - cmdobj, - input_args, - msg=None, - cmdset=None, - noansi=True, - caller=None, - receiver=None, - cmdstring=None, - obj=None, - inputs=None, - raw_string=None, - ): - """ - Test a command by assigning all the needed properties to a cmdobj and - running the sequence. The resulting `.msg` calls will be mocked and - the text= calls to them compared to a expected output. - - Args: - cmdobj (Command): The command object to use. - input_args (str): This should be the full input the Command should - see, such as 'look here'. This will become `.args` for the Command - instance to parse. - msg (str or dict, optional): This is the expected return value(s) - returned through `caller.msg(text=...)` calls in the command. If a string, the - receiver is controlled with the `receiver` kwarg (defaults to `caller`). - If this is a `dict`, it is a mapping - `{receiver1: "expected1", receiver2: "expected2",...}` and `receiver` is - ignored. The message(s) are compared with the actual messages returned - to the receiver(s) as the Command runs. Each check uses `.startswith`, - so you can choose to only include the first part of the - returned message if that's enough to verify a correct result. EvMenu - decorations (like borders) are stripped and should not be included. This - should also not include color tags unless `noansi=False`. - If the command returns texts in multiple separate `.msg`- - calls to a receiver, separate these with `|` if `noansi=True` - (default) and `||` if `noansi=False`. If no `msg` is given (`None`), - then no automatic comparison will be done. - cmdset (str, optional): If given, make `.cmdset` available on the Command - instance as it runs. While `.cmdset` is normally available on the - Command instance by default, this is usually only used by - commands that explicitly operates/displays cmdsets, like - `examine`. - noansi (str, optional): By default the color tags of the `msg` is - ignored, this makes them significant. If unset, `msg` must contain - the same color tags as the actual return message. - caller (Object or Account, optional): By default `self.char1` is used as the - command-caller (the `.caller` property on the Command). This allows to - execute with another caller, most commonly an Account. - receiver (Object or Account, optional): This is the object to receive the - return messages we want to test. By default this is the same as `caller` - (which in turn defaults to is `self.char1`). Note that if `msg` is - a `dict`, this is ignored since the receiver is already specified there. - cmdstring (str, optional): Normally this is the Command's `key`. - This allows for tweaking the `.cmdname` property of the - Command`. This isb used for commands with multiple aliases, - where the command explicitly checs which alias was used to - determine its functionality. - obj (str, optional): This sets the `.obj` property of the Command - the - object on which the Command 'sits'. By default this is the same as `caller`. - This can be used for testing on-object Command interactions. - inputs (list, optional): A list of strings to pass to functions that pause to - take input from the user (normally using `@interactive` and - `ret = yield(question)` or `evmenu.get_input`). Each element of the - list will be passed into the command as if the user wrote that at the prompt. - raw_string (str, optional): Normally the `.raw_string` property is set as - a combination of your `key/cmdname` and `input_args`. This allows - direct control of what this is, for example for testing edge cases - or malformed inputs. - - Returns: - str or dict: The message sent to `receiver`, or a dict of - `{receiver: "msg", ...}` if multiple are given. This is usually - only used with `msg=None` to do the validation externally. - - Raises: - AssertionError: If the returns of `.msg` calls (tested with `.startswith`) does not - match `expected_input`. - - Notes: - As part of the tests, all methods of the Command will be called in - the proper order: - - - cmdobj.at_pre_cmd() - - cmdobj.parse() - - cmdobj.func() - - cmdobj.at_post_cmd() - - """ - # The `self.char1` is created in the `EvenniaTest` base along with - # other helper objects like self.room and self.obj - caller = caller if caller else self.char1 - cmdobj.caller = caller - cmdobj.cmdname = cmdstring if cmdstring else cmdobj.key - cmdobj.raw_cmdname = cmdobj.cmdname - cmdobj.cmdstring = cmdobj.cmdname # deprecated - cmdobj.args = input_args - cmdobj.cmdset = cmdset - cmdobj.session = SESSIONS.session_from_sessid(1) - cmdobj.account = self.account - cmdobj.raw_string = raw_string if raw_string is not None else cmdobj.key + " " + input_args - cmdobj.obj = obj or (caller if caller else self.char1) - inputs = inputs or [] - - # set up receivers - receiver_mapping = {} - if isinstance(msg, dict): - # a mapping {receiver: msg, ...} - receiver_mapping = {recv: str(msg).strip() if msg else None - for recv, msg in msg.items()} - else: - # a single expected string and thus a single receiver (defaults to caller) - receiver = receiver if receiver else caller - receiver_mapping[receiver] = str(msg).strip() if msg is not None else None - - unmocked_msg_methods = {} - for receiver in receiver_mapping: - # save the old .msg method so we can get it back - # cleanly after the test - unmocked_msg_methods[receiver] = receiver.msg - # replace normal `.msg` with a mock - receiver.msg = Mock() - - # Run the methods of the Command. This mimics what happens in the - # cmdhandler. This will have the mocked .msg be called as part of the - # execution. Mocks remembers what was sent to them so we will be able - # to retrieve what was sent later. - try: - if cmdobj.at_pre_cmd(): - return - cmdobj.parse() - ret = cmdobj.func() - - # handle func's with yield in them (making them generators) - if isinstance(ret, types.GeneratorType): - while True: - try: - inp = inputs.pop() if inputs else None - if inp: - try: - # this mimics a user's reply to a prompt - ret.send(inp) - except TypeError: - next(ret) - ret = ret.send(inp) - else: - # non-input yield, like yield(10). We don't pause - # but fire it immediately. - next(ret) - except StopIteration: - break - - cmdobj.at_post_cmd() - except StopIteration: - pass - except InterruptCommand: - pass - - for inp in inputs: - # if there are any inputs left, we may have a non-generator - # input to handle (get_input/ask_yes_no that uses a separate - # cmdset rather than a yield - caller.execute_cmd(inp) - - # At this point the mocked .msg methods on each receiver will have - # stored all calls made to them (that's a basic function of the Mock - # class). We will not extract them and compare to what we expected to - # go to each receiver. - - returned_msgs = {} - for receiver, expected_msg in receiver_mapping.items(): - # get the stored messages from the Mock with Mock.mock_calls. - stored_msg = [ - args[0] if args and args[0] else kwargs.get("text", to_str(kwargs)) - for name, args, kwargs in receiver.msg.mock_calls - ] - # we can return this now, we are done using the mock - receiver.msg = unmocked_msg_methods[receiver] - - # Get the first element of a tuple if msg received a tuple instead of a string - stored_msg = [str(smsg[0]) - if isinstance(smsg, tuple) else str(smsg) for smsg in stored_msg] - if expected_msg is None: - # no expected_msg; just build the returned_msgs dict - - returned_msg = "\n".join(str(msg) for msg in stored_msg) - returned_msgs[receiver] = ansi.parse_ansi(returned_msg, strip_ansi=noansi).strip() - else: - # compare messages to expected - - # set our separator for returned messages based on parsing ansi or not - msg_sep = "|" if noansi else "||" - - # We remove Evmenu decorations since that just makes it harder - # to write the comparison string. We also strip ansi before this - # comparison since otherwise it would mess with the regex. - returned_msg = msg_sep.join( - _RE_STRIP_EVMENU.sub( - "", ansi.parse_ansi(mess, strip_ansi=noansi)) - for mess in stored_msg).strip() - - # this is the actual test - if expected_msg == "" and returned_msg or not returned_msg.startswith(expected_msg): - # failed the test - raise AssertionError( - self._ERROR_FORMAT.format( - expected_msg=expected_msg, returned_msg=returned_msg) - ) - # passed! - returned_msgs[receiver] = returned_msg - - if len(returned_msgs) == 1: - return list(returned_msgs.values())[0] - return returned_msgs
- - -# Base testing classes - -
[docs]@override_settings(**DEFAULT_SETTINGS) -class BaseEvenniaTestCase(TestCase): - """ - Base test (with no default objects) but with enforced default settings. - - """
- -
[docs]class EvenniaTestCase(TestCase): - """ - For use with gamedir settings; Just like the normal test case, only for naming consistency. - - """ - pass
- - -
[docs]@override_settings(**DEFAULT_SETTINGS) -class BaseEvenniaTest(EvenniaTestMixin, TestCase): - """ - This class parent has all default objects and uses only default settings. - - """
- -
[docs]class EvenniaTest(EvenniaTestMixin, TestCase): - """ - This test class is intended for inheriting in mygame tests. - It helps ensure your tests are run with your own objects - and settings from your game folder. - - """ - - account_typeclass = settings.BASE_ACCOUNT_TYPECLASS - object_typeclass = settings.BASE_OBJECT_TYPECLASS - character_typeclass = settings.BASE_CHARACTER_TYPECLASS - exit_typeclass = settings.BASE_EXIT_TYPECLASS - room_typeclass = settings.BASE_ROOM_TYPECLASS - script_typeclass = settings.BASE_SCRIPT_TYPECLASS
- - -
[docs]@patch("evennia.commands.account.COMMAND_DEFAULT_CLASS", MuxCommand) -@patch("evennia.commands.admin.COMMAND_DEFAULT_CLASS", MuxCommand) -@patch("evennia.commands.batchprocess.COMMAND_DEFAULT_CLASS", MuxCommand) -@patch("evennia.commands.building.COMMAND_DEFAULT_CLASS", MuxCommand) -@patch("evennia.commands.comms.COMMAND_DEFAULT_CLASS", MuxCommand) -@patch("evennia.commands.general.COMMAND_DEFAULT_CLASS", MuxCommand) -@patch("evennia.commands.help.COMMAND_DEFAULT_CLASS", MuxCommand) -@patch("evennia.commands.syscommands.COMMAND_DEFAULT_CLASS", MuxCommand) -@patch("evennia.commands.system.COMMAND_DEFAULT_CLASS", MuxCommand) -@patch("evennia.commands.unloggedin.COMMAND_DEFAULT_CLASS", MuxCommand) -class BaseEvenniaCommandTest(BaseEvenniaTest, EvenniaCommandTestMixin): - """ - Commands only using the default settings. - - """
- - -
[docs]class EvenniaCommandTest(EvenniaTest, EvenniaCommandTestMixin): - """ - Parent class to inherit from - makes tests use your own - classes and settings in mygame. - - """
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/text2html.html b/docs/0.9.5/_modules/evennia/utils/text2html.html deleted file mode 100644 index 0cf22aa7c8..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/text2html.html +++ /dev/null @@ -1,490 +0,0 @@ - - - - - - - - evennia.utils.text2html — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.utils.text2html

-"""
-ANSI -> html converter
-
-Credit for original idea and implementation
-goes to Muhammad Alkarouri and his
-snippet #577349 on http://code.activestate.com.
-
-(extensively modified by Griatch 2010)
-"""
-
-import re
-from html import escape as html_escape
-from .ansi import *
-
-
-# All xterm256 RGB equivalents
-
-XTERM256_FG = "\033[38;5;%sm"
-XTERM256_BG = "\033[48;5;%sm"
-
-
-
[docs]class TextToHTMLparser(object): - """ - This class describes a parser for converting from ANSI to html. - """ - - tabstop = 4 - # mapping html color name <-> ansi code. - hilite = ANSI_HILITE - unhilite = ANSI_UNHILITE # this will be stripped - there is no css equivalent. - normal = ANSI_NORMAL # " - underline = ANSI_UNDERLINE - blink = ANSI_BLINK - inverse = ANSI_INVERSE # this will produce an outline; no obvious css equivalent? - colorcodes = [ - ("color-000", unhilite + ANSI_BLACK), # pure black - ("color-001", unhilite + ANSI_RED), - ("color-002", unhilite + ANSI_GREEN), - ("color-003", unhilite + ANSI_YELLOW), - ("color-004", unhilite + ANSI_BLUE), - ("color-005", unhilite + ANSI_MAGENTA), - ("color-006", unhilite + ANSI_CYAN), - ("color-007", unhilite + ANSI_WHITE), # light grey - ("color-008", hilite + ANSI_BLACK), # dark grey - ("color-009", hilite + ANSI_RED), - ("color-010", hilite + ANSI_GREEN), - ("color-011", hilite + ANSI_YELLOW), - ("color-012", hilite + ANSI_BLUE), - ("color-013", hilite + ANSI_MAGENTA), - ("color-014", hilite + ANSI_CYAN), - ("color-015", hilite + ANSI_WHITE), # pure white - ] + [("color-%03i" % (i + 16), XTERM256_FG % ("%i" % (i + 16))) for i in range(240)] - - colorback = [ - ("bgcolor-000", ANSI_BACK_BLACK), # pure black - ("bgcolor-001", ANSI_BACK_RED), - ("bgcolor-002", ANSI_BACK_GREEN), - ("bgcolor-003", ANSI_BACK_YELLOW), - ("bgcolor-004", ANSI_BACK_BLUE), - ("bgcolor-005", ANSI_BACK_MAGENTA), - ("bgcolor-006", ANSI_BACK_CYAN), - ("bgcolor-007", ANSI_BACK_WHITE), # light grey - ("bgcolor-008", hilite + ANSI_BACK_BLACK), # dark grey - ("bgcolor-009", hilite + ANSI_BACK_RED), - ("bgcolor-010", hilite + ANSI_BACK_GREEN), - ("bgcolor-011", hilite + ANSI_BACK_YELLOW), - ("bgcolor-012", hilite + ANSI_BACK_BLUE), - ("bgcolor-013", hilite + ANSI_BACK_MAGENTA), - ("bgcolor-014", hilite + ANSI_BACK_CYAN), - ("bgcolor-015", hilite + ANSI_BACK_WHITE), # pure white - ] + [("bgcolor-%03i" % (i + 16), XTERM256_BG % ("%i" % (i + 16))) for i in range(240)] - - # make sure to escape [ - # colorcodes = [(c, code.replace("[", r"\[")) for c, code in colorcodes] - # colorback = [(c, code.replace("[", r"\[")) for c, code in colorback] - fg_colormap = dict((code, clr) for clr, code in colorcodes) - bg_colormap = dict((code, clr) for clr, code in colorback) - - # create stop markers - fgstop = "(?:\033\[1m|\033\[22m){0,1}\033\[3[0-8].*?m|\033\[0m|$" - bgstop = "(?:\033\[1m|\033\[22m){0,1}\033\[4[0-8].*?m|\033\[0m|$" - bgfgstop = bgstop[:-2] + r"(\s*)" + fgstop - - fgstart = "((?:\033\[1m|\033\[22m){0,1}\033\[3[0-8].*?m)" - bgstart = "((?:\033\[1m|\033\[22m){0,1}\033\[4[0-8].*?m)" - bgfgstart = bgstart + r"(\s*)" + "((?:\033\[1m|\033\[22m){0,1}\033\[[3-4][0-8].*?m){0,1}" - - # extract color markers, tagging the start marker and the text marked - re_fgs = re.compile(fgstart + "(.*?)(?=" + fgstop + ")") - re_bgs = re.compile(bgstart + "(.*?)(?=" + bgstop + ")") - re_bgfg = re.compile(bgfgstart + "(.*?)(?=" + bgfgstop + ")") - - re_normal = re.compile(normal.replace("[", r"\[")) - re_hilite = re.compile("(?:%s)(.*)(?=%s|%s)" % (hilite.replace("[", r"\["), fgstop, bgstop)) - re_unhilite = re.compile("(?:%s)(.*)(?=%s|%s)" % (unhilite.replace("[", r"\["), fgstop, bgstop)) - re_uline = re.compile("(?:%s)(.*?)(?=%s|%s)" % (underline.replace("[", r"\["), fgstop, bgstop)) - re_blink = re.compile("(?:%s)(.*?)(?=%s|%s)" % (blink.replace("[", r"\["), fgstop, bgstop)) - re_inverse = re.compile("(?:%s)(.*?)(?=%s|%s)" % (inverse.replace("[", r"\["), fgstop, bgstop)) - re_string = re.compile( - r"(?P<htmlchars>[<&>])|(?P<tab>[\t]+)|(?P<space> +)|" - r"(?P<spacestart>^ )|(?P<lineend>\r\n|\r|\n)", - re.S | re.M | re.I, - ) - re_dblspace = re.compile(r" {2,}", re.M) - re_url = re.compile( - r'(?<!=")((?:ftp|www|https?)\W+(?:(?!\.(?:\s|$)|&\w+;)[^"\',;$*^\\(){}<>\[\]\s])+)(\.(?:\s|$)|&\w+;|)' - ) - re_mxplink = re.compile(r"\|lc(.*?)\|lt(.*?)\|le", re.DOTALL) - re_mxpurl = re.compile(r"\|lu(.*?)\|lt(.*?)\|le", re.DOTALL) - - def _sub_bgfg(self, colormatch): - # print("colormatch.groups()", colormatch.groups()) - bgcode, prespace, fgcode, text, postspace = colormatch.groups() - if not fgcode: - ret = r"""<span class="%s">%s%s%s</span>""" % ( - self.bg_colormap.get(bgcode, self.fg_colormap.get(bgcode, "err")), - prespace and "&nbsp;" * len(prespace) or "", - postspace and "&nbsp;" * len(postspace) or "", - text, - ) - else: - ret = r"""<span class="%s"><span class="%s">%s%s%s</span></span>""" % ( - self.bg_colormap.get(bgcode, self.fg_colormap.get(bgcode, "err")), - self.fg_colormap.get(fgcode, self.bg_colormap.get(fgcode, "err")), - prespace and "&nbsp;" * len(prespace) or "", - postspace and "&nbsp;" * len(postspace) or "", - text, - ) - return ret - - def _sub_fg(self, colormatch): - code, text = colormatch.groups() - return r"""<span class="%s">%s</span>""" % (self.fg_colormap.get(code, "err"), text) - - def _sub_bg(self, colormatch): - code, text = colormatch.groups() - return r"""<span class="%s">%s</span>""" % (self.bg_colormap.get(code, "err"), text) - -
[docs] def re_color(self, text): - """ - Replace ansi colors with html color class names. Let the - client choose how it will display colors, if it wishes to. - - Args: - text (str): the string with color to replace. - - Returns: - text (str): Re-colored text. - - """ - text = self.re_bgfg.sub(self._sub_bgfg, text) - text = self.re_fgs.sub(self._sub_fg, text) - text = self.re_bgs.sub(self._sub_bg, text) - text = self.re_normal.sub("", text) - return text
- -
[docs] def re_bold(self, text): - """ - Clean out superfluous hilights rather than set <strong>to make - it match the look of telnet. - - Args: - text (str): Text to process. - - Returns: - text (str): Processed text. - - """ - text = self.re_hilite.sub(r"<strong>\1</strong>", text) - return self.re_unhilite.sub(r"\1", text) # strip unhilite - there is no equivalent in css.
- -
[docs] def re_underline(self, text): - """ - Replace ansi underline with html underline class name. - - Args: - text (str): Text to process. - - Returns: - text (str): Processed text. - - """ - return self.re_uline.sub(r'<span class="underline">\1</span>', text)
- -
[docs] def re_blinking(self, text): - """ - Replace ansi blink with custom blink css class - - Args: - text (str): Text to process. - - Returns: - text (str): Processed text. - """ - return self.re_blink.sub(r'<span class="blink">\1</span>', text)
- -
[docs] def re_inversing(self, text): - """ - Replace ansi inverse with custom inverse css class - - Args: - text (str): Text to process. - - Returns: - text (str): Processed text. - """ - return self.re_inverse.sub(r'<span class="inverse">\1</span>', text)
- -
[docs] def remove_bells(self, text): - """ - Remove ansi specials - - Args: - text (str): Text to process. - - Returns: - text (str): Processed text. - - """ - return text.replace("\07", "")
- -
[docs] def remove_backspaces(self, text): - """ - Removes special escape sequences - - Args: - text (str): Text to process. - - Returns: - text (str): Processed text. - - """ - backspace_or_eol = r"(.\010)|(\033\[K)" - n = 1 - while n > 0: - text, n = re.subn(backspace_or_eol, "", text, 1) - return text
- -
[docs] def convert_linebreaks(self, text): - """ - Extra method for cleaning linebreaks - - Args: - text (str): Text to process. - - Returns: - text (str): Processed text. - - """ - return text.replace("\n", r"<br>")
- -
[docs] def convert_urls(self, text): - """ - Replace urls (http://...) by valid HTML. - - Args: - text (str): Text to process. - - Returns: - text (str): Processed text. - - """ - # -> added target to output prevent the web browser from attempting to - # change pages (and losing our webclient session). - return self.re_url.sub(r'<a href="\1" target="_blank">\1</a>\2', text)
- -
[docs] def re_double_space(self, text): - """ - HTML will swallow any normal space after the first, so if any slipped - through we must make sure to replace them with " &nbsp;" - """ - return self.re_dblspace.sub(self.sub_dblspace, text)
- - - -
[docs] def sub_mxp_urls(self, match): - """ - Helper method to be passed to re.sub, - replaces MXP links with HTML code. - Args: - match (re.Matchobject): Match for substitution. - Returns: - text (str): Processed text. - """ - url, text = [grp.replace('"', "\\&quot;") for grp in match.groups()] - val = ( - r"""<a id="mxplink" href="{url}" target="_blank">{text}</a>""".format(url=url, text=text) - ) - return val
- -
[docs] def sub_text(self, match): - """ - Helper method to be passed to re.sub, - for handling all substitutions. - - Args: - match (re.Matchobject): Match for substitution. - - Returns: - text (str): Processed text. - - """ - cdict = match.groupdict() - if cdict["htmlchars"]: - return html_escape(cdict["htmlchars"]) - elif cdict["lineend"]: - return "<br>" - elif cdict["tab"]: - text = cdict["tab"].replace("\t", " " + "&nbsp;" * (self.tabstop - 1)) - return text - elif cdict["space"] or cdict["spacestart"]: - text = cdict["space"] - text = " " if len(text) == 1 else " " + text[1:].replace(" ", "&nbsp;") - return text - return None
- -
[docs] def sub_dblspace(self, match): - "clean up double-spaces" - return " " + "&nbsp;" * (len(match.group()) - 1)
- -
[docs] def parse(self, text, strip_ansi=False): - """ - Main access function, converts a text containing ANSI codes - into html statements. - - Args: - text (str): Text to process. - strip_ansi (bool, optional): - - Returns: - text (str): Parsed text. - """ - # parse everything to ansi first - text = parse_ansi(text, strip_ansi=strip_ansi, xterm256=True, mxp=True) - # convert all ansi to html - result = re.sub(self.re_string, self.sub_text, text) - result = re.sub(self.re_mxplink, self.sub_mxp_links, result) - result = re.sub(self.re_mxpurl, self.sub_mxp_urls, result) - result = self.re_color(result) - result = self.re_bold(result) - result = self.re_underline(result) - result = self.re_blinking(result) - result = self.re_inversing(result) - result = self.remove_bells(result) - result = self.convert_linebreaks(result) - result = self.remove_backspaces(result) - result = self.convert_urls(result) - result = self.re_double_space(result) - # clean out eventual ansi that was missed - # result = parse_ansi(result, strip_ansi=True) - - return result
- - -HTML_PARSER = TextToHTMLparser() - - -# -# Access function -# - - -
[docs]def parse_html(string, strip_ansi=False, parser=HTML_PARSER): - """ - Parses a string, replace ANSI markup with html - """ - return parser.parse(string, strip_ansi=strip_ansi)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/utils.html b/docs/0.9.5/_modules/evennia/utils/utils.html deleted file mode 100644 index 30b3343eb9..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/utils.html +++ /dev/null @@ -1,2785 +0,0 @@ - - - - - - - - evennia.utils.utils — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.utils.utils

-# -*- encoding: utf-8 -*-
-"""
-General helper functions that don't fit neatly under any given category.
-
-They provide some useful string and conversion methods that might
-be of use when designing your own game.
-
-"""
-import os
-import gc
-import sys
-import types
-import math
-import re
-import textwrap
-import random
-import inspect
-import traceback
-import importlib
-import importlib.util
-import importlib.machinery
-from ast import literal_eval
-from simpleeval import simple_eval
-from unicodedata import east_asian_width
-from twisted.internet.task import deferLater
-from twisted.internet.defer import returnValue  # noqa - used as import target
-from twisted.internet import threads, reactor
-from os.path import join as osjoin
-from inspect import ismodule, trace, getmembers, getmodule, getmro
-from collections import defaultdict, OrderedDict
-from django.conf import settings
-from django.utils import timezone
-from django.utils.html import strip_tags
-from django.utils.translation import gettext as _
-from django.apps import apps
-from django.core.validators import validate_email as django_validate_email
-from django.core.exceptions import ValidationError as DjangoValidationError
-
-from evennia.utils import logger
-
-_MULTIMATCH_TEMPLATE = settings.SEARCH_MULTIMATCH_TEMPLATE
-_EVENNIA_DIR = settings.EVENNIA_DIR
-_GAME_DIR = settings.GAME_DIR
-ENCODINGS = settings.ENCODINGS
-
-_TASK_HANDLER = None
-_TICKER_HANDLER = None
-_STRIP_UNSAFE_TOKENS = None
-
-_GA = object.__getattribute__
-_SA = object.__setattr__
-_DA = object.__delattr__
-
-
-
[docs]def is_iter(obj): - """ - Checks if an object behaves iterably. - - Args: - obj (any): Entity to check for iterability. - - Returns: - is_iterable (bool): If `obj` is iterable or not. - - Notes: - Strings are *not* accepted as iterable (although they are - actually iterable), since string iterations are usually not - what we want to do with a string. - - """ - if isinstance(obj, (str, bytes)): - return False - - try: - return iter(obj) and True - except TypeError: - return False
- - -
[docs]def make_iter(obj): - """ - Makes sure that the object is always iterable. - - Args: - obj (any): Object to make iterable. - - Returns: - iterable (list or iterable): The same object - passed-through or made iterable. - - """ - return not is_iter(obj) and [obj] or obj
- - -
[docs]def wrap(text, width=None, indent=0): - """ - Safely wrap text to a certain number of characters. - - Args: - text (str): The text to wrap. - width (int, optional): The number of characters to wrap to. - indent (int): How much to indent each line (with whitespace). - - Returns: - text (str): Properly wrapped text. - - """ - width = width if width else settings.CLIENT_DEFAULT_WIDTH - if not text: - return "" - indent = " " * indent - return to_str(textwrap.fill(text, width, initial_indent=indent, subsequent_indent=indent))
- - -# alias - fill -fill = wrap - - -
[docs]def pad(text, width=None, align="c", fillchar=" "): - """ - Pads to a given width. - - Args: - text (str): Text to pad. - width (int, optional): The width to pad to, in characters. - align (str, optional): This is one of 'c', 'l' or 'r' (center, - left or right). - fillchar (str, optional): The character to fill with. - - Returns: - text (str): The padded text. - - """ - width = width if width else settings.CLIENT_DEFAULT_WIDTH - align = align if align in ("c", "l", "r") else "c" - fillchar = fillchar[0] if fillchar else " " - if align == "l": - return text.ljust(width, fillchar) - elif align == "r": - return text.rjust(width, fillchar) - else: - return text.center(width, fillchar)
- - -
[docs]def crop(text, width=None, suffix="[...]"): - """ - Crop text to a certain width, throwing away text from too-long - lines. - - Args: - text (str): Text to crop. - width (int, optional): Width of line to crop, in characters. - suffix (str, optional): This is appended to the end of cropped - lines to show that the line actually continues. Cropping - will be done so that the suffix will also fit within the - given width. If width is too small to fit both crop and - suffix, the suffix will be dropped. - - Returns: - text (str): The cropped text. - - """ - width = width if width else settings.CLIENT_DEFAULT_WIDTH - ltext = len(text) - if ltext <= width: - return text - else: - lsuffix = len(suffix) - text = text[:width] if lsuffix >= width else "%s%s" % (text[: width - lsuffix], suffix) - return to_str(text)
- - -
[docs]def dedent(text, baseline_index=None, indent=None): - """ - Safely clean all whitespace at the left of a paragraph. - - Args: - text (str): The text to dedent. - baseline_index (int, optional): Which row to use as a 'base' - for the indentation. Lines will be dedented to this level but - no further. If None, indent so as to completely deindent the - least indented text. - indent (int, optional): If given, force all lines to this indent. - This bypasses `baseline_index`. - - Returns: - text (str): Dedented string. - - Notes: - This is useful for preserving triple-quoted string indentation - while still shifting it all to be next to the left edge of the - display. - - """ - if not text: - return "" - if indent is not None: - lines = text.split("\n") - ind = " " * indent - indline = "\n" + ind - return ind + indline.join(line.strip() for line in lines) - elif baseline_index is None: - return textwrap.dedent(text) - else: - lines = text.split("\n") - baseline = lines[baseline_index] - spaceremove = len(baseline) - len(baseline.lstrip(" ")) - return "\n".join( - line[min(spaceremove, len(line) - len(line.lstrip(" "))):] for line in lines - )
- - -
[docs]def justify(text, width=None, align="f", indent=0): - """ - Fully justify a text so that it fits inside `width`. When using - full justification (default) this will be done by padding between - words with extra whitespace where necessary. Paragraphs will - be retained. - - Args: - text (str): Text to justify. - width (int, optional): The length of each line, in characters. - align (str, optional): The alignment, 'l', 'c', 'r' or 'f' - for left, center, right or full justification respectively. - indent (int, optional): Number of characters indentation of - entire justified text block. - - Returns: - justified (str): The justified and indented block of text. - - """ - width = width if width else settings.CLIENT_DEFAULT_WIDTH - - def _process_line(line): - """ - helper function that distributes extra spaces between words. The number - of gaps is nwords - 1 but must be at least 1 for single-word lines. We - distribute odd spaces randomly to one of the gaps. - """ - line_rest = width - (wlen + ngaps) - gap = " " # minimum gap between words - if line_rest > 0: - if align == "l": - if line[-1] == "\n\n": - line[-1] = " " * (line_rest - 1) + "\n" + " " * width + "\n" + " " * width - else: - line[-1] += " " * line_rest - elif align == "r": - line[0] = " " * line_rest + line[0] - elif align == "c": - pad = " " * (line_rest // 2) - line[0] = pad + line[0] - if line[-1] == "\n\n": - line[-1] += ( - pad + " " * (line_rest % 2 - 1) + "\n" + " " * width + "\n" + " " * width - ) - else: - line[-1] = line[-1] + pad + " " * (line_rest % 2) - else: # align 'f' - gap += " " * (line_rest // max(1, ngaps)) - rest_gap = line_rest % max(1, ngaps) - for i in range(rest_gap): - line[i] += " " - elif not any(line): - return [" " * width] - return gap.join(line) - - # split into paragraphs and words - paragraphs = re.split("\n\s*?\n", text, re.MULTILINE) - words = [] - for ip, paragraph in enumerate(paragraphs): - if ip > 0: - words.append(("\n", 0)) - words.extend((word, len(word)) for word in paragraph.split()) - ngaps, wlen, line = 0, 0, [] - - lines = [] - while words: - if not line: - # start a new line - word = words.pop(0) - wlen = word[1] - line.append(word[0]) - elif (words[0][1] + wlen + ngaps) >= width: - # next word would exceed word length of line + smallest gaps - lines.append(_process_line(line)) - ngaps, wlen, line = 0, 0, [] - else: - # put a new word on the line - word = words.pop(0) - line.append(word[0]) - if word[1] == 0: - # a new paragraph, process immediately - lines.append(_process_line(line)) - ngaps, wlen, line = 0, 0, [] - else: - wlen += word[1] - ngaps += 1 - - if line: # catch any line left behind - lines.append(_process_line(line)) - indentstring = " " * indent - return "\n".join([indentstring + line for line in lines])
- - -
[docs]def columnize(string, columns=2, spacing=4, align="l", width=None): - """ - Break a string into a number of columns, using as little - vertical space as possible. - - Args: - string (str): The string to columnize. - columns (int, optional): The number of columns to use. - spacing (int, optional): How much space to have between columns. - width (int, optional): The max width of the columns. - Defaults to client's default width. - - Returns: - columns (str): Text divided into columns. - - Raises: - RuntimeError: If given invalid values. - - """ - columns = max(1, columns) - spacing = max(1, spacing) - width = width if width else settings.CLIENT_DEFAULT_WIDTH - - w_spaces = (columns - 1) * spacing - w_txt = max(1, width - w_spaces) - - if w_spaces + columns > width: # require at least 1 char per column - raise RuntimeError("Width too small to fit columns") - - colwidth = int(w_txt / (1.0 * columns)) - - # first make a single column which we then split - onecol = justify(string, width=colwidth, align=align) - onecol = onecol.split("\n") - - nrows, dangling = divmod(len(onecol), columns) - nrows = [nrows + 1 if i < dangling else nrows for i in range(columns)] - - height = max(nrows) - cols = [] - istart = 0 - for irows in nrows: - cols.append(onecol[istart: istart + irows]) - istart = istart + irows - for col in cols: - if len(col) < height: - col.append(" " * colwidth) - - sep = " " * spacing - rows = [] - for irow in range(height): - rows.append(sep.join(col[irow] for col in cols)) - - return "\n".join(rows)
- - -
[docs]def iter_to_str(iterable, endsep=", and", addquote=False): - """ - This pretty-formats an iterable list as string output, adding an optional - alternative separator to the second to last entry. If `addquote` - is `True`, the outgoing strings will be surrounded by quotes. - - Args: - iterable (any): Usually an iterable to print. Each element must be possible to - present with a string. Note that if this is a generator, it will be - consumed by this operation. - endsep (str, optional): If set, the last item separator will - be replaced with this value. - addquote (bool, optional): This will surround all outgoing - values with double quotes. - - Returns: - str: The list represented as a string. - - Notes: - Default is to use 'Oxford comma', like 1, 2, 3, and 4. To remove, give - `endsep` as just `and`. - - Examples: - - ```python - >>> list_to_string([1,2,3], endsep='') - '1, 2, 3' - >>> list_to_string([1,2,3], ensdep='and') - '1, 2 and 3' - >>> list_to_string([1,2,3], endsep=', and', addquote=True) - '"1", "2", and "3"' - ``` - - """ - if not iterable: - return "" - iterable = list(make_iter(iterable)) - len_iter = len(iterable) - - if addquote: - iterable = tuple(f'"{val}"' for val in iterable) - else: - iterable = tuple(str(val) for val in iterable) - - if endsep.startswith(","): - # oxford comma alternative - endsep = endsep[1:] if len_iter < 3 else endsep - elif endsep: - # normal space-separated end separator - endsep = " " + str(endsep).strip() - else: - # no separator given - use comma - endsep = ',' - - if len_iter == 1: - return str(iterable[0]) - elif len_iter == 2: - return f"{endsep} ".join(str(v) for v in iterable) - else: - return ", ".join(str(v) for v in iterable[:-1]) + f"{endsep} {iterable[-1]}"
- - -# legacy aliases -list_to_string = iter_to_str -iter_to_string = iter_to_str - - -
[docs]def wildcard_to_regexp(instring): - """ - Converts a player-supplied string that may have wildcards in it to - regular expressions. This is useful for name matching. - - Args: - instring (string): A string that may potentially contain - wildcards (`*` or `?`). - - Returns: - regex (str): A string where wildcards were replaced with - regular expressions. - - """ - regexp_string = "" - - # If the string starts with an asterisk, we can't impose the beginning of - # string (^) limiter. - if instring[0] != "*": - regexp_string += "^" - - # Replace any occurances of * or ? with the appropriate groups. - regexp_string += instring.replace("*", "(.*)").replace("?", "(.{1})") - - # If there's an asterisk at the end of the string, we can't impose the - # end of string ($) limiter. - if instring[-1] != "*": - regexp_string += "$" - - return regexp_string
- - -
[docs]def time_format(seconds, style=0): - """ - Function to return a 'prettified' version of a value in seconds. - - Args: - seconds (int): Number if seconds to format. - style (int): One of the following styles: - 0. "1d 08:30" - 1. "1d" - 2. "1 day, 8 hours, 30 minutes" - 3. "1 day, 8 hours, 30 minutes, 10 seconds" - 4. highest unit (like "3 years" or "8 months" or "1 second") - Returns: - timeformatted (str): A pretty time string. - """ - if seconds < 0: - seconds = 0 - else: - # We'll just use integer math, no need for decimal precision. - seconds = int(seconds) - - days = seconds // 86400 - seconds -= days * 86400 - hours = seconds // 3600 - seconds -= hours * 3600 - minutes = seconds // 60 - seconds -= minutes * 60 - - retval = "" - if style == 0: - """ - Standard colon-style output. - """ - if days > 0: - retval = "%id %02i:%02i" % (days, hours, minutes) - else: - retval = "%02i:%02i" % (hours, minutes) - return retval - - elif style == 1: - """ - Simple, abbreviated form that only shows the highest time amount. - """ - if days > 0: - return "%id" % (days,) - elif hours > 0: - return "%ih" % (hours,) - elif minutes > 0: - return "%im" % (minutes,) - else: - return "%is" % (seconds,) - elif style == 2: - """ - Full-detailed, long-winded format. We ignore seconds. - """ - days_str = hours_str = "" - minutes_str = "0 minutes" - - if days > 0: - if days == 1: - days_str = "%i day, " % days - else: - days_str = "%i days, " % days - if days or hours > 0: - if hours == 1: - hours_str = "%i hour, " % hours - else: - hours_str = "%i hours, " % hours - if hours or minutes > 0: - if minutes == 1: - minutes_str = "%i minute " % minutes - else: - minutes_str = "%i minutes " % minutes - retval = "%s%s%s" % (days_str, hours_str, minutes_str) - elif style == 3: - """ - Full-detailed, long-winded format. Includes seconds. - """ - days_str = hours_str = minutes_str = seconds_str = "" - if days > 0: - if days == 1: - days_str = "%i day, " % days - else: - days_str = "%i days, " % days - if days or hours > 0: - if hours == 1: - hours_str = "%i hour, " % hours - else: - hours_str = "%i hours, " % hours - if hours or minutes > 0: - if minutes == 1: - minutes_str = "%i minute " % minutes - else: - minutes_str = "%i minutes " % minutes - if minutes or seconds > 0: - if seconds == 1: - seconds_str = "%i second " % seconds - else: - seconds_str = "%i seconds " % seconds - retval = "%s%s%s%s" % (days_str, hours_str, minutes_str, seconds_str) - elif style == 4: - """ - Only return the highest unit. - """ - if days >= 730: # Several years - return "{} years".format(days // 365) - elif days >= 365: # One year - return "a year" - elif days >= 62: # Several months - return "{} months".format(days // 31) - elif days >= 31: # One month - return "a month" - elif days >= 2: # Several days - return "{} days".format(days) - elif days > 0: - return "a day" - elif hours >= 2: # Several hours - return "{} hours".format(hours) - elif hours > 0: # One hour - return "an hour" - elif minutes >= 2: # Several minutes - return "{} minutes".format(minutes) - elif minutes > 0: # One minute - return "a minute" - elif seconds >= 2: # Several seconds - return "{} seconds".format(seconds) - elif seconds == 1: - return "a second" - else: - return "0 seconds" - else: - raise ValueError("Unknown style for time format: %s" % style) - - return retval.strip()
- - -
[docs]def datetime_format(dtobj): - """ - Pretty-prints the time since a given time. - - Args: - dtobj (datetime): An datetime object, e.g. from Django's - `DateTimeField`. - - Returns: - deltatime (str): A string describing how long ago `dtobj` - took place. - - """ - - now = timezone.now() - - if dtobj.year < now.year: - # another year (Apr 5, 2019) - timestring = dtobj.strftime(f"%b {dtobj.day}, %Y") - elif dtobj.date() < now.date(): - # another date, same year (Apr 5) - timestring = dtobj.strftime(f"%b {dtobj.day}") - elif dtobj.hour < now.hour - 1: - # same day, more than 1 hour ago (10:45) - timestring = dtobj.strftime("%H:%M") - else: - # same day, less than 1 hour ago (10:45:33) - timestring = dtobj.strftime("%H:%M:%S") - return timestring
- - -
[docs]def host_os_is(osname): - """ - Check to see if the host OS matches the query. - - Args: - osname (str): Common names are "posix" (linux/unix/mac) and - "nt" (windows). - - Args: - is_os (bool): If the os matches or not. - - """ - return os.name == osname
- - -
[docs]def get_evennia_version(mode="long"): - """ - Helper method for getting the current evennia version. - - Args: - mode (str, optional): One of: - - long: 0.9.0 rev342453534 - - short: 0.9.0 - - pretty: Evennia 0.9.0 - - Returns: - version (str): The version string. - - """ - import evennia - - vers = evennia.__version__ - if mode == "short": - return vers.split()[0].strip() - elif mode == "pretty": - vers = vers.split()[0].strip() - return f"Evennia {vers}" - else: # mode "long": - return vers
- - -
[docs]def pypath_to_realpath(python_path, file_ending=".py", pypath_prefixes=None): - """ - Converts a dotted Python path to an absolute path under the - Evennia library directory or under the current game directory. - - Args: - python_path (str): A dot-python path - file_ending (str): A file ending, including the period. - pypath_prefixes (list): A list of paths to test for existence. These - should be on python.path form. EVENNIA_DIR and GAME_DIR are automatically - checked, they need not be added to this list. - - Returns: - abspaths (list): All existing, absolute paths created by - converting `python_path` to an absolute paths and/or - prepending `python_path` by `settings.EVENNIA_DIR`, - `settings.GAME_DIR` and by`pypath_prefixes` respectively. - - Notes: - This will also try a few combinations of paths to allow cases - where pypath is given including the "evennia." or "mygame." - prefixes. - - """ - path = python_path.strip().split(".") - plong = osjoin(*path) + file_ending - pshort = ( - osjoin(*path[1:]) + file_ending if len(path) > 1 else plong - ) # in case we had evennia. or mygame. - prefixlong = ( - [osjoin(*ppath.strip().split(".")) for ppath in make_iter(pypath_prefixes)] - if pypath_prefixes - else [] - ) - prefixshort = ( - [ - osjoin(*ppath.strip().split(".")[1:]) - for ppath in make_iter(pypath_prefixes) - if len(ppath.strip().split(".")) > 1 - ] - if pypath_prefixes - else [] - ) - paths = ( - [plong] - + [osjoin(_EVENNIA_DIR, prefix, plong) for prefix in prefixlong] - + [osjoin(_GAME_DIR, prefix, plong) for prefix in prefixlong] - + [osjoin(_EVENNIA_DIR, prefix, plong) for prefix in prefixshort] - + [osjoin(_GAME_DIR, prefix, plong) for prefix in prefixshort] - + [osjoin(_EVENNIA_DIR, plong), osjoin(_GAME_DIR, plong)] - + [osjoin(_EVENNIA_DIR, prefix, pshort) for prefix in prefixshort] - + [osjoin(_GAME_DIR, prefix, pshort) for prefix in prefixshort] - + [osjoin(_EVENNIA_DIR, prefix, pshort) for prefix in prefixlong] - + [osjoin(_GAME_DIR, prefix, pshort) for prefix in prefixlong] - + [osjoin(_EVENNIA_DIR, pshort), osjoin(_GAME_DIR, pshort)] - ) - # filter out non-existing paths - return list(set(p for p in paths if os.path.isfile(p)))
- - -
[docs]def dbref(inp, reqhash=True): - """ - Converts/checks if input is a valid dbref. - - Args: - inp (int, str): A database ref on the form N or #N. - reqhash (bool, optional): Require the #N form to accept - input as a valid dbref. - - Returns: - dbref (int or None): The integer part of the dbref or `None` - if input was not a valid dbref. - - """ - if reqhash: - num = ( - int(inp.lstrip("#")) - if (isinstance(inp, str) and inp.startswith("#") and inp.lstrip("#").isdigit()) - else None - ) - return num if isinstance(num, int) and num > 0 else None - elif isinstance(inp, str): - inp = inp.lstrip("#") - return int(inp) if inp.isdigit() and int(inp) > 0 else None - else: - return inp if isinstance(inp, int) else None
- - -
[docs]def dbref_to_obj(inp, objclass, raise_errors=True): - """ - Convert a #dbref to a valid object. - - Args: - inp (str or int): A valid #dbref. - objclass (class): A valid django model to filter against. - raise_errors (bool, optional): Whether to raise errors - or return `None` on errors. - - Returns: - obj (Object or None): An entity loaded from the dbref. - - Raises: - Exception: If `raise_errors` is `True` and - `objclass.objects.get(id=dbref)` did not return a valid - object. - - """ - dbid = dbref(inp) - if not dbid: - # we only convert #dbrefs - return inp - try: - if dbid < 0: - return None - except ValueError: - return None - - # if we get to this point, inp is an integer dbref; get the matching object - try: - return objclass.objects.get(id=dbid) - except Exception: - if raise_errors: - raise - return inp
- - -# legacy alias -dbid_to_obj = dbref_to_obj - - -# some direct translations for the latinify -_UNICODE_MAP = { - "EM DASH": "-", - "FIGURE DASH": "-", - "EN DASH": "-", - "HORIZONTAL BAR": "-", - "HORIZONTAL ELLIPSIS": "...", - "LEFT SINGLE QUOTATION MARK": "'", - "RIGHT SINGLE QUOTATION MARK": "'", - "LEFT DOUBLE QUOTATION MARK": '"', - "RIGHT DOUBLE QUOTATION MARK": '"', -} - - -
[docs]def latinify(string, default="?", pure_ascii=False): - """ - Convert a unicode string to "safe" ascii/latin-1 characters. - This is used as a last resort when normal encoding does not work. - - Arguments: - string (str): A string to convert to 'safe characters' convertable - to an latin-1 bytestring later. - default (str, optional): Characters resisting mapping will be replaced - with this character or string. The intent is to apply an encode operation - on the string soon after. - - Returns: - string (str): A 'latinified' string where each unicode character has been - replaced with a 'safe' equivalent available in the ascii/latin-1 charset. - Notes: - This is inspired by the gist by Ricardo Murri: - https://gist.github.com/riccardomurri/3c3ccec30f037be174d3 - - """ - - from unicodedata import name - - if isinstance(string, bytes): - string = string.decode("utf8") - - converted = [] - for unich in iter(string): - try: - ch = unich.encode("utf8").decode("ascii") - except UnicodeDecodeError: - # deduce a latin letter equivalent from the Unicode data - # point name; e.g., since `name(u'á') == 'LATIN SMALL - # LETTER A WITH ACUTE'` translate `á` to `a`. However, in - # some cases the unicode name is still "LATIN LETTER" - # although no direct equivalent in the Latin alphabet - # exists (e.g., Þ, "LATIN CAPITAL LETTER THORN") -- we can - # avoid these cases by checking that the letter name is - # composed of one letter only. - # We also supply some direct-translations for some particular - # common cases. - what = name(unich) - if what in _UNICODE_MAP: - ch = _UNICODE_MAP[what] - else: - what = what.split() - if what[0] == "LATIN" and what[2] == "LETTER" and len(what[3]) == 1: - ch = what[3].lower() if what[1] == "SMALL" else what[3].upper() - else: - ch = default - converted.append(chr(ord(ch))) - return "".join(converted)
- - -
[docs]def to_bytes(text, session=None): - """ - Try to encode the given text to bytes, using encodings from settings or from Session. Will - always return a bytes, even if given something that is not str or bytes. - - Args: - text (any): The text to encode to bytes. If bytes, return unchanged. If not a str, convert - to str before converting. - session (Session, optional): A Session to get encoding info from. Will try this before - falling back to settings.ENCODINGS. - - Returns: - encoded_text (bytes): the encoded text following the session's protocol flag followed by the - encodings specified in settings.ENCODINGS. If all attempt fail, log the error and send - the text with "?" in place of problematic characters. If the specified encoding cannot - be found, the protocol flag is reset to utf-8. In any case, returns bytes. - - Notes: - If `text` is already bytes, return it as is. - - """ - if isinstance(text, bytes): - return text - if not isinstance(text, str): - # convert to a str representation before encoding - try: - text = str(text) - except Exception: - text = repr(text) - - default_encoding = session.protocol_flags.get("ENCODING", "utf-8") if session else "utf-8" - try: - return text.encode(default_encoding) - except (LookupError, UnicodeEncodeError): - for encoding in settings.ENCODINGS: - try: - return text.encode(encoding) - except (LookupError, UnicodeEncodeError): - pass - # no valid encoding found. Replace unconvertable parts with ? - return text.encode(default_encoding, errors="replace")
- - -
[docs]def to_str(text, session=None): - """ - Try to decode a bytestream to a python str, using encoding schemas from settings - or from Session. Will always return a str(), also if not given a str/bytes. - - Args: - text (any): The text to encode to bytes. If a str, return it. If also not bytes, convert - to str using str() or repr() as a fallback. - session (Session, optional): A Session to get encoding info from. Will try this before - falling back to settings.ENCODINGS. - - Returns: - decoded_text (str): The decoded text. - - Notes: - If `text` is already str, return it as is. - """ - if isinstance(text, str): - return text - if not isinstance(text, bytes): - # not a byte, convert directly to str - try: - return str(text) - except Exception: - return repr(text) - - default_encoding = session.protocol_flags.get("ENCODING", "utf-8") if session else "utf-8" - try: - return text.decode(default_encoding) - except (LookupError, UnicodeDecodeError): - for encoding in settings.ENCODINGS: - try: - return text.decode(encoding) - except (LookupError, UnicodeDecodeError): - pass - # no valid encoding found. Replace unconvertable parts with ? - return text.decode(default_encoding, errors="replace")
- - -
[docs]def validate_email_address(emailaddress): - """ - Checks if an email address is syntactically correct. Makes use - of the django email-validator for consistency. - - Args: - emailaddress (str): Email address to validate. - - Returns: - bool: If this is a valid email or not. - - """ - try: - django_validate_email(str(emailaddress)) - except DjangoValidationError: - return False - except Exception: - logger.log_trace() - return False - else: - return True
- - -
[docs]def inherits_from(obj, parent): - """ - Takes an object and tries to determine if it inherits at *any* - distance from parent. - - Args: - obj (any): Object to analyze. This may be either an instance or - a class. - parent (any): Can be either an instance, a class or the python - path to the class. - - Returns: - inherits_from (bool): If `parent` is a parent to `obj` or not. - - Notes: - What differentiates this function from Python's `isinstance()` is the - flexibility in the types allowed for the object and parent being compared. - - """ - - if callable(obj): - # this is a class - obj_paths = ["%s.%s" % (mod.__module__, mod.__name__) for mod in obj.mro()] - else: - obj_paths = ["%s.%s" % (mod.__module__, mod.__name__) for mod in obj.__class__.mro()] - - if isinstance(parent, str): - # a given string path, for direct matching - parent_path = parent - elif callable(parent): - # this is a class - parent_path = "%s.%s" % (parent.__module__, parent.__name__) - else: - parent_path = "%s.%s" % (parent.__class__.__module__, parent.__class__.__name__) - return any(1 for obj_path in obj_paths if obj_path == parent_path)
- - -
[docs]def server_services(): - """ - Lists all services active on the Server. Observe that since - services are launched in memory, this function will only return - any results if called from inside the game. - - Returns: - services (dict): A dict of available services. - - """ - from evennia.server.sessionhandler import SESSIONS - - if hasattr(SESSIONS, "server") and hasattr(SESSIONS.server, "services"): - server = SESSIONS.server.services.namedServices - else: - # This function must be called from inside the evennia process. - server = {} - del SESSIONS - return server
- - -
[docs]def uses_database(name="sqlite3"): - """ - Checks if the game is currently using a given database. This is a - shortcut to having to use the full backend name. - - Args: - name (str): One of 'sqlite3', 'mysql', 'postgresql' or 'oracle'. - - Returns: - uses (bool): If the given database is used or not. - - """ - try: - engine = settings.DATABASES["default"]["ENGINE"] - except KeyError: - engine = settings.DATABASE_ENGINE - return engine == "django.db.backends.%s" % name
- - -
[docs]def delay(timedelay, callback, *args, **kwargs): - """ - Delay the calling of a callback (function). - - Args: - timedelay (int or float): The delay in seconds. - callback (callable): Will be called as `callback(*args, **kwargs)` - after `timedelay` seconds. - *args: Will be used as arguments to callback - Keyword Args: - persistent (bool, optional): If True the delay remains after a server restart. - persistent is False by default. - any (any): Will be used as keyword arguments to callback. - - Returns: - task (TaskHandlerTask): An instance of a task. - Refer to, evennia.scripts.taskhandler.TaskHandlerTask - - Notes: - The task handler (`evennia.scripts.taskhandler.TASK_HANDLER`) will - be called for persistent or non-persistent tasks. - If persistent is set to True, the callback, its arguments - and other keyword arguments will be saved (serialized) in the database, - assuming they can be. The callback will be executed even after - a server restart/reload, taking into account the specified delay - (and server down time). - Keep in mind that persistent tasks arguments and callback should not - use memory references. - If persistent is set to True the delay function will return an int - which is the task's id itended for use with TASK_HANDLER's do_task - and remove methods. - All persistent tasks whose time delays have passed will be called on server startup. - - """ - global _TASK_HANDLER - if _TASK_HANDLER is None: - from evennia.scripts.taskhandler import TASK_HANDLER as _TASK_HANDLER - - return _TASK_HANDLER.add(timedelay, callback, *args, **kwargs)
- - -
[docs]def repeat(interval, callback, persistent=True, idstring="", stop=False, - store_key=None, *args, **kwargs): - """ - Start a repeating task using the TickerHandler. - - Args: - interval (int): How often to call callback. - callback (callable): This will be called with `*args, **kwargs` every - `interval` seconds. This must be possible to pickle regardless - of if `persistent` is set or not! - persistent (bool, optional): If ticker survives a server reload. - idstring (str, optional): Separates multiple tickers. This is useful - mainly if wanting to set up multiple repeats for the same - interval/callback but with different args/kwargs. - stop (bool, optional): If set, use the given parameters to _stop_ a running - ticker instead of creating a new one. - store_key (tuple, optional): This is only used in combination with `stop` and - should be the return given from the original `repeat` call. If this - is given, all other args except `stop` are ignored. - *args: Used as arguments to `callback`. - **kwargs: Keyword-arguments to pass to `callback`. - - Returns: - tuple or None: The tuple is the `store_key` - the identifier for the - created ticker. Store this and pass into unrepat() in order to to stop - this ticker later. Returns `None` if `stop=True`. - - Raises: - KeyError: If trying to stop a ticker that was not found. - - """ - global _TICKER_HANDLER - if _TICKER_HANDLER is None: - from evennia.scripts.tickerhandler import TICKER_HANDLER as _TICKER_HANDLER - - if stop: - # we pass all args, but only store_key matters if given - _TICKER_HANDLER.remove(interval=interval, - callback=callback, - idstring=idstring, - persistent=persistent, - store_key=store_key) - else: - return _TICKER_HANDLER.add(interval=interval, - callback=callback, - idstring=idstring, - persistent=persistent)
- -
[docs]def unrepeat(store_key): - """ - This is used to stop a ticker previously started with `repeat`. - - Args: - store_key (tuple): This is the return from `repeat`, used to uniquely - identify the ticker to stop. Without the store_key, the ticker - must be stopped by passing its parameters to `TICKER_HANDLER.remove` - directly. - - Returns: - bool: True if a ticker was stopped, False if not (for example because no - matching ticker was found or it was already stopped). - - """ - try: - repeat(None, None, stop=True, store_key=store_key) - return True - except KeyError: - return False
- - -_PPOOL = None -_PCMD = None -_PROC_ERR = "A process has ended with a probable error condition: process ended by signal 9." - - -
[docs]def run_async(to_execute, *args, **kwargs): - """ - Runs a function or executes a code snippet asynchronously. - - Args: - to_execute (callable): If this is a callable, it will be - executed with `*args` and non-reserved `**kwargs` as arguments. - The callable will be executed using ProcPool, or in a thread - if ProcPool is not available. - Keyword Args: - at_return (callable): Should point to a callable with one - argument. It will be called with the return value from - to_execute. - at_return_kwargs (dict): This dictionary will be used as - keyword arguments to the at_return callback. - at_err (callable): This will be called with a Failure instance - if there is an error in to_execute. - at_err_kwargs (dict): This dictionary will be used as keyword - arguments to the at_err errback. - - Notes: - All other `*args` and `**kwargs` will be passed on to - `to_execute`. Run_async will relay executed code to a thread - or procpool. - - Use this function with restrain and only for features/commands - that you know has no influence on the cause-and-effect order of your - game (commands given after the async function might be executed before - it has finished). Accessing the same property from different threads - can lead to unpredicted behaviour if you are not careful (this is called a - "race condition"). - - Also note that some databases, notably sqlite3, don't support access from - multiple threads simultaneously, so if you do heavy database access from - your `to_execute` under sqlite3 you will probably run very slow or even get - tracebacks. - - """ - - # handle special reserved input kwargs - callback = kwargs.pop("at_return", None) - errback = kwargs.pop("at_err", None) - callback_kwargs = kwargs.pop("at_return_kwargs", {}) - errback_kwargs = kwargs.pop("at_err_kwargs", {}) - - if callable(to_execute): - # no process pool available, fall back to old deferToThread mechanism. - deferred = threads.deferToThread(to_execute, *args, **kwargs) - else: - # no appropriate input for this server setup - raise RuntimeError("'%s' could not be handled by run_async" % to_execute) - - # attach callbacks - if callback: - deferred.addCallback(callback, **callback_kwargs) - deferred.addErrback(errback, **errback_kwargs)
- - -
[docs]def check_evennia_dependencies(): - """ - Checks the versions of Evennia's dependencies including making - some checks for runtime libraries. - - Returns: - result (bool): `False` if a show-stopping version mismatch is - found. - - """ - - # check main dependencies - from evennia.server.evennia_launcher import check_main_evennia_dependencies - - not_error = check_main_evennia_dependencies() - - errstring = "" - # South is no longer used ... - if "south" in settings.INSTALLED_APPS: - errstring += ( - "\n ERROR: 'south' found in settings.INSTALLED_APPS. " - "\n South is no longer used. If this was added manually, remove it." - ) - not_error = False - # IRC support - if settings.IRC_ENABLED: - try: - import twisted.words - - twisted.words # set to avoid debug info about not-used import - except ImportError: - errstring += ( - "\n ERROR: IRC is enabled, but twisted.words is not installed. Please install it." - "\n Linux Debian/Ubuntu users should install package 'python-twisted-words', " - "\n others can get it from http://twistedmatrix.com/trac/wiki/TwistedWords." - ) - not_error = False - errstring = errstring.strip() - if errstring: - mlen = max(len(line) for line in errstring.split("\n")) - logger.log_err("%s\n%s\n%s" % ("-" * mlen, errstring, "-" * mlen)) - return not_error
- - -
[docs]def has_parent(basepath, obj): - """ - Checks if `basepath` is somewhere in obj's parent tree. - - Args: - basepath (str): Python dotpath to compare against obj path. - obj (any): Object whose path is to be checked. - - Returns: - has_parent (bool): If the check was successful or not. - - """ - try: - return any( - cls - for cls in obj.__class__.mro() - if basepath == "%s.%s" % (cls.__module__, cls.__name__) - ) - except (TypeError, AttributeError): - # this can occur if we tried to store a class object, not an - # instance. Not sure if one should defend against this. - return False
- - -
[docs]def mod_import_from_path(path): - """ - Load a Python module at the specified path. - - Args: - path (str): An absolute path to a Python module to load. - - Returns: - (module or None): An imported module if the path was a valid - Python module. Returns `None` if the import failed. - - """ - if not os.path.isabs(path): - path = os.path.abspath(path) - dirpath, filename = path.rsplit(os.path.sep, 1) - modname = filename.rstrip(".py") - - try: - return importlib.machinery.SourceFileLoader(modname, path).load_module() - except OSError: - logger.log_trace(f"Could not find module '{modname}' ({modname}.py) at path '{dirpath}'") - return None
- - -
[docs]def mod_import(module): - """ - A generic Python module loader. - - Args: - module (str, module): This can be either a Python path - (dot-notation like `evennia.objects.models`), an absolute path - (e.g. `/home/eve/evennia/evennia/objects/models.py`) or an - already imported module object (e.g. `models`) - Returns: - (module or None): An imported module. If the input argument was - already a module, this is returned as-is, otherwise the path is - parsed and imported. Returns `None` and logs error if import failed. - - """ - if not module: - return None - - if isinstance(module, types.ModuleType): - # if this is already a module, we are done - return module - - if module.endswith(".py") and os.path.exists(module): - return mod_import_from_path(module) - - try: - return importlib.import_module(module) - except ImportError: - return None
- - -
[docs]def all_from_module(module): - """ - Return all global-level variables defined in a module. - - Args: - module (str, module): This can be either a Python path - (dot-notation like `evennia.objects.models`), an absolute path - (e.g. `/home/eve/evennia/evennia/objects.models.py`) or an - already imported module object (e.g. `models`) - - Returns: - dict: A dict of {variablename: variable} for all - variables in the given module. - - Notes: - Ignores modules and variable names starting with an underscore, as well - as variables imported into the module from other modules. - - """ - mod = mod_import(module) - if not mod: - return {} - # make sure to only return variables actually defined in this - # module if available (try to avoid imports) - members = getmembers(mod, predicate=lambda obj: getmodule(obj) in (mod, None)) - return dict((key, val) for key, val in members if not key.startswith("_"))
- - -
[docs]def callables_from_module(module): - """ - Return all global-level callables defined in a module. - - Args: - module (str, module): A python-path to a module or an actual - module object. - - Returns: - callables (dict): A dict of {name: callable, ...} from the module. - - Notes: - Will ignore callables whose names start with underscore "_". - - """ - mod = mod_import(module) - if not mod: - return {} - # make sure to only return callables actually defined in this module (not imports) - members = getmembers(mod, predicate=lambda obj: callable(obj) and getmodule(obj) == mod) - return dict((key, val) for key, val in members if not key.startswith("_"))
- - -
[docs]def variable_from_module(module, variable=None, default=None): - """ - Retrieve a variable or list of variables from a module. The - variable(s) must be defined globally in the module. If no variable - is given (or a list entry is `None`), all global variables are - extracted from the module. - - Args: - module (string or module): Python path, absolute path or a module. - variable (string or iterable, optional): Single variable name or iterable - of variable names to extract. If not given, all variables in - the module will be returned. - default (string, optional): Default value to use if a variable fails to - be extracted. Ignored if `variable` is not given. - - Returns: - variables (value or list): A single value or a list of values - depending on if `variable` is given or not. Errors in lists - are replaced by the `default` argument. - - """ - - if not module: - return default - - mod = mod_import(module) - - if not mod: - return default - - if variable: - result = [] - for var in make_iter(variable): - if var: - # try to pick a named variable - result.append(mod.__dict__.get(var, default)) - else: - # get all - result = [ - val for key, val in mod.__dict__.items() if not (key.startswith("_") or ismodule(val)) - ] - - if len(result) == 1: - return result[0] - return result
- - -
[docs]def string_from_module(module, variable=None, default=None): - """ - This is a wrapper for `variable_from_module` that requires return - value to be a string to pass. It's primarily used by login screen. - - Args: - module (string or module): Python path, absolute path or a module. - variable (string or iterable, optional): Single variable name or iterable - of variable names to extract. If not given, all variables in - the module will be returned. - default (string, optional): Default value to use if a variable fails to - be extracted. Ignored if `variable` is not given. - - Returns: - variables (value or list): A single (string) value or a list of values - depending on if `variable` is given or not. Errors in lists (such - as the value not being a string) are replaced by the `default` argument. - - """ - val = variable_from_module(module, variable=variable, default=default) - if val: - if variable: - return val - else: - result = [v for v in make_iter(val) if isinstance(v, str)] - return result if result else default - return default
- - -
[docs]def random_string_from_module(module): - """ - Returns a random global string from a module. - - Args: - module (string or module): Python path, absolute path or a module. - - Returns: - random (string): A random stribg variable from `module`. - """ - return random.choice(string_from_module(module))
- - -
[docs]def fuzzy_import_from_module(path, variable, default=None, defaultpaths=None): - """ - Import a variable based on a fuzzy path. First the literal - `path` will be tried, then all given `defaultpaths` will be - prepended to see a match is found. - - Args: - path (str): Full or partial python path. - variable (str): Name of variable to import from module. - default (string, optional): Default value to use if a variable fails to - be extracted. Ignored if `variable` is not given. - defaultpaths (iterable, options): Python paths to attempt in order if - importing directly from `path` doesn't work. - - Returns: - value (any): The variable imported from the module, or `default`, if - not found. - - """ - paths = [path] + make_iter(defaultpaths) - for modpath in paths: - try: - mod = importlib.import_module(modpath) - except ImportError as ex: - if not str(ex).startswith("No module named %s" % modpath): - # this means the module was found but it - # triggers an ImportError on import. - raise ex - return getattr(mod, variable, default) - return default
- - -
[docs]def class_from_module(path, defaultpaths=None, fallback=None): - """ - Return a class from a module, given the class' full python path. This is - primarily used to convert db_typeclass_path:s to classes. - - Args: - path (str): Full Python dot-path to module. - defaultpaths (iterable, optional): If a direct import from `path` fails, - try subsequent imports by prepending those paths to `path`. - fallback (str): If all other attempts fail, use this path as a fallback. - This is intended as a last-resport. In the example of Evennia - loading, this would be a path to a default parent class in the - evennia repo itself. - - Returns: - class (Class): An uninstatiated class recovered from path. - - Raises: - ImportError: If all loading failed. - - """ - cls = None - err = "" - if defaultpaths: - paths = ( - [path] + ["%s.%s" % (dpath, path) for dpath in make_iter(defaultpaths)] - if defaultpaths - else [] - ) - else: - paths = [path] - - for testpath in paths: - if "." in path: - testpath, clsname = testpath.rsplit(".", 1) - else: - raise ImportError("the path '%s' is not on the form modulepath.Classname." % path) - - try: - if not importlib.util.find_spec(testpath, package="evennia"): - continue - except ModuleNotFoundError: - continue - - try: - mod = importlib.import_module(testpath, package="evennia") - except ModuleNotFoundError: - err = traceback.format_exc(30) - break - - try: - cls = getattr(mod, clsname) - break - except AttributeError: - if len(trace()) > 2: - # AttributeError within the module, don't hide it - err = traceback.format_exc(30) - break - if not cls: - err = "\nCould not load typeclass '{}'{}".format( - path, " with the following traceback:\n" + err if err else "" - ) - if defaultpaths: - err += "\nPaths searched:\n %s" % "\n ".join(paths) - else: - err += "." - logger.log_err(err) - if fallback: - logger.log_warn(f"Falling back to {fallback}.") - return class_from_module(fallback) - else: - # even fallback fails - raise ImportError(err) - return cls
- - -# alias -object_from_module = class_from_module - - -
[docs]def init_new_account(account): - """ - Deprecated. - """ - from evennia.utils import logger - - logger.log_dep("evennia.utils.utils.init_new_account is DEPRECATED and should not be used.")
- - -
[docs]def string_similarity(string1, string2): - """ - This implements a "cosine-similarity" algorithm as described for example in - *Proceedings of the 22nd International Conference on Computation - Linguistics* (Coling 2008), pages 593-600, Manchester, August 2008. - The measure-vectors used is simply a "bag of words" type histogram - (but for letters). - - Args: - string1 (str): String to compare (may contain any number of words). - string2 (str): Second string to compare (any number of words). - - Returns: - similarity (float): A value 0...1 rating how similar the two - strings are. - - """ - vocabulary = set(list(string1 + string2)) - vec1 = [string1.count(v) for v in vocabulary] - vec2 = [string2.count(v) for v in vocabulary] - try: - return float(sum(vec1[i] * vec2[i] for i in range(len(vocabulary)))) / ( - math.sqrt(sum(v1 ** 2 for v1 in vec1)) * math.sqrt(sum(v2 ** 2 for v2 in vec2)) - ) - except ZeroDivisionError: - # can happen if empty-string cmdnames appear for some reason. - # This is a no-match. - return 0
- - -
[docs]def string_suggestions(string, vocabulary, cutoff=0.6, maxnum=3): - """ - Given a `string` and a `vocabulary`, return a match or a list of - suggestions based on string similarity. - - Args: - string (str): A string to search for. - vocabulary (iterable): A list of available strings. - cutoff (int, 0-1): Limit the similarity matches (the higher - the value, the more exact a match is required). - maxnum (int): Maximum number of suggestions to return. - - Returns: - suggestions (list): Suggestions from `vocabulary` with a - similarity-rating that higher than or equal to `cutoff`. - Could be empty if there are no matches. - - """ - return [ - tup[1] - for tup in sorted( - [(string_similarity(string, sugg), sugg) for sugg in vocabulary], - key=lambda tup: tup[0], - reverse=True, - ) - if tup[0] >= cutoff - ][:maxnum]
- - -
[docs]def string_partial_matching(alternatives, inp, ret_index=True): - """ - Partially matches a string based on a list of `alternatives`. - Matching is made from the start of each subword in each - alternative. Case is not important. So e.g. "bi sh sw" or just - "big" or "shiny" or "sw" will match "Big shiny sword". Scoring is - done to allow to separate by most common demoninator. You will get - multiple matches returned if appropriate. - - Args: - alternatives (list of str): A list of possible strings to - match. - inp (str): Search criterion. - ret_index (bool, optional): Return list of indices (from alternatives - array) instead of strings. - Returns: - matches (list): String-matches or indices if `ret_index` is `True`. - - """ - if not alternatives or not inp: - return [] - - matches = defaultdict(list) - inp_words = inp.lower().split() - for altindex, alt in enumerate(alternatives): - alt_words = alt.lower().split() - last_index = 0 - score = 0 - for inp_word in inp_words: - # loop over parts, making sure only to visit each part once - # (this will invalidate input in the wrong word order) - submatch = [ - last_index + alt_num - for alt_num, alt_word in enumerate(alt_words[last_index:]) - if alt_word.startswith(inp_word) - ] - if submatch: - last_index = min(submatch) + 1 - score += 1 - else: - score = 0 - break - if score: - if ret_index: - matches[score].append(altindex) - else: - matches[score].append(alt) - if matches: - return matches[max(matches)] - return []
- - -
[docs]def format_table(table, extra_space=1): - """ - Format a 2D array of strings into a multi-column table. - - Args: - table (list): A list of lists to represent columns in the - table: `[[val,val,val,...], [val,val,val,...], ...]`, where - each val will be placed on a separate row in the - column. All columns must have the same number of rows (some - positions may be empty though). - extra_space (int, optional): Sets how much *minimum* extra - padding (in characters) should be left between columns. - - Returns: - list: A list of lists representing the rows to print out one by one. - - Notes: - The function formats the columns to be as wide as the widest member - of each column. - - `evennia.utils.evtable` is more powerful than this, but this - function can be useful when the number of columns and rows are - unknown and must be calculated on the fly. - - Examples: :: - - ftable = format_table([[1,2,3], [4,5,6]]) - string = "" - for ir, row in enumarate(ftable): - if ir == 0: - # make first row white - string += "\\n|w" + "".join(row) + "|n" - else: - string += "\\n" + "".join(row) - print(string) - - """ - - if not table: - return [[]] - - max_widths = [max([len(str(val)) for val in col]) for col in table] - ftable = [] - for irow in range(len(table[0])): - ftable.append( - [ - str(col[irow]).ljust(max_widths[icol]) + " " * extra_space - for icol, col in enumerate(table) - ] - ) - return ftable
- - -
[docs]def percent(value, minval, maxval, formatting="{:3.1f}%"): - """ - Get a value in an interval as a percentage of its position - in that interval. This also understands negative numbers. - - Args: - value (number): This should be a value minval<=value<=maxval. - minval (number or None): Smallest value in interval. This could be None - for an open interval (then return will always be 100%) - maxval (number or None): Biggest value in interval. This could be None - for an open interval (then return will always be 100%) - formatted (str, optional): This is a string that should - accept one formatting tag. This will receive the - current value as a percentage. If None, the - raw float will be returned instead. - Returns: - str or float: The formatted value or the raw percentage as a float. - Notes: - We try to handle a weird interval gracefully. - - - If either maxval or minval is None (open interval), we (aribtrarily) assume 100%. - - If minval > maxval, we return 0%. - - If minval == maxval == value we are looking at a single value match and return 100%. - - If minval == maxval != value we return 0%. - - If value not in [minval..maxval], we set value to the closest - boundary, so the result will be 0% or 100%, respectively. - - """ - result = None - if None in (minval, maxval): - # we have no boundaries, percent calculation makes no sense, - # we set this to 100% since it - result = 100.0 - elif minval > maxval: - # interval has no width so we cannot - # occupy any position within it. - result = 0.0 - elif minval == maxval == value: - # this is a single value that we match - result = 100.0 - elif minval == maxval != value: - # interval has no width so we cannot be in it. - result = 0.0 - - if result is None: - # constrain value to interval - value = min(max(minval, value), maxval) - - # these should both be >0 - dpart = value - minval - dfull = maxval - minval - result = (dpart / dfull) * 100.0 - - if isinstance(formatting, str): - return formatting.format(result) - return result
- - -import functools # noqa - - -
[docs]def percentile(iterable, percent, key=lambda x: x): - """ - Find the percentile of a list of values. - - Args: - iterable (iterable): A list of values. Note N MUST BE already sorted. - percent (float): A value from 0.0 to 1.0. - key (callable, optional). Function to compute value from each element of N. - - Returns: - float: The percentile of the values - - """ - if not iterable: - return None - k = (len(iterable) - 1) * percent - f = math.floor(k) - c = math.ceil(k) - if f == c: - return key(iterable[int(k)]) - d0 = key(iterable[int(f)]) * (c - k) - d1 = key(iterable[int(c)]) * (k - f) - return d0 + d1
- - -
[docs]def format_grid(elements, width=78, sep=" ", verbatim_elements=None): - """ - This helper function makes a 'grid' output, where it distributes the given - string-elements as evenly as possible to fill out the given width. - will not work well if the variation of length is very big! - - Args: - elements (iterable): A 1D list of string elements to put in the grid. - width (int, optional): The width of the grid area to fill. - sep (str, optional): The extra separator to put between words. If - set to the empty string, words may run into each other. - verbatim_elements (list, optional): This is a list of indices pointing to - specific items in the `elements` list. An element at this index will - not be included in the calculation of the slot sizes. It will still - be inserted into the grid at the correct position and may be surrounded - by padding unless filling the entire line. This is useful for embedding - decorations in the grid, such as horizontal bars. - ignore_ansi (bool, optional): Ignore ansi markups when calculating white spacing. - - Returns: - list: The grid as a list of ready-formatted rows. We return it - like this to make it easier to insert decorations between rows, such - as horizontal bars. - """ - - def _minimal_rows(elements): - """ - Minimalistic distribution with minimal spacing, good for single-line - grids but will look messy over many lines. - """ - rows = [""] - for element in elements: - rowlen = display_len((rows[-1])) - elen = display_len((element)) - if rowlen + elen <= width: - rows[-1] += element - else: - rows.append(element) - return rows - - def _weighted_rows(elements): - """ - Dynamic-space, good for making even columns in a multi-line grid but - will look strange for a single line. - """ - wls = [display_len((elem)) for elem in elements] - wls_percentile = [wl for iw, wl in enumerate(wls) if iw not in verbatim_elements] - - if wls_percentile: - # get the nth percentile as a good representation of average width - averlen = int(percentile(sorted(wls_percentile), 0.9)) + 2 # include extra space - aver_per_row = width // averlen + 1 - else: - # no adjustable rows, just keep all as-is - aver_per_row = 1 - - if aver_per_row == 1: - # one line per row, output directly since this is trivial - # we use rstrip here to remove extra spaces added by sep - return [ - crop(element.rstrip(), width) + " " \ - * max(0, width - display_len((element.rstrip()))) - for iel, element in enumerate(elements) - ] - - indices = [averlen * ind for ind in range(aver_per_row - 1)] - - rows = [] - ic = 0 - row = "" - for ie, element in enumerate(elements): - - wl = wls[ie] - lrow = display_len((row)) - # debug = row.replace(" ", ".") - - if lrow + wl > width: - # this slot extends outside grid, move to next line - row += " " * (width - lrow) - rows.append(row) - if wl >= width: - # remove sep if this fills the entire line - element = element.rstrip() - row = crop(element, width) - ic = 0 - elif ic >= aver_per_row - 1: - # no more slots available on this line - row += " " * max(0, (width - lrow)) - rows.append(row) - row = crop(element, width) - ic = 0 - else: - try: - while lrow > max(0, indices[ic]): - # slot too wide, extend into adjacent slot - ic += 1 - row += " " * max(0, indices[ic] - lrow) - except IndexError: - # we extended past edge of grid, crop or move to next line - if ic == 0: - row = crop(element, width) - else: - row += " " * max(0, width - lrow) - rows.append(row) - row = "" - ic = 0 - else: - # add a new slot - row += element + " " * max(0, averlen - wl) - ic += 1 - - if ie >= nelements - 1: - # last element, make sure to store - row += " " * max(0, width - display_len((row))) - rows.append(row) - return rows - - if not elements: - return [] - if not verbatim_elements: - verbatim_elements = [] - - nelements = len(elements) - # add sep to all but the very last element - elements = [elements[ie] + sep for ie in range(nelements - 1)] + [elements[-1]] - - if sum(display_len((element)) for element in elements) <= width: - # grid fits in one line - return _minimal_rows(elements) - else: - # full multi-line grid - return _weighted_rows(elements)
- - -
[docs]def get_evennia_pids(): - """ - Get the currently valid PIDs (Process IDs) of the Portal and - Server by trying to access a PID file. - - Returns: - server, portal (tuple): The PIDs of the respective processes, - or two `None` values if not found. - - Examples: - This can be used to determine if we are in a subprocess by - - ```python - self_pid = os.getpid() - server_pid, portal_pid = get_evennia_pids() - is_subprocess = self_pid not in (server_pid, portal_pid) - ``` - - """ - server_pidfile = os.path.join(settings.GAME_DIR, "server.pid") - portal_pidfile = os.path.join(settings.GAME_DIR, "portal.pid") - server_pid, portal_pid = None, None - if os.path.exists(server_pidfile): - with open(server_pidfile, "r") as f: - server_pid = f.read() - if os.path.exists(portal_pidfile): - with open(portal_pidfile, "r") as f: - portal_pid = f.read() - if server_pid and portal_pid: - return int(server_pid), int(portal_pid) - return None, None
- - -
[docs]def deepsize(obj, max_depth=4): - """ - Get not only size of the given object, but also the size of - objects referenced by the object, down to `max_depth` distance - from the object. - - Args: - obj (object): the object to be measured. - max_depth (int, optional): maximum referential distance - from `obj` that `deepsize()` should cover for - measuring objects referenced by `obj`. - - Returns: - size (int): deepsize of `obj` in Bytes. - - Notes: - This measure is necessarily approximate since some - memory is shared between objects. The `max_depth` of 4 is roughly - tested to give reasonable size information about database models - and their handlers. - - """ - - def _recurse(o, dct, depth): - if 0 <= max_depth < depth: - return - for ref in gc.get_referents(o): - idr = id(ref) - if idr not in dct: - dct[idr] = (ref, sys.getsizeof(ref, default=0)) - _recurse(ref, dct, depth + 1) - - sizedict = {} - _recurse(obj, sizedict, 0) - size = sys.getsizeof(obj) + sum([p[1] for p in sizedict.values()]) - return size
- - -# lazy load handler -_missing = object() - - -
[docs]class lazy_property: - """ - Delays loading of property until first access. Credit goes to the - Implementation in the werkzeug suite: - http://werkzeug.pocoo.org/docs/utils/#werkzeug.utils.cached_property - - This should be used as a decorator in a class and in Evennia is - mainly used to lazy-load handlers: - - ```python - @lazy_property - def attributes(self): - return AttributeHandler(self) - ``` - - Once initialized, the `AttributeHandler` will be available as a - property "attributes" on the object. This is read-only since - this functionality is pretty much exclusively used by handlers. - - """ - -
[docs] def __init__(self, func, name=None, doc=None): - """Store all properties for now""" - self.__name__ = name or func.__name__ - self.__module__ = func.__module__ - self.__doc__ = doc or func.__doc__ - self.func = func
- - def __get__(self, obj, type=None): - """Triggers initialization""" - if obj is None: - return self - value = obj.__dict__.get(self.__name__, _missing) - if value is _missing: - value = self.func(obj) - obj.__dict__[self.__name__] = value - return value - - def __set__(self, obj, value): - """Protect against setting""" - handlername = self.__name__ - raise AttributeError( - _("{obj}.{handlername} is a handler and can't be set directly. " - "To add values, use `{obj}.{handlername}.add()` instead.").format( - obj=obj, handlername=handlername) - ) - - def __delete__(self, obj): - """Protect against deleting""" - handlername = self.__name__ - raise AttributeError( - _("{obj}.{handlername} is a handler and can't be deleted directly. " - "To remove values, use `{obj}.{handlername}.remove()` instead.").format( - obj=obj, handlername=handlername) - )
- - -_STRIP_ANSI = None -_RE_CONTROL_CHAR = re.compile( - "[%s]" % re.escape("".join([chr(c) for c in range(0, 32)])) -) # + range(127,160)]))) - - -
[docs]def strip_control_sequences(string): - """ - Remove non-print text sequences. - - Args: - string (str): Text to strip. - - Returns. - text (str): Stripped text. - - """ - global _STRIP_ANSI - if not _STRIP_ANSI: - from evennia.utils.ansi import strip_raw_ansi as _STRIP_ANSI - return _RE_CONTROL_CHAR.sub("", _STRIP_ANSI(string))
- - -
[docs]def calledby(callerdepth=1): - """ - Only to be used for debug purposes. Insert this debug function in - another function; it will print which function called it. - - Args: - callerdepth (int): Must be larger than 0. When > 1, it will - print the caller of the caller etc. - - Returns: - calledby (str): A debug string detailing which routine called - us. - - """ - import inspect - - stack = inspect.stack() - # we must step one extra level back in stack since we don't want - # to include the call of this function itself. - callerdepth = min(max(2, callerdepth + 1), len(stack) - 1) - frame = inspect.stack()[callerdepth] - path = os.path.sep.join(frame[1].rsplit(os.path.sep, 2)[-2:]) - return "[called by '%s': %s:%s %s]" % (frame[3], path, frame[2], frame[4])
- - -
[docs]def m_len(target): - """ - Provides length checking for strings with MXP patterns, and falls - back to normal len for other objects. - - Args: - target (str): A string with potential MXP components - to search. - - Returns: - length (int): The length of `target`, ignoring MXP components. - - """ - # Would create circular import if in module root. - from evennia.utils.ansi import ANSI_PARSER - - if inherits_from(target, str) and "|lt" in target: - return len(ANSI_PARSER.strip_mxp(target)) - return len(target)
- - -
[docs]def display_len(target): - """ - Calculate the 'visible width' of text. This is not necessarily the same as the - number of characters in the case of certain asian characters. This will also - strip MXP patterns. - - Args: - target (any): Something to measure the length of. If a string, it will be - measured keeping asian-character and MXP links in mind. - - Return: - int: The visible width of the target. - - """ - # Would create circular import if in module root. - from evennia.utils.ansi import ANSI_PARSER - - if inherits_from(target, str): - # str or ANSIString - target = ANSI_PARSER.strip_mxp(target) - target = ANSI_PARSER.parse_ansi(target, strip_ansi=True) - extra_wide = ("F", "W") - return sum(2 if east_asian_width(char) in extra_wide else 1 for char in target) - else: - return len(target)
- - -# ------------------------------------------------------------------- -# Search handler function -# ------------------------------------------------------------------- -# -# Replace this hook function by changing settings.SEARCH_AT_RESULT. - - -
[docs]def at_search_result(matches, caller, query="", quiet=False, **kwargs): - """ - This is a generic hook for handling all processing of a search - result, including error reporting. This is also called by the cmdhandler - to manage errors in command lookup. - - Args: - matches (list): This is a list of 0, 1 or more typeclass - instances or Command instances, the matched result of the - search. If 0, a nomatch error should be echoed, and if >1, - multimatch errors should be given. Only if a single match - should the result pass through. - caller (Object): The object performing the search and/or which should - receive error messages. - query (str, optional): The search query used to produce `matches`. - quiet (bool, optional): If `True`, no messages will be echoed to caller - on errors. - Keyword Args: - nofound_string (str): Replacement string to echo on a notfound error. - multimatch_string (str): Replacement string to echo on a multimatch error. - - Returns: - processed_result (Object or None): This is always a single result - or `None`. If `None`, any error reporting/handling should - already have happened. The returned object is of the type we are - checking multimatches for (e.g. Objects or Commands) - - """ - - error = "" - if not matches: - # no results. - error = kwargs.get("nofound_string") or _("Could not find '{query}'.").format(query=query) - matches = None - elif len(matches) > 1: - multimatch_string = kwargs.get("multimatch_string") - if multimatch_string: - error = "%s\n" % multimatch_string - else: - error = _("More than one match for '{query}' (please narrow target):\n").format( - query=query - ) - - for num, result in enumerate(matches): - # we need to consider Commands, where .aliases is a list - aliases = result.aliases.all() if hasattr(result.aliases, "all") else result.aliases - # remove any pluralization aliases - aliases = [ - alias - for alias in aliases - if hasattr(alias, "category") and alias.category not in ("plural_key",) - ] - error += _MULTIMATCH_TEMPLATE.format( - number=num + 1, - name=result.get_display_name(caller) - if hasattr(result, "get_display_name") - else query, - aliases=" [{alias}]".format(alias=";".join(aliases) if aliases else ""), - info=result.get_extra_info(caller), - ) - matches = None - else: - # exactly one match - matches = matches[0] - - if error and not quiet: - caller.msg(error.strip()) - return matches
- - -
[docs]class LimitedSizeOrderedDict(OrderedDict): - """ - This dictionary subclass is both ordered and limited to a maximum - number of elements. Its main use is to hold a cache that can never - grow out of bounds. - - """ - -
[docs] def __init__(self, *args, **kwargs): - """ - Limited-size ordered dict. - - Keyword Args: - size_limit (int): Use this to limit the number of elements - alloweds to be in this list. By default the overshooting elements - will be removed in FIFO order. - fifo (bool, optional): Defaults to `True`. Remove overshooting elements - in FIFO order. If `False`, remove in FILO order. - - """ - super().__init__() - self.size_limit = kwargs.get("size_limit", None) - self.filo = not kwargs.get("fifo", True) # FIFO inverse of FILO - self._check_size()
- - def __eq__(self, other): - ret = super().__eq__(other) - if ret: - return ( - ret - and hasattr(other, "size_limit") - and self.size_limit == other.size_limit - and hasattr(other, "fifo") - and self.fifo == other.fifo - ) - return False - - def __ne__(self, other): - return not self.__eq__(other) - - def _check_size(self): - filo = self.filo - if self.size_limit is not None: - while self.size_limit < len(self): - self.popitem(last=filo) - - def __setitem__(self, key, value): - super().__setitem__(key, value) - self._check_size() - -
[docs] def update(self, *args, **kwargs): - super().update(*args, **kwargs) - self._check_size()
- - -
[docs]def get_game_dir_path(): - """ - This is called by settings_default in order to determine the path - of the game directory. - - Returns: - path (str): Full OS path to the game dir - - """ - # current working directory, assumed to be somewhere inside gamedir. - for inum in range(10): - gpath = os.getcwd() - if "server" in os.listdir(gpath): - if os.path.isfile(os.path.join("server", "conf", "settings.py")): - return gpath - else: - os.chdir(os.pardir) - raise RuntimeError("server/conf/settings.py not found: Must start from inside game dir.")
- - -
[docs]def get_all_typeclasses(parent=None): - """ - List available typeclasses from all available modules. - - Args: - parent (str, optional): If given, only return typeclasses inheriting - (at any distance) from this parent. - - Returns: - dict: On the form `{"typeclass.path": typeclass, ...}` - - Notes: - This will dynamically retrieve all abstract django models inheriting at - any distance from the TypedObject base (aka a Typeclass) so it will - work fine with any custom classes being added. - - """ - from evennia.typeclasses.models import TypedObject - - typeclasses = { - "{}.{}".format(model.__module__, model.__name__): model - for model in apps.get_models() - if TypedObject in getmro(model) - } - if parent: - typeclasses = { - name: typeclass - for name, typeclass in typeclasses.items() - if inherits_from(typeclass, parent) - } - return typeclasses
- - -
[docs]def get_all_cmdsets(parent=None): - """ - List available cmdsets from all available modules. - - Args: - parent (str, optional): If given, only return cmdsets inheriting (at - any distance) from this parent. - - Returns: - dict: On the form {"cmdset.path": cmdset, ...} - - Notes: - This will dynamically retrieve all abstract django models inheriting at - any distance from the CmdSet base so it will work fine with any custom - classes being added. - - """ - from evennia.commands.cmdset import CmdSet - - base_cmdset = class_from_module(parent) if parent else CmdSet - - cmdsets = { - "{}.{}".format(subclass.__module__, subclass.__name__): subclass - for subclass in base_cmdset.__subclasses__() - } - return cmdsets
- - -
[docs]def interactive(func): - """ - Decorator to make a method pausable with `yield(seconds)` - and able to ask for user-input with `response=yield(question)`. - For the question-asking to work, one of the args or kwargs to the - decorated function must be named 'caller'. - - Raises: - ValueError: If asking an interactive question but the decorated - function has no arg or kwarg named 'caller'. - ValueError: If passing non int/float to yield using for pausing. - - Examples: - - ```python - @interactive - def myfunc(caller): - caller.msg("This is a test") - # wait five seconds - yield(5) - # ask user (caller) a question - response = yield("Do you want to continue waiting?") - if response == "yes": - yield(5) - else: - # ... - ``` - - Notes: - This turns the decorated function or method into a generator. - - """ - from evennia.utils.evmenu import get_input - - def _process_input(caller, prompt, result, generator): - deferLater(reactor, 0, _iterate, generator, caller, response=result) - return False - - def _iterate(generator, caller=None, response=None): - try: - if response is None: - value = next(generator) - else: - value = generator.send(response) - except StopIteration: - pass - else: - if isinstance(value, (int, float)): - delay(value, _iterate, generator, caller=caller) - elif isinstance(value, str): - if not caller: - raise ValueError( - "To retrieve input from a @pausable method, that method " - "must be called with a 'caller' argument)" - ) - get_input(caller, value, _process_input, generator=generator) - else: - raise ValueError("yield(val) in a @pausable method must have an int/float as arg.") - - def decorator(*args, **kwargs): - argnames = inspect.getfullargspec(func).args - caller = None - if "caller" in argnames: - # we assume this is an object - caller = args[argnames.index("caller")] - - ret = func(*args, **kwargs) - if isinstance(ret, types.GeneratorType): - _iterate(ret, caller) - else: - return ret - - return decorator
- - -
[docs]def safe_convert_to_types(converters, *args, raise_errors=True, **kwargs): - """ - Helper function to safely convert inputs to expected data types. - - Args: - converters (tuple): A tuple `((converter, converter,...), {kwarg: converter, ...})` to - match a converter to each element in `*args` and `**kwargs`. - Each converter will will be called with the arg/kwarg-value as the only argument. - If there are too few converters given, the others will simply not be converter. If the - converter is given as the string 'py', it attempts to run - `safe_eval`/`literal_eval` on the input arg or kwarg value. It's possible to - skip the arg/kwarg part of the tuple, an empty tuple/dict will then be assumed. - *args: The arguments to convert with `argtypes`. - raise_errors (bool, optional): If set, raise any errors. This will - abort the conversion at that arg/kwarg. Otherwise, just skip the - conversion of the failing arg/kwarg. This will be set by the FuncParser if - this is used as a part of a FuncParser callable. - **kwargs: The kwargs to convert with `kwargtypes` - - Returns: - tuple: `(args, kwargs)` in converted form. - - Raises: - utils.funcparser.ParsingError: If parsing failed in the `'py'` - converter. This also makes this compatible with the FuncParser - interface. - any: Any other exception raised from other converters, if raise_errors is True. - - Notes: - This function is often used to validate/convert input from untrusted sources. For - security, the "py"-converter is deliberately limited and uses `safe_eval`/`literal_eval` - which only supports simple expressions or simple containers with literals. NEVER - use the python `eval` or `exec` methods as a converter for any untrusted input! Allowing - untrusted sources to execute arbitrary python on your server is a severe security risk, - - Example: - :: - - $funcname(1, 2, 3.0, c=[1,2,3]) - - def _funcname(*args, **kwargs): - args, kwargs = safe_convert_input(((int, int, float), {'c': 'py'}), *args, **kwargs) - # ... - - """ - def _safe_eval(inp): - if not inp: - return '' - if not isinstance(inp, str): - # already converted - return inp - - try: - return literal_eval(inp) - except Exception as err: - literal_err = f"{err.__class__.__name__}: {err}" - try: - return simple_eval(inp) - except Exception as err: - simple_err = f"{str(err.__class__.__name__)}: {err}" - pass - - if raise_errors: - from evennia.utils.funcparser import ParsingError - err = (f"Errors converting '{inp}' to python:\n" - f"literal_eval raised {literal_err}\n" - f"simple_eval raised {simple_err}") - raise ParsingError(err) - - # handle an incomplete/mixed set of input converters - if not converters: - return args, kwargs - arg_converters, *kwarg_converters = converters - arg_converters = make_iter(arg_converters) - kwarg_converters = kwarg_converters[0] if kwarg_converters else {} - - # apply the converters - if args and arg_converters: - args = list(args) - arg_converters = make_iter(arg_converters) - for iarg, arg in enumerate(args[:len(arg_converters)]): - converter = arg_converters[iarg] - converter = _safe_eval if converter in ('py', 'python') else converter - try: - args[iarg] = converter(arg) - except Exception: - if raise_errors: - raise - args = tuple(args) - if kwarg_converters and isinstance(kwarg_converters, dict): - for key, converter in kwarg_converters.items(): - converter = _safe_eval if converter in ('py', 'python') else converter - if key in {**kwargs}: - try: - kwargs[key] = converter(kwargs[key]) - except Exception: - if raise_errors: - raise - return args, kwargs
- - -
[docs]def strip_unsafe_input(txt, session=None, bypass_perms=None): - """ - Remove 'unsafe' text codes from text; these are used to elimitate - exploits in user-provided data, such as html-tags, line breaks etc. - - Args: - txt (str): The text to clean. - session (Session, optional): A Session in order to determine if - the check should be bypassed by permission (will be checked - with the 'perm' lock, taking permission hierarchies into account). - bypass_perms (list, optional): Iterable of permission strings - to check for bypassing the strip. If not given, use - `settings.INPUT_CLEANUP_BYPASS_PERMISSIONS`. - - Returns: - str: The cleaned string. - - Notes: - The `INPUT_CLEANUP_BYPASS_PERMISSIONS` list defines what account - permissions are required to bypass this strip. - - """ - global _STRIP_UNSAFE_TOKENS - if not _STRIP_UNSAFE_TOKENS: - from evennia.utils.ansi import strip_unsafe_tokens as _STRIP_UNSAFE_TOKENS - - if session: - obj = session.puppet if session.puppet else session.account - bypass_perms = bypass_perms or settings.INPUT_CLEANUP_BYPASS_PERMISSIONS - if obj.permissions.check(*bypass_perms): - return txt - - # remove html codes - txt = strip_tags(txt) - txt = _STRIP_UNSAFE_TOKENS(txt) - return txt
- - -
[docs]def copy_word_case(base_word, new_word): - """ - Converts a word to use the same capitalization as a first word. - - Args: - base_word (str): A word to get the capitalization from. - new_word (str): A new word to capitalize in the same way as `base_word`. - - Returns: - str: The `new_word` with capitalization matching the first word. - - Notes: - This is meant for words. Longer sentences may get unexpected results. - - If the two words have a mix of capital/lower letters _and_ `new_word` - is longer than `base_word`, the excess will retain its original case. - - """ - - # Word - if base_word.istitle(): - return new_word.title() - # word - elif base_word.islower(): - return new_word.lower() - # WORD - elif base_word.isupper(): - return new_word.upper() - else: - # WorD - a mix. Handle each character - maxlen = len(base_word) - shared, excess = new_word[:maxlen], new_word[maxlen - 1:] - return "".join(char.upper() if base_word[ic].isupper() else char.lower() - for ic, char in enumerate(new_word)) + excess
- -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/utils/validatorfuncs.html b/docs/0.9.5/_modules/evennia/utils/validatorfuncs.html deleted file mode 100644 index 5f563ce2ee..0000000000 --- a/docs/0.9.5/_modules/evennia/utils/validatorfuncs.html +++ /dev/null @@ -1,363 +0,0 @@ - - - - - - - - evennia.utils.validatorfuncs — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.utils.validatorfuncs

-"""
-Contains all the validation functions.
-
-All validation functions must have a checker (probably a session) and entry arg.
-
-They can employ more paramters at your leisure.
-
-
-"""
-
-import re as _re
-import pytz as _pytz
-import datetime as _dt
-from evennia.utils.ansi import strip_ansi
-from evennia.utils.utils import string_partial_matching as _partial, validate_email_address
-from django.utils.translation import gettext as _
-
-_TZ_DICT = {str(tz): _pytz.timezone(tz) for tz in _pytz.common_timezones}
-
-
-
[docs]def text(entry, option_key="Text", **kwargs): - try: - return str(entry) - except Exception as err: - raise ValueError(_("Input could not be converted to text ({err})").format(err=err))
- - -
[docs]def color(entry, option_key="Color", **kwargs): - """ - The color should be just a color character, so 'r' if red color is desired. - - """ - if not entry: - raise ValueError(_("Nothing entered for a {option_key}!").format(option_key=option_key)) - test_str = strip_ansi(f"|{entry}|n") - if test_str: - raise ValueError(_("'{entry}' is not a valid {option_key}.").format( - entry=entry, option_key=option_key)) - return entry
- - -
[docs]def datetime(entry, option_key="Datetime", account=None, from_tz=None, **kwargs): - """ - Process a datetime string in standard forms while accounting for the - inputer's timezone. Always returns a result in UTC. - - Args: - entry (str): A date string from a user. - option_key (str): Name to display this datetime as. - account (AccountDB): The Account performing this lookup. Unless `from_tz` is provided, - the account's timezone option will be used. - from_tz (pytz.timezone): An instance of a pytz timezone object from the - user. If not provided, tries to use the timezone option of `account`. - If neither one is provided, defaults to UTC. - Returns: - datetime in UTC. - Raises: - ValueError: If encountering a malformed timezone, date string or other format error. - - """ - if not entry: - raise ValueError(_("No {option_key} entered!").format(option_key=option_key)) - if not from_tz: - from_tz = _pytz.UTC - if account: - acct_tz = account.options.get("timezone", "UTC") - try: - from_tz = _pytz.timezone(acct_tz) - except Exception as err: - raise ValueError( - _("Timezone string '{acct_tz}' is not a valid timezone ({err})").format( - acct_tz=acct_tz, err=err - ) - ) - else: - from_tz = _pytz.UTC - - utc = _pytz.UTC - now = _dt.datetime.utcnow().replace(tzinfo=utc) - cur_year = now.strftime("%Y") - split_time = entry.split(" ") - if len(split_time) == 3: - entry = f"{split_time[0]} {split_time[1]} {split_time[2]} {cur_year}" - elif len(split_time) == 4: - entry = f"{split_time[0]} {split_time[1]} {split_time[2]} {split_time[3]}" - else: - raise ValueError( - _("{option_key} must be entered in a 24-hour format such as: {timeformat}").format( - option_key=option_key, - timeformat=now.strftime('%b %d %H:%M')) - ) - try: - local = _dt.datetime.strptime(entry, "%b %d %H:%M %Y") - except ValueError: - raise ValueError( - _("{option_key} must be entered in a 24-hour format such as: {timeformat}").format( - option_key=option_key, - timeformat=now.strftime('%b %d %H:%M')) - ) - local_tz = from_tz.localize(local) - return local_tz.astimezone(utc)
- - -
[docs]def duration(entry, option_key="Duration", **kwargs): - """ - Take a string and derive a datetime timedelta from it. - - Args: - entry (string): This is a string from user-input. The intended format is, for example: - "5d 2w 90s" for 'five days, two weeks, and ninety seconds.' Invalid sections are - ignored. - option_key (str): Name to display this query as. - - Returns: - timedelta - - """ - time_string = entry.lower().split(" ") - seconds = 0 - minutes = 0 - hours = 0 - days = 0 - weeks = 0 - - for interval in time_string: - if _re.match(r"^[\d]+s$", interval): - seconds += int(interval.rstrip("s")) - elif _re.match(r"^[\d]+m$", interval): - minutes += int(interval.rstrip("m")) - elif _re.match(r"^[\d]+h$", interval): - hours += int(interval.rstrip("h")) - elif _re.match(r"^[\d]+d$", interval): - days += int(interval.rstrip("d")) - elif _re.match(r"^[\d]+w$", interval): - weeks += int(interval.rstrip("w")) - elif _re.match(r"^[\d]+y$", interval): - days += int(interval.rstrip("y")) * 365 - else: - raise ValueError( - _("Could not convert section '{interval}' to a {option_key}.").format( - interval=interval, option_key=option_key) - ) - - return _dt.timedelta(days, seconds, 0, 0, minutes, hours, weeks)
- - -
[docs]def future(entry, option_key="Future Datetime", from_tz=None, **kwargs): - time = datetime(entry, option_key, from_tz=from_tz) - if time < _dt.datetime.utcnow().replace(tzinfo=_dt.timezone.utc): - raise ValueError(_("That {option_key} is in the past! Must give a Future datetime!").format( - option_key=option_key)) - return time
- - -
[docs]def signed_integer(entry, option_key="Signed Integer", **kwargs): - if not entry: - raise ValueError(_("Must enter a whole number for {option_key}!").format( - option_key=option_key)) - try: - num = int(entry) - except ValueError: - raise ValueError(_("Could not convert '{entry}' to a whole " - "number for {option_key}!").format( - entry=entry, option_key=option_key)) - return num
- - -
[docs]def positive_integer(entry, option_key="Positive Integer", **kwargs): - num = signed_integer(entry, option_key) - if not num >= 1: - raise ValueError(_("Must enter a whole number greater than 0 for {option_key}!").format( - option_key=option_key)) - return num
- - -
[docs]def unsigned_integer(entry, option_key="Unsigned Integer", **kwargs): - num = signed_integer(entry, option_key) - if not num >= 0: - raise ValueError(_("{option_key} must be a whole number greater than " - "or equal to 0!").format( - option_key=option_key)) - return num
- - -
[docs]def boolean(entry, option_key="True/False", **kwargs): - """ - Simplest check in computer logic, right? This will take user input to flick the switch on or off - - Args: - entry (str): A value such as True, On, Enabled, Disabled, False, 0, or 1. - option_key (str): What kind of Boolean we are setting. What Option is this for? - - Returns: - Boolean - - """ - error = (_("Must enter a true/false input for {option_key}. Accepts {alternatives}.").format( - option_key=option_key, - alternatives="0/1, True/False, On/Off, Yes/No, Enabled/Disabled")) - if not isinstance(entry, str): - raise ValueError(error) - entry = entry.upper() - if entry in ("1", "TRUE", "ON", "ENABLED", "ENABLE", "YES"): - return True - if entry in ("0", "FALSE", "OFF", "DISABLED", "DISABLE", "NO"): - return False - raise ValueError(error)
- - -
[docs]def timezone(entry, option_key="Timezone", **kwargs): - """ - Takes user input as string, and partial matches a Timezone. - - Args: - entry (str): The name of the Timezone. - option_key (str): What this Timezone is used for. - - Returns: - A PYTZ timezone. - - """ - if not entry: - raise ValueError(_("No {option_key} entered!").format(option_key=option_key)) - found = _partial(list(_TZ_DICT.keys()), entry, ret_index=False) - if len(found) > 1: - raise ValueError( - _("That matched: {matches}. Please be more specific!").format( - matches=', '.join(str(t) for t in found))) - if found: - return _TZ_DICT[found[0]] - raise ValueError(_("Could not find timezone '{entry}' for {option_key}!").format( - entry=entry, option_key=option_key))
- - -
[docs]def email(entry, option_key="Email Address", **kwargs): - if not entry: - raise ValueError(_("Email address field empty!")) - valid = validate_email_address(entry) - if not valid: - raise ValueError(_("That isn't a valid {option_key}!").format(option_key=option_key)) - return entry
- - -
[docs]def lock(entry, option_key="locks", access_options=None, **kwargs): - entry = entry.strip() - if not entry: - raise ValueError(_("No {option_key} entered to set!").format(option_key=option_key)) - for locksetting in entry.split(";"): - access_type, lockfunc = locksetting.split(":", 1) - if not access_type: - raise ValueError(_("Must enter an access type!")) - if access_options: - if access_type not in access_options: - raise ValueError(_("Access type must be one of: {alternatives}").format( - alternatives=', '.join(access_options))) - if not lockfunc: - raise ValueError(_("Lock func not entered.")) - return entry
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/web/utils/backends.html b/docs/0.9.5/_modules/evennia/web/utils/backends.html deleted file mode 100644 index 867c758533..0000000000 --- a/docs/0.9.5/_modules/evennia/web/utils/backends.html +++ /dev/null @@ -1,148 +0,0 @@ - - - - - - - - evennia.web.utils.backends — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.web.utils.backends

-from django.contrib.auth.backends import ModelBackend
-from django.contrib.auth import get_user_model
-
-
-
[docs]class CaseInsensitiveModelBackend(ModelBackend): - """ - By default ModelBackend does case _sensitive_ username - authentication, which isn't what is generally expected. This - backend supports case insensitive username authentication. - - """ - -
[docs] def authenticate(self, request, username=None, password=None, autologin=None): - """ - Custom authenticate with bypass for auto-logins - - Args: - request (Request): Request object. - username (str, optional): Name of user to authenticate. - password (str, optional): Password of user - autologin (Account, optional): If given, assume this is - an already authenticated account and bypass authentication. - """ - if autologin: - # Note: Setting .backend on account is critical in order to - # be allowed to call django.auth.login(account) later. This - # is necessary for the auto-login feature of the webclient, - # but it's important to make sure Django doesn't change this - # requirement or the name of the property down the line. /Griatch - autologin.backend = "evennia.web.utils.backends.CaseInsensitiveModelBackend" - return autologin - else: - # In this case .backend will be assigned automatically - # somewhere along the way. - Account = get_user_model() - try: - account = Account.objects.get(username__iexact=username) - if account.check_password(password): - return account - else: - return None - except Account.DoesNotExist: - return None
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/web/utils/general_context.html b/docs/0.9.5/_modules/evennia/web/utils/general_context.html deleted file mode 100644 index cb4f5e30a1..0000000000 --- a/docs/0.9.5/_modules/evennia/web/utils/general_context.html +++ /dev/null @@ -1,236 +0,0 @@ - - - - - - - - evennia.web.utils.general_context — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.web.utils.general_context

-"""
-This file defines global variables that will always be available in a view
-context without having to repeatedly include it.
-
-For this to work, this file is included in the settings file, in the
-TEMPLATES["OPTIONS"]["context_processors"] list.
-
-"""
-
-
-import os
-from django.conf import settings
-from evennia.utils.utils import get_evennia_version
-
-# Setup lists of the most relevant apps so
-# the adminsite becomes more readable.
-
-GAME_NAME = None
-GAME_SLOGAN = None
-SERVER_VERSION = None
-SERVER_HOSTNAME = None
-
-TELNET_ENABLED = None
-TELNET_PORTS = None
-TELNET_SSL_ENABLED = None
-TELNET_SSL_PORTS = None
-
-SSH_ENABLED = None
-SSH_PORTS = None
-
-WEBCLIENT_ENABLED = None
-WEBSOCKET_CLIENT_ENABLED = None
-WEBSOCKET_PORT = None
-WEBSOCKET_URL = None
-
-REST_API_ENABLED = False
-
-ACCOUNT_RELATED = ["Accounts"]
-GAME_ENTITIES = ["Objects", "Scripts", "Comms", "Help"]
-GAME_SETUP = ["Permissions", "Config"]
-CONNECTIONS = ["Irc"]
-WEBSITE = ["Flatpages", "News", "Sites"]
-
-
-
[docs]def load_game_settings(): - """ - Load and cache game settings. - - """ - global GAME_NAME, GAME_SLOGAN, SERVER_VERSION, SERVER_HOSTNAME - global TELNET_ENABLED, TELNET_PORTS - global TELNET_SSL_ENABLED, TELNET_SSL_PORTS - global SSH_ENABLED, SSH_PORTS - global WEBCLIENT_ENABLED, WEBSOCKET_CLIENT_ENABLED, WEBSOCKET_PORT, WEBSOCKET_URL - global REST_API_ENABLED - - try: - GAME_NAME = settings.SERVERNAME.strip() - except AttributeError: - GAME_NAME = "Evennia" - SERVER_VERSION = get_evennia_version() - try: - GAME_SLOGAN = settings.GAME_SLOGAN.strip() - except AttributeError: - GAME_SLOGAN = SERVER_VERSION - SERVER_HOSTNAME = settings.SERVER_HOSTNAME - - TELNET_ENABLED = settings.TELNET_ENABLED - TELNET_PORTS = settings.TELNET_PORTS - TELNET_SSL_ENABLED = settings.SSL_ENABLED - TELNET_SSL_PORTS = settings.SSL_PORTS - - SSH_ENABLED = settings.SSH_ENABLED - SSH_PORTS = settings.SSH_PORTS - - WEBCLIENT_ENABLED = settings.WEBCLIENT_ENABLED - WEBSOCKET_CLIENT_ENABLED = settings.WEBSOCKET_CLIENT_ENABLED - # if we are working through a proxy or uses docker port-remapping, the webclient port encoded - # in the webclient should be different than the one the server expects. Use the environment - # variable WEBSOCKET_CLIENT_PROXY_PORT if this is the case. - WEBSOCKET_PORT = int( - os.environ.get("WEBSOCKET_CLIENT_PROXY_PORT", settings.WEBSOCKET_CLIENT_PORT) - ) - # this is determined dynamically by the client and is less of an issue - WEBSOCKET_URL = settings.WEBSOCKET_CLIENT_URL - - REST_API_ENABLED = settings.REST_API_ENABLED
- - -load_game_settings() - - -# The main context processor function -
[docs]def general_context(request): - """ - Returns common Evennia-related context stuff, which is automatically added - to context of all views. - - """ - account = None - if request.user.is_authenticated: - account = request.user - - puppet = None - if account and request.session.get("puppet"): - pk = int(request.session.get("puppet")) - puppet = next((x for x in account.characters if x.pk == pk), None) - - return { - "account": account, - "puppet": puppet, - "game_name": GAME_NAME, - "game_slogan": GAME_SLOGAN, - "server_hostname": SERVER_HOSTNAME, - "evennia_userapps": ACCOUNT_RELATED, - "evennia_entityapps": GAME_ENTITIES, - "evennia_setupapps": GAME_SETUP, - "evennia_connectapps": CONNECTIONS, - "evennia_websiteapps": WEBSITE, - "telnet_enabled": TELNET_ENABLED, - "telnet_ports": TELNET_PORTS, - "telnet_ssl_enabled": TELNET_SSL_ENABLED, - "telnet_ssl_ports": TELNET_SSL_PORTS, - "ssh_enabled": SSH_ENABLED, - "ssh_ports": SSH_ENABLED, - "webclient_enabled": WEBCLIENT_ENABLED, - "websocket_enabled": WEBSOCKET_CLIENT_ENABLED, - "websocket_port": WEBSOCKET_PORT, - "websocket_url": WEBSOCKET_URL, - "rest_api_enabled": REST_API_ENABLED, - }
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/web/utils/middleware.html b/docs/0.9.5/_modules/evennia/web/utils/middleware.html deleted file mode 100644 index 89058eb53a..0000000000 --- a/docs/0.9.5/_modules/evennia/web/utils/middleware.html +++ /dev/null @@ -1,177 +0,0 @@ - - - - - - - - evennia.web.utils.middleware — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.web.utils.middleware

-from django.contrib.auth import authenticate, login
-from evennia.accounts.models import AccountDB
-from evennia.utils import logger
-
-
-
[docs]class SharedLoginMiddleware(object): - """ - Handle the shared login between website and webclient. - - """ - -
[docs] def __init__(self, get_response): - # One-time configuration and initialization. - self.get_response = get_response
- - def __call__(self, request): - # Code to be executed for each request before - # the view (and later middleware) are called. - - # Synchronize credentials between webclient and website - # Must be performed *before* rendering the view (issue #1723) - self.make_shared_login(request) - - # Process view - response = self.get_response(request) - - # Code to be executed for each request/response after - # the view is called. - - # Return processed view - return response - -
[docs] @classmethod - def make_shared_login(cls, request): - csession = request.session - account = request.user - website_uid = csession.get("website_authenticated_uid", None) - webclient_uid = csession.get("webclient_authenticated_uid", None) - - if not csession.session_key: - # this is necessary to build the sessid key - csession.save() - - if account.is_authenticated: - # Logged into website - if website_uid is None: - # fresh website login (just from login page) - csession["website_authenticated_uid"] = account.id - if webclient_uid is None: - # auto-login web client - csession["webclient_authenticated_uid"] = account.id - - elif webclient_uid: - # Not logged into website, but logged into webclient - if website_uid is None: - csession["website_authenticated_uid"] = account.id - account = AccountDB.objects.get(id=webclient_uid) - try: - # calls our custom authenticate, in web/utils/backend.py - authenticate(autologin=account) - login(request, account) - except AttributeError: - logger.log_trace() - - if csession.get("webclient_authenticated_uid", None): - # set a nonce to prevent the webclient from erasing the webclient_authenticated_uid value - csession["webclient_authenticated_nonce"] = ( - csession.get("webclient_authenticated_nonce", 0) + 1 - ) - # wrap around to prevent integer overflows - if csession["webclient_authenticated_nonce"] > 32: - csession["webclient_authenticated_nonce"] = 0
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/web/utils/tests.html b/docs/0.9.5/_modules/evennia/web/utils/tests.html deleted file mode 100644 index 36b4c4b83c..0000000000 --- a/docs/0.9.5/_modules/evennia/web/utils/tests.html +++ /dev/null @@ -1,155 +0,0 @@ - - - - - - - - evennia.web.utils.tests — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.web.utils.tests

-from django.contrib.auth.models import AnonymousUser
-from django.test import RequestFactory, TestCase
-from mock import MagicMock, patch
-from . import general_context
-
-
-
[docs]class TestGeneralContext(TestCase): - maxDiff = None - -
[docs] @patch("evennia.web.utils.general_context.GAME_NAME", "test_name") - @patch("evennia.web.utils.general_context.GAME_SLOGAN", "test_game_slogan") - @patch("evennia.web.utils.general_context.WEBSOCKET_CLIENT_ENABLED", - "websocket_client_enabled_testvalue") - @patch("evennia.web.utils.general_context.WEBCLIENT_ENABLED", "webclient_enabled_testvalue") - @patch("evennia.web.utils.general_context.WEBSOCKET_PORT", "websocket_client_port_testvalue") - @patch("evennia.web.utils.general_context.WEBSOCKET_URL", "websocket_client_url_testvalue") - @patch("evennia.web.utils.general_context.REST_API_ENABLED", True) - def test_general_context(self): - request = RequestFactory().get("/") - request.user = AnonymousUser() - request.session = {"account": None, "puppet": None} - - response = general_context.general_context(request) - - self.assertEqual( - response, - { - "account": None, - "puppet": None, - "game_name": "test_name", - "game_slogan": "test_game_slogan", - "evennia_userapps": ["Accounts"], - "evennia_entityapps": ["Objects", "Scripts", "Comms", "Help"], - "evennia_setupapps": ["Permissions", "Config"], - "evennia_connectapps": ["Irc"], - "evennia_websiteapps": ["Flatpages", "News", "Sites"], - "webclient_enabled": "webclient_enabled_testvalue", - "websocket_enabled": "websocket_client_enabled_testvalue", - "websocket_port": "websocket_client_port_testvalue", - "websocket_url": "websocket_client_url_testvalue", - "rest_api_enabled": True, - "server_hostname": 'localhost', - "ssh_enabled": False, - "ssh_ports": False, - "telnet_enabled": True, - "telnet_ports": [4000], - "telnet_ssl_enabled": False, - "telnet_ssl_ports": [4003], - }, - )
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/web/webclient/views.html b/docs/0.9.5/_modules/evennia/web/webclient/views.html deleted file mode 100644 index 4b6c53a4ef..0000000000 --- a/docs/0.9.5/_modules/evennia/web/webclient/views.html +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - - - evennia.web.webclient.views — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.web.webclient.views

-"""
-This contains a simple view for rendering the webclient
-page and serve it eventual static content.
-
-"""
-
-from django.conf import settings
-from django.http import Http404
-from django.shortcuts import render
-from django.contrib.auth import login, authenticate
-
-from evennia.accounts.models import AccountDB
-from evennia.utils import logger
-
-
-
[docs]def webclient(request): - """ - Webclient page template loading. - - """ - # auto-login is now handled by evennia.web.utils.middleware - - # check if webclient should be enabled - if not settings.WEBCLIENT_ENABLED: - raise Http404 - - # make sure to store the browser session's hash so the webclient can get to it! - pagevars = {"browser_sessid": request.session.session_key} - - return render(request, "webclient.html", pagevars)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/web/website/forms.html b/docs/0.9.5/_modules/evennia/web/website/forms.html deleted file mode 100644 index 36d66263ff..0000000000 --- a/docs/0.9.5/_modules/evennia/web/website/forms.html +++ /dev/null @@ -1,280 +0,0 @@ - - - - - - - - evennia.web.website.forms — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.web.website.forms

-from django import forms
-from django.conf import settings
-from django.contrib.auth.forms import UserCreationForm, UsernameField
-from django.forms import ModelForm
-from django.utils.html import escape
-from evennia.utils import class_from_module
-
-
-
[docs]class EvenniaForm(forms.Form): - """ - This is a stock Django form, but modified so that all values provided - through it are escaped (sanitized). Validation is performed by the fields - you define in the form. - - This has little to do with Evennia itself and is more general web security- - related. - - https://www.owasp.org/index.php/Input_Validation_Cheat_Sheet#Goals_of_Input_Validation - - """ - -
[docs] def clean(self): - """ - Django hook. Performed on form submission. - - Returns: - cleaned (dict): Dictionary of key:value pairs submitted on the form. - - """ - # Call parent function - cleaned = super().clean() - - # Escape all values provided by user - cleaned = {k: escape(v) for k, v in cleaned.items()} - return cleaned
- - -
[docs]class AccountForm(UserCreationForm): - """ - This is a generic Django form tailored to the Account model. - - In this incarnation it does not allow getting/setting of attributes, only - core User model fields (username, email, password). - - """ - -
[docs] class Meta: - """ - This is a Django construct that provides additional configuration to - the form. - - """ - - # The model/typeclass this form creates - model = class_from_module(settings.BASE_ACCOUNT_TYPECLASS, - fallback=settings.FALLBACK_ACCOUNT_TYPECLASS) - - # The fields to display on the form, in the given order - fields = ("username", "email") - - # Any overrides of field classes - field_classes = {"username": UsernameField}
- - # Username is collected as part of the core UserCreationForm, so we just need - # to add a field to (optionally) capture email. - email = forms.EmailField( - help_text="A valid email address. Optional; used for password resets.", required=False - )
- - -
[docs]class ObjectForm(EvenniaForm, ModelForm): - """ - This is a Django form for generic Evennia Objects that allows modification - of attributes when called from a descendent of ObjectUpdate or ObjectCreate - views. - - It defines no fields by default; you have to do that by extending this class - and defining what fields you want to be recorded. See the CharacterForm for - a simple example of how to do this. - - """ - -
[docs] class Meta: - """ - This is a Django construct that provides additional configuration to - the form. - - """ - - # The model/typeclass this form creates - model = class_from_module(settings.BASE_OBJECT_TYPECLASS, - fallback=settings.FALLBACK_OBJECT_TYPECLASS) - - # The fields to display on the form, in the given order - fields = ("db_key",) - - # This lets us rename ugly db-specific keys to something more human - labels = {"db_key": "Name"}
- - -
[docs]class CharacterForm(ObjectForm): - """ - This is a Django form for Evennia Character objects. - - Since Evennia characters only have one attribute by default, this form only - defines a field for that single attribute. The names of fields you define should - correspond to their names as stored in the dbhandler; you can display - 'prettier' versions of the fieldname on the form using the 'label' kwarg. - - The basic field types are CharFields and IntegerFields, which let you enter - text and numbers respectively. IntegerFields have some neat validation tricks - they can do, like mandating values fall within a certain range. - - For example, a complete "age" field (which stores its value to - `character.db.age` might look like: - - age = forms.IntegerField( - label="Your Age", - min_value=18, max_value=9000, - help_text="Years since your birth.") - - Default input fields are generic single-line text boxes. You can control what - sort of input field users will see by specifying a "widget." An example of - this is used for the 'desc' field to show a Textarea box instead of a Textbox. - - For help in building out your form, please see: - https://docs.djangoproject.com/en/1.11/topics/forms/#building-a-form-in-django - - For more information on fields and their capabilities, see: - https://docs.djangoproject.com/en/1.11/ref/forms/fields/ - - For more on widgets, see: - https://docs.djangoproject.com/en/1.11/ref/forms/widgets/ - - """ - -
[docs] class Meta: - """ - This is a Django construct that provides additional configuration to - the form. - - """ - - # Get the correct object model - model = class_from_module(settings.BASE_CHARACTER_TYPECLASS, - fallback=settings.FALLBACK_CHARACTER_TYPECLASS) - - # Allow entry of the 'key' field - fields = ("db_key",) - - # Rename 'key' to something more intelligible - labels = {"db_key": "Name"}
- - # Fields pertaining to configurable attributes on the Character object. - desc = forms.CharField( - label="Description", - max_length=2048, - required=False, - widget=forms.Textarea(attrs={"rows": 3}), - help_text="A brief description of your character.", - )
- - -
[docs]class CharacterUpdateForm(CharacterForm): - """ - This is a Django form for updating Evennia Character objects. - - By default it is the same as the CharacterForm, but if there are circumstances - in which you don't want to let players edit all the same attributes they had - access to during creation, you can redefine this form with those fields you do - wish to allow. - - """ - - pass
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/evennia/web/website/tests.html b/docs/0.9.5/_modules/evennia/web/website/tests.html deleted file mode 100644 index b13335039f..0000000000 --- a/docs/0.9.5/_modules/evennia/web/website/tests.html +++ /dev/null @@ -1,472 +0,0 @@ - - - - - - - - evennia.web.website.tests — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for evennia.web.website.tests

-from django.conf import settings
-from django.utils.text import slugify
-from django.test import Client, override_settings
-from django.urls import reverse
-from evennia.utils import class_from_module
-from evennia.utils.create import create_help_entry
-from evennia.utils.test_resources import BaseEvenniaTest
-from evennia.help import filehelp
-
-_FILE_HELP_ENTRIES = None
-
-
-
[docs]class EvenniaWebTest(BaseEvenniaTest): - - # Use the same classes the views are expecting - account_typeclass = settings.BASE_ACCOUNT_TYPECLASS - object_typeclass = settings.BASE_OBJECT_TYPECLASS - character_typeclass = settings.BASE_CHARACTER_TYPECLASS - exit_typeclass = settings.BASE_EXIT_TYPECLASS - room_typeclass = settings.BASE_ROOM_TYPECLASS - script_typeclass = settings.BASE_SCRIPT_TYPECLASS - channel_typeclass = settings.BASE_CHANNEL_TYPECLASS - - # Default named url - url_name = "index" - - # Response to expect for unauthenticated requests - unauthenticated_response = 200 - - # Response to expect for authenticated requests - authenticated_response = 200 - -
[docs] def setUp(self): - super(EvenniaWebTest, self).setUp() - - # Add chars to account rosters - self.account.db._playable_characters = [self.char1] - self.account2.db._playable_characters = [self.char2] - - for account in (self.account, self.account2): - # Demote accounts to Player permissions - account.permissions.add("Player") - account.permissions.remove("Developer") - - # Grant permissions to chars - for char in account.db._playable_characters: - char.locks.add("edit:id(%s) or perm(Admin)" % account.pk) - char.locks.add("delete:id(%s) or perm(Admin)" % account.pk) - char.locks.add("view:all()")
- -
[docs] def test_valid_chars(self): - "Make sure account has playable characters" - self.assertTrue(self.char1 in self.account.db._playable_characters) - self.assertTrue(self.char2 in self.account2.db._playable_characters)
- -
[docs] def get_kwargs(self): - return {}
- -
[docs] def test_get(self): - # Try accessing page while not logged in - response = self.client.get(reverse(self.url_name, kwargs=self.get_kwargs())) - self.assertEqual(response.status_code, self.unauthenticated_response)
- -
[docs] def login(self): - return self.client.login(username="TestAccount", password="testpassword")
- -
[docs] def test_get_authenticated(self): - logged_in = self.login() - self.assertTrue(logged_in, "Account failed to log in!") - - # Try accessing page while logged in - response = self.client.get(reverse(self.url_name, kwargs=self.get_kwargs()), follow=True) - - self.assertEqual(response.status_code, self.authenticated_response)
- - -# ------------------------------------------------------------------------------ - - -
[docs]class AdminTest(EvenniaWebTest): - url_name = "django_admin" - unauthenticated_response = 302
- - -
[docs]class IndexTest(EvenniaWebTest): - url_name = "index"
- - -
[docs]class RegisterTest(EvenniaWebTest): - url_name = "register"
- - -
[docs]class LoginTest(EvenniaWebTest): - url_name = "login"
- - -
[docs]class LogoutTest(EvenniaWebTest): - url_name = "logout"
- - -
[docs]class PasswordResetTest(EvenniaWebTest): - url_name = "password_change" - unauthenticated_response = 302
- - -
[docs]class WebclientTest(EvenniaWebTest): - url_name = "webclient:index" - -
[docs] @override_settings(WEBCLIENT_ENABLED=True) - def test_get(self): - self.authenticated_response = 200 - self.unauthenticated_response = 200 - super(WebclientTest, self).test_get()
- -
[docs] @override_settings(WEBCLIENT_ENABLED=False) - def test_get_disabled(self): - self.authenticated_response = 404 - self.unauthenticated_response = 404 - super(WebclientTest, self).test_get()
- - -
[docs]class ChannelListTest(EvenniaWebTest): - url_name = "channels"
- - -
[docs]class ChannelDetailTest(EvenniaWebTest): - url_name = "channel-detail" - -
[docs] def setUp(self): - super(ChannelDetailTest, self).setUp() - - klass = class_from_module(self.channel_typeclass, - fallback=settings.FALLBACK_CHANNEL_TYPECLASS) - - # Create a channel - klass.create("demo")
- -
[docs] def get_kwargs(self): - return {"slug": slugify("demo")}
- - -
[docs]class HelpListTest(EvenniaWebTest): - url_name = "help"
- - -HELP_ENTRY_DICTS = [ - { - "key": "unit test file entry", - "category": "General", - "text": "cache test file entry text" - } -] - -
[docs]class HelpDetailTest(EvenniaWebTest): - url_name = "help-entry-detail" - -
[docs] def setUp(self): - super().setUp() - - # create a db help entry - create_help_entry('unit test db entry', 'unit test db entry text', category="General")
- -
[docs] def get_kwargs(self): - return {"category": slugify("general"), - "topic": slugify('unit test db entry')}
- -
[docs] def test_view(self): - response = self.client.get(reverse(self.url_name, kwargs=self.get_kwargs()), follow=True) - self.assertEqual(response.context["entry_text"], 'unit test db entry text')
- -
[docs] def test_object_cache(self): - # clear file help entries, use local HELP_ENTRY_DICTS to recreate new entries - global _FILE_HELP_ENTRIES - if _FILE_HELP_ENTRIES is None: - from evennia.help.filehelp import FILE_HELP_ENTRIES as _FILE_HELP_ENTRIES - help_module = 'evennia.web.website.tests' - self.file_help_store = _FILE_HELP_ENTRIES.__init__(help_file_modules=[help_module]) - - # request access to an entry - response = self.client.get(reverse(self.url_name, kwargs=self.get_kwargs()), follow=True) - self.assertEqual(response.context["entry_text"], 'unit test db entry text') - # request a second entry, verifing the cached object is not provided on a new topic request - entry_two_args = {"category": slugify("general"), "topic": slugify('unit test file entry')} - response = self.client.get(reverse(self.url_name, kwargs=entry_two_args), follow=True) - self.assertEqual(response.context["entry_text"], 'cache test file entry text')
- - -
[docs]class HelpLockedDetailTest(EvenniaWebTest): - url_name = "help-entry-detail" - -
[docs] def setUp(self): - super(HelpLockedDetailTest, self).setUp() - - # create a db entry with a lock - self.db_help_entry = create_help_entry('unit test locked topic', 'unit test locked entrytext', - category="General", locks='read:perm(Developer)')
- -
[docs] def get_kwargs(self): - return {"category": slugify("general"), - "topic": slugify('unit test locked topic')}
- -
[docs] def test_locked_entry(self): - # request access to an entry for permission the account does not have - response = self.client.get(reverse(self.url_name, kwargs=self.get_kwargs()), follow=True) - self.assertEqual(response.context["entry_text"], 'Failed to find entry.')
- -
[docs] def test_lock_with_perm(self): - # log TestAccount in, grant permission required, read the entry - self.login() - self.account.permissions.add("Developer") - response = self.client.get(reverse(self.url_name, kwargs=self.get_kwargs()), follow=True) - self.assertEqual(response.context["entry_text"], 'unit test locked entrytext')
- - -
[docs]class CharacterCreateView(EvenniaWebTest): - url_name = "character-create" - unauthenticated_response = 302 - -
[docs] @override_settings(MULTISESSION_MODE=0) - def test_valid_access_multisession_0(self): - "Account1 with no characters should be able to create a new one" - self.account.db._playable_characters = [] - - # Login account - self.login() - - # Post data for a new character - data = {"db_key": "gannon", "desc": "Some dude."} - - response = self.client.post(reverse(self.url_name), data=data, follow=True) - self.assertEqual(response.status_code, 200) - - # Make sure the character was actually created - self.assertTrue( - len(self.account.db._playable_characters) == 1, - "Account only has the following characters attributed to it: %s" - % self.account.db._playable_characters, - )
- -
[docs] @override_settings(MULTISESSION_MODE=2) - @override_settings(MAX_NR_CHARACTERS=10) - def test_valid_access_multisession_2(self): - "Account1 should be able to create a new character" - # Login account - self.login() - - # Post data for a new character - data = {"db_key": "gannon", "desc": "Some dude."} - - response = self.client.post(reverse(self.url_name), data=data, follow=True) - self.assertEqual(response.status_code, 200) - - # Make sure the character was actually created - self.assertTrue( - len(self.account.db._playable_characters) > 1, - "Account only has the following characters attributed to it: %s" - % self.account.db._playable_characters, - )
- - -
[docs]class CharacterPuppetView(EvenniaWebTest): - url_name = "character-puppet" - unauthenticated_response = 302 - -
[docs] def get_kwargs(self): - return {"pk": self.char1.pk, "slug": slugify(self.char1.name)}
- -
[docs] def test_invalid_access(self): - "Account1 should not be able to puppet Account2:Char2" - # Login account - self.login() - - # Try to access puppet page for char2 - kwargs = {"pk": self.char2.pk, "slug": slugify(self.char2.name)} - response = self.client.get(reverse(self.url_name, kwargs=kwargs), follow=True) - self.assertTrue( - response.status_code >= 400, - "Invalid access should return a 4xx code-- either obj not found or permission denied! (Returned %s)" - % response.status_code, - )
- - -
[docs]class CharacterListView(EvenniaWebTest): - url_name = "characters" - unauthenticated_response = 302
- - -
[docs]class CharacterManageView(EvenniaWebTest): - url_name = "character-manage" - unauthenticated_response = 302
- - -
[docs]class CharacterUpdateView(EvenniaWebTest): - url_name = "character-update" - unauthenticated_response = 302 - -
[docs] def get_kwargs(self): - return {"pk": self.char1.pk, "slug": slugify(self.char1.name)}
- -
[docs] def test_valid_access(self): - "Account1 should be able to update Account1:Char1" - # Login account - self.login() - - # Try to access update page for char1 - response = self.client.get(reverse(self.url_name, kwargs=self.get_kwargs()), follow=True) - self.assertEqual(response.status_code, 200) - - # Try to update char1 desc - data = {"db_key": self.char1.db_key, "desc": "Just a regular type of dude."} - response = self.client.post( - reverse(self.url_name, kwargs=self.get_kwargs()), data=data, follow=True - ) - self.assertEqual(response.status_code, 200) - - # Make sure the change was made successfully - self.assertEqual(self.char1.db.desc, data["desc"])
- -
[docs] def test_invalid_access(self): - "Account1 should not be able to update Account2:Char2" - # Login account - self.login() - - # Try to access update page for char2 - kwargs = {"pk": self.char2.pk, "slug": slugify(self.char2.name)} - response = self.client.get(reverse(self.url_name, kwargs=kwargs), follow=True) - self.assertEqual(response.status_code, 403)
- - -
[docs]class CharacterDeleteView(EvenniaWebTest): - url_name = "character-delete" - unauthenticated_response = 302 - -
[docs] def get_kwargs(self): - return {"pk": self.char1.pk, "slug": slugify(self.char1.name)}
- -
[docs] def test_valid_access(self): - "Account1 should be able to delete Account1:Char1" - # Login account - self.login() - - # Try to access delete page for char1 - response = self.client.get(reverse(self.url_name, kwargs=self.get_kwargs()), follow=True) - self.assertEqual(response.status_code, 200) - - # Proceed with deleting it - data = {"value": "yes"} - response = self.client.post( - reverse(self.url_name, kwargs=self.get_kwargs()), data=data, follow=True - ) - self.assertEqual(response.status_code, 200) - - # Make sure it deleted - self.assertFalse( - self.char1 in self.account.db._playable_characters, - "Char1 is still in Account playable characters list.", - )
- -
[docs] def test_invalid_access(self): - "Account1 should not be able to delete Account2:Char2" - # Login account - self.login() - - # Try to access delete page for char2 - kwargs = {"pk": self.char2.pk, "slug": slugify(self.char2.name)} - response = self.client.get(reverse(self.url_name, kwargs=kwargs), follow=True) - self.assertEqual(response.status_code, 403)
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/functools.html b/docs/0.9.5/_modules/functools.html deleted file mode 100644 index 78333ffc99..0000000000 --- a/docs/0.9.5/_modules/functools.html +++ /dev/null @@ -1,1079 +0,0 @@ - - - - - - - - functools — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

Source code for functools

-"""functools.py - Tools for working with functions and callable objects
-"""
-# Python module wrapper for _functools C module
-# to allow utilities written in Python to be added
-# to the functools module.
-# Written by Nick Coghlan <ncoghlan at gmail.com>,
-# Raymond Hettinger <python at rcn.com>,
-# and Łukasz Langa <lukasz at langa.pl>.
-#   Copyright (C) 2006-2013 Python Software Foundation.
-# See C source code for _functools credits/copyright
-
-__all__ = ['update_wrapper', 'wraps', 'WRAPPER_ASSIGNMENTS', 'WRAPPER_UPDATES',
-           'total_ordering', 'cmp_to_key', 'lru_cache', 'reduce', 'partial',
-           'partialmethod', 'singledispatch', 'singledispatchmethod',
-           "cached_property"]
-
-from abc import get_cache_token
-from collections import namedtuple
-# import types, weakref  # Deferred to single_dispatch()
-from reprlib import recursive_repr
-from _thread import RLock
-
-
-################################################################################
-### update_wrapper() and wraps() decorator
-################################################################################
-
-# update_wrapper() and wraps() are tools to help write
-# wrapper functions that can handle naive introspection
-
-WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__qualname__', '__doc__',
-                       '__annotations__')
-WRAPPER_UPDATES = ('__dict__',)
-def update_wrapper(wrapper,
-                   wrapped,
-                   assigned = WRAPPER_ASSIGNMENTS,
-                   updated = WRAPPER_UPDATES):
-    """Update a wrapper function to look like the wrapped function
-
-       wrapper is the function to be updated
-       wrapped is the original function
-       assigned is a tuple naming the attributes assigned directly
-       from the wrapped function to the wrapper function (defaults to
-       functools.WRAPPER_ASSIGNMENTS)
-       updated is a tuple naming the attributes of the wrapper that
-       are updated with the corresponding attribute from the wrapped
-       function (defaults to functools.WRAPPER_UPDATES)
-    """
-    for attr in assigned:
-        try:
-            value = getattr(wrapped, attr)
-        except AttributeError:
-            pass
-        else:
-            setattr(wrapper, attr, value)
-    for attr in updated:
-        getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
-    # Issue #17482: set __wrapped__ last so we don't inadvertently copy it
-    # from the wrapped function when updating __dict__
-    wrapper.__wrapped__ = wrapped
-    # Return the wrapper so this can be used as a decorator via partial()
-    return wrapper
-
-def wraps(wrapped,
-          assigned = WRAPPER_ASSIGNMENTS,
-          updated = WRAPPER_UPDATES):
-    """Decorator factory to apply update_wrapper() to a wrapper function
-
-       Returns a decorator that invokes update_wrapper() with the decorated
-       function as the wrapper argument and the arguments to wraps() as the
-       remaining arguments. Default arguments are as for update_wrapper().
-       This is a convenience function to simplify applying partial() to
-       update_wrapper().
-    """
-    return partial(update_wrapper, wrapped=wrapped,
-                   assigned=assigned, updated=updated)
-
-
-################################################################################
-### total_ordering class decorator
-################################################################################
-
-# The total ordering functions all invoke the root magic method directly
-# rather than using the corresponding operator.  This avoids possible
-# infinite recursion that could occur when the operator dispatch logic
-# detects a NotImplemented result and then calls a reflected method.
-
-def _gt_from_lt(self, other, NotImplemented=NotImplemented):
-    'Return a > b.  Computed by @total_ordering from (not a < b) and (a != b).'
-    op_result = self.__lt__(other)
-    if op_result is NotImplemented:
-        return op_result
-    return not op_result and self != other
-
-def _le_from_lt(self, other, NotImplemented=NotImplemented):
-    'Return a <= b.  Computed by @total_ordering from (a < b) or (a == b).'
-    op_result = self.__lt__(other)
-    return op_result or self == other
-
-def _ge_from_lt(self, other, NotImplemented=NotImplemented):
-    'Return a >= b.  Computed by @total_ordering from (not a < b).'
-    op_result = self.__lt__(other)
-    if op_result is NotImplemented:
-        return op_result
-    return not op_result
-
-def _ge_from_le(self, other, NotImplemented=NotImplemented):
-    'Return a >= b.  Computed by @total_ordering from (not a <= b) or (a == b).'
-    op_result = self.__le__(other)
-    if op_result is NotImplemented:
-        return op_result
-    return not op_result or self == other
-
-def _lt_from_le(self, other, NotImplemented=NotImplemented):
-    'Return a < b.  Computed by @total_ordering from (a <= b) and (a != b).'
-    op_result = self.__le__(other)
-    if op_result is NotImplemented:
-        return op_result
-    return op_result and self != other
-
-def _gt_from_le(self, other, NotImplemented=NotImplemented):
-    'Return a > b.  Computed by @total_ordering from (not a <= b).'
-    op_result = self.__le__(other)
-    if op_result is NotImplemented:
-        return op_result
-    return not op_result
-
-def _lt_from_gt(self, other, NotImplemented=NotImplemented):
-    'Return a < b.  Computed by @total_ordering from (not a > b) and (a != b).'
-    op_result = self.__gt__(other)
-    if op_result is NotImplemented:
-        return op_result
-    return not op_result and self != other
-
-def _ge_from_gt(self, other, NotImplemented=NotImplemented):
-    'Return a >= b.  Computed by @total_ordering from (a > b) or (a == b).'
-    op_result = self.__gt__(other)
-    return op_result or self == other
-
-def _le_from_gt(self, other, NotImplemented=NotImplemented):
-    'Return a <= b.  Computed by @total_ordering from (not a > b).'
-    op_result = self.__gt__(other)
-    if op_result is NotImplemented:
-        return op_result
-    return not op_result
-
-def _le_from_ge(self, other, NotImplemented=NotImplemented):
-    'Return a <= b.  Computed by @total_ordering from (not a >= b) or (a == b).'
-    op_result = self.__ge__(other)
-    if op_result is NotImplemented:
-        return op_result
-    return not op_result or self == other
-
-def _gt_from_ge(self, other, NotImplemented=NotImplemented):
-    'Return a > b.  Computed by @total_ordering from (a >= b) and (a != b).'
-    op_result = self.__ge__(other)
-    if op_result is NotImplemented:
-        return op_result
-    return op_result and self != other
-
-def _lt_from_ge(self, other, NotImplemented=NotImplemented):
-    'Return a < b.  Computed by @total_ordering from (not a >= b).'
-    op_result = self.__ge__(other)
-    if op_result is NotImplemented:
-        return op_result
-    return not op_result
-
-_convert = {
-    '__lt__': [('__gt__', _gt_from_lt),
-               ('__le__', _le_from_lt),
-               ('__ge__', _ge_from_lt)],
-    '__le__': [('__ge__', _ge_from_le),
-               ('__lt__', _lt_from_le),
-               ('__gt__', _gt_from_le)],
-    '__gt__': [('__lt__', _lt_from_gt),
-               ('__ge__', _ge_from_gt),
-               ('__le__', _le_from_gt)],
-    '__ge__': [('__le__', _le_from_ge),
-               ('__gt__', _gt_from_ge),
-               ('__lt__', _lt_from_ge)]
-}
-
-def total_ordering(cls):
-    """Class decorator that fills in missing ordering methods"""
-    # Find user-defined comparisons (not those inherited from object).
-    roots = {op for op in _convert if getattr(cls, op, None) is not getattr(object, op, None)}
-    if not roots:
-        raise ValueError('must define at least one ordering operation: < > <= >=')
-    root = max(roots)       # prefer __lt__ to __le__ to __gt__ to __ge__
-    for opname, opfunc in _convert[root]:
-        if opname not in roots:
-            opfunc.__name__ = opname
-            setattr(cls, opname, opfunc)
-    return cls
-
-
-################################################################################
-### cmp_to_key() function converter
-################################################################################
-
-def cmp_to_key(mycmp):
-    """Convert a cmp= function into a key= function"""
-    class K(object):
-        __slots__ = ['obj']
-        def __init__(self, obj):
-            self.obj = obj
-        def __lt__(self, other):
-            return mycmp(self.obj, other.obj) < 0
-        def __gt__(self, other):
-            return mycmp(self.obj, other.obj) > 0
-        def __eq__(self, other):
-            return mycmp(self.obj, other.obj) == 0
-        def __le__(self, other):
-            return mycmp(self.obj, other.obj) <= 0
-        def __ge__(self, other):
-            return mycmp(self.obj, other.obj) >= 0
-        __hash__ = None
-    return K
-
-try:
-    from _functools import cmp_to_key
-except ImportError:
-    pass
-
-
-################################################################################
-### reduce() sequence to a single item
-################################################################################
-
-_initial_missing = object()
-
-def reduce(function, sequence, initial=_initial_missing):
-    """
-    reduce(function, sequence[, initial]) -> value
-
-    Apply a function of two arguments cumulatively to the items of a sequence,
-    from left to right, so as to reduce the sequence to a single value.
-    For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
-    ((((1+2)+3)+4)+5).  If initial is present, it is placed before the items
-    of the sequence in the calculation, and serves as a default when the
-    sequence is empty.
-    """
-
-    it = iter(sequence)
-
-    if initial is _initial_missing:
-        try:
-            value = next(it)
-        except StopIteration:
-            raise TypeError("reduce() of empty sequence with no initial value") from None
-    else:
-        value = initial
-
-    for element in it:
-        value = function(value, element)
-
-    return value
-
-try:
-    from _functools import reduce
-except ImportError:
-    pass
-
-
-################################################################################
-### partial() argument application
-################################################################################
-
-# Purely functional, no descriptor behaviour
-class partial:
-    """New function with partial application of the given arguments
-    and keywords.
-    """
-
-    __slots__ = "func", "args", "keywords", "__dict__", "__weakref__"
-
-    def __new__(cls, func, /, *args, **keywords):
-        if not callable(func):
-            raise TypeError("the first argument must be callable")
-
-        if hasattr(func, "func"):
-            args = func.args + args
-            keywords = {**func.keywords, **keywords}
-            func = func.func
-
-        self = super(partial, cls).__new__(cls)
-
-        self.func = func
-        self.args = args
-        self.keywords = keywords
-        return self
-
-    def __call__(self, /, *args, **keywords):
-        keywords = {**self.keywords, **keywords}
-        return self.func(*self.args, *args, **keywords)
-
-    @recursive_repr()
-    def __repr__(self):
-        qualname = type(self).__qualname__
-        args = [repr(self.func)]
-        args.extend(repr(x) for x in self.args)
-        args.extend(f"{k}={v!r}" for (k, v) in self.keywords.items())
-        if type(self).__module__ == "functools":
-            return f"functools.{qualname}({', '.join(args)})"
-        return f"{qualname}({', '.join(args)})"
-
-    def __reduce__(self):
-        return type(self), (self.func,), (self.func, self.args,
-               self.keywords or None, self.__dict__ or None)
-
-    def __setstate__(self, state):
-        if not isinstance(state, tuple):
-            raise TypeError("argument to __setstate__ must be a tuple")
-        if len(state) != 4:
-            raise TypeError(f"expected 4 items in state, got {len(state)}")
-        func, args, kwds, namespace = state
-        if (not callable(func) or not isinstance(args, tuple) or
-           (kwds is not None and not isinstance(kwds, dict)) or
-           (namespace is not None and not isinstance(namespace, dict))):
-            raise TypeError("invalid partial state")
-
-        args = tuple(args) # just in case it's a subclass
-        if kwds is None:
-            kwds = {}
-        elif type(kwds) is not dict: # XXX does it need to be *exactly* dict?
-            kwds = dict(kwds)
-        if namespace is None:
-            namespace = {}
-
-        self.__dict__ = namespace
-        self.func = func
-        self.args = args
-        self.keywords = kwds
-
-try:
-    from _functools import partial
-except ImportError:
-    pass
-
-# Descriptor version
-class partialmethod(object):
-    """Method descriptor with partial application of the given arguments
-    and keywords.
-
-    Supports wrapping existing descriptors and handles non-descriptor
-    callables as instance methods.
-    """
-
-    def __init__(*args, **keywords):
-        if len(args) >= 2:
-            self, func, *args = args
-        elif not args:
-            raise TypeError("descriptor '__init__' of partialmethod "
-                            "needs an argument")
-        elif 'func' in keywords:
-            func = keywords.pop('func')
-            self, *args = args
-            import warnings
-            warnings.warn("Passing 'func' as keyword argument is deprecated",
-                          DeprecationWarning, stacklevel=2)
-        else:
-            raise TypeError("type 'partialmethod' takes at least one argument, "
-                            "got %d" % (len(args)-1))
-        args = tuple(args)
-
-        if not callable(func) and not hasattr(func, "__get__"):
-            raise TypeError("{!r} is not callable or a descriptor"
-                                 .format(func))
-
-        # func could be a descriptor like classmethod which isn't callable,
-        # so we can't inherit from partial (it verifies func is callable)
-        if isinstance(func, partialmethod):
-            # flattening is mandatory in order to place cls/self before all
-            # other arguments
-            # it's also more efficient since only one function will be called
-            self.func = func.func
-            self.args = func.args + args
-            self.keywords = {**func.keywords, **keywords}
-        else:
-            self.func = func
-            self.args = args
-            self.keywords = keywords
-    __init__.__text_signature__ = '($self, func, /, *args, **keywords)'
-
-    def __repr__(self):
-        args = ", ".join(map(repr, self.args))
-        keywords = ", ".join("{}={!r}".format(k, v)
-                                 for k, v in self.keywords.items())
-        format_string = "{module}.{cls}({func}, {args}, {keywords})"
-        return format_string.format(module=self.__class__.__module__,
-                                    cls=self.__class__.__qualname__,
-                                    func=self.func,
-                                    args=args,
-                                    keywords=keywords)
-
-    def _make_unbound_method(self):
-        def _method(cls_or_self, /, *args, **keywords):
-            keywords = {**self.keywords, **keywords}
-            return self.func(cls_or_self, *self.args, *args, **keywords)
-        _method.__isabstractmethod__ = self.__isabstractmethod__
-        _method._partialmethod = self
-        return _method
-
-    def __get__(self, obj, cls=None):
-        get = getattr(self.func, "__get__", None)
-        result = None
-        if get is not None:
-            new_func = get(obj, cls)
-            if new_func is not self.func:
-                # Assume __get__ returning something new indicates the
-                # creation of an appropriate callable
-                result = partial(new_func, *self.args, **self.keywords)
-                try:
-                    result.__self__ = new_func.__self__
-                except AttributeError:
-                    pass
-        if result is None:
-            # If the underlying descriptor didn't do anything, treat this
-            # like an instance method
-            result = self._make_unbound_method().__get__(obj, cls)
-        return result
-
-    @property
-    def __isabstractmethod__(self):
-        return getattr(self.func, "__isabstractmethod__", False)
-
-# Helper functions
-
-def _unwrap_partial(func):
-    while isinstance(func, partial):
-        func = func.func
-    return func
-
-################################################################################
-### LRU Cache function decorator
-################################################################################
-
-_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])
-
-class _HashedSeq(list):
-    """ This class guarantees that hash() will be called no more than once
-        per element.  This is important because the lru_cache() will hash
-        the key multiple times on a cache miss.
-
-    """
-
-    __slots__ = 'hashvalue'
-
-    def __init__(self, tup, hash=hash):
-        self[:] = tup
-        self.hashvalue = hash(tup)
-
-    def __hash__(self):
-        return self.hashvalue
-
-def _make_key(args, kwds, typed,
-             kwd_mark = (object(),),
-             fasttypes = {int, str},
-             tuple=tuple, type=type, len=len):
-    """Make a cache key from optionally typed positional and keyword arguments
-
-    The key is constructed in a way that is flat as possible rather than
-    as a nested structure that would take more memory.
-
-    If there is only a single argument and its data type is known to cache
-    its hash value, then that argument is returned without a wrapper.  This
-    saves space and improves lookup speed.
-
-    """
-    # All of code below relies on kwds preserving the order input by the user.
-    # Formerly, we sorted() the kwds before looping.  The new way is *much*
-    # faster; however, it means that f(x=1, y=2) will now be treated as a
-    # distinct call from f(y=2, x=1) which will be cached separately.
-    key = args
-    if kwds:
-        key += kwd_mark
-        for item in kwds.items():
-            key += item
-    if typed:
-        key += tuple(type(v) for v in args)
-        if kwds:
-            key += tuple(type(v) for v in kwds.values())
-    elif len(key) == 1 and type(key[0]) in fasttypes:
-        return key[0]
-    return _HashedSeq(key)
-
-def lru_cache(maxsize=128, typed=False):
-    """Least-recently-used cache decorator.
-
-    If *maxsize* is set to None, the LRU features are disabled and the cache
-    can grow without bound.
-
-    If *typed* is True, arguments of different types will be cached separately.
-    For example, f(3.0) and f(3) will be treated as distinct calls with
-    distinct results.
-
-    Arguments to the cached function must be hashable.
-
-    View the cache statistics named tuple (hits, misses, maxsize, currsize)
-    with f.cache_info().  Clear the cache and statistics with f.cache_clear().
-    Access the underlying function with f.__wrapped__.
-
-    See:  http://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)
-
-    """
-
-    # Users should only access the lru_cache through its public API:
-    #       cache_info, cache_clear, and f.__wrapped__
-    # The internals of the lru_cache are encapsulated for thread safety and
-    # to allow the implementation to change (including a possible C version).
-
-    if isinstance(maxsize, int):
-        # Negative maxsize is treated as 0
-        if maxsize < 0:
-            maxsize = 0
-    elif callable(maxsize) and isinstance(typed, bool):
-        # The user_function was passed in directly via the maxsize argument
-        user_function, maxsize = maxsize, 128
-        wrapper = _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo)
-        return update_wrapper(wrapper, user_function)
-    elif maxsize is not None:
-        raise TypeError(
-            'Expected first argument to be an integer, a callable, or None')
-
-    def decorating_function(user_function):
-        wrapper = _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo)
-        return update_wrapper(wrapper, user_function)
-
-    return decorating_function
-
-def _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo):
-    # Constants shared by all lru cache instances:
-    sentinel = object()          # unique object used to signal cache misses
-    make_key = _make_key         # build a key from the function arguments
-    PREV, NEXT, KEY, RESULT = 0, 1, 2, 3   # names for the link fields
-
-    cache = {}
-    hits = misses = 0
-    full = False
-    cache_get = cache.get    # bound method to lookup a key or return None
-    cache_len = cache.__len__  # get cache size without calling len()
-    lock = RLock()           # because linkedlist updates aren't threadsafe
-    root = []                # root of the circular doubly linked list
-    root[:] = [root, root, None, None]     # initialize by pointing to self
-
-    if maxsize == 0:
-
-        def wrapper(*args, **kwds):
-            # No caching -- just a statistics update
-            nonlocal misses
-            misses += 1
-            result = user_function(*args, **kwds)
-            return result
-
-    elif maxsize is None:
-
-        def wrapper(*args, **kwds):
-            # Simple caching without ordering or size limit
-            nonlocal hits, misses
-            key = make_key(args, kwds, typed)
-            result = cache_get(key, sentinel)
-            if result is not sentinel:
-                hits += 1
-                return result
-            misses += 1
-            result = user_function(*args, **kwds)
-            cache[key] = result
-            return result
-
-    else:
-
-        def wrapper(*args, **kwds):
-            # Size limited caching that tracks accesses by recency
-            nonlocal root, hits, misses, full
-            key = make_key(args, kwds, typed)
-            with lock:
-                link = cache_get(key)
-                if link is not None:
-                    # Move the link to the front of the circular queue
-                    link_prev, link_next, _key, result = link
-                    link_prev[NEXT] = link_next
-                    link_next[PREV] = link_prev
-                    last = root[PREV]
-                    last[NEXT] = root[PREV] = link
-                    link[PREV] = last
-                    link[NEXT] = root
-                    hits += 1
-                    return result
-                misses += 1
-            result = user_function(*args, **kwds)
-            with lock:
-                if key in cache:
-                    # Getting here means that this same key was added to the
-                    # cache while the lock was released.  Since the link
-                    # update is already done, we need only return the
-                    # computed result and update the count of misses.
-                    pass
-                elif full:
-                    # Use the old root to store the new key and result.
-                    oldroot = root
-                    oldroot[KEY] = key
-                    oldroot[RESULT] = result
-                    # Empty the oldest link and make it the new root.
-                    # Keep a reference to the old key and old result to
-                    # prevent their ref counts from going to zero during the
-                    # update. That will prevent potentially arbitrary object
-                    # clean-up code (i.e. __del__) from running while we're
-                    # still adjusting the links.
-                    root = oldroot[NEXT]
-                    oldkey = root[KEY]
-                    oldresult = root[RESULT]
-                    root[KEY] = root[RESULT] = None
-                    # Now update the cache dictionary.
-                    del cache[oldkey]
-                    # Save the potentially reentrant cache[key] assignment
-                    # for last, after the root and links have been put in
-                    # a consistent state.
-                    cache[key] = oldroot
-                else:
-                    # Put result in a new link at the front of the queue.
-                    last = root[PREV]
-                    link = [last, root, key, result]
-                    last[NEXT] = root[PREV] = cache[key] = link
-                    # Use the cache_len bound method instead of the len() function
-                    # which could potentially be wrapped in an lru_cache itself.
-                    full = (cache_len() >= maxsize)
-            return result
-
-    def cache_info():
-        """Report cache statistics"""
-        with lock:
-            return _CacheInfo(hits, misses, maxsize, cache_len())
-
-    def cache_clear():
-        """Clear the cache and cache statistics"""
-        nonlocal hits, misses, full
-        with lock:
-            cache.clear()
-            root[:] = [root, root, None, None]
-            hits = misses = 0
-            full = False
-
-    wrapper.cache_info = cache_info
-    wrapper.cache_clear = cache_clear
-    return wrapper
-
-try:
-    from _functools import _lru_cache_wrapper
-except ImportError:
-    pass
-
-
-################################################################################
-### singledispatch() - single-dispatch generic function decorator
-################################################################################
-
-def _c3_merge(sequences):
-    """Merges MROs in *sequences* to a single MRO using the C3 algorithm.
-
-    Adapted from http://www.python.org/download/releases/2.3/mro/.
-
-    """
-    result = []
-    while True:
-        sequences = [s for s in sequences if s]   # purge empty sequences
-        if not sequences:
-            return result
-        for s1 in sequences:   # find merge candidates among seq heads
-            candidate = s1[0]
-            for s2 in sequences:
-                if candidate in s2[1:]:
-                    candidate = None
-                    break      # reject the current head, it appears later
-            else:
-                break
-        if candidate is None:
-            raise RuntimeError("Inconsistent hierarchy")
-        result.append(candidate)
-        # remove the chosen candidate
-        for seq in sequences:
-            if seq[0] == candidate:
-                del seq[0]
-
-def _c3_mro(cls, abcs=None):
-    """Computes the method resolution order using extended C3 linearization.
-
-    If no *abcs* are given, the algorithm works exactly like the built-in C3
-    linearization used for method resolution.
-
-    If given, *abcs* is a list of abstract base classes that should be inserted
-    into the resulting MRO. Unrelated ABCs are ignored and don't end up in the
-    result. The algorithm inserts ABCs where their functionality is introduced,
-    i.e. issubclass(cls, abc) returns True for the class itself but returns
-    False for all its direct base classes. Implicit ABCs for a given class
-    (either registered or inferred from the presence of a special method like
-    __len__) are inserted directly after the last ABC explicitly listed in the
-    MRO of said class. If two implicit ABCs end up next to each other in the
-    resulting MRO, their ordering depends on the order of types in *abcs*.
-
-    """
-    for i, base in enumerate(reversed(cls.__bases__)):
-        if hasattr(base, '__abstractmethods__'):
-            boundary = len(cls.__bases__) - i
-            break   # Bases up to the last explicit ABC are considered first.
-    else:
-        boundary = 0
-    abcs = list(abcs) if abcs else []
-    explicit_bases = list(cls.__bases__[:boundary])
-    abstract_bases = []
-    other_bases = list(cls.__bases__[boundary:])
-    for base in abcs:
-        if issubclass(cls, base) and not any(
-                issubclass(b, base) for b in cls.__bases__
-            ):
-            # If *cls* is the class that introduces behaviour described by
-            # an ABC *base*, insert said ABC to its MRO.
-            abstract_bases.append(base)
-    for base in abstract_bases:
-        abcs.remove(base)
-    explicit_c3_mros = [_c3_mro(base, abcs=abcs) for base in explicit_bases]
-    abstract_c3_mros = [_c3_mro(base, abcs=abcs) for base in abstract_bases]
-    other_c3_mros = [_c3_mro(base, abcs=abcs) for base in other_bases]
-    return _c3_merge(
-        [[cls]] +
-        explicit_c3_mros + abstract_c3_mros + other_c3_mros +
-        [explicit_bases] + [abstract_bases] + [other_bases]
-    )
-
-def _compose_mro(cls, types):
-    """Calculates the method resolution order for a given class *cls*.
-
-    Includes relevant abstract base classes (with their respective bases) from
-    the *types* iterable. Uses a modified C3 linearization algorithm.
-
-    """
-    bases = set(cls.__mro__)
-    # Remove entries which are already present in the __mro__ or unrelated.
-    def is_related(typ):
-        return (typ not in bases and hasattr(typ, '__mro__')
-                                 and issubclass(cls, typ))
-    types = [n for n in types if is_related(n)]
-    # Remove entries which are strict bases of other entries (they will end up
-    # in the MRO anyway.
-    def is_strict_base(typ):
-        for other in types:
-            if typ != other and typ in other.__mro__:
-                return True
-        return False
-    types = [n for n in types if not is_strict_base(n)]
-    # Subclasses of the ABCs in *types* which are also implemented by
-    # *cls* can be used to stabilize ABC ordering.
-    type_set = set(types)
-    mro = []
-    for typ in types:
-        found = []
-        for sub in typ.__subclasses__():
-            if sub not in bases and issubclass(cls, sub):
-                found.append([s for s in sub.__mro__ if s in type_set])
-        if not found:
-            mro.append(typ)
-            continue
-        # Favor subclasses with the biggest number of useful bases
-        found.sort(key=len, reverse=True)
-        for sub in found:
-            for subcls in sub:
-                if subcls not in mro:
-                    mro.append(subcls)
-    return _c3_mro(cls, abcs=mro)
-
-def _find_impl(cls, registry):
-    """Returns the best matching implementation from *registry* for type *cls*.
-
-    Where there is no registered implementation for a specific type, its method
-    resolution order is used to find a more generic implementation.
-
-    Note: if *registry* does not contain an implementation for the base
-    *object* type, this function may return None.
-
-    """
-    mro = _compose_mro(cls, registry.keys())
-    match = None
-    for t in mro:
-        if match is not None:
-            # If *match* is an implicit ABC but there is another unrelated,
-            # equally matching implicit ABC, refuse the temptation to guess.
-            if (t in registry and t not in cls.__mro__
-                              and match not in cls.__mro__
-                              and not issubclass(match, t)):
-                raise RuntimeError("Ambiguous dispatch: {} or {}".format(
-                    match, t))
-            break
-        if t in registry:
-            match = t
-    return registry.get(match)
-
-def singledispatch(func):
-    """Single-dispatch generic function decorator.
-
-    Transforms a function into a generic function, which can have different
-    behaviours depending upon the type of its first argument. The decorated
-    function acts as the default implementation, and additional
-    implementations can be registered using the register() attribute of the
-    generic function.
-    """
-    # There are many programs that use functools without singledispatch, so we
-    # trade-off making singledispatch marginally slower for the benefit of
-    # making start-up of such applications slightly faster.
-    import types, weakref
-
-    registry = {}
-    dispatch_cache = weakref.WeakKeyDictionary()
-    cache_token = None
-
-    def dispatch(cls):
-        """generic_func.dispatch(cls) -> <function implementation>
-
-        Runs the dispatch algorithm to return the best available implementation
-        for the given *cls* registered on *generic_func*.
-
-        """
-        nonlocal cache_token
-        if cache_token is not None:
-            current_token = get_cache_token()
-            if cache_token != current_token:
-                dispatch_cache.clear()
-                cache_token = current_token
-        try:
-            impl = dispatch_cache[cls]
-        except KeyError:
-            try:
-                impl = registry[cls]
-            except KeyError:
-                impl = _find_impl(cls, registry)
-            dispatch_cache[cls] = impl
-        return impl
-
-    def register(cls, func=None):
-        """generic_func.register(cls, func) -> func
-
-        Registers a new implementation for the given *cls* on a *generic_func*.
-
-        """
-        nonlocal cache_token
-        if func is None:
-            if isinstance(cls, type):
-                return lambda f: register(cls, f)
-            ann = getattr(cls, '__annotations__', {})
-            if not ann:
-                raise TypeError(
-                    f"Invalid first argument to `register()`: {cls!r}. "
-                    f"Use either `@register(some_class)` or plain `@register` "
-                    f"on an annotated function."
-                )
-            func = cls
-
-            # only import typing if annotation parsing is necessary
-            from typing import get_type_hints
-            argname, cls = next(iter(get_type_hints(func).items()))
-            if not isinstance(cls, type):
-                raise TypeError(
-                    f"Invalid annotation for {argname!r}. "
-                    f"{cls!r} is not a class."
-                )
-        registry[cls] = func
-        if cache_token is None and hasattr(cls, '__abstractmethods__'):
-            cache_token = get_cache_token()
-        dispatch_cache.clear()
-        return func
-
-    def wrapper(*args, **kw):
-        if not args:
-            raise TypeError(f'{funcname} requires at least '
-                            '1 positional argument')
-
-        return dispatch(args[0].__class__)(*args, **kw)
-
-    funcname = getattr(func, '__name__', 'singledispatch function')
-    registry[object] = func
-    wrapper.register = register
-    wrapper.dispatch = dispatch
-    wrapper.registry = types.MappingProxyType(registry)
-    wrapper._clear_cache = dispatch_cache.clear
-    update_wrapper(wrapper, func)
-    return wrapper
-
-
-# Descriptor version
-class singledispatchmethod:
-    """Single-dispatch generic method descriptor.
-
-    Supports wrapping existing descriptors and handles non-descriptor
-    callables as instance methods.
-    """
-
-    def __init__(self, func):
-        if not callable(func) and not hasattr(func, "__get__"):
-            raise TypeError(f"{func!r} is not callable or a descriptor")
-
-        self.dispatcher = singledispatch(func)
-        self.func = func
-
-    def register(self, cls, method=None):
-        """generic_method.register(cls, func) -> func
-
-        Registers a new implementation for the given *cls* on a *generic_method*.
-        """
-        return self.dispatcher.register(cls, func=method)
-
-    def __get__(self, obj, cls=None):
-        def _method(*args, **kwargs):
-            method = self.dispatcher.dispatch(args[0].__class__)
-            return method.__get__(obj, cls)(*args, **kwargs)
-
-        _method.__isabstractmethod__ = self.__isabstractmethod__
-        _method.register = self.register
-        update_wrapper(_method, self.func)
-        return _method
-
-    @property
-    def __isabstractmethod__(self):
-        return getattr(self.func, '__isabstractmethod__', False)
-
-
-################################################################################
-### cached_property() - computed once per instance, cached as attribute
-################################################################################
-
-_NOT_FOUND = object()
-
-
-class cached_property:
-    def __init__(self, func):
-        self.func = func
-        self.attrname = None
-        self.__doc__ = func.__doc__
-        self.lock = RLock()
-
-    def __set_name__(self, owner, name):
-        if self.attrname is None:
-            self.attrname = name
-        elif name != self.attrname:
-            raise TypeError(
-                "Cannot assign the same cached_property to two different names "
-                f"({self.attrname!r} and {name!r})."
-            )
-
-    def __get__(self, instance, owner=None):
-        if instance is None:
-            return self
-        if self.attrname is None:
-            raise TypeError(
-                "Cannot use cached_property instance without calling __set_name__ on it.")
-        try:
-            cache = instance.__dict__
-        except AttributeError:  # not all objects have __dict__ (e.g. class defines slots)
-            msg = (
-                f"No '__dict__' attribute on {type(instance).__name__!r} "
-                f"instance to cache {self.attrname!r} property."
-            )
-            raise TypeError(msg) from None
-        val = cache.get(self.attrname, _NOT_FOUND)
-        if val is _NOT_FOUND:
-            with self.lock:
-                # check if another thread filled cache while we awaited lock
-                val = cache.get(self.attrname, _NOT_FOUND)
-                if val is _NOT_FOUND:
-                    val = self.func(instance)
-                    try:
-                        cache[self.attrname] = val
-                    except TypeError:
-                        msg = (
-                            f"The '__dict__' attribute on {type(instance).__name__!r} instance "
-                            f"does not support item assignment for caching {self.attrname!r} property."
-                        )
-                        raise TypeError(msg) from None
-        return val
-
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_modules/index.html b/docs/0.9.5/_modules/index.html deleted file mode 100644 index 4669d4364a..0000000000 --- a/docs/0.9.5/_modules/index.html +++ /dev/null @@ -1,230 +0,0 @@ - - - - - - - - Overview: module code — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -

All modules for which code is available

- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/_sources/A-voice-operated-elevator-using-events.md.txt b/docs/0.9.5/_sources/A-voice-operated-elevator-using-events.md.txt deleted file mode 100644 index 24f6bdef33..0000000000 --- a/docs/0.9.5/_sources/A-voice-operated-elevator-using-events.md.txt +++ /dev/null @@ -1,436 +0,0 @@ -# A voice operated elevator using events - - -- Previous tutorial: [Adding dialogues in events](./Dialogues-in-events.md) - -This tutorial will walk you through the steps to create a voice-operated elevator, using the [in- -game Python -system](https://github.com/evennia/evennia/blob/master/evennia/contrib/ingame_python/README.md). -This tutorial assumes the in-game Python system is installed in your game. If it isn't, you can -follow the installation steps given in [the documentation on in-game -Python](https://github.com/evennia/evennia/blob/master/evennia/contrib/ingame_python/README.md), and -come back on this tutorial once the system is installed. **You do not need to read** the entire -documentation, it's a good reference, but not the easiest way to learn about it. Hence these -tutorials. - -The in-game Python system allows to run code on individual objects in some situations. You don't -have to modify the source code to add these features, past the installation. The entire system -makes it easy to add specific features to some objects, but not all. - -> What will we try to do? - -In this tutorial, we are going to create a simple voice-operated elevator. In terms of features, we -will: - -- Explore events with parameters. -- Work on more interesting callbacks. -- Learn about chained events. -- Play with variable modification in callbacks. - -## Our study case - -Let's summarize what we want to achieve first. We would like to create a room that will represent -the inside of our elevator. In this room, a character could just say "1", "2" or "3", and the -elevator will start moving. The doors will close and open on the new floor (the exits leading in -and out of the elevator will be modified). - -We will work on basic features first, and then will adjust some, showing you how easy and powerfully -independent actions can be configured through the in-game Python system. - -## Creating the rooms and exits we need - -We'll create an elevator right in our room (generally called "Limbo", of ID 2). You could easily -adapt the following instructions if you already have some rooms and exits, of course, just remember -to check the IDs. - -> Note: the in-game Python system uses IDs for a lot of things. While it is not mandatory, it is -good practice to know the IDs you have for your callbacks, because it will make manipulation much -quicker. There are other ways to identify objects, but as they depend on many factors, IDs are -usually the safest path in our callbacks. - -Let's go into limbo (`#2`) to add our elevator. We'll add it to the north. To create this room, -in-game you could type: - - tunnel n = Inside of an elevator - -The game should respond by telling you: - - Created room Inside of an elevator(#3) of type typeclasses.rooms.Room. - Created Exit from Limbo to Inside of an elevator: north(#4) (n). - Created Exit back from Inside of an elevator to Limbo: south(#5) (s). - -Note the given IDs: - -- `#2` is limbo, the first room the system created. -- `#3` is our room inside of an elevator. -- `#4` is the north exit from Limbo to our elevator. -- `#5` is the south exit from an elevator to Limbo. - -Keep these IDs somewhere for the demonstration. You will shortly see why they are important. - -> Why have we created exits to our elevator and back to Limbo? Isn't the elevator supposed to move? - -It is. But we need to have exits that will represent the way inside the elevator and out. What we -will do, at every floor, will be to change these exits so they become connected to the right room. -You'll see this process a bit later. - -We have two more rooms to create: our floor 2 and 3. This time, we'll use `dig`, because we don't -need exits leading there, not yet anyway. - - dig The second floor - dig The third floor - -Evennia should answer with: - - Created room The second floor(#6) of type typeclasses.rooms.Room. - Created room The third floor(#7) of type typeclasses.rooms.Room. - -Add these IDs to your list, we will use them too. - -## Our first callback in the elevator - -Let's go to the elevator (you could use `tel #3` if you have the same IDs I have). - -This is our elevator room. It looks a bit empty, feel free to add a prettier description or other -things to decorate it a bit. - -But what we want now is to be able to say "1", "2" or "3" and have the elevator move in that -direction. - -If you have read [the previous tutorial about adding dialogues in events](./Dialogues-in-events.md), you -may remember what we need to do. If not, here's a summary: we need to run some code when somebody -speaks in the room. So we need to create a callback (the callback will contain our lines of code). -We just need to know on which event this should be set. You can enter `call here` to see the -possible events in this room. - -In the table, you should see the "say" event, which is called when somebody says something in the -room. So we'll need to add a callback to this event. Don't worry if you're a bit lost, just follow -the following steps, the way they connect together will become more obvious. - - call/add here = say 1, 2, 3 - -1. We need to add a callback. A callback contains the code that will be executed at a given time. -So we use the `call/add` command and switch. -2. `here` is our object, the room in which we are. -3. An equal sign. -4. The name of the event to which the callback should be connected. Here, the event is "say". -Meaning this callback will be executed every time somebody says something in the room. -5. But we add an event parameter to indicate the keywords said in the room that should execute our -callback. Otherwise, our callback would be called every time somebody speaks, no matter what. Here -we limit, indicating our callback should be executed only if the spoken message contains "1", "2" or -"3". - -An editor should open, inviting you to enter the Python code that should be executed. The first -thing to remember is to read the text provided (it can contain important information) and, most of -all, the list of variables that are available in this callback: - -``` -Variables you can use in this event: - - character: the character having spoken in this room. - room: the room connected to this event. - message: the text having been spoken by the character. - -----------Line Editor [Callback say of Inside of an elevator]--------------------- -01| -----------[l:01 w:000 c:0000]------------(:h for help)---------------------------- -``` - -This is important, in order to know what variables we can use in our callback out-of-the-box. Let's -write a single line to be sure our callback is called when we expect it to: - -```python -character.msg("You just said {}.".format(message)) -``` - -You can paste this line in-game, then type the `:wq` command to exit the editor and save your -modifications. - -Let's check. Try to say "hello" in the room. You should see the standard message, but nothing -more. Now try to say "1". Below the standard message, you should see: - - You just said 1. - -You can try it. Our callback is only called when we say "1", "2" or "3". Which is just what we -want. - -Let's go back in our code editor and add something more useful. - - call/edit here = say - -> Notice that we used the "edit" switch this time, since the callback exists, we just want to edit -it. - -The editor opens again. Let's empty it first: - - :DD - -And turn off automatic indentation, which will help us: - - := - -> Auto-indentation is an interesting feature of the code editor, but we'd better not use it at this -point, it will make copy/pasting more complicated. - -## Our entire callback in the elevator - -So here's the time to truly code our callback in-game. Here's a little reminder: - -1. We have all the IDs of our three rooms and two exits. -2. When we say "1", "2" or "3", the elevator should move to the right room, that is change the -exits. Remember, we already have the exits, we just need to change their location and destination. - -It's a good idea to try to write this callback yourself, but don't feel bad about checking the -solution right now. Here's a possible code that you could paste in the code editor: - -```python -# First let's have some constants -ELEVATOR = get(id=3) -FLOORS = { - "1": get(id=2), - "2": get(id=6), - "3": get(id=7), -} -TO_EXIT = get(id=4) -BACK_EXIT = get(id=5) - -# Now we check that the elevator isn't already at this floor -floor = FLOORS.get(message) -if floor is None: - character.msg("Which floor do you want?") -elif TO_EXIT.location is floor: - character.msg("The elevator already is at this floor.") -else: - # 'floor' contains the new room where the elevator should be - room.msg_contents("The doors of the elevator close with a clank.") - TO_EXIT.location = floor - BACK_EXIT.destination = floor - room.msg_contents("The doors of the elevator open to {floor}.", - mapping=dict(floor=floor)) -``` - -Let's review this longer callback: - -1. We first obtain the objects of both exits and our three floors. We use the `get()` eventfunc, -which is a shortcut to obtaining objects. We usually use it to retrieve specific objects with an -ID. We put the floors in a dictionary. The keys of the dictionary are the floor number (as str), -the values are room objects. -2. Remember, the `message` variable contains the message spoken in the room. So either "1", "2", or -"3". We still need to check it, however, because if the character says something like "1 2" in the -room, our callback will be executed. Let's be sure what she says is a floor number. -3. We then check if the elevator is already at this floor. Notice that we use `TO_EXIT.location`. -`TO_EXIT` contains our "north" exit, leading inside of our elevator. Therefore, its `location` will -be the room where the elevator currently is. -4. If the floor is a different one, have the elevator "move", changing just the location and -destination of both exits. - - The `BACK_EXIT` (that is "north") should change its location. The elevator shouldn't be -accessible through our old floor. - - The `TO_EXIT` (that is "south", the exit leading out of the elevator) should have a different -destination. When we go out of the elevator, we should find ourselves in the new floor, not the old -one. - -Feel free to expand on this example, changing messages, making further checks. Usage and practice -are keys. - -You can quit the editor as usual with `:wq` and test it out. - -## Adding a pause in our callback - -Let's improve our callback. One thing that's worth adding would be a pause: for the time being, -when we say the floor number in the elevator, the doors close and open right away. It would be -better to have a pause of several seconds. More logical. - -This is a great opportunity to learn about chained events. Chained events are very useful to create -pauses. Contrary to the events we have seen so far, chained events aren't called automatically. -They must be called by you, and can be called after some time. - -- Chained events always have the name "chain_X". Usually, X is a number, but you can give the -chained event a more explicit name. -- In our original callback, we will call our chained events in, say, 15 seconds. -- We'll also have to make sure the elevator isn't already moving. - -Other than that, a chained event can be connected to a callback as usual. We'll create a chained -event in our elevator, that will only contain the code necessary to open the doors to the new floor. - - call/add here = chain_1 - -The callback is added to the "chain_1" event, an event that will not be automatically called by the -system when something happens. Inside this event, you can paste the code to open the doors at the -new floor. You can notice a few differences: - -```python -TO_EXIT.location = floor -TO_EXIT.destination = ELEVATOR -BACK_EXIT.location = ELEVATOR -BACK_EXIT.destination = floor -room.msg_contents("The doors of the elevator open to {floor}.", - mapping=dict(floor=floor)) -``` - -Paste this code into the editor, then use `:wq` to save and quit the editor. - -Now let's edit our callback in the "say" event. We'll have to change it a bit: - -- The callback will have to check the elevator isn't already moving. -- It must change the exits when the elevator move. -- It has to call the "chain_1" event we have defined. It should call it 15 seconds later. - -Let's see the code in our callback. - - call/edit here = say - -Remove the current code and disable auto-indentation again: - - :DD - := - -And you can paste instead the following code. Notice the differences with our first attempt: - -```python -# First let's have some constants -ELEVATOR = get(id=3) -FLOORS = { - "1": get(id=2), - "2": get(id=6), - "3": get(id=7), -} -TO_EXIT = get(id=4) -BACK_EXIT = get(id=5) - -# Now we check that the elevator isn't already at this floor -floor = FLOORS.get(message) -if floor is None: - character.msg("Which floor do you want?") -elif BACK_EXIT.location is None: - character.msg("The elevator is between floors.") -elif TO_EXIT.location is floor: - character.msg("The elevator already is at this floor.") -else: - # 'floor' contains the new room where the elevator should be - room.msg_contents("The doors of the elevator close with a clank.") - TO_EXIT.location = None - BACK_EXIT.location = None - call_event(room, "chain_1", 15) -``` - -What changed? - -1. We added a little test to make sure the elevator wasn't already moving. If it is, the -`BACK_EXIT.location` (the "south" exit leading out of the elevator) should be `None`. We'll remove -the exit while the elevator is moving. -2. When the doors close, we set both exits' `location` to `None`. Which "removes" them from their -room but doesn't destroy them. The exits still exist but they don't connect anything. If you say -"2" in the elevator and look around while the elevator is moving, you won't see any exits. -3. Instead of opening the doors immediately, we call `call_event`. We give it the object containing -the event to be called (here, our elevator), the name of the event to be called (here, "chain_1") -and the number of seconds from now when the event should be called (here, `15`). -4. The `chain_1` callback we have created contains the code to "re-open" the elevator doors. That -is, besides displaying a message, it reset the exits' `location` and `destination`. - -If you try to say "3" in the elevator, you should see the doors closing. Look around you and you -won't see any exit. Then, 15 seconds later, the doors should open, and you can leave the elevator -to go to the third floor. While the elevator is moving, the exit leading to it will be -inaccessible. - -> Note: we don't define the variables again in our chained event, we just call them. When we -execute `call_event`, a copy of our current variables is placed in the database. These variables -will be restored and accessible again when the chained event is called. - -You can use the `call/tasks` command to see the tasks waiting to be executed. For instance, say "2" -in the room, notice the doors closing, and then type the `call/tasks` command. You will see a task -in the elevator, waiting to call the `chain_1` event. - -## Changing exit messages - -Here's another nice little feature of events: you can modify the message of a single exit without -altering the others. In this case, when someone goes north into our elevator, we'd like to see -something like: "someone walks into the elevator." Something similar for the back exit would be -great too. - -Inside of the elevator, you can look at the available events on the exit leading outside (south). - - call south - -You should see two interesting rows in this table: - -``` -| msg_arrive | 0 (0) | Customize the message when a character | -| | | arrives through this exit. | -| msg_leave | 0 (0) | Customize the message when a character leaves | -| | | through this exit. | -``` - -So we can change the message others see when a character leaves, by editing the "msg_leave" event. -Let's do that: - - call/add south = msg_leave - -Take the time to read the help. It gives you all the information you should need. We'll need to -change the "message" variable, and use custom mapping (between braces) to alter the message. We're -given an example, let's use it. In the code editor, you can paste the following line: - -```python -message = "{character} walks out of the elevator." -``` - -Again, save and quit the editor by entering `:wq`. You can create a new character to see it leave. - - charcreate A beggar - tel #8 = here - -(Obviously, adapt the ID if necessary.) - - py self.search("beggar").move_to(self.search("south")) - -This is a crude way to force our beggar out of the elevator, but it allows us to test. You should -see: - - A beggar(#8) walks out of the elevator. - -Great! Let's do the same thing for the exit leading inside of the elevator. Follow the beggar, -then edit "msg_leave" of "north": - - call/add north = msg_leave - -```python -message = "{character} walks into the elevator." -``` - -Again, you can force our beggar to move and see the message we have just set. This modification -applies to these two exits, obviously: the custom message won't be used for other exits. Since we -use the same exits for every floor, this will be available no matter at what floor the elevator is, -which is pretty neat! - -## Tutorial F.A.Q. - -- **Q:** what happens if the game reloads or shuts down while a task is waiting to happen? -- **A:** if your game reloads while a task is in pause (like our elevator between floors), when the -game is accessible again, the task will be called (if necessary, with a new time difference to take -into account the reload). If the server shuts down, obviously, the task will not be called, but -will be stored and executed when the server is up again. -- **Q:** can I use all kinds of variables in my callback? Whether chained or not? -- **A:** you can use every variable type you like in your original callback. However, if you -execute `call_event`, since your variables are stored in the database, they will need to respect the -constraints on persistent attributes. A callback will not be stored in this way, for instance. -This variable will not be available in your chained event. -- **Q:** when you say I can call my chained events something else than "chain_1", "chain_2" and -such, what is the naming convention? -- **A:** chained events have names beginning by "chain_". This is useful for you and for the -system. But after the underscore, you can give a more useful name, like "chain_open_doors" in our -case. -- **Q:** do I have to pause several seconds to call a chained event? -- **A:** no, you can call it right away. Just leave the third parameter of `call_event` out (it -will default to 0, meaning the chained event will be called right away). This will not create a -task. -- **Q:** can I have chained events calling themselves? -- **A:** you can. There's no limitation. Just be careful, a callback that calls itself, -particularly without delay, might be a good recipe for an infinite loop. However, in some cases, it -is useful to have chained events calling themselves, to do the same repeated action every X seconds -for instance. -- **Q:** what if I need several elevators, do I need to copy/paste these callbacks each time? -- **A:** not advisable. There are definitely better ways to handle this situation. One of them is -to consider adding the code in the source itself. Another possibility is to call chained events -with the expected behavior, which makes porting code very easy. This side of chained events will be -shown in the next tutorial. - -- Previous tutorial: [Adding dialogues in events](./Dialogues-in-events.md) diff --git a/docs/0.9.5/_sources/API-refactoring.md.txt b/docs/0.9.5/_sources/API-refactoring.md.txt deleted file mode 100644 index 689b5893f5..0000000000 --- a/docs/0.9.5/_sources/API-refactoring.md.txt +++ /dev/null @@ -1,46 +0,0 @@ -# API refactoring - -Building up to Evennia 1.0 and beyond, it's time to comb through the Evennia API for old cruft. This -whitepage is for anyone interested to contribute with their views on what part of the API needs -refactoring, cleanup or clarification (or extension!) - -Note that this is not a forum. To keep things clean, each opinion text should ideally present a -clear argument or lay out a suggestion. Asking for clarification and any side-discussions should be -held in chat or forum. - ---- - -### Griatch (Aug 13, 2019) - -This is how to enter an opinion. Use any markdown needed but stay within your section. Also remember -to copy your text to the clipboard before saving since if someone else edited the wiki in the -meantime you'll have to start over. - -### Griatch (Sept 2, 2019) - -I don't agree with removing explicit keywords as suggested by [Johnny on Aug 29 below](API- -refactoring#reduce-usage-of-optionalpositional-arguments-aug-29-2019). Overriding such a method can -still be done by `get(self, **kwargs)` if so desired, making the kwargs explicit helps IMO -readability of the API. If just giving a generic `**kwargs`, one must read the docstring or even the -code to see which keywords are valid. - -On the other hand, I think it makes sense to as a standard offer an extra `**kwargs` at the end of -arg-lists for common methods that are expected to be over-ridden. This make the API more flexible by -hinting to the dev that they could expand their own over-ridden implementation with their own -keyword arguments if so desired. - ---- - -### Johnny - -#### Reduce usage of optional/positional arguments (Aug 29, 2019) -``` -# AttributeHandler -def get(self, key=None, default=None, category=None, return_obj=False, - strattr=False, raise_exception=False, accessing_obj=None, - default_access=True, return_list=False): -``` -Many classes have methods requiring lengthy positional argument lists, which are tedious and error- -prone to extend and override especially in cases where not all arguments are even required. It would -be useful if arguments were reserved for required inputs and anything else relegated to kwargs for -easier passthrough on extension. diff --git a/docs/0.9.5/_sources/Accounts.md.txt b/docs/0.9.5/_sources/Accounts.md.txt deleted file mode 100644 index 6d61136583..0000000000 --- a/docs/0.9.5/_sources/Accounts.md.txt +++ /dev/null @@ -1,108 +0,0 @@ -# Accounts - - -All *users* (real people) that starts a game [Session](./Sessions.md) on Evennia are doing so through an -object called *Account*. The Account object has no in-game representation, it represents a unique -game account. In order to actually get on the game the Account must *puppet* an [Object](./Objects.md) -(normally a [Character](./Objects.md#characters)). - -Exactly how many Sessions can interact with an Account and its Puppets at once is determined by -Evennia's [MULTISESSION_MODE](./Sessions.md#multisession-mode) setting. - -Apart from storing login information and other account-specific data, the Account object is what is -chatting on [Channels](./Communications.md). It is also a good place to store [Permissions](./Locks.md) to be -consistent between different in-game characters as well as configuration options. The Account -object also has its own [CmdSet](./Command-Sets.md), the `AccountCmdSet`. - -Logged into default evennia, you can use the `ooc` command to leave your current -[character](./Objects.md) and go into OOC mode. You are quite limited in this mode, basically it works -like a simple chat program. It acts as a staging area for switching between Characters (if your -game supports that) or as a safety mode if your Character gets deleted. Use `ic` to attempt to -(re)puppet a Character. - -Note that the Account object can have, and often does have, a different set of -[Permissions](./Locks.md#permissions) from the Character they control. Normally you should put your -permissions on the Account level - this will overrule permissions set on the Character level. For -the permissions of the Character to come into play the default `quell` command can be used. This -allows for exploring the game using a different permission set (but you can't escalate your -permissions this way - for hierarchical permissions like `Builder`, `Admin` etc, the *lower* of the -permissions on the Character/Account will always be used). - -## How to create your own Account types - -You will usually not want more than one Account typeclass for all new accounts (but you could in -principle create a system that changes an account's typeclass dynamically). - -An Evennia Account is, per definition, a Python class that includes `evennia.DefaultAccount` among -its parents. In `mygame/typeclasses/accounts.py` there is an empty class ready for you to modify. -Evennia defaults to using this (it inherits directly from `DefaultAccount`). - -Here's an example of modifying the default Account class in code: - -```python - # in mygame/typeclasses/accounts.py - - from evennia import DefaultAccount - - class Account(DefaultAccount): # [...] - - at_account_creation(self): "this is called only once, when account is first created" - self.db.real_name = None # this is set later self.db.real_address = None # -" - self.db.config_1 = True # default config self.db.config_2 = False # " - self.db.config_3 = 1 # " - - # ... whatever else our game needs to know ``` Reload the server with `reload`. - -``` - -... However, if you use `examine *self` (the asterisk makes you examine your Account object rather -than your Character), you won't see your new Attributes yet. This is because `at_account_creation` -is only called the very *first* time the Account is called and your Account object already exists -(any new Accounts that connect will see them though). To update yourself you need to make sure to -re-fire the hook on all the Accounts you have already created. Here is an example of how to do this -using `py`: - - -``` py [account.at_account_creation() for account in evennia.managers.accounts.all()] ``` - -You should now see the Attributes on yourself. - - -> If you wanted Evennia to default to a completely *different* Account class located elsewhere, you -> must point Evennia to it. Add `BASE_ACCOUNT_TYPECLASS` to your settings file, and give the python -> path to your custom class as its value. By default this points to `typeclasses.accounts.Account`, -> the empty template we used above. - - -## Properties on Accounts - -Beyond those properties assigned to all typeclassed objects (see [Typeclasses](./Typeclasses.md)), the -Account also has the following custom properties: - -- `user` - a unique link to a `User` Django object, representing the logged-in user. -- `obj` - an alias for `character`. -- `name` - an alias for `user.username` -- `sessions` - an instance of - [ObjectSessionHandler](github:evennia.objects.objects#objectsessionhandler) - managing all connected Sessions (physical connections) this object listens to (Note: In older - versions of Evennia, this was a list). The so-called `session-id` (used in many places) is found -as - a property `sessid` on each Session instance. -- `is_superuser` (bool: True/False) - if this account is a superuser. - -Special handlers: -- `cmdset` - This holds all the current [Commands](./Commands.md) of this Account. By default these are - the commands found in the cmdset defined by `settings.CMDSET_ACCOUNT`. -- `nicks` - This stores and handles [Nicks](./Nicks.md), in the same way as nicks it works on Objects. - For Accounts, nicks are primarily used to store custom aliases for -[Channels](./Communications.md#channels). - -Selection of special methods (see `evennia.DefaultAccount` for details): -- `get_puppet` - get a currently puppeted object connected to the Account and a given session id, if - any. -- `puppet_object` - connect a session to a puppetable Object. -- `unpuppet_object` - disconnect a session from a puppetable Object. -- `msg` - send text to the Account -- `execute_cmd` - runs a command as if this Account did it. -- `search` - search for Accounts. diff --git a/docs/0.9.5/_sources/Add-a-simple-new-web-page.md.txt b/docs/0.9.5/_sources/Add-a-simple-new-web-page.md.txt deleted file mode 100644 index c146a54f10..0000000000 --- a/docs/0.9.5/_sources/Add-a-simple-new-web-page.md.txt +++ /dev/null @@ -1,100 +0,0 @@ -# Add a simple new web page - - -Evennia leverages [Django](https://docs.djangoproject.com) which is a web development framework. -Huge professional websites are made in Django and there is extensive documentation (and books) on it -. You are encouraged to at least look at the Django basic tutorials. Here we will just give a brief -introduction for how things hang together, to get you started. - -We assume you have installed and set up Evennia to run. A webserver and website comes out of the -box. You can get to that by entering `http://localhost:4001` in your web browser - you should see a -welcome page with some game statistics and a link to the web client. Let us add a new page that you -can get to by going to `http://localhost:4001/story`. - -### Create the view - -A django "view" is a normal Python function that django calls to render the HTML page you will see -in the web browser. Here we will just have it spit back the raw html, but Django can do all sorts of -cool stuff with the page in the view, like adding dynamic content or change it on the fly. Open -`mygame/web` folder and add a new module there named `story.py` (you could also put it in its own -folder if you wanted to be neat. Don't forget to add an empty `__init__.py` file if you do, to tell -Python you can import from the new folder). Here's how it looks: - -```python -# in mygame/web/story.py - -from django.shortcuts import render - -def storypage(request): - return render(request, "story.html") -``` - -This view takes advantage of a shortcut provided to use by Django, _render_. This shortcut gives the -template some information from the request, for instance, the game name, and then renders it. - -### The HTML page - -We need to find a place where Evennia (and Django) looks for html files (called *templates* in -Django parlance). You can specify such places in your settings (see the `TEMPLATES` variable in -`default_settings.py` for more info), but here we'll use an existing one. Go to -`mygame/template/overrides/website/` and create a page `story.html` there. - -This is not a HTML tutorial, so we'll go simple: - -```html -{% extends "base.html" %} -{% block content %} -
-
-

A story about a tree

-

- This is a story about a tree, a classic tale ... -

-
-
-{% endblock %} -``` - -Since we've used the _render_ shortcut, Django will allow us to extend our base styles easily. - -If you'd rather not take advantage of Evennia's base styles, you can do something like this instead: - -```html - - -

A story about a tree

-

- This is a story about a tree, a classic tale ... - - -``` - - -### The URL - -When you enter the address `http://localhost:4001/story` in your web browser, Django will parse that -field to figure out which page you want to go to. You tell it which patterns are relevant in the -file -[mygame/web/urls.py](https://github.com/evennia/evennia/blob/master/evennia/game_template/web/urls.py). -Open it now. - -Django looks for the variable `urlpatterns` in this file. You want to add your new pattern to the -`custom_patterns` list we have prepared - that is then merged with the default `urlpatterns`. Here's -how it could look: - -```python -from web import story - -# ... - -custom_patterns = [ - url(r'story', story.storypage, name='Story'), -] -``` - -That is, we import our story view module from where we created it earlier and then create an `url` -instance. The first argument to `url` is the pattern of the url we want to find (`"story"`) (this is -a regular expression if you are familiar with those) and then our view function we want to direct -to. - -That should be it. Reload Evennia and you should be able to browse to your new story page! diff --git a/docs/0.9.5/_sources/Add-a-wiki-on-your-website.md.txt b/docs/0.9.5/_sources/Add-a-wiki-on-your-website.md.txt deleted file mode 100644 index a8f476d28e..0000000000 --- a/docs/0.9.5/_sources/Add-a-wiki-on-your-website.md.txt +++ /dev/null @@ -1,232 +0,0 @@ -# Add a wiki on your website - - -**Before doing this tutorial you will probably want to read the intro in -[Basic Web tutorial](./Web-Tutorial.md).** Reading the three first parts of the -[Django tutorial](https://docs.djangoproject.com/en/1.9/intro/tutorial01/) might help as well. - -This tutorial will provide a step-by-step process to installing a wiki on your website. -Fortunately, you don't have to create the features manually, since it has been done by others, and -we can integrate their work quite easily with Django. I have decided to focus on -the [Django-wiki](http://django-wiki.readthedocs.io/). - -> Note: this article has been updated for Evennia 0.9. If you're not yet using this version, be -careful, as the django wiki doesn't support Python 2 anymore. (Remove this note when enough time -has passed.) - -The [Django-wiki](http://django-wiki.readthedocs.io/) offers a lot of features associated with -wikis, is -actively maintained (at this time, anyway), and isn't too difficult to install in Evennia. You can -see a [demonstration of Django-wiki here](https://demo.django.wiki). - -## Basic installation - -You should begin by shutting down the Evennia server if it is running. We will run migrations and -alter the virtual environment just a bit. Open a terminal and activate your Python environment, the -one you use to run the `evennia` command. - -* On Linux: - ``` - source evenv/bin/activate - ``` -* Or Windows: - ``` - evenv\bin\activate - ``` - -### Installing with pip - -Install the wiki using pip: - - pip install wiki - -> Note: this will install the last version of Django wiki. Version >0.4 doesn't support Python 2, so -install wiki 0.3 if you haven't updated to Python 3 yet. - -It might take some time, the Django-wiki having some dependencies. - -### Adding the wiki in the settings - -You will need to add a few settings to have the wiki app on your website. Open your -`server/conf/settings.py` file and add the following at the bottom (but before importing -`secret_settings`). Here's what you'll find in my own setting file (add the whole Django-wiki -section): - -```python -r""" -Evennia settings file. - -... - -""" - -# Use the defaults from Evennia unless explicitly overridden -from evennia.settings_default import * - -###################################################################### -# Evennia base server config -###################################################################### - -# This is the name of your game. Make it catchy! -SERVERNAME = "demowiki" - -###################################################################### -# Django-wiki settings -###################################################################### -INSTALLED_APPS += ( - 'django.contrib.humanize.apps.HumanizeConfig', - 'django_nyt.apps.DjangoNytConfig', - 'mptt', - 'sorl.thumbnail', - 'wiki.apps.WikiConfig', - 'wiki.plugins.attachments.apps.AttachmentsConfig', - 'wiki.plugins.notifications.apps.NotificationsConfig', - 'wiki.plugins.images.apps.ImagesConfig', - 'wiki.plugins.macros.apps.MacrosConfig', -) - -# Disable wiki handling of login/signup -WIKI_ACCOUNT_HANDLING = False -WIKI_ACCOUNT_SIGNUP_ALLOWED = False - -###################################################################### -# Settings given in secret_settings.py override those in this file. -###################################################################### -try: - from server.conf.secret_settings import * -except ImportError: - print("secret_settings.py file not found or failed to import.") -``` - -### Adding the new URLs - -Next we need to add two URLs in our `web/urls.py` file. Open it and compare the following output: -you will need to add two URLs in `custom_patterns` and add one import line: - -```python -from django.conf.urls import url, include -from django.urls import path # NEW! - -# default evenni a patterns -from evennia.web.urls import urlpatterns - -# eventual custom patterns -custom_patterns = [ - # url(r'/desired/url/', view, name='example'), - url('notifications/', include('django_nyt.urls')), # NEW! - url('wiki/', include('wiki.urls')), # NEW! -] - -# this is required by Django. -urlpatterns = custom_patterns + urlpatterns -``` - -You will probably need to copy line 2, 10, and 11. Be sure to place them correctly, as shown in -the example above. - -### Running migrations - -It's time to run the new migrations. The wiki app adds a few tables in our database. We'll need to -run: - - evennia migrate - -And that's it, you can start the server. If you go to http://localhost:4001/wiki , you should see -the wiki. Use your account's username and password to connect to it. That's how simple it is. - -## Customizing privileges - -A wiki can be a great collaborative tool, but who can see it? Who can modify it? Django-wiki comes -with a privilege system centered around four values per wiki page. The owner of an article can -always read and write in it (which is somewhat logical). The group of the article defines who can -read and who can write, if the user seeing the page belongs to this group. The topic of groups in -wiki pages will not be discussed here. A last setting determines which other user (that is, these -who aren't in the groups, and aren't the article's owner) can read and write. Each article has -these four settings (group read, group write, other read, other write). Depending on your purpose, -it might not be a good default choice, particularly if you have to remind every builder to keep the -pages private. Fortunately, Django-wiki gives us additional settings to customize who can read, and -who can write, a specific article. - -These settings must be placed, as usual, in your `server/conf/settings.py` file. They take a -function as argument, said function (or callback) will be called with the article and the user. -Remember, a Django user, for us, is an account. So we could check lockstrings on them if needed. -Here is a default setting to restrict the wiki: only builders can write in it, but anyone (including -non-logged in users) can read it. The superuser has some additional privileges. - -```python -# In server/conf/settings.py -# ... - -def is_superuser(article, user): - """Return True if user is a superuser, False otherwise.""" - return not user.is_anonymous() and user.is_superuser - -def is_builder(article, user): - """Return True if user is a builder, False otherwise.""" - return not user.is_anonymous() and user.locks.check_lockstring(user, "perm(Builders)") - -def is_anyone(article, user): - """Return True even if the user is anonymous.""" - return True - -# Who can create new groups and users from the wiki? -WIKI_CAN_ADMIN = is_superuser -# Who can change owner and group membership? -WIKI_CAN_ASSIGN = is_superuser -# Who can change group membership? -WIKI_CAN_ASSIGN_OWNER = is_superuser -# Who can change read/write access to groups or others? -WIKI_CAN_CHANGE_PERMISSIONS = is_superuser -# Who can soft-delete an article? -WIKI_CAN_DELETE = is_builder -# Who can lock an article and permanently delete it? -WIKI_CAN_MODERATE = is_superuser -# Who can edit articles? -WIKI_CAN_WRITE = is_builder -# Who can read articles? -WIKI_CAN_READ = is_anyone -``` - -Here, we have created three functions: one to return `True` if the user is the superuser, one to -return `True` if the user is a builder, one to return `True` no matter what (this includes if the -user is anonymous, E.G. if it's not logged-in). We then change settings to allow either the -superuser or -each builder to moderate, read, write, delete, and more. You can, of course, add more functions, -adapting them to your need. This is just a demonstration. - -Providing the `WIKI_CAN*...` settings will bypass the original permission system. The superuser -could change permissions of an article, but still, only builders would be able to write it. If you -need something more custom, you will have to expand on the functions you use. - -### Managing wiki pages from Evennia - -Unfortunately, Django wiki doesn't provide a clear and clean entry point to read and write articles -from Evennia and it doesn't seem to be a very high priority. If you really need to keep Django wiki -and to create and manage wiki pages from your code, you can do so, but this article won't elaborate, -as this is somewhat more technical. - -However, it is a good opportunity to present a small project that has been created more recently: -[evennia-wiki](https://github.com/vincent-lg/evennia-wiki) has been created to provide a simple -wiki, more tailored to Evennia and easier to connect. It doesn't, as yet, provide as many options -as does Django wiki, but it's perfectly usable: - -- Pages have an inherent and much-easier to understand hierarchy based on URLs. -- Article permissions are connected to Evennia groups and are much easier to accommodate specific -requirements. -- Articles can easily be created, read or updated from the Evennia code itself. -- Markdown is fully-supported with a default integration to Bootstrap to look good on an Evennia -website. Tables and table of contents are supported as well as wiki links. -- The process to override wiki templates makes full use of the `template_overrides` directory. - -However evennia-wiki doesn't yet support: - -- Images in markdown and the uploading schema. If images are important to you, please consider -contributing to this new project. -- Modifying permissions on a per page/setting basis. -- Moving pages to new locations. -- Viewing page history. - -Considering the list of features in Django wiki, obviously other things could be added to the list. -However, these features may be the most important and useful. Additional ones might not be that -necessary. If you're interested in supporting this little project, you are more than welcome to -[contribute to it](https://github.com/vincent-lg/evennia-wiki). Thanks! \ No newline at end of file diff --git a/docs/0.9.5/_sources/Adding-Command-Tutorial.md.txt b/docs/0.9.5/_sources/Adding-Command-Tutorial.md.txt deleted file mode 100644 index 569c12252d..0000000000 --- a/docs/0.9.5/_sources/Adding-Command-Tutorial.md.txt +++ /dev/null @@ -1,171 +0,0 @@ -# Adding Command Tutorial - -This is a quick first-time tutorial expanding on the [Commands](./Commands.md) documentation. - -Let's assume you have just downloaded Evennia, installed it and created your game folder (let's call -it just `mygame` here). Now you want to try to add a new command. This is the fastest way to do it. - -## Step 1: Creating a custom command - -1. Open `mygame/commands/command.py` in a text editor. This is just one place commands could be -placed but you get it setup from the onset as an easy place to start. It also already contains some -example code. -1. Create a new class in `command.py` inheriting from `default_cmds.MuxCommand`. Let's call it - `CmdEcho` in this example. -1. Set the class variable `key` to a good command name, like `echo`. -1. Give your class a useful _docstring_. A docstring is the string at the very top of a class or -function/method. The docstring at the top of the command class is read by Evennia to become the help -entry for the Command (see - [Command Auto-help](./Help-System.md#command-auto-help-system)). -1. Define a class method `func(self)` that echoes your input back to you. - -Below is an example how this all could look for the echo command: - -```python - # file mygame/commands/command.py - #[...] - from evennia import default_cmds - class CmdEcho(default_cmds.MuxCommand): - """ - Simple command example - - Usage: - echo [text] - - This command simply echoes text back to the caller. - """ - - key = "echo" - - def func(self): - "This actually does things" - if not self.args: - self.caller.msg("You didn't enter anything!") - else: - self.caller.msg("You gave the string: '%s'" % self.args) -``` - -## Step 2: Adding the Command to a default Cmdset - -The command is not available to use until it is part of a [Command Set](./Command-Sets.md). In this -example we will go the easiest route and add it to the default Character commandset that already -exists. - -1. Edit `mygame/commands/default_cmdsets.py` -1. Import your new command with `from commands.command import CmdEcho`. -1. Add a line `self.add(CmdEcho())` to `CharacterCmdSet`, in the `at_cmdset_creation` method (the - template tells you where). - -This is approximately how it should look at this point: - -```python - # file mygame/commands/default_cmdsets.py - #[...] - from commands.command import CmdEcho - #[...] - class CharacterCmdSet(default_cmds.CharacterCmdSet): - - key = "DefaultCharacter" - - def at_cmdset_creation(self): - - # this first adds all default commands - super().at_cmdset_creation() - - # all commands added after this point will extend or - # overwrite the default commands. - self.add(CmdEcho()) -``` - -Next, run the `@reload` command. You should now be able to use your new `echo` command from inside -the game. Use `help echo` to see the documentation for the command. - -If you have trouble, make sure to check the log for error messages (probably due to syntax errors in -your command definition). - -> Note: Typing `echotest` will also work. It will be handled as the command `echo` directly followed -by -its argument `test` (which will end up in `self.args). To change this behavior, you can add the -`arg_regex` property alongside `key`, `help_category` etc. [See the arg_regex -documentation](./Commands.md#on-arg_regex) for more info. - -If you want to overload existing default commands (such as `look` or `get`), just add your new -command with the same key as the old one - it will then replace it. Just remember that you must use -`@reload` to see any changes. - -See [Commands](./Commands.md) for many more details and possibilities when defining Commands and using -Cmdsets in various ways. - - -## Adding the command to specific object types - -Adding your Command to the `CharacterCmdSet` is just one easy exapmple. The cmdset system is very -generic. You can create your own cmdsets (let's say in a module `mycmdsets.py`) and add them to -objects as you please (how to control their merging is described in detail in the [Command Set -documentation](./Command-Sets.md)). - -```python - # file mygame/commands/mycmdsets.py - #[...] - from commands.command import CmdEcho - from evennia import CmdSet - #[...] - class MyCmdSet(CmdSet): - - key = "MyCmdSet" - - def at_cmdset_creation(self): - self.add(CmdEcho()) -``` -Now you just need to add this to an object. To test things (as superuser) you can do - - @py self.cmdset.add("mycmdsets.MyCmdSet") - -This will add this cmdset (along with its echo command) to yourself so you can test it. Note that -you cannot add a single Command to an object on its own, it must be part of a CommandSet in order to -do so. - -The Command you added is not there permanently at this point. If you do a `@reload` the merger will -be gone. You *could* add the `permanent=True` keyword to the `cmdset.add` call. This will however -only make the new merged cmdset permanent on that *single* object. Often you want *all* objects of -this particular class to have this cmdset. - -To make sure all new created objects get your new merged set, put the `cmdset.add` call in your -custom [Typeclasses](./Typeclasses.md)' `at_object_creation` method: - -```python - # e.g. in mygame/typeclasses/objects.py - - from evennia import DefaultObject - class MyObject(DefaultObject): - - def at_object_creation(self): - "called when the object is first created" - self.cmdset.add("mycmdset.MyCmdSet", permanent=True) -``` - -All new objects of this typeclass will now start with this cmdset and it will survive a `@reload`. - -*Note:* An important caveat with this is that `at_object_creation` is only called *once*, when the -object is first created. This means that if you already have existing objects in your databases -using that typeclass, they will not have been initiated the same way. There are many ways to update -them; since it's a one-time update you can usually just simply loop through them. As superuser, try -the following: - - @py from typeclasses.objects import MyObject; [o.cmdset.add("mycmdset.MyCmdSet") for o in -MyObject.objects.all()] - -This goes through all objects in your database having the right typeclass, adding the new cmdset to -each. The good news is that you only have to do this if you want to post-add *cmdsets*. If you just -want to add a new *command*, you can simply add that command to the cmdset's `at_cmdset_creation` -and `@reload` to make the Command immediately available. - -## Change where Evennia looks for command sets - -Evennia uses settings variables to know where to look for its default command sets. These are -normally not changed unless you want to re-organize your game folder in some way. For example, the -default character cmdset defaults to being defined as - - CMDSET_CHARACTER="commands.default_cmdset.CharacterCmdSet" - -See `evennia/settings_default.py` for the other settings. diff --git a/docs/0.9.5/_sources/Adding-Object-Typeclass-Tutorial.md.txt b/docs/0.9.5/_sources/Adding-Object-Typeclass-Tutorial.md.txt deleted file mode 100644 index 4e4e0b66bb..0000000000 --- a/docs/0.9.5/_sources/Adding-Object-Typeclass-Tutorial.md.txt +++ /dev/null @@ -1,109 +0,0 @@ -# Adding Object Typeclass Tutorial - -Evennia comes with a few very basic classes of in-game entities: - - DefaultObject - | - DefaultCharacter - DefaultRoom - DefaultExit - DefaultChannel - -When you create a new Evennia game (with for example `evennia --init mygame`) Evennia will -automatically create empty child classes `Object`, `Character`, `Room` and `Exit` respectively. They -are found `mygame/typeclasses/objects.py`, `mygame/typeclasses/rooms.py` etc. - -> Technically these are all [Typeclassed](./Typeclasses.md), which can be ignored for now. In -> `mygame/typeclasses` are also base typeclasses for out-of-character things, notably -> [Channels](./Communications.md), [Accounts](./Accounts.md) and [Scripts](./Scripts.md). We don't cover those in -> this tutorial. - -For your own game you will most likely want to expand on these very simple beginnings. It's normal -to want your Characters to have various attributes, for example. Maybe Rooms should hold extra -information or even *all* Objects in your game should have properties not included in basic Evennia. - -## Change Default Rooms, Exits, Character Typeclass - -This is the simplest case. - -The default build commands of a new Evennia game is set up to use the `Room`, `Exit` and `Character` -classes found in the same-named modules under `mygame/typeclasses/`. By default these are empty and -just implements the default parents from the Evennia library (`DefaultRoom`etc). Just add the -changes you want to these classes and run `@reload` to add your new functionality. - -## Create a new type of object - -Say you want to create a new "Heavy" object-type that characters should not have the ability to pick -up. - -1. Edit `mygame/typeclasses/objects.py` (you could also create a new module there, named something - like `heavy.py`, that's up to how you want to organize things). -1. Create a new class inheriting at any distance from `DefaultObject`. It could look something like - this: -```python - # end of file mygame/typeclasses/objects.py - from evennia import DefaultObject - - class Heavy(DefaultObject): - "Heavy object" - def at_object_creation(self): - "Called whenever a new object is created" - # lock the object down by default - self.locks.add("get:false()") - # the default "get" command looks for this Attribute in order - # to return a customized error message (we just happen to know - # this, you'd have to look at the code of the 'get' command to - # find out). - self.db.get_err_msg = "This is too heavy to pick up." -``` -1. Once you are done, log into the game with a build-capable account and do `@create/drop - rock:objects.Heavy` to drop a new heavy "rock" object in your location. Next try to pick it up -(`@quell` yourself first if you are a superuser). If you get errors, look at your log files where -you will find the traceback. The most common error is that you have some sort of syntax error in -your class. - -Note that the [Locks](./Locks.md) and [Attribute](./Attributes.md) which are set in the typeclass could just -as well have been set using commands in-game, so this is a *very* simple example. - -## Storing data on initialization - -The `at_object_creation` is only called once, when the object is first created. This makes it ideal -for database-bound things like [Attributes](./Attributes.md). But sometimes you want to create temporary -properties (things that are not to be stored in the database but still always exist every time the -object is created). Such properties can be initialized in the `at_init` method on the object. -`at_init` is called every time the object is loaded into memory. - -> Note: It's usually pointless and wasteful to assign database data in `at_init`, since this will -> hit the database with the same value over and over. Put those in `at_object_creation` instead. - -You are wise to use `ndb` (non-database Attributes) to store these non-persistent properties, since -ndb-properties are protected against being cached out in various ways and also allows you to list -them using various in-game tools: - -```python -def at_init(self): - self.ndb.counter = 0 - self.ndb.mylist = [] -``` - -> Note: As mentioned in the [Typeclasses](./Typeclasses.md) documentation, `at_init` replaces the use of -> the standard `__init__` method of typeclasses due to how the latter may be called in situations -> other than you'd expect. So use `at_init` where you would normally use `__init__`. - - -## Updating existing objects - -If you already have some `Heavy` objects created and you add a new `Attribute` in -`at_object_creation`, you will find that those existing objects will not have this Attribute. This -is not so strange, since `at_object_creation` is only called once, it will not be called again just -because you update it. You need to update existing objects manually. - -If the number of objects is limited, you can use `@typeclass/force/reload objectname` to force a -re-load of the `at_object_creation` method (only) on the object. This case is common enough that -there is an alias `@update objectname` you can use to get the same effect. If there are multiple -objects you can use `@py` to loop over the objects you need: - -``` -@py from typeclasses.objects import Heavy; [obj.at_object_creation() for obj in Heavy.objects.all()] - -``` diff --git a/docs/0.9.5/_sources/Administrative-Docs.md.txt b/docs/0.9.5/_sources/Administrative-Docs.md.txt deleted file mode 100644 index 154fbd83ec..0000000000 --- a/docs/0.9.5/_sources/Administrative-Docs.md.txt +++ /dev/null @@ -1,76 +0,0 @@ -# Administrative Docs - -The following pages are aimed at game administrators -- the higher-ups that possess shell access and -are responsible for managing the game. - -### Installation and Early Life - -- [Choosing (and installing) an SQL Server](./Choosing-An-SQL-Server.md) -- [Getting Started - Installing Evennia](./Getting-Started.md) -- [Running Evennia in Docker Containers](./Running-Evennia-in-Docker.md) -- [Starting, stopping, reloading and resetting Evennia](./Start-Stop-Reload.md) -- [Keeping your game up to date](./Updating-Your-Game.md) - - [Resetting your database](./Updating-Your-Game.md#resetting-your-database) -- [Making your game available online](./Online-Setup.md) - - [Hosting options](./Online-Setup.md#hosting-options) - - [Securing your server with SSL/Let's Encrypt](./Online-Setup.md#ssl) -- [Listing your game](./Evennia-Game-Index.md) at the online [Evennia game -index](http://games.evennia.com) - -### Customizing the server - -- [Changing the Settings](./Server-Conf.md#settings-file) - - [Available Master -Settings](https://github.com/evennia/evennia/blob/master/evennia/settings_default.py) -- [Change Evennia's language](./Internationalization.md) (internationalization) -- [Apache webserver configuration](./Apache-Config.md) (optional) -- [Changing text encodings used by the server](./Text-Encodings.md) -- [The Connection Screen](./Connection-Screen.md) -- [Guest Logins](./Guest-Logins.md) -- [How to connect Evennia to IRC channels](./IRC.md) -- [How to connect Evennia to RSS feeds](./RSS.md) -- [How to connect Evennia to Grapevine](./Grapevine.md) -- [How to connect Evennia to Twitter](./How-to-connect-Evennia-to-Twitter.md) - -### Administrating the running game - -- [Supported clients](./Client-Support-Grid.md) (grid of known client issues) -- [Changing Permissions](./Building-Permissions.md) of users -- [Banning](./Banning.md) and deleting users - - [Summary of abuse-handling tools](./Banning.md#summary-of-abuse-handling-tools) in the default cmdset - -### Working with Evennia - -- [Setting up your work environment with version control](./Version-Control.md) -- [First steps coding with Evennia](./First-Steps-Coding.md) -- [Setting up a continuous integration build environment](./Continuous-Integration.md) - - -```{toctree} - :hidden: - - Choosing-An-SQL-Server - Getting-Started - Running-Evennia-in-Docker - Start-Stop-Reload - Updating-Your-Game - Online-Setup - Evennia-Game-Index - Server-Conf - Internationalization - Apache-Config - Text-Encodings - Connection-Screen - Guest-Logins - IRC - RSS - Grapevine - How-to-connect-Evennia-to-Twitter - Client-Support-Grid - Building-Permissions - Banning - Version-Control - First-Steps-Coding - Continuous-Integration - -``` \ No newline at end of file diff --git a/docs/0.9.5/_sources/Apache-Config.md.txt b/docs/0.9.5/_sources/Apache-Config.md.txt deleted file mode 100644 index 76a21ee24f..0000000000 --- a/docs/0.9.5/_sources/Apache-Config.md.txt +++ /dev/null @@ -1,171 +0,0 @@ -# Apache Config - - -**Warning**: This information is presented as a convenience, using another webserver than Evennia's -own is not directly supported and you are on your own if you want to do so. Evennia's webserver -works out of the box without any extra configuration and also runs in-process making sure to avoid -caching race conditions. The browser web client will most likely not work (at least not without -tweaking) on a third-party web server. - -One reason for wanting to use an external webserver like Apache would be to act as a *proxy* in -front of the Evennia webserver. Getting this working with TLS (encryption) requires some extra work -covered at the end of this page. - -Note that the Apache instructions below might be outdated. If something is not working right, or you -use Evennia with a different server, please let us know. Also, if there is a particular Linux distro -you would like covered, please let us know. - -## `mod_wsgi` Setup - -### Install `mod_wsgi` - -- *Fedora/RHEL* - Apache HTTP Server and `mod_wsgi` are available in the standard package -repositories for Fedora and RHEL: - ``` - $ dnf install httpd mod_wsgi - or - $ yum install httpd mod_wsgi - ``` -- *Ubuntu/Debian* - Apache HTTP Server and `mod_wsgi` are available in the standard package -repositories for Ubuntu and Debian: - ``` - $ apt-get update - $ apt-get install apache2 libapache2-mod-wsgi - ``` - -### Copy and modify the VHOST - -After `mod_wsgi` is installed, copy the `evennia/web/utils/evennia_wsgi_apache.conf` file to your -apache2 vhosts/sites folder. On Debian/Ubuntu, this is `/etc/apache2/sites-enabled/`. Make your -modifications **after** copying the file there. - -Read the comments and change the paths to point to the appropriate locations within your setup. - -### Restart/Reload Apache - -You'll then want to reload or restart apache2 after changing the configurations. - -- *Fedora/RHEL/Ubuntu* - ``` - $ systemctl restart httpd - ``` -- *Ubuntu/Debian* - ``` - $ systemctl restart apache2 - ``` - -### Enjoy - -With any luck, you'll be able to point your browser at your domain or subdomain that you set up in -your vhost and see the nifty default Evennia webpage. If not, read the hopefully informative error -message and work from there. Questions may be directed to our [Evennia Community -site](http://evennia.com). - -### A note on code reloading - -If your `mod_wsgi` is set up to run on daemon mode (as will be the case by default on Debian and -Ubuntu), you may tell `mod_wsgi` to reload by using the `touch` command on -`evennia/game/web/utils/apache_wsgi.conf`. When `mod_wsgi` sees that the file modification time has -changed, it will force a code reload. Any modifications to the code will not be propagated to the -live instance of your site until reloaded. - -If you are not running in daemon mode or want to force the issue, simply restart or reload apache2 -to apply your changes. - -### Further notes and hints: - -If you get strange (and usually uninformative) `Permission denied` errors from Apache, make sure -that your `evennia` directory is located in a place the webserver may actually access. For example, -some Linux distributions may default to very restrictive access permissions on a user's `/home` -directory. - -One user commented that they had to add the following to their Apache config to get things to work. -Not confirmed, but worth trying if there are trouble. - - /evennia/game/web"> - Options +ExecCGI - Allow from all - - -## `mod_proxy` and `mod_ssl` setup - -Below are steps on running Evennia using a front-end proxy (Apache HTTP), `mod_proxy_http`, -`mod_proxy_wstunnel`, and `mod_ssl`. `mod_proxy_http` and `mod_proxy_wstunnel` will simply be -referred to as -`mod_proxy` below. - -### Install `mod_ssl` - -- *Fedora/RHEL* - Apache HTTP Server and `mod_ssl` are available in the standard package -repositories for Fedora and RHEL: - ``` - $ dnf install httpd mod_ssl - or - $ yum install httpd mod_ssl - - ``` -- *Ubuntu/Debian* - Apache HTTP Server and `mod_sslj`kl are installed together in the `apache2` -package and available in the -standard package repositories for Ubuntu and Debian. `mod_ssl` needs to be enabled after -installation: - ``` - $ apt-get update - $ apt-get install apache2 - $ a2enmod ssl - - ``` - -### TLS proxy+websocket configuration - -Below is a sample configuration for Evennia with a TLS-enabled http and websocket proxy. - -#### Apache HTTP Server Configuration - -``` - - # Always redirect to https/443 - ServerName mud.example.com - Redirect / https://mud.example.com - - - - ServerName mud.example.com - - SSLEngine On - - # Location of certificate and key - SSLCertificateFile /etc/pki/tls/certs/mud.example.com.crt - SSLCertificateKeyFile /etc/pki/tls/private/mud.example.com.key - - # Use a tool https://www.ssllabs.com/ssltest/ to scan your set after setting up. - SSLProtocol TLSv1.2 - SSLCipherSuite HIGH:!eNULL:!NULL:!aNULL - - # Proxy all websocket traffic to port 4002 in Evennia - ProxyPass /ws ws://127.0.0.1:4002/ - ProxyPassReverse /ws ws://127.0.0.1:4002/ - - # Proxy all HTTP traffic to port 4001 in Evennia - ProxyPass / http://127.0.0.1:4001/ - ProxyPassReverse / http://127.0.0.1:4001/ - - # Configure separate logging for this Evennia proxy - ErrorLog logs/evennia_error.log - CustomLog logs/evennia_access.log combined - -``` - -#### Evennia secure websocket configuration - -There is a slight trick in setting up Evennia so websocket traffic is handled correctly by the -proxy. You must set the `WEBSOCKET_CLIENT_URL` setting in your `mymud/server/conf/settings.py` file: - -``` -WEBSOCKET_CLIENT_URL = "wss://external.example.com/ws" -``` - -The setting above is what the client's browser will actually use. Note the use of `wss://` is -because our client will be communicating over an encrypted connection ("wss" indicates websocket -over SSL/TLS). Also, especially note the additional path `/ws` at the end of the URL. This is how -Apache HTTP Server identifies that a particular request should be proxied to Evennia's websocket -port but this should be applicable also to other types of proxies (like nginx). diff --git a/docs/0.9.5/_sources/Arxcode-installing-help.md.txt b/docs/0.9.5/_sources/Arxcode-installing-help.md.txt deleted file mode 100644 index e7efdfae28..0000000000 --- a/docs/0.9.5/_sources/Arxcode-installing-help.md.txt +++ /dev/null @@ -1,272 +0,0 @@ -# Arxcode installing help - -## Introduction - -[Arx - After the Reckoning](http://play.arxmush.org/) is a big and very popular -[Evennia](http://www.evennia.com)-based game. Arx is heavily roleplaying-centric, relying on game -masters to drive the story. Technically it's maybe best described as "a MUSH, but with more coded -systems". In August of 2018, the game's developer, Tehom, generously released the [source code of -Arx on github](https://github.com/Arx-Game/arxcode). This is a treasure-trove for developers wanting -to pick ideas or even get a starting game to build on. These instructions are based on the Arx-code -released as of *Aug 12, 2018*. - -If you are not familiar with what Evennia is, you can read -[an introduction here](./Evennia-Introduction.md). - -It's not too hard to run Arx from the sources (of course you'll start with an empty database) but -since part of Arx has grown organically, it doesn't follow standard Evennia paradigms everywhere. -This page covers one take on installing and setting things up while making your new Arx-based game -better match with the vanilla Evennia install. - -## Installing Evennia - -Firstly, set aside a folder/directory on your drive for everything to follow. - -You need to start by installing [Evennia](http://www.evennia.com) by following most of the [Getting -Started -Instructions](./Getting-Started.md) for your OS. The difference is that you need to `git clone -https://github.com/TehomCD/evennia.git` instead of Evennia's repo because Arx uses TehomCD's older -Evennia 0.8 [fork](https://github.com/TehomCD/evennia), notably still using Python2. This detail is -important if referring to newer Evennia documentation. - -If you are new to Evennia it's *highly* recommended that you run through the -instructions in full - including initializing and starting a new empty game and connecting to it. -That way you can be sure Evennia works correctly as a base line. If you have trouble, make sure to -read the [Troubleshooting instructions](./Getting-Started.md#troubleshooting) for your -operating system. You can also drop into our -[forums](https://groups.google.com/forum/#%21forum/evennia), join `#evennia` on `irc.freenode.net` -or chat from the linked [Discord Server](https://discord.gg/NecFePw). - -After installing you should have a `virtualenv` running and you should have the following file -structure in your set-aside folder: - -``` -vienv/ -evennia/ -mygame/ - -``` - -Here `mygame` is the empty game you created during the Evennia install, with `evennia --init`. Go to -that and run `evennia stop` to make sure your empty game is not running. We'll instead let Evenna -run Arx, so in principle you could erase `mygame` - but it could also be good to have a clean game -to compare to. - -## Installing Arxcode - -### Clone the arxcode repo - -Cd to the root of your directory and clone the released source code from github: - - git clone https://github.com/Arx-Game/arxcode.git myarx - -A new folder `myarx` should appear next to the ones you already had. You could rename this to -something else if you want. - -Cd into `myarx`. If you wonder about the structure of the game dir, you can [read more about it -here](./Directory-Overview.md). - -### Clean up settings - -Arx has split evennia's normal settings into `base_settings.py` and `production_settings.py`. It -also has its own solution for managing 'secret' parts of the settings file. We'll keep most of Arx -way but remove the secret-handling and replace it with the normal Evennia method. - -Cd into `myarx/server/conf/` and open the file `settings.py` in a text editor. The top part (within -`"""..."""`) is just help text. Wipe everything underneath that and make it look like this instead -(don't forget to save): - -``` -from base_settings import * - -TELNET_PORTS = [4000] -SERVERNAME = "MyArx" -GAME_SLOGAN = "The cool game" - -try: - from server.conf.secret_settings import * -except ImportError: - print("secret_settings.py file not found or failed to import.") -``` - -> Note: Indents and capitalization matter in Python. Make indents 4 spaces (not tabs) for your own -> sanity. If you want a starter on Python in Evennia, [you can look here](Python-basic- -introduction). - -This will import Arx' base settings and override them with the Evennia-default telnet port and give -the game a name. The slogan changes the sub-text shown under the name of your game in the website -header. You can tweak these to your own liking later. - -Next, create a new, empty file `secret_settings.py` in the same location as the `settings.py` file. -This can just contain the following: - -```python -SECRET_KEY = "sefsefiwwj3 jnwidufhjw4545_oifej whewiu hwejfpoiwjrpw09&4er43233fwefwfw" - -``` - -Replace the long random string with random ASCII characters of your own. The secret key should not -be shared. - -Next, open `myarx/server/conf/base_settings.py` in your text editor. We want to remove/comment out -all mentions of the `decouple` package, which Evennia doesn't use (we use `private_settings.py` to -hide away settings that should not be shared). - -Comment out `from decouple import config` by adding a `#` to the start of the line: `# from decouple -import config`. Then search for `config(` in the file and comment out all lines where this is used. -Many of these are specific to the server environment where the original Arx runs, so is not that -relevant to us. - -### Install Arx dependencies - -Arx has some further dependencies beyond vanilla Evennia. Start by `cd`:ing to the root of your -`myarx` folder. - -> If you run *Linux* or *Mac*: Edit `myarx/requirements.txt` and comment out the line -> `pypiwin32==219` - it's only needed on Windows and will give an error on other platforms. - -Make sure your `virtualenv` is active, then run - - pip install -r requirements.txt - -The needed Python packages will be installed for you. - -### Adding logs/ folder - -The Arx repo does not contain the `myarx/server/logs/` folder Evennia expects for storing server -logs. This is simple to add: - - # linux/mac - mkdir server/logs - # windows - mkdir server\logs - -### Setting up the database and starting - -From the `myarx` folder, run - - evennia migrate - -This creates the database and will step through all database migrations needed. - - evennia start - -If all goes well Evennia will now start up, running Arx! You can connect to it on `localhost` (or -`127.0.0.1` if your platform doesn't alias `localhost`), port `4000` using a Telnet client. -Alternatively, you can use your web browser to browse to `http://localhost:4001` to see the game's -website and get to the web client. - -When you log in you'll get the standard Evennia greeting (since the database is empty), but you can -try `help` to see that it's indeed Arx that is running. - -### Additional Setup Steps - -The first time you start Evennia after creating the database with the `evennia migrate` step above, -it should create a few starting objects for you - your superuser account, which it will prompt you -to enter, a starting room (Limbo), and a character object for you. If for some reason this does not -occur, you may have to follow the steps below. For the first time Superuser login you may have to -run steps 7-8 and 10 to create and connect to your in-came Character. - -1. Login to the game website with your Superuser account. -2. Press the `Admin` button to get into the (Django-) Admin Interface. -3. Navigate to the `Accounts` section. -4. Add a new Account named for the new staffer. Use a place holder password and dummy e-mail - address. -5. Flag account as `Staff` and apply the `Admin` permission group (This assumes you have already set - up an Admin Group in Django). -6. Add Tags named `player` and `developer`. -7. Log into the game using the web client (or a third-party telnet client) using your superuser - account. Move to where you want the new staffer character to appear. -8. In the game client, run `@create/drop :typeclasses.characters.Character`, where - `` is usually the same name you used for the Staffer account you created in the - Admin earlier (if you are creating a Character for your superuser, use your superuser account -name). - This creates a new in-game Character and places it in your current location. -9. Have the new Admin player log into the game. -10. Have the new Admin puppet the character with `@ic StafferName`. -11. Have the new Admin change their password - `@password = `. - -Now that you have a Character and an Account object, there's a few additional things you may need to -do in order for some commands to function properly. You can either execute these as in-game commands -while `@ic` (controlling your character object). - -1. `@py from web.character.models import RosterEntry;RosterEntry.objects.create(player=self.player, -character=self)` -2. `@py from world.dominion.models import PlayerOrNpc, AssetOwner;dompc = -PlayerOrNpc.objects.create(player = self.player);AssetOwner.objects.create(player=dompc)` - -Those steps will give you a 'RosterEntry', 'PlayerOrNpc', and 'AssetOwner' objects. RosterEntry -explicitly connects a character and account object together, even while offline, and contains -additional information about a character's current presence in game (such as which 'roster' they're -in, if you choose to use an active roster of characters). PlayerOrNpc are more character extensions, -as well as support for npcs with no in-game presence and just represented by a name which can be -offscreen members of a character's family. It also allows for membership in Organizations. -AssetOwner holds information about a character or organization's money and resources. - -## Alternate guide by Pax for installing on Windows - -If for some reason you cannot use the Windows Subsystem for Linux (which would use instructions -identical to the ones above), it's possible to get Evennia running under Anaconda for Windows. The -process is a little bit trickier. - - Make sure you have: - * Git for Windows https://git-scm.com/download/win - * Anaconda for Windows https://www.anaconda.com/distribution/ - * VC++ Compiler for Python 2.7 http://aka.ms/vcpython27 - -conda update conda -conda create -n arx python=2.7 -source activate arx - - Set up a convenient repository place for things. - -cd ~ -mkdir Source -cd Source -mkdir Arx -cd Arx - - Replace the SSH git clone links below with your own github forks. - If you don't plan to change Evennia at all, you can use the - evennia/evennia.git repo instead of a forked one. - -git clone git@github.com:/evennia.git -git clone git@github.com:/arxcode.git - - Evennia is a package itself, so we want to install it and all of its - prerequisites, after switching to the appropriately-tagged branch for - Arxcode. - -cd evennia -git checkout tags/v0.7 -b arx-master -pip install -e . - - Arx has some dependencies of its own, so now we'll go install them - As it is not a package, we'll use the normal requirements file. - -cd ../arxcode -pip install -r requirements.txt - - The git repo doesn't include the empty log directory and Evennia is unhappy if you - don't have it, so while still in the arxcode directory... - -mkdir server/logs - - Now hit https://github.com/evennia/evennia/wiki/Arxcode-installing-help and - change the setup stuff as in the 'Clean up settings' section. - - Then we will create our default database... - -../evennia/bin/windows/evennia.bat migrate - - ...and do the first run. You need winpty because Windows does not have a TTY/PTY - by default, and so the Python console input commands (used for prompts on first - run) will fail and you will end up in an unhappy place. Future runs, you should - not need winpty. - -winpty ../evennia/bin/windows/evennia.bat start - - Once this is done, you should have your Evennia server running Arxcode up - on localhost at port 4000, and the webserver at http://localhost:4001/ - - And you are done! Huzzah! \ No newline at end of file diff --git a/docs/0.9.5/_sources/Async-Process.md.txt b/docs/0.9.5/_sources/Async-Process.md.txt deleted file mode 100644 index e44e9330a2..0000000000 --- a/docs/0.9.5/_sources/Async-Process.md.txt +++ /dev/null @@ -1,233 +0,0 @@ -# Async Process - - -*This is considered an advanced topic.* - -## Synchronous versus Asynchronous - -Most program code operates *synchronously*. This means that each statement in your code gets -processed and finishes before the next can begin. This makes for easy-to-understand code. It is also -a *requirement* in many cases - a subsequent piece of code often depend on something calculated or -defined in a previous statement. - -Consider this piece of code in a traditional Python program: - -```python - print("before call ...") - long_running_function() - print("after call ...") - -``` - -When run, this will print `"before call ..."`, after which the `long_running_function` gets to work -for however long time. Only once that is done, the system prints `"after call ..."`. Easy and -logical to follow. Most of Evennia work in this way and often it's important that commands get -executed in the same strict order they were coded. - -Evennia, via Twisted, is a single-process multi-user server. In simple terms this means that it -swiftly switches between dealing with player input so quickly that each player feels like they do -things at the same time. This is a clever illusion however: If one user, say, runs a command -containing that `long_running_function`, *all* other players are effectively forced to wait until it -finishes. - -Now, it should be said that on a modern computer system this is rarely an issue. Very few commands -run so long that other users notice it. And as mentioned, most of the time you *want* to enforce -all commands to occur in strict sequence. - -When delays do become noticeable and you don't care in which order the command actually completes, -you can run it *asynchronously*. This makes use of the `run_async()` function in -`src/utils/utils.py`: - -```python - run_async(function, *args, **kwargs) -``` - -Where `function` will be called asynchronously with `*args` and `**kwargs`. Example: - -```python - from evennia import utils - print("before call ...") - utils.run_async(long_running_function) - print("after call ...") -``` - -Now, when running this you will find that the program will not wait around for -`long_running_function` to finish. In fact you will see `"before call ..."` and `"after call ..."` -printed out right away. The long-running function will run in the background and you (and other -users) can go on as normal. - -## Customizing asynchronous operation - -A complication with using asynchronous calls is what to do with the result from that call. What if -`long_running_function` returns a value that you need? It makes no real sense to put any lines of -code after the call to try to deal with the result from `long_running_function` above - as we saw -the `"after call ..."` got printed long before `long_running_function` was finished, making that -line quite pointless for processing any data from the function. Instead one has to use *callbacks*. - -`utils.run_async` takes reserved kwargs that won't be passed into the long-running function: - -- `at_return(r)` (the *callback*) is called when the asynchronous function (`long_running_function` - above) finishes successfully. The argument `r` will then be the return value of that function (or - `None`). - - ```python - def at_return(r): - print(r) - ``` - -- `at_return_kwargs` - an optional dictionary that will be fed as keyword arguments to the -`at_return` callback. -- `at_err(e)` (the *errback*) is called if the asynchronous function fails and raises an exception. - This exception is passed to the errback wrapped in a *Failure* object `e`. If you do not supply an - errback of your own, Evennia will automatically add one that silently writes errors to the evennia - log. An example of an errback is found below: - -```python - def at_err(e): - print("There was an error:", str(e)) -``` - -- `at_err_kwargs` - an optional dictionary that will be fed as keyword arguments to the `at_err` - errback. - -An example of making an asynchronous call from inside a [Command](./Commands.md) definition: - -```python - from evennia import utils, Command - - class CmdAsync(Command): - - key = "asynccommand" - - def func(self): - - def long_running_function(): - #[... lots of time-consuming code ...] - return final_value - - def at_return_function(r): - self.caller.msg("The final value is %s" % r) - - def at_err_function(e): - self.caller.msg("There was an error: %s" % e) - - # do the async call, setting all callbacks - utils.run_async(long_running_function, at_return=at_return_function, -at_err=at_err_function) -``` - -That's it - from here on we can forget about `long_running_function` and go on with what else need -to be done. *Whenever* it finishes, the `at_return_function` function will be called and the final -value will -pop up for us to see. If not we will see an error message. - -## delay - -The `delay` function is a much simpler sibling to `run_async`. It is in fact just a way to delay the -execution of a command until a future time. This is equivalent to something like `time.sleep()` -except delay is asynchronous while `sleep` would lock the entire server for the duration of the -sleep. - -```python - from evennia.utils import delay - - # [...] - # e.g. inside a Command, where `self.caller` is available - def callback(obj): - obj.msg("Returning!") - delay(10, callback, self.caller) -``` - -This will delay the execution of the callback for 10 seconds. This function is explored much more in -the [Command Duration Tutorial](./Command-Duration.md). - -You can also try the following snippet just see how it works: - - @py from evennia.utils import delay; delay(10, lambda who: who.msg("Test!"), self) - -Wait 10 seconds and 'Test!' should be echoed back to you. - - -## The @interactive decorator - -As of Evennia 0.9, the `@interactive` [decorator](https://realpython.com/primer-on-python-decorators/) -is available. This makes any function or method possible to 'pause' and/or await player input -in an interactive way. - -```python - from evennia.utils import interactive - - @interactive - def myfunc(caller): - - while True: - caller.msg("Getting ready to wait ...") - yield(5) - caller.msg("Now 5 seconds have passed.") - - response = yield("Do you want to wait another 5 secs?") - - if response.lower() not in ("yes", "y"): - break -``` - -The `@interactive` decorator gives the function the ability to pause. The use -of `yield(seconds)` will do just that - it will asynchronously pause for the -number of seconds given before continuing. This is technically equivalent to -using `call_async` with a callback that continues after 5 secs. But the code -with `@interactive` is a little easier to follow. - -Within the `@interactive` function, the `response = yield("question")` question -allows you to ask the user for input. You can then process the input, just like -you would if you used the Python `input` function. There is one caveat to this -functionality though - _it will only work if the function/method has an -argument named exactly `caller`_. This is because internally Evennia will look -for the `caller` argument and treat that as the source of input. - -All of this makes the `@interactive` decorator very useful. But it comes with a -few caveats. Notably, decorating a function/method with `@interactive` turns it -into a Python [generator](https://wiki.python.org/moin/Generators). The most -common issue is that you cannot use `return ` from a generator (just an -empty `return` works). To return a value from a function/method you have decorated -with `@interactive`, you must instead use a special Twisted function -`twisted.internet.defer.returnValue`. Evennia also makes this function -conveniently available from `evennia.utils`: - -```python - from evennia.utils import interactive, returnValue - - @interactive - def myfunc(): - - # ... - result = 10 - - # this must be used instead of `return result` - returnValue(result) - -``` - - - -## Assorted notes - -Overall, be careful with choosing when to use asynchronous calls. It is mainly useful for large -administration operations that have no direct influence on the game world (imports and backup -operations come to mind). Since there is no telling exactly when an asynchronous call actually ends, -using them for in-game commands is to potentially invite confusion and inconsistencies (and very -hard-to-reproduce bugs). - -The very first synchronous example above is not *really* correct in the case of Twisted, which is -inherently an asynchronous server. Notably you might find that you will *not* see the first `before -call ...` text being printed out right away. Instead all texts could end up being delayed until -after the long-running process finishes. So all commands will retain their relative order as -expected, but they may appear with delays or in groups. - -## Further reading - -Technically, `run_async` is just a very thin and simplified wrapper around a -[Twisted Deferred](http://twistedmatrix.com/documents/9.0.0/core/howto/defer.html) object; the -wrapper sets -up a default errback also if none is supplied. If you know what you are doing there is nothing -stopping you from bypassing the utility function, building a more sophisticated callback chain after -your own liking. diff --git a/docs/0.9.5/_sources/Attributes.md.txt b/docs/0.9.5/_sources/Attributes.md.txt deleted file mode 100644 index b04d18f654..0000000000 --- a/docs/0.9.5/_sources/Attributes.md.txt +++ /dev/null @@ -1,393 +0,0 @@ -# Attributes - - -When performing actions in Evennia it is often important that you store data for later. If you write -a menu system, you have to keep track of the current location in the menu tree so that the player -can give correct subsequent commands. If you are writing a combat system, you might have a -combattant's next roll get easier dependent on if their opponent failed. Your characters will -probably need to store roleplaying-attributes like strength and agility. And so on. - -[Typeclassed](./Typeclasses.md) game entities ([Accounts](./Accounts.md), [Objects](./Objects.md), -[Scripts](./Scripts.md) and [Channels](./Communications.md)) always have *Attributes* associated with them. -Attributes are used to store any type of data 'on' such entities. This is different from storing -data in properties already defined on entities (such as `key` or `location`) - these have very -specific names and require very specific types of data (for example you couldn't assign a python -*list* to the `key` property no matter how hard you tried). `Attributes` come into play when you -want to assign arbitrary data to arbitrary names. - -**Attributes are _not_ secure by default and any player may be able to change them unless you -[prevent this behavior](./Attributes.md#locking-and-checking-attributes).** - -## The .db and .ndb shortcuts - -To save persistent data on a Typeclassed object you normally use the `db` (DataBase) operator. Let's -try to save some data to a *Rose* (an [Object](./Objects.md)): - -```python - # saving - rose.db.has_thorns = True - # getting it back - is_ouch = rose.db.has_thorns - -``` - -This looks like any normal Python assignment, but that `db` makes sure that an *Attribute* is -created behind the scenes and is stored in the database. Your rose will continue to have thorns -throughout the life of the server now, until you deliberately remove them. - -To be sure to save **non-persistently**, i.e. to make sure NOT to create a database entry, you use -`ndb` (NonDataBase). It works in the same way: - -```python - # saving - rose.ndb.has_thorns = True - # getting it back - is_ouch = rose.ndb.has_thorns -``` - -Technically, `ndb` has nothing to do with `Attributes`, despite how similar they look. No -`Attribute` object is created behind the scenes when using `ndb`. In fact the database is not -invoked at all since we are not interested in persistence. There is however an important reason to -use `ndb` to store data rather than to just store variables direct on entities - `ndb`-stored data -is tracked by the server and will not be purged in various cache-cleanup operations Evennia may do -while it runs. Data stored on `ndb` (as well as `db`) will also be easily listed by example the -`@examine` command. - -You can also `del` properties on `db` and `ndb` as normal. This will for example delete an -`Attribute`: - -```python - del rose.db.has_thorns -``` - -Both `db` and `ndb` defaults to offering an `all` property on themselves. This returns all -associated attributes or non-persistent properties. - -```python - list_of_all_rose_attributes = rose.db.all - list_of_all_rose_ndb_attrs = rose.ndb.all -``` - -If you use `all` as the name of an attribute, this will be used instead. Later deleting your custom -`all` will return the default behaviour. - -## The AttributeHandler - -The `.db` and `.ndb` properties are very convenient but if you don't know the name of the Attribute -beforehand they cannot be used. Behind the scenes `.db` actually accesses the `AttributeHandler` -which sits on typeclassed entities as the `.attributes` property. `.ndb` does the same for the -`.nattributes` property. - -The handlers have normal access methods that allow you to manage and retrieve `Attributes` and -`NAttributes`: - -- `has('attrname')` - this checks if the object has an Attribute with this key. This is equivalent - to doing `obj.db.attrname`. -- `get(...)` - this retrieves the given Attribute. Normally the `value` property of the Attribute is - returned, but the method takes keywords for returning the Attribute object itself. By supplying an - `accessing_object` to the call one can also make sure to check permissions before modifying - anything. -- `add(...)` - this adds a new Attribute to the object. An optional [lockstring](./Locks.md) can be - supplied here to restrict future access and also the call itself may be checked against locks. -- `remove(...)` - Remove the given Attribute. This can optionally be made to check for permission - before performing the deletion. - `clear(...)` - removes all Attributes from object. -- `all(...)` - returns all Attributes (of the given category) attached to this object. - -See [this section](./Attributes.md#locking-and-checking-attributes) for more about locking down Attribute -access and editing. The `Nattribute` offers no concept of access control. - -Some examples: - -```python - import evennia - obj = evennia.search_object("MyObject") - - obj.attributes.add("test", "testvalue") - print(obj.db.test) # prints "testvalue" - print(obj.attributes.get("test")) # " - print(obj.attributes.all()) # prints [] - obj.attributes.remove("test") -``` - - -## Properties of Attributes - -An Attribute object is stored in the database. It has the following properties: - -- `key` - the name of the Attribute. When doing e.g. `obj.db.attrname = value`, this property is set - to `attrname`. -- `value` - this is the value of the Attribute. This value can be anything which can be pickled - - objects, lists, numbers or what have you (see - [this section](./Attributes.md#what-types-of-data-can-i-save-in-an-attribute) for more info). In the -example - `obj.db.attrname = value`, the `value` is stored here. -- `category` - this is an optional property that is set to None for most Attributes. Setting this - allows to use Attributes for different functionality. This is usually not needed unless you want - to use Attributes for very different functionality ([Nicks](./Nicks.md) is an example of using -Attributes - in this way). To modify this property you need to use the [Attribute -Handler](#the-attributehandler). -- `strvalue` - this is a separate value field that only accepts strings. This severely limits the - data possible to store, but allows for easier database lookups. This property is usually not used - except when re-using Attributes for some other purpose ([Nicks](./Nicks.md) use it). It is only - accessible via the [Attribute Handler](./Attributes.md#the-attributehandler). - -There are also two special properties: - -- `attrtype` - this is used internally by Evennia to separate [Nicks](./Nicks.md), from Attributes (Nicks - use Attributes behind the scenes). -- `model` - this is a *natural-key* describing the model this Attribute is attached to. This is on - the form *appname.modelclass*, like `objects.objectdb`. It is used by the Attribute and - NickHandler to quickly sort matches in the database. Neither this nor `attrtype` should normally - need to be modified. - -Non-database attributes have no equivalence to `category` nor `strvalue`, `attrtype` or `model`. - -## Persistent vs non-persistent - -So *persistent* data means that your data will survive a server reboot, whereas with -*non-persistent* data it will not ... - -... So why would you ever want to use non-persistent data? The answer is, you don't have to. Most of -the time you really want to save as much as you possibly can. Non-persistent data is potentially -useful in a few situations though. - -- You are worried about database performance. Since Evennia caches Attributes very aggressively, - this is not an issue unless you are reading *and* writing to your Attribute very often (like many - times per second). Reading from an already cached Attribute is as fast as reading any Python - property. But even then this is not likely something to worry about: Apart from Evennia's own - caching, modern database systems themselves also cache data very efficiently for speed. Our -default - database even runs completely in RAM if possible, alleviating much of the need to write to disk - during heavy loads. -- A more valid reason for using non-persistent data is if you *want* to lose your state when logging - off. Maybe you are storing throw-away data that are re-initialized at server startup. Maybe you - are implementing some caching of your own. Or maybe you are testing a buggy [Script](./Scripts.md) that - does potentially harmful stuff to your character object. With non-persistent storage you can be -sure - that whatever is messed up, it's nothing a server reboot can't clear up. -- NAttributes have no restrictions at all on what they can store (see next section), since they - don't need to worry about being saved to the database - they work very well for temporary storage. -- You want to implement a fully or partly *non-persistent world*. Who are we to argue with your - grand vision! - -## What types of data can I save in an Attribute? - -> None of the following affects NAttributes, which does not invoke the database at all. There are no -> restrictions to what can be stored in a NAttribute. - -The database doesn't know anything about Python objects, so Evennia must *serialize* Attribute -values into a string representation in order to store it to the database. This is done using the -`pickle` module of Python (the only exception is if you use the `strattr` keyword of the -AttributeHandler to save to the `strvalue` field of the Attribute. In that case you can only save -*strings* which will not be pickled). - -It's important to note that when you access the data in an Attribute you are *always* de-serializing -it from the database representation every time. This is because we allow for storing -database-entities in Attributes too. If we cached it as its Python form, we might end up with -situations where the database entity was deleted since we last accessed the Attribute. -De-serializing data with a database-entity in it means querying the database for that object and -making sure it still exists (otherwise it will be set to `None`). Performance-wise this is usually -not a big deal. But if you are accessing the Attribute as part of some big loop or doing a large -amount of reads/writes you should first extract it to a temporary variable, operate on *that* and -then save the result back to the Attribute. If you are storing a more complex structure like a -`dict` or a `list` you should make sure to "disconnect" it from the database before looping over it, -as mentioned in the [Retrieving Mutable Objects](./Attributes.md#retrieving-mutable-objects) section -below. - -### Storing single objects - -With a single object, we mean anything that is *not iterable*, like numbers, strings or custom class -instances without the `__iter__` method. - -* You can generally store any non-iterable Python entity that can be - [pickled](http://docs.python.org/library/pickle.html). -* Single database objects/typeclasses can be stored as any other in the Attribute. These can - normally *not* be pickled, but Evennia will behind the scenes convert them to an internal - representation using their classname, database-id and creation-date with a microsecond precision, - guaranteeing you get the same object back when you access the Attribute later. -* If you *hide* a database object inside a non-iterable custom class (like stored as a variable - inside it), Evennia will not know it's there and won't convert it safely. Storing classes with - such hidden database objects is *not* supported and will lead to errors! - -```python -# Examples of valid single-value attribute data: -obj.db.test1 = 23 -obj.db.test1 = False -# a database object (will be stored as an internal representation) -obj.db.test2 = myobj - -# example of an invalid, "hidden" dbobject -class Invalid(object): - def __init__(self, dbobj): - # no way for Evennia to know this is a dbobj - self.dbobj = dbobj -invalid = Invalid(myobj) -obj.db.invalid = invalid # will cause error! -``` - -### Storing multiple objects - -This means storing objects in a collection of some kind and are examples of *iterables*, pickle-able -entities you can loop over in a for-loop. Attribute-saving supports the following iterables: - -* [Tuples](https://docs.python.org/2/library/functions.html#tuple), like `(1,2,"test", )`. -* [Lists](https://docs.python.org/2/tutorial/datastructures.html#more-on-lists), like `[1,2,"test", -]`. -* [Dicts](https://docs.python.org/2/tutorial/datastructures.html#dictionaries), like `{1:2, -"test":]`. -* [Sets](https://docs.python.org/2/tutorial/datastructures.html#sets), like `{1,2,"test",}`. -* [collections.OrderedDict](https://docs.python.org/2/library/collections.html#collections.OrderedDict), like `OrderedDict((1,2), ("test", ))`. -* [collections.Deque](https://docs.python.org/2/library/collections.html#collections.deque), like -`deque((1,2,"test",))`. -* *Nestings* of any combinations of the above, like lists in dicts or an OrderedDict of tuples, each -containing dicts, etc. -* All other iterables (i.e. entities with the `__iter__` method) will be converted to a *list*. - Since you can use any combination of the above iterables, this is generally not much of a - limitation. - -Any entity listed in the [Single object](./Attributes.md#storing-single-objects) section above can be -stored in the iterable. - -> As mentioned in the previous section, database entities (aka typeclasses) are not possible to -> pickle. So when storing an iterable, Evennia must recursively traverse the iterable *and all its -> nested sub-iterables* in order to find eventual database objects to convert. This is a very fast -> process but for efficiency you may want to avoid too deeply nested structures if you can. - -```python -# examples of valid iterables to store -obj.db.test3 = [obj1, 45, obj2, 67] -# a dictionary -obj.db.test4 = {'str':34, 'dex':56, 'agi':22, 'int':77} -# a mixed dictionary/list -obj.db.test5 = {'members': [obj1,obj2,obj3], 'enemies':[obj4,obj5]} -# a tuple with a list in it -obj.db.test6 = (1,3,4,8, ["test", "test2"], 9) -# a set -obj.db.test7 = set([1,2,3,4,5]) -# in-situ manipulation -obj.db.test8 = [1,2,{"test":1}] -obj.db.test8[0] = 4 -obj.db.test8[2]["test"] = 5 -# test8 is now [4,2,{"test":5}] -``` - -### Retrieving Mutable objects - -A side effect of the way Evennia stores Attributes is that *mutable* iterables (iterables that can -be modified in-place after they were created, which is everything except tuples) are handled by -custom objects called `_SaverList`, `_SaverDict` etc. These `_Saver...` classes behave just like the -normal variant except that they are aware of the database and saves to it whenever new data gets -assigned to them. This is what allows you to do things like `self.db.mylist[7] = val` and be sure -that the new version of list is saved. Without this you would have to load the list into a temporary -variable, change it and then re-assign it to the Attribute in order for it to save. - -There is however an important thing to remember. If you retrieve your mutable iterable into another -variable, e.g. `mylist2 = obj.db.mylist`, your new variable (`mylist2`) will *still* be a -`_SaverList`. This means it will continue to save itself to the database whenever it is updated! - - -```python - obj.db.mylist = [1,2,3,4] - mylist = obj.db.mylist - mylist[3] = 5 # this will also update database - print(mylist) # this is now [1,2,3,5] - print(obj.db.mylist) # this is also [1,2,3,5] -``` - -To "disconnect" your extracted mutable variable from the database you simply need to convert the -`_Saver...` iterable to a normal Python structure. So to convert a `_SaverList`, you use the -`list()` function, for a `_SaverDict` you use `dict()` and so on. - -```python - obj.db.mylist = [1,2,3,4] - mylist = list(obj.db.mylist) # convert to normal list - mylist[3] = 5 - print(mylist) # this is now [1,2,3,5] - print(obj.db.mylist) # this is still [1,2,3,4] -``` - -A further problem comes with *nested mutables*, like a dict containing lists of dicts or something -like that. Each of these nested mutables would be `_Saver*` structures connected to the database and -disconnecting the outermost one of them would not disconnect those nested within. To make really -sure you disonnect a nested structure entirely from the database, Evennia provides a special -function `evennia.utils.dbserialize.deserialize`: - -``` -from evennia.utils.dbserialize import deserialize - -decoupled_mutables = deserialize(nested_mutables) - -``` - -The result of this operation will be a structure only consisting of normal Python mutables (`list` -instead of `_SaverList` and so on). - - -Remember, this is only valid for *mutable* iterables. -[Immutable](http://en.wikipedia.org/wiki/Immutable) objects (strings, numbers, tuples etc) are -already disconnected from the database from the onset. - -```python - obj.db.mytup = (1,2,[3,4]) - obj.db.mytup[0] = 5 # this fails since tuples are immutable - - # this works but will NOT update database since outermost is a tuple - obj.db.mytup[2][1] = 5 - print(obj.db.mytup[2][1]) # this still returns 4, not 5 - - mytup1 = obj.db.mytup # mytup1 is already disconnected from database since outermost - # iterable is a tuple, so we can edit the internal list as we want - # without affecting the database. -``` - -> Attributes will fetch data fresh from the database whenever you read them, so -> if you are performing big operations on a mutable Attribute property (such as looping over a list -> or dict) you should make sure to "disconnect" the Attribute's value first and operate on this -> rather than on the Attribute. You can gain dramatic speed improvements to big loops this -> way. - - -## Locking and checking Attributes - -Attributes are normally not locked down by default, but you can easily change that for individual -Attributes (like those that may be game-sensitive in games with user-level building). - -First you need to set a *lock string* on your Attribute. Lock strings are specified [Locks](./Locks.md). -The relevant lock types are - -- `attrread` - limits who may read the value of the Attribute -- `attredit` - limits who may set/change this Attribute - -You cannot use the `db` handler to modify Attribute object (such as setting a lock on them) - The -`db` handler will return the Attribute's *value*, not the Attribute object itself. Instead you use -the AttributeHandler and set it to return the object instead of the value: - -```python - lockstring = "attread:all();attredit:perm(Admins)" - obj.attributes.get("myattr", return_obj=True).locks.add(lockstring) -``` - -Note the `return_obj` keyword which makes sure to return the `Attribute` object so its LockHandler -could be accessed. - -A lock is no good if nothing checks it -- and by default Evennia does not check locks on Attributes. -You have to add a check to your commands/code wherever it fits (such as before setting an -Attribute). - -```python - # in some command code where we want to limit - # setting of a given attribute name on an object - attr = obj.attributes.get(attrname, - return_obj=True, - accessing_obj=caller, - default=None, - default_access=False) - if not attr: - caller.msg("You cannot edit that Attribute!") - return - # edit the Attribute here -``` - -The same keywords are available to use with `obj.attributes.set()` and `obj.attributes.remove()`, -those will check for the `attredit` lock type. diff --git a/docs/0.9.5/_sources/Banning.md.txt b/docs/0.9.5/_sources/Banning.md.txt deleted file mode 100644 index 09baae2b95..0000000000 --- a/docs/0.9.5/_sources/Banning.md.txt +++ /dev/null @@ -1,148 +0,0 @@ -# Banning - - -Whether due to abuse, blatant breaking of your rules, or some other reason, you will eventually find -no other recourse but to kick out a particularly troublesome player. The default command set has -admin tools to handle this, primarily `ban`, `unban`, and `boot`. - -## Creating a ban - -Say we have a troublesome player "YouSuck" - this is a person that refuses common courtesy - an -abusive -and spammy account that is clearly created by some bored internet hooligan only to cause grief. You -have tried to be nice. Now you just want this troll gone. - -### Name ban - -The easiest recourse is to block the account YouSuck from ever connecting again. - - ban YouSuck - -This will lock the name YouSuck (as well as 'yousuck' and any other capitalization combination), and -next time they try to log in with this name the server will not let them! - -You can also give a reason so you remember later why this was a good thing (the banned account will -never see this) - - ban YouSuck:This is just a troll. - -If you are sure this is just a spam account, you might even consider deleting the player account -outright: - - account/delete YouSuck - -Generally, banning the name is the easier and safer way to stop the use of an account -- if you -change your mind you can always remove the block later whereas a deletion is permanent. - -### IP ban - -Just because you block YouSuck's name might not mean the trolling human behind that account gives -up. They can just create a new account YouSuckMore and be back at it. One way to make things harder -for them is to tell the server to not allow connections from their particular IP address. - -First, when the offending account is online, check which IP address they use. This you can do with -the `who` command, which will show you something like this: - - Account Name On for Idle Room Cmds Host - YouSuckMore 01:12 2m 22 212 237.333.0.223 - -The "Host" bit is the IP address from which the account is connecting. Use this to define the ban -instead of the name: - - ban 237.333.0.223 - -This will stop YouSuckMore connecting from their computer. Note however that IP address might change -easily - either due to how the player's Internet Service Provider operates or by the user simply -changing computers. You can make a more general ban by putting asterisks `*` as wildcards for the -groups of three digits in the address. So if you figure out that !YouSuckMore mainly connects from -237.333.0.223, 237.333.0.225, and 237.333.0.256 (only changes in their subnet), it might be an idea -to put down a ban like this to include any number in that subnet: - - ban 237.333.0.* - -You should combine the IP ban with a name-ban too of course, so the account YouSuckMore is truly -locked regardless of where they connect from. - -Be careful with too general IP bans however (more asterisks above). If you are unlucky you could be -blocking out innocent players who just happen to connect from the same subnet as the offender. - -## Booting - -YouSuck is not really noticing all this banning yet though - and won't until having logged out and -trying to log back in again. Let's help the troll along. - - boot YouSuck - -Good riddance. You can give a reason for booting too (to be echoed to the player before getting -kicked out). - - boot YouSuck:Go troll somewhere else. - -### Lifting a ban - -Use the `unban` (or `ban`) command without any arguments and you will see a list of all currently -active bans: - - Active bans - id name/ip date reason - 1 yousuck Fri Jan 3 23:00:22 2020 This is just a Troll. - 2 237.333.0.* Fri Jan 3 23:01:03 2020 YouSuck's IP. - -Use the `id` from this list to find out which ban to lift. - - unban 2 - - Cleared ban 2: 237.333.0.* - -## Summary of abuse-handling tools - -Below are other useful commands for dealing with annoying players. - -- **who** -- (as admin) Find the IP of a account. Note that one account can be connected to from -multiple IPs depending on what you allow in your settings. -- **examine/account thomas** -- Get all details about an account. You can also use `*thomas` to get -the account. If not given, you will get the *Object* thomas if it exists in the same location, which -is not what you want in this case. -- **boot thomas** -- Boot all sessions of the given account name. -- **boot 23** -- Boot one specific client session/IP by its unique id. -- **ban** -- List all bans (listed with ids) -- **ban thomas** -- Ban the user with the given account name -- **ban/ip `134.233.2.111`** -- Ban by IP -- **ban/ip `134.233.2.*`** -- Widen IP ban -- **ban/ip `134.233.*.*`** -- Even wider IP ban -- **unban 34** -- Remove ban with id #34 - -- **cboot mychannel = thomas** -- Boot a subscriber from a channel you control -- **clock mychannel = control:perm(Admin);listen:all();send:all()** -- Fine control of access to -your channel using [lock definitions](./Locks.md). - -Locking a specific command (like `page`) is accomplished like so: -1. Examine the source of the command. [The default `page` command class]( -https://github.com/evennia/evennia/blob/master/evennia/commands/default/comms.py#L686) has the lock -string **"cmd:not pperm(page_banned)"**. This means that unless the player has the 'permission' -"page_banned" they can use this command. You can assign any lock string to allow finer customization -in your commands. You might look for the value of an [Attribute](./Attributes.md) or [Tag](./Tags.md), your -current location etc. -2. **perm/account thomas = page_banned** -- Give the account the 'permission' which causes (in this -case) the lock to fail. - -- **perm/del/account thomas = page_banned** -- Remove the given permission - -- **tel thomas = jail** -- Teleport a player to a specified location or #dbref -- **type thomas = FlowerPot** -- Turn an annoying player into a flower pot (assuming you have a -`FlowerPot` typeclass ready) -- **userpassword thomas = fooBarFoo** -- Change a user's password -- **account/delete thomas** -- Delete a player account (not recommended, use **ban** instead) - -- **server** -- Show server statistics, such as CPU load, memory usage, and how many objects are -cached -- **time** -- Gives server uptime, runtime, etc -- **reload** -- Reloads the server without disconnecting anyone -- **reset** -- Restarts the server, kicking all connections -- **shutdown** -- Stops the server cold without it auto-starting again -- **py** -- Executes raw Python code, allows for direct inspection of the database and account -objects on the fly. For advanced users. - - -**Useful Tip:** `evennia changepassword ` entered into the command prompt will reset the -password of any account, including the superuser or admin accounts. This is a feature of Django. diff --git a/docs/0.9.5/_sources/Batch-Code-Processor.md.txt b/docs/0.9.5/_sources/Batch-Code-Processor.md.txt deleted file mode 100644 index df8eaff1ff..0000000000 --- a/docs/0.9.5/_sources/Batch-Code-Processor.md.txt +++ /dev/null @@ -1,229 +0,0 @@ -# Batch Code Processor - - -For an introduction and motivation to using batch processors, see [here](./Batch-Processors.md). This -page describes the Batch-*code* processor. The Batch-*command* one is covered [here](Batch-Command- -Processor). - -## Basic Usage - -The batch-code processor is a superuser-only function, invoked by - - > @batchcode path.to.batchcodefile - -Where `path.to.batchcodefile` is the path to a *batch-code file*. Such a file should have a name -ending in "`.py`" (but you shouldn't include that in the path). The path is given like a python path -relative to a folder you define to hold your batch files, set by `BATCH_IMPORT_PATH` in your -settings. Default folder is (assuming your game is called "mygame") `mygame/world/`. So if you want -to run the example batch file in `mygame/world/batch_code.py`, you could simply use - - > @batchcode batch_code - -This will try to run through the entire batch file in one go. For more gradual, *interactive* -control you can use the `/interactive` switch. The switch `/debug` will put the processor in -*debug* mode. Read below for more info. - -## The batch file - -A batch-code file is a normal Python file. The difference is that since the batch processor loads -and executes the file rather than importing it, you can reliably update the file, then call it -again, over and over and see your changes without needing to `@reload` the server. This makes for -easy testing. In the batch-code file you have also access to the following global variables: - -- `caller` - This is a reference to the object running the batchprocessor. -- `DEBUG` - This is a boolean that lets you determine if this file is currently being run in debug- -mode or not. See below how this can be useful. - -Running a plain Python file through the processor will just execute the file from beginning to end. -If you want to get more control over the execution you can use the processor's *interactive* mode. -This runs certain code blocks on their own, rerunning only that part until you are happy with it. In -order to do this you need to add special markers to your file to divide it up into smaller chunks. -These take the form of comments, so the file remains valid Python. - -Here are the rules of syntax of the batch-code `*.py` file. - -- `#CODE` as the first on a line marks the start of a *code* block. It will last until the beginning -of another marker or the end of the file. Code blocks contain functional python code. Each `#CODE` -block will be run in complete isolation from other parts of the file, so make sure it's self- -contained. -- `#HEADER` as the first on a line marks the start of a *header* block. It lasts until the next -marker or the end of the file. This is intended to hold imports and variables you will need for all -other blocks .All python code defined in a header block will always be inserted at the top of every -`#CODE` blocks in the file. You may have more than one `#HEADER` block, but that is equivalent to -having one big one. Note that you can't exchange data between code blocks, so editing a header- -variable in one code block won't affect that variable in any other code block! -- `#INSERT path.to.file` will insert another batchcode (Python) file at that position. -- A `#` that is not starting a `#HEADER`, `#CODE` or `#INSERT` instruction is considered a comment. -- Inside a block, normal Python syntax rules apply. For the sake of indentation, each block acts as -a separate python module. - -Below is a version of the example file found in `evennia/contrib/tutorial_examples/`. - -```python - # - # This is an example batch-code build file for Evennia. - # - - #HEADER - - # This will be included in all other #CODE blocks - - from evennia import create_object, search_object - from evennia.contrib.tutorial_examples import red_button - from typeclasses.objects import Object - - limbo = search_object('Limbo')[0] - - - #CODE - - red_button = create_object(red_button.RedButton, key="Red button", - location=limbo, aliases=["button"]) - - # caller points to the one running the script - caller.msg("A red button was created.") - - # importing more code from another batch-code file - #INSERT batch_code_insert - - #CODE - - table = create_object(Object, key="Blue Table", location=limbo) - chair = create_object(Object, key="Blue Chair", location=limbo) - - string = "A %s and %s were created." - if DEBUG: - table.delete() - chair.delete() - string += " Since debug was active, " \ - "they were deleted again." - caller.msg(string % (table, chair)) -``` - -This uses Evennia's Python API to create three objects in sequence. - -## Debug mode - -Try to run the example script with - - > @batchcode/debug tutorial_examples.example_batch_code - -The batch script will run to the end and tell you it completed. You will also get messages that the -button and the two pieces of furniture were created. Look around and you should see the button -there. But you won't see any chair nor a table! This is because we ran this with the `/debug` -switch, which is directly visible as `DEBUG==True` inside the script. In the above example we -handled this state by deleting the chair and table again. - -The debug mode is intended to be used when you test out a batchscript. Maybe you are looking for -bugs in your code or try to see if things behave as they should. Running the script over and over -would then create an ever-growing stack of chairs and tables, all with the same name. You would have -to go back and painstakingly delete them later. - -## Interactive mode - -Interactive mode works very similar to the [batch-command processor counterpart](Batch-Command- -Processor). It allows you more step-wise control over how the batch file is executed. This is useful -for debugging or for picking and choosing only particular blocks to run. Use `@batchcode` with the -`/interactive` flag to enter interactive mode. - - > @batchcode/interactive tutorial_examples.example_batch_code - -You should see the following: - - 01/02: red_button = create_object(red_button.RedButton, [...] (hh for help) - -This shows that you are on the first `#CODE` block, the first of only two commands in this batch -file. Observe that the block has *not* actually been executed at this point! - -To take a look at the full code snippet you are about to run, use `ll` (a batch-processor version of -`look`). - -```python - from evennia.utils import create, search - from evennia.contrib.tutorial_examples import red_button - from typeclasses.objects import Object - - limbo = search.objects(caller, 'Limbo', global_search=True)[0] - - red_button = create.create_object(red_button.RedButton, key="Red button", - location=limbo, aliases=["button"]) - - # caller points to the one running the script - caller.msg("A red button was created.") -``` - -Compare with the example code given earlier. Notice how the content of `#HEADER` has been pasted at -the top of the `#CODE` block. Use `pp` to actually execute this block (this will create the button -and give you a message). Use `nn` (next) to go to the next command. Use `hh` for a list of commands. - -If there are tracebacks, fix them in the batch file, then use `rr` to reload the file. You will -still be at the same code block and can rerun it easily with `pp` as needed. This makes for a simple -debug cycle. It also allows you to rerun individual troublesome blocks - as mentioned, in a large -batch file this can be very useful (don't forget the `/debug` mode either). - -Use `nn` and `bb` (next and back) to step through the file; e.g. `nn 12` will jump 12 steps forward -(without processing any blocks in between). All normal commands of Evennia should work too while -working in interactive mode. - -## Limitations and Caveats - -The batch-code processor is by far the most flexible way to build a world in Evennia. There are -however some caveats you need to keep in mind. - -### Safety -Or rather the lack of it. There is a reason only *superusers* are allowed to run the batch-code -processor by default. The code-processor runs **without any Evennia security checks** and allows -full access to Python. If an untrusted party could run the code-processor they could execute -arbitrary python code on your machine, which is potentially a very dangerous thing. If you want to -allow other users to access the batch-code processor you should make sure to run Evennia as a -separate and very limited-access user on your machine (i.e. in a 'jail'). By comparison, the batch- -command processor is much safer since the user running it is still 'inside' the game and can't -really do anything outside what the game commands allow them to. - -### No communication between code blocks -Global variables won't work in code batch files, each block is executed as stand-alone environments. -`#HEADER` blocks are literally pasted on top of each `#CODE` block so updating some header-variable -in your block will not make that change available in another block. Whereas a python execution -limitation, allowing this would also lead to very hard-to-debug code when using the interactive mode -- this would be a classical example of "spaghetti code". - -The main practical issue with this is when building e.g. a room in one code block and later want to -connect that room with a room you built in the current block. There are two ways to do this: - -- Perform a database search for the name of the room you created (since you cannot know in advance -which dbref it got assigned). The problem is that a name may not be unique (you may have a lot of "A -dark forest" rooms). There is an easy way to handle this though - use [Tags](./Tags.md) or *Aliases*. You -can assign any number of tags and/or aliases to any object. Make sure that one of those tags or -aliases is unique to the room (like "room56") and you will henceforth be able to always uniquely -search and find it later. -- Use the `caller` global property as an inter-block storage. For example, you could have a -dictionary of room references in an `ndb`: - ```python - #HEADER - if caller.ndb.all_rooms is None: - caller.ndb.all_rooms = {} - - #CODE - # create and store the castle - castle = create_object("rooms.Room", key="Castle") - caller.ndb.all_rooms["castle"] = castle - - #CODE - # in another node we want to access the castle - castle = caller.ndb.all_rooms.get("castle") - ``` -Note how we check in `#HEADER` if `caller.ndb.all_rooms` doesn't already exist before creating the -dict. Remember that `#HEADER` is copied in front of every `#CODE` block. Without that `if` statement -we'd be wiping the dict every block! - -### Don't treat a batchcode file like any Python file -Despite being a valid Python file, a batchcode file should *only* be run by the batchcode processor. -You should not do things like define Typeclasses or Commands in them, or import them into other -code. Importing a module in Python will execute base level of the module, which in the case of your -average batchcode file could mean creating a lot of new objects every time. -### Don't let code rely on the batch-file's real file path - -When you import things into your batchcode file, don't use relative imports but always import with -paths starting from the root of your game directory or evennia library. Code that relies on the -batch file's "actual" location *will fail*. Batch code files are read as text and the strings -executed. When the code runs it has no knowledge of what file those strings where once a part of. diff --git a/docs/0.9.5/_sources/Batch-Command-Processor.md.txt b/docs/0.9.5/_sources/Batch-Command-Processor.md.txt deleted file mode 100644 index 9278b4be7f..0000000000 --- a/docs/0.9.5/_sources/Batch-Command-Processor.md.txt +++ /dev/null @@ -1,182 +0,0 @@ -# Batch Command Processor - - -For an introduction and motivation to using batch processors, see [here](./Batch-Processors.md). This -page describes the Batch-*command* processor. The Batch-*code* one is covered [here](Batch-Code- -Processor). - -## Basic Usage - -The batch-command processor is a superuser-only function, invoked by - - > @batchcommand path.to.batchcmdfile - -Where `path.to.batchcmdfile` is the path to a *batch-command file* with the "`.ev`" file ending. -This path is given like a python path relative to a folder you define to hold your batch files, set -with `BATCH_IMPORT_PATH` in your settings. Default folder is (assuming your game is in the `mygame` -folder) `mygame/world`. So if you want to run the example batch file in -`mygame/world/batch_cmds.ev`, you could use - - > @batchcommand batch_cmds - -A batch-command file contains a list of Evennia in-game commands separated by comments. The -processor will run the batch file from beginning to end. Note that *it will not stop if commands in -it fail* (there is no universal way for the processor to know what a failure looks like for all -different commands). So keep a close watch on the output, or use *Interactive mode* (see below) to -run the file in a more controlled, gradual manner. - -## The batch file - -The batch file is a simple plain-text file containing Evennia commands. Just like you would write -them in-game, except you have more freedom with line breaks. - -Here are the rules of syntax of an `*.ev` file. You'll find it's really, really simple: - -- All lines having the `#` (hash)-symbol *as the first one on the line* are considered *comments*. -All non-comment lines are treated as a command and/or their arguments. -- Comment lines have an actual function -- they mark the *end of the previous command definition*. -So never put two commands directly after one another in the file - separate them with a comment, or -the second of the two will be considered an argument to the first one. Besides, using plenty of -comments is good practice anyway. -- A line that starts with the word `#INSERT` is a comment line but also signifies a special -instruction. The syntax is `#INSERT ` and tries to import a given batch-cmd file -into this one. The inserted batch file (file ending `.ev`) will run normally from the point of the -`#INSERT` instruction. -- Extra whitespace in a command definition is *ignored*. - A completely empty line translates in to -a line break in texts. Two empty lines thus means a new paragraph (this is obviously only relevant -for commands accepting such formatting, such as the `@desc` command). -- The very last command in the file is not required to end with a comment. -- You *cannot* nest another `@batchcommand` statement into your batch file. If you want to link many -batch-files together, use the `#INSERT` batch instruction instead. You also cannot launch the -`@batchcode` command from your batch file, the two batch processors are not compatible. - -Below is a version of the example file found in `evennia/contrib/tutorial_examples/batch_cmds.ev`. - -```bash - # - # This is an example batch build file for Evennia. - # - - # This creates a red button - @create button:tutorial_examples.red_button.RedButton - # (This comment ends input for @create) - # Next command. Let's create something. - @set button/desc = - This is a large red button. Now and then - it flashes in an evil, yet strangely tantalizing way. - - A big sign sits next to it. It says: - - - ----------- - - Press me! - - ----------- - - - ... It really begs to be pressed! You - know you want to! - - # This inserts the commands from another batch-cmd file named - # batch_insert_file.ev. - #INSERT examples.batch_insert_file - - - # (This ends the @set command). Note that single line breaks - # and extra whitespace in the argument are ignored. Empty lines - # translate into line breaks in the output. - # Now let's place the button where it belongs (let's say limbo #2 is - # the evil lair in our example) - @teleport #2 - # (This comments ends the @teleport command.) - # Now we drop it so others can see it. - # The very last command in the file needs not be ended with #. - drop button -``` - -To test this, run `@batchcommand` on the file: - - > @batchcommand contrib.tutorial_examples.batch_cmds - -A button will be created, described and dropped in Limbo. All commands will be executed by the user -calling the command. - -> Note that if you interact with the button, you might find that its description changes, loosing -your custom-set description above. This is just the way this particular object works. - -## Interactive mode - -Interactive mode allows you to more step-wise control over how the batch file is executed. This is -useful for debugging and also if you have a large batch file and is only updating a small part of it --- running the entire file again would be a waste of time (and in the case of `@create`-ing objects -you would to end up with multiple copies of same-named objects, for example). Use `@batchcommand` -with the `/interactive` flag to enter interactive mode. - - > @batchcommand/interactive tutorial_examples.batch_cmds - -You will see this: - - 01/04: @create button:tutorial_examples.red_button.RedButton (hh for help) - -This shows that you are on the `@create` command, the first out of only four commands in this batch -file. Observe that the command `@create` has *not* been actually processed at this point! - -To take a look at the full command you are about to run, use `ll` (a batch-processor version of -`look`). Use `pp` to actually process the current command (this will actually `@create` the button) --- and make sure it worked as planned. Use `nn` (next) to go to the next command. Use `hh` for a -list of commands. - -If there are errors, fix them in the batch file, then use `rr` to reload the file. You will still be -at the same command and can rerun it easily with `pp` as needed. This makes for a simple debug -cycle. It also allows you to rerun individual troublesome commands - as mentioned, in a large batch -file this can be very useful. Do note that in many cases, commands depend on the previous ones (e.g. -if `@create` in the example above had failed, the following commands would have had nothing to -operate on). - -Use `nn` and `bb` (next and back) to step through the file; e.g. `nn 12` will jump 12 steps forward -(without processing any command in between). All normal commands of Evennia should work too while -working in interactive mode. - -## Limitations and Caveats - -The batch-command processor is great for automating smaller builds or for testing new commands and -objects repeatedly without having to write so much. There are several caveats you have to be aware -of when using the batch-command processor for building larger, complex worlds though. - -The main issue is that when you run a batch-command script you (*you*, as in your superuser -character) are actually moving around in the game creating and building rooms in sequence, just as -if you had been entering those commands manually, one by one. You have to take this into account -when creating the file, so that you can 'walk' (or teleport) to the right places in order. - -This also means there are several pitfalls when designing and adding certain types of objects. Here -are some examples: - -- *Rooms that change your [Command Set](./Command-Sets.md)*: Imagine that you build a 'dark' room, which -severely limits the cmdsets of those entering it (maybe you have to find the light switch to -proceed). In your batch script you would create this room, then teleport to it - and promptly be -shifted into the dark state where none of your normal build commands work ... -- *Auto-teleportation*: Rooms that automatically teleport those that enter them to another place -(like a trap room, for example). You would be teleported away too. -- *Mobiles*: If you add aggressive mobs, they might attack you, drawing you into combat. If they -have AI they might even follow you around when building - or they might move away from you before -you've had time to finish describing and equipping them! - -The solution to all these is to plan ahead. Make sure that superusers are never affected by whatever -effects are in play. Add an on/off switch to objects and make sure it's always set to *off* upon -creation. It's all doable, one just needs to keep it in mind. - -## Assorted notes - -The fact that you build as 'yourself' can also be considered an advantage however, should you ever -decide to change the default command to allow others than superusers to call the processor. Since -normal access-checks are still performed, a malevolent builder with access to the processor should -not be able to do all that much damage (this is the main drawback of the [Batch Code -Processor](./Batch-Code-Processor.md)) - -- [GNU Emacs](https://www.gnu.org/software/emacs/) users might find it interesting to use emacs' -*evennia mode*. This is an Emacs major mode found in `evennia/utils/evennia-mode.el`. It offers -correct syntax highlighting and indentation with `` when editing `.ev` files in Emacs. See the -header of that file for installation instructions. -- [VIM](http://www.vim.org/) users can use amfl's [vim-evennia](https://github.com/amfl/vim-evennia) -mode instead, see its readme for install instructions. \ No newline at end of file diff --git a/docs/0.9.5/_sources/Batch-Processors.md.txt b/docs/0.9.5/_sources/Batch-Processors.md.txt deleted file mode 100644 index 85a4c8a30f..0000000000 --- a/docs/0.9.5/_sources/Batch-Processors.md.txt +++ /dev/null @@ -1,82 +0,0 @@ -# Batch Processors - - -Building a game world is a lot of work, especially when starting out. Rooms should be created, -descriptions have to be written, objects must be detailed and placed in their proper places. In many -traditional MUD setups you had to do all this online, line by line, over a telnet session. - -Evennia already moves away from much of this by shifting the main coding work to external Python -modules. But also building would be helped if one could do some or all of it externally. Enter -Evennia's *batch processors* (there are two of them). The processors allows you, as a game admin, to -build your game completely offline in normal text files (*batch files*) that the processors -understands. Then, when you are ready, you use the processors to read it all into Evennia (and into -the database) in one go. - -You can of course still build completely online should you want to - this is certainly the easiest -way to go when learning and for small build projects. But for major building work, the advantages of -using the batch-processors are many: -- It's hard to compete with the comfort of a modern desktop text editor; Compared to a traditional -MUD line input, you can get much better overview and many more features. Also, accidentally pressing -Return won't immediately commit things to the database. -- You might run external spell checkers on your batch files. In the case of one of the batch- -processors (the one that deals with Python code), you could also run external debuggers and code -analyzers on your file to catch problems before feeding it to Evennia. -- The batch files (as long as you keep them) are records of your work. They make a natural starting -point for quickly re-building your world should you ever decide to start over. -- If you are an Evennia developer, using a batch file is a fast way to setup a test-game after -having reset the database. -- The batch files might come in useful should you ever decide to distribute all or part of your -world to others. - - -There are two batch processors, the Batch-*command* processor and the Batch-*code* processor. The -first one is the simpler of the two. It doesn't require any programming knowledge - you basically -just list in-game commands in a text file. The code-processor on the other hand is much more -powerful but also more complex - it lets you use Evennia's API to code your world in full-fledged -Python code. - -- The [Batch Command Processor](./Batch-Command-Processor.md) -- The [Batch Code Processor](./Batch-Code-Processor.md) - -If you plan to use international characters in your batchfiles you are wise to read about *file -encodings* below. - -## A note on File Encodings - -As mentioned, both the processors take text files as input and then proceed to process them. As long -as you stick to the standard [ASCII](http://en.wikipedia.org/wiki/Ascii) character set (which means -the normal English characters, basically) you should not have to worry much about this section. - -Many languages however use characters outside the simple `ASCII` table. Common examples are various -apostrophes and umlauts but also completely different symbols like those of the greek or cyrillic -alphabets. - -First, we should make it clear that Evennia itself handles international characters just fine. It -(and Django) uses [unicode](http://en.wikipedia.org/wiki/Unicode) strings internally. - -The problem is that when reading a text file like the batchfile, we need to know how to decode the -byte-data stored therein to universal unicode. That means we need an *encoding* (a mapping) for how -the file stores its data. There are many, many byte-encodings used around the world, with opaque -names such as `Latin-1`, `ISO-8859-3` or `ARMSCII-8` to pick just a few examples. Problem is that -it's practially impossible to determine which encoding was used to save a file just by looking at it -(it's just a bunch of bytes!). You have to *know*. - -With this little introduction it should be clear that Evennia can't guess but has to *assume* an -encoding when trying to load a batchfile. The text editor and Evennia must speak the same "language" -so to speak. Evennia will by default first try the international `UTF-8` encoding, but you can have -Evennia try any sequence of different encodings by customizing the `ENCODINGS` list in your settings -file. Evennia will use the first encoding in the list that do not raise any errors. Only if none -work will the server give up and return an error message. - -You can often change the text editor encoding (this depends on your editor though), otherwise you -need to add the editor's encoding to Evennia's `ENCODINGS` list. If you are unsure, write a test -file with lots of non-ASCII letters in the editor of your choice, then import to make sure it works -as it should. - -More help with encodings can be found in the entry [Text Encodings](./Text-Encodings.md) and also in the -Wikipedia article [here](http://en.wikipedia.org/wiki/Text_encodings). - -**A footnote for the batch-code processor**: Just because *Evennia* can parse your file and your -fancy special characters, doesn't mean that *Python* allows their use. Python syntax only allows -international characters inside *strings*. In all other source code only `ASCII` set characters are -allowed. diff --git a/docs/0.9.5/_sources/Bootstrap-&-Evennia.md.txt b/docs/0.9.5/_sources/Bootstrap-&-Evennia.md.txt deleted file mode 100644 index fd7db78909..0000000000 --- a/docs/0.9.5/_sources/Bootstrap-&-Evennia.md.txt +++ /dev/null @@ -1,100 +0,0 @@ -# Bootstrap & Evennia - -# What is Bootstrap? -Evennia's new default web page uses a framework called [Bootstrap](https://getbootstrap.com/). This -framework is in use across the internet - you'll probably start to recognize its influence once you -learn some of the common design patterns. This switch is great for web developers, perhaps like -yourself, because instead of wondering about setting up different grid systems or what custom class -another designer used, we have a base, a bootstrap, to work from. Bootstrap is responsive by -default, and comes with some default styles that Evennia has lightly overrode to keep some of the -same colors and styles you're used to from the previous design. - -For your reading pleasure, a brief overview of Bootstrap follows. For more in-depth info, please -read [the documentation](https://getbootstrap.com/docs/4.0/getting-started/introduction/). -*** - -## The Layout System -Other than the basic styling Bootstrap includes, it also includes [a built in layout and grid -system](https://getbootstrap.com/docs/4.0/layout/overview/). -The first part of this system is [the -container](https://getbootstrap.com/docs/4.0/layout/overview/#containers). - -The container is meant to hold all your page content. Bootstrap provides two types: fixed-width and -full-width. -Fixed-width containers take up a certain max-width of the page - they're useful for limiting the -width on Desktop or Tablet platforms, instead of making the content span the width of the page. -``` -

- -
-``` -Full width containers take up the maximum width available to them - they'll span across a wide- -screen desktop or a smaller screen phone, edge-to-edge. -``` -
- -
-``` - -The second part of the layout system is [the grid](https://getbootstrap.com/docs/4.0/layout/grid/). -This is the bread-and-butter of the layout of Bootstrap - it allows you to change the size of -elements depending on the size of the screen, without writing any media queries. We'll briefly go -over it - to learn more, please read the docs or look at the source code for Evennia's home page in -your browser. -> Important! Grid elements should be in a .container or .container-fluid. This will center the -contents of your site. - -Bootstrap's grid system allows you to create rows and columns by applying classes based on -breakpoints. The default breakpoints are extra small, small, medium, large, and extra-large. If -you'd like to know more about these breakpoints, please [take a look at the documentation for -them.](https://getbootstrap.com/docs/4.0/layout/overview/#responsive-breakpoints) - -To use the grid system, first create a container for your content, then add your rows and columns -like so: -``` -
-
-
- 1 of 3 -
-
- 2 of 3 -
-
- 3 of 3 -
-
-
-``` -This layout would create three equal-width columns. - -To specify your sizes - for instance, Evennia's default site has three columns on desktop and -tablet, but reflows to single-column on smaller screens. Try it out! -``` -
-
-
- 1 of 4 -
-
- 2 of 4 -
-
- 3 of 4 -
-
- 4 of 4 -
-
-
-``` -This layout would be 4 columns on large screens, 2 columns on medium screens, and 1 column on -anything smaller. - -To learn more about Bootstrap's grid, please [take a look at the -docs](https://getbootstrap.com/docs/4.0/layout/grid/) -*** - -## More Bootstrap -Bootstrap also provides a huge amount of utilities, as well as styling and content elements. To -learn more about them, please [read the Bootstrap docs](https://getbootstrap.com/docs/4.0/getting-started/introduction/) or read one of our other web tutorials. diff --git a/docs/0.9.5/_sources/Bootstrap-Components-and-Utilities.md.txt b/docs/0.9.5/_sources/Bootstrap-Components-and-Utilities.md.txt deleted file mode 100644 index 5e46964766..0000000000 --- a/docs/0.9.5/_sources/Bootstrap-Components-and-Utilities.md.txt +++ /dev/null @@ -1,82 +0,0 @@ -# Bootstrap Components and Utilities - -Bootstrap provides many utilities and components you can use when customizing Evennia's web -presence. We'll go over a few examples here that you might find useful. -> Please take a look at either [the basic web tutorial](./Add-a-simple-new-web-page.md) or [the web -character view tutorial](./Web-Character-View-Tutorial.md) -> to get a feel for how to add pages to Evennia's website to test these examples. - -## General Styling -Bootstrap provides base styles for your site. These can be customized through CSS, but the default -styles are intended to provide a consistent, clean look for sites. - -### Color -Most elements can be styled with default colors. [Take a look at the -documentation](https://getbootstrap.com/docs/4.0/utilities/colors/) to learn more about these colors -- suffice to say, adding a class of text-* or bg-*, for instance, text-primary, sets the text color -or background color. - -### Borders -Simply adding a class of 'border' to an element adds a border to the element. For more in-depth -info, please [read the documentation on -borders.](https://getbootstrap.com/docs/4.0/utilities/borders/). -``` - -``` -You can also easily round corners just by adding a class. -``` - -``` - -### Spacing -Bootstrap provides classes to easily add responsive margin and padding. Most of the time, you might -like to add margins or padding through CSS itself - however these classes are used in the default -Evennia site. [Take a look at the docs](https://getbootstrap.com/docs/4.0/utilities/spacing/) to -learn more. - -*** -## Components - -### Buttons -[Buttons](https://getbootstrap.com/docs/4.0/components/buttons/) in Bootstrap are very easy to use - -button styling can be added to ` - - - -``` -### Cards -[Cards](https://getbootstrap.com/docs/4.0/components/card/) provide a container for other elements -that stands out from the rest of the page. The "Accounts", "Recently Connected", and "Database -Stats" on the default webpage are all in cards. Cards provide quite a bit of formatting options - -the following is a simple example, but read the documentation or look at the site's source for more. -``` -
-
-

Card title

-
Card subtitle
-

Fancy, isn't it?

- Card link -
-
-``` - -### Jumbotron -[Jumbotrons](https://getbootstrap.com/docs/4.0/components/jumbotron/) are useful for featuring an -image or tagline for your game. They can flow with the rest of your content or take up the full -width of the page - Evennia's base site uses the former. -``` -
-
-

Full Width Jumbotron

-

Look at the source of the default Evennia page for a regular Jumbotron

-
-
-``` - -### Forms -[Forms](https://getbootstrap.com/docs/4.0/components/forms/) are highly customizable with Bootstrap. -For a more in-depth look at how to use forms and their styles in your own Evennia site, please read -over [the web character gen tutorial.](./Web-Character-Generation.md) \ No newline at end of file diff --git a/docs/0.9.5/_sources/Builder-Docs.md.txt b/docs/0.9.5/_sources/Builder-Docs.md.txt deleted file mode 100644 index 9bd7a11a05..0000000000 --- a/docs/0.9.5/_sources/Builder-Docs.md.txt +++ /dev/null @@ -1,43 +0,0 @@ -# Builder Docs - -This section contains information useful to world builders. - -### Building basics - -- [Default in-game commands](evennia.commands.default) -- [Building Quick-start](./Building-Quickstart.md) -- [Giving build permissions to others](./Building-Permissions.md) -- [Adding text tags](./TextTags.md) - - [Colored text](./TextTags.md#coloured-text) - - [Clickable links](./TextTags.md#clickable-links) - - [Inline functions](./TextTags.md#inline-functions) -- [Customizing the connection screen](./Connection-Screen.md) - -### Advanced building and World building - -- [Overview of batch processors](./Batch-Processors.md) - - [Batch-command processor](./Batch-Command-Processor.md) - - [Batch-code processor](./Batch-Code-Processor.md) -- [Using the Spawner for individualizing objects](./Spawner-and-Prototypes.md) -- [Adding Zones](./Zones.md) - -### The Tutorial world - -- [Introduction and setup](./Tutorial-World-Introduction.md) - - -```{toctree} - :hidden: - - Building-Quickstart - Building-Permissions - TextTags - Connection-Screen - Batch-Processors - Batch-Command-Processor - Batch-Code-Processor - Spawner-and-Prototypes - Zones - Tutorial-World-Introduction - -``` \ No newline at end of file diff --git a/docs/0.9.5/_sources/Building-Permissions.md.txt b/docs/0.9.5/_sources/Building-Permissions.md.txt deleted file mode 100644 index 2f41d9c95b..0000000000 --- a/docs/0.9.5/_sources/Building-Permissions.md.txt +++ /dev/null @@ -1,72 +0,0 @@ -# Building Permissions - - -*OBS: This gives only a brief introduction to the access system. Locks and permissions are fully -detailed* [here](./Locks.md). - -## The super user - -There are strictly speaking two types of users in Evennia, the *super user* and everyone else. The -superuser is the first user you create, object `#1`. This is the all-powerful server-owner account. -Technically the superuser not only has access to everything, it *bypasses* the permission checks -entirely. This makes the superuser impossible to lock out, but makes it unsuitable to actually play- -test the game's locks and restrictions with (see `@quell` below). Usually there is no need to have -but one superuser. - -## Assigning permissions - -Whereas permissions can be used for anything, those put in `settings.PERMISSION_HIERARCHY` will have -a ranking relative each other as well. We refer to these types of permissions as *hierarchical -permissions*. When building locks to check these permissions, the `perm()` [lock function](./Locks.md) is -used. By default Evennia creates the following hierarchy (spelled exactly like this): - -1. **Developers** basically have the same access as superusers except that they do *not* sidestep -the Permission system. Assign only to really trusted server-admin staff since this level gives -access both to server reload/shutdown functionality as well as (and this may be more critical) gives -access to the all-powerful `@py` command that allows the execution of arbitrary Python code on the -command line. -1. **Admins** can do everything *except* affecting the server functions themselves. So an Admin -couldn't reload or shutdown the server for example. They also cannot execute arbitrary Python code -on the console or import files from the hard drive. -1. **Builders** - have all the build commands, but cannot affect other accounts or mess with the -server. -1. **Helpers** are almost like a normal *Player*, but they can also add help files to the database. -1. **Players** is the default group that new players end up in. A new player have permission to use -tells and to use and create new channels. - -A user having a certain level of permission automatically have access to locks specifying access of -a lower level. - -To assign a new permission from inside the game, you need to be able to use the `@perm` command. -This is an *Developer*-level command, but it could in principle be made lower-access since it only -allows assignments equal or lower to your current level (so you cannot use it to escalate your own -permission level). So, assuming you yourself have *Developer* access (or is superuser), you assign -a new account "Tommy" to your core staff with the command - - @perm/account Tommy = Developer - -or - - @perm *Tommy = Developer - -We use a switch or the `*name` format to make sure to put the permission on the *Account* and not on -any eventual *Character* that may also be named "Tommy". This is usually what you want since the -Account will then remain an Developer regardless of which Character they are currently controlling. -To limit permission to a per-Character level you should instead use *quelling* (see below). Normally -permissions can be any string, but for these special hierarchical permissions you can also use -plural ("Developer" and "Developers" both grant the same powers). - -## Quelling your permissions - -When developing it can be useful to check just how things would look had your permission-level been -lower. For this you can use *quelling*. Normally, when you puppet a Character you are using your -Account-level permission. So even if your Character only has *Accounts* level permissions, your -*Developer*-level Account will take precedence. With the `@quell` command you can change so that the -Character's permission takes precedence instead: - - @quell - -This will allow you to test out the game using the current Character's permission level. A developer -or builder can thus in principle maintain several test characters, all using different permission -levels. Note that you cannot escalate your permissions this way; If the Character happens to have a -*higher* permission level than the Account, the *Account's* (lower) permission will still be used. diff --git a/docs/0.9.5/_sources/Building-Quickstart.md.txt b/docs/0.9.5/_sources/Building-Quickstart.md.txt deleted file mode 100644 index 64fa277a0f..0000000000 --- a/docs/0.9.5/_sources/Building-Quickstart.md.txt +++ /dev/null @@ -1,274 +0,0 @@ -# Building Quickstart - - -The [default command](./Default-Commands.md) definitions coming with Evennia -follows a style [similar](./Using-MUX-as-a-Standard.md) to that of MUX, so the -commands should be familiar if you used any such code bases before. - -> Throughout the larger documentation you may come across commands prefixed -> with `@`. This is just an optional marker used in some places to make a -> command stand out. Evennia defaults to ignoring the use of `@` in front of -> your command (so entering `dig` is the same as entering `@dig`). - -The default commands have the following style (where `[...]` marks optional parts): - - command[/switch/switch...] [arguments ...] - -A _switch_ is a special, optional flag to the command to make it behave differently. It is always -put directly after the command name, and begins with a forward slash (`/`). The _arguments_ are one -or more inputs to the commands. It's common to use an equal sign (`=`) when assigning something to -an object. - -Below are some examples of commands you can try when logged in to the game. Use `help ` for -learning more about each command and their detailed options. - -## Stepping Down From Godhood - -If you just installed Evennia, your very first player account is called user #1, also known as the -_superuser_ or _god user_. This user is very powerful, so powerful that it will override many game -restrictions such as locks. This can be useful, but it also hides some functionality that you might -want to test. - -To temporarily step down from your superuser position you can use the `quell` command in-game: - - quell - -This will make you start using the permission of your current character's level instead of your -superuser level. If you didn't change any settings your game Character should have an _Developer_ -level permission - high as can be without bypassing locks like the superuser does. This will work -fine for the examples on this page. Use `unquell` to get back to superuser status again afterwards. - -## Creating an Object - -Basic objects can be anything -- swords, flowers and non-player characters. They are created using -the `create` command: - - create box - -This created a new 'box' (of the default object type) in your inventory. Use the command `inventory` -(or `i`) to see it. Now, 'box' is a rather short name, let's rename it and tack on a few aliases. - - name box = very large box;box;very;crate - -We now renamed the box to _very large box_ (and this is what we will see when looking at it), but we -will also recognize it by any of the other names we give - like _crate_ or simply _box_ as before. -We could have given these aliases directly after the name in the `create` command, this is true for -all creation commands - you can always tag on a list of `;`-separated aliases to the name of your -new object. If you had wanted to not change the name itself, but to only add aliases, you could have -used the `alias` command. - -We are currently carrying the box. Let's drop it (there is also a short cut to create and drop in -one go by using the `/drop` switch, for example `create/drop box`). - - drop box - -Hey presto - there it is on the ground, in all its normality. - - examine box - -This will show some technical details about the box object. For now we will ignore what this -information means. - -Try to `look` at the box to see the (default) description. - - look box - You see nothing special. - -The description you get is not very exciting. Let's add some flavor. - - describe box = This is a large and very heavy box. - -If you try the `get` command we will pick up the box. So far so good, but if we really want this to -be a large and heavy box, people should _not_ be able to run off with it that easily. To prevent -this we need to lock it down. This is done by assigning a _Lock_ to it. Make sure the box was -dropped in the room, then try this: - - lock box = get:false() - -Locks represent a rather [big topic](./Locks.md), but for now that will do what we want. This will lock -the box so noone can lift it. The exception is superusers, they override all locks and will pick it -up anyway. Make sure you are quelling your superuser powers and try to get the box now: - - > get box - You can't get that. - -Think thís default error message looks dull? The `get` command looks for an [Attribute](./Attributes.md) -named `get_err_msg` for returning a nicer error message (we just happen to know this, you would need -to peek into the -[code](https://github.com/evennia/evennia/blob/master/evennia/commands/default/general.py#L235) for -the `get` command to find out.). You set attributes using the `set` command: - - set box/get_err_msg = It's way too heavy for you to lift. - -Try to get it now and you should see a nicer error message echoed back to you. To see what this -message string is in the future, you can use 'examine.' - - examine box/get_err_msg - -Examine will return the value of attributes, including color codes. `examine here/desc` would return -the raw description of your current room (including color codes), so that you can copy-and-paste to -set its description to something else. - -You create new Commands (or modify existing ones) in Python outside the game. See the [Adding -Commands tutorial](./Adding-Command-Tutorial.md) for help with creating your first own Command. - -## Get a Personality - -[Scripts](./Scripts.md) are powerful out-of-character objects useful for many "under the hood" things. -One of their optional abilities is to do things on a timer. To try out a first script, let's put one -on ourselves. There is an example script in `evennia/contrib/tutorial_examples/bodyfunctions.py` -that is called `BodyFunctions`. To add this to us we will use the `script` command: - - script self = tutorial_examples.bodyfunctions.BodyFunctions - -(note that you don't have to give the full path as long as you are pointing to a place inside the -`contrib` directory, it's one of the places Evennia looks for Scripts). Wait a while and you will -notice yourself starting making random observations. - - script self - -This will show details about scripts on yourself (also `examine` works). You will see how long it is -until it "fires" next. Don't be alarmed if nothing happens when the countdown reaches zero - this -particular script has a randomizer to determine if it will say something or not. So you will not see -output every time it fires. - -When you are tired of your character's "insights", kill the script with - - script/stop self = tutorial_examples.bodyfunctions.BodyFunctions - -You create your own scripts in Python, outside the game; the path you give to `script` is literally -the Python path to your script file. The [Scripts](./Scripts.md) page explains more details. - -## Pushing Your Buttons - -If we get back to the box we made, there is only so much fun you can do with it at this point. It's -just a dumb generic object. If you renamed it to `stone` and changed its description noone would be -the wiser. However, with the combined use of custom [Typeclasses](./Typeclasses.md), [Scripts](./Scripts.md) -and object-based [Commands](./Commands.md), you could expand it and other items to be as unique, complex -and interactive as you want. - -Let's take an example. So far we have only created objects that use the default object typeclass -named simply `Object`. Let's create an object that is a little more interesting. Under -`evennia/contrib/tutorial_examples` there is a module `red_button.py`. It contains the enigmatic -`RedButton` typeclass. - -Let's make us one of _those_! - - create/drop button:tutorial_examples.red_button.RedButton - -We import the RedButton python class the same way you would import it in Python except Evennia makes -sure to look in`evennia/contrib/` so you don't have to write the full path every time. There you go -- one red button. - -The RedButton is an example object intended to show off a few of Evennia's features. You will find -that the [Typeclass](./Typeclasses.md) and [Commands](./Commands.md) controlling it are inside -`evennia/contrib/tutorial_examples/`. - -If you wait for a while (make sure you dropped it!) the button will blink invitingly. Why don't you -try to push it ...? Surely a big red button is meant to be pushed. You know you want to. - -## Making Yourself a House - -The main command for shaping the game world is `dig`. For example, if you are standing in Limbo you -can dig a route to your new house location like this: - - dig house = large red door;door;in,to the outside;out - -This will create a new room named 'house'. Spaces at the start/end of names and aliases are ignored -so you could put more air if you wanted. This call will directly create an exit from your current -location named 'large red door' and a corresponding exit named 'to the outside' in the house room -leading back to Limbo. We also define a few aliases to those exits, so people don't have to write -the full thing all the time. - -If you wanted to use normal compass directions (north, west, southwest etc), you could do that with -`dig` too. But Evennia also has a limited version of `dig` that helps for compass directions (and -also up/down and in/out). It's called `tunnel`: - - tunnel sw = cliff - -This will create a new room "cliff" with an exit "southwest" leading there and a path "northeast" -leading back from the cliff to your current location. - -You can create new exits from where you are using the `open` command: - - open north;n = house - -This opens an exit `north` (with an alias `n`) to the previously created room `house`. - -If you have many rooms named `house` you will get a list of matches and have to select which one you -want to link to. You can also give its database (#dbref) number, which is unique to every object. -This can be found with the `examine` command or by looking at the latest constructions with -`objects`. - -Follow the north exit to your 'house' or `teleport` to it: - - north - -or: - - teleport house - -To manually open an exit back to Limbo (if you didn't do so with the `dig` command): - - open door = limbo - -(or give limbo's dbref which is #2) - -## Reshuffling the World - -You can find things using the `find` command. Assuming you are back at `Limbo`, let's teleport the -_large box to our house_. - - > teleport box = house - very large box is leaving Limbo, heading for house. - Teleported very large box -> house. - -We can still find the box by using find: - - > find box - One Match(#1-#8): - very large box(#8) - src.objects.objects.Object - -Knowing the `#dbref` of the box (#8 in this example), you can grab the box and get it back here -without actually yourself going to `house` first: - - teleport #8 = here - -(You can usually use `here` to refer to your current location. To refer to yourself you can use -`self` or `me`). The box should now be back in Limbo with you. - -We are getting tired of the box. Let's destroy it. - - destroy box - -You can destroy many objects in one go by giving a comma-separated list of objects (or their -#dbrefs, if they are not in the same location) to the command. - -## Adding a Help Entry - -An important part of building is keeping the help files updated. You can add, delete and append to -existing help entries using the `sethelp` command. - - sethelp/add MyTopic = This help topic is about ... - -## Adding a World - -After this brief introduction to building you may be ready to see a more fleshed-out example. -Evennia comes with a tutorial world for you to explore. - -First you need to switch back to _superuser_ by using the `unquell` command. Next, place yourself in -`Limbo` and run the following command: - - batchcommand tutorial_world.build - -This will take a while (be patient and don't re-run the command). You will see all the commands used -to build the world scroll by as the world is built for you. - -You will end up with a new exit from Limbo named _tutorial_. Apart from being a little solo- -adventure in its own right, the tutorial world is a good source for learning Evennia building (and -coding). - -Read [the batch -file](https://github.com/evennia/evennia/blob/master/evennia/contrib/tutorial_world/build.ev) to see -exactly how it's built, step by step. See also more info about the tutorial world [here](Tutorial- -World-Introduction). diff --git a/docs/0.9.5/_sources/Building-a-mech-tutorial.md.txt b/docs/0.9.5/_sources/Building-a-mech-tutorial.md.txt deleted file mode 100644 index 9d14bcbfc3..0000000000 --- a/docs/0.9.5/_sources/Building-a-mech-tutorial.md.txt +++ /dev/null @@ -1,236 +0,0 @@ -# Building a mech tutorial - -> This page was adapted from the article "Building a Giant Mech in Evennia" by Griatch, published in -Imaginary Realities Volume 6, issue 1, 2014. The original article is no longer available online, -this is a version adopted to be compatible with the latest Evennia. - -## Creating the Mech - -Let us create a functioning giant mech using the Python MUD-creation system Evennia. Everyone likes -a giant mech, right? Start in-game as a character with build privileges (or the superuser). - - @create/drop Giant Mech ; mech - -Boom. We created a Giant Mech Object and dropped it in the room. We also gave it an alias *mech*. -Let’s describe it. - - @desc mech = This is a huge mech. It has missiles and stuff. - -Next we define who can “puppet” the mech object. - - @lock mech = puppet:all() - -This makes it so that everyone can control the mech. More mechs to the people! (Note that whereas -Evennia’s default commands may look vaguely MUX-like, you can change the syntax to look like -whatever interface style you prefer.) - -Before we continue, let’s make a brief detour. Evennia is very flexible about its objects and even -more flexible about using and adding commands to those objects. Here are some ground rules well -worth remembering for the remainder of this article: - -- The [Account](./Accounts.md) represents the real person logging in and has no game-world existence. -- Any [Object](./Objects.md) can be puppeted by an Account (with proper permissions). -- [Characters](./Objects.md#characters), [Rooms](./Objects.md#rooms), and [Exits](./Objects.md#exits) are just -children of normal Objects. -- Any Object can be inside another (except if it creates a loop). -- Any Object can store custom sets of commands on it. Those commands can: - - be made available to the puppeteer (Account), - - be made available to anyone in the same location as the Object, and - - be made available to anyone “inside” the Object - - Also Accounts can store commands on themselves. Account commands are always available unless -commands on a puppeted Object explicitly override them. - -In Evennia, using the `@ic` command will allow you to puppet a given Object (assuming you have -puppet-access to do so). As mentioned above, the bog-standard Character class is in fact like any -Object: it is auto-puppeted when logging in and just has a command set on it containing the normal -in-game commands, like look, inventory, get and so on. - - @ic mech - -You just jumped out of your Character and *are* now the mech! If people look at you in-game, they -will look at a mech. The problem at this point is that the mech Object has no commands of its own. -The usual things like look, inventory and get sat on the Character object, remember? So at the -moment the mech is not quite as cool as it could be. - - @ic - -You just jumped back to puppeting your normal, mundane Character again. All is well. - -> (But, you ask, where did that `@ic` command come from, if the mech had no commands on it? The -answer is that it came from the Account's command set. This is important. Without the Account being -the one with the `@ic` command, we would not have been able to get back out of our mech again.) - - -### Arming the Mech - -Let us make the mech a little more interesting. In our favorite text editor, we will create some new -mech-suitable commands. In Evennia, commands are defined as Python classes. - -```python -# in a new file mygame/commands/mechcommands.py - -from evennia import Command - -class CmdShoot(Command): - """ - Firing the mech’s gun - - Usage: - shoot [target] - - This will fire your mech’s main gun. If no - target is given, you will shoot in the air. - """ - key = "shoot" - aliases = ["fire", "fire!"] - - def func(self): - "This actually does the shooting" - - caller = self.caller - location = caller.location - - if not self.args: - # no argument given to command - shoot in the air - message = "BOOM! The mech fires its gun in the air!" - location.msg_contents(message) - return - - # we have an argument, search for target - target = caller.search(self.args.strip()) - if target: - message = "BOOM! The mech fires its gun at %s" % target.key - location.msg_contents(message) - -class CmdLaunch(Command): - # make your own 'launch'-command here as an exercise! - # (it's very similar to the 'shoot' command above). - -``` - -This is saved as a normal Python module (let’s call it `mechcommands.py`), in a place Evennia looks -for such modules (`mygame/commands/`). This command will trigger when the player gives the command -“shoot”, “fire,” or even “fire!” with an exclamation mark. The mech can shoot in the air or at a -target if you give one. In a real game the gun would probably be given a chance to hit and give -damage to the target, but this is enough for now. - -We also make a second command for launching missiles (`CmdLaunch`). To save -space we won’t describe it here; it looks the same except it returns a text -about the missiles being fired and has different `key` and `aliases`. We leave -that up to you to create as an exercise. You could have it print "WOOSH! The -mech launches missiles against !", for example. - -Now we shove our commands into a command set. A [Command Set](./Command-Sets.md) (CmdSet) is a container -holding any number of commands. The command set is what we will store on the mech. - -```python -# in the same file mygame/commands/mechcommands.py - -from evennia import CmdSet -from evennia import default_cmds - -class MechCmdSet(CmdSet): - """ - This allows mechs to do do mech stuff. - """ - key = "mechcmdset" - - def at_cmdset_creation(self): - "Called once, when cmdset is first created" - self.add(CmdShoot()) - self.add(CmdLaunch()) -``` - -This simply groups all the commands we want. We add our new shoot/launch commands. Let’s head back -into the game. For testing we will manually attach our new CmdSet to the mech. - - @py self.search("mech").cmdset.add("commands.mechcommands.MechCmdSet") - -This is a little Python snippet (run from the command line as an admin) that searches for the mech -in our current location and attaches our new MechCmdSet to it. What we add is actually the Python -path to our cmdset class. Evennia will import and initialize it behind the scenes. - - @ic mech - -We are back as the mech! Let’s do some shooting! - - fire! - BOOM! The mech fires its gun in the air! - -There we go, one functioning mech. Try your own `launch` command and see that it works too. We can -not only walk around as the mech — since the CharacterCmdSet is included in our MechCmdSet, the mech -can also do everything a Character could do, like look around, pick up stuff, and have an inventory. -We could now shoot the gun at a target or try the missile launch command. Once you have your own -mech, what else do you need? - -> Note: You'll find that the mech's commands are available to you by just standing in the same -location (not just by puppeting it). We'll solve this with a *lock* in the next section. - -## Making a Mech production line - -What we’ve done so far is just to make a normal Object, describe it and put some commands on it. -This is great for testing. The way we added it, the MechCmdSet will even go away if we reload the -server. Now we want to make the mech an actual object “type” so we can create mechs without those -extra steps. For this we need to create a new Typeclass. - -A [Typeclass](./Typeclasses.md) is a near-normal Python class that stores its existence to the database -behind the scenes. A Typeclass is created in a normal Python source file: - -```python -# in the new file mygame/typeclasses/mech.py - -from typeclasses.objects import Object -from commands.mechcommands import MechCmdSet -from evennia import default_cmds - -class Mech(Object): - """ - This typeclass describes an armed Mech. - """ - def at_object_creation(self): - "This is called only when object is first created" - self.cmdset.add_default(default_cmds.CharacterCmdSet) - self.cmdset.add(MechCmdSet, permanent=True) - self.locks.add("puppet:all();call:false()") - self.db.desc = "This is a huge mech. It has missiles and stuff." -``` - -For convenience we include the full contents of the default `CharacterCmdSet` in there. This will -make a Character’s normal commands available to the mech. We also add the mech-commands from before, -making sure they are stored persistently in the database. The locks specify that anyone can puppet -the meck and no-one can "call" the mech's Commands from 'outside' it - you have to puppet it to be -able to shoot. - -That’s it. When Objects of this type are created, they will always start out with the mech’s command -set and the correct lock. We set a default description, but you would probably change this with -`@desc` to individualize your mechs as you build them. - -Back in the game, just exit the old mech (`@ic` back to your old character) then do - - @create/drop The Bigger Mech ; bigmech : mech.Mech - -We create a new, bigger mech with an alias bigmech. Note how we give the python-path to our -Typeclass at the end — this tells Evennia to create the new object based on that class (we don't -have to give the full path in our game dir `typeclasses.mech.Mech` because Evennia knows to look in -the `typeclasses` folder already). A shining new mech will appear in the room! Just use - - @ic bigmech - -to take it on a test drive. - -## Future Mechs - -To expand on this you could add more commands to the mech and remove others. Maybe the mech -shouldn’t work just like a Character after all. Maybe it makes loud noises every time it passes from -room to room. Maybe it cannot pick up things without crushing them. Maybe it needs fuel, ammo and -repairs. Maybe you’ll lock it down so it can only be puppeted by emo teenagers. - -Having you puppet the mech-object directly is also just one way to implement a giant mech in -Evennia. - -For example, you could instead picture a mech as a “vehicle” that you “enter” as your normal -Character (since any Object can move inside another). In that case the “insides” of the mech Object -could be the “cockpit”. The cockpit would have the `MechCommandSet` stored on itself and all the -shooting goodness would be made available to you only when you enter it. - -And of course you could put more guns on it. And make it fly. diff --git a/docs/0.9.5/_sources/Building-menus.md.txt b/docs/0.9.5/_sources/Building-menus.md.txt deleted file mode 100644 index 4389a44695..0000000000 --- a/docs/0.9.5/_sources/Building-menus.md.txt +++ /dev/null @@ -1,1233 +0,0 @@ -# Building menus - - -# The building_menu contrib - -This contrib allows you to write custom and easy to use building menus. As the name implies, these -menus are most useful for building things, that is, your builders might appreciate them, although -you can use them for your players as well. - -Building menus are somewhat similar to `EvMenu` although they don't use the same system at all and -are intended to make building easier. They replicate what other engines refer to as "building -editors", which allow to you to build in a menu instead of having to enter a lot of complex -commands. Builders might appreciate this simplicity, and if the code that was used to create them -is simple as well, coders could find this contrib useful. - -## A simple menu - -Before diving in, there are some things to point out: - -- Building menus work on an object. This object will be edited by manipulations in the menu. So -you can create a menu to add/edit a room, an exit, a character and so on. -- Building menus are arranged in layers of choices. A choice gives access to an option or to a sub- -menu. Choices are linked to commands (usually very short). For instance, in the example shown -below, to edit the room key, after opening the building menu, you can type `k`. That will lead you -to the key choice where you can enter a new key for the room. Then you can enter `@` to leave this -choice and go back to the entire menu. (All of this can be changed). -- To open the menu, you will need something like a command. This contrib offers a basic command for -demonstration, but we will override it in this example, using the same code with more flexibility. - -So let's add a very basic example to begin with. - -### A generic editing command - -Let's begin by adding a new command. You could add or edit the following file (there's no trick -here, feel free to organize the code differently): - -```python -# file: commands/building.py -from evennia.contrib.building_menu import BuildingMenu -from commands.command import Command - -class EditCmd(Command): - - """ - Editing command. - - Usage: - @edit [object] - - Open a building menu to edit the specified object. This menu allows to - specific information about this object. - - Examples: - @edit here - @edit self - @edit #142 - - """ - - key = "@edit" - locks = "cmd:id(1) or perm(Builders)" - help_category = "Building" - - def func(self): - if not self.args.strip(): - self.msg("|rYou should provide an argument to this function: the object to edit.|n") - return - - obj = self.caller.search(self.args.strip(), global_search=True) - if not obj: - return - - if obj.typename == "Room": - Menu = RoomBuildingMenu - else: - self.msg("|rThe object {} cannot be -edited.|n".format(obj.get_display_name(self.caller))) - return - - menu = Menu(self.caller, obj) - menu.open() -``` - -This command is rather simple in itself: - -1. It has a key `@edit` and a lock to only allow builders to use it. -2. In its `func` method, it begins by checking the arguments, returning an error if no argument is -specified. -3. It then searches for the given argument. We search globally. The `search` method used in this -way will return the found object or `None`. It will also send the error message to the caller if -necessary. -4. Assuming we have found an object, we check the object `typename`. This will be used later when -we want to display several building menus. For the time being, we only handle `Room`. If the -caller specified something else, we'll display an error. -5. Assuming this object is a `Room`, we have defined a `Menu` object containing the class of our -building menu. We build this class (creating an instance), giving it the caller and the object to -edit. -6. We then open the building menu, using the `open` method. - -The end might sound a bit surprising at first glance. But the process is still very simple: we -create an instance of our building menu and call its `open` method. Nothing more. - -> Where is our building menu? - -If you go ahead and add this command and test it, you'll get an error. We haven't defined -`RoomBuildingMenu` yet. - -To add this command, edit `commands/default_cmdsets.py`. Import our command, adding an import line -at the top of the file: - -```python -""" -... -""" - -from evennia import default_cmds - -# The following line is to be added -from commands.building import EditCmd -``` - -And in the class below (`CharacterCmdSet`), add the last line of this code: - -```python -class CharacterCmdSet(default_cmds.CharacterCmdSet): - """ - The `CharacterCmdSet` contains general in-game commands like `look`, - `get`, etc available on in-game Character objects. It is merged with - the `AccountCmdSet` when an Account puppets a Character. - """ - key = "DefaultCharacter" - - def at_cmdset_creation(self): - """ - Populates the cmdset - """ - super().at_cmdset_creation() - # - # any commands you add below will overload the default ones. - # - self.add(EditCmd()) -``` - -### Our first menu - -So far, we can't use our building menu. Our `@edit` command will throw an error. We have to define -the `RoomBuildingMenu` class. Open the `commands/building.py` file and add to the end of the file: - -```python -# ... at the end of commands/building.py -# Our building menu - -class RoomBuildingMenu(BuildingMenu): - - """ - Building menu to edit a room. - - For the time being, we have only one choice: key, to edit the room key. - - """ - - def init(self, room): - self.add_choice("key", "k", attr="key") -``` - -Save these changes, reload your game. You can now use the `@edit` command. Here's what we get -(notice that the commands we enter into the game are prefixed with `> `, though this prefix will -probably not appear in your MUD client): - -``` -> look -Limbo(#2) -Welcome to your new Evennia-based game! Visit http://www.evennia.com if you need -help, want to contribute, report issues or just join the community. -As Account #1 you can create a demo/tutorial area with @batchcommand tutorial_world.build. - -> @edit here -Building menu: Limbo - - [K]ey: Limbo - [Q]uit the menu - -> q -Closing the building menu. - -> @edit here -Building menu: Limbo - - [K]ey: Limbo - [Q]uit the menu - -> k -------------------------------------------------------------------------------- -key for Limbo(#2) - -You can change this value simply by entering it. - -Use @ to go back to the main menu. - -Current value: Limbo - -> A beautiful meadow -------------------------------------------------------------------------------- - -key for A beautiful meadow(#2) - -You can change this value simply by entering it. - -Use @ to go back to the main menu. - -Current value: A beautiful meadow - -> @ -Building menu: A beautiful meadow - - [K]ey: A beautiful meadow - [Q]uit the menu - -> q - -Closing the building menu. - -> look -A beautiful meadow(#2) -Welcome to your new Evennia-based game! Visit http://www.evennia.com if you need -help, want to contribute, report issues or just join the community. -As Account #1 you can create a demo/tutorial area with @batchcommand tutorial_world.build. -``` - -Before diving into the code, let's examine what we have: - -- When we use the `@edit here` command, a building menu for this room appears. -- This menu has two choices: - - Enter `k` to edit the room key. You will go into a choice where you can simply type the key -room key (the way we have done here). You can use `@` to go back to the menu. - - You can use `q` to quit the menu. - -We then check, with the `look` command, that the menu has modified this room key. So by adding a -class, with a method and a single line of code within, we've added a menu with two choices. - -### Code explanation - -Let's examine our code again: - -```python -class RoomBuildingMenu(BuildingMenu): - - """ - Building menu to edit a room. - - For the time being, we have only one choice: key, to edit the room key. - - """ - - def init(self, room): - self.add_choice("key", "k", attr="key") -``` - -- We first create a class inheriting from `BuildingMenu`. This is usually the case when we want to -create a building menu with this contrib. -- In this class, we override the `init` method, which is called when the menu opens. -- In this `init` method, we call `add_choice`. This takes several arguments, but we've defined only -three here: - - The choice name. This is mandatory and will be used by the building menu to know how to -display this choice. - - The command key to access this choice. We've given a simple `"k"`. Menu commands usually are -pretty short (that's part of the reason building menus are appreciated by builders). You can also -specify additional aliases, but we'll see that later. - - We've added a keyword argument, `attr`. This tells the building menu that when we are in this -choice, the text we enter goes into this attribute name. It's called `attr`, but it could be a room -attribute or a typeclass persistent or non-persistent attribute (we'll see other examples as well). - -> We've added the menu choice for `key` here, why is another menu choice defined for `quit`? - -Our building menu creates a choice at the end of our choice list if it's a top-level menu (sub-menus -don't have this feature). You can, however, override it to provide a different "quit" message or to -perform some actions. - -I encourage you to play with this code. As simple as it is, it offers some functionalities already. - -## Customizing building menus - -This somewhat long section explains how to customize building menus. There are different ways -depending on what you would like to achieve. We'll go from specific to more advanced here. - -### Generic choices - -In the previous example, we've used `add_choice`. This is one of three methods you can use to add -choices. The other two are to handle more generic actions: - -- `add_choice_edit`: this is called to add a choice which points to the `EvEditor`. It is used to -edit a description in most cases, although you could edit other things. We'll see an example -shortly. `add_choice_edit` uses most of the `add_choice` keyword arguments we'll see, but usually -we specify only two (sometimes three): - - The choice title as usual. - - The choice key (command key) as usual. - - Optionally, the attribute of the object to edit, with the `attr` keyword argument. By -default, `attr` contains `db.desc`. It means that this persistent data attribute will be edited by -the `EvEditor`. You can change that to whatever you want though. -- `add_choice_quit`: this allows to add a choice to quit the editor. Most advisable! If you don't -do it, the building menu will do it automatically, except if you really tell it not to. Again, you -can specify the title and key of this menu. You can also call a function when this menu closes. - -So here's a more complete example (you can replace your `RoomBuildingMenu` class in -`commands/building.py` to see it): - -```python -class RoomBuildingMenu(BuildingMenu): - - """ - Building menu to edit a room. - """ - - def init(self, room): - self.add_choice("key", "k", attr="key") - self.add_choice_edit("description", "d") - self.add_choice_quit("quit this editor", "q") -``` - -So far, our building menu class is still thin... and yet we already have some interesting feature. -See for yourself the following MUD client output (again, the commands are prefixed with `> ` to -distinguish them): - -``` -> @reload - -> @edit here -Building menu: A beautiful meadow - - [K]ey: A beautiful meadow - [D]escription: - Welcome to your new Evennia-based game! Visit http://www.evennia.com if you need -help, want to contribute, report issues or just join the community. -As Account #1 you can create a demo/tutorial area with @batchcommand tutorial_world.build. - [Q]uit this editor - -> d - -----------Line Editor [editor]---------------------------------------------------- -01| Welcome to your new |wEvennia|n-based game! Visit http://www.evennia.com if you need -02| help, want to contribute, report issues or just join the community. -03| As Account #1 you can create a demo/tutorial area with |w@batchcommand tutorial_world.build|n. - -> :DD - -----------[l:03 w:034 c:0247]------------(:h for help)---------------------------- -Cleared 3 lines from buffer. - -> This is a beautiful meadow. But so beautiful I can't describe it. - -01| This is a beautiful meadow. But so beautiful I can't describe it. - -> :wq -Building menu: A beautiful meadow - - [K]ey: A beautiful meadow - [D]escription: - This is a beautiful meadow. But so beautiful I can't describe it. - [Q]uit this editor - -> q -Closing the building menu. - -> look -A beautiful meadow(#2) -This is a beautiful meadow. But so beautiful I can't describe it. -``` - -So by using the `d` shortcut in our building menu, an `EvEditor` opens. You can use the `EvEditor` -commands (like we did here, `:DD` to remove all, `:wq` to save and quit). When you quit the editor, -the description is saved (here, in `room.db.desc`) and you go back to the building menu. - -Notice that the choice to quit has changed too, which is due to our adding `add_choice_quit`. In -most cases, you will probably not use this method, since the quit menu is added automatically. - -### `add_choice` options - -`add_choice` and the two methods `add_choice_edit` and `add_choice_quit` take a lot of optional -arguments to make customization easier. Some of these options might not apply to `add_choice_edit` -or `add_choice_quit` however. - -Below are the options of `add_choice`, specify them as arguments: - -- The first positional, mandatory argument is the choice title, as we have seen. This will -influence how the choice appears in the menu. -- The second positional, mandatory argument is the command key to access to this menu. It is best -to use keyword arguments for the other arguments. -- The `aliases` keyword argument can contain a list of aliases that can be used to access to this -menu. For instance: `add_choice(..., aliases=['t'])` -- The `attr` keyword argument contains the attribute to edit when this choice is selected. It's a -string, it has to be the name, from the object (specified in the menu constructor) to reach this -attribute. For instance, a `attr` of `"key"` will try to find `obj.key` to read and write the -attribute. You can specify more complex attribute names, for instance, `attr="db.desc"` to set the -`desc` persistent attribute, or `attr="ndb.something"` so use a non-persistent data attribute on the -object. -- The `text` keyword argument is used to change the text that will be displayed when the menu choice -is selected. Menu choices provide a default text that you can change. Since this is a long text, -it's useful to use multi-line strings (see an example below). -- The `glance` keyword argument is used to specify how to display the current information while in -the menu, when the choice hasn't been opened. If you examine the previous examples, you will see -that the current (`key` or `db.desc`) was shown in the menu, next to the command key. This is -useful for seeing at a glance the current value (hence the name). Again, menu choices will provide -a default glance if you don't specify one. -- The `on_enter` keyword argument allows to add a callback to use when the menu choice is opened. -This is more advanced, but sometimes useful. -- The `on_nomatch` keyword argument is called when, once in the menu, the caller enters some text -that doesn't match any command (including the `@` command). By default, this will edit the -specified `attr`. -- The `on_leave` keyword argument allows to specify a callback used when the caller leaves the menu -choice. This can be useful for cleanup as well. - -These are a lot of possibilities, and most of the time you won't need them all. Here is a short -example using some of these arguments (again, replace the `RoomBuildingMenu` class in -`commands/building.py` with the following code to see it working): - -```python -class RoomBuildingMenu(BuildingMenu): - - """ - Building menu to edit a room. - - For the time being, we have only one choice: key, to edit the room key. - - """ - - def init(self, room): - self.add_choice("title", key="t", attr="key", glance="{obj.key}", text=""" - ------------------------------------------------------------------------------- - Editing the title of {{obj.key}}(#{{obj.id}}) - - You can change the title simply by entering it. - Use |y{back}|n to go back to the main menu. - - Current title: |c{{obj.key}}|n - """.format(back="|n or |y".join(self.keys_go_back))) - self.add_choice_edit("description", "d") -``` - -Reload your game and see it in action: - -``` -> @edit here -Building menu: A beautiful meadow - - [T]itle: A beautiful meadow - [D]escription: - This is a beautiful meadow. But so beautiful I can't describe it. - [Q]uit the menu - -> t -------------------------------------------------------------------------------- - -Editing the title of A beautiful meadow(#2) - -You can change the title simply by entering it. -Use @ to go back to the main menu. - -Current title: A beautiful meadow - -> @ - -Building menu: A beautiful meadow - - [T]itle: A beautiful meadow - [D]escription: - This is a beautiful meadow. But so beautiful I can't describe it. - [Q]uit the menu - -> q -Closing the building menu. -``` - -The most surprising part is no doubt the text. We use the multi-line syntax (with `"""`). -Excessive spaces will be removed from the left for each line automatically. We specify some -information between braces... sometimes using double braces. What might be a bit odd: - -- `{back}` is a direct format argument we'll use (see the `.format` specifiers). -- `{{obj...}} refers to the object being edited. We use two braces, because `.format` will remove -them. - -In `glance`, we also use `{obj.key}` to indicate we want to show the room's key. - -### Everything can be a function - -The keyword arguments of `add_choice` are often strings (type `str`). But each of these arguments -can also be a function. This allows for a lot of customization, since we define the callbacks that -will be executed to achieve such and such an operation. - -To demonstrate, we will try to add a new feature. Our building menu for rooms isn't that bad, but -it would be great to be able to edit exits too. So we can add a new menu choice below -description... but how to actually edit exits? Exits are not just an attribute to set: exits are -objects (of type `Exit` by default) which stands between two rooms (object of type `Room`). So how -can we show that? - -First let's add a couple of exits in limbo, so we have something to work with: - -``` -@tunnel n -@tunnel s -``` - -This should create two new rooms, exits leading to them from limbo and back to limbo. - -``` -> look -A beautiful meadow(#2) -This is a beautiful meadow. But so beautiful I can't describe it. -Exits: north(#4) and south(#7) -``` - -We can access room exits with the `exits` property: - -``` -> @py here.exits -[, ] -``` - -So what we need is to display this list in our building menu... and to allow to edit it would be -great. Perhaps even add new exits? - -First of all, let's write a function to display the `glance` on existing exits. Here's the code, -it's explained below: - -```python -class RoomBuildingMenu(BuildingMenu): - - """ - Building menu to edit a room. - - """ - - def init(self, room): - self.add_choice("title", key="t", attr="key", glance="{obj.key}", text=""" - ------------------------------------------------------------------------------- - Editing the title of {{obj.key}}(#{{obj.id}}) - - You can change the title simply by entering it. - Use |y{back}|n to go back to the main menu. - - Current title: |c{{obj.key}}|n - """.format(back="|n or |y".join(self.keys_go_back))) - self.add_choice_edit("description", "d") - self.add_choice("exits", "e", glance=glance_exits, attr="exits") - - -# Menu functions -def glance_exits(room): - """Show the room exits.""" - if room.exits: - glance = "" - for exit in room.exits: - glance += "\n |y{exit}|n".format(exit=exit.key) - - return glance - - return "\n |gNo exit yet|n" -``` - -When the building menu opens, it displays each choice to the caller. A choice is displayed with its -title (rendered a bit nicely to show the key as well) and the glance. In the case of the `exits` -choice, the glance is a function, so the building menu calls this function giving it the object -being edited (the room here). The function should return the text to see. - -``` -> @edit here -Building menu: A beautiful meadow - - [T]itle: A beautiful meadow - [D]escription: - This is a beautiful meadow. But so beautiful I can't describe it. - [E]xits: - north - south - [Q]uit the menu - -> q -Closing the editor. -``` - -> How do I know the parameters of the function to give? - -The function you give can accept a lot of different parameters. This allows for a flexible approach -but might seem complicated at first. Basically, your function can accept any parameter, and the -building menu will send only the parameter based on their names. If your function defines an -argument named `caller` for instance (like `def func(caller):` ), then the building menu knows that -the first argument should contain the caller of the building menu. Here are the arguments, you -don't have to specify them (if you do, they need to have the same name): - -- `menu`: if your function defines an argument named `menu`, it will contain the building menu -itself. -- `choice`: if your function defines an argument named `choice`, it will contain the `Choice` object -representing this menu choice. -- `string`: if your function defines an argument named `string`, it will contain the user input to -reach this menu choice. This is not very useful, except on `nomatch` callbacks which we'll see -later. -- `obj`: if your function defines an argument named `obj`, it will contain the building menu edited -object. -- `caller`: if your function defines an argument named `caller`, it will contain the caller of the -building menu. -- Anything else: any other argument will contain the object being edited by the building menu. - -So in our case: - -```python -def glance_exits(room): -``` - -The only argument we need is `room`. It's not present in the list of possible arguments, so the -editing object of the building menu (the room, here) is given. - -> Why is it useful to get the menu or choice object? - -Most of the time, you will not need these arguments. In very rare cases, you will use them to get -specific data (like the default attribute that was set). This tutorial will not elaborate on these -possibilities. Just know that they exist. - -We should also define a text callback, so that we can enter our menu to see the room exits. We'll -see how to edit them in the next section but this is a good opportunity to show a more complete -callback. To see it in action, as usual, replace the class and functions in `commands/building.py`: - -```python -# Our building menu - -class RoomBuildingMenu(BuildingMenu): - - """ - Building menu to edit a room. - - """ - - def init(self, room): - self.add_choice("title", key="t", attr="key", glance="{obj.key}", text=""" - ------------------------------------------------------------------------------- - Editing the title of {{obj.key}}(#{{obj.id}}) - - You can change the title simply by entering it. - Use |y{back}|n to go back to the main menu. - - Current title: |c{{obj.key}}|n - """.format(back="|n or |y".join(self.keys_go_back))) - self.add_choice_edit("description", "d") - self.add_choice("exits", "e", glance=glance_exits, attr="exits", text=text_exits) - - -# Menu functions -def glance_exits(room): - """Show the room exits.""" - if room.exits: - glance = "" - for exit in room.exits: - glance += "\n |y{exit}|n".format(exit=exit.key) - - return glance - - return "\n |gNo exit yet|n" - -def text_exits(caller, room): - """Show the room exits in the choice itself.""" - text = "-" * 79 - text += "\n\nRoom exits:" - text += "\n Use |y@c|n to create a new exit." - text += "\n\nExisting exits:" - if room.exits: - for exit in room.exits: - text += "\n |y@e {exit}|n".format(exit=exit.key) - if exit.aliases.all(): - text += " (|y{aliases}|n)".format(aliases="|n, |y".join( - alias for alias in exit.aliases.all())) - if exit.destination: - text += " toward {destination}".format(destination=exit.get_display_name(caller)) - else: - text += "\n\n |gNo exit has yet been defined.|n" - - return text -``` - -Look at the second callback in particular. It takes an additional argument, the caller (remember, -the argument names are important, their order is not relevant). This is useful for displaying -destination of exits accurately. Here is a demonstration of this menu: - -``` -> @edit here -Building menu: A beautiful meadow - - [T]itle: A beautiful meadow - [D]escription: - This is a beautiful meadow. But so beautiful I can't describe it. - [E]xits: - north - south - [Q]uit the menu - -> e -------------------------------------------------------------------------------- - -Room exits: - Use @c to create a new exit. - -Existing exits: - @e north (n) toward north(#4) - @e south (s) toward south(#7) - -> @ -Building menu: A beautiful meadow - - [T]itle: A beautiful meadow - [D]escription: - This is a beautiful meadow. But so beautiful I can't describe it. - [E]xits: - north - south - [Q]uit the menu - -> q -Closing the building menu. -``` - -Using callbacks allows a great flexibility. We'll now see how to handle sub-menus. - -### Sub-menus for complex menus - -A menu is relatively flat: it has a root (where you see all the menu choices) and individual choices -you can go to using the menu choice keys. Once in a choice you can type some input or go back to -the root menu by entering the return command (usually `@`). - -Why shouldn't individual exits have their own menu though? Say, you edit an exit and can change its -key, description or aliases... perhaps even destination? Why ever not? It would make building much -easier! - -The building menu system offers two ways to do that. The first is nested keys: nested keys allow to -go beyond just one menu/choice, to have menus with more layers. Using them is quick but might feel -a bit counter-intuitive at first. Another option is to create a different menu class and redirect -from the first to the second. This option might require more lines but is more explicit and can be -re-used for multiple menus. Adopt one of them depending of your taste. - -#### Nested menu keys - -So far, we've only used menu keys with one letter. We can add more, of course, but menu keys in -their simple shape are just command keys. Press "e" to go to the "exits" choice. - -But menu keys can be nested. Nested keys allow to add choices with sub-menus. For instance, type -"e" to go to the "exits" choice, and then you can type "c" to open a menu to create a new exit, or -"d" to open a menu to delete an exit. The first menu would have the "e.c" key (first e, then c), -the second menu would have key as "e.d". - -That's more advanced and, if the following code doesn't sound very friendly to you, try the next -section which provides a different approach of the same problem. - -So we would like to edit exits. That is, you can type "e" to go into the choice of exits, then -enter `@e` followed by the exit name to edit it... which will open another menu. In this sub-menu -you could change the exit key or description. - -So we have a menu hierarchy similar to that: - -``` -t Change the room title -d Change the room description -e Access the room exits - [exit name] Access the exit name sub-menu - [text] Change the exit key -``` - -Or, if you prefer an example output: - -``` -> look -A beautiful meadow(#2) -This is a beautiful meadow. But so beautiful I can't describe it. -Exits: north(#4) and south(#7) - -> @edit here -Building menu: A beautiful meadow - - [T]itle: A beautiful meadow - [D]escription: - This is a beautiful meadow. But so beautiful I can't describe it. - [E]xits: - north - south - [Q]uit the menu - -> e -------------------------------------------------------------------------------- - -Room exits : - Use @c to create a new exit. - -Existing exits: - @e north (n) toward north(#4) - @e south (s) toward south(#7) - -> @e north -Editing: north -Exit north: -Enter the exit key to change it, or @ to go back. - -New exit key: - -> door - -Exit door: -Enter the exit key to change it, or @ to go back. - -New exit key: - -> @ - -------------------------------------------------------------------------------- - -Room exits : - Use @c to create a new exit. - -Existing exits: - @e door (n) toward door(#4) - @e south (s) toward south(#7) - -> @ -Building menu: A beautiful meadow - - [T]itle: A beautiful meadow - [D]escription: - This is a beautiful meadow. But so beautiful I can't describe it. - [E]xits: - door - south - [Q]uit the menu - -> q -Closing the building menu. -``` - -This needs a bit of code and a bit of explanation. So here we go... the code first, the -explanations next! - -```python -# ... from commands/building.py -# Our building menu - -class RoomBuildingMenu(BuildingMenu): - - """ - Building menu to edit a room. - - For the time being, we have only one choice: key, to edit the room key. - - """ - - def init(self, room): - self.add_choice("title", key="t", attr="key", glance="{obj.key}", text=""" - ------------------------------------------------------------------------------- - Editing the title of {{obj.key}}(#{{obj.id}}) - - You can change the title simply by entering it. - Use |y{back}|n to go back to the main menu. - - Current title: |c{{obj.key}}|n - """.format(back="|n or |y".join(self.keys_go_back))) - self.add_choice_edit("description", "d") - self.add_choice("exits", "e", glance=glance_exits, text=text_exits, -on_nomatch=nomatch_exits) - - # Exit sub-menu - self.add_choice("exit", "e.*", text=text_single_exit, on_nomatch=nomatch_single_exit) - - - -# Menu functions -def glance_exits(room): - """Show the room exits.""" - if room.exits: - glance = "" - for exit in room.exits: - glance += "\n |y{exit}|n".format(exit=exit.key) - - return glance - - return "\n |gNo exit yet|n" - -def text_exits(caller, room): - """Show the room exits in the choice itself.""" - text = "-" * 79 - text += "\n\nRoom exits:" - text += "\n Use |y@c|n to create a new exit." - text += "\n\nExisting exits:" - if room.exits: - for exit in room.exits: - text += "\n |y@e {exit}|n".format(exit=exit.key) - if exit.aliases.all(): - text += " (|y{aliases}|n)".format(aliases="|n, |y".join( - alias for alias in exit.aliases.all())) - if exit.destination: - text += " toward {destination}".format(destination=exit.get_display_name(caller)) - else: - text += "\n\n |gNo exit has yet been defined.|n" - - return text - -def nomatch_exits(menu, caller, room, string): - """ - The user typed something in the list of exits. Maybe an exit name? - """ - string = string[3:] - exit = caller.search(string, candidates=room.exits) - if exit is None: - return - - # Open a sub-menu, using nested keys - caller.msg("Editing: {}".format(exit.key)) - menu.move(exit) - return False - -# Exit sub-menu -def text_single_exit(menu, caller): - """Show the text to edit single exits.""" - exit = menu.keys[1] - if exit is None: - return "" - - return """ - Exit {exit}: - - Enter the exit key to change it, or |y@|n to go back. - - New exit key: - """.format(exit=exit.key) - -def nomatch_single_exit(menu, caller, room, string): - """The user entered something in the exit sub-menu. Replace the exit key.""" - # exit is the second key element: keys should contain ['e', ] - exit = menu.keys[1] - if exit is None: - caller.msg("|rCannot find the exit.|n") - menu.move(back=True) - return False - - exit.key = string - return True -``` - -> That's a lot of code! And we only handle editing the exit key! - -That's why at some point you might want to write a real sub-menu, instead of using simple nested -keys. But you might need both to build pretty menus too! - -1. The first thing new is in our menu class. After creating a `on_nomatch` callback for the exits -menu (that shouldn't be a surprised), we need to add a nested key. We give this menu a key of -`"e.*"`. That's a bit odd! "e" is our key to the exits menu, . is the separator to indicate a -nested menu, and * means anything. So basically, we create a nested menu that is contains within -the exits menu and anything. We'll see what this "anything" is in practice. -2. The `glance_exits` and `text_exits` are basically the same. -3. The `nomatch_exits` is short but interesting. It's called when we enter some text in the "exits" -menu (that is, in the list of exits). We have said that the user should enter `@e` followed by the -exit name to edit it. So in the `nomatch_exits` callbac, we check for that input. If the entered -text begins by `@e`, we try to find the exit in the room. If we do... -4. We call the `menu.move` method. That's where things get a bit complicated with nested menus: we -need to use `menu.move` to change from layer to layer. Here, we are in the choice of exits (the -exits menu, of key "e"). We need to go down one layer to edit an exit. So we call `menu.move` and -give it an exit object. The menu system remembers what position the user is based on the keys she -has entered: when the user opens the menu, there is no key. If she selects the exits choice, the -menu key being "e", the position of the user is `["e"]` (a list with the menu keys). If we call -`menu.move`, whatever we give to this method will be appended to the list of keys, so that the user -position becomes `["e", ]`. -5. In the menu class, we have defined the menu "e.*", meaning "the menu contained in the exits -choice plus anything". The "anything" here is an exit: we have called `menu.move(exit)`, so the -`"e.*"` menu choice is chosen. -6. In this menu, the text is set to a callback. There is also a `on_nomatch` callback that is -called whenever the user enters some text. If so, we change the exit name. - -Using `menu.move` like this is a bit confusing at first. Sometimes it's useful. In this case, if -we want a more complex menu for exits, it makes sense to use a real sub-menu, not nested keys like -this. But sometimes, you will find yourself in a situation where you don't need a full menu to -handle a choice. - -#### Full sub-menu as separate classes - -The best way to handle individual exits is to create two separate classes: - -- One for the room menu. -- One for the individual exit menu. - -The first one will have to redirect on the second. This might be more intuitive and flexible, -depending on what you want to achieve. So let's build two menus: - -```python -# Still in commands/building.py, replace the menu class and functions by... -# Our building menus - -class RoomBuildingMenu(BuildingMenu): - - """ - Building menu to edit a room. - """ - - def init(self, room): - self.add_choice("title", key="t", attr="key", glance="{obj.key}", text=""" - ------------------------------------------------------------------------------- - Editing the title of {{obj.key}}(#{{obj.id}}) - - You can change the title simply by entering it. - Use |y{back}|n to go back to the main menu. - - Current title: |c{{obj.key}}|n - """.format(back="|n or |y".join(self.keys_go_back))) - self.add_choice_edit("description", "d") - self.add_choice("exits", "e", glance=glance_exits, text=text_exits, -on_nomatch=nomatch_exits) - - -# Menu functions -def glance_exits(room): - """Show the room exits.""" - if room.exits: - glance = "" - for exit in room.exits: - glance += "\n |y{exit}|n".format(exit=exit.key) - - return glance - - return "\n |gNo exit yet|n" - -def text_exits(caller, room): - """Show the room exits in the choice itself.""" - text = "-" * 79 - text += "\n\nRoom exits:" - text += "\n Use |y@c|n to create a new exit." - text += "\n\nExisting exits:" - if room.exits: - for exit in room.exits: - text += "\n |y@e {exit}|n".format(exit=exit.key) - if exit.aliases.all(): - text += " (|y{aliases}|n)".format(aliases="|n, |y".join( - alias for alias in exit.aliases.all())) - if exit.destination: - text += " toward {destination}".format(destination=exit.get_display_name(caller)) - else: - text += "\n\n |gNo exit has yet been defined.|n" - - return text - -def nomatch_exits(menu, caller, room, string): - """ - The user typed something in the list of exits. Maybe an exit name? - """ - string = string[3:] - exit = caller.search(string, candidates=room.exits) - if exit is None: - return - - # Open a sub-menu, using nested keys - caller.msg("Editing: {}".format(exit.key)) - menu.open_submenu("commands.building.ExitBuildingMenu", exit, parent_keys=["e"]) - return False - -class ExitBuildingMenu(BuildingMenu): - - """ - Building menu to edit an exit. - - """ - - def init(self, exit): - self.add_choice("key", key="k", attr="key", glance="{obj.key}") - self.add_choice_edit("description", "d") -``` - -The code might be much easier to read. But before detailing it, let's see how it behaves in the -game: - -``` -> @edit here -Building menu: A beautiful meadow - - [T]itle: A beautiful meadow - [D]escription: - This is a beautiful meadow. But so beautiful I can't describe it. - [E]xits: - door - south - [Q]uit the menu - -> e -------------------------------------------------------------------------------- - -Room exits: - Use @c to create a new exit. - -Existing exits: - @e door (n) toward door(#4) - @e south (s) toward south(#7) - -Editing: door - -> @e door -Building menu: door - - [K]ey: door - [D]escription: - None - -> k -------------------------------------------------------------------------------- -key for door(#4) - -You can change this value simply by entering it. - -Use @ to go back to the main menu. - -Current value: door - -> north - -------------------------------------------------------------------------------- -key for north(#4) - -You can change this value simply by entering it. - -Use @ to go back to the main menu. - -Current value: north - -> @ -Building menu: north - - [K]ey: north - [D]escription: - None - -> d -----------Line Editor [editor]---------------------------------------------------- -01| None -----------[l:01 w:001 c:0004]------------(:h for help)---------------------------- - -> :DD -Cleared 1 lines from buffer. - -> This is the northern exit. Cool huh? -01| This is the northern exit. Cool huh? - -> :wq -Building menu: north - [K]ey: north - [D]escription: - This is the northern exit. Cool huh? - -> @ -------------------------------------------------------------------------------- -Room exits: - Use @c to create a new exit. - -Existing exits: - @e north (n) toward north(#4) - @e south (s) toward south(#7) - -> @ -Building menu: A beautiful meadow - - [T]itle: A beautiful meadow - [D]escription: - This is a beautiful meadow. But so beautiful I can't describe it. - [E]xits: - north - south - [Q]uit the menu - -> q -Closing the building menu. - -> look -A beautiful meadow(#2) -This is a beautiful meadow. But so beautiful I can't describe it. -Exits: north(#4) and south(#7) -> @py here.exits[0] ->>> here.exits[0] -north -> @py here.exits[0].db.desc ->>> here.exits[0].db.desc -This is the northern exit. Cool huh? -``` - -Very simply, we created two menus and bridged them together. This needs much less callbacks. There -is only one line in the `nomatch_exits` to add: - -```python - menu.open_submenu("commands.building.ExitBuildingMenu", exit, parent_keys=["e"]) -``` - -We have to call `open_submenu` on the menu object (which opens, as its name implies, a sub menu) -with three arguments: - -- The path of the menu class to create. It's the Python class leading to the menu (notice the -dots). -- The object that will be edited by the menu. Here, it's our exit, so we give it to the sub-menu. -- The keys of the parent to open when the sub-menu closes. Basically, when we're in the root of the -sub-menu and press `@`, we'll open the parent menu, with the parent keys. So we specify `["e"]`, -since the parent menus is the "exits" choice. - -And that's it. The new class will be automatically created. As you can see, we have to create a -`on_nomatch` callback to open the sub-menu, but once opened, it automatically close whenever needed. - -### Generic menu options - -There are some options that can be set on any menu class. These options allow for greater -customization. They are class attributes (see the example below), so just set them in the class -body: - -- `keys_go_back` (default to `["@"]`): the keys to use to go back in the menu hierarchy, from choice -to root menu, from sub-menu to parent-menu. By default, only a `@` is used. You can change this -key for one menu or all of them. You can define multiple return commands if you want. -- `sep_keys` (default `"."`): this is the separator for nested keys. There is no real need to -redefine it except if you really need the dot as a key, and need nested keys in your menu. -- `joker_key` (default to `"*"`): used for nested keys to indicate "any key". Again, you shouldn't -need to change it unless you want to be able to use the @*@ in a command key, and also need nested -keys in your menu. -- `min_shortcut` (default to `1`): although we didn't see it here, one can create a menu choice -without giving it a key. If so, the menu system will try to "guess" the key. This option allows to -change the minimum length of any key for security reasons. - -To set one of them just do so in your menu class(es): - -```python -class RoomBuildingMenu(BuildingMenu): - keys_go_back = ["/"] - min_shortcut = 2 -``` - -## Conclusion - -Building menus mean to save you time and create a rich yet simple interface. But they can be -complicated to learn and require reading the source code to find out how to do such and such a -thing. This documentation, however long, is an attempt at describing this system, but chances are -you'll still have questions about it after reading it, especially if you try to push this system to -a great extent. Do not hesitate to read the documentation of this contrib, it's meant to be -exhaustive but user-friendly. \ No newline at end of file diff --git a/docs/0.9.5/_sources/Choosing-An-SQL-Server.md.txt b/docs/0.9.5/_sources/Choosing-An-SQL-Server.md.txt deleted file mode 100644 index b0cb784826..0000000000 --- a/docs/0.9.5/_sources/Choosing-An-SQL-Server.md.txt +++ /dev/null @@ -1,249 +0,0 @@ -# Choosing An SQL Server - - -This page gives an overview of the supported SQL databases as well as instructions on install: - - - SQLite3 (default) - - PostgreSQL - - MySQL / MariaDB - -Since Evennia uses [Django](http://djangoproject.com), most of our notes are based off of what we -know from the community and their documentation. While the information below may be useful, you can -always find the most up-to-date and "correct" information at Django's [Notes about supported -Databases](http://docs.djangoproject.com/en/dev/ref/databases/#ref-databases) page. - -## SQLite3 - -[SQLite3](https://sqlite.org/) is a light weight single-file database. It is our default database -and Evennia will set this up for you automatically if you give no other options. SQLite stores the -database in a single file (`mygame/server/evennia.db3`). This means it's very easy to reset this -database - just delete (or move) that `evennia.db3` file and run `evennia migrate` again! No server -process is needed and the administrative overhead and resource consumption is tiny. It is also very -fast since it's run in-memory. For the vast majority of Evennia installs it will probably be all -that's ever needed. - -SQLite will generally be much faster than MySQL/PostgreSQL but its performance comes with two -drawbacks: - -* SQLite [ignores length constraints by design](https://www.sqlite.org/faq.html#q9); it is possible -to store very large strings and numbers in fields that technically should not accept them. This is -not something you will notice; your game will read and write them and function normally, but this -*can* create some data migration problems requiring careful thought if you do need to change -databases later. -* SQLite can scale well to storage of millions of objects, but if you end up with a thundering herd -of users trying to access your MUD and web site at the same time, or you find yourself writing long- -running functions to update large numbers of objects on a live game, either will yield errors and -interference. SQLite does not work reliably with multiple concurrent threads or processes accessing -its records. This has to do with file-locking clashes of the database file. So for a production -server making heavy use of process- or thread pools (or when using a third-party webserver like -Apache), a proper database is a more appropriate choice. - -### Install of SQlite3 - -This is installed and configured as part of Evennia. The database file is created as -`mygame/server/evennia.db3` when you run - - evennia migrate - -without changing any database options. An optional requirement is the `sqlite3` client program - -this is required if you want to inspect the database data manually. A shortcut for using it with the -evennia database is `evennia dbshell`. Linux users should look for the `sqlite3` package for their -distro while Mac/Windows should get the [sqlite-tools package from this -page](https://sqlite.org/download.html). - -To inspect the default Evennia database (once it's been created), go to your game dir and do - -```bash - sqlite3 server/evennia.db3 - # or - evennia dbshell -``` - -This will bring you into the sqlite command line. Use `.help` for instructions and `.quit` to exit. -See [here](https://gist.github.com/vincent178/10889334) for a cheat-sheet of commands. - -## PostgreSQL - -[PostgreSQL](https://www.postgresql.org/) is an open-source database engine, recommended by Django. -While not as fast as SQLite for normal usage, it will scale better than SQLite, especially if your -game has an very large database and/or extensive web presence through a separate server process. - -### Install and initial setup of PostgreSQL - -First, install the posgresql server. Version `9.6` is tested with Evennia. Packages are readily -available for all distributions. You need to also get the `psql` client (this is called `postgresql- -client` on debian-derived systems). Windows/Mac users can [find what they need on the postgresql -download page](https://www.postgresql.org/download/). You should be setting up a password for your -database-superuser (always called `postgres`) when you install. - -For interaction with Evennia you need to also install `psycopg2` to your Evennia install (`pip -install psycopg2-binary` in your virtualenv). This acts as the python bridge to the database server. - -Next, start the postgres client: - -```bash - psql -U postgres --password -``` -> :warning: **Warning:** With the `--password` argument, Postgres should prompt you for a password. -If it won't, replace that with `-p yourpassword` instead. Do not use the `-p` argument unless you -have to since the resulting command, and your password, will be logged in the shell history. - -This will open a console to the postgres service using the psql client. - -On the psql command line: - -```sql -CREATE USER evennia WITH PASSWORD 'somepassword'; -CREATE DATABASE evennia; - --- Postgres-specific optimizations --- https://docs.djangoproject.com/en/dev/ref/databases/#optimizing-postgresql-s-configuration -ALTER ROLE evennia SET client_encoding TO 'utf8'; -ALTER ROLE evennia SET default_transaction_isolation TO 'read committed'; -ALTER ROLE evennia SET timezone TO 'UTC'; - -GRANT ALL PRIVILEGES ON DATABASE evennia TO evennia; --- Other useful commands: --- \l (list all databases and permissions) --- \q (exit) - -``` -[Here](https://gist.github.com/Kartones/dd3ff5ec5ea238d4c546) is a cheat-sheet for psql commands. - -We create a database user 'evennia' and a new database named `evennia` (you can call them whatever -you want though). We then grant the 'evennia' user full privileges to the new database so it can -read/write etc to it. -If you in the future wanted to completely wipe the database, an easy way to do is to log in as the -`postgres` superuser again, then do `DROP DATABASE evennia;`, then `CREATE` and `GRANT` steps above -again to recreate the database and grant privileges. - -### Evennia PostgreSQL configuration - -Edit `mygame/server/conf/secret_settings.py and add the following section: - -```python -# -# PostgreSQL Database Configuration -# -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'NAME': 'evennia', - 'USER': 'evennia', - 'PASSWORD': 'somepassword', - 'HOST': 'localhost', - 'PORT': '' # use default - }} -``` - -If you used some other name for the database and user, enter those instead. Run - - evennia migrate - -to populate your database. Should you ever want to inspect the database directly you can from now on -also use - - evennia dbshell - -as a shortcut to get into the postgres command line for the right database and user. - -With the database setup you should now be able to start start Evennia normally with your new -database. - -## MySQL / MariaDB - -[MySQL](https://www.mysql.com/) is a commonly used proprietary database system, on par with -PostgreSQL. There is an open-source alternative called [MariaDB](https://mariadb.org/) that mimics -all functionality and command syntax of the former. So this section covers both. - -### Installing and initial setup of MySQL/MariaDB - -First, install and setup MariaDB or MySQL for your specific server. Linux users should look for the -`mysql-server` or `mariadb-server` packages for their respective distributions. Windows/Mac users -will find what they need from the [MySQL downloads](https://www.mysql.com/downloads/) or [MariaDB -downloads](https://mariadb.org/download/) pages. You also need the respective database clients -(`mysql`, `mariadb-client`), so you can setup the database itself. When you install the server you -should usually be asked to set up the database root user and password. - -You will finally also need a Python interface to allow Evennia to talk to the database. Django -recommends the `mysqlclient` one. Install this into the evennia virtualenv with `pip install -mysqlclient`. - -Start the database client (this is named the same for both mysql and mariadb): - -```bash -mysql -u root -p -``` - -You should get to enter your database root password (set this up when you installed the database -server). - -Inside the database client interface: - -```sql -CREATE USER 'evennia'@'localhost' IDENTIFIED BY 'somepassword'; -CREATE DATABASE evennia; -ALTER DATABASE `evennia` CHARACTER SET utf8; -- note that it's `evennia` with back-ticks, not -quotes! -GRANT ALL PRIVILEGES ON evennia.* TO 'evennia'@'localhost'; -FLUSH PRIVILEGES; --- use 'exit' to quit client -``` -[Here](https://gist.github.com/hofmannsven/9164408) is a mysql command cheat sheet. - -Above we created a new local user and database (we called both 'evennia' here, you can name them -what you prefer). We set the character set to `utf8` to avoid an issue with prefix character length -that can pop up on some installs otherwise. Next we grant the 'evennia' user all privileges on the -`evennia` database and make sure the privileges are applied. Exiting the client brings us back to -the normal terminal/console. - -> Note: If you are not using MySQL for anything else you might consider granting the 'evennia' user -full privileges with `GRANT ALL PRIVILEGES ON *.* TO 'evennia'@'localhost';`. If you do, it means -you can use `evennia dbshell` later to connect to mysql, drop your database and re-create it as a -way of easy reset. Without this extra privilege you will be able to drop the database but not re- -create it without first switching to the database-root user. - -## Add MySQL configuration to Evennia - -To tell Evennia to use your new database you need to edit `mygame/server/conf/settings.py` (or -`secret_settings.py` if you don't want your db info passed around on git repositories). - -> Note: The Django documentation suggests using an external `db.cnf` or other external conf- -formatted file. Evennia users have however found that this leads to problems (see e.g. [issue -#1184](https://git.io/vQdiN)). To avoid trouble we recommend you simply put the configuration in -your settings as below. - -```python - # - # MySQL Database Configuration - # - DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': 'evennia', - 'USER': 'evennia', - 'PASSWORD': 'somepassword', - 'HOST': 'localhost', # or an IP Address that your DB is hosted on - 'PORT': '', # use default port - } - } -``` -Change this to fit your database setup. Next, run: - - evennia migrate - -to populate your database. Should you ever want to inspect the database directly you can from now on -also use - - evennia dbshell - -as a shortcut to get into the postgres command line for the right database and user. - -With the database setup you should now be able to start start Evennia normally with your new -database. - -## Others - -No testing has been performed with Oracle, but it is also supported through Django. There are -community maintained drivers for [MS SQL](http://code.google.com/p/django-mssql/) and possibly a few -others. If you try other databases out, consider expanding this page with instructions. diff --git a/docs/0.9.5/_sources/Client-Support-Grid.md.txt b/docs/0.9.5/_sources/Client-Support-Grid.md.txt deleted file mode 100644 index 1acd9e257c..0000000000 --- a/docs/0.9.5/_sources/Client-Support-Grid.md.txt +++ /dev/null @@ -1,84 +0,0 @@ -# Client Support Grid - -This grid tries to gather info about different MU clients when used with Evennia. -If you want to report a problem, update an entry or add a client, make a -new [documentation issue](github:issue) for it. Everyone's encouraged to report their findings. - -## Client Grid - -Legend: - - - **Name**: The name of the client. Also note if it's OS-specific. - - **Version**: Which version or range of client versions were tested. - - **Comments**: Any quirks on using this client with Evennia should be added here. - - -| Name | Version tested | Comments | -| --- | --- | --- | -| [Evennia Webclient][1] | 1.0+ | Evennia-specific | -| [tintin++][2] | 2.0+ | No MXP support | -| [tinyfugue][3] | 5.0+ | No UTF-8 support | -| [MUSHclient][4] (Win) | 4.94 | NAWS reports full text area | -| [Zmud][5] (Win) | 7.21 | *UNTESTED* | -| [Cmud][6] (Win) | v3 | *UNTESTED* | -| [Potato][7]_ | 2.0.0b16 | No MXP, MCCP support. Win 32bit does not understand | -| | | "localhost", must use `127.0.0.1`. | -| [Mudlet][8] | 3.4+ | No known issues. Some older versions showed <> as html | -| | | under MXP. | -| [SimpleMU][9] (Win) | full | Discontinued. NAWS reports pixel size. | -| [Atlantis][10] (Mac) | 0.9.9.4 | No known issues. | -| [GMUD][11] | 0.0.1 | Can't handle any telnet handshakes. Not recommended. | -| [BeipMU][12] (Win) | 3.0.255 | No MXP support. Best to enable "MUD prompt handling", disable | -| | | "Handle HTML tags". | -| [MudRammer][13] (IOS) | 1.8.7 | Bad Telnet Protocol compliance: displays spurious characters. | -| [MUDMaster][14] | 1.3.1 | *UNTESTED* | -| [BlowTorch][15] (Andr) | 1.1.3 | Telnet NOP displays as spurious character. | -| [Mukluk][16] (Andr) | 2015.11.20| Telnet NOP displays as spurious character. Has UTF-8/Emoji | -| | | support. | -| [Gnome-MUD][17] (Unix) | 0.11.2 | Telnet handshake errors. First (only) attempt at logging in | -| | | fails. | -| [Spyrit][18] | 0.4 | No MXP, OOB support. | -| [JamochaMUD][19] | 5.2 | Does not support ANSI within MXP text. | -| [DuckClient][20] (Chrome) | 4.2 | No MXP support. Displays Telnet Go-Ahead and | -| | | WILL SUPPRESS-GO-AHEAD as ù character. Also seems to run | -| | | the `version` command on connection, which will not work in | -| | | `MULTISESSION_MODES` above 1. | -| [KildClient][21] | 2.11.1 | No known issues. | - - -[1]: ./Webclient -[2]: http://tintin.sourceforge.net/ -[3]: http://tinyfugue.sourceforge.net/ -[4]: https://mushclient.com/ -[5]: http://forums.zuggsoft.com/index.php?page=4&action=file&file_id=65 -[6]: http://forums.zuggsoft.com/index.php?page=4&action=category&cat_id=11 -[7]: https://www.potatomushclient.com/ -[8]: https://www.mudlet.org/ -[9]: https://archive.org/details/tucows_196173_SimpleMU_MU_Client -[10]: https://www.riverdark.net/atlantis/ -[11]: https://sourceforge.net/projects/g-mud/ -[12]: http://www.beipmu.com/ -[13]: https://itunes.apple.com/us/app/mudrammer-a-modern-mud-client/id597157072 -[14]: https://itunes.apple.com/us/app/mudmaster/id341160033 -[15]: https://bt.happygoatstudios.com/ -[16]: https://play.google.com/store/apps/details?id=com.crap.mukluk -[17]: https://github.com/GNOME/gnome-mud -[18]: https://spyrit.ierne.eu.org/ -[19]: https://jamochamud.org/ -[20]: http://duckclient.com/ -[21]: https://www.kildclient.org/ - -## Workarounds for client issues: - -### Issue: Telnet NOP displays as spurious character. - -Known clients: - -* BlowTorch (Andr) -* Mukluk (Andr) - -Workaround: - -* In-game: Use `@option NOPKEEPALIVE=off` for the session, or use the `/save` -parameter to disable it for that Evennia account permanently. -* Client-side: Set a gag-type trigger on the NOP character to make it invisible to the client. diff --git a/docs/0.9.5/_sources/Coding-FAQ.md.txt b/docs/0.9.5/_sources/Coding-FAQ.md.txt deleted file mode 100644 index 8b61ca1a18..0000000000 --- a/docs/0.9.5/_sources/Coding-FAQ.md.txt +++ /dev/null @@ -1,389 +0,0 @@ -# Coding FAQ - -*This FAQ page is for users to share their solutions to coding problems. Keep it brief and link to -the docs if you can rather than too lengthy explanations. Don't forget to check if an answer already -exists before answering - maybe you can clarify that answer rather than to make a new Q&A section.* - - -## Table of Contents - -- [Will I run out of dbrefs?](./Coding-FAQ.md#will-i-run-out-of-dbrefs) -- [Removing default commands](./Coding-FAQ.md#removing-default-commands) -- [Preventing character from moving based on a condition](./Coding-FAQ.md#preventing-character-from- -moving-based-on-a-condition) -- [Reference initiating object in an EvMenu command](./Coding-FAQ.md#reference-initiating-object-in-an- -evmenu-command) -- [Adding color to default Evennia Channels](./Coding-FAQ.md#adding-color-to-default-evennia-channels) -- [Selectively turn off commands in a room](./Coding-FAQ.md#selectively-turn-off-commands-in-a-room) -- [Select Command based on a condition](./Coding-FAQ.md#select-command-based-on-a-condition) -- [Automatically updating code when reloading](./Coding-FAQ.md#automatically-updating-code-when- -reloading) -- [Changing all exit messages](./Coding-FAQ.md#changing-all-exit-messages) -- [Add parsing with the "to" delimiter](./Coding-FAQ.md#add-parsing-with-the-to-delimiter) -- [Store last used session IP address](./Coding-FAQ.md#store-last-used-session-ip-address) -- [Use wide characters with EvTable](./Coding-FAQ.md#non-latin-characters-in-evtable) - -## Will I run out of dbrefs? -**Q:** The `#dbref` of a database object is ever-increasing. Evennia doesn't allow you to change or -reuse them. Will not a big/old game run out of dbref integers eventually? - -**A:** No. For example, the default sqlite3 database's max dbref is `2**64`. If you created `10 000` -objects every second every minute and every day of the year it would take ~60 million years for you -to run out of dbref numbers. That's a database of 140 TeraBytes, if every row was empty. If you are -still using Evennia at that point and has this concern, get back to us and we can discuss adding -dbref reuse then. - -## Removing default commands -**Q:** How does one *remove* (not replace) e.g. the default `get` [Command](./Commands.md) from the -Character [Command Set](./Command-Sets.md)? - -**A:** Go to `mygame/commands/default_cmdsets.py`. Find the `CharacterCmdSet` class. It has one -method named `at_cmdset_creation`. At the end of that method, add the following line: -`self.remove(default_cmds.CmdGet())`. See the [Adding Commands Tutorial](./Adding-Command-Tutorial.md) -for more info. - -## Preventing character from moving based on a condition -**Q:** How does one keep a character from using any exit, if they meet a certain condition? (I.E. in -combat, immobilized, etc.) - -**A:** The `at_before_move` hook is called by Evennia just before performing any move. If it returns -`False`, the move is aborted. Let's say we want to check for an [Attribute](./Attributes.md) `cantmove`. -Add the following code to the `Character` class: - -```python -def at_before_move(self, destination): - "Called just before trying to move" - if self.db.cantmove: # replace with condition you want to test - self.msg("Something is preventing you from moving!") - return False - return True -``` - -## Reference initiating object in an EvMenu command. -**Q:** An object has a Command on it starts up an EvMenu instance. How do I capture a reference to -that object for use in the menu? - -**A:** When an [EvMenu](./EvMenu.md) is started, the menu object is stored as `caller.ndb._menutree`. -This is a good place to store menu-specific things since it will clean itself up when the menu -closes. When initiating the menu, any additional keywords you give will be available for you as -properties on this menu object: - -```python -class MyObjectCommand(Command): - # A Command stored on an object (the object is always accessible from - # the Command as self.obj) - def func(self): - # add the object as the stored_obj menu property - EvMenu(caller, ..., stored_obj=self.obj) - -``` - -Inside the menu you can now access the object through `caller.ndb._menutree.stored_obj`. - - -## Adding color to default Evennia Channels -**Q:** How do I add colors to the names of Evennia channels? - -**A:** The Channel typeclass' `channel_prefix` method decides what is shown at the beginning of a -channel send. Edit `mygame/typeclasses/channels.py` (and then `@reload`): - -```python -# define our custom color names -CHANNEL_COLORS = {'public': '|015Public|n', - 'newbie': '|550N|n|551e|n|552w|n|553b|n|554i|n|555e|n', - 'staff': '|010S|n|020t|n|030a|n|040f|n|050f|n'} - -# Add to the Channel class - # ... - def channel_prefix(self, msg, emit=False): - prefix_string = "" - if self.key in COLORS: - prefix_string = "[%s] " % CHANNEL_COLORS.get(self.key.lower()) - else: - prefix_string = "[%s] " % self.key.capitalize() - return prefix_string -``` -Additional hint: To make colors easier to change from one place you could instead put the -`CHANNEL_COLORS` dict in your settings file and import it as `from django.conf.settings import -CHANNEL_COLORS`. - - -## Selectively turn off commands in a room -**Q:** I want certain commands to turn off in a given room. They should still work normally for -staff. - -**A:** This is done using a custom cmdset on a room [locked with the 'call' lock type](./Locks.md). Only -if this lock is passed will the commands on the room be made available to an object inside it. Here -is an example of a room where certain commands are disabled for non-staff: - -```python -# in mygame/typeclasses/rooms.py - -from evennia import default_commands, CmdSet - -class CmdBlocking(default_commands.MuxCommand): - # block commands give, get, inventory and drop - key = "give" - aliases = ["get", "inventory", "drop"] - def func(self): - self.caller.msg("You cannot do that in this room.") - -class BlockingCmdSet(CmdSet): - key = "blocking_cmdset" - # default commands have prio 0 - priority = 1 - def at_cmdset_creation(self): - self.add(CmdBlocking()) - -class BlockingRoom(Room): - def at_object_creation(self): - self.cmdset.add(BlockingCmdSet, permanent=True) - # only share commands with players in the room that - # are NOT Builders or higher - self.locks.add("call:not perm(Builders)") -``` -After `@reload`, make some `BlockingRooms` (or switch a room to it with `@typeclass`). Entering one -will now replace the given commands for anyone that does not have the `Builders` or higher -permission. Note that the 'call' lock is special in that even the superuser will be affected by it -(otherwise superusers would always see other player's cmdsets and a game would be unplayable for -superusers). - -## Select Command based on a condition -**Q:** I want a command to be available only based on a condition. For example I want the "werewolf" -command to only be available on a full moon, from midnight to three in-game time. - -**A:** This is easiest accomplished by putting the "werewolf" command on the Character as normal, -but to [lock](./Locks.md) it with the "cmd" type lock. Only if the "cmd" lock type is passed will the -command be available. - -```python -# in mygame/commands/command.py - -from evennia import Command - -class CmdWerewolf(Command): - key = "werewolf" - # lock full moon, between 00:00 (midnight) and 03:00. - locks = "cmd:is_full_moon(0, 3)" - def func(self): - # ... -``` -Add this to the [default cmdset as usual](./Adding-Command-Tutorial.md). The `is_full_moon` [lock -function](./Locks.md#lock-functions) does not yet exist. We must create that: - -```python -# in mygame/server/conf/lockfuncs.py - -def is_full_moon(accessing_obj, accessed_obj, - starthour, endhour, *args, **kwargs): - # calculate if the moon is full here and - # if current game time is between starthour and endhour - # return True or False - -``` -After a `@reload`, the `werewolf` command will be available only at the right time, that is when the -`is_full_moon` lock function returns True. - -## Automatically updating code when reloading -**Q:** I have a development server running Evennia. Can I have the server update its code-base when -I reload? - -**A:** Having a development server that pulls updated code whenever you reload it can be really -useful if you have limited shell access to your server, or want to have it done automatically. If -you have your project in a configured Git environment, it's a matter of automatically calling `git -pull` when you reload. And that's pretty straightforward: - -In `/server/conf/at_server_startstop.py`: - -```python -import subprocess - -# ... other hooks ... - -def at_server_reload_stop(): - """ - This is called only time the server stops before a reload. - """ - print("Pulling from the game repository...") - process = subprocess.call(["git", "pull"], shell=False) -``` - -That's all. We call `subprocess` to execute a shell command (that code works on Windows and Linux, -assuming the current directory is your game directory, which is probably the case when you run -Evennia). `call` waits for the process to complete, because otherwise, Evennia would reload on -partially-modified code, which would be problematic. - -Now, when you enter `@reload` on your development server, the game repository is updated from the -configured remote repository (Github, for instance). Your development cycle could resemble -something like: - -1. Coding on the local machine. -2. Testing modifications. -3. Committing once, twice or more (being sure the code is still working, unittests are pretty useful -here). -4. When the time comes, login to the development server and run `@reload`. - -The reloading might take one or two additional seconds, since Evennia will pull from your remote Git -repository. But it will reload on it and you will have your modifications ready, without needing -connecting to your server using SSH or something similar. - -## Changing all exit messages -**Q:** How can I change the default exit messages to something like "XXX leaves east" or "XXX -arrives from the west"? - -**A:** the default exit messages are stored in two hooks, namely `announce_move_from` and -`announce_move_to`, on the `Character` typeclass (if what you want to change is the message other -characters will see when a character exits). - -These two hooks provide some useful features to easily update the message to be displayed. They -take both the default message and mapping as argument. You can easily call the parent hook with -these information: - -* The message represents the string of characters sent to characters in the room when a character -leaves. -* The mapping is a dictionary containing additional mappings (you will probably not need it for -simple customization). - -It is advisable to look in the [code of both -hooks](https://github.com/evennia/evennia/tree/master/evennia/objects/objects.py), and read the -hooks' documentation. The explanations on how to quickly update the message are shown below: - -```python -# In typeclasses/characters.py -""" -Characters - -""" -from evennia import DefaultCharacter - -class Character(DefaultCharacter): - """ - The default character class. - - ... - """ - - def announce_move_from(self, destination, msg=None, mapping=None): - """ - Called if the move is to be announced. This is - called while we are still standing in the old - location. - - Args: - destination (Object): The place we are going to. - msg (str, optional): a replacement message. - mapping (dict, optional): additional mapping objects. - - You can override this method and call its parent with a - message to simply change the default message. In the string, - you can use the following as mappings (between braces): - object: the object which is moving. - exit: the exit from which the object is moving (if found). - origin: the location of the object before the move. - destination: the location of the object after moving. - - """ - super().announce_move_from(destination, msg="{object} leaves {exit}.") - - def announce_move_to(self, source_location, msg=None, mapping=None): - """ - Called after the move if the move was not quiet. At this point - we are standing in the new location. - - Args: - source_location (Object): The place we came from - msg (str, optional): the replacement message if location. - mapping (dict, optional): additional mapping objects. - - You can override this method and call its parent with a - message to simply change the default message. In the string, - you can use the following as mappings (between braces): - object: the object which is moving. - exit: the exit from which the object is moving (if found). - origin: the location of the object before the move. - destination: the location of the object after moving. - - """ - super().announce_move_to(source_location, msg="{object} arrives from the {exit}.") -``` - -We override both hooks, but call the parent hook to display a different message. If you read the -provided docstrings, you will better understand why and how we use mappings (information between -braces). You can provide additional mappings as well, if you want to set a verb to move, for -instance, or other, extra information. - -## Add parsing with the "to" delimiter - -**Q:** How do I change commands to undestand say `give obj to target` as well as the default `give -obj = target`? - -**A:** You can make change the default `MuxCommand` parent with your own class making a small change -in its `parse` method: - -```python - # in mygame/commands/command.py - from evennia import default_cmds - class MuxCommand(default_cmds.MuxCommand): - def parse(self): - """Implement an additional parsing of 'to'""" - super().parse() - if " to " in self.args: - self.lhs, self.rhs = self.args.split(" to ", 1) -``` -Next you change the parent of the default commands in settings: - -```python - COMMAND_DEFAULT_CLASS = "commands.command.MuxCommand" -``` - -Do a `@reload` and all default commands will now use your new tweaked parent class. A copy of the -MuxCommand class is also found commented-out in the `mygame/commands/command.py` file. - -## Store last used session IP address - -**Q:** If a user has already logged out of an Evennia account, their IP is no longer visible to -staff that wants to ban-by-ip (instead of the user) with `@ban/ip`? - -**A:** One approach is to write the IP from the last session onto the "account" account object. - -`typeclasses/accounts.py` -```python - def at_post_login(self, session=None, **kwargs): - super().at_post_login(session=session, **kwargs) - self.db.lastsite = self.sessions.all()[-1].address -``` -Adding timestamp for login time and appending to a list to keep the last N login IP addresses and -timestamps is possible, also. Additionally, if you don't want the list to grow beyond a -`do_not_exceed` length, conditionally pop a value after you've added it, if the length has grown too -long. - -**NOTE:** You'll need to add `import time` to generate the login timestamp. -```python - def at_post_login(self, session=None, **kwargs): - super().at_post_login(session=session, **kwargs) - do_not_exceed = 24 # Keep the last two dozen entries - session = self.sessions.all()[-1] # Most recent session - if not self.db.lastsite: - self.db.lastsite = [] - self.db.lastsite.insert(0, (session.address, int(time.time()))) - if len(self.db.lastsite) > do_not_exceed: - self.db.lastsite.pop() -``` -This only stores the data. You may want to interface the `@ban` command or make a menu-driven viewer -for staff to browse the list and display how long ago the login occurred. - -## Non-latin characters in EvTable - -**Q:** When using e.g. Chinese characters in EvTable, some lines appear to be too wide, for example -``` -+------+------+ -| | | -| 测试 | 测试 | -| | | -+~~~~~~+~~~~~~+ -``` -**A:** The reason for this is because certain non-latin characters are *visually* much wider than -their len() suggests. There is little Evennia can (reliably) do about this. If you are using such -characters, you need to make sure to use a suitable mono-spaced font where are width are equal. You -can set this in your web client and need to recommend it for telnet-client users. See [this -discussion](https://github.com/evennia/evennia/issues/1522) where some suitable fonts are suggested. diff --git a/docs/0.9.5/_sources/Coding-Introduction.md.txt b/docs/0.9.5/_sources/Coding-Introduction.md.txt deleted file mode 100644 index 88232b591f..0000000000 --- a/docs/0.9.5/_sources/Coding-Introduction.md.txt +++ /dev/null @@ -1,99 +0,0 @@ -# Coding Introduction - - -Evennia allows for a lot of freedom when designing your game - but to code efficiently you still -need to adopt some best practices as well as find a good place to start to learn. - -Here are some pointers to get you going. - -### Python - -Evennia is developed using Python. Even if you are more of a designer than a coder, it is wise to -learn how to read and understand basic Python code. If you are new to Python, or need a refresher, -take a look at our two-part [Python introduction](./Python-basic-introduction.md). - -### Explore Evennia interactively - -When new to Evennia it can be hard to find things or figure out what is available. Evennia offers a -special interactive python shell that allows you to experiment and try out things. It's recommended -to use [ipython](http://ipython.org/) for this since the vanilla python prompt is very limited. Here -are some simple commands to get started: - - # [open a new console/terminal] - # [activate your evennia virtualenv in this console/terminal] - pip install ipython # [only needed the first time] - cd mygame - evennia shell - -This will open an Evennia-aware python shell (using ipython). From within this shell, try - - import evennia - evennia. - -That is, enter `evennia.` and press the `` key. This will show you all the resources made -available at the top level of Evennia's "flat API". See the [flat API](./Evennia-API.md) page for more -info on how to explore it efficiently. - -You can complement your exploration by peeking at the sections of the much more detailed -[Developer Central](./Developer-Central.md). The [Tutorials](./Tutorials.md) section also contains a growing collection -of system- or implementation-specific help. - -### Use a python syntax checker - -Evennia works by importing your own modules and running them as part of the server. Whereas Evennia -should just gracefully tell you what errors it finds, it can nevertheless be a good idea for you to -check your code for simple syntax errors *before* you load it into the running server. There are -many python syntax checkers out there. A fast and easy one is -[pyflakes](https://pypi.python.org/pypi/pyflakes), a more verbose one is -[pylint](http://www.pylint.org/). You can also check so that your code looks up to snuff using -[pep8](https://pypi.python.org/pypi/pep8). Even with a syntax checker you will not be able to catch -every possible problem - some bugs or problems will only appear when you actually run the code. But -using such a checker can be a good start to weed out the simple problems. - -### Plan before you code - -Before you start coding away at your dream game, take a look at our [Game Planning](./Game-Planning.md) -page. It might hopefully help you avoid some common pitfalls and time sinks. - -### Code in your game folder, not in the evennia/ repository - -As part of the Evennia setup you will create a game folder to host your game code. This is your -home. You should *never* need to modify anything in the `evennia` library (anything you download -from us, really). You import useful functionality from here and if you see code you like, copy&paste -it out into your game folder and edit it there. - -If you find that Evennia doesn't support some functionality you need, make a -[Feature Request](github:issue) about it. Same goes for [bugs](github:issue). If you add features or fix bugs -yourself, please consider [Contributing](./Contributing.md) your changes upstream! - -### Learn to read tracebacks - -Python is very good at reporting when and where things go wrong. A *traceback* shows everything you -need to know about crashing code. The text can be pretty long, but you usually are only interested -in the last bit, where it says what the error is and at which module and line number it happened - -armed with this info you can resolve most problems. - -Evennia will usually not show the full traceback in-game though. Instead the server outputs errors -to the terminal/console from which you started Evennia in the first place. If you want more to show -in-game you can add `IN_GAME_ERRORS = True` to your settings file. This will echo most (but not all) -tracebacks both in-game as well as to the terminal/console. This is a potential security problem -though, so don't keep this active when your game goes into production. - -> A common confusing error is finding that objects in-game are suddenly of the type `DefaultObject` -rather than your custom typeclass. This happens when you introduce a critical Syntax error to the -module holding your custom class. Since such a module is not valid Python, Evennia can't load it at -all. Instead of crashing, Evennia will then print the full traceback to the terminal/console and -temporarily fall back to the safe `DefaultObject` until you fix the problem and reload. - -### Docs are here to help you - -Some people find reading documentation extremely dull and shun it out of principle. That's your -call, but reading docs really *does* help you, promise! Evennia's documentation is pretty thorough -and knowing what is possible can often give you a lot of new cool game ideas. That said, if you -can't find the answer in the docs, don't be shy to ask questions! The -[discussion group](https://sites.google.com/site/evenniaserver/discussions) and the -[irc chat](http://webchat.freenode.net/?channels=evennia) are also there for you. - -### The most important point - -And finally, of course, have fun! \ No newline at end of file diff --git a/docs/0.9.5/_sources/Coding-Utils.md.txt b/docs/0.9.5/_sources/Coding-Utils.md.txt deleted file mode 100644 index e4f1862dbd..0000000000 --- a/docs/0.9.5/_sources/Coding-Utils.md.txt +++ /dev/null @@ -1,297 +0,0 @@ -# Coding Utils - - -Evennia comes with many utilities to help with common coding tasks. Most are accessible directly -from the flat API, otherwise you can find them in the `evennia/utils/` folder. - -## Searching - -A common thing to do is to search for objects. There it's easiest to use the `search` method defined -on all objects. This will search for objects in the same location and inside the self object: - -```python - obj = self.search(objname) -``` - -The most common time one needs to do this is inside a command body. `obj = -self.caller.search(objname)` will search inside the caller's (typically, the character that typed -the command) `.contents` (their "inventory") and `.location` (their "room"). - -Give the keyword `global_search=True` to extend search to encompass entire database. Aliases will -also be matched by this search. You will find multiple examples of this functionality in the default -command set. - -If you need to search for objects in a code module you can use the functions in -`evennia.utils.search`. You can access these as shortcuts `evennia.search_*`. - -```python - from evennia import search_object - obj = search_object(objname) -``` - -- [evennia.search_account](evennia.accounts.manager.AccountDBManager.search_account) -- [evennia.search_object](evennia.objects.manager.ObjectDBManager.search_object) -- [evennia.search_tag](evennia.utils.search.search_tag) -- [evennia.search_script](evennia.scripts.manager.ScriptDBManager.search_script) -- [evennia.search_channel](evennia.comms.managers.ChannelDBManager.search_channel) -- [evennia.search_message](evennia.comms.managers.MsgManager.search_message) -- [evennia.search_help](evennia.utils.search.search_help_entry) - -Note that these latter methods will always return a `list` of results, even if the list has one or -zero entries. - -## Create - -Apart from the in-game build commands (`@create` etc), you can also build all of Evennia's game -entities directly in code (for example when defining new create commands). -```python - import evennia - - myobj = evennia.create_objects("game.gamesrc.objects.myobj.MyObj", key="MyObj") -``` - -- [evennia.create_account](create_account) -- [evennia.create_object](create_object) -- [evennia.create_script](create_script) -- [evennia.create_channel](create_channel) -- [evennia.create_help_entry](create_help_entry) -- [evennia.create_message](create_message) - -Each of these create-functions have a host of arguments to further customize the created entity. See -`evennia/utils/create.py` for more information. - -## Logging - -Normally you can use Python `print` statements to see output to the terminal/log. The `print` -statement should only be used for debugging though. For producion output, use the `logger` which -will create proper logs either to terminal or to file. - -```python - from evennia import logger - # - logger.log_err("This is an Error!") - logger.log_warn("This is a Warning!") - logger.log_info("This is normal information") - logger.log_dep("This feature is deprecated") -``` - -There is a special log-message type, `log_trace()` that is intended to be called from inside a -traceback - this can be very useful for relaying the traceback message back to log without having it -kill the server. - -```python - try: - # [some code that may fail...] - except Exception: - logger.log_trace("This text will show beneath the traceback itself.") -``` - -The `log_file` logger, finally, is a very useful logger for outputting arbitrary log messages. This -is a heavily optimized asynchronous log mechanism using -[threads](https://en.wikipedia.org/wiki/Thread_%28computing%29) to avoid overhead. You should be -able to use it for very heavy custom logging without fearing disk-write delays. - -```python - logger.log_file(message, filename="mylog.log") -``` - -If not an absolute path is given, the log file will appear in the `mygame/server/logs/` directory. -If the file already exists, it will be appended to. Timestamps on the same format as the normal -Evennia logs will be automatically added to each entry. If a filename is not specified, output will -be written to a file `game/logs/game.log`. - -## Time Utilities -### Game time - -Evennia tracks the current server time. You can access this time via the `evennia.gametime` -shortcut: - -```python -from evennia import gametime - -# all the functions below return times in seconds). - -# total running time of the server -runtime = gametime.runtime() -# time since latest hard reboot (not including reloads) -uptime = gametime.uptime() -# server epoch (its start time) -server_epoch = gametime.server_epoch() - -# in-game epoch (this can be set by `settings.TIME_GAME_EPOCH`. -# If not, the server epoch is used. -game_epoch = gametime.game_epoch() -# in-game time passed since time started running -gametime = gametime.gametime() -# in-game time plus game epoch (i.e. the current in-game -# time stamp) -gametime = gametime.gametime(absolute=True) -# reset the game time (back to game epoch) -gametime.reset_gametime() - -``` - -The setting `TIME_FACTOR` determines how fast/slow in-game time runs compared to the real world. The -setting `TIME_GAME_EPOCH` sets the starting game epoch (in seconds). The functions from the -`gametime` module all return their times in seconds. You can convert this to whatever units of time -you desire for your game. You can use the `@time` command to view the server time info. - -You can also *schedule* things to happen at specific in-game times using the -[gametime.schedule](github:evennia.utils.gametime#schedule) function: - -```python -import evennia - -def church_clock: - limbo = evennia.search_object(key="Limbo") - limbo.msg_contents("The church clock chimes two.") - -gametime.schedule(church_clock, hour=2) -``` - -### utils.time_format() - -This function takes a number of seconds as input (e.g. from the `gametime` module above) and -converts it to a nice text output in days, hours etc. It's useful when you want to show how old -something is. It converts to four different styles of output using the *style* keyword: - -- style 0 - `5d:45m:12s` (standard colon output) -- style 1 - `5d` (shows only the longest time unit) -- style 2 - `5 days, 45 minutes` (full format, ignores seconds) -- style 3 - `5 days, 45 minutes, 12 seconds` (full format, with seconds) - -### utils.delay() - -```python -from evennia import utils - -def _callback(obj, text): - obj.msg(text) - -# wait 10 seconds before sending "Echo!" to obj (which we assume is defined) -deferred = utils.delay(10, _callback, obj, "Echo!", persistent=False) - -# code here will run immediately, not waiting for the delay to fire! - -``` - -This creates an asynchronous delayed call. It will fire the given callback function after the given -number of seconds. This is a very light wrapper over a Twisted -[Deferred](https://twistedmatrix.com/documents/current/core/howto/defer.html). Normally this is run -non-persistently, which means that if the server is `@reload`ed before the delay is over, the -callback will never run (the server forgets it). If setting `persistent` to True, the delay will be -stored in the database and survive a `@reload` - but for this to work it is susceptible to the same -limitations incurred when saving to an [Attribute](./Attributes.md). - -The `deferred` return object can usually be ignored, but calling its `.cancel()` method will abort -the delay prematurely. - -`utils.delay` is the lightest form of delayed call in Evennia. For other way to create time-bound -tasks, see the [TickerHandler](./TickerHandler.md) and [Scripts](./Scripts.md). - -> Note that many delayed effects can be achieved without any need for an active timer. For example -if you have a trait that should recover a point every 5 seconds you might just need its value when -it's needed, but checking the current time and calculating on the fly what value it should have. - -## Object Classes -### utils.inherits_from() - -This useful function takes two arguments - an object to check and a parent. It returns `True` if -object inherits from parent *at any distance* (as opposed to Python's in-built `is_instance()` that -will only catch immediate dependence). This function also accepts as input any combination of -classes, instances or python-paths-to-classes. - -Note that Python code should usually work with [duck -typing](http://en.wikipedia.org/wiki/Duck_typing). But in Evennia's case it can sometimes be useful -to check if an object inherits from a given [Typeclass](./Typeclasses.md) as a way of identification. Say -for example that we have a typeclass *Animal*. This has a subclass *Felines* which in turn has a -subclass *HouseCat*. Maybe there are a bunch of other animal types too, like horses and dogs. Using -`inherits_from` will allow you to check for all animals in one go: - -```python - from evennia import utils - if (utils.inherits_from(obj, "typeclasses.objects.animals.Animal"): - obj.msg("The bouncer stops you in the door. He says: 'No talking animals allowed.'") -``` - - - -## Text utilities - -In a text game, you are naturally doing a lot of work shuffling text back and forth. Here is a *non- -complete* selection of text utilities found in `evennia/utils/utils.py` (shortcut `evennia.utils`). -If nothing else it can be good to look here before starting to develop a solution of your own. - -### utils.fill() - -This flood-fills a text to a given width (shuffles the words to make each line evenly wide). It also -indents as needed. - -```python - outtxt = fill(intxt, width=78, indent=4) -``` - -### utils.crop() - -This function will crop a very long line, adding a suffix to show the line actually continues. This -can be useful in listings when showing multiple lines would mess up things. - -```python - intxt = "This is a long text that we want to crop." - outtxt = crop(intxt, width=19, suffix="[...]") - # outtxt is now "This is a long text[...]" -``` - -### utils.dedent() - -This solves what may at first glance appear to be a trivial problem with text - removing -indentations. It is used to shift entire paragraphs to the left, without disturbing any further -formatting they may have. A common case for this is when using Python triple-quoted strings in code -- they will retain whichever indentation they have in the code, and to make easily-readable source -code one usually don't want to shift the string to the left edge. - -```python - #python code is entered at a given indentation - intxt = """ - This is an example text that will end - up with a lot of whitespace on the left. - It also has indentations of - its own.""" - outtxt = dedent(intxt) - # outtxt will now retain all internal indentation - # but be shifted all the way to the left. -``` - -Normally you do the dedent in the display code (this is for example how the help system homogenizes -help entries). - -### to_str() and to_bytes() - -Evennia supplies two utility functions for converting text to the correct -encodings. `to_str()` and `to_bytes()`. Unless you are adding a custom protocol and -need to send byte-data over the wire, `to_str` is the only one you'll need. - -The difference from Python's in-built `str()` and `bytes()` operators are that -the Evennia ones makes use of the `ENCODINGS` setting and will try very hard to -never raise a traceback but instead echo errors through logging. See -[here](./Text-Encodings.md) for more info. - -### Ansi Coloring Tools -- [evennia.ansi](evennia.utils.ansi) - -## Display utilities -### Making ascii tables - -The [EvTable](github:evennia.utils.evtable#evtable) class (`evennia/utils/evtable.py`) can be used -to create correctly formatted text tables. There is also -[EvForm](github:evennia.utils.evform#evform) (`evennia/utils/evform.py`). This reads a fixed-format -text template from a file in order to create any level of sophisticated ascii layout. Both evtable -and evform have lots of options and inputs so see the header of each module for help. - -The third-party [PrettyTable](https://code.google.com/p/prettytable/) module is also included in -Evennia. PrettyTable is considered deprecated in favor of EvTable since PrettyTable cannot handle -ANSI colour. PrettyTable can be found in `evennia/utils/prettytable/`. See its homepage above for -instructions. - -### Menus -- [evennia.EvMenu](github:evennia.utils.evmenu#evmenu) diff --git a/docs/0.9.5/_sources/Command-Cooldown.md.txt b/docs/0.9.5/_sources/Command-Cooldown.md.txt deleted file mode 100644 index c150a39c62..0000000000 --- a/docs/0.9.5/_sources/Command-Cooldown.md.txt +++ /dev/null @@ -1,98 +0,0 @@ -# Command Cooldown - - -Some types of games want to limit how often a command can be run. If a -character casts the spell *Firestorm*, you might not want them to spam that -command over and over. Or in an advanced combat system, a massive swing may -offer a chance of lots of damage at the cost of not being able to re-do it for -a while. Such effects are called *cooldowns*. - -This page exemplifies a very resource-efficient way to do cooldowns. A more -'active' way is to use asynchronous delays as in the [command duration -tutorial](./Command-Duration.md#blocking-commands), the two might be useful to -combine if you want to echo some message to the user after the cooldown ends. - -## Non-persistent cooldown - -This little recipe will limit how often a particular command can be run. Since -Commands are class instances, and those are cached in memory, a command -instance will remember things you store on it. So just store the current time -of execution! Next time the command is run, it just needs to check if it has -that time stored, and compare it with the current time to see if a desired -delay has passed. - -```python -import time -from evennia import default_cmds - -class CmdSpellFirestorm(default_cmds.MuxCommand): - """ - Spell - Firestorm - - Usage: - cast firestorm - - This will unleash a storm of flame. You can only release one - firestorm every five minutes (assuming you have the mana). - """ - key = "cast firestorm" - locks = "cmd:isFireMage()" - - def func(self): - "Implement the spell" - - # check cooldown (5 minute cooldown) - now = time.time() - if hasattr(self, "lastcast") and \ - now - self.lastcast < 5 * 60: - message = "You cannot cast this spell again yet." - self.caller.msg(message) - return - - #[the spell effect is implemented] - - # if the spell was successfully cast, store the casting time - self.lastcast = now -``` - -We just check the `lastcast` flag, and update it if everything works out. -Simple and very effective since everything is just stored in memory. The -drawback of this simple scheme is that it's non-persistent. If you do -`@reload`, the cache is cleaned and all such ongoing cooldowns will be -forgotten. It is also limited only to this one command, other commands cannot -(easily) check for this value. - -## Persistent cooldown - -This is essentially the same mechanism as the simple one above, except we use -the database to store the information which means the cooldown will survive a -server reload/reboot. Since commands themselves have no representation in the -database, you need to use the caster for the storage. - -```python - # inside the func() of CmdSpellFirestorm as above - - # check cooldown (5 minute cooldown) - - now = time.time() - lastcast = self.caller.db.firestorm_lastcast - - if lastcast and now - lastcast < 5 * 60: - message = "You need to wait before casting this spell again." - self.caller.msg(message) - return - - #[the spell effect is implemented] - - # if the spell was successfully cast, store the casting time - self.caller.db.firestorm_lastcast = now -``` - -Since we are storing as an [Attribute](./Attributes.md), we need to identify the -variable as `firestorm_lastcast` so we are sure we get the right one (we'll - likely have other skills with cooldowns after all). But this method of -using cooldowns also has the advantage of working *between* commands - you can -for example let all fire-related spells check the same cooldown to make sure -the casting of *Firestorm* blocks all fire-related spells for a while. Or, in -the case of taking that big swing with the sword, this could now block all -other types of attacks for a while before the warrior can recover. diff --git a/docs/0.9.5/_sources/Command-Duration.md.txt b/docs/0.9.5/_sources/Command-Duration.md.txt deleted file mode 100644 index 8a6bee7732..0000000000 --- a/docs/0.9.5/_sources/Command-Duration.md.txt +++ /dev/null @@ -1,403 +0,0 @@ -# Command Duration - - -Before reading this tutorial, if you haven't done so already, you might want to -read [the documentation on commands](./Commands.md) to get a basic understanding of -how commands work in Evennia. - -In some types of games a command should not start and finish immediately. -Loading a crossbow might take a bit of time to do - time you don't have when -the enemy comes rushing at you. Crafting that armour will not be immediate -either. For some types of games the very act of moving or changing pose all -comes with a certain time associated with it. - -## The simple way to pause commands with yield - -Evennia allows a shortcut in syntax to create simple pauses in commands. This -syntax uses the `yield` keyword. The `yield` keyword is used in Python to -create generators, although you don't need to know what generators are to use -this syntax. A short example will probably make it clear: - -```python -class CmdTest(Command): - - """ - A test command just to test waiting. - - Usage: - test - - """ - - key = "test" - locks = "cmd:all()" - - def func(self): - self.msg("Before ten seconds...") - yield 10 - self.msg("Afterwards.") -``` -> Important: The `yield` functionality will *only* work in the `func` method of -> Commands. It only works because Evennia has especially -> catered for it in Commands. If you want the same functionality elsewhere you -> must use the [interactive decorator](./Async-Process.md#the-interactive-decorator). - -The important line is the `yield 10`. It tells Evennia to "pause" the command -and to wait for 10 seconds to execute the rest. If you add this command and -run it, you'll see the first message, then, after a pause of ten seconds, the -next message. You can use `yield` several times in your command. - -This syntax will not "freeze" all commands. While the command is "pausing", - you can execute other commands (or even call the same command again). And - other players aren't frozen either. - -> Note: this will not save anything in the database. If you reload the game -> while a command is "paused", it will not resume after the server has -> reloaded. - - -## The more advanced way with utils.delay - -The `yield` syntax is easy to read, easy to understand, easy to use. But it's not that flexible if -you want more advanced options. Learning to use alternatives might be much worth it in the end. - -Below is a simple command example for adding a duration for a command to finish. - -```python -from evennia import default_cmds, utils - -class CmdEcho(default_cmds.MuxCommand): - """ - wait for an echo - - Usage: - echo - - Calls and waits for an echo - """ - key = "echo" - locks = "cmd:all()" - - def func(self): - """ - This is called at the initial shout. - """ - self.caller.msg("You shout '%s' and wait for an echo ..." % self.args) - # this waits non-blocking for 10 seconds, then calls self.echo - utils.delay(10, self.echo) # call echo after 10 seconds - - def echo(self): - "Called after 10 seconds." - shout = self.args - string = "You hear an echo: %s ... %s ... %s" - string = string % (shout.upper(), shout.capitalize(), shout.lower()) - self.caller.msg(string) -``` - -Import this new echo command into the default command set and reload the server. You will find that -it will take 10 seconds before you see your shout coming back. You will also find that this is a -*non-blocking* effect; you can issue other commands in the interim and the game will go on as usual. -The echo will come back to you in its own time. - -### About utils.delay() - -`utils.delay(timedelay, callback, persistent=False, *args, **kwargs)` is a useful function. It will -wait `timedelay` seconds, then call the `callback` function, optionally passing to it the arguments -provided to utils.delay by way of *args and/or **kwargs`. - -> Note: The callback argument should be provided with a python path to the desired function, for -instance `my_object.my_function` instead of `my_object.my_function()`. Otherwise my_function would -get called and run immediately upon attempting to pass it to the delay function. -If you want to provide arguments for utils.delay to use, when calling your callback function, you -have to do it separatly, for instance using the utils.delay *args and/or **kwargs, as mentioned -above. - -> If you are not familiar with the syntax `*args` and `**kwargs`, [see the Python documentation -here](https://docs.python.org/2/tutorial/controlflow.html#arbitrary-argument-lists). - -Looking at it you might think that `utils.delay(10, callback)` in the code above is just an -alternative to some more familiar thing like `time.sleep(10)`. This is *not* the case. If you do -`time.sleep(10)` you will in fact freeze the *entire server* for ten seconds! The `utils.delay()`is -a thin wrapper around a Twisted -[Deferred](http://twistedmatrix.com/documents/11.0.0/core/howto/defer.html) that will delay -execution until 10 seconds have passed, but will do so asynchronously, without bothering anyone else -(not even you - you can continue to do stuff normally while it waits to continue). - -The point to remember here is that the `delay()` call will not "pause" at that point when it is -called (the way `yield` does in the previous section). The lines after the `delay()` call will -actually execute *right away*. What you must do is to tell it which function to call *after the time -has passed* (its "callback"). This may sound strange at first, but it is normal practice in -asynchronous systems. You can also link such calls together as seen below: - -```python -from evennia import default_cmds, utils - -class CmdEcho(default_cmds.MuxCommand): - """ - waits for an echo - - Usage: - echo - - Calls and waits for an echo - """ - key = "echo" - locks = "cmd:all()" - - def func(self): - "This sets off a chain of delayed calls" - self.caller.msg("You shout '%s', waiting for an echo ..." % self.args) - - # wait 2 seconds before calling self.echo1 - utils.delay(2, self.echo1) - - # callback chain, started above - def echo1(self): - "First echo" - self.caller.msg("... %s" % self.args.upper()) - # wait 2 seconds for the next one - utils.delay(2, self.echo2) - - def echo2(self): - "Second echo" - self.caller.msg("... %s" % self.args.capitalize()) - # wait another 2 seconds - utils.delay(2, callback=self.echo3) - - def echo3(self): - "Last echo" - self.caller.msg("... %s ..." % self.args.lower()) -``` - -The above version will have the echoes arrive one after another, each separated by a two second -delay. - - > echo Hello! - ... HELLO! - ... Hello! - ... hello! ... - -## Blocking commands - -As mentioned, a great thing about the delay introduced by `yield` or `utils.delay()` is that it does -not block. It just goes on in the background and you are free to play normally in the interim. In -some cases this is not what you want however. Some commands should simply "block" other commands -while they are running. If you are in the process of crafting a helmet you shouldn't be able to also -start crafting a shield at the same time, or if you just did a huge power-swing with your weapon you -should not be able to do it again immediately. - -The simplest way of implementing blocking is to use the technique covered in the [Command -Cooldown](./Command-Cooldown.md) tutorial. In that tutorial we implemented cooldowns by having the -Command store the current time. Next time the Command was called, we compared the current time to -the stored time to determine if enough time had passed for a renewed use. This is a *very* -efficient, reliable and passive solution. The drawback is that there is nothing to tell the Player -when enough time has passed unless they keep trying. - -Here is an example where we will use `utils.delay` to tell the player when the cooldown has passed: - -```python -from evennia import utils, default_cmds - -class CmdBigSwing(default_cmds.MuxCommand): - """ - swing your weapon in a big way - - Usage: - swing - - Makes a mighty swing. Doing so will make you vulnerable - to counter-attacks before you can recover. - """ - key = "bigswing" - locks = "cmd:all()" - - def func(self): - "Makes the swing" - - if self.caller.ndb.off_balance: - # we are still off-balance. - self.caller.msg("You are off balance and need time to recover!") - return - - # [attack/hit code goes here ...] - self.caller.msg("You swing big! You are off balance now.") - - # set the off-balance flag - self.caller.ndb.off_balance = True - - # wait 8 seconds before we can recover. During this time - # we won't be able to swing again due to the check at the top. - utils.delay(8, self.recover) - - def recover(self): - "This will be called after 8 secs" - del self.caller.ndb.off_balance - self.caller.msg("You regain your balance.") -``` - -Note how, after the cooldown, the user will get a message telling them they are now ready for -another swing. - -By storing the `off_balance` flag on the character (rather than on, say, the Command instance -itself) it can be accessed by other Commands too. Other attacks may also not work when you are off -balance. You could also have an enemy Command check your `off_balance` status to gain bonuses, to -take another example. - -## Abortable commands - -One can imagine that you will want to abort a long-running command before it has a time to finish. -If you are in the middle of crafting your armor you will probably want to stop doing that when a -monster enters your smithy. - -You can implement this in the same way as you do the "blocking" command above, just in reverse. -Below is an example of a crafting command that can be aborted by starting a fight: - -```python -from evennia import utils, default_cmds - -class CmdCraftArmour(default_cmds.MuxCommand): - """ - Craft armour - - Usage: - craft - - This will craft a suit of armour, assuming you - have all the components and tools. Doing some - other action (such as attacking someone) will - abort the crafting process. - """ - key = "craft" - locks = "cmd:all()" - - def func(self): - "starts crafting" - - if self.caller.ndb.is_crafting: - self.caller.msg("You are already crafting!") - return - if self._is_fighting(): - self.caller.msg("You can't start to craft " - "in the middle of a fight!") - return - - # [Crafting code, checking of components, skills etc] - - # Start crafting - self.caller.ndb.is_crafting = True - self.caller.msg("You start crafting ...") - utils.delay(60, self.step1) - - def _is_fighting(self): - "checks if we are in a fight." - if self.caller.ndb.is_fighting: - del self.caller.ndb.is_crafting - return True - - def step1(self): - "first step of armour construction" - if self._is_fighting(): - return - self.msg("You create the first part of the armour.") - utils.delay(60, callback=self.step2) - - def step2(self): - "second step of armour construction" - if self._is_fighting(): - return - self.msg("You create the second part of the armour.") - utils.delay(60, step3) - - def step3(self): - "last step of armour construction" - if self._is_fighting(): - return - - # [code for creating the armour object etc] - - del self.caller.ndb.is_crafting - self.msg("You finalize your armour.") - - -# example of a command that aborts crafting - -class CmdAttack(default_cmds.MuxCommand): - """ - attack someone - - Usage: - attack - - Try to cause harm to someone. This will abort - eventual crafting you may be currently doing. - """ - key = "attack" - aliases = ["hit", "stab"] - locks = "cmd:all()" - - def func(self): - "Implements the command" - - self.caller.ndb.is_fighting = True - - # [...] -``` - -The above code creates a delayed crafting command that will gradually create the armour. If the -`attack` command is issued during this process it will set a flag that causes the crafting to be -quietly canceled next time it tries to update. - -## Persistent delays - -In the latter examples above we used `.ndb` storage. This is fast and easy but it will reset all -cooldowns/blocks/crafting etc if you reload the server. If you don't want that you can replace -`.ndb` with `.db`. But even this won't help because the `yield` keyword is not persisent and nor is -the use of `delay` shown above. To resolve this you can use `delay` with the `persistent=True` -keyword. But wait! Making something persistent will add some extra complications, because now you -must make sure Evennia can properly store things to the database. - -Here is the original echo-command reworked to function with persistence: -```python -from evennia import default_cmds, utils - -# this is now in the outermost scope and takes two args! -def echo(caller, args): - "Called after 10 seconds." - shout = args - string = "You hear an echo: %s ... %s ... %s" - string = string % (shout.upper(), shout.capitalize(), shout.lower()) - caller.msg(string) - -class CmdEcho(default_cmds.MuxCommand): - """ - wait for an echo - - Usage: - echo - - Calls and waits for an echo - """ - key = "echo" - locks = "cmd:all()" - - def func(self): - """ - This is called at the initial shout. - """ - self.caller.msg("You shout '%s' and wait for an echo ..." % self.args) - # this waits non-blocking for 10 seconds, then calls echo(self.caller, self.args) - utils.delay(10, echo, self.caller, self.args, persistent=True) # changes! - -``` - -Above you notice two changes: -- The callback (`echo`) was moved out of the class and became its own stand-alone function in the -outermost scope of the module. It also now takes `caller` and `args` as arguments (it doesn't have -access to them directly since this is now a stand-alone function). -- `utils.delay` specifies the `echo` function (not `self.echo` - it's no longer a method!) and sends -`self.caller` and `self.args` as arguments for it to use. We also set `persistent=True`. - -The reason for this change is because Evennia needs to `pickle` the callback into storage and it -cannot do this correctly when the method sits on the command class. Now this behave the same as the -first version except if you reload (or even shut down) the server mid-delay it will still fire the -callback when the server comes back up (it will resume the countdown and ignore the downtime). diff --git a/docs/0.9.5/_sources/Command-Prompt.md.txt b/docs/0.9.5/_sources/Command-Prompt.md.txt deleted file mode 100644 index bf99b5ddc6..0000000000 --- a/docs/0.9.5/_sources/Command-Prompt.md.txt +++ /dev/null @@ -1,129 +0,0 @@ -# Command Prompt - - -A *prompt* is quite common in MUDs. The prompt display useful details about your character that you -are likely to want to keep tabs on at all times, such as health, magical power etc. It might also -show things like in-game time, weather and so on. Many modern MUD clients (including Evennia's own -webclient) allows for identifying the prompt and have it appear in a correct location (usually just -above the input line). Usually it will remain like that until it is explicitly updated. - -## Sending a prompt - -A prompt is sent using the `prompt` keyword to the `msg()` method on objects. The prompt will be -sent without any line breaks. - -```python - self.msg(prompt="HP: 5, MP: 2, SP: 8") -``` -You can combine the sending of normal text with the sending (updating of the prompt): - -```python - self.msg("This is a text", prompt="This is a prompt") -``` - -You can update the prompt on demand, this is normally done using [OOB](./OOB.md)-tracking of the relevant -Attributes (like the character's health). You could also make sure that attacking commands update -the prompt when they cause a change in health, for example. - -Here is a simple example of the prompt sent/updated from a command class: - -```python - from evennia import Command - - class CmdDiagnose(Command): - """ - see how hurt your are - - Usage: - diagnose [target] - - This will give an estimate of the target's health. Also - the target's prompt will be updated. - """ - key = "diagnose" - - def func(self): - if not self.args: - target = self.caller - else: - target = self.search(self.args) - if not target: - return - # try to get health, mana and stamina - hp = target.db.hp - mp = target.db.mp - sp = target.db.sp - - if None in (hp, mp, sp): - # Attributes not defined - self.caller.msg("Not a valid target!") - return - - text = "You diagnose %s as having " \ - "%i health, %i mana and %i stamina." \ - % (hp, mp, sp) - prompt = "%i HP, %i MP, %i SP" % (hp, mp, sp) - self.caller.msg(text, prompt=prompt) -``` -## A prompt sent with every command - -The prompt sent as described above uses a standard telnet instruction (the Evennia web client gets a -special flag). Most MUD telnet clients will understand and allow users to catch this and keep the -prompt in place until it updates. So *in principle* you'd not need to update the prompt every -command. - -However, with a varying user base it can be unclear which clients are used and which skill level the -users have. So sending a prompt with every command is a safe catch-all. You don't need to manually -go in and edit every command you have though. Instead you edit the base command class for your -custom commands (like `MuxCommand` in your `mygame/commands/command.py` folder) and overload the -`at_post_cmd()` hook. This hook is always called *after* the main `func()` method of the Command. - -```python -from evennia import default_cmds - -class MuxCommand(default_cmds.MuxCommand): - # ... - def at_post_cmd(self): - "called after self.func()." - caller = self.caller - prompt = "%i HP, %i MP, %i SP" % (caller.db.hp, - caller.db.mp, - caller.db.sp) - caller.msg(prompt=prompt) - -``` - -### Modifying default commands - -If you want to add something small like this to Evennia's default commands without modifying them -directly the easiest way is to just wrap those with a multiple inheritance to your own base class: - -```python -# in (for example) mygame/commands/mycommands.py - -from evennia import default_cmds -# our custom MuxCommand with at_post_cmd hook -from commands.command import MuxCommand - -# overloading the look command -class CmdLook(default_cmds.CmdLook, MuxCommand): - pass -``` - -The result of this is that the hooks from your custom `MuxCommand` will be mixed into the default -`CmdLook` through multiple inheritance. Next you just add this to your default command set: - -```python -# in mygame/commands/default_cmdsets.py - -from evennia import default_cmds -from commands import mycommands - -class CharacterCmdSet(default_cmds.CharacterCmdSet): - # ... - def at_cmdset_creation(self): - # ... - self.add(mycommands.CmdLook()) -``` - -This will automatically replace the default `look` command in your game with your own version. \ No newline at end of file diff --git a/docs/0.9.5/_sources/Command-Sets.md.txt b/docs/0.9.5/_sources/Command-Sets.md.txt deleted file mode 100644 index ab4d56a446..0000000000 --- a/docs/0.9.5/_sources/Command-Sets.md.txt +++ /dev/null @@ -1,376 +0,0 @@ -# Command Sets - - -Command Sets are intimately linked with [Commands](./Commands.md) and you should be familiar with -Commands before reading this page. The two pages were split for ease of reading. - -A *Command Set* (often referred to as a CmdSet or cmdset) is the basic unit for storing one or more -*Commands*. A given Command can go into any number of different command sets. Storing Command -classes in a command set is the way to make commands available to use in your game. - -When storing a CmdSet on an object, you will make the commands in that command set available to the -object. An example is the default command set stored on new Characters. This command set contains -all the useful commands, from `look` and `inventory` to `@dig` and `@reload` -([permissions](./Locks.md#permissions) then limit which players may use them, but that's a separate -topic). - -When an account enters a command, cmdsets from the Account, Character, its location, and elsewhere -are pulled together into a *merge stack*. This stack is merged together in a specific order to -create a single "merged" cmdset, representing the pool of commands available at that very moment. - -An example would be a `Window` object that has a cmdset with two commands in it: `look through -window` and `open window`. The command set would be visible to players in the room with the window, -allowing them to use those commands only there. You could imagine all sorts of clever uses of this, -like a `Television` object which had multiple commands for looking at it, switching channels and so -on. The tutorial world included with Evennia showcases a dark room that replaces certain critical -commands with its own versions because the Character cannot see. - -If you want a quick start into defining your first commands and using them with command sets, you -can head over to the [Adding Command Tutorial](./Adding-Command-Tutorial.md) which steps through things -without the explanations. - -## Defining Command Sets - -A CmdSet is, as most things in Evennia, defined as a Python class inheriting from the correct parent -(`evennia.CmdSet`, which is a shortcut to `evennia.commands.cmdset.CmdSet`). The CmdSet class only -needs to define one method, called `at_cmdset_creation()`. All other class parameters are optional, -but are used for more advanced set manipulation and coding (see the [merge rules](Command- -Sets#merge-rules) section). - -```python -# file mygame/commands/mycmdset.py - -from evennia import CmdSet - -# this is a theoretical custom module with commands we -# created previously: mygame/commands/mycommands.py -from commands import mycommands - -class MyCmdSet(CmdSet): - def at_cmdset_creation(self): - """ - The only thing this method should need - to do is to add commands to the set. - """ - self.add(mycommands.MyCommand1()) - self.add(mycommands.MyCommand2()) - self.add(mycommands.MyCommand3()) -``` - -The CmdSet's `add()` method can also take another CmdSet as input. In this case all the commands -from that CmdSet will be appended to this one as if you added them line by line: - -```python - def at_cmdset_creation(): - ... - self.add(AdditionalCmdSet) # adds all command from this set - ... -``` - -If you added your command to an existing cmdset (like to the default cmdset), that set is already -loaded into memory. You need to make the server aware of the code changes: - -``` -@reload -``` - -You should now be able to use the command. - -If you created a new, fresh cmdset, this must be added to an object in order to make the commands -within available. A simple way to temporarily test a cmdset on yourself is use the `@py` command to -execute a python snippet: - -```python -@py self.cmdset.add('commands.mycmdset.MyCmdSet') -``` - -This will stay with you until you `@reset` or `@shutdown` the server, or you run - -```python -@py self.cmdset.delete('commands.mycmdset.MyCmdSet') -``` - -In the example above, a specific Cmdset class is removed. Calling `delete` without arguments will -remove the latest added cmdset. - -> Note: Command sets added using `cmdset.add` are, by default, *not* persistent in the database. - -If you want the cmdset to survive a reload, you can do: - -``` -@py self.cmdset.add(commands.mycmdset.MyCmdSet, permanent=True) -``` - -Or you could add the cmdset as the *default* cmdset: - -``` -@py self.cmdset.add_default(commands.mycmdset.MyCmdSet) -``` - -An object can only have one "default" cmdset (but can also have none). This is meant as a safe fall- -back even if all other cmdsets fail or are removed. It is always persistent and will not be affected -by `cmdset.delete()`. To remove a default cmdset you must explicitly call `cmdset.remove_default()`. - -Command sets are often added to an object in its `at_object_creation` method. For more examples of -adding commands, read the [Step by step tutorial](./Adding-Command-Tutorial.md). Generally you can -customize which command sets are added to your objects by using `self.cmdset.add()` or -`self.cmdset.add_default()`. - -> Important: Commands are identified uniquely by key *or* alias (see [Commands](./Commands.md)). If any -overlap exists, two commands are considered identical. Adding a Command to a command set that -already has an identical command will *replace* the previous command. This is very important. You -must take this behavior into account when attempting to overload any default Evennia commands with -your own. Otherwise, you may accidentally "hide" your own command in your command set when adding a -new one that has a matching alias. - -### Properties on Command Sets - -There are several extra flags that you can set on CmdSets in order to modify how they work. All are -optional and will be set to defaults otherwise. Since many of these relate to *merging* cmdsets, -you might want to read the [Adding and Merging Command Sets](./Command-Sets.md#adding-and-merging- -command-sets) section for some of these to make sense. - -- `key` (string) - an identifier for the cmdset. This is optional, but should be unique. It is used -for display in lists, but also to identify special merging behaviours using the `key_mergetype` -dictionary below. -- `mergetype` (string) - allows for one of the following string values: "*Union*", "*Intersect*", -"*Replace*", or "*Remove*". -- `priority` (int) - This defines the merge order of the merge stack - cmdsets will merge in rising -order of priority with the highest priority set merging last. During a merger, the commands from the -set with the higher priority will have precedence (just what happens depends on the [merge -type](./Command-Sets.md#adding-and-merging-command-sets)). If priority is identical, the order in the -merge stack determines preference. The priority value must be greater or equal to `-100`. Most in- -game sets should usually have priorities between `0` and `100`. Evennia default sets have priorities -as follows (these can be changed if you want a different distribution): - - EmptySet: `-101` (should be lower than all other sets) - - SessionCmdSet: `-20` - - AccountCmdSet: `-10` - - CharacterCmdSet: `0` - - ExitCmdSet: ` 101` (generally should always be available) - - ChannelCmdSet: `101` (should usually always be available) - since exits never accept -arguments, there is no collision between exits named the same as a channel even though the commands -"collide". -- `key_mergetype` (dict) - a dict of `key:mergetype` pairs. This allows this cmdset to merge -differently with certain named cmdsets. If the cmdset to merge with has a `key` matching an entry in -`key_mergetype`, it will not be merged according to the setting in `mergetype` but according to the -mode in this dict. Please note that this is more complex than it may seem due to the [merge -order](./Command-Sets.md#adding-and-merging-command-sets) of command sets. Please review that section -before using `key_mergetype`. -- `duplicates` (bool/None default `None`) - this determines what happens when merging same-priority -cmdsets containing same-key commands together. The`dupicate` option will *only* apply when merging -the cmdset with this option onto one other cmdset with the same priority. The resulting cmdset will -*not* retain this `duplicate` setting. - - `None` (default): No duplicates are allowed and the cmdset being merged "onto" the old one -will take precedence. The result will be unique commands. *However*, the system will assume this -value to be `True` for cmdsets on Objects, to avoid dangerous clashes. This is usually the safe bet. - - `False`: Like `None` except the system will not auto-assume any value for cmdsets defined on -Objects. - - `True`: Same-named, same-prio commands will merge into the same cmdset. This will lead to a -multimatch error (the user will get a list of possibilities in order to specify which command they -meant). This is is useful e.g. for on-object cmdsets (example: There is a `red button` and a `green -button` in the room. Both have a `press button` command, in cmdsets with the same priority. This -flag makes sure that just writing `press button` will force the Player to define just which object's -command was intended). -- `no_objs` this is a flag for the cmdhandler that builds the set of commands available at every -moment. It tells the handler not to include cmdsets from objects around the account (nor from rooms -or inventory) when building the merged set. Exit commands will still be included. This option can -have three values: - - `None` (default): Passthrough of any value set explicitly earlier in the merge stack. If never -set explicitly, this acts as `False`. - - `True`/`False`: Explicitly turn on/off. If two sets with explicit `no_objs` are merged, -priority determines what is used. -- `no_exits` - this is a flag for the cmdhandler that builds the set of commands available at every -moment. It tells the handler not to include cmdsets from exits. This flag can have three values: - - `None` (default): Passthrough of any value set explicitly earlier in the merge stack. If -never set explicitly, this acts as `False`. - - `True`/`False`: Explicitly turn on/off. If two sets with explicit `no_exits` are merged, -priority determines what is used. -- `no_channels` (bool) - this is a flag for the cmdhandler that builds the set of commands available -at every moment. It tells the handler not to include cmdsets from available in-game channels. This -flag can have three values: - - `None` (default): Passthrough of any value set explicitly earlier in the merge stack. If -never set explicitly, this acts as `False`. - - `True`/`False`: Explicitly turn on/off. If two sets with explicit `no_channels` are merged, -priority determines what is used. - -## Command Sets Searched - -When a user issues a command, it is matched against the [merged](./Command-Sets.md#adding-and-merging- -command-sets) command sets available to the player at the moment. Which those are may change at any -time (such as when the player walks into the room with the `Window` object described earlier). - -The currently valid command sets are collected from the following sources: - -- The cmdsets stored on the currently active [Session](./Sessions.md). Default is the empty -`SessionCmdSet` with merge priority `-20`. -- The cmdsets defined on the [Account](./Accounts.md). Default is the AccountCmdSet with merge priority -`-10`. -- All cmdsets on the Character/Object (assuming the Account is currently puppeting such a -Character/Object). Merge priority `0`. -- The cmdsets of all objects carried by the puppeted Character (checks the `call` lock). Will not be -included if `no_objs` option is active in the merge stack. -- The cmdsets of the Character's current location (checks the `call` lock). Will not be included if -`no_objs` option is active in the merge stack. -- The cmdsets of objects in the current location (checks the `call` lock). Will not be included if -`no_objs` option is active in the merge stack. -- The cmdsets of Exits in the location. Merge priority `+101`. Will not be included if `no_exits` -*or* `no_objs` option is active in the merge stack. -- The [channel](./Communications.md) cmdset containing commands for posting to all channels the account -or character is currently connected to. Merge priority `+101`. Will not be included if `no_channels` -option is active in the merge stack. - -Note that an object does not *have* to share its commands with its surroundings. A Character's -cmdsets should not be shared for example, or all other Characters would get multi-match errors just -by being in the same room. The ability of an object to share its cmdsets is managed by its `call` -[lock](./Locks.md). For example, [Character objects](./Objects.md) defaults to `call:false()` so that any -cmdsets on them can only be accessed by themselves, not by other objects around them. Another -example might be to lock an object with `call:inside()` to only make their commands available to -objects inside them, or `cmd:holds()` to make their commands available only if they are held. - -## Adding and Merging Command Sets - -*Note: This is an advanced topic. It's very useful to know about, but you might want to skip it if -this is your first time learning about commands.* - -CmdSets have the special ability that they can be *merged* together into new sets. Which of the -ingoing commands end up in the merged set is defined by the *merge rule* and the relative -*priorities* of the two sets. Removing the latest added set will restore things back to the way it -was before the addition. - -CmdSets are non-destructively stored in a stack inside the cmdset handler on the object. This stack -is parsed to create the "combined" cmdset active at the moment. CmdSets from other sources are also -included in the merger such as those on objects in the same room (like buttons to press) or those -introduced by state changes (such as when entering a menu). The cmdsets are all ordered after -priority and then merged together in *reverse order*. That is, the higher priority will be merged -"onto" lower-prio ones. By defining a cmdset with a merge-priority between that of two other sets, -you will make sure it will be merged in between them. -The very first cmdset in this stack is called the *Default cmdset* and is protected from accidental -deletion. Running `obj.cmdset.delete()` will never delete the default set. Instead one should add -new cmdsets on top of the default to "hide" it, as described below. Use the special -`obj.cmdset.delete_default()` only if you really know what you are doing. - -CmdSet merging is an advanced feature useful for implementing powerful game effects. Imagine for -example a player entering a dark room. You don't want the player to be able to find everything in -the room at a glance - maybe you even want them to have a hard time to find stuff in their backpack! -You can then define a different CmdSet with commands that override the normal ones. While they are -in the dark room, maybe the `look` and `inv` commands now just tell the player they cannot see -anything! Another example would be to offer special combat commands only when the player is in -combat. Or when being on a boat. Or when having taken the super power-up. All this can be done on -the fly by merging command sets. - -### Merge Rules - -Basic rule is that command sets are merged in *reverse priority order*. That is, lower-prio sets are -merged first and higher prio sets are merged "on top" of them. Think of it like a layered cake with -the highest priority on top. - -To further understand how sets merge, we need to define some examples. Let's call the first command -set **A** and the second **B**. We assume **B** is the command set already active on our object and -we will merge **A** onto **B**. In code terms this would be done by `object.cdmset.add(A)`. -Remember, B is already active on `object` from before. - -We let the **A** set have higher priority than **B**. A priority is simply an integer number. As -seen in the list above, Evennia's default cmdsets have priorities in the range `-101` to `120`. You -are usually safe to use a priority of `0` or `1` for most game effects. - -In our examples, both sets contain a number of commands which we'll identify by numbers, like `A1, -A2` for set **A** and `B1, B2, B3, B4` for **B**. So for that example both sets contain commands -with the same keys (or aliases) "1" and "2" (this could for example be "look" and "get" in the real -game), whereas commands 3 and 4 are unique to **B**. To describe a merge between these sets, we -would write `A1,A2 + B1,B2,B3,B4 = ?` where `?` is a list of commands that depend on which merge -type **A** has, and which relative priorities the two sets have. By convention, we read this -statement as "New command set **A** is merged onto the old command set **B** to form **?**". - -Below are the available merge types and how they work. Names are partly borrowed from [Set -theory](http://en.wikipedia.org/wiki/Set_theory). - -- **Union** (default) - The two cmdsets are merged so that as many commands as possible from each -cmdset ends up in the merged cmdset. Same-key commands are merged by priority. - - # Union - A1,A2 + B1,B2,B3,B4 = A1,A2,B3,B4 - -- **Intersect** - Only commands found in *both* cmdsets (i.e. which have the same keys) end up in -the merged cmdset, with the higher-priority cmdset replacing the lower one's commands. - - # Intersect - A1,A3,A5 + B1,B2,B4,B5 = A1,A5 - -- **Replace** - The commands of the higher-prio cmdset completely replaces the lower-priority -cmdset's commands, regardless of if same-key commands exist or not. - - # Replace - A1,A3 + B1,B2,B4,B5 = A1,A3 - -- **Remove** - The high-priority command sets removes same-key commands from the lower-priority -cmdset. They are not replaced with anything, so this is a sort of filter that prunes the low-prio -set using the high-prio one as a template. - - # Remove - A1,A3 + B1,B2,B3,B4,B5 = B2,B4,B5 - -Besides `priority` and `mergetype`, a command-set also takes a few other variables to control how -they merge: - -- `duplicates` (bool) - determines what happens when two sets of equal priority merge. Default is -that the new set in the merger (i.e. **A** above) automatically takes precedence. But if -*duplicates* is true, the result will be a merger with more than one of each name match. This will -usually lead to the player receiving a multiple-match error higher up the road, but can be good for -things like cmdsets on non-player objects in a room, to allow the system to warn that more than one -'ball' in the room has the same 'kick' command defined on it and offer a chance to select which -ball to kick ... Allowing duplicates only makes sense for *Union* and *Intersect*, the setting is -ignored for the other mergetypes. -- `key_mergetypes` (dict) - allows the cmdset to define a unique mergetype for particular cmdsets, -identified by their cmdset `key`. Format is `{CmdSetkey:mergetype}`. Example: -`{'Myevilcmdset','Replace'}` which would make sure for this set to always use 'Replace' on the -cmdset with the key `Myevilcmdset` only, no matter what the main `mergetype` is set to. - -> Warning: The `key_mergetypes` dictionary *can only work on the cmdset we merge onto*. When using -`key_mergetypes` it is thus important to consider the merge priorities - you must make sure that you -pick a priority *between* the cmdset you want to detect and the next higher one, if any. That is, if -we define a cmdset with a high priority and set it to affect a cmdset that is far down in the merge -stack, we would not "see" that set when it's time for us to merge. Example: Merge stack is -`A(prio=-10), B(prio=-5), C(prio=0), D(prio=5)`. We now merge a cmdset `E(prio=10)` onto this stack, -with a `key_mergetype={"B":"Replace"}`. But priorities dictate that we won't be merged onto B, we -will be merged onto E (which is a merger of the lower-prio sets at this point). Since we are merging -onto E and not B, our `key_mergetype` directive won't trigger. To make sure it works we must make -sure we merge onto B. Setting E's priority to, say, -4 will make sure to merge it onto B and affect -it appropriately. - -More advanced cmdset example: - -```python -from commands import mycommands - -class MyCmdSet(CmdSet): - - key = "MyCmdSet" - priority = 4 - mergetype = "Replace" - key_mergetypes = {'MyOtherCmdSet':'Union'} - - def at_cmdset_creation(self): - """ - The only thing this method should need - to do is to add commands to the set. - """ - self.add(mycommands.MyCommand1()) - self.add(mycommands.MyCommand2()) - self.add(mycommands.MyCommand3()) -``` - -### Assorted Notes - -It is very important to remember that two commands are compared *both* by their `key` properties -*and* by their `aliases` properties. If either keys or one of their aliases match, the two commands -are considered the *same*. So consider these two Commands: - - - A Command with key "kick" and alias "fight" - - A Command with key "punch" also with an alias "fight" - -During the cmdset merging (which happens all the time since also things like channel commands and -exits are merged in), these two commands will be considered *identical* since they share alias. It -means only one of them will remain after the merger. Each will also be compared with all other -commands having any combination of the keys and/or aliases "kick", "punch" or "fight". - -... So avoid duplicate aliases, it will only cause confusion. \ No newline at end of file diff --git a/docs/0.9.5/_sources/Command-System.md.txt b/docs/0.9.5/_sources/Command-System.md.txt deleted file mode 100644 index 364d6f09ef..0000000000 --- a/docs/0.9.5/_sources/Command-System.md.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Command System - -- [Commands](./Commands.md) -- [Command Sets](./Command-Sets.md) -- [Command Auto-help](./Help-System.md#command-auto-help-system) - -See also: -- [Default Command Help](./Default-Commands.md) -- [Adding Command Tutorial](./Adding-Command-Tutorial.md) \ No newline at end of file diff --git a/docs/0.9.5/_sources/Commands.md.txt b/docs/0.9.5/_sources/Commands.md.txt deleted file mode 100644 index 934579acb8..0000000000 --- a/docs/0.9.5/_sources/Commands.md.txt +++ /dev/null @@ -1,663 +0,0 @@ -# Commands - - -Commands are intimately linked to [Command Sets](./Command-Sets.md) and you need to read that page too to -be familiar with how the command system works. The two pages were split for easy reading. - -The basic way for users to communicate with the game is through *Commands*. These can be commands -directly related to the game world such as *look*, *get*, *drop* and so on, or administrative -commands such as *examine* or *@dig*. - -The [default commands](./Default-Commands.md) coming with Evennia are 'MUX-like' in that they use @ -for admin commands, support things like switches, syntax with the '=' symbol etc, but there is -nothing that prevents you from implementing a completely different command scheme for your game. You -can find the default commands in `evennia/commands/default`. You should not edit these directly - -they will be updated by the Evennia team as new features are added. Rather you should look to them -for inspiration and inherit your own designs from them. - -There are two components to having a command running - the *Command* class and the [Command -Set](./Command-Sets.md) (command sets were split into a separate wiki page for ease of reading). - -1. A *Command* is a python class containing all the functioning code for what a command does - for -example, a *get* command would contain code for picking up objects. -1. A *Command Set* (often referred to as a CmdSet or cmdset) is like a container for one or more -Commands. A given Command can go into any number of different command sets. Only by putting the -command set on a character object you will make all the commands therein available to use by that -character. You can also store command sets on normal objects if you want users to be able to use the -object in various ways. Consider a "Tree" object with a cmdset defining the commands *climb* and -*chop down*. Or a "Clock" with a cmdset containing the single command *check time*. - -This page goes into full detail about how to use Commands. To fully use them you must also read the -page detailing [Command Sets](./Command-Sets.md). There is also a step-by-step [Adding Command -Tutorial](./Adding-Command-Tutorial.md) that will get you started quickly without the extra explanations. - -## Defining Commands - -All commands are implemented as normal Python classes inheriting from the base class `Command` -(`evennia.Command`). You will find that this base class is very "bare". The default commands of -Evennia actually inherit from a child of `Command` called `MuxCommand` - this is the class that -knows all the mux-like syntax like `/switches`, splitting by "=" etc. Below we'll avoid mux- -specifics and use the base `Command` class directly. - -```python - # basic Command definition - from evennia import Command - - class MyCmd(Command): - """ - This is the help-text for the command - """ - key = "mycommand" - def parse(self): - # parsing the command line here - def func(self): - # executing the command here -``` - -Here is a minimalistic command with no custom parsing: - -```python - from evennia import Command - - class CmdEcho(Command): - key = "echo" - - def func(self): - # echo the caller's input back to the caller - self.caller.msg("Echo: {}".format(self.args) - -``` - -You define a new command by assigning a few class-global properties on your inherited class and -overloading one or two hook functions. The full gritty mechanic behind how commands work are found -towards the end of this page; for now you only need to know that the command handler creates an -instance of this class and uses that instance whenever you use this command - it also dynamically -assigns the new command instance a few useful properties that you can assume to always be available. - -### Who is calling the command? - -In Evennia there are three types of objects that may call the command. It is important to be aware -of this since this will also assign appropriate `caller`, `session`, `sessid` and `account` -properties on the command body at runtime. Most often the calling type is `Session`. - -* A [Session](./Sessions.md). This is by far the most common case when a user is entering a command in -their client. - * `caller` - this is set to the puppeted [Object](./Objects.md) if such an object exists. If no -puppet is found, `caller` is set equal to `account`. Only if an Account is not found either (such as -before being logged in) will this be set to the Session object itself. - * `session` - a reference to the [Session](./Sessions.md) object itself. - * `sessid` - `sessid.id`, a unique integer identifier of the session. - * `account` - the [Account](./Accounts.md) object connected to this Session. None if not logged in. -* An [Account](./Accounts.md). This only happens if `account.execute_cmd()` was used. No Session -information can be obtained in this case. - * `caller` - this is set to the puppeted Object if such an object can be determined (without -Session info this can only be determined in `MULTISESSION_MODE=0` or `1`). If no puppet is found, -this is equal to `account`. - * `session` - `None*` - * `sessid` - `None*` - * `account` - Set to the Account object. -* An [Object](./Objects.md). This only happens if `object.execute_cmd()` was used (for example by an -NPC). - * `caller` - This is set to the calling Object in question. - * `session` - `None*` - * `sessid` - `None*` - * `account` - `None` - -> `*)`: There is a way to make the Session available also inside tests run directly on Accounts and -Objects, and that is to pass it to `execute_cmd` like so: `account.execute_cmd("...", -session=)`. Doing so *will* make the `.session` and `.sessid` properties available in the -command. - -### Properties assigned to the command instance at run-time - -Let's say account *Bob* with a character *BigGuy* enters the command *look at sword*. After the -system having successfully identified this as the "look" command and determined that BigGuy really -has access to a command named `look`, it chugs the `look` command class out of storage and either -loads an existing Command instance from cache or creates one. After some more checks it then assigns -it the following properties: - -- `caller` - The character BigGuy, in this example. This is a reference to the object executing the -command. The value of this depends on what type of object is calling the command; see the previous -section. -- `session` - the [Session](./Sessions.md) Bob uses to connect to the game and control BigGuy (see also -previous section). -- `sessid` - the unique id of `self.session`, for quick lookup. -- `account` - the [Account](./Accounts.md) Bob (see previous section). -- `cmdstring` - the matched key for the command. This would be *look* in our example. -- `args` - this is the rest of the string, except the command name. So if the string entered was -*look at sword*, `args` would be " *at sword*". Note the space kept - Evennia would correctly -interpret `lookat sword` too. This is useful for things like `/switches` that should not use space. -In the `MuxCommand` class used for default commands, this space is stripped. Also see the -`arg_regex` property if you want to enforce a space to make `lookat sword` give a command-not-found -error. -- `obj` - the game [Object](./Objects.md) on which this command is defined. This need not be the caller, -but since `look` is a common (default) command, this is probably defined directly on *BigGuy* - so -`obj` will point to BigGuy. Otherwise `obj` could be an Account or any interactive object with -commands defined on it, like in the example of the "check time" command defined on a "Clock" object. -- `cmdset` - this is a reference to the merged CmdSet (see below) from which this command was -matched. This variable is rarely used, it's main use is for the [auto-help system](Help- -System#command-auto-help-system) (*Advanced note: the merged cmdset need NOT be the same as -`BigGuy.cmdset`. The merged set can be a combination of the cmdsets from other objects in the room, -for example*). -- `raw_string` - this is the raw input coming from the user, without stripping any surrounding -whitespace. The only thing that is stripped is the ending newline marker. - -#### Other useful utility methods: - -- `.get_help(caller, cmdset)` - Get the help entry for this command. By default the arguments are -not - used, but they could be used to implement alternate help-display systems. -- `.client_width()` - Shortcut for getting the client's screen-width. Note that not all clients will - truthfully report this value - that case the `settings.DEFAULT_SCREEN_WIDTH` will be returned. -- `.styled_table(*args, **kwargs)` - This returns an [EvTable](module- -evennia.utils.evtable) styled based on the - session calling this command. The args/kwargs are the same as for EvTable, except styling defaults -are set. -- `.styled_header`, `_footer`, `separator` - These will produce styled decorations for - display to the user. They are useful for creating listings and forms with colors adjustable per- -user. - -### Defining your own command classes - -Beyond the properties Evennia always assigns to the command at run-time (listed above), your job is -to define the following class properties: - -- `key` (string) - the identifier for the command, like `look`. This should (ideally) be unique. A -key can consist of more than one word, like "press button" or "pull left lever". Note that *both* -`key` and `aliases` below determine the identity of a command. So two commands are considered if -either matches. This is important for merging cmdsets described below. -- `aliases` (optional list) - a list of alternate names for the command (`["glance", "see", "l"]`). -Same name rules as for `key` applies. -- `locks` (string) - a [lock definition](./Locks.md), usually on the form `cmd:`. Locks is a -rather big topic, so until you learn more about locks, stick to giving the lockstring `"cmd:all()"` -to make the command available to everyone (if you don't provide a lock string, this will be assigned -for you). -- `help_category` (optional string) - setting this helps to structure the auto-help into categories. -If none is set, this will be set to *General*. -- `save_for_next` (optional boolean). This defaults to `False`. If `True`, a copy of this command -object (along with any changes you have done to it) will be stored by the system and can be accessed -by the next command by retrieving `self.caller.ndb.last_cmd`. The next run command will either clear -or replace the storage. -- `arg_regex` (optional raw string): Used to force the parser to limit itself and tell it when the -command-name ends and arguments begin (such as requiring this to be a space or a /switch). This is -done with a regular expression. [See the arg_regex section](./Commands.md#on-arg_regex) for the details. -- `auto_help` (optional boolean). Defaults to `True`. This allows for turning off the [auto-help -system](./Help-System.md#command-auto-help-system) on a per-command basis. This could be useful if you -either want to write your help entries manually or hide the existence of a command from `help`'s -generated list. -- `is_exit` (bool) - this marks the command as being used for an in-game exit. This is, by default, -set by all Exit objects and you should not need to set it manually unless you make your own Exit -system. It is used for optimization and allows the cmdhandler to easily disregard this command when -the cmdset has its `no_exits` flag set. -- `is_channel` (bool)- this marks the command as being used for an in-game channel. This is, by -default, set by all Channel objects and you should not need to set it manually unless you make your -own Channel system. is used for optimization and allows the cmdhandler to easily disregard this -command when its cmdset has its `no_channels` flag set. -- `msg_all_sessions` (bool): This affects the behavior of the `Command.msg` method. If unset -(default), calling `self.msg(text)` from the Command will always only send text to the Session that -actually triggered this Command. If set however, `self.msg(text)` will send to all Sessions relevant -to the object this Command sits on. Just which Sessions receives the text depends on the object and -the server's `MULTISESSION_MODE`. - -You should also implement at least two methods, `parse()` and `func()` (You could also implement -`perm()`, but that's not needed unless you want to fundamentally change how access checks work). - -- `at_pre_cmd()` is called very first on the command. If this function returns anything that -evaluates to `True` the command execution is aborted at this point. -- `parse()` is intended to parse the arguments (`self.args`) of the function. You can do this in any -way you like, then store the result(s) in variable(s) on the command object itself (i.e. on `self`). -To take an example, the default mux-like system uses this method to detect "command switches" and -store them as a list in `self.switches`. Since the parsing is usually quite similar inside a command -scheme you should make `parse()` as generic as possible and then inherit from it rather than re- -implementing it over and over. In this way, the default `MuxCommand` class implements a `parse()` -for all child commands to use. -- `func()` is called right after `parse()` and should make use of the pre-parsed input to actually -do whatever the command is supposed to do. This is the main body of the command. The return value -from this method will be returned from the execution as a Twisted Deferred. -- `at_post_cmd()` is called after `func()` to handle eventual cleanup. - -Finally, you should always make an informative [doc -string](http://www.python.org/dev/peps/pep-0257/#what-is-a-docstring) (`__doc__`) at the top of your -class. This string is dynamically read by the [Help System](./Help-System.md) to create the help entry -for this command. You should decide on a way to format your help and stick to that. - -Below is how you define a simple alternative "`smile`" command: - -```python -from evennia import Command - -class CmdSmile(Command): - """ - A smile command - - Usage: - smile [at] [] - grin [at] [] - - Smiles to someone in your vicinity or to the room - in general. - - (This initial string (the __doc__ string) - is also used to auto-generate the help - for this command) - """ - - key = "smile" - aliases = ["smile at", "grin", "grin at"] - locks = "cmd:all()" - help_category = "General" - - def parse(self): - "Very trivial parser" - self.target = self.args.strip() - - def func(self): - "This actually does things" - caller = self.caller - - if not self.target or self.target == "here": - string = f"{caller.key} smiles" - else: - target = caller.search(self.target) - if not target: - return - string = f"{caller.key} smiles at {target.key}" - - caller.location.msg_contents(string) - -``` - -The power of having commands as classes and to separate `parse()` and `func()` -lies in the ability to inherit functionality without having to parse every -command individually. For example, as mentioned the default commands all -inherit from `MuxCommand`. `MuxCommand` implements its own version of `parse()` -that understands all the specifics of MUX-like commands. Almost none of the -default commands thus need to implement `parse()` at all, but can assume the -incoming string is already split up and parsed in suitable ways by its parent. - -Before you can actually use the command in your game, you must now store it -within a *command set*. See the [Command Sets](./Command-Sets.md) page. - -### On arg_regex - -The command parser is very general and does not require a space to end your command name. This means -that the alias `:` to `emote` can be used like `:smiles` without modification. It also means -`getstone` will get you the stone (unless there is a command specifically named `getstone`, then -that will be used). If you want to tell the parser to require a certain separator between the -command name and its arguments (so that `get stone` works but `getstone` gives you a 'command not -found' error) you can do so with the `arg_regex` property. - -The `arg_regex` is a [raw regular expression string](http://docs.python.org/library/re.html). The -regex will be compiled by the system at runtime. This allows you to customize how the part -*immediately following* the command name (or alias) must look in order for the parser to match for -this command. Some examples: - -- `commandname argument` (`arg_regex = r"\s.+"`): This forces the parser to require the command name -to be followed by one or more spaces. Whatever is entered after the space will be treated as an -argument. However, if you'd forget the space (like a command having no arguments), this would *not* -match `commandname`. -- `commandname` or `commandname argument` (`arg_regex = r"\s.+|$"`): This makes both `look` and -`look me` work but `lookme` will not. -- `commandname/switches arguments` (`arg_regex = r"(?:^(?:\s+|\/).*$)|^$"`. If you are using -Evennia's `MuxCommand` Command parent, you may wish to use this since it will allow `/switche`s to -work as well as having or not having a space. - -The `arg_regex` allows you to customize the behavior of your commands. You can put it in the parent -class of your command to customize all children of your Commands. However, you can also change the -base default behavior for all Commands by modifying `settings.COMMAND_DEFAULT_ARG_REGEX`. - -## Exiting a command - -Normally you just use `return` in one of your Command class' hook methods to exit that method. That -will however still fire the other hook methods of the Command in sequence. That's usually what you -want but sometimes it may be useful to just abort the command, for example if you find some -unacceptable input in your parse method. To exit the command this way you can raise -`evennia.InterruptCommand`: - -```python -from evennia import InterruptCommand - -class MyCommand(Command): - - # ... - - def parse(self): - # ... - # if this fires, `func()` and `at_post_cmd` will not - # be called at all - raise InterruptCommand() - -``` - -## Pauses in commands - -Sometimes you want to pause the execution of your command for a little while before continuing - -maybe you want to simulate a heavy swing taking some time to finish, maybe you want the echo of your -voice to return to you with an ever-longer delay. Since Evennia is running asynchronously, you -cannot use `time.sleep()` in your commands (or anywhere, really). If you do, the *entire game* will -be frozen for everyone! So don't do that. Fortunately, Evennia offers a really quick syntax for -making pauses in commands. - -In your `func()` method, you can use the `yield` keyword. This is a Python keyword that will freeze -the current execution of your command and wait for more before processing. - -> Note that you *cannot* just drop `yield` into any code and expect it to pause. Evennia will only -pause for you if you `yield` inside the Command's `func()` method. Don't expect it to work anywhere -else. - -Here's an example of a command using a small pause of five seconds between messages: - -```python -from evennia import Command - -class CmdWait(Command): - """ - A dummy command to show how to wait - - Usage: - wait - - """ - - key = "wait" - locks = "cmd:all()" - help_category = "General" - - def func(self): - """Command execution.""" - self.msg("Starting to wait ...") - yield 5 - self.msg("... This shows after 5 seconds. Waiting ...") - yield 2 - self.msg("... And now another 2 seconds have passed.") -``` - -The important line is the `yield 5` and `yield 2` lines. It will tell Evennia to pause execution -here and not continue until the number of seconds given has passed. - -There are two things to remember when using `yield` in your Command's `func` method: - -1. The paused state produced by the `yield` is not saved anywhere. So if the server reloads in the -middle of your command pausing, it will *not* resume when the server comes back up - the remainder -of the command will never fire. So be careful that you are not freezing the character or account in -a way that will not be cleared on reload. -2. If you use `yield` you may not also use `return ` in your `func` method. You'll get an -error explaining this. This is due to how Python generators work. You can however use a "naked" -`return` just fine. Usually there is no need for `func` to return a value, but if you ever do need -to mix `yield` with a final return value in the same `func`, look at [twisted.internet.defer.returnV -alue](https://twistedmatrix.com/documents/current/api/twisted.internet.defer.html#returnValue). - -## Asking for user input - -The `yield` keyword can also be used to ask for user input. Again you can't -use Python's `input` in your command, for it would freeze Evennia for -everyone while waiting for that user to input their text. Inside a Command's -`func` method, the following syntax can also be used: - -```python -answer = yield("Your question") -``` - -Here's a very simple example: - -```python -class CmdConfirm(Command): - - """ - A dummy command to show confirmation. - - Usage: - confirm - - """ - - key = "confirm" - - def func(self): - answer = yield("Are you sure you want to go on?") - if answer.strip().lower() in ("yes", "y"): - self.msg("Yes!") - else: - self.msg("No!") -``` - -This time, when the user enters the 'confirm' command, she will be asked if she wants to go on. -Entering 'yes' or "y" (regardless of case) will give the first reply, otherwise the second reply -will show. - -> Note again that the `yield` keyword does not store state. If the game reloads while waiting for -the user to answer, the user will have to start over. It is not a good idea to use `yield` for -important or complex choices, a persistent [EvMenu](./EvMenu.md) might be more appropriate in this case. - -## System commands - -*Note: This is an advanced topic. Skip it if this is your first time learning about commands.* - -There are several command-situations that are exceptional in the eyes of the server. What happens if -the account enters an empty string? What if the 'command' given is infact the name of a channel the -user wants to send a message to? Or if there are multiple command possibilities? - -Such 'special cases' are handled by what's called *system commands*. A system command is defined -in the same way as other commands, except that their name (key) must be set to one reserved by the -engine (the names are defined at the top of `evennia/commands/cmdhandler.py`). You can find (unused) -implementations of the system commands in `evennia/commands/default/system_commands.py`. Since these -are not (by default) included in any `CmdSet` they are not actually used, they are just there for -show. When the special situation occurs, Evennia will look through all valid `CmdSet`s for your -custom system command. Only after that will it resort to its own, hard-coded implementation. - -Here are the exceptional situations that triggers system commands. You can find the command keys -they use as properties on `evennia.syscmdkeys`: - -- No input (`syscmdkeys.CMD_NOINPUT`) - the account just pressed return without any input. Default -is to do nothing, but it can be useful to do something here for certain implementations such as line -editors that interpret non-commands as text input (an empty line in the editing buffer). -- Command not found (`syscmdkeys.CMD_NOMATCH`) - No matching command was found. Default is to -display the "Huh?" error message. -- Several matching commands where found (`syscmdkeys.CMD_MULTIMATCH`) - Default is to show a list of -matches. -- User is not allowed to execute the command (`syscmdkeys.CMD_NOPERM`) - Default is to display the -"Huh?" error message. -- Channel (`syscmdkeys.CMD_CHANNEL`) - This is a [Channel](./Communications.md) name of a channel you are -subscribing to - Default is to relay the command's argument to that channel. Such commands are -created by the Comm system on the fly depending on your subscriptions. -- New session connection (`syscmdkeys.CMD_LOGINSTART`). This command name should be put in the -`settings.CMDSET_UNLOGGEDIN`. Whenever a new connection is established, this command is always -called on the server (default is to show the login screen). - -Below is an example of redefining what happens when the account doesn't provide any input (e.g. just -presses return). Of course the new system command must be added to a cmdset as well before it will -work. - -```python - from evennia import syscmdkeys, Command - - class MyNoInputCommand(Command): - "Usage: Just press return, I dare you" - key = syscmdkeys.CMD_NOINPUT - def func(self): - self.caller.msg("Don't just press return like that, talk to me!") -``` - -## Dynamic Commands - -*Note: This is an advanced topic.* - -Normally Commands are created as fixed classes and used without modification. There are however -situations when the exact key, alias or other properties is not possible (or impractical) to pre- -code ([Exits](./Commands.md#exits) is an example of this). - -To create a command with a dynamic call signature, first define the command body normally in a class -(set your `key`, `aliases` to default values), then use the following call (assuming the command -class you created is named `MyCommand`): - -```python - cmd = MyCommand(key="newname", - aliases=["test", "test2"], - locks="cmd:all()", - ...) -``` - -*All* keyword arguments you give to the Command constructor will be stored as a property on the -command object. This will overload existing properties defined on the parent class. - -Normally you would define your class and only overload things like `key` and `aliases` at run-time. -But you could in principle also send method objects (like `func`) as keyword arguments in order to -make your command completely customized at run-time. - -## Exits - -*Note: This is an advanced topic.* - -Exits are examples of the use of a [Dynamic Command](./Commands.md#dynamic-commands). - -The functionality of [Exit](./Objects.md) objects in Evennia is not hard-coded in the engine. Instead -Exits are normal [typeclassed](./Typeclasses.md) objects that auto-create a [CmdSet](./Command-Sets.md) on -themselves when they load. This cmdset has a single dynamically created Command with the same -properties (key, aliases and locks) as the Exit object itself. When entering the name of the exit, -this dynamic exit-command is triggered and (after access checks) moves the Character to the exit's -destination. -Whereas you could customize the Exit object and its command to achieve completely different -behaviour, you will usually be fine just using the appropriate `traverse_*` hooks on the Exit -object. But if you are interested in really changing how things work under the hood, check out -`evennia/objects/objects.py` for how the `Exit` typeclass is set up. - -## Command instances are re-used - -*Note: This is an advanced topic that can be skipped when first learning about Commands.* - -A Command class sitting on an object is instantiated once and then re-used. So if you run a command -from object1 over and over you are in fact running the same command instance over and over (if you -run the same command but sitting on object2 however, it will be a different instance). This is -usually not something you'll notice, since every time the Command-instance is used, all the relevant -properties on it will be overwritten. But armed with this knowledge you can implement some of the -more exotic command mechanism out there, like the command having a 'memory' of what you last entered -so that you can back-reference the previous arguments etc. - -> Note: On a server reload, all Commands are rebuilt and memory is flushed. - -To show this in practice, consider this command: - -```python -class CmdTestID(Command): - key = "testid" - - def func(self): - - if not hasattr(self, "xval"): - self.xval = 0 - self.xval += 1 - - self.caller.msg("Command memory ID: {} (xval={})".format(id(self), self.xval)) - -``` - -Adding this to the default character cmdset gives a result like this in-game: - -``` -> testid -Command memory ID: 140313967648552 (xval=1) -> testid -Command memory ID: 140313967648552 (xval=2) -> testid -Command memory ID: 140313967648552 (xval=3) -``` - -Note how the in-memory address of the `testid` command never changes, but `xval` keeps ticking up. - -## Dynamically created commands - -*This is also an advanced topic.* - -Commands can also be created and added to a cmdset on the fly. Creating a class instance with a -keyword argument, will assign that keyword argument as a property on this paricular command: - -``` -class MyCmdSet(CmdSet): - - def at_cmdset_creation(self): - - self.add(MyCommand(myvar=1, foo="test") - -``` - -This will start the `MyCommand` with `myvar` and `foo` set as properties (accessable as `self.myvar` -and `self.foo`). How they are used is up to the Command. Remember however the discussion from the -previous section - since the Command instance is re-used, those properties will *remain* on the -command as long as this cmdset and the object it sits is in memory (i.e. until the next reload). -Unless `myvar` and `foo` are somehow reset when the command runs, they can be modified and that -change will be remembered for subsequent uses of the command. - - -## How commands actually work - -*Note: This is an advanced topic mainly of interest to server developers.* - -Any time the user sends text to Evennia, the server tries to figure out if the text entered -corresponds to a known command. This is how the command handler sequence looks for a logged-in user: - -1. A user enters a string of text and presses enter. -2. The user's Session determines the text is not some protocol-specific control sequence or OOB -command, but sends it on to the command handler. -3. Evennia's *command handler* analyzes the Session and grabs eventual references to Account and -eventual puppeted Characters (these will be stored on the command object later). The *caller* -property is set appropriately. -4. If input is an empty string, resend command as `CMD_NOINPUT`. If no such command is found in -cmdset, ignore. -5. If command.key matches `settings.IDLE_COMMAND`, update timers but don't do anything more. -6. The command handler gathers the CmdSets available to *caller* at this time: - - The caller's own currently active CmdSet. - - CmdSets defined on the current account, if caller is a puppeted object. - - CmdSets defined on the Session itself. - - The active CmdSets of eventual objects in the same location (if any). This includes commands -on [Exits](./Objects.md#exits). - - Sets of dynamically created *System commands* representing available -[Communications](./Communications.md#channels). -7. All CmdSets *of the same priority* are merged together in groups. Grouping avoids order- -dependent issues of merging multiple same-prio sets onto lower ones. -8. All the grouped CmdSets are *merged* in reverse priority into one combined CmdSet according to -each set's merge rules. -9. Evennia's *command parser* takes the merged cmdset and matches each of its commands (using its -key and aliases) against the beginning of the string entered by *caller*. This produces a set of -candidates. -10. The *cmd parser* next rates the matches by how many characters they have and how many percent -matches the respective known command. Only if candidates cannot be separated will it return multiple -matches. - - If multiple matches were returned, resend as `CMD_MULTIMATCH`. If no such command is found in -cmdset, return hard-coded list of matches. - - If no match was found, resend as `CMD_NOMATCH`. If no such command is found in cmdset, give -hard-coded error message. -11. If a single command was found by the parser, the correct command object is plucked out of -storage. This usually doesn't mean a re-initialization. -12. It is checked that the caller actually has access to the command by validating the *lockstring* -of the command. If not, it is not considered as a suitable match and `CMD_NOMATCH` is triggered. -13. If the new command is tagged as a channel-command, resend as `CMD_CHANNEL`. If no such command -is found in cmdset, use hard-coded implementation. -14. Assign several useful variables to the command instance (see previous sections). -15. Call `at_pre_command()` on the command instance. -16. Call `parse()` on the command instance. This is fed the remainder of the string, after the name -of the command. It's intended to pre-parse the string into a form useful for the `func()` method. -17. Call `func()` on the command instance. This is the functional body of the command, actually -doing useful things. -18. Call `at_post_command()` on the command instance. - -## Assorted notes - -The return value of `Command.func()` is a Twisted -[deferred](http://twistedmatrix.com/documents/current/core/howto/defer.html). -Evennia does not use this return value at all by default. If you do, you must -thus do so asynchronously, using callbacks. - -```python - # in command class func() - def callback(ret, caller): - caller.msg("Returned is %s" % ret) - deferred = self.execute_command("longrunning") - deferred.addCallback(callback, self.caller) -``` - -This is probably not relevant to any but the most advanced/exotic designs (one might use it to -create a "nested" command structure for example). - -The `save_for_next` class variable can be used to implement state-persistent commands. For example -it can make a command operate on "it", where it is determined by what the previous command operated -on. diff --git a/docs/0.9.5/_sources/Communications.md.txt b/docs/0.9.5/_sources/Communications.md.txt deleted file mode 100644 index 3c3056c54f..0000000000 --- a/docs/0.9.5/_sources/Communications.md.txt +++ /dev/null @@ -1,113 +0,0 @@ -# Communications - - -Apart from moving around in the game world and talking, players might need other forms of -communication. This is offered by Evennia's `Comm` system. Stock evennia implements a 'MUX-like' -system of channels, but there is nothing stopping you from changing things to better suit your -taste. - -Comms rely on two main database objects - `Msg` and `Channel`. There is also the `TempMsg` which -mimics the API of a `Msg` but has no connection to the database. - -## Msg - -The `Msg` object is the basic unit of communication in Evennia. A message works a little like an -e-mail; it always has a sender (a [Account](./Accounts.md)) and one or more recipients. The recipients -may be either other Accounts, or a *Channel* (see below). You can mix recipients to send the message -to both Channels and Accounts if you like. - -Once created, a `Msg` is normally not changed. It is peristently saved in the database. This allows -for comprehensive logging of communications. This could be useful for allowing senders/receivers to -have 'mailboxes' with the messages they want to keep. - -### Properties defined on `Msg` - -- `senders` - this is a reference to one or many [Account](./Accounts.md) or [Objects](./Objects.md) (normally -*Characters*) sending the message. This could also be an *External Connection* such as a message -coming in over IRC/IMC2 (see below). There is usually only one sender, but the types can also be -mixed in any combination. -- `receivers` - a list of target [Accounts](./Accounts.md), [Objects](./Objects.md) (usually *Characters*) or -*Channels* to send the message to. The types of receivers can be mixed in any combination. -- `header` - this is a text field for storing a title or header for the message. -- `message` - the actual text being sent. -- `date_sent` - when message was sent (auto-created). -- `locks` - a [lock definition](./Locks.md). -- `hide_from` - this can optionally hold a list of objects, accounts or channels to hide this `Msg` -from. This relationship is stored in the database primarily for optimization reasons, allowing for -quickly post-filter out messages not intended for a given target. There is no in-game methods for -setting this, it's intended to be done in code. - -You create new messages in code using `evennia.create_message` (or -`evennia.utils.create.create_message.`) - -## TempMsg - -`evennia.comms.models` also has `TempMsg` which mimics the API of `Msg` but is not connected to the -database. TempMsgs are used by Evennia for channel messages by default. They can be used for any -system expecting a `Msg` but when you don't actually want to save anything. - -## Channels - -Channels are [Typeclassed](./Typeclasses.md) entities, which mean they can be easily extended and their -functionality modified. To change which channel typeclass Evennia uses, change -settings.BASE_CHANNEL_TYPECLASS. - -Channels act as generic distributors of messages. Think of them as "switch boards" redistributing -`Msg` or `TempMsg` objects. Internally they hold a list of "listening" objects and any `Msg` (or -`TempMsg`) sent to the channel will be distributed out to all channel listeners. Channels have -[Locks](./Locks.md) to limit who may listen and/or send messages through them. - -The *sending* of text to a channel is handled by a dynamically created [Command](./Commands.md) that -always have the same name as the channel. This is created for each channel by the global -`ChannelHandler`. The Channel command is added to the Account's cmdset and normal command locks are -used to determine which channels are possible to write to. When subscribing to a channel, you can -then just write the channel name and the text to send. - -The default ChannelCommand (which can be customized by pointing `settings.CHANNEL_COMMAND_CLASS` to -your own command), implements a few convenient features: - - - It only sends `TempMsg` objects. Instead of storing individual entries in the database it instead -dumps channel output a file log in `server/logs/channel_.log`. This is mainly for -practical reasons - we find one rarely need to query individual Msg objects at a later date. Just -stupidly dumping the log to a file also means a lot less database overhead. - - It adds a `/history` switch to view the 20 last messages in the channel. These are read from the -end of the log file. One can also supply a line number to start further back in the file (but always -20 entries at a time). It's used like this: - - > public/history - > public/history 35 - - -There are two default channels created in stock Evennia - `MudInfo` and `Public`. `MudInfo` -receives server-related messages meant for Admins whereas `Public` is open to everyone to chat on -(all new accounts are automatically joined to it when logging in, it is useful for asking -questions). The default channels are defined by the `DEFAULT_CHANNELS` list (see -`evennia/settings_default.py` for more details). - -You create new channels with `evennia.create_channel` (or `evennia.utils.create.create_channel`). - -In code, messages are sent to a channel using the `msg` or `tempmsg` methods of channels: - - channel.msg(msgobj, header=None, senders=None, persistent=True) - -The argument `msgobj` can be either a string, a previously constructed `Msg` or a `TempMsg` - in the -latter cases all the following keywords are ignored since the message objects already contains all -this information. If `msgobj` is a string, the other keywords are used for creating a new `Msg` or -`TempMsg` on the fly, depending on if `persistent` is set or not. By default, a `TempMsg` is emitted -for channel communication (since the default ChannelCommand instead logs to a file). - -```python - # assume we have a 'sender' object and a channel named 'mychan' - - # manually sending a message to a channel - mychan.msg("Hello!", senders=[sender]) -``` - -### Properties defined on `Channel` - -- `key` - main name for channel -- `aliases` - alternative native names for channels -- `desc` - optional description of channel (seen in listings) -- `keep_log` (bool) - if the channel should store messages (default) -- `locks` - A [lock definition](./Locks.md). Channels normally use the access_types `send, control` and -`listen`. \ No newline at end of file diff --git a/docs/0.9.5/_sources/Connection-Screen.md.txt b/docs/0.9.5/_sources/Connection-Screen.md.txt deleted file mode 100644 index bb15919f30..0000000000 --- a/docs/0.9.5/_sources/Connection-Screen.md.txt +++ /dev/null @@ -1,36 +0,0 @@ -# Connection Screen - - -When you first connect to your game you are greeted by Evennia's default connection screen. - - - ============================================================== - Welcome to Evennia, version Beta-ra4d24e8a3cab+! - - If you have an existing account, connect to it by typing: - connect - If you need to create an account, type (without the <>'s): - create - - If you have spaces in your username, enclose it in quotes. - Enter help for more info. look will re-show this screen. - ============================================================== - -Effective, but not very exciting. You will most likely want to change this to be more unique for -your game. This is simple: - -1. Edit `mygame/server/conf/connection_screens.py`. -1. [Reload](./Start-Stop-Reload.md) Evennia. - -Evennia will look into this module and locate all *globally defined strings* in it. These strings -are used as the text in your connection screen and are shown to the user at startup. If more than -one such string/screen is defined in the module, a *random* screen will be picked from among those -available. - -### Commands available at the Connection Screen - -You can also customize the [Commands](./Commands.md) available to use while the connection screen is -shown (`connect`, `create` etc). These commands are a bit special since when the screen is running -the account is not yet logged in. A command is made available at the login screen by adding them to -`UnloggedinCmdSet` in `mygame/commands/default_cmdset.py`. See [Commands](./Commands.md) and the -tutorial section on how to add new commands to a default command set. diff --git a/docs/0.9.5/_sources/Continuous-Integration.md.txt b/docs/0.9.5/_sources/Continuous-Integration.md.txt deleted file mode 100644 index f4bf7e5199..0000000000 --- a/docs/0.9.5/_sources/Continuous-Integration.md.txt +++ /dev/null @@ -1,222 +0,0 @@ -# Continuous Integration - -One of the advantages of Evennia over traditional MUSH development systems is that Evennia is -capable of integrating into enterprise level integration environments and source control. Because of -this, it can also be the subject of automation for additional convenience, allowing a more -streamlined development environment. - -## What is Continuous Integration? - -[Continuous Integration (CI)](https://www.thoughtworks.com/continuous-integration) is a development -practice that requires developers to integrate code into a shared repository several times a day. -Each check-in is then verified by an automated build, allowing teams to detect problems early. - -For Evennia, continuous integration allows an automated build process to: -* Pull down a latest build from Source Control. -* Run migrations on the backing SQL database. -* Automate additional unique tasks for that project. -* Run unit tests. -* Publish those files to the server directory -* Reload the game. - -## Preparation -To prepare a CI environment for your `MU*`, it will be necessary to set up some prerequisite -software for your server. - -Among those you will need: -* A Continuous Integration Environment. - * I recommend [TeamCity](https://www.jetbrains.com/teamcity/) which has an in-depth [Setup -Guide](https://confluence.jetbrains.com/display/TCD8/Installing+and+Configuring+the+TeamCity+Server) -* [Source Control](./Version-Control.md) - * This could be Git or SVN or any other available SC. - -## Linux TeamCity Setup -For this part of the guide, an example setup will be provided for administrators running a TeamCity -build integration environment on Linux. - -After meeting the preparation steps for your specific environment, log on to your teamcity interface -at `http://:8111/`. - -Create a new project named "Evennia" and in it construct a new template called continuous- -integration. - -### A Quick Overview -Templates are fancy objects in TeamCity that allow an administrator to define build steps that are -shared between one or more build projects. Assigning a VCS Root (Source Control) is unnecessary at -this stage, primarily you'll be worrying about the build steps and your default parameters (both -visible on the tabs to the left.) - -### Template Setup - -In this template, you'll be outlining the steps necessary to build your specific game. (A number of -sample scripts are provided under this section below!) Click Build Steps and prepare your general -flow. For this example, we will be doing a few basic example steps: - -* Transforming the Settings.py file - * We do this to update ports or other information that make your production environment unique - from your development environment. -* Making migrations and migrating the game database. -* Publishing the game files. -* Reloading the server. - -For each step we'll being use the "Command Line Runner" (a fancy name for a shell script executor). - -* Create a build step with the name: Transform Configuration -* For the script add: - - ```bash - #!/bin/bash - # Replaces the game configuration with one - # appropriate for this deployment. - - CONFIG="%system.teamcity.build.checkoutDir%/server/conf/settings.py" - MYCONF="%system.teamcity.build.checkoutDir%/server/conf/my.cnf" - - sed -e 's/TELNET_PORTS = [4000]/TELNET_PORTS = [%game.ports%]/g' "$CONFIG" > "$CONFIG".tmp && mv -"$CONFIG".tmp "$CONFIG" - sed -e 's/WEBSERVER_PORTS = [(4001, 4002)]/WEBSERVER_PORTS = [%game.webports%]/g' "$CONFIG" > -"$CONFIG".tmp && mv "$CONFIG".tmp "$CONFIG" - - # settings.py MySQL DB configuration - echo Configuring Game Database... - echo "" >> "$CONFIG" - echo "######################################################################" >> "$CONFIG" - echo "# MySQL Database Configuration" >> "$CONFIG" - echo "######################################################################" >> "$CONFIG" - - echo "DATABASES = {" >> "$CONFIG" - echo " 'default': {" >> "$CONFIG" - echo " 'ENGINE': 'django.db.backends.mysql'," >> "$CONFIG" - echo " 'OPTIONS': {" >> "$CONFIG" - echo " 'read_default_file': 'server/conf/my.cnf'," >> "$CONFIG" - echo " }," >> "$CONFIG" - echo " }" >> "$CONFIG" - echo "}" >> "$CONFIG" - - # Create the My.CNF file. - echo "[client]" >> "$MYCONF" - echo "database = %mysql.db%" >> "$MYCONF" - echo "user = %mysql.user%" >> "$MYCONF" - echo "password = %mysql.pass%" >> "$MYCONF" - echo "default-character-set = utf8" >> "$MYCONF" - ``` - -If you look at the parameters side of the page after saving this script, you'll notice that some new -parameters have been populated for you. This is because we've included new teamcity configuration -parameters that are populated when the build itself is ran. When creating projects that inherit this -template, we'll be able to fill in or override those parameters for project-specific configuration. - -* Go ahead and create another build step called "Make Database Migration" - * If you're using SQLLite on your game, it will be prudent to change working directory on this -step to: %game.dir% -* In this script include: - - ```bash - #!/bin/bash - # Update the DB migration - - LOGDIR="server/logs" - - . %evenv.dir%/bin/activate - - # Check that the logs directory exists. - if [ ! -d "$LOGDIR" ]; then - # Control will enter here if $LOGDIR doesn't exist. - mkdir "$LOGDIR" - fi - - evennia makemigrations - ``` - -* Create yet another build step, this time named: "Execute Database Migration": - * If you're using SQLLite on your game, it will be prudent to change working directory on this -step to: %game.dir% - ```bash - #!/bin/bash - # Apply the database migration. - - LOGDIR="server/logs" - - . %evenv.dir%/bin/activate - - # Check that the logs directory exists. - if [ ! -d "$LOGDIR" ]; then - # Control will enter here if $LOGDIR doesn't exist. - mkdir "$LOGDIR" - fi - - evennia migrate - - ``` - -Our next build step is where we actually publish our build. Up until now, all work on game has been -done in a 'work' directory on TeamCity's build agent. From that directory we will now copy our files -to where our game actually exists on the local server. - -* Create a new build step called "Publish Build": - * If you're using SQLLite on your game, be sure to order this step ABOVE the Database Migration -steps. The build order will matter! - ```bash - #!/bin/bash - # Publishes the build to the proper build directory. - - DIRECTORY="%game.dir%" - - if [ ! -d "$DIRECTORY" ]; then - # Control will enter here if $DIRECTORY doesn't exist. - mkdir "$DIRECTORY" - fi - - # Copy all the files. - cp -ruv %teamcity.build.checkoutDir%/* "$DIRECTORY" - chmod -R 775 "$DIRECTORY" - - ``` - -Finally the last script will reload our game for us. - -* Create a new script called "Reload Game": - * The working directory on this build step will be: %game.dir% - ```bash - #!/bin/bash - # Apply the database migration. - - LOGDIR="server/logs" - PIDDIR="server/server.pid" - - . %evenv.dir%/bin/activate - - # Check that the logs directory exists. - if [ ! -d "$LOGDIR" ]; then - # Control will enter here if $LOGDIR doesn't exist. - mkdir "$LOGDIR" - fi - - # Check that the server is running. - if [ -d "$PIDDIR" ]; then - # Control will enter here if the game is running. - evennia reload - fi - ``` - -Now the template is ready for use! It would be useful this time to revisit the parameters page and -set the evenv parameter to the directory where your virtualenv exists: IE "/srv/mush/evenv". - -### Creating the Project - -Now it's time for the last few steps to set up a CI environment. - -* Return to the Evennia Project overview/administration page. -* Create a new Sub-Project called "Production" - * This will be the category that holds our actual game. -* Create a new Build Configuration in Production with the name of your MUSH. - * Base this configuration off of the continuous-integration template we made earlier. -* In the build configuration, enter VCS roots and create a new VCS root that points to the -branch/version control that you are using. -* Go to the parameters page and fill in the undefined parameters for your specific configuration. -* If you wish for the CI to run every time a commit is made, go to the VCS triggers and add one for -"On Every Commit". - -And you're done! At this point, you can return to the project overview page and queue a new build -for your game. If everything was set up correctly, the build will complete successfully. Additional -build steps could be added or removed at this point, adding some features like Unit Testing or more! diff --git a/docs/0.9.5/_sources/Contributing-Docs.md.txt b/docs/0.9.5/_sources/Contributing-Docs.md.txt deleted file mode 100644 index a7236cee9c..0000000000 --- a/docs/0.9.5/_sources/Contributing-Docs.md.txt +++ /dev/null @@ -1,681 +0,0 @@ -# Contributing to Evennia Docs - - -```{warning} -This system is still WIP and many things are bound to change! -``` - -Contributing to the docs is is like [contributing to the rest of Evennia][contributing]: Check out the branch of Evennia -you want to edit the documentation for. Create your own work-branch, make your changes to files -in `evennia/docs/source/` and make a PR for it! - -The documentation source files are `*.md` (Markdown) files found in `evennia/docs/source/`. -Markdown files are simple text files that can be edited with a normal text editor. They can also -contain raw HTML directives (but that is very rarely needed). They use -the [Markdown][commonmark] syntax with [MyST extensions][MyST]. - -```{important} -You do _not_ need to be able to test/build the docs locally to contribute a documentation PR. -We'll resolve any issues when we merge and build documentation. If you still want to build -the docs for yourself, instructions are [at the end of this document](#building-the-docs-locally). -``` - -## Source file structure - -The sources are organized into several rough categories, with only a few administrative documents -at the root of `evennia/docs/source/`. The folders are named in singular form since they will -primarily be accessed as link refs (e.g. `Component/Accounts`) - -- `source/Components/` are docs describing separate Evennia building blocks, that is, things - that you can import and use. This extends and elaborates on what can be found out by reading - the api docs themselves. Example are documentation for `Accounts`, `Objects` and `Commands`. -- `source/Concepts/` describes how larger-scale features of Evennia hang together - things that - can't easily be broken down into one isolated component. This can be general descriptions of - how Models and Typeclasses interact to the path a message takes from the client to the server - and back. -- `source/Setup/` holds detailed docs on installing, running and maintaining the Evennia server and - the infrastructure around it. -- `source/Coding/` has help on how to interact with, use and navigate the Evennia codebase itself. - This also has non-Evennia-specific help on general development concepts and how to set up a sane - development environment. -- `source/Contribs/` holds documentation specifically for packages in the `evennia/contribs/` folder. - Any contrib-specific tutorials will be found here instead of in `Howtos` -- `source/Howtos/` holds docs that describe how to achieve a specific goal, effect or - result in Evennia. This is often on a tutorial or FAQ form and will refer to the rest of the - documentation for further reading. - - `source/Howtos/Starting/` holds all documents part of the initial tutorial sequence. - - - Other files and folders: - - `source/api/` contains the auto-generated API documentation as `.rst` files. Don't edit these - files manually, your changes will be lost. To refer to these files, use `api:` followed by - the Python path, for example `[rpsystem contrib](evennia.contrib.rpsystem)`. - - `source/_templates` and `source/_static` should not be modified unless adding a new doc-page - feature or changing the look of the HTML documentation. - - `conf.py` holds the Sphinx configuration. It should usually not be modified except to update - the Evennia version on a new branch. - - -# Editing syntax - -The format used for Evennia's docs is [Markdown][commonmark-help] (Commonmark). While markdown -supports a few alternative forms for some of these, we try to stick to the below forms for consistency. - -## Italic/Bold - -We generally use underscores for italics and double-asterisks for bold: - -- `_Italic text_` - _Italic text_ -- `**Bold Text**` - **Bold text** - -## Headings - -We use `#` to indicate sections/headings. The more `#` the more of a sub-heading it is (will get -smaller and smaller font). - -- `# Heading` -- `## SubHeading` -- `### SubSubHeading` -- `#### SubSubSubHeading` - -> Don't use the same heading/subheading name more than once in one page. While Markdown -does not prevent it, it will make it impossible to refer to that heading uniquely. -The Evennia documentation preparser will detect this and give you an error. - -## Lists - -One can create both bullet-point lists and numbered lists: - -``` -- first bulletpoint -- second bulletpoint -- third bulletpoint -``` - -- first bulletpoint -- second bulletpoint -- third bulletpoint - -``` -1. Numbered point one -2. Numbered point two -3. Numbered point three -``` - -1. Numbered point one -2. Numbered point two -3. Numbered point three - -## Blockquotes - -A blockquote will create an indented block. It's useful for emphasis and is -added by starting one or more lines with `>`. For 'notes' you can also use -an explicit [Note](#note). - -``` -> This is an important -> thing to remember. -``` - -> Note: This is an important -> thing to remember. - -## Links - -The link syntax is `[linktext](url_or_ref)` - this gives a clickable link [linktext](#links). - -### Internal links - -Most links will be to other pages of the documentation or to Evennia's API docs. Each document -heading can be referenced. The reference always starts with `#`. The heading-name is always -given in lowercase and ignores any non-letters. Spaces in the heading title are replaced with -a single dash `-`. - -As an example, let's assume the following is the contents of a file `Menu-stuff.md`: - -``` -# Menu items - -Some text... - -## A yes/no? example - -Some more text... -``` - -- From _inside the same file_ you can refer to each heading as - - [menus](#menu-items) - [example](#a-yesno-example) - -- From _another file_, you reference them as as - - [menus](Menu-Stuff.md#menu-items) - [example](Menu-Stuff.md#a-yesno-example) - -> It's fine to not include the `.md` file ending in the reference. The Evennia doc-build process -> will correct for this (and also insert any needed relative paths in the reference). - -### API links - -The documentation contains auto-generated documentation for all of Evennia's source code. You -can direct the reader to the sources by just giving the python-path to the location of the -resource under the `evennia/` repository: - - [DefaultObject](evennia.objects.objects.DefaultObject) - -[DefaultObject](evennia.objects.objects.DefaultObject) <- like this! - -Note that you can't refer to files in the `mygame` folder this way. The game folder is generated -dynamically and is not part of the api docs. Refer to the parent classes in `evennia` where possible. - -### External links - -These are links to resources outside of the documentation. We also provide some convenient shortcuts. - -- `[linkname](https://evennia.com)` - link to an external website. -- `[linkname](github:evennia/objects/objects.py)` - this is a shortcut to point to a location in the - official Evennia repository on Github. Note that you must use `/` and give the full file name. By - default this is code in the `master` branch. -- `[linkname](github:develop/evennia/objects.objects.py` - this points to code in the `develop` branch. -- `[make an issue](github:issue)` - this is a shortcut to the Evennia github issue-creation page. - -> Note that if you want to refer to code, it's usually better to [link to the API](#api-links) as -> described above. - -### Urls/References in one place - -Urls can get long and if you are using the same url/reference in many places it can get a -little cluttered. So you can also put the url as a 'footnote' at the end of your document. -You can then refer to it by putting your reference within square brackets `[ ]`. Here's an example: - -``` -This is a [clickable link][mylink]. This is [another link][1]. - -... - - -[mylink]: http://... -[1]: My-Document.md#this-is-a-long-ref - -``` - -This makes the main text a little shorter. - -## Tables - -A table is done like this: - -```` -| heading1 | heading2 | heading3 | -| --- | --- | --- | -| value1 | value2 | value3 | -| | value 4 | | -| value 5 | value 6 | | -```` - -| heading1 | heading2 | heading3 | -| --- | --- | --- | -| value1 | value2 | value3 | -| | value 4 | | -| value 5 | value 6 | | - -As seen, the Markdown syntax can be pretty sloppy (columns don't need to line up) as long as you -include the heading separators and make sure to add the correct number of `|` on every line. - - -## Verbatim text - -It's common to want to mark something to be displayed verbatim - just as written - without any -Markdown parsing. In running text, this is done using backticks (\`), like \`verbatim text\` becomes -`verbatim text`. - -If you want to put the verbatim text on its own line, you can do so easily by simply indenting -it 4 spaces (add empty lines on each side for readability too): - -``` -This is normal text - - This is verbatim text - -This is normal text -``` - -Another way is to use triple-backticks: - -```` -``` -Everything within these backticks will be verbatim. - -``` -```` - -### Code blocks - -A special 'verbatim' case is code examples - we want them to get code-highlighting for readability. -This is done by using the triple-backticks and specify which language we use: - -```` -```python -from evennia import Command -class CmdEcho(Command): - """ - Usage: echo - """ - key = "echo" - def func(self): - self.caller.msg(self.args.strip()) -``` -```` - -```python -from evennia import Command -class CmdEcho(Command): - """ - Usage: echo - """ - key = "echo" - def func(self): - self.caller.msg(self.args.strip()) -``` - -## MyST directives - -Markdown is easy to read and use. But while it does most of what we need, there are some things it's -not quite as expressive as it needs to be. For this we use extended [MyST][MyST] syntax. This is -on the form - -```` -```{directive} any_options_here - -content - -``` -```` - - -#### Note - -This kind of note may pop more than doing a `> Note: ...`. - -```` -```{note} - -This is some noteworthy content that stretches over more than one line to show how the content indents. -Also the important/warning notes indents like this. - -``` -```` - -```{note} - -This is some noteworthy content that stretches over more than one line to show how the content indents. -Also the important/warning notes indents like this. - -``` - -### Important - -This is for particularly important and visible notes. - -```` -```{important} - This is important because it is! -``` - -```` -```{important} - This is important because it is! -``` - -### Warning - -A warning block is used to draw attention to particularly dangerous things, or features easy to -mess up. - -```` -```{warning} - Be careful about this ... -``` -```` - -```{warning} - Be careful about this ... -``` - -### Version changes and deprecations - -These will show up as one-line warnings that suggest an added, changed or deprecated -feature beginning with particular version. - -```` -```{versionadded} 1.0 -``` -```` - -```{versionadded} 1.0 -``` - -```` -```{versionchanged} 1.0 - How the feature changed with this version. -``` -```` - -```{versionchanged} 1.0 - How the feature changed with this version. -``` - -```` -```{deprecated} 1.0 -``` -```` - -```{deprecated} 1.0 -``` - -### Sidebar - -This will display an informative sidebar that floats to the side of regular content. This is useful -for example to remind the reader of some concept relevant to the text. - -```` -```{sidebar} Things to remember - -- There can be bullet lists -- in here. - -Separate sections with - -an empty line. -``` -```` - -```{sidebar} Things to remember - -- There can be bullet lists -- in here. - -Separate sections with - -an empty line. -``` - -Hint: If wanting to make sure to have the next header appear on a row of its own (rather than -squeezed to the left of the sidebar), one can embed a plain HTML string in the markdown like so: - -```html -
-``` - -
- -### A more flexible code block - -The regular Markdown Python codeblock is usually enough but for more direct control over the style, one -can also use the `{code-block}` directive that takes a set of additional `:options:`: - -```` -```{code-block} python -:linenos: -:emphasize-lines: 1-2,8 -:caption: An example code block -:name: A full code block example - -from evennia import Command -class CmdEcho(Command): - """ - Usage: echo - """ - key = "echo" - def func(self): - self.caller.msg(self.args.strip()) -``` -```` - -```{code-block} python -:linenos: -:emphasize-lines: 1-2,8 -:caption: An example code block -:name: A full code block example - -from evennia import Command -class CmdEcho(Command): - """ - Usage: echo - """ - key = "echo" - def func(self): - self.caller.msg(self.args.strip()) -``` -Here, `:linenos:` turns on line-numbers and `:emphasize-lines:` allows for emphasizing certain lines -in a different color. The `:caption:` shows an instructive text and `:name:` is used to reference -this -block through the link that will appear (so it should be unique for a given document). - - - -### eval-rst directive - -As a last resort, we can also fall back to writing [ReST][ReST] directives directly: - - -```` -```{eval-rst} - - This will be evaluated as ReST. - All content must be indented. - -``` -```` - -Within a ReST block, one must use Restructured Text syntax, which is not the -same as Markdown. - -- Single backticks around text makes it _italic_. -- Double backticks around text makes it `verbatim`. -- A link is written within back-ticks, with an underscore at the end: - - `python `_ - -[Here is a ReST formatting cheat sheet](https://thomas-cokelaer.info/tutorials/sphinx/rest_syntax.html). - -## Code docstrings - -The source code docstrings will be parsed as Markdown. When writing a module docstring, you can use Markdown formatting, -including header levels down to 4th level (`#### SubSubSubHeader`). After the module documentation it's -a good idea to end with four dashes `----`. This will create a visible line between the documentation and the -class/function docs to follow. - -All non-private classes, methods and functions must have a Google-style docstring, as per the -[Evennia coding style guidelines][github:evennia/CODING_STYLE.md]. This will then be correctly formatted -into pretty api docs. - -## Technical - -Evennia leverages [Sphinx][sphinx] with the [MyST][MyST] extension, which allows us -to write our docs in light-weight Markdown (more specifically [CommonMark][commonmark], like on github) -rather than Sphinx' normal ReST syntax. The `MyST` parser allows for some extra syntax to -make us able to express more complex displays than plain Markdown can. - -For [autodoc-generation][sphinx-autodoc] generation, we use the sphinx-[napoleon][sphinx-napoleon] -extension to understand our friendly Google-style docstrings used in classes and functions etc. - -# Building the docs locally - -The sources in `evennia/docs/source/` are built into a documentation using the -[Sphinx][sphinx] static generator system. To do this locally you need to use a -system with `make` (Linux/Unix/Mac or [Windows-WSL][Windows-WSL]). Lacking -that, you could in principle also run the sphinx build-commands manually - read -the `evennia/docs/Makefile` to see which commands are run by the `make`-commands -referred to in this document. - -You don't necessarily _have_ to build the docs locally to contribute. Markdown is -not hard and is very readable on its raw text-form. - -You can furthermore get a good feel for how things will look using a -Markdown-viewer like [Grip][grip]. Editors like [ReText][retext] or IDE's like -[PyCharm][pycharm] also have native Markdown previews. Building the docs locally is -however the only way to make sure the outcome is exactly as you expect. The process -will also find any mistakes you made, like making a typo in a link. - -### Building only the main documentation - -This is the fastest way to compile and view your changes. It will only build -the main documentation pages and not the API auto-docs or versions. All is -done in your terminal/console. - -- (Optional, but recommended): Activate a virtualenv with Python 3.7. -- `cd` to into the `evennia/docs` folder. -- Install the documentation-build requirements: - - ``` - make install - or - pip install -r requirements.txt - ``` - -- Next, build the html-based documentation (re-run this in the future to build your changes): - - ``` - make quick - ``` -- Note any errors from files you have edited. -- The html-based documentation will appear in the new - folder `evennia/docs/build/html/`. -- Use a web browser to open `file:///evennia/docs/build/html/index.html` and view - the docs. Note that you will get errors if clicking a link to the auto-docs, because you didn't - build them! - -### Building the main documentation and API docs - -The full documentation includes both the doc pages and the API documentation -generated from the Evennia source. For this you must install Evennia and -initialize a new game with a default database (you don't need to have any server -running) - -- It's recommended that you use a virtualenv. Install your cloned version of Evennia into - by pointing to the repo folder (the one containing `/docs`): - - ``` - pip install -e evennia - ``` - -- Make sure you are in the parent folder _containing_ your `evennia/` repo (so _two_ levels - up from `evennia/docs/`). -- Create a new game folder called exactly `gamedir` at the same level as your `evennia` - repo with - - ``` - evennia --init gamedir - ``` - -- Then `cd` into it and create a new, empty database. You don't need to start the - game or do any further changes after this. - - ``` - evennia migrate - ``` - -- This is how the structure should look at this point: - - ``` - (top) - | - ----- evennia/ (the top-level folder, containing docs/) - | - ----- gamedir/ - ``` - -(If you are already working on a game, you may of course have your 'real' game folder there as -well. We won't touch that.) - -- Go to `evennia/docs/` and install the doc-building requirements (you only need to do this once): - - ``` - make install - or - pip install -r requirements.txt - ``` - -- Finally, build the full documentation, including the auto-docs: - - ``` - make local - ``` - -- The rendered files will appear in a new folder `evennia/docs/build/html/`. - Note any errors from files you have edited. -- Point your web browser to `file:///evennia/docs/build/html/index.html` to - view the full docs. - -#### Building with another gamedir - -If you for some reason want to use another location of your `gamedir/`, or want it -named something else (maybe you already use the name 'gamedir' for your development ...), -you can do so by setting the `EVGAMEDIR` environment variable to the absolute path -of your alternative game dir. For example: - -``` -EVGAMEDIR=/my/path/to/mygamedir make local -``` - -### Building for release - -The full Evennia documentation contains docs from many Evennia -versions, old and new. This is done by pulling documentation from Evennia's old release -branches and building them all so readers can choose which one to view. Only -specific official Evennia branches will be built, so you can't use this to -build your own testing branch. - -- All local changes must have been committed to git first, since the versioned - docs are built by looking at the git tree. -- To build for local checking, run (`mv` stands for "multi-version"): - - ``` - make mv-local - ``` - -This is as close to the 'real' version of the docs as you can get locally. The different versions -will be found under `evennia/docs/build/versions/`. During deploy a symlink `latest` will point -to the latest version of the docs. - -#### Release - -Releasing the official docs requires git-push access the the Evennia `gh-pages` branch -on `github`. So there is no risk of you releasing your local changes accidentally. - -- To deploy docs in two steps - - ``` - make mv-local - make deploy - ``` - -- If you know what you are doing you can also do build + deploy in one step: - - ``` - make release - ``` - -After deployment finishes, the updated live documentation will be -available at https://evennia.github.io/evennia/latest/. - - - -[sphinx]: https://www.sphinx-doc.org/en/master/ -[MyST]: https://myst-parser.readthedocs.io/en/latest/syntax/reference.html -[commonmark]: https://spec.commonmark.org/current/ -[commonmark-help]: https://commonmark.org/help/ -[sphinx-autodoc]: https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#module-sphinx.ext.autodoc -[sphinx-napoleon]: https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html -[getting-started]: Setup/Setup-Quickstart -[contributing]: ./Contributing -[ReST]: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html -[ReST-tables]: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#tables -[ReST-directives]: https://www.sphinx-doc.org/en/master/usage/restruturedtext/directives.html -[Windows-WSL]: https://docs.microsoft.com/en-us/windows/wsl/install-win10 -[linkdemo]: #Links -[retext]: https://github.com/retext-project/retext -[grip]: https://github.com/joeyespo/grip -[pycharm]: https://www.jetbrains.com/pycharm/ \ No newline at end of file diff --git a/docs/0.9.5/_sources/Contributing.md.txt b/docs/0.9.5/_sources/Contributing.md.txt deleted file mode 100644 index e49f033c4d..0000000000 --- a/docs/0.9.5/_sources/Contributing.md.txt +++ /dev/null @@ -1,118 +0,0 @@ -# Contributing - - -Wanna help out? Great! Here's how. - -## Spreading the word - -Even if you are not keen on working on the server code yourself, just spreading the word is a big -help - it will help attract more people which leads to more feedback, motivation and interest. -Consider writing about Evennia on your blog or in your favorite (relevant) forum. Write a review -somewhere (good or bad, we like feedback either way). Rate it on places like [ohloh][ohloh]. Talk -about it to your friends ... that kind of thing. - -## Donations - -The best way to support Evennia is to become an [Evennia patron][patron]. Evennia is a free, -open-source project and any monetary donations you want to offer are completely voluntary. See it as -a way of announcing that you appreciate the work done - a tip of the hat! A patron donates a -(usually small) sum every month to show continued support. If this is not your thing you can also -show your appreciation via a [one-time donation][donate] (this is a PayPal link but you don't need -PayPal yourself). - -## Help with Documentation - -Evennia depends heavily on good documentation and we are always looking for extra eyes and hands to -improve it. Even small things such as fixing typos are a great help! - -The documentation is a wiki and as long as you have a GitHub account you can edit it. It can be a -good idea to discuss in the chat or forums if you want to add new pages/tutorials. Otherwise, it -goes a long way just pointing out wiki errors so we can fix them (in an Issue or just over -chat/forum). - -## Contributing through a forked repository - -We always need more eyes and hands on the code. Even if you don't feel confident with tackling a -[bug or feature][issues], just correcting typos, adjusting formatting or simply *using* the thing -and reporting when stuff doesn't make sense helps us a lot. - -The most elegant way to contribute code to Evennia is to use GitHub to create a *fork* of the -Evennia repository and make your changes to that. Refer to the [Forking Evennia](Version- -Control#forking-evennia) version -control instructions for detailed instructions. - -Once you have a fork set up, you can not only work on your own game in a separate branch, you can -also commit your fixes to Evennia itself. Make separate branches for all Evennia additions you do - -don't edit your local `master` or `develop` branches directly. It will make your life a lot easier. -If you have a change that you think is suitable for the main Evennia repository, you issue a [Pull -Request][pullrequest]. This will let Evennia devs know you have stuff to share. Bug fixes should -generally be done against the `master` branch of Evennia, while new features/contribs should go into -the `develop` branch. If you are unsure, just pick one and we'll figure it out. - -## Contributing with Patches - -To help with Evennia development it's recommended to do so using a fork repository as described -above. But for small, well isolated fixes you are also welcome to submit your suggested Evennia -fixes/addendums as a [patch][patch]. - -You can include your patch in an Issue or a Mailing list post. Please avoid pasting the full patch -text directly in your post though, best is to use a site like [Pastebin](http://pastebin.com/) and -just supply the link. - -## Contributing with Contribs - -While Evennia's core is pretty much game-agnostic, it also has a `contrib/` directory. The `contrib` -directory contains game systems that are specialized or useful only to certain types of games. Users -are welcome to contribute to the `contrib/` directory. Such contributions should always happen via a -Forked repository as described above. - -* If you are unsure if your idea/code is suitable as a contrib, *ask the devs before putting any -work into it*. This can also be a good idea in order to not duplicate efforts. This can also act as -a check that your implementation idea is sound. We are, for example, unlikely to accept contribs -that require large modifications of the game directory structure. -* If your code is intended *primarily* as an example or shows a concept/principle rather than a -working system, it is probably not suitable for `contrib/`. You are instead welcome to use it as -part of a [new tutorial][tutorials]! -* The code should ideally be contained within a single Python module. But if the contribution is -large this may not be practical and it should instead be grouped in its own subdirectory (not as -loose modules). -* The contribution should preferably be isolated (only make use of core Evennia) so it can easily be -dropped into use. If it does depend on other contribs or third-party modules, these must be clearly -documented and part of the installation instructions. -* The code itself should follow Evennia's [Code style guidelines][codestyle]. -* The code must be well documented as described in our [documentation style -guide](https://github.com/evennia/evennia/blob/master/CODING_STYLE.md#doc-strings). Expect that your -code will be read and should be possible to understand by others. Include comments as well as a -header in all modules. If a single file, the header should include info about how to include the -contrib in a game (installation instructions). If stored in a subdirectory, this info should go into -a new `README.md` file within that directory. -* Within reason, your contribution should be designed as genre-agnostic as possible. Limit the -amount of game-style-specific code. Assume your code will be applied to a very different game than -you had in mind when creating it. -* To make the licensing situation clear we assume all contributions are released with the same -[license as Evennia](./Licensing.md). If this is not possible for some reason, talk to us and we'll -handle it on a case-by-case basis. -* Your contribution must be covered by [unit tests](./Unit-Testing.md). Having unit tests will both help -make your code more stable and make sure small changes does not break it without it being noticed, -it will also help us test its functionality and merge it quicker. If your contribution is a single -module, you can add your unit tests to `evennia/contribs/tests.py`. If your contribution is bigger -and in its own sub-directory you could just put the tests in your own `tests.py` file (Evennia will -find it automatically). -* Merging of your code into Evennia is not guaranteed. Be ready to receive feedback and to be asked -to make corrections or fix bugs. Furthermore, merging a contrib means the Evennia project takes on -the responsibility of maintaining and supporting it. For various reasons this may be deemed to be -beyond our manpower. However, if your code were to *not* be accepted for merger for some reason, we -will instead add a link to your online repository so people can still find and use your work if they -want. - -[ohloh]: http://www.ohloh.net/p/evennia -[patron]: https://www.patreon.com/griatch -[donate]: https://www.paypal.com/en/cgi-bin/webscr?cmd=_flow&SESSION=TWy_epDPSWqNr4UJCOtVWxl- -pO1X1jbKiv_- -UBBFWIuVDEZxC0M_2pM6ywO&dispatch=5885d80a13c0db1f8e263663d3faee8d66f31424b43e9a70645c907a6cbd8fb4 -[forking]: https://github.com/evennia/evennia/wiki/Version-Control#wiki-forking-from-evennia -[pullrequest]: https://github.com/evennia/evennia/pulls -[issues]: https://github.com/evennia/evennia/issues -[patch]: https://secure.wikimedia.org/wikipedia/en/wiki/Patch_%28computing%29 -[codestyle]: https://github.com/evennia/evennia/blob/master/CODING_STYLE.md -[tutorials]: https://github.com/evennia/evennia/wiki/Tutorials diff --git a/docs/0.9.5/_sources/Coordinates.md.txt b/docs/0.9.5/_sources/Coordinates.md.txt deleted file mode 100644 index 5c5653ffdd..0000000000 --- a/docs/0.9.5/_sources/Coordinates.md.txt +++ /dev/null @@ -1,348 +0,0 @@ -# Coordinates - -# Adding room coordinates in your game - -This tutorial is moderately difficult in content. You might want to be familiar and at ease with -some Python concepts (like properties) and possibly Django concepts (like queries), although this -tutorial will try to walk you through the process and give enough explanations each time. If you -don't feel very confident with math, don't hesitate to pause, go to the example section, which shows -a tiny map, and try to walk around the code or read the explanation. - -Evennia doesn't have a coordinate system by default. Rooms and other objects are linked by location -and content: - -- An object can be in a location, that is, another object. Like an exit in a room. -- An object can access its content. A room can see what objects uses it as location (that would - include exits, rooms, characters and so on). - -This system allows for a lot of flexibility and, fortunately, can be extended by other systems. -Here, I offer you a way to add coordinates to every room in a way most compliant with Evennia -design. This will also show you how to use coordinates, find rooms around a given point for -instance. - -## Coordinates as tags - -The first concept might be the most surprising at first glance: we will create coordinates as -[tags](./Tags.md). - -> Why not attributes, wouldn't that be easier? - -It would. We could just do something like `room.db.x = 3`. The advantage of using tags is that it -will be easy and effective to search. Although this might not seem like a huge advantage right now, -with a database of thousands of rooms, it might make a difference, particularly if you have a lot of -things based on coordinates. - -Rather than giving you a step-by-step process, I'll show you the code. Notice that we use -properties to easily access and update coordinates. This is a Pythonic approach. Here's our first -`Room` class, that you can modify in `typeclasses/rooms.py`: - -```python -# in typeclasses/rooms.py - -from evennia import DefaultRoom - -class Room(DefaultRoom): - """ - Rooms are like any Object, except their location is None - (which is default). They also use basetype_setup() to - add locks so they cannot be puppeted or picked up. - (to change that, use at_object_creation instead) - - See examples/object.py for a list of - properties and methods available on all Objects. - """ - - @property - def x(self): - """Return the X coordinate or None.""" - x = self.tags.get(category="coordx") - return int(x) if isinstance(x, str) else None - - @x.setter - def x(self, x): - """Change the X coordinate.""" - old = self.tags.get(category="coordx") - if old is not None: - self.tags.remove(old, category="coordx") - if x is not None: - self.tags.add(str(x), category="coordx") - - @property - def y(self): - """Return the Y coordinate or None.""" - y = self.tags.get(category="coordy") - return int(y) if isinstance(y, str) else None - - @y.setter - def y(self, y): - """Change the Y coordinate.""" - old = self.tags.get(category="coordy") - if old is not None: - self.tags.remove(old, category="coordy") - if y is not None: - self.tags.add(str(y), category="coordy") - - @property - def z(self): - """Return the Z coordinate or None.""" - z = self.tags.get(category="coordz") - return int(z) if isinstance(z, str) else None - - @z.setter - def z(self, z): - """Change the Z coordinate.""" - old = self.tags.get(category="coordz") - if old is not None: - self.tags.remove(old, category="coordz") - if z is not None: - self.tags.add(str(z), category="coordz") -``` - -If you aren't familiar with the concept of properties in Python, I encourage you to read a good -tutorial on the subject. [This article on Python properties](https://www.programiz.com/python-programming/property) -is well-explained and should help you understand the idea. - -Let's look at our properties for `x`. First of all is the read property. - -```python - @property - def x(self): - """Return the X coordinate or None.""" - x = self.tags.get(category="coordx") - return int(x) if isinstance(x, str) else None -``` - -What it does is pretty simple: - -1. It gets the tag of category `"coordx"`. It's the tag category where we store our X coordinate. - The `tags.get` method will return `None` if the tag can't be found. -2. We convert the value to an integer, if it's a `str`. Remember that tags can only contain `str`, - so we'll need to convert it. - -> I thought tags couldn't contain values? - -Well, technically, they can't: they're either here or not. But using tag categories, as we have -done, we get a tag, knowing only its category. That's the basic approach to coordinates in this -tutorial. - -Now, let's look at the method that will be called when we wish to set `x` in our room: - -```python - @x.setter - def x(self, x): - """Change the X coordinate.""" - old = self.tags.get(category="coordx") - if old is not None: - self.tags.remove(old, category="coordx") - if x is not None: - self.tags.add(str(x), category="coordx") -``` - -1. First, we remove the old X coordinate, if it exists. Otherwise, we'd end up with two tags in our - room with "coordx" as their category, which wouldn't do at all. -2. Then we add the new tag, giving it the proper category. - -> Now what? - -If you add this code and reload your game, once you're logged in with a character in a room as its -location, you can play around: - -``` -@py here.x -@py here.x = 0 -@py here.y = 3 -@py here.z = -2 -@py here.z = None -``` - -The code might not be that easy to read, but you have to admit it's fairly easy to use. - -## Some additional searches - -Having coordinates is useful for several reasons: - -1. It can help in shaping a truly logical world, in its geography, at least. -2. It can allow to look for specific rooms at given coordinates. -3. It can be good in order to quickly find the rooms around a location. -4. It can even be great in path-finding (finding the shortest path between two rooms). - -So far, our coordinate system can help with 1., but not much else. Here are some methods that we -could add to the `Room` typeclass. These methods will just be search methods. Notice that they are -class methods, since we want to get rooms. - -### Finding one room - -First, a simple one: how to find a room at a given coordinate? Say, what is the room at X=0, Y=0, -Z=0? - -```python -class Room(DefaultRoom): - # ... - @classmethod - def get_room_at(cls, x, y, z): - """ - Return the room at the given location or None if not found. - - Args: - x (int): the X coord. - y (int): the Y coord. - z (int): the Z coord. - - Return: - The room at this location (Room) or None if not found. - - """ - rooms = cls.objects.filter( - db_tags__db_key=str(x), db_tags__db_category="coordx").filter( - db_tags__db_key=str(y), db_tags__db_category="coordy").filter( - db_tags__db_key=str(z), db_tags__db_category="coordz") - if rooms: - return rooms[0] - - return None -``` - -This solution includes a bit of [Django -queries](https://docs.djangoproject.com/en/1.11/topics/db/queries/). -Basically, what we do is reach for the object manager and search for objects with the matching tags. -Again, don't spend too much time worrying about the mechanism, the method is quite easy to use: - -``` -Room.get_room_at(5, 2, -3) -``` - -Notice that this is a class method: you will call it from `Room` (the class), not an instance. -Though you still can: - - @py here.get_room_at(3, 8, 0) - -### Finding several rooms - -Here's another useful method that allows us to look for rooms around a given coordinate. This is -more advanced search and doing some calculation, beware! Look at the following section if you're -lost. - -```python -from math import sqrt - -class Room(DefaultRoom): - - # ... - - @classmethod - def get_rooms_around(cls, x, y, z, distance): - """ - Return the list of rooms around the given coordinates. - - This method returns a list of tuples (distance, room) that - can easily be browsed. This list is sorted by distance (the - closest room to the specified position is always at the top - of the list). - - Args: - x (int): the X coord. - y (int): the Y coord. - z (int): the Z coord. - distance (int): the maximum distance to the specified position. - - Returns: - A list of tuples containing the distance to the specified - position and the room at this distance. Several rooms - can be at equal distance from the position. - - """ - # Performs a quick search to only get rooms in a square - x_r = list(reversed([str(x - i) for i in range(0, distance + 1)])) - x_r += [str(x + i) for i in range(1, distance + 1)] - y_r = list(reversed([str(y - i) for i in range(0, distance + 1)])) - y_r += [str(y + i) for i in range(1, distance + 1)] - z_r = list(reversed([str(z - i) for i in range(0, distance + 1)])) - z_r += [str(z + i) for i in range(1, distance + 1)] - wide = cls.objects.filter( - db_tags__db_key__in=x_r, db_tags__db_category="coordx").filter( - db_tags__db_key__in=y_r, db_tags__db_category="coordy").filter( - db_tags__db_key__in=z_r, db_tags__db_category="coordz") - - # We now need to filter down this list to find out whether - # these rooms are really close enough, and at what distance - # In short: we change the square to a circle. - rooms = [] - for room in wide: - x2 = int(room.tags.get(category="coordx")) - y2 = int(room.tags.get(category="coordy")) - z2 = int(room.tags.get(category="coordz")) - distance_to_room = sqrt( - (x2 - x) ** 2 + (y2 - y) ** 2 + (z2 - z) ** 2) - if distance_to_room <= distance: - rooms.append((distance_to_room, room)) - - # Finally sort the rooms by distance - rooms.sort(key=lambda tup: tup[0]) - return rooms -``` - -This gets more serious. - -1. We have specified coordinates as parameters. We determine a broad range using the distance. - That is, for each coordinate, we create a list of possible matches. See the example below. -2. We then search for the rooms within this broader range. It gives us a square - around our location. Some rooms are definitely outside the range. Again, see the example below -to follow the logic. -3. We filter down the list and sort it by distance from the specified coordinates. - -Notice that we only search starting at step 2. Thus, the Django search doesn't look and cache all -objects, just a wider range than what would be really necessary. This method returns a circle of -coordinates around a specified point. Django looks for a square. What wouldn't fit in the circle -is removed at step 3, which is the only part that includes systematic calculation. This method is -optimized to be quick and efficient. - -### An example - -An example might help. Consider this very simple map (a textual description follows): - -``` -4 A B C D -3 E F G H -2 I J K L -1 M N O P - 1 2 3 4 -``` - -The X coordinates are given below. The Y coordinates are given on the left. This is a simple -square with 16 rooms: 4 on each line, 4 lines of them. All the rooms are identified by letters in -this example: the first line at the top has rooms A to D, the second E to H, the third I to L and -the fourth M to P. The bottom-left room, X=1 and Y=1, is M. The upper-right room X=4 and Y=4 is D. - -So let's say we want to find all the neighbors, distance 1, from the room J. J is at X=2, Y=2. - -So we use: - - Room.get_rooms_around(x=2, y=2, z=0, distance=1) - # we'll assume a z coordinate of 0 for simplicity - -1. First, this method gets all the rooms in a square around J. So it gets E F G, I J K, M N O. If -you want, draw the square around these coordinates to see what's happening. -2. Next, we browse over this list and check the real distance between J (X=2, Y=2) and the room. -The four corners of the square are not in this circle. For instance, the distance between J and M -is not 1. If you draw a circle of center J and radius 1, you'll notice that the four corners of our -square (E, G, M and O) are not in this circle. So we remove them. -3. We sort by distance from J. - -So in the end we might obtain something like this: - -``` -[ - (0, J), # yes, J is part of this circle after all, with a distance of 0 - (1, F), - (1, I), - (1, K), - (1, N), -] -``` - -You can try with more examples if you want to see this in action. - -### To conclude - -You can definitely use this system to map other objects, not just rooms. You can easily remove the -`Z coordinate too, if you simply need X and Y. diff --git a/docs/0.9.5/_sources/Custom-Protocols.md.txt b/docs/0.9.5/_sources/Custom-Protocols.md.txt deleted file mode 100644 index 93d17ca218..0000000000 --- a/docs/0.9.5/_sources/Custom-Protocols.md.txt +++ /dev/null @@ -1,239 +0,0 @@ -# Custom Protocols - - -*Note: This is considered an advanced topic and is mostly of interest to users planning to implement -their own custom client protocol.* - - -A [PortalSession](./Sessions.md#portal-and-server-sessions) is the basic data object representing an -external -connection to the Evennia [Portal](./Portal-And-Server.md) -- usually a human player running a mud client -of some kind. The way they connect (the language the player's client and Evennia use to talk to -each other) is called the connection *Protocol*. The most common such protocol for MUD:s is the -*Telnet* protocol. All Portal Sessions are stored and managed by the Portal's *sessionhandler*. - -It's technically sometimes hard to separate the concept of *PortalSession* from the concept of -*Protocol* since both depend heavily on the other (they are often created as the same class). When -data flows through this part of the system, this is how it goes - -``` -# In the Portal -You <-> - Protocol + PortalSession <-> - PortalSessionHandler <-> - (AMP) <-> - ServerSessionHandler <-> - ServerSession <-> - InputFunc -``` - -(See the [Message Path](./Messagepath.md) for the bigger picture of how data flows through Evennia). The -parts that needs to be customized to make your own custom protocol is the `Protocol + PortalSession` -(which translates between data coming in/out over the wire to/from Evennia internal representation) -as well as the `InputFunc` (which handles incoming data). - -## Adding custom Protocols - -Evennia has a plugin-system that add the protocol as a new "service" to the application. - -Take a look at `evennia/server/portal/portal.py`, notably the sections towards the end of that file. -These are where the various in-built services like telnet, ssh, webclient etc are added to the -Portal (there is an equivalent but shorter list in `evennia/server/server.py`). - -To add a new service of your own (for example your own custom client protocol) to the Portal or -Server, look at `mygame/server/conf/server_services_plugins` and `portal_services_plugins`. By -default Evennia will look into these modules to find plugins. If you wanted to have it look for more -modules, you could do the following: - -```python - # add to the Server - SERVER_SERVICES_PLUGIN_MODULES.append('server.conf.my_server_plugins') - # or, if you want to add to the Portal - PORTAL_SERVICES_PLUGIN_MODULES.append('server.conf.my_portal_plugins') -``` - -When adding a new connection you'll most likely only need to add new things to the -`PORTAL_SERVICES_PLUGIN_MODULES`. - -This module can contain whatever you need to define your protocol, but it *must* contain a function -`start_plugin_services(app)`. This is called by the Portal as part of its upstart. The function -`start_plugin_services` must contain all startup code the server need. The `app` argument is a -reference to the Portal/Server application itself so the custom service can be added to it. The -function should not return anything. - -This is how it looks: - -```python - # mygame/server/conf/portal_services_plugins.py - - # here the new Portal Twisted protocol is defined - class MyOwnFactory( ... ): - [...] - - # some configs - MYPROC_ENABLED = True # convenient off-flag to avoid having to edit settings all the time - MY_PORT = 6666 - - def start_plugin_services(portal): - "This is called by the Portal during startup" - if not MYPROC_ENABLED: - return - # output to list this with the other services at startup - print(" myproc: %s" % MY_PORT) - - # some setup (simple example) - factory = MyOwnFactory() - my_service = internet.TCPServer(MY_PORT, factory) - # all Evennia services must be uniquely named - my_service.setName("MyService") - # add to the main portal application - portal.services.addService(my_service) -``` - -Once the module is defined and targeted in settings, just reload the server and your new -protocol/services should start with the others. - -## Writing your own Protocol - -Writing a stable communication protocol from scratch is not something we'll cover here, it's no -trivial task. The good news is that Twisted offers implementations of many common protocols, ready -for adapting. - -Writing a protocol implementation in Twisted usually involves creating a class inheriting from an -already existing Twisted protocol class and from `evennia.server.session.Session` (multiple -inheritance), then overloading the methods that particular protocol uses to link them to the -Evennia-specific inputs. - -Here's a example to show the concept: - -```python -# In module that we'll later add to the system through PORTAL_SERVICE_PLUGIN_MODULES - -# pseudo code -from twisted.something import TwistedClient -# this class is used both for Portal- and Server Sessions -from evennia.server.session import Session - -from evennia.server.portal.portalsessionhandler import PORTAL_SESSIONS - -class MyCustomClient(TwistedClient, Session): - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.sessionhandler = PORTAL_SESSIONS - - # these are methods we must know that TwistedClient uses for - # communication. Name and arguments could vary for different Twisted protocols - def onOpen(self, *args, **kwargs): - # let's say this is called when the client first connects - - # we need to init the session and connect to the sessionhandler. The .factory - # is available through the Twisted parents - - client_address = self.getClientAddress() # get client address somehow - - self.init_session("mycustom_protocol", client_address, self.factory.sessionhandler) - self.sessionhandler.connect(self) - - def onClose(self, reason, *args, **kwargs): - # called when the client connection is dropped - # link to the Evennia equivalent - self.disconnect(reason) - - def onMessage(self, indata, *args, **kwargs): - # called with incoming data - # convert as needed here - self.data_in(data=indata) - - def sendMessage(self, outdata, *args, **kwargs): - # called to send data out - # modify if needed - super().sendMessage(self, outdata, *args, **kwargs) - - # these are Evennia methods. They must all exist and look exactly like this - # The above twisted-methods call them and vice-versa. This connects the protocol - # the Evennia internals. - - def disconnect(self, reason=None): - """ - Called when connection closes. - This can also be called directly by Evennia when manually closing the connection. - Do any cleanups here. - """ - self.sessionhandler.disconnect(self) - - def at_login(self): - """ - Called when this session authenticates by the server (if applicable) - """ - - def data_in(self, **kwargs): - """ - Data going into the server should go through this method. It - should pass data into `sessionhandler.data_in`. THis will be called - by the sessionhandler with the data it gets from the approrpriate - send_* method found later in this protocol. - """ - self.sessionhandler.data_in(self, text=kwargs['data']) - - def data_out(self, **kwargs): - """ - Data going out from the server should go through this method. It should - hand off to the protocol's send method, whatever it's called. - """ - # we assume we have a 'text' outputfunc - self.onMessage(kwargs['text']) - - # 'outputfuncs' are defined as `send_`. From in-code, they are called - # with `msg(outfunc_name=)`. - - def send_text(self, txt, *args, **kwargs): - """ - Send text, used with e.g. `session.msg(text="foo")` - """ - # we make use of the - self.data_out(text=txt) - - def send_default(self, cmdname, *args, **kwargs): - """ - Handles all outputfuncs without an explicit `send_*` method to handle them. - """ - self.data_out(**{cmdname: str(args)}) - -``` -The principle here is that the Twisted-specific methods are overridden to redirect inputs/outputs to -the Evennia-specific methods. - -### Sending data out - -To send data out through this protocol, you'd need to get its Session and then you could e.g. - -```python - session.msg(text="foo") -``` - -The message will pass through the system such that the sessionhandler will dig out the session and -check if it has a `send_text` method (it has). It will then pass the "foo" into that method, which -in our case means sending "foo" across the network. - -### Receiving data - -Just because the protocol is there, does not mean Evennia knows what to do with it. An -[Inputfunc](./Inputfuncs.md) must exist to receive it. In the case of the `text` input exemplified above, -Evennia alredy handles this input - it will parse it as a Command name followed by its inputs. So -handle that you need to simply add a cmdset with commands on your receiving Session (and/or the -Object/Character it is puppeting). If not you may need to add your own Inputfunc (see the -[Inputfunc](./Inputfuncs.md) page for how to do this. - -These might not be as clear-cut in all protocols, but the principle is there. These four basic -components - however they are accessed - links to the *Portal Session*, which is the actual common -interface between the different low-level protocols and Evennia. - -## Assorted notes - -To take two examples, Evennia supports the *telnet* protocol as well as *webclient*, via ajax or -websockets. You'll find that whereas telnet is a textbook example of a Twisted protocol as seen -above, the ajax protocol looks quite different due to how it interacts with the -webserver through long-polling (comet) style requests. All the necessary parts -mentioned above are still there, but by necessity implemented in very different -ways. diff --git a/docs/0.9.5/_sources/Customize-channels.md.txt b/docs/0.9.5/_sources/Customize-channels.md.txt deleted file mode 100644 index 67bc381750..0000000000 --- a/docs/0.9.5/_sources/Customize-channels.md.txt +++ /dev/null @@ -1,483 +0,0 @@ -# Customize channels - - -# Channel commands in Evennia - -By default, Evennia's default channel commands are inspired by MUX. They all -begin with "c" followed by the action to perform (like "ccreate" or "cdesc"). -If this default seems strange to you compared to other Evennia commands that -rely on switches, you might want to check this tutorial out. - -This tutorial will also give you insight into the workings of the channel system. -So it may be useful even if you don't plan to make the exact changes shown here. - -## What we will try to do - -Our mission: change the default channel commands to have a different syntax. - -This tutorial will do the following changes: - -- Remove all the default commands to handle channels. -- Add a `+` and `-` command to join and leave a channel. So, assuming there is -a `public` channel on your game (most often the case), you could type `+public` -to join it and `-public` to leave it. -- Group the commands to manipulate channels under the channel name, after a -switch. For instance, instead of writing `cdesc public = My public channel`, - you would write `public/desc My public channel`. - - -> I listed removing the default Evennia commands as a first step in the -> process. Actually, we'll move it at the very bottom of the list, since we -> still want to use them, we might get it wrong and rely on Evennia commands -> for a while longer. - -## A command to join, another to leave - -We'll do the most simple task at first: create two commands, one to join a -channel, one to leave. - -> Why not have them as switches? `public/join` and `public/leave` for instance? - -For security reasons, I will hide channels to which the caller is not -connected. It means that if the caller is not connected to the "public" -channel, he won't be able to use the "public" command. This is somewhat -standard: if we create an administrator-only channel, we don't want players to -try (or even know) the channel command. Again, you could design it a different -way should you want to. - -First create a file named `comms.py` in your `commands` package. It's -a rather logical place, since we'll write different commands to handle -communication. - -Okay, let's add the first command to join a channel: - -```python -# in commands/comms.py -from evennia.utils.search import search_channel -from commands.command import Command - -class CmdConnect(Command): - """ - Connect to a channel. - """ - - key = "+" - help_category = "Comms" - locks = "cmd:not pperm(channel_banned)" - auto_help = False - - def func(self): - """Implement the command""" - caller = self.caller - args = self.args - if not args: - self.msg("Which channel do you want to connect to?") - return - - channelname = self.args - channel = search_channel(channelname) - if not channel: - return - - # Check permissions - if not channel.access(caller, 'listen'): - self.msg("%s: You are not allowed to listen to this channel." % channel.key) - return - - # If not connected to the channel, try to connect - if not channel.has_connection(caller): - if not channel.connect(caller): - self.msg("%s: You are not allowed to join this channel." % channel.key) - return - else: - self.msg("You now are connected to the %s channel. " % channel.key.lower()) - else: - self.msg("You already are connected to the %s channel. " % channel.key.lower()) -``` - -Okay, let's review this code, but if you're used to Evennia commands, it shouldn't be too strange: - -1. We import `search_channel`. This is a little helper function that we will use to search for -channels by name and aliases, found in `evennia.utils.search`. It's just more convenient. -2. Our class `CmdConnect` contains the body of our command to join a channel. -3. Notice the key of this command is simply `"+"`. When you enter `+something` in the game, it will -try to find a command key `+something`. Failing that, it will look at other potential matches. -Evennia is smart enough to understand that when we type `+something`, `+` is the command key and -`something` is the command argument. This will, of course, fail if you have a command beginning by -`+` conflicting with the `CmdConnect` key. -4. We have altered some class attributes, like `auto_help`. If you want to know what they do and -why they have changed here, you can check the [documentation on commands](./Commands.md). -5. In the command body, we begin by extracting the channel name. Remember that this name should be -in the command arguments (that is, in `self.args`). Following the same example, if a player enters -`+something`, `self.args` should contain `"something"`. We use `search_channel` to see if this -channel exists. -6. We then check the access level of the channel, to see if the caller can listen to it (not -necessarily use it to speak, mind you, just listen to others speak, as these are two different locks -on Evennia). -7. Finally, we connect the caller if he's not already connected to the channel. We use the -channel's `connect` method to do this. Pretty straightforward eh? - -Now we'll add a command to leave a channel. It's almost the same, turned upside down: - -```python -class CmdDisconnect(Command): - """ - Disconnect from a channel. - """ - - key = "-" - help_category = "Comms" - locks = "cmd:not pperm(channel_banned)" - auto_help = False - - def func(self): - """Implement the command""" - caller = self.caller - args = self.args - if not args: - self.msg("Which channel do you want to disconnect from?") - return - - channelname = self.args - channel = search_channel(channelname) - if not channel: - return - - # If connected to the channel, try to disconnect - if channel.has_connection(caller): - if not channel.disconnect(caller): - self.msg("%s: You are not allowed to disconnect from this channel." % channel.key) - return - else: - self.msg("You stop listening to the %s channel. " % channel.key.lower()) - else: - self.msg("You are not connected to the %s channel. " % channel.key.lower()) -``` - -So far, you shouldn't have trouble following what this command does: it's -pretty much the same as the `CmdConnect` class in logic, though it accomplishes -the opposite. If you are connected to the channel `public` you could -disconnect from it using `-public`. Remember, you can use channel aliases too -(`+pub` and `-pub` will also work, assuming you have the alias `pub` on the - `public` channel). - -It's time to test this code, and to do so, you will need to add these two -commands. Here is a good time to say it: by default, Evennia connects accounts -to channels. Some other games (usually with a higher multisession mode) will -want to connect characters instead of accounts, so that several characters in -the same account can be connected to various channels. You can definitely add -these commands either in the `AccountCmdSet` or `CharacterCmdSet`, the caller -will be different and the command will add or remove accounts of characters. -If you decide to install these commands on the `CharacterCmdSet`, you might -have to disconnect your superuser account (account #1) from the channel before -joining it with your characters, as Evennia tends to subscribe all accounts -automatically if you don't tell it otherwise. - -So here's an example of how to add these commands into your `AccountCmdSet`. -Edit the file `commands/default_cmdsets.py` to change a few things: - -```python -# In commands/default_cmdsets.py -from evennia import default_cmds -from commands.comms import CmdConnect, CmdDisconnect - - -# ... Skip to the AccountCmdSet class ... - -class AccountCmdSet(default_cmds.AccountCmdSet): - """ - This is the cmdset available to the Account at all times. It is - combined with the `CharacterCmdSet` when the Account puppets a - Character. It holds game-account-specific commands, channel - commands, etc. - """ - key = "DefaultAccount" - - def at_cmdset_creation(self): - """ - Populates the cmdset - """ - super().at_cmdset_creation() - - # Channel commands - self.add(CmdConnect()) - self.add(CmdDisconnect()) -``` - -Save, reload your game, and you should be able to use `+public` and `-public` -now! - -## A generic channel command with switches - -It's time to dive a little deeper into channel processing. What happens in -Evennia when a player enters `public Hello everybody!`? - -Like exits, channels are a particular command that Evennia automatically -creates and attaches to individual channels. So when you enter `public -message` in your game, Evennia calls the `public` command. - -> But I didn't add any public command... - -Evennia will just create these commands automatically based on the existing -channels. The base command is the command we'll need to edit. - -> Why edit it? It works just fine to talk. - -Unfortunately, if we want to add switches to our channel names, we'll have to -edit this command. It's not too hard, however, we'll just start writing a -standard command with minor twitches. - -### Some additional imports - -You'll need to add a line of import in your `commands/comms.py` file. We'll -see why this import is important when diving in the command itself: - -```python -from evennia.comms.models import ChannelDB -``` - -### The class layout - -```python -# In commands/comms.py -class ChannelCommand(Command): - """ - {channelkey} channel - - {channeldesc} - - Usage: - {lower_channelkey} - {lower_channelkey}/history [start] - {lower_channelkey}/me - {lower_channelkey}/who - - Switch: - history: View 20 previous messages, either from the end or - from number of messages from the end. - me: Perform an emote on this channel. - who: View who is connected to this channel. - - Example: - {lower_channelkey} Hello World! - {lower_channelkey}/history - {lower_channelkey}/history 30 - {lower_channelkey}/me grins. - {lower_channelkey}/who - """ - # note that channeldesc and lower_channelkey will be filled - # automatically by ChannelHandler - - # this flag is what identifies this cmd as a channel cmd - # and branches off to the system send-to-channel command - # (which is customizable by admin) - is_channel = True - key = "general" - help_category = "Channel Names" - obj = None - arg_regex = "" -``` - -There are some differences here compared to most common commands. - -- There is something disconcerting in the class docstring. Some information is -between curly braces. This is a format-style which is only used for channel -commands. `{channelkey}` will be replaced by the actual channel key (like - public). `{channeldesc}` will be replaced by the channel description (like - "public channel"). And `{lower_channelkey}`. -- We have set `is_channel` to `True` in the command class variables. You -shouldn't worry too much about that: it just tells Evennia this is a special -command just for channels. -- `key` is a bit misleading because it will be replaced eventually. So we -could set it to virtually anything. -- The `obj` class variable is another one we won't detail right now. -- `arg_regex` is important: the default `arg_regex` in the channel command will -forbid to use switches (a slash just after the channel name is not allowed). -That's why we enforce it here, we allow any syntax. - -> What will become of this command? - -Well, when we'll be through with it, and once we'll add it as the default -command to handle channels, Evennia will create one per existing channel. For -instance, the public channel will receive one command of this class, with `key` -set to `public` and `aliases` set to the channel aliases (like `['pub']`). - -> Can I see it work? - -Not just yet, there's still a lot of code needed. - -Okay we have the command structure but it's rather empty. - -### The parse method - -The `parse` method is called before `func` in every command. Its job is to -parse arguments and in our case, we will analyze switches here. - -```python -# ... - def parse(self): - """ - Simple parser - """ - # channel-handler sends channame:msg here. - channelname, msg = self.args.split(":", 1) - self.switch = None - if msg.startswith("/"): - try: - switch, msg = msg[1:].split(" ", 1) - except ValueError: - switch = msg[1:] - msg = "" - - self.switch = switch.lower().strip() - - self.args = (channelname.strip(), msg.strip()) -``` - -Reading the comments we see that the channel handler will send the command in a -strange way: a string with the channel name, a colon and the actual message -entered by the player. So if the player enters "public hello", the command -`args` will contain `"public:hello"`. You can look at the way the channel name -and message are parsed, this can be used in a lot of different commands. - -Next we check if there's any switch, that is, if the message starts with a -slash. This would be the case if a player entered `public/me jumps up and -down`, for instance. If there is a switch, we save it in `self.switch`. We -alter `self.args` at the end to contain a tuple with two values: the channel -name, and the message (if a switch was used, notice that the switch will be - stored in `self.switch`, not in the second element of `self.args`). - -### The command func - -Finally, let's see the `func` method in the command class. It will have to -handle switches and also the raw message to send if no switch was used. - - -```python -# ... - def func(self): - """ - Create a new message and send it to channel, using - the already formatted input. - """ - channelkey, msg = self.args - caller = self.caller - channel = ChannelDB.objects.get_channel(channelkey) - - # Check that the channel exists - if not channel: - self.msg(_("Channel '%s' not found.") % channelkey) - return - - # Check that the caller is connected - if not channel.has_connection(caller): - string = "You are not connected to channel '%s'." - self.msg(string % channelkey) - return - - # Check that the caller has send access - if not channel.access(caller, 'send'): - string = "You are not permitted to send to channel '%s'." - self.msg(string % channelkey) - return - - # Handle the various switches - if self.switch == "me": - if not msg: - self.msg("What do you want to do on this channel?") - else: - msg = "{} {}".format(caller.key, msg) - channel.msg(msg, online=True) - elif self.switch: - self.msg("{}: Invalid switch {}.".format(channel.key, self.switch)) - elif not msg: - self.msg("Say what?") - else: - if caller in channel.mutelist: - self.msg("You currently have %s muted." % channel) - return - channel.msg(msg, senders=self.caller, online=True) -``` - -- First of all, we try to get the channel object from the channel name we have -in the `self.args` tuple. We use `ChannelDB.objects.get_channel` this time -because we know the channel name isn't an alias (that was part of the deal, - `channelname` in the `parse` method contains a command key). -- We check that the channel does exist. -- We then check that the caller is connected to the channel. Remember, if the -caller isn't connected, we shouldn't allow him to use this command (that - includes the switches on channels). -- We then check that the caller has access to the channel's `send` lock. This -time, we make sure the caller can send messages to the channel, no matter what -operation he's trying to perform. -- Finally we handle switches. We try only one switch: `me`. This switch would -be used if a player entered `public/me jumps up and down` (to do a channel - emote). -- We handle the case where the switch is unknown and where there's no switch -(the player simply wants to talk on this channel). - -The good news: The code is not too complicated by itself. The bad news is that -this is just an abridged version of the code. If you want to handle all the -switches mentioned in the command help, you will have more code to write. This -is left as an exercise. - -### End of class - -It's almost done, but we need to add a method in this command class that isn't -often used. I won't detail it's usage too much, just know that Evennia will use -it and will get angry if you don't add it. So at the end of your class, just -add: - -```python -# ... - def get_extra_info(self, caller, **kwargs): - """ - Let users know that this command is for communicating on a channel. - - Args: - caller (TypedObject): A Character or Account who has entered an ambiguous command. - - Returns: - A string with identifying information to disambiguate the object, conventionally with a -preceding space. - """ - return " (channel)" -``` - -### Adding this channel command - -Contrary to most Evennia commands, we won't add our `ChannelCommand` to a -`CmdSet`. Instead we need to tell Evennia that it should use the command we -just created instead of its default channel-command. - -In your `server/conf/settings.py` file, add a new setting: - -```python -# Channel options -CHANNEL_COMMAND_CLASS = "commands.comms.ChannelCommand" -``` - -Then you can reload your game. Try to type `public hello` and `public/me jumps -up and down`. Don't forget to enter `help public` to see if your command has -truly been added. - -## Conclusion and full code - -That was some adventure! And there's still things to do! But hopefully, this -tutorial will have helped you in designing your own channel system. Here are a -few things to do: - -- Add more switches to handle various actions, like changing the description of -a channel for instance, or listing the connected participants. -- Remove the default Evennia commands to handle channels. -- Alter the behavior of the channel system so it better aligns with what you -want to do. - -As a special bonus, you can find a full, working example of a communication -system similar to the one I've shown you: this is a working example, it -integrates all switches and does ever some extra checking, but it's also very -close from the code I've provided here. Notice, however, that this resource is -external to Evennia and not maintained by anyone but the original author of -this article. - -[Read the full example on Github](https://github.com/vincent-lg/avenew/blob/master/commands/comms.py) diff --git a/docs/0.9.5/_sources/Debugging.md.txt b/docs/0.9.5/_sources/Debugging.md.txt deleted file mode 100644 index 62e199037e..0000000000 --- a/docs/0.9.5/_sources/Debugging.md.txt +++ /dev/null @@ -1,296 +0,0 @@ -# Debugging - - -Sometimes, an error is not trivial to resolve. A few simple `print` statements is not enough to find -the cause of the issue. Running a *debugger* can then be very helpful and save a lot of time. -Debugging -means running Evennia under control of a special *debugger* program. This allows you to stop the -action at a given point, view the current state and step forward through the program to see how its -logic works. - -Evennia natively supports these debuggers: - -- [Pdb](https://docs.python.org/2/library/pdb.html) is a part of the Python distribution and - available out-of-the-box. -- [PuDB](https://pypi.org/project/pudb/) is a third-party debugger that has a slightly more - 'graphical', curses-based user interface than pdb. It is installed with `pip install pudb`. - -## Debugging Evennia - -To run Evennia with the debugger, follow these steps: - -1. Find the point in the code where you want to have more insight. Add the following line at that - point. - ```python - from evennia import set_trace;set_trace() - ``` -2. (Re-)start Evennia in interactive (foreground) mode with `evennia istart`. This is important - - without this step the debugger will not start correctly - it will start in this interactive - terminal. -3. Perform the steps that will trigger the line where you added the `set_trace()` call. The debugger - will start in the terminal from which Evennia was interactively started. - -The `evennia.set_trace` function takes the following arguments: - - -```python - evennia.set_trace(debugger='auto', term_size=(140, 40)) -``` - -Here, `debugger` is one of `pdb`, `pudb` or `auto`. If `auto`, use `pudb` if available, otherwise -use `pdb`. The `term_size` tuple sets the viewport size for `pudb` only (it's ignored by `pdb`). - - -## A simple example using pdb - -The debugger is useful in different cases, but to begin with, let's see it working in a command. -Add the following test command (which has a range of deliberate errors) and also add it to your -default cmdset. Then restart Evennia in interactive mode with `evennia istart`. - - -```python -# In file commands/command.py - - -class CmdTest(Command): - - """ - A test command just to test pdb. - - Usage: - test - - """ - - key = "test" - - def func(self): - from evennia import set_trace; set_trace() # <--- start of debugger - obj = self.search(self.args) - self.msg("You've found {}.".format(obj.get_display_name())) - -``` - -If you type `test` in your game, everything will freeze. You won't get any feedback from the game, -and you won't be able to enter any command (nor anyone else). It's because the debugger has started -in your console, and you will find it here. Below is an example with `pdb`. - -``` -... -> .../mygame/commands/command.py(79)func() --> obj = self.search(self.args) -(Pdb) - -``` - -`pdb` notes where it has stopped execution and, what line is about to be executed (in our case, `obj -= self.search(self.args)`), and ask what you would like to do. - -### Listing surrounding lines of code - -When you have the `pdb` prompt `(Pdb)`, you can type in different commands to explore the code. The -first one you should know is `list` (you can type `l` for short): - -``` -(Pdb) l - 43 - 44 key = "test" - 45 - 46 def func(self): - 47 from evennia import set_trace; set_trace() # <--- start of debugger - 48 -> obj = self.search(self.args) - 49 self.msg("You've found {}.".format(obj.get_display_name())) - 50 - 51 # ------------------------------------------------------------- - 52 # - 53 # The default commands inherit from -(Pdb) -``` - -Okay, this didn't do anything spectacular, but when you become more confident with `pdb` and find -yourself in lots of different files, you sometimes need to see what's around in code. Notice that -there is a little arrow (`->`) before the line that is about to be executed. - -This is important: **about to be**, not **has just been**. You need to tell `pdb` to go on (we'll -soon see how). - -### Examining variables - -`pdb` allows you to examine variables (or really, to run any Python instruction). It is very useful -to know the values of variables at a specific line. To see a variable, just type its name (as if -you were in the Python interpreter: - -``` -(Pdb) self - -(Pdb) self.args -u'' -(Pdb) self.caller - -(Pdb) -``` - -If you try to see the variable `obj`, you'll get an error: - -``` -(Pdb) obj -*** NameError: name 'obj' is not defined -(Pdb) -``` - -That figures, since at this point, we haven't created the variable yet. - -> Examining variable in this way is quite powerful. You can even run Python code and keep on -> executing, which can help to check that your fix is actually working when you have identified an -> error. If you have variable names that will conflict with `pdb` commands (like a `list` -> variable), you can prefix your variable with `!`, to tell `pdb` that what follows is Python code. - -### Executing the current line - -It's time we asked `pdb` to execute the current line. To do so, use the `next` command. You can -shorten it by just typing `n`: - -``` -(Pdb) n -AttributeError: "'CmdTest' object has no attribute 'search'" -> .../mygame/commands/command.py(79)func() --> obj = self.search(self.args) -(Pdb) -``` - -`Pdb` is complaining that you try to call the `search` method on a command... whereas there's no -`search` method on commands. The character executing the command is in `self.caller`, so we might -change our line: - -```python -obj = self.caller.search(self.args) -``` - -### Letting the program run - -`pdb` is waiting to execute the same instruction... it provoked an error but it's ready to try -again, just in case. We have fixed it in theory, but we need to reload, so we need to enter a -command. To tell `pdb` to terminate and keep on running the program, use the `continue` (or `c`) -command: - -``` -(Pdb) c -... -``` - -You see an error being caught, that's the error we have fixed... or hope to have. Let's reload the -game and try again. You need to run `evennia istart` again and then run `test` to get into the -command again. - -``` -> .../mygame/commands/command.py(79)func() --> obj = self.caller.search(self.args) -(Pdb) - -``` - -`pdb` is about to run the line again. - -``` -(Pdb) n -> .../mygame/commands/command.py(80)func() --> self.msg("You've found {}.".format(obj.get_display_name())) -(Pdb) -``` - -This time the line ran without error. Let's see what is in the `obj` variable: - -``` -(Pdb) obj -(Pdb) print obj -None -(Pdb) -``` - -We have entered the `test` command without parameter, so no object could be found in the search -(`self.args` is an empty string). - -Let's allow the command to continue and try to use an object name as parameter (although, we should -fix that bug too, it would be better): - -``` -(Pdb) c -... -``` - -Notice that you'll have an error in the game this time. Let's try with a valid parameter. I have -another character, `barkeep`, in this room: - -```test barkeep``` - -And again, the command freezes, and we have the debugger opened in the console. - -Let's execute this line right away: - -``` -> .../mygame/commands/command.py(79)func() --> obj = self.caller.search(self.args) -(Pdb) n -> .../mygame/commands/command.py(80)func() --> self.msg("You've found {}.".format(obj.get_display_name())) -(Pdb) obj - -(Pdb) -``` - -At least this time we have found the object. Let's process... - -``` -(Pdb) n -TypeError: 'get_display_name() takes exactly 2 arguments (1 given)' -> .../mygame/commands/command.py(80)func() --> self.msg("You've found {}.".format(obj.get_display_name())) -(Pdb) -``` - -As an exercise, fix this error, reload and run the debugger again. Nothing better than some -experimenting! - -Your debugging will often follow the same strategy: - -1. Receive an error you don't understand. -2. Put a breaking point **BEFORE** the error occurs. -3. Run the code again and see the debugger open. -4. Run the program line by line,examining variables, checking the logic of instructions. -5. Continue and try again, each step a bit further toward the truth and the working feature. - -### Stepping through a function - -`n` is useful, but it will avoid stepping inside of functions if it can. But most of the time, when -we have an error we don't understand, it's because we use functions or methods in a way that wasn't -intended by the developer of the API. Perhaps using wrong arguments, or calling the function in a -situation that would cause a bug. When we have a line in the debugger that calls a function or -method, we can "step" to examine it further. For instance, in the previous example, when `pdb` was -about to execute `obj = self.caller.search(self.args)`, we may want to see what happens inside of -the `search` method. - -To do so, use the `step` (or `s`) command. This command will show you the definition of the -function/method and you can then use `n` as before to see it line-by-line. In our little example, -stepping through a function or method isn't that useful, but when you have an impressive set of -commands, functions and so on, it might really be handy to examine some feature and make sure they -operate as planned. - -## Cheat-sheet of pdb/pudb commands - -PuDB and Pdb share the same commands. The only real difference is how it's presented. The `look` -command is not needed much in `pudb` since it displays the code directly in its user interface. - -| Pdb/PuDB command | To do what | -| ----------- | ---------- | -| list (or l) | List the lines around the point of execution (not needed for `pudb`, it will show -this directly). | -| print (or p) | Display one or several variables. | -| `!` | Run Python code (using a `!` is often optional). | -| continue (or c) | Continue execution and terminate the debugger for this time. | -| next (or n) | Execute the current line and goes to the next one. | -| step (or s) | Step inside of a function or method to examine it. | -| `` | Repeat the last command (don't type `n` repeatedly, just type it once and then press -`` to repeat it). | - -If you want to learn more about debugging with Pdb, you will find an [interesting tutorial on that -topic here](https://pymotw.com/3/pdb/). diff --git a/docs/0.9.5/_sources/Default-Commands.md.txt b/docs/0.9.5/_sources/Default-Commands.md.txt deleted file mode 100644 index 36d32e14d5..0000000000 --- a/docs/0.9.5/_sources/Default-Commands.md.txt +++ /dev/null @@ -1,107 +0,0 @@ - - -# Default Commands - -The full set of default Evennia commands currently contains 98 commands in 9 source -files. Our policy for adding default commands is outlined [here](./Using-MUX-as-a-Standard.md). The -[Commands](./Commands.md) documentation explains how Commands work as well as make new or customize -existing ones. Note that this page is auto-generated. Report problems to the [issue -tracker](github:issues). - -```{note} -Some game-states adds their own Commands which are not listed here. Examples include editing a text -with [EvEditor](./EvEditor.md), flipping pages in [EvMore](./EvMore.md) or using the -[Batch-Processor](./Batch-Processors.md)'s interactive mode. -``` - -- [**__unloggedin_look_command** [l, look]](evennia.commands.default.unloggedin.CmdUnconnectedLook) (cmdset: [UnloggedinCmdSet](evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet), help-category: _General_) -- [**about** [version]](evennia.commands.default.system.CmdAbout) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _System_) -- [**access** [hierarchy, groups]](evennia.commands.default.general.CmdAccess) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _General_) -- [**accounts** [account, listaccounts]](evennia.commands.default.system.CmdAccounts) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _System_) -- [**addcom** [chanalias, aliaschan]](evennia.commands.default.comms.CmdAddCom) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_) -- [**alias** [setobjalias]](evennia.commands.default.building.CmdSetObjAlias) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**allcom**](evennia.commands.default.comms.CmdAllCom) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_) -- [**batchcode** [batchcodes]](evennia.commands.default.batchprocess.CmdBatchCode) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**batchcommands** [batchcmd, batchcommand]](evennia.commands.default.batchprocess.CmdBatchCommands) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**cboot**](evennia.commands.default.comms.CmdCBoot) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_) -- [**ccreate** [channelcreate]](evennia.commands.default.comms.CmdChannelCreate) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_) -- [**cdesc**](evennia.commands.default.comms.CmdCdesc) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_) -- [**cdestroy**](evennia.commands.default.comms.CmdCdestroy) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_) -- [**cemit** [cmsg]](evennia.commands.default.comms.CmdCemit) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_) -- [**channels** [clist, chanlist, all channels, channellist, comlist]](evennia.commands.default.comms.CmdChannels) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_) -- [**charcreate**](evennia.commands.default.account.CmdCharCreate) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_) -- [**chardelete**](evennia.commands.default.account.CmdCharDelete) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_) -- [**clock**](evennia.commands.default.comms.CmdClock) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_) -- [**cmdsets** [listcmsets]](evennia.commands.default.building.CmdListCmdSets) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**color**](evennia.commands.default.account.CmdColorTest) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_) -- [**connect** [conn, co, con]](evennia.commands.default.unloggedin.CmdUnconnectedConnect) (cmdset: [UnloggedinCmdSet](evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet), help-category: _General_) -- [**copy**](evennia.commands.default.building.CmdCopy) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**cpattr**](evennia.commands.default.building.CmdCpAttr) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**create**](evennia.commands.default.building.CmdCreate) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**create** [cre, cr]](evennia.commands.default.unloggedin.CmdUnconnectedCreate) (cmdset: [UnloggedinCmdSet](evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet), help-category: _General_) -- [**cwho**](evennia.commands.default.comms.CmdCWho) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_) -- [**delcom** [delchanalias, delaliaschan]](evennia.commands.default.comms.CmdDelCom) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_) -- [**desc** [describe]](evennia.commands.default.building.CmdDesc) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**destroy** [delete, del]](evennia.commands.default.building.CmdDestroy) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**dig**](evennia.commands.default.building.CmdDig) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**drop**](evennia.commands.default.general.CmdDrop) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _General_) -- [**encoding** [encode]](evennia.commands.default.unloggedin.CmdUnconnectedEncoding) (cmdset: [UnloggedinCmdSet](evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet), help-category: _General_) -- [**examine** [ex, exam]](evennia.commands.default.building.CmdExamine) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Building_) -- [**find** [search, locate]](evennia.commands.default.building.CmdFind) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**get** [grab]](evennia.commands.default.general.CmdGet) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _General_) -- [**give**](evennia.commands.default.general.CmdGive) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _General_) -- [**grapevine2chan**](evennia.commands.default.comms.CmdGrapevine2Chan) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_) -- [**help** [?]](evennia.commands.default.help.CmdHelp) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_) -- [**help** [h, ?]](evennia.commands.default.unloggedin.CmdUnconnectedHelp) (cmdset: [UnloggedinCmdSet](evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet), help-category: _General_) -- [**home**](evennia.commands.default.general.CmdHome) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _General_) -- [**ic** [puppet]](evennia.commands.default.account.CmdIC) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_) -- [**info**](evennia.commands.default.unloggedin.CmdUnconnectedInfo) (cmdset: [UnloggedinCmdSet](evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet), help-category: _General_) -- [**inventory** [inv, i]](evennia.commands.default.general.CmdInventory) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _General_) -- [**irc2chan**](evennia.commands.default.comms.CmdIRC2Chan) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_) -- [**ircstatus**](evennia.commands.default.comms.CmdIRCStatus) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_) -- [**link**](evennia.commands.default.building.CmdLink) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**lock** [locks]](evennia.commands.default.building.CmdLock) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**look** [l, ls]](evennia.commands.default.account.CmdOOCLook) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_) -- [**look** [l, ls]](evennia.commands.default.general.CmdLook) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _General_) -- [**mvattr**](evennia.commands.default.building.CmdMvAttr) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**name** [rename]](evennia.commands.default.building.CmdName) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**nick** [nickname, nicks]](evennia.commands.default.general.CmdNick) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_) -- [**objects** [listobjects, db, listobjs, stats]](evennia.commands.default.system.CmdObjects) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _System_) -- [**ooc** [unpuppet]](evennia.commands.default.account.CmdOOC) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_) -- [**open**](evennia.commands.default.building.CmdOpen) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**option** [options]](evennia.commands.default.account.CmdOption) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_) -- [**page** [tell]](evennia.commands.default.comms.CmdPage) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_) -- [**password**](evennia.commands.default.account.CmdPassword) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_) -- [**pose** [emote, :]](evennia.commands.default.general.CmdPose) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _General_) -- [**py** [!]](evennia.commands.default.system.CmdPy) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _System_) -- [**quell** [unquell]](evennia.commands.default.account.CmdQuell) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_) -- [**quit**](evennia.commands.default.account.CmdQuit) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_) -- [**quit** [qu, q]](evennia.commands.default.unloggedin.CmdUnconnectedQuit) (cmdset: [UnloggedinCmdSet](evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet), help-category: _General_) -- [**reload** [restart]](evennia.commands.default.system.CmdReload) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _System_) -- [**reset** [reboot]](evennia.commands.default.system.CmdReset) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _System_) -- [**rss2chan**](evennia.commands.default.comms.CmdRSS2Chan) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _Comms_) -- [**say** [', "]](evennia.commands.default.general.CmdSay) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _General_) -- [**screenreader**](evennia.commands.default.unloggedin.CmdUnconnectedScreenreader) (cmdset: [UnloggedinCmdSet](evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet), help-category: _General_) -- [**script** [addscript]](evennia.commands.default.building.CmdScript) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**scripts** [listscripts, globalscript]](evennia.commands.default.system.CmdScripts) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _System_) -- [**server** [serverload, serverprocess]](evennia.commands.default.system.CmdServerLoad) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _System_) -- [**service** [services]](evennia.commands.default.system.CmdService) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _System_) -- [**sessions**](evennia.commands.default.account.CmdSessions) (cmdset: [SessionCmdSet](evennia.commands.default.cmdset_session.SessionCmdSet), help-category: _General_) -- [**set**](evennia.commands.default.building.CmdSetAttribute) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**setdesc**](evennia.commands.default.general.CmdSetDesc) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _General_) -- [**sethelp**](evennia.commands.default.help.CmdSetHelp) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**sethome**](evennia.commands.default.building.CmdSetHome) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**shutdown**](evennia.commands.default.system.CmdShutdown) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _System_) -- [**spawn** [olc]](evennia.commands.default.building.CmdSpawn) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**style**](evennia.commands.default.account.CmdStyle) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_) -- [**tag** [tags]](evennia.commands.default.building.CmdTag) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**tel** [teleport]](evennia.commands.default.building.CmdTeleport) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**tickers**](evennia.commands.default.system.CmdTickers) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _System_) -- [**time** [uptime]](evennia.commands.default.system.CmdTime) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _System_) -- [**tunnel** [tun]](evennia.commands.default.building.CmdTunnel) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**typeclass** [swap, parent, update, type]](evennia.commands.default.building.CmdTypeclass) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**unlink**](evennia.commands.default.building.CmdUnLink) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) -- [**whisper**](evennia.commands.default.general.CmdWhisper) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _General_) -- [**who** [doing]](evennia.commands.default.account.CmdWho) (cmdset: [AccountCmdSet](evennia.commands.default.cmdset_account.AccountCmdSet), help-category: _General_) -- [**wipe**](evennia.commands.default.building.CmdWipe) (cmdset: [CharacterCmdSet](evennia.commands.default.cmdset_character.CharacterCmdSet), help-category: _Building_) - diff --git a/docs/0.9.5/_sources/Default-Exit-Errors.md.txt b/docs/0.9.5/_sources/Default-Exit-Errors.md.txt deleted file mode 100644 index 81a26d45e3..0000000000 --- a/docs/0.9.5/_sources/Default-Exit-Errors.md.txt +++ /dev/null @@ -1,122 +0,0 @@ -# Default Exit Errors - - -Evennia allows for exits to have any name. The command "kitchen" is a valid exit name as well as -"jump out the window" or "north". An exit actually consists of two parts: an [Exit Object](./Objects.md) -and an [Exit Command](./Commands.md) stored on said exit object. The command has the same key and aliases -as the object, which is why you can see the exit in the room and just write its name to traverse it. - -If you try to enter the name of a non-existing exit, it is thus the same as trying a non-exising -command; Evennia doesn't care about the difference: - - > jump out the window - Command 'jump out the window' is not available. Type "help" for help. - -Many games don't need this type of freedom however. They define only the cardinal directions as -valid exit names (Evennia's `@tunnel` command also offers this functionality). In this case, the -error starts to look less logical: - - > west - Command 'west' is not available. Maybe you meant "@set" or "@reset"? - -Since we for our particular game *know* that west is an exit direction, it would be better if the -error message just told us that we couldn't go there. - -## Adding default error commands - -To solve this you need to be aware of how to [write and add new commands](./Adding-Command-Tutorial.md). -What you need to do is to create new commands for all directions you want to support in your game. -In this example all we'll do is echo an error message, but you could certainly consider more -advanced uses. You add these commands to the default command set. Here is an example of such a set -of commands: - -```python -# for example in a file mygame/commands/movecommands.py - -from evennia import default_cmds - -class CmdExitError(default_cmds.MuxCommand): - "Parent class for all exit-errors." - locks = "cmd:all()" - arg_regex = r"\s|$" - auto_help = False - def func(self): - "returns the error" - self.caller.msg("You cannot move %s." % self.key) - -class CmdExitErrorNorth(CmdExitError): - key = "north" - aliases = ["n"] - -class CmdExitErrorEast(CmdExitError): - key = "east" - aliases = ["e"] - -class CmdExitErrorSouth(CmdExitError): - key = "south" - aliases = ["s"] - -class CmdExitErrorWest(CmdExitError): - key = "west" - aliases = ["w"] -``` - -Make sure to add the directional commands (not their parent) to the `CharacterCmdSet` class in -`mygame/commands/default_cmdsets.py`: - -```python -# in mygame/commands/default_cmdsets.py - -from commands import movecommands - -# [...] -class CharacterCmdSet(default_cmds.CharacterCmdSet): - # [...] - def at_cmdset_creation(self): - # [...] - self.add(movecommands.CmdExitErrorNorth()) - self.add(movecommands.CmdExitErrorEast()) - self.add(movecommands.CmdExitErrorSouth()) - self.add(movecommands.CmdExitErrorWest()) -``` - -After a `@reload` these commands (assuming you don't get any errors - check your log) will be -loaded. What happens henceforth is that if you are in a room with an Exitobject (let's say it's -"north"), the proper Exit-command will overload your error command (also named "north"). But if you -enter an direction without having a matching exit for it, you will fallback to your default error -commands: - - > east - You cannot move east. - -Further expansions by the exit system (including manipulating the way the Exit command itself is -created) can be done by modifying the [Exit typeclass](./Typeclasses.md) directly. - -## Additional Comments - -So why didn't we create a single error command above? Something like this: - -```python - class CmdExitError(default_cmds.MuxCommand): - "Handles all exit-errors." - key = "error_cmd" - aliases = ["north", "n", - "east", "e", - "south", "s", - "west", "w"] - #[...] -``` -The anwer is that this would *not* work and understanding why is important in order to not be -confused when working with commands and command sets. - -The reason it doesn't work is because Evennia's [command system](./Commands.md) compares commands *both* -by `key` and by `aliases`. If *either* of those match, the two commands are considered *identical* -as far as cmdset merging system is concerned. - -So the above example would work fine as long as there were no Exits at all in the room. But what -happens when we enter a room with an exit "north"? The Exit's cmdset is merged onto the default one, -and since there is an alias match, the system determines our `CmdExitError` to be identical. It is -thus overloaded by the Exit command (which also correctly defaults to a higher priority). The result -is that you can go through the north exit normally but none of the error messages for the other -directions are available since the single error command was completely overloaded by the single -matching "north" exit-command. diff --git a/docs/0.9.5/_sources/Developer-Central.md.txt b/docs/0.9.5/_sources/Developer-Central.md.txt deleted file mode 100644 index e2ee32fc53..0000000000 --- a/docs/0.9.5/_sources/Developer-Central.md.txt +++ /dev/null @@ -1,170 +0,0 @@ -# Developer Central - - -This page serves as a central nexus for information on using Evennia as well as developing the -library itself. - -### General Evennia development information - -- [Introduction to coding with Evennia](./Coding-Introduction.md) -- [Evennia Licensing FAQ](./Licensing.md) -- [Contributing to Evennia](./Contributing.md) -- [Code Style Guide](https://github.com/evennia/evennia/blob/master/CODING_STYLE.md) (Important!) -- [Policy for 'MUX-like' default commands](./Using-MUX-as-a-Standard.md) -- [Setting up a Git environment for coding](./Version-Control.md) -- [Getting started with Travis and Github for continuous integration testing](./Using-Travis.md) -- [Planning your own Evennia game](./Game-Planning.md) -- [First steps coding Evennia](./First-Steps-Coding.md) -- [Translating Evennia](./Internationalization.md#translating-evennia) -- [Evennia Quirks](./Quirks.md) to keep in mind. -- [Directions for configuring PyCharm with Evennia on Windows](./Setting-up-PyCharm.md) - -### Evennia API - -- [Directory Overview](./Directory-Overview.md) -- [evennia - the flat API](./Evennia-API.md) - - [Running and Testing Python code](./Execute-Python-Code.md) - -#### Core components and protocols - -- [Server and Portal](./Portal-And-Server.md) - - [Sessions](./Sessions.md) - - [Configuration and module plugins](./Server-Conf.md) -- [The message path](./Messagepath.md) - - [OOB](./OOB.md) - Out-of-band communication - - [Inputfuncs](./Inputfuncs.md) - - [Adding new protocols (client APIs) and services](./Custom-Protocols.md) -- [Adding new database models](./New-Models.md) -- [Unit Testing](./Unit-Testing.md) -- [Running profiling](./Profiling.md) -- [Debugging your code](./Debugging.md) - -#### In-game Commands - -- [Command System overview](./Command-System.md) -- [Commands](./Commands.md) -- [Command Sets](./Command-Sets.md) -- [Command Auto-help](./Help-System.md#command-auto-help-system) - -#### Typeclasses and related concepts - -- [General about Typeclasses](./Typeclasses.md) -- [Objects](./Objects.md) - - [Characters](./Objects.md#characters) - - [Rooms](./Objects.md#rooms) - - [Exits](./Objects.md#exits) -- [Accounts](./Accounts.md) -- [Communications](./Communications.md) - - [Channels](./Communications.md#channels) -- [Scripts](./Scripts.md) - - [Global Scripts](./Scripts.md#global-scripts) - - [TickerHandler](./TickerHandler.md) - - [utils.delay](./Coding-Utils.md#utilsdelay) - - [MonitorHandler](./MonitorHandler.md) -- [Attributes](./Attributes.md) -- [Nicks](./Nicks.md) -- [Tags](./Tags.md) - - [Tags for Aliases and Permissions](./Tags.md#using-aliases-and-permissions) - -#### Web - -- [Web features overview](./Web-Features.md) -- [The Webclient](./Webclient.md) -- [Web tutorials](./Web-Tutorial.md) - -#### Other systems - -- [Locks](./Locks.md) - - [Permissions](./Locks.md#permissions) -- [Help System](./Help-System.md) -- [Signals](./Signals.md) -- [General coding utilities](./Coding-Utils.md) - - [Utils in evennia.utils.utils](evennia.utils.utils) -- [Game time](./Coding-Utils.md#game-time) -- [Game Menus](./EvMenu.md) (EvMenu) -- [Text paging/scrolling](./EvMore.md) (EvMore) -- [Text Line Editor](./EvEditor.md) (EvEditor) -- [Text Tables](github:evennia.utils.evtable) (EvTable) -- [Text Form generation](github:evennia.utils.evform) (EvForm) -- [Spawner and Prototypes](./Spawner-and-Prototypes.md) -- [Inlinefuncs](./TextTags.md#inline-functions) -- [Asynchronous execution](./Async-Process.md) - -### Developer brainstorms and whitepages - -- [API refactoring](./API-refactoring.md), discussing what parts of the Evennia API needs a -refactoring/cleanup/simplification -- [Docs refactoring](./Docs-refactoring.md), discussing how to reorganize and structure this wiki/docs -better going forward -- [Webclient brainstorm](./Webclient-brainstorm.md), some ideas for a future webclient gui -- [Roadmap](./Roadmap.md), a tentative list of future major features -- [Change log](https://github.com/evennia/evennia/blob/master/CHANGELOG.md) of big Evennia updates -over time - - -[group]: https://groups.google.com/forum/#!forum/evennia -[online-form]: https://docs.google.com/spreadsheet/viewform?hl=en_US&formkey=dGN0VlJXMWpCT3VHaHpscDE -zY1RoZGc6MQ#gid=0 -[issues]: https://github.com/evennia/evennia/issues - - -```{toctree} - :hidden: - - Coding-Introduction - Licensing - Contributing - Using-MUX-as-a-Standard - Version-Control - Using-Travis - Game-Planning - First-Steps-Coding - Internationalization - Quirks - Setting-up-PyCharm - Directory-Overview - Evennia-API - Execute-Python-Code - Portal-And-Server - Sessions - Server-Conf - Messagepath - OOB - Inputfuncs - Custom-Protocols - New-Models - Unit-Testing - Profiling - Debugging - Command-System - Commands - Command-Sets - Help-System - Typeclasses - Objects - Accounts - Communications - Scripts - TickerHandler - Coding-Utils - MonitorHandler - Attributes - Nicks - Tags - Web-Features - Webclient - Web-Tutorial - Locks - Signals - Coding-Utils - EvMenu - EvMore - EvEditor - Spawner-and-Prototypes - TextTags - Async-Process - API-refactoring - Docs-refactoring - Webclient-brainstorm - -``` diff --git a/docs/0.9.5/_sources/Dialogues-in-events.md.txt b/docs/0.9.5/_sources/Dialogues-in-events.md.txt deleted file mode 100644 index f3bb5c0d06..0000000000 --- a/docs/0.9.5/_sources/Dialogues-in-events.md.txt +++ /dev/null @@ -1,247 +0,0 @@ -# Dialogues in events - - -- Next tutorial: [adding a voice-operated elevator with events](A-voice-operated-elevator-using- -events). - -This tutorial will walk you through the steps to create several dialogues with characters, using the -[in-game Python -system](https://github.com/evennia/evennia/blob/master/evennia/contrib/ingame_python/README.md). -This tutorial assumes the in-game Python system is installed in your game. If it isn't, you can -follow the installation steps given in [the documentation on in-game -Python](https://github.com/evennia/evennia/blob/master/evennia/contrib/ingame_python/README.md), and -come back on this tutorial once the system is installed. **You do not need to read** the entire -documentation, it's a good reference, but not the easiest way to learn about it. Hence these -tutorials. - -The in-game Python system allows to run code on individual objects in some situations. You don't -have to modify the source code to add these features, past the installation. The entire system -makes it easy to add specific features to some objects, but not all. This is why it can be very -useful to create a dialogue system taking advantage of the in-game Python system. - -> What will we try to do? - -In this tutorial, we are going to create a basic dialogue to have several characters automatically -respond to specific messages said by others. - -## A first example with a first character - -Let's create a character to begin with. - - @charcreate a merchant - -This will create a merchant in the room where you currently are. It doesn't have anything, like a -description, you can decorate it a bit if you like. - -As said above, the in-game Python system consists in linking objects with arbitrary code. This code -will be executed in some circumstances. Here, the circumstance is "when someone says something in -the same room", and might be more specific like "when someone says hello". We'll decide what code -to run (we'll actually type the code in-game). Using the vocabulary of the in-game Python system, -we'll create a callback: a callback is just a set of lines of code that will run under some -conditions. - -You can have an overview of every "conditions" in which callbacks can be created using the `@call` -command (short for `@callback`). You need to give it an object as argument. Here for instance, we -could do: - - @call a merchant - -You should see a table with three columns, showing the list of events existing on our newly-created -merchant. There are quite a lot of them, as it is, althougn no line of code has been set yet. For -our system, you might be more interested by the line describing the `say` event: - - | say | 0 (0) | After another character has said something in | - | | | the character's room. | - -We'll create a callback on the `say` event, called when we say "hello" in the merchant's room: - - @call/add a merchant = say hello - -Before seeing what this command displays, let's see the command syntax itself: - -- `@call` is the command name, `/add` is a switch. You can read the help of the command to get the -help of available switches and a brief overview of syntax. -- We then enter the object's name, here "a merchant". You can enter the ID too ("#3" in my case), -which is useful to edit the object when you're not in the same room. You can even enter part of the -name, as usual. -- An equal sign, a simple separator. -- The event's name. Here, it's "say". The available events are displayed when you use `@call` -without switch. -- After a space, we enter the conditions in which this callback should be called. Here, the -conditions represent what the other character should say. We enter "hello". Meaning that if -someone says something containing "hello" in the room, the callback we are now creating will be -called. - -When you enter this command, you should see something like this: - -``` -After another character has said something in the character's room. -This event is called right after another character has said -something in the same location. The action cannot be prevented -at this moment. Instead, this event is ideal to create keywords -that would trigger a character (like a NPC) in doing something -if a specific phrase is spoken in the same location. - -To use this event, you have to specify a list of keywords as -parameters that should be present, as separate words, in the -spoken phrase. For instance, you can set a callback that would -fire if the phrase spoken by the character contains "menu" or -"dinner" or "lunch": - @call/add ... = say menu, dinner, lunch -Then if one of the words is present in what the character says, -this callback will fire. - -Variables you can use in this event: - speaker: the character speaking in this room. - character: the character connected to this event. - message: the text having been spoken by the character. -``` - -That's some list of information. What's most important to us now is: - -- The "say" event is called whenever someone else speaks in the room. -- We can set callbacks to fire when specific keywords are present in the phrase by putting them as -additional parameters. Here we have set this parameter to "hello". We can have several keywords -separated by a comma (we'll see this in more details later). -- We have three default variables we can use in this callback: `speaker` which contains the -character who speaks, `character` which contains the character who's modified by the in-game Python -system (here, or merchant), and `message` which contains the spoken phrase. - -This concept of variables is important. If it makes things more simple to you, think of them as -parameters in a function: they can be used inside of the function body because they have been set -when the function was called. - -This command has opened an editor where we can type our Python code. - -``` -----------Line Editor [Callback say of a merchant]-------------------------------- -01| -----------[l:01 w:000 c:0000]------------(:h for help)---------------------------- -``` - -For our first test, let's type something like: - -```python -character.location.msg_contents("{character} shrugs and says: 'well, yes, hello to you!'", -mapping=dict(character=character)) -``` - -Once you have entered this line, you can type `:wq` to save the editor and quit it. - -And now if you use the "say" command with a message containing "hello": - -``` -You say, "Hello sir merchant!" -a merchant(#3) shrugs and says: 'well, yes, hello to you!' -``` - -If you say something that doesn't contain "hello", our callback won't execute. - -**In summary**: - -1. When we say something in the room, using the "say" command, the "say" event of all characters -(except us) is called. -2. The in-game Python system looks at what we have said, and checks whether one of our callbacks in -the "say" event contains a keyword that we have spoken. -3. If so, call it, defining the event variables as we have seen. -4. The callback is then executed as normal Python code. Here we have called the `msg_contents` -method on the character's location (probably a room) to display a message to the entire room. We -have also used mapping to easily display the character's name. This is not specific to the in-game -Python system. If you feel overwhelmed by the code we've used, just shorten it and use something -more simple, for instance: - -```python -speaker.msg("You have said something to me.") -``` - -## The same callback for several keywords - -It's easy to create a callback that will be triggered if the sentence contains one of several -keywords. - - @call/add merchant = say trade, trader, goods - -And in the editor that opens: - -```python -character.location.msg_contents("{character} says: 'Ho well, trade's fine as long as roads are -safe.'", mapping=dict(character=character)) -``` - -Then you can say something with either "trade", "trader" or "goods" in your sentence, which should -call the callback: - -``` -You say, "and how is your trade going?" -a merchant(#3) says: 'Ho well, trade's fine as long as roads are safe.' -``` - -We can set several keywords when adding the callback. We just need to separate them with commas. - -## A longer callback - -So far, we have only set one line in our callbacks. Which is useful, but we often need more. For -an entire dialogue, you might want to do a bit more than that. - - @call/add merchant = say bandit, bandits - -And in the editor you can paste the following lines: - -```python -character.location.msg_contents("{character} says: 'Bandits he?'", -mapping=dict(character=character)) -character.location.msg_contents("{character} scratches his head, considering.", -mapping=dict(character=character)) -character.location.msg_contents("{character} whispers: 'Aye, saw some of them, north from here. No -trouble o' mine, but...'", mapping=dict(character=character)) -speaker.msg("{character} looks at you more -closely.".format(character=character.get_display_name(speaker))) -speaker.msg("{character} continues in a low voice: 'Ain't my place to say, but if you need to find -'em, they're encamped some distance away from the road, I guess near a cave or -something.'.".format(character=character.get_display_name(speaker))) -``` - -Now try to ask the merchant about bandits: - -``` -You say, "have you seen bandits?" -a merchant(#3) says: 'Bandits he?' -a merchant(#3) scratches his head, considering. -a merchant(#3) whispers: 'Aye, saw some of them, north from here. No trouble o' mine, but...' -a merchant(#3) looks at you more closely. -a merchant(#3) continues in a low voice: 'Ain't my place to say, but if you need to find 'em, -they're encamped some distance away from the road, I guess near a cave or something.'. -``` - -Notice here that the first lines of dialogue are spoken to the entire room, but then the merchant is -talking directly to the speaker, and only the speaker hears it. There's no real limit to what you -can do with this. - -- You can set a mood system, storing attributes in the NPC itself to tell you in what mood he is, -which will influence the information he will give... perhaps the accuracy of it as well. -- You can add random phrases spoken in some context. -- You can use other actions (you're not limited to having the merchant say something, you can ask -him to move, gives you something, attack if you have a combat system, or whatever else). -- The callbacks are in pure Python, so you can write conditions or loops. -- You can add in "pauses" between some instructions using chained events. This tutorial won't -describe how to do that however. You already have a lot to play with. - -## Tutorial F.A.Q. - -- **Q:** can I create several characters who would answer to specific dialogue? -- **A:** of course. Te in-game Python system is so powerful because you can set unique code for -various objects. You can have several characters answering to different things. You can even have -different characters in the room answering to greetings. All callbacks will be executed one after -another. -- **Q:** can I have two characters answering to the same dialogue in exactly the same way? -- **A:** It's possible but not so easy to do. Usually, event grouping is set in code, and depends -on different games. However, if it is for some infrequent occurrences, it's easy to do using -[chained events](https://github.com/evennia/evennia/blob/master/evennia/contrib/ingame_python/README.md#chained-events). -- **Q:** is it possible to deploy callbacks on all characters sharing the same prototype? -- **A:** not out of the box. This depends on individual settings in code. One can imagine that all -characters of some type would share some events, but this is game-specific. Rooms of the same zone -could share the same events as well. It is possible to do but requires modification of the source -code. - -- Next tutorial: [adding a voice-operated elevator with events](A-voice-operated-elevator-using- -events). diff --git a/docs/0.9.5/_sources/Directory-Overview.md.txt b/docs/0.9.5/_sources/Directory-Overview.md.txt deleted file mode 100644 index be69c1bf1b..0000000000 --- a/docs/0.9.5/_sources/Directory-Overview.md.txt +++ /dev/null @@ -1,68 +0,0 @@ -# Directory Overview - - -This is an overview of the directories relevant to Evennia coding. - -## The Game directory - -The game directory is created with `evennia --init `. In the Evennia documentation we always -assume it's called `mygame`. Apart from the `server/` subfolder within, you could reorganize this -folder if you preferred a different code structure for your game. - - - `mygame/` - - `commands/` - Overload default [Commands](./Commands.md) or add your own Commands/[Command -sets](./Command-Sets.md) here. - - `server`/ - The structure of this folder should not change since Evennia expects it. - - [`conf/`](https://github.com/evennia/evennia/tree/master/evennia/game_template/server) - All -server configuration files sits here. The most important file is `settings.py`. - - `logs/` - Portal log files are stored here (Server is logging to the terminal by default) - - `typeclasses/` - this folder contains empty templates for overloading default game entities of -Evennia. Evennia will automatically use the changes in those templates for the game entities it -creates. - - `web/` - This holds the [Web features](./Web-Features.md) of your game. - - `world/` - this is a "miscellaneous" folder holding everything related to the world you are -building, such as build scripts and rules modules that don't fit with one of the other folders. - -## Evennia library layout: - -If you cloned the GIT repo following the instructions, you will have a folder named `evennia`. The -top level of it contains Python package specific stuff such as a readme file, `setup.py` etc. It -also has two subfolders`bin/` and `evennia/` (again). - -The `bin/` directory holds OS-specific binaries that will be used when installing Evennia with `pip` -as per the [Getting started](./Getting-Started.md) instructions. The library itself is in the `evennia` -subfolder. From your code you will access this subfolder simply by `import evennia`. - - - evennia - - [`__init__.py`](./Evennia-API.md) - The "flat API" of Evennia resides here. - - [`commands/`](./Commands.md) - The command parser and handler. - - `default/` - The [default commands](./Default-Commands.md) and cmdsets. - - [`comms/`](./Communications.md) - Systems for communicating in-game. - - `contrib/` - Optional plugins too game-specific for core Evennia. - - `game_template/` - Copied to become the "game directory" when using `evennia --init`. - - [`help/`](./Help-System.md) - Handles the storage and creation of help entries. - - `locale/` - Language files ([i18n](./Internationalization.md)). - - [`locks/`](./Locks.md) - Lock system for restricting access to in-game entities. - - [`objects/`](./Objects.md) - In-game entities (all types of items and Characters). - - [`prototypes/`](./Spawner-and-Prototypes.md) - Object Prototype/spawning system and OLC menu - - [`accounts/`](./Accounts.md) - Out-of-game Session-controlled entities (accounts, bots etc) - - [`scripts/`](./Scripts.md) - Out-of-game entities equivalence to Objects, also with timer support. - - [`server/`](./Portal-And-Server.md) - Core server code and Session handling. - - `portal/` - Portal proxy and connection protocols. - - [`settings_default.py`](./Server-Conf.md#settings-file) - Root settings of Evennia. Copy settings -from here to `mygame/server/settings.py` file. - - [`typeclasses/`](./Typeclasses.md) - Abstract classes for the typeclass storage and database system. - - [`utils/`](./Coding-Utils.md) - Various miscellaneous useful coding resources. - - [`web/`](./Web-Features.md) - Web resources and webserver. Partly copied into game directory on -initialization. - -All directories contain files ending in `.py`. These are Python *modules* and are the basic units of -Python code. The roots of directories also have (usually empty) files named `__init__.py`. These are -required by Python so as to be able to find and import modules in other directories. When you have -run Evennia at least once you will find that there will also be `.pyc` files appearing, these are -pre-compiled binary versions of the `.py` files to speed up execution. - -The root of the `evennia` folder has an `__init__.py` file containing the "[flat API](./Evennia-API.md)". -This holds shortcuts to various subfolders in the evennia library. It is provided to make it easier -to find things; it allows you to just import `evennia` and access things from that rather than -having to import from their actual locations inside the source tree. diff --git a/docs/0.9.5/_sources/Docs-refactoring.md.txt b/docs/0.9.5/_sources/Docs-refactoring.md.txt deleted file mode 100644 index f8473beaac..0000000000 --- a/docs/0.9.5/_sources/Docs-refactoring.md.txt +++ /dev/null @@ -1,117 +0,0 @@ -# Docs refactoring - -This is a whitepage for free discussion about the wiki docs and refactorings needed. - -Note that this is not a forum. To keep things clean, each opinion text should ideally present a -clear argument or lay out a suggestion. Asking for clarification and any side-discussions should be -held in chat or forum. - -### Griatch (Aug 13, 2019) - -This is how to make a discussion entry for the whitepage. Use any markdown formatting you need. Also -remember to copy your work to the clipboard before saving the page since if someone else edited the -page since you started, you'll have to reload and write again. - -#### (Sept 23, 2019) - -[This (now closed) issue by DamnedScholar](https://github.com/evennia/evennia/issues/1431) gives the -following suggestion: -> I think it would be useful for the pages that explain how to use various features of Evennia to -have explicit and easily visible links to the respective API entry or entries. Some pages do, but -not all. I imagine this as a single entry at the top of the page [...]. - -[This (now closed) issue by taladan](https://github.com/evennia/evennia/issues/1578) gives the -following suggestion: -> It would help me (and probably a couple of others) if there is a way to show the file path where a -particular thing exists. Maybe up under the 'last edited' line we could have a line like: -evennia/locks/lockhandler.py - -This would help in development to quickly refer to where a resource is located. - - -### Kovitikus (Sept. 11, 2019) - -[Batch Code](./Batch-Code-Processor.md) should have a link in the developer area. It is currently only -listed in the tutorials section as an afterthought to a tutorial title. - -*** - -In regards to the general structure of each wiki page: I'd like to see a table of contents at the -top of each one, so that it can be quickly navigated and is immediately apparent what sections are -covered on the page. Similar to the current [Getting Started](./Getting-Started.md) page. - -*** - -The structuring of the page should also include a quick reference cheatsheet for certain aspects. -Such as [Tags](./Tags.md) including a quick reference section at the top that lists an example of every -available method you can use in a clear and consistent format, along with a comment. Readers -shouldn't have to decipher the article to gather such basic information and it should instead be -available at first glance. - -Example of a quick reference: - -**Tags** -``` -# Add a tag. -obj.tags.add("label") - -# Remove a tag. -obj.tags.remove("label") - -# Remove all tags. -obj.tags.clear() - -# Search for a tag. Evennia must be imported first. -store_result = evennia.search_tag("label") - -# Return a list of all tags. -obj.tags.all() -``` - -**Aliases** -``` -# Add an alias. -obj.aliases.add("label") - -ETC... -``` - -*** - -In regards to comment structure, I often find that smushing together lines with comments to be too -obscure. White space should be used to clearly delineate what information the comment is for. I -understand that the current format is that a comment references whatever is below it, but newbies -may not know that until they realize it. - -Example of poor formatting: -``` -#comment -command/code -#comment -command/code -``` - -Example of good formatting: -``` -# Comment. -command/code - -# Comment. -command/code -``` - -### Sage (3/28/20) - -If I want to find information on the correct syntax for is_typeclass(), here's what I do: -* Pop over to the wiki. Okay, this is a developer functionality. Let's try that. -* Ctrl+F on Developer page. No results. -* Ctrl+F on API page. No results. Ctrl+F on Flat API page. No results -* Ctrl+F on utils page. No results. -* Ctrl+F on utils.utils page. No results. -* Ctrl+F in my IDE. Results. -* Fortunately, there's only one result for def is_typeclass. If this was at_look, there would be -several results, and I'd have to go through each of those individually, and most of them would just -call return_appearance - -An important part of a refactor, in my opinion, is separating out the "Tutorials" from the -"Reference" documentation. diff --git a/docs/0.9.5/_sources/Dynamic-In-Game-Map.md.txt b/docs/0.9.5/_sources/Dynamic-In-Game-Map.md.txt deleted file mode 100644 index 5d21a9fc94..0000000000 --- a/docs/0.9.5/_sources/Dynamic-In-Game-Map.md.txt +++ /dev/null @@ -1,495 +0,0 @@ -# Dynamic In Game Map - - -## Introduction - -An often desired feature in a MUD is to show an in-game map to help navigation. The [Static in-game -map](./Static-In-Game-Map.md) tutorial solves this by creating a *static* map, meaning the map is pre- -drawn once and for all - the rooms are then created to match that map. When walking around, parts of -the static map is then cut out and displayed next to the room description. - -In this tutorial we'll instead do it the other way around; We will dynamically draw the map based on -the relationships we find between already existing rooms. - -## The Grid of Rooms - -There are at least two requirements needed for this tutorial to work. - -1. The structure of your mud has to follow a logical layout. Evennia supports the layout of your -world to be 'logically' impossible with rooms looping to themselves or exits leading to the other -side of the map. Exits can also be named anything, from "jumping out the window" to "into the fifth -dimension". This tutorial assumes you can only move in the cardinal directions (N, E, S and W). -2. Rooms must be connected and linked together for the map to be generated correctly. Vanilla -Evennia comes with a admin command [tunnel](evennia.commands.default.building.CmdTunnel) that allows a -user to create rooms in the cardinal directions, but additional work is needed to assure that rooms -are connected. For example, if you `tunnel east` and then immediately do `tunnel west` you'll find -that you have created two completely stand-alone rooms. So care is needed if you want to create a -"logical" layout. In this tutorial we assume you have such a grid of rooms that we can generate the -map from. - -## Concept - -Before getting into the code, it is beneficial to understand and conceptualize how this is going to -work. The idea is analogous to a worm that starts at your current position. It chooses a direction -and 'walks' outward from it, mapping its route as it goes. Once it has traveled a pre-set distance -it stops and starts over in another direction. An important note is that we want a system which is -easily callable and not too complicated. Therefore we will wrap this entire code into a custom -Python class (not a typeclass as this doesn't use any core objects from evennia itself). - -We are going to create something that displays like this when you type 'look': - -``` - Hallway - - [.] [.] - [@][.][.][.][.] - [.] [.] [.] - - The distant echoes of the forgotten - wail throughout the empty halls. - - Exits: North, East, South -``` - -Your current location is defined by `[@]` while the `[.]`s are other rooms that the "worm" has seen -since departing from your location. - -## Setting up the Map Display - -First we must define the components for displaying the map. For the "worm" to know what symbol to -draw on the map we will have it check an Attribute on the room it visits called `sector_type`. For -this tutorial we understand two symbols - a normal room and the room with us in it. We also define a -fallback symbol for rooms without said Attribute - that way the map will still work even if we -didn't prepare the room correctly. Assuming your game folder is named `mygame`, we create this code -in `mygame/world/map.py.` - -```python -# in mygame/world/map.py - -# the symbol is identified with a key "sector_type" on the -# Room. Keys None and "you" must always exist. -SYMBOLS = { None : ' . ', # for rooms without sector_type Attribute - 'you' : '[@]', - 'SECT_INSIDE': '[.]' } -``` - -Since trying to access an unset Attribute returns `None`, this means rooms without the `sector_type` -Atttribute will show as ` . `. Next we start building the custom class `Map`. It will hold all -methods we need. - -```python -# in mygame/world/map.py - -class Map(object): - - def __init__(self, caller, max_width=9, max_length=9): - self.caller = caller - self.max_width = max_width - self.max_length = max_length - self.worm_has_mapped = {} - self.curX = None - self.curY = None -``` - -- `self.caller` is normally your Character object, the one using the map. -- `self.max_width/length` determine the max width and length of the map that will be generated. Note -that it's important that these variables are set to *odd* numbers to make sure the display area has -a center point. -- ` self.worm_has_mapped` is building off the worm analogy above. This dictionary will store all -rooms the "worm" has mapped as well as its relative position within the grid. This is the most -important variable as it acts as a 'checker' and 'address book' that is able to tell us where the -worm has been and what it has mapped so far. -- `self.curX/Y` are coordinates representing the worm's current location on the grid. - - -Before any sort of mapping can actually be done we need to create an empty display area and do some -sanity checks on it by using the following methods. - -```python -# in mygame/world/map.py - -class Map(object): - # [... continued] - - def create_grid(self): - # This method simply creates an empty grid/display area - # with the specified variables from __init__(self): - board = [] - for row in range(self.max_width): - board.append([]) - for column in range(self.max_length): - board[row].append(' ') - return board - - def check_grid(self): - # this method simply checks the grid to make sure - # that both max_l and max_w are odd numbers. - return True if self.max_length % 2 != 0 or self.max_width % 2 != 0\ - else False -``` - -Before we can set our worm on its way, we need to know some of the computer science behind all this -called 'Graph Traversing'. In Pseudo code what we are trying to accomplish is this: - -```python -# pseudo code - -def draw_room_on_map(room, max_distance): - self.draw(room) - - if max_distance == 0: - return - - for exit in room.exits: - if self.has_drawn(exit.destination): - # skip drawing if we already visited the destination - continue - else: - # first time here! - self.draw_room_on_map(exit.destination, max_distance - 1) -``` - -The beauty of Python is that our actual code of doing this doesn't differ much if at all from this -Pseudo code example. - -- `max_distance` is a variable indicating to our Worm how many rooms AWAY from your current location -will it map. Obviously the larger the number the more time it will take if your current location has -many many rooms around you. - -The first hurdle here is what value to use for 'max_distance'. There is no reason for the worm to -travel further than what is actually displayed to you. For example, if your current location is -placed in the center of a display area of size `max_length = max_width = 9`, then the worm need only -go `4` spaces in either direction: - -``` -[.][.][.][.][@][.][.][.][.] - 4 3 2 1 0 1 2 3 4 -``` - -The max_distance can be set dynamically based on the size of the display area. As your width/length -changes it becomes a simple algebraic linear relationship which is simply `max_distance = -(min(max_width, max_length) -1) / 2`. - -## Building the Mapper - -Now we can start to fill our Map object with some methods. We are still missing a few methods that -are very important: - -* `self.draw(self, room)` - responsible for actually drawing room to grid. -* `self.has_drawn(self, room)` - checks to see if the room has been mapped and worm has already been -here. -* `self.median(self, number)` - a simple utility method that finds the median (middle point) from 0, -n -* `self.update_pos(self, room, exit_name)` - updates the worm's physical position by reassigning -self.curX/Y. .accordingly -* `self.start_loc_on_grid(self)` - the very first initial draw on the grid representing your -location in the middle of the grid -* 'self.show_map` - after everything is done convert the map into a readable string` -* `self.draw_room_on_map(self, room, max_distance)` - the main method that ties it all together.` - - -Now that we know which methods we need, let's refine our initial `__init__(self)` to pass some -conditional statements and set it up to start building the display. - - -```python -#mygame/world/map.py - -class Map(object): - - def __init__(self, caller, max_width=9, max_length=9): - self.caller = caller - self.max_width = max_width - self.max_length = max_length - self.worm_has_mapped = {} - self.curX = None - self.curY = None - - if self.check_grid(): - # we have to store the grid into a variable - self.grid = self.create_grid() - # we use the algebraic relationship - self.draw_room_on_map(caller.location, - ((min(max_width, max_length) -1 ) / 2) - -``` - -Here we check to see if the parameters for the grid are okay, then we create an empty canvas and map -our initial location as the first room! - -As mentioned above, the code for the `self.draw_room_on_map()` is not much different than the Pseudo -code. The method is shown below: - -```python -# in mygame/world/map.py, in the Map class - -def draw_room_on_map(self, room, max_distance): - self.draw(room) - - if max_distance == 0: - return - - for exit in room.exits: - if exit.name not in ("north", "east", "west", "south"): - # we only map in the cardinal directions. Mapping up/down would be - # an interesting learning project for someone who wanted to try it. - continue - if self.has_drawn(exit.destination): - # we've been to the destination already, skip ahead. - continue - - self.update_pos(room, exit.name.lower()) - self.draw_room_on_map(exit.destination, max_distance - 1) -``` - -The first thing the "worm" does is to draw your current location in `self.draw`. Lets define that... - -```python -#in mygame/word/map.py, in the Map class - -def draw(self, room): - # draw initial ch location on map first! - if room == self.caller.location: - self.start_loc_on_grid() - self.worm_has_mapped[room] = [self.curX, self.curY] - else: - # map all other rooms - self.worm_has_mapped[room] = [self.curX, self.curY] - # this will use the sector_type Attribute or None if not set. - self.grid[self.curX][self.curY] = SYMBOLS[room.db.sector_type] -``` - -In `self.start_loc_on_grid()`: - -```python -def median(self, num): - lst = sorted(range(0, num)) - n = len(lst) - m = n -1 - return (lst[n//2] + lst[m//2]) / 2.0 - -def start_loc_on_grid(self): - x = self.median(self.max_width) - y = self.median(self.max_length) - # x and y are floats by default, can't index lists with float types - x, y = int(x), int(y) - - self.grid[x][y] = SYMBOLS['you'] - self.curX, self.curY = x, y # updating worms current location -``` - -After the system has drawn the current map it checks to see if the `max_distance` is `0` (since this -is the inital start phase it is not). Now we handle the iteration once we have each individual exit -in the room. The first thing it does is check if the room the Worm is in has been mapped already.. -lets define that... - - -```python -def has_drawn(self, room): - return True if room in self.worm_has_mapped.keys() else False -``` - -If `has_drawn` returns `False` that means the worm has found a room that hasn't been mapped yet. It -will then 'move' there. The self.curX/Y sort of lags behind, so we have to make sure to track the -position of the worm; we do this in `self.update_pos()` below. - -```python -def update_pos(self, room, exit_name): - # this ensures the coordinates stays up to date - # to where the worm is currently at. - self.curX, self.curY = \ - self.worm_has_mapped[room][0], self.worm_has_mapped[room][1] - - # now we have to actually move the pointer - # variables depending on which 'exit' it found - if exit_name == 'east': - self.curY += 1 - elif exit_name == 'west': - self.curY -= 1 - elif exit_name == 'north': - self.curX -= 1 - elif exit_name == 'south': - self.curX += 1 -``` - -Once the system updates the position of the worm it feeds the new room back into the original -`draw_room_on_map()` and starts the process all over again.. - -That is essentially the entire thing. The final method is to bring it all together and make a nice -presentational string out of it using the `self.show_map()` method. - -```python -def show_map(self): - map_string = "" - for row in self.grid: - map_string += " ".join(row) - map_string += "\n" - - return map_string -``` - -## Using the Map - -In order for the map to get triggered we store it on the Room typeclass. If we put it in -`return_appearance` we will get the map back every time we look at the room. - -> `return_appearance` is a default Evennia hook available on all objects; it is called e.g. by the -`look` command to get the description of something (the room in this case). - -```python -# in mygame/typeclasses/rooms.py - -from evennia import DefaultRoom -from world.map import Map - -class Room(DefaultRoom): - - def return_appearance(self, looker): - # [...] - string = "%s\n" % Map(looker).show_map() - # Add all the normal stuff like room description, - # contents, exits etc. - string += "\n" + super().return_appearance(looker) - return string -``` - -Obviously this method of generating maps doesn't take into account of any doors or exits that are -hidden.. etc.. but hopefully it serves as a good base to start with. Like previously mentioned, it -is very important to have a solid foundation on rooms before implementing this. You can try this on -vanilla evennia by using @tunnel and essentially you can just create a long straight/edgy non- -looping rooms that will show on your in-game map. - -The above example will display the map above the room description. You could also use an -[EvTable](github:evennia.utils.evtable) to place description and map next to each other. Some other -things you can do is to have a [Command](./Commands.md) that displays with a larger radius, maybe with a -legend and other features. - -Below is the whole `map.py` for your reference. You need to update your `Room` typeclass (see above) -to actually call it. Remember that to see different symbols for a location you also need to set the -`sector_type` Attribute on the room to one of the keys in the `SYMBOLS` dictionary. So in this -example, to make a room be mapped as `[.]` you would set the room's `sector_type` to -`"SECT_INSIDE"`. Try it out with `@set here/sector_type = "SECT_INSIDE"`. If you wanted all new -rooms to have a given sector symbol, you could change the default in the `SYMBOLS´ dictionary below, -or you could add the Attribute in the Room's `at_object_creation` method. - -```python -#mygame/world/map.py - -# These are keys set with the Attribute sector_type on the room. -# The keys None and "you" must always exist. -SYMBOLS = { None : ' . ', # for rooms without a sector_type attr - 'you' : '[@]', - 'SECT_INSIDE': '[.]' } - -class Map(object): - - def __init__(self, caller, max_width=9, max_length=9): - self.caller = caller - self.max_width = max_width - self.max_length = max_length - self.worm_has_mapped = {} - self.curX = None - self.curY = None - - if self.check_grid(): - # we actually have to store the grid into a variable - self.grid = self.create_grid() - self.draw_room_on_map(caller.location, - ((min(max_width, max_length) -1 ) / 2)) - - def update_pos(self, room, exit_name): - # this ensures the pointer variables always - # stays up to date to where the worm is currently at. - self.curX, self.curY = \ - self.worm_has_mapped[room][0], self.worm_has_mapped[room][1] - - # now we have to actually move the pointer - # variables depending on which 'exit' it found - if exit_name == 'east': - self.curY += 1 - elif exit_name == 'west': - self.curY -= 1 - elif exit_name == 'north': - self.curX -= 1 - elif exit_name == 'south': - self.curX += 1 - - def draw_room_on_map(self, room, max_distance): - self.draw(room) - - if max_distance == 0: - return - - for exit in room.exits: - if exit.name not in ("north", "east", "west", "south"): - # we only map in the cardinal directions. Mapping up/down would be - # an interesting learning project for someone who wanted to try it. - continue - if self.has_drawn(exit.destination): - # we've been to the destination already, skip ahead. - continue - - self.update_pos(room, exit.name.lower()) - self.draw_room_on_map(exit.destination, max_distance - 1) - - def draw(self, room): - # draw initial caller location on map first! - if room == self.caller.location: - self.start_loc_on_grid() - self.worm_has_mapped[room] = [self.curX, self.curY] - else: - # map all other rooms - self.worm_has_mapped[room] = [self.curX, self.curY] - # this will use the sector_type Attribute or None if not set. - self.grid[self.curX][self.curY] = SYMBOLS[room.db.sector_type] - - def median(self, num): - lst = sorted(range(0, num)) - n = len(lst) - m = n -1 - return (lst[n//2] + lst[m//2]) / 2.0 - - def start_loc_on_grid(self): - x = self.median(self.max_width) - y = self.median(self.max_length) - # x and y are floats by default, can't index lists with float types - x, y = int(x), int(y) - - self.grid[x][y] = SYMBOLS['you'] - self.curX, self.curY = x, y # updating worms current location - - - def has_drawn(self, room): - return True if room in self.worm_has_mapped.keys() else False - - - def create_grid(self): - # This method simply creates an empty grid - # with the specified variables from __init__(self): - board = [] - for row in range(self.max_width): - board.append([]) - for column in range(self.max_length): - board[row].append(' ') - return board - - def check_grid(self): - # this method simply checks the grid to make sure - # both max_l and max_w are odd numbers - return True if self.max_length % 2 != 0 or \ - self.max_width % 2 != 0 else False - - def show_map(self): - map_string = "" - for row in self.grid: - map_string += " ".join(row) - map_string += "\n" - - return map_string -``` - -## Final Comments - -The Dynamic map could be expanded with further capabilities. For example, it could mark exits or -allow NE, SE etc directions as well. It could have colors for different terrain types. One could -also look into up/down directions and figure out how to display that in a good way. diff --git a/docs/0.9.5/_sources/EvEditor.md.txt b/docs/0.9.5/_sources/EvEditor.md.txt deleted file mode 100644 index 4b9dde97d7..0000000000 --- a/docs/0.9.5/_sources/EvEditor.md.txt +++ /dev/null @@ -1,181 +0,0 @@ -# EvEditor - - -Evennia offers a powerful in-game line editor in `evennia.utils.eveditor.EvEditor`. This editor, -mimicking the well-known VI line editor. It offers line-by-line editing, undo/redo, line deletes, -search/replace, fill, dedent and more. - -### Launching the editor - -The editor is created as follows: - -```python -from evennia.utils.eveditor import EvEditor - -EvEditor(caller, - loadfunc=None, savefunc=None, quitfunc=None, - key="") -``` - - - `caller` (Object or Account): The user of the editor. - - `loadfunc` (callable, optional): This is a function called when the editor is first started. It -is called with `caller` as its only argument. The return value from this function is used as the -starting text in the editor buffer. - - `savefunc` (callable, optional): This is called when the user saves their buffer in the editor is -called with two arguments, `caller` and `buffer`, where `buffer` is the current buffer. - - `quitfunc` (callable, optional): This is called when the user quits the editor. If given, all -cleanup and exit messages to the user must be handled by this function. - - `key` (str, optional): This text will be displayed as an identifier and reminder while editing. -It has no other mechanical function. - - `persistent` (default `False`): if set to `True`, the editor will survive a reboot. - -### Example of usage - -This is an example command for setting a specific Attribute using the editor. - -```python -from evennia import Command -from evennia.utils import eveditor - -class CmdSetTestAttr(Command): - """ - Set the "test" Attribute using - the line editor. - - Usage: - settestattr - - """ - key = "settestattr" - def func(self): - "Set up the callbacks and launch the editor" - def load(caller): - "get the current value" - return caller.attributes.get("test") - def save(caller, buffer): - "save the buffer" - caller.attributes.set("test", buffer) - def quit(caller): - "Since we define it, we must handle messages" - caller.msg("Editor exited") - key = "%s/test" % self.caller - # launch the editor - eveditor.EvEditor(self.caller, - loadfunc=load, savefunc=save, quitfunc=quit, - key=key) -``` - -### Persistent editor - -If you set the `persistent` keyword to `True` when creating the editor, it will remain open even -when reloading the game. In order to be persistent, an editor needs to have its callback functions -(`loadfunc`, `savefunc` and `quitfunc`) as top-level functions defined in the module. Since these -functions will be stored, Python will need to find them. - -```python -from evennia import Command -from evennia.utils import eveditor - -def load(caller): - "get the current value" - return caller.attributes.get("test") - -def save(caller, buffer): - "save the buffer" - caller.attributes.set("test", buffer) - -def quit(caller): - "Since we define it, we must handle messages" - caller.msg("Editor exited") - -class CmdSetTestAttr(Command): - """ - Set the "test" Attribute using - the line editor. - - Usage: - settestattr - - """ - key = "settestattr" - def func(self): - "Set up the callbacks and launch the editor" - key = "%s/test" % self.caller - # launch the editor - eveditor.EvEditor(self.caller, - loadfunc=load, savefunc=save, quitfunc=quit, - key=key, persistent=True) -``` - -### Line editor usage - -The editor mimics the `VIM` editor as best as possible. The below is an excerpt of the return from -the in-editor help command (`:h`). - -``` - - any non-command is appended to the end of the buffer. - : - view buffer or only line - :: - view buffer without line numbers or other parsing - ::: - print a ':' as the only character on the line... - :h - this help. - - :w - save the buffer (don't quit) - :wq - save buffer and quit - :q - quit (will be asked to save if buffer was changed) - :q! - quit without saving, no questions asked - - :u - (undo) step backwards in undo history - :uu - (redo) step forward in undo history - :UU - reset all changes back to initial state - - :dd - delete line - :dw - delete word or regex in entire buffer or on line - :DD - clear buffer - - :y - yank (copy) line to the copy buffer - :x - cut line and store it in the copy buffer - :p - put (paste) previously copied line directly after - :i - insert new text at line . Old line will move down - :r - replace line with text - :I - insert text at the beginning of line - :A - append text after the end of line - - :s - search/replace word or regex in buffer or on line - - :f - flood-fill entire buffer or line - :fi - indent entire buffer or line - :fd - de-indent entire buffer or line - - :echo - turn echoing of the input on/off (helpful for some clients) - - Legend: - - line numbers, or range lstart:lend, e.g. '3:7'. - - one word or several enclosed in quotes. - - longer string, usually not needed to be enclosed in quotes. -``` - -### The EvEditor to edit code - -The `EvEditor` is also used to edit some Python code in Evennia. The `@py` command supports an -`/edit` switch that will open the EvEditor in code mode. This mode isn't significantly different -from the standard one, except it handles automatic indentation of blocks and a few options to -control this behavior. - -- `:<` to remove a level of indentation for the future lines. -- `:+` to add a level of indentation for the future lines. -- `:=` to disable automatic indentation altogether. - -Automatic indentation is there to make code editing more simple. Python needs correct indentation, -not as an aesthetic addition, but as a requirement to determine beginning and ending of blocks. The -EvEditor will try to guess the next level of indentation. If you type a block "if", for instance, -the EvEditor will propose you an additional level of indentation at the next line. This feature -cannot be perfect, however, and sometimes, you will have to use the above options to handle -indentation. - -`:=` can be used to turn automatic indentation off completely. This can be very useful when trying -to paste several lines of code that are already correctly indented, for instance. - -To see the EvEditor in code mode, you can use the `@py/edit` command. Type in your code (on one or -several lines). You can then use the `:w` option (save without quitting) and the code you have -typed will be executed. The `:!` will do the same thing. Executing code while not closing the -editor can be useful if you want to test the code you have typed but add new lines after your test. \ No newline at end of file diff --git a/docs/0.9.5/_sources/EvMenu.md.txt b/docs/0.9.5/_sources/EvMenu.md.txt deleted file mode 100644 index 90fa5c3e9e..0000000000 --- a/docs/0.9.5/_sources/EvMenu.md.txt +++ /dev/null @@ -1,1312 +0,0 @@ -# EvMenu - - -## Introduction - -The `EvMenu` utility class is located in -[evennia/utils/evmenu.py](https://github.com/evennia/evennia/blob/master/evennia/utils/evmenu.py). -It allows for easily adding interactive menus to the game; for example to implement Character -creation, building commands or similar. Below is an example of offering NPC conversation choices: - -``` -The guard looks at you suspiciously. -"No one is supposed to be in here ..." -he says, a hand on his weapon. -_______________________________________________ - 1. Try to bribe him [Cha + 10 gold] - 2. Convince him you work here [Int] - 3. Appeal to his vanity [Cha] - 4. Try to knock him out [Luck + Dex] - 5. Try to run away [Dex] - -``` - -This is an example of a menu *node*. Think of a node as a point where the menu stops printing text -and waits for user to give some input. By jumping to different nodes depending on the input, a menu -is constructed. - -## Ways to create the menu - -### node functions - -The native way to define an EvMenu is to define Python functions, one per node. It will load all -those -functions/nodes either from a module or by being passed a dictionary mapping the node's names to -said functions, like `{"nodename": , ...}`. Since you are dealing with raw code, this is -by -far the most powerful way - for example you could have dynamic nodes that change content depending -on game context, time and what you picked before. - -### menu templating - -For a simpler menu you often don't need the full flexibility you get from defining each node as a -Python function. For that, there is the _EvMenu templating_ language. This allows you to define the -menu -in a more human-readable string with a simple format. This is then parsed to produce the -`{"nodename": , ...}` mapping for you, for the EvMenu to use normally. The templating -language is described in the [Menu templating section](./EvMenu.md#evmenu-templating-language). - - -## Launching the menu - -Initializing the menu is done using a call to the `evennia.utils.evmenu.EvMenu` class. This is the -most common way to do so - from inside a [Command](./Commands.md): - -```python -# in, for example gamedir/commands/command.py - -from evennia.utils.evmenu import EvMenu - -class CmdTestMenu(Command): - - key = "testcommand" - - def func(self): - - EvMenu(caller, "world.mymenu") - -``` - -When running this command, the menu will start using the menu nodes loaded from -`mygame/world/mymenu.py` and use this to build the menu-tree - each function name becomes -the name of a node in the tree. See next section on how to define menu nodes. - -Alternatively, you could pass the menu-tree to EvMenu directly: - -```python - - menutree = {"start": nodestartfunc, - "node1": nodefunc1, - "node2": nodefunc2,, ...} - EvMenu(caller, menutree) - -``` -This menutree can also be generated from an *EvMenu template* - -```python - from evennia.utils.evmenu import parse_menu_template - - menutree = parse_menu_template(caller, template_string, goto_callables) - EvMenu(caller, menutree) -``` - -The `template_string` and `goto_callables` are described in [Template language -section](./EvMenu.md#evmenu-templating-language). - - -## The EvMenu class - -The `EvMenu` has the following optional callsign: - -```python -EvMenu(caller, menu_data, - startnode="start", - cmdset_mergetype="Replace", cmdset_priority=1, - auto_quit=True, auto_look=True, auto_help=True, - cmd_on_exit="look", - persistent=False, - startnode_input="", - session=None, - debug=False, - **kwargs) - -``` - - - `caller` (Object or Account): is a reference to the object using the menu. This object will get a - new [CmdSet](./Command-Sets.md) assigned to it, for handling the menu. - - `menu_data` (str, module or dict): is a module or python path to a module where the global-level - functions will each be considered to be a menu node. Their names in the module will be the names - by which they are referred to in the module. Importantly, function names starting with an -underscore - `_` will be ignored by the loader. Alternatively, this can be a direct mapping -`{"nodename":function, ...}`. - - `startnode` (str): is the name of the menu-node to start the menu at. Changing this means that - you can jump into a menu tree at different positions depending on circumstance and thus possibly - re-use menu entries. - - `cmdset_mergetype` (str): This is usually one of "Replace" or "Union" (see [CmdSets](Command- -Sets). - The first means that the menu is exclusive - the user has no access to any other commands while - in the menu. The Union mergetype means the menu co-exists with previous commands (and may -overload - them, so be careful as to what to name your menu entries in this case). - - `cmdset_priority` (int): The priority with which to merge in the menu cmdset. This allows for - advanced usage. - - `auto_quit`, `auto_look`, `auto_help` (bool): If either of these are `True`, the menu - automatically makes a `quit`, `look` or `help` command available to the user. The main reason why - you'd want to turn this off is if you want to use the aliases "q", "l" or "h" for something in -your - menu. Nevertheless, at least `quit` is highly recommend - if `False`, the menu *must* itself -supply - an "exit node" (a node without any options), or the user will be stuck in the menu until the -server - reloads (or eternally if the menu is `persistent`)! - - `cmd_on_exit` (str): This command string will be executed right *after* the menu has closed down. - From experience, it's useful to trigger a "look" command to make sure the user is aware of the - change of state; but any command can be used. If set to `None`, no command will be triggered -after - exiting the menu. - - `persistent` (bool) - if `True`, the menu will survive a reload (so the user will not be kicked - out by the reload - make sure they can exit on their own!) - - `startnode_input` (str or (str, dict) tuple): Pass an input text or a input text + kwargs to the - start node as if it was entered on a fictional previous node. This can be very useful in order to - start a menu differently depending on the Command's arguments in which it was initialized. - - `session` (Session): Useful when calling the menu from an [Account](./Accounts.md) in - `MULTISESSION_MODDE` higher than 2, to make sure only the right Session sees the menu output. - - `debug` (bool): If set, the `menudebug` command will be made available in the menu. Use it to - list the current state of the menu and use `menudebug ` to inspect a specific state - variable from the list. - - All other keyword arguments will be available as initial data for the nodes. They will be - available in all nodes as properties on `caller.ndb._menutree` (see below). These will also -survive a `@reload` if the menu is `persistent`. - -You don't need to store the EvMenu instance anywhere - the very act of initializing it will store it -as `caller.ndb._menutree` on the `caller`. This object will be deleted automatically when the menu -is exited and you can also use it to store your own temporary variables for access throughout the -menu. Temporary variables you store on a persistent `_menutree` as it runs will -*not* survive a `@reload`, only those you set as part of the original `EvMenu` call. - - -## The Menu nodes - -The EvMenu nodes consist of functions on one of these forms. - -```python -def menunodename1(caller): - # code - return text, options - -def menunodename2(caller, raw_string): - # code - return text, options - -def menunodename3(caller, raw_string, **kwargs): - # code - return text, options - -``` - -> While all of the above forms are okay, it's recommended to stick to the third and last form since -it -> gives the most flexibility. The previous forms are mainly there for backwards compatibility with -> existing menus from a time when EvMenu was less able. - - -### Input arguments to the node - - - `caller` (Object or Account): The object using the menu - usually a Character but could also be a - Session or Account depending on where the menu is used. - - `raw_string` (str): If this is given, it will be set to the exact text the user entered on the - *previous* node (that is, the command entered to get to this node). On the starting-node of the - menu, this will be an empty string, unless `startnode_input` was set. - - `kwargs` (dict): These extra keyword arguments are extra optional arguments passed to the node - when the user makes a choice on the *previous* node. This may include things like status flags - and details about which exact option was chosen (which can be impossible to determine from - `raw_string` alone). Just what is passed in `kwargs` is up to you when you create the previous - node. - -### Return values from the node - -Each function must return two variables, `text` and `options`. - - -#### text - -The `text` variable is a string or tuple. This text is what will be displayed when the user reaches -this node. If this is a tuple, then the first element of the tuple will be considered the displayed -text and the second the help-text to display when the user enters the `help` command on this node. - -```python - text = ("This is the text to display", "This is the help text for this node") -``` - -Returning a `None` text is allowed and simply leads to a node with no text and only options. If the -help text is not given, the menu will give a generic error message when using `help`. - - -#### options - -The `options` list describe all the choices available to the user when viewing this node. If -`options` is -returned as `None`, it means that this node is an *Exit node* - any text is displayed and then the -menu immediately exits, running the `exit_cmd` if given. - -Otherwise, `options` should be a list (or tuple) of dictionaries, one for each option. If only one -option is -available, a single dictionary can also be returned. This is how it could look: - - -```python -def node_test(caller, raw_string, **kwargs): - - text = "A goblin attacks you!" - - options = ( - {"key": ("Attack", "a", "att"), - "desc": "Strike the enemy with all your might", - "goto": "node_attack"}, - {"key": ("Defend", "d", "def"), - "desc": "Hold back and defend yourself", - "goto": (_defend, {"str": 10, "enemyname": "Goblin"})}) - - return text, options - -``` - -This will produce a menu node looking like this: - - -``` -A goblin attacks you! -________________________________ - -Attack: Strike the enemy with all your might -Defend: Hold back and defend yourself - -``` - -##### option-key 'key' - -The option's `key` is what the user should enter in order to choose that option. If given as a -tuple, the -first string of that tuple will be what is shown on-screen while the rest are aliases for picking -that option. In the above example, the user could enter "Attack" (or "attack", it's not -case-sensitive), "a" or "att" in order to attack the goblin. Aliasing is useful for adding custom -coloring to the choice. The first element of the aliasing tuple should then be the colored version, -followed by a version without color - since otherwise the user would have to enter the color codes -to select that choice. - -Note that the `key` is *optional*. If no key is given, it will instead automatically be replaced -with a running number starting from `1`. If removing the `key` part of each option, the resulting -menu node would look like this instead: - - -``` -A goblin attacks you! -________________________________ - -1: Strike the enemy with all your might -2: Hold back and defend yourself - -``` - -Whether you want to use a key or rely on numbers is mostly -a matter of style and the type of menu. - -EvMenu accepts one important special `key` given only as `"_default"`. This key is used when a user -enters something that does not match any other fixed keys. It is particularly useful for getting -user input: - -```python -def node_readuser(caller, raw_string, **kwargs): - text = "Please enter your name" - - options = {"key": "_default", - "goto": "node_parse_input"} - - return text, options - -``` - -A `"_default"` option does not show up in the menu, so the above will just be a node saying -`"Please enter your name"`. The name they entered will appear as `raw_string` in the next node. - - -#### option-key 'desc' - -This simply contains the description as to what happens when selecting the menu option. For -`"_default"` options or if the `key` is already long or descriptive, it is not strictly needed. But -usually it's better to keep the `key` short and put more detail in `desc`. - - -#### option-key 'goto' - -This is the operational part of the option and fires only when the user chooses said option. Here -are three ways to write it - -```python - -def _action_two(caller, raw_string, **kwargs): - # do things ... - return "calculated_node_to_go_to" - -def _action_three(caller, raw_string, **kwargs): - # do things ... - return "node_four", {"mode": 4} - -def node_select(caller, raw_string, **kwargs): - - text = ("select one", - "help - they all do different things ...") - - options = ({"desc": "Option one", - "goto": "node_one"}, - {"desc": "Option two", - "goto": _action_two}, - {"desc": "Option three", - "goto": (_action_three, {"key": 1, "key2": 2})} - ) - - return text, options - -``` - -As seen above, `goto` could just be pointing to a single `nodename` string - the name of the node to -go to. When given like this, EvMenu will look for a node named like this and call its associated -function as - -```python - nodename(caller, raw_string, **kwargs) -``` - -Here, `raw_string` is always the input the user entered to make that choice and `kwargs` are the -same as those `kwargs` that already entered the *current* node (they are passed on). - -Alternatively the `goto` could point to a "goto-callable". Such callables are usually defined in the -same -module as the menu nodes and given names starting with `_` (to avoid being parsed as nodes -themselves). These callables will be called the same as a node function - `callable(caller, -raw_string, **kwargs)`, where `raw_string` is what the user entered on this node and `**kwargs` is -forwarded from the node's own input. - -The `goto` option key could also point to a tuple `(callable, kwargs)` - this allows for customizing -the kwargs passed into the goto-callable, for example you could use the same callable but change the -kwargs passed into it depending on which option was actually chosen. - -The "goto callable" must either return a string `"nodename"` or a tuple `("nodename", mykwargs)`. -This will lead to the next node being called as either `nodename(caller, raw_string, **kwargs)` or -`nodename(caller, raw_string, **mykwargs)` - so this allows changing (or replacing) the options -going -into the next node depending on what option was chosen. - -There is one important case - if the goto-callable returns `None` for a `nodename`, *the current -node will run again*, possibly with different kwargs. This makes it very easy to re-use a node over -and over, for example allowing different options to update some text form being passed and -manipulated for every iteration. - - -> The EvMenu also supports the `exec` option key. This allows for running a callable *before* the -> goto-callable. This functionality comes from a time before goto could be a callable and is -> *deprecated* as of Evennia 0.8. Use `goto` for all functionality where you'd before use `exec`. - - -## Temporary storage - -When the menu starts, the EvMenu instance is stored on the caller as `caller.ndb._menutree`. Through -this object you can in principle reach the menu's internal state if you know what you are doing. -This is also a good place to store temporary, more global variables that may be cumbersome to keep -passing from node to node via the `**kwargs`. The `_menutree` will be deleted automatically when the -menu closes, meaning you don't need to worry about cleaning anything up. - -If you want *permanent* state storage, it's instead better to use an Attribute on `caller`. Remember -that this will remain after the menu closes though, so you need to handle any needed cleanup -yourself. - - -## Customizing Menu formatting - -The `EvMenu` display of nodes, options etc are controlled by a series of formatting methods on the -`EvMenu` class. To customize these, simply create a new child class of `EvMenu` and override as -needed. Here is an example: - -```python -from evennia.utils.evmenu import EvMenu - -class MyEvMenu(EvMenu): - - def nodetext_formatter(self, nodetext): - """ - Format the node text itself. - - Args: - nodetext (str): The full node text (the text describing the node). - - Returns: - nodetext (str): The formatted node text. - - """ - - def helptext_formatter(self, helptext): - """ - Format the node's help text - - Args: - helptext (str): The unformatted help text for the node. - - Returns: - helptext (str): The formatted help text. - - """ - - def options_formatter(self, optionlist): - """ - Formats the option block. - - Args: - optionlist (list): List of (key, description) tuples for every - option related to this node. - caller (Object, Account or None, optional): The caller of the node. - - Returns: - options (str): The formatted option display. - - """ - - def node_formatter(self, nodetext, optionstext): - """ - Formats the entirety of the node. - - Args: - nodetext (str): The node text as returned by `self.nodetext_formatter`. - optionstext (str): The options display as returned by `self.options_formatter`. - caller (Object, Account or None, optional): The caller of the node. - - Returns: - node (str): The formatted node to display. - - """ - -``` -See `evennia/utils/evmenu.py` for the details of their default implementations. - - - -## Evmenu templating language - -The EvMenu is very powerful and flexible. But often your menu is simple enough to -not require the full power of EvMenu. For this you can use the Evmenu templating language. - -This is how the templating is used: - -```python -from evennia.utils.evmenu import parse_menu_template, EvMenu - -template_string = "(will be described below)" -# this could be empty if you don't need to access any callables -# in your template -goto_callables = {"mycallable1": function, ...} - -# generate the menutree -menutree = parse_menu_template(caller, template_string, goto_callables) -# a normal EvMenu call -EvMenu(caller, menutree, ...) - -``` - -... So the `parse_menu_template` is just another way to generate the `menutree` dict needed by -EvMenu - after this EvMenu works normally. - -The good thing with this two-step procedude is that you can mix- and match - if you wanted -you could insert a normal, fully flexible function-based node-function in the `menutree` before -passing -the whole thing into `EvMenu` and get the best of both worlds. It also makes it -easy to substitute base EvMenu with a child class that changes the menu display. - -... But if you really don't need any such customization, you can also apply the template in one step -using -the `template2menu` helper: - - -```python -from evennia.utils.evmenu import template2menu - -template_string = "(will be described below)" -goto_callables = {"mycallable1": function, ...} - -template2menu(caller, template_string, goto_callables, startnode="start", ...) - -``` -In addition to the template-related arguments, `template2menu` takes all the same `**kwargs` -as `EvMenu` and will parse the template and start the menu for you in one go. - -### The templating string - -The template is a normal string with a very simple format. Each node begins -with a marker `## Node `, follwowed by a `## Options` separator (the `Node` and -`Options` are -case-insensitive). - -```python -template_string = """ - -## NODE start - - - -## OPTIONS - -# this is a comment. Only line-comments are allowed. - -key;alias;alias: description -> goto_str_or_callable -key;alias;alias: goto_str_or_callable ->pattern: goto_str_or_callable - -""" -``` - -- The text after `## NODE` defines the name of the node. This must be unique within the - menu because this is what you use for `goto` statements. The name could have spaces. -- The area between `## NODE` and `## OPTIONS` contains the text of the node. It can have - normal formatting and will retain intentation. -- The `## OPTIONS` section, until the next `## NODE` or the end of the string, - holds the options, one per line. -- Option-indenting is ignored but can be useful for readability. -- The options-section can also have line-comments, marked by starting the line with `#`. -- A node without a following `## OPTIONS` section indicates an end node, and reaching - it will print the text and immediately exit the menu (same as for regular EvMenu). - -### Templating options format - -The normal, full syntax is: - - key;alias;alias: description -> goto_str_or_callable - -An example would be - - next;n: Go to node Two -> node2 - -In the menu, this will become an option - - next: Go to node Two - -where you can enter `next` or `n` to go to the menu node named `node2`. - -To skip the description, just add the goto without the `->`: - - next;n: node2 - -This will create a menu option without any description: - - next - -A special key is `>`. This acts as a _pattern matcher_. Between `>` and the `:` one -can fit an optional _pattern_. This -pattern will first be parsed with [glob-style -parsing](https://docs.python.org/2/library/fnmatch.html) and then -with [regex](https://docs.python.org/3/library/re.html#module-re), and only if -the player's input matches either will the option be chosen. An input-matching -option cannot have a description. - -``` - # this matches the empty string (just pressing return) - >: node2 - - # this matches input starting with 'test' (regex match) - > ^test.+?: testnode - - # this matches any number input (regex match) - > [0-9]+?: countnode - - # this matches everything not covered by previous options - # (glob-matching, space is stripped without quotes) - > *: node3 -``` - -You can have multiple pattern-matchers for a node but remember that options are -checked in the order they are listed. So make sure to put your pattern-matchers -in decending order of generality; if you have a 'catch-all' pattern, -it should be put last or those behind it will never be tried. - -``` - next;n: node2 - back;b: node1 - >: node2 -``` - -The above would give you the option to write next/back but you can also just press return to move on -to the next node. - -### Templating goto-callables - -Instead of giving the name of a node to go to, you can also give the name -of a _goto_callable_, which in turn returns the name of the node to go to. You -tell the template it's a callable by simply adding `()` at the end. - - next: Go to node 2 -> goto_node2() - -You can also add keyword arguments: - - back: myfunction(from=foo) - -> Note: ONLY keyword-arguments are supported! Trying to pass a positional -> argument will lead to an error. - -The contents of the kwargs-values will be evaluated by `literal_eval` so -you don't need to add quotes to strings _unless they have spaces in them_. Numbers -will be converted correctly, but more complex input structures (like lists or dicts) will -_not_ - if you want more complex input you should use a full function-based EvMenu -node instead. - -The goto-callable is defined just like any Evmenu goto-func. You must always -use the full form (including `**kwargs`): - -```python -def mygotocallable(caller, raw_string, **kwargs): - # ... - return "nodename_to_goto" - -``` - -Return `None` to re-run the current node. Any keyword arguments you specify in -your template will be passed to your goto-callable in `**kwargs`. Unlike in -regular EvMenu nodes you _can't_ return kwargs to pass it between nodes and other dynamic -tricks. - -All goto-callables you use in your menu-template must be added to the -`goto_callable` mapping that you pass to `parse_menu_template` or -`template2menu`. - -### Templating example to show all possible options: - - -```python - -template_string = """ - -## NODE start - -This is the text of the start node. -Both ## NODE, ## node or ## Node works. The node-name can have -spaces. - -The text area can have multiple lines, line breaks etc. - -## OPTIONS - - # here starts the option-defition - # comments are only allowed from beginning of line. - # Indenting is not necessary, but good for readability - - 1: Option number 1 -> node1 - 2: Option number 2 -> node2 - next: This steps next -> go_back() - # the -> can be ignored if there is no desc - back: go_back(from_node=start) - abort: abort - -# ----------------------------------- this is ignored - -## NODE node1 - -Text for Node1. Enter a message! - to go back. - -## options - - # Starting the option-line with > - # allows to perform different actions depending on - # what is inserted. - - # this catches everything starting with foo - > foo*: handle_foo_message() - - # regex are also allowed (this catches number inputs) - > [0-9]+?: handle_numbers() - - # this catches the empty return - >: start - - # this catches everything else - > *: handle_message(from_node=node1) - -# ----------------------------------------- - -## NODE node2 - -Text for Node2. Just go back. - -## options - - >: start - -# node abort - -This exits the menu since there is no `## options` section. - - -""" - -# we assume the callables are defined earlier -goto_callables = {"go_back": go_back_func, - "handle_foo_message": handle_message, - "handle_numbers": my_number_handler, - "handle_message": handle_message2} - -# boom - a menu -template2menu(caller, template_string, goto_callables) - -``` - - -## Examples: - -- **[Simple branching menu](./EvMenu.md#example-simple-branching-menu)** - choose from options -- **[Dynamic goto](./EvMenu.md#example-dynamic-goto)** - jumping to different nodes based on response -- **[Set caller properties](./EvMenu.md#example-set-caller-properties)** - a menu that changes things -- **[Getting arbitrary input](./EvMenu.md#example-get-arbitrary-input)** - entering text -- **[Storing data between nodes](./EvMenu.md#example-storing-data-between-nodes)** - keeping states and -information while in the menu -- **[Repeating the same node](./EvMenu.md#example-repeating-the-same-node)** - validating within the node -before moving to the next -- **[Yes/No prompt](./EvMenu.md#example-yesno-prompt)** - entering text with limited possible responses -(this is *not* using EvMenu but the conceptually similar yet technically unrelated `get_input` -helper function accessed as `evennia.utils.evmenu.get_input`). - - -### Example: Simple branching menu - -Below is an example of a simple branching menu node leading to different other nodes depending on -choice: - -```python -# in mygame/world/mychargen.py - -def define_character(caller): - text = \ - """ - What aspect of your character do you want - to change next? - """ - options = ({"desc": "Change the name", - "goto": "set_name"}, - {"desc": "Change the description", - "goto": "set_description"}) - return text, options - -EvMenu(caller, "world.mychargen", startnode="define_character") - -``` - -This will result in the following node display: - -``` -What aspect of your character do you want -to change next? -_________________________ -1: Change the name -2: Change the description -``` - -Note that since we didn't specify the "name" key, EvMenu will let the user enter numbers instead. In -the following examples we will not include the `EvMenu` call but just show nodes running inside the -menu. Also, since `EvMenu` also takes a dictionary to describe the menu, we could have called it -like this instead in the example: - -```python -EvMenu(caller, {"define_character": define_character}, startnode="define_character") - -``` - -### Example: Dynamic goto - -```python - -def _is_in_mage_guild(caller, raw_string, **kwargs): - if caller.tags.get('mage', category="guild_member"): - return "mage_guild_welcome" - else: - return "mage_guild_blocked" - -def enter_guild: - text = 'You say to the mage guard:' - options ({'desc': 'I need to get in there.', - 'goto': _is_in_mage_guild}, - {'desc': 'Never mind', - 'goto': 'end_conversation'}) - return text, options -``` - -This simple callable goto will analyse what happens depending on who the `caller` is. The -`enter_guild` node will give you a choice of what to say to the guard. If you try to enter, you will -end up in different nodes depending on (in this example) if you have the right [Tag](./Tags.md) set on -yourself or not. Note that since we don't include any 'key's in the option dictionary, you will just -get to pick between numbers. - -### Example: Set caller properties - -Here is an example of passing arguments into the `goto` callable and use that to influence -which node it should go to next: - -```python - -def _set_attribute(caller, raw_string, **kwargs): - "Get which attribute to modify and set it" - - attrname, value = kwargs.get("attr", (None, None)) - next_node = kwargs.get("next_node") - - caller.attributes.add(attrname, attrvalue) - - return next_node - - -def node_background(caller): - text = \ - """ - {} experienced a traumatic event - in their childhood. What was it? - """.format(caller.key} - - options = ({"key": "death", - "desc": "A violent death in the family", - "goto": (_set_attribute, {"attr": ("experienced_violence", True), - "next_node": "node_violent_background"})}, - {"key": "betrayal", - "desc": "The betrayal of a trusted grown-up", - "goto": (_set_attribute, {"attr": ("experienced_betrayal", True), - "next_node": "node_betrayal_background"})}) - return text, options -``` - -This will give the following output: - -``` -Kovash the magnificent experienced a traumatic event -in their childhood. What was it? -____________________________________________________ -death: A violent death in the family -betrayal: The betrayal of a trusted grown-up - -``` - -Note above how we use the `_set_attribute` helper function to set the attribute depending on the -User's choice. In thie case the helper function doesn't know anything about what node called it - we -even tell it which nodename it should return, so the choices leads to different paths in the menu. -We could also imagine the helper function analyzing what other choices - - -### Example: Get arbitrary input - -An example of the menu asking the user for input - any input. - -```python - -def _set_name(caller, raw_string, **kwargs): - - inp = raw_string.strip() - - prev_entry = kwargs.get("prev_entry") - - if not inp: - # a blank input either means OK or Abort - if prev_entry: - caller.key = prev_entry - caller.msg("Set name to {}.".format(prev_entry)) - return "node_background" - else: - caller.msg("Aborted.") - return "node_exit" - else: - # re-run old node, but pass in the name given - return None, {"prev_entry": inp} - - -def enter_name(caller, raw_string, **kwargs): - - # check if we already entered a name before - prev_entry = kwargs.get("prev_entry") - - if prev_entry: - text = "Current name: {}.\nEnter another name or to accept." - else: - text = "Enter your character's name or to abort." - - options = {"key": "_default", - "goto": (_set_name, {"prev_entry": prev_entry})} - - return text, options - -``` - -This will display as - -``` -Enter your character's name or to abort. - -> Gandalf - -Current name: Gandalf -Enter another name or to accept. - -> - -Set name to Gandalf. - -``` - -Here we re-use the same node twice for reading the input data from the user. Whatever we enter will -be caught by the `_default` option and passed into the helper function. We also pass along whatever -name we have entered before. This allows us to react correctly on an "empty" input - continue to the -node named `"node_background"` if we accept the input or go to an exit node if we presses Return -without entering anything. By returning `None` from the helper function we automatically re-run the -previous node, but updating its ingoing kwargs to tell it to display a different text. - - - -### Example: Storing data between nodes - -A convenient way to store data is to store it on the `caller.ndb._menutree` which you can reach from -every node. The advantage of doing this is that the `_menutree` NAttribute will be deleted -automatically when you exit the menu. - -```python - -def _set_name(caller, raw_string, **kwargs): - - caller.ndb._menutree.charactersheet = {} - caller.ndb._menutree.charactersheet['name'] = raw_string - caller.msg("You set your name to {}".format(raw_string) - return "background" - -def node_set_name(caller): - text = 'Enter your name:' - options = {'key': '_default', - 'goto': _set_name} - - return text, options - -... - - -def node_view_sheet(caller): - text = "Character sheet:\n {}".format(self.ndb._menutree.charactersheet) - - options = ({"key": "Accept", - "goto": "finish_chargen"}, - {"key": "Decline", - "goto": "start_over"}) - - return text, options - -``` - -Instead of passing the character sheet along from node to node through the `kwargs` we instead -set it up temporarily on `caller.ndb._menutree.charactersheet`. This makes it easy to reach from -all nodes. At the end we look at it and, if we accept the character the menu will likely save the -result to permanent storage and exit. - -> One point to remember though is that storage on `caller.ndb._menutree` is not persistent across -> `@reloads`. If you are using a persistent menu (using `EvMenu(..., persistent=True)` you should -use -> `caller.db` to store in-menu data like this as well. You must then yourself make sure to clean it -> when the user exits the menu. - - -### Example: Repeating the same node - -Sometimes you want to make a chain of menu nodes one after another, but you don't want the user to -be able to continue to the next node until you have verified that what they input in the previous -node is ok. A common example is a login menu: - - -```python - -def _check_username(caller, raw_string, **kwargs): - # we assume lookup_username() exists - if not lookup_username(raw_string): - # re-run current node by returning `None` - caller.msg("|rUsername not found. Try again.") - return None - else: - # username ok - continue to next node - return "node_password" - - -def node_username(caller): - text = "Please enter your user name." - options = {"key": "_default", - "goto": _check_username} - return text, options - - -def _check_password(caller, raw_string, **kwargs): - - nattempts = kwargs.get("nattempts", 0) - if nattempts > 3: - caller.msg("Too many failed attempts. Logging out") - return "node_abort" - elif not validate_password(raw_string): - caller.msg("Password error. Try again.") - return None, {"nattempts", nattempts + 1} - else: - # password accepted - return "node_login" - -def node_password(caller, raw_string, **kwargs): - text = "Enter your password." - options = {"key": "_default", - "goto": _check_password} - return text, options - -``` - -This will display something like - - -``` ---------------------------- -Please enter your username. ---------------------------- - -> Fo - ------------------------------- -Username not found. Try again. -______________________________ -abort: (back to start) ------------------------------- - -> Foo - ---------------------------- -Please enter your password. ---------------------------- - -> Bar - --------------------------- -Password error. Try again. --------------------------- -``` - -And so on. - -Here the goto-callables will return to the previous node if there is an error. In the case of -password attempts, this will tick up the `nattempts` argument that will get passed on from iteration -to iteration until too many attempts have been made. - - -### Defining nodes in a dictionary - -You can also define your nodes directly in a dictionary to feed into the `EvMenu` creator. - -```python -def mynode(caller): - # a normal menu node function - return text, options - -menu_data = {"node1": mynode, - "node2": lambda caller: ( - "This is the node text", - ({"key": "lambda node 1", - "desc": "go to node 1 (mynode)", - "goto": "node1"}, - {"key": "lambda node 2", - "desc": "go to thirdnode", - "goto": "node3"})), - "node3": lambda caller, raw_string: ( - # ... etc ) } - -# start menu, assuming 'caller' is available from earlier -EvMenu(caller, menu_data, startnode="node1") - -``` - -The keys of the dictionary become the node identifiers. You can use any callable on the right form -to describe each node. If you use Python `lambda` expressions you can make nodes really on the fly. -If you do, the lambda expression must accept one or two arguments and always return a tuple with two -elements (the text of the node and its options), same as any menu node function. - -Creating menus like this is one way to present a menu that changes with the circumstances - you -could for example remove or add nodes before launching the menu depending on some criteria. The -drawback is that a `lambda` expression [is much more -limited](https://docs.python.org/2/tutorial/controlflow.html#lambda-expressions) than a full -function - for example you can't use other Python keywords like `if` inside the body of the -`lambda`. - -Unless you are dealing with a relatively simple dynamic menu, defining menus with lambda's is -probably more work than it's worth: You can create dynamic menus by instead making each node -function more clever. See the [NPC shop tutorial](./NPC-shop-Tutorial.md) for an example of this. - - -## Ask for simple input - -This describes two ways for asking for simple questions from the user. Using Python's `input` -will *not* work in Evennia. `input` will *block* the entire server for *everyone* until that one -player has entered their text, which is not what you want. - -### The `yield` way - -In the `func` method of your Commands (only) you can use Python's built-in `yield` command to -request input in a similar way to `input`. It looks like this: - -```python -result = yield("Please enter your answer:") -``` - -This will send "Please enter your answer" to the Command's `self.caller` and then pause at that -point. All other players at the server will be unaffected. Once caller enteres a reply, the code -execution will continue and you can do stuff with the `result`. Here is an example: - -```python -from evennia import Command -class CmdTestInput(Command): - key = "test" - def func(self): - result = yield("Please enter something:") - self.caller.msg(f"You entered {result}.") - result2 = yield("Now enter something else:") - self.caller.msg(f"You now entered {result2}.") -``` - -Using `yield` is simple and intuitive, but it will only access input from `self.caller` and you -cannot abort or time out the pause until the player has responded. Under the hood, it is actually -just a wrapper calling `get_input` described in the following section. - -> Important Note: In Python you *cannot mix `yield` and `return ` in the same method*. It has -> to do with `yield` turning the method into a -> [generator](https://www.learnpython.org/en/Generators). A `return` without an argument works, you -> can just not do `return `. This is usually not something you need to do in `func()` anyway, -> but worth keeping in mind. - -### The `get_input` way - -The evmenu module offers a helper function named `get_input`. This is wrapped by the `yield` -statement which is often easier and more intuitive to use. But `get_input` offers more flexibility -and power if you need it. While in the same module as `EvMenu`, `get_input` is technically unrelated -to it. The `get_input` allows you to ask and receive simple one-line input from the user without -launching the full power of a menu to do so. To use, call `get_input` like this: - -```python -get_input(caller, prompt, callback) -``` - -Here `caller` is the entity that should receive the prompt for input given as `prompt`. The -`callback` is a callable `function(caller, prompt, user_input)` that you define to handle the answer -from the user. When run, the caller will see `prompt` appear on their screens and *any* text they -enter will be sent into the callback for whatever processing you want. - -Below is a fully explained callback and example call: - -```python -from evennia import Command -from evennia.utils.evmenu import get_input - -def callback(caller, prompt, user_input): - """ - This is a callback you define yourself. - - Args: - caller (Account or Object): The one being asked - for input - prompt (str): A copy of the current prompt - user_input (str): The input from the account. - - Returns: - repeat (bool): If not set or False, exit the - input prompt and clean up. If returning anything - True, stay in the prompt, which means this callback - will be called again with the next user input. - """ - caller.msg(f"When asked '{prompt}', you answered '{user_input}'.") - -get_input(caller, "Write something! ", callback) -``` - -This will show as - -``` -Write something! -> Hello -When asked 'Write something!', you answered 'Hello'. - -``` - -Normally, the `get_input` function quits after any input, but as seen in the example docs, you could -return True from the callback to repeat the prompt until you pass whatever check you want. - -> Note: You *cannot* link consecutive questions by putting a new `get_input` call inside the -> callback. If you want that you should use an EvMenu instead (see the [Repeating the same -> node](./EvMenu.md#example-repeating-the-same-node) example above). Otherwise you can either peek at the -> implementation of `get_input` and implement your own mechanism (it's just using cmdset nesting) or -> you can look at [this extension suggested on the mailing -> list](https://groups.google.com/forum/#!category-topic/evennia/evennia-questions/16pi0SfMO5U). - - -#### Example: Yes/No prompt - -Below is an example of a Yes/No prompt using the `get_input` function: - -```python -def yesno(caller, prompt, result): - if result.lower() in ("y", "yes", "n", "no"): - # do stuff to handle the yes/no answer - # ... - # if we return None/False the prompt state - # will quit after this - else: - # the answer is not on the right yes/no form - caller.msg("Please answer Yes or No. \n{prompt}") -@ # returning True will make sure the prompt state is not exited - return True - -# ask the question -get_input(caller, "Is Evennia great (Yes/No)?", yesno) -``` - -## The `@list_node` decorator - -The `evennia.utils.evmenu.list_node` is an advanced decorator for use with `EvMenu` node functions. -It is used to quickly create menus for manipulating large numbers of items. - - -``` -text here -______________________________________________ - -1. option1 7. option7 13. option13 -2. option2 8. option8 14. option14 -3. option3 9. option9 [p]revius page -4. option4 10. option10 page 2 -5. option5 11. option11 [n]ext page -6. option6 12. option12 - -``` - -The menu will automatically create an multi-page option listing that one can flip through. One can -inpect each entry and then select them with prev/next. This is how it is used: - - -```python -from evennia.utils.evmenu import list_node - - -... - -_options(caller): - return ['option1', 'option2', ... 'option100'] - -_select(caller, menuchoice, available_choices): - # analyze choice - return node_matching_the_choice - -@list_node(_options, select=_select, pagesize=10) -def node_mylist(caller, raw_string, **kwargs): - ... - - # the decorator auto-creates the options; any options - # returned here would be appended to the auto-options - return node_text, {} -``` - -The `options` argument to `list_node` is either a list, a generator or a callable returning a list -of strings for each option that should be displayed in the node. - -The `select` is a callable in the example above but could also be the name of a menu node. If a -callable, the `menuchoice` argument holds the selection done and `available_choices` holds all the -options available. The callable should return the menu to go to depending on the selection (or -`None` to rerun the same node). If the name of a menu node, the selection will be passed as -`selection` kwarg to that node. - -The decorated node itself should return `text` to display in the node. It must return at least an -empty dictionary for its options. It returning options, those will supplement the options -auto-created by the `list_node` decorator. - - -## Assorted notes - -The EvMenu is implemented using [Commands](./Commands.md). When you start a new EvMenu, the user of the -menu will be assigned a [CmdSet](./Command-Sets.md) with the commands they need to navigate the menu. -This means that if you were to, from inside the menu, assign a new command set to the caller, *you -may override the Menu Cmdset and kill the menu*. If you want to assign cmdsets to the caller as part -of the menu, you should store the cmdset on `caller.ndb._menutree` and wait to actually assign it -until the exit node. diff --git a/docs/0.9.5/_sources/EvMore.md.txt b/docs/0.9.5/_sources/EvMore.md.txt deleted file mode 100644 index 452c4fb2b7..0000000000 --- a/docs/0.9.5/_sources/EvMore.md.txt +++ /dev/null @@ -1,38 +0,0 @@ -# EvMore - - -When sending a very long text to a user client, it might scroll beyond of the height of the client -window. The `evennia.utils.evmore.EvMore` class gives the user the in-game ability to only view one -page of text at a time. It is usually used via its access function, `evmore.msg`. - -The name comes from the famous unix pager utility *more* which performs just this function. - -### Using EvMore - -To use the pager, just pass the long text through it: - -```python -from evennia.utils import evmore - -evmore.msg(receiver, long_text) -``` -Where receiver is an [Object](./Objects.md) or a [Account](./Accounts.md). If the text is longer than the -client's screen height (as determined by the NAWS handshake or by `settings.CLIENT_DEFAULT_HEIGHT`) -the pager will show up, something like this: - ->[...] -aute irure dolor in reprehenderit in voluptate velit -esse cillum dolore eu fugiat nulla pariatur. Excepteur -sint occaecat cupidatat non proident, sunt in culpa qui -officia deserunt mollit anim id est laborum. - ->(**more** [1/6] retur**n**|**b**ack|**t**op|**e**nd|**a**bort) - - -where the user will be able to hit the return key to move to the next page, or use the suggested -commands to jump to previous pages, to the top or bottom of the document as well as abort the -paging. - -The pager takes several more keyword arguments for controlling the message output. See the -[evmore-API](github:evennia.utils.evmore) for more info. - diff --git a/docs/0.9.5/_sources/Evennia-API.md.txt b/docs/0.9.5/_sources/Evennia-API.md.txt deleted file mode 100644 index cb5bcac883..0000000000 --- a/docs/0.9.5/_sources/Evennia-API.md.txt +++ /dev/null @@ -1,97 +0,0 @@ -# API Summary - -[evennia](evennia) - library root -- [evennia.accounts](evennia.accounts) - the out-of-character entities representing players -- [evennia.commands](evennia.commands) - handle all inputs. Also includes default commands -- [evennia.comms](evennia.comms) - in-game channels and messaging -- [evennia.contrib](evennia.contrib) - game-specific tools and code contributed by the community -- [evennia.help](evennia.help) - in-game help system -- [evennia.locks](evennia.locks) - limiting access to various systems and resources -- [evennia.objects](evennia.objects) - all in-game entities, like Rooms, Characters, Exits etc -- [evennia.prototypes](evennia.prototypes) - customize entities using dicts -- [evennia.scripts](evennia.scripts) - all out-of-character game objects -- [evennia.server](evennia.server) - core Server and Portal programs, also network protocols -- [evennia.typeclasses](evennia.typeclasses) - core database-python bridge -- [evennia.utils](evennia.utils) - lots of useful coding tools and utilities -- [evennia.web](evennia.web) - webclient, website and other web resources - - -## Shortcuts - -Evennia's 'flat API' has shortcuts to common tools, available by only importing `evennia`. -The flat API is defined in `__init__.py` [viewable here](github:evennia/__init__.py) - - -### Main config - -- [evennia.settings_default](github:evennia/settings_default.py) - all settings (modify/override in `mygame/server/settings.py`) - -### Search functions - -- [evennia.search_account](evennia.utils.search.search_account) -- [evennia.search_object](evennia.utils.search.search_object) -- [evennia.search_object_by_tag](evennia.utils.search.search_tag) -- [evennia.search_script](evennia.utils.search.search_script) -- [evennia.search_channel](evennia.utils.search.search_channel) -- [evennia.search_message](evennia.utils.search.search_message) -- [evennia.search_help](evennia.utils.search.search_help_entry) - -### Create functions - -- [evennia.create_account](evennia.utils.create.create_account) -- [evennia.create_object](evennia.utils.create.create_object) -- [evennia.create_script](evennia.utils.create.create_script) -- [evennia.create_channel](evennia.utils.create.create_channel) -- [evennia.create_help_entry](evennia.utils.create.create_help_entry) -- [evennia.create_message](evennia.utils.create.create_message) - -### Typeclasses - -- [evennia.Defaultaccount](evennia.accounts.accounts.DefaultAccount) - player account class ([docs](./Accounts.md)) -- [evennia.DefaultGuest](evennia.accounts.accounts.DefaultGuest) - base guest account class -- [evennia.DefaultObject](evennia.objects.objects.DefaultObject) - base class for all objects ([docs](./Objects.md)) -- [evennia.DefaultCharacter](evennia.objects.objects.DefaultCharacter) - base class for in-game characters ([docs](./Objects.md#characters)) -- [evennia.DefaultRoom](evennia.objects.objects.DefaultRoom) - base class for rooms ([docs](./Objects.md#rooms)) -- [evennia.DefaultExit](evennia.objects.objects.DefaultExit) - base class for exits ([docs](./Objects.md#exits)) -- [evennia.DefaultScript](evennia.scripts.scripts.DefaultScript) - base class for OOC-objects ([docs](./Scripts.md)) -- [evennia.DefaultChannel](evennia.comms.comms.DefaultChannel) - base class for in-game channels ([docs](./Communications.md)) - -### Commands - -- [evennia.Command](evennia.commands.command.Command) - base [Command](./Commands.md) class. See also `evennia.default_cmds.MuxCommand` -- [evennia.CmdSet](evennia.commands.cmdset.CmdSet) - base [Cmdset](./Command-Sets.md) class -- evennia.default_cmds - access to all [default command classes](evennia.commands.default) as properties -- evennia.syscmdkeys - access to all [system command](./Commands.md#system-commands) names as properties - -### Utilities - -- [evennia.utils.utils](evennia.utils.utils) - mixed useful utilities -- [evennia.gametime](evennia.utils.gametime) - server run- and game time ([docs](./Coding-Utils.md#game-time)) -- [evennia.logger](evennia.utils.logger) - logging tools -- [evennia.ansi](evennia.utils.ansi) - ansi coloring tools -- [evennia.spawn](evennia.prototypes.spawner.spawn) - spawn/prototype system ([docs](./Spawner-and-Prototypes.md)) -- [evennia.lockfuncs](evennia.locks.lockfuncs) - default lock functions for access control ([docs](./Locks.md)) -- [evennia.EvMenu](evennia.utils.evmenu.EvMenu) - menu system ([docs](./EvMenu.md)) -- [evennia.EvTable](evennia.utils.evtable.EvTable) - text table creater -- [evennia.EvForm](evennia.utils.evform.EvForm) - text form creator -- [evennia.EvEditor](evennia.utils.eveditor.EvEditor) - in game text line editor ([docs](./EvEditor.md)) - -### Global singleton handlers - -- [evennia.TICKER_HANDLER](evennia.scripts.tickerhandler) - allow objects subscribe to tickers ([docs](./TickerHandler.md)) -- [evennia.MONITOR_HANDLER](evennia.scripts.monitorhandler) - monitor changes ([docs](./MonitorHandler.md)) -- [evennia.CHANNEL_HANDLER](evennia.comms.channelhandler) - maintains channels -- [evennia.SESSION_HANDLER](evennia.server.sessionhandler) - manages all sessions - -### Database core models (for more advanced lookups) - -- [evennia.ObjectDB](evennia.objects.models.ObjectDB) -- [evennia.accountDB](evennia.accounts.models.AccountDB) -- [evennia.ScriptDB](evennia.scripts.models.ScriptDB) -- [evennia.ChannelDB](evennia.comms.models.ChannelDB) -- [evennia.Msg](evennia.comms.models.Msg) -- evennia.managers - contains shortcuts to all database managers - -### Contributions - -- [evennia.contrib](evennia.contrib) - game-specific contributions and plugins ([README](github:evennia/contrib/README.md)) diff --git a/docs/0.9.5/_sources/Evennia-Game-Index.md.txt b/docs/0.9.5/_sources/Evennia-Game-Index.md.txt deleted file mode 100644 index 9f47bbc322..0000000000 --- a/docs/0.9.5/_sources/Evennia-Game-Index.md.txt +++ /dev/null @@ -1,71 +0,0 @@ -# Evennia Game Index - - -The [Evennia game index](http://games.evennia.com) is a list of games built or -being built with Evennia. Anyone is allowed to add their game to the index -- also if you have just started development and don't yet accept external -players. It's a chance for us to know you are out there and for you to make us -intrigued about or excited for your upcoming game! - -All we ask is that you check so your game-name does not collide with one -already in the list - be nice! - -## Connect with the wizard - -From your game dir, run - - evennia connections - -This will start the Evennia _Connection wizard_. From the menu, select to add -your game to the Evennia Game Index. Follow the prompts and don't forget to -save your new settings in the end. Use `quit` at any time if you change your -mind. - -> The wizard will create a new file `mygame/server/conf/connection_settings.py` -> with the settings you chose. This is imported from the end of your main -> settings file and will thus override it. You can edit this new file if you -> want, but remember that if you run the wizard again, your changes may get -> over-written. - -## Manual Settings - -If you don't want to use the wizard (maybe because you already have the client installed from an -earlier version), you can also configure your index entry in your settings file -(`mygame/server/conf/settings.py`). Add the following: - -```python -GAME_INDEX_ENABLED = True - -GAME_INDEX_LISTING = { - # required - 'game_status': 'pre-alpha', # pre-alpha, alpha, beta, launched - 'listing_contact': "dummy@dummy.com", # not publicly shown. - 'short_description': 'Short blurb', - - # optional - 'long_description': - "Longer description that can use Markdown like *bold*, _italic_" - "and [linkname](http://link.com). Use \n for line breaks." - 'telnet_hostname': 'dummy.com', - 'telnet_port': '1234', - 'web_client_url': 'dummy.com/webclient', - 'game_website': 'dummy.com', - # 'game_name': 'MyGame', # set only if different than settings.SERVERNAME -} -``` - -Of these, the `game_status`, `short_description` and `listing_contact` are -required. The `listing_contact` is not publicly visible and is only meant as a -last resort if we need to get in touch with you over any listing issue/bug (so -far this has never happened). - -If `game_name` is not set, the `settings.SERVERNAME` will be used. Use empty strings -(`''`) for optional fields you don't want to specify at this time. - -## Non-public games - -If you don't specify neither `telnet_hostname + port` nor -`web_client_url`, the Game index will list your game as _Not yet public_. -Non-public games are moved to the bottom of the index since there is no way -for people to try them out. But it's a good way to show you are out there, even -if you are not ready for players yet. diff --git a/docs/0.9.5/_sources/Evennia-Introduction.md.txt b/docs/0.9.5/_sources/Evennia-Introduction.md.txt deleted file mode 100644 index 96fd2a8f2d..0000000000 --- a/docs/0.9.5/_sources/Evennia-Introduction.md.txt +++ /dev/null @@ -1,178 +0,0 @@ -# Evennia Introduction - -> *A MUD (originally Multi-User Dungeon, with later variants Multi-User Dimension and Multi-User -Domain) is a multiplayer real-time virtual world described primarily in text. MUDs combine elements -of role-playing games, hack and slash, player versus player, interactive fiction and online chat. -Players can read or view descriptions of rooms, objects, other players, non-player characters, and -actions performed in the virtual world. Players typically interact with each other and the world by -typing commands that resemble a natural language.* - [Wikipedia](http://en.wikipedia.org/wiki/MUD) - -If you are reading this, it's quite likely you are dreaming of creating and running a text-based -massively-multiplayer game ([MUD/MUX/MUSH](http://tinyurl.com/c5sc4bm) etc) of your very own. You -might just be starting to think about it, or you might have lugged around that *perfect* game in -your mind for years ... you know *just* how good it would be, if you could only make it come to -reality. We know how you feel. That is, after all, why Evennia came to be. - -Evennia is in principle a MUD-building system: a bare-bones Python codebase and server intended to -be highly extendable for any style of game. "Bare-bones" in this context means that we try to impose -as few game-specific things on you as possible. So whereas we for convenience offer basic building -blocks like objects, characters, rooms, default commands for building and administration etc, we -don't prescribe any combat rules, mob AI, races, skills, character classes or other things that will -be different from game to game anyway. It is possible that we will offer some such systems as -contributions in the future, but these will in that case all be optional. - -What we *do* however, is to provide a solid foundation for all the boring database, networking, and -behind-the-scenes administration stuff that all online games need whether they like it or not. -Evennia is *fully persistent*, that means things you drop on the ground somewhere will still be -there a dozen server reboots later. Through Django we support a large variety of different database -systems (a database is created for you automatically if you use the defaults). - -Using the full power of Python throughout the server offers some distinct advantages. All your -coding, from object definitions and custom commands to AI scripts and economic systems is done in -normal Python modules rather than some ad-hoc scripting language. The fact that you script the game -in the same high-level language that you code it in allows for very powerful and custom game -implementations indeed. - -The server ships with a default set of player commands that are similar to the MUX command set. We -*do not* aim specifically to be a MUX server, but we had to pick some default to go with (see -[this](./Soft-Code.md) for more about our original motivations). It's easy to remove or add commands, or -to have the command syntax mimic other systems, like Diku, LP, MOO and so on. Or why not create a -new and better command system of your own design. - -## Can I test it somewhere? - -Evennia's demo server can be found at [demo.evennia.com](http://demo.evennia.com). If you prefer to -connect to the demo via your own telnet client you can do so at `silvren.com`, port `4280`. Here is -a [screenshot](./Screenshot.md). - -Once you installed Evennia yourself it comes with its own tutorial - this shows off some of the -possibilities _and_ gives you a small single-player quest to play. The tutorial takes only one -single in-game command to install as explained [here](./Tutorial-World-Introduction.md). - -## Brief summary of features - -### Technical - -- Game development is done by the server importing your normal Python modules. Specific server -features are implemented by overloading hooks that the engine calls appropriately. -- All game entities are simply Python classes that handle database negotiations behind the scenes -without you needing to worry. -- Command sets are stored on individual objects (including characters) to offer unique functionality -and object-specific commands. Sets can be updated and modified on the fly to expand/limit player -input options during play. -- Scripts are used to offer asynchronous/timed execution abilities. Scripts can also be persistent. -There are easy mechanisms to thread particularly long-running processes and built-in ways to start -"tickers" for games that wants them. -- In-game communication channels are modular and can be modified to any functionality, including -mailing systems and full logging of all messages. -- Server can be fully rebooted/reloaded without users disconnecting. -- An Account can freely connect/disconnect from game-objects, offering an easy way to implement -multi-character systems and puppeting. -- Each Account can optionally control multiple Characters/Objects at the same time using the same -login information. -- Spawning of individual objects via a prototypes-like system. -- Tagging can be used to implement zones and object groupings. -- All source code is extensively documented. -- Unit-testing suite, including tests of default commands and plugins. - -### Default content - -- Basic classes for Objects, Characters, Rooms and Exits -- Basic login system, using the Account's login name as their in-game Character's name for -simplicity -- "MUX-like" command set with administration, building, puppeting, channels and social commands -- In-game Tutorial -- Contributions folder with working, but optional, code such as alternative login, menus, character -generation and more - -### Standards/Protocols supported - -- TCP/websocket HTML5 browser web client, with ajax/comet fallback for older browsers -- Telnet and Telnet + SSL with mud-specific extensions ([MCCP](http://tintin.sourceforge.net/mccp/), -[MSSP](http://tintin.sourceforge.net/mssp/), [TTYPE](http://tintin.sourceforge.net/mtts/), -[MSDP](http://tintin.sourceforge.net/msdp/), -[GMCP](https://www.ironrealms.com/rapture/manual/files/FeatGMCP-txt.html), -[MXP](https://www.zuggsoft.com/zmud/mxp.htm) links) -- ANSI and xterm256 colours -- SSH -- HTTP - Website served by in-built webserver and connected to same database as game. -- IRC - external IRC channels can be connected to in-game chat channels -- RSS feeds can be echoed to in-game channels (things like Twitter can easily be added) -- Several different databases supported (SQLite3, MySQL, PostgreSQL, ...) - -For more extensive feature information, see the [Developer Central](./Developer-Central.md). - -## What you need to know to work with Evennia - -Assuming you have Evennia working (see the [quick start instructions](./Getting-Started.md)) and have -gotten as far as to start the server and connect to it with the client of your choice, here's what -you need to know depending on your skills and needs. - -### I don't know (or don't want to do) any programming - I just want to run a game! - -Evennia comes with a default set of commands for the Python newbies and for those who need to get a -game running *now*. Stock Evennia is enough for running a simple 'Talker'-type game - you can build -and describe rooms and basic objects, have chat channels, do emotes and other things suitable for a -social or free-form MU\*. Combat, mobs and other game elements are not included, so you'll have a -very basic game indeed if you are not willing to do at least *some* coding. - -### I know basic Python, or I am willing to learn - -Evennia's source code is extensively documented and is [viewable online](https://github.com/evennia/evennia). -We also have a comprehensive [online manual](https://www/evennia/com/docs) with lots of examples. -But while Python is -considered a very easy programming language to get into, you do have a learning curve to climb if -you are new to programming. You should probably sit down -with a Python beginner's [tutorial](http://docs.python.org/tutorial/) (there are plenty of them on -the web if you look around) so you at least know what you are seeing. See also our -[link page](./Links.md) for some reading suggestions. To efficiently code your dream game in -Evennia you don't need to be a Python guru, but you do need to be able to read example code -containing at least these basic Python features: - -- Importing and using python [modules](http://docs.python.org/3.7/tutorial/modules.html) -- Using [variables](http://www.tutorialspoint.com/python/python_variable_types.htm), -[conditional statements](http://docs.python.org/tutorial/controlflow.html#if-statements), -[loops](http://docs.python.org/tutorial/controlflow.html#for-statements) and -[functions](http://docs.python.org/tutorial/controlflow.html#defining-functions) -- Using [lists, dictionaries and list comprehensions](http://docs.python.org/tutorial/datastructures.html) -- Doing [string handling and formatting](http://docs.python.org/tutorial/introduction.html#strings) -- Have a basic understanding of [object-oriented programming](http://www.tutorialspoint.com/python/python_classes_objects.htm), using -[Classes](http://docs.python.org/tutorial/classes.html), their methods and properties - -Obviously, the more things you feel comfortable with, the easier time you'll have to find your way. -With just basic knowledge you should be able to define your own [Commands](./Commands.md), create custom -[Objects](./Objects.md) as well as make your world come alive with basic [Scripts](./Scripts.md). You can -definitely build a whole advanced and customized game from extending Evennia's examples only. - -### I know my Python stuff and I am willing to use it! - -Even if you started out as a Python beginner, you will likely get to this point after working on -your game for a while. With more general knowledge in Python the full power of Evennia opens up for -you. Apart from modifying commands, objects and scripts, you can develop everything from advanced -mob AI and economic systems, through sophisticated combat and social mini games, to redefining how -commands, players, rooms or channels themselves work. Since you code your game by importing normal -Python modules, there are few limits to what you can accomplish. - -If you *also* happen to know some web programming (HTML, CSS, Javascript) there is also a web -presence (a website and a mud web client) to play around with ... - -### Where to from here? - -From here you can continue browsing the [online documentation](./index.md) to -find more info about Evennia. Or you can jump into the [Tutorials](./Tutorials.md) and get your hands -dirty with code right away. You can also read the developer's [dev blog](https://evennia.blogspot.com/) for many tidbits and snippets about Evennia's development and -structure. - -Some more hints: - -1. Get engaged in the community. Make an introductory post to our [mailing list/forum](https://groups.google.com/forum/#!forum/evennia) and get to know people. It's also -highly recommended you hop onto our [Developer chat](http://webchat.freenode.net/?channels=evennia&uio=MT1mYWxzZSY5PXRydWUmMTE9MTk1JjEyPXRydWUbb) -on IRC. This allows you to chat directly with other developers new and old as well as with the devs -of Evennia itself. This chat is logged (you can find links on http://www.evennia.com) and can also -be searched from the same place for discussion topics you are interested in. -2. Read the [Game Planning](./Game-Planning.md) wiki page. It gives some ideas for your work flow and the -state of mind you should aim for - including cutting down the scope of your game for its first -release. -3. Do the [Tutorial for basic MUSH-like game](./Tutorial-for-basic-MUSH-like-game.md) carefully from -beginning to end and try to understand what does what. Even if you are not interested in a MUSH for -your own game, you will end up with a small (very small) game that you can build or learn from. diff --git a/docs/0.9.5/_sources/Evennia-for-Diku-Users.md.txt b/docs/0.9.5/_sources/Evennia-for-Diku-Users.md.txt deleted file mode 100644 index 5ce7b14352..0000000000 --- a/docs/0.9.5/_sources/Evennia-for-Diku-Users.md.txt +++ /dev/null @@ -1,200 +0,0 @@ -# Evennia for Diku Users - - -Evennia represents a learning curve for those who used to code on -[Diku](https://en.wikipedia.org/wiki/DikuMUD) type MUDs. While coding in Python is easy if you -already know C, the main effort is to get rid of old C programming habits. Trying to code Python the -way you code C will not only look ugly, it will lead to less optimal and harder to maintain code. -Reading Evennia example code is a good way to get a feel for how different problems are approached -in Python. - -Overall, Python offers an extensive library of resources, safe memory management and excellent -handling of errors. While Python code does not run as fast as raw C code does, the difference is not -all that important for a text-based game. The main advantage of Python is an extremely fast -development cycle with and easy ways to create game systems that would take many times more code and -be much harder to make stable and maintainable in C. - -### Core Differences - -- As mentioned, the main difference between Evennia and a Diku-derived codebase is that Evennia is -written purely in Python. Since Python is an interpreted language there is no compile stage. It is -modified and extended by the server loading Python modules at run-time. It also runs on all computer -platforms Python runs on (which is basically everywhere). -- Vanilla Diku type engines save their data in custom *flat file* type storage solutions. By -contrast, Evennia stores all game data in one of several supported SQL databases. Whereas flat files -have the advantage of being easier to implement, they (normally) lack many expected safety features -and ways to effectively extract subsets of the stored data. For example, if the server loses power -while writing to a flatfile it may become corrupt and the data lost. A proper database solution is -not susceptible to this - at no point is the data in a state where it cannot be recovered. Databases -are also highly optimized for querying large data sets efficiently. - -### Some Familiar Things - -Diku expresses the character object referenced normally by: - -`struct char ch*` then all character-related fields can be accessed by `ch->`. In Evennia, one must -pay attention to what object you are using, and when you are accessing another through back- -handling, that you are accessing the right object. In Diku C, accessing character object is normally -done by: - -```c -/* creating pointer of both character and room struct */ - -void(struct char ch*, struct room room*){ - int dam; - if (ROOM_FLAGGED(room, ROOM_LAVA)){ - dam = 100 - ch->damage_taken = dam - }; -}; -``` - -As an example for creating Commands in Evennia via the `from evennia import Command` the character -object that calls the command is denoted by a class property as `self.caller`. In this example -`self.caller` is essentially the 'object' that has called the Command, but most of the time it is an -Account object. For a more familiar Diku feel, create a variable that becomes the account object as: - -```python -#mygame/commands/command.py - -from evennia import Command - -class CmdMyCmd(Command): - """ - This is a Command Evennia Object - """ - - [...] - - def func(self): - ch = self.caller - # then you can access the account object directly by using the familiar ch. - ch.msg("...") - account_name = ch.name - race = ch.db.race - -``` - -As mentioned above, care must be taken what specific object you are working with. If focused on a -room object and you need to access the account object: - -```python -#mygame/typeclasses/room.py - -from evennia import DefaultRoom - -class MyRoom(DefaultRoom): - [...] - - def is_account_object(self, object): - # a test to see if object is an account - [...] - - def myMethod(self): - #self.caller would not make any sense, since self refers to the - # object of 'DefaultRoom', you must find the character obj first: - for ch in self.contents: - if self.is_account_object(ch): - # now you can access the account object with ch: - account_name = ch.name - race = ch.db.race -``` - - -## Emulating Evennia to Look and Feel Like A Diku/ROM - -To emulate a Diku Mud on Evennia some work has to be done before hand. If there is anything that all -coders and builders remember from Diku/Rom days is the presence of VNUMs. Essentially all data was -saved in flat files and indexed by VNUMs for easy access. Evennia has the ability to emulate VNUMS -to the extent of categorising rooms/mobs/objs/trigger/zones[...] into vnum ranges. - -Evennia has objects that are called Scripts. As defined, they are the 'out of game' instances that -exist within the mud, but never directly interacted with. Scripts can be used for timers, mob AI, -and even a stand alone databases. - -Because of their wonderful structure all mob, room, zone, triggers, etc.. data can be saved in -independently created global scripts. - -Here is a sample mob file from a Diku Derived flat file. - -```text -#0 -mob0~ -mob0~ -mob0 -~ - Mob0 -~ -10 0 0 0 0 0 0 0 0 E -1 20 9 0d0+10 1d2+0 -10 100 -8 8 0 -E -#1 -Puff dragon fractal~ -Puff~ -Puff the Fractal Dragon is here, contemplating a higher reality. -~ - Is that some type of differential curve involving some strange, and unknown -calculus that she seems to be made out of? -~ -516106 0 0 0 2128 0 0 0 1000 E -34 9 -10 6d6+340 5d5+5 -340 115600 -8 8 2 -BareHandAttack: 12 -E -T 95 -``` -Each line represents something that the MUD reads in and does something with it. This isn't easy to -read, but let's see if we can emulate this as a dictionary to be stored on a database script created -in Evennia. - -First, let's create a global script that does absolutely nothing and isn't attached to anything. You -can either create this directly in-game with the @py command or create it in another file to do some -checks and balances if for whatever reason the script needs to be created again. Progmatically it -can be done like so: - -```python -from evennia import create_script - -mob_db = create_script("typeclasses.scripts.DefaultScript", key="mobdb", - persistent=True, obj=None) -mob_db.db.vnums = {} -``` -Just by creating a simple script object and assigning it a 'vnums' attribute as a type dictionary. -Next we have to create the mob layout.. - -```python -# vnum : mob_data - -mob_vnum_1 = { - 'key' : 'puff', - 'sdesc' : 'puff the fractal dragon', - 'ldesc' : 'Puff the Fractal Dragon is here, ' \ - 'contemplating a higher reality.', - 'ddesc' : ' Is that some type of differential curve ' \ - 'involving some strange, and unknown calculus ' \ - 'that she seems to be made out of?', - [...] - } - -# Then saving it to the data, assuming you have the script obj stored in a variable. -mob_db.db.vnums[1] = mob_vnum_1 -``` - -This is a very 'caveman' example, but it gets the idea across. You can use the keys in the -`mob_db.vnums` to act as the mob vnum while the rest contains the data.. - -Much simpler to read and edit. If you plan on taking this route, you must keep in mind that by -default evennia 'looks' at different properties when using the `look` command for instance. If you -create an instance of this mob and make its `self.key = 1`, by default evennia will say - -`Here is : 1` - -You must restructure all default commands so that the mud looks at different properties defined on -your mob. - - - - diff --git a/docs/0.9.5/_sources/Evennia-for-MUSH-Users.md.txt b/docs/0.9.5/_sources/Evennia-for-MUSH-Users.md.txt deleted file mode 100644 index f0fe7d4670..0000000000 --- a/docs/0.9.5/_sources/Evennia-for-MUSH-Users.md.txt +++ /dev/null @@ -1,218 +0,0 @@ -# Evennia for MUSH Users - -*This page is adopted from an article originally posted for the MUSH community [here on -musoapbox.net](http://musoapbox.net/topic/1150/evennia-for-mushers).* - -[MUSH](https://en.wikipedia.org/wiki/MUSH)es are text multiplayer games traditionally used for -heavily roleplay-focused game styles. They are often (but not always) utilizing game masters and -human oversight over code automation. MUSHes are traditionally built on the TinyMUSH-family of game -servers, like PennMUSH, TinyMUSH, TinyMUX and RhostMUSH. Also their siblings -[MUCK](https://en.wikipedia.org/wiki/TinyMUCK) and [MOO](https://en.wikipedia.org/wiki/MOO) are -often mentioned together with MUSH since they all inherit from the same -[TinyMUD](https://en.wikipedia.org/wiki/MUD_trees#TinyMUD_family_tree) base. A major feature is the -ability to modify and program the game world from inside the game by using a custom scripting -language. We will refer to this online scripting as *softcode* here. - -Evennia works quite differently from a MUSH both in its overall design and under the hood. The same -things are achievable, just in a different way. Here are some fundamental differences to keep in -mind if you are coming from the MUSH world. - -## Developers vs Players - -In MUSH, users tend to code and expand all aspects of the game from inside it using softcode. A MUSH -can thus be said to be managed solely by *Players* with different levels of access. Evennia on the -other hand, differentiates between the role of the *Player* and the *Developer*. - -- An Evennia *Developer* works in Python from *outside* the game, in what MUSH would consider -“hardcode”. Developers implement larger-scale code changes and can fundamentally change how the game -works. They then load their changes into the running Evennia server. Such changes will usually not -drop any connected players. -- An Evennia *Player* operates from *inside* the game. Some staff-level players are likely to double -as developers. Depending on access level, players can modify and expand the game's world by digging -new rooms, creating new objects, alias commands, customize their experience and so on. Trusted staff -may get access to Python via the `@py` command, but this would be a security risk for normal Players -to use. So the *Player* usually operates by making use of the tools prepared for them by the -*Developer* - tools that can be as rigid or flexible as the developer desires. - -## Collaborating on a game - Python vs Softcode - -For a *Player*, collaborating on a game need not be too different between MUSH and Evennia. The -building and description of the game world can still happen mostly in-game using build commands, -using text tags and [inline functions](./TextTags.md#inline-functions) to prettify and customize the -experience. Evennia offers external ways to build a world but those are optional. There is also -nothing *in principle* stopping a Developer from offering a softcode-like language to Players if -that is deemed necessary. - -For *Developers* of the game, the difference is larger: Code is mainly written outside the game in -Python modules rather than in-game on the command line. Python is a very popular and well-supported -language with tons of documentation and help to be found. The Python standard library is also a -great help for not having to reinvent the wheel. But that said, while Python is considered one of -the easier languages to learn and use it is undoubtedly very different from MUSH softcode. - -While softcode allows collaboration in-game, Evennia's external coding instead opens up the -possibility for collaboration using professional version control tools and bug tracking using -websites like github (or bitbucket for a free private repo). Source code can be written in proper -text editors and IDEs with refactoring, syntax highlighting and all other conveniences. In short, -collaborative development of an Evennia game is done in the same way most professional collaborative -development is done in the world, meaning all the best tools can be used. - - -## `@parent` vs `@typeclass` and `@spawn` - -Inheritance works differently in Python than in softcode. Evennia has no concept of a "master -object" that other objects inherit from. There is in fact no reason at all to introduce "virtual -objects" in the game world - code and data are kept separate from one another. - -In Python (which is an [object oriented](https://en.wikipedia.org/wiki/Object-oriented_programming) -language) one instead creates *classes* - these are like blueprints from which you spawn any number -of *object instances*. Evennia also adds the extra feature that every instance is persistent in the -database (this means no SQL is ever needed). To take one example, a unique character in Evennia is -an instances of the class `Character`. - -One parallel to MUSH's `@parent` command may be Evennia's `@typeclass` command, which changes which -class an already existing object is an instance of. This way you can literally turn a `Character` -into a `Flowerpot` on the spot. - -if you are new to object oriented design it's important to note that all object instances of a class -does *not* have to be identical. If they did, all Characters would be named the same. Evennia allows -to customize individual objects in many different ways. One way is through *Attributes*, which are -database-bound properties that can be linked to any object. For example, you could have an `Orc` -class that defines all the stuff an Orc should be able to do (probably in turn inheriting from some -`Monster` class shared by all monsters). Setting different Attributes on different instances -(different strength, equipment, looks etc) would make each Orc unique despite all sharing the same -class. - - The `@spawn` command allows one to conveniently choose between different "sets" of Attributes to -put on each new Orc (like the "warrior" set or "shaman" set) . Such sets can even inherit one -another which is again somewhat remniscent at least of the *effect* of `@parent` and the object- -based inheritance of MUSH. - -There are other differences for sure, but that should give some feel for things. Enough with the -theory. Let's get down to more practical matters next. To install, see the -[Getting Started instructions](./Getting-Started.md). - -## A first step making things more familiar - -We will here give two examples of customizing Evennia to be more familiar to a MUSH *Player*. - -### Activating a multi-descer - -By default Evennia’s `desc` command updates your description and that’s it. There is a more feature- -rich optional “multi-descer” in `evennia/contrib/multidesc.py` though. This alternative allows for -managing and combining a multitude of keyed descriptions. - -To activate the multi-descer, `cd` to your game folder and into the `commands` sub-folder. There -you’ll find the file `default_cmdsets.py`. In Python lingo all `*.py` files are called *modules*. -Open the module in a text editor. We won’t go into Evennia in-game *Commands* and *Command sets* -further here, but suffice to say Evennia allows you to change which commands (or versions of -commands) are available to the player from moment to moment depending on circumstance. - -Add two new lines to the module as seen below: - -```python -# the file mygame/commands/default_cmdsets.py -# [...] - -from evennia.contrib import multidescer # <- added now - -class CharacterCmdSet(default_cmds.CharacterCmdSet): - """ - The CharacterCmdSet contains general in-game commands like look, - get etc available on in-game Character objects. It is merged with - the AccountCmdSet when an Account puppets a Character. - """ - key = "DefaultCharacter" - - def at_cmdset_creation(self): - """ - Populates the cmdset - """ - super().at_cmdset_creation() - # - # any commands you add below will overload the default ones. - # - self.add(multidescer.CmdMultiDesc()) # <- added now -# [...] -``` - -Note that Python cares about indentation, so make sure to indent with the same number of spaces as -shown above! - -So what happens above? We [import the module](http://www.linuxtopia.org/online_books/programming_books/python_programming/python_ch28s03.html) `evennia/contrib/multidescer.py` at the top. Once -imported we can access stuff inside that module using full stop (`.`). The multidescer is defined as -a class `CmdMultiDesc` (we could find this out by opening said module in a text editor). At the -bottom we create a new instance of this class and add it to the `CharacterCmdSet` class. For the -sake of this tutorial we only need to know that `CharacterCmdSet` contains all commands that should -be be available to the `Character` by default. - -This whole thing will be triggered when the command set is first created, which happens on server -start. So we need to reload Evennia with `@reload` - no one will be disconnected by doing this. If -all went well you should now be able to use `desc` (or `+desc`) and find that you have more -possibilities: - -```text -> help +desc # get help on the command -> +desc eyes = His eyes are blue. -> +desc basic = A big guy. -> +desc/set basic + + eyes # we add an extra space between -> look me -A big guy. His eyes are blue. -``` - -If there are errors, a *traceback* will show in the server log - several lines of text showing -where the error occurred. Find where the error is by locating the line number related to the -`default_cmdsets.py` file (it's the only one you've changed so far). Most likely you mis-spelled -something or missed the indentation. Fix it and either `@reload` again or run `evennia start` as -needed. - -### Customizing the multidescer syntax - -As seen above the multidescer uses syntax like this (where `|/` are Evennia's tags for line breaks) -: - -```text -> +desc/set basic + |/|/ + cape + footwear + |/|/ + attitude -``` - -This use of `+ ` was prescribed by the *Developer* that coded this `+desc` command. What if the -*Player* doesn’t like this syntax though? Do players need to pester the dev to change it? Not -necessarily. While Evennia does not allow the player to build their own multi-descer on the command -line, it does allow for *re-mapping* the command syntax to one they prefer. This is done using the -`nick` command. - -Here’s a nick that changes how to input the command above: - -```text -> nick setdesc $1 $2 $3 $4 = +desc/set $1 + |/|/ + $2 + $3 + |/|/ + $4 -``` - -The string on the left will be matched against your input and if matching, it will be replaced with -the string on the right. The `$`-type tags will store space-separated arguments and put them into -the replacement. The nick allows [shell-like wildcards](http://www.linfo.org/wildcard.html), so you -can use `*`, `?`, `[...]`, `[!...]` etc to match parts of the input. - -The same description as before can now be set as - -```text -> setdesc basic cape footwear attitude -``` - -With the `nick` functionality players can mitigate a lot of syntax dislikes even without the -developer changing the underlying Python code. - -## Next steps - -If you are a *Developer* and are interested in making a more MUSH-like Evennia game, a good start is -to look into the Evennia [Tutorial for a first MUSH-like game](./Tutorial-for-basic-MUSH-like-game.md). -That steps through building a simple little game from scratch and helps to acquaint you with the -various corners of Evennia. There is also the [Tutorial for running roleplaying sessions](./Evennia-for-roleplaying-sessions.md) that can be of interest. - -An important aspect of making things more familiar for *Players* is adding new and tweaking existing -commands. How this is done is covered by the [Tutorial on adding new commands](./Adding-Command-Tutorial.md). You may also find it useful to shop through the `evennia/contrib/` folder. The [Tutorial -world](./Tutorial-World-Introduction.md) is a small single-player quest you can try (it’s not very MUSH- -like but it does show many Evennia concepts in action). Beyond that there are [many more -tutorials](./Tutorials.md) to try out. If you feel you want a more visual overview you can also look at -[Evennia in pictures](https://evennia.blogspot.se/2016/05/evennia-in-pictures.html). - -… And of course, if you need further help you can always drop into the [Evennia chatroom](http://webchat.freenode.net/?channels=evennia&uio=MT1mYWxzZSY5PXRydWUmMTE9MTk1JjEyPXRydWUbb) or post a -question in our [forum/mailing list](https://groups.google.com/forum/#%21forum/evennia)! diff --git a/docs/0.9.5/_sources/Evennia-for-roleplaying-sessions.md.txt b/docs/0.9.5/_sources/Evennia-for-roleplaying-sessions.md.txt deleted file mode 100644 index f3fa385321..0000000000 --- a/docs/0.9.5/_sources/Evennia-for-roleplaying-sessions.md.txt +++ /dev/null @@ -1,732 +0,0 @@ -# Evennia for roleplaying sessions - -This tutorial will explain how to set up a realtime or play-by-post tabletop style game using a -fresh Evennia server. - -The scenario is thus: You and a bunch of friends want to play a tabletop role playing game online. -One of you will be the game master and you are all okay with playing using written text. You want -both the ability to role play in real-time (when people happen to be online at the same time) as -well as the ability for people to post when they can and catch up on what happened since they were -last online. - -This is the functionality we will be needing and using: - -* The ability to make one of you the *GM* (game master), with special abilities. -* A *Character sheet* that players can create, view and fill in. It can also be locked so only the -GM can modify it. -* A *dice roller* mechanism, for whatever type of dice the RPG rules require. -* *Rooms*, to give a sense of location and to compartmentalize play going on- This means both -Character movements from location to location and GM explicitly moving them around. -* *Channels*, for easily sending text to all subscribing accounts, regardless of location. -* Account-to-Account *messaging* capability, including sending to multiple recipients -simultaneously, regardless of location. - -We will find most of these things are already part of vanilla Evennia, but that we can expand on the -defaults for our particular use-case. Below we will flesh out these components from start to finish. - -## Starting out - -We will assume you start from scratch. You need Evennia installed, as per the [Getting -Started](./Getting-Started.md) instructions. Initialize a new game directory with `evennia init -`. In this tutorial we assume your game dir is simply named `mygame`. You can use the -default database and keep all other settings to default for now. Familiarize yourself with the -`mygame` folder before continuing. You might want to browse the [First Steps Coding](First-Steps- -Coding) tutorial, just to see roughly where things are modified. - -## The Game Master role - -In brief: - -* Simplest way: Being an admin, just give one account `Admins` permission using the standard `@perm` -command. -* Better but more work: Make a custom command to set/unset the above, while tweaking the Character -to show your renewed GM status to the other accounts. - -### The permission hierarchy - -Evennia has the following [permission hierarchy](./Building-Permissions.md#assigning-permissions) out of -the box: *Players, Helpers, Builders, Admins* and finally *Developers*. We could change these but -then we'd need to update our Default commands to use the changes. We want to keep this simple, so -instead we map our different roles on top of this permission ladder. - -1. `Players` is the permission set on normal players. This is the default for anyone creating a new -account on the server. -2. `Helpers` are like `Players` except they also have the ability to create/edit new help entries. -This could be granted to players who are willing to help with writing lore or custom logs for -everyone. -3. `Builders` is not used in our case since the GM should be the only world-builder. -4. `Admins` is the permission level the GM should have. Admins can do everything builders can -(create/describe rooms etc) but also kick accounts, rename them and things like that. -5. `Developers`-level permission are the server administrators, the ones with the ability to -restart/shutdown the server as well as changing the permission levels. - -> The [superuser](./Building-Permissions.md#the-super-user) is not part of the hierarchy and actually -completely bypasses it. We'll assume server admin(s) will "just" be Developers. - -### How to grant permissions - -Only `Developers` can (by default) change permission level. Only they have access to the `@perm` -command: - -``` -> @perm Yvonne -Permissions on Yvonne: accounts - -> @perm Yvonne = Admins -> @perm Yvonne -Permissions on Yvonne: accounts, admins - -> @perm/del Yvonne = Admins -> @perm Yvonne -Permissions on Yvonne: accounts -``` - -There is no need to remove the basic `Players` permission when adding the higher permission: the -highest will be used. Permission level names are *not* case sensitive. You can also use both plural -and singular, so "Admins" gives the same powers as "Admin". - - -### Optional: Making a GM-granting command - -Use of `@perm` works out of the box, but it's really the bare minimum. Would it not be nice if other -accounts could tell at a glance who the GM is? Also, we shouldn't really need to remember that the -permission level is called "Admins". It would be easier if we could just do `@gm ` and -`@notgm ` and at the same time change something make the new GM status apparent. - -So let's make this possible. This is what we'll do: - -1. We'll customize the default Character class. If an object of this class has a particular flag, -its name will have the string`(GM)` added to the end. -2. We'll add a new command, for the server admin to assign the GM-flag properly. - -#### Character modification - -Let's first start by customizing the Character. We recommend you browse the beginning of the -[Account](./Accounts.md) page to make sure you know how Evennia differentiates between the OOC "Account -objects" (not to be confused with the `Accounts` permission, which is just a string specifying your -access) and the IC "Character objects". - -Open `mygame/typeclasses/characters.py` and modify the default `Character` class: - -```python -# in mygame/typeclasses/characters.py - -# [...] - -class Character(DefaultCharacter): - # [...] - def get_display_name(self, looker, **kwargs): - """ - This method customizes how character names are displayed. We assume - only permissions of types "Developers" and "Admins" require - special attention. - """ - name = self.key - selfaccount = self.account # will be None if we are not puppeted - lookaccount = looker.account # - " - - - if selfaccount and selfaccount.db.is_gm: - # A GM. Show name as name(GM) - name = "%s(GM)" % name - - if lookaccount and \ - (lookaccount.permissions.get("Developers") or lookaccount.db.is_gm): - # Developers/GMs see name(#dbref) or name(GM)(#dbref) - return "%s(#%s)" % (name, self.id) - else: - return name - -``` - -Above, we change how the Character's name is displayed: If the account controlling this Character is -a GM, we attach the string `(GM)` to the Character's name so everyone can tell who's the boss. If we -ourselves are Developers or GM's we will see database ids attached to Characters names, which can -help if doing database searches against Characters of exactly the same name. We base the "gm- -ingness" on having an flag (an [Attribute](./Attributes.md)) named `is_gm`. We'll make sure new GM's -actually get this flag below. - -> **Extra exercise:** This will only show the `(GM)` text on *Characters* puppeted by a GM account, -that is, it will show only to those in the same location. If we wanted it to also pop up in, say, -`who` listings and channels, we'd need to make a similar change to the `Account` typeclass in -`mygame/typeclasses/accounts.py`. We leave this as an exercise to the reader. - -#### New @gm/@ungm command - -We will describe in some detail how to create and add an Evennia [command](./Commands.md) here with the -hope that we don't need to be as detailed when adding commands in the future. We will build on -Evennia's default "mux-like" commands here. - -Open `mygame/commands/command.py` and add a new Command class at the bottom: - -```python -# in mygame/commands/command.py - -from evennia import default_cmds - -# [...] - -import evennia - -class CmdMakeGM(default_cmds.MuxCommand): - """ - Change an account's GM status - - Usage: - @gm - @ungm - - """ - # note using the key without @ means both @gm !gm etc will work - key = "gm" - aliases = "ungm" - locks = "cmd:perm(Developers)" - help_category = "RP" - - def func(self): - "Implement the command" - caller = self.caller - - if not self.args: - caller.msg("Usage: @gm account or @ungm account") - return - - accountlist = evennia.search_account(self.args) # returns a list - if not accountlist: - caller.msg("Could not find account '%s'" % self.args) - return - elif len(accountlist) > 1: - caller.msg("Multiple matches for '%s': %s" % (self.args, accountlist)) - return - else: - account = accountlist[0] - - if self.cmdstring == "gm": - # turn someone into a GM - if account.permissions.get("Admins"): - caller.msg("Account %s is already a GM." % account) - else: - account.permissions.add("Admins") - caller.msg("Account %s is now a GM." % account) - account.msg("You are now a GM (changed by %s)." % caller) - account.character.db.is_gm = True - else: - # @ungm was entered - revoke GM status from someone - if not account.permissions.get("Admins"): - caller.msg("Account %s is not a GM." % account) - else: - account.permissions.remove("Admins") - caller.msg("Account %s is no longer a GM." % account) - account.msg("You are no longer a GM (changed by %s)." % caller) - del account.character.db.is_gm - -``` - -All the command does is to locate the account target and assign it the `Admins` permission if we -used `@gm` or revoke it if using the `@ungm` alias. We also set/unset the `is_gm` Attribute that is -expected by our new `Character.get_display_name` method from earlier. - -> We could have made this into two separate commands or opted for a syntax like `@gm/revoke -`. Instead we examine how this command was called (stored in `self.cmdstring`) in order -to act accordingly. Either way works, practicality and coding style decides which to go with. - -To actually make this command available (only to Developers, due to the lock on it), we add it to -the default Account command set. Open the file `mygame/commands/default_cmdsets.py` and find the -`AccountCmdSet` class: - -```python -# mygame/commands/default_cmdsets.py - -# [...] -from commands.command import CmdMakeGM - -class AccountCmdSet(default_cmds.AccountCmdSet): - # [...] - def at_cmdset_creation(self): - # [...] - self.add(CmdMakeGM()) - -``` - -Finally, issue the `@reload` command to update the server to your changes. Developer-level players -(or the superuser) should now have the `@gm/@ungm` command available. - -## Character sheet - -In brief: - -* Use Evennia's EvTable/EvForm to build a Character sheet -* Tie individual sheets to a given Character. -* Add new commands to modify the Character sheet, both by Accounts and GMs. -* Make the Character sheet lockable by a GM, so the Player can no longer modify it. - -### Building a Character sheet - -There are many ways to build a Character sheet in text, from manually pasting strings together to -more automated ways. Exactly what is the best/easiest way depends on the sheet one tries to create. -We will here show two examples using the *EvTable* and *EvForm* utilities.Later we will create -Commands to edit and display the output from those utilities. - -> Note that due to the limitations of the wiki, no color is used in any of the examples. See [the -text tag documentation](./TextTags.md) for how to add color to the tables and forms. - -#### Making a sheet with EvTable - -[EvTable](github:evennia.utils.evtable) is a text-table generator. It helps with displaying text in -ordered rows and columns. This is an example of using it in code: - -````python -# this can be tried out in a Python shell like iPython - -from evennia.utils import evtable - -# we hardcode these for now, we'll get them as input later -STR, CON, DEX, INT, WIS, CHA = 12, 13, 8, 10, 9, 13 - -table = evtable.EvTable("Attr", "Value", - table = [ - ["STR", "CON", "DEX", "INT", "WIS", "CHA"], - [STR, CON, DEX, INT, WIS, CHA] - ], align='r', border="incols") -```` - -Above, we create a two-column table by supplying the two columns directly. We also tell the table to -be right-aligned and to use the "incols" border type (borders drawns only in between columns). The -`EvTable` class takes a lot of arguments for customizing its look, you can see [some of the possible -keyword arguments here](github:evennia.utils.evtable#evtable__init__). Once you have the `table` you -could also retroactively add new columns and rows to it with `table.add_row()` and -`table.add_column()`: if necessary the table will expand with empty rows/columns to always remain -rectangular. - -The result from printing the above table will be - -```python -table_string = str(table) - -print(table_string) - - Attr | Value -~~~~~~+~~~~~~~ - STR | 12 - CON | 13 - DEX | 8 - INT | 10 - WIS | 9 - CHA | 13 -``` - -This is a minimalistic but effective Character sheet. By combining the `table_string` with other -strings one could build up a reasonably full graphical representation of a Character. For more -advanced layouts we'll look into EvForm next. - -#### Making a sheet with EvForm - -[EvForm](github:evennia.utils.evform) allows the creation of a two-dimensional "graphic" made by -text characters. On this surface, one marks and tags rectangular regions ("cells") to be filled with -content. This content can be either normal strings or `EvTable` instances (see the previous section, -one such instance would be the `table` variable in that example). - -In the case of a Character sheet, these cells would be comparable to a line or box where you could -enter the name of your character or their strength score. EvMenu also easily allows to update the -content of those fields in code (it use EvTables so you rebuild the table first before re-sending it -to EvForm). - -The drawback of EvForm is that its shape is static; if you try to put more text in a region than it -was sized for, the text will be cropped. Similarly, if you try to put an EvTable instance in a field -too small for it, the EvTable will do its best to try to resize to fit, but will eventually resort -to cropping its data or even give an error if too small to fit any data. - -An EvForm is defined in a Python module. Create a new file `mygame/world/charsheetform.py` and -modify it thus: - -````python -#coding=utf-8 - -# in mygame/world/charsheetform.py - -FORMCHAR = "x" -TABLECHAR = "c" - -FORM = """ -.--------------------------------------. -| | -| Name: xxxxxxxxxxxxxx1xxxxxxxxxxxxxxx | -| xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | -| | - >------------------------------------< -| | -| ccccccccccc Advantages: | -| ccccccccccc xxxxxxxxxxxxxxxxxxxxxx | -| ccccccccccc xxxxxxxxxx3xxxxxxxxxxx | -| ccccccccccc xxxxxxxxxxxxxxxxxxxxxx | -| ccccc2ccccc Disadvantages: | -| ccccccccccc xxxxxxxxxxxxxxxxxxxxxx | -| ccccccccccc xxxxxxxxxx4xxxxxxxxxxx | -| ccccccccccc xxxxxxxxxxxxxxxxxxxxxx | -| | -+--------------------------------------+ -""" -```` -The `#coding` statement (which must be put on the very first line to work) tells Python to use the -utf-8 encoding for the file. Using the `FORMCHAR` and `TABLECHAR` we define what single-character we -want to use to "mark" the regions of the character sheet holding cells and tables respectively. -Within each block (which must be separated from one another by at least one non-marking character) -we embed identifiers 1-4 to identify each block. The identifier could be any single character except -for the `FORMCHAR` and `TABLECHAR` - -> You can still use `FORMCHAR` and `TABLECHAR` elsewhere in your sheet, but not in a way that it -would identify a cell/table. The smallest identifiable cell/table area is 3 characters wide -including the identifier (for example `x2x`). - -Now we will map content to this form. - -````python -# again, this can be tested in a Python shell - -# hard-code this info here, later we'll ask the -# account for this info. We will re-use the 'table' -# variable from the EvTable example. - -NAME = "John, the wise old admin with a chip on his shoulder" -ADVANTAGES = "Language-wiz, Intimidation, Firebreathing" -DISADVANTAGES = "Bad body odor, Poor eyesight, Troubled history" - -from evennia.utils import evform - -# load the form from the module -form = evform.EvForm("world/charsheetform.py") - -# map the data to the form -form.map(cells={"1":NAME, "3": ADVANTAGES, "4": DISADVANTAGES}, - tables={"2":table}) -```` - -We create some RP-sounding input and re-use the `table` variable from the previous `EvTable` -example. - -> Note, that if you didn't want to create the form in a separate module you *could* also load it -directly into the `EvForm` call like this: `EvForm(form={"FORMCHAR":"x", "TABLECHAR":"c", "FORM": -formstring})` where `FORM` specifies the form as a string in the same way as listed in the module -above. Note however that the very first line of the `FORM` string is ignored, so start with a `\n`. - -We then map those to the cells of the form: - -````python -print(form) -```` -```` -.--------------------------------------. -| | -| Name: John, the wise old admin with | -| a chip on his shoulder | -| | - >------------------------------------< -| | -| Attr|Value Advantages: | -| ~~~~~+~~~~~ Language-wiz, | -| STR| 12 Intimidation, | -| CON| 13 Firebreathing | -| DEX| 8 Disadvantages: | -| INT| 10 Bad body odor, Poor | -| WIS| 9 eyesight, Troubled | -| CHA| 13 history | -| | -+--------------------------------------+ -```` - -As seen, the texts and tables have been slotted into the text areas and line breaks have been added -where needed. We chose to just enter the Advantages/Disadvantages as plain strings here, meaning -long names ended up split between rows. If we wanted more control over the display we could have -inserted `\n` line breaks after each line or used a borderless `EvTable` to display those as well. - -### Tie a Character sheet to a Character - -We will assume we go with the `EvForm` example above. We now need to attach this to a Character so -it can be modified. For this we will modify our `Character` class a little more: - -```python -# mygame/typeclasses/character.py - -from evennia.utils import evform, evtable - -[...] - -class Character(DefaultCharacter): - [...] - def at_object_creation(self): - "called only once, when object is first created" - # we will use this to stop account from changing sheet - self.db.sheet_locked = False - # we store these so we can build these on demand - self.db.chardata = {"str": 0, - "con": 0, - "dex": 0, - "int": 0, - "wis": 0, - "cha": 0, - "advantages": "", - "disadvantages": ""} - self.db.charsheet = evform.EvForm("world/charsheetform.py") - self.update_charsheet() - - def update_charsheet(self): - """ - Call this to update the sheet after any of the ingoing data - has changed. - """ - data = self.db.chardata - table = evtable.EvTable("Attr", "Value", - table = [ - ["STR", "CON", "DEX", "INT", "WIS", "CHA"], - [data["str"], data["con"], data["dex"], - data["int"], data["wis"], data["cha"]]], - align='r', border="incols") - self.db.charsheet.map(tables={"2": table}, - cells={"1":self.key, - "3":data["advantages"], - "4":data["disadvantages"]}) - -``` - -Use `@reload` to make this change available to all *newly created* Characters. *Already existing* -Characters will *not* have the charsheet defined, since `at_object_creation` is only called once. -The easiest to force an existing Character to re-fire its `at_object_creation` is to use the -`@typeclass` command in-game: - -``` -@typeclass/force -``` - -### Command for Account to change Character sheet - -We will add a command to edit the sections of our Character sheet. Open -`mygame/commands/command.py`. - -```python -# at the end of mygame/commands/command.py - -ALLOWED_ATTRS = ("str", "con", "dex", "int", "wis", "cha") -ALLOWED_FIELDNAMES = ALLOWED_ATTRS + \ - ("name", "advantages", "disadvantages") - -def _validate_fieldname(caller, fieldname): - "Helper function to validate field names." - if fieldname not in ALLOWED_FIELDNAMES: - err = "Allowed field names: %s" % (", ".join(ALLOWED_FIELDNAMES)) - caller.msg(err) - return False - if fieldname in ALLOWED_ATTRS and not value.isdigit(): - caller.msg("%s must receive a number." % fieldname) - return False - return True - -class CmdSheet(MuxCommand): - """ - Edit a field on the character sheet - - Usage: - @sheet field value - - Examples: - @sheet name Ulrik the Warrior - @sheet dex 12 - @sheet advantages Super strength, Night vision - - If given without arguments, will view the current character sheet. - - Allowed field names are: - name, - str, con, dex, int, wis, cha, - advantages, disadvantages - - """ - - key = "sheet" - aliases = "editsheet" - locks = "cmd: perm(Players)" - help_category = "RP" - - def func(self): - caller = self.caller - if not self.args or len(self.args) < 2: - # not enough arguments. Display the sheet - if sheet: - caller.msg(caller.db.charsheet) - else: - caller.msg("You have no character sheet.") - return - - # if caller.db.sheet_locked: - caller.msg("Your character sheet is locked.") - return - - # split input by whitespace, once - fieldname, value = self.args.split(None, 1) - fieldname = fieldname.lower() # ignore case - - if not _validate_fieldnames(caller, fieldname): - return - if fieldname == "name": - self.key = value - else: - caller.chardata[fieldname] = value - caller.update_charsheet() - caller.msg("%s was set to %s." % (fieldname, value)) - -``` - -Most of this command is error-checking to make sure the right type of data was input. Note how the -`sheet_locked` Attribute is checked and will return if not set. - -This command you import into `mygame/commands/default_cmdsets.py` and add to the `CharacterCmdSet`, -in the same way the `@gm` command was added to the `AccountCmdSet` earlier. - -### Commands for GM to change Character sheet - -Game masters use basically the same input as Players do to edit a character sheet, except they can -do it on other players than themselves. They are also not stopped by any `sheet_locked` flags. - -```python -# continuing in mygame/commands/command.py - -class CmdGMsheet(MuxCommand): - """ - GM-modification of char sheets - - Usage: - @gmsheet character [= fieldname value] - - Switches: - lock - lock the character sheet so the account - can no longer edit it (GM's still can) - unlock - unlock character sheet for Account - editing. - - Examples: - @gmsheet Tom - @gmsheet Anna = str 12 - @gmsheet/lock Tom - - """ - key = "gmsheet" - locks = "cmd: perm(Admins)" - help_category = "RP" - - def func(self): - caller = self.caller - if not self.args: - caller.msg("Usage: @gmsheet character [= fieldname value]") - - if self.rhs: - # rhs (right-hand-side) is set only if a '=' - # was given. - if len(self.rhs) < 2: - caller.msg("You must specify both a fieldname and value.") - return - fieldname, value = self.rhs.split(None, 1) - fieldname = fieldname.lower() - if not _validate_fieldname(caller, fieldname): - return - charname = self.lhs - else: - # no '=', so we must be aiming to look at a charsheet - fieldname, value = None, None - charname = self.args.strip() - - character = caller.search(charname, global_search=True) - if not character: - return - - if "lock" in self.switches: - if character.db.sheet_locked: - caller.msg("The character sheet is already locked.") - else: - character.db.sheet_locked = True - caller.msg("%s can no longer edit their character sheet." % character.key) - elif "unlock" in self.switches: - if not character.db.sheet_locked: - caller.msg("The character sheet is already unlocked.") - else: - character.db.sheet_locked = False - caller.msg("%s can now edit their character sheet." % character.key) - - if fieldname: - if fieldname == "name": - character.key = value - else: - character.db.chardata[fieldname] = value - character.update_charsheet() - caller.msg("You set %s's %s to %s." % (character.key, fieldname, value) - else: - # just display - caller.msg(character.db.charsheet) -``` - -The `@gmsheet` command takes an additional argument to specify which Character's character sheet to -edit. It also takes `/lock` and `/unlock` switches to block the Player from tweaking their sheet. - -Before this can be used, it should be added to the default `CharacterCmdSet` in the same way as the -normal `@sheet`. Due to the lock set on it, this command will only be available to `Admins` (i.e. -GMs) or higher permission levels. - -## Dice roller - -Evennia's *contrib* folder already comes with a full dice roller. To add it to the game, simply -import `contrib.dice.CmdDice` into `mygame/commands/default_cmdsets.py` and add `CmdDice` to the -`CharacterCmdset` as done with other commands in this tutorial. After a `@reload` you will be able -to roll dice using normal RPG-style format: - -``` -roll 2d6 + 3 -7 -``` - -Use `help dice` to see what syntax is supported or look at `evennia/contrib/dice.py` to see how it's -implemented. - -## Rooms - -Evennia comes with rooms out of the box, so no extra work needed. A GM will automatically have all -needed building commands available. A fuller go-through is found in the [Building -tutorial](./Building-Quickstart.md). Here are some useful highlights: - -* `@dig roomname;alias = exit_there;alias, exit_back;alias` - this is the basic command for digging -a new room. You can specify any exit-names and just enter the name of that exit to go there. -* `@tunnel direction = roomname` - this is a specialized command that only accepts directions in the -cardinal directions (n,ne,e,se,s,sw,w,nw) as well as in/out and up/down. It also automatically -builds "matching" exits back in the opposite direction. -* `@create/drop objectname` - this creates and drops a new simple object in the current location. -* `@desc obj` - change the look-description of the object. -* `@tel object = location` - teleport an object to a named location. -* `@search objectname` - locate an object in the database. - -> TODO: Describe how to add a logging room, that logs says and poses to a log file that people can -access after the fact. - -## Channels - -Evennia comes with [Channels](./Communications.md#channels) in-built and they are described fully in the -documentation. For brevity, here are the relevant commands for normal use: - -* `@ccreate new_channel;alias;alias = short description` - Creates a new channel. -* `addcom channel` - join an existing channel. Use `addcom alias = channel` to add a new alias you -can use to talk to the channel, as many as desired. -* `delcom alias or channel` - remove an alias from a channel or, if the real channel name is given, -unsubscribe completely. -* `@channels` lists all available channels, including your subscriptions and any aliases you have -set up for them. - -You can read channel history: if you for example are chatting on the `public` channel you can do -`public/history` to see the 20 last posts to that channel or `public/history 32` to view twenty -posts backwards, starting with the 32nd from the end. - -## PMs - -To send PMs to one another, players can use the `@page` (or `tell`) command: - -``` -page recipient = message -page recipient, recipient, ... = message -``` - -Players can use `page` alone to see the latest messages. This also works if they were not online -when the message was sent. diff --git a/docs/0.9.5/_sources/Execute-Python-Code.md.txt b/docs/0.9.5/_sources/Execute-Python-Code.md.txt deleted file mode 100644 index a37c080022..0000000000 --- a/docs/0.9.5/_sources/Execute-Python-Code.md.txt +++ /dev/null @@ -1,120 +0,0 @@ -# Execute Python Code - - -The `@py` command supplied with the default command set of Evennia allows you to execute Python -commands directly from inside the game. An alias to `@py` is simply "`!`". *Access to the `@py` -command should be severely restricted*. This is no joke - being able to execute arbitrary Python -code on the server is not something you should entrust to just anybody. - - @py 1+2 - <<< 3 - -## Available variables - -A few local variables are made available when running `@py`. These offer entry into the running -system. - -- **self** / **me** - the calling object (i.e. you) -- **here** - the current caller's location -- **obj** - a dummy [Object](./Objects.md) instance -- **evennia** - Evennia's [flat API](./Evennia-API.md) - through this you can access all of Evennia. - -For accessing other objects in the same room you need to use `self.search(name)`. For objects in -other locations, use one of the `evennia.search_*` methods. See [below](./Execute-Python-Code.md#finding- -objects). - -## Returning output - -This is an example where we import and test one of Evennia's utilities found in -`src/utils/utils.py`, but also accessible through `ev.utils`: - - @py from ev import utils; utils.time_format(33333) - <<< Done. - -Note that we didn't get any return value, all we where told is that the code finished executing -without error. This is often the case in more complex pieces of code which has no single obvious -return value. To see the output from the `time_format()` function we need to tell the system to -echo it to us explicitly with `self.msg()`. - - @py from ev import utils; self.msg(str(utils.time_format(33333))) - 09:15 - <<< Done. - -> Warning: When using the `msg` function wrap our argument in `str()` to convert it into a string -above. This is not strictly necessary for most types of data (Evennia will usually convert to a -string behind the scenes for you). But for *lists* and *tuples* you will be confused by the output -if you don't wrap them in `str()`: only the first item of the iterable will be returned. This is -because doing `msg(text)` is actually just a convenience shortcut; the full argument that `msg` -accepts is something called an *outputfunc* on the form `(cmdname, (args), {kwargs})` (see [the -message path](./Messagepath.md) for more info). Sending a list/tuple confuses Evennia to think you are -sending such a structure. Converting it to a string however makes it clear it should just be -displayed as-is. - -If you were to use Python's standard `print`, you will see the result in your current `stdout` (your -terminal by default, otherwise your log file). - -## Finding objects - -A common use for `@py` is to explore objects in the database, for debugging and performing specific -operations that are not covered by a particular command. - -Locating an object is best done using `self.search()`: - - @py self.search("red_ball") - <<< Ball - - @py self.search("red_ball").db.color = "red" - <<< Done. - - @py self.search("red_ball").db.color - <<< red - -`self.search()` is by far the most used case, but you can also search other database tables for -other Evennia entities like scripts or configuration entities. To do this you can use the generic -search entries found in `ev.search_*`. - - @py evennia.search_script("sys_game_time") - <<< [] - -(Note that since this becomes a simple statement, we don't have to wrap it in `self.msg()` to get -the output). You can also use the database model managers directly (accessible through the `objects` -properties of database models or as `evennia.managers.*`). This is a bit more flexible since it -gives you access to the full range of database search methods defined in each manager. - - @py evennia.managers.scripts.script_search("sys_game_time") - <<< [] - -The managers are useful for all sorts of database studies. - - @py ev.managers.configvalues.all() - <<< [, , ...] - -## Testing code outside the game - -`@py` has the advantage of operating inside a running server (sharing the same process), where you -can test things in real time. Much of this *can* be done from the outside too though. - -In a terminal, cd to the top of your game directory (this bit is important since we need access to -your config file) and run - - evennia shell - -Your default Python interpreter will start up, configured to be able to work with and import all -modules of your Evennia installation. From here you can explore the database and test-run individual -modules as desired. - -It's recommended that you get a more fully featured Python interpreter like -[iPython](http://ipython.scipy.org/moin/). If you use a virtual environment, you can just get it -with `pip install ipython`. IPython allows you to better work over several lines, and also has a lot -of other editing features, such as tab-completion and `__doc__`-string reading. - - $ evennia shell - - IPython 0.10 -- An enhanced Interactive Python - ... - - In [1]: import evennia - In [2]: evennia.managers.objects.all() - Out[3]: [, , ...] - -See the page about the [Evennia-API](./Evennia-API.md) for more things to explore. diff --git a/docs/0.9.5/_sources/First-Steps-Coding.md.txt b/docs/0.9.5/_sources/First-Steps-Coding.md.txt deleted file mode 100644 index a29f3d0113..0000000000 --- a/docs/0.9.5/_sources/First-Steps-Coding.md.txt +++ /dev/null @@ -1,292 +0,0 @@ -# First Steps Coding - - -This section gives a brief step-by-step introduction on how to set up Evennia for the first time so -you can modify and overload the defaults easily. You should only need to do these steps once. It -also walks through you making your first few tweaks. - -Before continuing, make sure you have Evennia installed and running by following the [Getting -Started](./Getting-Started.md) instructions. You should have initialized a new game folder with the -`evennia --init foldername` command. We will in the following assume this folder is called -"mygame". - -It might be a good idea to eye through the brief [Coding Introduction](./Coding-Introduction.md) too -(especially the recommendations in the section about the evennia "flat" API and about using `evennia -shell` will help you here and in the future). - -To follow this tutorial you also need to know the basics of operating your computer's -terminal/command line. You also need to have a text editor to edit and create source text files. -There are plenty of online tutorials on how to use the terminal and plenty of good free text -editors. We will assume these things are already familiar to you henceforth. - - -## Your First Changes - -Below are some first things to try with your new custom modules. You can test these to get a feel -for the system. See also [Tutorials](./Tutorials.md) for more step-by-step help and special cases. - -### Tweak Default Character - -We will add some simple rpg attributes to our default Character. In the next section we will follow -up with a new command to view those attributes. - -1. Edit `mygame/typeclasses/characters.py` and modify the `Character` class. The -`at_object_creation` method also exists on the `DefaultCharacter` parent and will overload it. The -`get_abilities` method is unique to our version of `Character`. - - ```python - class Character(DefaultCharacter): - # [...] - def at_object_creation(self): - """ - Called only at initial creation. This is a rather silly - example since ability scores should vary from Character to - Character and is usually set during some character - generation step instead. - """ - #set persistent attributes - self.db.strength = 5 - self.db.agility = 4 - self.db.magic = 2 - - def get_abilities(self): - """ - Simple access method to return ability - scores as a tuple (str,agi,mag) - """ - return self.db.strength, self.db.agility, self.db.magic - ``` - -1. [Reload](./Start-Stop-Reload.md) the server (you will still be connected to the game after doing -this). Note that if you examine *yourself* you will *not* see any new Attributes appear yet. Read -the next section to understand why. - -#### Updating Yourself - -It's important to note that the new [Attributes](./Attributes.md) we added above will only be stored on -*newly* created characters. The reason for this is simple: The `at_object_creation` method, where we -added those Attributes, is per definition only called when the object is *first created*, then never -again. This is usually a good thing since those Attributes may change over time - calling that hook -would reset them back to start values. But it also means that your existing character doesn't have -them yet. You can see this by calling the `get_abilities` hook on yourself at this point: - -``` -# (you have to be superuser to use @py) -@py self.get_abilities() -<<< (None, None, None) -``` - -This is easily remedied. - -``` -@update self -``` - -This will (only) re-run `at_object_creation` on yourself. You should henceforth be able to get the -abilities successfully: - -``` -@py self.get_abilities() -<<< (5, 4, 2) -``` - -This is something to keep in mind if you start building your world before your code is stable - -startup-hooks will not (and should not) automatically run on *existing* objects - you have to update -your existing objects manually. Luckily this is a one-time thing and pretty simple to do. If the -typeclass you want to update is in `typeclasses.myclass.MyClass`, you can do the following (e.g. -from `evennia shell`): - -```python -from typeclasses.myclass import MyClass -# loop over all MyClass instances in the database -# and call .swap_typeclass on them -for obj in MyClass.objects.all(): - obj.swap_typeclass(MyClass, run_start_hooks="at_object_creation") -``` - -Using `swap_typeclass` to the same typeclass we already have will re-run the creation hooks (this is -what the `@update` command does under the hood). From in-game you can do the same with `@py`: - -``` -@py typeclasses.myclass import MyClass;[obj.swap_typeclass(MyClass) for obj in -MyClass.objects.all()] -``` - -See the [Object Typeclass tutorial](./Adding-Object-Typeclass-Tutorial.md) for more help and the -[Typeclasses](./Typeclasses.md) and [Attributes](./Attributes.md) page for detailed documentation about -Typeclasses and Attributes. - -#### Troubleshooting: Updating Yourself - -One may experience errors for a number of reasons. Common beginner errors are spelling mistakes, -wrong indentations or code omissions leading to a `SyntaxError`. Let's say you leave out a colon -from the end of a class function like so: ```def at_object_creation(self)```. The client will reload -without issue. *However*, if you look at the terminal/console (i.e. not in-game), you will see -Evennia complaining (this is called a *traceback*): - -``` -Traceback (most recent call last): -File "C:\mygame\typeclasses\characters.py", line 33 - def at_object_creation(self) - ^ -SyntaxError: invalid syntax -``` - -Evennia will still be restarting and following the tutorial, doing `@py self.get_abilities()` will -return the right response `(None, None, None)`. But when attempting to `@typeclass/force self` you -will get this response: - -```python - AttributeError: 'DefaultObject' object has no attribute 'get_abilities' -``` - -The full error will show in the terminal/console but this is confusing since you did add -`get_abilities` before. Note however what the error says - you (`self`) should be a `Character` but -the error talks about `DefaultObject`. What has happened is that due to your unhandled `SyntaxError` -earlier, Evennia could not load the `character.py` module at all (it's not valid Python). Rather -than crashing, Evennia handles this by temporarily falling back to a safe default - `DefaultObject` -- in order to keep your MUD running. Fix the original `SyntaxError` and reload the server. Evennia -will then be able to use your modified `Character` class again and things should work. - -> Note: Learning how to interpret an error traceback is a critical skill for anyone learning Python. -Full tracebacks will appear in the terminal/Console you started Evennia from. The traceback text can -sometimes be quite long, but you are usually just looking for the last few lines: The description of -the error and the filename + line number for where the error occurred. In the example above, we see -it's a `SyntaxError` happening at `line 33` of `mygame\typeclasses\characters.py`. In this case it -even points out *where* on the line it encountered the error (the missing colon). Learn to read -tracebacks and you'll be able to resolve the vast majority of common errors easily. - -### Add a New Default Command - -The `@py` command used above is only available to privileged users. We want any player to be able to -see their stats. Let's add a new [command](./Commands.md) to list the abilities we added in the previous -section. - -1. Open `mygame/commands/command.py`. You could in principle put your command anywhere but this -module has all the imports already set up along with some useful documentation. Make a new class at -the bottom of this file: - - ```python - class CmdAbilities(BaseCommand): - """ - List abilities - - Usage: - abilities - - Displays a list of your current ability values. - """ - key = "abilities" - aliases = ["abi"] - lock = "cmd:all()" - help_category = "General" - - def func(self): - """implements the actual functionality""" - - str, agi, mag = self.caller.get_abilities() - string = "STR: %s, AGI: %s, MAG: %s" % (str, agi, mag) - self.caller.msg(string) - ``` - -1. Next you edit `mygame/commands/default_cmdsets.py` and add a new import to it near the top: - - ```python - from commands.command import CmdAbilities - ``` - -1. In the `CharacterCmdSet` class, add the following near the bottom (it says where): - - ```python - self.add(CmdAbilities()) - ``` - -1. [Reload](./Start-Stop-Reload.md) the server (noone will be disconnected by doing this). - -You (and anyone else) should now be able to use `abilities` (or its alias `abi`) as part of your -normal commands in-game: - -``` -abilities -STR: 5, AGI: 4, MAG: 2 -``` - -See the [Adding a Command tutorial](./Adding-Command-Tutorial.md) for more examples and the -[Commands](./Commands.md) section for detailed documentation about the Command system. - -### Make a New Type of Object - -Let's test to make a new type of object. This example is an "wise stone" object that returns some -random comment when you look at it, like this: - - > look stone - - A very wise stone - - This is a very wise old stone. - It grumbles and says: 'The world is like a rock of chocolate.' - -1. Create a new module in `mygame/typeclasses/`. Name it `wiseobject.py` for this example. -1. In the module import the base `Object` (`typeclasses.objects.Object`). This is empty by default, -meaning it is just a proxy for the default `evennia.DefaultObject`. -1. Make a new class in your module inheriting from `Object`. Overload hooks on it to add new -functionality. Here is an example of how the file could look: - - ```python - from random import choice - from typeclasses.objects import Object - - class WiseObject(Object): - """ - An object speaking when someone looks at it. We - assume it looks like a stone in this example. - """ - def at_object_creation(self): - """Called when object is first created""" - self.db.wise_texts = \ - ["Stones have feelings too.", - "To live like a stone is to not have lived at all.", - "The world is like a rock of chocolate."] - - def return_appearance(self, looker): - """ - Called by the look command. We want to return - a wisdom when we get looked at. - """ - # first get the base string from the - # parent's return_appearance. - string = super().return_appearance(looker) - wisewords = "\n\nIt grumbles and says: '%s'" - wisewords = wisewords % choice(self.db.wise_texts) - return string + wisewords - ``` - -1. Check your code for bugs. Tracebacks will appear on your command line or log. If you have a grave -Syntax Error in your code, the source file itself will fail to load which can cause issues with the -entire cmdset. If so, fix your bug and [reload the server from the command line](./Start-Stop-Reload.md) -(noone will be disconnected by doing this). -1. Use `@create/drop stone:wiseobject.WiseObject` to create a talkative stone. If the `@create` -command spits out a warning or cannot find the typeclass (it will tell you which paths it searched), -re-check your code for bugs and that you gave the correct path. The `@create` command starts looking -for Typeclasses in `mygame/typeclasses/`. -1. Use `look stone` to test. You will see the default description ("You see nothing special") -followed by a random message of stony wisdom. Use `@desc stone = This is a wise old stone.` to make -it look nicer. See the [Builder Docs](./Builder-Docs.md) for more information. - -Note that `at_object_creation` is only called once, when the stone is first created. If you make -changes to this method later, already existing stones will not see those changes. As with the -`Character` example above you can use `@typeclass/force` to tell the stone to re-run its -initialization. - -The `at_object_creation` is a special case though. Changing most other aspects of the typeclass does -*not* require manual updating like this - you just need to `@reload` to have all changes applied -automatically to all existing objects. - -## Where to Go From Here? - -There are more [Tutorials](./Tutorials.md), including one for building a [whole little MUSH-like -game](./Tutorial-for-basic-MUSH-like-game.md) - that is instructive also if you have no interest in -MUSHes per se. A good idea is to also get onto the [IRC -chat](http://webchat.freenode.net/?channels=evennia) and the [mailing -list](https://groups.google.com/forum/#!forum/evennia) to get in touch with the community and other -developers. diff --git a/docs/0.9.5/_sources/Game-Planning.md.txt b/docs/0.9.5/_sources/Game-Planning.md.txt deleted file mode 100644 index d20ca900d1..0000000000 --- a/docs/0.9.5/_sources/Game-Planning.md.txt +++ /dev/null @@ -1,214 +0,0 @@ -# Game Planning - - -So you have Evennia up and running. You have a great game idea in mind. Now it's time to start -cracking! But where to start? Here are some ideas for a workflow. Note that the suggestions on this -page are just that - suggestions. Also, they are primarily aimed at a lone hobby designer or a small -team developing a game in their free time. - -Below are some minimal steps for getting the first version of a new game world going with players. -It's worth to at least make the attempt to do these steps in order even if you are itching to jump -ahead in the development cycle. On the other hand, you should also make sure to keep your work fun -for you, or motivation will falter. Making a full game is a lot of work as it is, you'll need all -your motivation to make it a reality. - -Remember that *99.99999% of all great game ideas never lead to a game*. Especially not to an online -game that people can actually play and enjoy. So our first all overshadowing goal is to beat those -odds and get *something* out the door! Even if it's a scaled-down version of your dream game, -lacking many "must-have" features! It's better to get it out there and expand on it later than to -code in isolation forever until you burn out, lose interest or your hard drive crashes. - -Like is common with online games, getting a game out the door does not mean you are going to be -"finished" with the game - most MUDs add features gradually over the course of years - it's often -part of the fun! - -## Planning (step 1) - -This is what you do before having coded a single line or built a single room. Many prospective game -developers are very good at *parts* of this process, namely in defining what their world is "about": -The theme, the world concept, cool monsters and so on. It is by all means very important to define -what is the unique appeal of your game. But it's unfortunately not enough to make your game a -reality. To do that you must also have an idea of how to actually map those great ideas onto -Evennia. - -A good start is to begin by planning out the basic primitives of the game and what they need to be -able to do. Below are a far-from-complete list of examples (and for your first version you should -definitely try for a much shorter list): - -### Systems - -These are the behind-the-scenes features that exist in your game, often without being represented by -a specific in-game object. - -- Should your game rules be enforced by coded systems or are you planning for human game masters to -run and arbitrate rules? -- What are the actual mechanical game rules? How do you decide if an action succeeds or fails? What -"rolls" does the game need to be able to do? Do you base your game off an existing system or make up -your own? -- Does the flow of time matter in your game - does night and day change? What about seasons? Maybe -your magic system is affected by the phase of the moon? -- Do you want changing, global weather? This might need to operate in tandem over a large number of -rooms. -- Do you want a game-wide economy or just a simple barter system? Or no formal economy at all? -- Should characters be able to send mail to each other in-game? -- Should players be able to post on Bulletin boards? -- What is the staff hierarchy in your game? What powers do you want your staff to have? -- What should a Builder be able to build and what commands do they need in order to do that? -- etc. - -### Rooms - -Consider the most basic room in your game. - - - Is a simple description enough or should the description be able to change (such as with time, by -light conditions, weather or season)? - - Should the room have different statuses? Can it have smells, sounds? Can it be affected by -dramatic weather, fire or magical effects? If so, how would this affect things in the room? Or are -these things something admins/game masters should handle manually? - - Can objects be hidden in the room? Can a person hide in the room? How does the room display this? - - etc. - -### Objects - -Consider the most basic (non-player-controlled) object in your game. - -- How numerous are your objects? Do you want large loot-lists or are objects just role playing props -created on demand? -- Does the game use money? If so, is each coin a separate object or do you just store a bank account -value? -- What about multiple identical objects? Do they form stacks and how are those stacks handled in -that case? -- Does an object have weight or volume (so you cannot carry an infinite amount of them)? -- Can objects be broken? If so, does it have a health value? Is burning it causing the same damage -as smashing it? Can it be repaired? -- Is a weapon a specific type of object or are you supposed to be able to fight with a chair too? -Can you fight with a flower or piece of paper as well? -- NPCs/mobs are also objects. Should they just stand around or should they have some sort of AI? -- Are NPCs/mobs differet entities? How is an Orc different from a Kobold, in code - are they the -same object with different names or completely different types of objects, with custom code? -- Should there be NPCs giving quests? If so, how would you track quest status and what happens when -multiple players try to do the same quest? Do you use instances or some other mechanism? -- etc. - -### Characters - -These are the objects controlled directly by Players. - -- Can players have more than one Character active at a time or are they allowed to multi-play? -- How does a Player create their Character? A Character-creation screen? Answering questions? -Filling in a form? -- Do you want to use classes (like "Thief", "Warrior" etc) or some other system, like Skill-based? -- How do you implement different "classes" or "races"? Are they separate types of objects or do you -simply load different stats on a basic object depending on what the Player wants? -- If a Character can hide in a room, what skill will decide if they are detected? -- What skill allows a Character to wield a weapon and hit? Do they need a special skill to wield a -chair rather than a sword? -- Does a Character need a Strength attribute to tell how much they can carry or which objects they -can smash? -- What does the skill tree look like? Can a Character gain experience to improve? By killing -enemies? Solving quests? By roleplaying? -- etc. - -A MUD's a lot more involved than you would think and these things hang together in a complex web. It -can easily become overwhelming and it's tempting to want *all* functionality right out of the door. -Try to identify the basic things that "make" your game and focus *only* on them for your first -release. Make a list. Keep future expansions in mind but limit yourself. - -## Coding (step 2) - -This is the actual work of creating the "game" part of your game. Many "game-designer" types tend to -gloss over this bit and jump directly to **World Building**. Vice versa, many "game-coder" types -tend to jump directly to this part without doing the **Planning** first. Neither way is good and -*will* lead to you having to redo all your hard work at least once, probably more. - -Evennia's [Developer Central](./Developer-Central.md) tries to help you with this bit of development. We -also have a slew of [Tutorials](./Tutorials.md) with worked examples. Evennia tries hard to make this -part easier for you, but there is no way around the fact that if you want anything but a very basic -Talker-type game you *will* have to bite the bullet and code your game (or find a coder willing to -do it for you). - -Even if you won't code anything yourself, as a designer you need to at least understand the basic -paradigms of Evennia, such as [Objects](./Objects.md), [Commands](./Commands.md) and [Scripts](./Scripts.md) and -how they hang together. We recommend you go through the [Tutorial World](Tutorial-World- -Introduction) in detail (as well as glancing at its code) to get at least a feel for what is -involved behind the scenes. You could also look through the tutorial for [building a game from -scratch](./Tutorial-for-basic-MUSH-like-game.md). - -During Coding you look back at the things you wanted during the **Planning** phase and try to -implement them. Don't be shy to update your plans if you find things easier/harder than you thought. -The earlier you revise problems, the easier they will be to fix. - -A good idea is to host your code online (publicly or privately) using version control. Not only will -this make it easy for multiple coders to collaborate (and have a bug-tracker etc), it also means -your work is backed up at all times. The [Version Control](./Version-Control.md) tutorial has -instructions for setting up a sane developer environment with proper version control. - -### "Tech Demo" Building - -This is an integral part of your Coding. It might seem obvious to experienced coders, but it cannot -be emphasized enough that you should *test things on a small scale* before putting your untested -code into a large game-world. The earlier you test, the easier and cheaper it will be to fix bugs -and even rework things that didn't work out the way you thought they would. You might even have to -go back to the **Planning** phase if your ideas can't handle their meet with reality. - -This means building singular in-game examples. Make one room and one object of each important type -and test so they work correctly in isolation. Then add more if they are supposed to interact with -each other in some way. Build a small series of rooms to test how mobs move around ... and so on. In -short, a test-bed for your growing code. It should be done gradually until you have a fully -functioning (if not guaranteed bug-free) miniature tech demo that shows *all* the features you want -in the first release of your game. There does not need to be any game play or even a theme to your -tests, this is only for you and your co-coders to see. The more testing you do on this small scale, -the less headaches you will have in the next phase. - -## World Building (step 3) - -Up until this point we've only had a few tech-demo objects in the database. This step is the act of -populating the database with a larger, thematic world. Too many would-be developers jump to this -stage too soon (skipping the **Coding** or even **Planning** stages). What if the rooms you build -now doesn't include all the nice weather messages the code grows to support? Or the way you store -data changes under the hood? Your building work would at best require some rework and at worst you -would have to redo the whole thing. And whereas Evennia's typeclass system does allow you to edit -the properties of existing objects, some hooks are only called at object creation ... Suffice to -say you are in for a *lot* of unnecessary work if you build stuff en masse without having the -underlying code systems in some reasonable shape first. - -So before starting to build, the "game" bit (**Coding** + **Testing**) should be more or less -**complete**, *at least to the level of your initial release*. - -Before starting to build, you should also plan ahead again. Make sure it is clear to yourself and -your eventual builders just which parts of the world you want for your initial release. Establish -for everyone which style, quality and level of detail you expect. Your goal should *not* be to -complete your entire world in one go. You want just enough to make the game's "feel" come across. -You want a minimal but functioning world where the intended game play can be tested and roughly -balanced. You can always add new areas later. - -During building you get free and extensive testing of whatever custom build commands and systems you -have made at this point. Since Building often involves different people than those Coding, you also -get a chance to hear if some things are hard to understand or non-intuitive. Make sure to respond -to this feedback. - - -## Alpha Release - -As mentioned, don't hold onto your world more than necessary. *Get it out there* with a huge *Alpha* -flag and let people try it! Call upon your alpha-players to try everything - they *will* find ways -to break your game in ways that you never could have imagined. In Alpha you might be best off to -focus on inviting friends and maybe other MUD developers, people who you can pester to give proper -feedback and bug reports (there *will* be bugs, there is no way around it). Follow the quick -instructions for [Online Setup](./Online-Setup.md) to make your game visible online. If you hadn't -already, make sure to put up your game on the [Evennia game index](http://games.evennia.com/) so -people know it's in the works (actually, even pre-alpha games are allowed in the index so don't be -shy)! - -## Beta Release/Perpetual Beta - -Once things stabilize in Alpha you can move to *Beta* and let more people in. Many MUDs are in -[perpetual beta](http://en.wikipedia.org/wiki/Perpetual_beta), meaning they are never considered -"finished", but just repeat the cycle of Planning, Coding, Testing and Building over and over as new -features get implemented or Players come with suggestions. As the game designer it is now up to you -to gradually perfect your vision. - -## Congratulate yourself! - -You are worthy of a celebration since at this point you have joined the small, exclusive crowd who -have made their dream game a reality! diff --git a/docs/0.9.5/_sources/Gametime-Tutorial.md.txt b/docs/0.9.5/_sources/Gametime-Tutorial.md.txt deleted file mode 100644 index eb10504650..0000000000 --- a/docs/0.9.5/_sources/Gametime-Tutorial.md.txt +++ /dev/null @@ -1,302 +0,0 @@ -# Gametime Tutorial - - -A lot of games use a separate time system we refer to as *game time*. This runs in parallel to what -we usually think of as *real time*. The game time might run at a different speed, use different -names for its time units or might even use a completely custom calendar. You don't need to rely on a -game time system at all. But if you do, Evennia offers basic tools to handle these various -situations. This tutorial will walk you through these features. - -### A game time with a standard calendar - -Many games let their in-game time run faster or slower than real time, but still use our normal -real-world calendar. This is common both for games set in present day as well as for games in -historical or futuristic settings. Using a standard calendar has some advantages: - -- Handling repetitive actions is much easier, since converting from the real time experience to the -in-game perceived one is easy. -- The intricacies of the real world calendar, with leap years and months of different length etc are -automatically handled by the system. - -Evennia's game time features assume a standard calendar (see the relevant section below for a custom -calendar). - -#### Setting up game time for a standard calendar - -All is done through the settings. Here are the settings you should use if you want a game time with -a standard calendar: - -```python -# in a file settings.py in mygame/server/conf -# The time factor dictates if the game world runs faster (timefactor>1) -# or slower (timefactor<1) than the real world. -TIME_FACTOR = 2.0 - -# The starting point of your game time (the epoch), in seconds. -# In Python a value of 0 means Jan 1 1970 (use negatives for earlier -# start date). This will affect the returns from the utils.gametime -# module. -TIME_GAME_EPOCH = None -``` - -By default, the game time runs twice as fast as the real time. You can set the time factor to be 1 -(the game time would run exactly at the same speed than the real time) or lower (the game time will -be slower than the real time). Most games choose to have the game time spinning faster (you will -find some games that have a time factor of 60, meaning the game time runs sixty times as fast as the -real time, a minute in real time would be an hour in game time). - -The epoch is a slightly more complex setting. It should contain a number of seconds that would -indicate the time your game started. As indicated, an epoch of 0 would mean January 1st, 1970. If -you want to set your time in the future, you just need to find the starting point in seconds. There -are several ways to do this in Python, this method will show you how to do it in local time: - -```python -# We're looking for the number of seconds representing -# January 1st, 2020 -from datetime import datetime -import time -start = datetime(2020, 1, 1) -time.mktime(start.timetuple()) -``` - -This should return a huge number - the number of seconds since Jan 1 1970. Copy that directly into -your settings (editing `server/conf/settings.py`): - -```python -# in a file settings.py in mygame/server/conf -TIME_GAME_EPOCH = 1577865600 -``` - -Reload the game with `@reload`, and then use the `@time` command. You should see something like -this: - -``` -+----------------------------+-------------------------------------+ -| Server time | | -+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ -| Current uptime | 20 seconds | -| Total runtime | 1 day, 1 hour, 55 minutes | -| First start | 2017-02-12 15:47:50.565000 | -| Current time | 2017-02-13 17:43:10.760000 | -+----------------------------+-------------------------------------+ -| In-Game time | Real time x 2 | -+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ -| Epoch (from settings) | 2020-01-01 00:00:00 | -| Total time passed: | 1 day, 17 hours, 34 minutes | -| Current time | 2020-01-02 17:34:55.430000 | -+----------------------------+-------------------------------------+ -``` - -The line that is most relevant here is the game time epoch. You see it shown at 2020-01-01. From -this point forward, the game time keeps increasing. If you keep typing `@time`, you'll see the game -time updated correctly... and going (by default) twice as fast as the real time. - -#### Time-related events - -The `gametime` utility also has a way to schedule game-related events, taking into account your game -time, and assuming a standard calendar (see below for the same feature with a custom calendar). For -instance, it can be used to have a specific message every (in-game) day at 6:00 AM showing how the -sun rises. - -The function `schedule()` should be used here. It will create a [script](./Scripts.md) with some -additional features to make sure the script is always executed when the game time matches the given -parameters. - -The `schedule` function takes the following arguments: - -- The *callback*, a function to be called when time is up. -- The keyword `repeat` (`False` by default) to indicate whether this function should be called -repeatedly. -- Additional keyword arguments `sec`, `min`, `hour`, `day`, `month` and `year` to describe the time -to schedule. If the parameter isn't given, it assumes the current time value of this specific unit. - -Here is a short example for making the sun rise every day: - -```python -# in a file ingame_time.py in mygame/world/ - -from evennia.utils import gametime -from typeclasses.rooms import Room - -def at_sunrise(): - """When the sun rises, display a message in every room.""" - # Browse all rooms - for room in Room.objects.all(): - room.msg_contents("The sun rises from the eastern horizon.") - -def start_sunrise_event(): - """Schedule an sunrise event to happen every day at 6 AM.""" - script = gametime.schedule(at_sunrise, repeat=True, hour=6, min=0, sec=0) - script.key = "at sunrise" -``` - -If you want to test this function, you can easily do something like: - -``` -@py from world import ingame_time; ingame_time.start_sunrise_event() -``` - -The script will be created silently. The `at_sunrise` function will now be called every in-game day -at 6 AM. You can use the `@scripts` command to see it. You could stop it using `@scripts/stop`. If -we hadn't set `repeat` the sun would only have risen once and then never again. - -We used the `@py` command here: nothing prevents you from adding the system into your game code. -Remember to be careful not to add each event at startup, however, otherwise there will be a lot of -overlapping events scheduled when the sun rises. - -The `schedule` function when using `repeat` set to `True` works with the higher, non-specified unit. -In our example, we have specified hour, minute and second. The higher unit we haven't specified is -day: `schedule` assumes we mean "run the callback every day at the specified time". Therefore, you -can have an event that runs every hour at HH:30, or every month on the 3rd day. - -> A word of caution for repeated scripts on a monthly or yearly basis: due to the variations in the -real-life calendar you need to be careful when scheduling events for the end of the month or year. -For example, if you set a script to run every month on the 31st it will run in January but find no -such day in February, April etc. Similarly, leap years may change the number of days in the year. - -### A game time with a custom calendar - -Using a custom calendar to handle game time is sometimes needed if you want to place your game in a -fictional universe. For instance you may want to create the Shire calendar which Tolkien described -having 12 months, each which 30 days. That would give only 360 days per year (presumably hobbits -weren't really fond of the hassle of following the astronomical calendar). Another example would be -creating a planet in a different solar system with, say, days 29 hours long and months of only 18 -days. - -Evennia handles custom calendars through an optional *contrib* module, called `custom_gametime`. -Contrary to the normal `gametime` module described above it is not active by default. - -#### Setting up the custom calendar - -In our first example of the Shire calendar, used by hobbits in books by Tolkien, we don't really -need the notion of weeks... but we need the notion of months having 30 days, not 28. - -The custom calendar is defined by adding the `TIME_UNITS` setting to your settings file. It's a -dictionary containing as keys the name of the units, and as value the number of seconds (the -smallest unit for us) in this unit. Its keys must be picked among the following: "sec", "min", -"hour", "day", "week", "month" and "year" but you don't have to include them all. Here is the -configuration for the Shire calendar: - -```python -# in a file settings.py in mygame/server/conf -TIME_UNITS = {"sec": 1, - "min": 60, - "hour": 60 * 60, - "day": 60 * 60 * 24, - "month": 60 * 60 * 24 * 30, - "year": 60 * 60 * 24 * 30 * 12 } -``` - -We give each unit we want as keys. Values represent the number of seconds in that unit. Hour is -set to 60 * 60 (that is, 3600 seconds per hour). Notice that we don't specify the week unit in this -configuration: instead, we skip from days to months directly. - -In order for this setting to work properly, remember all units have to be multiples of the previous -units. If you create "day", it needs to be multiple of hours, for instance. - -So for our example, our settings may look like this: - -```python -# in a file settings.py in mygame/server/conf -# Time factor -TIME_FACTOR = 4 - -# Game time epoch -TIME_GAME_EPOCH = 0 - -# Units -TIME_UNITS = { - "sec": 1, - "min": 60, - "hour": 60 * 60, - "day": 60 * 60 * 24, - "month": 60 * 60 * 24 * 30, - "year": 60 * 60 * 24 * 30 * 12, -} -``` - -Notice we have set a time epoch of 0. Using a custom calendar, we will come up with a nice display -of time on our own. In our case the game time starts at year 0, month 0, day 0, and at midnight. - -Note that while we use "month", "week" etc in the settings, your game may not use those terms in- -game, instead referring to them as "cycles", "moons", "sand falls" etc. This is just a matter of you -displaying them differently. See next section. - -#### A command to display the current game time - -As pointed out earlier, the `@time` command is meant to be used with a standard calendar, not a -custom one. We can easily create a new command though. We'll call it `time`, as is often the case -on other MU*. Here's an example of how we could write it (for the example, you can create a file -`showtime.py` in your `commands` directory and paste this code in it): - -```python -# in a file mygame/commands/gametime.py - -from evennia.contrib import custom_gametime - -from commands.command import Command - -class CmdTime(Command): - - """ - Display the time. - - Syntax: - time - - """ - - key = "time" - locks = "cmd:all()" - - def func(self): - """Execute the time command.""" - # Get the absolute game time - year, month, day, hour, min, sec = custom_gametime.custom_gametime(absolute=True) - string = "We are in year {year}, day {day}, month {month}." - string += "\nIt's {hour:02}:{min:02}:{sec:02}." - self.msg(string.format(year=year, month=month, day=day, - hour=hour, min=min, sec=sec)) -``` - -Don't forget to add it in your CharacterCmdSet to see this command: - -```python -# in mygame/commands/default_cmdset.py - -from commands.gametime import CmdTime # <-- Add - -# ... - -class CharacterCmdSet(default_cmds.CharacterCmdSet): - """ - The `CharacterCmdSet` contains general in-game commands like `look`, - `get`, etc available on in-game Character objects. It is merged with - the `AccountCmdSet` when an Account puppets a Character. - """ - key = "DefaultCharacter" - - def at_cmdset_creation(self): - """ - Populates the cmdset - """ - super().at_cmdset_creation() - # ... - self.add(CmdTime()) # <- Add -``` - -Reload your game with the `@reload` command. You should now see the `time` command. If you enter -it, you might see something like: - - We are in year 0, day 0, month 0. - It's 00:52:17. - -You could display it a bit more prettily with names for months and perhaps even days, if you want. -And if "months" are called "moons" in your game, this is where you'd add that. - -#### Time-related events in custom gametime - -The `custom_gametime` module also has a way to schedule game-related events, taking into account -your game time (and your custom calendar). It can be used to have a specific message every day at -6:00 AM, to show the sun rises, for instance. The `custom_gametime.schedule` function works in the -same way as described for the default one above. diff --git a/docs/0.9.5/_sources/Getting-Started.md.txt b/docs/0.9.5/_sources/Getting-Started.md.txt deleted file mode 100644 index bcbf49de24..0000000000 --- a/docs/0.9.5/_sources/Getting-Started.md.txt +++ /dev/null @@ -1,542 +0,0 @@ -# Getting Started - - -This will help you download, install and start Evennia for the first time. - -> Note: You don't need to make anything visible to the 'net in order to run and -> test out Evennia. Apart from downloading and updating you don't even need an -> internet connection until you feel ready to share your game with the world. - -- [Quick Start](./Getting-Started.md#quick-start) -- [Requirements](./Getting-Started.md#requirements) -- [Linux Install](./Getting-Started.md#linux-install) -- [Mac Install](./Getting-Started.md#mac-install) -- [Windows Install](./Getting-Started.md#windows-install) -- [Running in Docker](./Running-Evennia-in-Docker.md) -- [Where to Go Next](./Getting-Started.md#where-to-go-next) -- [Troubleshooting](./Getting-Started.md#troubleshooting) -- [Glossary of terms](./Glossary.md) - -## Quick Start - -For the impatient. If you have trouble with a step, you should jump on to the -more detailed instructions for your platform. - -1. Install Python, GIT and python-virtualenv. Start a Console/Terminal. -2. `cd` to some place you want to do your development (like a folder - `/home/anna/muddev/` on Linux or a folder in your personal user directory on Windows). -3. `git clone https://github.com/evennia/evennia.git` -4. `virtualenv evenv` -5. `source evenv/bin/activate` (Linux, Mac), `evenv\Scripts\activate` (Windows) -6. `pip install -e evennia` -7. `evennia --init mygame` -8. `cd mygame` -9. `evennia migrate` -10. `evennia start` (make sure to make a superuser when asked) -Evennia should now be running and you can connect to it by pointing a web browser to -`http://localhost:4001` or a MUD telnet client to `localhost:4000` (use `127.0.0.1` if your OS does -not recognize `localhost`). - -We also release [Docker images](./Running-Evennia-in-Docker.md) -based on `master` and `develop` branches. - -## Requirements - -Any system that supports Python3.7+ should work. We'll describe how to install -everything in the following sections. -- Linux/Unix -- Windows (Vista, Win7, Win8, Win10) -- Mac OSX (>=10.5 recommended) - -- [Python](http://www.python.org) (v3.7, 3.8 or 3.9) - - [virtualenv](http://pypi.python.org/pypi/virtualenv) for making isolated - Python environments. Installed with `pip install virtualenv`. - -- [GIT](http://git-scm.com/) - version control software for getting and -updating Evennia itself - Mac users can use the -[git-osx-installer](http://code.google.com/p/git-osx-installer/) or the -[MacPorts version](http://git-scm.com/book/en/Getting-Started-Installing-Git#Installing-on-Mac). -- [Twisted](http://twistedmatrix.com) (v21.0+) - - [ZopeInterface](http://www.zope.org/Products/ZopeInterface) (v3.0+) - usually included in -Twisted packages - - Linux/Mac users may need the `gcc` and `python-dev` packages or equivalent. - - Windows users need [MS Visual C++](https://aka.ms/vs/16/release/vs_buildtools.exe) and *maybe* -[pypiwin32](https://pypi.python.org/pypi/pypiwin32). -- [Django](http://www.djangoproject.com) (v3.2.x), be warned that latest dev - version is usually untested with Evennia) - -## Linux Install - -If you run into any issues during the installation and first start, please -check out [Linux Troubleshooting](./Getting-Started.md#linux-troubleshooting). - -For Debian-derived systems (like Ubuntu, Mint etc), start a terminal and -install the [dependencies](./Getting-Started.md#requirements): - -``` -sudo apt-get update -sudo apt-get install python3 python3-pip python3-dev python3-setuptools python3-git -python3-virtualenv gcc - -# If you are using an Ubuntu version that defaults to Python3, like 18.04+, use this instead: -sudo apt-get update -sudo apt-get install python3.7 python3-pip python3.7-dev python3-setuptools virtualenv gcc - -``` -Note that, the default Python version for your distribution may still not be Python3.7 after this. -This is ok - we'll specify exactly which Python to use later. -You should make sure to *not* be `root` after this step, running as `root` is a -security risk. Now create a folder where you want to do all your Evennia -development: - -``` -mkdir muddev -cd muddev -``` - -Next we fetch Evennia itself: - -``` -git clone https://github.com/evennia/evennia.git -``` -A new folder `evennia` will appear containing the Evennia library. This only -contains the source code though, it is not *installed* yet. To isolate the -Evennia install and its dependencies from the rest of the system, it is good -Python practice to install into a _virtualenv_. If you are unsure about what a -virtualenv is and why it's useful, see the [Glossary entry on -virtualenv](./Glossary.md#virtualenv). - -Run `python -V` to see which version of Python your system defaults to. - -``` -# If your Linux defaults to Python3.7+: -virtualenv evenv - -# If your Linux defaults to Python2 or an older version -# of Python3, you must instead point to Python3.7+ explicitly: -virtualenv -p /usr/bin/python3.7 evenv -``` - -A new folder `evenv` will appear (we could have called it anything). This -folder will hold a self-contained setup of Python packages without interfering -with default Python packages on your system (or the Linux distro lagging behind -on Python package versions). It will also always use the right version of Python. -Activate the virtualenv: - -``` -source evenv/bin/activate -``` - -The text `(evenv)` should appear next to your prompt to show that the virtual -environment is active. - -> Remember that you need to activate the virtualenv like this *every time* you -> start a new terminal to get access to the Python packages (notably the -> important `evennia` program) we are about to install. - -Next, install Evennia into your active virtualenv. Make sure you are standing -at the top of your mud directory tree (so you see the `evennia/` and `evenv/` -folders) and run - -``` -pip install -e evennia -``` - -For more info about `pip`, see the [Glossary entry on pip](./Glossary.md#pip). If -install failed with any issues, see [Linux Troubleshooting](./Getting-Started.md#linux-troubleshooting). - -Next we'll start our new game, here called "mygame". This will create yet -another new folder where you will be creating your new game: - -``` -evennia --init mygame -``` - -Your final folder structure should look like this: -``` -./muddev - evenv/ - evennia/ - mygame/ -``` - -You can [configure Evennia](./Server-Conf.md#settings-file) extensively, for example -to use a [different database](./Choosing-An-SQL-Server.md). For now we'll just stick -to the defaults though. - -``` -cd mygame -evennia migrate # (this creates the database) -evennia start # (create a superuser when asked. Email is optional.) -``` - -> Server logs are found in `mygame/server/logs/`. To easily view server logs -> live in the terminal, use `evennia -l` (exit the log-view with Ctrl-C). - -Your game should now be running! Open a web browser at `http://localhost:4001` -or point a telnet client to `localhost:4000` and log in with the user you -created. Check out [where to go next](./Getting-Started.md#where-to-go-next). - - -## Mac Install - -The Evennia server is a terminal program. Open the terminal e.g. from -*Applications->Utilities->Terminal*. [Here is an introduction to the Mac -terminal](http://blog.teamtreehouse.com/introduction-to-the-mac-os-x-command-line) -if you are unsure how it works. If you run into any issues during the -installation, please check out [Mac Troubleshooting](./Getting-Started.md#mac-troubleshooting). - -* Python should already be installed but you must make sure it's a high enough version. -([This](http://docs.python-guide.org/en/latest/starting/install/osx/) discusses - how you may upgrade it). Remember that you need Python3.7, not Python2.7! -* GIT can be obtained with -[git-osx-installer](http://code.google.com/p/git-osx-installer/) or via -MacPorts [as described -here](http://git-scm.com/book/en/Getting-Started-Installing-Git#Installing-on-Mac). -* If you run into issues with installing `Twisted` later you may need to -install gcc and the Python headers. - -After this point you should not need `sudo` or any higher privileges to install anything. - -Now create a folder where you want to do all your Evennia development: - -``` -mkdir muddev -cd muddev -``` - -Next we fetch Evennia itself: - -``` -git clone https://github.com/evennia/evennia.git -``` - -A new folder `evennia` will appear containing the Evennia library. This only -contains the source code though, it is not *installed* yet. To isolate the -Evennia install and its dependencies from the rest of the system, it is good -Python practice to install into a _virtualenv_. If you are unsure about what a -virtualenv is and why it's useful, see the [Glossary entry on virtualenv](./Glossary.md#virtualenv). - -Run `python -V` to check which Python your system defaults to. - - -``` -# If your Mac defaults to Python3: -virtualenv evenv - -# If your Mac defaults to Python2 you need to specify the Python3.7 binary explicitly: -virtualenv -p /path/to/your/python3.7 evenv -``` - -A new folder `evenv` will appear (we could have called it anything). This -folder will hold a self-contained setup of Python packages without interfering -with default Python packages on your system. Activate the virtualenv: - -``` -source evenv/bin/activate -``` - -The text `(evenv)` should appear next to your prompt to show the virtual -environment is active. - -> Remember that you need to activate the virtualenv like this *every time* you -> start a new terminal to get access to the Python packages (notably the -> important `evennia` program) we are about to install. - -Next, install Evennia into your active virtualenv. Make sure you are standing -at the top of your mud directory tree (so you see the `evennia/` and `evenv/` -folders) and run - -``` -pip install --upgrade pip # Old pip versions may be an issue on Mac. -pip install --upgrade setuptools # Ditto concerning Mac issues. -pip install -e evennia -``` - -For more info about `pip`, see the [Glossary entry on pip](./Glossary.md#pip). If -install failed with any issues, see [Mac Troubleshooting](./Getting-Started.md#mac-troubleshooting). - -Next we'll start our new game. We'll call it "mygame" here. This creates a new -folder where you will be creating your new game: - -``` -evennia --init mygame -``` - -Your final folder structure should look like this: - -``` -./muddev - evenv/ - evennia/ - mygame/ -``` - -You can [configure Evennia](./Server-Conf.md#settings-file) extensively, for example -to use a [different database](./Choosing-An-SQL-Server.md). We'll go with the -defaults here. - -``` -cd mygame -evennia migrate # (this creates the database) -evennia start # (create a superuser when asked. Email is optional.) -``` - -> Server logs are found in `mygame/server/logs/`. To easily view server logs -> live in the terminal, use `evennia -l` (exit the log-view with Ctrl-C). - -Your game should now be running! Open a web browser at `http://localhost:4001` -or point a telnet client to `localhost:4000` and log in with the user you -created. Check out [where to go next](./Getting-Started.md#where-to-go-next). - - -## Windows Install - -If you run into any issues during the installation, please check out -[Windows Troubleshooting](./Getting-Started.md#windows-troubleshooting). - -> If you are running Windows10, consider using the Windows Subsystem for Linux -> ([WSL](https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux)) instead. -> You should then follow the Linux install instructions above. - -The Evennia server itself is a command line program. In the Windows launch -menu, start *All Programs -> Accessories -> command prompt* and you will get -the Windows command line interface. Here is [one of many tutorials on using the Windows command -line](http://www.bleepingcomputer.com/tutorials/windows-command-prompt-introduction/) -if you are unfamiliar with it. - -* Install Python [from the Python homepage](https://www.python.org/downloads/windows/). You will -need to be a -Windows Administrator to install packages. You want Python version **3.7.0** (latest verified -version), usually -the 64-bit version (although it doesn't matter too much). **When installing, make sure -to check-mark *all* install options, especially the one about making Python -available on the path (you may have to scroll to see it)**. This allows you to -just write `python` in any console without first finding where the `python` -program actually sits on your hard drive. -* You need to also get [GIT](http://git-scm.com/downloads) and install it. You -can use the default install options but when you get asked to "Adjust your PATH -environment", you should select the second option "Use Git from the Windows -Command Prompt", which gives you more freedom as to where you can use the -program. -* Finally you must install the [Microsoft Visual C++ compiler for -Python](https://aka.ms/vs/16/release/vs_buildtools.exe). Download and run the linked installer and -install the C++ tools. Keep all the defaults. Allow the install of the "Win10 SDK", even if you are -on Win7 (not tested on older Windows versions). If you later have issues with installing Evennia due -to a failure to build the "Twisted wheels", this is where you are missing things. -* You *may* need the [pypiwin32](https://pypi.python.org/pypi/pypiwin32) Python headers. Install -these only if you have issues. - -You can install Evennia wherever you want. `cd` to that location and create a -new folder for all your Evennia development (let's call it `muddev`). - -``` -mkdir muddev -cd muddev -``` - -> Hint: If `cd` isn't working you can use `pushd` instead to force the -> directory change. - -Next we fetch Evennia itself: - -``` -git clone https://github.com/evennia/evennia.git -``` - -A new folder `evennia` will appear containing the Evennia library. This only -contains the source code though, it is not *installed* yet. To isolate the -Evennia install and its dependencies from the rest of the system, it is good -Python practice to install into a _virtualenv_. If you are unsure about what a -virtualenv is and why it's useful, see the [Glossary entry on virtualenv](./Glossary.md#virtualenv). - -In your console, try `python -V` to see which version of Python your system -defaults to. - - -``` -pip install virtualenv - -# If your setup defaults to Python3.7: -virtualenv evenv - -# If your setup defaults to Python2, specify path to python3.exe explicitly: -virtualenv -p C:\Python37\python.exe evenv - -# If you get an infinite spooling response, press CTRL + C to interrupt and try using: -python -m venv evenv - -``` -A new folder `evenv` will appear (we could have called it anything). This -folder will hold a self-contained setup of Python packages without interfering -with default Python packages on your system. Activate the virtualenv: - -``` -# If you are using a standard command prompt, you can use the following: -evenv\scripts\activate.bat - -# If you are using a PS Shell, Git Bash, or other, you can use the following: -.\evenv\scripts\activate - -``` -The text `(evenv)` should appear next to your prompt to show the virtual -environment is active. - -> Remember that you need to activate the virtualenv like this *every time* you -> start a new console window if you want to get access to the Python packages -> (notably the important `evennia` program) we are about to install. - -Next, install Evennia into your active virtualenv. Make sure you are standing -at the top of your mud directory tree (so you see the `evennia` and `evenv` -folders when you use the `dir` command) and run - -``` -pip install -e evennia -``` -For more info about `pip`, see the [Glossary entry on pip](./Glossary.md#pip). If -the install failed with any issues, see [Windows Troubleshooting](./Getting-Started.md#windows- -troubleshooting). -Next we'll start our new game, we'll call it "mygame" here. This creates a new folder where you will -be -creating your new game: - -``` -evennia --init mygame -``` - -Your final folder structure should look like this: - -``` -path\to\muddev - evenv\ - evennia\ - mygame\ -``` - -You can [configure Evennia](./Server-Conf.md#settings-file) extensively, for example -to use a [different database](./Choosing-An-SQL-Server.md). We'll go with the -defaults here. - -``` -cd mygame -evennia migrate # (this creates the database) -evennia start # (create a superuser when asked. Email is optional.) -``` - -> Server logs are found in `mygame/server/logs/`. To easily view server logs -> live in the terminal, use `evennia -l` (exit the log-view with Ctrl-C). - -Your game should now be running! Open a web browser at `http://localhost:4001` -or point a telnet client to `localhost:4000` and log in with the user you -created. Check out [where to go next](./Getting-Started.md#where-to-go-next). - - -## Where to Go Next - -Welcome to Evennia! Your new game is fully functioning, but empty. If you just -logged in, stand in the `Limbo` room and run - - @batchcommand tutorial_world.build - -to build [Evennia's tutorial world](./Tutorial-World-Introduction.md) - it's a small solo quest to -explore. Only run the instructed `@batchcommand` once. You'll get a lot of text scrolling by as the -tutorial is built. Once done, the `tutorial` exit will have appeared out of Limbo - just write -`tutorial` to enter it. - -Once you get back to `Limbo` from the tutorial (if you get stuck in the tutorial quest you can do -`@tel #2` to jump to Limbo), a good idea is to learn how to [start, stop and reload](Start-Stop- -Reload) the Evennia server. You may also want to familiarize yourself with some [commonly used terms -in our Glossary](./Glossary.md). After that, why not experiment with [creating some new items and build -some new rooms](./Building-Quickstart.md) out from Limbo. - -From here on, you could move on to do one of our [introductory tutorials](./Tutorials.md) or simply dive -headlong into Evennia's comprehensive [manual](https://github.com/evennia/evennia/wiki). While -Evennia has no major game systems out of the box, we do supply a range of optional *contribs* that -you can use or borrow from. They range from dice rolling and alternative color schemes to barter and -combat systems. You can find the [growing list of contribs -here](https://github.com/evennia/evennia/blob/master/evennia/contrib/README.md). - -If you have any questions, you can always ask in [the developer -chat](http://webchat.freenode.net/?channels=evennia&uio=MT1mYWxzZSY5PXRydWUmMTE9MTk1JjEyPXRydWUbb) -`#evennia` on `irc.freenode.net` or by posting to the [Evennia -forums](https://groups.google.com/forum/#%21forum/evennia). You can also join the [Discord -Server](https://discord.gg/NecFePw). - -Finally, if you are itching to help out or support Evennia (awesome!) have an -issue to report or a feature to request, [see here](./How-To-Get-And-Give-Help.md). - -Enjoy your stay! - - -## Troubleshooting - -If you have issues with installing or starting Evennia for the first time, -check the section for your operating system below. If you have an issue not -covered here, [please report it](https://github.com/evennia/evennia/issues) -so it can be fixed or a workaround found! - -Remember, the server logs are in `mygame/server/logs/`. To easily view server logs in the terminal, -you can run `evennia -l`, or (in the future) start the server with `evennia start -l`. - -### Linux Troubleshooting - -- If you get an error when installing Evennia (especially with lines mentioning - failing to include `Python.h`) then try `sudo apt-get install python3-setuptools python3-dev`. - Once installed, run `pip install -e evennia` again. -- Under some not-updated Linux distributions you may run into errors with a - too-old `setuptools` or missing `functools`. If so, update your environment - with `pip install --upgrade pip wheel setuptools`. Then try `pip install -e evennia` again. -- If you get an `setup.py not found` error message while trying to `pip install`, make sure you are - in the right directory. You should be at the same level of the `evenv` directory, and the - `evennia` git repository. Note that there is an `evennia` directory inside of the repository too. -- One user reported a rare issue on Ubuntu 16 is an install error on installing Twisted; `Command -"python setup.py egg_info" failed with error code 1 in /tmp/pip-build-vnIFTg/twisted/` with errors -like `distutils.errors.DistutilsError: Could not find suitable distribution for -Requirement.parse('incremental>=16.10.1')`. This appears possible to solve by simply updating Ubuntu -with `sudo apt-get update && sudo apt-get dist-upgrade`. -- Users of Fedora (notably Fedora 24) has reported a `gcc` error saying the directory -`/usr/lib/rpm/redhat/redhat-hardened-cc1` is missing, despite `gcc` itself being installed. [The -confirmed work-around](https://gist.github.com/yograterol/99c8e123afecc828cb8c) seems to be to -install the `redhat-rpm-config` package with e.g. `sudo dnf install redhat-rpm-config`. -- Some users trying to set up a virtualenv on an NTFS filesystem find that it fails due to issues -with symlinks not being supported. Answer is to not use NTFS (seriously, why would you do that to -yourself?) - -### Mac Troubleshooting - -- Mac users have reported a critical `MemoryError` when trying to start Evennia on Mac with a Python -version below `2.7.12`. If you get this error, update to the latest XCode and Python2 version. -- Some Mac users have reported not being able to connect to `localhost` (i.e. your own computer). If -so, try to connect to `127.0.0.1` instead, which is the same thing. Use port 4000 from mud clients -and port 4001 from the web browser as usual. - -### Windows Troubleshooting - -- If you installed Python but the `python` command is not available (even in a new console), then -you might have missed installing Python on the path. In the Windows Python installer you get a list -of options for what to install. Most or all options are pre-checked except this one, and you may -even have to scroll down to see it. Reinstall Python and make sure it's checked. -- If your MUD client cannot connect to `localhost:4000`, try the equivalent `127.0.0.1:4000` -instead. Some MUD clients on Windows does not appear to understand the alias `localhost`. -- If you run `virtualenv evenv` and get a `'virtualenv' is not recognized as an internal or external -command, -operable program or batch file.` error, you can `mkdir evenv`, `cd evenv` and then `python -m -virtualenv .` as a workaround. -- Some Windows users get an error installing the Twisted 'wheel'. A wheel is a pre-compiled binary -package for Python. A common reason for this error is that you are using a 32-bit version of Python, -but Twisted has not yet uploaded the latest 32-bit wheel. Easiest way to fix this is to install a -slightly older Twisted version. So if, say, version `18.1` failed, install `18.0` manually with `pip -install twisted==18.0`. Alternatively you could try to get a 64-bit version of Python (uninstall the -32bit one). If so, you must then `deactivate` the virtualenv, delete the `evenv` folder and recreate -it anew (it will then use the new Python executable). -- If your server won't start, with no error messages (and no log files at all when starting from -scratch), try to start with `evennia ipstart` instead. If you then see an error about `system cannot -find the path specified`, it may be that the file `evennia/evennia/server/twistd.bat` has the wrong -path to the `twistd` executable. This file is auto-generated, so try to delete it and then run -`evennia start` to rebuild it and see if it works. If it still doesn't work you need to open it in a -text editor like Notepad. It's just one line containing the path to the `twistd.exe` executable as -determined by Evennia. If you installed Twisted in a non-standard location this might be wrong and -you should update the line to the real location. -- Some users have reported issues with Windows WSL and anti-virus software during Evennia -development. Timeout errors and the inability to run `evennia connections` may be due to your anti- -virus software interfering. Try disabling or changing your anti-virus software settings. diff --git a/docs/0.9.5/_sources/Glossary.md.txt b/docs/0.9.5/_sources/Glossary.md.txt deleted file mode 100644 index 6b74b4ce01..0000000000 --- a/docs/0.9.5/_sources/Glossary.md.txt +++ /dev/null @@ -1,381 +0,0 @@ -# Glossary - - -This explains common recurring terms used in the Evennia docs. It will be expanded as needed. - -- _[account](./Glossary.md#account)_ - the player's account on the game -- _[admin-site](./Glossary.md#admin-site)_ - the Django web page for manipulating the database -- _[attribute](./Glossary.md#attribute)_ - persistent, custom data stored on typeclasses -- _[channel](./Glossary.md#channel)_ - game communication channels -- _[character](./Glossary.md#character)_ - the player's avatar in the game, controlled from -_[account](./Glossary.md#account)_ -- _[core](./Glossary.md#core)_ - a term used for the code distributed with Evennia proper -- _[django](./Glossary.md#django)_ - web framework Evennia uses for database access and web integration -- _[field](./Glossary.md#field)_ - a _[typeclass](./Glossary.md#typeclass)_ property representing a database -column -- _[git](./Glossary.md#git)_ - the version-control system we use -- _[github](./Glossary.md#github)_ - the online hosting of our source code -- _[migrate](./Glossary.md#migrate)_ - updating the database schema -- _[multisession mode`](#multisession-mode)_ - a setting defining how users connect to Evennia -- _[object](./Glossary.md#object)_ - Python instance, general term or in-game -_[typeclass](./Glossary.md#typeclass)_ -- _[pip](./Glossary.md#pip)_ - the Python installer -- _player_ - the human connecting to the game with their client -- _[puppet](./Glossary.md#puppet)_ - when an [account](./Glossary.md#account) controls an in-game -[object](./Glossary.md#object) -- _[property](./Glossary.md#property)_ - a python property -- _evenv_ - see _[virtualenv](./Glossary.md#virtualenv)_ -- _[repository](./Glossary.md#repository)_ - a store of source code + source history -- _[script](./Glossary.md#script)_ - a building block for custom storage, systems and time-keepint -- _[session](./Glossary.md#session)_ - represents one client connection -- _[ticker](./Glossary.md#ticker)_ - Allows to run events on a steady 'tick' -- _[twisted](./Glossary.md#twisted)_ - networking engine responsible for Evennia's event loop and -communications -- _[typeclass](./Glossary.md#typeclass)_ - Evennia's database-connected Python class -- _upstream_ - see _[github](./Glossary.md#github)_ -- _[virtualenv](./Glossary.md#virtualenv)_ - a Python program and way to make an isolated Python install - - ---- - -### _account_ - -The term 'account' refers to the player's unique account on the game. It is -represented by the `Account` [typeclass](./Glossary.md#typeclass) and holds things like email, password, -configuration etc. - -When a player connects to the game, they connect to their account. The account has *no* -representation in the game world. Through their Account they can instead choose to -[puppet](./Glossary.md#puppet) one (or more, depending on game mode) [Characters](./Glossary.md#character) in -the game. - -In the default [multisession mode](./Sessions.md#multisession-mode) of Evennia, you immediately start -puppeting a Character with the same name as your Account when you log in - mimicking how older -servers used to work. - -### _admin-site_ - -This usually refers to [Django's](./Glossary.md#django) *Admin site* or database-administration web page -([link to Django docs](https://docs.djangoproject.com/en/2.1/ref/contrib/admin/)). The admin site is -an automatically generated web interface to the database (it can be customized extensively). It's -reachable from the `admin` link on the default Evennia website you get with your server. - -### _attribute_ - -The term _Attribute_ should not be confused with ([properties](./Glossary.md#property) or -[fields](./Glossary.md#field). The `Attribute` represents arbitrary pieces of data that can be attached -to any [typeclassed](./Glossary.md#typeclass) entity in Evennia. Attributes allows storing new persistent -data on typeclasses without changing their underlying database schemas. [Read more about Attributes -here](./Attributes.md). - -### _channel_ - -A _Channel_ refers to an in-game communication channel. It's an entity that people subscribe to and -which re-distributes messages between all subscribers. Such subscribers default to being -[Accounts](./Glossary.md#account), for out-of-game communication but could also be [Objects (usually -Characters)](./Glossary.md#character) if one wanted to adopt Channels for things like in-game walkie- -talkies or phone systems. It is represented by the `Channel` typeclass. [You can read more about the -comm system here](./Communications.md#channels). - -### _character_ - -The _Character_ is the term we use for the default avatar being [puppeted](./Glossary.md#puppet) by the -[account](./Glossary.md#account) in the game world. It is represented by the `Character` typeclass (which -is a child of [Object](./Glossary.md#object)). Many developers use children of this class to represent -monsters and other NPCs. You can [read more about it here](./Objects.md#subclasses-of-object). - -### _django_ - -[Django](https://www.djangoproject.com/) is a professional and very popular Python web framework, -similar to Rails for the Ruby language. It is one of Evennia's central library dependencies (the -other one is [Twisted](./Glossary.md#twisted)). Evennia uses Django for two main things - to map all -database operations to Python and for structuring our web site. - -Through Django, we can work with any supported database (SQlite3, Postgres, MySQL ...) using generic -Python instead of database-specific SQL: A database table is represented in Django as a Python class -(called a *model*). An Python instance of such a class represents a row in that table. - -There is usually no need to know the details of Django's database handling in order to use Evennia - -it will handle most of the complexity for you under the hood using what we call -[typeclasses](./Glossary.md#typeclass). But should you need the power of Django you can always get it. -Most commonly people want to use "raw" Django when doing more advanced/custom database queries than -offered by Evennia's [default search functions](./Tutorial-Searching-For-Objects.md). One will then need -to read about Django's _querysets_. Querysets are Python method calls on a special form that lets -you build complex queries. They get converted into optimized SQL queries under the hood, suitable -for your current database. [Here is our tutorial/explanation of Django queries](Tutorial-Searching- -For-Objects#queries-in-django). - -> By the way, Django (and Evennia) does allow you to fall through and send raw SQL if you really -want to. It's highly unlikely to be needed though; the Django database abstraction is very, very -powerful. - -The other aspect where Evennia uses Django is for web integration. On one end Django gives an -infrastructure for wiring Python functions (called *views*) to URLs: the view/function is called -when a user goes that URL in their browser, enters data into a form etc. The return is the web page -to show. Django also offers templating with features such as being able to add special markers in -HTML where it will insert the values of Python variables on the fly (like showing the current player -count on the web page). [Here is one of our tutorials on wiring up such a web page](Add-a-simple- -new-web-page). Django also comes with the [admin site](./Glossary.md#admin-site), which automatically -maps the database into a form accessible from a web browser. - -### _contrib_ - -Contribs are optional and often more game-specific code-snippets contributed by the Evennia community. -They are distributed with Evennia in the `contrib/` folder. - -### _core_ - -This term is sometimes used to represent the main Evennia library code suite, *excluding* its -[contrib](./Glossary.md#contrib) directory. It can sometimes come up in code reviews, such as - -> Evennia is game-agnostic but this feature is for a particular game genre. So it does not belong in -core. Better make it a contrib. - -### _field_ - -A _field_ or _database field_ in Evennia refers to a [property](./Glossary.md#property) on a -[typeclass](./Glossary.md#typeclass) directly linked to an underlying database column. Only a few fixed -properties per typeclass are database fields but they are often tied to the core functionality of -that base typeclass (for example [Objects](./Glossary.md#object) store its location as a field). In all -other cases, [attributes](./Glossary.md#attribute) are used to add new persistent data to the typeclass. -[Read more about typeclass properties here](./Typeclasses.md#about-typeclass-properties). - -### _git_ - -[Git](https://git-scm.com/) is a [version control](https://en.wikipedia.org/wiki/Version_control) -tool. It allows us to track the development of the Evennia code by dividing it into units called -*commits*. A 'commit' is sort of a save-spot - you save the current state of your code and can then -come back to it later if later changes caused problems. By tracking commits we know what 'version' -of the code we are currently using. - -Evennia's source code + its source history is jointly called a [repository](./Glossary.md#repository). -This is centrally stored at our online home on [GitHub](./Glossary.md#github). Everyone using or -developing Evennia makes a 'clone' of this repository to their own computer - everyone -automatically gets everything that is online, including all the code history. - -> Don't confuse Git and [GitHub](./Glossary.md#github). The former is the version control system. The -latter is a website (run by a company) that allows you to upload source code controlled by Git for -others to see (among other things). - -Git allows multiple users from around the world to efficiently collaborate on Evennia's code: People -can make local commits on their cloned code. The commits they do can then be uploaded to GitHub and -reviewed by the Evennia lead devs - and if the changes look ok they can be safely *merged* into the -central Evennia code - and everyone can *pull* those changes to update their local copies. - -Developers using Evennia often uses Git on their own games in the same way - to track their changes -and to help collaboration with team mates. This is done completely independently of Evennia's Git -usage. - -Common usage (for non-Evennia developers): -- `git clone ` - clone an online repository to your computer. This is what you do when -you 'download' Evennia. You only need to do this once. -- `git pull` (inside local copy of repository) - sync your local repository with what is online. - -> Full usage of Git is way beyond the scope of this glossary. See [Tutorial - version -control](./Version-Control.md) for more info and links to the Git documentation. - -### _migrate_ - -This term is used for upgrading the database structure (it's _schema_ )to a new version. Most often -this is due to Evennia's [upstream](./Glossary.md#github) schema changing. When that happens you need to -migrate that schema to the new version as well. Once you have used [git](./Glossary.md#git) to pull the -latest changes, just `cd` into your game dir and run - - evennia migrate - -That should be it (see [virtualenv](./Glossary.md#virtualenv) if you get a warning that the `evennia` -command is not available). See also [Updating your game](./Updating-Your-Game.md) for more details. - -> Technically, migrations are shipped as little Python snippets of code that explains which database -actions must be taken to upgrade from one version of the schema to the next. When you run the -command above, those snippets are run in sequence. - -### _multisession mode_ - -This term refers to the `MULTISESSION_MODE` setting, which has a value of 0 to 3. The mode alters -how players can connect to the game, such as how many Sessions a player can start with one account -and how many Characters they can control at the same time. It is [described in detail -here](./Sessions.md#multisession-mode). - -### _github_ - -[Github](https://github.com/evennia) is where Evennia's source code and documentation is hosted. -This online [repository](./Glossary.md#repository) of code we also sometimes refer to as _upstream_. - -GitHub is a business, offering free hosting to Open-source projects like Evennia. Despite the -similarity in name, don't confuse GitHub the website with [Git](./Glossary.md#git), the versioning -system. Github hosts Git [repositories](./Glossary.md#repository) online and helps with collaboration and -infrastructure. Git itself is a separate project. - -### _object_ - -In general Python (and other [object-oriented languages](https://en.wikipedia.org/wiki/Object-oriented_programming)), an `object` is what we call the instance of a *class*. But one of Evennia's -core [typeclasses](./Glossary.md#typeclass) is also called "Object". To separate these in the docs we -try to use `object` to refer to the general term and capitalized `Object` when we refer to the -typeclass. - -The `Object` is a typeclass that represents all *in-game* entities, including -[Characters](./Glossary.md#character), rooms, trees, weapons etc. [Read more about Objects -here](./Objects.md). - -### _pip_ - -_[pip](https://pypi.org/project/pip/)_ comes with Python and is the main tool for installing third- -party Python packages from the web. Once a python package is installed you can do `import -` in your Python code. - -Common usage: -- `pip install ` - install the given package along with all its dependencies. -- `pip search ` - search Python's central package repository [PyPi](https://pypi.org/) for a -package of that name. -- `pip install --upgrade ` - upgrade a package you already have to the latest version. -- `pip install ==1.5` - install exactly a specific package version. -- `pip install ` - install a Python package you have downloaded earlier (or cloned using -git). -- `pip install -e ` - install a local package by just making a soft link to the folder. This -means that if the code in `` changes, the installed Python package is immediately updated. -If not using `-e`, one would need to run `pip install --upgrade ` every time to make the -changes available when you import this package into your code. Evennia is installed this way. - -For development, `pip` is usually used together with a [virtualenv](./Glossary.md#virtualenv) to install -all packages and dependencies needed for a project in one, isolated location on the hard drive. - -### _puppet_ - -An [account](./Glossary.md#account) can take control and "play as" any [Object](./Glossary.md#object). When -doing so, we call this _puppeting_, (like [puppeteering](https://en.wikipedia.org/wiki/Puppeteer)). -Normally the entity being puppeted is of the [Character](./Glossary.md#character) subclass but it does -not have to be. - -### _property_ - -A _property_ is a general term used for properties on any Python object. The term also sometimes -refers to the `property` built-in function of Python ([read more here](https://www.python-course.eu/python3_properties.php)). Note the distinction between properties, -[fields](./Glossary.md#field) and [Attributes](./Glossary.md#attribute). - -### _repository_ - -A _repository_ is a version control/[git](./Glossary.md#git) term. It represents a folder containing -source code plus its versioning history. - -> In Git's case, that history is stored in a hidden folder `.git`. If you ever feel the need to look -into this folder you probably already know enough Git to know why. - -The `evennia` folder you download from us with `git clone` is a repository. The code on -[GitHub](./Glossary.md#github) is often referred to as the 'online repository' (or the _upstream_ -repository). If you put your game dir under version control, that of course becomes a repository as -well. - -### _script_ - -When we refer to _Scripts_, we generally refer to the `Script` [typeclass](./Typeclasses.md). Scripts are -the mavericks of Evennia - they are like [Objects](./Glossary.md#object) but without any in-game -existence. They are useful as custom places to store data but also as building blocks in persistent -game systems. Since the can be initialized with timing capabilities they can also be used for long- -time persistent time keeping (for fast updates other types of timers may be better though). [Read -more about Scripts here](./Scripts.md) - -### _session_ - -A [Session](./Sessions.md) is a Python object representing a single client connection to the server. A -given human player could connect to the game from different clients and each would get a Session -(even if you did not allow them to actually log in and get access to an -[account](./Glossary.md#account)). - -Sessions are _not_ [typeclassed](./Glossary.md#typeclass) and has no database persistence. But since they -always exist (also when not logged in), they share some common functionality with typeclasses that -can be useful for certain game states. - -### _tag_ - -A [Tag](./Tags.md) is a simple label one can attach to one or more objects in the game. Tagging is a -powerful way to group entities and can also be used to indicate they have particular shared abilities. -Tags are shared between objects (unlike [Attributes](#attribute)). - -### _ticker_ - -The [Ticker handler](./TickerHandler.md) runs Evennia's optional 'ticker' system. In other engines, such -as [DIKU](https://en.wikipedia.org/wiki/DikuMUD), all game events are processed only at specific -intervals called 'ticks'. Evennia has no such technical limitation (events are processed whenever -needed) but using a fixed tick can still be useful for certain types of game systems, like combat. -Ticker Handler allows you to emulate any number of tick rates (not just one) and subscribe actions -to be called when those ticks come around. - -### _typeclass_ - -The [typeclass](./Typeclasses.md) is an Evennia-specific term. A typeclass allows developers to work with -database-persistent objects as if they were normal Python objects. It makes use of specific -[Django](./Glossary.md#django) features to link a Python class to a database table. Sometimes we refer to -such code entities as _being typeclassed_. - -Evennia's main typeclasses are [Account](./Glossary.md#account), [Object](./Glossary.md#object), -[Script](./Glossary.md#script) and [Channel](./Glossary.md#channel). Children of the base class (such as -[Character](./Glossary.md#character)) will use the same database table as the parent, but can have vastly -different Python capabilities (and persistent features through [Attributes](./Glossary.md#attribute) and -[Tags](./Glossary.md#tag). A typeclass can be coded and treated pretty much like any other Python class -except it must inherit (at any distance) from one of the base typeclasses. Also, creating a new -instance of a typeclass will add a new row to the database table to which it is linked. - -The [core](./Glossary.md#core) typeclasses in the Evennia library are all named `DefaultAccount`, -`DefaultObject` etc. When you initialize your [game dir] you automatically get empty children of -these, called `Account`, `Object` etc that you can start working with. - -### _twisted_ - -[Twisted](https://twistedmatrix.com/trac/) is a heavy-duty asynchronous networking engine. It is one -of Evennia's two major library dependencies (the other one is [Django](./Glossary.md#django)). Twisted is -what "runs" Evennia - it handles Evennia's event loop. Twisted also has the building blocks we need -to construct network protocols and communicate with the outside world; such as our MUD-custom -version of Telnet, Telnet+SSL, SSH, webclient-websockets etc. Twisted also runs our integrated web -server, serving the Django-based website for your game. - -### _virtualenv_ - -The standard [virtualenv](https://virtualenv.pypa.io/en/stable/) program comes with Python. It is -used to isolate all Python packages needed by a given Python project into one folder (we call that -folder `evenv` but it could be called anything). A package environment created this way is usually -referred to as "a virtualenv". If you ever try to run the `evennia` program and get an error saying -something like "the command 'evennia' is not available" - it's probably because your virtualenv is -not 'active' yet (see below). - -Usage: -- `virtualenv ` - initialize a new virtualenv `` in a new folder `` in the current -location. Called `evenv` in these docs. -- `virtualenv -p path/to/alternate/python_executable ` - create a virtualenv using another -Python version than default. -- `source /bin/activate`(linux/mac) - activate the virtualenv in ``. -- `\Scripts\activate` (windows) -- `deactivate` - turn off the currently activated virtualenv. - -A virtualenv is 'activated' only for the console/terminal it was started in, but it's safe to -activate the same virtualenv many times in different windows if you want. Once activated, all Python -packages now installed with [pip](./Glossary.md#pip) will install to `evenv` rather than to a global -location like `/usr/local/bin` or `C:\Program Files`. - -> Note that if you have root/admin access you *could* install Evennia globally just fine, without -using a virtualenv. It's strongly discouraged and considered bad practice though. Experienced Python -developers tend to rather create one new virtualenv per project they are working on, to keep the -varying installs cleanly separated from one another. - -When you execute Python code within this activated virtualenv, *only* those packages installed -within will be possible to `import` into your code. So if you installed a Python package globally on -your computer, you'll need to install it again in your virtualenv. - -> Virtualenvs *only* deal with Python programs/packages. Other programs on your computer couldn't -care less if your virtualenv is active or not. So you could use `git` without the virtualenv being -active, for example. - -When your virtualenv is active you should see your console/terminal prompt change to - - (evenv) ... - -... or whatever name you gave the virtualenv when you initialized it. - -> We sometimes say that we are "in" the virtualenv when it's active. But just to be clear - you -never have to actually `cd` into the `evenv` folder. You can activate it from anywhere and will -still be considered "in" the virtualenv wherever you go until you `deactivate` or close the -console/terminal. - -So, when do I *need* to activate my virtualenv? If the virtualenv is not active, none of the Python -packages/programs you installed in it will be available to you. So at a minimum, *it needs to be -activated whenever you want to use the `evennia` command* for any reason. diff --git a/docs/0.9.5/_sources/Grapevine.md.txt b/docs/0.9.5/_sources/Grapevine.md.txt deleted file mode 100644 index fb8ede4372..0000000000 --- a/docs/0.9.5/_sources/Grapevine.md.txt +++ /dev/null @@ -1,71 +0,0 @@ -# Grapevine - - -[Grapevine](http://grapevine.haus) is a new chat network for `MU*`*** games. By -connecting an in-game channel to the grapevine network, players on your game -can chat with players in other games, also non-Evennia ones. - -## Configuring Grapevine - -To use Grapevine, you first need the `pyopenssl` module. Install it into your -Evennia python environment with - - pip install pyopenssl - -To configure Grapevine, you'll need to activate it in your settings file. - -```python - GRAPEVINE_ENABLED = True -``` - -Next, register an account at https://grapevine.haus. When you have logged in, -go to your Settings/Profile and to the `Games` sub menu. Here you register your -new game by filling in its information. At the end of registration you are going -to get a `Client ID` and a `Client Secret`. These should not be shared. - -Open/create the file `mygame/server/conf/secret_settings.py` and add the following: - -```python - GRAPEVINE_CLIENT_ID = "" - GRAPEVINE_CLIENT_SECRET = "" -``` - -You can also customize the Grapevine channels you are allowed to connect to. This -is added to the `GRAPEVINE_CHANNELS` setting. You can see which channels are available -by going to the Grapevine online chat here: https://grapevine.haus/chat. - -Start/reload Evennia and log in as a privileged user. You should now have a new -command available: `@grapevine2chan`. This command is called like this: - - @grapevine2chan[/switches] = - -Here, the `evennia_channel` must be the name of an existing Evennia channel and -`grapevine_channel` one of the supported channels in `GRAPEVINE_CHANNELS`. - -> At the time of writing, the Grapevine network only has two channels: -> `testing` and `gossip`. Evennia defaults to allowing connecting to both. Use -> `testing` for trying your connection. - -## Setting up Grapevine, step by step - -You can connect Grapevine to any Evennia channel (so you could connect it to -the default *public* channel if you like), but for testing, let's set up a -new channel `gw`. - - @ccreate gw = This is connected to an gw channel! - -You will automatically join the new channel. - -Next we will create a connection to the Grapevine network. - - @grapevine2chan gw = gossip - -Evennia will now create a new connection and connect it to Grapevine. Connect -to https://grapevine.haus/chat to check. - - -Write something in the Evennia channel *gw* and check so a message appears in -the Grapevine chat. Write a reply in the chat and the grapevine bot should echo -it to your channel in-game. - -Your Evennia gamers can now chat with users on external Grapevine channels! diff --git a/docs/0.9.5/_sources/Guest-Logins.md.txt b/docs/0.9.5/_sources/Guest-Logins.md.txt deleted file mode 100644 index d1cf8cae21..0000000000 --- a/docs/0.9.5/_sources/Guest-Logins.md.txt +++ /dev/null @@ -1,29 +0,0 @@ -# Guest Logins - - -Evennia supports *guest logins* out of the box. A guest login is an anonymous, low-access account -and can be useful if you want users to have a chance to try out your game without committing to -creating a real account. - -Guest accounts are turned off by default. To activate, add this to your `game/settings.py` file: - - GUEST_ENABLED = True - -Henceforth users can use `connect guest` (in the default command set) to login with a guest account. -You may need to change your [Connection Screen](./Connection-Screen.md) to inform them of this -possibility. Guest accounts work differently from normal accounts - they are automatically *deleted* -whenever the user logs off or the server resets (but not during a reload). They are literally re- -usable throw-away accounts. - -You can add a few more variables to your `settings.py` file to customize your guests: - -- `BASE_GUEST_TYPECLASS` - the python-path to the default [typeclass](./Typeclasses.md) for guests. -Defaults to `"typeclasses.accounts.Guest"`. -- `PERMISSION_GUEST_DEFAULT` - [permission level](./Locks.md) for guest accounts. Defaults to `"Guests"`, -which is the lowest permission level in the hierarchy. -- `GUEST_START_LOCATION` - the `#dbref` to the starting location newly logged-in guests should -appear at. Defaults to `"#2` (Limbo). -- `GUEST_HOME` - guest home locations. Defaults to Limbo as well. -- `GUEST_LIST` - this is a list holding the possible guest names to use when entering the game. The -length of this list also sets how many guests may log in at the same time. By default this is a list -of nine names from `"Guest1"` to `"Guest9"`. diff --git a/docs/0.9.5/_sources/HAProxy-Config.md.txt b/docs/0.9.5/_sources/HAProxy-Config.md.txt deleted file mode 100644 index 7bdf1f99a5..0000000000 --- a/docs/0.9.5/_sources/HAProxy-Config.md.txt +++ /dev/null @@ -1,176 +0,0 @@ -# HAProxy Config (Optional) - -## Making Evennia, HTTPS and Secure Websockets play nicely together - -This we can do by installing a _proxy_ between Evennia and the outgoing ports of your server. -Essentially, -Evennia will think it's only running locally (on localhost, IP 127.0.0.1) - the proxy will -transparently -map that to the "real" outgoing ports and handle HTTPS/WSS for us. - -``` -Evennia <-> (inside-visible IP/ports) <-> Proxy <-> (outside-visible IP/ports) <-> Internet -``` - - -Here we will use [HAProxy](https://www.haproxy.org/), an open-source proxy that is easy to set up -and use. We will -also be using [LetsEncrypt](https://letsencrypt.org/getting-started/), especially the excellent -helper-program [Certbot](https://certbot.eff.org/instructions) which pretty much automates the whole -certificate setup process for us. - -Before starting you also need the following: - -- (optional) The host name of your game (like `myawesomegame.com`). This is something you must -previously have purchased from a _domain registrar_ and set up with DNS to point to the IP of your -server. -- If you don't have a domain name or haven't set it up yet, you must at least know the IP of your -server. Find this with `ifconfig` or similar from inside the server. If you use a hosting service -like DigitalOcean you can also find the droplet's IP address in the control panel. -- You must open port 80 in your firewall. This is used by Certbot below to auto-renew certificates. -So you can't really run another webserver alongside this setup without tweaking. -- You must open port 443 (HTTPS) in your firewall. -- You must open port 4002 (the default Websocket port) in your firewall. - - -## Getting certificates - -Certificates guarantee that you are you. Easiest is to get this with -[Letsencrypt](https://letsencrypt.org/getting-started/) and the -[Certbot](https://certbot.eff.org/instructions) program. Certbot has a lot of install instructions -for various operating systems. Here's for Debian/Ubuntu: - -``` -sudo apt install certbot -``` - -Make sure to stop Evennia and that no port-80 using service is running, then - -``` -sudo certbot certonly --standalone -``` - -You will get some questions you need to answer, such as an email to send certificate errors to and -the host name (or IP, supposedly) to use with this certificate. After this, the certificates will -end up in `/etc/letsencrypt/live//*pem` (example from Ubuntu). The critical files -for our purposes are `fullchain.pem` and `privkey.pem`. - -Certbot sets up a cron-job/systemd job to regularly renew the certificate. To check this works, try - -``` -sudo certbot renew --dry-run -``` - -The certificate is only valid for 3 months at a time, so make sure this test works (it requires port -80 to be open). Look up Certbot's page for more help. - -We are not quite done. HAProxy expects these two files to be _one_ file. - -``` -sudo cp /etc/letsencrypt/live//privkey.pem /etc/letsencrypt/live//.pem -sudo bash -c "cat /etc/letsencrypt/live//fullchain.pem >> -/etc/letsencrypt/live//.pem" -``` - -This will create a new `.pem` file by concatenating the two files together. The `yourhostname.pem` -file (or whatever you named it) is what we will use when the the HAProxy config file (below) asks -for "your-certificate.pem". - -## Installing and configuring HAProxy - -Installing HaProxy is usually as simple as: -``` -# Debian derivatives (Ubuntu, Mint etc) -sudo apt install haproxy - -# Redhat derivatives (dnf instead of yum for very recent Fedora distros) -sudo yum install haproxy - -``` - -Configuration of HAProxy is done in a single file. Put this wherever you like, for example in -your game dir; name it something like haproxy.conf. - -Here is an example tested on Centos7 and Ubuntu. Make sure to change the file to put in your own -values. - -``` -# base stuff to set up haproxy -global - log /dev/log local0 - chroot /var/lib/haproxy - maxconn 4000 - user haproxy - tune.ssl.default-dh-param 2048 - ## uncomment this when everything works - # daemon -defaults - mode http - option forwardfor - -# Evennia Specifics -listen evennia-https-website - bind : ssl no-sslv3 no-tlsv10 crt -/etc/letsencrypt/live//.pem - server localhost 127.0.0.1: - timeout client 10m - timeout server 10m - timeout connect 5m - -listen evennia-secure-websocket - bind : ssl no-sslv3 no-tlsv10 crt -/etc/letsencrypt/live//.pem - server localhost 127.0.0.1: - timeout client 10m - timeout server 10m - timeout connect 5m -``` - -## Putting it all together - -Get back to the Evennia game dir and edit mygame/server/conf/settings.py. Add: - -``` -WEBSERVER_INTERFACES = ['127.0.0.1'] -WEBSOCKET_CLIENT_INTERFACE = '127.0.0.1' -``` -and -``` -WEBSOCKET_CLIENT_URL="wss://fullhost.domain.name:4002/" -``` - -Make sure to reboot (stop + start) evennia completely: - -``` -evennia reboot -``` - - -Finally you start the proxy: - -``` -sudo haproxy -f /path/to/the/above/config_file.cfg -``` - -Make sure you can connect to your game from your browser and that you end up with an `https://` page -and can use the websocket webclient. - -Once everything works you may want to start the proxy automatically and in the background. Stop the -proxy with `Ctrl-C` and uncomment the line `# daemon` in the config file, then start the proxy again -- it will now start in the bacground. - -You may also want to have the proxy start automatically; this you can do with `cron`, the inbuilt -Linux mechanism for running things at specific times. - -``` -sudo crontab -e -``` - -Choose your editor and add a new line at the end of the crontab file that opens: - -``` -@reboot haproxy -f /path/to/the/above/config_file.cfg -``` - -Save the file and haproxy should start up automatically when you reboot the server. \ No newline at end of file diff --git a/docs/0.9.5/_sources/Help-System-Tutorial.md.txt b/docs/0.9.5/_sources/Help-System-Tutorial.md.txt deleted file mode 100644 index 585168f629..0000000000 --- a/docs/0.9.5/_sources/Help-System-Tutorial.md.txt +++ /dev/null @@ -1,465 +0,0 @@ -# Help System Tutorial - - -**Before doing this tutorial you will probably want to read the intro in [Basic Web tutorial](./Web-Tutorial.md).** Reading the three first parts of the [Django tutorial](https://docs.djangoproject.com/en/2.2/) might help as well. - -This tutorial will show you how to access the help system through your website. Both help commands -and regular help entries will be visible, depending on the logged-in user or an anonymous character. - -This tutorial will show you how to: - -- Create a new page to add to your website. -- Take advantage of a basic view and basic templates. -- Access the help system on your website. -- Identify whether the viewer of this page is logged-in and, if so, to what account. - -## Creating our app - -The first step is to create our new Django *app*. An app in Django can contain pages and -mechanisms: your website may contain different apps. Actually, the website provided out-of-the-box -by Evennia has already three apps: a "webclient" app, to handle the entire webclient, a "website" -app to contain your basic pages, and a third app provided by Django to create a simple admin -interface. So we'll create another app in parallel, giving it a clear name to represent our help -system. - -From your game directory, use the following command: - - evennia startapp help_system - -> Note: calling the app "help" would have been more explicit, but this name is already used by -Django. - -This will create a directory named `help_system` at the root of your game directory. It's a good -idea to keep things organized and move this directory in the "web" directory of your game. Your -game directory should look like: - - mygame/ - ... - web/ - help_system/ - ... - -The "web/help_system" directory contains files created by Django. We'll use some of them, but if -you want to learn more about them all, you should read [the Django -tutorial](https://docs.djangoproject.com/en/1.9/intro/tutorial01/). - -There is a last thing to be done: your folder has been added, but Django doesn't know about it, it -doesn't know it's a new app. We need to tell it, and we do so by editing a simple setting. Open -your "server/conf/settings.py" file and add, or edit, these lines: - -```python -# Web configuration -INSTALLED_APPS += ( - "web.help_system", -) -``` - -You can start Evennia if you want, and go to your website, probably at -[http://localhost:4001](http://localhost:4001) . You won't see anything different though: we added -the app but it's fairly empty. - -## Our new page - -At this point, our new *app* contains mostly empty files that you can explore. In order to create -a page for our help system, we need to add: - -- A *view*, dealing with the logic of our page. -- A *template* to display our new page. -- A new *URL* pointing to our page. - -> We could get away by creating just a view and a new URL, but that's not a recommended way to work -with your website. Building on templates is so much more convenient. - -### Create a view - -A *view* in Django is a simple Python function placed in the "views.py" file in your app. It will -handle the behavior that is triggered when a user asks for this information by entering a *URL* (the -connection between *views* and *URLs* will be discussed later). - -So let's create our view. You can open the "web/help_system/views.py" file and paste the following -lines: - -```python -from django.shortcuts import render - -def index(request): - """The 'index' view.""" - return render(request, "help_system/index.html") -``` - -Our view handles all code logic. This time, there's not much: when this function is called, it will -render the template we will now create. But that's where we will do most of our work afterward. - -### Create a template - -The `render` function called into our *view* asks the *template* `help_system/index.html`. The -*templates* of our apps are stored in the app directory, "templates" sub-directory. Django may have -created the "templates" folder already. If not, create it yourself. In it, create another folder -"help_system", and inside of this folder, create a file named "index.html". Wow, that's some -hierarchy. Your directory structure (starting from `web`) should look like this: - - web/ - help_system/ - ... - templates/ - help_system/ - index.html - -Open the "index.html" file and paste in the following lines: - -``` -{% extends "base.html" %} -{% block titleblock %}Help index{% endblock %} -{% block content %} -

Help index

-{% endblock %} -``` - -Here's a little explanation line by line of what this template does: - -1. It loads the "base.html" *template*. This describes the basic structure of all your pages, with -a menu at the top and a footer, and perhaps other information like images and things to be present -on each page. You can create templates that do not inherit from "base.html", but you should have a -good reason for doing so. -2. The "base.html" *template* defines all the structure of the page. What is left is to override -some sections of our pages. These sections are called *blocks*. On line 2, we override the block -named "blocktitle", which contains the title of our page. -3. Same thing here, we override the *block* named "content", which contains the main content of our -web page. This block is bigger, so we define it on several lines. -4. This is perfectly normal HTML code to display a level-2 heading. -5. And finally we close the *block* named "content". - -### Create a new URL - -Last step to add our page: we need to add a *URL* leading to it... otherwise users won't be able to -access it. The URLs of our apps are stored in the app's directory "urls.py" file. - -Open the "web/help_system/urls.py" file (you might have to create it) and write in it: - -```python -# URL patterns for the help_system app - -from django.urls import include, path -from web.help_system.views import index - -urlpatterns = [ - path(r'', index, name="help-index") -] -``` - -We also need to add our app as a namespace holder for URLS. Edit the file "web/urls.py" (you might -have to create this one too). In it you will find the `custom_patterns` variable. Replace it with: - -```python -custom_patterns = [ - path(r'help_system/', include('web.help_system.urls')), -] -``` - -When a user will ask for a specific *URL* on your site, Django will: - -1. Read the list of custom patterns defined in "web/urls.py". There's one pattern here, which -describes to Django that all URLs beginning by 'help/' should be sent to the 'help_system' app. The -'help/' part is removed. -2. Then Django will check the "web.help_system/urls.py" file. It contains only one URL, which is -empty. - -In other words, if the URL is '/help/', then Django will execute our defined view. - -### Let's see it work - -You can now reload or start Evennia. Open a tab in your browser and go to -[http://localhost:4001/help_system/](http://localhost:4001/help_system/) . If everything goes well, -you should see your new page... which isn't empty since Evennia uses our "base.html" *template*. In -the content of our page, there's only a heading that reads "help index". Notice that the title of -our page is "mygame - Help index" ("mygame" is replaced by the name of your game). - -From now on, it will be easier to move forward and add features. - -### A brief reminder - -We'll be trying the following things: - -- Have the help of commands and help entries accessed online. -- Have various commands and help entries depending on whether the user is logged in or not. - -In terms of pages, we'll have: - -- One to display the list of help topics. -- One to display the content of a help topic. - -The first one would link to the second. - -> Should we create two URLs? - -The answer is... maybe. It depends on what you want to do. We have our help index accessible -through the "/help_system/" URL. We could have the detail of a help entry accessible through -"/help_system/desc" (to see the detail of the "desc" command). The problem is that our commands or -help topics may contain special characters that aren't to be present in URLs. There are different -ways around this problem. I have decided to use a *GET variable* here, which would create URLs like -this: - - /help_system?name=desc - -If you use this system, you don't have to add a new URL: GET and POST variables are accessible -through our requests and we'll see how soon enough. - -## Handling logged-in users - -One of our requirements is to have a help system tailored to our accounts. If an account with admin -access logs in, the page should display a lot of commands that aren't accessible to common users. -And perhaps even some additional help topics. - -Fortunately, it's fairly easy to get the logged in account in our view (remember that we'll do most -of our coding there). The *request* object, passed to our function, contains a `user` attribute. -This attribute will always be there: we cannot test whether it's `None` or not, for instance. But -when the request comes from a user that isn't logged in, the `user` attribute will contain an -anonymous Django user. We then can use the `is_anonymous` method to see whether the user is logged- -in or not. Last gift by Evennia, if the user is logged in, `request.user` contains a reference to -an account object, which will help us a lot in coupling the game and online system. - -So we might end up with something like: - -```python -def index(request): - """The 'index' view.""" - user = request.user - if not user.is_anonymous() and user.character: - character = user.character -``` - -> Note: this code works when your MULTISESSION_MODE is set to 0 or 1. When it's above, you would -have something like: - -```python -def index(request): - """The 'index' view.""" - user = request.user - if not user.is_anonymous() and user.db._playable_characters: - character = user.db._playable_characters[0] -``` - -In this second case, it will select the first character of the account. - -But what if the user's not logged in? Again, we have different solutions. One of the most simple -is to create a character that will behave as our default character for the help system. You can -create it through your game: connect to it and enter: - - @charcreate anonymous - -The system should answer: - - Created new character anonymous. Use @ic anonymous to enter the game as this character. - -So in our view, we could have something like this: - -```python -from typeclasses.characters import Character - -def index(request): - """The 'index' view.""" - user = request.user - if not user.is_anonymous() and user.character: - character = user.character - else: - character = Character.objects.get(db_key="anonymous") -``` - -This time, we have a valid character no matter what: remember to adapt this code if you're running -in multisession mode above 1. - -## The full system - -What we're going to do is to browse through all commands and help entries, and list all the commands -that can be seen by this character (either our 'anonymous' character, or our logged-in character). - -The code is longer, but it presents the entire concept in our view. Edit the -"web/help_system/views.py" file and paste into it: - -```python -from django.http import Http404 -from django.shortcuts import render -from evennia.help.models import HelpEntry - -from typeclasses.characters import Character - -def index(request): - """The 'index' view.""" - user = request.user - if not user.is_anonymous() and user.character: - character = user.character - else: - character = Character.objects.get(db_key="anonymous") - - # Get the categories and topics accessible to this character - categories, topics = _get_topics(character) - - # If we have the 'name' in our GET variable - topic = request.GET.get("name") - if topic: - if topic not in topics: - raise Http404("This help topic doesn't exist.") - - topic = topics[topic] - context = { - "character": character, - "topic": topic, - } - return render(request, "help_system/detail.html", context) - else: - context = { - "character": character, - "categories": categories, - } - return render(request, "help_system/index.html", context) - -def _get_topics(character): - """Return the categories and topics for this character.""" - cmdset = character.cmdset.all()[0] - commands = cmdset.commands - entries = [entry for entry in HelpEntry.objects.all()] - categories = {} - topics = {} - - # Browse commands - for command in commands: - if not command.auto_help or not command.access(character): - continue - - # Create the template for a command - template = { - "name": command.key, - "category": command.help_category, - "content": command.get_help(character, cmdset), - } - - category = command.help_category - if category not in categories: - categories[category] = [] - categories[category].append(template) - topics[command.key] = template - - # Browse through the help entries - for entry in entries: - if not entry.access(character, 'view', default=True): - continue - - # Create the template for an entry - template = { - "name": entry.key, - "category": entry.help_category, - "content": entry.entrytext, - } - - category = entry.help_category - if category not in categories: - categories[category] = [] - categories[category].append(template) - topics[entry.key] = template - - # Sort categories - for entries in categories.values(): - entries.sort(key=lambda c: c["name"]) - - categories = list(sorted(categories.items())) - return categories, topics -``` - -That's a bit more complicated here, but all in all, it can be divided in small chunks: - -- The `index` function is our view: - - It begins by getting the character as we saw in the previous section. - - It gets the help topics (commands and help entries) accessible to this character. It's another -function that handles that part. - - If there's a *GET variable* "name" in our URL (like "/help?name=drop"), it will retrieve it. If -it's not a valid topic's name, it returns a *404*. Otherwise, it renders the template called -"detail.html", to display the detail of our topic. - - If there's no *GET variable* "name", render "index.html", to display the list of topics. -- The `_get_topics` is a private function. Its sole mission is to retrieve the commands a character -can execute, and the help entries this same character can see. This code is more Evennia-specific -than Django-specific, it will not be detailed in this tutorial. Just notice that all help topics -are stored in a dictionary. This is to simplify our job when displaying them in our templates. - -Notice that, in both cases when we asked to render a *template*, we passed to `render` a third -argument which is the dictionary of variables used in our templates. We can pass variables this -way, and we will use them in our templates. - -### The index template - -Let's look at our full "index" *template*. You can open the -"web/help_system/templates/help_system/index.html" file and paste the following into it: - -``` -{% extends "base.html" %} -{% block titleblock %}Help index{% endblock %} -{% block content %} -

Help index

-{% if categories %} - {% for category, topics in categories %} -

{{ category|capfirst }}

- - - {% for topic in topics %} - {% if forloop.counter|divisibleby:"5" %} - - - {% endif %} - - {% endfor %} - -
- {{ topic.name }}
- {% endfor %} -{% endif %} -{% endblock %} -``` - -This template is definitely more detailed. What it does is: - -1. Browse through all categories. -2. For all categories, display a level-2 heading with the name of the category. -3. All topics in a category (remember, they can be either commands or help entries) are displayed in -a table. The trickier part may be that, when the loop is above 5, it will create a new line. The -table will have 5 columns at the most per row. -4. For every cell in the table, we create a link redirecting to the detail page (see below). The -URL would look something like "help?name=say". We use `urlencode` to ensure special characters are -properly escaped. - -### The detail template - -It's now time to show the detail of a topic (command or help entry). You can create the file -"web/help_system/templates/help_system/detail.html". You can paste into it the following code: - -``` -{% extends "base.html" %} -{% block titleblock %}Help for {{ topic.name }}{% endblock %} -{% block content %} -

{{ topic.name|capfirst }} help topic

-

Category: {{ topic.category|capfirst }}

-{{ topic.content|linebreaks }} -{% endblock %} -``` - -This template is much easier to read. Some *filters* might be unknown to you, but they are just -used to format here. - -### Put it all together - -Remember to reload or start Evennia, and then go to -[http://localhost:4001/help_system](http://localhost:4001/help_system/). You should see the list of -commands and topics accessible by all characters. Try to login (click the "login" link in the menu -of your website) and go to the same page again. You should now see a more detailed list of commands -and help entries. Click on one to see its detail. - -## To improve this feature - -As always, a tutorial is here to help you feel comfortable adding new features and code by yourself. -Here are some ideas of things to improve this little feature: - -- Links at the bottom of the detail template to go back to the index might be useful. -- A link in the main menu to link to this page would be great... for the time being you have to -enter the URL, users won't guess it's there. -- Colors aren't handled at this point, which isn't exactly surprising. You could add it though. -- Linking help entries between one another won't be simple, but it would be great. For instance, if -you see a help entry about how to use several commands, it would be great if these commands were -themselves links to display their details. diff --git a/docs/0.9.5/_sources/Help-System.md.txt b/docs/0.9.5/_sources/Help-System.md.txt deleted file mode 100644 index 5dda8132ac..0000000000 --- a/docs/0.9.5/_sources/Help-System.md.txt +++ /dev/null @@ -1,122 +0,0 @@ -# Help System - - -An important part of Evennia is the online help system. This allows the players and staff alike to -learn how to use the game's commands as well as other information pertinent to the game. The help -system has many different aspects, from the normal editing of help entries from inside the game, to -auto-generated help entries during code development using the *auto-help system*. - -## Viewing the help database - -The main command is `help`: - - help [searchstring] - -This will show a list of help entries, ordered after categories. You will find two sections, -*Command help entries* and *Other help entries* (initially you will only have the first one). You -can use help to get more info about an entry; you can also give partial matches to get suggestions. -If you give category names you will only be shown the topics in that category. - - -## Command Auto-help system - -A common item that requires help entries are in-game commands. Keeping these entries up-to-date with -the actual source code functionality can be a chore. Evennia's commands are therefore auto- -documenting straight from the sources through its *auto-help system*. Only commands that you and -your character can actually currently use are picked up by the auto-help system. That means an admin -will see a considerably larger amount of help topics than a normal player when using the default -`help` command. - -The auto-help system uses the `__doc__` strings of your command classes and formats this to a nice- -looking help entry. This makes for a very easy way to keep the help updated - just document your -commands well and updating the help file is just a `@reload` away. There is no need to manually -create and maintain help database entries for commands; as long as you keep the docstrings updated -your help will be dynamically updated for you as well. - -Example (from a module with command definitions): - -```python - class CmdMyCmd(Command): - """ - mycmd - my very own command - - Usage: - mycmd[/switches] - - Switches: - test - test the command - run - do something else - - This is my own command that does this and that. - - """ - # [...] - - help_category = "General" # default - auto_help = True # default - - # [...] -``` - -The text at the very top of the command class definition is the class' `__doc__`-string and will be -shown to users looking for help. Try to use a consistent format - all default commands are using the -structure shown above. - -You should also supply the `help_category` class property if you can; this helps to group help -entries together for people to more easily find them. See the `help` command in-game to see the -default categories. If you don't specify the category, "General" is assumed. - -If you don't want your command to be picked up by the auto-help system at all (like if you want to -write its docs manually using the info in the next section or you use a [cmdset](./Command-Sets.md) that -has its own help functionality) you can explicitly set `auto_help` class property to `False` in your -command definition. - -Alternatively, you can keep the advantages of *auto-help* in commands, but control the display of -command helps. You can do so by overriding the command's `get_help()` method. By default, this -method will return the class docstring. You could modify it to add custom behavior: the text -returned by this method will be displayed to the character asking for help in this command. - -## Database help entries - -These are all help entries not involving commands (this is handled automatically by the [Command -Auto-help system](./Help-System.md#command-auto-help-system)). Non-automatic help entries describe how -your particular game is played - its rules, world descriptions and so on. - -A help entry consists of four parts: - -- The *topic*. This is the name of the help entry. This is what players search for when they are -looking for help. The topic can contain spaces and also partial matches will be found. -- The *help category*. Examples are *Administration*, *Building*, *Comms* or *General*. This is an -overall grouping of similar help topics, used by the engine to give a better overview. -- The *text* - the help text itself, of any length. -- locks - a [lock definition](./Locks.md). This can be used to limit access to this help entry, maybe -because it's staff-only or otherwise meant to be restricted. Help commands check for `access_type`s -`view` and `edit`. An example of a lock string would be `view:perm(Builders)`. - -You can create new help entries in code by using `evennia.create_help_entry()`. - -```python -from evennia import create_help_entry -entry = create_help_entry("emote", - "Emoting is important because ...", - category="Roleplaying", locks="view:all()") -``` - -From inside the game those with the right permissions can use the `@sethelp` command to add and -modify help entries. - - > @sethelp/add emote = The emote command is ... - -Using `@sethelp` you can add, delete and append text to existing entries. By default new entries -will go in the *General* help category. You can change this using a different form of the `@sethelp` -command: - - > @sethelp/add emote, Roleplaying = Emoting is important because ... - -If the category *Roleplaying* did not already exist, it is created and will appear in the help -index. - -You can, finally, define a lock for the help entry by following the category with a [lock -definition](./Locks.md): - - > @sethelp/add emote, Roleplaying, view:all() = Emoting is ... diff --git a/docs/0.9.5/_sources/How-To-Get-And-Give-Help.md.txt b/docs/0.9.5/_sources/How-To-Get-And-Give-Help.md.txt deleted file mode 100644 index 85ef9fb8a7..0000000000 --- a/docs/0.9.5/_sources/How-To-Get-And-Give-Help.md.txt +++ /dev/null @@ -1,71 +0,0 @@ -# How To Get And Give Help - - -### How to *get* Help - -If you cannot find what you are looking for in the [online documentation](./index.md), here's what to do: - -- If you think the documentation is not clear enough and are short on time, fill in our quick little -[online form][form] and let us know - no login required. Maybe the docs need to be improved or a new -tutorial added! Note that while this form is useful as a suggestion box we cannot answer questions -or reply to you. Use the discussion group or chat (linked below) if you want feedback. -- If you have trouble with a missing feature or a problem you think is a bug, go to the -[issue tracker][issues] and search to see if has been reported/suggested already. If you can't find an -existing entry create a new one. -- If you need help, want to start a discussion or get some input on something you are working on, -make a post to the [discussions group][group] This is technically a 'mailing list', but you don't -need to use e-mail; you can post and read all messages just as easily from your browser via the -online interface. -- If you want more direct discussions with developers and other users, consider dropping into our -IRC chat channel [#evennia][chat] on the *Freenode* network. Please note however that you have to be -patient if you don't get any response immediately; we are all in very different time zones and many -have busy personal lives. So you might have to hang around for a while - you'll get noticed -eventually! - - -### How to *give* Help - -Evennia is a completely non-funded project. It relies on the time donated by its users and -developers in order to progress. - -The first and easiest way you as a user can help us out is by taking part in -[community discussions][group] and by giving feedback on what is good or bad. Report bugs you find and features -you lack to our [issue tracker][issues]. Just the simple act of letting developers know you are out -there using their program is worth a lot. Generally mentioning and reviewing Evennia elsewhere is -also a nice way to spread the word. - -If you'd like to help develop Evennia more hands-on, here are some ways to get going: - -- Look through our [online documentation wiki](./index.md) and see if you -can help improve or expand the documentation (even small things like fixing typos!). You don't need -any particular permissions to edit the wiki. -- Send a message to our [discussion group][group] and/or our [IRC chat][chat] asking about what -needs doing, along with what your interests and skills are. -- Take a look at our [issue tracker][issues] and see if there's something you feel like taking on. -[here are bugs][issues-master] that need fixes. At any given time there may also be some -[bounties][issues-bounties] open - these are issues members of the community has put up money to see -fixed (if you want to put up a bounty yourself you can do so via our page on -[bountysource][bountysource]). -- Check out the [Contributing](./Contributing.md) page on how to practically contribute with code using -github. - -... And finally, if you want to help motivate and support development you can also drop some coins -in the developer's cup. You can [make a donation via PayPal][paypal] or, even better, -[become an Evennia patron on Patreon][patreon]! This is a great way to tip your hat and show that you -appreciate the work done with the server! Finally, if you want to encourage the community to resolve -a particular - -[form]: https://docs.google.com/spreadsheet/viewform?hl=en_US&formkey=dGN0VlJXMWpCT3VHaHpscDEzY1RoZGc6MQ#gid=0 -[group]: http://groups.google.com/group/evennia/ -[issues]: https://github.com/evennia/evennia/issues -[issues-master]: https://github.com/evennia/evennia/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Abug%20label%3Amaster-branch -[chat]: http://webchat.freenode.net/?channels=evennia -[paypal]: https://www.paypal.com/se/cgi-bin/webscr?cmd=_flow&SESSION=Z-VlOvfGjYq2qvCDOUGpb6C8Due7skT0qOklQEy5EbaD1f0eyEQaYlmCc8O&dispatch=5885d80a13c0db1f8e263663d3faee8d64ad11bbf4d2a5a1a0d303a50933f9 -b2 -[donate-img]: http://images-focus-opensocial.googleusercontent.com/gadgets/proxy?url=https://www.paypalobjects.com/en%255fUS/SE/i/btn/btn%255fdonateCC%255fLG.gif&container=focus&gadget=a&rewriteMime=image/* -[patreon]: https://www.patreon.com/griatch -[patreon-img]: http://www.evennia.com/_/rsrc/1424724909023/home/evennia_patreon_100x100.png -[issues-bounties]: https://github.com/evennia/evennia/labels/bounty -[bountysource]: https://www.bountysource.com/teams/evennia - - diff --git a/docs/0.9.5/_sources/How-to-connect-Evennia-to-Twitter.md.txt b/docs/0.9.5/_sources/How-to-connect-Evennia-to-Twitter.md.txt deleted file mode 100644 index 36dd7bdf78..0000000000 --- a/docs/0.9.5/_sources/How-to-connect-Evennia-to-Twitter.md.txt +++ /dev/null @@ -1,110 +0,0 @@ -# How to connect Evennia to Twitter - - -[Twitter](http://en.wikipedia.org/wiki/twitter) is an online social networking service that enables -users to send and read short 280-character messages called "tweets". Following is a short tutorial -explaining how to enable users to send tweets from inside Evennia. - -## Configuring Twitter - -You must first have a Twitter account. Log in and register an App at the [Twitter Dev -Site](https://apps.twitter.com/). Make sure you enable access to "write" tweets! - -To tweet from Evennia you will need both the "API Token" and the "API secret" strings as well as the -"Access Token" and "Access Secret" strings. - -Twitter changed their requirements to require a Mobile number on the Twitter account to register new -apps with write access. If you're unable to do this, please see [this Dev -post](https://dev.twitter.com/notifications/new-apps-registration) which describes how to get around -it. - -## Install the twitter python module - -To use Twitter you must install the [Twitter](https://pypi.python.org/pypi/twitter) Python module: - -``` -pip install python-twitter -``` - -## A basic tweet command - -Evennia doesn't have a `tweet` command out of the box so you need to write your own little -[Command](./Commands.md) in order to tweet. If you are unsure about how commands work and how to add -them, it can be an idea to go through the [Adding a Command Tutorial](./Adding-Command-Tutorial.md) -before continuing. - -You can create the command in a separate command module (something like `mygame/commands/tweet.py`) -or together with your other custom commands, as you prefer. - -This is how it can look: - -```python -import twitter -from evennia import Command - -# here you insert your unique App tokens -# from the Twitter dev site -TWITTER_API = twitter.Api(consumer_key='api_key', - consumer_secret='api_secret', - access_token_key='access_token_key', - access_token_secret='access_token_secret') - -class CmdTweet(Command): - """ - Tweet a message - - Usage: - tweet - - This will send a Twitter tweet to a pre-configured Twitter account. - A tweet has a maximum length of 280 characters. - """ - - key = "tweet" - locks = "cmd:pperm(tweet) or pperm(Developers)" - help_category = "Comms" - - def func(self): - "This performs the tweet" - - caller = self.caller - tweet = self.args - - if not tweet: - caller.msg("Usage: tweet ") - return - - tlen = len(tweet) - if tlen > 280: - caller.msg("Your tweet was %i chars long (max 280)." % tlen) - return - - # post the tweet - TWITTER_API.PostUpdate(tweet) - - caller.msg("You tweeted:\n%s" % tweet) -``` - -Be sure to substitute your own actual API/Access keys and secrets in the appropriate places. - -We default to limiting tweet access to players with `Developers`-level access *or* to those players -that have the permission "tweet" (allow individual characters to tweet with `@perm/player playername -= tweet`). You may change the [lock](./Locks.md) as you feel is appropriate. Change the overall -permission to `Players` if you want everyone to be able to tweet. - -Now add this command to your default command set (e.g in `mygame/commands/defalt_cmdsets.py`") and -reload the server. From now on those with access can simply use `tweet ` to see the tweet -posted from the game's Twitter account. - -## Next Steps - -This shows only a basic tweet setup, other things to do could be: - -* Auto-Adding the character name to the tweet -* More error-checking of postings -* Changing locks to make tweeting open to more people -* Echo your tweets to an in-game channel - -Rather than using an explicit command you can set up a Script to send automatic tweets, for example -to post updated game stats. See the [Tweeting Game Stats tutorial](./Tutorial-Tweeting-Game-Stats.md) for -help. diff --git a/docs/0.9.5/_sources/IRC.md.txt b/docs/0.9.5/_sources/IRC.md.txt deleted file mode 100644 index 9b3684dee7..0000000000 --- a/docs/0.9.5/_sources/IRC.md.txt +++ /dev/null @@ -1,90 +0,0 @@ -# IRC - - -_Disambiguation: This page is related to using IRC inside an Evennia game. To join the official -Evennia IRC chat, connect to irc.freenode.net and join #evennia. Alternatively, you can [join our -Discord](https://discord.gg/NecFePw), which is mirrored to IRC._ - -[IRC (Internet Relay Chat)](http://en.wikipedia.org/wiki/Internet_Relay_Chat) is a long standing -chat protocol used by many open-source projects for communicating in real time. By connecting one of -Evennia's [Channels](./Communications.md) to an IRC channel you can communicate also with people not on -an mud themselves. You can also use IRC if you are only running your Evennia MUD locally on your -computer (your game doesn't need to be open to the public)! All you need is an internet connection. -For IRC operation you also need [twisted.words](http://twistedmatrix.com/trac/wiki/TwistedWords). -This is available simply as a package *python-twisted-words* in many Linux distros, or directly -downloadable from the link. - -## Configuring IRC - -To configure IRC, you'll need to activate it in your settings file. - -```python - IRC_ENABLED = True -``` - -Start Evennia and log in as a privileged user. You should now have a new command available: -`@irc2chan`. This command is called like this: - - @irc2chan[/switches] = <#irchannel> - -If you already know how IRC works, this should be pretty self-evident to use. Read the help entry -for more features. - -## Setting up IRC, step by step - -You can connect IRC to any Evennia channel (so you could connect it to the default *public* channel -if you like), but for testing, let's set up a new channel `irc`. - - @ccreate irc = This is connected to an irc channel! - -You will automatically join the new channel. - -Next we will create a connection to an external IRC network and channel. There are many, many IRC -nets. [Here is a list](http://www.irchelp.org/irchelp/networks/popular.html) of some of the biggest -ones, the one you choose is not really very important unless you want to connect to a particular -channel (also make sure that the network allows for "bots" to connect). - -For testing, we choose the *Freenode* network, `irc.freenode.net`. We will connect to a test -channel, let's call it *#myevennia-test* (an IRC channel always begins with `#`). It's best if you -pick an obscure channel name that didn't exist previously - if it didn't exist it will be created -for you. - -> *Don't* connect to `#evennia` for testing and debugging, that is Evennia's official chat channel! -You *are* welcome to connect your game to `#evennia` once you have everything working though - it -can be a good way to get help and ideas. But if you do, please do so with an in-game channel open -only to your game admins and developers). - -The *port* needed depends on the network. For Freenode this is `6667`. - -What will happen is that your Evennia server will connect to this IRC channel as a normal user. This -"user" (or "bot") needs a name, which you must also supply. Let's call it "mud-bot". - -To test that the bot connects correctly you also want to log onto this channel with a separate, -third-party IRC client. There are hundreds of such clients available. If you use Firefox, the -*Chatzilla* plugin is good and easy. Freenode also offers its own web-based chat page. Once you -have connected to a network, the command to join is usually `/join #channelname` (don't forget the -#). - -Next we connect Evennia with the IRC channel. - - @irc2chan irc = irc.freenode.net 6667 #myevennia-test mud-bot - -Evennia will now create a new IRC bot `mud-bot` and connect it to the IRC network and the channel -#myevennia. If you are connected to the IRC channel you will soon see the user *mud-bot* connect. - -Write something in the Evennia channel *irc*. - - irc Hello, World! - [irc] Anna: Hello, World! - -If you are viewing your IRC channel with a separate IRC client you should see your text appearing -there, spoken by the bot: - - mud-bot> [irc] Anna: Hello, World! - -Write `Hello!` in your IRC client window and it will appear in your normal channel, marked with the -name of the IRC channel you used (#evennia here). - - [irc] Anna@#myevennia-test: Hello! - -Your Evennia gamers can now chat with users on external IRC channels! diff --git a/docs/0.9.5/_sources/Implementing-a-game-rule-system.md.txt b/docs/0.9.5/_sources/Implementing-a-game-rule-system.md.txt deleted file mode 100644 index 26fd0471c6..0000000000 --- a/docs/0.9.5/_sources/Implementing-a-game-rule-system.md.txt +++ /dev/null @@ -1,302 +0,0 @@ -# Implementing a game rule system - - -The simplest way to create an online roleplaying game (at least from a code perspective) is to -simply grab a paperback RPG rule book, get a staff of game masters together and start to run scenes -with whomever logs in. Game masters can roll their dice in front of their computers and tell the -players the results. This is only one step away from a traditional tabletop game and puts heavy -demands on the staff - it is unlikely staff will be able to keep up around the clock even if they -are very dedicated. - -Many games, even the most roleplay-dedicated, thus tend to allow for players to mediate themselves -to some extent. A common way to do this is to introduce *coded systems* - that is, to let the -computer do some of the heavy lifting. A basic thing is to add an online dice-roller so everyone can -make rolls and make sure noone is cheating. Somewhere at this level you find the most bare-bones -roleplaying MUSHes. - -The advantage of a coded system is that as long as the rules are fair the computer is too - it makes -no judgement calls and holds no personal grudges (and cannot be accused of holding any). Also, the -computer doesn't need to sleep and can always be online regardless of when a player logs on. The -drawback is that a coded system is not flexible and won't adapt to the unprogrammed actions human -players may come up with in role play. For this reason many roleplay-heavy MUDs do a hybrid -variation - they use coded systems for things like combat and skill progression but leave role play -to be mostly freeform, overseen by staff game masters. - -Finally, on the other end of the scale are less- or no-roleplay games, where game mechanics (and -thus player fairness) is the most important aspect. In such games the only events with in-game value -are those resulting from code. Such games are very common and include everything from hack-and-slash -MUDs to various tactical simulations. - -So your first decision needs to be just what type of system you are aiming for. This page will try -to give some ideas for how to organize the "coded" part of your system, however big that may be. - -## Overall system infrastructure - -We strongly recommend that you code your rule system as stand-alone as possible. That is, don't -spread your skill check code, race bonus calculation, die modifiers or what have you all over your -game. - -- Put everything you would need to look up in a rule book into a module in `mygame/world`. Hide away -as much as you can. Think of it as a black box (or maybe the code representation of an all-knowing -game master). The rest of your game will ask this black box questions and get answers back. Exactly -how it arrives at those results should not need to be known outside the box. Doing it this way -makes it easier to change and update things in one place later. -- Store only the minimum stuff you need with each game object. That is, if your Characters need -values for Health, a list of skills etc, store those things on the Character - don't store how to -roll or change them. -- Next is to determine just how you want to store things on your Objects and Characters. You can -choose to either store things as individual [Attributes](./Attributes.md), like `character.db.STR=34` and -`character.db.Hunting_skill=20`. But you could also use some custom storage method, like a -dictionary `character.db.skills = {"Hunting":34, "Fishing":20, ...}`. A much more fancy solution is -to look at the Ainneve [Trait -handler](https://github.com/evennia/ainneve/blob/master/world/traits.py). Finally you could even go -with a [custom django model](./New-Models.md). Which is the better depends on your game and the -complexity of your system. -- Make a clear [API](http://en.wikipedia.org/wiki/Application_programming_interface) into your -rules. That is, make methods/functions that you feed with, say, your Character and which skill you -want to check. That is, you want something similar to this: - - ```python - from world import rules - result = rules.roll_skill(character, "hunting") - result = rules.roll_challenge(character1, character2, "swords") - ``` - -You might need to make these functions more or less complex depending on your game. For example the -properties of the room might matter to the outcome of a roll (if the room is dark, burning etc). -Establishing just what you need to send into your game mechanic module is a great way to also get a -feel for what you need to add to your engine. - -## Coded systems - -Inspired by tabletop role playing games, most game systems mimic some sort of die mechanic. To this -end Evennia offers a full [dice -roller](https://github.com/evennia/evennia/blob/master/evennia/contrib/dice.py) in its `contrib` -folder. For custom implementations, Python offers many ways to randomize a result using its in-built -`random` module. No matter how it's implemented, we will in this text refer to the action of -determining an outcome as a "roll". - -In a freeform system, the result of the roll is just compared with values and people (or the game -master) just agree on what it means. In a coded system the result now needs to be processed somehow. -There are many things that may happen as a result of rule enforcement: - -- Health may be added or deducted. This can effect the character in various ways. -- Experience may need to be added, and if a level-based system is used, the player might need to be -informed they have increased a level. -- Room-wide effects need to be reported to the room, possibly affecting everyone in the room. - -There are also a slew of other things that fall under "Coded systems", including things like -weather, NPC artificial intelligence and game economy. Basically everything about the world that a -Game master would control in a tabletop role playing game can be mimicked to some level by coded -systems. - - -## Example of Rule module - -Here is a simple example of a rule module. This is what we assume about our simple example game: -- Characters have only four numerical values: - - Their `level`, which starts at 1. - - A skill `combat`, which determines how good they are at hitting things. Starts between 5 and -10. - - Their Strength, `STR`, which determine how much damage they do. Starts between 1 and 10. - - Their Health points, `HP`, which starts at 100. -- When a Character reaches `HP = 0`, they are presumed "defeated". Their HP is reset and they get a -failure message (as a stand-in for death code). -- Abilities are stored as simple Attributes on the Character. -- "Rolls" are done by rolling a 100-sided die. If the result plus the `combat`value is greater than -the other character, it's a success and damage is rolled. Damage is rolled as a six-sided die + the -value of `STR` (for this example we ignore weapons and assume `STR` is all that matters). -- Every successful `attack` roll gives 1-3 experience points (`XP`). Every time the number of `XP` -reaches `(level + 1) ** 2`, the Character levels up. When leveling up, the Character's `combat` -value goes up by 2 points and `STR` by one (this is a stand-in for a real progression system). -- Characters with the name `dummy` will gain no XP. Allowing us to make a dummy to train with. - -### Character - -The Character typeclass is simple. It goes in `mygame/typeclasses/characters.py`. There is already -an empty `Character` class there that Evennia will look to and use. - -```python -from random import randint -from evennia import DefaultCharacter - -class Character(DefaultCharacter): - """ - Custom rule-restricted character. We randomize - the initial skill and ability values bettween 1-10. - """ - def at_object_creation(self): - "Called only when first created" - self.db.level = 1 - self.db.HP = 100 - self.db.XP = 0 - self.db.STR = randint(1, 10) - self.db.combat = randint(5, 10) -``` - -`@reload` the server to load up the new code. Doing `examine self` will however *not* show the new -Attributes on yourself. This is because the `at_object_creation` hook is only called on *new* -Characters. Your Character was already created and will thus not have them. To force a reload, use -the following command: - -``` -@typeclass/force/reset self -``` - -The `examine self` command will now show the new Attributes. - -### Rule module - -This is a module `mygame/world/rules.py`. - -```python -""" -mygame/world/rules.py -""" -from random import randint - - -def roll_hit(): - "Roll 1d100" - return randint(1, 100) - - -def roll_dmg(): - "Roll 1d6" - return randint(1, 6) - - -def check_defeat(character): - "Checks if a character is 'defeated'." - if character.db.HP <= 0: - character.msg("You fall down, defeated!") - character.db.HP = 100 # reset - - -def add_XP(character, amount): - "Add XP to character, tracking level increases." - if "training_dummy" in character.tags.all(): # don't allow the training dummy to level - character.location.msg_contents("Training Dummies can not gain XP.") - return - else: - character.db.XP += amount - if character.db.XP >= (character.db.level + 1) ** 2: - character.db.level += 1 - character.db.STR += 1 - character.db.combat += 2 - character.msg("You are now level %i!" % character.db.level) - - -def skill_combat(*args): - """ - This determines outcome of combat. The one who - rolls under their combat skill AND higher than - their opponent's roll hits. - """ - char1, char2 = args - roll1, roll2 = roll_hit(), roll_hit() - failtext = "You are hit by %s for %i damage!" - wintext = "You hit %s for %i damage!" - xp_gain = randint(1, 3) - - # display messages showing attack numbers - attack_message = f"{char1.name} rolls {roll1} + combat {char1.db.combat} " \ - f"= {char1.db.combat+roll1} | {char2.name} rolls {roll2} + combat " \ - f"{char2.db.combat} = {char2.db.combat+roll2}" - char1.location.msg_contents(attack_message) - attack_summary = f"{char1.name} {char1.db.combat+roll1} " \ - f"vs {char2.name} {char2.db.combat+roll2}" - char1.location.msg_contents(attack_summary) - - if char1.db.combat+roll1 > char2.db.combat+roll2: - # char 1 hits - dmg = roll_dmg() + char1.db.STR - char1.msg(wintext % (char2, dmg)) - add_XP(char1, xp_gain) - char2.msg(failtext % (char1, dmg)) - char2.db.HP -= dmg - check_defeat(char2) - elif char2.db.combat+roll2 > char1.db.combat+roll1: - # char 2 hits - dmg = roll_dmg() + char2.db.STR - char1.msg(failtext % (char2, dmg)) - char1.db.HP -= dmg - check_defeat(char1) - char2.msg(wintext % (char1, dmg)) - add_XP(char2, xp_gain) - else: - # a draw - drawtext = "Neither of you can find an opening." - char1.msg(drawtext) - char2.msg(drawtext) - - -SKILLS = {"combat": skill_combat} - - -def roll_challenge(character1, character2, skillname): - """ - Determine the outcome of a skill challenge between - two characters based on the skillname given. - """ - if skillname in SKILLS: - SKILLS[skillname](character1, character2) - else: - raise RunTimeError("Skillname %s not found." % skillname) -``` - -These few functions implement the entirety of our simple rule system. We have a function to check -the "defeat" condition and reset the `HP` back to 100 again. We define a generic "skill" function. -Multiple skills could all be added with the same signature; our `SKILLS` dictionary makes it easy to -look up the skills regardless of what their actual functions are called. Finally, the access -function `roll_challenge` just picks the skill and gets the result. - -In this example, the skill function actually does a lot - it not only rolls results, it also informs -everyone of their results via `character.msg()` calls. - -### Attack Command - -Here is an example of usage in a game command: - -```python -from evennia import Command -from world import rules - -class CmdAttack(Command): - """ - attack an opponent - - Usage: - attack - - This will attack a target in the same room, dealing - damage with your bare hands. - """ - def func(self): - "Implementing combat" - - caller = self.caller - if not self.args: - caller.msg("You need to pick a target to attack.") - return - - target = caller.search(self.args) - if target: - rules.roll_challenge(caller, target, "combat") -``` - -Note how simple the command becomes and how generic you can make it. It becomes simple to offer any -number of Combat commands by just extending this functionality - you can easily roll challenges and -pick different skills to check. And if you ever decided to, say, change how to determine hit chance, -you don't have to change every command, but need only change the single `roll_hit` function inside -your `rules` module. - -### Training dummy -Create a dummy to test the attack command. Give it a `training_dummy` tag anything with the tag -`training_dummy` will not gain xp.
-> create/drop dummy:characters.Character
-tag dummy=training_dummy - -Attack it with your new command - -> attack dummy \ No newline at end of file diff --git a/docs/0.9.5/_sources/Inputfuncs.md.txt b/docs/0.9.5/_sources/Inputfuncs.md.txt deleted file mode 100644 index 7a708021a8..0000000000 --- a/docs/0.9.5/_sources/Inputfuncs.md.txt +++ /dev/null @@ -1,174 +0,0 @@ -# Inputfuncs - - -An *inputfunc* is an Evennia function that handles a particular input (an [inputcommand](./OOB.md)) from -the client. The inputfunc is the last destination for the inputcommand along the [ingoing message -path](./Messagepath.md#the-ingoing-message-path). The inputcommand always has the form `(commandname, -(args), {kwargs})` and Evennia will use this to try to find and call an inputfunc on the form - -```python - def commandname(session, *args, **kwargs): - # ... - -``` -Or, if no match was found, it will call an inputfunc named "default" on this form - -```python - def default(session, cmdname, *args, **kwargs): - # cmdname is the name of the mismatched inputcommand - -``` - -## Adding your own inputfuncs - -This is simple. Add a function on the above form to `mygame/server/conf/inputfuncs.py`. Your -function must be in the global, outermost scope of that module and not start with an underscore -(`_`) to be recognized as an inputfunc. Reload the server. That's it. To overload a default -inputfunc (see below), just add a function with the same name. - -The modules Evennia looks into for inputfuncs are defined in the list `settings.INPUT_FUNC_MODULES`. -This list will be imported from left to right and later imported functions will replace earlier -ones. - -## Default inputfuncs - -Evennia defines a few default inputfuncs to handle the common cases. These are defined in -`evennia/server/inputfuncs.py`. - -### text - - - Input: `("text", (textstring,), {})` - - Output: Depends on Command triggered - -This is the most common of inputcommands, and the only one supported by every traditional mud. The -argument is usually what the user sent from their command line. Since all text input from the user -like this is considered a [Command](./Commands.md), this inputfunc will do things like nick-replacement -and then pass on the input to the central Commandhandler. - -### echo - - - Input: `("echo", (args), {})` - - Output: `("text", ("Echo returns: %s" % args), {})` - -This is a test input, which just echoes the argument back to the session as text. Can be used for -testing custom client input. - -### default - -The default function, as mentioned above, absorbs all non-recognized inputcommands. The default one -will just log an error. - -### client_options - - - Input: `("client_options, (), {key:value, ...})` - - Output: - - normal: None - - get: `("client_options", (), {key:value, ...})` - -This is a direct command for setting protocol options. These are settable with the `@option` -command, but this offers a client-side way to set them. Not all connection protocols makes use of -all flags, but here are the possible keywords: - - - get (bool): If this is true, ignore all other kwargs and immediately return the current settings -as an outputcommand `("client_options", (), {key=value, ...})`- - - client (str): A client identifier, like "mushclient". - - version (str): A client version - - ansi (bool): Supports ansi colors - - xterm256 (bool): Supports xterm256 colors or not - - mxp (bool): Supports MXP or not - - utf-8 (bool): Supports UTF-8 or not - - screenreader (bool): Screen-reader mode on/off - - mccp (bool): MCCP compression on/off - - screenheight (int): Screen height in lines - - screenwidth (int): Screen width in characters - - inputdebug (bool): Debug input functions - - nomarkup (bool): Strip all text tags - - raw (bool): Leave text tags unparsed - -> Note that there are two GMCP aliases to this inputfunc - `hello` and `supports_set`, which means -it will be accessed via the GMCP `Hello` and `Supports.Set` instructions assumed by some clients. - -### get_client_options - - - Input: `("get_client_options, (), {key:value, ...})` - - Output: `("client_options, (), {key:value, ...})` - -This is a convenience wrapper that retrieves the current options by sending "get" to -`client_options` above. - -### get_inputfuncs - -- Input: `("get_inputfuncs", (), {})` -- Output: `("get_inputfuncs", (), {funcname:docstring, ...})` - -Returns an outputcommand on the form `("get_inputfuncs", (), {funcname:docstring, ...})` - a list of -all the available inputfunctions along with their docstrings. - -### login - -> Note: this is currently experimental and not very well tested. - - - Input: `("login", (username, password), {})` - - Output: Depends on login hooks - -This performs the inputfunc version of a login operation on the current Session. - -### get_value - -Input: `("get_value", (name, ), {})` -Output: `("get_value", (value, ), {})` - -Retrieves a value from the Character or Account currently controlled by this Session. Takes one -argument, This will only accept particular white-listed names, you'll need to overload the function -to expand. By default the following values can be retrieved: - - - "name" or "key": The key of the Account or puppeted Character. - - "location": Name of the current location, or "None". - - "servername": Name of the Evennia server connected to. - -### repeat - - - Input: `("repeat", (), {"callback":funcname, - "interval": secs, "stop": False})` - - Output: Depends on the repeated function. Will return `("text", (repeatlist),{}` with a list of -accepted names if given an unfamiliar callback name. - -This will tell evennia to repeatedly call a named function at a given interval. Behind the scenes -this will set up a [Ticker](./TickerHandler.md). Only previously acceptable functions are possible to -repeat-call in this way, you'll need to overload this inputfunc to add the ones you want to offer. -By default only two example functions are allowed, "test1" and "test2", which will just echo a text -back at the given interval. Stop the repeat by sending `"stop": True` (note that you must include -both the callback name and interval for Evennia to know what to stop). - -### unrepeat - - - Input: `("unrepeat", (), ("callback":funcname, - "interval": secs)` - - Output: None - -This is a convenience wrapper for sending "stop" to the `repeat` inputfunc. - -### monitor - - - Input: `("monitor", (), ("name":field_or_argname, stop=False)` - - Output (on change): `("monitor", (), {"name":name, "value":value})` - -This sets up on-object monitoring of Attributes or database fields. Whenever the field or Attribute -changes in any way, the outputcommand will be sent. This is using the -[MonitorHandler](./MonitorHandler.md) behind the scenes. Pass the "stop" key to stop monitoring. Note -that you must supply the name also when stopping to let the system know which monitor should be -cancelled. - -Only fields/attributes in a whitelist are allowed to be used, you have to overload this function to -add more. By default the following fields/attributes can be monitored: - - - "name": The current character name - - "location": The current location - - "desc": The description Argument - -## unmonitor - - - Input: `("unmonitor", (), {"name":name})` - - Output: None - -A convenience wrapper that sends "stop" to the `monitor` function. \ No newline at end of file diff --git a/docs/0.9.5/_sources/Installing-on-Android.md.txt b/docs/0.9.5/_sources/Installing-on-Android.md.txt deleted file mode 100644 index 0a41c3ee04..0000000000 --- a/docs/0.9.5/_sources/Installing-on-Android.md.txt +++ /dev/null @@ -1,143 +0,0 @@ -# Installing on Android - - -This page describes how to install and run the Evennia server on an Android phone. This will involve -installing a slew of third-party programs from the Google Play store, so make sure you are okay with -this before starting. - -## Install Termux - -The first thing to do is install a terminal emulator that allows a "full" version of linux to be -run. Note that Android is essentially running on top of linux so if you have a rooted phone, you may -be able to skip this step. You *don't* require a rooted phone to install Evennia though. - -Assuming we do not have root, we will install -[Termux](https://play.google.com/store/apps/details?id=com.termux&hl=en). -Termux provides a base installation of Linux essentials, including apt and Python, and makes them -available under a writeable directory. It also gives us a terminal where we can enter commands. By -default, Android doesn't give you permissions to the root folder, so Termux pretends that its own -installation directory is the root directory. - -Termux will set up a base system for us on first launch, but we will need to install some -prerequisites for Evennia. Commands you should run in Termux will look like this: - -``` -$ cat file.txt -``` -The `$` symbol is your prompt - do not include it when running commands. - -## Prerequisites - -To install some of the libraries Evennia requires, namely Pillow and Twisted, we have to first -install some packages they depend on. In Termux, run the following -``` -$ pkg install -y clang git zlib ndk-sysroot libjpeg-turbo libcrypt python -``` - -Termux ships with Python 3, perfect. Python 3 has venv (virtualenv) and pip (Python's module -installer) built-in. - -So, let's set up our virtualenv. This keeps the Python packages we install separate from the system -versions. - -``` -$ cd -$ python3 -m venv evenv -``` - -This will create a new folder, called `evenv`, containing the new python executable. -Next, let's activate our new virtualenv. Every time you want to work on Evennia, you need to run the -following command: - -``` -$ source evenv/bin/activate -``` - -Your prompt will change to look like this: -``` -(evenv) $ -``` -Update the updaters and installers in the venv: pip, setuptools and wheel. -``` -python3 -m pip install --upgrade pip setuptools wheel -``` - -### Installing Evennia - -Now that we have everything in place, we're ready to download and install Evennia itself. - -Mysterious incantations -``` -export LDFLAGS="-L/data/data/com.termux/files/usr/lib/" -export CFLAGS="-I/data/data/com.termux/files/usr/include/" -``` -(these tell clang, the C compiler, where to find the bits for zlib when building Pillow) - -Install the latest Evennia in a way that lets you edit the source -``` -(evenv) $ pip install --upgrade -e 'git+https://github.com/evennia/evennia#egg=evennia' -``` - -This step will possibly take quite a while - we are downloading Evennia and are then installing it, -building all of the requirements for Evennia to run. If you run into trouble on this step, please -see [Troubleshooting](./Installing-on-Android.md#troubleshooting). - -You can go to the dir where Evennia is installed with `cd $VIRTUAL_ENV/src/evennia`. `git grep -(something)` can be handy, as can `git diff` - -### Final steps - -At this point, Evennia is installed on your phone! You can now continue with the original [Getting -Started](./Getting-Started.md) instruction, we repeat them here for clarity. - -To start a new game: - -``` -(evenv) $ evennia --init mygame -(evenv) $ ls -mygame evenv -``` - -To start the game for the first time: - -``` -(evenv) $ cd mygame -(evenv) $ evennia migrate -(evenv) $ evennia start -``` - -Your game should now be running! Open a web browser at http://localhost:4001 or point a telnet -client to localhost:4000 and log in with the user you created. - -## Running Evennia - -When you wish to run Evennia, get into your Termux console and make sure you have activated your -virtualenv as well as are in your game's directory. You can then run evennia start as normal. - -``` -$ cd ~ && source evenv/bin/activate -(evenv) $ cd mygame -(evenv) $ evennia start -``` - -You may wish to look at the [Linux Instructions](./Getting-Started.md#linux-install) for more. - -## Caveats - -- Android's os module doesn't support certain functions - in particular getloadavg. Thusly, running -the command @server in-game will throw an exception. So far, there is no fix for this problem. -- As you might expect, performance is not amazing. -- Android is fairly aggressive about memory handling, and you may find that your server process is -killed if your phone is heavily taxed. Termux seems to keep a notification up to discourage this. - -## Troubleshooting - -As time goes by and errors are reported, this section will be added to. - -Some steps to try anyway: -* Make sure your packages are up-to-date, try running `pkg update && pkg upgrade -y` -* Make sure you've installed the clang package. If not, try `pkg install clang -y` -* Make sure you're in the right directory. `cd ~/mygame -* Make sure you've sourced your virtualenv. type `cd && source evenv/bin/activate` -* See if a shell will start: `cd ~/mygame ; evennia shell` -* Look at the log files in ~/mygame/server/logs/ \ No newline at end of file diff --git a/docs/0.9.5/_sources/Internationalization.md.txt b/docs/0.9.5/_sources/Internationalization.md.txt deleted file mode 100644 index f521221b41..0000000000 --- a/docs/0.9.5/_sources/Internationalization.md.txt +++ /dev/null @@ -1,88 +0,0 @@ -# Internationalization - - -*Internationalization* (often abbreviated *i18n* since there are 18 characters between the first "i" -and the last "n" in that word) allows Evennia's core server to return texts in other languages than -English - without anyone having to edit the source code. Take a look at the `locale` directory of -the Evennia installation, there you will find which languages are currently supported. - -## Changing server language - -Change language by adding the following to your `mygame/server/conf/settings.py` file: - -```python - USE_I18N = True - LANGUAGE_CODE = 'en' -``` - -Here `'en'` should be changed to the abbreviation for one of the supported languages found in -`locale/`. Restart the server to activate i18n. The two-character international language codes are -found [here](http://www.science.co.il/Language/Codes.asp). - -> Windows Note: If you get errors concerning `gettext` or `xgettext` on Windows, see the [Django -documentation](https://docs.djangoproject.com/en/1.7/topics/i18n/translation/#gettext-on-windows). A -self-installing and up-to-date version of gettext for Windows (32/64-bit) is available on -[Github](https://github.com/mlocati/gettext-iconv-windows). - -## Translating Evennia - -> **Important Note:** Evennia offers translations of hard-coded strings in the server, things like -"Connection closed" or "Server restarted", strings that end users will see and which game devs are -not supposed to change on their own. Text you see in the log file or on the command line (like error -messages) are generally *not* translated (this is a part of Python). - -> In addition, text in default Commands and in default Typeclasses will *not* be translated by -switching *i18n* language. To translate Commands and Typeclass hooks you must overload them in your -game directory and translate their returns to the language you want. This is because from Evennia's -perspective, adding *i18n* code to commands tend to add complexity to code that is *meant* to be -changed anyway. One of the goals of Evennia is to keep the user-changeable code as clean and easy- -to-read as possible. - -If you cannot find your language in `evennia/locale/` it's because noone has translated it yet. -Alternatively you might have the language but find the translation bad ... You are welcome to help -improve the situation! - -To start a new translation you need to first have cloned the Evennia repositry with GIT and -activated a python virtualenv as described on the [Getting Started](./Getting-Started.md) page. You now -need to `cd` to the `evennia/` directory. This is *not* your created game folder but the main -Evennia library folder. If you see a folder `locale/` then you are in the right place. From here you -run: - - evennia makemessages - -where `` is the [two-letter locale code](http://www.science.co.il/Language/Codes.asp) -for the language you want, like 'sv' for Swedish or 'es' for Spanish. After a moment it will tell -you the language has been processed. For instance: - - evennia makemessages sv - -If you started a new language a new folder for that language will have emerged in the `locale/` -folder. Otherwise the system will just have updated the existing translation with eventual new -strings found in the server. Running this command will not overwrite any existing strings so you can -run it as much as you want. - -> Note: in Django, the `makemessages` command prefixes the locale name by the `-l` option (`... -makemessages -l sv` for instance). This syntax is not allowed in Evennia, due to the fact that `-l` -is the option to tail log files. Hence, `makemessages` doesn't use the `-l` flag. - -Next head to `locale//LC_MESSAGES` and edit the `**.po` file you find there. You can -edit this with a normal text editor but it is easiest if you use a special po-file editor from the -web (search the web for "po editor" for many free alternatives). - -The concept of translating is simple, it's just a matter of taking the english strings you find in -the `**.po` file and add your language's translation best you can. The `**.po` format (and many -supporting editors) allow you to mark translations as "fuzzy". This tells the system (and future -translators) that you are unsure about the translation, or that you couldn't find a translation that -exactly matched the intention of the original text. Other translators will see this and might be -able to improve it later. -Finally, you need to compile your translation into a more efficient form. Do so from the `evennia` -folder -again: - - evennia compilemessages - -This will go through all languages and create/update compiled files (`**.mo`) for them. This needs -to be done whenever a `**.po` file is updated. - -When you are done, send the `**.po` and `*.mo` file to the Evennia developer list (or push it into -your own repository clone) so we can integrate your translation into Evennia! diff --git a/docs/0.9.5/_sources/Learn-Python-for-Evennia-The-Hard-Way.md.txt b/docs/0.9.5/_sources/Learn-Python-for-Evennia-The-Hard-Way.md.txt deleted file mode 100644 index fd7e22a3c6..0000000000 --- a/docs/0.9.5/_sources/Learn-Python-for-Evennia-The-Hard-Way.md.txt +++ /dev/null @@ -1,70 +0,0 @@ -# Learn Python for Evennia The Hard Way - -# WORK IN PROGRESS - DO NOT USE - -Evennia provides a great foundation to build your very own MU* whether you have programming -experience or none at all. Whilst Evennia has a number of in-game building commands and tutorials -available to get you started, when approaching game systems of any complexity it is advisable to -have the basics of Python under your belt before jumping into the code. There are many Python -tutorials freely available online however this page focuses on Learn Python the Hard Way (LPTHW) by -Zed Shaw. This tutorial takes you through the basics of Python and progresses you to creating your -very own online text based game. Whilst completing the course feel free to install Evennia and try -out some of our beginner tutorials. On completion you can return to this page, which will act as an -overview to the concepts separating your online text based game and the inner-workings of Evennia. --The latter portion of the tutorial focuses working your engine into a webpage and is not strictly -required for development in Evennia. - -## Exercise 23 -You may have returned here when you were invited to read some code. If you haven’t already, you -should now have the knowledge necessary to install Evennia. Head over to the Getting Started page -for install instructions. You can also try some of our tutorials to get you started on working with -Evennia. - -## Bridging the gap. -If you have successfully completed the Learn Python the Hard Way tutorial you should now have a -simple browser based Interactive Fiction engine which looks similar to this. -This engine is built using a single interactive object type, the Room class. The Room class holds a -description of itself that is presented to the user and a list of hardcoded commands which if -selected correctly will present you with the next rooms’ description and commands. Whilst your game -only has one interactive object, MU* have many more: Swords and shields, potions and scrolls or even -laser guns and robots. Even the player has an in-game representation in the form of your character. -Each of these examples are represented by their own object with their own description that can be -presented to the user. - -A basic object in Evennia has a number of default functions but perhaps most important is the idea -of location. In your text engine you receive a description of a room but you are not really in the -room because you have no in-game representation. However, in Evennia when you enter a Dungeon you -ARE in the dungeon. That is to say your character.location = Dungeon whilst the Dungeon.contents now -has a spunky young adventurer added to it. In turn, your character.contents may have amongst it a -number of swords and potions to help you on your adventure and their location would be you. - -In reality each of these “objects” are just an entry in your Evennia projects database which keeps -track of all these attributes, such as location and contents. Making changes to those attributes and -the rules in which they are changed is the most fundamental perspective of how your game works. We -define those rules in the objects Typeclass. The Typeclass is a Python class with a special -connection to the games database which changes values for us through various class methods. Let’s -look at your characters Typeclass rules for changing location. - - 1. `self.at_before_move(destination)` (if this returns False, move is aborted) - 2. `self.announce_move_from(destination)` - 3. (move happens here) - 4. `self.announce_move_to(source_location)` - 5. `self.at_after_move(source_location)` - -First we check if it’s okay to leave our current location, then we tell everyone there that we’re -leaving. We move locations and tell everyone at our new location that we’ve arrived before checking -we’re okay to be there. By default stages 1 and 5 are empty ready for us to add some rules. We’ll -leave an explanation as to how to make those changes for the tutorial section, but imagine if you -were an astronaut. A smart astronaut might stop at step 1 to remember to put his helmet on whilst a -slower astronaut might realise he’s forgotten in step 5 before shortly after ceasing to be an -astronaut. - -With all these objects and all this moving around it raises another problem. In your text engine the -commands available to the player were hard-coded to the room. That means if we have commands we -always want available to the player we’ll need to have those commands hard-coded on every single -room. What about an armoury? When all the swords are gone the command to take a sword would still -remain causing confusion. Evennia solves this problem by giving each object the ability to hold -commands. Rooms can have commands attached to them specific to that location, like climbing a tree; -Players can have commands which are always available to them, like ‘look’, ‘get’ and ‘say’; and -objects can have commands attached to them which unlock when taking possession of it, like attack -commands when obtaining a weapon. diff --git a/docs/0.9.5/_sources/Licensing.md.txt b/docs/0.9.5/_sources/Licensing.md.txt deleted file mode 100644 index 04520213d0..0000000000 --- a/docs/0.9.5/_sources/Licensing.md.txt +++ /dev/null @@ -1,32 +0,0 @@ -# Licensing - - -Evennia is licensed under the very friendly [BSD](http://en.wikipedia.org/wiki/BSD_license) -(3-clause) license. You can find the license as -[LICENSE.txt](https://github.com/evennia/evennia/blob/master/LICENSE.txt) in the Evennia -repository's root. - -**Q: When creating a game using Evennia, what does the license permit me to do with it?** - -**A:** It's your own game world to do with as you please! Keep it to yourself or re-distribute it -under another license of your choice - or sell it and become filthy rich for all we care. - -**Q: I have modified the Evennia library itself, what does the license say about that?** - -**A:** Our license allows you to do whatever you want with your modified Evennia, including -re-distributing or selling it, as long as you include our license and copyright info found in -`LICENSE.txt` along with your distribution. - -... Of course, if you fix bugs or add some new snazzy feature we *softly nudge* you to make those -changes available so they can be added to the core Evennia package for everyone's benefit. The -license doesn't *require* you to do it, but that doesn't mean we won't still greatly appreciate it -if you do! - -**Q: Can I re-distribute the Evennia server package along with my custom game implementation?** - -**A:** Sure. As long as the text in `LICENSE.txt` is included. - -**Q: What about Contributions?** - -The contributions in `evennia/evennia/contrib` are considered to be released under the same license -as Evennia itself, unless the individual contributor has specifically defined otherwise. diff --git a/docs/0.9.5/_sources/Links.md.txt b/docs/0.9.5/_sources/Links.md.txt deleted file mode 100644 index 21a73992ab..0000000000 --- a/docs/0.9.5/_sources/Links.md.txt +++ /dev/null @@ -1,176 +0,0 @@ -# Links - -*A list of resources that may be useful for Evennia users and developers.* - -### Official Evennia links - -- [evennia.com](http://www.evennia.com) - Main Evennia portal page. Links to all corners of Evennia. -- [Evennia github page](https://github.com/evennia/evennia) - Download code and read documentation. -- [Evennia official chat channel](http://webchat.freenode.net/?channels=evennia&uio=MT1mYWxzZSY5PXRydWUmMTE9MTk1JjEyPXRydWUbb) - Our official IRC chat #evennia at irc.freenode.net:6667. -- [Evennia forums/mailing list](http://groups.google.com/group/evennia) - Web interface to our -google group. -- [Evennia development blog](http://evennia.blogspot.se/) - Musings from the lead developer. -- [Evennia's manual on ReadTheDocs](http://readthedocs.org/projects/evennia/) - Read and download -offline in html, PDF or epub formats. -- [Evennia Game Index](http://games.evennia.com/) - An automated listing of Evennia games. ----- -- [Evennia on Open Hub](https://www.openhub.net/p/6906) -- [Evennia on OpenHatch](https://openhatch.org/projects/Evennia) -- [Evennia on PyPi](https://pypi.python.org/pypi/Evennia-MUD-Server/) -- [Evennia subreddit](http://www.reddit.com/r/Evennia/) (not much there yet though) - -### Third-party Evennia utilities and resources - -*For publicly available games running on Evennia, add and find those in the [Evennia game -index](http://games.evennia.com) instead!* - -- [Discord Evennia channel](https://discord.gg/NecFePw) - This is a fan-driven Discord channel with -a bridge to the official Evennia IRC channel. - ---- - -- [Discord live blog](https://discordapp.com/channels/517176782357528616/517176782781415434) of the -_Blackbirds_ Evennia game project. -- [Unreal Engine Evennia plugin](https://www.unrealengine.com/marketplace/en-US/slug/evennia-plugin) -- an in-progress Unreal plugin for integrating Evennia with Epic Games' Unreal Engine. -- [The dark net/March Hare MUD](https://github.com/thedarknet/evennia) from the 2019 [DEF CON -27](https://www.defcon.org/html/defcon-27/dc-27-index.html) hacker conference in Paris. This is an -Evennia game dir with batchcode to build the custom _Hackers_ style cyberspace zone with puzzles and -challenges [used during the conference](https://dcdark.net/home#). -- [Arx sources](https://github.com/Arx-Game/arxcode) - Open-source code release of the very popular -[Arx](http://play.arxmush.org/) Evennia game. [Here are instructions for installing](Arxcode- -installing-help) -- [Evennia-wiki](https://github.com/vincent-lg/evennia-wiki) - An Evennia-specific Wiki for your -website. -- [Evcolor](https://github.com/taladan/Pegasus/blob/origin/world/utilities/evcolor) - Optional -coloration for Evennia unit-test output. -- [Paxboards](https://github.com/aurorachain/paxboards) - Evennia bulletin board system (both for -telnet/web). -- [Encarnia sources](https://github.com/whitehorse-io/encarnia) - An open-sourced game dir for -Evennia with things like races, combat etc. [Summary -here](https://www.reddit.com/r/MUD/comments/6z6s3j/encarnia_an_evennia_python_mud_code_base_with/). -- [The world of Cool battles sources](https://github.com/FlutterSprite/coolbattles) - Open source -turn-based battle system for Evennia. It also has a [live demo](http://wcb.battlestudio.com/). -- [nextRPI](https://github.com/cluebyte/nextrpi) - A github project for making a toolbox for people -to make [RPI](http://www.topmudsites.com/forums/showthread.php?t=4804)-style Evennia games. -- [Muddery](https://github.com/muddery/muddery) - A mud framework under development, based on an -older fork of Evennia. It has some specific design goals for building and extending the game based -on input files. -- [vim-evennia](https://github.com/amfl/vim-evennia) - A mode for editing batch-build files (`.ev`) -files in the [vim](http://www.vim.org/) text editor (Emacs users can use [evennia- -mode.el](https://github.com/evennia/evennia/blob/master/evennia/utils/evennia-mode.el)). -- [Other Evennia-related repos on github](https://github.com/search?p=1&q=evennia) ----- -- [EvCast video series](https://www.youtube.com/playlist?list=PLyYMNttpc-SX1hvaqlUNmcxrhmM64pQXl) - -Tutorial videos explaining installing Evennia, basic Python etc. -- [Evennia-docker](https://github.com/gtaylor/evennia-docker) - Evennia in a [Docker -container](https://www.docker.com/) for quick install and deployment in just a few commands. -- [Evennia's docs in Chinese](http://www.evenniacn.com/) - A translated mirror of a slightly older -Evennia version. Announcement [here](https://groups.google.com/forum/#!topic/evennia/3AXS8ZTzJaA). -- [Evennia for MUSHers](http://musoapbox.net/topic/1150/evennia-for-mushers) - An article describing -Evennia for those used to the MUSH way of doing things. -- *[Language Understanding for Text games using Deep reinforcement -learning](http://news.mit.edu/2015/learning-language-playing-computer-games-0924#_msocom_1)* -([PDF](http://people.csail.mit.edu/karthikn/pdfs/mud-play15.pdf)) - MIT research paper using Evennia -to train AIs. - -### Other useful mud development resources - -- [ROM area reader](https://github.com/ctoth/area_reader) - Parser for converting ROM area files to -Python objects. -- [Gossip MUD chat network](https://gossip.haus/) - -### General MUD forums and discussions - -- [MUD Coder's Guild](https://mudcoders.com/) - A blog and [associated Slack -channel](https://slack.mudcoders.com/) with discussions on MUD development. -- [MuSoapbox](http://www.musoapbox.net/) - Very active Mu* game community mainly focused on MUSH- -type gaming. -- [Imaginary Realities](http://journal.imaginary-realities.com/) - An e-magazine on game and MUD -design that has several articles about Evennia. There is also an [archive of older -issues](http://disinterest.org/resource/imaginary-realities/) from 1998-2001 that are still very -relevant. -- [Optional Realities](http://optionalrealities.com/) - Mud development discussion forums that has -regular articles on MUD development focused on roleplay-intensive games. After a HD crash it's not -as content-rich as it once was. -- [MudLab](http://mudlab.org/) - Mud design discussion forum -- [MudConnector](http://www.mudconnect.com/) - Mud listing and forums -- [MudBytes](http://www.mudbytes.net/) - Mud listing and forums -- [Top Mud Sites](http://www.topmudsites.com/) - Mud listing and forums -- [Planet Mud-Dev](http://planet-muddev.disinterest.org/) - A blog aggregator following blogs of -current MUD development (including Evennia) around the 'net. Worth to put among your RSS -subscriptions. -- Mud Dev mailing list archive ([mirror](http://www.disinterest.org/resource/MUD-Dev/)) - -Influential mailing list active 1996-2004. Advanced game design discussions. -- [Mud-dev wiki](http://mud-dev.wikidot.com/) - A (very) slowly growing resource on MUD creation. -- [Mud Client/Server Interaction](http://cryosphere.net/mud-protocol.html) - A page on classic MUD -telnet protocols. -- [Mud Tech's fun/cool but ...](http://gc-taylor.com/blog/2013/01/08/mud-tech-funcool-dont-forget-ship-damned-thing/) - Greg Taylor gives good advice on mud design. -- [Lost Library of MOO](http://www.hayseed.net/MOO/) - Archive of scientific articles on mudding (in -particular moo). -- [Nick Gammon's hints thread](http://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=5959) - -Contains a very useful list of things to think about when starting your new MUD. -- [Lost Garden](http://www.lostgarden.com/) - A game development blog with long and interesting -articles (not MUD-specific) -- [What Games Are](http://whatgamesare.com/) - A blog about general game design (not MUD-specific) -- [The Alexandrian](http://thealexandrian.net/) - A blog about tabletop roleplaying and board games, -but with lots of general discussion about rule systems and game balance that could be applicable -also for MUDs. -- [Raph Koster's laws of game design](https://www.raphkoster.com/games/laws-of-online-world-design/the-laws-of-online-world-design/) - thought-provoking guidelines and things to think about -when designing a virtual multiplayer world (Raph is known for *Ultima Online* among other things). - -### Literature - -- Richard Bartle *Designing Virtual Worlds* ([amazon page](http://www.amazon.com/Designing-Virtual-Worlds-Richard-Bartle/dp/0131018167)) - Essential reading for the design of any persistent game -world, written by the co-creator of the original game *MUD*. Published in 2003 but it's still as -relevant now as when it came out. Covers everything you need to know and then some. -- Zed A. Shaw *Learn Python the Hard way* ([homepage](https://learnpythonthehardway.org/)) - Despite -the imposing name this book is for the absolute Python/programming beginner. One learns the language -by gradually creating a small text game! It has been used by multiple users before moving on to -Evennia. *Update: This used to be free to read online, this is no longer the case.* -- David M. Beazley *Python Essential Reference (4th ed)* ([amazon -page](http://www.amazon.com/Python-Essential-Reference-David-Beazley/dp/0672329786/)) - Our -recommended book on Python; it not only efficiently summarizes the language but is also an excellent -reference to the standard library for more experienced Python coders. -- Luciano Ramalho, *Fluent Python* ([o'reilly -page](http://shop.oreilly.com/product/0636920032519.do)) - This is an excellent book for experienced -Python coders willing to take their code to the next level. A great read with a lot of useful info -also for veteran Pythonistas. -- Richard Cantillon *An Essay on Economic Theory* ([free -pdf](http://mises.org/books/essay_on_economic_theory_cantillon.pdf)) - A very good English -translation of *Essai sur la Nature du Commerce en Général*, one of the foundations of modern -economic theory. Written in 1730 but the translation is annotated and the essay is actually very -easy to follow also for a modern reader. Required reading if you think of implementing a sane game -economic system. - -### Frameworks - -- [Django's homepage](http://www.djangoproject.com/) - - [Documentation](http://docs.djangoproject.com/en) - - [Code](http://code.djangoproject.com/) -- [Twisted homepage](http://twistedmatrix.com/) - - [Documentation](http://twistedmatrix.com/documents/current/core/howto/index.html) - - [Code](http://twistedmatrix.com/trac/browser) - -### Tools - -- [GIT](http://git-scm.com/) - - [Documentation](http://git-scm.com/documentation) - - [Learn GIT in 15 minutes](http://try.github.io/levels/1/challenges/1) (interactive tutorial) - -### Python Info - -- [Python Website](http://www.python.org/) - - [Documentation](http://www.python.org/doc/) - - [Tutorial](http://docs.python.org/tut/tut.html) - - [Library Reference](http://docs.python.org/lib/lib.html) - - [Language Reference](http://docs.python.org/ref/ref.html) - - [Python tips and tricks](http://www.siafoo.net/article/52) - - [Jetbrains Python academy](https://hyperskill.org/onboarding?track=python) - free online -programming curriculum for different skill levels - -### Credits - - - Wiki [Home](./index.md) Icons made by [Freepik](http://www.freepik.com"-title="Freepik">Freepik) from -[flaticon.com](http://www.flaticon.com), licensed under [Creative Commons BY -3.0](http://creativecommons.org/licenses/by/3.0). diff --git a/docs/0.9.5/_sources/Locks.md.txt b/docs/0.9.5/_sources/Locks.md.txt deleted file mode 100644 index dd1801f81d..0000000000 --- a/docs/0.9.5/_sources/Locks.md.txt +++ /dev/null @@ -1,495 +0,0 @@ -# Locks - - -For most games it is a good idea to restrict what people can do. In Evennia such restrictions are -applied and checked by something called *locks*. All Evennia entities ([Commands](./Commands.md), -[Objects](./Objects.md), [Scripts](./Scripts.md), [Accounts](./Accounts.md), [Help System](./Help-System.md), -[messages](./Communications.md#msg) and [channels](./Communications.md#channels)) are accessed through locks. - -A lock can be thought of as an "access rule" restricting a particular use of an Evennia entity. -Whenever another entity wants that kind of access the lock will analyze that entity in different -ways to determine if access should be granted or not. Evennia implements a "lockdown" philosophy - -all entities are inaccessible unless you explicitly define a lock that allows some or full access. - -Let's take an example: An object has a lock on itself that restricts how people may "delete" that -object. Apart from knowing that it restricts deletion, the lock also knows that only players with -the specific ID of, say, `34` are allowed to delete it. So whenever a player tries to run `delete` -on the object, the `delete` command makes sure to check if this player is really allowed to do so. -It calls the lock, which in turn checks if the player's id is `34`. Only then will it allow `delete` -to go on with its job. - -## Setting and checking a lock - -The in-game command for setting locks on objects is `lock`: - - > lock obj = - -The `` is a string of a certain form that defines the behaviour of the lock. We will go -into more detail on how `` should look in the next section. - -Code-wise, Evennia handles locks through what is usually called `locks` on all relevant entities. -This is a handler that allows you to add, delete and check locks. - -```python - myobj.locks.add() -``` - -One can call `locks.check()` to perform a lock check, but to hide the underlying implementation all -objects also have a convenience function called `access`. This should preferably be used. In the -example below, `accessing_obj` is the object requesting the 'delete' access whereas `obj` is the -object that might get deleted. This is how it would look (and does look) from inside the `delete` -command: - -```python - if not obj.access(accessing_obj, 'delete'): - accessing_obj.msg("Sorry, you may not delete that.") - return -``` - -## Defining locks - -Defining a lock (i.e. an access restriction) in Evennia is done by adding simple strings of lock -definitions to the object's `locks` property using `obj.locks.add()`. - -Here are some examples of lock strings (not including the quotes): - -```python - delete:id(34) # only allow obj #34 to delete - edit:all() # let everyone edit - # only those who are not "very_weak" or are Admins may pick this up - get: not attr(very_weak) or perm(Admin) -``` - -Formally, a lockstring has the following syntax: - -```python - access_type: [NOT] lockfunc1([arg1,..]) [AND|OR] [NOT] lockfunc2([arg1,...]) [...] -``` - -where `[]` marks optional parts. `AND`, `OR` and `NOT` are not case sensitive and excess spaces are -ignored. `lockfunc1, lockfunc2` etc are special _lock functions_ available to the lock system. - -So, a lockstring consists of the type of restriction (the `access_type`), a colon (`:`) and then an -expression involving function calls that determine what is needed to pass the lock. Each function -returns either `True` or `False`. `AND`, `OR` and `NOT` work as they do normally in Python. If the -total result is `True`, the lock is passed. - -You can create several lock types one after the other by separating them with a semicolon (`;`) in -the lockstring. The string below yields the same result as the previous example: - - delete:id(34);edit:all();get: not attr(very_weak) or perm(Admin) - - -### Valid access_types - -An `access_type`, the first part of a lockstring, defines what kind of capability a lock controls, -such as "delete" or "edit". You may in principle name your `access_type` anything as long as it is -unique for the particular object. The name of the access types is not case-sensitive. - -If you want to make sure the lock is used however, you should pick `access_type` names that you (or -the default command set) actually checks for, as in the example of `delete` above that uses the -'delete' `access_type`. - -Below are the access_types checked by the default commandset. - -- [Commands](./Commands.md) - - `cmd` - this defines who may call this command at all. -- [Objects](./Objects.md): - - `control` - who is the "owner" of the object. Can set locks, delete it etc. Defaults to the -creator of the object. - - `call` - who may call Object-commands stored on this Object except for the Object itself. By -default, Objects share their Commands with anyone in the same location (e.g. so you can 'press' a -`Button` object in the room). For Characters and Mobs (who likely only use those Commands for -themselves and don't want to share them) this should usually be turned off completely, using -something like `call:false()`. - - `examine` - who may examine this object's properties. - - `delete` - who may delete the object. - - `edit` - who may edit properties and attributes of the object. - - `view` - if the `look` command will display/list this object - - `get`- who may pick up the object and carry it around. - - `puppet` - who may "become" this object and control it as their "character". - - `attrcreate` - who may create new attributes on the object (default True) -- [Characters](./Objects.md#characters): - - Same as for Objects -- [Exits](./Objects.md#exits): - - Same as for Objects - - `traverse` - who may pass the exit. -- [Accounts](./Accounts.md): - - `examine` - who may examine the account's properties. - - `delete` - who may delete the account. - - `edit` - who may edit the account's attributes and properties. - - `msg` - who may send messages to the account. - - `boot` - who may boot the account. -- [Attributes](./Attributes.md): (only checked by `obj.secure_attr`) - - `attrread` - see/access attribute - - `attredit` - change/delete attribute -- [Channels](./Communications.md#channels): - - `control` - who is administrating the channel. This means the ability to delete the channel, -boot listeners etc. - - `send` - who may send to the channel. - - `listen` - who may subscribe and listen to the channel. -- [HelpEntry](./Help-System.md): - - `examine` - who may view this help entry (usually everyone) - - `edit` - who may edit this help entry. - -So to take an example, whenever an exit is to be traversed, a lock of the type *traverse* will be -checked. Defining a suitable lock type for an exit object would thus involve a lockstring `traverse: -`. - -### Custom access_types - -As stated above, the `access_type` part of the lock is simply the 'name' or 'type' of the lock. The -text is an arbitrary string that must be unique for an object. If adding a lock with the same -`access_type` as one that already exists on the object, the new one override the old one. - -For example, if you wanted to create a bulletin board system and wanted to restrict who can either -read a board or post to a board. You could then define locks such as: - -```python - obj.locks.add("read:perm(Player);post:perm(Admin)") -``` - -This will create a 'read' access type for Characters having the `Player` permission or above and a -'post' access type for those with `Admin` permissions or above (see below how the `perm()` lock -function works). When it comes time to test these permissions, simply check like this (in this -example, the `obj` may be a board on the bulletin board system and `accessing_obj` is the player -trying to read the board): - -```python - if not obj.access(accessing_obj, 'read'): - accessing_obj.msg("Sorry, you may not read that.") - return -``` - -### Lock functions - -A lock function is a normal Python function put in a place Evennia looks for such functions. The -modules Evennia looks at is the list `settings.LOCK_FUNC_MODULES`. *All functions* in any of those -modules will automatically be considered a valid lock function. The default ones are found in -`evennia/locks/lockfuncs.py` and you can start adding your own in `mygame/server/conf/lockfuncs.py`. -You can append the setting to add more module paths. To replace a default lock function, just add -your own with the same name. - -A lock function must always accept at least two arguments - the *accessing object* (this is the -object wanting to get access) and the *accessed object* (this is the object with the lock). Those -two are fed automatically as the first two arguments to the function when the lock is checked. Any -arguments explicitly given in the lock definition will appear as extra arguments. - -```python - # A simple example lock function. Called with e.g. `id(34)`. This is - # defined in, say mygame/server/conf/lockfuncs.py - - def id(accessing_obj, accessed_obj, *args, **kwargs): - if args: - wanted_id = args[0] - return accessing_obj.id == wanted_id - return False -``` - -The above could for example be used in a lock function like this: - -```python - # we have `obj` and `owner_object` from before - obj.locks.add("edit: id(%i)" % owner_object.id) -``` - -We could check if the "edit" lock is passed with something like this: - -```python - # as part of a Command's func() method, for example - if not obj.access(caller, "edit"): - caller.msg("You don't have access to edit this!") - return -``` - -In this example, everyone except the `caller` with the right `id` will get the error. - -> (Using the `*` and `**` syntax causes Python to magically put all extra arguments into a list -`args` and all keyword arguments into a dictionary `kwargs` respectively. If you are unfamiliar with -how `*args` and `**kwargs` work, see the Python manuals). - -Some useful default lockfuncs (see `src/locks/lockfuncs.py` for more): - -- `true()/all()` - give access to everyone -- `false()/none()/superuser()` - give access to none. Superusers bypass the check entirely and are -thus the only ones who will pass this check. -- `perm(perm)` - this tries to match a given `permission` property, on an Account firsthand, on a -Character second. See [below](./Locks.md#permissions). -- `perm_above(perm)` - like `perm` but requires a "higher" permission level than the one given. -- `id(num)/dbref(num)` - checks so the access_object has a certain dbref/id. -- `attr(attrname)` - checks if a certain [Attribute](./Attributes.md) exists on accessing_object. -- `attr(attrname, value)` - checks so an attribute exists on accessing_object *and* has the given -value. -- `attr_gt(attrname, value)` - checks so accessing_object has a value larger (`>`) than the given -value. -- `attr_ge, attr_lt, attr_le, attr_ne` - corresponding for `>=`, `<`, `<=` and `!=`. -- `holds(objid)` - checks so the accessing objects contains an object of given name or dbref. -- `inside()` - checks so the accessing object is inside the accessed object (the inverse of -`holds()`). -- `pperm(perm)`, `pid(num)/pdbref(num)` - same as `perm`, `id/dbref` but always looks for -permissions and dbrefs of *Accounts*, not on Characters. -- `serversetting(settingname, value)` - Only returns True if Evennia has a given setting or a -setting set to a given value. - -## Checking simple strings - -Sometimes you don't really need to look up a certain lock, you just want to check a lockstring. A -common use is inside Commands, in order to check if a user has a certain permission. The lockhandler -has a method `check_lockstring(accessing_obj, lockstring, bypass_superuser=False)` that allows this. - -```python - # inside command definition - if not self.caller.locks.check_lockstring(self.caller, "dummy:perm(Admin)"): - self.caller.msg("You must be an Admin or higher to do this!") - return -``` - -Note here that the `access_type` can be left to a dummy value since this method does not actually do -a Lock lookup. - -## Default locks - -Evennia sets up a few basic locks on all new objects and accounts (if we didn't, noone would have -any access to anything from the start). This is all defined in the root [Typeclasses](./Typeclasses.md) -of the respective entity, in the hook method `basetype_setup()` (which you usually don't want to -edit unless you want to change how basic stuff like rooms and exits store their internal variables). -This is called once, before `at_object_creation`, so just put them in the latter method on your -child object to change the default. Also creation commands like `create` changes the locks of -objects you create - for example it sets the `control` lock_type so as to allow you, its creator, to -control and delete the object. - -# Permissions - -> This section covers the underlying code use of permissions. If you just want to learn how to -practically assign permissions in-game, refer to the [Building Permissions](./Building-Permissions.md) -page, which details how you use the `perm` command. - -A *permission* is simply a list of text strings stored in the handler `permissions` on `Objects` -and `Accounts`. Permissions can be used as a convenient way to structure access levels and -hierarchies. It is set by the `perm` command. Permissions are especially handled by the `perm()` and -`pperm()` lock functions listed above. - -Let's say we have a `red_key` object. We also have red chests that we want to unlock with this key. - - perm red_key = unlocks_red_chests - -This gives the `red_key` object the permission "unlocks_red_chests". Next we lock our red chests: - - lock red chest = unlock:perm(unlocks_red_chests) - -What this lock will expect is to the fed the actual key object. The `perm()` lock function will -check the permissions set on the key and only return true if the permission is the one given. - -Finally we need to actually check this lock somehow. Let's say the chest has an command `open ` -sitting on itself. Somewhere in its code the command needs to figure out which key you are using and -test if this key has the correct permission: - -```python - # self.obj is the chest - # and used_key is the key we used as argument to - # the command. The self.caller is the one trying - # to unlock the chest - if not self.obj.access(used_key, "unlock"): - self.caller.msg("The key does not fit!") - return -``` - -All new accounts are given a default set of permissions defined by -`settings.PERMISSION_ACCOUNT_DEFAULT`. - -Selected permission strings can be organized in a *permission hierarchy* by editing the tuple -`settings.PERMISSION_HIERARCHY`. Evennia's default permission hierarchy is as follows: - - Developer # like superuser but affected by locks - Admin # can administrate accounts - Builder # can edit the world - Helper # can edit help files - Player # can chat and send tells (default level) - -(Also the plural form works, so you could use `Developers` etc too). - -> There is also a `Guest` level below `Player` that is only active if `settings.GUEST_ENABLED` is -set. This is never part of `settings.PERMISSION_HIERARCHY`. - -The main use of this is that if you use the lock function `perm()` mentioned above, a lock check for -a particular permission in the hierarchy will *also* grant access to those with *higher* hierarchy -access. So if you have the permission "Admin" you will also pass a lock defined as `perm(Builder)` -or any of those levels below "Admin". - -When doing an access check from an [Object](./Objects.md) or Character, the `perm()` lock function will -always first use the permissions of any Account connected to that Object before checking for -permissions on the Object. In the case of hierarchical permissions (Admins, Builders etc), the -Account permission will always be used (this stops an Account from escalating their permission by -puppeting a high-level Character). If the permission looked for is not in the hierarchy, an exact -match is required, first on the Account and if not found there (or if no Account is connected), then -on the Object itself. - -Here is how you use `perm` to give an account more permissions: - - perm/account Tommy = Builders - perm/account/del Tommy = Builders # remove it again - -Note the use of the `/account` switch. It means you assign the permission to the -[Accounts](./Accounts.md) Tommy instead of any [Character](./Objects.md) that also happens to be named -"Tommy". - -Putting permissions on the *Account* guarantees that they are kept, *regardless* of which Character -they are currently puppeting. This is especially important to remember when assigning permissions -from the *hierarchy tree* - as mentioned above, an Account's permissions will overrule that of its -character. So to be sure to avoid confusion you should generally put hierarchy permissions on the -Account, not on their Characters (but see also [quelling](./Locks.md#quelling)). - -Below is an example of an object without any connected account - -```python - obj1.permissions = ["Builders", "cool_guy"] - obj2.locks.add("enter:perm_above(Accounts) and perm(cool_guy)") - - obj2.access(obj1, "enter") # this returns True! -``` - -And one example of a puppet with a connected account: - -```python - account.permissions.add("Accounts") - puppet.permissions.add("Builders", "cool_guy") - obj2.locks.add("enter:perm_above(Accounts) and perm(cool_guy)") - - obj2.access(puppet, "enter") # this returns False! -``` - -## Superusers - -There is normally only one *superuser* account and that is the one first created when starting -Evennia (User #1). This is sometimes known as the "Owner" or "God" user. A superuser has more than -full access - it completely *bypasses* all locks so no checks are even run. This allows for the -superuser to always have access to everything in an emergency. But it also hides any eventual errors -you might have made in your lock definitions. So when trying out game systems you should either use -quelling (see below) or make a second Developer-level character so your locks get tested correctly. - -## Quelling - -The `quell` command can be used to enforce the `perm()` lockfunc to ignore permissions on the -Account and instead use the permissions on the Character only. This can be used e.g. by staff to -test out things with a lower permission level. Return to the normal operation with `unquell`. Note -that quelling will use the smallest of any hierarchical permission on the Account or Character, so -one cannot escalate one's Account permission by quelling to a high-permission Character. Also the -superuser can quell their powers this way, making them affectable by locks. - -## More Lock definition examples - - examine: attr(eyesight, excellent) or perm(Builders) - -You are only allowed to do *examine* on this object if you have 'excellent' eyesight (that is, has -an Attribute `eyesight` with the value `excellent` defined on yourself) or if you have the -"Builders" permission string assigned to you. - - open: holds('the green key') or perm(Builder) - -This could be called by the `open` command on a "door" object. The check is passed if you are a -Builder or has the right key in your inventory. - - cmd: perm(Builders) - -Evennia's command handler looks for a lock of type `cmd` to determine if a user is allowed to even -call upon a particular command or not. When you define a command, this is the kind of lock you must -set. See the default command set for lots of examples. If a character/account don't pass the `cmd` -lock type the command will not even appear in their `help` list. - - cmd: not perm(no_tell) - -"Permissions" can also be used to block users or implement highly specific bans. The above example -would be be added as a lock string to the `tell` command. This will allow everyone *not* having the -"permission" `no_tell` to use the `tell` command. You could easily give an account the "permission" -`no_tell` to disable their use of this particular command henceforth. - - -```python - dbref = caller.id - lockstring = "control:id(%s);examine:perm(Builders);delete:id(%s) or perm(Admin);get:all()" % -(dbref, dbref) - new_obj.locks.add(lockstring) -``` - -This is how the `create` command sets up new objects. In sequence, this permission string sets the -owner of this object be the creator (the one running `create`). Builders may examine the object -whereas only Admins and the creator may delete it. Everyone can pick it up. - -## A complete example of setting locks on an object - -Assume we have two objects - one is ourselves (not superuser) and the other is an [Object](./Objects.md) -called `box`. - - > create/drop box - > desc box = "This is a very big and heavy box." - -We want to limit which objects can pick up this heavy box. Let's say that to do that we require the -would-be lifter to to have an attribute *strength* on themselves, with a value greater than 50. We -assign it to ourselves to begin with. - - > set self/strength = 45 - -Ok, so for testing we made ourselves strong, but not strong enough. Now we need to look at what -happens when someone tries to pick up the the box - they use the `get` command (in the default set). -This is defined in `evennia/commands/default/general.py`. In its code we find this snippet: - -```python - if not obj.access(caller, 'get'): - if obj.db.get_err_msg: - caller.msg(obj.db.get_err_msg) - else: - caller.msg("You can't get that.") - return -``` - -So the `get` command looks for a lock with the type *get* (not so surprising). It also looks for an -[Attribute](./Attributes.md) on the checked object called _get_err_msg_ in order to return a customized -error message. Sounds good! Let's start by setting that on the box: - - > set box/get_err_msg = You are not strong enough to lift this box. - -Next we need to craft a Lock of type *get* on our box. We want it to only be passed if the accessing -object has the attribute *strength* of the right value. For this we would need to create a lock -function that checks if attributes have a value greater than a given value. Luckily there is already -such a one included in evennia (see `evennia/locks/lockfuncs.py`), called `attr_gt`. - -So the lock string will look like this: `get:attr_gt(strength, 50)`. We put this on the box now: - - lock box = get:attr_gt(strength, 50) - -Try to `get` the object and you should get the message that we are not strong enough. Increase your -strength above 50 however and you'll pick it up no problem. Done! A very heavy box! - -If you wanted to set this up in python code, it would look something like this: - -```python - - from evennia import create_object - - # create, then set the lock - box = create_object(None, key="box") - box.locks.add("get:attr_gt(strength, 50)") - - # or we can assign locks in one go right away - box = create_object(None, key="box", locks="get:attr_gt(strength, 50)") - - # set the attributes - box.db.desc = "This is a very big and heavy box." - box.db.get_err_msg = "You are not strong enough to lift this box." - - # one heavy box, ready to withstand all but the strongest... -``` - -## On Django's permission system - -Django also implements a comprehensive permission/security system of its own. The reason we don't -use that is because it is app-centric (app in the Django sense). Its permission strings are of the -form `appname.permstring` and it automatically adds three of them for each database model in the app -- for the app evennia/object this would be for example 'object.create', 'object.admin' and -'object.edit'. This makes a lot of sense for a web application, not so much for a MUD, especially -when we try to hide away as much of the underlying architecture as possible. - -The django permissions are not completely gone however. We use it for validating passwords during -login. It is also used exclusively for managing Evennia's web-based admin site, which is a graphical -front-end for the database of Evennia. You edit and assign such permissions directly from the web -interface. It's stand-alone from the permissions described above. diff --git a/docs/0.9.5/_sources/Manually-Configuring-Color.md.txt b/docs/0.9.5/_sources/Manually-Configuring-Color.md.txt deleted file mode 100644 index 8b4aa17b79..0000000000 --- a/docs/0.9.5/_sources/Manually-Configuring-Color.md.txt +++ /dev/null @@ -1,169 +0,0 @@ -# Manually Configuring Color - - -This is a small tutorial for customizing your character objects, using the example of letting users -turn on and off ANSI color parsing as an example. `@options NOCOLOR=True` will now do what this -tutorial shows, but the tutorial subject can be applied to other toggles you may want, as well. - -In the Building guide's [Colors](./TextTags.md#coloured-text) page you can learn how to add color to your -game by using special markup. Colors enhance the gaming experience, but not all users want color. -Examples would be users working from clients that don't support color, or people with various seeing -disabilities that rely on screen readers to play your game. Also, whereas Evennia normally -automatically detects if a client supports color, it may get it wrong. Being able to turn it on -manually if you know it **should** work could be a nice feature. - -So here's how to allow those users to remove color. It basically means you implementing a simple -configuration system for your characters. This is the basic sequence: - -1. Define your own default character typeclass, inheriting from Evennia's default. -1. Set an attribute on the character to control markup on/off. -1. Set your custom character class to be the default for new accounts. -1. Overload the `msg()` method on the typeclass and change how it uses markup. -1. Create a custom command to allow users to change their setting. - -## Setting up a custom Typeclass - -Create a new module in `mygame/typeclasses` named, for example, `mycharacter.py`. Alternatively you -can simply add a new class to 'mygamegame/typeclasses/characters.py'. - -In your new module(or characters.py), create a new [Typeclass](./Typeclasses.md) inheriting from -`evennia.DefaultCharacter`. We will also import `evennia.utils.ansi`, which we will use later. - -```python - from evennia import Character - from evennia.utils import ansi - - class ColorableCharacter(Character): - at_object_creation(self): - # set a color config value - self.db.config_color = True -``` - -Above we set a simple config value as an [Attribute](./Attributes.md). - -Let's make sure that new characters are created of this type. Edit your -`mygame/server/conf/settings.py` file and add/change `BASE_CHARACTER_TYPECLASS` to point to your new -character class. Observe that this will only affect *new* characters, not those already created. You -have to convert already created characters to the new typeclass by using the `@typeclass` command -(try on a secondary character first though, to test that everything works - you don't want to render -your root user unusable!). - - @typeclass/reset/force Bob = mycharacter.ColorableCharacter - -`@typeclass` changes Bob's typeclass and runs all its creation hooks all over again. The `/reset` -switch clears all attributes and properties back to the default for the new typeclass - this is -useful in this case to avoid ending up with an object having a "mixture" of properties from the old -typeclass and the new one. `/force` might be needed if you edit the typeclass and want to update the -object despite the actual typeclass name not having changed. - -## Overload the `msg()` method - -Next we need to overload the `msg()` method. What we want is to check the configuration value before -calling the main function. The original `msg` method call is seen in `evennia/objects/objects.py` -and is called like this: - -```python - msg(self, text=None, from_obj=None, session=None, options=None, **kwargs): -``` - -As long as we define a method on our custom object with the same name and keep the same number of -arguments/keywords we will overload the original. Here's how it could look: - -```python - class ColorableCharacter(Character): - # [...] - msg(self, text=None, from_obj=None, session=None, options=None, - **kwargs): - "our custom msg()" - if self.db.config_color is not None: # this would mean it was not set - if not self.db.config_color: - # remove the ANSI from the text - text = ansi.strip_ansi(text) - super().msg(text=text, from_obj=from_obj, - session=session, **kwargs) -``` - -Above we create a custom version of the `msg()` method. If the configuration Attribute is set, it -strips the ANSI from the text it is about to send, and then calls the parent `msg()` as usual. You -need to `@reload` before your changes become visible. - -There we go! Just flip the attribute `config_color` to False and your users will not see any color. -As superuser (assuming you use the Typeclass `ColorableCharacter`) you can test this with the `@py` -command: - - @py self.db.config_color = False - -## Custom color config command - -For completeness, let's add a custom command so users can turn off their color display themselves if -they want. - -In `mygame/commands`, create a new file, call it for example `configcmds.py` (it's likely that -you'll want to add other commands for configuration down the line). You can also copy/rename the -command template. - -```python - from evennia import Command - - class CmdConfigColor(Command): - """ - Configures your color - - Usage: - @togglecolor on|off - - This turns ANSI-colors on/off. - Default is on. - """ - - key = "@togglecolor" - aliases = ["@setcolor"] - - def func(self): - "implements the command" - # first we must remove whitespace from the argument - self.args = self.args.strip() - if not self.args or not self.args in ("on", "off"): - self.caller.msg("Usage: @setcolor on|off") - return - if self.args == "on": - self.caller.db.config_color = True - # send a message with a tiny bit of formatting, just for fun - self.caller.msg("Color was turned |won|W.") - else: - self.caller.db.config_color = False - self.caller.msg("Color was turned off.") -``` - -Lastly, we make this command available to the user by adding it to the default `CharacterCmdSet` in -`mygame/commands/default_cmdsets.py` and reloading the server. Make sure you also import the -command: - -```python -from mygame.commands import configcmds -class CharacterCmdSet(default_cmds.CharacterCmdSet): - # [...] - def at_cmdset_creation(self): - """ - Populates the cmdset - """ - super().at_cmdset_creation() - # - # any commands you add below will overload the default ones. - # - - # here is the only line that we edit - self.add(configcmds.CmdConfigColor()) -``` - -## More colors - -Apart from ANSI colors, Evennia also supports **Xterm256** colors (See [Colors](./TextTags.md#colored- -text)). The `msg()` method supports the `xterm256` keyword for manually activating/deactiving -xterm256. It should be easy to expand the above example to allow players to customize xterm256 -regardless of if Evennia thinks their client supports it or not. - -To get a better understanding of how `msg()` works with keywords, you can try this as superuser: - - @py self.msg("|123Dark blue with xterm256, bright blue with ANSI", xterm256=True) - @py self.msg("|gThis should be uncolored", nomarkup=True) diff --git a/docs/0.9.5/_sources/Mass-and-weight-for-objects.md.txt b/docs/0.9.5/_sources/Mass-and-weight-for-objects.md.txt deleted file mode 100644 index d8a43571c0..0000000000 --- a/docs/0.9.5/_sources/Mass-and-weight-for-objects.md.txt +++ /dev/null @@ -1,95 +0,0 @@ -# Mass and weight for objects - - -An easy addition to add dynamic variety to your world objects is to give them some mass. Why mass -and not weight? Weight varies in setting; for example things on the Moon weigh 1/6 as much. On -Earth's surface and in most environments, no relative weight factor is needed. - -In most settings, mass can be used as weight to spring a pressure plate trap or a floor giving way, -determine a character's burden weight for travel speed... The total mass of an object can -contribute to the force of a weapon swing, or a speeding meteor to give it a potential striking -force. - -#### Objects - -Now that we have reasons for keeping track of object mass, let's look at the default object class -inside your mygame/typeclasses/objects.py and see how easy it is to total up mass from an object and -its contents. - -```python -# inside your mygame/typeclasses/objects.py - -class Object(DefaultObject): -# [...] - def get_mass(self): - mass = self.attributes.get('mass', 1) # Default objects have 1 unit mass. - return mass + sum(obj.get_mass() for obj in self.contents) -``` - -Adding the `get_mass` definition to the objects you want to sum up the masses for is done with -Python's "sum" function which operates on all the contents, in this case by summing them to -return a total mass value. - -If you only wanted specific object types to have mass or have the new object type in a different -module, see [[Adding-Object-Typeclass-Tutorial]] with its Heavy class object. You could set the -default for Heavy types to something much larger than 1 gram or whatever unit you want to use. Any -non-default mass would be stored on the `mass` [[Attributes]] of the objects. - - -#### Characters and rooms - -You can add a `get_mass` definition to characters and rooms, also. - -If you were in a one metric-ton elevator with four other friends also wearing armor and carrying -gold bricks, you might wonder if this elevator's going to move, and how fast. - -Assuming the unit is grams and the elevator itself weights 1,000 kilograms, it would already be -`@set elevator/mass=1000000`, we're `@set me/mass=85000` and our armor is `@set armor/mass=50000`. -We're each carrying 20 gold bars each `@set gold bar/mass=12400` then step into the elevator and see -the following message in the elevator's appearance: `Elevator weight and contents should not exceed -3 metric tons.` Are we safe? Maybe not if you consider dynamic loading. But at rest: - -```python -# Elevator object knows when it checks itself: -if self.get_mass() < 3000000: - pass # Elevator functions as normal. -else: - pass # Danger! Alarm sounds, cable snaps, elevator stops... -``` - -#### Inventory -Example of listing mass of items in your inventory, don't forget to add it to your -default_cmdsets.py file: - -```python -from evennia import utils - -class CmdInventory(Command): - """ - view inventory - Usage: - inventory - inv - Switches: - /weight to display all available channels. - Shows your inventory: carrying, wielding, wearing, obscuring. - """ - - key = "inventory" - aliases = ["inv", "i"] - locks = "cmd:all()" - - def func(self): - "check inventory" - items = self.caller.contents - if not items: - string = "You are not carrying anything." - else: - table = utils.evtable.EvTable("name", "weight") - for item in items: - mass = item.get_mass() - table.add_row(item.name, mass) - string = f"|wYou are carrying:|n\n{table}" - self.caller.msg(string) - -``` diff --git a/docs/0.9.5/_sources/Messagepath.md.txt b/docs/0.9.5/_sources/Messagepath.md.txt deleted file mode 100644 index bf974b89fc..0000000000 --- a/docs/0.9.5/_sources/Messagepath.md.txt +++ /dev/null @@ -1,292 +0,0 @@ -# Messagepath - - -The main functionality of Evennia is to communicate with clients connected to it; a player enters -commands or their client queries for a gui update (ingoing data). The server responds or sends data -on its own as the game changes (outgoing data). It's important to understand how this flow of -information works in Evennia. - -## The ingoing message path - -We'll start by tracing data from the client to the server. Here it is in short: - - Client -> - PortalSession -> - PortalSessionhandler -> - (AMP) -> - ServerSessionHandler -> - ServerSession -> - Inputfunc - -### Client (ingoing) - -The client sends data to Evennia in two ways. - - - When first connecting, the client can send data to the server about its - capabilities. This is things like "I support xterm256 but not unicode" and is - mainly used when a Telnet client connects. This is called a "handshake" and - will generally set some flags on the [Portal Session](./Portal-And-Server.md) that - are later synced to the Server Session. Since this is not something the player - controls, we'll not explore this further here. - - The client can send an *inputcommand* to the server. Traditionally this only - happens when the player enters text on the command line. But with a custom - client GUI, a command could also come from the pressing of a button. Finally - the client may send commands based on a timer or some trigger. - -Exactly how the inputcommand looks when it travels from the client to Evennia -depends on the [Protocol](./Custom-Protocols.md) used: - - Telnet: A string. If GMCP or MSDP OOB protocols are used, this string will - be formatted in a special way, but it's still a raw string. If Telnet SSL is - active, the string will be encrypted. - - SSH: An encrypted string - - Webclient: A JSON-serialized string. - -### Portal Session (ingoing) - -Each client is connected to the game via a *Portal Session*, one per connection. This Session is -different depending on the type of connection (telnet, webclient etc) and thus know how to handle -that particular data type. So regardless of how the data arrives, the Session will identify the type -of the instruction and any arguments it should have. For example, the telnet protocol will figure -that anything arriving normally over the wire should be passed on as a "text" type. - -### PortalSessionHandler (ingoing) - -The *PortalSessionhandler* manages all connected Sessions in the Portal. Its `data_in` method -(called by each Portal Session) will parse the command names and arguments from the protocols and -convert them to a standardized form we call the *inputcommand*: - -```python - (commandname, (args), {kwargs}) -``` - -All inputcommands must have a name, but they may or may not have arguments and keyword arguments - -in fact no default inputcommands use kwargs at all. The most common inputcommand is "text", which -has the argument the player input on the command line: - -```python - ("text", ("look",), {}) -``` - -This inputcommand-structure is pickled together with the unique session-id of the Session to which -it belongs. This is then sent over the AMP connection. - -### ServerSessionHandler (ingoing) - -On the Server side, the AMP unpickles the data and associates the session id with the server-side -[Session](./Sessions.md). Data and Session are passed to the server-side `SessionHandler.data_in`. This -in turn calls `ServerSession.data_in()` - -### ServerSession (ingoing) - -The method `ServerSession.data_in` is meant to offer a single place to override if they want to -examine *all* data passing into the server from the client. It is meant to call the -`ssessionhandler.call_inputfuncs` with the (potentially processed) data (so this is technically a -sort of detour back to the sessionhandler). - -In `call_inputfuncs`, the inputcommand's name is compared against the names of all the *inputfuncs* -registered with the server. The inputfuncs are named the same as the inputcommand they are supposed -to handle, so the (default) inputfunc for handling our "look" command is called "text". These are -just normal functions and one can plugin new ones by simply putting them in a module where Evennia -looks for such functions. - -If a matching inputfunc is found, it will be called with the Session and the inputcommand's -arguments: - -```python - text(session, *("look",), **{}) -``` - - If no matching inputfunc is found, an inputfunc named "default" will be tried and if that is also -not found, an error will be raised. - -### Inputfunc - -The [Inputfunc](./Inputfuncs.md) must be on the form `func(session, *args, **kwargs)`. An exception is -the `default` inputfunc which has form `default(session, cmdname, *args, **kwargs)`, where `cmdname` -is the un-matched inputcommand string. - -This is where the message's path diverges, since just what happens next depends on the type of -inputfunc was triggered. In the example of sending "look", the inputfunc is named "text". It will -pass the argument to the `cmdhandler` which will eventually lead to the `look` command being -executed. - - -## The outgoing message path - -Next let's trace the passage from server to client. - - msg -> - ServerSession -> - ServerSessionHandler -> - (AMP) -> - PortalSessionHandler -> - PortalSession -> - Client - -### msg - -All outgoing messages start in the `msg` method. This is accessible from three places: - - - `Object.msg` - - `Account.msg` - - `Session.msg` - -The call sign of the `msg` method looks like this: - -```python - msg(text=None, from_obj=None, session=None, options=None, **kwargs) -``` - -For our purposes, what is important to know is that with the exception of `from_obj`, `session` and -`options`, all keywords given to the `msg` method is the name of an *outputcommand* and its -arguments. So `text` is actually such a command, taking a string as its argument. The reason `text` -sits as the first keyword argument is that it's so commonly used (`caller.msg("Text")` for example). -Here are some examples - -```python - msg("Hello!") # using the 'text' outputfunc - msg(prompt="HP:%i, SP: %i, MP: %i" % (HP, SP, MP)) - msg(mycommand=((1,2,3,4), {"foo": "bar"}) - -``` -Note the form of the `mycommand` outputfunction. This explicitly defines the arguments and keyword -arguments for the function. In the case of the `text` and `prompt` calls we just specify a string - -this works too: The system will convert this into a single argument for us later in the message -path. - -> Note: The `msg` method sits on your Object- and Account typeclasses. It means you can easily -override `msg` and make custom- or per-object modifications to the flow of data as it passes -through. - -### ServerSession (outgoing) - -Nothing is processed on the Session, it just serves as a gathering points for all different `msg`. -It immediately passes the data on to ... - -### ServerSessionHandler (outgoing) - -In the *ServerSessionhandler*, the keywords from the `msg` method are collated into one or more -*outputcommands* on a standardized form (identical to inputcommands): - -``` - (commandname, (args), {kwargs}) -``` - -This will intelligently convert different input to the same form. So `msg("Hello")` will end up as -an outputcommand `("text", ("Hello",), {})`. - -This is also the point where [Inlinefuncs](./TextTags.md#inline-functions) are parsed, depending on the -session to receive the data. Said data is pickled together with the Session id then sent over the -AMP bridge. - -### PortalSessionHandler (outgoing) - -After the AMP connection has unpickled the data and paired the session id to the matching -PortalSession, the handler next determines if this Session has a suitable method for handling the -outputcommand. - -The situation is analogous to how inputfuncs work, except that protocols are fixed things that don't -need a plugin infrastructure like the inputfuncs are handled. So instead of an "outputfunc", the -handler looks for methods on the PortalSession with names of the form `send_`. - -For example, the common sending of text expects a PortalSession method `send_text`. This will be -called as `send_text(*("Hello",), **{})`. If the "prompt" outputfunction was used, send_prompt is -called. In all other cases the `send_default(cmdname, *args, **kwargs)` will be called - this is the -case for all client-custom outputcommands, like when wanting to tell the client to update a graphic -or play a sound. - -### PortalSession (outgoing) - -At this point it is up to the session to convert the command into a form understood by this -particular protocol. For telnet, `send_text` will just send the argument as a string (since that is -what telnet clients expect when "text" is coming). If `send_default` was called (basically -everything that is not traditional text or a prompt), it will pack the data as an GMCP or MSDP -command packet if the telnet client supports either (otherwise it won't send at all). If sending to -the webclient, the data will get packed into a JSON structure at all times. - -### Client (outgoing) - -Once arrived at the client, the outputcommand is handled in the way supported by the client (or it -may be quietly ignored if not). "text" commands will be displayed in the main window while others -may trigger changes in the GUI or play a sound etc. - -### Full example of Outgoing Message - -For a full outgoing message, you need to have the outgoing function defined in the javascript. See -https://evennia.readthedocs.io/en/latest/Web-Client-Webclient.html for getting set up with custom -webclient code. Once you have a custom plugin defined and loaded, create a new function in the -plugin, onCustomFunc() for example: - -```javascript - var onCustomFunc = function(args, kwargs) { - var = args.var - console.log(var) - } -``` - -You'll also need to add the function to what the main plugin function returns: - -```javascript - return { - init: init, - onCustomFunc, - } -``` - -This defines the function and looks for "var" as a variable that is passed to it. Once you have this -in place in your custom plugin, you also need to update the static/webclient/js/webclient_gui.js -file to recognize the new function when it's called. First you should add a new function inside the -plugin_handler function to recognize the new function: - -```javascript - var onCustomFunc = function (cmdname, args, kwargs) { - for( let n=0; n < ordered_plugins.length; n++ ) { - let plugin = ordered_plugins[n]; - if( 'onCustomFunc' in plugin ) { - if( plugin.onCustomFunc(args, kwargs) ) { - // True -- means this plugin claims this command exclusively. - return; - } - } - } - } -``` - -This looks through all the plugins for a function that corresponds to the custom function being -called. Next, add the custom function to the return statement of the plugin handler: - -```javascript - return { - add: add, - onKeydown: onKeydown, - onBeforeUnload: onBeforeUnload, - onLoggedIn: onLoggedIn, - onText: onText, - onGotOptions: onGotOptions, - onPrompt: onPrompt, - onDefault: onDefault, - onSilence: onSilence, - onConnectionClose: onConnectionClose, - onSend: onSend, - init: init, - postInit: postInit, - onCustomFunc: onCustomFunc, - } -``` -Lastly, you will also need to need to add an entry to the Evennia emitter to tie the python function -call to this new javascript function (this is in the $(document).ready function): - -```javascript - Evennia.emitter.on("customFunc", plugin_handler.onCustomFunc); -``` - -Now you can make a call from your python code to the new custom function to pass information from -the server to the client: - -```python - character.msg(customFunc=({"var": "blarg"})) -``` - -When this code in your python is run, you should be able to see the "blarg" string printed in the -web client console. You should now be able to update the function call and definition to pass any -information needed between server and client. \ No newline at end of file diff --git a/docs/0.9.5/_sources/MonitorHandler.md.txt b/docs/0.9.5/_sources/MonitorHandler.md.txt deleted file mode 100644 index 8b49bd1684..0000000000 --- a/docs/0.9.5/_sources/MonitorHandler.md.txt +++ /dev/null @@ -1,79 +0,0 @@ -# MonitorHandler - - -The *MonitorHandler* is a system for watching changes in properties or Attributes on objects. A -monitor can be thought of as a sort of trigger that responds to change. - -The main use for the MonitorHandler is to report changes to the client; for example the client -Session may ask Evennia to monitor the value of the Characer's `health` attribute and report -whenever it changes. This way the client could for example update its health bar graphic as needed. - -## Using the MonitorHandler - -The MontorHandler is accessed from the singleton `evennia.MONITOR_HANDLER`. The code for the handler -is in `evennia.scripts.monitorhandler`. - -Here's how to add a new monitor: - -```python -from evennia import MONITOR_HANDLER - -MONITOR_HANDLER.add(obj, fieldname, callback, - idstring="", persistent=False, **kwargs) - -``` - - - `obj` ([Typeclassed](./Typeclasses.md) entity) - the object to monitor. Since this must be -typeclassed, it means you can't monitor changes on [Sessions](./Sessions.md) with the monitorhandler, for -example. - - `fieldname` (str) - the name of a field or [Attribute](./Attributes.md) on `obj`. If you want to -monitor a database field you must specify its full name, including the starting `db_` (like -`db_key`, `db_location` etc). Any names not starting with `db_` are instead assumed to be the names -of Attributes. This difference matters, since the MonitorHandler will automatically know to watch -the `db_value` field of the Attribute. - - `callback`(callable) - This will be called as `callback(fieldname=fieldname, obj=obj, **kwargs)` -when the field updates. - - `idstring` (str) - this is used to separate multiple monitors on the same object and fieldname. -This is required in order to properly identify and remove the monitor later. It's also used for -saving it. - - `persistent` (bool) - if True, the monitor will survive a server reboot. - -Example: - -```python -from evennia import MONITOR_HANDLER as monitorhandler - -def _monitor_callback(fieldname="", obj=None, **kwargs): - # reporting callback that works both - # for db-fields and Attributes - if fieldname.startswith("db_"): - new_value = getattr(obj, fieldname) - else: # an attribute - new_value = obj.attributes.get(fieldname) - - obj.msg("%s.%s changed to '%s'." % \ - (obj.key, fieldname, new_value)) - -# (we could add _some_other_monitor_callback here too) - -# monitor Attribute (assume we have obj from before) -monitorhandler.add(obj, "desc", _monitor_callback) - -# monitor same db-field with two different callbacks (must separate by id_string) -monitorhandler.add(obj, "db_key", _monitor_callback, id_string="foo") -monitorhandler.add(obj, "db_key", _some_other_monitor_callback, id_string="bar") - -``` - -A monitor is uniquely identified by the combination of the *object instance* it is monitoring, the -*name* of the field/attribute to monitor on that object and its `idstring` (`obj` + `fieldname` + -`idstring`). The `idstring` will be the empty string unless given explicitly. - -So to "un-monitor" the above you need to supply enough information for the system to uniquely find -the monitor to remove: - -``` -monitorhandler.remove(obj, "desc") -monitorhandler.remove(obj, "db_key", idstring="foo") -monitorhandler.remove(obj, "db_key", idstring="bar") -``` diff --git a/docs/0.9.5/_sources/NPC-shop-Tutorial.md.txt b/docs/0.9.5/_sources/NPC-shop-Tutorial.md.txt deleted file mode 100644 index e070750585..0000000000 --- a/docs/0.9.5/_sources/NPC-shop-Tutorial.md.txt +++ /dev/null @@ -1,334 +0,0 @@ -# NPC shop Tutorial - -This tutorial will describe how to make an NPC-run shop. We will make use of the [EvMenu](./EvMenu.md) -system to present shoppers with a menu where they can buy things from the store's stock. - -Our shop extends over two rooms - a "front" room open to the shop's customers and a locked "store -room" holding the wares the shop should be able to sell. We aim for the following features: - - - The front room should have an Attribute `storeroom` that points to the store room. - - Inside the front room, the customer should have a command `buy` or `browse`. This will open a -menu listing all items available to buy from the store room. - - A customer should be able to look at individual items before buying. - - We use "gold" as an example currency. To determine cost, the system will look for an Attribute -`gold_value` on the items in the store room. If not found, a fixed base value of 1 will be assumed. -The wealth of the customer should be set as an Attribute `gold` on the Character. If not set, they -have no gold and can't buy anything. - - When the customer makes a purchase, the system will check the `gold_value` of the goods and -compare it to the `gold` Attribute of the customer. If enough gold is available, this will be -deducted and the goods transferred from the store room to the inventory of the customer. - - We will lock the store room so that only people with the right key can get in there. - -### The shop menu - -We want to show a menu to the customer where they can list, examine and buy items in the store. This -menu should change depending on what is currently for sale. Evennia's *EvMenu* utility will manage -the menu for us. It's a good idea to [read up on EvMenu](./EvMenu.md) if you are not familiar with it. - -#### Designing the menu - -The shopping menu's design is straightforward. First we want the main screen. You get this when you -enter a shop and use the `browse` or `buy` command: - -``` -*** Welcome to ye Old Sword shop! *** - Things for sale (choose 1-3 to inspect, quit to exit): -_________________________________________________________ -1. A rusty sword (5 gold) -2. A sword with a leather handle (10 gold) -3. Excalibur (100 gold) -``` - -There are only three items to buy in this example but the menu should expand to however many items -are needed. When you make a selection you will get a new screen showing the options for that -particular item: - -``` -You inspect A rusty sword: - -This is an old weapon maybe once used by soldiers in some -long forgotten army. It is rusty and in bad condition. -__________________________________________________________ -1. Buy A rusty sword (5 gold) -2. Look for something else. -``` - -Finally, when you buy something, a brief message should pop up: - -``` -You pay 5 gold and purchase A rusty sword! -``` -or -``` -You cannot afford 5 gold for A rusty sword! -``` -After this you should be back to the top level of the shopping menu again and can continue browsing. - -#### Coding the menu - -EvMenu defines the *nodes* (each menu screen with options) as normal Python functions. Each node -must be able to change on the fly depending on what items are currently for sale. EvMenu will -automatically make the `quit` command available to us so we won't add that manually. For compactness -we will put everything needed for our shop in one module, `mygame/typeclasses/npcshop.py`. - -```python -# mygame/typeclasses/npcshop.py - -from evennia.utils import evmenu - -def menunode_shopfront(caller): - "This is the top-menu screen." - - shopname = caller.location.key - wares = caller.location.db.storeroom.contents - - # Wares includes all items inside the storeroom, including the - # door! Let's remove that from our for sale list. - wares = [ware for ware in wares if ware.key.lower() != "door"] - - text = "*** Welcome to %s! ***\n" % shopname - if wares: - text += " Things for sale (choose 1-%i to inspect);" \ - " quit to exit:" % len(wares) - else: - text += " There is nothing for sale; quit to exit." - - options = [] - for ware in wares: - # add an option for every ware in store - options.append({"desc": "%s (%s gold)" % - (ware.key, ware.db.gold_value or 1), - "goto": "menunode_inspect_and_buy"}) - return text, options -``` - -In this code we assume the caller to be *inside* the shop when accessing the menu. This means we can -access the shop room via `caller.location` and get its `key` to display as the shop's name. We also -assume the shop has an Attribute `storeroom` we can use to get to our stock. We loop over our goods -to build up the menu's options. - -Note that *all options point to the same menu node* called `menunode_inspect_and_buy`! We can't know -which goods will be available to sale so we rely on this node to modify itself depending on the -circumstances. Let's create it now. - -```python -# further down in mygame/typeclasses/npcshop.py - -def menunode_inspect_and_buy(caller, raw_string): - "Sets up the buy menu screen." - - wares = caller.location.db.storeroom.contents - # Don't forget, we will need to remove that pesky door again! - wares = [ware for ware in wares if ware.key.lower() != "door"] - iware = int(raw_string) - 1 - ware = wares[iware] - value = ware.db.gold_value or 1 - wealth = caller.db.gold or 0 - text = "You inspect %s:\n\n%s" % (ware.key, ware.db.desc) - - def buy_ware_result(caller): - "This will be executed first when choosing to buy." - if wealth >= value: - rtext = "You pay %i gold and purchase %s!" % \ - (value, ware.key) - caller.db.gold -= value - ware.move_to(caller, quiet=True) - else: - rtext = "You cannot afford %i gold for %s!" % \ - (value, ware.key) - caller.msg(rtext) - - options = ({"desc": "Buy %s for %s gold" % \ - (ware.key, ware.db.gold_value or 1), - "goto": "menunode_shopfront", - "exec": buy_ware_result}, - {"desc": "Look for something else", - "goto": "menunode_shopfront"}) - - return text, options -``` - -In this menu node we make use of the `raw_string` argument to the node. This is the text the menu -user entered on the *previous* node to get here. Since we only allow numbered options in our menu, -`raw_input` must be an number for the player to get to this point. So we convert it to an integer -index (menu lists start from 1, whereas Python indices always starts at 0, so we need to subtract -1). We then use the index to get the corresponding item from storage. - -We just show the customer the `desc` of the item. In a more elaborate setup you might want to show -things like weapon damage and special stats here as well. - -When the user choose the "buy" option, EvMenu will execute the `exec` instruction *before* we go -back to the top node (the `goto` instruction). For this we make a little inline function -`buy_ware_result`. EvMenu will call the function given to `exec` like any menu node but it does not -need to return anything. In `buy_ware_result` we determine if the customer can afford the cost and -give proper return messages. This is also where we actually move the bought item into the inventory -of the customer. - -#### The command to start the menu - -We could *in principle* launch the shopping menu the moment a customer steps into our shop room, but -this would probably be considered pretty annoying. It's better to create a [Command](./Commands.md) for -customers to explicitly wanting to shop around. - -```python -# mygame/typeclasses/npcshop.py - -from evennia import Command - -class CmdBuy(Command): - """ - Start to do some shopping - - Usage: - buy - shop - browse - - This will allow you to browse the wares of the - current shop and buy items you want. - """ - key = "buy" - aliases = ("shop", "browse") - - def func(self): - "Starts the shop EvMenu instance" - evmenu.EvMenu(self.caller, - "typeclasses.npcshop", - startnode="menunode_shopfront") -``` - -This will launch the menu. The `EvMenu` instance is initialized with the path to this very module - -since the only global functions available in this module are our menu nodes, this will work fine -(you could also have put those in a separate module). We now just need to put this command in a -[CmdSet](./Command-Sets.md) so we can add it correctly to the game: - -```python -from evennia import CmdSet - -class ShopCmdSet(CmdSet): - def at_cmdset_creation(self): - self.add(CmdBuy()) -``` - -### Building the shop - -There are really only two things that separate our shop from any other Room: - -- The shop has the `storeroom` Attribute set on it, pointing to a second (completely normal) room. -- It has the `ShopCmdSet` stored on itself. This makes the `buy` command available to users entering -the shop. - -For testing we could easily add these features manually to a room using `@py` or other admin -commands. Just to show how it can be done we'll instead make a custom [Typeclass](./Typeclasses.md) for -the shop room and make a small command that builders can use to build both the shop and the -storeroom at once. - -```python -# bottom of mygame/typeclasses/npcshop.py - -from evennia import DefaultRoom, DefaultExit, DefaultObject -from evennia.utils.create import create_object - -# class for our front shop room -class NPCShop(DefaultRoom): - def at_object_creation(self): - # we could also use add(ShopCmdSet, permanent=True) - self.cmdset.add_default(ShopCmdSet) - self.db.storeroom = None - -# command to build a complete shop (the Command base class -# should already have been imported earlier in this file) -class CmdBuildShop(Command): - """ - Build a new shop - - Usage: - @buildshop shopname - - This will create a new NPCshop room - as well as a linked store room (named - simply -storage) for the - wares on sale. The store room will be - accessed through a locked door in - the shop. - """ - key = "@buildshop" - locks = "cmd:perm(Builders)" - help_category = "Builders" - - def func(self): - "Create the shop rooms" - if not self.args: - self.msg("Usage: @buildshop ") - return - # create the shop and storeroom - shopname = self.args.strip() - shop = create_object(NPCShop, - key=shopname, - location=None) - storeroom = create_object(DefaultRoom, - key="%s-storage" % shopname, - location=None) - shop.db.storeroom = storeroom - # create a door between the two - shop_exit = create_object(DefaultExit, - key="back door", - aliases=["storage", "store room"], - location=shop, - destination=storeroom) - storeroom_exit = create_object(DefaultExit, - key="door", - location=storeroom, - destination=shop) - # make a key for accessing the store room - storeroom_key_name = "%s-storekey" % shopname - storeroom_key = create_object(DefaultObject, - key=storeroom_key_name, - location=shop) - # only allow chars with this key to enter the store room - shop_exit.locks.add("traverse:holds(%s)" % storeroom_key_name) - - # inform the builder about progress - self.caller.msg("The shop %s was created!" % shop) -``` - -Our typeclass is simple and so is our `buildshop` command. The command (which is for Builders only) -just takes the name of the shop and builds the front room and a store room to go with it (always -named `"-storage"`. It connects the rooms with a two-way exit. You need to add -`CmdBuildShop` [to the default cmdset](./Adding-Command-Tutorial.md#step-2-adding-the-command-to-a- -default-cmdset) before you can use it. Once having created the shop you can now `@teleport` to it or -`@open` a new exit to it. You could also easily expand the above command to automatically create -exits to and from the new shop from your current location. - -To avoid customers walking in and stealing everything, we create a [Lock](./Locks.md) on the storage -door. It's a simple lock that requires the one entering to carry an object named -`-storekey`. We even create such a key object and drop it in the shop for the new shop -keeper to pick up. - -> If players are given the right to name their own objects, this simple lock is not very secure and -you need to come up with a more robust lock-key solution. - -> We don't add any descriptions to all these objects so looking "at" them will not be too thrilling. -You could add better default descriptions as part of the `@buildshop` command or leave descriptions -this up to the Builder. - -### The shop is open for business! - -We now have a functioning shop and an easy way for Builders to create it. All you need now is to -`@open` a new exit from the rest of the game into the shop and put some sell-able items in the store -room. Our shop does have some shortcomings: - -- For Characters to be able to buy stuff they need to also have the `gold` Attribute set on -themselves. -- We manually remove the "door" exit from our items for sale. But what if there are other unsellable -items in the store room? What if the shop owner walks in there for example - anyone in the store -could then buy them for 1 gold. -- What if someone else were to buy the item we're looking at just before we decide to buy it? It -would then be gone and the counter be wrong - the shop would pass us the next item in the list. - -Fixing these issues are left as an exercise. - -If you want to keep the shop fully NPC-run you could add a [Script](./Scripts.md) to restock the shop's -store room regularly. This shop example could also easily be owned by a human Player (run for them -by a hired NPC) - the shop owner would get the key to the store room and be responsible for keeping -it well stocked. diff --git a/docs/0.9.5/_sources/New-Models.md.txt b/docs/0.9.5/_sources/New-Models.md.txt deleted file mode 100644 index 4d73365d86..0000000000 --- a/docs/0.9.5/_sources/New-Models.md.txt +++ /dev/null @@ -1,264 +0,0 @@ -# New Models - -*Note: This is considered an advanced topic.* - -Evennia offers many convenient ways to store object data, such as via Attributes or Scripts. This is -sufficient for most use cases. But if you aim to build a large stand-alone system, trying to squeeze -your storage requirements into those may be more complex than you bargain for. Examples may be to -store guild data for guild members to be able to change, tracking the flow of money across a game- -wide economic system or implement other custom game systems that requires the storage of custom data -in a quickly accessible way. Whereas [Tags](./Tags.md) or [Scripts](./Scripts.md) can handle many situations, -sometimes things may be easier to handle by adding your own database model. - -## Overview of database tables - -SQL-type databases (which is what Evennia supports) are basically highly optimized systems for -retrieving text stored in tables. A table may look like this - -``` - id | db_key | db_typeclass_path | db_permissions ... - ------------------------------------------------------------------ - 1 | Griatch | evennia.DefaultCharacter | Developers ... - 2 | Rock | evennia.DefaultObject | None ... -``` - -Each line is considerably longer in your database. Each column is referred to as a "field" and every -row is a separate object. You can check this out for yourself. If you use the default sqlite3 -database, go to your game folder and run - - evennia dbshell - -You will drop into the database shell. While there, try: - - sqlite> .help # view help - - sqlite> .tables # view all tables - - # show the table field names for objects_objectdb - sqlite> .schema objects_objectdb - - # show the first row from the objects_objectdb table - sqlite> select * from objects_objectdb limit 1; - - sqlite> .exit - -Evennia uses [Django](https://docs.djangoproject.com), which abstracts away the database SQL -manipulation and allows you to search and manipulate your database entirely in Python. Each database -table is in Django represented by a class commonly called a *model* since it describes the look of -the table. In Evennia, Objects, Scripts, Channels etc are examples of Django models that we then -extend and build on. - -## Adding a new database table - -Here is how you add your own database table/models: - -1. In Django lingo, we will create a new "application" - a subsystem under the main Evennia program. -For this example we'll call it "myapp". Run the following (you need to have a working Evennia -running before you do this, so make sure you have run the steps in [Getting Started](Getting- -Started) first): - - cd mygame/world - evennia startapp myapp - -1. A new folder `myapp` is created. "myapp" will also be the name (the "app label") from now on. We -chose to put it in the `world/` subfolder here, but you could put it in the root of your `mygame` if -that makes more sense. -1. The `myapp` folder contains a few empty default files. What we are -interested in for now is `models.py`. In `models.py` you define your model(s). Each model will be a -table in the database. See the next section and don't continue until you have added the models you -want. -1. You now need to tell Evennia that the models of your app should be a part of your database -scheme. Add this line to your `mygame/server/conf/settings.py`file (make sure to use the path where -you put `myapp` and don't forget the comma at the end of the tuple): - - ``` - INSTALLED_APPS = INSTALLED_APPS + ("world.myapp", ) - ``` - -1. From `mygame/`, run - - evennia makemigrations myapp - evennia migrate - -This will add your new database table to the database. If you have put your game under version -control (if not, [you should](./Version-Control.md)), don't forget to `git add myapp/*` to add all items -to version control. - -## Defining your models - -A Django *model* is the Python representation of a database table. It can be handled like any other -Python class. It defines *fields* on itself, objects of a special type. These become the "columns" -of the database table. Finally, you create new instances of the model to add new rows to the -database. - -We won't describe all aspects of Django models here, for that we refer to the vast [Django -documentation](https://docs.djangoproject.com/en/2.2/topics/db/models/) on the subject. Here is a -(very) brief example: - -```python -from django.db import models - -class MyDataStore(models.Model): - "A simple model for storing some data" - db_key = models.CharField(max_length=80, db_index=True) - db_category = models.CharField(max_length=80, null=True, blank=True) - db_text = models.TextField(null=True, blank=True) - # we need this one if we want to be - # able to store this in an Evennia Attribute! - db_date_created = models.DateTimeField('date created', editable=False, - auto_now_add=True, db_index=True) -``` - -We create four fields: two character fields of limited length and one text field which has no -maximum length. Finally we create a field containing the current time of us creating this object. - -> The `db_date_created` field, with exactly this name, is *required* if you want to be able to store -instances of your custom model in an Evennia [Attribute](./Attributes.md). It will automatically be set -upon creation and can after that not be changed. Having this field will allow you to do e.g. -`obj.db.myinstance = mydatastore`. If you know you'll never store your model instances in Attributes -the `db_date_created` field is optional. - -You don't *have* to start field names with `db_`, this is an Evennia convention. It's nevertheless -recommended that you do use `db_`, partly for clarity and consistency with Evennia (if you ever want -to share your code) and partly for the case of you later deciding to use Evennia's -`SharedMemoryModel` parent down the line. - -The field keyword `db_index` creates a *database index* for this field, which allows quicker -lookups, so it's recommended to put it on fields you know you'll often use in queries. The -`null=True` and `blank=True` keywords means that these fields may be left empty or set to the empty -string without the database complaining. There are many other field types and keywords to define -them, see django docs for more info. - -Similar to using [django-admin](https://docs.djangoproject.com/en/2.2/howto/legacy-databases/) you -are able to do `evennia inspectdb` to get an automated listing of model information for an existing -database. As is the case with any model generating tool you should only use this as a starting -point for your models. - -## Creating a new model instance - -To create a new row in your table, you instantiate the model and then call its `save()` method: - -```python - from evennia.myapp import MyDataStore - - new_datastore = MyDataStore(db_key="LargeSword", - db_category="weapons", - db_text="This is a huge weapon!") - # this is required to actually create the row in the database! - new_datastore.save() - -``` - -Note that the `db_date_created` field of the model is not specified. Its flag `at_now_add=True` -makes sure to set it to the current date when the object is created (it can also not be changed -further after creation). - -When you update an existing object with some new field value, remember that you have to save the -object afterwards, otherwise the database will not update: - -```python - my_datastore.db_key = "Larger Sword" - my_datastore.save() -``` - -Evennia's normal models don't need to explicitly save, since they are based on `SharedMemoryModel` -rather than the raw django model. This is covered in the next section. - -## Using the `SharedMemoryModel` parent - -Evennia doesn't base most of its models on the raw `django.db.models` but on the Evennia base model -`evennia.utils.idmapper.models.SharedMemoryModel`. There are two main reasons for this: - -1. Ease of updating fields without having to explicitly call `save()` -2. On-object memory persistence and database caching - -The first (and least important) point means that as long as you named your fields `db_*`, Evennia -will automatically create field wrappers for them. This happens in the model's -[Metaclass](http://en.wikibooks.org/wiki/Python_Programming/Metaclasses) so there is no speed -penalty for this. The name of the wrapper will be the same name as the field, minus the `db_` -prefix. So the `db_key` field will have a wrapper property named `key`. You can then do: - -```python - my_datastore.key = "Larger Sword" -``` - -and don't have to explicitly call `save()` afterwards. The saving also happens in a more efficient -way under the hood, updating only the field rather than the entire model using django optimizations. -Note that if you were to manually add the property or method `key` to your model, this will be used -instead of the automatic wrapper and allows you to fully customize access as needed. - -To explain the second and more important point, consider the following example using the default -Django model parent: - -```python - shield = MyDataStore.objects.get(db_key="SmallShield") - shield.cracked = True # where cracked is not a database field -``` - -And then later: - -```python - shield = MyDataStore.objects.get(db_key="SmallShield") - print(shield.cracked) # error! -``` - -The outcome of that last print statement is *undefined*! It could *maybe* randomly work but most -likely you will get an `AttributeError` for not finding the `cracked` property. The reason is that -`cracked` doesn't represent an actual field in the database. It was just added at run-time and thus -Django don't care about it. When you retrieve your shield-match later there is *no* guarantee you -will get back the *same Python instance* of the model where you defined `cracked`, even if you -search for the same database object. - -Evennia relies heavily on on-model handlers and other dynamically created properties. So rather than -using the vanilla Django models, Evennia uses `SharedMemoryModel`, which levies something called -*idmapper*. The idmapper caches model instances so that we will always get the *same* instance back -after the first lookup of a given object. Using idmapper, the above example would work fine and you -could retrieve your `cracked` property at any time - until you rebooted when all non-persistent data -goes. - -Using the idmapper is both more intuitive and more efficient *per object*; it leads to a lot less -reading from disk. The drawback is that this system tends to be more memory hungry *overall*. So if -you know that you'll *never* need to add new properties to running instances or know that you will -create new objects all the time yet rarely access them again (like for a log system), you are -probably better off making "plain" Django models rather than using `SharedMemoryModel` and its -idmapper. - -To use the idmapper and the field-wrapper functionality you just have to have your model classes -inherit from `evennia.utils.idmapper.models.SharedMemoryModel` instead of from the default -`django.db.models.Model`: - -```python -from evennia.utils.idmapper.models import SharedMemoryModel - -class MyDataStore(SharedMemoryModel): - # the rest is the same as before, but db_* is important; these will - # later be settable as .key, .category, .text ... - db_key = models.CharField(max_length=80, db_index=True) - db_category = models.CharField(max_length=80, null=True, blank=True) - db_text = models.TextField(null=True, blank=True) - db_date_created = models.DateTimeField('date created', editable=False, - auto_now_add=True, db_index=True) -``` - -## Searching for your models - -To search your new custom database table you need to use its database *manager* to build a *query*. -Note that even if you use `SharedMemoryModel` as described in the previous section, you have to use -the actual *field names* in the query, not the wrapper name (so `db_key` and not just `key`). - -```python - from world.myapp import MyDataStore - - # get all datastore objects exactly matching a given key - matches = MyDataStore.objects.filter(db_key="Larger Sword") - # get all datastore objects with a key containing "sword" - # and having the category "weapons" (both ignoring upper/lower case) - matches2 = MyDataStore.objects.filter(db_key__icontains="sword", - db_category__iequals="weapons") - # show the matching data (e.g. inside a command) - for match in matches2: - self.caller.msg(match.db_text) -``` - -See the [Django query documentation](https://docs.djangoproject.com/en/2.2/topics/db/queries/) for a -lot more information about querying the database. diff --git a/docs/0.9.5/_sources/Nicks.md.txt b/docs/0.9.5/_sources/Nicks.md.txt deleted file mode 100644 index a49406c0de..0000000000 --- a/docs/0.9.5/_sources/Nicks.md.txt +++ /dev/null @@ -1,124 +0,0 @@ -# Nicks - - -*Nicks*, short for *Nicknames* is a system allowing an object (usually a [Account](./Accounts.md)) to -assign custom replacement names for other game entities. - -Nicks are not to be confused with *Aliases*. Setting an Alias on a game entity actually changes an -inherent attribute on that entity, and everyone in the game will be able to use that alias to -address the entity thereafter. A *Nick* on the other hand, is used to map a different way *you -alone* can refer to that entity. Nicks are also commonly used to replace your input text which means -you can create your own aliases to default commands. - -Default Evennia use Nicks in three flavours that determine when Evennia actually tries to do the -substitution. - -- inputline - replacement is attempted whenever you write anything on the command line. This is the -default. -- objects - replacement is only attempted when referring to an object -- accounts - replacement is only attempted when referring an account - -Here's how to use it in the default command set (using the `nick` command): - - nick ls = look - -This is a good one for unix/linux users who are accustomed to using the `ls` command in their daily -life. It is equivalent to `nick/inputline ls = look`. - - nick/object mycar2 = The red sports car - -With this example, substitutions will only be done specifically for commands expecting an object -reference, such as - - look mycar2 - -becomes equivalent to "`look The red sports car`". - - nick/accounts tom = Thomas Johnsson - -This is useful for commands searching for accounts explicitly: - - @find *tom - -One can use nicks to speed up input. Below we add ourselves a quicker way to build red buttons. In -the future just writing *rb* will be enough to execute that whole long string. - - nick rb = @create button:examples.red_button.RedButton - -Nicks could also be used as the start for building a "recog" system suitable for an RP mud. - - nick/account Arnold = The mysterious hooded man - -The nick replacer also supports unix-style *templating*: - - nick build $1 $2 = @create/drop $1;$2 - -This will catch space separated arguments and store them in the the tags `$1` and `$2`, to be -inserted in the replacement string. This example allows you to do `build box crate` and have Evennia -see `@create/drop box;crate`. You may use any `$` numbers between 1 and 99, but the markers must -match between the nick pattern and the replacement. - -> If you want to catch "the rest" of a command argument, make sure to put a `$` tag *with no spaces -to the right of it* - it will then receive everything up until the end of the line. - -You can also use [shell-type wildcards](http://www.linfo.org/wildcard.html): - -- \* - matches everything. -- ? - matches a single character. -- [seq] - matches everything in the sequence, e.g. [xyz] will match both x, y and z -- [!seq] - matches everything *not* in the sequence. e.g. [!xyz] will match all but x,y z. - - - - - -## Coding with nicks - -Nicks are stored as the `Nick` database model and are referred from the normal Evennia -[object](./Objects.md) through the `nicks` property - this is known as the *NickHandler*. The NickHandler -offers effective error checking, searches and conversion. - -```python - # A command/channel nick: - obj.nicks.add("greetjack", "tell Jack = Hello pal!") - - # An object nick: - obj.nicks.add("rose", "The red flower", nick_type="object") - - # An account nick: - obj.nicks.add("tom", "Tommy Hill", nick_type="account") - - # My own custom nick type (handled by my own game code somehow): - obj.nicks.add("hood", "The hooded man", nick_type="my_identsystem") - - # get back the translated nick: - full_name = obj.nicks.get("rose", nick_type="object") - - # delete a previous set nick - object.nicks.remove("rose", nick_type="object") -``` - -In a command definition you can reach the nick handler through `self.caller.nicks`. See the `nick` -command in `evennia/commands/default/general.py` for more examples. - -As a last note, The Evennia [channel](./Communications.md) alias systems are using nicks with the -`nick_type="channel"` in order to allow users to create their own custom aliases to channels. - -# Advanced note - -Internally, nicks are [Attributes](./Attributes.md) saved with the `db_attrype` set to "nick" (normal -Attributes has this set to `None`). - -The nick stores the replacement data in the Attribute.db_value field as a tuple with four fields -`(regex_nick, template_string, raw_nick, raw_template)`. Here `regex_nick` is the converted regex -representation of the `raw_nick` and the `template-string` is a version of the `raw_template` -prepared for efficient replacement of any `$`- type markers. The `raw_nick` and `raw_template` are -basically the unchanged strings you enter to the `nick` command (with unparsed `$` etc). - -If you need to access the tuple for some reason, here's how: - -```python -tuple = obj.nicks.get("nickname", return_tuple=True) -# or, alternatively -tuple = obj.nicks.get("nickname", return_obj=True).value -``` \ No newline at end of file diff --git a/docs/0.9.5/_sources/OOB.md.txt b/docs/0.9.5/_sources/OOB.md.txt deleted file mode 100644 index efaa472c55..0000000000 --- a/docs/0.9.5/_sources/OOB.md.txt +++ /dev/null @@ -1,170 +0,0 @@ -# OOB - -OOB, or Out-Of-Band, means sending data between Evennia and the user's client without the user -prompting it or necessarily being aware that it's being passed. Common uses would be to update -client health-bars, handle client button-presses or to display certain tagged text in a different -window pane. - -## Briefly on input/outputcommands - -Inside Evennia, all server-client communication happens in the same way (so plain text is also an -'OOB message' as far as Evennia is concerned). The message follows the [Message Path](./Messagepath.md). -You should read up on that if you are unfamiliar with it. As the message travels along the path it -has a standardized internal form: a tuple with a string, a tuple and a dict: - - ("cmdname", (args), {kwargs}) - -This is often referred to as an *inputcommand* or *outputcommand*, depending on the direction it's -traveling. The end point for an inputcommand, (the 'Evennia-end' of the message path) is a matching -[Inputfunc](./Inputfuncs.md). This function is called as `cmdname(session, *args, **kwargs)` where -`session` is the Session-source of the command. Inputfuncs can easily be added by the developer to -support/map client commands to actions inside Evennia (see the [inputfunc](./Inputfuncs.md) page for more -details). - -When a message is outgoing (at the 'Client-end' of the message path) the outputcommand is handled by -a matching *Outputfunc*. This is responsible for converting the internal Evennia representation to a -form suitable to send over the wire to the Client. Outputfuncs are hard-coded. Which is chosen and -how it processes the outgoing data depends on the nature of the client it's connected to. The only -time one would want to add new outputfuncs is as part of developing support for a new Evennia -[Protocol](./Custom-Protocols.md). - -## Sending and receiving an OOB message - -Sending is simple. You just use the normal `msg` method of the object whose session you want to send -to. For example in a Command: - -```python - caller.msg(cmdname=((args, ...), {key:value, ...})) -``` - -A special case is the `text` input/outputfunc. It's so common that it's the default of the `msg` -method. So these are equivalent: - -```python - caller.msg("Hello") - caller.msg(text="Hello") -``` - -You don't have to specify the full output/input definition. So for example, if your particular -command only needs kwargs, you can skip the `(args)` part. Like in the `text` case you can skip -writing the tuple if there is only one arg ... and so on - the input is pretty flexible. If there -are no args at all you need to give the empty tuple `msg(cmdname=(,)` (giving `None` would mean a -single argument `None`). - -Which commands you can send depends on the client. If the client does not support an explicit OOB -protocol (like many old/legacy MUD clients) Evennia can only send `text` to them and will quietly -drop any other types of outputfuncs. - -> Remember that a given message may go to multiple clients with different capabilities. So unless -you turn off telnet completely and only rely on the webclient, you should never rely on non-`text` -OOB messages always reaching all targets. - -[Inputfuncs](./Inputfuncs.md) lists the default inputfuncs available to handle incoming OOB messages. To -accept more you need to add more inputfuncs (see that page for more info). - -## Supported OOB protocols - -Evennia supports clients using one of the following protocols: - -### Telnet - -By default telnet (and telnet+SSL) supports only the plain `text` outputcommand. Evennia however -detects if the Client supports one of two MUD-specific OOB *extensions* to the standard telnet -protocol - GMCP or MSDP. Evennia supports both simultaneously and will switch to the protocol the -client uses. If the client supports both, GMCP will be used. - -> Note that for Telnet, `text` has a special status as the "in-band" operation. So the `text` -outputcommand sends the `text` argument directly over the wire, without going through the OOB -translations described below. - -#### Telnet + GMCP - -[GMCP](http://www.gammon.com.au/gmcp), the *Generic Mud Communication Protocol* sends data on the -form `cmdname + JSONdata`. Here the cmdname is expected to be on the form "Package.Subpackage". -There could also be additional Sub-sub packages etc. The names of these 'packages' and 'subpackages' -are not that well standardized beyond what individual MUDs or companies have chosen to go with over -the years. You can decide on your own package names, but here are what others are using: - -- [Aardwolf GMCP](http://www.aardwolf.com/wiki/index.php/Clients/GMCP) -- [Discworld GMCP](http://discworld.starturtle.net/lpc/playing/documentation.c?path=/concepts/gmcp) -- [Avatar GMCP](http://www.outland.org/infusions/wiclear/index.php?title=MUD%20Protocols&lang=en) -- [IRE games GMCP](http://nexus.ironrealms.com/GMCP) - -Evennia will translate underscores to `.` and capitalize to fit the specification. So the -outputcommand `foo_bar` will become a GMCP command-name `Foo.Bar`. A GMCP command "Foo.Bar" will be -come `foo_bar`. To send a GMCP command that turns into an Evennia inputcommand without an -underscore, use the `Core` package. So `Core.Cmdname` becomes just `cmdname` in Evennia and vice -versa. - -On the wire, a GMCP instruction for `("cmdname", ("arg",), {})` will look like this: - - IAC SB GMCP "cmdname" "arg" IAC SE - -where all the capitalized words are telnet character constants specified in -`evennia/server/portal/telnet_oob.py`. These are parsed/added by the protocol and we don't include -these in the listings below. - -Input/Outputfunc | GMCP-Command ------------------- -`[cmd_name, [], {}]` | Cmd.Name -`[cmd_name, [arg], {}]` | Cmd.Name arg -`[cmd_na_me, [args],{}]` | Cmd.Na.Me [args] -`[cmd_name, [], {kwargs}]` | Cmd.Name {kwargs} -`[cmdname, [args, {kwargs}]` | Core.Cmdname [[args],{kwargs}] - -Since Evennia already supplies default inputfuncs that don't match the names expected by the most -common GMCP implementations we have a few hard-coded mappings for those: - -GMCP command name | Input/Outputfunc name ------------------ -"Core.Hello" | "client_options" -"Core.Supports.Get" | "client_options" -"Core.Commands.Get" | "get_inputfuncs" -"Char.Value.Get" | "get_value" -"Char.Repeat.Update" | "repeat" -"Char.Monitor.Update" | "monitor" - -#### Telnet + MSDP - -[MSDP](http://tintin.sourceforge.net/msdp/), the *Mud Server Data Protocol*, is a competing standard -to GMCP. The MSDP protocol page specifies a range of "recommended" available MSDP command names. -Evennia does *not* support those - since MSDP doesn't specify a special format for its command names -(like GMCP does) the client can and should just call the internal Evennia inputfunc by its actual -name. - -MSDP uses Telnet character constants to package various structured data over the wire. MSDP supports -strings, arrays (lists) and tables (dicts). These are used to define the cmdname, args and kwargs -needed. When sending MSDP for `("cmdname", ("arg",), {})` the resulting MSDP instruction will look -like this: - - IAC SB MSDP VAR cmdname VAL arg IAC SE - -The various available MSDP constants like `VAR` (variable), `VAL` (value), `ARRAYOPEN`/`ARRAYCLOSE` -and `TABLEOPEN`/`TABLECLOSE` are specified in `evennia/server/portal/telnet_oob`. - -Outputfunc/Inputfunc | MSDP instruction -------------------------- -`[cmdname, [], {}]` | VAR cmdname VAL -`[cmdname, [arg], {}]` | VAR cmdname VAL arg -`[cmdname, [args],{}]` | VAR cmdname VAL ARRAYOPEN VAL arg VAL arg ... ARRAYCLOSE -`[cmdname, [], {kwargs}]` | VAR cmdname VAL TABLEOPEN VAR key VAL val ... TABLECLOSE -`[cmdname, [args], {kwargs}]` | VAR cmdname VAL ARRAYOPEN VAL arg VAL arg ... ARRAYCLOSE VAR cmdname -VAL TABLEOPEN VAR key VAL val ... TABLECLOSE - -Observe that `VAR ... VAL` always identifies cmdnames, so if there are multiple arrays/dicts tagged -with the same cmdname they will be appended to the args, kwargs of that inputfunc. Vice-versa, a -different `VAR ... VAL` (outside a table) will come out as a second, different command input. - -### SSH - -SSH only supports the `text` input/outputcommand. - -### Web client - -Our web client uses pure JSON structures for all its communication, including `text`. This maps -directly to the Evennia internal output/inputcommand, including eventual empty args/kwargs. So the -same example `("cmdname", ("arg",), {})` will be sent/received as a valid JSON structure - - ["cmdname, ["arg"], {}] - -Since JSON is native to Javascript, this becomes very easy for the webclient to handle. diff --git a/docs/0.9.5/_sources/Objects.md.txt b/docs/0.9.5/_sources/Objects.md.txt deleted file mode 100644 index f0e8010df5..0000000000 --- a/docs/0.9.5/_sources/Objects.md.txt +++ /dev/null @@ -1,185 +0,0 @@ -# Objects - - -All in-game objects in Evennia, be it characters, chairs, monsters, rooms or hand grenades are -represented by an Evennia *Object*. Objects form the core of Evennia and is probably what you'll -spend most time working with. Objects are [Typeclassed](./Typeclasses.md) entities. - -## How to create your own object types - -An Evennia Object is, per definition, a Python class that includes `evennia.DefaultObject` among its -parents. In `mygame/typeclasses/objects.py` there is already a class `Object` that inherits from -`DefaultObject` and that you can inherit from. You can put your new typeclass directly in that -module or you could organize your code in some other way. Here we assume we make a new module -`mygame/typeclasses/flowers.py`: - -```python - # mygame/typeclasses/flowers.py - - from typeclasses.objects import Object - - class Rose(Object): - """ - This creates a simple rose object - """ - def at_object_creation(self): - "this is called only once, when object is first created" - # add a persistent attribute 'desc' - # to object (silly example). - self.db.desc = "This is a pretty rose with thorns." -``` - -You could save this in the `mygame/typeclasses/objects.py` (then you'd not need to import `Object`) -or you can put it in a new module. Let's say we do the latter, making a module -`typeclasses/flowers.py`. Now you just need to point to the class *Rose* with the `@create` command -to make a new rose: - - @create/drop MyRose:flowers.Rose - -What the `@create` command actually *does* is to use `evennia.create_object`. You can do the same -thing yourself in code: - -```python - from evennia import create_object - new_rose = create_object("typeclasses.flowers.Rose", key="MyRose") -``` - -(The `@create` command will auto-append the most likely path to your typeclass, if you enter the -call manually you have to give the full path to the class. The `create.create_object` function is -powerful and should be used for all coded object creating (so this is what you use when defining -your own building commands). Check out the `ev.create_*` functions for how to build other entities -like [Scripts](./Scripts.md)). - -This particular Rose class doesn't really do much, all it does it make sure the attribute -`desc`(which is what the `look` command looks for) is pre-set, which is pretty pointless since you -will usually want to change this at build time (using the `@desc` command or using the -[Spawner](./Spawner-and-Prototypes.md)). The `Object` typeclass offers many more hooks that is available -to use though - see next section. - -## Properties and functions on Objects - -Beyond the properties assigned to all [typeclassed](./Typeclasses.md) objects (see that page for a list -of those), the Object also has the following custom properties: - -- `aliases` - a handler that allows you to add and remove aliases from this object. Use -`aliases.add()` to add a new alias and `aliases.remove()` to remove one. -- `location` - a reference to the object currently containing this object. -- `home` is a backup location. The main motivation is to have a safe place to move the object to if -its `location` is destroyed. All objects should usually have a home location for safety. -- `destination` - this holds a reference to another object this object links to in some way. Its -main use is for [Exits](./Objects.md#exits), it's otherwise usually unset. -- `nicks` - as opposed to aliases, a [Nick](./Nicks.md) holds a convenient nickname replacement for a -real name, word or sequence, only valid for this object. This mainly makes sense if the Object is -used as a game character - it can then store briefer shorts, example so as to quickly reference game -commands or other characters. Use nicks.add(alias, realname) to add a new one. -- `account` - this holds a reference to a connected [Account](./Accounts.md) controlling this object (if -any). Note that this is set also if the controlling account is *not* currently online - to test if -an account is online, use the `has_account` property instead. -- `sessions` - if `account` field is set *and the account is online*, this is a list of all active -sessions (server connections) to contact them through (it may be more than one if multiple -connections are allowed in settings). -- `has_account` - a shorthand for checking if an *online* account is currently connected to this -object. -- `contents` - this returns a list referencing all objects 'inside' this object (i,e. which has this -object set as their `location`). -- `exits` - this returns all objects inside this object that are *Exits*, that is, has the -`destination` property set. - -The last two properties are special: - -- `cmdset` - this is a handler that stores all [command sets](./Command-Sets.md) defined on the -object (if any). -- `scripts` - this is a handler that manages [Scripts](./Scripts.md) attached to the object (if any). - -The Object also has a host of useful utility functions. See the function headers in -`src/objects/objects.py` for their arguments and more details. - -- `msg()` - this function is used to send messages from the server to an account connected to this -object. -- `msg_contents()` - calls `msg` on all objects inside this object. -- `search()` - this is a convenient shorthand to search for a specific object, at a given location -or globally. It's mainly useful when defining commands (in which case the object executing the -command is named `caller` and one can do `caller.search()` to find objects in the room to operate -on). -- `execute_cmd()` - Lets the object execute the given string as if it was given on the command line. -- `move_to` - perform a full move of this object to a new location. This is the main move method -and will call all relevant hooks, do all checks etc. -- `clear_exits()` - will delete all [Exits](./Objects.md#exits) to *and* from this object. -- `clear_contents()` - this will not delete anything, but rather move all contents (except Exits) to -their designated `Home` locations. -- `delete()` - deletes this object, first calling `clear_exits()` and - `clear_contents()`. - -The Object Typeclass defines many more *hook methods* beyond `at_object_creation`. Evennia calls -these hooks at various points. When implementing your custom objects, you will inherit from the -base parent and overload these hooks with your own custom code. See `evennia.objects.objects` for an -updated list of all the available hooks or the [API for DefaultObject -here](evennia.objects.objects.DefaultObject). - -## Subclasses of `Object` - -There are three special subclasses of *Object* in default Evennia - *Characters*, *Rooms* and -*Exits*. The reason they are separated is because these particular object types are fundamental, -something you will always need and in some cases requires some extra attention in order to be -recognized by the game engine (there is nothing stopping you from redefining them though). In -practice they are all pretty similar to the base Object. - -### Characters - -Characters are objects controlled by [Accounts](./Accounts.md). When a new Account -logs in to Evennia for the first time, a new `Character` object is created and -the Account object is assigned to the `account` attribute. A `Character` object -must have a [Default Commandset](./Command-Sets.md) set on itself at -creation, or the account will not be able to issue any commands! If you just -inherit your own class from `evennia.DefaultCharacter` and make sure to use -`super()` to call the parent methods you should be fine. In -`mygame/typeclasses/characters.py` is an empty `Character` class ready for you -to modify. - -### Rooms - -*Rooms* are the root containers of all other objects. The only thing really separating a room from -any other object is that they have no `location` of their own and that default commands like `@dig` -creates objects of this class - so if you want to expand your rooms with more functionality, just -inherit from `ev.DefaultRoom`. In `mygame/typeclasses/rooms.py` is an empty `Room` class ready for -you to modify. - -### Exits - -*Exits* are objects connecting other objects (usually *Rooms*) together. An object named *North* or -*in* might be an exit, as well as *door*, *portal* or *jump out the window*. An exit has two things -that separate them from other objects. Firstly, their *destination* property is set and points to a -valid object. This fact makes it easy and fast to locate exits in the database. Secondly, exits -define a special [Transit Command](./Commands.md) on themselves when they are created. This command is -named the same as the exit object and will, when called, handle the practicalities of moving the -character to the Exits's *destination* - this allows you to just enter the name of the exit on its -own to move around, just as you would expect. - -The exit functionality is all defined on the Exit typeclass, so you could in principle completely -change how exits work in your game (it's not recommended though, unless you really know what you are -doing). Exits are [locked](./Locks.md) using an access_type called *traverse* and also make use of a few -hook methods for giving feedback if the traversal fails. See `evennia.DefaultExit` for more info. -In `mygame/typeclasses/exits.py` there is an empty `Exit` class for you to modify. - -The process of traversing an exit is as follows: - -1. The traversing `obj` sends a command that matches the Exit-command name on the Exit object. The -[cmdhandler](./Commands.md) detects this and triggers the command defined on the Exit. Traversal always -involves the "source" (the current location) and the `destination` (this is stored on the Exit -object). -1. The Exit command checks the `traverse` lock on the Exit object -1. The Exit command triggers `at_traverse(obj, destination)` on the Exit object. -1. In `at_traverse`, `object.move_to(destination)` is triggered. This triggers the following hooks, -in order: - 1. `obj.at_before_move(destination)` - if this returns False, move is aborted. - 1. `origin.at_object_leave(obj, destination)` - 1. `obj.announce_move_from(destination)` - 1. Move is performed by changing `obj.location` from source location to `destination`. - 1. `obj.announce_move_to(source)` - 1. `destination.at_object_receive(obj, source)` - 1. `obj.at_after_move(source)` -1. On the Exit object, `at_after_traverse(obj, source)` is triggered. - -If the move fails for whatever reason, the Exit will look for an Attribute `err_traverse` on itself -and display this as an error message. If this is not found, the Exit will instead call -`at_failed_traverse(obj)` on itself. diff --git a/docs/0.9.5/_sources/Online-Setup.md.txt b/docs/0.9.5/_sources/Online-Setup.md.txt deleted file mode 100644 index c9f5c36ca8..0000000000 --- a/docs/0.9.5/_sources/Online-Setup.md.txt +++ /dev/null @@ -1,426 +0,0 @@ -# Online Setup - - -Evennia development can be made without any Internet connection beyond fetching updates. At some -point however, you are likely to want to make your game visible online, either as part opening it to -the public or to allow other developers or beta testers access to it. - -## Connecting from the outside - -Accessing your Evennia server from the outside is not hard on its own. Any issues are usually due to -the various security measures your computer, network or hosting service has. These will generally -(and correctly) block outside access to servers on your machine unless you tell them otherwise. - -We will start by showing how to host your server on your own local computer. Even if you plan to -host your "real" game on a remote host later, setting it up locally is useful practice. We cover -remote hosting later in this document. - -Out of the box, Evennia uses three ports for outward communication. If your computer has a firewall, -these should be open for in/out communication (and only these, other ports used by Evennia are -internal to your computer only). - - `4000`, telnet, for traditional mud clients - - `4001`, HTTP for the website) - - `4002`, websocket, for the web client - -Evennia will by default accept incoming connections on all interfaces (`0.0.0.0`) so in principle -anyone knowing the ports to use and has the IP address to your machine should be able to connect to -your game. - - - Make sure Evennia is installed and that you have activated the virtualenv. Start the server with -`evennia start --log`. The `--log` (or `-l`) will make sure that the logs are echoed to the -terminal. -> Note: If you need to close the log-view, use `Ctrl-C`. Use just `evennia --log` on its own to -start tailing the logs again. - - Make sure you can connect with your web browser to `http://localhost:4001` or, alternatively, -`http://127.0.0.1:4001` which is the same thing. You should get your Evennia web site and be able to -play the game in the web client. Also check so that you can connect with a mud client to host -`localhost`, port `4000` or host `127.0.0.1`, port `4000`. -- [Google for "my ip"](https://www.google.se/search?q=my+ip) or use any online service to figure out -what your "outward-facing" IP address is. For our purposes, let's say your outward-facing IP is -`203.0.113.0`. - - Next try your outward-facing IP by opening `http://203.0.113.0:4001` in a browser. If this works, -that's it! Also try telnet, with the server set to `203.0.113.0` and port `4000`. However, most -likely it will *not* work. If so, read on. - - If your computer has a firewall, it may be blocking the ports we need (it may also block telnet -overall). If so, you need to open the outward-facing ports to in/out communication. See the -manual/instructions for your firewall software on how to do this. To test you could also temporarily -turn off your firewall entirely to see if that was indeed the problem. - - Another common problem for not being able to connect is that you are using a hardware router -(like a wifi router). The router sits 'between' your computer and the Internet. So the IP you find -with Google is the *router's* IP, not that of your computer. To resolve this you need to configure -your router to *forward* data it gets on its ports to the IP and ports of your computer sitting in -your private network. How to do this depends on the make of your router; you usually configure it -using a normal web browser. In the router interface, look for "Port forwarding" or maybe "Virtual -server". If that doesn't work, try to temporarily wire your computer directly to the Internet outlet -(assuming your computer has the ports for it). You'll need to check for your IP again. If that -works, you know the problem is the router. - -> Note: If you need to reconfigure a router, the router's Internet-facing ports do *not* have to -have to have the same numbers as your computer's (and Evennia's) ports! For example, you might want -to connect Evennia's outgoing port 4001 to an outgoing router port 80 - this is the port HTTP -requests use and web browsers automatically look for - if you do that you could go to -`http://203.0.113.0` without having to add the port at the end. This would collide with any other -web services you are running through this router though. - -### Settings example - -You can connect Evennia to the Internet without any changes to your settings. The default settings -are easy to use but are not necessarily the safest. You can customize your online presence in your -[settings file](./Server-Conf.md#settings-file). To have Evennia recognize changed port settings you have -to do a full `evennia reboot` to also restart the Portal and not just the Server component. - -Below is an example of a simple set of settings, mostly using the defaults. Evennia will require -access to five computer ports, of which three (only) should be open to the outside world. Below we -continue to assume that our server address is `203.0.113.0`. - -```python -# in mygame/server/conf/settings.py - -SERVERNAME = "MyGame" - -# open to the internet: 4000, 4001, 4002 -# closed to the internet (internal use): 4005, 4006 -TELNET_PORTS = [4000] -WEBSOCKET_CLIENT_PORT = 4002 -WEBSERVER_PORTS = [(4001, 4005)] -AMP_PORT = 4006 - -# Optional - security measures limiting interface access -# (don't set these before you know things work without them) -TELNET_INTERFACES = ['203.0.113.0'] -WEBSOCKET_CLIENT_INTERFACE = '203.0.113.0' -ALLOWED_HOSTS = [".mymudgame.com"] - -# uncomment if you want to lock the server down for maintenance. -# LOCKDOWN_MODE = True - -``` - -Read on for a description of the individual settings. - -### Telnet - -```python -# Required. Change to whichever outgoing Telnet port(s) -# you are allowed to use on your host. -TELNET_PORTS = [4000] -# Optional for security. Restrict which telnet -# interfaces we should accept. Should be set to your -# outward-facing IP address(es). Default is ´0.0.0.0´ -# which accepts all interfaces. -TELNET_INTERFACES = ['0.0.0.0'] -``` - -The `TELNET_*` settings are the most important ones for getting a traditional base game going. Which -IP addresses you have available depends on your server hosting solution (see the next sections). -Some hosts will restrict which ports you are allowed you use so make sure to check. - -### Web server - -```python -# Required. This is a list of tuples -# (outgoing_port, internal_port). Only the outgoing -# port should be open to the world! -# set outgoing port to 80 if you want to run Evennia -# as the only web server on your machine (if available). -WEBSERVER_PORTS = [(4001, 4005)] -# Optional for security. Change this to the IP your -# server can be reached at (normally the same -# as TELNET_INTERFACES) -WEBSERVER_INTERFACES = ['0.0.0.0'] -# Optional for security. Protects against -# man-in-the-middle attacks. Change it to your server's -# IP address or URL when you run a production server. -ALLOWED_HOSTS = ['*'] -``` - -The web server is always configured with two ports at a time. The *outgoing* port (`4001` by -default) is the port external connections can use. If you don't want users to have to specify the -port when they connect, you should set this to `80` - this however only works if you are not running -any other web server on the machine. -The *internal* port (`4005` by default) is used internally by Evennia to communicate between the -Server and the Portal. It should not be available to the outside world. You usually only need to -change the outgoing port unless the default internal port is clashing with some other program. - -### Web client - -```python -# Required. Change this to the main IP address of your server. -WEBSOCKET_CLIENT_INTERFACE = '0.0.0.0' -# Optional and needed only if using a proxy or similar. Change -# to the IP or address where the client can reach -# your server. The ws:// part is then required. If not given, the client -# will use its host location. -WEBSOCKET_CLIENT_URL = "" -# Required. Change to a free port for the websocket client to reach -# the server on. This will be automatically appended -# to WEBSOCKET_CLIENT_URL by the web client. -WEBSOCKET_CLIENT_PORT = 4002 -``` - -The websocket-based web client needs to be able to call back to the server, and these settings must -be changed for it to find where to look. If it cannot find the server you will get an warning in -your browser's Console (in the dev tools of the browser), and the client will revert to the AJAX- -based of the client instead, which tends to be slower. - -### Other ports - -```python -# Optional public facing. Only allows SSL connections (off by default). -SSL_PORTS = [4003] -SSL_INTERFACES = ['0.0.0.0'] -# Optional public facing. Only if you allow SSH connections (off by default). -SSH_PORTS = [4004] -SSH_INTERFACES = ['0.0.0.0'] -# Required private. You should only change this if there is a clash -# with other services on your host. Should NOT be open to the -# outside world. -AMP_PORT = 4006 -``` - -The `AMP_PORT` is required to work, since this is the internal port linking Evennia's -[Server and Portal](../Components/Portal-And-Server.md) components together. The other ports are encrypted ports that may be -useful for custom protocols but are otherwise not used. - -### Lockdown mode - -When you test things out and check configurations you may not want players to drop in on you. -Similarly, if you are doing maintenance on a live game you may want to take it offline for a while -to fix eventual problems without risking people connecting. To do this, stop the server with -`evennia stop` and add `LOCKDOWN_MODE = True` to your settings file. When you start the server -again, your game will only be accessible from localhost. - -### Registering with the Evennia game directory - -Once your game is online you should make sure to register it with the [Evennia Game -Index](http://games.evennia.com/). Registering with the index will help people find your server, -drum up interest for your game and also shows people that Evennia is being used. You can do this -even if you are just starting development - if you don't give any telnet/web address it will appear -as _Not yet public_ and just be a teaser. If so, pick _pre-alpha_ as the development status. - -To register, stand in your game dir, run - - evennia connections - -and follow the instructions. See the [Game index page](./Evennia-Game-Index.md) for more details. - -## SSL - -SSL can be very useful for web clients. It will protect the credentials and gameplay of your users -over a web client if they are in a public place, and your websocket can also be switched to WSS for -the same benefit. SSL certificates used to cost money on a yearly basis, but there is now a program -that issues them for free with assisted setup to make the entire process less painful. - -Options that may be useful in combination with an SSL proxy: - -``` -# See above for the section on Lockdown Mode. -# Useful for a proxy on the public interface connecting to Evennia on localhost. -LOCKDOWN_MODE = True - -# Have clients communicate via wss after connecting with https to port 4001. -# Without this, you may get DOMException errors when the browser tries -# to create an insecure websocket from a secure webpage. -WEBSOCKET_CLIENT_URL = "wss://fqdn:4002" -``` - -### Let's Encrypt - -[Let's Encrypt](https://letsencrypt.org) is a certificate authority offering free certificates to -secure a website with HTTPS. To get started issuing a certificate for your web server using Let's -Encrypt, see these links: - - - [Let's Encrypt - Getting Started](https://letsencrypt.org/getting-started/) - - The [CertBot Client](https://certbot.eff.org/) is a program for automatically obtaining a -certificate, use it and maintain it with your website. - -Also, on Freenode visit the #letsencrypt channel for assistance from the community. For an -additional resource, Let's Encrypt has a very active [community -forum](https://community.letsencrypt.org/). - -[A blog where someone sets up Let's Encrypt](https://www.digitalocean.com/community/tutorials/how- -to-secure-apache-with-let-s-encrypt-on-ubuntu-16-04) - -The only process missing from all of the above documentation is how to pass verification. This is -how Let's Encrypt verifies that you have control over your domain (not necessarily ownership, it's -Domain Validation (DV)). This can be done either with configuring a certain path on your web server -or through a TXT record in your DNS. Which one you will want to do is a personal preference, but can -also be based on your hosting choice. In a controlled/cPanel environment, you will most likely have -to use DNS verification. - -## Relevant SSL Proxy Setup Information -- [Apache webserver configuration](./Apache-Config.md) (optional) -- [HAProxy Config](./HAProxy-Config.md) - -## Hosting locally or remotely? - -### Using your own computer as a server - -What we showed above is by far the simplest and probably cheapest option: Run Evennia on your own -home computer. Moreover, since Evennia is its own web server, you don't need to install anything -extra to have a website. - -**Advantages** -- Free (except for internet costs and the electrical bill). -- Full control over the server and hardware (it sits right there!). -- Easy to set up. -- Suitable for quick setups - e.g. to briefly show off results to your collaborators. - -**Disadvantages** -- You need a good internet connection, ideally without any upload/download limits/costs. -- If you want to run a full game this way, your computer needs to always be on. It could be noisy, -and as mentioned, the electrical bill must be considered. -- No support or safety - if your house burns down, so will your game. Also, you are yourself -responsible for doing regular backups. -- Potentially not as easy if you don't know how to open ports in your firewall or router. -- Home IP numbers are often dynamically allocated, so for permanent online time you need to set up a -DNS to always re-point to the right place (see below). -- You are personally responsible for any use/misuse of your internet connection-- though unlikely -(but not impossible) if running your server somehow causes issues for other customers on the -network, goes against your ISP's terms of service (many ISPs insist on upselling you to a business- -tier connection) or you are the subject of legal action by a copyright holder, you may find your -main internet connection terminated as a consequence. - -#### Setting up your own machine as a server - -[The first section](./Online-Setup.md#connecting-from-the-outside) of this page describes how to do this -and allow users to connect to the IP address of your machine/router. - -A complication with using a specific IP address like this is that your home IP might not remain the -same. Many ISPs (Internet Service Providers) allocates a *dynamic* IP to you which could change at -any time. When that happens, that IP you told people to go to will be worthless. Also, that long -string of numbers is not very pretty, is it? It's hard to remember and not easy to use in marketing -your game. What you need is to alias it to a more sensible domain name - an alias that follows you -around also when the IP changes. - -1. To set up a domain name alias, we recommend starting with a free domain name from -[FreeDNS](https://freedns.afraid.org/). Once you register there (it's free) you have access to tens -of thousands domain names that people have "donated" to allow you to use for your own sub domain. -For example, `strangled.net` is one of those available domains. So tying our IP address to -`strangled.net` using the subdomain `evennia` would mean that one could henceforth direct people to -`http://evennia.strangled.net:4001` for their gaming needs - far easier to remember! -1. So how do we make this new, nice domain name follow us also if our IP changes? For this we need -to set up a little program on our computer. It will check whenever our ISP decides to change our IP -and tell FreeDNS that. There are many alternatives to be found from FreeDNS:s homepage, one that -works on multiple platforms is [inadyn](http://www.inatech.eu/inadyn/). Get it from their page or, -in Linux, through something like `apt-get install inadyn`. -1. Next, you login to your account on FreeDNS and go to the -[Dynamic](https://freedns.afraid.org/dynamic/) page. You should have a list of your subdomains. Click -the `Direct URL` link and you'll get a page with a text message. Ignore that and look at the URL of -the page. It should be ending in a lot of random letters. Everything after the question mark is your -unique "hash". Copy this string. -1. You now start inadyn with the following command (Linux): - - `inadyn --dyndns_system default@freedns.afraid.org -a , &` - - where `` would be `evennia.strangled.net` and `` the string of numbers we copied -from FreeDNS. The `&` means we run in the background (might not be valid in other operating -systems). `inadyn` will henceforth check for changes every 60 seconds. You should put the `inadyn` -command string in a startup script somewhere so it kicks into gear whenever your computer starts. - -### Remote hosting - -Your normal "web hotel" will probably not be enough to run Evennia. A web hotel is normally aimed at -a very specific usage - delivering web pages, at the most with some dynamic content. The "Python -scripts" they refer to on their home pages are usually only intended to be CGI-like scripts launched -by their webserver. Even if they allow you shell access (so you can install the Evennia dependencies -in the first place), resource usage will likely be very restricted. Running a full-fledged game -server like Evennia will probably be shunned upon or be outright impossible. If you are unsure, -contact your web hotel and ask about their policy on you running third-party servers that will want -to open custom ports. - -The options you probably need to look for are *shell account services*, *VPS:es* or *Cloud -services*. A "Shell account" service means that you get a shell account on a server and can log in -like any normal user. By contrast, a *VPS* (Virtual Private Server) service usually means that you -get `root` access, but in a virtual machine. There are also *Cloud*-type services which allows for -starting up multiple virtual machines and pay for what resources you use. - -**Advantages** -- Shell accounts/VPS/clouds offer more flexibility than your average web hotel - it's the ability to -log onto a shared computer away from home. -- Usually runs a Linux flavor, making it easy to install Evennia. -- Support. You don't need to maintain the server hardware. If your house burns down, at least your -game stays online. Many services guarantee a certain level of up-time and also do regular backups -for you. Make sure to check, some offer lower rates in exchange for you yourself being fully -responsible for your data/backups. -- Usually offers a fixed domain name, so no need to mess with IP addresses. -- May have the ability to easily deploy [docker](./Running-Evennia-in-Docker.md) versions of evennia -and/or your game. - -**Disadvantages** -- Might be pretty expensive (more so than a web hotel). Note that Evennia will normally need at -least 100MB RAM and likely much more for a large production game. -- Linux flavors might feel unfamiliar to users not used to ssh/PuTTy and the Linux command line. -- You are probably sharing the server with many others, so you are not completely in charge. CPU -usage might be limited. Also, if the server people decides to take the server down for maintenance, -you have no choice but to sit it out (but you'll hopefully be warned ahead of time). - -#### Installing Evennia on a remote server - -Firstly, if you are familiar with server infrastructure, consider using [Docker](Running-Evennia-in- -Docker) to deploy your game to the remote server; it will likely ease installation and deployment. -Docker images may be a little confusing if you are completely new to them though. - -If not using docker, and assuming you know how to connect to your account over ssh/PuTTy, you should -be able to follow the [Setup Quickstart](./Setup-Quickstart.md) instructions normally. You only need Python -and GIT pre-installed; these should both be available on any servers (if not you should be able to -easily ask for them to be installed). On a VPS or Cloud service you can install them yourself as -needed. - -If `virtualenv` is not available and you can't get it, you can download it (it's just a single file) -from [the virtualenv pypi](https://pypi.python.org/pypi/virtualenv). Using `virtualenv` you can -install everything without actually needing to have further `root` access. Ports might be an issue, -so make sure you know which ports are available to use and reconfigure Evennia accordingly. - -### Hosting options - -To find commercial solutions, browse the web for "shell access", "VPS" or "Cloud services" in your -region. You may find useful offers for "low cost" VPS hosting on [Low End Box][7]. The associated -[Low End Talk][8] forum can be useful for health checking the many small businesses that offer -"value" hosting, and occasionally for technical suggestions. - -There are all sorts of services available. Below are some international suggestions offered by -Evennia users: - -| Hosting name | Type | Lowest price | Comments | -|---|---| ---| --- | -| [silvren.com][1] | Shell account | Free for MU* | Private hobby provider so don't assume backups or expect immediate support. To ask for an account,connect with a MUD client to rostdev.mushpark.com, port 4201 and ask for "Jarin". | -| [Digital Ocean][2] | VPS | $5/month | You can get a $50 credit if you use the referral link https://m.do.co/c/8f64fec2670c - if you do, once you've had it long enough to have paid $25 we will get that as a referral bonus to help Evennia development.| -| [Amazon Web services][3] | Cloud | ~$5/month / on-demand | Free Tier first 12 months. Regions available around the globe.| -| [Amazon Lightsail][9] | Cloud | $5/month | Free first month. AWS's new "fixed cost" offering.| -| [Azure App Services][12] | Cloud | Free | Provides a free tier for hobbyist. Limited regions to be deployed to under the free tier| -| [Huawei Cloud][13] | Cloud | on demand | Similar to Amazon. Free Tier first 12 months. Limited regions to be deployed to| -| [Genesis MUD hosting][4] | Shell account | $8/month | Dedicated MUD host with very limited memory offerings. As for 2017, runs a 13 years old Python version (2.4) so you'd need to either convince them to update or compile yourself. Note that Evennia needs *at least* the "Deluxe" package (50MB RAM) and probably *a lot* higher for a production game. This host is *not* recommended for Evennia.| -| [Host1Plus][5] | VPS & Cloud | $4/month | $4-$8/month depending on length of sign-up period. -| [Scaleway][6] | Cloud | €3/month / on-demand | EU based (Paris, Amsterdam). Smallest option provides 2GB RAM. | -| [Prgmr][10] | VPS | $5/month | 1 month free with a year prepay. You likely want some experience with servers with this option as they don't have a lot of support.| -| [Linode][11] | Cloud | $5/month / on-demand | Multiple regions. Smallest option provides 1GB RAM| - -*Please help us expand this list.* - -[1]: https://silvren.com -[2]: https://www.digitalocean.com/pricing -[3]: https://aws.amazon.com/pricing/ -[4]: https://www.genesismuds.com/ -[5]: https://www.host1plus.com/ -[6]: https://www.scaleway.com/ -[7]: https://lowendbox.com/ -[8]: https://www.lowendtalk.com -[9]: https://amazonlightsail.com -[10]: https://prgmr.com/ -[11]: https://www.linode.com/ -[12]: https://azure.microsoft.com/en-us/pricing/details/app-service/windows/ -[13]: https://activity.huaweicloud.com/intl/en-us/free_packages/index.html - -## Cloud9 - -If you are interested in running Evennia in the online dev environment [Cloud9](https://c9.io/), you -can spin it up through their normal online setup using the Evennia Linux install instructions. The -one extra thing you will have to do is update `mygame/server/conf/settings.py` and add -`WEBSERVER_PORTS = [(8080, 4001)]`. This will then let you access the web server and do everything -else as normal. - -Note that, as of December 2017, Cloud9 was re-released by Amazon as a service within their AWS cloud -service offering. New customers entitled to the 1 year AWS "free tier" may find it provides -sufficient resources to operate a Cloud9 development environment without charge. -https://aws.amazon.com/cloud9/ diff --git a/docs/0.9.5/_sources/Parsing-command-arguments,-theory-and-best-practices.md.txt b/docs/0.9.5/_sources/Parsing-command-arguments,-theory-and-best-practices.md.txt deleted file mode 100644 index 025f43a95e..0000000000 --- a/docs/0.9.5/_sources/Parsing-command-arguments,-theory-and-best-practices.md.txt +++ /dev/null @@ -1,748 +0,0 @@ -# Parsing command arguments, theory and best practices - - -This tutorial will elaborate on the many ways one can parse command arguments. The first step after -[adding a command](./Adding-Command-Tutorial.md) usually is to parse its arguments. There are lots of -ways to do it, but some are indeed better than others and this tutorial will try to present them. - -If you're a Python beginner, this tutorial might help you a lot. If you're already familiar with -Python syntax, this tutorial might still contain useful information. There are still a lot of -things I find in the standard library that come as a surprise, though they were there all along. -This might be true for others. - -In this tutorial we will: - -- Parse arguments with numbers. -- Parse arguments with delimiters. -- Take a look at optional arguments. -- Parse argument containing object names. - -## What are command arguments? - -I'm going to talk about command arguments and parsing a lot in this tutorial. So let's be sure we -talk about the same thing before going any further: - -> A command is an Evennia object that handles specific user input. - -For instance, the default `look` is a command. After having created your Evennia game, and -connected to it, you should be able to type `look` to see what's around. In this context, `look` is -a command. - -> Command arguments are additional text passed after the command. - -Following the same example, you can type `look self` to look at yourself. In this context, `self` -is the text specified after `look`. `" self"` is the argument to the `look` command. - -Part of our task as a game developer is to connect user inputs (mostly commands) with actions in the -game. And most of the time, entering commands is not enough, we have to rely on arguments for -specifying actions with more accuracy. - -Take the `say` command. If you couldn't specify what to say as a command argument (`say hello!`), -you would have trouble communicating with others in the game. One would need to create a different -command for every kind of word or sentence, which is, of course, not practical. - -Last thing: what is parsing? - -> In our case, parsing is the process by which we convert command arguments into something we can -work with. - -We don't usually use the command argument as is (which is just text, of type `str` in Python). We -need to extract useful information. We might want to ask the user for a number, or the name of -another character present in the same room. We're going to see how to do all that now. - -## Working with strings - -In object terms, when you write a command in Evennia (when you write the Python class), the -arguments are stored in the `args` attribute. Which is to say, inside your `func` method, you can -access the command arguments in `self.args`. - -### self.args - -To begin with, look at this example: - -```python -class CmdTest(Command): - - """ - Test command. - - Syntax: - test [argument] - - Enter any argument after test. - - """ - - key = "test" - - def func(self): - self.msg(f"You have entered: {self.args}.") -``` - -If you add this command and test it, you will receive exactly what you have entered without any -parsing: - -``` -> test Whatever -You have entered: Whatever. -> test -You have entered: . -``` - -> The lines starting with `>` indicate what you enter into your client. The other lines are what -you receive from the game server. - -Notice two things here: - -1. The left space between our command key ("test", here) and our command argument is not removed. -That's why there are two spaces in our output at line 2. Try entering something like "testok". -2. Even if you don't enter command arguments, the command will still be called with an empty string -in `self.args`. - -Perhaps a slight modification to our code would be appropriate to see what's happening. We will -force Python to display the command arguments as a debug string using a little shortcut. - -```python -class CmdTest(Command): - - """ - Test command. - - Syntax: - test [argument] - - Enter any argument after test. - - """ - - key = "test" - - def func(self): - self.msg(f"You have entered: {self.args!r}.") -``` - -The only line we have changed is the last one, and we have added `!r` between our braces to tell -Python to print the debug version of the argument (the repr-ed version). Let's see the result: - -``` -> test Whatever -You have entered: ' Whatever'. -> test -You have entered: ''. -> test And something with '? -You have entered: " And something with '?". -``` - -This displays the string in a way you could see in the Python interpreter. It might be easier to -read... to debug, anyway. - -I insist so much on that point because it's crucial: the command argument is just a string (of type -`str`) and we will use this to parse it. What you will see is mostly not Evennia-specific, it's -Python-specific and could be used in any other project where you have the same need. - -### Stripping - -As you've seen, our command arguments are stored with the space. And the space between the command -and the arguments is often of no importance. - -> Why is it ever there? - -Evennia will try its best to find a matching command. If the user enters your command key with -arguments (but omits the space), Evennia will still be able to find and call the command. You might -have seen what happened if the user entered `testok`. In this case, `testok` could very well be a -command (Evennia checks for that) but seeing none, and because there's a `test` command, Evennia -calls it with the arguments `"ok"`. - -But most of the time, we don't really care about this left space, so you will often see code to -remove it. There are different ways to do it in Python, but a command use case is the `strip` -method on `str` and its cousins, `lstrip` and `rstrip`. - -- `strip`: removes one or more characters (either spaces or other characters) from both ends of the -string. -- `lstrip`: same thing but only removes from the left end (left strip) of the string. -- `rstrip`: same thing but only removes from the right end (right strip) of the string. - -Some Python examples might help: - -```python ->>> ' this is '.strip() # remove spaces by default -'this is' ->>> " What if I'm right? ".lstrip() # strip spaces from the left -"What if I'm right? " ->>> 'Looks good to me...'.strip('.') # removes '.' -'Looks good to me' ->>> '"Now, what is it?"'.strip('"?') # removes '"' and '?' from both ends -'Now, what is it' -``` - -Usually, since we don't need the space separator, but still want our command to work if there's no -separator, we call `lstrip` on the command arguments: - -```python -class CmdTest(Command): - - """ - Test command. - - Syntax: - test [argument] - - Enter any argument after test. - - """ - - key = "test" - - def parse(self): - """Parse arguments, just strip them.""" - self.args = self.args.lstrip() - - def func(self): - self.msg(f"You have entered: {self.args!r}.") -``` - -> We are now beginning to override the command's `parse` method, which is typically useful just for -argument parsing. This method is executed before `func` and so `self.args` in `func()` will contain -our `self.args.lstrip()`. - -Let's try it: - -``` -> test Whatever -You have entered: 'Whatever'. -> test -You have entered: ''. -> test And something with '? -You have entered: "And something with '?". -> test And something with lots of spaces -You have entered: 'And something with lots of spaces'. -``` - -Spaces at the end of the string are kept, but all spaces at the beginning are removed: - -> `strip`, `lstrip` and `rstrip` without arguments will strip spaces, line breaks and other common -separators. You can specify one or more characters as a parameter. If you specify more than one -character, all of them will be stripped from your original string. - -### Convert arguments to numbers - -As pointed out, `self.args` is a string (of type `str`). What if we want the user to enter a -number? - -Let's take a very simple example: creating a command, `roll`, that allows to roll a six-sided die. -The player has to guess the number, specifying the number as argument. To win, the player has to -match the number with the die. Let's see an example: - -``` -> roll 3 -You roll a die. It lands on the number 4. -You played 3, you have lost. -> dice 1 -You roll a die. It lands on the number 2. -You played 1, you have lost. -> dice 1 -You roll a die. It lands on the number 1. -You played 1, you have won! -``` - -If that's your first command, it's a good opportunity to try to write it. A command with a simple -and finite role always is a good starting choice. Here's how we could (first) write it... but it -won't work as is, I warn you: - -```python -from random import randint - -from evennia import Command - -class CmdRoll(Command): - - """ - Play random, enter a number and try your luck. - - Usage: - roll - - Enter a valid number as argument. A random die will be rolled and you - will win if you have specified the correct number. - - Example: - roll 3 - - """ - - key = "roll" - - def parse(self): - """Convert the argument to a number.""" - self.args = self.args.lstrip() - - def func(self): - # Roll a random die - figure = randint(1, 6) # return a pseudo-random number between 1 and 6, including both - self.msg(f"You roll a die. It lands on the number {figure}.") - - if self.args == figure: # THAT WILL BREAK! - self.msg(f"You played {self.args}, you have won!") - else: - self.msg(f"You played {self.args}, you have lost.") -``` - -If you try this code, Python will complain that you try to compare a number with a string: `figure` -is a number and `self.args` is a string and can't be compared as-is in Python. Python doesn't do -"implicit converting" as some languages do. By the way, this might be annoying sometimes, and other -times you will be glad it tries to encourage you to be explicit rather than implicit about what to -do. This is an ongoing debate between programmers. Let's move on! - -So we need to convert the command argument from a `str` into an `int`. There are a few ways to do -it. But the proper way is to try to convert and deal with the `ValueError` Python exception. - -Converting a `str` into an `int` in Python is extremely simple: just use the `int` function, give it -the string and it returns an integer, if it could. If it can't, it will raise `ValueError`. So -we'll need to catch that. However, we also have to indicate to Evennia that, should the number be -invalid, no further parsing should be done. Here's a new attempt at our command with this -converting: - -```python -from random import randint - -from evennia import Command, InterruptCommand - -class CmdRoll(Command): - - """ - Play random, enter a number and try your luck. - - Usage: - roll - - Enter a valid number as argument. A random die will be rolled and you - will win if you have specified the correct number. - - Example: - roll 3 - - """ - - key = "roll" - - def parse(self): - """Convert the argument to number if possible.""" - args = self.args.lstrip() - - # Convert to int if possible - # If not, raise InterruptCommand. Evennia will catch this - # exception and not call the 'func' method. - try: - self.entered = int(args) - except ValueError: - self.msg(f"{args} is not a valid number.") - raise InterruptCommand - - def func(self): - # Roll a random die - figure = randint(1, 6) # return a pseudo-random number between 1 and 6, including both - self.msg(f"You roll a die. It lands on the number {figure}.") - - if self.entered == figure: - self.msg(f"You played {self.entered}, you have won!") - else: - self.msg(f"You played {self.entered}, you have lost.") -``` - -Before enjoying the result, let's examine the `parse` method a little more: what it does is try to -convert the entered argument from a `str` to an `int`. This might fail (if a user enters `roll -something`). In such a case, Python raises a `ValueError` exception. We catch it in our -`try/except` block, send a message to the user and raise the `InterruptCommand` exception in -response to tell Evennia to not run `func()`, since we have no valid number to give it. - -In the `func` method, instead of using `self.args`, we use `self.entered` which we have defined in -our `parse` method. You can expect that, if `func()` is run, then `self.entered` contains a valid -number. - -If you try this command, it will work as expected this time: the number is converted as it should -and compared to the die roll. You might spend some minutes playing this game. Time out! - -Something else we could want to address: in our small example, we only want the user to enter a -positive number between 1 and 6. And the user can enter `roll 0` or `roll -8` or `roll 208` for -that matter, the game still works. It might be worth addressing. Again, you could write a -condition to do that, but since we're catching an exception, we might end up with something cleaner -by grouping: - -```python -from random import randint - -from evennia import Command, InterruptCommand - -class CmdRoll(Command): - - """ - Play random, enter a number and try your luck. - - Usage: - roll - - Enter a valid number as argument. A random die will be rolled and you - will win if you have specified the correct number. - - Example: - roll 3 - - """ - - key = "roll" - - def parse(self): - """Convert the argument to number if possible.""" - args = self.args.lstrip() - - # Convert to int if possible - try: - self.entered = int(args) - if not 1 <= self.entered <= 6: - # self.entered is not between 1 and 6 (including both) - raise ValueError - except ValueError: - self.msg(f"{args} is not a valid number.") - raise InterruptCommand - - def func(self): - # Roll a random die - figure = randint(1, 6) # return a pseudo-random number between 1 and 6, including both - self.msg(f"You roll a die. It lands on the number {figure}.") - - if self.entered == figure: - self.msg(f"You played {self.entered}, you have won!") - else: - self.msg(f"You played {self.entered}, you have lost.") -``` - -Using grouped exceptions like that makes our code easier to read, but if you feel more comfortable -checking, afterward, that the number the user entered is in the right range, you can do so in a -latter condition. - -> Notice that we have updated our `parse` method only in this last attempt, not our `func()` method -which remains the same. This is one goal of separating argument parsing from command processing, -these two actions are best kept isolated. - -### Working with several arguments - -Often a command expects several arguments. So far, in our example with the "roll" command, we only -expect one argument: a number and just a number. What if we want the user to specify several -numbers? First the number of dice to roll, then the guess? - -> You won't win often if you roll 5 dice but that's for the example. - -So we would like to interpret a command like this: - - > roll 3 12 - -(To be understood: roll 3 dice, my guess is the total number will be 12.) - -What we need is to cut our command argument, which is a `str`, break it at the space (we use the -space as a delimiter). Python provides the `str.split` method which we'll use. Again, here are -some examples from the Python interpreter: - - >>> args = "3 12" - >>> args.split(" ") - ['3', '12'] - >>> args = "a command with several arguments" - >>> args.split(" ") - ['a', 'command', 'with', 'several', 'arguments'] - >>> - -As you can see, `str.split` will "convert" our strings into a list of strings. The specified -argument (`" "` in our case) is used as delimiter. So Python browses our original string. When it -sees a delimiter, it takes whatever is before this delimiter and append it to a list. - -The point here is that `str.split` will be used to split our argument. But, as you can see from the -above output, we can never be sure of the length of the list at this point: - - >>> args = "something" - >>> args.split(" ") - ['something'] - >>> args = "" - >>> args.split(" ") - [''] - >>> - -Again we could use a condition to check the number of split arguments, but Python offers a better -approach, making use of its exception mechanism. We'll give a second argument to `str.split`, the -maximum number of splits to do. Let's see an example, this feature might be confusing at first -glance: - - >>> args = "that is something great" - >>> args.split(" ", 1) # one split, that is a list with two elements (before, after) - ['that', 'is something great'] - >>> - -Read this example as many times as needed to understand it. The second argument we give to -`str.split` is not the length of the list that should be returned, but the number of times we have -to split. Therefore, we specify 1 here, but we get a list of two elements (before the separator, -after the separator). - -> What will happen if Python can't split the number of times we ask? - -It won't: - - >>> args = "whatever" - >>> args.split(" ", 1) # there isn't even a space here... - ['whatever'] - >>> - -This is one moment I would have hoped for an exception and didn't get one. But there's another way -which will raise an exception if there is an error: variable unpacking. - -We won't talk about this feature in details here. It would be complicated. But the code is really -straightforward to use. Let's take our example of the roll command but let's add a first argument: -the number of dice to roll. - -```python -from random import randint - -from evennia import Command, InterruptCommand - -class CmdRoll(Command): - - """ - Play random, enter a number and try your luck. - - Specify two numbers separated by a space. The first number is the - number of dice to roll (1, 2, 3) and the second is the expected sum - of the roll. - - Usage: - roll - - For instance, to roll two 6-figure dice, enter 2 as first argument. - If you think the sum of these two dice roll will be 10, you could enter: - - roll 2 10 - - """ - - key = "roll" - - def parse(self): - """Split the arguments and convert them.""" - args = self.args.lstrip() - - # Split: we expect two arguments separated by a space - try: - number, guess = args.split(" ", 1) - except ValueError: - self.msg("Invalid usage. Enter two numbers separated by a space.") - raise InterruptCommand - - # Convert the entered number (first argument) - try: - self.number = int(number) - if self.number <= 0: - raise ValueError - except ValueError: - self.msg(f"{number} is not a valid number of dice.") - raise InterruptCommand - - # Convert the entered guess (second argument) - try: - self.guess = int(guess) - if not 1 <= self.guess <= self.number * 6: - raise ValueError - except ValueError: - self.msg(f"{self.guess} is not a valid guess.") - raise InterruptCommand - - def func(self): - # Roll a random die X times (X being self.number) - figure = 0 - for _ in range(self.number): - figure += randint(1, 6) - - self.msg(f"You roll {self.number} dice and obtain the sum {figure}.") - - if self.guess == figure: - self.msg(f"You played {self.guess}, you have won!") - else: - self.msg(f"You played {self.guess}, you have lost.") -``` - -The beginning of the `parse()` method is what interests us most: - -```python -try: - number, guess = args.split(" ", 1) -except ValueError: - self.msg("Invalid usage. Enter two numbers separated by a space.") - raise InterruptCommand -``` - -We split the argument using `str.split` but we capture the result in two variables. Python is smart -enough to know that we want what's left of the space in the first variable, what's right of the -space in the second variable. If there is not even a space in the string, Python will raise a -`ValueError` exception. - -This code is much easier to read than browsing through the returned strings of `str.split`. We can -convert both variables the way we did previously. Actually there are not so many changes in this -version and the previous one, most of it is due to name changes for clarity. - -> Splitting a string with a maximum of splits is a common occurrence while parsing command -arguments. You can also see the `str.rspli8t` method that does the same thing but from the right of -the string. Therefore, it will attempt to find delimiters at the end of the string and work toward -the beginning of it. - -We have used a space as a delimiter. This is absolutely not necessary. You might remember that -most default Evennia commands can take an `=` sign as a delimiter. Now you know how to parse them -as well: - - >>> cmd_key = "tel" - >>> cmd_args = "book = chest" - >>> left, right = cmd_args.split("=") # mighht raise ValueError! - >>> left - 'book ' - >>> right - ' chest' - >>> - -### Optional arguments - -Sometimes, you'll come across commands that have optional arguments. These arguments are not -necessary but they can be set if more information is needed. I will not provide the entire command -code here but just enough code to show the mechanism in Python: - -Again, we'll use `str.split`, knowing that we might not have any delimiter at all. For instance, -the player could enter the "tel" command like this: - - > tel book - > tell book = chest - -The equal sign is optional along with whatever is specified after it. A possible solution in our -`parse` method would be: - -```python - def parse(self): - args = self.args.lstrip() - - # = is optional - try: - obj, destination = args.split("=", 1) - except ValueError: - obj = args - destination = None -``` - -This code would place everything the user entered in `obj` if she didn't specify any equal sign. -Otherwise, what's before the equal sign will go in `obj`, what's after the equal sign will go in -`destination`. This makes for quick testing after that, more robust code with less conditions that -might too easily break your code if you're not careful. - -> Again, here we specified a maximum numbers of splits. If the users enters: - - > tel book = chest = chair - -Then `destination` will contain: `" chest = chair"`. This is often desired, but it's up to you to -set parsing however you like. - -## Evennia searches - -After this quick tour of some `str` methods, we'll take a look at some Evennia-specific features -that you won't find in standard Python. - -One very common task is to convert a `str` into an Evennia object. Take the previous example: -having `"book"` in a variable is great, but we would prefer to know what the user is talking -about... what is this `"book"`? - -To get an object from a string, we perform an Evennia search. Evennia provides a `search` method on -all typeclassed objects (you will most likely use the one on characters or accounts). This method -supports a very wide array of arguments and has [its own tutorial](./Tutorial-Searching-For-Objects.md). -Some examples of useful cases follow: - -### Local searches - -When an account or a character enters a command, the account or character is found in the `caller` -attribute. Therefore, `self.caller` will contain an account or a character (or a session if that's -a session command, though that's not as frequent). The `search` method will be available on this -caller. - -Let's take the same example of our little "tel" command. The user can specify an object as -argument: - -```python - def parse(self): - name = self.args.lstrip() -``` - -We then need to "convert" this string into an Evennia object. The Evennia object will be searched -in the caller's location and its contents by default (that is to say, if the command has been -entered by a character, it will search the object in the character's room and the character's -inventory). - -```python - def parse(self): - name = self.args.lstrip() - - self.obj = self.caller.search(name) -``` - -We specify only one argument to the `search` method here: the string to search. If Evennia finds a -match, it will return it and we keep it in the `obj` attribute. If it can't find anything, it will -return `None` so we need to check for that: - -```python - def parse(self): - name = self.args.lstrip() - - self.obj = self.caller.search(name) - if self.obj is None: - # A proper error message has already been sent to the caller - raise InterruptCommand -``` - -That's it. After this condition, you know that whatever is in `self.obj` is a valid Evennia object -(another character, an object, an exit...). - -### Quiet searches - -By default, Evennia will handle the case when more than one match is found in the search. The user -will be asked to narrow down and re-enter the command. You can, however, ask to be returned the -list of matches and handle this list yourself: - -```python - def parse(self): - name = self.args.lstrip() - - objs = self.caller.search(name, quiet=True) - if not objs: - # This is an empty list, so no match - self.msg(f"No {name!r} was found.") - raise InterruptCommand - - self.obj = objs[0] # Take the first match even if there are several -``` - -All we have changed to obtain a list is a keyword argument in the `search` method: `quiet`. If set -to `True`, then errors are ignored and a list is always returned, so we need to handle it as such. -Notice in this example, `self.obj` will contain a valid object too, but if several matches are -found, `self.obj` will contain the first one, even if more matches are available. - -### Global searches - -By default, Evennia will perform a local search, that is, a search limited by the location in which -the caller is. If you want to perform a global search (search in the entire database), just set the -`global_search` keyword argument to `True`: - -```python - def parse(self): - name = self.args.lstrip() - self.obj = self.caller.search(name, global_search=True) -``` - -## Conclusion - -Parsing command arguments is vital for most game designers. If you design "intelligent" commands, -users should be able to guess how to use them without reading the help, or with a very quick peek at -said help. Good commands are intuitive to users. Better commands do what they're told to do. For -game designers working on MUDs, commands are the main entry point for users into your game. This is -no trivial. If commands execute correctly (if their argument is parsed, if they don't behave in -unexpected ways and report back the right errors), you will have happier players that might stay -longer on your game. I hope this tutorial gave you some pointers on ways to improve your command -parsing. There are, of course, other ways you will discover, or ways you are already using in your -code. diff --git a/docs/0.9.5/_sources/Portal-And-Server.md.txt b/docs/0.9.5/_sources/Portal-And-Server.md.txt deleted file mode 100644 index d51f152a9c..0000000000 --- a/docs/0.9.5/_sources/Portal-And-Server.md.txt +++ /dev/null @@ -1,14 +0,0 @@ -# Portal And Server - - -Evennia consists of two processes, known as *Portal* and *Server*. They can be controlled from -inside the game or from the command line as described [here](./Start-Stop-Reload.md). - -If you are new to the concept, the main purpose of separating the two is to have accounts connect to -the Portal but keep the MUD running on the Server. This way one can restart/reload the game (the -Server part) without Accounts getting disconnected. - -![portal and server layout](https://474a3b9f-a-62cb3a1a-s-sites.googlegroups.com/site/evenniaserver/file-cabinet/evennia_server_portal.png) - -The Server and Portal are glued together via an AMP (Asynchronous Messaging Protocol) connection. -This allows the two programs to communicate seamlessly. diff --git a/docs/0.9.5/_sources/Profiling.md.txt b/docs/0.9.5/_sources/Profiling.md.txt deleted file mode 100644 index d9442e4d34..0000000000 --- a/docs/0.9.5/_sources/Profiling.md.txt +++ /dev/null @@ -1,125 +0,0 @@ -# Profiling - -*This is considered an advanced topic mainly of interest to server developers.* - -## Introduction - -Sometimes it can be useful to try to determine just how efficient a particular piece of code is, or -to figure out if one could speed up things more than they are. There are many ways to test the -performance of Python and the running server. - -Before digging into this section, remember Donald Knuth's [words of -wisdom](https://en.wikipedia.org/wiki/Program_optimization#When_to_optimize): - -> *[...]about 97% of the time: Premature optimization is the root of all evil*. - -That is, don't start to try to optimize your code until you have actually identified a need to do -so. This means your code must actually be working before you start to consider optimization. -Optimization will also often make your code more complex and harder to read. Consider readability -and maintainability and you may find that a small gain in speed is just not worth it. - -## Simple timer tests - -Python's `timeit` module is very good for testing small things. For example, in order to test if it -is faster to use a `for` loop or a list comprehension you could use the following code: - -```python - import timeit - # Time to do 1000000 for loops - timeit.timeit("for i in range(100):\n a.append(i)", setup="a = []") - <<< 10.70982813835144 - # Time to do 1000000 list comprehensions - timeit.timeit("a = [i for i in range(100)]") - <<< 5.358283996582031 -``` - -The `setup` keyword is used to set up things that should not be included in the time measurement, -like `a = []` in the first call. - -By default the `timeit` function will re-run the given test 1000000 times and returns the *total -time* to do so (so *not* the average per test). A hint is to not use this default for testing -something that includes database writes - for that you may want to use a lower number of repeats -(say 100 or 1000) using the `number=100` keyword. - -## Using cProfile - -Python comes with its own profiler, named cProfile (this is for cPython, no tests have been done -with `pypy` at this point). Due to the way Evennia's processes are handled, there is no point in -using the normal way to start the profiler (`python -m cProfile evennia.py`). Instead you start the -profiler through the launcher: - - evennia --profiler start - -This will start Evennia with the Server component running (in daemon mode) under cProfile. You could -instead try `--profile` with the `portal` argument to profile the Portal (you would then need to -[start the Server separately](./Start-Stop-Reload.md)). - -Please note that while the profiler is running, your process will use a lot more memory than usual. -Memory usage is even likely to climb over time. So don't leave it running perpetually but monitor it -carefully (for example using the `top` command on Linux or the Task Manager's memory display on -Windows). - -Once you have run the server for a while, you need to stop it so the profiler can give its report. -Do *not* kill the program from your task manager or by sending it a kill signal - this will most -likely also mess with the profiler. Instead either use `evennia.py stop` or (which may be even -better), use `@shutdown` from inside the game. - -Once the server has fully shut down (this may be a lot slower than usual) you will find that -profiler has created a new file `mygame/server/logs/server.prof`. - -## Analyzing the profile - -The `server.prof` file is a binary file. There are many ways to analyze and display its contents, -all of which has only been tested in Linux (If you are a Windows/Mac user, let us know what works). - -We recommend the -[Runsnake](http://www.vrplumber.com/programming/runsnakerun/) visualizer to see the processor usage -of different processes in a graphical form. For more detailed listing of usage time, you can use -[KCachegrind](http://kcachegrind.sourceforge.net/html/Home.html). To make KCachegrind work with -Python profiles you also need the wrapper script -[pyprof2calltree](https://pypi.python.org/pypi/pyprof2calltree/). You can get pyprof2calltree via -`pip` whereas KCacheGrind is something you need to get via your package manager or their homepage. - -How to analyze and interpret profiling data is not a trivial issue and depends on what you are -profiling for. Evennia being an asynchronous server can also confuse profiling. Ask on the mailing -list if you need help and be ready to be able to supply your `server.prof` file for comparison, -along with the exact conditions under which it was obtained. - -## The Dummyrunner - -It is difficult to test "actual" game performance without having players in your game. For this -reason Evennia comes with the *Dummyrunner* system. The Dummyrunner is a stress-testing system: a -separate program that logs into your game with simulated players (aka "bots" or "dummies"). Once -connected these dummies will semi-randomly perform various tasks from a list of possible actions. -Use `Ctrl-C` to stop the Dummyrunner. - -> Warning: You should not run the Dummyrunner on a production database. It will spawn many objects -and also needs to run with general permissions. - -To launch the Dummyrunner, first start your server normally (with or without profiling, as above). -Then start a new terminal/console window and active your virtualenv there too. In the new terminal, -try to connect 10 dummy players: - - evennia --dummyrunner 10 - -The first time you do this you will most likely get a warning from Dummyrunner. It will tell you to -copy an import string to the end of your settings file. Quit the Dummyrunner (`Ctrl-C`) and follow -the instructions. Restart Evennia and try `evennia --dummyrunner 10` again. Make sure to remove that -extra settings line when running a public server. - -The actions perform by the dummies is controlled by a settings file. The default Dummyrunner -settings file is `evennia/server/server/profiling/dummyrunner_settings.py` but you shouldn't modify -this directly. Rather create/copy the default file to `mygame/server/conf/` and modify it there. To -make sure to use your file over the default, add the following line to your settings file: - -```python -DUMMYRUNNER_SETTINGS_MODULE = "server/conf/dummyrunner_settings.py" -``` - -> Hint: Don't start with too many dummies. The Dummyrunner defaults to taxing the server much more -intensely than an equal number of human players. A good dummy number to start with is 10-100. - -Once you have the dummyrunner running, stop it with `Ctrl-C`. - -Generally, the dummyrunner system makes for a decent test of general performance; but it is of -course hard to actually mimic human user behavior. For this, actual real-game testing is required. diff --git a/docs/0.9.5/_sources/Python-3.md.txt b/docs/0.9.5/_sources/Python-3.md.txt deleted file mode 100644 index 96b3479a83..0000000000 --- a/docs/0.9.5/_sources/Python-3.md.txt +++ /dev/null @@ -1,4 +0,0 @@ -# Python 3 - -Evennia supports Python 3+ since v0.8. This page is deprecated. - diff --git a/docs/0.9.5/_sources/Python-basic-introduction.md.txt b/docs/0.9.5/_sources/Python-basic-introduction.md.txt deleted file mode 100644 index 66512e06fd..0000000000 --- a/docs/0.9.5/_sources/Python-basic-introduction.md.txt +++ /dev/null @@ -1,266 +0,0 @@ -# Python basic introduction - -This is the first part of our beginner's guide to the basics of using Python with Evennia. It's -aimed at you with limited or no programming/Python experience. But also if you are an experienced -programmer new to Evennia or Python you might still pick up a thing or two. It is by necessity brief -and low on detail. There are countless Python guides and tutorials, books and videos out there for -learning more in-depth - use them! - -**Contents:** -- [Evennia Hello world](./Python-basic-introduction.md#evennia-hello-world) -- [Importing modules](./Python-basic-introduction.md#importing-modules) -- [Parsing Python errors](./Python-basic-introduction.md#parsing-python-errors) -- [Our first function](./Python-basic-introduction.md#our-first-function) -- [Looking at the log](./Python-basic-introduction.md#looking-at-the-log) -- (continued in [part 2](./Python-basic-tutorial-part-two.md)) - -This quickstart assumes you have [gotten Evennia started](./Getting-Started.md). You should make sure -that you are able to see the output from the server in the console from which you started it. Log -into the game either with a mud client on `localhost:4000` or by pointing a web browser to -`localhost:4001/webclient`. Log in as your superuser (the user you created during install). - -Below, lines starting with a single `>` means command input. - -### Evennia Hello world - -The `py` (or `!` which is an alias) command allows you as a superuser to run raw Python from in- -game. From the game's input line, enter the following: - - > py print("Hello World!") - -You will see - - > print("Hello world!") - Hello World - -To understand what is going on: some extra info: The `print(...)` *function* is the basic, in-built -way to output text in Python. The quotes `"..."` means you are inputing a *string* (i.e. text). You -could also have used single-quotes `'...'`, Python accepts both. - -The first return line (with `>>>`) is just `py` echoing what you input (we won't include that in the -examples henceforth). - -> Note: You may sometimes see people/docs refer to `@py` or other commands starting with `@`. -Evennia ignores `@` by default, so `@py` is the exact same thing as `py`. - -The `print` command is a standard Python structure. We can use that here in the `py` command, and -it's great for debugging and quick testing. But if you need to send a text to an actual player, -`print` won't do, because it doesn't know _who_ to send to. Try this: - - > py me.msg("Hello world!") - Hello world! - -This looks the same as the `print` result, but we are now actually messaging a specific *object*, -`me`. The `me` is something uniquely available in the `py` command (we could also use `self`, it's -an alias). It represents "us", the ones calling the `py` command. The `me` is an example of an -*Object instance*. Objects are fundamental in Python and Evennia. The `me` object not only -represents the character we play in the game, it also contains a lot of useful resources for doing -things with that Object. One such resource is `msg`. `msg` works like `print` except it sends the -text to the object it is attached to. So if we, for example, had an object `you`, doing -`you.msg(...)` would send a message to the object `you`. - -You access an Object's resources by using the full-stop character `.`. So `self.msg` accesses the -`msg` resource and then we call it like we did print, with our "Hello World!" greeting in -parentheses. - -> Important: something like `print(...)` we refer to as a *function*, while `msg(...)` which sits on -an object is called a *method*. - -For now, `print` and `me.msg` behaves the same, just remember that you're going to mostly be using -the latter in the future. Try printing other things. Also try to include `|r` at the start of your -string to make the output red in-game. Use `color` to learn more color tags. - -### Importing modules - -Keep your game running, then open a text editor of your choice. If your game folder is called -`mygame`, create a new text file `test.py` in the subfolder `mygame/world`. This is how the file -structure should look: - -``` -mygame/ - world/ - test.py -``` - -For now, only add one line to `test.py`: - -```python -print("Hello World!") -``` - -Don't forget to save the file. A file with the ending `.py` is referred to as a Python *module*. To -use this in-game we have to *import* it. Try this: - -```python -> @py import world.test -Hello World -``` -If you make some error (we'll cover how to handle errors below) you may need to run the `@reload` -command for your changes to take effect. - -So importing `world.test` actually means importing `world/test.py`. Think of the period `.` as -replacing `/` (or `\` for Windows) in your path. The `.py` ending of `test.py` is also never -included in this "Python-path", but _only_ files with that ending can be imported this way. Where is -`mygame` in that Python-path? The answer is that Evennia has already told Python that your `mygame` -folder is a good place to look for imports. So we don't include `mygame` in the path - Evennia -handles this for us. - -When you import the module, the top "level" of it will execute. In this case, it will immediately -print "Hello World". - -> If you look in the folder you'll also often find new files ending with `.pyc`. These are compiled -Python binaries that Python auto-creates when running code. Just ignore them, you should never edit -those anyway. - -Now try to run this a second time: - -```python -> py import world.test -``` -You will *not* see any output this second time or any subsequent times! This is not a bug. Rather -it is because Python is being clever - it stores all imported modules and to be efficient it will -avoid importing them more than once. So your `print` will only run the first time, when the module -is first imported. To see it again you need to `@reload` first, so Python forgets about the module -and has to import it again. - -We'll get back to importing code in the second part of this tutorial. For now, let's press on. - -### Parsing Python errors - -Next, erase the single `print` statement you had in `test.py` and replace it with this instead: - -```python -me.msg("Hello World!") -``` - -As you recall we used this from `py` earlier - it echoed "Hello World!" in-game. -Save your file and `reload` your server - this makes sure Evennia sees the new version of your code. -Try to import it from `py` in the same way as earlier: - -```python -> py import world.test -``` - -No go - this time you get an error! - -```python -File "./world/test.py", line 1, in - me.msg("Hello world!") -NameError: name 'me' is not defined -``` - -This is called a *traceback*. Python's errors are very friendly and will most of the time tell you -exactly what and where things are wrong. It's important that you learn to parse tracebacks so you -can fix your code. Let's look at this one. A traceback is to be read from the _bottom up_. The last -line is the error Python balked at, while the two lines above it details exactly where that error -was encountered. - -1. An error of type `NameError` is the problem ... -2. ... more specifically it is due to the variable `me` not being defined. -3. This happened on the line `me.msg("Hello world!")` ... -4. ... which is on line `1` of the file `./world/test.py`. - -In our case the traceback is short. There may be many more lines above it, tracking just how -different modules called each other until it got to the faulty line. That can sometimes be useful -information, but reading from the bottom is always a good start. - -The `NameError` we see here is due to a module being its own isolated thing. It knows nothing about -the environment into which it is imported. It knew what `print` is because that is a special -[reserved Python keyword](https://docs.python.org/2.5/ref/keywords.html). But `me` is *not* such a -reserved word. As far as the module is concerned `me` is just there out of nowhere. Hence the -`NameError`. - -### Our first function - -Let's see if we can resolve that `NameError` from the previous section. We know that `me` is defined -at the time we use the `@py` command because if we do `py me.msg("Hello World!")` directly in-game -it works fine. What if we could *send* that `me` to the `test.py` module so it knows what it is? One -way to do this is with a *function*. - -Change your `mygame/world/test.py` file to look like this: - -```python -def hello_world(who): - who.msg("Hello World!") -``` - -Now that we are moving onto multi-line Python code, there are some important things to remember: - -- Capitalization matters in Python. It must be `def` and not `DEF`, `who` is not the same as `Who` -etc. -- Indentation matters in Python. The second line must be indented or it's not valid code. You should -also use a consistent indentation length. We *strongly* recommend that you set up your editor to -always indent *4 spaces* (**not** a single tab-character) when you press the TAB key - it will make -your life a lot easier. -- `def` is short for "define" and defines a *function* (or a *method*, if sitting on an object). -This is a [reserved Python keyword](https://docs.python.org/2.5/ref/keywords.html); try not to use -these words anywhere else. -- A function name can not have spaces but otherwise we could have called it almost anything. We call -it `hello_world`. Evennia follows [Python's standard naming style](https://github.com/evennia/evennia/blob/master/CODING_STYLE.md#a-quick-list-of-code-style- -points) with lowercase letters and underscores. Use this style for now. -- `who` is what we call the *argument* to our function. Arguments are variables we pass to the -function. We could have named it anything and we could also have multiple arguments separated by -commas. What `who` is depends on what we pass to this function when we *call* it later (hint: we'll -pass `me` to it). -- The colon (`:`) at the end of the first line indicates that the header of the function is -complete. -- The indentation marks the beginning of the actual operating code of the function (the function's -*body*). If we wanted more lines to belong to this function those lines would all have to have to -start at this indentation level. -- In the function body we take the `who` argument and treat it as we would have treated `me` earlier -- we expect it to have a `.msg` method we can use to send "Hello World" to. - -First, `reload` your game to make it aware of the updated Python module. Now we have defined our -first function, let's use it. - - > reload - > py import world.test - -Nothing happened! That is because the function in our module won't do anything just by importing it. -It will only act when we *call* it. We will need to enter the module we just imported and do so. - - > py import world.test ; world.test.hello_world(me) - Hello world! - -There is our "Hello World"! The `;` is the way to put multiple Python-statements on one line. - -> Some MUD clients use `;` for their own purposes to separate client-inputs. If so you'll get a -`NameError` stating that `world` is not defined. Check so you understand why this is! Change the use -of `;` in your client or use the Evennia web client if this is a problem. - -In the second statement we access the module path we imported (`world.test`) and reach for the -`hello_world` function within. We *call* the function with `me`, which becomes the `who` variable we -use inside the `hello_function`. - -> As an exercise, try to pass something else into `hello_world`. Try for example to pass _who_ as -the number `5` or the simple string `"foo"`. You'll get errors that they don't have the attribute -`msg`. As we've seen, `me` *does* make `msg` available which is why it works (you'll learn more -about Objects like `me` in the next part of this tutorial). If you are familiar with other -programming languages you may be tempted to start *validating* `who` to make sure it works as -expected. This is usually not recommended in Python which suggests it's better to -[handle](https://docs.python.org/2/tutorial/errors.html) the error if it happens rather than to make -a lot of code to prevent it from happening. See also [duck -typing](https://en.wikipedia.org/wiki/Duck_typing). - -# Looking at the log - -As you start to explore Evennia, it's important that you know where to look when things go wrong. -While using the friendly `py` command you'll see errors directly in-game. But if something goes -wrong in your code while the game runs, you must know where to find the _log_. - -Open a terminal (or go back to the terminal you started Evennia in), make sure your `virtualenv` is -active and that you are standing in your game directory (the one created with `evennia --init` -during installation). Enter - -``` -evennia --log -``` -(or `evennia -l`) - -This will show the log. New entries will show up in real time. Whenever you want to leave the log, -enter `Ctrl-C` or `Cmd-C` depending on your system. As a game dev it is important to look at the -log output when working in Evennia - many errors will only appear with full details here. You may -sometimes have to scroll up in the history if you miss it. - -This tutorial is continued in [Part 2](./Python-basic-tutorial-part-two.md), where we'll start learning -about objects and to explore the Evennia library. diff --git a/docs/0.9.5/_sources/Python-basic-tutorial-part-two.md.txt b/docs/0.9.5/_sources/Python-basic-tutorial-part-two.md.txt deleted file mode 100644 index 10dd60b38f..0000000000 --- a/docs/0.9.5/_sources/Python-basic-tutorial-part-two.md.txt +++ /dev/null @@ -1,492 +0,0 @@ -# Python basic tutorial part two - -[In the first part](./Python-basic-introduction.md) of this Python-for-Evennia basic tutorial we learned -how to run some simple Python code from inside the game. We also made our first new *module* -containing a *function* that we called. Now we're going to start exploring the very important -subject of *objects*. - -**Contents:** -- [On the subject of objects](./Python-basic-tutorial-part-two.md#on-the-subject-of-objects) -- [Exploring the Evennia library](./Python-basic-tutorial-part-two.md#exploring-the-evennia-library) -- [Tweaking our Character class](./Python-basic-tutorial-part-two.md#tweaking-our-character-class) -- [The Evennia shell](./Python-basic-tutorial-part-two.md#the-evennia-shell) -- [Where to go from here](./Python-basic-tutorial-part-two.md#where-to-go-from-here) - -### On the subject of objects - -In the first part of the tutorial we did things like - - > py me.msg("Hello World!") - -To learn about functions and imports we also passed that `me` on to a function `hello_world` in -another module. - -Let's learn some more about this `me` thing we are passing around all over the place. In the -following we assume that we named our superuser Character "Christine". - - > py me - Christine - > py me.key - Christine - -These returns look the same at first glance, but not if we examine them more closely: - - > py type(me) - - > py type(me.key) - - -> Note: In some MU clients, such as Mudlet and MUSHclient simply returning `type(me)`, you may not -see the proper return from the above commands. This is likely due to the HTML-like tags `<...>`, -being swallowed by the client. - -The `type` function is, like `print`, another in-built function in Python. It -tells us that we (`me`) are of the *class* `typeclasses.characters.Character`. -Meanwhile `me.key` is a *property* on us, a string. It holds the name of this -object. - -> When you do `py me`, the `me` is defined in such a way that it will use its `.key` property to -represent itself. That is why the result is the same as when doing `py me.key`. Also, remember that -as noted in the first part of the tutorial, the `me` is *not* a reserved Python word; it was just -defined by the Evennia developers as a convenient short-hand when creating the `py` command. So -don't expect `me` to be available elsewhere. - -A *class* is like a "factory" or blueprint. From a class you then create individual *instances*. So -if class is`Dog`, an instance of `Dog` might be `fido`. Our in-game persona is of a class -`Character`. The superuser `christine` is an *instance* of the `Character` class (an instance is -also often referred to as an *object*). This is an important concept in *object oriented -programming*. You are wise to [familiarize yourself with it](https://en.wikipedia.org/wiki/Class-based_programming) a little. - -> In other terms: -> * class: A description of a thing, all the methods (code) and data (information) -> * object: A thing, defined as an *instance* of a class. -> -> So in "Fido is a Dog", "Fido" is an object--a unique thing--and "Dog" is a class. Coders would -also say, "Fido is an instance of Dog". There can be other dogs too, such as Butch and Fifi. They, -too, would be instances of Dog. -> -> As another example: "Christine is a Character", or "Christine is an instance of -typeclasses.characters.Character". To start, all characters will be instances of -typeclass.characters.Character. -> -> You'll be writing your own class soon! The important thing to know here is how classes and objects -relate. - -The string `'typeclasses.characters.Character'` we got from the `type()` function is not arbitrary. -You'll recognize this from when we _imported_ `world.test` in part one. This is a _path_ exactly -describing where to find the python code describing this class. Python treats source code files on -your hard drive (known as *modules*) as well as folders (known as *packages*) as objects that you -access with the `.` operator. It starts looking at a place that Evennia has set up for you - namely -the root of your own game directory. - -Open and look at your game folder (named `mygame` if you exactly followed the Getting Started -instructions) in a file editor or in a new terminal/console. Locate the file -`mygame/typeclasses/characters.py` - -``` -mygame/ - typeclasses - characters.py -``` - -This represents the first part of the python path - `typeclasses.characters` (the `.py` file ending -is never included in the python path). The last bit, `.Character` is the actual class name inside -the `characters.py` module. Open that file in a text editor and you will see something like this: - -```python -""" -(Doc string for module) -""" - -from evennia import DefaultCharacter - -class Character(DefaultCharacter): - """ - (Doc string for class) - """ - pass - -``` - -There is `Character`, the last part of the path. Note how empty this file is. At first glance one -would think a Character had no functionality at all. But from what we have used already we know it -has at least the `key` property and the method `msg`! Where is the code? The answer is that this -'emptiness' is an illusion caused by something called *inheritance*. Read on. - -Firstly, in the same way as the little `hello.py` we did in the first part of the tutorial, this is -an example of full, multi-line Python code. Those triple-quoted strings are used for strings that -have line breaks in them. When they appear on their own like this, at the top of a python module, -class or similar they are called *doc strings*. Doc strings are read by Python and is used for -producing online help about the function/method/class/module. By contrast, a line starting with `#` -is a *comment*. It is ignored completely by Python and is only useful to help guide a human to -understand the code. - -The line - -```python - class Character(DefaultCharacter): -``` - -means that the class `Character` is a *child* of the class `DefaultCharacter`. This is called -*inheritance* and is another fundamental concept. The answer to the question "where is the code?" is -that the code is *inherited* from its parent, `DefaultCharacter`. And that in turn may inherit code -from *its* parent(s) and so on. Since our child, `Character` is empty, its functionality is *exactly -identical* to that of its parent. The moment we add new things to Character, these will take -precedence. And if we add something that already existed in the parent, our child-version will -*override* the version in the parent. This is very practical: It means that we can let the parent do -the heavy lifting and only tweak the things we want to change. It also means that we could easily -have many different Character classes, all inheriting from `DefaultCharacter` but changing different -things. And those can in turn also have children ... - -Let's go on an expedition up the inheritance tree. - -### Exploring the Evennia library - -Let's figure out how to tweak `Character`. Right now we don't know much about `DefaultCharacter` -though. Without knowing that we won't know what to override. At the top of the file you find - -```python -from evennia import DefaultCharacter -``` - -This is an `import` statement again, but on a different form to what we've seen before. `from ... -import ...` is very commonly used and allows you to precisely dip into a module to extract just the -component you need to use. In this case we head into the `evennia` package to get -`DefaultCharacter`. - -Where is `evennia`? To find it you need to go to the `evennia` folder (repository) you originally -cloned from us. If you open it, this is how it looks: - -``` -evennia/ - __init__.py - bin/ - CHANGELOG.txt etc. - ... - evennia/ - ... -``` -There are lots of things in there. There are some docs but most of those have to do with the -distribution of Evennia and does not concern us right now. The `evennia` subfolder is what we are -looking for. *This* is what you are accessing when you do `from evennia import ...`. It's set up by -Evennia as a good place to find modules when the server starts. The exact layout of the Evennia -library [is covered by our directory overview](./Directory-Overview.md#evennia-library-layout). You can -also explore it [online on github](https://github.com/evennia/evennia/tree/master/evennia). - -The structure of the library directly reflects how you import from it. - -- To, for example, import [the text justify function](https://github.com/evennia/evennia/blob/master/evennia/utils/utils.py#L201) from -`evennia/utils/utils.py` you would do `from evennia.utils.utils import justify`. In your code you -could then just call `justify(...)` to access its functionality. -- You could also do `from evennia.utils import utils`. In code you would then have to write -`utils.justify(...)`. This is practical if want a lot of stuff from that `utils.py` module and don't -want to import each component separately. -- You could also do `import evennia`. You would then have to enter the full -`evennia.utils.utils.justify(...)` every time you use it. Using `from` to only import the things you -need is usually easier and more readable. -- See [this overview](http://effbot.org/zone/import-confusion.htm) about the different ways to -import in Python. - -Now, remember that our `characters.py` module did `from evennia import DefaultCharacter`. But if we -look at the contents of the `evennia` folder, there is no `DefaultCharacter` anywhere! This is -because Evennia gives a large number of optional "shortcuts", known as [the "flat" API](./Evennia-API.md). The intention is to make it easier to remember where to find stuff. The flat API is defined in -that weirdly named `__init__.py` file. This file just basically imports useful things from all over -Evennia so you can more easily find them in one place. - -We could [just look at the documenation](github:evennia#typeclasses) to find out where we can look -at our `DefaultCharacter` parent. But for practice, let's figure it out. Here is where -`DefaultCharacter` [is imported from](https://github.com/evennia/evennia/blob/master/evennia/__init__.py#L188) inside `__init__.py`: - -```python -from .objects.objects import DefaultCharacter -``` - -The period at the start means that it imports beginning from the same location this module sits(i.e. -the `evennia` folder). The full python-path accessible from the outside is thus -`evennia.objects.objects.DefaultCharacter`. So to import this into our game it'd be perfectly valid -to do - -```python -from evennia.objects.objects import DefaultCharacter -``` - -Using - -```python -from evennia import DefaultCharacter -``` - -is the same thing, just a little easier to remember. - -> To access the shortcuts of the flat API you *must* use `from evennia import -> ...`. Using something like `import evennia.DefaultCharacter` will not work. -> See [more about the Flat API here](./Evennia-API.md). - - -### Tweaking our Character class - -In the previous section we traced the parent of our `Character` class to be -`DefaultCharacter` in -[evennia/objects/objects.py](https://github.com/evennia/evennia/blob/master/evennia/objects/objects.py). -Open that file and locate the `DefaultCharacter` class. It's quite a bit down -in this module so you might want to search using your editor's (or browser's) -search function. Once you find it, you'll find that the class starts like this: - -```python - -class DefaultCharacter(DefaultObject): - """ - This implements an Object puppeted by a Session - that is, a character - avatar controlled by an account. - """ - - def basetype_setup(self): - """ - Setup character-specific security. - You should normally not need to overload this, but if you do, - make sure to reproduce at least the two last commands in this - method (unless you want to fundamentally change how a - Character object works). - """ - super().basetype_setup() - self.locks.add(";".join(["get:false()", # noone can pick up the character - "call:false()"])) # no commands can be called on character from -outside - # add the default cmdset - self.cmdset.add_default(settings.CMDSET_CHARACTER, permanent=True) - - def at_after_move(self, source_location, **kwargs): - """ - We make sure to look around after a move. - """ - if self.location.access(self, "view"): - self.msg(self.at_look(self.location)) - - def at_pre_puppet(self, account, session=None, **kwargs): - """ - Return the character from storage in None location in `at_post_unpuppet`. - """ - - # ... - -``` - -... And so on (you can see the full [class online here](https://github.com/evennia/evennia/blob/master/evennia/objects/objects.py#L1915)). Here we -have functional code! These methods may not be directly visible in `Character` back in our game dir, -but they are still available since `Character` is a child of `DefaultCharacter` above. Here is a -brief summary of the methods we find in `DefaultCharacter` (follow in the code to see if you can see -roughly where things happen):: - -- `basetype_setup` is called by Evennia only once, when a Character is first created. In the -`DefaultCharacter` class it sets some particular [Locks](./Locks.md) so that people can't pick up and -puppet Characters just like that. It also adds the [Character Cmdset](./Command-Sets.md) so that -Characters always can accept command-input (this should usually not be modified - the normal hook to -override is `at_object_creation`, which is called after `basetype_setup` (it's in the parent)). -- `at_after_move` makes it so that every time the Character moves, the `look` command is -automatically fired (this would not make sense for just any regular Object). -- `at_pre_puppet` is called when an Account begins to puppet this Character. When not puppeted, the -Character is hidden away to a `None` location. This brings it back to the location it was in before. -Without this, "headless" Characters would remain in the game world just standing around. -- `at_post_puppet` is called when puppeting is complete. It echoes a message to the room that his -Character has now connected. -- `at_post_unpuppet` is called once stopping puppeting of the Character. This hides away the -Character to a `None` location again. -- There are also some utility properties which makes it easier to get some time stamps from the -Character. - -Reading the class we notice another thing: - -```python -class DefaultCharacter(DefaultObject): - # ... -``` - -This means that `DefaultCharacter` is in *itself* a child of something called `DefaultObject`! Let's -see what this parent class provides. It's in the same module as `DefaultCharacter`, you just need to -[scroll up near the top](https://github.com/evennia/evennia/blob/master/evennia/objects/objects.py#L193): - -```python -class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): - # ... -``` - -This is a really big class where the bulk of code defining an in-game object resides. It consists of -a large number of methods, all of which thus also becomes available on the `DefaultCharacter` class -below *and* by extension in your `Character` class over in your game dir. In this class you can for -example find the `msg` method we have been using before. - -> You should probably not expect to understand all details yet, but as an exercise, find and read -the doc string of `msg`. - -> As seen, `DefaultObject` actually has multiple parents. In one of those the basic `key` property -is defined, but we won't travel further up the inheritance tree in this tutorial. If you are -interested to see them, you can find `TypeclassBase` in [evennia/typeclasses/models.py](https://github.com/evennia/evennia/blob/master/evennia/typeclasses/models.py#L93) and `ObjectDB` in [evennia/obj -ects/models.py](https://github.com/evennia/evennia/blob/master/evennia/objects/models.py#L121). We -will also not go into the details of [Multiple Inheritance](https://docs.python.org/2/tutorial/classes.html#multiple-inheritance) or -[Metaclasses](http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html) here. The general rule -is that if you realize that you need these features, you already know enough to use them. - -Remember the `at_pre_puppet` method we looked at in `DefaultCharacter`? If you look at the -`at_pre_puppet` hook as defined in `DefaultObject` you'll find it to be completely empty (just a -`pass`). So if you puppet a regular object it won't be hiding/retrieving the object when you -unpuppet it. The `DefaultCharacter` class *overrides* its parent's functionality with a version of -its own. And since it's `DefaultCharacter` that our `Character` class inherits back in our game dir, -it's *that* version of `at_pre_puppet` we'll get. Anything not explicitly overridden will be passed -down as-is. - -While it's useful to read the code, we should never actually modify anything inside the `evennia` -folder. Only time you would want that is if you are planning to release a bug fix or new feature for -Evennia itself. Instead you *override* the default functionality inside your game dir. - -So to conclude our little foray into classes, objects and inheritance, locate the simple little -`at_before_say` method in the `DefaultObject` class: - -```python - def at_before_say(self, message, **kwargs): - """ - (doc string here) - """ - return message -``` - -If you read the doc string you'll find that this can be used to modify the output of `say` before it -goes out. You can think of it like this: Evennia knows the name of this method, and when someone -speaks, Evennia will make sure to redirect the outgoing message through this method. It makes it -ripe for us to replace with a version of our own. - -> In the Evennia documentation you may sometimes see the term *hook* used for a method explicitly -meant to be overridden like this. - -As you can see, the first argument to `at_before_say` is `self`. In Python, the first argument of a -method is *always a back-reference to the object instance on which the method is defined*. By -convention this argument is always called `self` but it could in principle be named anything. The -`self` is very useful. If you wanted to, say, send a message to the same object from inside -`at_before_say`, you would do `self.msg(...)`. - -What can trip up newcomers is that you *don't* include `self` when you *call* the method. Try: - - > @py me.at_before_say("Hello World!") - Hello World! - -Note that we don't send `self` but only the `message` argument. Python will automatically add `self` -for us. In this case, `self` will become equal to the Character instance `me`. - -By default the `at_before_say` method doesn't do anything. It just takes the `message` input and -`return`s it just the way it was (the `return` is another reserved Python word). - -> We won't go into `**kwargs` here, but it (and its sibling `*args`) is also important to -understand, extra reading is [here for `**kwargs`](https://stackoverflow.com/questions/1769403/understanding-kwargs-in-python). - -Now, open your game folder and edit `mygame/typeclasses/characters.py`. Locate your `Character` -class and modify it as such: - -```python -class Character(DefaultCharacter): - """ - (docstring here) - """ - def at_before_say(self, message, **kwargs): - "Called before say, allows for tweaking message" - return f"{message} ..." -``` - -So we add our own version of `at_before_say`, duplicating the `def` line from the parent but putting -new code in it. All we do in this tutorial is to add an ellipsis (`...`) to the message as it passes -through the method. - -Note that `f` in front of the string, it means we turned the string into a 'formatted string'. We -can now easily inject stuff directly into the string by wrapping them in curly brackets `{ }`. In -this example, we put the incoming `message` into the string, followed by an ellipsis. This is only -one way to format a string. Python has very powerful [string formatting](https://docs.python.org/2/library/string.html#format-specification-mini-language) and -you are wise to learn it well, considering your game will be mainly text-based. - -> You could also copy & paste the relevant method from `DefaultObject` here to get the full doc -string. For more complex methods, or if you only want to change some small part of the default -behavior, copy & pasting will eliminate the need to constantly look up the original method and keep -you sane. - -In-game, now try - - > @reload - > say Hello - You say, "Hello ..." - -An ellipsis `...` is added to what you said! This is a silly example but you have just made your -first code change to core functionality - without touching any of Evennia's original code! We just -plugged in our own version of the `at_before_say` method and it replaced the default one. Evennia -happily redirected the message through our version and we got a different output. - -> For sane overriding of parent methods you should also be aware of Python's -[super](https://docs.python.org/3/library/functions.html#super), which allows you to call the -methods defined on a parent in your child class. - -### The Evennia shell - -Now on to some generally useful tools as you continue learning Python and Evennia. We have so far -explored using `py` and have inserted Python code directly in-game. We have also modified Evennia's -behavior by overriding default functionality with our own. There is a third way to conveniently -explore Evennia and Python - the Evennia shell. - -Outside of your game, `cd` to your mygame folder and make sure any needed virtualenv is running. -Next: - - > pip install ipython # only needed once - -The [`IPython`](https://en.wikipedia.org/wiki/IPython) program is just a nicer interface to the -Python interpreter - you only need to install it once, after which Evennia will use it -automatically. - - > evennia shell - -If you did this call from your game dir you will now be in a Python prompt managed by the IPython -program. - - IPython ... - ... - In [1]: IPython has some very nice ways to explore what Evennia has to offer. - - > import evennia - > evennia. - -That is, write `evennia.` and press the Tab key. You will be presented with a list of all available -resources in the Evennia Flat API. We looked at the `__init__.py` file in the `evennia` folder -earlier, so some of what you see should be familiar. From the IPython prompt, do: - - > from evennia import DefaultCharacter - > DefaultCharacter.at_before_say? - -Don't forget that you can use `` to auto-complete code as you write. Appending a single `?` to -the end will show you the doc-string for `at_before_say` we looked at earlier. Use `??` to get the -whole source code. - -Let's look at our over-ridden version instead. Since we started the `evennia shell` from our game -dir we can easily get to our code too: - - > from typeclasses.characters import Character - > Character.at_before_say?? - -This will show us the changed code we just did. Having a window with IPython running is very -convenient for quickly exploring code without having to go digging through the file structure! - -### Where to go from here - -This should give you a running start using Python with Evennia. If you are completely new to -programming or Python you might want to look at a more formal Python tutorial. You can find links -and resources [on our link page](./Links.md). - -We have touched upon many of the concepts here but to use Evennia and to be able to follow along in -the code, you will need basic understanding of Python -[modules](http://docs.python.org/2/tutorial/modules.html), -[variables](http://www.tutorialspoint.com/python/python_variable_types.htm), -[conditional statements](http://docs.python.org/tutorial/controlflow.html#if-statements), -[loops](http://docs.python.org/tutorial/controlflow.html#for-statements), -[functions](http://docs.python.org/tutorial/controlflow.html#defining-functions), -[lists, dictionaries, list comprehensions](http://docs.python.org/tutorial/datastructures.html) -and [string formatting](http://docs.python.org/tutorial/introduction.html#strings). You should also have a basic -understanding of [object-oriented programming](http://www.tutorialspoint.com/python/python_classes_objects.htm) -and what Python [Classes](http://docs.python.org/tutorial/classes.html) are. - -Once you have familiarized yourself, or if you prefer to pick Python up as you go, continue to one -of the beginning-level [Evennia tutorials](./Tutorials.md) to gradually build up your understanding. - -Good luck! diff --git a/docs/0.9.5/_sources/Quirks.md.txt b/docs/0.9.5/_sources/Quirks.md.txt deleted file mode 100644 index c23b4a41fc..0000000000 --- a/docs/0.9.5/_sources/Quirks.md.txt +++ /dev/null @@ -1,120 +0,0 @@ -# Quirks - - -This is a list of various quirks or common stumbling blocks that people often ask about or report -when using (or trying to use) Evennia. They are not bugs. - -### Forgetting to use @reload to see changes to your typeclasses - -Firstly: Reloading the server is a safe and usually quick operation which will *not* disconnect any -accounts. - -New users tend to forget this step. When editing source code (such as when tweaking typeclasses and -commands or adding new commands to command sets) you need to either use the in-game `@reload` -command or, from the command line do `python evennia.py reload` before you see your changes. - -### Web admin to create new Account - -If you use the default login system and are trying to use the Web admin to create a new Player -account, you need to consider which `MULTIACCOUNT_MODE` you are in. If you are in -`MULTIACCOUNT_MODE` `0` or `1`, the login system expects each Account to also have a Character -object named the same as the Account - there is no character creation screen by default. If using -the normal mud login screen, a Character with the same name is automatically created and connected -to your Account. From the web interface you must do this manually. - -So, when creating the Account, make sure to also create the Character *from the same form* as you -create the Account from. This should set everything up for you. Otherwise you need to manually set -the "account" property on the Character and the "character" property on the Account to point to each -other. You must also set the lockstring of the Character to allow the Account to "puppet" this -particular character. - -### Mutable attributes and their connection to the database - -When storing a mutable object (usually a list or a dictionary) in an Attribute - -```python - object.db.mylist = [1,2,3] -``` - -you should know that the connection to the database is retained also if you later extract that -Attribute into another variable (what is stored and retrieved is actually a `PackedList` or a -`PackedDict` that works just like their namesakes except they save themselves to the database when -changed). So if you do - -```python - alist = object.db.mylist - alist.append(4) -``` - -this updates the database behind the scenes, so both `alist` and `object.db.mylist` are now -`[1,2,3,4]` - -If you don't want this, Evennia provides a way to stably disconnect the mutable from the database by -use of `evennia.utils.dbserialize.deserialize`: - -```python - from evennia.utils.dbserialize import deserialize - - blist = deserialize(object.db.mylist) - blist.append(4) -``` - -The property `blist` is now `[1,2,3,4]` whereas `object.db.mylist` remains unchanged. If you want to -update the database you'd need to explicitly re-assign the updated data to the `mylist` Attribute. - -### Commands are matched by name *or* alias - -When merging [command sets](./Commands.md) it's important to remember that command objects are identified -*both* by key *or* alias. So if you have a command with a key `look` and an alias `ls`, introducing -another command with a key `ls` will be assumed by the system to be *identical* to the first one. -This usually means merging cmdsets will overload one of them depending on priority. Whereas this is -logical once you know how command objects are handled, it may be confusing if you are just looking -at the command strings thinking they are parsed as-is. - -### Objects turning to `DefaultObject` - -A common confusing error for new developers is finding that one or more objects in-game are suddenly -of the type `DefaultObject` rather than the typeclass you wanted it to be. This happens when you -introduce a critical Syntax error to the module holding your custom class. Since such a module is -not valid Python, Evennia can't load it at all to get to the typeclasses within. To keep on running, -Evennia will solve this by printing the full traceback to the terminal/console and temporarily fall -back to the safe `DefaultObject` until you fix the problem and reload. Most errors of this kind will -be caught by any good text editors. Keep an eye on the terminal/console during a reload to catch -such errors - you may have to scroll up if your window is small. - -### Overriding of magic methods - -Python implements a system of [magic -methods](https://docs.python.org/3/reference/datamodel.html#emulating-container-types), usually -prefixed and suffixed by double-underscores (`__example__`) that allow object instances to have -certain operations performed on them without needing to do things like turn them into strings or -numbers first-- for example, is `obj1` greater than or equal to `obj2`? - -Neither object is a number, but given `obj1.size == "small"` and `obj2.size == "large"`, how might -one compare these two arbitrary English adjective strings to figure out which is greater than the -other? By defining the `__ge__` (greater than or equal to) magic method on the object class in which -you figure out which word has greater significance, perhaps through use of a mapping table -(`{'small':0, 'large':10}`) or other lookup and comparing the numeric values of each. - -Evennia extensively makes use of magic methods on typeclasses to do things like initialize objects, -check object existence or iterate over objects in an inventory or container. If you override or -interfere with the return values from the methods Evennia expects to be both present and working, it -can result in very inconsistent and hard-to-diagnose errors. - -The moral of the story-- it can be dangerous to tinker with magic methods on typeclassed objects. -Try to avoid doing so. - -### Known upstream bugs - -- There is currently (Autumn 2017) a bug in the `zope.interface` installer on some Linux Ubuntu -distributions (notably Ubuntu 16.04 LTS). Zope is a dependency of Twisted. The error manifests in -the server not starting with an error that `zope.interface` is not found even though `pip list` -shows it's installed. The reason is a missing empty `__init__.py` file at the root of the zope -package. If the virtualenv is named "evenv" as suggested in the [Getting Started](./Getting-Started.md) -instructions, use the following command to fix it: - - ```shell - touch evenv/local/lib/python2.7/site-packages/zope/__init__.py - ``` - - This will create the missing file and things should henceforth work correctly. \ No newline at end of file diff --git a/docs/0.9.5/_sources/RSS.md.txt b/docs/0.9.5/_sources/RSS.md.txt deleted file mode 100644 index 73c35b0f2f..0000000000 --- a/docs/0.9.5/_sources/RSS.md.txt +++ /dev/null @@ -1,47 +0,0 @@ -# RSS - - -[RSS](http://en.wikipedia.org/wiki/RSS) is a format for easily tracking updates on websites. The -principle is simple - whenever a site is updated, a small text file is updated. An RSS reader can -then regularly go online, check this file for updates and let the user know what's new. - -Evennia allows for connecting any number of RSS feeds to any number of in-game channels. Updates to -the feed will be conveniently echoed to the channel. There are many potential uses for this: For -example the MUD might use a separate website to host its forums. Through RSS, the players can then -be notified when new posts are made. Another example is to let everyone know you updated your dev -blog. Admins might also want to track the latest Evennia updates through our own RSS feed -[here](http://code.google.com/feeds/p/evennia/updates/basic). - -## Configuring RSS - -To use RSS, you first need to install the [feedparser](http://code.google.com/p/feedparser/) python -module. - - pip install feedparser - -Next you activate RSS support in your config file by settting `RSS_ENABLED=True`. - -Start/reload Evennia as a privileged user. You should now have a new command available, `@rss2chan`: - - @rss2chan = - -### Setting up RSS, step by step - -You can connect RSS to any Evennia channel, but for testing, let's set up a new channel "rss". - - @ccreate rss = RSS feeds are echoed to this channel! - -Let's connect Evennia's code-update feed to this channel. The RSS url for evennia updates is -`https://github.com/evennia/evennia/commits/master.atom`, so let's add that: - - @rss2chan rss = https://github.com/evennia/evennia/commits/master.atom - -That's it, really. New Evennia updates will now show up as a one-line title and link in the channel. -Give the `@rss2chan` command on its own to show all connections. To remove a feed from a channel, -you specify the connection again (use the command to see it in the list) but add the `/delete` -switch: - - @rss2chan/delete rss = https://github.com/evennia/evennia/commits/master.atom - -You can connect any number of RSS feeds to a channel this way. You could also connect them to the -same channels as [IRC](./IRC.md) to have the feed echo to external chat channels as well. diff --git a/docs/0.9.5/_sources/Roadmap.md.txt b/docs/0.9.5/_sources/Roadmap.md.txt deleted file mode 100644 index 5dde75a599..0000000000 --- a/docs/0.9.5/_sources/Roadmap.md.txt +++ /dev/null @@ -1,5 +0,0 @@ -# Roadmap - - -*As of Autumn 2016, Evennia's development roadmap is tracked through the [Evennia Projects -Page](https://github.com/evennia/evennia/projects).* \ No newline at end of file diff --git a/docs/0.9.5/_sources/Running-Evennia-in-Docker.md.txt b/docs/0.9.5/_sources/Running-Evennia-in-Docker.md.txt deleted file mode 100644 index ca546dc7a1..0000000000 --- a/docs/0.9.5/_sources/Running-Evennia-in-Docker.md.txt +++ /dev/null @@ -1,299 +0,0 @@ -# Running Evennia in Docker - -Evennia has an [official docker image](https://hub.docker.com/r/evennia/evennia/) which makes -running an Evennia-based game in a Docker container easy. - -## Install Evennia through docker - -First, install the `docker` program so you can run the Evennia container. You can get it freely from -[docker.com](https://www.docker.com/). Linux users can likely also get it through their normal -package manager. - -To fetch the latest evennia docker image, run: - - docker pull evennia/evennia - -This is a good command to know, it is also how you update to the latest version when we make updates -in the future. This tracks the `master` branch of Evennia. - -> Note: If you want to experiment with the (unstable) `develop` branch, use `docker pull -evennia/evennia:develop`. - -Next `cd` to a place where your game dir is, or where you want to create it. Then run: - - docker run -it --rm -p 4000:4000 -p 4001:4001 -p 4002:4002 --rm -v $PWD:/usr/src/game --user -$UID:$GID evennia/evennia - -Having run this (see next section for a description of what's what), you will be at a prompt inside -the docker container: - -```bash -evennia|docker /usr/src/game $ -``` - -This is a normal shell prompt. We are in the `/usr/src/game` location inside the docker container. -If you had anything in the folder you started from, you should see it here (with `ls`) since we -mounted the current directory to `/usr/src/game` (with `-v` above). You have the `evennia` command -available and can now proceed to create a new game as per the [Getting Started](./Getting-Started.md) -instructions (you can skip the virtualenv and install 'globally' in the container though). - -You can run Evennia from inside this container if you want to, it's like you are root in a little -isolated Linux environment. To exit the container and all processes in there, press `Ctrl-D`. If you -created a new game folder, you will find that it has appeared on-disk. - -> The game folder or any new files that you created from inside the container will appear as owned -by `root`. If you want to edit the files outside of the container you should change the ownership. -On Linux/Mac you do this with `sudo chown myname:myname -R mygame`, where you replace `myname` with -your username and `mygame` with whatever your game folder is named. - -### Description of the `docker run` command - -```bash - docker run -it --rm -p 4000:4000 -p 4001:4001 -p 4002:4002 --rm -v $PWD:/usr/src/game --user -$UID:$GID evennia/evennia -``` - -This is what it does: - -- `docker run ... evennia/evennia` tells us that we want to run a new container based on the -`evennia/evennia` docker image. Everything in between are options for this. The `evennia/evennia` is -the name of our [official docker image on the dockerhub -repository](https://hub.docker.com/r/evennia/evennia/). If you didn't do `docker pull -evennia/evennia` first, the image will be downloaded when running this, otherwise your already -downloaded version will be used. It contains everything needed to run Evennia. -- `-it` has to do with creating an interactive session inside the container we start. -- `--rm` will make sure to delete the container when it shuts down. This is nice to keep things tidy -on your drive. -- `-p 4000:4000 -p 4001:4001 -p 4002:4002` means that we *map* ports `4000`, `4001` and `4002` from -inside the docker container to same-numbered ports on our host machine. These are ports for telnet, -webserver and websockets. This is what allows your Evennia server to be accessed from outside the -container (such as by your MUD client)! -- `-v $PWD:/usr/src/game` mounts the current directory (*outside* the container) to the path -`/usr/src/game` *inside* the container. This means that when you edit that path in the container you -will actually be modifying the "real" place on your hard drive. If you didn't do this, any changes -would only exist inside the container and be gone if we create a new one. Note that in linux a -shortcut for the current directory is `$PWD`. If you don't have this for your OS, you can replace it -with the full path to the current on-disk directory (like `C:/Development/evennia/game` or wherever -you want your evennia files to appear). -- `--user $UID:$GID` ensures the container's modifications to `$PWD` are done with you user and -group IDs instead of root's IDs (root is the user running evennia inside the container). This avoids -having stale `.pid` files in your filesystem between container reboots which you have to force -delete with `sudo rm server/*.pid` before each boot. - -## Running your game as a docker image - -If you run the `docker` command given in the previous section from your game dir you can then -easily start Evennia and have a running server without any further fuss. - -But apart from ease of install, the primary benefit to running an Evennia-based game in a container -is to simplify its deployment into a public production environment. Most cloud-based hosting -providers these days support the ability to run container-based applications. This makes deploying -or updating your game as simple as building a new container image locally, pushing it to your Docker -Hub account, and then pulling from Docker Hub into your AWS/Azure/other docker-enabled hosting -account. The container eliminates the need to install Python, set up a virtualenv, or run pip to -install dependencies. - -### Start Evennia and run through docker - -For remote or automated deployment you may want to start Evennia immediately as soon as the docker -container comes up. If you already have a game folder with a database set up you can also start the -docker container and pass commands directly to it. The command you pass will be the main process to -run in the container. From your game dir, run for example this command: - - docker run -it --rm -p 4000:4000 -p 4001:4001 -p 4002:4002 --rm -v $PWD:/usr/src/game -evennia/evennia evennia start --log - -This will start Evennia as the foreground process, echoing the log to the terminal. Closing the -terminal will kill the server. Note that you *must* use a foreground command like `evennia start ---log` or `evennia ipstart` to start the server - otherwise the foreground process will finish -immediately and the container go down. - -### Create your own game image - -You may want to create your own image in order to bake in your gamedir directly into the docker -container for easy upload and deployment. -These steps assume that you have created or otherwise obtained a game directory already. First, `cd` -to your game dir and create a new empty text file named `Dockerfile`. Save the following two lines -into it: - -``` -FROM evennia/evennia:latest - -ENTRYPOINT evennia start --log -``` - -These are instructions for building a new docker image. This one is based on the official -`evennia/evennia` image. We add the second line to -make make sure evennia starts immediately along with the container (so we don't need to enter it and -run commands). - -To build the image: - -```bash - docker build -t mydhaccount/mygame . -``` - -(don't forget the period `.` at the end, it tells docker to use use the `Dockerfile` from the -current location). Here `mydhaccount` is the name of your `dockerhub` account. If you don't have a -dockerhub account you can build the image locally only (name the container whatever you like in that -case, like just `mygame`). - -Docker images are stored centrally on your computer. You can see which ones you have available -locally with `docker images`. Once built, you have a couple of options to run your game. - -If you have a docker-hub account, you can push your (new or updated) image there: - -```bash - docker push myhdaccount/mygame -``` - -### Run container from your game image for development - -To run the container based on your game image locally for development, mount the local game -directory as before: - -``` -docker run -it --rm -p 4000:4000 -p 4001:4001 -p 4002:4002 -v $PWD:/usr/src/game --user $UID:$GID -mydhaccount/mygame -``` - -Evennia will start and you'll get output in the terminal, perfect for development. You should be -able to connect to the game with your clients normally. - -### Deploy game image for production - -Each time you rebuild the docker image as per the above instructions, the latest copy of your game -directory is actually copied inside the image (at `/usr/src/game/`). If you don't mount your on-disk -folder there, the internal one will be used. So for deploying evennia on a server, omit the `-v` -option and just give the following command: - -``` -docker run -it --rm -d -p 4000:4000 -p 4001:4001 -p 4002:4002 --user $UID:$GID mydhaccount/mygame -``` - -Your game will be downloaded from your docker-hub account and a new container will be built using -the image and started on the server! If your server environment forces you to use different ports, -you can just map the normal ports differently in the command above. - -Above we added the `-d` option, which starts the container in *daemon* mode - you won't see any -return in the console. You can see it running with `docker ps`: - -```bash -$ docker ps - -CONTAINER ID IMAGE COMMAND CREATED ... -f6d4ca9b2b22 mygame "/bin/sh -c 'evenn..." About a minute ago ... -``` - -Note the container ID, this is how you manage the container as it runs. - -``` - docker logs f6d4ca9b2b22 -``` -Looks at the STDOUT output of the container (i.e. the normal server log) -``` - docker logs -f f6d4ca9b2b22 -``` -Tail the log (so it updates to your screen 'live'). -``` - docker pause f6d4ca9b2b22 -``` -Suspend the state of the container. -``` - docker unpause f6d4ca9b2b22 -``` -Un-suspend it again after a pause. It will pick up exactly where it were. -``` - docker stop f6d4ca9b2b22 -``` -Stop the container. To get it up again you need to use `docker run`, specifying ports etc. A new -container will get a new container id to reference. - -## How it Works - -The `evennia/evennia` docker image holds the evennia library and all of its dependencies. It also -has an `ONBUILD` directive which is triggered during builds of images derived from it. This -`ONBUILD` directive handles setting up a volume and copying your game directory code into the proper -location within the container. - -In most cases, the Dockerfile for an Evennia-based game will only need the `FROM -evennia/evennia:latest` directive, and optionally a `MAINTAINER` directive if you plan to publish -your image on Docker Hub and would like to provide contact info. - -For more information on Dockerfile directives, see the [Dockerfile -Reference](https://docs.docker.com/engine/reference/builder/). - -For more information on volumes and Docker containers, see the Docker site's [Manage data in -containers](https://docs.docker.com/engine/tutorials/dockervolumes/) page. - -### What if I Don't Want "LATEST"? - -A new `evennia/evennia` image is built automatically whenever there is a new commit to the `master` -branch of Evennia. It is possible to create your own custom evennia base docker image based on any -arbitrary commit. - -1. Use git tools to checkout the commit that you want to base your image upon. (In the example -below, we're checking out commit a8oc3d5b.) -``` -git checkout -b my-stable-branch a8oc3d5b -``` -2. Change your working directory to the `evennia` directory containing `Dockerfile`. Note that -`Dockerfile` has changed over time, so if you are going far back in the commit history you might -want to bring a copy of the latest `Dockerfile` with you and use that instead of whatever version -was used at the time. -3. Use the `docker build` command to build the image based off of the currently checked out commit. -The example below assumes your docker account is **mydhaccount**. -``` -docker build -t mydhaccount/evennia . -``` -4. Now you have a base evennia docker image built off of a specific commit. To use this image to -build your game, you would modify **FROM** directive in the **Dockerfile** for your game directory -to be: - -``` -FROM mydhacct/evennia:latest -``` - -Note: From this point, you can also use the `docker tag` command to set a specific tag on your image -and/or upload it into Docker Hub under your account. - -5. At this point, build your game using the same `docker build` command as usual. Change your -working directory to be your game directory and run - -``` -docker build -t mydhaccountt/mygame . -``` - -## Additional Creature Comforts - -The Docker ecosystem includes a tool called `docker-compose`, which can orchestrate complex multi- -container applications, or in our case, store the default port and terminal parameters that we want -specified every time we run our container. A sample `docker-compose.yml` file to run a containerized -Evennia game in development might look like this: -``` -version: '2' - -services: - evennia: - image: mydhacct/mygame - stdin_open: true - tty: true - ports: - - "4001-4002:4001-4002" - - "4000:4000" - volumes: - - .:/usr/src/game -``` -With this file in the game directory next to the `Dockerfile`, starting the container is as simple -as -``` -docker-compose up -``` -For more information about `docker-compose`, see [Getting Started with docker- -compose](https://docs.docker.com/compose/gettingstarted/). - -> Note that with this setup you lose the `--user $UID` option. The problem is that the variable -`UID` is not available inside the configuration file `docker-compose.yml`. A workaround is to -hardcode your user and group id. In a terminal run `echo $UID:$GID` and if for example you get -`1000:1000` you can add to `docker-compose.yml` a line `user: 1000:1000` just below the `image: ...` -line. diff --git a/docs/0.9.5/_sources/Screenshot.md.txt b/docs/0.9.5/_sources/Screenshot.md.txt deleted file mode 100644 index 322dda2349..0000000000 --- a/docs/0.9.5/_sources/Screenshot.md.txt +++ /dev/null @@ -1,19 +0,0 @@ -# Screenshot - - -![evennia_screenshot2017](https://user-images.githubusercontent.com/294267/30773728-ea45afb6-a076-11e7-8820-49be2168a6b8.png) -*(right-click and choose your browser's equivalent of "view image" to see it full size)* - -This screenshot shows a vanilla [install](./Getting-Started.md) of the just started Evennia MUD server. -In the bottom window we can see the log messages from the running server. - -In the top left window we see the default website of our new game displayed in a web browser (it has -shrunk to accomodate the smaller screen). Evennia contains its own webserver to serve this page. The -default site shows some brief info about the database. From here you can also reach Django's *admin -interface* for editing the database online. - -To the upper right is the included web-browser client showing a connection to the server on port -4001. This allows users to access the game without downloading a mud client separately. - -Bottom right we see a login into the stock game using a third-party MUD client -([Mudlet](http://www.mudlet.org)). This connects to the server via the telnet protocol on port 4000. diff --git a/docs/0.9.5/_sources/Scripts.md.txt b/docs/0.9.5/_sources/Scripts.md.txt deleted file mode 100644 index dc1c5a8d98..0000000000 --- a/docs/0.9.5/_sources/Scripts.md.txt +++ /dev/null @@ -1,384 +0,0 @@ -# Scripts - - -*Scripts* are the out-of-character siblings to the in-character -[Objects](./Objects.md). Scripts are so flexible that the "Script" is a bit limiting -- we had to pick something to name them after all. Other possible names -(depending on what you'd use them for) would be `OOBObjects`, -`StorageContainers` or `TimerObjects`. - -Scripts can be used for many different things in Evennia: - -- They can attach to Objects to influence them in various ways - or exist - independently of any one in-game entity (so-called *Global Scripts*). -- They can work as timers and tickers - anything that may change with Time. But - they can also have no time dependence at all. Note though that if all you want - is just to have an object method called repeatedly, you should consider using - the [TickerHandler](./TickerHandler.md) which is more limited but is specialized on - just this task. -- They can describe State changes. A Script is an excellent platform for -hosting a persistent, but unique system handler. For example, a Script could be -used as the base to track the state of a turn-based combat system. Since -Scripts can also operate on a timer they can also update themselves regularly -to perform various actions. -- They can act as data stores for storing game data persistently in the database -(thanks to its ability to have [Attributes](./Attributes.md)). -- They can be used as OOC stores for sharing data between groups of objects, for -example for tracking the turns in a turn-based combat system or barter exchange. - -Scripts are [Typeclassed](./Typeclasses.md) entities and are manipulated in a similar -way to how it works for other such Evennia entities: - -```python -# create a new script -new_script = evennia.create_script(key="myscript", typeclass=...) - -# search (this is always a list, also if there is only one match) -list_of_myscript = evennia.search_script("myscript") - -``` - -## Defining new Scripts - -A Script is defined as a class and is created in the same way as other -[typeclassed](./Typeclasses.md) entities. The class has several properties -to control the timer-component of the scripts. These are all _optional_ - -leaving them out will just create a Script with no timer components (useful to act as -a database store or to hold a persistent game system, for example). - -This you can do for example in the module -`evennia/typeclasses/scripts.py`. Below is an example Script - Typeclass. - -```python -from evennia import DefaultScript - -class MyScript(DefaultScript): - - def at_script_creation(self): - self.key = "myscript" - self.interval = 60 # 1 min repeat - - def at_repeat(self): - # do stuff every minute -``` - -In `mygame/typeclasses/scripts.py` is the `Script` class which inherits from `DefaultScript` -already. This is provided as your own base class to do with what you like: You can tweak `Script` if -you want to change the default behavior and it is usually convenient to inherit from this instead. -Here's an example: - -```python - # for example in mygame/typeclasses/scripts.py - # Script class is defined at the top of this module - - import random - - class Weather(Script): - """ - A timer script that displays weather info. Meant to - be attached to a room. - - """ - def at_script_creation(self): - self.key = "weather_script" - self.desc = "Gives random weather messages." - self.interval = 60 * 5 # every 5 minutes - self.persistent = True # will survive reload - - def at_repeat(self): - "called every self.interval seconds." - rand = random.random() - if rand < 0.5: - weather = "A faint breeze is felt." - elif rand < 0.7: - weather = "Clouds sweep across the sky." - else: - weather = "There is a light drizzle of rain." - # send this message to everyone inside the object this - # script is attached to (likely a room) - self.obj.msg_contents(weather) -``` - -If we put this script on a room, it will randomly report some weather -to everyone in the room every 5 minutes. - -To activate it, just add it to the script handler (`scripts`) on an -[Room](./Objects.md). That object becomes `self.obj` in the example above. Here we -put it on a room called `myroom`: - -``` - myroom.scripts.add(scripts.Weather) -``` - -> Note that `typeclasses` in your game dir is added to the setting `TYPECLASS_PATHS`. -> Therefore we don't need to give the full path (`typeclasses.scripts.Weather` -> but only `scripts.Weather` above. - -If you wanted to stop and delete that script on the [Room](./Objects.md). You could do that -with the script handler by passing the `delete` method with the script key (`self.key`) as: - -``` - myroom.scripts.delete('weather_script') -``` - -> Note that If no key is given, this will delete *all* scripts on the object! - -You can also create scripts using the `evennia.create_script` function: - -```python - from evennia import create_script - create_script('typeclasses.weather.Weather', obj=myroom) -``` - -Note that if you were to give a keyword argument to `create_script`, that would -override the default value in your Typeclass. So for example, here is an instance -of the weather script that runs every 10 minutes instead (and also not survive -a server reload): - -```python - create_script('typeclasses.weather.Weather', obj=myroom, - persistent=False, interval=10*60) -``` - -From in-game you can use the `@script` command to launch the Script on things: - -``` - @script here = typeclasses.scripts.Weather -``` - -You can conveniently view and kill running Scripts by using the `@scripts` -command in-game. - -## Properties and functions defined on Scripts - -A Script has all the properties of a typeclassed object, such as `db` and `ndb`(see -[Typeclasses](./Typeclasses.md)). Setting `key` is useful in order to manage scripts (delete them by name -etc). These are usually set up in the Script's typeclass, but can also be assigned on the fly as -keyword arguments to `evennia.create_script`. - -- `desc` - an optional description of the script's function. Seen in script listings. -- `interval` - how often the script should run. If `interval == 0` (default), this script has no -timing component, will not repeat and will exist forever. This is useful for Scripts used for -storage or acting as bases for various non-time dependent game systems. -- `start_delay` - (bool), if we should wait `interval` seconds before firing for the first time or -not. -- `repeats` - How many times we should repeat, assuming `interval > 0`. If repeats is set to `<= 0`, -the script will repeat indefinitely. Note that *each* firing of the script (including the first one) -counts towards this value. So a `Script` with `start_delay=False` and `repeats=1` will start, -immediately fire and shut down right away. -- `persistent`- if this script should survive a server *reset* or server *shutdown*. (You don't need -to set this for it to survive a normal reload - the script will be paused and seamlessly restart -after the reload is complete). - -There is one special property: - -- `obj` - the [Object](./Objects.md) this script is attached to (if any). You should not need to set -this manually. If you add the script to the Object with `myobj.scripts.add(myscriptpath)` or give -`myobj` as an argument to the `utils.create.create_script` function, the `obj` property will be set -to `myobj` for you. - -It's also imperative to know the hook functions. Normally, overriding -these are all the customization you'll need to do in Scripts. You can -find longer descriptions of these in `src/scripts/scripts.py`. - -- `at_script_creation()` - this is usually where the script class sets things like `interval` and -`repeats`; things that control how the script runs. It is only called once - when the script is -first created. -- `is_valid()` - determines if the script should still be running or not. This is called when -running `obj.scripts.validate()`, which you can run manually, but which is also called by Evennia -during certain situations such as reloads. This is also useful for using scripts as state managers. -If the method returns `False`, the script is stopped and cleanly removed. -- `at_start()` - this is called when the script starts or is unpaused. For persistent scripts this -is at least once ever server startup. Note that this will *always* be called right away, also if -`start_delay` is `True`. -- `at_repeat()` - this is called every `interval` seconds, or not at all. It is called right away at -startup, unless `start_delay` is `True`, in which case the system will wait `interval` seconds -before calling. -- `at_stop()` - this is called when the script stops for whatever reason. It's a good place to do -custom cleanup. -- `at_server_reload()` - this is called whenever the server is warm-rebooted (e.g. with the -`@reload` command). It's a good place to save non-persistent data you might want to survive a -reload. -- `at_server_shutdown()` - this is called when a system reset or systems shutdown is invoked. - -Running methods (usually called automatically by the engine, but possible to also invoke manually) - -- `start()` - this will start the script. This is called automatically whenever you add a new script -to a handler. `at_start()` will be called. -- `stop()` - this will stop the script and delete it. Removing a script from a handler will stop it -automatically. `at_stop()` will be called. -- `pause()` - this pauses a running script, rendering it inactive, but not deleting it. All -properties are saved and timers can be resumed. This is called automatically when the server reloads -and will *not* lead to the *at_stop()* hook being called. This is a suspension of the script, not a -change of state. -- `unpause()` - resumes a previously paused script. The `at_start()` hook *will* be called to allow -it to reclaim its internal state. Timers etc are restored to what they were before pause. The server -automatically unpauses all paused scripts after a server reload. -- `force_repeat()` - this will forcibly step the script, regardless of when it would otherwise have -fired. The timer will reset and the `at_repeat()` hook is called as normal. This also counts towards -the total number of repeats, if limited. -- `time_until_next_repeat()` - for timed scripts, this returns the time in seconds until it next -fires. Returns `None` if `interval==0`. -- `remaining_repeats()` - if the Script should run a limited amount of times, this tells us how many -are currently left. -- `reset_callcount(value=0)` - this allows you to reset the number of times the Script has fired. It -only makes sense if `repeats > 0`. -- `restart(interval=None, repeats=None, start_delay=None)` - this method allows you to restart the -Script in-place with different run settings. If you do, the `at_stop` hook will be called and the -Script brought to a halt, then the `at_start` hook will be called as the Script starts up with your -(possibly changed) settings. Any keyword left at `None` means to not change the original setting. - - -## Global Scripts - -A script does not have to be connected to an in-game object. If not it is -called a *Global script*. You can create global scripts by simply not supplying an object to store -it on: - -```python - # adding a global script - from evennia import create_script - create_script("typeclasses.globals.MyGlobalEconomy", - key="economy", persistent=True, obj=None) -``` -Henceforth you can then get it back by searching for its key or other identifier with -`evennia.search_script`. In-game, the `scripts` command will show all scripts. - -Evennia supplies a convenient "container" called `GLOBAL_SCRIPTS` that can offer an easy -way to access global scripts. If you know the name (key) of the script you can get it like so: - -```python -from evennia import GLOBAL_SCRIPTS - -my_script = GLOBAL_SCRIPTS.my_script -# needed if there are spaces in name or name determined on the fly -another_script = GLOBAL_SCRIPTS.get("another script") -# get all global scripts (this returns a Queryset) -all_scripts = GLOBAL_SCRIPTS.all() -# you can operate directly on the script -GLOBAL_SCRIPTS.weather.db.current_weather = "Cloudy" - -``` - -> Note that global scripts appear as properties on `GLOBAL_SCRIPTS` based on their `key`. -If you were to create two global scripts with the same `key` (even with different typeclasses), -the `GLOBAL_SCRIPTS` container will only return one of them (which one depends on order in -the database). Best is to organize your scripts so that this does not happen. Otherwise, use -`evennia.search_script` to get exactly the script you want. - -There are two ways to make a script appear as a property on `GLOBAL_SCRIPTS`. The first is -to manually create a new global script with `create_script` as mentioned above. Often you want this -to happen automatically when the server starts though. For this you add a python global dictionary -named `GLOBAL_SCRIPTS` to your `settings.py` file. The `settings.py` fie is located in -`mygame/conf/settings.py`: - -```python -GLOBAL_SCRIPTS = { - "my_script": { - "typeclass": "typeclasses.scripts.Weather", - "repeats": -1, - "interval": 50, - "desc": "Weather script", - "persistent": True - }, - "storagescript": { - "typeclass": "typeclasses.scripts.Storage", - "persistent": True - }, - { - "another_script": { - "typeclass": "typeclasses.another_script.AnotherScript" - } -} -``` -Here the key (`myscript` and `storagescript` above) is required, all other fields are optional. If -`typeclass` is not given, a script of type `settings.BASE_SCRIPT_TYPECLASS` is assumed. The keys -related to timing and intervals are only needed if the script is timed. - -> Note: Provide the full path to the scripts module in GLOBAL_SCRIPTS. In the example with -`another_script`, you can also create separate script modules that exist beyond scrypt.py for -further organizational requirements if needed. - -Evennia will use the information in `settings.GLOBAL_SCRIPTS` to automatically create and start -these -scripts when the server starts (unless they already exist, based on their `key`). You need to reload -the server before the setting is read and new scripts become available. You can then find the `key` -you gave as properties on `evennia.GLOBAL_SCRIPTS` -(such as `evennia.GLOBAL_SCRIPTS.storagescript`). - -> Note: Make sure that your Script typeclass does not have any critical errors. If so, you'll see -errors in your log and your Script will temporarily fall back to being a `DefaultScript` type. - -Moreover, a script defined this way is *guaranteed* to exist when you try to access it: -```python -from evennia import GLOBAL_SCRIPTS -# first stop the script -GLOBAL_SCRIPTS.storagescript.stop() -# running the `scripts` command now will show no storagescript -# but below now it's recreated again! -storage = GLOBAL_SCRIPTS.storagescript -``` -That is, if the script is deleted, next time you get it from `GLOBAL_SCRIPTS`, it will use the -information -in settings to recreate it for you. - -> Note that if your goal with the Script is to store persistent data, you should set it as -`persistent=True`, either in `settings.GLOBAL_SCRIPTS` or in the Scripts typeclass. Otherwise any -data you wanted to store on it will be gone (since a new script of the same name is restarted -instead). - -## Dealing with Errors - -Errors inside an timed, executing script can sometimes be rather terse or point to -parts of the execution mechanism that is hard to interpret. One way to make it -easier to debug scripts is to import Evennia's native logger and wrap your -functions in a try/catch block. Evennia's logger can show you where the -traceback occurred in your script. - -```python - -from evennia.utils import logger - -class Weather(DefaultScript): - - # [...] - - def at_repeat(self): - - try: - # [...] code as above - except Exception: - # logs the error - logger.log_trace() - -``` - -## Example of a timed script - -In-game you can try out scripts using the `@script` command. In the -`evennia/contrib/tutorial_examples/bodyfunctions.py` is a little example script -that makes you do little 'sounds' at random intervals. Try the following to apply an -example time-based script to your character. - - > @script self = bodyfunctions.BodyFunctions - -> Note: Since `evennia/contrib/tutorial_examples` is in the default setting -> `TYPECLASS_PATHS`, we only need to specify the final part of the path, -> that is, `bodyfunctions.BodyFunctions`. - -If you want to inflict your flatulence script on another person, place or -thing, try something like the following: - - > @py self.location.search('matt').scripts.add('bodyfunctions.BodyFunctions') - -Here's how you stop it on yourself. - - > @script/stop self = bodyfunctions.BodyFunctions - -This will kill the script again. You can use the `@scripts` command to list all -active scripts in the game, if any (there are none by default). - - -For another example of a Script in use, check out the [Turn Based Combat System -tutorial](https://github.com/evennia/evennia/wiki/Turn%20based%20Combat%20System). diff --git a/docs/0.9.5/_sources/Security.md.txt b/docs/0.9.5/_sources/Security.md.txt deleted file mode 100644 index e3a5ca60eb..0000000000 --- a/docs/0.9.5/_sources/Security.md.txt +++ /dev/null @@ -1,152 +0,0 @@ -# Security - -Hackers these days aren't discriminating, and their backgrounds range from bored teenagers to -international intelligence agencies. Their scripts and bots endlessly crawl the web, looking for -vulnerable systems they can break into. Who owns the system is irrelevant-- it doesn't matter if it -belongs to you or the Pentagon, the goal is to take advantage of poorly-secured systems and see what -resources can be controlled or stolen from them. - -If you're considering deploying to a cloud-based host, you have a vested interest in securing your -applications-- you likely have a credit card on file that your host can freely bill. Hackers pegging -your CPU to mine cryptocurrency or saturating your network connection to participate in a botnet or -send spam can run up your hosting bill, get your service suspended or get your address/site -blacklisted by ISPs. It can be a difficult legal or political battle to undo this damage after the -fact. - -As a developer about to expose a web application to the threat landscape of the modern internet, -here are a few tips to consider to increase the security of your Evennia install. - -### Know your logs -In case of emergency, check your logs! By default they are located in the `server/logs/` folder. -Here are some of the more important ones and why you should care: - -* `http_requests.log` will show you what HTTP requests have been made against Evennia's built-in -webserver (TwistedWeb). This is a good way to see if people are innocuously browsing your site or -trying to break it through code injection. -* `portal.log` will show you various networking-related information. This is a good place to check -for odd or unusual types or amounts of connections to your game, or other networking-related -issues-- like when users are reporting an inability to connect. -* `server.log` is the MUX administrator's best friend. Here is where you'll find information -pertaining to who's trying to break into your system by guessing at passwords, who created what -objects, and more. If your game fails to start or crashes and you can't tell why, this is the first -place you should look for answers. Security-related events are prefixed with an `[SS]` so when -there's a problem you might want to pay special attention to those. - -### Disable development/debugging options -There are a few Evennia/Django options that are set when you first create your game to make it more -obvious to you where problems arise. These options should be disabled before you push your game into -production-- leaving them on can expose variables or code someone with malicious intent can easily -abuse to compromise your environment. - -In `server/conf/settings.py`: - - # Disable Django's debug mode - DEBUG = False - # Disable the in-game equivalent - IN_GAME_ERRORS = False - # If you've registered a domain name, force Django to check host headers. Otherwise leave this -as-is. - # Note the leading period-- it is not a typo! - ALLOWED_HOSTS = ['.example.com'] - -### Handle user-uploaded images with care -If you decide to allow users to upload their own images to be served from your site, special care -must be taken. Django will read the file headers to confirm it's an image (as opposed to a document -or zip archive), but [code can be injected into an image -file](https://insinuator.net/2014/05/django-image-validation-vulnerability/) *after* the headers -that can be interpreted as HTML and/or give an attacker a web shell through which they can access -other filesystem resources. - -[Django has a more comprehensive overview of how to handle user-uploaded -files](https://docs.djangoproject.com/en/dev/topics/security/#user-uploaded-content-security), but -in short you should take care to do one of two things-- - -* Serve all user-uploaded assets from a *separate* domain or CDN (*not* a subdomain of the one you -already have!). For example, you may be browsing `reddit.com` but note that all the user-submitted -images are being served from the `redd.it` domain. There are both security and performance benefits -to this (webservers tend to load local resources one-by-one, whereas they will request external -resources in bulk). -* If you don't want to pay for a second domain, don't understand what any of this means or can't be -bothered with additional infrastructure, then simply reprocess user images upon receipt using an -image library. Convert them to a different format, for example. *Destroy the originals!* - -### Disable the web interface -The web interface allows visitors to see an informational page as well as log into a browser-based -telnet client with which to access Evennia. It also provides authentication endpoints against which -an attacker can attempt to validate stolen lists of credentials to see which ones might be shared by -your users. Django's security is robust, but if you don't want/need these features and fully intend -to force your users to use traditional clients to access your game, you might consider disabling -either/both to minimize your attack surface. - -In `server/conf/settings.py`: - - # Disable the Javascript webclient - WEBCLIENT_ENABLED = False - # Disable the website altogether - WEBSERVER_ENABLED = False - -### Change your ssh port -Automated attacks will often target port 22 seeing as how it's the standard port for SSH traffic. -Also, -many public wifi hotspots block ssh traffic over port 22 so you might not be able to access your -server from these locations if you like to work remotely or don't have a home internet connection. - -If you don't intend on running a website or securing it with TLS, you can mitigate both problems by -changing the port used for ssh to 443, which most/all hotspot providers assume is HTTPS traffic and -allows through. - -(Ubuntu) In /etc/ssh/sshd_config, change the following variable: - - # What ports, IPs and protocols we listen for - Port 443 - -Save, close, then run the following command: - - sudo service ssh restart - -### Set up a firewall -Ubuntu users can make use of the simple ufw utility. Anybody else can use iptables. - - # Install ufw (if not already) - sudo apt-get install ufw - -UFW's default policy is to deny everything. We must specify what we want to allow through our -firewall. - - # Allow terminal connections to your game - sudo ufw allow 4000/tcp - # Allow browser connections to your website - sudo ufw allow 4001/tcp - -Use ONE of the next two commands depending on which port your ssh daemon is listening on: - - sudo ufw allow 22/tcp - sudo ufw allow 443/tcp - -Finally: - - sudo ufw enable - -Now the only ports open will be your administrative ssh port (whichever you chose), and Evennia on -4000-4001. - -### Use an external webserver -Though not officially supported, there are some benefits to [deploying a webserver](./Apache-Config.md) -to handle/proxy traffic to your Evennia instance. - -For example, Evennia's game engine and webservice are tightly integrated. If you bring your game -down for maintenance (or if it simply crashes) your website will go down with it. In these cases a -standalone webserver can still be used to display a maintenance page or otherwise communicate to -your users the reason for the downtime, instead of disappearing off the face of the earth and -returning opaque `SERVER NOT FOUND` error messages. - -Proper webservers are also written in more efficient programming languages than Python, and while -Twisted can handle its own, putting a webserver in front of it is like hiring a bouncer to deal with -nuisances and crowds before they even get in the door. - -Many of the popular webservers also let you plug in additional modules (like -[mod_security](https://en.wikipedia.org/wiki/ModSecurity) for Apache) that can be used to detect -(and block!) malicious users or requests before they even touch your game or site. There are also -automated solutions for installing and configuring TLS (via [Certbot/Let's -Encrypt](https://en.wikipedia.org/wiki/Let%27s_Encrypt)) to secure your website against hotspot and -ISP snooping. \ No newline at end of file diff --git a/docs/0.9.5/_sources/Server-Conf.md.txt b/docs/0.9.5/_sources/Server-Conf.md.txt deleted file mode 100644 index 4d72e5b1f1..0000000000 --- a/docs/0.9.5/_sources/Server-Conf.md.txt +++ /dev/null @@ -1,104 +0,0 @@ -# Server Conf - - -Evennia runs out of the box without any changes to its settings. But there are several important -ways to customize the server and expand it with your own plugins. - -## Settings file - -The "Settings" file referenced throughout the documentation is the file -`mygame/server/conf/settings.py`. This is automatically created on the first run of `evennia --init` -(see the [Getting Started](./Getting-Started.md) page). - -Your new `settings.py` is relatively bare out of the box. Evennia's core settings file is actually -[evennia/settings_default.py](https://github.com/evennia/evennia/blob/master/evennia/settings_default -.py) and is considerably more extensive (it is also heavily documented so you should refer to this -file directly for the available settings). - -Since `mygame/server/conf/settings.py` is a normal Python module, it simply imports -`evennia/settings_default.py` into itself at the top. - -This means that if any setting you want to change were to depend on some *other* default setting, -you might need to copy & paste both in order to change them and get the effect you want (for most -commonly changed settings, this is not something you need to worry about). - -You should never edit `evennia/settings_default.py`. Rather you should copy&paste the select -variables you want to change into your `settings.py` and edit them there. This will overload the -previously imported defaults. - -> Warning: It may be tempting to copy everything from `settings_default.py` into your own settings -file. There is a reason we don't do this out of the box though: it makes it directly clear what -changes you did. Also, if you limit your copying to the things you really need you will directly be -able to take advantage of upstream changes and additions to Evennia for anything you didn't -customize. - -In code, the settings is accessed through - -```python - from django.conf import settings - # or (shorter): - from evennia import settings - # example: - servername = settings.SERVER_NAME -``` - -Each setting appears as a property on the imported `settings` object. You can also explore all -possible options with `evennia.settings_full` (this also includes advanced Django defaults that are -not touched in default Evennia). - -> It should be pointed out that when importing `settings` into your code like this, it will be *read -only*. You *cannot* edit your settings from your code! The only way to change an Evennia setting is -to edit `mygame/server/conf/settings.py` directly. You also generally need to restart the server -(possibly also the Portal) before a changed setting becomes available. - -## Other files in the `server/conf` directory - -Apart from the main `settings.py` file, - -- `at_initial_setup.py` - this allows you to add a custom startup method to be called (only) the -very first time Evennia starts (at the same time as user #1 and Limbo is created). It can be made to -start your own global scripts or set up other system/world-related things your game needs to have -running from the start. -- `at_server_startstop.py` - this module contains two functions that Evennia will call every time -the Server starts and stops respectively - this includes stopping due to reloading and resetting as -well as shutting down completely. It's a useful place to put custom startup code for handlers and -other things that must run in your game but which has no database persistence. -- `connection_screens.py` - all global string variables in this module are interpreted by Evennia as -a greeting screen to show when an Account first connects. If more than one string variable is -present in the module a random one will be picked. -- `inlinefuncs.py` - this is where you can define custom [Inline functions](./TextTags.md#inline-functions). -- `inputfuncs.py` - this is where you define custom [Input functions](./Inputfuncs.md) to handle data -from the client. -- `lockfuncs.py` - this is one of many possible modules to hold your own "safe" *lock functions* to -make available to Evennia's [Locks](./Locks.md). -- `mssp.py` - this holds meta information about your game. It is used by MUD search engines (which -you often have to register with) in order to display what kind of game you are running along with - statistics such as number of online accounts and online status. -- `oobfuncs.py` - in here you can define custom [OOB functions](./OOB.md). -- `portal_services_plugin.py` - this allows for adding your own custom services/protocols to the -Portal. It must define one particular function that will be called by Evennia at startup. There can -be any number of service plugin modules, all will be imported and used if defined. More info can be -found [here](http://code.google.com/p/evennia/wiki/SessionProtocols#Adding_custom_Protocols). -- `server_services_plugin.py` - this is equivalent to the previous one, but used for adding new -services to the Server instead. More info can be found -[here](http://code.google.com/p/evennia/wiki/SessionProtocols#Adding_custom_Protocols). - -Some other Evennia systems can be customized by plugin modules but has no explicit template in -`conf/`: - -- *cmdparser.py* - a custom module can be used to totally replace Evennia's default command parser. -All this does is to split the incoming string into "command name" and "the rest". It also handles -things like error messages for no-matches and multiple-matches among other things that makes this -more complex than it sounds. The default parser is *very* generic, so you are most often best served -by modifying things further down the line (on the command parse level) than here. -- *at_search.py* - this allows for replacing the way Evennia handles search results. It allows to -change how errors are echoed and how multi-matches are resolved and reported (like how the default -understands that "2-ball" should match the second "ball" object if there are two of them in the -room). - -## ServerConf - -There is a special database model called `ServerConf` that stores server internal data and settings -such as current account count (for interfacing with the webserver), startup status and many other -things. It's rarely of use outside the server core itself but may be good to -know about if you are an Evennia developer. diff --git a/docs/0.9.5/_sources/Sessions.md.txt b/docs/0.9.5/_sources/Sessions.md.txt deleted file mode 100644 index aac20214a6..0000000000 --- a/docs/0.9.5/_sources/Sessions.md.txt +++ /dev/null @@ -1,188 +0,0 @@ -# Sessions - - -An Evennia *Session* represents one single established connection to the server. Depending on the -Evennia session, it is possible for a person to connect multiple times, for example using different -clients in multiple windows. Each such connection is represented by a session object. - -A session object has its own [cmdset](./Command-Sets.md), usually the "unloggedin" cmdset. This is what -is used to show the login screen and to handle commands to create a new account (or -[Account](./Accounts.md) in evennia lingo) read initial help and to log into the game with an existing -account. A session object can either be "logged in" or not. Logged in means that the user has -authenticated. When this happens the session is associated with an Account object (which is what -holds account-centric stuff). The account can then in turn puppet any number of objects/characters. - -> Warning: A Session is not *persistent* - it is not a [Typeclass](./Typeclasses.md) and has no -connection to the database. The Session will go away when a user disconnects and you will lose any -custom data on it if the server reloads. The `.db` handler on Sessions is there to present a uniform -API (so you can assume `.db` exists even if you don't know if you receive an Object or a Session), -but this is just an alias to `.ndb`. So don't store any data on Sessions that you can't afford to -lose in a reload. You have been warned. - -## Properties on Sessions - -Here are some important properties available on (Server-)Sessions - -- `sessid` - The unique session-id. This is an integer starting from 1. -- `address` - The connected client's address. Different protocols give different information here. -- `logged_in` - `True` if the user authenticated to this session. -- `account` - The [Account](./Accounts.md) this Session is attached to. If not logged in yet, this is -`None`. -- `puppet` - The [Character/Object](./Objects.md) currently puppeted by this Account/Session combo. If -not logged in or in OOC mode, this is `None`. -- `ndb` - The [Non-persistent Attribute](./Attributes.md) handler. -- `db` - As noted above, Sessions don't have regular Attributes. This is an alias to `ndb`. -- `cmdset` - The Session's [CmdSetHandler](./Command-Sets.md) - -Session statistics are mainly used internally by Evennia. - -- `conn_time` - How long this Session has been connected -- `cmd_last` - Last active time stamp. This will be reset by sending `idle` keepalives. -- `cmd_last_visible` - last active time stamp. This ignores `idle` keepalives and representes the -last time this session was truly visibly active. -- `cmd_total` - Total number of Commands passed through this Session. - - -## Multisession mode - -The number of sessions possible to connect to a given account at the same time and how it works is -given by the `MULTISESSION_MODE` setting: - -* `MULTISESSION_MODE=0`: One session per account. When connecting with a new session the old one is -disconnected. This is the default mode and emulates many classic mud code bases. In default Evennia, -this mode also changes how the `create account` Command works - it will automatically create a -Character with the *same name* as the Account. When logging in, the login command is also modified -to have the player automatically puppet that Character. This makes the distinction between Account -and Character minimal from the player's perspective. -* `MULTISESSION_MODE=1`: Many sessions per account, input/output from/to each session is treated the -same. For the player this means they can connect to the game from multiple clients and see the same -output in all of them. The result of a command given in one client (that is, through one Session) -will be returned to *all* connected Sessions/clients with no distinction. This mode will have the -Session(s) auto-create and puppet a Character in the same way as mode 0. -* `MULTISESSION_MODE=2`: Many sessions per account, one character per session. In this mode, -puppeting an Object/Character will link the puppet back only to the particular Session doing the -puppeting. That is, input from that Session will make use of the CmdSet of that Object/Character and -outgoing messages (such as the result of a `look`) will be passed back only to that puppeting -Session. If another Session tries to puppet the same Character, the old Session will automatically -un-puppet it. From the player's perspective, this will mean that they can open separate game clients -and play a different Character in each using one game account. -This mode will *not* auto-create a Character and *not* auto-puppet on login like in modes 0 and 1. -Instead it changes how the account-cmdsets's `OOCLook` command works so as to show a simple -'character select' menu. -* `MULTISESSION_MODE=3`: Many sessions per account *and* character. This is the full multi-puppeting -mode, where multiple sessions may not only connect to the player account but multiple sessions may -also puppet a single character at the same time. From the user's perspective it means one can open -multiple client windows, some for controlling different Characters and some that share a Character's -input/output like in mode 1. This mode otherwise works the same as mode 2. - -> Note that even if multiple Sessions puppet one Character, there is only ever one instance of that -Character. - -## Returning data to the session - -When you use `msg()` to return data to a user, the object on which you call the `msg()` matters. The -`MULTISESSION_MODE` also matters, especially if greater than 1. - -For example, if you use `account.msg("hello")` there is no way for evennia to know which session it -should send the greeting to. In this case it will send it to all sessions. If you want a specific -session you need to supply its session to the `msg` call (`account.msg("hello", -session=mysession)`). - -On the other hand, if you call the `msg()` message on a puppeted object, like -`character.msg("hello")`, the character already knows the session that controls it - it will -cleverly auto-add this for you (you can specify a different session if you specifically want to send -stuff to another session). - -Finally, there is a wrapper for `msg()` on all command classes: `command.msg()`. This will -transparently detect which session was triggering the command (if any) and redirects to that session -(this is most often what you want). If you are having trouble redirecting to a given session, -`command.msg()` is often the safest bet. - -You can get the `session` in two main ways: -* [Accounts](./Accounts.md) and [Objects](./Objects.md) (including Characters) have a `sessions` property. -This is a *handler* that tracks all Sessions attached to or puppeting them. Use e.g. -`accounts.sessions.get()` to get a list of Sessions attached to that entity. -* A Command instance has a `session` property that always points back to the Session that triggered -it (it's always a single one). It will be `None` if no session is involved, like when a mob or -script triggers the Command. - -## Customizing the Session object - -When would one want to customize the Session object? Consider for example a character creation -system: You might decide to keep this on the out-of-character level. This would mean that you create -the character at the end of some sort of menu choice. The actual char-create cmdset would then -normally be put on the account. This works fine as long as you are `MULTISESSION_MODE` below 2. -For higher modes, replacing the Account cmdset will affect *all* your connected sessions, also those -not involved in character creation. In this case you want to instead put the char-create cmdset on -the Session level - then all other sessions will keep working normally despite you creating a new -character in one of them. - -By default, the session object gets the `commands.default_cmdsets.UnloggedinCmdSet` when the user -first connects. Once the session is authenticated it has *no* default sets. To add a "logged-in" -cmdset to the Session, give the path to the cmdset class with `settings.CMDSET_SESSION`. This set -will then henceforth always be present as soon as the account logs in. - -To customize further you can completely override the Session with your own subclass. To replace the -default Session class, change `settings.SERVER_SESSION_CLASS` to point to your custom class. This is -a dangerous practice and errors can easily make your game unplayable. Make sure to take heed of the -[original](https://github.com/evennia/evennia/blob/master/evennia/server/session.py) and make your -changes carefully. - -## Portal and Server Sessions - -*Note: This is considered an advanced topic. You don't need to know this on a first read-through.* - -Evennia is split into two parts, the [Portal and the Server](./Portal-And-Server.md). Each side tracks -its own Sessions, syncing them to each other. - -The "Session" we normally refer to is actually the `ServerSession`. Its counter-part on the Portal -side is the `PortalSession`. Whereas the server sessions deal with game states, the portal session -deals with details of the connection-protocol itself. The two are also acting as backups of critical -data such as when the server reboots. - -New Account connections are listened for and handled by the Portal using the [protocols](Portal-And- -Server) it understands (such as telnet, ssh, webclient etc). When a new connection is established, a -`PortalSession` is created on the Portal side. This session object looks different depending on -which protocol is used to connect, but all still have a minimum set of attributes that are generic -to all -sessions. - -These common properties are piped from the Portal, through the AMP connection, to the Server, which -is now informed a new connection has been established. On the Server side, a `ServerSession` object -is created to represent this. There is only one type of `ServerSession`; It looks the same -regardless of how the Account connects. - -From now on, there is a one-to-one match between the `ServerSession` on one side of the AMP -connection and the `PortalSession` on the other. Data arriving to the Portal Session is sent on to -its mirror Server session and vice versa. - -During certain situations, the portal- and server-side sessions are -"synced" with each other: -- The Player closes their client, killing the Portal Session. The Portal syncs with the Server to -make sure the corresponding Server Session is also deleted. -- The Player quits from inside the game, killing the Server Session. The Server then syncs with the -Portal to make sure to close the Portal connection cleanly. -- The Server is rebooted/reset/shutdown - The Server Sessions are copied over ("saved") to the -Portal side. When the Server comes back up, this data is returned by the Portal so the two are again -in sync. This way an Account's login status and other connection-critical things can survive a -server reboot (assuming the Portal is not stopped at the same time, obviously). - -## Sessionhandlers - -Both the Portal and Server each have a *sessionhandler* to manage the connections. These handlers -are global entities contain all methods for relaying data across the AMP bridge. All types of -Sessions hold a reference to their respective Sessionhandler (the property is called -`sessionhandler`) so they can relay data. See [protocols](./Custom-Protocols.md) for more info -on building new protocols. - -To get all Sessions in the game (i.e. all currently connected clients), you access the server-side -Session handler, which you get by -``` -from evennia.server.sessionhandler import SESSION_HANDLER -``` -> Note: The `SESSION_HANDLER` singleton has an older alias `SESSIONS` that is commonly seen in -various places as well. - -See the -[sessionhandler.py](https://github.com/evennia/evennia/blob/master/evennia/server/sessionhandler.py) -module for details on the capabilities of the `ServerSessionHandler`. diff --git a/docs/0.9.5/_sources/Setting-up-PyCharm.md.txt b/docs/0.9.5/_sources/Setting-up-PyCharm.md.txt deleted file mode 100644 index cacc71b6be..0000000000 --- a/docs/0.9.5/_sources/Setting-up-PyCharm.md.txt +++ /dev/null @@ -1,116 +0,0 @@ -# Setting up PyCharm - -# Directions for setting up PyCharm with Evennia - -[PyCharm](https://www.jetbrains.com/pycharm/) is a Python developer's IDE from Jetbrains available -for Windows, Mac and Linux. It is a commercial product but offer free trials, a scaled-down -community edition and also generous licenses for OSS projects like Evennia. - -> This page was originally tested on Windows (so use Windows-style path examples), but should work -the same for all platforms. - -First, install Evennia on your local machine with [[Getting Started]]. If you're new to PyCharm, -loading your project is as easy as selecting the `Open` option when PyCharm starts, and browsing to -your game folder (the one created with `evennia --init`). We refer to it as `mygame` here. - -If you want to be able to examine evennia's core code or the scripts inside your virtualenv, you'll -need to add them to your project too: -1. Go to `File > Open...` -1. Select the folder (i.e. the `evennia` root) -1. Select "Open in current window" and "Add to currently opened projects" - -## Setting up the project interpreter - -It's a good idea to do this before attempting anything further. The rest of this page assumes your -project is already configured in PyCharm. - -1. Go to `File > Settings... > Project: \ > Project Interpreter` -1. Click the Gear symbol `> Add local` -1. Navigate to your `evenv/scripts directory`, and select Python.exe - -Enjoy seeing all your imports checked properly, setting breakpoints, and live variable watching! - -## Attaching PyCharm debugger to Evennia - -1. Launch Evennia in your preferred way (usually from a console/terminal) -1. Open your project in PyCharm -1. In the PyCharm menu, select `Run > Attach to Local Process...` -1. From the list, pick the `twistd` process with the `server.py` parameter (Example: `twistd.exe ---nodaemon --logfile=\\server\logs\server.log --python=\\evennia\server\server.py`) - -Of course you can attach to the `portal` process as well. If you want to debug the Evennia launcher -or runner for some reason (or just learn how they work!), see Run Configuration below. - -> NOTE: Whenever you reload Evennia, the old Server process will die and a new one start. So when -you restart you have to detach from the old and then reattach to the new process that was created. - -> To make the process less tedious you can apply a filter in settings to show only the server.py -process in the list. To do that navigate to: `Settings/Preferences | Build, Execution, Deployment | -Python Debugger` and then in `Attach to process` field put in: `twistd.exe" --nodaemon`. This is an -example for windows, I don't have a working mac/linux box. -![Example process filter configuration](https://i.imgur.com/vkSheR8.png) - -## Setting up an Evennia run configuration - -This configuration allows you to launch Evennia from inside PyCharm. Besides convenience, it also -allows suspending and debugging the evennia_launcher or evennia_runner at points earlier than you -could by running them externally and attaching. In fact by the time the server and/or portal are -running the launcher will have exited already. - -1. Go to `Run > Edit Configutations...` -1. Click the plus-symbol to add a new configuration and choose Python -1. Add the script: `\\evenv\Scripts\evennia_launcher.py` (substitute your virtualenv if -it's not named `evenv`) -1. Set script parameters to: `start -l` (-l enables console logging) -1. Ensure the chosen interpreter is from your virtualenv -1. Set Working directory to your `mygame` folder (not evenv nor evennia) -1. You can refer to the PyCharm documentation for general info, but you'll want to set at least a -config name (like "MyMUD start" or similar). - -Now set up a "stop" configuration by following the same steps as above, but set your Script -parameters to: stop (and name the configuration appropriately). - -A dropdown box holding your new configurations should appear next to your PyCharm run button. -Select MyMUD start and press the debug icon to begin debugging. Depending on how far you let the -program run, you may need to run your "MyMUD stop" config to actually stop the server, before you'll -be able start it again. - -## Alternative run configuration - utilizing logfiles as source of data - -This configuration takes a bit different approach as instead of focusing on getting the data back -through logfiles. Reason for that is this way you can easily separate data streams, for example you -rarely want to follow both server and portal at the same time, and this will allow it. This will -also make sure to stop the evennia before starting it, essentially working as reload command (it -will also include instructions how to disable that part of functionality). We will start by defining -a configuration that will stop evennia. This assumes that `upfire` is your pycharm project name, and -also the game name, hence the `upfire/upfire` path. - -1. Go to `Run > Edit Configutations...`\ -1. Click the plus-symbol to add a new configuration and choose the python interpreter to use (should -be project default) -1. Name the configuration as "stop evennia" and fill rest of the fields accordingly to the image: -![Stop run configuration](https://i.imgur.com/gbkXhlG.png) -1. Press `Apply` - -Now we will define the start/reload command that will make sure that evennia is not running already, -and then start the server in one go. -1. Go to `Run > Edit Configutations...`\ -1. Click the plus-symbol to add a new configuration and choose the python interpreter to use (should -be project default) -1. Name the configuration as "start evennia" and fill rest of the fields accordingly to the image: -![Start run configuration](https://i.imgur.com/5YEjeHq.png) -1. Navigate to the `Logs` tab and add the log files you would like to follow. The picture shows -adding `portal.log` which will show itself in `portal` tab when running: -![Configuring logs following](https://i.imgur.com/gWYuOWl.png) -1. Skip the following steps if you don't want the launcher to stop evennia before starting. -1. Head back to `Configuration` tab and press the `+` sign at the bottom, under `Before launch....` -and select `Run another configuration` from the submenu that will pop up. -1. Click `stop evennia` and make sure that it's added to the list like on the image above. -1. Click `Apply` and close the run configuration window. - -You are now ready to go, and if you will fire up `start evennia` configuration you should see -following in the bottom panel: -![Example of running alternative configuration](https://i.imgur.com/nTfpC04.png) -and you can click through the tabs to check appropriate logs, or even the console output as it is -still running in interactive mode. \ No newline at end of file diff --git a/docs/0.9.5/_sources/Signals.md.txt b/docs/0.9.5/_sources/Signals.md.txt deleted file mode 100644 index 5e172b09ff..0000000000 --- a/docs/0.9.5/_sources/Signals.md.txt +++ /dev/null @@ -1,122 +0,0 @@ -# Signals - - -_This is feature available from evennia 0.9 and onward_. - -There are multiple ways for you to plug in your own functionality into Evennia. -The most common way to do so is through *hooks* - methods on typeclasses that -gets called at particular events. Hooks are great when you want a game entity -to behave a certain way when something happens to it. _Signals_ complements -hooks for cases when you want to easily attach new functionality without -overriding things on the typeclass. - -When certain events happen in Evennia, a _Signal_ is fired. The idea is that -you can "attach" any number of event-handlers to these signals. You can attach -any number of handlers and they'll all fire whenever any entity triggers the -signal. - -Evennia uses the [Django Signal system](https://docs.djangoproject.com/en/2.2/topics/signals/). - - -## Attaching a handler to a signal - -First you create your handler - -```python - -def myhandler(sender, **kwargs): - # do stuff - -``` - -The `**kwargs` is mandatory. Then you attach it to the signal of your choice: - -```python -from evennia.server import signals - -signals.SIGNAL_OBJECT_POST_CREATE.connect(myhandler) - -``` - -This particular signal fires after (post) an Account has connected to the game. -When that happens, `myhandler` will fire with the `sender` being the Account that just connected. - -If you want to respond only to the effects of a specific entity you can do so -like this: - -```python -from evennia import search_account -from evennia import signals - -account = search_account("foo")[0] -signals.SIGNAL_ACCOUNT_POST_CONNECT.connect(myhandler, account) -``` - -## Available signals - -All signals (including some django-specific defaults) are available in the module -`evennia.server.signals` -(with a shortcut `evennia.signals`). Signals are named by the sender type. So `SIGNAL_ACCOUNT_*` -returns -`Account` instances as senders, `SIGNAL_OBJECT_*` returns `Object`s etc. Extra keywords (kwargs) -should -be extracted from the `**kwargs` dict in the signal handler. - -- `SIGNAL_ACCOUNT_POST_CREATE` - this is triggered at the very end of `Account.create()`. Note that - calling `evennia.create.create_account` (which is called internally by `Account.create`) will -*not* - trigger this signal. This is because using `Account.create()` is expected to be the most commonly - used way for users to themselves create accounts during login. It passes and extra kwarg `ip` with - the client IP of the connecting account. -- `SIGNAL_ACCOUNT_POST_LOGIN` - this will always fire when the account has authenticated. Sends - extra kwarg `session` with the new [Session](./Sessions.md) object involved. -- `SIGNAL_ACCCOUNT_POST_FIRST_LOGIN` - this fires just before `SIGNAL_ACCOUNT_POST_LOGIN` but only -if - this is the *first* connection done (that is, if there are no previous sessions connected). Also - passes the `session` along as a kwarg. -- `SIGNAL_ACCOUNT_POST_LOGIN_FAIL` - sent when someone tried to log into an account by failed. -Passes - the `session` as an extra kwarg. -- `SIGNAL_ACCOUNT_POST_LOGOUT` - always fires when an account logs off, no matter if other sessions - remain or not. Passes the disconnecting `session` along as a kwarg. -- `SIGNAL_ACCOUNT_POST_LAST_LOGOUT` - fires before `SIGNAL_ACCOUNT_POST_LOGOUT`, but only if this is - the *last* Session to disconnect for that account. Passes the `session` as a kwarg. -- `SIGNAL_OBJECT_POST_PUPPET` - fires when an account puppets this object. Extra kwargs `session` - and `account` represent the puppeting entities. - `SIGNAL_OBJECT_POST_UNPUPPET` - fires when the sending object is unpuppeted. Extra kwargs are - `session` and `account`. -- `SIGNAL_ACCOUNT_POST_RENAME` - triggered by the setting of `Account.username`. Passes extra - kwargs `old_name`, `new_name`. -- `SIGNAL_TYPED_OBJECT_POST_RENAME` - triggered when any Typeclassed entity's `key` is changed. -Extra - kwargs passed are `old_key` and `new_key`. -- `SIGNAL_SCRIPT_POST_CREATE` - fires when a script is first created, after any hooks. -- `SIGNAL_CHANNEL_POST_CREATE` - fires when a Channel is first created, after any hooks. -- `SIGNAL_HELPENTRY_POST_CREATE` - fires when a help entry is first created. - -The `evennia.signals` module also gives you conveneient access to the default Django signals (these -use a -different naming convention). - -- `pre_save` - fired when any database entitiy's `.save` method fires, before any saving has -happened. -- `post_save` - fires after saving a database entity. -- `pre_delete` - fires just before a database entity is deleted. -- `post_delete` - fires after a database entity was deleted. -- `pre_init` - fires before a typeclass' `__init__` method (which in turn - happens before the `at_init` hook fires). -- `post_init` - triggers at the end of `__init__` (still before the `at_init` hook). - -These are highly specialized Django signals that are unlikely to be useful to most users. But -they are included here for completeness. - -- `m2m_changed` - fires after a Many-to-Many field (like `db_attributes`) changes. -- `pre_migrate` - fires before database migration starts with `evennia migrate`. -- `post_migrate` - fires after database migration finished. -- `request_started` - sent when HTTP request begins. -- `request_finished` - sent when HTTP request ends. -- `settings_changed` - sent when changing settings due to `@override_settings` - decorator (only relevant for unit testing) -- `template_rendered` - sent when test system renders http template (only useful for unit tests). -- `connection_creation` - sent when making initial connection to database. - diff --git a/docs/0.9.5/_sources/Soft-Code.md.txt b/docs/0.9.5/_sources/Soft-Code.md.txt deleted file mode 100644 index 3f49bdb99c..0000000000 --- a/docs/0.9.5/_sources/Soft-Code.md.txt +++ /dev/null @@ -1,94 +0,0 @@ -# Soft Code - - -Softcode is a very simple programming language that was created for in-game development on TinyMUD -derivatives such as MUX, PennMUSH, TinyMUSH, and RhostMUSH. The idea is that by providing a stripped -down, minimalistic language for in-game use, you can allow quick and easy building and game -development to happen without having to learn C/C++. There is an added benefit of not having to have -to hand out shell access to all developers, and permissions can be used to alleviate many security -problems. - -Writing and installing softcode is done through a MUD client. Thus it is not a formatted language. -Each softcode function is a single line of varying size. Some functions can be a half of a page long -or more which is obviously not very readable nor (easily) maintainable over time. - -## Examples of Softcode - -Here is a simple 'Hello World!' command: - -```bash - @set me=HELLO_WORLD.C:$hello:@pemit %#=Hello World! -``` - -Pasting this into a MUX/MUSH and typing 'hello' will theoretically yield 'Hello World!', assuming -certain flags are not set on your account object. - -Setting attributes is done via `@set`. Softcode also allows the use of the ampersand (`&`) symbol. -This shorter version looks like this: - -```bash - &HELLO_WORLD.C me=$hello:@pemit %#=Hello World! -``` - -Perhaps I want to break the Hello World into an attribute which is retrieved when emitting: - -```bash - &HELLO_VALUE.D me=Hello World - &HELLO_WORLD.C me=$hello:@pemit %#=[v(HELLO_VALUE.D)] -``` - -The `v()` function returns the `HELLO_VALUE.D` attribute on the object that the command resides -(`me`, which is yourself in this case). This should yield the same output as the first example. - -If you are still curious about how Softcode works, take a look at some external resources: - -- http://www.tinymux.com/wiki/index.php/Softcode -- http://www.duh.com/discordia/mushman/man2x1 - -## Problems with Softcode - -Softcode is excellent at what it was intended for: *simple things*. It is a great tool for making an -interactive object, a room with ambiance, simple global commands, simple economies and coded -systems. However, once you start to try to write something like a complex combat system or a higher -end economy, you're likely to find yourself buried under a mountain of functions that span multiple -objects across your entire code. - -Not to mention, softcode is not an inherently fast language. It is not compiled, it is parsed with -each calling of a function. While MUX and MUSH parsers have jumped light years ahead of where they -once were they can still stutter under the weight of more complex systems if not designed properly. - -## Changing Times - -Now that starting text-based games is easy and an option for even the most technically inarticulate, -new projects are a dime a dozen. People are starting new MUDs every day with varying levels of -commitment and ability. Because of this shift from fewer, larger, well-staffed games to a bunch of -small, one or two developer games, some of the benefit of softcode fades. - -Softcode is great in that it allows a mid to large sized staff all work on the same game without -stepping on one another's toes. As mentioned before, shell access is not necessary to develop a MUX -or a MUSH. However, now that we are seeing a lot more small, one or two-man shops, the issue of -shell access and stepping on each other's toes is a lot less. - -## Our Solution - -Evennia shuns in-game softcode for on-disk Python modules. Python is a popular, mature and -professional programming language. You code it using the conveniences of modern text editors. -Evennia developers have access to the entire library of Python modules out there in the wild - not -to mention the vast online help resources available. Python code is not bound to one-line functions -on objects but complex systems may be organized neatly into real source code modules, sub-modules, -or even broken out into entire Python packages as desired. - -So what is *not* included in Evennia is a MUX/MOO-like online player-coding system. Advanced coding -in Evennia is primarily intended to be done outside the game, in full-fledged Python modules. -Advanced building is best handled by extending Evennia's command system with your own sophisticated -building commands. We feel that with a small development team you are better off using a -professional source-control system (svn, git, bazaar, mercurial etc) anyway. - -## Your Solution - -Adding advanced and flexible building commands to your game is easy and will probably be enough to -satisfy most creative builders. However, if you really, *really* want to offer online coding, there -is of course nothing stopping you from adding that to Evennia, no matter our recommendations. You -could even re-implement MUX' softcode in Python should you be very ambitious. The -[in-game-python](./Dialogues-in-events.md) is an optional -pseudo-softcode plugin aimed at developers wanting to script their game from inside it. diff --git a/docs/0.9.5/_sources/Spawner-and-Prototypes.md.txt b/docs/0.9.5/_sources/Spawner-and-Prototypes.md.txt deleted file mode 100644 index caaf12a192..0000000000 --- a/docs/0.9.5/_sources/Spawner-and-Prototypes.md.txt +++ /dev/null @@ -1,332 +0,0 @@ -# Spawner and Prototypes - - -The *spawner* is a system for defining and creating individual objects from a base template called a -*prototype*. It is only designed for use with in-game [Objects](./Objects.md), not any other type of -entity. - -The normal way to create a custom object in Evennia is to make a [Typeclass](./Typeclasses.md). If you -haven't read up on Typeclasses yet, think of them as normal Python classes that save to the database -behind the scenes. Say you wanted to create a "Goblin" enemy. A common way to do this would be to -first create a `Mobile` typeclass that holds everything common to mobiles in the game, like generic -AI, combat code and various movement methods. A `Goblin` subclass is then made to inherit from -`Mobile`. The `Goblin` class adds stuff unique to goblins, like group-based AI (because goblins are -smarter in a group), the ability to panic, dig for gold etc. - -But now it's time to actually start to create some goblins and put them in the world. What if we -wanted those goblins to not all look the same? Maybe we want grey-skinned and green-skinned goblins -or some goblins that can cast spells or which wield different weapons? We *could* make subclasses of -`Goblin`, like `GreySkinnedGoblin` and `GoblinWieldingClub`. But that seems a bit excessive (and a -lot of Python code for every little thing). Using classes can also become impractical when wanting -to combine them - what if we want a grey-skinned goblin shaman wielding a spear - setting up a web -of classes inheriting each other with multiple inheritance can be tricky. - -This is what the *prototype* is for. It is a Python dictionary that describes these per-instance -changes to an object. The prototype also has the advantage of allowing an in-game builder to -customize an object without access to the Python backend. Evennia also allows for saving and -searching prototypes so other builders can find and use (and tweak) them later. Having a library of -interesting prototypes is a good reasource for builders. The OLC system allows for creating, saving, -loading and manipulating prototypes using a menu system. - -The *spawner* takes a prototype and uses it to create (spawn) new, custom objects. - -## Using the OLC - -Enter the `olc` command or `@spawn/olc` to enter the prototype wizard. This is a menu system for -creating, loading, saving and manipulating prototypes. It's intended to be used by in-game builders -and will give a better understanding of prototypes in general. Use `help` on each node of the menu -for more information. Below are further details about how prototypes work and how they are used. - -## The prototype - -The prototype dictionary can either be created for you by the OLC (see above), be written manually -in a Python module (and then referenced by the `@spawn` command/OLC), or created on-the-fly and -manually loaded into the spawner function or `@spawn` command. - -The dictionary defines all possible database-properties of an Object. It has a fixed set of allowed -keys. When preparing to store the prototype in the database (or when using the OLC), some -of these keys are mandatory. When just passing a one-time prototype-dict to the spawner the system -is -more lenient and will use defaults for keys not explicitly provided. - -In dictionary form, a prototype can look something like this: - -```python -{ - "prototype_key": "house" - "key": "Large house" - "typeclass": "typeclasses.rooms.house.House" - } -``` -If you wanted to load it into the spawner in-game you could just put all on one line: - - @spawn {"prototype_key="house", "key": "Large house", ...} - -> Note that the prototype dict as given on the command line must be a valid Python structure - -so you need to put quotes around strings etc. For security reasons, a dict inserted from-in game -cannot have any -other advanced Python functionality, such as executable code, `lambda` etc. If builders are supposed -to be able to use such features, you need to offer them through [$protfuncs](Spawner-and- -Prototypes#protfuncs), embedded runnable functions that you have full control to check and vet -before running. - -### Prototype keys - -All keys starting with `prototype_` are for book keeping. - - - `prototype_key` - the 'name' of the prototype. While this can sometimes be skipped (such as when - defining a prototype in a module or feeding a prototype-dict manually to the spawner function), -it's good - practice to try to include this. It is used for book-keeping and storing of the prototype so you - can find it later. - - `prototype_parent` - If given, this should be the `prototype_key` of another prototype stored in - the system or available in a module. This makes this prototype *inherit* the keys from the - parent and only override what is needed. Give a tuple `(parent1, parent2, ...)` for multiple - left-right inheritance. If this is not given, a `typeclass` should usually be defined (below). - - `prototype_desc` - this is optional and used when listing the prototype in in-game listings. - - `protototype_tags` - this is optional and allows for tagging the prototype in order to find it - easier later. - - `prototype_locks` - two lock types are supported: `edit` and `spawn`. The first lock restricts - the copying and editing of the prototype when loaded through the OLC. The second determines who - may use the prototype to create new objects. - -The remaining keys determine actual aspects of the objects to spawn from this prototype: - - - `key` - the main object identifier. Defaults to "Spawned Object *X*", where *X* is a random -integer. - - `typeclass` - A full python-path (from your gamedir) to the typeclass you want to use. If not -set, the `prototype_parent` should be - defined, with `typeclass` defined somewhere in the parent chain. When creating a one-time -prototype - dict just for spawning, one could omit this - `settings.BASE_OBJECT_TYPECLASS` will be used -instead. - - `location` - this should be a `#dbref`. - - `home` - a valid `#dbref`. Defaults to `location` or `settings.DEFAULT_HOME` if location does not -exist. - - `destination` - a valid `#dbref`. Only used by exits. - - `permissions` - list of permission strings, like `["Accounts", "may_use_red_door"]` - - `locks` - a [lock-string](./Locks.md) like `"edit:all();control:perm(Builder)"` - - `aliases` - list of strings for use as aliases - - `tags` - list [Tags](./Tags.md). These are given as tuples `(tag, category, data)`. - - `attrs` - list of [Attributes](./Attributes.md). These are given as tuples `(attrname, value, -category, lockstring)` - - Any other keywords are interpreted as non-category [Attributes](./Attributes.md) and their values. -This is - convenient for simple Attributes - use `attrs` for full control of Attributes. - -Deprecated as of Evennia 0.8: - - - `ndb_` - sets the value of a non-persistent attribute (`"ndb_"` is stripped from the name). - This is simply not useful in a prototype and is deprecated. - - `exec` - This accepts a code snippet or a list of code snippets to run. This should not be used - - use callables or [$protfuncs](./Spawner-and-Prototypes.md#protfuncs) instead (see below). - -### Prototype values - -The prototype supports values of several different types. - -It can be a hard-coded value: - -```python - {"key": "An ugly goblin", ...} - -``` - -It can also be a *callable*. This callable is called without arguments whenever the prototype is -used to -spawn a new object: - -```python - {"key": _get_a_random_goblin_name, ...} - -``` - -By use of Python `lambda` one can wrap the callable so as to make immediate settings in the -prototype: - -```python - {"key": lambda: random.choice(("Urfgar", "Rick the smelly", "Blargh the foul", ...)), ...} - -``` - -#### Protfuncs - -Finally, the value can be a *prototype function* (*Protfunc*). These look like simple function calls -that you embed in strings and that has a `$` in front, like - -```python - {"key": "$choice(Urfgar, Rick the smelly, Blargh the foul)", - "attrs": {"desc": "This is a large $red(and very red) demon. " - "He has $randint(2,5) skulls in a chain around his neck."} -``` -At execution time, the place of the protfunc will be replaced with the result of that protfunc being -called (this is always a string). A protfunc works in much the same way as an -[InlineFunc](./TextTags.md#inline-functions) - they are actually -parsed using the same parser - except protfuncs are run every time the prototype is used to spawn a -new object (whereas an inlinefunc is called when a text is returned to the user). - -Here is how a protfunc is defined (same as an inlinefunc). - -```python -# this is a silly example, you can just color the text red with |r directly! -def red(*args, **kwargs): - """ - Usage: $red() - Returns the same text you entered, but red. - """ - if not args or len(args) > 1: - raise ValueError("Must have one argument, the text to color red!") - return "|r{}|n".format(args[0]) -``` - -> Note that we must make sure to validate input and raise `ValueError` if that fails. Also, it is -*not* possible to use keywords in the call to the protfunc (so something like `$echo(text, -align=left)` is invalid). The `kwargs` requred is for internal evennia use and not used at all for -protfuncs (only by inlinefuncs). - -To make this protfunc available to builders in-game, add it to a new module and add the path to that -module to `settings.PROT_FUNC_MODULES`: - -```python -# in mygame/server/conf/settings.py - -PROT_FUNC_MODULES += ["world.myprotfuncs"] - -``` -All *global callables* in your added module will be considered a new protfunc. To avoid this (e.g. -to have helper functions that are not protfuncs on their own), name your function something starting -with `_`. - -The default protfuncs available out of the box are defined in `evennia/prototypes/profuncs.py`. To -override the ones available, just add the same-named function in your own protfunc module. - -| Protfunc | Description | - -| `$random()` | Returns random value in range [0, 1) | -| `$randint(start, end)` | Returns random value in range [start, end] | -| `$left_justify()` | Left-justify text | -| `$right_justify()` | Right-justify text to screen width | -| `$center_justify()` | Center-justify text to screen width | -| `$full_justify()` | Spread text across screen width by adding spaces | -| `$protkey()` | Returns value of another key in this prototype (self-reference) | -| `$add(, )` | Returns value1 + value2. Can also be lists, dicts etc | -| `$sub(, )` | Returns value1 - value2 | -| `$mult(, )` | Returns value1 * value2 | -| `$div(, )` | Returns value2 / value1 | -| `$toint()` | Returns value converted to integer (or value if not possible) | -| `$eval()` | Returns result of [literal- -eval](https://docs.python.org/2/library/ast.html#ast.literal_eval) of code string. Only simple -python expressions. | -| `$obj()` | Returns object #dbref searched globally by key, tag or #dbref. Error if more -than one found." | -| `$objlist()` | Like `$obj`, except always returns a list of zero, one or more results. | -| `$dbref(dbref)` | Returns argument if it is formed as a #dbref (e.g. #1234), otherwise error. - -For developers with access to Python, using protfuncs in prototypes is generally not useful. Passing -real Python functions is a lot more powerful and flexible. Their main use is to allow in-game -builders to -do limited coding/scripting for their prototypes without giving them direct access to raw Python. - -## Storing prototypes - -A prototype can be defined and stored in two ways, either in the database or as a dict in a module. - -### Database prototypes - -Stored as [Scripts](./Scripts.md) in the database. These are sometimes referred to as *database- -prototypes* This is the only way for in-game builders to modify and add prototypes. They have the -advantage of being easily modifiable and sharable between builders but you need to work with them -using in-game tools. - -### Module-based prototypes - -These prototypes are defined as dictionaries assigned to global variables in one of the modules -defined in `settings.PROTOTYPE_MODULES`. They can only be modified from outside the game so they are -are necessarily "read-only" from in-game and cannot be modified (but copies of them could be made -into database-prototypes). These were the only prototypes available before Evennia 0.8. Module based -prototypes can be useful in order for developers to provide read-only "starting" or "base" -prototypes to build from or if they just prefer to work offline in an external code editor. - -By default `mygame/world/prototypes.py` is set up for you to add your own prototypes. *All global -dicts* in this module will be considered by Evennia to be a prototype. You could also tell Evennia -to look for prototypes in more modules if you want: - -```python -# in mygame/server/conf/settings.py - -PROTOTYPE_MODULES += ["world.myownprototypes", "combat.prototypes"] - -``` -> Note the += operator in the above example. This will extend the already defined `world.prototypes` -definition in the settings_default.py file in Evennia. If you would like to completely override the -location of your `PROTOTYPE_MODULES` then set this to just = without the addition operator. - -Here is an example of a prototype defined in a module: - -```python - # in a module Evennia looks at for prototypes, - # (like mygame/world/prototypes.py) - - ORC_SHAMAN = {"key":"Orc shaman", - "typeclass": "typeclasses.monsters.Orc", - "weapon": "wooden staff", - "health": 20} -``` - -> Note that in the example above, `"ORC_SHAMAN"` will become the `prototype_key` of this prototype. -> It's the only case when `prototype_key` can be skipped in a prototype. However, if `prototype_key` -> was given explicitly, that would take precedence. This is a legacy behavior and it's recommended -> that you always add `prototype_key` to be consistent. - - -## Using @spawn - -The spawner can be used from inside the game through the Builder-only `@spawn` command. Assuming the -"goblin" typeclass is available to the system (either as a database-prototype or read from module), -you can spawn a new goblin with - - @spawn goblin - -You can also specify the prototype directly as a valid Python dictionary: - - @spawn {"prototype_key": "shaman", \ - "key":"Orc shaman", \ - "prototype_parent": "goblin", \ - "weapon": "wooden staff", \ - "health": 20} - -> Note: The `@spawn` command is more lenient about the prototype dictionary than shown here. So you -can for example skip the `prototype_key` if you are just testing a throw-away prototype. A random -hash will be used to please the validation. You could also skip `prototype_parent/typeclass` - then -the typeclass given by `settings.BASE_OBJECT_TYPECLASS` will be used. - -## Using evennia.prototypes.spawner() - -In code you access the spawner mechanism directly via the call - -```python - new_objects = evennia.prototypes.spawner.spawn(*prototypes) -``` - -All arguments are prototype dictionaries or the unique `prototype_key`s of prototypes -known to the system (either database- or module-based). The function will return a matching list of -created objects. Example: - -```python - obj1, obj2, obj3 = evennia.prototypes.spawner.spawn({"key": "Obj1", "desc": "A test"}, - {"key": "Obj2", "desc": "Another test"}, - "GOBLIN_SHAMAN") -``` -> Hint: Same as when using `@spawn`, when spawning from a one-time prototype dict like this, you can -skip otherwise required keys, like `prototype_key` or `typeclass`/`prototype_parent`. Defaults will -be used. - -Note that no `location` will be set automatically when using `evennia.prototypes.spawner.spawn()`, -you -have to specify `location` explicitly in the prototype dict. - -If the prototypes you supply are using `prototype_parent` keywords, the spawner will read prototypes -from modules -in `settings.PROTOTYPE_MODULES` as well as those saved to the database to determine the body of -available parents. The `spawn` command takes many optional keywords, you can find its definition [in -the api docs](github:evennia.prototypes.spawner#spawn). \ No newline at end of file diff --git a/docs/0.9.5/_sources/Start-Stop-Reload.md.txt b/docs/0.9.5/_sources/Start-Stop-Reload.md.txt deleted file mode 100644 index 36e2a827d9..0000000000 --- a/docs/0.9.5/_sources/Start-Stop-Reload.md.txt +++ /dev/null @@ -1,196 +0,0 @@ -# Start Stop Reload - - -You control Evennia from your game folder (we refer to it as `mygame/` here), using the `evennia` -program. If the `evennia` program is not available on the command line you must first install -Evennia as described in the [Getting Started](./Getting-Started.md) page. - -> Hint: If you ever try the `evennia` command and get an error complaining that the command is not -available, make sure your [virtualenv](./Glossary.md#virtualenv) is active. - -Below are described the various management options. Run - - evennia -h - -to give you a brief help and - - evennia menu - -to give you a menu with options. - -## Starting Evennia - -Evennia consists of two components, the Evennia [Server and Portal](./Portal-And-Server.md). Briefly, -the *Server* is what is running the mud. It handles all game-specific things but doesn't care -exactly how players connect, only that they have. The *Portal* is a gateway to which players -connect. It knows everything about telnet, ssh, webclient protocols etc but very little about the -game. Both are required for a functioning mud. - - evennia start - -The above command will start the Portal, which in turn will boot up the Server. The command will -print a summary of the process and unless there is an error you will see no further output. Both -components will instead log to log files in `mygame/server/logs/`. For convenience you can follow -those logs directly in your terminal by attaching `-l` to commands: - - evennia -l - -Will start following the logs of an already running server. When starting Evennia you can also do - - evennia start -l - -> To stop viewing the log files, press `Ctrl-C`. - -## Foreground mode - -Normally, Evennia runs as a 'daemon', in the background. If you want you can start either of the -processes (but not both) as foreground processes in *interactive* mode. This means they will log -directly to the terminal (rather than to log files that we then echo to the terminal) and you can -kill the process (not just the log-file view) with `Ctrl-C`. - - evennia istart - -will start/restart the *Server* in interactive mode. This is required if you want to run a -*debugger*. Next time you reload the server, it will return to normal mode. - - evennia ipstart - -will start the *Portal* in interactive mode. This is usually only necessary if you want to run -Evennia under the control of some other type of process. - -## Reloading - -The act of *reloading* means the Portal will tell the Server to shut down and then boot it back up -again. Everyone will get a message and the game will be briefly paused for all accounts as the -server -reboots. Since they are connected to the *Portal*, their connections are not lost. - - -Reloading is as close to a "warm reboot" you can get. It reinitializes all code of Evennia, but -doesn't kill "persistent" [Scripts](./Scripts.md). It also calls `at_server_reload()` hooks on all -objects so you -can save eventual temporary properties you want. - -From in-game the `@reload` command is used. You can also reload the server from outside the game: - - evennia reload - -Sometimes reloading from "the outside" is necessary in case you have added some sort of bug that -blocks in-game input. - -## Resetting - -*Resetting* is the equivalent of a "cold reboot" - the Server will shut down and then restarted -again, but will behave as if it was fully shut down. As opposed to a "real" shutdown, no accounts -will be disconnected during a -reset. A reset will however purge all non-persistent scripts and will call `at_server_shutdown()` -hooks. It can be a good way to clean unsafe scripts during development, for example. - -From in-game the `@reset` command is used. From the terminal: - - evennia reset - - -## Rebooting - -This will shut down *both* Server and Portal, which means all connected players will lose their -connection. It can only be initiated from the terminal: - - evennia reboot - -This is identical to doing these two commands: - - evennia stop - evennia start - - -## Shutting down - -A full shutdown closes Evennia completely, both Server and Portal. All accounts will be booted and -systems saved and turned off cleanly. - -From inside the game you initiate a shutdown with the `@shutdown` command. From command line you do - - evennia stop - -You will see messages of both Server and Portal closing down. All accounts will see the shutdown -message and then be disconnected. The same effect happens if you press `Ctrl+C` while the server -runs in interactive mode. - -## Status and info - -To check basic Evennia settings, such as which ports and services are active, this will repeat the -initial return given when starting the server: - - evennia info - -You can also get a briefer run-status from both components with this command - - evennia status - -This can be useful for automating checks to make sure the game is running and is responding. - - -## Killing (Linux/Mac only) - -In the extreme case that neither of the server processes locks up and does not respond to commands, -you can send them kill-signals to force them to shut down. To kill only the Server: - - evennia skill - -To kill both Server and Portal: - - evennia kill - -Note that this functionality is not supported on Windows. - - -## Django options - -The `evennia` program will also pass-through options used by the `django-admin`. These operate on -the database in various ways. - -```bash - - evennia migrate # migrate the database - evennia shell # launch an interactive, django-aware python shell - evennia dbshell # launch database shell - -``` - -For (many) more options, see [the django-admin -docs](https://docs.djangoproject.com/en/1.7/ref/django-admin/#usage). - -## Advanced handling of Evennia processes - -If you should need to manually manage Evennia's processors (or view them in a task manager program -such as Linux' `top` or the more advanced `htop`), you will find the following processes to be -related to Evennia: - -* 1 x `twistd ... evennia/server/portal/portal.py` - this is the Portal process. -* 3 x `twistd ... server.py` - One of these processes manages Evennia's Server component, the main - game. The other processes (with the same name but different process id) handle's Evennia's - internal web server threads. You can look at `mygame/server/server.pid` to determine which is the - main process. - -### Syntax errors during live development - -During development, you will usually modify code and then reload the server to see your changes. -This is done by Evennia re-importing your custom modules from disk. Usually bugs in a module will -just have you see a traceback in the game, in the log or on the command line. For some really -serious syntax errors though, your module might not even be recognized as valid Python. Evennia may -then fail to restart correctly. - -From inside the game you see a text about the Server restarting followed by an ever growing list of -"...". Usually this only lasts a very short time (up to a few seconds). If it seems to go on, it -means the Portal is still running (you are still connected to the game) but the Server-component of -Evennia failed to restart (that is, it remains in a shut-down state). Look at your log files or -terminal to see what the problem is - you will usually see a clear traceback showing what went -wrong. - -Fix your bug then run - - evennia start - -Assuming the bug was fixed, this will start the Server manually (while not restarting the Portal). -In-game you should now get the message that the Server has successfully restarted. diff --git a/docs/0.9.5/_sources/Static-In-Game-Map.md.txt b/docs/0.9.5/_sources/Static-In-Game-Map.md.txt deleted file mode 100644 index d40fea7ed6..0000000000 --- a/docs/0.9.5/_sources/Static-In-Game-Map.md.txt +++ /dev/null @@ -1,412 +0,0 @@ -# Static In Game Map - - -## Introduction - -This tutorial describes the creation of an in-game map display based on a pre-drawn map. It also -details how to use the [Batch code processor](./Batch-Code-Processor.md) for advanced building. There is -also the [Dynamic in-game map tutorial](./Dynamic-In-Game-Map.md) that works in the opposite direction, -by generating a map from an existing grid of rooms. - -Evennia does not require its rooms to be positioned in a "logical" way. Your exits could be named -anything. You could make an exit "west" that leads to a room described to be in the far north. You -could have rooms inside one another, exits leading back to the same room or describing spatial -geometries impossible in the real world. - -That said, most games *do* organize their rooms in a logical fashion, if nothing else to retain the -sanity of their players. And when they do, the game becomes possible to map. This tutorial will give -an example of a simple but flexible in-game map system to further help player's to navigate. We will - -To simplify development and error-checking we'll break down the work into bite-size chunks, each -building on what came before. For this we'll make extensive use of the [Batch code processor](./Batch-Code-Processor.md), so you may want to familiarize yourself with that. - -1. **Planning the map** - Here we'll come up with a small example map to use for the rest of the -tutorial. -2. **Making a map object** - This will showcase how to make a static in-game "map" object a -Character could pick up and look at. -3. **Building the map areas** - Here we'll actually create the small example area according to the -map we designed before. -4. **Map code** - This will link the map to the location so our output looks something like this: - - ``` - crossroads(#3) - ↑╚∞╝↑ - ≈↑│↑∩ The merger of two roads. To the north looms a mighty castle. - O─O─O To the south, the glow of a campfire can be seen. To the east lie - ≈↑│↑∩ the vast mountains and to the west is heard the waves of the sea. - ↑▲O▲↑ - - Exits: north(#8), east(#9), south(#10), west(#11) - ``` - -We will henceforth assume your game folder is name named `mygame` and that you haven't modified the -default commands. We will also not be using [Colors](./TextTags.md#coloured-text) for our map since they -don't show in the documentation wiki. - -## Planning the Map - -Let's begin with the fun part! Maps in MUDs come in many different [shapes and sizes](http://journal.imaginary-realities.com/volume-05/issue-01/modern-interface-modern-mud/index.html). Some appear as just boxes connected by lines. Others have complex graphics that are -external to the game itself. - -Our map will be in-game text but that doesn't mean we're restricted to the normal alphabet! If -you've ever selected the [Wingdings font](https://en.wikipedia.org/wiki/Wingdings) in Microsoft Word -you will know there are a multitude of other characters around to use. When creating your game with -Evennia you have access to the [UTF-8 character encoding](https://en.wikipedia.org/wiki/UTF-8) which -put at your disposal [thousands of letters, number and geometric shapes](http://mcdlr.com/utf-8/#1). - -For this exercise, we've copy-and-pasted from the pallet of special characters used over at [Dwarf -Fortress](http://dwarffortresswiki.org/index.php/Character_table) to create what is hopefully a -pleasing and easy to understood landscape: - -``` -≈≈↑↑↑↑↑∩∩ -≈≈↑╔═╗↑∩∩ Places the account can visit are indicated by "O". -≈≈↑║O║↑∩∩ Up the top is a castle visitable by the account. -≈≈↑╚∞╝↑∩∩ To the right is a cottage and to the left the beach. -≈≈≈↑│↑∩∩∩ And down the bottom is a camp site with tents. -≈≈O─O─O⌂∩ In the center is the starting location, a crossroads -≈≈≈↑│↑∩∩∩ which connect the four other areas. -≈≈↑▲O▲↑∩∩ -≈≈↑↑▲↑↑∩∩ -≈≈↑↑↑↑↑∩∩ -``` -There are many considerations when making a game map depending on the play style and requirements -you intend to implement. Here we will display a 5x5 character map of the area surrounding the -account. This means making sure to account for 2 characters around every visitable location. Good -planning at this stage can solve many problems before they happen. - -## Creating a Map Object - -In this section we will try to create an actual "map" object that an account can pick up and look -at. - -Evennia offers a range of [default commands](./Default-Commands.md) for [creating objects and rooms -in-game](./Building-Quickstart.md). While readily accessible, these commands are made to do very -specific, restricted things and will thus not offer as much flexibility to experiment (for an -advanced exception see [in-line functions](./TextTags.md#new-inlinefuncs)). Additionally, entering long -descriptions and properties over and over in the game client can become tedious; especially when -testing and you may want to delete and recreate things over and over. - -To overcome this, Evennia offers [batch processors](./Batch-Processors.md) that work as input-files -created out-of-game. In this tutorial we'll be using the more powerful of the two available batch -processors, the [Batch Code Processor ](./Batch-Code-Processor.md), called with the `@batchcode` command. -This is a very powerful tool. It allows you to craft Python files to act as blueprints of your -entire game world. These files have access to use Evennia's Python API directly. Batchcode allows -for easy editing and creation in whatever text editor you prefer, avoiding having to manually build -the world line-by-line inside the game. - -> Important warning: `@batchcode`'s power is only rivaled by the `@py` command. Batchcode is so -powerful it should be reserved only for the [superuser](./Building-Permissions.md). Think carefully -before you let others (such as `Developer`- level staff) run `@batchcode` on their own - make sure -you are okay with them running *arbitrary Python code* on your server. - -While a simple example, the map object it serves as good way to try out `@batchcode`. Go to -`mygame/world` and create a new file there named `batchcode_map.py`: - -```Python -# mygame/world/batchcode_map.py - -from evennia import create_object -from evennia import DefaultObject - -# We use the create_object function to call into existence a -# DefaultObject named "Map" wherever you are standing. - -map = create_object(DefaultObject, key="Map", location=caller.location) - -# We then access its description directly to make it our map. - -map.db.desc = """ -≈≈↑↑↑↑↑∩∩ -≈≈↑╔═╗↑∩∩ -≈≈↑║O║↑∩∩ -≈≈↑╚∞╝↑∩∩ -≈≈≈↑│↑∩∩∩ -≈≈O─O─O⌂∩ -≈≈≈↑│↑∩∩∩ -≈≈↑▲O▲↑∩∩ -≈≈↑↑▲↑↑∩∩ -≈≈↑↑↑↑↑∩∩ -""" - -# This message lets us know our map was created successfully. -caller.msg("A map appears out of thin air and falls to the ground.") -``` - -Log into your game project as the superuser and run the command - -``` -@batchcode batchcode_map -``` - -This will load your `batchcode_map.py` file and execute the code (Evennia will look in your `world/` -folder automatically so you don't need to specify it). - -A new map object should have appeared on the ground. You can view the map by using `look map`. Let's -take it with the `get map` command. We'll need it in case we get lost! - -## Building the map areas - -We've just used batchcode to create an object useful for our adventures. But the locations on that -map does not actually exist yet - we're all mapped up with nowhere to go! Let's use batchcode to -build a game area based on our map. We have five areas outlined: a castle, a cottage, a campsite, a -coastal beach and the crossroads which connects them. Create a new batchcode file for this in -`mygame/world`, named `batchcode_world.py`. - -```Python -# mygame/world/batchcode_world.py - -from evennia import create_object, search_object -from typeclasses import rooms, exits - -# We begin by creating our rooms so we can detail them later. - -centre = create_object(rooms.Room, key="crossroads") -north = create_object(rooms.Room, key="castle") -east = create_object(rooms.Room, key="cottage") -south = create_object(rooms.Room, key="camp") -west = create_object(rooms.Room, key="coast") - -# This is where we set up the cross roads. -# The rooms description is what we see with the 'look' command. - -centre.db.desc = """ -The merger of two roads. A single lamp post dimly illuminates the lonely crossroads. -To the north looms a mighty castle. To the south the glow of a campfire can be seen. -To the east lie a wall of mountains and to the west the dull roar of the open sea. -""" - -# Here we are creating exits from the centre "crossroads" location to -# destinations to the north, east, south, and west. We will be able -# to use the exit by typing it's key e.g. "north" or an alias e.g. "n". - -centre_north = create_object(exits.Exit, key="north", - aliases=["n"], location=centre, destination=north) -centre_east = create_object(exits.Exit, key="east", - aliases=["e"], location=centre, destination=east) -centre_south = create_object(exits.Exit, key="south", - aliases=["s"], location=centre, destination=south) -centre_west = create_object(exits.Exit, key="west", - aliases=["w"], location=centre, destination=west) - -# Now we repeat this for the other rooms we'll be implementing. -# This is where we set up the northern castle. - -north.db.desc = "An impressive castle surrounds you. " \ - "There might be a princess in one of these towers." -north_south = create_object(exits.Exit, key="south", - aliases=["s"], location=north, destination=centre) - -# This is where we set up the eastern cottage. - -east.db.desc = "A cosy cottage nestled among mountains " \ - "stretching east as far as the eye can see." -east_west = create_object(exits.Exit, key="west", - aliases=["w"], location=east, destination=centre) - -# This is where we set up the southern camp. - -south.db.desc = "Surrounding a clearing are a number of " \ - "tribal tents and at their centre a roaring fire." -south_north = create_object(exits.Exit, key="north", - aliases=["n"], location=south, destination=centre) - -# This is where we set up the western coast. - -west.db.desc = "The dark forest halts to a sandy beach. " \ - "The sound of crashing waves calms the soul." -west_east = create_object(exits.Exit, key="east", - aliases=["e"], location=west, destination=centre) - -# Lastly, lets make an entrance to our world from the default Limbo room. - -limbo = search_object('Limbo')[0] -limbo_exit = create_object(exits.Exit, key="enter world", - aliases=["enter"], location=limbo, destination=centre) - -``` - -Apply this new batch code with `@batchcode batchcode_world`. If there are no errors in the code we -now have a nice mini-world to explore. Remember that if you get lost you can look at the map we -created! - -## In-game minimap - -Now we have a landscape and matching map, but what we really want is a mini-map that displays -whenever we move to a room or use the `look` command. - -We *could* manually enter a part of the map into the description of every room like we did our map -object description. But some MUDs have tens of thousands of rooms! Besides, if we ever changed our -map we would have to potentially alter a lot of those room descriptions manually to match the -change. So instead we will make one central module to hold our map. Rooms will reference this -central location on creation and the map changes will thus come into effect when next running our -batchcode. - -To make our mini-map we need to be able to cut our full map into parts. To do this we need to put it -in a format which allows us to do that easily. Luckily, python allows us to treat strings as lists -of characters allowing us to pick out the characters we need. - -`mygame/world/map_module.py` -```Python -# We place our map into a sting here. -world_map = """\ -≈≈↑↑↑↑↑∩∩ -≈≈↑╔═╗↑∩∩ -≈≈↑║O║↑∩∩ -≈≈↑╚∞╝↑∩∩ -≈≈≈↑│↑∩∩∩ -≈≈O─O─O⌂∩ -≈≈≈↑│↑∩∩∩ -≈≈↑▲O▲↑∩∩ -≈≈↑↑▲↑↑∩∩ -≈≈↑↑↑↑↑∩∩ -""" - -# This turns our map string into a list of rows. Because python -# allows us to treat strings as a list of characters, we can access -# those characters with world_map[5][5] where world_map[row][column]. -world_map = world_map.split('\n') - -def return_map(): - """ - This function returns the whole map - """ - map = "" - - #For each row in our map, add it to map - for valuey in world_map: - map += valuey - map += "\n" - - return map - -def return_minimap(x, y, radius = 2): - """ - This function returns only part of the map. - Returning all chars in a 2 char radius from (x,y) - """ - map = "" - - #For each row we need, add the characters we need. - for valuey in world_map[y-radius:y+radius+1]: for valuex in valuey[x-radius:x+radius+1]: - map += valuex - map += "\n" - - return map -``` - -With our map_module set up, let's replace our hardcoded map in `mygame/world/batchcode_map.py` with -a reference to our map module. Make sure to import our map_module! - -```python -# mygame/world/batchcode_map.py - -from evennia import create_object -from evennia import DefaultObject -from world import map_module - -map = create_object(DefaultObject, key="Map", location=caller.location) - -map.db.desc = map_module.return_map() - -caller.msg("A map appears out of thin air and falls to the ground.") -``` - -Log into Evennia as the superuser and run this batchcode. If everything worked our new map should -look exactly the same as the old map - you can use `@delete` to delete the old one (use a number to -pick which to delete). - -Now, lets turn our attention towards our game's rooms. Let's use the `return_minimap` method we -created above in order to include a minimap in our room descriptions. This is a little more -complicated. - -By itself we would have to settle for either the map being *above* the description with -`room.db.desc = map_string + description_string`, or the map going *below* by reversing their order. -Both options are rather unsatisfactory - we would like to have the map next to the text! For this -solution we'll explore the utilities that ship with Evennia. Tucked away in `evennia\evennia\utils` -is a little module called [EvTable](github:evennia.utils.evtable) . This is an advanced ASCII table -creator for you to utilize in your game. We'll use it by creating a basic table with 1 row and two -columns (one for our map and one for our text) whilst also hiding the borders. Open the batchfile -again - -```python -# mygame\world\batchcode_world.py - -# Add to imports -from evennia.utils import evtable -from world import map_module - -# [...] - -# Replace the descriptions with the below code. - -# The cross roads. -# We pass what we want in our table and EvTable does the rest. -# Passing two arguments will create two columns but we could add more. -# We also specify no border. -centre.db.desc = evtable.EvTable(map_module.return_minimap(4,5), - "The merger of two roads. A single lamp post dimly " \ - "illuminates the lonely crossroads. To the north " \ - "looms a mighty castle. To the south the glow of " \ - "a campfire can be seen. To the east lie a wall of " \ - "mountains and to the west the dull roar of the open sea.", - border=None) -# EvTable allows formatting individual columns and cells. We use that here -# to set a maximum width for our description, but letting the map fill -# whatever space it needs. -centre.db.desc.reformat_column(1, width=70) - -# [...] - -# The northern castle. -north.db.desc = evtable.EvTable(map_module.return_minimap(4,2), - "An impressive castle surrounds you. There might be " \ - "a princess in one of these towers.", - border=None) -north.db.desc.reformat_column(1, width=70) - -# [...] - -# The eastern cottage. -east.db.desc = evtable.EvTable(map_module.return_minimap(6,5), - "A cosy cottage nestled among mountains stretching " \ - "east as far as the eye can see.", - border=None) -east.db.desc.reformat_column(1, width=70) - -# [...] - -# The southern camp. -south.db.desc = evtable.EvTable(map_module.return_minimap(4,7), - "Surrounding a clearing are a number of tribal tents " \ - "and at their centre a roaring fire.", - border=None) -south.db.desc.reformat_column(1, width=70) - -# [...] - -# The western coast. -west.db.desc = evtable.EvTable(map_module.return_minimap(2,5), - "The dark forest halts to a sandy beach. The sound of " \ - "crashing waves calms the soul.", - border=None) -west.db.desc.reformat_column(1, width=70) -``` - -Before we run our new batchcode, if you are anything like me you would have something like 100 maps -lying around and 3-4 different versions of our rooms extending from limbo. Let's wipe it all and -start with a clean slate. In Command Prompt you can run `evennia flush` to clear the database and -start anew. It won't reset dbref values however, so if you are at #100 it will start from there. -Alternatively you can navigate to `mygame/server` and delete the `evennia.db3` file. Now in Command -Prompt use `evennia migrate` to have a completely freshly made database. - -Log in to evennia and run `@batchcode batchcode_world` and you'll have a little world to explore. - -## Conclusions - -You should now have a mapped little world and a basic understanding of batchcode, EvTable and how -easily new game defining features can be added to Evennia. - -You can easily build from this tutorial by expanding the map and creating more rooms to explore. Why -not add more features to your game by trying other tutorials: [Add weather to your world](./Weather-Tutorial.md), -[fill your world with NPC's](./Tutorial-Aggressive-NPCs.md) or [implement a combat system](./Turn-based-Combat-System.md). diff --git a/docs/0.9.5/_sources/Tags.md.txt b/docs/0.9.5/_sources/Tags.md.txt deleted file mode 100644 index 8b34e09021..0000000000 --- a/docs/0.9.5/_sources/Tags.md.txt +++ /dev/null @@ -1,170 +0,0 @@ -# Tags - - -A common task of a game designer is to organize and find groups of objects and do operations on -them. A classic example is to have a weather script affect all "outside" rooms. Another would be for -a player casting a magic spell that affects every location "in the dungeon", but not those -"outside". Another would be to quickly find everyone joined with a particular guild or everyone -currently dead. - -*Tags* are short text labels that you attach to objects so as to easily be able to retrieve and -group them. An Evennia entity can be tagged with any number of Tags. On the database side, Tag -entities are *shared* between all objects with that tag. This makes them very efficient but also -fundamentally different from [Attributes](./Attributes.md), each of which always belongs to one *single* -object. - -In Evennia, Tags are technically also used to implement `Aliases` (alternative names for objects) -and `Permissions` (simple strings for [Locks](./Locks.md) to check for). - - -## Properties of Tags (and Aliases and Permissions) - -Tags are *unique* per object model. This means that for each object model (`Objects`, `Scripts`, -`Msgs`, etc.) there is only ever one Tag object with a given key and category. - -> Not specifying a category (default) gives the tag a category of `None`, which is also considered a -unique key + category combination. - -When Tags are assigned to game entities, these entities are actually sharing the same Tag. This -means that Tags are not suitable for storing information about a single object - use an -[Attribute](./Attributes.md) for this instead. Tags are a lot more limited than Attributes but this also -makes them very quick to lookup in the database - this is the whole point. - -Tags have the following properties, stored in the database: - -- **key** - the name of the Tag. This is the main property to search for when looking up a Tag. -- **category** - this category allows for retrieving only specific subsets of tags used for -different purposes. You could have one category of tags for "zones", another for "outdoor -locations", for example. If not given, the category will be `None`, which is also considered a -separate, default, category. -- **data** - this is an optional text field with information about the tag. Remember that Tags are -shared between entities, so this field cannot hold any object-specific information. Usually it would -be used to hold info about the group of entities the Tag is tagging - possibly used for contextual -help like a tool tip. It is not used by default. - -There are also two special properties. These should usually not need to be changed or set, it is -used internally by Evennia to implement various other uses it makes of the `Tag` object: -- **model** - this holds a *natural-key* description of the model object that this tag deals with, -on the form *application.modelclass*, for example `objects.objectdb`. It used by the TagHandler of -each entity type for correctly storing the data behind the scenes. -- **tagtype** - this is a "top-level category" of sorts for the inbuilt children of Tags, namely -*Aliases* and *Permissions*. The Taghandlers using this special field are especially intended to -free up the *category* property for any use you desire. - -## Adding/Removing Tags - -You can tag any *typeclassed* object, namely [Objects](./Objects.md), [Accounts](./Accounts.md), -[Scripts](./Scripts.md) and [Channels](./Communications.md). General tags are added by the *Taghandler*. The -tag handler is accessed as a property `tags` on the relevant entity: - -```python - mychair.tags.add("furniture") - mychair.tags.add("furniture", category="luxurious") - myroom.tags.add("dungeon#01") - myscript.tags.add("weather", category="climate") - myaccount.tags.add("guestaccount") - - mychair.tags.all() # returns a list of Tags - mychair.tags.remove("furniture") - mychair.tags.clear() -``` - -Adding a new tag will either create a new Tag or re-use an already existing one. Note that there are -_two_ "furniture" tags, one with a `None` category, and one with the "luxurious" category. - -When using `remove`, the `Tag` is not deleted but are just disconnected from the tagged object. This -makes for very quick operations. The `clear` method removes (disconnects) all Tags from the object. -You can also use the default `@tag` command: - - @tag mychair = furniture - -This tags the chair with a 'furniture' Tag (the one with a `None` category). - -## Searching for objects with a given tag - -Usually tags are used as a quick way to find tagged database entities. You can retrieve all objects -with a given Tag like this in code: - -```python - import evennia - - # all methods return Querysets - - # search for objects - objs = evennia.search_tag("furniture") - objs2 = evennia.search_tag("furniture", category="luxurious") - dungeon = evennia.search_tag("dungeon#01") - forest_rooms = evennia.search_tag(category="forest") - forest_meadows = evennia.search_tag("meadow", category="forest") - magic_meadows = evennia.search_tag("meadow", category="magical") - - # search for scripts - weather = evennia.search_tag_script("weather") - climates = evennia.search_tag_script(category="climate") - - # search for accounts - accounts = evennia.search_tag_account("guestaccount") -``` - -> Note that searching for just "furniture" will only return the objects tagged with the "furniture" -tag that -has a category of `None`. We must explicitly give the category to get the "luxurious" furniture. - -Using any of the `search_tag` variants will all return [Django -Querysets](https://docs.djangoproject.com/en/2.1/ref/models/querysets/), including if you only have -one match. You can treat querysets as lists and iterate over them, or continue building search -queries with them. - -Remember when searching that not setting a category means setting it to `None` - this does *not* -mean that category is undefined, rather `None` is considered the default, unnamed category. - -```python -import evennia - -myobj1.tags.add("foo") # implies category=None -myobj2.tags.add("foo", category="bar") - -# this returns a queryset with *only* myobj1 -objs = evennia.search_tag("foo") - -# these return a queryset with *only* myobj2 -objs = evennia.search_tag("foo", category="bar") -# or -objs = evennia.search_tag(category="bar") - -``` - - - -There is also an in-game command that deals with assigning and using ([Object-](./Objects.md)) tags: - - @tag/search furniture - -## Using Aliases and Permissions - -Aliases and Permissions are implemented using normal TagHandlers that simply save Tags with a -different `tagtype`. These handlers are named `aliases` and `permissions` on all Objects. They are -used in the same way as Tags above: - -```python - boy.aliases.add("rascal") - boy.permissions.add("Builders") - boy.permissions.remove("Builders") - - all_aliases = boy.aliases.all() -``` - -and so on. Similarly to how `@tag` works in-game, there is also the `@perm` command for assigning -permissions and `@alias` command for aliases. - -## Assorted notes - -Generally, tags are enough on their own for grouping objects. Having no tag `category` is perfectly -fine and the normal operation. Simply adding a new Tag for grouping objects is often better than -making a new category. So think hard before deciding you really need to categorize your Tags. - -That said, tag categories can be useful if you build some game system that uses tags. You can then -use tag categories to make sure to separate tags created with this system from any other tags -created elsewhere. You can then supply custom search methods that *only* find objects tagged with -tags of that category. An example of this -is found in the [Zone tutorial](./Zones.md). diff --git a/docs/0.9.5/_sources/Text-Encodings.md.txt b/docs/0.9.5/_sources/Text-Encodings.md.txt deleted file mode 100644 index 1dfdf5a4e4..0000000000 --- a/docs/0.9.5/_sources/Text-Encodings.md.txt +++ /dev/null @@ -1,66 +0,0 @@ -# Text Encodings - - -Evennia is a text-based game server. This makes it important to understand how -it actually deals with data in the form of text. - -Text *byte encodings* describe how a string of text is actually stored in the -computer - that is, the particular sequence of bytes used to represent the -letters of your particular alphabet. A common encoding used in English-speaking -languages is the *ASCII* encoding. This describes the letters in the English -alphabet (Aa-Zz) as well as a bunch of special characters. For describing other -character sets (such as that of other languages with other letters than - English), sets with names such as *Latin-1*, *ISO-8859-3* and *ARMSCII-8* -are used. There are hundreds of different byte encodings in use around the -world. - -A string of letters in a byte encoding is represented with the `bytes` type. -In contrast to the byte encoding is the *unicode representation*. In Python -this is the `str` type. The unicode is an internationally agreed-upon table -describing essentially all available letters you could ever want to print. -Everything from English to Chinese alphabets and all in between. So what -Evennia (as well as Python and Django) does is to store everything in Unicode -internally, but then converts the data to one of the encodings whenever -outputting data to the user. - -An easy memory aid is that `bytes` are what are sent over the network wire. At -all other times, `str` (unicode) is used. This means that we must convert -between the two at the points where we send/receive network data. - -The problem is that when receiving a string of bytes over the network it's -impossible for Evennia to guess which encoding was used - it's just a bunch of -bytes! Evennia must know the encoding in order to convert back and from the -correct unicode representation. - -## How to customize encodings - -As long as you stick to the standard ASCII character set (which means the -normal English characters, basically) you should not have to worry much -about this section. - -If you want to build your game in another language however, or expect your -users to want to use special characters not in ASCII, you need to consider -which encodings you want to support. - -As mentioned, there are many, many byte-encodings used around the world. It -should be clear at this point that Evennia can't guess but has to assume or -somehow be told which encoding you want to use to communicate with the server. -Basically the encoding used by your client must be the same encoding used by -the server. This can be customized in two complementary ways. - -1. Point users to the default `@encoding` command or the `@options` command. - This allows them to themselves set which encoding they (and their client of - choice) uses. Whereas data will remain stored as unicode strings internally in - Evennia, all data received from and sent to this particular player will be - converted to the given format before transmitting. -1. As a back-up, in case the user-set encoding translation is erroneous or - fails in some other way, Evennia will fall back to trying with the names - defined in the settings variable `ENCODINGS`. This is a list of encoding - names Evennia will try, in order, before giving up and giving an encoding - error message. - -Note that having to try several different encodings every input/output adds -unneccesary overhead. Try to guess the most common encodings you players will -use and make sure these are tried first. The International *UTF-8* encoding is -what Evennia assumes by default (and also what Python/Django use normally). See -the Wikipedia article [here](http://en.wikipedia.org/wiki/Text_encodings) for more help. diff --git a/docs/0.9.5/_sources/TextTags.md.txt b/docs/0.9.5/_sources/TextTags.md.txt deleted file mode 100644 index 4c326b4a83..0000000000 --- a/docs/0.9.5/_sources/TextTags.md.txt +++ /dev/null @@ -1,345 +0,0 @@ -# TextTags - - -This documentation details the various text tags supported by Evennia, namely *colours*, *command -links* and *inline functions*. - -There is also an [Understanding Color Tags](./Understanding-Color-Tags.md) tutorial which expands on the -use of ANSI color tags and the pitfalls of mixing ANSI and Xterms256 color tags in the same context. - -## Coloured text - -*Note that the Documentation does not display colour the way it would look on the screen.* - -Color can be a very useful tool for your game. It can be used to increase readability and make your -game more appealing visually. - -Remember however that, with the exception of the webclient, you generally don't control the client -used to connect to the game. There is, for example, one special tag meaning "yellow". But exactly -*which* hue of yellow is actually displayed on the user's screen depends on the settings of their -particular mud client. They could even swap the colours around or turn them off altogether if so -desired. Some clients don't even support color - text games are also played with special reading -equipment by people who are blind or have otherwise diminished eyesight. - -So a good rule of thumb is to use colour to enhance your game but don't *rely* on it to display -critical information. If you are coding the game, you can add functionality to let users disable -colours as they please, as described [here](./Manually-Configuring-Color.md). - -To see which colours your client support, use the default `@color` command. This will list all -available colours for ANSI and Xterm256 along with the codes you use for them. You can find a list -of all the parsed `ANSI`-colour codes in `evennia/utils/ansi.py`. - -### ANSI colours - -Evennia supports the `ANSI` standard for text. This is by far the most supported MUD-color standard, -available in all but the most ancient mud clients. The ANSI colours are **r**ed, **g**reen, -**y**ellow, **b**lue, **m**agenta, **c**yan, **w**hite and black. They are abbreviated by their -first letter except for black which is abbreviated with the letter **x**. In ANSI there are "bright" -and "normal" (darker) versions of each color, adding up to a total of 16 colours to use for -foreground text. There are also 8 "background" colours. These have no bright alternative in ANSI -(but Evennia uses the [Xterm256](./TextTags.md#xterm256-colours) extension behind the scenes to offer -them anyway). - -To colour your text you put special tags in it. Evennia will parse these and convert them to the -correct markup for the client used. If the user's client/console/display supports ANSI colour, they -will see the text in the specified colour, otherwise the tags will be stripped (uncolored text). -This works also for non-terminal clients, such as the webclient. For the webclient, Evennia will -translate the codes to HTML RGB colors. - -Here is an example of the tags in action: - - |rThis text is bright red.|n This is normal text. - |RThis is a dark red text.|n This is normal text. - |[rThis text has red background.|n This is normal text. - |b|[yThis is bright blue text on yellow background.|n This is normal text. - -- `|n` - this tag will turn off all color formatting, including background colors. -- `|#`- markup marks the start of foreground color. The case defines if the text is "bright" or -"normal". So `|g` is a bright green and `|G` is "normal" (darker) green. -- `|[#` is used to add a background colour to the text. The case again specifies if it is "bright" -or "normal", so `|[c` starts a bright cyan background and `|[C` a darker cyan background. -- `|!#` is used to add foreground color without any enforced brightness/normal information. - These are normal-intensity and are thus always given as uppercase, such as - `|!R` for red. The difference between e.g. `|!R` and `|R` is that - `|!R` will "inherit" the brightness setting from previously set color tags, whereas `|R` will -always reset to the normal-intensity red. The `|#` format contains an implicit `|h`/`|H` tag in it: -disabling highlighting when switching to a normal color, and enabling it for bright ones. So `|btest -|!Rtest2` will result in a bright red `test2` since the brightness setting from `|b` "bleeds over". -You could use this to for example quickly switch the intensity of a multitude of color tags. There -is no background-color equivalent to `|!` style tags. -- `|h` is used to make any following foreground ANSI colors bright (it has no effect on Xterm -colors). This is only relevant to use with `|!` type tags and will be valid until the next `|n`, -`|H` or normal (upper-case) `|#` tag. This tag will never affect background colors, those have to be -set bright/normal explicitly. Technically, `|h|!G` is identical to `|g`. -- `|H` negates the effects `|h` and returns all ANSI foreground colors (`|!` and `|` types) to -'normal' intensity. It has no effect on background and Xterm colors. - -> Note: The ANSI standard does not actually support bright backgrounds like `|[r` - the standard -only supports "normal" intensity backgrounds. To get around this Evennia instead implements these -as [Xterm256 colours](./TextTags.md#xterm256-colours) behind the scenes. If the client does not support -Xterm256 the ANSI colors will be used instead and there will be no visible difference between using -upper- and lower-case background tags. - -If you want to display an ANSI marker as output text (without having any effect), you need to escape -it by preceding its `|` with another `|`: - -``` -say The ||r ANSI marker changes text color to bright red. -``` - -This will output the raw `|r` without any color change. This can also be necessary if you are doing -ansi art that uses `|` with a letter directly following it. - -Use the command - - @color ansi - -to get a list of all supported ANSI colours and the tags used to produce them. - -A few additional ANSI codes are supported: - -- `|/` A line break. You cannot put the normal Python `\n` line breaks in text entered inside the -game (Evennia will filter this for security reasons). This is what you use instead: use the `|/` -marker to format text with line breaks from the game command line. -- `` This will translate into a `TAB` character. This will not always show (or show differently) to -the client since it depends on their local settings. It's often better to use multiple spaces. -- `|_` This is a space. You can usually use the normal space character, but if the space is *at the -end of the line*, Evennia will likely crop it. This tag will not be cropped but always result in a -space. -- `|*` This will invert the current text/background colours. Can be useful to mark things (but see -below). - -##### Caveats of `|*` - -The `|*` tag (inverse video) is an old ANSI standard and should usually not be used for more than to -mark short snippets of text. If combined with other tags it comes with a series of potentially -confusing behaviors: - -* The `|*` tag will only work once in a row:, ie: after using it once it won't have an effect again -until you declare another tag. This is an example: - - ``` - Normal text, |*reversed text|*, still reversed text. - ``` - - that is, it will not reverse to normal at the second `|*`. You need to reset it manually: - - ``` - Normal text, |*reversed text|n, normal again. - ``` - -* The `|*` tag does not take "bright" colors into account: - - ``` - |RNormal red, |hnow brightened. |*BG is normal red. - ``` - - So `|*` only considers the 'true' foreground color, ignoring any highlighting. Think of the bright -state (`|h`) as something like like `` in HTML: it modifies the _appearance_ of a normal -foreground color to match its bright counterpart, without changing its normal color. -* Finally, after a `|*`, if the previous background was set to a dark color (via `|[`), `|!#`) will -actually change the background color instead of the foreground: - - ``` - |*reversed text |!R now BG is red. - ``` -For a detailed explanation of these caveats, see the [Understanding Color Tags](Understanding-Color- -Tags) tutorial. But most of the time you might be better off to simply avoid `|*` and mark your text -manually instead. - -### Xterm256 Colours - -The _Xterm256_ standard is a colour scheme that supports 256 colours for text and/or background. -While this offers many more possibilities than traditional ANSI colours, be wary that too many text -colors will be confusing to the eye. Also, not all clients support Xterm256 - these will instead see -the closest equivalent ANSI color. You can mix Xterm256 tags with ANSI tags as you please. - - |555 This is pure white text.|n This is normal text. - |230 This is olive green text. - |[300 This text has a dark red background. - |005|[054 This is dark blue text on a bright cyan background. - |=a This is a greyscale value, equal to black. - |=m This is a greyscale value, midway between white and black. - |=z This is a greyscale value, equal to white. - |[=m This is a background greyscale value. - -- `|###` - markup consists of three digits, each an integer from 0 to 5. The three digits describe -the amount of **r**ed, **g**reen and **b**lue (RGB) components used in the colour. So `|500` means -maximum red and none of the other colours - the result is a bright red. `|520` is red with a touch -of green - the result is orange. As opposed to ANSI colors, Xterm256 syntax does not worry about -bright/normal intensity, a brighter (lighter) color is just achieved by upping all RGB values with -the same amount. -- `|[###` - this works the same way but produces a coloured background. -- `|=#` - markup produces the xterm256 gray scale tones, where `#` is a letter from `a` (black) to -`z` (white). This offers many more nuances of gray than the normal `|###` markup (which only has -four gray tones between solid black and white (`|000`, `|111`, `|222`, `|333` and `|444`)). -- `|[=#` - this works in the same way but produces background gray scale tones. - -If you have a client that supports Xterm256, you can use - - @color xterm256 - -to get a table of all the 256 colours and the codes that produce them. If the table looks broken up -into a few blocks of colors, it means Xterm256 is not supported and ANSI are used as a replacement. -You can use the `@options` command to see if xterm256 is active for you. This depends on if your -client told Evennia what it supports - if not, and you know what your client supports, you may have -to activate some features manually. - -## Clickable links - -Evennia supports clickable links for clients that supports it. This marks certain text so it can be -clicked by a mouse and trigger a given Evennia command. To support clickable links, Evennia requires -the webclient or an third-party telnet client with [MXP](http://www.zuggsoft.com/zmud/mxp.htm) -support (*Note: Evennia only supports clickable links, no other MXP features*). - - - `|lc` to start the link, by defining the command to execute. - - `|lt` to continue with the text to show to the user (the link text). - - `|le` to end the link text and the link definition. - -All elements must appear in exactly this order to make a valid link. For example, - -``` -"If you go |lcnorth|ltto the north|le you will find a cottage." -``` - -This will display as "If you go __to the north__ you will find a cottage." where clicking the link -will execute the command `north`. If the client does not support clickable links, only the link text -will be shown. - -## Inline functions - -> Note: Inlinefuncs are **not** activated by default. To use them you need to add -`INLINEFUNC_ENABLED=True` to your settings file. - -Evennia has its own inline text formatting language, known as *inlinefuncs*. It allows the builder -to include special function calls in code. They are executed dynamically by each session that -receives them. - -To add an inlinefunc, you embed it in a text string like this: - -``` -"A normal string with $funcname(arg, arg, ...) embedded inside it." -``` - -When this string is sent to a session (with the `msg()` method), these embedded inlinefuncs will be -parsed. Their return value (which always is a string) replace their call location in the finalized -string. The interesting thing with this is that the function called will have access to which -session is seeing the string, meaning the string can end up looking different depending on who is -looking. It could of course also vary depending on other factors like game time. - -Any number of comma-separated arguments can be given (or none). No keywords are supported. You can -also nest inlinefuncs by letting an argument itself also be another `$funcname(arg, arg, ...)` call -(down to a depth of nesting given by `settings.INLINEFUNC_STACK_MAXSIZE`). Function call resolution -happens as in all programming languages inside-out, with the nested calls replacing the argument -with their return strings before calling he parent. - -``` - > say "This is $pad(a center-padded text, 30,c,-) of width 30." - You say, "This is ---- a center-padded text----- of width 30." - > say "I roll a die and the result is ... a $random(1,6)!" - You say, "I roll a die and the result is ... a 5!" -``` - -A special case happens if wanting to use an inlinefunc argument that itself includes a comma - this -would be parsed as an argument separator. To escape commas you can either escape each comma manually -with a backslash `\,`, or you can embed the entire string in python triple-quotes `"""` or `'''` - -this will escape the entire argument, including commas and any nested inlinefunc calls within. - -Only certain functions are available to use as inlinefuncs and the game developer may add their own -functions as needed. - -### New inlinefuncs - -To add new inlinefuncs, edit the file `mygame/server/conf/inlinefuncs.py`. - -*All globally defined functions in this module* are considered inline functions by the system. The -only exception is functions whose name starts with an underscore `_`. An inlinefunc must be of the -following form: - -```python -def funcname(*args, **kwargs): - # ... - return modified_text -``` - -where `*args` denotes all the arguments this function will accept as an `$inlinefunc`. The inline -function is expected to clean arguments and check that they are valid. If needed arguments are not -given, default values should be used. The function should always return a string (even if it's -empty). An inlinefunc should never cause a traceback regardless of the input (but it could log -errors if desired). - -Note that whereas the function should accept `**kwargs`, keyword inputs are *not* usable in the call -to the inlinefunction. The `kwargs` part is instead intended for Evennia to be able to supply extra -information. Currently Evennia sends a single keyword to every inline function and that is -`session`, which holds the [serversession](./Sessions.md) this text is targeted at. Through the session -object, a lot of dynamic possibilities are opened up for your inline functions. - -The `settings.INLINEFUNC_MODULES` configuration option is a list that decides which modules should -be parsed for inline function definitions. This will include `mygame/server/conf/inlinefuncs.py` but -more could be added. The list is read from left to right so if you want to overload default -functions you just have to put your custom module-paths later in the list and name your functions -the same as default ones. - -Here is an example, the `crop` default inlinefunction: - -```python -from evennia.utils import utils - -def crop(*args, **kwargs): - """ - Inlinefunc. Crops ingoing text to given widths. - Args: - text (str, optional): Text to crop. - width (str, optional): Will be converted to an integer. Width of - crop in characters. - suffix (str, optional): End string to mark the fact that a part - of the string was cropped. Defaults to `[...]`. - Kwargs: - session (Session): Session performing the crop. - Example: - `$crop(text, 50, [...])` - - """ - text, width, suffix = "", 78, "[...]" - nargs = len(args) - if nargs > 0: - text = args[0] - if nargs > 1: - width = int(args[1]) if args[1].strip().isdigit() else 78 - if nargs > 2: - suffix = args[2] - return utils.crop(text, width=width, suffix=suffix) -``` -Another example, making use of the Session: - -```python -def charactername(*args, **kwargs): - """ - Inserts the character name of whomever sees the string - (so everyone will see their own name). Uses the account - name for OOC communications. - - Example: - say "This means YOU, $charactername()!" - - """ - session = kwargs["session"] - if session.puppet: - return kwargs["session"].puppet.key - else: - return session.account.key -``` - -Evennia itself offers the following default inline functions (mostly as examples): - -* `crop(text, width, suffix)` - See above. -* `pad(text, width, align, fillchar)` - this pads the text to `width` (default 78), alignment ("c", -"l" or "r", defaulting to "c") and fill-in character (defaults to space). Example: `$pad(40,l,-)` -* `clr(startclr, text, endclr)` - A programmatic way to enter colored text for those who don't want -to use the normal `|c` type color markers for some reason. The `color` argument is the same as the -color markers except without the actual pre-marker, so `|r` would be just `r`. If `endclr` is not -given, it defaults to resetting the color (`n`). Example: `$clr(b, A blue text)` -* `space(number)` - Inserts the given number of spaces. If no argument is given, use 4 spaces. -* `random()`, `random(max)`, `random(min, max)` - gives a random value between min and max. With no -arguments, give 0 or 1 (on/off). If one argument, returns 0...max. If values are floats, random -value will be a float (so `random(1.0)` replicates the normal Python `random` function). \ No newline at end of file diff --git a/docs/0.9.5/_sources/TickerHandler.md.txt b/docs/0.9.5/_sources/TickerHandler.md.txt deleted file mode 100644 index 9b9a5878b6..0000000000 --- a/docs/0.9.5/_sources/TickerHandler.md.txt +++ /dev/null @@ -1,136 +0,0 @@ -# TickerHandler - - -One way to implement a dynamic MUD is by using "tickers", also known as "heartbeats". A ticker is a -timer that fires ("ticks") at a given interval. The tick triggers updates in various game systems. - -## About Tickers - -Tickers are very common or even unavoidable in other mud code bases. Certain code bases are even -hard-coded to rely on the concept of the global 'tick'. Evennia has no such notion - the decision to -use tickers is very much up to the need of your game and which requirements you have. The "ticker -recipe" is just one way of cranking the wheels. - -The most fine-grained way to manage the flow of time is of course to use [Scripts](./Scripts.md). Many -types of operations (weather being the classic example) are however done on multiple objects in the -same way at regular intervals, and for this, storing separate Scripts on each object is inefficient. -The way to do this is to use a ticker with a "subscription model" - let objects sign up to be -triggered at the same interval, unsubscribing when the updating is no longer desired. - -Evennia offers an optimized implementation of the subscription model - the *TickerHandler*. This is -a singleton global handler reachable from `evennia.TICKER_HANDLER`. You can assign any *callable* (a -function or, more commonly, a method on a database object) to this handler. The TickerHandler will -then call this callable at an interval you specify, and with the arguments you supply when adding -it. This continues until the callable un-subscribes from the ticker. The handler survives a reboot -and is highly optimized in resource usage. - -Here is an example of importing `TICKER_HANDLER` and using it: - -```python - # we assume that obj has a hook "at_tick" defined on itself - from evennia import TICKER_HANDLER as tickerhandler - - tickerhandler.add(20, obj.at_tick) -``` - -That's it - from now on, `obj.at_tick()` will be called every 20 seconds. - -You can also import function and tick that: - -```python - from evennia import TICKER_HANDLER as tickerhandler - from mymodule import myfunc - - tickerhandler.add(30, myfunc) -``` - -Removing (stopping) the ticker works as expected: - -```python - tickerhandler.remove(20, obj.at_tick) - tickerhandler.remove(30, myfunc) -``` - -Note that you have to also supply `interval` to identify which subscription to remove. This is -because the TickerHandler maintains a pool of tickers and a given callable can subscribe to be -ticked at any number of different intervals. - -The full definition of the `tickerhandler.add` method is - -```python - tickerhandler.add(interval, callback, - idstring="", persistent=True, *args, **kwargs) -``` - -Here `*args` and `**kwargs` will be passed to `callback` every `interval` seconds. If `persistent` -is `False`, this subscription will not survive a server reload. - -Tickers are identified and stored by making a key of the callable itself, the ticker-interval, the -`persistent` flag and the `idstring` (the latter being an empty string when not given explicitly). - -Since the arguments are not included in the ticker's identification, the `idstring` must be used to -have a specific callback triggered multiple times on the same interval but with different arguments: - -```python - tickerhandler.add(10, obj.update, "ticker1", True, 1, 2, 3) - tickerhandler.add(10, obj.update, "ticker2", True, 4, 5) -``` - -> Note that, when we want to send arguments to our callback within a ticker handler, we need to -specify `idstring` and `persistent` before, unless we call our arguments as keywords, which would -often be more readable: - -```python - tickerhandler.add(10, obj.update, caller=self, value=118) -``` - -If you add a ticker with exactly the same combination of callback, interval and idstring, it will -overload the existing ticker. This identification is also crucial for later removing (stopping) the -subscription: - -```python - tickerhandler.remove(10, obj.update, idstring="ticker1") - tickerhandler.remove(10, obj.update, idstring="ticker2") -``` - -The `callable` can be on any form as long as it accepts the arguments you give to send to it in -`TickerHandler.add`. - -> Note that everything you supply to the TickerHandler will need to be pickled at some point to be -saved into the database. Most of the time the handler will correctly store things like database -objects, but the same restrictions as for [Attributes](./Attributes.md) apply to what the TickerHandler -may store. - -When testing, you can stop all tickers in the entire game with `tickerhandler.clear()`. You can also -view the currently subscribed objects with `tickerhandler.all()`. - -See the [Weather Tutorial](./Weather-Tutorial.md) for an example of using the TickerHandler. - -### When *not* to use TickerHandler - -Using the TickerHandler may sound very useful but it is important to consider when not to use it. -Even if you are used to habitually relying on tickers for everything in other code bases, stop and -think about what you really need it for. This is the main point: - -> You should *never* use a ticker to catch *changes*. - -Think about it - you might have to run the ticker every second to react to the change fast enough. -Most likely nothing will have changed at a given moment. So you are doing pointless calls (since -skipping the call gives the same result as doing it). Making sure nothing's changed might even be -computationally expensive depending on the complexity of your system. Not to mention that you might -need to run the check *on every object in the database*. Every second. Just to maintain status quo -... - -Rather than checking over and over on the off-chance that something changed, consider a more -proactive approach. Could you implement your rarely changing system to *itself* report when its -status changes? It's almost always much cheaper/efficient if you can do things "on demand". Evennia -itself uses hook methods for this very reason. - -So, if you consider a ticker that will fire very often but which you expect to have no effect 99% of -the time, consider handling things things some other way. A self-reporting on-demand solution is -usually cheaper also for fast-updating properties. Also remember that some things may not need to be -updated until someone actually is examining or using them - any interim changes happening up to that -moment are pointless waste of computing time. - -The main reason for needing a ticker is when you want things to happen to multiple objects at the -same time without input from something else. \ No newline at end of file diff --git a/docs/0.9.5/_sources/Turn-based-Combat-System.md.txt b/docs/0.9.5/_sources/Turn-based-Combat-System.md.txt deleted file mode 100644 index a4577185df..0000000000 --- a/docs/0.9.5/_sources/Turn-based-Combat-System.md.txt +++ /dev/null @@ -1,516 +0,0 @@ -# Turn based Combat System - - -This tutorial gives an example of a full, if simplified, combat system for Evennia. It was inspired -by the discussions held on the [mailing list](https://groups.google.com/forum/#!msg/evennia/wnJNM2sXSfs/-dbLRrgWnYMJ). - -## Overview of combat system concepts - -Most MUDs will use some sort of combat system. There are several main variations: - -- _Freeform_ - the simplest form of combat to implement, common to MUSH-style roleplaying games. -This means the system only supplies dice rollers or maybe commands to compare skills and spit out -the result. Dice rolls are done to resolve combat according to the rules of the game and to direct -the scene. A game master may be required to resolve rule disputes. -- _Twitch_ - This is the traditional MUD hack&slash style combat. In a twitch system there is often -no difference between your normal "move-around-and-explore mode" and the "combat mode". You enter an -attack command and the system will calculate if the attack hits and how much damage was caused. -Normally attack commands have some sort of timeout or notion of recovery/balance to reduce the -advantage of spamming or client scripting. Whereas the simplest systems just means entering `kill -` over and over, more sophisticated twitch systems include anything from defensive stances -to tactical positioning. -- _Turn-based_ - a turn based system means that the system pauses to make sure all combatants can -choose their actions before continuing. In some systems, such entered actions happen immediately -(like twitch-based) whereas in others the resolution happens simultaneously at the end of the turn. -The disadvantage of a turn-based system is that the game must switch to a "combat mode" and one also -needs to take special care of how to handle new combatants and the passage of time. The advantage is -that success is not dependent on typing speed or of setting up quick client macros. This potentially -allows for emoting as part of combat which is an advantage for roleplay-heavy games. - -To implement a freeform combat system all you need is a dice roller and a roleplaying rulebook. See -[contrib/dice.py](https://github.com/evennia/evennia/blob/master/evennia/contrib/dice.py) for an -example dice roller. To implement at twitch-based system you basically need a few combat -[commands](./Commands.md), possibly ones with a [cooldown](./Command-Cooldown.md). You also need a [game rule -module](./Implementing-a-game-rule-system.md) that makes use of it. We will focus on the turn-based -variety here. - -## Tutorial overview - -This tutorial will implement the slightly more complex turn-based combat system. Our example has the -following properties: - -- Combat is initiated with `attack `, this initiates the combat mode. -- Characters may join an ongoing battle using `attack ` against a character already in -combat. -- Each turn every combating character will get to enter two commands, their internal order matters -and they are compared one-to-one in the order given by each combatant. Use of `say` and `pose` is -free. -- The commands are (in our example) simple; they can either `hit `, `feint ` or -`parry `. They can also `defend`, a generic passive defense. Finally they may choose to -`disengage/flee`. -- When attacking we use a classic [rock-paper-scissors](https://en.wikipedia.org/wiki/Rock-paper-scissors) mechanic to determine success: `hit` defeats `feint`, which defeats `parry` which defeats -`hit`. `defend` is a general passive action that has a percentage chance to win against `hit` -(only). -- `disengage/flee` must be entered two times in a row and will only succeed if there is no `hit` -against them in that time. If so they will leave combat mode. -- Once every player has entered two commands, all commands are resolved in order and the result is -reported. A new turn then begins. -- If players are too slow the turn will time out and any unset commands will be set to `defend`. - -For creating the combat system we will need the following components: - -- A combat handler. This is the main mechanic of the system. This is a [Script](./Scripts.md) object -created for each combat. It is not assigned to a specific object but is shared by the combating -characters and handles all the combat information. Since Scripts are database entities it also means -that the combat will not be affected by a server reload. -- A combat [command set](./Command-Sets.md) with the relevant commands needed for combat, such as the -various attack/defend options and the `flee/disengage` command to leave the combat mode. -- A rule resolution system. The basics of making such a module is described in the [rule system tutorial](./Implementing-a-game-rule-system.md). We will only sketch such a module here for our end-turn -combat resolution. -- An `attack` [command](./Commands.md) for initiating the combat mode. This is added to the default -command set. It will create the combat handler and add the character(s) to it. It will also assign -the combat command set to the characters. - -## The combat handler - -The _combat handler_ is implemented as a stand-alone [Script](./Scripts.md). This Script is created when -the first Character decides to attack another and is deleted when no one is fighting any more. Each -handler represents one instance of combat and one combat only. Each instance of combat can hold any -number of characters but each character can only be part of one combat at a time (a player would -need to disengage from the first combat before they could join another). - -The reason we don't store this Script "on" any specific character is because any character may leave -the combat at any time. Instead the script holds references to all characters involved in the -combat. Vice-versa, all characters holds a back-reference to the current combat handler. While we -don't use this very much here this might allow the combat commands on the characters to access and -update the combat handler state directly. - -_Note: Another way to implement a combat handler would be to use a normal Python object and handle -time-keeping with the [TickerHandler](./TickerHandler.md). This would require either adding custom hook -methods on the character or to implement a custom child of the TickerHandler class to track turns. -Whereas the TickerHandler is easy to use, a Script offers more power in this case._ - -Here is a basic combat handler. Assuming our game folder is named `mygame`, we store it in -`mygame/typeclasses/combat_handler.py`: - -```python -# mygame/typeclasses/combat_handler.py - -import random -from evennia import DefaultScript -from world.rules import resolve_combat - -class CombatHandler(DefaultScript): - """ - This implements the combat handler. - """ - - # standard Script hooks - - def at_script_creation(self): - "Called when script is first created" - - self.key = "combat_handler_%i" % random.randint(1, 1000) - self.desc = "handles combat" - self.interval = 60 * 2 # two minute timeout - self.start_delay = True - self.persistent = True - - # store all combatants - self.db.characters = {} - # store all actions for each turn - self.db.turn_actions = {} - # number of actions entered per combatant - self.db.action_count = {} - - def _init_character(self, character): - """ - This initializes handler back-reference - and combat cmdset on a character - """ - character.ndb.combat_handler = self - character.cmdset.add("commands.combat.CombatCmdSet") - - def _cleanup_character(self, character): - """ - Remove character from handler and clean - it of the back-reference and cmdset - """ - dbref = character.id - del self.db.characters[dbref] - del self.db.turn_actions[dbref] - del self.db.action_count[dbref] - del character.ndb.combat_handler - character.cmdset.delete("commands.combat.CombatCmdSet") - - def at_start(self): - """ - This is called on first start but also when the script is restarted - after a server reboot. We need to re-assign this combat handler to - all characters as well as re-assign the cmdset. - """ - for character in self.db.characters.values(): - self._init_character(character) - - def at_stop(self): - "Called just before the script is stopped/destroyed." - for character in list(self.db.characters.values()): - # note: the list() call above disconnects list from database - self._cleanup_character(character) - - def at_repeat(self): - """ - This is called every self.interval seconds (turn timeout) or - when force_repeat is called (because everyone has entered their - commands). We know this by checking the existence of the - `normal_turn_end` NAttribute, set just before calling - force_repeat. - - """ - if self.ndb.normal_turn_end: - # we get here because the turn ended normally - # (force_repeat was called) - no msg output - del self.ndb.normal_turn_end - else: - # turn timeout - self.msg_all("Turn timer timed out. Continuing.") - self.end_turn() - - # Combat-handler methods - - def add_character(self, character): - "Add combatant to handler" - dbref = character.id - self.db.characters[dbref] = character - self.db.action_count[dbref] = 0 - self.db.turn_actions[dbref] = [("defend", character, None), - ("defend", character, None)] - # set up back-reference - self._init_character(character) - - def remove_character(self, character): - "Remove combatant from handler" - if character.id in self.db.characters: - self._cleanup_character(character) - if not self.db.characters: - # if no more characters in battle, kill this handler - self.stop() - - def msg_all(self, message): - "Send message to all combatants" - for character in self.db.characters.values(): - character.msg(message) - - def add_action(self, action, character, target): - """ - Called by combat commands to register an action with the handler. - - action - string identifying the action, like "hit" or "parry" - character - the character performing the action - target - the target character or None - - actions are stored in a dictionary keyed to each character, each - of which holds a list of max 2 actions. An action is stored as - a tuple (character, action, target). - """ - dbref = character.id - count = self.db.action_count[dbref] - if 0 <= count <= 1: # only allow 2 actions - self.db.turn_actions[dbref][count] = (action, character, target) - else: - # report if we already used too many actions - return False - self.db.action_count[dbref] += 1 - return True - - def check_end_turn(self): - """ - Called by the command to eventually trigger - the resolution of the turn. We check if everyone - has added all their actions; if so we call force the - script to repeat immediately (which will call - `self.at_repeat()` while resetting all timers). - """ - if all(count > 1 for count in self.db.action_count.values()): - self.ndb.normal_turn_end = True - self.force_repeat() - - def end_turn(self): - """ - This resolves all actions by calling the rules module. - It then resets everything and starts the next turn. It - is called by at_repeat(). - """ - resolve_combat(self, self.db.turn_actions) - - if len(self.db.characters) < 2: - # less than 2 characters in battle, kill this handler - self.msg_all("Combat has ended") - self.stop() - else: - # reset counters before next turn - for character in self.db.characters.values(): - self.db.characters[character.id] = character - self.db.action_count[character.id] = 0 - self.db.turn_actions[character.id] = [("defend", character, None), - ("defend", character, None)] - self.msg_all("Next turn begins ...") -``` - -This implements all the useful properties of our combat handler. This Script will survive a reboot -and will automatically re-assert itself when it comes back online. Even the current state of the -combat should be unaffected since it is saved in Attributes at every turn. An important part to note -is the use of the Script's standard `at_repeat` hook and the `force_repeat` method to end each turn. -This allows for everything to go through the same mechanisms with minimal repetition of code. - -What is not present in this handler is a way for players to view the actions they set or to change -their actions once they have been added (but before the last one has added theirs). We leave this as -an exercise. - -## Combat commands - -Our combat commands - the commands that are to be available to us during the combat - are (in our -example) very simple. In a full implementation the commands available might be determined by the -weapon(s) held by the player or by which skills they know. - -We create them in `mygame/commands/combat.py`. - -```python -# mygame/commands/combat.py - -from evennia import Command - -class CmdHit(Command): - """ - hit an enemy - - Usage: - hit - - Strikes the given enemy with your current weapon. - """ - key = "hit" - aliases = ["strike", "slash"] - help_category = "combat" - - def func(self): - "Implements the command" - if not self.args: - self.caller.msg("Usage: hit ") - return - target = self.caller.search(self.args) - if not target: - return - ok = self.caller.ndb.combat_handler.add_action("hit", - self.caller, - target) - if ok: - self.caller.msg("You add 'hit' to the combat queue") - else: - self.caller.msg("You can only queue two actions per turn!") - - # tell the handler to check if turn is over - self.caller.ndb.combat_handler.check_end_turn() -``` - -The other commands `CmdParry`, `CmdFeint`, `CmdDefend` and `CmdDisengage` look basically the same. -We should also add a custom `help` command to list all the available combat commands and what they -do. - -We just need to put them all in a cmdset. We do this at the end of the same module: - -```python -# mygame/commands/combat.py - -from evennia import CmdSet -from evennia import default_cmds - -class CombatCmdSet(CmdSet): - key = "combat_cmdset" - mergetype = "Replace" - priority = 10 - no_exits = True - - def at_cmdset_creation(self): - self.add(CmdHit()) - self.add(CmdParry()) - self.add(CmdFeint()) - self.add(CmdDefend()) - self.add(CmdDisengage()) - self.add(CmdHelp()) - self.add(default_cmds.CmdPose()) - self.add(default_cmds.CmdSay()) -``` - -## Rules module - -A general way to implement a rule module is found in the [rule system tutorial](./Implementing-a-game-rule-system.md). Proper resolution would likely require us to change our Characters to store things -like strength, weapon skills and so on. So for this example we will settle for a very simplistic -rock-paper-scissors kind of setup with some randomness thrown in. We will not deal with damage here -but just announce the results of each turn. In a real system the Character objects would hold stats -to affect their skills, their chosen weapon affect the choices, they would be able to lose health -etc. - -Within each turn, there are "sub-turns", each consisting of one action per character. The actions -within each sub-turn happens simultaneously and only once they have all been resolved we move on to -the next sub-turn (or end the full turn). - -*Note: In our simple example the sub-turns don't affect each other (except for `disengage/flee`), -nor do any effects carry over between turns. The real power of a turn-based system would be to add -real tactical possibilities here though; For example if your hit got parried you could be out of -balance and your next action would be at a disadvantage. A successful feint would open up for a -subsequent attack and so on ...* - -Our rock-paper-scissor setup works like this: - -- `hit` beats `feint` and `flee/disengage`. It has a random chance to fail against `defend`. -- `parry` beats `hit`. -- `feint` beats `parry` and is then counted as a `hit`. -- `defend` does nothing but has a chance to beat `hit`. -- `flee/disengage` must succeed two times in a row (i.e. not beaten by a `hit` once during the -turn). If so the character leaves combat. - - -```python -# mygame/world/rules.py - -import random - -# messages - -def resolve_combat(combat_handler, actiondict): - """ - This is called by the combat handler - actiondict is a dictionary with a list of two actions - for each character: - {char.id:[(action1, char, target), (action2, char, target)], ...} - """ - flee = {} # track number of flee commands per character - for isub in range(2): - # loop over sub-turns - messages = [] - for subturn in (sub[isub] for sub in actiondict.values()): - # for each character, resolve the sub-turn - action, char, target = subturn - if target: - taction, tchar, ttarget = actiondict[target.id][isub] - if action == "hit": - if taction == "parry" and ttarget == char: - msg = "%s tries to hit %s, but %s parries the attack!" - messages.append(msg % (char, tchar, tchar)) - elif taction == "defend" and random.random() < 0.5: - msg = "%s defends against the attack by %s." - messages.append(msg % (tchar, char)) - elif taction == "flee": - msg = "%s stops %s from disengaging, with a hit!" - flee[tchar] = -2 - messages.append(msg % (char, tchar)) - else: - msg = "%s hits %s, bypassing their %s!" - messages.append(msg % (char, tchar, taction)) - elif action == "parry": - if taction == "hit": - msg = "%s parries the attack by %s." - messages.append(msg % (char, tchar)) - elif taction == "feint": - msg = "%s tries to parry, but %s feints and hits!" - messages.append(msg % (char, tchar)) - else: - msg = "%s parries to no avail." - messages.append(msg % char) - elif action == "feint": - if taction == "parry": - msg = "%s feints past %s's parry, landing a hit!" - messages.append(msg % (char, tchar)) - elif taction == "hit": - msg = "%s feints but is defeated by %s hit!" - messages.append(msg % (char, tchar)) - else: - msg = "%s feints to no avail." - messages.append(msg % char) - elif action == "defend": - msg = "%s defends." - messages.append(msg % char) - elif action == "flee": - if char in flee: - flee[char] += 1 - else: - flee[char] = 1 - msg = "%s tries to disengage (two subsequent turns needed)" - messages.append(msg % char) - - # echo results of each subturn - combat_handler.msg_all("\n".join(messages)) - - # at the end of both sub-turns, test if anyone fled - msg = "%s withdraws from combat." - for (char, fleevalue) in flee.items(): - if fleevalue == 2: - combat_handler.msg_all(msg % char) - combat_handler.remove_character(char) -``` - -To make it simple (and to save space), this example rule module actually resolves each interchange -twice - first when it gets to each character and then again when handling the target. Also, since we -use the combat handler's `msg_all` method here, the system will get pretty spammy. To clean it up, -one could imagine tracking all the possible interactions to make sure each pair is only handled and -reported once. - -## Combat initiator command - -This is the last component we need, a command to initiate combat. This will tie everything together. -We store this with the other combat commands. - -```python -# mygame/commands/combat.py - -from evennia import create_script - -class CmdAttack(Command): - """ - initiates combat - - Usage: - attack - - This will initiate combat with . If ") - return - target = self.caller.search(self.args) - if not target: - return - # set up combat - if target.ndb.combat_handler: - # target is already in combat - join it - target.ndb.combat_handler.add_character(self.caller) - target.ndb.combat_handler.msg_all("%s joins combat!" % self.caller) - else: - # create a new combat handler - chandler = create_script("combat_handler.CombatHandler") - chandler.add_character(self.caller) - chandler.add_character(target) - self.caller.msg("You attack %s! You are in combat." % target) - target.msg("%s attacks you! You are in combat." % self.caller) -``` - -The `attack` command will not go into the combat cmdset but rather into the default cmdset. See e.g. -the [Adding Command Tutorial](./Adding-Command-Tutorial.md) if you are unsure about how to do this. - -## Expanding the example - -At this point you should have a simple but flexible turn-based combat system. We have taken several -shortcuts and simplifications in this example. The output to the players is likely too verbose -during combat and too limited when it comes to informing about things surrounding it. Methods for -changing your commands or list them, view who is in combat etc is likely needed - this will require -play testing for each game and style. There is also currently no information displayed for other -people happening to be in the same room as the combat - some less detailed information should -probably be echoed to the room to -show others what's going on. diff --git a/docs/0.9.5/_sources/Tutorial-Aggressive-NPCs.md.txt b/docs/0.9.5/_sources/Tutorial-Aggressive-NPCs.md.txt deleted file mode 100644 index 9af3bfcf92..0000000000 --- a/docs/0.9.5/_sources/Tutorial-Aggressive-NPCs.md.txt +++ /dev/null @@ -1,127 +0,0 @@ -# Tutorial Aggressive NPCs - - -This tutorial shows the implementation of an NPC object that responds to characters entering their -location. In this example the NPC has the option to respond aggressively or not, but any actions -could be triggered this way. - -One could imagine using a [Script](./Scripts.md) that is constantly checking for newcomers. This would be -highly inefficient (most of the time its check would fail). Instead we handle this on-demand by -using a couple of existing object hooks to inform the NPC that a Character has entered. - -It is assumed that you already know how to create custom room and character typeclasses, please see -the [Basic Game tutorial](./Tutorial-for-basic-MUSH-like-game.md) if you haven't already done this. - -What we will need is the following: - -- An NPC typeclass that can react when someone enters. -- A custom [Room](./Objects.md#rooms) typeclass that can tell the NPC that someone entered. -- We will also tweak our default `Character` typeclass a little. - -To begin with, we need to create an NPC typeclass. Create a new file inside of your typeclasses -folder and name it `npcs.py` and then add the following code: - -```python -from typeclasses.characters import Character - -class NPC(Character): - """ - A NPC typeclass which extends the character class. - """ - def at_char_entered(self, character): - """ - A simple is_aggressive check. - Can be expanded upon later. - """ - if self.db.is_aggressive: - self.execute_cmd(f"say Graaah, die {character}!") - else: - self.execute_cmd(f"say Greetings, {character}!") -``` - -We will define our custom `Character` typeclass below. As for the new `at_char_entered` method we've -just defined, we'll ensure that it will be called by the room where the NPC is located, when a -player enters that room. You'll notice that right now, the NPC merely speaks. You can expand this -part as you like and trigger all sorts of effects here (like combat code, fleeing, bartering or -quest-giving) as your game design dictates. - -Now your `typeclasses.rooms` module needs to have the following added: - -```python -# Add this import to the top of your file. -from evennia import utils - - # Add this hook in any empty area within your Room class. - def at_object_receive(self, obj, source_location): - if utils.inherits_from(obj, 'typeclasses.npcs.NPC'): # An NPC has entered - return - elif utils.inherits_from(obj, 'typeclasses.characters.Character'): - # A PC has entered. - # Cause the player's character to look around. - obj.execute_cmd('look') - for item in self.contents: - if utils.inherits_from(item, 'typeclasses.npcs.NPC'): - # An NPC is in the room - item.at_char_entered(obj) -``` - -`inherits_from` must be given the full path of the class. If the object inherited a class from your -`world.races` module, then you would check inheritance with `world.races.Human`, for example. There -is no need to import these prior, as we are passing in the full path. As a matter of a fact, -`inherits_from` does not properly work if you import the class and only pass in the name of the -class. - -> Note: -[at_object_receive](https://github.com/evennia/evennia/blob/master/evennia/objects/objects.py#L1529) -is a default hook of the `DefaultObject` typeclass (and its children). Here we are overriding this -hook in our customized room typeclass to suit our needs. - -This room checks the typeclass of objects entering it (using `utils.inherits_from` and responds to -`Characters`, ignoring other NPCs or objects. When triggered the room will look through its -contents and inform any `NPCs inside by calling their `at_char_entered` method. - -You'll also see that we have added a 'look' into this code. This is because, by default, the -`at_object_receive` is carried out *before* the character's `at_after_move` which, we will now -overload. This means that a character entering would see the NPC perform its actions before the -'look' command. Deactivate the look command in the default `Character` class within the -`typeclasses.characters` module: - -```python - # Add this hook in any blank area within your Character class. - def at_after_move(self, source_location): - """ - Default is to look around after a move - Note: This has been moved to Room.at_object_receive - """ - #self.execute_cmd('look') - pass -``` - -Now let's create an NPC and make it aggressive. Type the following commands into your MUD client: -``` -reload -create/drop Orc:npcs.NPC -``` - -> Note: You could also give the path as `typeclasses.npcs.NPC`, but Evennia will look into the -`typeclasses` folder automatically, so this is a little shorter. - -When you enter the aggressive NPC's location, it will default to using its peaceful action (say your -name is Anna): - -``` -Orc says, "Greetings, Anna!" -``` - -Now we turn on the aggressive mode (we do it manually but it could also be triggered by some sort of -AI code). - -``` -set orc/is_aggressive = True -``` - -Now it will perform its aggressive action whenever a character enters. - -``` -Orc says, "Graaah, die, Anna!" -``` diff --git a/docs/0.9.5/_sources/Tutorial-NPCs-listening.md.txt b/docs/0.9.5/_sources/Tutorial-NPCs-listening.md.txt deleted file mode 100644 index 77238e705d..0000000000 --- a/docs/0.9.5/_sources/Tutorial-NPCs-listening.md.txt +++ /dev/null @@ -1,112 +0,0 @@ -# Tutorial NPCs listening - - -This tutorial shows the implementation of an NPC object that responds to characters speaking in -their location. In this example the NPC parrots what is said, but any actions could be triggered -this way. - -It is assumed that you already know how to create custom room and character typeclasses, please see -the [Basic Game tutorial](./Tutorial-for-basic-MUSH-like-game.md) if you haven't already done this. - -What we will need is simply a new NPC typeclass that can react when someone speaks. - -```python -# mygame/typeclasses/npc.py - -from characters import Character -class Npc(Character): - """ - A NPC typeclass which extends the character class. - """ - def at_heard_say(self, message, from_obj): - """ - A simple listener and response. This makes it easy to change for - subclasses of NPCs reacting differently to says. - - """ - # message will be on the form ` says, "say_text"` - # we want to get only say_text without the quotes and any spaces - message = message.split('says, ')[1].strip(' "') - - # we'll make use of this in .msg() below - return "%s said: '%s'" % (from_obj, message) -``` - -When someone in the room speaks to this NPC, its `msg` method will be called. We will modify the -NPCs `.msg` method to catch says so the NPC can respond. - - -```python -# mygame/typeclasses/npc.py - -from characters import Character -class Npc(Character): - - # [at_heard_say() goes here] - - def msg(self, text=None, from_obj=None, **kwargs): - "Custom msg() method reacting to say." - - if from_obj != self: - # make sure to not repeat what we ourselves said or we'll create a loop - try: - # if text comes from a say, `text` is `('say_text', {'type': 'say'})` - say_text, is_say = text[0], text[1]['type'] == 'say' - except Exception: - is_say = False - if is_say: - # First get the response (if any) - response = self.at_heard_say(say_text, from_obj) - # If there is a response - if response != None: - # speak ourselves, using the return - self.execute_cmd("say %s" % response) - - # this is needed if anyone ever puppets this NPC - without it you would never - # get any feedback from the server (not even the results of look) - super().msg(text=text, from_obj=from_obj, **kwargs) -``` - -So if the NPC gets a say and that say is not coming from the NPC itself, it will echo it using the -`at_heard_say` hook. Some things of note in the above example: - -- The `text` input can be on many different forms depending on where this `msg` is called from. -Instead of trying to analyze `text` in detail with a range of `if` statements we just assume the -form we want and catch the error if it does not match. This simplifies the code considerably. It's -called 'leap before you look' and is a Python paradigm that may feel unfamiliar if you are used to -other languages. Here we 'swallow' the error silently, which is fine when the code checked is -simple. If not we may want to import `evennia.logger.log_trace` and add `log_trace()` in the -`except` clause.
-If you would like to learn more about the `text` list used above refer to the [Out-Of-Band](./OOB.md) -documentation. -- We use `execute_cmd` to fire the `say` command back. We could also have called -`self.location.msg_contents` directly but using the Command makes sure all hooks are called (so -those seeing the NPC's `say` can in turn react if they want). -- Note the comments about `super` at the end. This will trigger the 'default' `msg` (in the parent -class) as well. It's not really necessary as long as no one puppets the NPC (by `@ic `) but -it's wise to keep in there since the puppeting player will be totally blind if `msg()` is never -returning anything to them! - -Now that's done, let's create an NPC and see what it has to say for itself. - -``` -@reload -@create/drop Guild Master:npc.Npc -``` - -(you could also give the path as `typeclasses.npc.Npc`, but Evennia will look into the `typeclasses` -folder automatically so this is a little shorter). - - > say hi - You say, "hi" - Guild Master says, "Anna said: 'hi'" - -## Assorted notes - -There are many ways to implement this kind of functionality. An alternative example to overriding -`msg` would be to modify the `at_say` hook on the *Character* instead. It could detect that it's -sending to an NPC and call the `at_heard_say` hook directly. - -While the tutorial solution has the advantage of being contained only within the NPC class, -combining this with using the Character class gives more direct control over how the NPC will react. -Which way to go depends on the design requirements of your particular game. diff --git a/docs/0.9.5/_sources/Tutorial-Searching-For-Objects.md.txt b/docs/0.9.5/_sources/Tutorial-Searching-For-Objects.md.txt deleted file mode 100644 index 3bf7076ed5..0000000000 --- a/docs/0.9.5/_sources/Tutorial-Searching-For-Objects.md.txt +++ /dev/null @@ -1,430 +0,0 @@ -# Tutorial Searching For Objects - - -You will often want to operate on a specific object in the database. For example when a player -attacks a named target you'll need to find that target so it can be attacked. Or when a rain storm -draws in you need to find all outdoor-rooms so you can show it raining in them. This tutorial -explains Evennia's tools for searching. - -## Things to search for - -The first thing to consider is the base type of the thing you are searching for. Evennia organizes -its database into a few main tables: [Objects](./Objects.md), [Accounts](./Accounts.md), [Scripts](./Scripts.md), -[Channels](./Communications.md#channels), [Messages](./Communications.md#msg) and [Help Entries](./Help-System.md). -Most of the time you'll likely spend your time searching for Objects and the occasional Accounts. - -So to find an entity, what can be searched for? - - - The `key` is the name of the entity. While you can get this from `obj.key` the *database field* -is actually named `obj.db_key` - this is useful to know only when you do [direct database -queries](./Tutorial-Searching-For-Objects.md#queries-in-django). The one exception is `Accounts`, where -the database field for `.key` is instead named `username` (this is a Django requirement). When you -don't specify search-type, you'll usually search based on key. *Aliases* are extra names given to -Objects using something like `@alias` or `obj.aliases.add('name')`. The main search functions (see -below) will automatically search for aliases whenever you search by-key. - - [Tags](./Tags.md) are the main way to group and identify objects in Evennia. Tags can most often be -used (sometimes together with keys) to uniquely identify an object. For example, even though you -have two locations with the same name, you can separate them by their tagging (this is how Evennia -implements 'zones' seen in other systems). Tags can also have categories, to further organize your -data for quick lookups. - - An object's [Attributes](./Attributes.md) can also used to find an object. This can be very useful but -since Attributes can store almost any data they are far less optimized to search for than Tags or -keys. -- The object's [Typeclass](./Typeclasses.md) indicate the sub-type of entity. A Character, Flower or -Sword are all types of Objects. A Bot is a kind of Account. The database field is called -`typeclass_path` and holds the full Python-path to the class. You can usually specify the -`typeclass` as an argument to Evennia's search functions as well as use the class directly to limit -queries. -- The `location` is only relevant for [Objects](./Objects.md) but is a very common way to weed down the -number of candidates before starting to search. The reason is that most in-game commands tend to -operate on things nearby (in the same room) so the choices can be limited from the start. -- The database id or the '#dbref' is unique (and never re-used) within each database table. So while -there is one and only one Object with dbref `#42` there could also be an Account or Script with the -dbref `#42` at the same time. In almost all search methods you can replace the "key" search -criterion with `"#dbref"` to search for that id. This can occasionally be practical and may be what -you are used to from other code bases. But it is considered *bad practice* in Evennia to rely on -hard-coded #dbrefs to do your searches. It makes your code tied to the exact layout of the database. -It's also not very maintainable to have to remember abstract numbers. Passing the actual objects -around and searching by Tags and/or keys will usually get you what you need. - - -## Getting objects inside another - -All in-game [Objects](./Objects.md) have a `.contents` property that returns all objects 'inside' them -(that is, all objects which has its `.location` property set to that object. This is a simple way to -get everything in a room and is also faster since this lookup is cached and won't hit the database. - -- `roomobj.contents` returns a list of all objects inside `roomobj`. -- `obj.contents` same as for a room, except this usually represents the object's inventory -- `obj.location.contents` gets everything in `obj`'s location (including `obj` itself). -- `roomobj.exits` returns all exits starting from `roomobj` (Exits are here defined as Objects with -their `destination` field set). -- `obj.location.contents_get(exclude=obj)` - this helper method returns all objects in `obj`'s -location except `obj`. - -## Searching using `Object.search` - -Say you have a [command](./Commands.md), and you want it to do something to a target. You might be -wondering how you retrieve that target in code, and that's where Evennia's search utilities come in. -In the most common case, you'll often use the `search` method of the `Object` or `Account` -typeclasses. In a command, the `.caller` property will refer back to the object using the command -(usually a `Character`, which is a type of `Object`) while `.args` will contain Command's arguments: - -```python -# e.g. in file mygame/commands/command.py - -from evennia import default_cmds - -class CmdPoke(Command): - """ - Pokes someone. - - Usage: poke - """ - key = "poke" - - def func(self): - """Executes poke command""" - target = self.caller.search(self.args.lstrip()) - if not target: - # we didn't find anyone, but search has already let the - # caller know. We'll just return, since we're done - return - # we found a target! we'll do stuff to them. - target.msg(f"{self.caller} pokes you.") - self.caller.msg(f"You poke {target}.") -``` -By default, the search method of a Character will attempt to find a unique object match for the -string sent to it (`self.args`, in this case, which is the arguments passed to the command by the -player) in the surroundings of the Character - the room or their inventory. If there is no match -found, the return value (which is assigned to `target`) will be `None`, and an appropriate failure -message will be sent to the Character. If there's not a unique match, `None` will again be returned, -and a different error message will be sent asking them to disambiguate the multi-match. By default, -the user can then pick out a specific match using with a number and dash preceding the name of the -object: `character.search("2-pink unicorn")` will try to find the second pink unicorn in the room. - -The search method has many [arguments](github:evennia.objects.objects#defaultcharactersearch) that -allow you to refine the search, such as by designating the location to search in or only matching -specific typeclasses. - -## Searching using `utils.search` - -Sometimes you will want to find something that isn't tied to the search methods of a character or -account. In these cases, Evennia provides a [utility module with a number of search -functions](github:evennia.utils.search). For example, suppose you want a command that will find and -display all the rooms that are tagged as a 'hangout', for people to gather by. Here's a simple -Command to do this: - -```python -# e.g. in file mygame/commands/command.py - -from evennia import default_cmds -from evennia.utils.search import search_tag - -class CmdListHangouts(default_cmds.MuxCommand): - """Lists hangouts""" - key = "hangouts" - - def func(self): - """Executes 'hangouts' command""" - hangouts = search_tag(key="hangout", category="location tags") - self.caller.msg(f"Hangouts available: {', '.join(str(ob) for ob in hangouts)}") -``` - -This uses the `search_tag` function to find all objects previously tagged with [Tags](./Tags.md) -"hangout" and with category "location tags". - -Other important search methods in `utils.search` are - -- `search_object` -- `search_account` -- `search_scripts` -- `search_channel` -- `search_message` -- `search_help` -- `search_tag` - find Objects with a given Tag. [See also here for how to search by -tag](./Tags.md#searching-for-objects-with-a-given-tag). -- `search_account_tag` - find Accounts with a given Tag. -- `search_script_tag` - find Scripts with a given Tag. -- `search_channel_tag` - find Channels with a given Tag. -- `search_object_attribute` - find Objects with a given Attribute. -- `search_account_attribute` - find Accounts with a given Attribute. -- `search_attribute_object` - this returns the actual Attribute, not the object it sits on. - -> Note: All search functions return a Django `queryset` which is technically a list-like -representation of the database-query it's about to do. Only when you convert it to a real list, loop -over it or try to slice or access any of its contents will the datbase-lookup happen. This means you -could yourself customize the query further if you know what you are doing (see the next section). - -## Queries in Django - -*This is an advanced topic.* - -Evennia's search methods should be sufficient for the vast majority of situations. But eventually -you might find yourself trying to figure out how to get searches for unusual circumstances: Maybe -you want to find all characters who are *not* in rooms tagged as hangouts *and* have the lycanthrope -tag *and* whose names start with a vowel, but *not* with 'Ab', and *only if* they have 3 or more -objects in their inventory ... You could in principle use one of the earlier search methods to find -all candidates and then loop over them with a lot of if statements in raw Python. But you can do -this much more efficiently by querying the database directly. - -Enter [django's querysets](https://docs.djangoproject.com/en/1.11/ref/models/querysets/). A QuerySet -is the representation of a database query and can be modified as desired. Only once one tries to -retrieve the data of that query is it *evaluated* and does an actual database request. This is -useful because it means you can modify a query as much as you want (even pass it around) and only -hit the database once you are happy with it. -Evennia's search functions are themselves an even higher level wrapper around Django's queries, and -many search methods return querysets. That means that you could get the result from a search -function and modify the resulting query to your own ends to further tweak what you search for. - -Evaluated querysets can either contain objects such as Character objects, or lists of values derived -from the objects. Queries usually use the 'manager' object of a class, which by convention is the -`.objects` attribute of a class. For example, a query of Accounts that contain the letter 'a' could -be: - -```python - from typeclasses.accounts import Account - -queryset = Account.objects.filter(username__contains='a') - -``` - -The `filter` method of a manager takes arguments that allow you to define the query, and you can -continue to refine the query by calling additional methods until you evaluate the queryset, causing -the query to be executed and return a result. For example, if you have the result above, you could, -without causing the queryset to be evaluated yet, get rid of matches that contain the letter 'e by -doing this: - -```python -queryset = result.exclude(username__contains='e') - -``` - -> You could also have chained `.exclude` directly to the end of the previous line. - -Once you try to access the result, the queryset will be evaluated automatically under the hood: - -```python -accounts = list(queryset) # this fills list with matches - -for account in queryset: - # do something with account - -accounts = queryset[:4] # get first four matches -account = queryset[0] # get first match -# etc - -``` - -### Limiting by typeclass - -Although `Character`s, `Exit`s, `Room`s, and other children of `DefaultObject` all shares the same -underlying database table, Evennia provides a shortcut to do more specific queries only for those -typeclasses. For example, to find only `Character`s whose names start with 'A', you might do: - -```python -Character.objects.filter(db_key__startswith="A") - -``` - -If Character has a subclass `Npc` and you wanted to find only Npc's you'd instead do - -```python -Npc.objects.filter(db_key__startswith="A") - -``` - -If you wanted to search both Characters and all its subclasses (like Npc) you use the `*_family` -method which is added by Evennia: - - -```python -Character.objects.filter_family(db_key__startswith="A") -``` - -The higher up in the inheritance hierarchy you go the more objects will be included in these -searches. There is one special case, if you really want to include *everything* from a given -database table. You do that by searching on the database model itself. These are named `ObjectDB`, -`AccountDB`, `ScriptDB` etc. - -```python -from evennia import AccountDB - -# all Accounts in the database, regardless of typeclass -all = AccountDB.objects.all() - -``` - -Here are the most commonly used methods to use with the `objects` managers: - -- `filter` - query for a listing of objects based on search criteria. Gives empty queryset if none -were found. -- `get` - query for a single match - raises exception if none were found, or more than one was -found. -- `all` - get all instances of the particular type. -- `filter_family` - like `filter`, but search all sub classes as well. -- `get_family` - like `get`, but search all sub classes as well. -- `all_family` - like `all`, but return entities of all subclasses as well. - -## Multiple conditions - -If you pass more than one keyword argument to a query method, the query becomes an `AND` -relationship. For example, if we want to find characters whose names start with "A" *and* are also -werewolves (have the `lycanthrope` tag), we might do: - -```python -queryset = Character.objects.filter(db_key__startswith="A", db_tags__db_key="lycanthrope") -``` - -To exclude lycanthropes currently in rooms tagged as hangouts, we might tack on an `.exclude` as -before: - -```python -queryset = quersyet.exclude(db_location__db_tags__db_key="hangout") -``` - -Note the syntax of the keywords in building the queryset. For example, `db_location` is the name of -the database field sitting on (in this case) the `Character` (Object). Double underscore `__` works -like dot-notation in normal Python (it's used since dots are not allowed in keyword names). So the -instruction `db_location__db_tags__db_key="hangout"` should be read as such: - -1. "On the `Character` object ... (this comes from us building this queryset using the -`Character.objects` manager) -2. ... get the value of the `db_location` field ... (this references a Room object, normally) -3. ... on that location, get the value of the `db_tags` field ... (this is a many-to-many field that -can be treated like an object for this purpose. It references all tags on the location) -4. ... through the `db_tag` manager, find all Tags having a field `db_key` set to the value -"hangout"." - -This may seem a little complex at first, but this syntax will work the same for all queries. Just -remember that all *database-fields* in Evennia are prefaced with `db_`. So even though Evennia is -nice enough to alias the `db_key` field so you can normally just do `char.key` to get a character's -name, the database field is actually called `db_key` and the real name must be used for the purpose -of building a query. - -> Don't confuse database fields with [Attributes](./Attributes.md) you set via `obj.db.attr = 'foo'` or -`obj.attributes.add()`. Attributes are custom database entities *linked* to an object. They are not -separate fields *on* that object like `db_key` or `db_location` are. You can get attached Attributes -manually through the `db_attributes` many-to-many field in the same way as `db_tags` above. - -### Complex queries - -What if you want to have a query with with `OR` conditions or negated requirements (`NOT`)? Enter -Django's Complex Query object, -[Q](https://docs.djangoproject.com/en/1.11/topics/db/queries/#complex-lookups-with-q-objects). `Q()` -objects take a normal django keyword query as its arguments. The special thing is that these Q -objects can then be chained together with set operations: `|` for OR, `&` for AND, and preceded with -`~` for NOT to build a combined, complex query. - -In our original Lycanthrope example we wanted our werewolves to have names that could start with any -vowel except for the specific beginning "ab". - -```python -from django.db.models import Q -from typeclasses.characters import Character - -query = Q() -for letter in ("aeiouy"): - query |= Q(db_key__istartswith=letter) -query &= ~Q(db_key__istartswith="ab") -query = Character.objects.filter(query) - -list_of_lycanthropes = list(query) -``` - -In the above example, we construct our query our of several Q objects that each represent one part -of the query. We iterate over the list of vowels, and add an `OR` condition to the query using `|=` -(this is the same idea as using `+=` which may be more familiar). Each `OR` condition checks that -the name starts with one of the valid vowels. Afterwards, we add (using `&=`) an `AND` condition -that is negated with the `~` symbol. In other words we require that any match should *not* start -with the string "ab". Note that we don't actually hit the database until we convert the query to a -list at the end (we didn't need to do that either, but could just have kept the query until we -needed to do something with the matches). - -### Annotations and `F` objects - -What if we wanted to filter on some condition that isn't represented easily by a field on the -object? Maybe we want to find rooms only containing five or more objects? - -We *could* retrieve all interesting candidates and run them through a for-loop to get and count -their `.content` properties. We'd then just return a list of only those objects with enough -contents. It would look something like this (note: don't actually do this!): - -```python -# probably not a good idea to do it this way - -from typeclasses.rooms import Room - -queryset = Room.objects.all() # get all Rooms -rooms = [room for room in queryset if len(room.contents) >= 5] - -``` - -Once the number of rooms in your game increases, this could become quite expensive. Additionally, in -some particular contexts, like when using the web features of Evennia, you must have the result as a -queryset in order to use it in operations, such as in Django's admin interface when creating list -filters. - -Enter [F objects](https://docs.djangoproject.com/en/1.11/ref/models/expressions/#f-expressions) and -*annotations*. So-called F expressions allow you to do a query that looks at a value of each object -in the database, while annotations allow you to calculate and attach a value to a query. So, let's -do the same example as before directly in the database: - -```python -from typeclasses.rooms import Room -from django.db.models import Count - -room_count = Room.objects.annotate(num_objects=Count('locations_set')) -queryset = room_count.filter(num_objects__gte=5) - -rooms = (Room.objects.annotate(num_objects=Count('locations_set')) - .filter(num_objects__gte=5)) - -rooms = list(rooms) - -``` -Here we first create an annotation `num_objects` of type `Count`, which is a Django class. Note that -use of `location_set` in that `Count`. The `*_set` is a back-reference automatically created by -Django. In this case it allows you to find all objects that *has the current object as location*. -Once we have those, they are counted. -Next we filter on this annotation, using the name `num_objects` as something we can filter for. We -use `num_objects__gte=5` which means that `num_objects` should be greater than 5. This is a little -harder to get one's head around but much more efficient than lopping over all objects in Python. - -What if we wanted to compare two parameters against one another in a query? For example, what if -instead of having 5 or more objects, we only wanted objects that had a bigger inventory than they -had tags? Here an F-object comes in handy: - -```python -from django.db.models import Count, F -from typeclasses.rooms import Room - -result = (Room.objects.annotate(num_objects=Count('locations_set'), - num_tags=Count('db_tags')) - .filter(num_objects__gt=F('num_tags'))) -``` - -F-objects allows for wrapping an annotated structure on the right-hand-side of the expression. It -will be evaluated on-the-fly as needed. - -### Grouping By and Values - -Suppose you used tags to mark someone belonging an organization. Now you want to make a list and -need to get the membership count of every organization all at once. That's where annotations and the -`.values_list` queryset method come in. Values/Values Lists are an alternate way of returning a -queryset - instead of objects, you get a list of dicts or tuples that hold selected properties from -the the matches. It also allows you a way to 'group up' queries for returning information. For -example, to get a display about each tag per Character and the names of the tag: - -```python -result = (Character.objects.filter(db_tags__db_category="organization") - .values_list('db_tags__db_key') - .annotate(cnt=Count('id')) - .order_by('-cnt')) -``` -The result queryset will be a list of tuples ordered in descending order by the number of matches, -in a format like the following: -``` -[('Griatch Fanclub', 3872), ("Chainsol's Ainneve Testers", 2076), ("Blaufeuer's Whitespace Fixers", -1903), - ("Volund's Bikeshed Design Crew", 1764), ("Tehom's Misanthropes", 1)] diff --git a/docs/0.9.5/_sources/Tutorial-Tweeting-Game-Stats.md.txt b/docs/0.9.5/_sources/Tutorial-Tweeting-Game-Stats.md.txt deleted file mode 100644 index e17197af8c..0000000000 --- a/docs/0.9.5/_sources/Tutorial-Tweeting-Game-Stats.md.txt +++ /dev/null @@ -1,96 +0,0 @@ -# Tutorial Tweeting Game Stats - - -This tutorial will create a simple script that will send a tweet to your already configured twitter -account. Please see: [How to connect Evennia to Twitter](./How-to-connect-Evennia-to-Twitter.md) if you -haven't already done so. - -The script could be expanded to cover a variety of statistics you might wish to tweet about -regularly, from player deaths to how much currency is in the economy etc. - -```python -# evennia/typeclasses/tweet_stats.py - -import twitter -from random import randint -from django.conf import settings -from evennia import ObjectDB -from evennia import spawner -from evennia import logger -from evennia import DefaultScript - -class TweetStats(DefaultScript): - """ - This implements the tweeting of stats to a registered twitter account - """ - - # standard Script hooks - - def at_script_creation(self): - "Called when script is first created" - - self.key = "tweet_stats" - self.desc = "Tweets interesting stats about the game" - self.interval = 86400 # 1 day timeout - self.start_delay = False - - def at_repeat(self): - """ - This is called every self.interval seconds to tweet interesting stats about the game. - """ - - api = twitter.Api(consumer_key='consumer_key', - consumer_secret='consumer_secret', - access_token_key='access_token_key', - access_token_secret='access_token_secret') - - number_tweet_outputs = 2 - - tweet_output = randint(1, number_tweet_outputs) - - if tweet_output == 1: - ##Game Chars, Rooms, Objects taken from @stats command - nobjs = ObjectDB.objects.count() - base_char_typeclass = settings.BASE_CHARACTER_TYPECLASS - nchars = ObjectDB.objects.filter(db_typeclass_path=base_char_typeclass).count() - nrooms = ObjectDB.objects.filter(db_location__isnull=True).exclude(db_typeclass_path=bas -e_char_typeclass).count() - nexits = ObjectDB.objects.filter(db_location__isnull=False, -db_destination__isnull=False).count() - nother = nobjs - nchars - nrooms - nexits - tweet = "Chars: %s, Rooms: %s, Objects: %s" %(nchars, nrooms, nother) - else: - if tweet_output == 2: ##Number of prototypes and 3 random keys - taken from @spawn -command - prototypes = spawner.spawn(return_prototypes=True) - - keys = prototypes.keys() - nprots = len(prototypes) - tweet = "Prototype Count: %s Random Keys: " % nprots - - tweet += " %s" % keys[randint(0,len(keys)-1)] - for x in range(0,2): ##tweet 3 - tweet += ", %s" % keys[randint(0,len(keys)-1)] - # post the tweet - try: - response = api.PostUpdate(tweet) - except: - logger.log_trace("Tweet Error: When attempting to tweet %s" % tweet) -``` - -In the `at_script_creation` method, we configure the script to fire immediately (useful for testing) -and setup the delay (1 day) as well as script information seen when you use `@scripts` - -In the `at_repeat` method (which is called immediately and then at interval seconds later) we setup -the Twitter API (just like in the initial configuration of twitter). numberTweetOutputs is used to -show how many different types of outputs we have (in this case 2). We then build the tweet based on -randomly choosing between these outputs. - -1. Shows the number of Player Characters, Rooms and Other/Objects -2. Shows the number of prototypes currently in the game and then selects 3 random keys to show - -[Scripts Information](./Scripts.md) will show you how to add it as a Global script, however, for testing -it may be useful to start/stop it quickly from within the game. Assuming that you create the file -as `mygame/typeclasses/tweet_stats.py` it can be started by using the following command - - @script Here = tweet_stats.TweetStats diff --git a/docs/0.9.5/_sources/Tutorial-Vehicles.md.txt b/docs/0.9.5/_sources/Tutorial-Vehicles.md.txt deleted file mode 100644 index cd48177f67..0000000000 --- a/docs/0.9.5/_sources/Tutorial-Vehicles.md.txt +++ /dev/null @@ -1,422 +0,0 @@ -# Tutorial Vehicles - - -This tutorial explains how you can create vehicles that can move around in your world. The tutorial -will explain how to create a train, but this can be equally applied to create other kind of vehicles -(cars, planes, boats, spaceships, submarines, ...). - -## How it works - -Objects in Evennia have an interesting property: you can put any object inside another object. This -is most obvious in rooms: a room in Evennia is just like any other game object (except rooms tend to -not themselves be inside anything else). - -Our train will be similar: it will be an object that other objects can get inside. We then simply -move the Train, which brings along everyone inside it. - -## Creating our train object - -The first step we need to do is create our train object, including a new typeclass. To do this, -create a new file, for instance in `mygame/typeclasses/train.py` with the following content: - -```python -# file mygame/typeclasses/train.py - -from evennia import DefaultObject - -class TrainObject(DefaultObject): - - def at_object_creation(self): - # We'll add in code here later. - pass - -``` - -Now we can create our train in our game: - -``` -@create/drop train:train.TrainObject -``` - -Now this is just an object that doesn't do much yet... but we can already force our way inside it -and back (assuming we created it in limbo). - -``` -@tel train -@tel limbo -``` - -## Entering and leaving the train - -Using the `@tel`command like shown above is obviously not what we want. `@tel` is an admin command -and normal players will thus never be able to enter the train! It is also not really a good idea to -use [Exits](./Objects.md#exits) to get in and out of the train - Exits are (at least by default) objects -too. They point to a specific destination. If we put an Exit in this room leading inside the train -it would stay here when the train moved away (still leading into the train like a magic portal!). In -the same way, if we put an Exit object inside the train, it would always point back to this room, -regardless of where the Train has moved. Now, one *could* define custom Exit types that move with -the train or change their destination in the right way - but this seems to be a pretty cumbersome -solution. - -What we will do instead is to create some new [commands](./Commands.md): one for entering the train and -another for leaving it again. These will be stored *on the train object* and will thus be made -available to whomever is either inside it or in the same room as the train. - -Let's create a new command module as `mygame/commands/train.py`: - -```python -# mygame/commands/train.py - -from evennia import Command, CmdSet - -class CmdEnterTrain(Command): - """ - entering the train - - Usage: - enter train - - This will be available to players in the same location - as the train and allows them to embark. - """ - - key = "enter train" - locks = "cmd:all()" - - def func(self): - train = self.obj - self.caller.msg("You board the train.") - self.caller.move_to(train) - - -class CmdLeaveTrain(Command): - """ - leaving the train - - Usage: - leave train - - This will be available to everyone inside the - train. It allows them to exit to the train's - current location. - """ - - key = "leave train" - locks = "cmd:all()" - - def func(self): - train = self.obj - parent = train.location - self.caller.move_to(parent) - - -class CmdSetTrain(CmdSet): - - def at_cmdset_creation(self): - self.add(CmdEnterTrain()) - self.add(CmdLeaveTrain()) -``` -Note that while this seems like a lot of text, the majority of lines here are taken up by -documentation. - -These commands are work in a pretty straightforward way: `CmdEnterTrain` moves the location of the -player to inside the train and `CmdLeaveTrain` does the opposite: it moves the player back to the -current location of the train (back outside to its current location). We stacked them in a -[cmdset](./Command-Sets.md) `CmdSetTrain` so they can be used. - -To make the commands work we need to add this cmdset to our train typeclass: - -```python -# file mygame/typeclasses/train.py - -from evennia import DefaultObject -from commands.train import CmdSetTrain - -class TrainObject(DefaultObject): - - def at_object_creation(self): - self.cmdset.add_default(CmdSetTrain) - -``` - -If we now `@reload` our game and reset our train, those commands should work and we can now enter -and leave the train: - -``` -@reload -@typeclass/force/reset train = train.TrainObject -enter train -leave train -``` - -Note the switches used with the `@typeclass` command: The `/force` switch is necessary to assign our -object the same typeclass we already have. The `/reset` re-triggers the typeclass' -`at_object_creation()` hook (which is otherwise only called the very first an instance is created). -As seen above, when this hook is called on our train, our new cmdset will be loaded. - -## Locking down the commands - -If you have played around a bit, you've probably figured out that you can use `leave train` when -outside the train and `enter train` when inside. This doesn't make any sense ... so let's go ahead -and fix that. We need to tell Evennia that you can not enter the train when you're already inside -or leave the train when you're outside. One solution to this is [locks](./Locks.md): we will lock down -the commands so that they can only be called if the player is at the correct location. - -Right now commands defaults to the lock `cmd:all()`. The `cmd` lock type in combination with the -`all()` lock function means that everyone can run those commands as long as they are in the same -room as the train *or* inside the train. We're going to change this to check the location of the -player and *only* allow access if they are inside the train. - -First of all we need to create a new lock function. Evennia comes with many lock functions built-in -already, but none that we can use for locking a command in this particular case. Create a new entry -in `mygame/server/conf/lockfuncs.py`: - -```python - -# file mygame/server/conf/lockfuncs.py - -def cmdinside(accessing_obj, accessed_obj, *args, **kwargs): - """ - Usage: cmdinside() - Used to lock commands and only allows access if the command - is defined on an object which accessing_obj is inside of. - """ - return accessed_obj.obj == accessing_obj.location - -``` -If you didn't know, Evennia is by default set up to use all functions in this module as lock -functions (there is a setting variable that points to it). - -Our new lock function, `cmdinside`, is to be used by Commands. The `accessed_obj` is the Command -object (in our case this will be `CmdEnterTrain` and `CmdLeaveTrain`) — Every command has an `obj` -property: this is the the object on which the command "sits". Since we added those commands to our -train object, the `.obj` property will be set to the train object. Conversely, `accessing_obj` is -the object that called the command: in our case it's the Character trying to enter or leave the -train. - -What this function does is to check that the player's location is the same as the train object. If -it is, it means the player is inside the train. Otherwise it means the player is somewhere else and -the check will fail. - -The next step is to actually use this new lock function to create a lock of type `cmd`: - -```python -# file commands/train.py -... -class CmdEnterTrain(Command): - key = "enter train" - locks = "cmd:not cmdinside()" - # ... - -class CmdLeaveTrain(Command): - key = "leave train" - locks = "cmd:cmdinside()" - # ... -``` - -Notice how we use the `not` here so that we can use the same `cmdinside` to check if we are inside -and outside, without having to create two separate lock functions. After a `@reload` our commands -should be locked down appropriately and you should only be able to use them at the right places. - -> Note: If you're logged in as the super user (user `#1`) then this lock will not work: the super -user ignores lock functions. In order to use this functionality you need to `@quell` first. - -## Making our train move - -Now that we can enter and leave the train correctly, it's time to make it move. There are different -things we need to consider for this: - -* Who can control your vehicle? The first player to enter it, only players that have a certain -"drive" skill, automatically? -* Where should it go? Can the player steer the vehicle to go somewhere else or will it always follow -the same route? - -For our example train we're going to go with automatic movement through a predefined route (its -track). The train will stop for a bit at the start and end of the route to allow players to enter -and leave it. - -Go ahead and create some rooms for our train. Make a list of the room ids along the route (using the -`@ex` command). - -``` -@dig/tel South station -@ex # note the id of the station -@tunnel/tel n = Following a railroad -@ex # note the id of the track -@tunnel/tel n = Following a railroad -... -@tunnel/tel n = North Station -``` - -Put the train onto the tracks: - -``` -@tel south station -@tel train = here -``` - -Next we will tell the train how to move and which route to take. - -```python -# file typeclasses/train.py - -from evennia import DefaultObject, search_object - -from commands.train import CmdSetTrain - -class TrainObject(DefaultObject): - - def at_object_creation(self): - self.cmdset.add_default(CmdSetTrain) - self.db.driving = False - # The direction our train is driving (1 for forward, -1 for backwards) - self.db.direction = 1 - # The rooms our train will pass through (change to fit your game) - self.db.rooms = ["#2", "#47", "#50", "#53", "#56", "#59"] - - def start_driving(self): - self.db.driving = True - - def stop_driving(self): - self.db.driving = False - - def goto_next_room(self): - currentroom = self.location.dbref - idx = self.db.rooms.index(currentroom) + self.db.direction - - if idx < 0 or idx >= len(self.db.rooms): - # We reached the end of our path - self.stop_driving() - # Reverse the direction of the train - self.db.direction *= -1 - else: - roomref = self.db.rooms[idx] - room = search_object(roomref)[0] - self.move_to(room) - self.msg_contents("The train is moving forward to %s." % (room.name, )) -``` - -We added a lot of code here. Since we changed the `at_object_creation` to add in variables we will -have to reset our train object like earlier (using the `@typeclass/force/reset` command). - -We are keeping track of a few different things now: whether the train is moving or standing still, -which direction the train is heading to and what rooms the train will pass through. - -We also added some methods: one to start moving the train, another to stop and a third that actually -moves the train to the next room in the list. Or makes it stop driving if it reaches the last stop. - -Let's try it out, using `@py` to call the new train functionality: - -``` -@reload -@typeclass/force/reset train = train.TrainObject -enter train -@py here.goto_next_room() -``` - -You should see the train moving forward one step along the rail road. - -## Adding in scripts - -If we wanted full control of the train we could now just add a command to step it along the track -when desired. We want the train to move on its own though, without us having to force it by manually -calling the `goto_next_room` method. - -To do this we will create two [scripts](./Scripts.md): one script that runs when the train has stopped at -a station and is responsible for starting the train again after a while. The other script will take -care of the driving. - -Let's make a new file in `mygame/typeclasses/trainscript.py` - -```python -# file mygame/typeclasses/trainscript.py - -from evennia import DefaultScript - -class TrainStoppedScript(DefaultScript): - - def at_script_creation(self): - self.key = "trainstopped" - self.interval = 30 - self.persistent = True - self.repeats = 1 - self.start_delay = True - - def at_repeat(self): - self.obj.start_driving() - - def at_stop(self): - self.obj.scripts.add(TrainDrivingScript) - - -class TrainDrivingScript(DefaultScript): - - def at_script_creation(self): - self.key = "traindriving" - self.interval = 1 - self.persistent = True - - def is_valid(self): - return self.obj.db.driving - - def at_repeat(self): - if not self.obj.db.driving: - self.stop() - else: - self.obj.goto_next_room() - - def at_stop(self): - self.obj.scripts.add(TrainStoppedScript) -``` - -Those scripts work as a state system: when the train is stopped, it waits for 30 seconds and then -starts again. When the train is driving, it moves to the next room every second. The train is always -in one of those two states - both scripts take care of adding the other one once they are done. - -As a last step we need to link the stopped-state script to our train, reload the game and reset our -train again., and we're ready to ride it around! - -```python -# file typeclasses/train.py - -from typeclasses.trainscript import TrainStoppedScript - -class TrainObject(DefaultObject): - - def at_object_creation(self): - # ... - self.scripts.add(TrainStoppedScript) -``` - -``` -@reload -@typeclass/force/reset train = train.TrainObject -enter train - -# output: -< The train is moving forward to Following a railroad. -< The train is moving forward to Following a railroad. -< The train is moving forward to Following a railroad. -... -< The train is moving forward to Following a railroad. -< The train is moving forward to North station. - -leave train -``` - -Our train will stop 30 seconds at each end station and then turn around to go back to the other end. - -## Expanding - -This train is very basic and still has some flaws. Some more things to do: - -* Make it look like a train. -* Make it impossible to exit and enter the train mid-ride. This could be made by having the -enter/exit commands check so the train is not moving before allowing the caller to proceed. -* Have train conductor commands that can override the automatic start/stop. -* Allow for in-between stops between the start- and end station -* Have a rail road track instead of hard-coding the rooms in the train object. This could for -example be a custom [Exit](./Objects.md#exits) only traversable by trains. The train will follow the -track. Some track segments can split to lead to two different rooms and a player can switch the -direction to which room it goes. -* Create another kind of vehicle! diff --git a/docs/0.9.5/_sources/Tutorial-World-Introduction.md.txt b/docs/0.9.5/_sources/Tutorial-World-Introduction.md.txt deleted file mode 100644 index df295858b9..0000000000 --- a/docs/0.9.5/_sources/Tutorial-World-Introduction.md.txt +++ /dev/null @@ -1,109 +0,0 @@ -# Tutorial World Introduction - - -The *Tutorial World* is a small and functioning MUD-style game world. It is intended to be -deconstructed and used as a way to learn Evennia. The game consists of a single-player quest and -has some 20 rooms that you can explore as you seek to discover the whereabouts of a mythical weapon. - -The source code is fully documented. You can find the whole thing in -`evennia/contrib/tutorial_world/`. - -Some features exemplified by the tutorial world: - -- Tutorial command, giving "behind-the-scenes" help for every room and some of the special objects -- Rooms with custom `return_appearance` to show details. -- Hidden exits -- Objects with multiple custom interactions -- Large-area rooms -- Outdoor weather rooms -- Dark room, needing light source -- Puzzle object -- Multi-room puzzle -- Aggressive mobile with roam, pursue and battle state-engine AI -- Weapons, also used by mobs -- Simple combat system with attack/defend commands -- Object spawning -- Teleporter trap rooms - - -## Install - -The tutorial world consists of a few modules in `evennia/contrib/tutorial_world/` containing custom -[Typeclasses](./Typeclasses.md) for [rooms and objects](./Objects.md) and associated [Commands](./Commands.md). - -These reusable bits and pieces are then put together into a functioning game area ("world" is maybe -too big a word for such a small zone) using a [batch script](./Batch-Processors.md) called `build.ev`. To -install, log into the server as the superuser (user #1) and run: - - @batchcommand tutorial_world.build - -The world will be built (this might take a while, so don't rerun the command even if it seems the -system has frozen). After finishing you will end up back in Limbo with a new exit called `tutorial`. - -An alternative is - - @batchcommand/interactive tutorial_world.build - -with the /interactive switch you are able to step through the building process at your own pace to -see what happens in detail. - -## Quelling and permissions in the tutorial-world - -Non-superusers entering the tutorial will be auto-`quelled` so they play with their Character's -permission. As superuser you will not be auto-quelled, but it's recommended that you still `quell` -manually to play the tutorial "correctly". The reason for this is that many game systems ignore the -presence of a superuser and will thus not work as normal. - -Use `unquell` if you want to get back your main account-level permissions to examine things under -the hood. When you exit the tutorial (either by winning or using the `abort/give up` command) you -will automatically be unquelled. - -## Gameplay - -![the castle off the moor](https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/22916c25-6299-453d-a221-446ec839f567/da2pmzu-46d63c6d-9cdc-41dd-87d6-1106db5a5e1a.jpg/v1/fill/w_600,h_849,q_75,strp/the_castle_off_the_moor_by_griatch_art_da2pmzu-fullview.jpg?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOiIsImlzcyI6InVybjphcHA6Iiwib2JqIjpbW3siaGVpZ2h0IjoiPD04NDkiLCJwYXRoIjoiXC9mXC8yMjkxNmMyNS02Mjk5LTQ1M2QtYTIyMS00NDZlYzgzOWY1NjdcL2RhMnBtenUtNDZkNjNjNmQtOWNkYy00MWRkLTg3ZDYtMTEwNmRiNWE1ZTFhLmpwZyIsIndpZHRoIjoiPD02MDAifV1dLCJhdWQiOlsidXJuOnNlcnZpY2U6aW1hZ2Uub3BlcmF0aW9ucyJdfQ.omuS3D1RmFiZCy9OSXiIita-HxVGrBok3_7asq0rflw) - - -*To get into the mood of this miniature quest, imagine you are an adventurer out to find fame and -fortune. You have heard rumours of an old castle ruin by the coast. In its depth a warrior princess -was buried together with her powerful magical weapon - a valuable prize, if it's true. Of course -this is a chance to adventure that you cannot turn down!* - -*You reach the ocean in the midst of a raging thunderstorm. With wind and rain screaming in your -face you stand where the moor meets the sea along a high, rocky coast ...* - -- Look at everything. -- Some objects are interactive in more than one way. Use the normal `help` command to get a feel for -which commands are available at any given time. (use the command `tutorial` to get insight behind -the scenes of the tutorial). - -- In order to fight, you need to first find some type of weapon. -- *slash* is a normal attack -- *stab* launches an attack that makes more damage but has a lower chance to hit. -- *defend* will lower the chance to taking damage on your enemy's next attack. -- You *can* run from a fight that feels too deadly. Expect to be chased though. -- Being defeated is a part of the experience ... - -## Uninstall - -Uninstalling the tutorial world basically means deleting all the rooms and objects it consists of. -First, move out of the tutorial area. - - @find tut#01 - @find tut#16 - -This should locate the first and last rooms created by `build.ev` - *Intro* and *Outro*. If you -installed normally, everything created between these two numbers should be part of the tutorial. -Note their dbref numbers, for example 5 and 80. Next we just delete all objects in that range: - - @del 5-80 - -You will see some errors since some objects are auto-deleted and so cannot be found when the delete -mechanism gets to them. That's fine. You should have removed the tutorial completely once the -command finishes. - -## Notes - -When reading and learning from the code, keep in mind that *Tutorial World* was created with a very -specific goal: to install easily and to not permanently modify the rest of the server. It therefore -goes to some length to use only temporary solutions and to clean up after -itself. diff --git a/docs/0.9.5/_sources/Tutorial-for-basic-MUSH-like-game.md.txt b/docs/0.9.5/_sources/Tutorial-for-basic-MUSH-like-game.md.txt deleted file mode 100644 index 3f925151be..0000000000 --- a/docs/0.9.5/_sources/Tutorial-for-basic-MUSH-like-game.md.txt +++ /dev/null @@ -1,651 +0,0 @@ -# Tutorial for basic MUSH like game - - -This tutorial lets you code a small but complete and functioning MUSH-like game in Evennia. A -[MUSH](http://en.wikipedia.org/wiki/MUSH) is, for our purposes, a class of roleplay-centric games -focused on free form storytelling. Even if you are not interested in MUSH:es, this is still a good -first game-type to try since it's not so code heavy. You will be able to use the same principles for -building other types of games. - -The tutorial starts from scratch. If you did the [First Steps Coding](./First-Steps-Coding.md) tutorial -already you should have some ideas about how to do some of the steps already. - -The following are the (very simplistic and cut-down) features we will implement (this was taken from -a feature request from a MUSH user new to Evennia). A Character in this system should: - -- Have a “Power” score from 1 to 10 that measures how strong they are (stand-in for the stat -system). -- Have a command (e.g. `+setpower 4`) that sets their power (stand-in for character generation -code). -- Have a command (e.g. `+attack`) that lets them roll their power and produce a "Combat Score" -between `1` and `10*Power`, displaying the result and editing their object to record this number -(stand-in for `+actions` in the command code). -- Have a command that displays everyone in the room and what their most recent "Combat Score" roll -was (stand-in for the combat code). -- Have a command (e.g. `+createNPC Jenkins`) that creates an NPC with full abilities. -- Have a command to control NPCs, such as `+npc/cmd (name)=(command)` (stand-in for the NPC -controlling code). - -In this tutorial we will assume you are starting from an empty database without any previous -modifications. - -## Server Settings - -To emulate a MUSH, the default `MULTISESSION_MODE=0` is enough (one unique session per -account/character). This is the default so you don't need to change anything. You will still be able -to puppet/unpuppet objects you have permission to, but there is no character selection out of the -box in this mode. - -We will assume our game folder is called `mygame` henceforth. You should be fine with the default -SQLite3 database. - -## Creating the Character - -First thing is to choose how our Character class works. We don't need to define a special NPC object --- an NPC is after all just a Character without an Account currently controlling them. - -Make your changes in the `mygame/typeclasses/characters.py` file: - -```python -# mygame/typeclasses/characters.py - -from evennia import DefaultCharacter - -class Character(DefaultCharacter): - """ - [...] - """ - def at_object_creation(self): - "This is called when object is first created, only." - self.db.power = 1 - self.db.combat_score = 1 -``` - -We defined two new [Attributes](./Attributes.md) `power` and `combat_score` and set them to default -values. Make sure to `@reload` the server if you had it already running (you need to reload every -time you update your python code, don't worry, no accounts will be disconnected by the reload). - -Note that only *new* characters will see your new Attributes (since the `at_object_creation` hook is -called when the object is first created, existing Characters won't have it). To update yourself, -run - - @typeclass/force self - -This resets your own typeclass (the `/force` switch is a safety measure to not do this -accidentally), this means that `at_object_creation` is re-run. - - examine self - -Under the "Persistent attributes" heading you should now find the new Attributes `power` and `score` -set on yourself by `at_object_creation`. If you don't, first make sure you `@reload`ed into the new -code, next look at your server log (in the terminal/console) to see if there were any syntax errors -in your code that may have stopped your new code from loading correctly. - -## Character Generation - -We assume in this example that Accounts first connect into a "character generation area". Evennia -also supports full OOC menu-driven character generation, but for this example, a simple start room -is enough. When in this room (or rooms) we allow character generation commands. In fact, character -generation commands will *only* be available in such rooms. - -Note that this again is made so as to be easy to expand to a full-fledged game. With our simple -example, we could simply set an `is_in_chargen` flag on the account and have the `+setpower` command -check it. Using this method however will make it easy to add more functionality later. - -What we need are the following: - -- One character generation [Command](./Commands.md) to set the "Power" on the `Character`. -- A chargen [CmdSet](./Command-Sets.md) to hold this command. Lets call it `ChargenCmdset`. -- A custom `ChargenRoom` type that makes this set of commands available to players in such rooms. -- One such room to test things in. - -### The +setpower command - -For this tutorial we will add all our new commands to `mygame/commands/command.py` but you could -split your commands into multiple module if you prefered. - -For this tutorial character generation will only consist of one [Command](./Commands.md) to set the -Character s "power" stat. It will be called on the following MUSH-like form: - - +setpower 4 - -Open `command.py` file. It contains documented empty templates for the base command and the -"MuxCommand" type used by default in Evennia. We will use the plain `Command` type here, the -`MuxCommand` class offers some extra features like stripping whitespace that may be useful - if so, -just import from that instead. - -Add the following to the end of the `command.py` file: - -```python -# end of command.py -from evennia import Command # just for clarity; already imported above - -class CmdSetPower(Command): - """ - set the power of a character - - Usage: - +setpower <1-10> - - This sets the power of the current character. This can only be - used during character generation. - """ - - key = "+setpower" - help_category = "mush" - - def func(self): - "This performs the actual command" - errmsg = "You must supply a number between 1 and 10." - if not self.args: - self.caller.msg(errmsg) - return - try: - power = int(self.args) - except ValueError: - self.caller.msg(errmsg) - return - if not (1 <= power <= 10): - self.caller.msg(errmsg) - return - # at this point the argument is tested as valid. Let's set it. - self.caller.db.power = power - self.caller.msg("Your Power was set to %i." % power) -``` -This is a pretty straightforward command. We do some error checking, then set the power on ourself. -We use a `help_category` of "mush" for all our commands, just so they are easy to find and separate -in the help list. - -Save the file. We will now add it to a new [CmdSet](./Command-Sets.md) so it can be accessed (in a full -chargen system you would of course have more than one command here). - -Open `mygame/commands/default_cmdsets.py` and import your `command.py` module at the top. We also -import the default `CmdSet` class for the next step: - -```python -from evennia import CmdSet -from commands import command -``` - -Next scroll down and define a new command set (based on the base `CmdSet` class we just imported at -the end of this file, to hold only our chargen-specific command(s): - -```python -# end of default_cmdsets.py - -class ChargenCmdset(CmdSet): - """ - This cmdset it used in character generation areas. - """ - key = "Chargen" - def at_cmdset_creation(self): - "This is called at initialization" - self.add(command.CmdSetPower()) -``` - -In the future you can add any number of commands to this cmdset, to expand your character generation -system as you desire. Now we need to actually put that cmdset on something so it's made available to -users. We could put it directly on the Character, but that would make it available all the time. -It's cleaner to put it on a room, so it's only available when players are in that room. - -### Chargen areas - -We will create a simple Room typeclass to act as a template for all our Chargen areas. Edit -`mygame/typeclasses/rooms.py` next: - -```python -from commands.default_cmdsets import ChargenCmdset - -# ... -# down at the end of rooms.py - -class ChargenRoom(Room): - """ - This room class is used by character-generation rooms. It makes - the ChargenCmdset available. - """ - def at_object_creation(self): - "this is called only at first creation" - self.cmdset.add(ChargenCmdset, permanent=True) -``` -Note how new rooms created with this typeclass will always start with `ChargenCmdset` on themselves. -Don't forget the `permanent=True` keyword or you will lose the cmdset after a server reload. For -more information about [Command Sets](./Command-Sets.md) and [Commands](./Commands.md), see the respective -links. - -### Testing chargen - -First, make sure you have `@reload`ed the server (or use `evennia reload` from the terminal) to have -your new python code added to the game. Check your terminal and fix any errors you see - the error -traceback lists exactly where the error is found - look line numbers in files you have changed. - -We can't test things unless we have some chargen areas to test. Log into the game (you should at -this point be using the new, custom Character class). Let's dig a chargen area to test. - - @dig chargen:rooms.ChargenRoom = chargen,finish - -If you read the help for `@dig` you will find that this will create a new room named `chargen`. The -part after the `:` is the python-path to the Typeclass you want to use. Since Evennia will -automatically try the `typeclasses` folder of our game directory, we just specify -`rooms.ChargenRoom`, meaning it will look inside the module `rooms.py` for a class named -`ChargenRoom` (which is what we created above). The names given after `=` are the names of exits to -and from the room from your current location. You could also append aliases to each one name, such -as `chargen;character generation`. - -So in summary, this will create a new room of type ChargenRoom and open an exit `chargen` to it and -an exit back here named `finish`. If you see errors at this stage, you must fix them in your code. -`@reload` -between fixes. Don't continue until the creation seems to have worked okay. - - chargen - -This should bring you to the chargen room. Being in there you should now have the `+setpower` -command available, so test it out. When you leave (via the `finish` exit), the command will go away -and trying `+setpower` should now give you a command-not-found error. Use `ex me` (as a privileged -user) to check so the `Power` [Attribute](./Attributes.md) has been set correctly. - -If things are not working, make sure your typeclasses and commands are free of bugs and that you -have entered the paths to the various command sets and commands correctly. Check the logs or command -line for tracebacks and errors. - -## Combat System - -We will add our combat command to the default command set, meaning it will be available to everyone -at all times. The combat system consists of a `+attack` command to get how successful our attack is. -We also change the default `look` command to display the current combat score. - - -### Attacking with the +attack command - -Attacking in this simple system means rolling a random "combat score" influenced by the `power` stat -set during Character generation: - - > +attack - You +attack with a combat score of 12! - -Go back to `mygame/commands/command.py` and add the command to the end like this: - -```python -import random - -# ... - -class CmdAttack(Command): - """ - issues an attack - - Usage: - +attack - - This will calculate a new combat score based on your Power. - Your combat score is visible to everyone in the same location. - """ - key = "+attack" - help_category = "mush" - - def func(self): - "Calculate the random score between 1-10*Power" - caller = self.caller - power = caller.db.power - if not power: - # this can happen if caller is not of - # our custom Character typeclass - power = 1 - combat_score = random.randint(1, 10 * power) - caller.db.combat_score = combat_score - - # announce - message = "%s +attack%s with a combat score of %s!" - caller.msg(message % ("You", "", combat_score)) - caller.location.msg_contents(message % - (caller.key, "s", combat_score), - exclude=caller) -``` - -What we do here is simply to generate a "combat score" using Python's inbuilt `random.randint()` -function. We then store that and echo the result to everyone involved. - -To make the `+attack` command available to you in game, go back to -`mygame/commands/default_cmdsets.py` and scroll down to the `CharacterCmdSet` class. At the correct -place add this line: - -```python -self.add(command.CmdAttack()) -``` - -`@reload` Evennia and the `+attack` command should be available to you. Run it and use e.g. `@ex` to -make sure the `combat_score` attribute is saved correctly. - -### Have "look" show combat scores - -Players should be able to view all current combat scores in the room. We could do this by simply -adding a second command named something like `+combatscores`, but we will instead let the default -`look` command do the heavy lifting for us and display our scores as part of its normal output, like -this: - - > look Tom - Tom (combat score: 3) - This is a great warrior. - -We don't actually have to modify the `look` command itself however. To understand why, take a look -at how the default `look` is actually defined. It sits in `evennia/commands/default/general.py` (or -browse it online -[here](https://github.com/evennia/evennia/blob/master/evennia/commands/default/general.py#L44)). -You will find that the actual return text is done by the `look` command calling a *hook method* -named `return_appearance` on the object looked at. All the `look` does is to echo whatever this hook -returns. So what we need to do is to edit our custom Character typeclass and overload its -`return_appearance` to return what we want (this is where the advantage of having a custom typeclass -comes into play for real). - -Go back to your custom Character typeclass in `mygame/typeclasses/characters.py`. The default -implementation of `return appearance` is found in `evennia.DefaultCharacter` (or online -[here](https://github.com/evennia/evennia/blob/master/evennia/objects/objects.py#L1438)). If you -want to make bigger changes you could copy & paste the whole default thing into our overloading -method. In our case the change is small though: - -```python -class Character(DefaultCharacter): - """ - [...] - """ - def at_object_creation(self): - "This is called when object is first created, only." - self.db.power = 1 - self.db.combat_score = 1 - - def return_appearance(self, looker): - """ - The return from this method is what - looker sees when looking at this object. - """ - text = super().return_appearance(looker) - cscore = " (combat score: %s)" % self.db.combat_score - if "\n" in text: - # text is multi-line, add score after first line - first_line, rest = text.split("\n", 1) - text = first_line + cscore + "\n" + rest - else: - # text is only one line; add score to end - text += cscore - return text -``` - -What we do is to simply let the default `return_appearance` do its thing (`super` will call the -parent's version of the same method). We then split out the first line of this text, append our -`combat_score` and put it back together again. - -`@reload` the server and you should be able to look at other Characters and see their current combat -scores. - -> Note: A potentially more useful way to do this would be to overload the entire `return_appearance` -of the `Room`s of your mush and change how they list their contents; in that way one could see all -combat scores of all present Characters at the same time as looking at the room. We leave this as an -exercise. - -## NPC system - -Here we will re-use the Character class by introducing a command that can create NPC objects. We -should also be able to set its Power and order it around. - -There are a few ways to define the NPC class. We could in theory create a custom typeclass for it -and put a custom NPC-specific cmdset on all NPCs. This cmdset could hold all manipulation commands. -Since we expect NPC manipulation to be a common occurrence among the user base however, we will -instead put all relevant NPC commands in the default command set and limit eventual access with -[Permissions and Locks](./Locks.md#permissions). - -### Creating an NPC with +createNPC - -We need a command for creating the NPC, this is a very straightforward command: - - > +createnpc Anna - You created the NPC 'Anna'. - -At the end of `command.py`, create our new command: - -```python -from evennia import create_object - -class CmdCreateNPC(Command): - """ - create a new npc - - Usage: - +createNPC - - Creates a new, named NPC. The NPC will start with a Power of 1. - """ - key = "+createnpc" - aliases = ["+createNPC"] - locks = "call:not perm(nonpcs)" - help_category = "mush" - - def func(self): - "creates the object and names it" - caller = self.caller - if not self.args: - caller.msg("Usage: +createNPC ") - return - if not caller.location: - # may not create npc when OOC - caller.msg("You must have a location to create an npc.") - return - # make name always start with capital letter - name = self.args.strip().capitalize() - # create npc in caller's location - npc = create_object("characters.Character", - key=name, - location=caller.location, - locks="edit:id(%i) and perm(Builders);call:false()" % caller.id) - # announce - message = "%s created the NPC '%s'." - caller.msg(message % ("You", name)) - caller.location.msg_contents(message % (caller.key, name), - exclude=caller) -``` -Here we define a `+createnpc` (`+createNPC` works too) that is callable by everyone *not* having the -`nonpcs` "[permission](./Locks.md#permissions)" (in Evennia, a "permission" can just as well be used to -block access, it depends on the lock we define). We create the NPC object in the caller's current -location, using our custom `Character` typeclass to do so. - -We set an extra lock condition on the NPC, which we will use to check who may edit the NPC later -- -we allow the creator to do so, and anyone with the Builders permission (or higher). See -[Locks](./Locks.md) for more information about the lock system. - -Note that we just give the object default permissions (by not specifying the `permissions` keyword -to the `create_object()` call). In some games one might want to give the NPC the same permissions -as the Character creating them, this might be a security risk though. - -Add this command to your default cmdset the same way you did the `+attack` command earlier. -`@reload` and it will be available to test. - -### Editing the NPC with +editNPC - -Since we re-used our custom character typeclass, our new NPC already has a *Power* value - it -defaults to 1. How do we change this? - -There are a few ways we can do this. The easiest is to remember that the `power` attribute is just a -simple [Attribute](./Attributes.md) stored on the NPC object. So as a Builder or Admin we could set this -right away with the default `@set` command: - - @set mynpc/power = 6 - -The `@set` command is too generally powerful though, and thus only available to staff. We will add a -custom command that only changes the things we want players to be allowed to change. We could in -principle re-work our old `+setpower` command, but let's try something more useful. Let's make a -`+editNPC` command. - - > +editNPC Anna/power = 10 - Set Anna's property 'power' to 10. - -This is a slightly more complex command. It goes at the end of your `command.py` file as before. - -```python -class CmdEditNPC(Command): - """ - edit an existing NPC - - Usage: - +editnpc [/ [= value]] - - Examples: - +editnpc mynpc/power = 5 - +editnpc mynpc/power - displays power value - +editnpc mynpc - shows all editable - attributes and values - - This command edits an existing NPC. You must have - permission to edit the NPC to use this. - """ - key = "+editnpc" - aliases = ["+editNPC"] - locks = "cmd:not perm(nonpcs)" - help_category = "mush" - - def parse(self): - "We need to do some parsing here" - args = self.args - propname, propval = None, None - if "=" in args: - args, propval = [part.strip() for part in args.rsplit("=", 1)] - if "/" in args: - args, propname = [part.strip() for part in args.rsplit("/", 1)] - # store, so we can access it below in func() - self.name = args - self.propname = propname - # a propval without a propname is meaningless - self.propval = propval if propname else None - - def func(self): - "do the editing" - - allowed_propnames = ("power", "attribute1", "attribute2") - - caller = self.caller - if not self.args or not self.name: - caller.msg("Usage: +editnpc name[/propname][=propval]") - return - npc = caller.search(self.name) - if not npc: - return - if not npc.access(caller, "edit"): - caller.msg("You cannot change this NPC.") - return - if not self.propname: - # this means we just list the values - output = f"Properties of {npc.key}:" - for propname in allowed_propnames: - output += f"\n {propname} = {npc.attributes.get(propname, default='N/A')}" - caller.msg(output) - elif self.propname not in allowed_propnames: - caller.msg(f"You may only change {', '.join(allowed_propnames)}.") - elif self.propval: - # assigning a new propvalue - # in this example, the properties are all integers... - intpropval = int(self.propval) - npc.attributes.add(self.propname, intpropval) - caller.msg(f"Set {npc.key}'s property {self.propname} to {self.propval}") - else: - # propname set, but not propval - show current value - caller.msg(f"{npc.key} has property {self.propname} = {npc.attributes.get(self.propname, -default='N/A')}") -``` - -This command example shows off the use of more advanced parsing but otherwise it's mostly error -checking. It searches for the given npc in the same room, and checks so the caller actually has -permission to "edit" it before continuing. An account without the proper permission won't even be -able to view the properties on the given NPC. It's up to each game if this is the way it should be. - -Add this to the default command set like before and you should be able to try it out. - -_Note: If you wanted a player to use this command to change an on-object property like the NPC's -name (the `key` property), you'd need to modify the command since "key" is not an Attribute (it is -not retrievable via `npc.attributes.get` but directly via `npc.key`). We leave this as an optional -exercise._ - -### Making the NPC do stuff - the +npc command - -Finally, we will make a command to order our NPC around. For now, we will limit this command to only -be usable by those having the "edit" permission on the NPC. This can be changed if it's possible for -anyone to use the NPC. - -The NPC, since it inherited our Character typeclass has access to most commands a player does. What -it doesn't have access to are Session and Player-based cmdsets (which means, among other things that -they cannot chat on channels, but they could do that if you just added those commands). This makes -the `+npc` command simple: - - +npc Anna = say Hello! - Anna says, 'Hello!' - -Again, add to the end of your `command.py` module: - -```python -class CmdNPC(Command): - """ - controls an NPC - - Usage: - +npc = - - This causes the npc to perform a command as itself. It will do so - with its own permissions and accesses. - """ - key = "+npc" - locks = "call:not perm(nonpcs)" - help_category = "mush" - - def parse(self): - "Simple split of the = sign" - name, cmdname = None, None - if "=" in self.args: - name, cmdname = self.args.rsplit("=", 1) - name = name.strip() - cmdname = cmdname.strip() - self.name, self.cmdname = name, cmdname - - def func(self): - "Run the command" - caller = self.caller - if not self.cmdname: - caller.msg("Usage: +npc = ") - return - npc = caller.search(self.name) - if not npc: - return - if not npc.access(caller, "edit"): - caller.msg("You may not order this NPC to do anything.") - return - # send the command order - npc.execute_cmd(self.cmdname) - caller.msg(f"You told {npc.key} to do '{self.cmdname}'.") -``` - -Note that if you give an erroneous command, you will not see any error message, since that error -will be returned to the npc object, not to you. If you want players to see this, you can give the -caller's session ID to the `execute_cmd` call, like this: - -```python -npc.execute_cmd(self.cmdname, sessid=self.caller.sessid) -``` - -Another thing to remember is however that this is a very simplistic way to control NPCs. Evennia -supports full puppeting very easily. An Account (assuming the "puppet" permission was set correctly) -could simply do `@ic mynpc` and be able to play the game "as" that NPC. This is in fact just what -happens when an Account takes control of their normal Character as well. - -## Concluding remarks - -This ends the tutorial. It looks like a lot of text but the amount of code you have to write is -actually relatively short. At this point you should have a basic skeleton of a game and a feel for -what is involved in coding your game. - -From here on you could build a few more ChargenRooms and link that to a bigger grid. The `+setpower` -command can either be built upon or accompanied by many more to get a more elaborate character -generation. - -The simple "Power" game mechanic should be easily expandable to something more full-fledged and -useful, same is true for the combat score principle. The `+attack` could be made to target a -specific player (or npc) and automatically compare their relevant attributes to determine a result. - -To continue from here, you can take a look at the [Tutorial World](./Tutorial-World-Introduction.md). For -more specific ideas, see the [other tutorials and hints](./Tutorials.md) as well -as the [Developer Central](./Developer-Central.md). diff --git a/docs/0.9.5/_sources/Tutorials.md.txt b/docs/0.9.5/_sources/Tutorials.md.txt deleted file mode 100644 index 681539c33e..0000000000 --- a/docs/0.9.5/_sources/Tutorials.md.txt +++ /dev/null @@ -1,207 +0,0 @@ -# Tutorials - - -Before continuing to read these tutorials (and especially before you start to code or build your -game in earnest) it's strongly recommended that you read the -[Evennia coding introduction](./Coding-Introduction.md) as well as the [Planning your own game](./Game-Planning.md) pages first. - -Please note that it's not within the scope of our tutorials to teach you basic Python. If you are -new to the language, expect to have to look up concepts you are unfamiliar with. Usually a quick -internet search will give you all info you need. Furthermore, our tutorials tend to focus on -implementation and concepts. As such they give only brief explanations to use Evennia features while -providing ample links to the relevant detailed documentation. - -The main information resource for builders is the [Builder Documentation](./Builder-Docs.md). Coders -should refer to the [Developer Central](./Developer-Central.md) for further information. - -### Building - -_Help with populating your game world._ - -- [Tutorial: Building Quick-start](./Building-Quickstart.md) - helps you build your first rocks and -crates using Evennia's defaults. -- [Tutorial: Understanding Color Tags](./Understanding-Color-Tags.md)- explains how you color your game's -text. -- [Introduction: The Tutorial World](./Tutorial-World-Introduction.md) - this introduces the full (if -small) solo-adventure game that comes with the Evennia distribution. It is useful both as an example -of building and of coding. -- [Tutorial: Building a Giant Mech](./Building-a-mech-tutorial.md) - this starts as a building tutorial -and transitions into writing code. - -### General Development tutorials - -_General code practices for newbie game developers._ - -To use Evennia, you will need basic understanding of Python -[modules](http://docs.python.org/3.7/tutorial/modules.html), -[variables](http://www.tutorialspoint.com/python/python_variable_types.htm), [conditional statements](http://docs.python.org/tutorial/controlflow.html#if-statements), -[loops](http://docs.python.org/tutorial/controlflow.html#for-statements), -[functions](http://docs.python.org/tutorial/controlflow.html#defining-functions), [lists, dictionaries, list comprehensions](http://docs.python.org/tutorial/datastructures.html) and [string formatting](http://docs.python.org/tutorial/introduction.html#strings). You should also have a basic -understanding of [object-oriented programming](http://www.tutorialspoint.com/python/python_classes_objects.htm) and what Python -[Classes](http://docs.python.org/tutorial/classes.html) are. - -- [Python tutorials for beginners](https://wiki.python.org/moin/BeginnersGuide/NonProgrammers) - -external link with tutorials for those not familiar with coding in general or Python in particular. -- [Tutorial: Version Control](./Version-Control.md) - use GIT to organize your code both for your own -game project and for contributing to Evennia. -- MIT offers free courses in many subjects. Their [Introduction to Computer Science and Programming](https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-00sc- -introduction-to-computer-science-and-programming-spring-2011/) uses Python as its language of -choice. Longer path, but more in-depth. Definitely worth a look. - -### Coding - First Step tutorials - -_Starting tutorials for you who are new to developing with Evennia._ - -- [Python basic introduction](./Python-basic-introduction.md) (part 1) - Python intro using Evennia. -- [Python basic introduction](./Python-basic-tutorial-part-two.md) (part 2) - More on objects, classes -and finding where things are. -- [Tutorial: First Steps Coding](./First-Steps-Coding.md) - learn each basic feature on their own through -step-by-step instruction. -- [Tutorial: A small first game](./Tutorial-for-basic-MUSH-like-game.md) - learn basic features as part -of building a small but working game from scratch. -- [Tutorial: Adding new commands](./Adding-Command-Tutorial.md) - focuses specifically on how to add new -commands. -- [Tutorial: Parsing command argument](./Parsing-command-arguments,-theory-and-best-practices.md). -- [Tutorial: Adding new objects](./Adding-Object-Typeclass-Tutorial.md) - focuses specifically on how to -add new objects. -- [Tutorial: Searching objects in the database](./Tutorial-Searching-For-Objects.md) - how to find -existing objects so you can operate on them. - - -### Custom objects and typeclasses - -_Examples of designing new objects for your game world_ - -- [Tutorial: Rooms with Weather](./Weather-Tutorial.md) -- [Tutorial: Aggressive NPC's](./Tutorial-Aggressive-NPCs.md) -- [Tutorial: Listening NPC's](./Tutorial-NPCs-listening.md) -- [Tutorial: Creating a vehicle](./Tutorial-Vehicles.md) -- [Tutorial: Making an NPC shop](./NPC-shop-Tutorial.md) (also advanced [EvMenu](./EvMenu.md) usage) -- [Tutorial: Implementing a Static In Game Map](./Static-In-Game-Map.md) (also [Batch Code](Batch-Code- -Processor) usage) -- [Tutorial: Implementing a Dynamic In Game Map](./Dynamic-In-Game-Map.md) -- [Tutorial: Writing your own unit tests](./Unit-Testing.md#testing-for-game-development-mini-tutorial) - -### Game mechanics tutorials - -_Creating the underlying game mechanics of game play._ - -- [Hints: Implementing a game rule system](./Implementing-a-game-rule-system.md) -- [Tutorial: Implementing a Combat system](./Turn-based-Combat-System.md) -- [Tutorial: Evennia for running tabletop rpgs](./Evennia-for-roleplaying-sessions.md) - -### Miscellaneous system tutorials - -_Design various game systems and achieve particular effects._ - -- [FAQ](./Coding-FAQ.md): A place for users to enter their own hints on achieving various goals in -Evennia. -- [Tutorial: Adding a Command prompt](./Command-Prompt.md) -- [Tutorial: Creating a Zoning system](./Zones.md) -- [Tutorial: Letting players manually configure color settings](./Manually-Configuring-Color.md) -- [Hints: Asking the user a question and dealing with the result](./EvMenu.md#ask-for-simple-input) -- [Hints: Designing commands that take time to finish](./Command-Duration.md) -- [Hints: Adding cooldowns to commands](./Command-Cooldown.md) -- [Tutorial: Mass and weight for objects](./Mass-and-weight-for-objects.md) -- [Hints: Show a different message when trying a non-existent exit](./Default-Exit-Errors.md) -- [Tutorial: Make automatic tweets of game statistics](./Tutorial-Tweeting-Game-Stats.md) -- [Tutorial: Handling virtual time in your game](./Gametime-Tutorial.md) -- [Tutorial: Setting up a coordinate system for rooms](./Coordinates.md) -- [Tutorial: customize the way channels and channel commands work in your game](./Customize-channels.md) -- [Tutorial: Adding unit tests to your game project](./Unit-Testing.md#testing-for-game-development-mini- tutorial) - -### Contrib - -_This section contains tutorials linked with contribs. These contribs can be used in your game, but -you'll need to install them explicitly. They add common features that can earn you time in -implementation._ - -- [list of contribs](https://github.com/evennia/evennia/blob/master/evennia/contrib/README.md) - -- [In-game Python: dialogues with characters](./Dialogues-in-events.md). -- [In-game Python: a voice-operated elevator](./A-voice-operated-elevator-using-events.md). - -### Web tutorials - -_Expanding Evennia's web presence._ - -- [Tutorial: Add a new web page](./Add-a-simple-new-web-page.md) - simple example to see how Django pages -hang together. -- [Tutorial: Website customization](./Web-Tutorial.md) - learn how to start customizing your game's web -presence. -- [Tutorial: Bootstrap & Evennia](./Bootstrap-&-Evennia.md) - Learn more about Bootstrap, the current CSS -framework Evennia is using -- [Tutorial: Build a web page displaying a game character](./Web-Character-View-Tutorial.md) - make a way -to view your character on the web page. -- [Tutorial: access your help system from your website](./Help-System-Tutorial.md) -- [Tutorial: add a wiki on your website](./Add-a-wiki-on-your-website.md) -- [Tutorial: Web Character Generation](Web-Character-Generation/) - make a web-based character -application form. -- [Tutorial: Bootstrap Components and Utilities](./Bootstrap-Components-and-Utilities.md) - Describes -some common Bootstrap Components and Utilities that might help in designing for Evennia - -### Evennia for [Engine]-Users - -_Hints for new users more familiar with other game engines._ - -- [Evennia for Diku Users](./Evennia-for-Diku-Users.md) - read up on the differences between Diku style -muds and Evennia. -- [Evennia for MUSH Users](./Evennia-for-MUSH-Users.md) - an introduction to Evennia for those accustomed -to MUSH-style servers. - - -```{toctree} - :hidden: - - Game-Planning - Building-Quickstart - Understanding-Color-Tags - Tutorial-World-Introduction - Building-a-mech-tutorial - Version-Control - Python-basic-introduction - Python-basic-tutorial-part-two - First-Steps-Coding - Tutorial-for-basic-MUSH-like-game - Adding-Command-Tutorial - Parsing-command-arguments,-theory-and-best-practices - Adding-Object-Typeclass-Tutorial - Tutorial-Searching-For-Objects - Weather-Tutorial - Tutorial-Aggressive-NPCs - Tutorial-NPCs-listening - Tutorial-Vehicles - NPC-shop-Tutorial - Static-In-Game-Map - Dynamic-In-Game-Map - Unit-Testing - Implementing-a-game-rule-system - Turn-based-Combat-System - Evennia-for-roleplaying-sessions - Coding-FAQ - Command-Prompt - Zones - Manually-Configuring-Color - EvMenu - Command-Duration - Command-Cooldown - Mass-and-weight-for-objects - Default-Exit-Errors - Tutorial-Tweeting-Game-Stats - Gametime-Tutorial - Coordinates - Customize-channels - Dialogues-in-events - A-voice-operated-elevator-using-events - Add-a-simple-new-web-page - Web-Tutorial - Bootstrap-&-Evennia - Web-Character-View-Tutorial - Help-System-Tutorial - Add-a-wiki-on-your-website - Web-Character-Generation - Bootstrap-Components-and-Utilities - Evennia-for-Diku-Users - Evennia-for-MUSH-Users - -``` diff --git a/docs/0.9.5/_sources/Typeclasses.md.txt b/docs/0.9.5/_sources/Typeclasses.md.txt deleted file mode 100644 index 456611f520..0000000000 --- a/docs/0.9.5/_sources/Typeclasses.md.txt +++ /dev/null @@ -1,354 +0,0 @@ -# Typeclasses - - -*Typeclasses* form the core of Evennia data storage. It allows Evennia to represent any number of -different game entities as Python classes, without having to modify the database schema for every -new type. - -In Evennia the most important game entities, [Accounts](./Accounts.md), [Objects](./Objects.md), -[Scripts](./Scripts.md) and [Channels](./Communications.md#channels) are all Python classes inheriting, at -varying distance, from `evennia.typeclasses.models.TypedObject`. In the documentation we refer to -these objects as being "typeclassed" or even "being a typeclass". - -This is how the inheritance looks for the typeclasses in Evennia: - -``` - TypedObject - _________________|_________________________________ - | | | | -1: AccountDB ObjectDB ScriptDB ChannelDB - | | | | -2: DefaultAccount DefaultObject DefaultScript DefaultChannel - | DefaultCharacter | | - | DefaultRoom | | - | DefaultExit | | - | | | | -3: Account Object Script Channel - Character - Room - Exit -``` - -- **Level 1** above is the "database model" level. This describes the database tables and fields -(this is technically a [Django model](https://docs.djangoproject.com/en/2.2/topics/db/models/)). -- **Level 2** is where we find Evennia's default implementations of the various game entities, on -top of the database. These classes define all the hook methods that Evennia calls in various -situations. `DefaultObject` is a little special since it's the parent for `DefaultCharacter`, -`DefaultRoom` and `DefaultExit`. They are all grouped under level 2 because they all represents -defaults to build from. -- **Level 3**, finally, holds empty template classes created in your game directory. This is the -level you are meant to modify and tweak as you please, overloading the defaults as befits your game. -The templates inherit directly from their defaults, so `Object` inherits from `DefaultObject` and -`Room` inherits from `DefaultRoom`. - -The `typeclass/list` command will provide a list of all typeclasses known to -Evennia. This can be useful for getting a feel for what is available. Note -however that if you add a new module with a class in it but do not import that -module from anywhere, the `typeclass/list` will not find it. To make it known -to Evennia you must import that module from somewhere. - - -### Difference between typeclasses and classes - -All Evennia classes inheriting from class in the table above share one important feature and two -important limitations. This is why we don't simply call them "classes" but "typeclasses". - - 1. A typeclass can save itself to the database. This means that some properties (actually not that -many) on the class actually represents database fields and can only hold very specific data types. -This is detailed [below](./Typeclasses.md#about-typeclass-properties). - 1. Due to its connection to the database, the typeclass' name must be *unique* across the _entire_ -server namespace. That is, there must never be two same-named classes defined anywhere. So the below -code would give an error (since `DefaultObject` is now globally found both in this module and in the -default library): - - ```python - from evennia import DefaultObject as BaseObject - class DefaultObject(BaseObject): - pass - ``` - - 1. A typeclass' `__init__` method should normally not be overloaded. This has mostly to do with the -fact that the `__init__` method is not called in a predictable way. Instead Evennia suggest you use -the `at_*_creation` hooks (like `at_object_creation` for Objects) for setting things the very first -time the typeclass is saved to the database or the `at_init` hook which is called every time the -object is cached to memory. If you know what you are doing and want to use `__init__`, it *must* -both accept arbitrary keyword arguments and use `super` to call its parent:: - - ```python - def __init__(self, **kwargs): - # my content - super().__init__(**kwargs) - # my content - ``` - -Apart from this, a typeclass works like any normal Python class and you can -treat it as such. - - -## Creating a new typeclass - -It's easy to work with Typeclasses. Either you use an existing typeclass or you create a new Python -class inheriting from an existing typeclass. Here is an example of creating a new type of Object: - -```python - from evennia import DefaultObject - - class Furniture(DefaultObject): - # this defines what 'furniture' is, like - # storing who sits on it or something. - pass - -``` - -You can now create a new `Furniture` object in two ways. First (and usually not the most -convenient) way is to create an instance of the class and then save it manually to the database: - -```python -chair = Furniture(db_key="Chair") -chair.save() - -``` - -To use this you must give the database field names as keywords to the call. Which are available -depends on the entity you are creating, but all start with `db_*` in Evennia. This is a method you -may be familiar with if you know Django from before. - -It is recommended that you instead use the `create_*` functions to create typeclassed entities: - - -```python -from evennia import create_object - -chair = create_object(Furniture, key="Chair") -# or (if your typeclass is in a module furniture.py) -chair = create_object("furniture.Furniture", key="Chair") -``` - -The `create_object` (`create_account`, `create_script` etc) takes the typeclass as its first -argument; this can both be the actual class or the python path to the typeclass as found under your -game directory. So if your `Furniture` typeclass sits in `mygame/typeclasses/furniture.py`, you -could point to it as `typeclasses.furniture.Furniture`. Since Evennia will itself look in -`mygame/typeclasses`, you can shorten this even further to just `furniture.Furniture`. The create- -functions take a lot of extra keywords allowing you to set things like [Attributes](./Attributes.md) and -[Tags](./Tags.md) all in one go. These keywords don't use the `db_*` prefix. This will also automatically -save the new instance to the database, so you don't need to call `save()` explicitly. - -### About typeclass properties - -An example of a database field is `db_key`. This stores the "name" of the entity you are modifying -and can thus only hold a string. This is one way of making sure to update the `db_key`: - -```python -chair.db_key = "Table" -chair.save() - -print(chair.db_key) -<<< Table -``` - -That is, we change the chair object to have the `db_key` "Table", then save this to the database. -However, you almost never do things this way; Evennia defines property wrappers for all the database -fields. These are named the same as the field, but without the `db_` part: - -```python -chair.key = "Table" - -print(chair.key) -<<< Table - -``` - -The `key` wrapper is not only shorter to write, it will make sure to save the field for you, and -does so more efficiently by levering sql update mechanics under the hood. So whereas it is good to -be aware that the field is named `db_key` you should use `key` as much as you can. - -Each typeclass entity has some unique fields relevant to that type. But all also share the -following fields (the wrapper name without `db_` is given): - - - `key` (str): The main identifier for the entity, like "Rose", "myscript" or "Paul". `name` is an -alias. - - `date_created` (datetime): Time stamp when this object was created. - - `typeclass_path` (str): A python path pointing to the location of this (type)class - -There is one special field that doesn't use the `db_` prefix (it's defined by Django): - - - `id` (int): the database id (database ref) of the object. This is an ever-increasing, unique -integer. It can also be accessed as `dbid` (database ID) or `pk` (primary key). The `dbref` property -returns the string form "#id". - -The typeclassed entity has several common handlers: - - - `tags` - the [TagHandler](./Tags.md) that handles tagging. Use `tags.add()` , `tags.get()` etc. - - `locks` - the [LockHandler](./Locks.md) that manages access restrictions. Use `locks.add()`, -`locks.get()` etc. - - `attributes` - the [AttributeHandler](./Attributes.md) that manages Attributes on the object. Use -`attributes.add()` -etc. - - `db` (DataBase) - a shortcut property to the AttributeHandler; allowing `obj.db.attrname = value` - - `nattributes` - the [Non-persistent AttributeHandler](./Attributes.md) for attributes not saved in the -database. - - `ndb` (NotDataBase) - a shortcut property to the Non-peristent AttributeHandler. Allows -`obj.ndb.attrname = value` - - -Each of the typeclassed entities then extend this list with their own properties. Go to the -respective pages for [Objects](./Objects.md), [Scripts](./Scripts.md), [Accounts](./Accounts.md) and -[Channels](./Communications.md) for more info. It's also recommended that you explore the available -entities using [Evennia's flat API](./Evennia-API.md) to explore which properties and methods they have -available. - -### Overloading hooks - -The way to customize typeclasses is usually to overload *hook methods* on them. Hooks are methods -that Evennia call in various situations. An example is the `at_object_creation` hook on `Objects`, -which is only called once, the very first time this object is saved to the database. Other examples -are the `at_login` hook of Accounts and the `at_repeat` hook of Scripts. - -### Querying for typeclasses - -Most of the time you search for objects in the database by using convenience methods like the -`caller.search()` of [Commands](./Commands.md) or the search functions like `evennia.search_objects`. - -You can however also query for them directly using [Django's query -language](https://docs.djangoproject.com/en/1.7/topics/db/queries/). This makes use of a _database -manager_ that sits on all typeclasses, named `objects`. This manager holds methods that allow -database searches against that particular type of object (this is the way Django normally works -too). When using Django queries, you need to use the full field names (like `db_key`) to search: - -```python -matches = Furniture.objects.get(db_key="Chair") - -``` - -It is important that this will *only* find objects inheriting directly from `Furniture` in your -database. If there was a subclass of `Furniture` named `Sitables` you would not find any chairs -derived from `Sitables` with this query (this is not a Django feature but special to Evennia). To -find objects from subclasses Evennia instead makes the `get_family` and `filter_family` query -methods available: - -```python -# search for all furnitures and subclasses of furnitures -# whose names starts with "Chair" -matches = Furniture.objects.filter_family(db_key__startswith="Chair") - -``` - -To make sure to search, say, all `Scripts` *regardless* of typeclass, you need to query from the -database model itself. So for Objects, this would be `ObjectDB` in the diagram above. Here's an -example for Scripts: - -```python -from evennia import ScriptDB -matches = ScriptDB.objects.filter(db_key__contains="Combat") -``` - -When querying from the database model parent you don't need to use `filter_family` or `get_family` - -you will always query all children on the database model. - -## Updating existing typeclass instances - -If you already have created instances of Typeclasses, you can modify the *Python code* at any time - -due to how Python inheritance works your changes will automatically be applied to all children once -you have reloaded the server. - -However, database-saved data, like `db_*` fields, [Attributes](./Attributes.md), [Tags](./Tags.md) etc, are -not themselves embedded into the class and will *not* be updated automatically. This you need to -manage yourself, by searching for all relevant objects and updating or adding the data: - -```python -# add a worth Attribute to all existing Furniture -for obj in Furniture.objects.all(): - # this will loop over all Furniture instances - obj.db.worth = 100 -``` - -A common use case is putting all Attributes in the `at_*_creation` hook of the entity, such as -`at_object_creation` for `Objects`. This is called every time an object is created - and only then. -This is usually what you want but it does mean already existing objects won't get updated if you -change the contents of `at_object_creation` later. You can fix this in a similar way as above -(manually setting each Attribute) or with something like this: - -```python -# Re-run at_object_creation only on those objects not having the new Attribute -for obj in Furniture.objects.all(): - if not obj.db.worth: - obj.at_object_creation() -``` - -The above examples can be run in the command prompt created by `evennia shell`. You could also run -it all in-game using `@py`. That however requires you to put the code (including imports) as one -single line using `;` and [list -comprehensions](http://www.secnetix.de/olli/Python/list_comprehensions.hawk), like this (ignore the -line break, that's only for readability in the wiki): - -``` -@py from typeclasses.furniture import Furniture; -[obj.at_object_creation() for obj in Furniture.objects.all() if not obj.db.worth] -``` - -It is recommended that you plan your game properly before starting to build, to avoid having to -retroactively update objects more than necessary. - -## Swap typeclass - -If you want to swap an already existing typeclass, there are two ways to do so: From in-game and via -code. From inside the game you can use the default `@typeclass` command: - -``` -@typeclass objname = path.to.new.typeclass -``` - -There are two important switches to this command: -- `/reset` - This will purge all existing Attributes on the object and re-run the creation hook -(like `at_object_creation` for Objects). This assures you get an object which is purely of this new -class. -- `/force` - This is required if you are changing the class to be *the same* class the object -already has - it's a safety check to avoid user errors. This is usually used together with `/reset` -to re-run the creation hook on an existing class. - -In code you instead use the `swap_typeclass` method which you can find on all typeclassed entities: - -```python -obj_to_change.swap_typeclass(new_typeclass_path, clean_attributes=False, - run_start_hooks="all", no_default=True, clean_cmdsets=False) -``` - -The arguments to this method are described [in the API docs -here](github:evennia.typeclasses.models#typedobjectswap_typeclass). - - -## How typeclasses actually work - -*This is considered an advanced section.* - -Technically, typeclasses are [Django proxy -models](https://docs.djangoproject.com/en/1.7/topics/db/models/#proxy-models). The only database -models that are "real" in the typeclass system (that is, are represented by actual tables in the -database) are `AccountDB`, `ObjectDB`, `ScriptDB` and `ChannelDB` (there are also -[Attributes](./Attributes.md) and [Tags](./Tags.md) but they are not typeclasses themselves). All the -subclasses of them are "proxies", extending them with Python code without actually modifying the -database layout. - -Evennia modifies Django's proxy model in various ways to allow them to work without any boiler plate -(for example you don't need to set the Django "proxy" property in the model `Meta` subclass, Evennia -handles this for you using metaclasses). Evennia also makes sure you can query subclasses as well as -patches django to allow multiple inheritance from the same base class. - -### Caveats - -Evennia uses the *idmapper* to cache its typeclasses (Django proxy models) in memory. The idmapper -allows things like on-object handlers and properties to be stored on typeclass instances and to not -get lost as long as the server is running (they will only be cleared on a Server reload). Django -does not work like this by default; by default every time you search for an object in the database -you'll get a *different* instance of that object back and anything you stored on it that was not in -the database would be lost. The bottom line is that Evennia's Typeclass instances subside in memory -a lot longer than vanilla Django model instance do. - -There is one caveat to consider with this, and that relates to [making your own models](New- -Models): Foreign relationships to typeclasses are cached by Django and that means that if you were -to change an object in a foreign relationship via some other means than via that relationship, the -object seeing the relationship may not reliably update but will still see its old cached version. -Due to typeclasses staying so long in memory, stale caches of such relationships could be more -visible than common in Django. See the [closed issue #1098 and its -comments](https://github.com/evennia/evennia/issues/1098) for examples and solutions. - diff --git a/docs/0.9.5/_sources/Understanding-Color-Tags.md.txt b/docs/0.9.5/_sources/Understanding-Color-Tags.md.txt deleted file mode 100644 index 0d23924be5..0000000000 --- a/docs/0.9.5/_sources/Understanding-Color-Tags.md.txt +++ /dev/null @@ -1,198 +0,0 @@ -# Understanding Color Tags - -This tutorial aims at dispelling confusions regarding the use of color tags within Evennia. - -Correct understanding of this topic requires having read the [TextTags](./TextTags.md) page and learned -Evennia's color tags. Here we'll explain by examples the reasons behind the unexpected (or -apparently incoherent) behaviors of some color tags, as mentioned _en passant_ in the -[TextTags](./TextTags.md) page. - - -All you'll need for this tutorial is access to a running instance of Evennia via a color-enabled -client. The examples provided are just commands that you can type in your client. - -Evennia, ANSI and Xterm256 -========================== - -All modern MUD clients support colors; nevertheless, the standards to which all clients abide dates -back to old day of terminals, and when it comes to colors we are dealing with ANSI and Xterm256 -standards. - -Evennia handles transparently, behind the scenes, all the code required to enforce these -standards—so, if a user connects with a client which doesn't support colors, or supports only ANSI -(16 colors), Evennia will take all due steps to ensure that the output will be adjusted to look -right at the client side. - -As for you, the developer, all you need to care about is knowing how to correctly use the color tags -within your MUD. Most likely, you'll be adding colors to help pages, descriptions, automatically -generated text, etc. - -You are free to mix together ANSI and Xterm256 color tags, but you should be aware of a few -pitfalls. ANSI and Xterm256 coexist without conflicts in Evennia, but in many ways they don't «see» -each other: ANSI-specific color tags will have no effect on Xterm-defined colors, as we shall see -here. - -ANSI -==== - -ANSI has a set of 16 colors, to be more precise: ANSI has 8 basic colors which come in _dark_ and -_bright_ flavours—with _dark_ being _normal_. The colors are: red, green, yellow, blue, magenta, -cyan, white and black. White in its dark version is usually referred to as gray, and black in its -bright version as darkgray. Here, for sake of simplicity they'll be referred to as dark and bright: -bright/dark black, bright/dark white. - -The default colors of MUD clients is normal (dark) white on normal black (ie: gray on black). - -It's important to grasp that in the ANSI standard bright colors apply only to text (foreground), not -to background. Evennia allows to bypass this limitation via Xterm256, but doing so will impact the -behavior of ANSI tags, as we shall see. - -Also, it's important to remember that the 16 ANSI colors are a convention, and the final user can -always customize their appearance—he might decide to have green show as red, and dark green as blue, -etc. - -Xterm256 -======== - -The 16 colors of ANSI should be more than enough to handle simple coloring of text. But when an -author wants to be sure that a given color will show as he intended it, she might choose to rely on -Xterm256 colors. - -Xterm256 doesn't rely on a palette of named colors, it instead represent colors by their values. So, -a red color could be `|[500` (bright and pure red), or `|[300` (darker red), and so on. - -ANSI Color Tags in Evennia -========================== - -> NOTE: for ease of reading, the examples contain extra white spaces after the -> color tags (eg: `|g green |b blue` ). This is done only so that it's easier -> to see the tags separated from their context; it wouldn't be good practice -> in real-life coding. - -Let's proceed by examples. In your MUD client type: - - - say Normal |* Negative - -Evennia should output the word "Normal" normally (ie: gray on black) and "Negative" in reversed -colors (ie: black on gray). - -This is pretty straight forward, the `|*` ANSI *invert* tag switches between foreground and -background—from now on, **FG** and **BG** shorthands will be used to refer to foreground and -background. - -But take mental note of this: `|*` has switched *dark white* and *dark black*. - -Now try this: - - say |w Bright white FG |* Negative - -You'll notice that the word "Negative" is not black on white, it's darkgray on gray. Why is this? -Shouldn't it be black text on a white BG? Two things are happening here. - -As mentioned, ANSI has 8 base colors, the dark ones. The bright ones are achieved by means of -*highlighting* the base/dark/normal colors, and they only apply to FG. - -What happened here is that when we set the bright white FG with `|w`, Evennia translated this into -the ANSI sequence of Highlight On + White FG. In terms of Evennia's color tags, it's as if we typed: - - - say |h|!W Bright white FG |* Negative - -Furthermore, the Highlight-On property (which only works for BG!) is preserved after the FG/BG -switch, this being the reason why we see black as darkgray: highlighting makes it *bright black* -(ie: darkgray). - -As for the BG being also grey, that is normal—ie: you are seeing *normal white* (ie: dark white = -gray). Remember that since there are no bright BG colors, the ANSI `|*` tag will transpose any FG -color in its normal/dark version. So here the FG's bright white became dark white in the BG! In -reality, it was always normal/dark white, except that in the FG is seen as bright because of the -highlight tag behind the scenes. - -Let's try the same thing with some color: - - say |m |[G Bright Magenta on Dark Green |* Negative - -Again, the BG stays dark because of ANSI rules, and the FG stays bright because of the implicit `|h` -in `|m`. - -Now, let's see what happens if we set a bright BG and then invert—yes, Evennia kindly allows us to -do it, even if it's not within ANSI expectations. - - say |[b Dark White on Bright Blue |* Negative - -Before color inversion, the BG does show in bright blue, and after inversion (as expected) it's -*dark white* (gray). The bright blue of the BG survived the inversion and gave us a bright blue FG. -This behavior is tricky though, and not as simple as it might look. - -If the inversion were to be pure ANSI, the bright blue would have been accounted just as normal -blue, and should have converted to normal blue in the FG (after all, there was no highlighting on). -The fact is that in reality this color is not bright blue at all, it just an Xterm version of it! - -To demonstrate this, type: - - say |[b Dark White on Bright Blue |* Negative |H un-bright - -The `|H` Highlight-Off tag should have turned *dark blue* the last word; but it didn't because it -couldn't: in order to enforce the non-ANSI bright BG Evennia turned to Xterm, and Xterm entities are -not affected by ANSI tags! - -So, we are getting at the heart of all confusions and possible odd-behaviors pertaining color tags -in Evennia: apart from Evennia's translations from- and to- ANSI/Xterm, the two systems are -independent and transparent to each other. - -The bright blue of the previous example was just an Xterm representation of the ANSI standard blue. -Try to change the default settings of your client, so that blue shows as some other color, you'll -then realize the difference when Evennia is sending a true ANSI color (which will show up according -to your settings) and when instead it's sending an Xterm representation of that color (which will -show up always as defined by Evennia). - -You'll have to keep in mind that the presence of an Xterm BG or FG color might affect the way your -tags work on the text. For example: - - say |[b Bright Blue BG |* Negative |!Y Dark Yellow |h not bright - -Here the `|h` tag no longer affects the FG color. Even though it was changed via the `|!` tag, the -ANSI system is out-of-tune because of the intrusion of an Xterm color (bright blue BG, then moved to -FG with `|*`). - -All unexpected ANSI behaviours are the result of mixing Xterm colors (either on purpose or either -via bright BG colors). The `|n` tag will restore things in place and ANSI tags will respond properly -again. So, at the end is just an issue of being mindful when using Xterm colors or bright BGs, and -avoid wild mixing them with ANSI tags without normalizing (`|n`) things again. - -Try this: - - say |[b Bright Blue BG |* Negative |!R Red FG - -And then: - - say |[B Dark Blue BG |* Negative |!R Red BG?? - -In this second example the `|!` changes the BG color instead of the FG! In fact, the odd behavior is -the one from the former example, non the latter. When you invert FG and BG with `|*` you actually -inverting their references. This is why the last example (which has a normal/dark BG!) allows `|!` -to change the BG color. In the first example, it's again the presence of an Xterm color (bright blue -BG) which changes the default behavior. - -Try this: - -`say Normal |* Negative |!R Red BG` - -This is the normal behavior, and as you can see it allows `|!` to change BG color after the -inversion of FG and BG. - -As long as you have an understanding of how ANSI works, it should be easy to handle color tags -avoiding the pitfalls of Xterm-ANSI promisquity. - -One last example: - -`say Normal |* Negative |* still Negative` - -Shows that `|*` only works once in a row and will not (and should not!) revert back if used again. -Nor it will have any effect until the `|n` tag is called to "reset" ANSI back to normal. This is how -it is meant to work. - -ANSI operates according to a simple states-based mechanism, and it's important to understand the -positive effect of resetting with the `|n` tag, and not try to -push it over the limit, so to speak. diff --git a/docs/0.9.5/_sources/Unit-Testing.md.txt b/docs/0.9.5/_sources/Unit-Testing.md.txt deleted file mode 100644 index 6a828e982f..0000000000 --- a/docs/0.9.5/_sources/Unit-Testing.md.txt +++ /dev/null @@ -1,435 +0,0 @@ -# Unit Testing - - -*Unit testing* means testing components of a program in isolation from each other to make sure every -part works on its own before using it with others. Extensive testing helps avoid new updates causing -unexpected side effects as well as alleviates general code rot (a more comprehensive wikipedia -article on unit testing can be found [here](http://en.wikipedia.org/wiki/Unit_test)). - -A typical unit test set calls some function or method with a given input, looks at the result and -makes sure that this result looks as expected. Rather than having lots of stand-alone test programs, -Evennia makes use of a central *test runner*. This is a program that gathers all available tests all -over the Evennia source code (called *test suites*) and runs them all in one go. Errors and -tracebacks are reported. - -By default Evennia only tests itself. But you can also add your own tests to your game code and have -Evennia run those for you. - -## Running the Evennia test suite - -To run the full Evennia test suite, go to your game folder and issue the command - - evennia test evennia - -This will run all the evennia tests using the default settings. You could also run only a subset of -all tests by specifying a subpackage of the library: - - evennia test evennia.commands.default - -A temporary database will be instantiated to manage the tests. If everything works out you will see -how many tests were run and how long it took. If something went wrong you will get error messages. -If you contribute to Evennia, this is a useful sanity check to see you haven't introduced an -unexpected bug. - -## Running tests with custom settings file - -If you have implemented your own tests for your game (see below) you can run them from your game dir -with - - evennia test . - -The period (`.`) means to run all tests found in the current directory and all subdirectories. You -could also specify, say, `typeclasses` or `world` if you wanted to just run tests in those subdirs. - -Those tests will all be run using the default settings. To run the tests with your own settings file -you must use the `--settings` option: - - evennia test --settings settings.py . - -The `--settings` option of Evennia takes a file name in the `mygame/server/conf` folder. It is -normally used to swap settings files for testing and development. In combination with `test`, it -forces Evennia to use this settings file over the default one. - -## Writing new tests - -Evennia's test suite makes use of Django unit test system, which in turn relies on Python's -*unittest* module. - -> If you want to help out writing unittests for Evennia, take a look at Evennia's [coveralls.io page](https://coveralls.io/github/evennia/evennia). There you see which modules have any form of -test coverage and which does not. - -To make the test runner find the tests, they must be put in a module named `test*.py` (so `test.py`, -`tests.py` etc). Such a test module will be found wherever it is in the package. It can be a good -idea to look at some of Evennia's `tests.py` modules to see how they look. - -Inside a testing file, a `unittest.TestCase` class is used to test a single aspect or component in -various ways. Each test case contains one or more *test methods* - these define the actual tests to -run. You can name the test methods anything you want as long as the name starts with "`test_`". -Your `TestCase` class can also have a method `setUp(self):`. This is run before each test, setting -up and storing whatever preparations the test methods need. Conversely, a `tearDown(self):` method -can optionally do cleanup after each test. - -To test the results, you use special methods of the `TestCase` class. Many of those start with -"`assert`", such as `assertEqual` or `assertTrue`. - -Example of a `TestCase` class: - -```python - import unittest - - # the function we want to test - from mypath import myfunc - - class TestObj(unittest.TestCase): - "This tests a function myfunc." - - def test_return_value(self): - "test method. Makes sure return value is as expected." - expected_return = "This is me being nice." - actual_return = myfunc() - # test - self.assertEqual(expected_return, actual_return) - def test_alternative_call(self): - "test method. Calls with a keyword argument." - expected_return = "This is me being baaaad." - actual_return = myfunc(bad=True) - # test - self.assertEqual(expected_return, actual_return) -``` - -You might also want to read the [documentation for the unittest module](http://docs.python.org/library/unittest.html). - -### Using the EvenniaTest class - -Evennia offers a custom TestCase, the `evennia.utils.test_resources.EvenniaTest` class. This class -initiates a range of useful properties on themselves for testing Evennia systems. Examples are -`.account` and `.session` representing a mock connected Account and its Session and `.char1` and -`.char2` representing Characters complete with a location in the test database. These are all useful -when testing Evennia system requiring any of the default Evennia typeclasses as inputs. See the full -definition of the `EvenniaTest` class in [evennia/utils/test_resources.py](https://github.com/evennia/evennia/blob/master/evennia/utils/test_resources.py). - -```python -# in a test module - -from evennia.utils.test_resources import EvenniaTest - -class TestObject(EvenniaTest): - def test_object_search(self): - # char1 and char2 are both created in room1 - self.assertEqual(self.char1.search(self.char2.key), self.char2) - self.assertEqual(self.char1.search(self.char1.location.key), self.char1.location) - # ... -``` - -### Testing in-game Commands - -In-game Commands are a special case. Tests for the default commands are put in -`evennia/commands/default/tests.py`. This uses a custom `CommandTest` class that inherits from -`evennia.utils.test_resources.EvenniaTest` described above. `CommandTest` supplies extra convenience -functions for executing commands and check that their return values (calls of `msg()` returns -expected values. It uses Characters and Sessions generated on the `EvenniaTest` class to call each -class). - -Each command tested should have its own `TestCase` class. Inherit this class from the `CommandTest` -class in the same module to get access to the command-specific utilities mentioned. - -```python - from evennia.commands.default.tests import CommandTest - from evennia.commands.default import general - class TestSet(CommandTest): - "tests the look command by simple call, using Char2 as a target" - def test_mycmd_char(self): - self.call(general.CmdLook(), "Char2", "Char2(#7)") - "tests the look command by simple call, with target as room" - def test_mycmd_room(self): - self.call(general.CmdLook(), "Room", - "Room(#1)\nroom_desc\nExits: out(#3)\n" - "You see: Obj(#4), Obj2(#5), Char2(#7)") -``` - -### Unit testing contribs with custom models - -A special case is if you were to create a contribution to go to the `evennia/contrib` folder that -uses its [own database models](./New-Models.md). The problem with this is that Evennia (and Django) will -only recognize models in `settings.INSTALLED_APPS`. If a user wants to use your contrib, they will -be required to add your models to their settings file. But since contribs are optional you cannot -add the model to Evennia's central `settings_default.py` file - this would always create your -optional models regardless of if the user wants them. But at the same time a contribution is a part -of the Evennia distribution and its unit tests should be run with all other Evennia tests using -`evennia test evennia`. - -The way to do this is to only temporarily add your models to the `INSTALLED_APPS` directory when the -test runs. here is an example of how to do it. - -> Note that this solution, derived from this [stackexchange answer](http://stackoverflow.com/questions/502916/django-how-to-create-a-model-dynamically-just-for-testing#503435) is currently untested! Please report your findings. - -```python -# a file contrib/mycontrib/tests.py - -from django.conf import settings -import django -from evennia.utils.test_resources import EvenniaTest - -OLD_DEFAULT_SETTINGS = settings.INSTALLED_APPS -DEFAULT_SETTINGS = dict( - INSTALLED_APPS=( - 'contrib.mycontrib.tests', - ), - DATABASES={ - "default": { - "ENGINE": "django.db.backends.sqlite3" - } - }, - SILENCED_SYSTEM_CHECKS=["1_7.W001"], - ) - -class TestMyModel(EvenniaTest): - def setUp(self): - - if not settings.configured: - settings.configure(**DEFAULT_SETTINGS) - django.setup() - - from django.core.management import call_command - from django.db.models import loading - loading.cache.loaded = False - call_command('syncdb', verbosity=0) - - def tearDown(self): - settings.configure(**OLD_DEFAULT_SETTINGS) - django.setup() - - from django.core.management import call_command - from django.db.models import loading - loading.cache.loaded = False - call_command('syncdb', verbosity=0) - - # test cases below ... - - def test_case(self): - # test case here -``` - -### A note on adding new tests - -Having an extensive tests suite is very important for avoiding code degradation as Evennia is -developed. Only a small fraction of the Evennia codebase is covered by test suites at this point. -Writing new tests is not hard, it's more a matter of finding the time to do so. So adding new tests -is really an area where everyone can contribute, also with only limited Python skills. - -### A note on making the test runner faster - -If you have custom models with a large number of migrations, creating the test database can take a -very long time. If you don't require migrations to run for your tests, you can disable them with the -django-test-without-migrations package. To install it, simply: - -``` -$ pip install django-test-without-migrations -``` - -Then add it to your `INSTALLED_APPS` in your `server.conf.settings.py`: - -```python -INSTALLED_APPS = ( - # ... - 'test_without_migrations', -) -``` - -After doing so, you can then run tests without migrations by adding the `--nomigrations` argument: - -``` -evennia test --settings settings.py --nomigrations . -``` - -## Testing for Game development (mini-tutorial) - -Unit testing can be of paramount importance to game developers. When starting with a new game, it is -recommended to look into unit testing as soon as possible; an already huge game is much harder to -write tests for. The benefits of testing a game aren't different from the ones regarding library -testing. For example it is easy to introduce bugs that affect previously working code. Testing is -there to ensure your project behaves the way it should and continue to do so. - -If you have never used unit testing (with Python or another language), you might want to check the -[official Python documentation about unit testing](https://docs.python.org/2/library/unittest.html), -particularly the first section dedicated to a basic example. - -### Basic testing using Evennia - -Evennia's test runner can be used to launch tests in your game directory (let's call it 'mygame'). -Evennia's test runner does a few useful things beyond the normal Python unittest module: - -* It creates and sets up an empty database, with some useful objects (accounts, characters and -rooms, among others). -* It provides simple ways to test commands, which can be somewhat tricky at times, if not tested -properly. - -Therefore, you should use the command-line to execute the test runner, while specifying your own -game directories (not the one containing evennia). Go to your game directory (referred as 'mygame' -in this section) and execute the test runner: - - evennia test --settings settings.py commands - -This command will execute Evennia's test runner using your own settings file. It will set up a dummy -database of your choice and look into the 'commands' package defined in your game directory -(`mygame/commands` in this example) to find tests. The test module's name should begin with 'test' -and contain one or more `TestCase`. A full example can be found below. - -### A simple example - -In your game directory, go to `commands` and create a new file `tests.py` inside (it could be named -anything starting with `test`). We will start by making a test that has nothing to do with Commands, -just to show how unit testing works: - -```python - # mygame/commands/tests.py - - import unittest - - class TestString(unittest.TestCase): - - """Unittest for strings (just a basic example).""" - - def test_upper(self): - """Test the upper() str method.""" - self.assertEqual('foo'.upper(), 'FOO') -``` - -This example, inspired from the Python documentation, is used to test the 'upper()' method of the -'str' class. Not very useful, but it should give you a basic idea of how tests are used. - -Let's execute that test to see if it works. - - > evennia test --settings settings.py commands - - TESTING: Using specified settings file 'server.conf.settings'. - - (Obs: Evennia's full test suite may not pass if the settings are very - different from the default. Use 'test .' as arguments to run only tests - on the game dir.) - - Creating test database for alias 'default'... - . - ---------------------------------------------------------------------- - Ran 1 test in 0.001s - - OK - Destroying test database for alias 'default'... - -We specified the `commands` package to the evennia test command since that's where we put our test -file. In this case we could just as well just said `.` to search all of `mygame` for testing files. -If we have a lot of tests it may be useful to test only a single set at a time though. We get an -information text telling us we are using our custom settings file (instead of Evennia's default -file) and then the test runs. The test passes! Change the "FOO" string to something else in the test -to see how it looks when it fails. - -### Testing commands - -This section will test the proper execution of the 'abilities' command, as described in the -[First Steps Coding](./First-Steps-Coding.md) page. Follow this tutorial to create the 'abilities' command, we -will need it to test it. - -Testing commands in Evennia is a bit more complex than the simple testing example we have seen. -Luckily, Evennia supplies a special test class to do just that ... we just need to inherit from it -and use it properly. This class is called 'CommandTest' and is defined in the -'evennia.commands.default.tests' package. To create a test for our 'abilities' command, we just -need to create a class that inherits from 'CommandTest' and add methods. - -We could create a new test file for this but for now we just append to the `tests.py` file we -already have in `commands` from before. - -```python - # bottom of mygame/commands/tests.py - - from evennia.commands.default.tests import CommandTest - - from commands.command import CmdAbilities - from typeclasses.characters import Character - - class TestAbilities(CommandTest): - - character_typeclass = Character - - def test_simple(self): - self.call(CmdAbilities(), "", "STR: 5, AGI: 4, MAG: 2") -``` - -* Line 1-4: we do some importing. 'CommandTest' is going to be our base class for our test, so we -need it. We also import our command ('CmdAbilities' in this case). Finally we import the -'Character' typeclass. We need it, since 'CommandTest' doesn't use 'Character', but -'DefaultCharacter', which means the character calling the command won't have the abilities we have -written in the 'Character' typeclass. -* Line 6-8: that's the body of our test. Here, a single command is tested in an entire class. -Default commands are usually grouped by category in a single class. There is no rule, as long as -you know where you put your tests. Note that we set the 'character_typeclass' class attribute to -Character. As explained above, if you didn't do that, the system would create a 'DefaultCharacter' -object, not a 'Character'. You can try to remove line 4 and 8 to see what happens when running the -test. -* Line 10-11: our unique testing method. Note its name: it should begin by 'test_'. Apart from -that, the method is quite simple: it's an instance method (so it takes the 'self' argument) but no -other arguments are needed. Line 11 uses the 'call' method, which is defined in 'CommandTest'. -It's a useful method that compares a command against an expected result. It would be like comparing -two strings with 'assertEqual', but the 'call' method does more things, including testing the -command in a realistic way (calling its hooks in the right order, so you don't have to worry about -that). - -Line 11 can be understood as: test the 'abilities' command (first parameter), with no argument -(second parameter), and check that the character using it receives his/her abilities (third -parameter). - -Let's run our new test: - - > evennia test --settings settings.py commands - [...] - Creating test database for alias 'default'... - .. - ---------------------------------------------------------------------- - Ran 2 tests in 0.156s - - OK - Destroying test database for alias 'default'... - -Two tests were executed, since we have kept 'TestString' from last time. In case of failure, you -will get much more information to help you fix the bug. - -### Testing Dynamic Output - -Having read the unit test tutorial on [Testing commands](./Unit-Testing.md#testing-commands) we can see -the code expects static unchanging numbers. While very good for learning it is unlikely a project -will have nothing but static output to test. Here we are going to learn how to test against dynamic -output.
- -This tutorial assumes you have a basic understanding of what regular expressions are. If you do not -I recommend reading the `Introduction` and `Simple Pattern` sections at -[Python regular expressions tutorial](https://docs.python.org/3/howto/regex.html). If you do plan on making a complete Evennia -project learning regular expressions will save a great deal of time.
- -Append the code below to your `tests.py` file.
- -```python - # bottom of mygame/commands/tests.py - - class TestDynamicAbilities(CommandTest): - - character_typeclass = Character - - def test_simple(self): - cmd_abil_result = self.call(CmdAbilities(), "") - self.assertRegex(cmd_abil_result, "STR: \d+, AGI: \d+, MAG: \d+") -``` - -Noticed that we removed the test string from `self.call`. That method always returns the string it -found from the commands output. If we remove the string to test against, all `self.call` will do is -return the screen output from the command object passed to it.
- -We are instead using the next line to test our command's output. -[assertRegex](https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertRegex) is a -method of `unittest.TestCase` this is inherited to `TestDynamicAbilities` from `CommandTest` who -inherited it from `EvenniaTest`.
- -What we are doing is testing the result of the `CmdAbilities` method or command against a regular -expression pattern. In this case, `"STR: \d+, AGI: \d+, MAG: \d+"`. `\d` in regular expressions or -regex are digits (numbers), the `+` is to state we want 1 or more of that pattern. Together `\d+` is -telling [assertRegex](https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertRegex) -that in that position of the string we expect 1 or more digits (numbers) to appear in the -string.
diff --git a/docs/0.9.5/_sources/Updating-Your-Game.md.txt b/docs/0.9.5/_sources/Updating-Your-Game.md.txt deleted file mode 100644 index ba85cf9d50..0000000000 --- a/docs/0.9.5/_sources/Updating-Your-Game.md.txt +++ /dev/null @@ -1,132 +0,0 @@ -# Updating Your Game - - -Fortunately, it's extremely easy to keep your Evennia server up-to-date. If you haven't already, see -the [Getting Started guide](./Getting-Started.md) and get everything running. - -### Updating with the latest Evennia code changes - -Very commonly we make changes to the Evennia code to improve things. There are many ways to get told -when to update: You can subscribe to the RSS feed or manually check up on the feeds from -http://www.evennia.com. You can also simply fetch the latest regularly. - -When you're wanting to apply updates, simply `cd` to your cloned `evennia` root directory and type: - - git pull - -assuming you've got the command line client. If you're using a graphical client, you will probably -want to navigate to the `evennia` directory and either right click and find your client's pull -function, or use one of the menus (if applicable). - -You can review the latest changes with - - git log - -or the equivalent in the graphical client. You can also see the latest changes online -[here](https://github.com/evennia/evennia/blob/master/CHANGELOG.md). - -You will always need to do `evennia reload` (or `reload` from -in-game) from your game-dir to have -the new code affect your game. If you want to be really sure you should run a full `evennia reboot` -so that both Server and Portal can restart (this will disconnect everyone though, so if you know the -Portal has had no updates you don't have to do that). - -### Upgrading Evennia dependencies - -On occasion we update the versions of third-party libraries Evennia depend on (or we may add a new -dependency). This will be announced on the mailing list/forum. If you run into errors when starting -Evennia, always make sure you have the latest versions of everything. In some cases, like for -Django, starting the server may also give warning saying that you are using a working, but too-old -version that should not be used in production. - -Upgrading `evennia` will automatically fetch all the latest packages that it now need. First `cd` to -your cloned `evennia` folder. Make sure your `virtualenv` is active and use - - pip install --upgrade -e . - -Remember the period (`.`) at the end - that applies the upgrade to the current location (your -`evennia` dir). - -> The `-e` means that we are _linking_ the evennia sources rather than copying them into the -environment. This means we can most of the time just update the sources (with `git pull`) and see -those changes directly applied to our installed `evennia` package. Without installing/upgrading the -package with `-e`, we would have to remember to upgrade the package every time we downloaded any new -source-code changes. - -Follow the upgrade output to make sure it finishes without errors. To check what packages are -currently available in your python environment after the upgrade, use - - pip list - -This will show you the version of all installed packages. The `evennia` package will also show the -location of its source code. - -## Migrating the Database Schema - -Whenever we change the database layout of Evennia upstream (such as when we add new features) you -will need to *migrate* your existing database. When this happens it will be clearly noted in the -`git log` (it will say something to the effect of "Run migrations"). Database changes will also be -announced on the Evennia [mailing list](https://groups.google.com/forum/#!forum/evennia). - -When the database schema changes, you just go to your game folder and run - - evennia migrate - -> Hint: If the `evennia` command is not found, you most likely need to activate your -[virtualenv](./Glossary.md#virtualenv). - -## Resetting your database - -Should you ever want to start over completely from scratch, there is no need to re-download Evennia -or anything like that. You just need to clear your database. Once you are done, you just rebuild it -from scratch as described in the second step of the [Getting Started guide](./Getting-Started.md). - -First stop a running server with - - evennia stop - -If you run the default `SQlite3` database (to change this you need to edit your `settings.py` file), -the database is actually just a normal file in `mygame/server/` called `evennia.db3`. *Simply delete -that file* - that's it. Now run `evennia migrate` to recreate a new, fresh one. - -If you run some other database system you can instead flush the database: - - evennia flush - -This will empty the database. However, it will not reset the internal counters of the database, so -you will start with higher dbref values. If this is okay, this is all you need. - -Django also offers an easy way to start the database's own management should we want more direct -control: - - evennia dbshell - -In e.g. MySQL you can then do something like this (assuming your MySQL database is named "Evennia": - - mysql> DROP DATABASE Evennia; - mysql> exit - -> NOTE: Under Windows OS, in order to access SQLite dbshell you need to [download the SQLite -command-line shell program](https://www.sqlite.org/download.html). It's a single executable file -(sqlite3.exe) that you should place in the root of either your MUD folder or Evennia's (it's the -same, in both cases Django will find it). - -## More about schema migrations - -If and when an Evennia update modifies the database *schema* (that is, the under-the-hood details as -to how data is stored in the database), you must update your existing database correspondingly to -match the change. If you don't, the updated Evennia will complain that it cannot read the database -properly. Whereas schema changes should become more and more rare as Evennia matures, it may still -happen from time to time. - -One way one could handle this is to apply the changes manually to your database using the database's -command line. This often means adding/removing new tables or fields as well as possibly convert -existing data to match what the new Evennia version expects. It should be quite obvious that this -quickly becomes cumbersome and error-prone. If your database doesn't contain anything critical yet -it's probably easiest to simply reset it and start over rather than to bother converting. - -Enter *migrations*. Migrations keeps track of changes in the database schema and applies them -automatically for you. Basically, whenever the schema changes we distribute small files called -"migrations" with the source. Those tell the system exactly how to implement the change so you don't -have to do so manually. When a migration has been added we will tell you so on Evennia's mailing -lists and in commit messages - -you then just run `evennia migrate` to be up-to-date again. diff --git a/docs/0.9.5/_sources/Using-MUX-as-a-Standard.md.txt b/docs/0.9.5/_sources/Using-MUX-as-a-Standard.md.txt deleted file mode 100644 index fb27e619b7..0000000000 --- a/docs/0.9.5/_sources/Using-MUX-as-a-Standard.md.txt +++ /dev/null @@ -1,85 +0,0 @@ -# Using MUX as a Standard - - -Evennia allows for any command syntax. If you like the way DikuMUDs, LPMuds or MOOs handle things, -you could emulate that with Evennia. If you are ambitious you could even design a whole new style, -perfectly fitting your own dreams of the ideal game. - -We do offer a default however. The default Evennia setup tends to *resemble* -[MUX2](http://www.tinymux.org/), and its cousins [PennMUSH](http://www.pennmush.org), -[TinyMUSH](http://tinymush.sourceforge.net/), and [RhostMUSH](http://www.rhostmush.org/). While the -reason for this similarity is partly historical, these codebases offer very mature feature sets for -administration and building. - -Evennia is *not* a MUX system though. It works very differently in many ways. For example, Evennia -deliberately lacks an online softcode language (a policy explained on our [softcode policy -page](./Soft-Code.md)). Evennia also does not shy from using its own syntax when deemed appropriate: the -MUX syntax has grown organically over a long time and is, frankly, rather arcane in places. All in -all the default command syntax should at most be referred to as "MUX-like" or "MUX-inspired". - -## Documentation policy - -All the commands in the default command sets should have their doc-strings formatted on a similar -form: - -```python - """ - Short header - - Usage: - key[/switches, if any] [optional] choice1||choice2||choice3 - - Switches: - switch1 - description - switch2 - description - - Examples: - usage example and output - - Longer documentation detailing the command. - - """ -``` - -- Two spaces are used for *indentation* in all default commands. -- Square brackets `[ ]` surround *optional, skippable arguments*. -- Angled brackets `< >` surround a _description_ of what to write rather than the exact syntax. -- *Explicit choices are separated by `|`. To avoid this being parsed as a color code, use `||` (this -will come out as a single `|`) or put spaces around the character ("` | `") if there's plenty of -room. -- The `Switches` and `Examples` blocks are optional based on the Command. - -Here is the `nick` command as an example: - -```python - """ - Define a personal alias/nick - - Usage: - nick[/switches] = [] - alias '' - - Switches: - object - alias an object - account - alias an account - clearall - clear all your aliases - list - show all defined aliases (also "nicks" works) - - Examples: - nick hi = say Hello, I'm Sarah! - nick/object tom = the tall man - - A 'nick' is a personal shortcut you create for your own use [...] - - """ -``` - -For commands that *require arguments*, the policy is for it to return a `Usage:` string if the -command is entered without any arguments. So for such commands, the Command body should contain -something to the effect of - -```python - if not self.args: - self.caller.msg("Usage: nick[/switches] = []") - return -``` diff --git a/docs/0.9.5/_sources/Using-Travis.md.txt b/docs/0.9.5/_sources/Using-Travis.md.txt deleted file mode 100644 index c867933ab6..0000000000 --- a/docs/0.9.5/_sources/Using-Travis.md.txt +++ /dev/null @@ -1,37 +0,0 @@ -# Using Travis - -Evennia uses [Travis CI](http://travis-ci.org/) to check that it's building successfully after every -commit to its Github repository (you can for example see the `build: passing` badge at the top of -Evennia's [Readme file](https://github.com/evennia/evennia)). If your game is open source on Github -you may use Travis for free. See [the Travis docs](http://docs.travis-ci.com/user/getting-started/) -for how to get started. - -After logging in you need to point Travis to your repository on github. One further thing you need -to set up yourself is a Travis config file named `.travis.yml` (note the initial period `.`). This -should be created in the _root_ of your game directory. - -``` yaml -dist: xenial -language: python -cache: pip - -python: - - "3.7" - - "3.8" - -install: - - git clone https://github.com/evennia/evennia.git ../evennia - - pip install -e ../evennia - -script: - - evennia test --settings settings.py - -``` - -Here we tell Travis how to download and install Evennia into a folder a level up from your game dir. -It will then install the server (so the `evennia` command is available) and run the tests only for -your game dir (based on your `settings.py` file in `server/conf/`). - -Running this will not actually do anything though, because there are no unit tests in your game dir -yet. [We have a page](./Unit-Testing.md) on how we set those up for Evennia, you should be able to refer -to that for making tests fitting your game. \ No newline at end of file diff --git a/docs/0.9.5/_sources/Version-Control.md.txt b/docs/0.9.5/_sources/Version-Control.md.txt deleted file mode 100644 index 1e8ddb32e4..0000000000 --- a/docs/0.9.5/_sources/Version-Control.md.txt +++ /dev/null @@ -1,475 +0,0 @@ -# Version Control - - -Version control software allows you to track the changes you make to your code, as well as being -able to easily backtrack these changes, share your development efforts and more. Even if you are not -contributing to Evennia itself, and only wish to develop your own MU* using Evennia, having a -version control system in place is a good idea (and standard coding practice). For an introduction -to the concept, start with the Wikipedia article -[here](http://en.wikipedia.org/wiki/Version_control). Evennia uses the version control system -[Git](https://git-scm.com/) and this is what will be covered henceforth. Note that this page also -deals with commands for Linux operating systems, and the steps below may vary for other systems, -however where possible links will be provided for alternative instructions. - -For more help on using Git, please refer to the [Official GitHub -documentation](https://help.github.com/articles/set-up-git#platform-all). - -## Setting up Git - -If you have gotten Evennia installed, you will have Git already and can skip to **Step 2** below. -Otherwise you will need to install Git on your platform. You can find expanded instructions for -installation [here](http://git-scm.com/book/en/Getting-Started-Installing-Git). - -### Step 1: Install Git - -- **Fedora Linux** - - yum install git-core - -- **Debian Linux** _(Ubuntu, Linux Mint, etc.)_ - - apt-get install git - -- **Windows**: It is recommended to use [Git for Windows](http://msysgit.github.io/). -- **Mac**: Mac platforms offer two methods for installation, one via MacPorts, which you can find -out about [here](http://git-scm.com/book/en/Getting-Started-Installing-Git#Installing-on-Mac), or -you can use the [Git OSX Installer](https://sourceforge.net/projects/git-osx-installer/). - -### Step 2: Define user/e-mail Settings for Git - -To avoid a common issue later, you will need to set a couple of settings; first you will need to -tell Git your username, followed by your e-mail address, so that when you commit code later you will -be properly credited. - -> Note that your commit information will be visible to everyone if you ever contribute to Evennia or -use an online service like github to host your code. So if you are not comfortable with using your -real, full name online, put a nickname here. - -1. Set the default name for git to use when you commit: - - git config --global user.name "Your Name Here" - -2. Set the default email for git to use when you commit: - - git config --global user.email "your_email@example.com" - - -## Putting your game folder under version control - -> Note: The game folder's version control is completely separate from Evennia's repository. - -After you have set up your game you will have created a new folder to host your particular game -(let's call this folder `mygame` for now). - -This folder is *not* under version control at this point. - - git init mygame - -Your mygame folder is now ready for version control! Now add all the content and make a first -commit: - - cd mygame - git add * - git commit -m "Initial commit" - -Read on for help on what these commands do. - - -### Tracking files - -When working on your code or fix bugs in your local branches you may end up creating new files. If -you do you must tell Git to track them by using the add command: - -``` -git add -``` - -You can check the current status of version control with `git status`. This will show if you have -any modified, added or otherwise changed files. Some files, like database files, logs and temporary -PID files are usually *not* tracked in version control. These should either not show up or have a -question mark in front of them. - -### Controlling tracking - -You will notice that some files are not covered by your git version control, notably your settings -file (`mygame/server/conf/settings.py`) and your sqlite3 database file `mygame/server/evennia.db3`. -This is controlled by the hidden file `mygame/.gitignore`. Evennia creates this file as part of the -creation of your game directory. Everything matched in this file will be ignored by GIT. If you want -to, for example, include your settings file for collaborators to access, remove that entry in -`.gitignore`. - -> Note: You should *never* put your sqlite3 database file into git by removing its entry in -`.gitignore`. GIT is for backing up your code, not your database. That way lies madness and a good -chance you'll confuse yourself so that after a few commits and reverts don't know what is in your -database or not. If you want to backup your database, do so by simply copying the file on your hard -drive to a backup-name. - -### Committing your Code - -> Committing means storing the current snapshot of your code within git. This creates a "save point" -or "history" of your development process. You can later jump back and forth in your history, for -example to figure out just when a bug was introduced or see what results the code used to produce -compared to now. - -It's usually a good idea to commit your changes often. Committing is fast and local only - you will -never commit anything online at this point. To commit your changes, use - -``` -git commit --all -``` - -This will save all changes you made since last commit. The command will open a text editor where you -can add a message detailing the changes you've made. Make it brief but informative. You can see the -history of commits with `git log`. If you don't want to use the editor you can set the message -directly by using the `-m` flag: - -``` -git commit --all -m "This fixes a bug in the combat code." -``` - -### Changing your mind - -If you have non-committed changes that you realize you want to throw away, you can do the following: - -``` -git checkout -``` - -This will revert the file to the state it was in at your last `commit`, throwing away the changes -you did to it since. It's a good way to make wild experiments without having to remember just what -you changed. If you do ` git checkout .` you will throw away _all_ changes since the last commit. - -### Pushing your code online - -So far your code is only located on your private machine. A good idea is to back it up online. The -easiest way to do this is to push it to your own remote repository on GitHub. - -1. Make sure you have your game directory setup under git version control as described above. Make -sure to commit any changes. -2. Create a new, empty repository on Github. Github explains how -[here](https://help.github.com/articles/create-a-repo/) (do *not* "Initialize the repository with a -README" or else you'll create unrelated histories). -3. From your local game dir, do `git remote add origin ` where `` is the URL -to your online repo. This tells your game dir that it should be pushing to the remote online dir. -4. `git remote -v` to verify the online dir. -5. `git push origin master` now pushes your game dir online so you can see it on github.com. - -You can commit your work locally (`git commit --all -m "Make a change that ..."`) as many times as -you want. When you want to push those changes to your online repo, you do `git push`. You can also -`git clone ` from your online repo to somewhere else (like your production -server) and henceforth do `git pull` to update that to the latest thing you pushed. - -Note that GitHub's repos are, by default publicly visible by all. Creating a publicly visible online -clone might not be what you want for all parts of your development process - you may prefer a more -private venue when sharing your revolutionary work with your team. If that's the case you can change -your repository to "Private" in the github settings. Then your code will only be visible to those -you specifically grant access. - - -## Forking Evennia - -This helps you set up an online *fork* of Evennia so you can easily commit fixes and help with -upstream development. - -### Step 1: Fork the evennia/master repository - -> Before proceeding with the following step, make sure you have registered and created an account on -[GitHub.com](https://github.com/). This is necessary in order to create a fork of Evennia's master -repository, and to push your commits to your fork either for yourself or for contributing to -Evennia. - -A _fork_ is a clone of the master repository that you can make your own commits and changes to. At -the top of [this page](https://github.com/evennia/evennia), click the "Fork" button, as it appears -below. ![](https://github-images.s3.amazonaws.com/help/bootcamp/Bootcamp-Fork.png) - -### Step 2: Clone your fork - -The fork only exists online as of yet. In a terminal, change your directory to the folder you wish -to develop in. From this directory run the following command: - -``` -git clone https://github.com/yourusername/evennia.git -``` - -This will download your fork to your computer. It creates a new folder `evennia/` at your current -location. - -### Step 3: Configure remotes - -A _remote_ is a repository stored on another computer, in this case on GitHub's server. When a -repository is cloned, it has a default remote called `origin`. This points to your fork on GitHub, -not the original repository it was forked from. To easily keep track of the original repository -(that is, Evennia's official repository), you need to add another remote. The standard name for this -remote is "upstream". - -Below we change the active directory to the newly cloned "evennia" directory and then assign the -original Evennia repository to a remote called "upstream": - -``` -cd evennia -git remote add upstream https://github.com/evennia/evennia.git -``` - -If you also want to access Evennia's `develop` branch (the bleeding edge development branch) do the -following: - -``` -git fetch upstream develop -git checkout develop -``` - -You should now have the upstream branch available locally. You can use this instead of `master` -below if you are contributing new features rather than bug fixes. - - -## Working with your fork - -> A _branch_ is a separate instance of your code. Changes you do to code in a branch does not affect -that in other branches (so if you for example add/commit a file to one branch and then switches to -another branch, that file will be gone until you switch back to the first branch again). One can -switch between branches at will and create as many branches as one needs for a given project. The -content of branches can also be merged together or deleted without affecting other branches. This is -not only a common way to organize development but also to test features without messing with -existing code. - -The default _branch_ of git is called the "master" branch. As a rule of thumb, you should *never* -make modifications directly to your local copy of the master branch. Rather keep the master clean -and only update it by pulling our latest changes to it. Any work you do should instead happen in a -local, other branches. - -### Making a work branch - -``` -git checkout -b myfixes -``` - -This command will checkout and automatically create the new branch `myfixes` on your machine. If you -stared out in the master branch, *myfixes* will be a perfect copy of the master branch. You can see -which branch you are on with `git branch` and change between different branches with `git checkout -`. - -Branches are fast and cheap to create and manage. It is common practice to create a new branch for -every bug you want to work on or feature you want to create, then create a *pull request* for that -branch to be merged upstream (see below). Not only will this organize your work, it will also make -sure that *your* master branch version of Evennia is always exactly in sync with the upstream -version's master branch. - -### Updating with upstream changes - -When Evennia's official repository updates, first make sure to commit all your changes to your -branch and then checkout the "clean" master branch: - -``` -git commit --all -git checkout master -``` - -Pull the latest changes from upstream: - -``` -git pull upstream master -``` - -This should sync your local master branch with upstream Evennia's master branch. Now we go back to -our own work-branch (let's say it's still called "myfixes") and _merge_ the updated master into our -branch. - -``` -git checkout myfixes -git merge master -``` - -If everything went well, your `myfixes` branch will now have the latest version of Evennia merged -with whatever changes you have done. Use `git log` to see what has changed. You may need to restart -the server or run `manage.py migrate` if the database schema changed (this will be seen in the -commit log and on the mailing list). See the [Git manuals](http://git-scm.com/documentation) for -learning more about useful day-to-day commands, and special situations such as dealing with merge -collisions. - -## Sharing your Code Publicly - -Up to this point your `myfixes` branch only exists on your local computer. No one else can see it. -If you want a copy of this branch to also appear in your online fork on GitHub, make sure to have -checked out your "myfixes" branch and then run the following: - -``` -git push -u origin myfixes -``` - -This will create a new _remote branch_ named "myfixes" in your online repository (which is refered -to as "origin" by default); the `-u` flag makes sure to set this to the default push location. -Henceforth you can just use `git push` from your myfixes branch to push your changes online. This is -a great way to keep your source backed-up and accessible. Remember though that by default your -repository will be public so everyone will be able to browse and download your code (same way as you -can with Evennia itself). If you want secrecy you can change your repository to "Private" in the -Github settings. Note though that if you do, you might have trouble contributing to Evennia (since -we can't see the code you want to share). - -*Note: If you hadn't setup a public key on GitHub or aren't asked for a username/password, you might -get an error `403: Forbidden Access` at this stage. In that case, some users have reported that the -workaround is to create a file `.netrc` under your home directory and add your credentials there:* - -```bash -machine github.com -login -password -``` - -## Committing fixes to Evennia - -_Contributing_ can mean both bug-fixes or adding new features to Evennia. Please note that if your -change is not already listed and accepted in the [Issue -Tracker](https://github.com/evennia/evennia/issues), it is recommended that you first hit the -developer mailing list or IRC chat to see beforehand if your feature is deemed suitable to include -as a core feature in the engine. When it comes to bug-fixes, other developers may also have good -input on how to go about resolving the issue. - -To contribute you need to have [forked Evennia](./Version-Control.md#forking-evennia) first. As described -above you should do your modification in a separate local branch (not in the master branch). This -branch is what you then present to us (as a *Pull request*, PR, see below). We can then merge your -change into the upstream master and you then do `git pull` to update master usual. Now that the -master is updated with your fixes, you can safely delete your local work branch. Below we describe -this work flow. - -First update the Evennia master branch to the latest Evennia version: - -``` -git checkout master -git pull upstream master -``` - -Next, create a new branch to hold your contribution. Let's call it the "fixing_strange_bug" branch: - -``` -git checkout -b fixing_strange_bug -``` - -It is wise to make separate branches for every fix or series of fixes you want to contribute. You -are now in your new `fixing_strange_bug` branch. You can list all branches with `git branch` and -jump between branches with `git checkout `. Code and test things in here, committing as -you go: - -``` -git commit --all -m "Fix strange bug in look command. Resolves #123." -``` - -You can make multiple commits if you want, depending on your work flow and progress. Make sure to -always make clear and descriptive commit messages so it's easy to see what you intended. To refer -to, say, issue number 123, write `#123`, it will turn to a link on GitHub. If you include the text -"Resolves #123", that issue will be auto-closed on GitHub if your commit gets merged into main -Evennia. - ->If you refer to in-game commands that start with `@`(such as `@examine`), please put them in -backticks \`, for example \`@examine\`. The reason for this is that GitHub uses `@username` to refer -to GitHub users, so if you forget the ticks, any user happening to be named `examine` will get a -notification .... - -If you implement multiple separate features/bug-fixes, split them into different branches if they -are very different and should be handled as separate PRs. You can do any number of commits to your -branch as you work. Once you are at a stage where you want to show the world what you did you might -want to consider making it clean for merging into Evennia's master branch by using [git -rebase](https://www.git-scm.com/book/en/v2/Git-Branching-Rebasing) (this is not always necessary, -and if it sounds too hard, say so and we'll handle it on our end). - -Once you are ready, push your work to your online Evennia fork on github, in a new remote branch: - -``` -git push -u origin fixing_strange_bug -``` - -The `-u` flag is only needed the first time - this tells GIT to create a remote branch. If you -already created the remote branch earlier, just stand in your `fixing_strange_bug` branch and do -`git push`. - -Now you should tell the Evennia developers that they should consider merging your brilliant changes -into Evennia proper. [Create a pull request](https://github.com/evennia/evennia/pulls) and follow -the instructions. Make sure to specifically select your `fixing_strange_bug` branch to be the source -of the merge. Evennia developers will then be able to examine your request and merge it if it's -deemed suitable. - -Once your changes have been merged into Evennia your local `fixing_strange_bug` can be deleted -(since your changes are now available in the "clean" Evennia repository). Do - -``` -git branch -D fixing_strange_bug -``` - -to delete your work branch. Update your master branch (`checkout master` and then `git pull`) and -you should get your fix back, now as a part of official Evennia! - - -## GIT tips and tricks - -Some of the GIT commands can feel a little long and clunky if you need to do them often. Luckily you -can create aliases for those. Here are some useful commands to run: - - -``` -# git st -# - view brief status info -git config --global alias.st 'status -s' -``` - -Above, you only need to ever enter the `git config ...` command once - you have then added the new -alias. Afterwards, just do `git st` to get status info. All the examples below follow the same -template. - -``` -# git cl -# - clone a repository -git config --global alias.cl clone -``` - -``` -# git cma "commit message" -# - commit all changes without opening editor for message -git config --global alias.cma 'commit -a -m' -``` - -``` -# git ca -# - amend text to your latest commit message -git config --global alias.ca 'commit --amend' -``` - -``` -# git fl -# - file log; shows diffs of files in latest commits -git config --global alias.fl 'log -u' -``` - -``` -# git co [branchname] -# - checkout -git config --global alias.co checkout -``` - -``` -# git br -# - create branch -git config --global alias.br branch -``` - -``` -# git ls -# - view log tree -git config --global alias.ls 'log --pretty=format:"%C(green)%h\ %C(yellow)[%ad]%Cred%d\ -%Creset%s%Cblue\ [%cn]" --decorate --date=relative --graph' -``` - -``` -# git diff -# - show current uncommitted changes -git config --global alias.diff 'diff --word-diff' -``` - -``` -# git grep -# - search (grep) codebase for a search criterion -git config --global alias.grep 'grep -Ii' -``` - -To get a further feel for GIT there is also [a good YouTube talk about -it](https://www.youtube.com/watch?v=1ffBJ4sVUb4#t=1m58s) - it's a bit long but it will help you -understand the underlying ideas behind GIT -(which in turn makes it a lot more intuitive to use). diff --git a/docs/0.9.5/_sources/Weather-Tutorial.md.txt b/docs/0.9.5/_sources/Weather-Tutorial.md.txt deleted file mode 100644 index b8da86932c..0000000000 --- a/docs/0.9.5/_sources/Weather-Tutorial.md.txt +++ /dev/null @@ -1,54 +0,0 @@ -# Weather Tutorial - - -This tutorial will have us create a simple weather system for our MUD. The way we want to use this -is to have all outdoor rooms echo weather-related messages to the room at regular and semi-random -intervals. Things like "Clouds gather above", "It starts to rain" and so on. - -One could imagine every outdoor room in the game having a script running on themselves that fires -regularly. For this particular example it is however more efficient to do it another way, namely by -using a "ticker-subscription" model. The principle is simple: Instead of having each Object -individually track the time, they instead subscribe to be called by a global ticker who handles time -keeping. Not only does this centralize and organize much of the code in one place, it also has less -computing overhead. - -Evennia offers the [TickerHandler](./TickerHandler.md) specifically for using the subscription model. We -will use it for our weather system. - -We will assume you know how to make your own Typeclasses. If not see one of the beginning tutorials. -We will create a new WeatherRoom typeclass that is aware of the day-night cycle. - -```python - - import random - from evennia import DefaultRoom, TICKER_HANDLER - - ECHOES = ["The sky is clear.", - "Clouds gather overhead.", - "It's starting to drizzle.", - "A breeze of wind is felt.", - "The wind is picking up"] # etc - - class WeatherRoom(DefaultRoom): - "This room is ticked at regular intervals" - - def at_object_creation(self): - "called only when the object is first created" - TICKER_HANDLER.add(60 * 60, self.at_weather_update) - - def at_weather_update(self, *args, **kwargs): - "ticked at regular intervals" - echo = random.choice(ECHOES) - self.msg_contents(echo) -``` - -In the `at_object_creation` method, we simply added ourselves to the TickerHandler and tell it to -call `at_weather_update` every hour (`60*60` seconds). During testing you might want to play with a -shorter time duration. - -For this to work we also create a custom hook `at_weather_update(*args, **kwargs)`, which is the -call sign required by TickerHandler hooks. - -Henceforth the room will inform everyone inside it when the weather changes. This particular example -is of course very simplistic - the weather echoes are just randomly chosen and don't care what -weather came before it. Expanding it to be more realistic is a useful exercise. diff --git a/docs/0.9.5/_sources/Web-Character-Generation.md.txt b/docs/0.9.5/_sources/Web-Character-Generation.md.txt deleted file mode 100644 index ed417ce9c2..0000000000 --- a/docs/0.9.5/_sources/Web-Character-Generation.md.txt +++ /dev/null @@ -1,637 +0,0 @@ -# Web Character Generation - - -## Introduction - -This tutorial will create a simple web-based interface for generating a new in-game Character. -Accounts will need to have first logged into the website (with their `AccountDB` account). Once -finishing character generation the Character will be created immediately and the Accounts can then -log into the game and play immediately (the Character will not require staff approval or anything -like that). This guide does not go over how to create an AccountDB on the website with the right -permissions to transfer to their web-created characters. - -It is probably most useful to set `MULTISESSION_MODE = 2` or `3` (which gives you a character- -selection screen when you log into the game later). Other modes can be used with some adaptation to -auto-puppet the new Character. - -You should have some familiarity with how Django sets up its Model Template View framework. You need -to understand what is happening in the basic [Web Character View tutorial](./Web-Character-View-Tutorial.md). If you don’t understand the listed tutorial or have a grasp of Django basics, please look -at the [Django tutorial](https://docs.djangoproject.com/en/1.8/intro/) to get a taste of what Django -does, before throwing Evennia into the mix (Evennia shares its API and attributes with the website -interface). This guide will outline the format of the models, views, urls, and html templates -needed. - -## Pictures - -Here are some screenshots of the simple app we will be making. - -Index page, with no character application yet done: - -*** -![Index page, with no character application yet done.](https://lh3.googleusercontent.com/-57KuSWHXQ_M/VWcULN152tI/AAAAAAAAEZg/kINTmVlHf6M/w425-h189-no/webchargen_index2.gif) -*** - -Having clicked the "create" link you get to create your character (here we will only have name and -background, you can add whatever is needed to fit your game): - -*** -![Character creation.](https://lh3.googleusercontent.com/-ORiOEM2R_yQ/VWcUKgy84rI/AAAAAAAAEZY/B3CBh3FHii4/w607-h60-no/webchargen_creation.gif) -*** - -Back to the index page. Having entered our character application (we called our character "TestApp") -you see it listed: - -*** -![Having entered an application.](https://lh6.googleusercontent.com/-HlxvkvAimj4/VWcUKjFxEiI/AAAAAAAAEZo/gLppebr05JI/w321-h194-no/webchargen_index1.gif) -*** - -We can also view an already written character application by clicking on it - this brings us to the -*detail* page: - -*** -![Detail view of character application.](https://lh6.googleusercontent.com/-2m1UhSE7s_k/VWcUKfLRfII/AAAAAAAAEZc/UFmBOqVya4k/w267-h175-no/webchargen_detail.gif) -*** - -## Installing an App - -Assuming your game is named "mygame", navigate to your `mygame/` directory, and type: - - evennia startapp chargen - -This will initialize a new Django app we choose to call "chargen". It is directory containing some -basic starting things Django needs. You will need to move this directory: for the time being, it is -in your `mygame` directory. Better to move it in your `mygame/web` directory, so you have -`mygame/web/chargen` in the end. - -Next, navigate to `mygame/server/conf/settings.py` and add or edit the following line to make -Evennia (and Django) aware of our new app: - - INSTALLED_APPS += ('web.chargen',) - -After this, we will get into defining our *models* (the description of the database storage), -*views* (the server-side website content generators), *urls* (how the web browser finds the pages) -and *templates* (how the web page should be structured). - -### Installing - Checkpoint: - -* you should have a folder named `chargen` or whatever you chose in your mygame/web/ directory -* you should have your application name added to your INSTALLED_APPS in settings.py - -## Create Models - -Models are created in `mygame/web/chargen/models.py`. - -A [Django database model](./New-Models.md) is a Python class that describes the database storage of the -data you want to manage. Any data you choose to store is stored in the same database as the game and -you have access to all the game's objects here. - -We need to define what a character application actually is. This will differ from game to game so -for this tutorial we will define a simple character sheet with the following database fields: - - -* `app_id` (AutoField): Primary key for this character application sheet. -* `char_name` (CharField): The new character's name. -* `date_applied` (DateTimeField): Date that this application was received. -* `background` (TextField): Character story background. -* `account_id` (IntegerField): Which account ID does this application belong to? This is an -AccountID from the AccountDB object. -* `submitted` (BooleanField): `True`/`False` depending on if the application has been submitted yet. - -> Note: In a full-fledged game, you’d likely want them to be able to select races, skills, -attributes and so on. - -Our `models.py` file should look something like this: - -```python -# in mygame/web/chargen/models.py - -from django.db import models - -class CharApp(models.Model): - app_id = models.AutoField(primary_key=True) - char_name = models.CharField(max_length=80, verbose_name='Character Name') - date_applied = models.DateTimeField(verbose_name='Date Applied') - background = models.TextField(verbose_name='Background') - account_id = models.IntegerField(default=1, verbose_name='Account ID') - submitted = models.BooleanField(default=False) -``` - -You should consider how you are going to link your application to your account. For this tutorial, -we are using the account_id attribute on our character application model in order to keep track of -which characters are owned by which accounts. Since the account id is a primary key in Evennia, it -is a good candidate, as you will never have two of the same IDs in Evennia. You can feel free to use -anything else, but for the purposes of this guide, we are going to use account ID to join the -character applications with the proper account. - -### Model - Checkpoint: - -* you should have filled out `mygame/web/chargen/models.py` with the model class shown above -(eventually adding fields matching what you need for your game). - -## Create Views - -*Views* are server-side constructs that make dynamic data available to a web page. We are going to -add them to `mygame/web/chargen.views.py`. Each view in our example represents the backbone of a -specific web page. We will use three views and three pages here: - -* The index (managing `index.html`). This is what you see when you navigate to -`http://yoursite.com/chargen`. -* The detail display sheet (manages `detail.html`). A page that passively displays the stats of a -given Character. -* Character creation sheet (manages `create.html`). This is the main form with fields to fill in. - -### *Index* view - -Let’s get started with the index first. - -We’ll want characters to be able to see their created characters so let’s - -```python -# file mygame/web/chargen.views.py - -from .models import CharApp - -def index(request): - current_user = request.user # current user logged in - p_id = current_user.id # the account id - # submitted Characters by this account - sub_apps = CharApp.objects.filter(account_id=p_id, submitted=True) - context = {'sub_apps': sub_apps} - # make the variables in 'context' available to the web page template - return render(request, 'chargen/index.html', context) -``` - -### *Detail* view - -Our detail page will have pertinent character application information our users can see. Since this -is a basic demonstration, our detail page will only show two fields: - -* Character name -* Character background - -We will use the account ID again just to double-check that whoever tries to check our character page -is actually the account who owns the application. - -```python -# file mygame/web/chargen.views.py - -def detail(request, app_id): - app = CharApp.objects.get(app_id=app_id) - name = app.char_name - background = app.background - submitted = app.submitted - p_id = request.user.id - context = {'name': name, 'background': background, - 'p_id': p_id, 'submitted': submitted} - return render(request, 'chargen/detail.html', context) -``` - -## *Creating* view - -Predictably, our *create* function will be the most complicated of the views, as it needs to accept -information from the user, validate the information, and send the information to the server. Once -the form content is validated will actually create a playable Character. - -The form itself we will define first. In our simple example we are just looking for the Character's -name and background. This form we create in `mygame/web/chargen/forms.py`: - -```python -# file mygame/web/chargen/forms.py - -from django import forms - -class AppForm(forms.Form): - name = forms.CharField(label='Character Name', max_length=80) - background = forms.CharField(label='Background') -``` - -Now we make use of this form in our view. - -```python -# file mygame/web/chargen/views.py - -from web.chargen.models import CharApp -from web.chargen.forms import AppForm -from django.http import HttpResponseRedirect -from datetime import datetime -from evennia.objects.models import ObjectDB -from django.conf import settings -from evennia.utils import create - -def creating(request): - user = request.user - if request.method == 'POST': - form = AppForm(request.POST) - if form.is_valid(): - name = form.cleaned_data['name'] - background = form.cleaned_data['background'] - applied_date = datetime.now() - submitted = True - if 'save' in request.POST: - submitted = False - app = CharApp(char_name=name, background=background, - date_applied=applied_date, account_id=user.id, - submitted=submitted) - app.save() - if submitted: - # Create the actual character object - typeclass = settings.BASE_CHARACTER_TYPECLASS - home = ObjectDB.objects.get_id(settings.GUEST_HOME) - # turn the permissionhandler to a string - perms = str(user.permissions) - # create the character - char = create.create_object(typeclass=typeclass, key=name, - home=home, permissions=perms) - user.db._playable_characters.append(char) - # add the right locks for the character so the account can - # puppet it - char.locks.add("puppet:id(%i) or pid(%i) or perm(Developers) " - "or pperm(Developers)" % (char.id, user.id)) - char.db.background = background # set the character background - return HttpResponseRedirect('/chargen') - else: - form = AppForm() - return render(request, 'chargen/create.html', {'form': form}) -``` - -> Note also that we basically create the character using the Evennia API, and we grab the proper -permissions from the `AccountDB` object and copy them to the character object. We take the user -permissions attribute and turn that list of strings into a string object in order for the -create_object function to properly process the permissions. - -Most importantly, the following attributes must be set on the created character object: - -* Evennia [permissions](./Locks.md#permissions) (copied from the `AccountDB`). -* The right `puppet` [locks](./Locks.md) so the Account can actually play as this Character later. -* The relevant Character [typeclass](./Typeclasses.md) -* Character name (key) -* The Character's home room location (`#2` by default) - -Other attributes are strictly speaking optional, such as the `background` attribute on our -character. It may be a good idea to decompose this function and create a separate _create_character -function in order to set up your character object the account owns. But with the Evennia API, -setting custom attributes is as easy as doing it in the meat of your Evennia game directory. - -After all of this, our `views.py` file should look like something like this: - -```python -# file mygame/web/chargen/views.py - -from django.shortcuts import render -from web.chargen.models import CharApp -from web.chargen.forms import AppForm -from django.http import HttpResponseRedirect -from datetime import datetime -from evennia.objects.models import ObjectDB -from django.conf import settings -from evennia.utils import create - -def index(request): - current_user = request.user # current user logged in - p_id = current_user.id # the account id - # submitted apps under this account - sub_apps = CharApp.objects.filter(account_id=p_id, submitted=True) - context = {'sub_apps': sub_apps} - return render(request, 'chargen/index.html', context) - -def detail(request, app_id): - app = CharApp.objects.get(app_id=app_id) - name = app.char_name - background = app.background - submitted = app.submitted - p_id = request.user.id - context = {'name': name, 'background': background, - 'p_id': p_id, 'submitted': submitted} - return render(request, 'chargen/detail.html', context) - -def creating(request): - user = request.user - if request.method == 'POST': - form = AppForm(request.POST) - if form.is_valid(): - name = form.cleaned_data['name'] - background = form.cleaned_data['background'] - applied_date = datetime.now() - submitted = True - if 'save' in request.POST: - submitted = False - app = CharApp(char_name=name, background=background, - date_applied=applied_date, account_id=user.id, - submitted=submitted) - app.save() - if submitted: - # Create the actual character object - typeclass = settings.BASE_CHARACTER_TYPECLASS - home = ObjectDB.objects.get_id(settings.GUEST_HOME) - # turn the permissionhandler to a string - perms = str(user.permissions) - # create the character - char = create.create_object(typeclass=typeclass, key=name, - home=home, permissions=perms) - user.db._playable_characters.append(char) - # add the right locks for the character so the account can - # puppet it - char.locks.add("puppet:id(%i) or pid(%i) or perm(Developers) " - "or pperm(Developers)" % (char.id, user.id)) - char.db.background = background # set the character background - return HttpResponseRedirect('/chargen') - else: - form = AppForm() - return render(request, 'chargen/create.html', {'form': form}) -``` - -### Create Views - Checkpoint: - -* you’ve defined a `views.py` that has an index, detail, and creating functions. -* you’ve defined a forms.py with the `AppForm` class needed by the `creating` function of -`views.py`. -* your `mygame/web/chargen` directory should now have a `views.py` and `forms.py` file - -## Create URLs - -URL patterns helps redirect requests from the web browser to the right views. These patterns are -created in `mygame/web/chargen/urls.py`. - -```python -# file mygame/web/chargen/urls.py - -from django.conf.urls import url -from web.chargen import views - -urlpatterns = [ - # ex: /chargen/ - url(r'^$', views.index, name='index'), - # ex: /chargen/5/ - url(r'^(?P[0-9]+)/$', views.detail, name='detail'), - # ex: /chargen/create - url(r'^create/$', views.creating, name='creating'), -] -``` - -You could change the format as you desire. To make it more secure, you could remove app_id from the -"detail" url, and instead just fetch the account’s applications using a unifying field like -account_id to find all the character application objects to display. - -We must also update the main `mygame/web/urls.py` file (that is, one level up from our chargen app), -so the main website knows where our app's views are located. Find the `patterns` variable, and -change it to include: - -```python -# in file mygame/web/urls.py - -from django.conf.urls import url, include - -# default evennia patterns -from evennia.web.urls import urlpatterns - -# eventual custom patterns -custom_patterns = [ - # url(r'/desired/url/', view, name='example'), -] - -# this is required by Django. -urlpatterns += [ - url(r'^chargen/', include('web.chargen.urls')), -] - -urlpatterns = custom_patterns + urlpatterns -``` - -### URLs - Checkpoint: - -* You’ve created a urls.py file in the `mygame/web/chargen` directory -* You have edited the main `mygame/web/urls.py` file to include urls to the `chargen` directory. - -## HTML Templates - -So we have our url patterns, views, and models defined. Now we must define our HTML templates that -the actual user will see and interact with. For this tutorial we us the basic *prosimii* template -that comes with Evennia. - -Take note that we use `user.is_authenticated` to make sure that the user cannot create a character -without logging in. - -These files will all go into the `/mygame/web/chargen/templates/chargen/` directory. - -### index.html - -This HTML template should hold a list of all the applications the account currently has active. For -this demonstration, we will only list the applications that the account has submitted. You could -easily adjust this to include saved applications, or other types of applications if you have -different kinds. - -Please refer back to `views.py` to see where we define the variables these templates make use of. - -```html - - -{% extends "base.html" %} -{% block content %} -{% if user.is_authenticated %} -

Character Generation

- {% if sub_apps %} - - {% else %} -

You haven't submitted any character applications.

- {% endif %} - {% else %} -

Please loginfirst.

-{% endif %} -{% endblock %} -``` - -### detail.html - -This page should show a detailed character sheet of their application. This will only show their -name and character background. You will likely want to extend this to show many more fields for your -game. In a full-fledged character generation, you may want to extend the boolean attribute of -submitted to allow accounts to save character applications and submit them later. - -```html - - -{% extends "base.html" %} -{% block content %} -

Character Information

-{% if user.is_authenticated %} - {% if user.id == p_id %} -

{{name}}

-

Background

-

{{background}}

-

Submitted: {{submitted}}

- {% else %} -

You didn't submit this character.

- {% endif %} -{% else %} -

You aren't logged in.

-{% endif %} -{% endblock %} -``` - -### create.html - -Our create HTML template will use the Django form we defined back in views.py/forms.py to drive the -majority of the application process. There will be a form input for every field we defined in -forms.py, which is handy. We have used POST as our method because we are sending information to the -server that will update the database. As an alternative, GET would be much less secure. You can read -up on documentation elsewhere on the web for GET vs. POST. - -```html - - -{% extends "base.html" %} -{% block content %} -

Character Creation

-{% if user.is_authenticated %} -
- {% csrf_token %} - {{ form }} - -
-{% else %} -

You aren't logged in.

-{% endif %} -{% endblock %} -``` - -### Templates - Checkpoint: - -* Create a `index.html`, `detail.html` and `create.html` template in your -`mygame/web/chargen/templates/chargen` directory - -## Activating your new character generation - -After finishing this tutorial you should have edited or created the following files: - -```bash -mygame/web/urls.py -mygame/web/chargen/models.py -mygame/web/chargen/views.py -mygame/web/chargen/urls.py -mygame/web/chargen/templates/chargen/index.html -mygame/web/chargen/templates/chargen/create.html -mygame/web/chargen/templates/chargen/detail.html -``` - -Once you have all these files stand in your `mygame/`folder and run: - -```bash -evennia makemigrations -evennia migrate -``` - -This will create and update the models. If you see any errors at this stage, read the traceback -carefully, it should be relatively easy to figure out where the error is. - -Login to the website (you need to have previously registered an Player account with the game to do -this). Next you navigate to `http://yourwebsite.com/chargen` (if you are running locally this will -be something like `http://localhost:4001/chargen` and you will see your new app in action. - -This should hopefully give you a good starting point in figuring out how you’d like to approach your -own web generation. The main difficulties are in setting the appropriate settings on your newly -created character object. Thankfully, the Evennia API makes this easy. - -## Adding a no CAPCHA reCAPCHA on your character generation - -As sad as it is, if your server is open to the web, bots might come to visit and take advantage of -your open form to create hundreds, thousands, millions of characters if you give them the -opportunity. This section shows you how to use the [No CAPCHA reCAPCHA](https://www.google.com/recaptcha/intro/invisible.html) designed by Google. Not only is it -easy to use, it is user-friendly... for humans. A simple checkbox to check, except if Google has -some suspicion, in which case you will have a more difficult test with an image and the usual text -inside. It's worth pointing out that, as long as Google doesn't suspect you of being a robot, this -is quite useful, not only for common users, but to screen-reader users, to which reading inside of -an image is pretty difficult, if not impossible. And to top it all, it will be so easy to add in -your website. - -### Step 1: Obtain a SiteKey and secret from Google - -The first thing is to ask Google for a way to safely authenticate your website to their service. To -do it, we need to create a site key and a secret. Go to -[https://www.google.com/recaptcha/admin](https://www.google.com/recaptcha/admin) to create such a -site key. It's quite easy when you have a Google account. - -When you have created your site key, save it safely. Also copy your secret key as well. You should -find both information on the web page. Both would contain a lot of letters and figures. - -### Step 2: installing and configuring the dedicated Django app - -Since Evennia runs on Django, the easiest way to add our CAPCHA and perform the proper check is to -install the dedicated Django app. Quite easy: - - pip install django-nocaptcha-recaptcha - -And add it to the installed apps in your settings. In your `mygame/server/conf/settings.py`, you -might have something like this: - -```python -# ... -INSTALLED_APPS += ( - 'web.chargen', - 'nocaptcha_recaptcha', -) -``` - -Don't close the setting file just yet. We have to add in the site key and secret key. You can add -them below: - -```python -# NoReCAPCHA site key -NORECAPTCHA_SITE_KEY = "PASTE YOUR SITE KEY HERE" -# NoReCAPCHA secret key -NORECAPTCHA_SECRET_KEY = "PUT YOUR SECRET KEY HERE" -``` - -### Step 3: Adding the CAPCHA to our form - -Finally we have to add the CAPCHA to our form. It will be pretty easy too. First, open your -`web/chargen/forms.py` file. We're going to add a new field, but hopefully, all the hard work has -been done for us. Update at your convenience, You might end up with something like this: - -```python -from django import forms -from nocaptcha_recaptcha.fields import NoReCaptchaField - -class AppForm(forms.Form): - name = forms.CharField(label='Character Name', max_length=80) - background = forms.CharField(label='Background') - captcha = NoReCaptchaField() -``` - -As you see, we added a line of import (line 2) and a field in our form. - -And lastly, we need to update our HTML file to add in the Google library. You can open -`web/chargen/templates/chargen/create.html`. There's only one line to add: - -```html - -``` - -And you should put it at the bottom of the page. Just before the closing body would be good, but -for the time being, the base page doesn't provide a footer block, so we'll put it in the content -block. Note that it's not the best place, but it will work. In the end, your -`web/chargen/templates/chargen/create.html` file should look like this: - -```html -{% extends "base.html" %} -{% block content %} -

Character Creation

-{% if user.is_authenticated %} -
- {% csrf_token %} - {{ form }} - -
-{% else %} -

You aren't logged in.

-{% endif %} - -{% endblock %} -``` - -Reload and open [http://localhost:4001/chargen/create](http://localhost:4001/chargen/create/) and -you should see your beautiful CAPCHA just before the "submit" button. Try not to check the checkbox -to see what happens. And do the same while checking the checkbox! diff --git a/docs/0.9.5/_sources/Web-Character-View-Tutorial.md.txt b/docs/0.9.5/_sources/Web-Character-View-Tutorial.md.txt deleted file mode 100644 index 893ba0330a..0000000000 --- a/docs/0.9.5/_sources/Web-Character-View-Tutorial.md.txt +++ /dev/null @@ -1,228 +0,0 @@ -# Web Character View Tutorial - - -**Before doing this tutorial you will probably want to read the intro in [Basic Web tutorial](./Web-Tutorial.md).** - -In this tutorial we will create a web page that displays the stats of a game character. For this, -and all other pages we want to make specific to our game, we'll need to create our own Django "app" - -We'll call our app `character`, since it will be dealing with character information. From your game -dir, run - - evennia startapp character - -This will create a directory named `character` in the root of your game dir. It contains all basic -files that a Django app needs. To keep `mygame` well ordered, move it to your `mygame/web/` -directory instead: - - mv character web/ - -Note that we will not edit all files in this new directory, many of the generated files are outside -the scope of this tutorial. - -In order for Django to find our new web app, we'll need to add it to the `INSTALLED_APPS` setting. -Evennia's default installed apps are already set, so in `server/conf/settings.py`, we'll just extend -them: - -```python -INSTALLED_APPS += ('web.character',) -``` - -> Note: That end comma is important. It makes sure that Python interprets the addition as a tuple -instead of a string. - -The first thing we need to do is to create a *view* and an *URL pattern* to point to it. A view is a -function that generates the web page that a visitor wants to see, while the URL pattern lets Django -know what URL should trigger the view. The pattern may also provide some information of its own as -we shall see. - -Here is our `character/urls.py` file (**Note**: you may have to create this file if a blank one -wasn't generated for you): - -```python -# URL patterns for the character app - -from django.conf.urls import url -from web.character.views import sheet - -urlpatterns = [ - url(r'^sheet/(?P\d+)/$', sheet, name="sheet") -] -``` - -This file contains all of the URL patterns for the application. The `url` function in the -`urlpatterns` list are given three arguments. The first argument is a pattern-string used to -identify which URLs are valid. Patterns are specified as *regular expressions*. Regular expressions -are used to match strings and are written in a special, very compact, syntax. A detailed description -of regular expressions is beyond this tutorial but you can learn more about them -[here](https://docs.python.org/2/howto/regex.html). For now, just accept that this regular -expression requires that the visitor's URL looks something like this: - -```` -sheet/123/ -```` - -That is, `sheet/` followed by a number, rather than some other possible URL pattern. We will -interpret this number as object ID. Thanks to how the regular expression is formulated, the pattern -recognizer stores the number in a variable called `object_id`. This will be passed to the view (see -below). We add the imported view function (`sheet`) in the second argument. We also add the `name` -keyword to identify the URL pattern itself. You should always name your URL patterns, this makes -them easy to refer to in html templates using the `{% url %}` tag (but we won't get more into that -in this tutorial). - -> Security Note: Normally, users do not have the ability to see object IDs within the game (it's -restricted to superusers only). Exposing the game's object IDs to the public like this enables -griefers to perform what is known as an [account enumeration -attack](http://www.sans.edu/research/security-laboratory/article/attacks-browsing) in the efforts of -hijacking your superuser account. Consider this: in every Evennia installation, there are two -objects that we can *always* expect to exist and have the same object IDs-- Limbo (#2) and the -superuser you create in the beginning (#1). Thus, the griefer can get 50% of the information they -need to hijack the admin account (the admin's username) just by navigating to `sheet/1`! - -Next we create `views.py`, the view file that `urls.py` refers to. - -```python -# Views for our character app - -from django.http import Http404 -from django.shortcuts import render -from django.conf import settings - -from evennia.utils.search import object_search -from evennia.utils.utils import inherits_from - -def sheet(request, object_id): - object_id = '#' + object_id - try: - character = object_search(object_id)[0] - except IndexError: - raise Http404("I couldn't find a character with that ID.") - if not inherits_from(character, settings.BASE_CHARACTER_TYPECLASS): - raise Http404("I couldn't find a character with that ID. " - "Found something else instead.") - return render(request, 'character/sheet.html', {'character': character}) -``` - -As explained earlier, the URL pattern parser in `urls.py` parses the URL and passes `object_id` to -our view function `sheet`. We do a database search for the object using this number. We also make -sure such an object exists and that it is actually a Character. The view function is also handed a -`request` object. This gives us information about the request, such as if a logged-in user viewed it -- we won't use that information here but it is good to keep in mind. - -On the last line, we call the `render` function. Apart from the `request` object, the `render` -function takes a path to an html template and a dictionary with extra data you want to pass into -said template. As extra data we pass the Character object we just found. In the template it will be -available as the variable "character". - -The html template is created as `templates/character/sheet.html` under your `character` app folder. -You may have to manually create both `template` and its subfolder `character`. Here's the template -to create: - -````html -{% extends "base.html" %} -{% block content %} - -

{{ character.name }}

- -

{{ character.db.desc }}

- -

Stats

- - - - - - - - - - - - - - - - - - - - - -
StatValue
Strength{{ character.db.str }}
Intelligence{{ character.db.int }}
Speed{{ character.db.spd }}
- -

Skills

-
    - {% for skill in character.db.skills %} -
  • {{ skill }}
  • - {% empty %} -
  • This character has no skills yet.
  • - {% endfor %} -
- - {% if character.db.approved %} -

This character has been approved!

- {% else %} -

This character has not yet been approved!

- {% endif %} -{% endblock %} -```` - -In Django templates, `{% ... %}` denotes special in-template "functions" that Django understands. -The `{{ ... }}` blocks work as "slots". They are replaced with whatever value the code inside the -block returns. - -The first line, `{% extends "base.html" %}`, tells Django that this template extends the base -template that Evennia is using. The base template is provided by the theme. Evennia comes with the -open-source third-party theme `prosimii`. You can find it and its `base.html` in -`evennia/web/templates/prosimii`. Like other templates, these can be overwritten. - -The next line is `{% block content %}`. The `base.html` file has `block`s, which are placeholders -that templates can extend. The main block, and the one we use, is named `content`. - -We can access the `character` variable anywhere in the template because we passed it in the `render` -call at the end of `view.py`. That means we also have access to the Character's `db` attributes, -much like you would in normal Python code. You don't have the ability to call functions with -arguments in the template-- in fact, if you need to do any complicated logic, you should do it in -`view.py` and pass the results as more variables to the template. But you still have a great deal of -flexibility in how you display the data. - -We can do a little bit of logic here as well. We use the `{% for %} ... {% endfor %}` and `{% if %} -... {% else %} ... {% endif %}` structures to change how the template renders depending on how many -skills the user has, or if the user is approved (assuming your game has an approval system). - -The last file we need to edit is the master URLs file. This is needed in order to smoothly integrate -the URLs from your new `character` app with the URLs from Evennia's existing pages. Find the file -`web/urls.py` and update its `patterns` list as follows: - -```python -# web/urls.py - -custom_patterns = [ - url(r'^character/', include('web.character.urls')) - ] -``` - -Now reload the server with `evennia reload` and visit the page in your browser. If you haven't -changed your defaults, you should be able to find the sheet for character `#1` at -`http://localhost:4001/character/sheet/1/` - -Try updating the stats in-game and refresh the page in your browser. The results should show -immediately. - -As an optional final step, you can also change your character typeclass to have a method called -'get_absolute_url'. -```python -# typeclasses/characters.py - - # inside Character - def get_absolute_url(self): - from django.urls import reverse - return reverse('character:sheet', kwargs={'object_id':self.id}) -``` -Doing so will give you a 'view on site' button in the top right of the Django Admin Objects -changepage that links to your new character sheet, and allow you to get the link to a character's -page by using {{ object.get_absolute_url }} in any template where you have a given object. - -*Now that you've made a basic page and app with Django, you may want to read the full Django -tutorial to get a better idea of what it can do. [You can find Django's tutorial -here](https://docs.djangoproject.com/en/1.8/intro/tutorial01/).* diff --git a/docs/0.9.5/_sources/Web-Features.md.txt b/docs/0.9.5/_sources/Web-Features.md.txt deleted file mode 100644 index aab41c597d..0000000000 --- a/docs/0.9.5/_sources/Web-Features.md.txt +++ /dev/null @@ -1,131 +0,0 @@ -# Web Features - - -Evennia is its own webserver and hosts a default website and browser webclient. - -## Web site - -The Evennia website is a Django application that ties in with the MUD database. Since the website -shares this database you could, for example, tell website visitors how many accounts are logged into -the game at the moment, how long the server has been up and any other database information you may -want. During development you can access the website by pointing your browser to -`http://localhost:4001`. - -> You may also want to set `DEBUG = True` in your settings file for debugging the website. You will -then see proper tracebacks in the browser rather than just error codes. Note however that this will -*leak memory a lot* (it stores everything all the time) and is *not to be used in production*. It's -recommended to only use `DEBUG` for active web development and to turn it off otherwise. - -A Django (and thus Evennia) website basically consists of three parts, a -[view](https://docs.djangoproject.com/en/1.9/topics/http/views/) an associated -[template](https://docs.djangoproject.com/en/1.9/topics/templates/) and an `urls.py` file. Think of -the view as the Python back-end and the template as the HTML files you are served, optionally filled -with data from the back-end. The urls file is a sort of mapping that tells Django that if a specific -URL is given in the browser, a particular view should be triggered. You are wise to review the -Django documentation for details on how to use these components. - -Evennia's default website is located in -[evennia/web/website](https://github.com/evennia/evennia/tree/master/evennia/web/website). In this -folder you'll find the simple default view as well as subfolders `templates` and `static`. Static -files are things like images, CSS files and Javascript. - -### Customizing the Website - -You customize your website from your game directory. In the folder `web` you'll find folders -`static`, `templates`, `static_overrides` and `templates_overrides`. The first two of those are -populated automatically by Django and used to serve the website. You should not edit anything in -them - the change will be lost. To customize the website you'll need to copy the file you want to -change from the `web/website/template/` or `web/website/static/` path to the corresponding place -under one of `_overrides` directories. - -Example: To override or modify `evennia/web/website/template/website/index.html` you need to -add/modify `mygame/web/template_overrides/website/index.html`. - -The detailed description on how to customize the website is best described in tutorial form. See the -[Web Tutorial](./Web-Tutorial.md) for more information. - -### Overloading Django views - -The Python backend for every HTML page is called a [Django -view](https://docs.djangoproject.com/en/1.9/topics/http/views/). A view can do all sorts of -functions, but the main one is to update variables data that the page can display, like how your -out-of-the-box website will display statistics about number of users and database objects. - -To re-point a given page to a `view.py` of your own, you need to modify `mygame/web/urls.py`. An -[URL pattern](https://docs.djangoproject.com/en/1.9/topics/http/urls/) is a [regular -expression](https://en.wikipedia.org/wiki/Regular_expression) that you need to enter in the address -field of your web browser to get to the page in question. If you put your own URL pattern *before* -the default ones, your own view will be used instead. The file `urls.py` even marks where you should -put your change. - -Here's an example: - -```python -# mygame/web/urls.py - -from django.conf.urls import url, include -# default patterns -from evennia.web.urls import urlpatterns - -# our own view to use as a replacement -from web.myviews import myview - -# custom patterns to add -patterns = [ - # overload the main page view - url(r'^', myview, name='mycustomview'), -] - -urlpatterns = patterns + urlpatterns - -``` - -Django will always look for a list named `urlpatterns` which consists of the results of `url()` -calls. It will use the *first* match it finds in this list. Above, we add a new URL redirect from -the root of the website. It will now our own function `myview` from a new module -`mygame/web/myviews.py`. - -> If our game is found on `http://mygame.com`, the regular expression `"^"` means we just entered -`mygame.com` in the address bar. If we had wanted to add a view for `http://mygame.com/awesome`, the -regular expression would have been `^/awesome`. - -Look at [evennia/web/website/views.py](https://github.com/evennia/evennia/blob/master/evennia/web/website/views.py#L82) to see the inputs and outputs you must have to define a view. Easiest may be to -copy the default file to `mygame/web` to have something to modify and expand on. - -Restart the server and reload the page in the browser - the website will now use your custom view. -If there are errors, consider turning on `settings.DEBUG` to see the full tracebacks - in debug mode -you will also log all requests in `mygame/server/logs/http_requests.log`. - -## Web client - - -Evennia comes with a MUD client accessible from a normal web browser. During -development you can try it at `http://localhost:4001/webclient`. -[See the Webclient page](./Webclient.md) for more details. - - -## The Django 'Admin' Page - -Django comes with a built-in [admin -website](https://docs.djangoproject.com/en/1.10/ref/contrib/admin/). This is accessible by clicking -the 'admin' button from your game website. The admin site allows you to see, edit and create objects -in your database from a graphical interface. - -The behavior of default Evennia models are controlled by files `admin.py` in the Evennia package. -New database models you choose to add yourself (such as in the Web Character View Tutorial) can/will -also have `admin.py` files. New models are registered to the admin website by a call of -`admin.site.register(model class, admin class)` inside an admin.py file. It is an error to attempt -to register a model that has already been registered. - -To overload Evennia's admin files you don't need to modify Evennia itself. To customize you can call -`admin.site.unregister(model class)`, then follow that with `admin.site.register` in one of your own -admin.py files in a new app that you add. - -## More reading - -Evennia relies on Django for its web features. For details on expanding your web experience, the -[Django documentation](https://docs.djangoproject.com/en) or the [Django -Book](http://www.djangobook.com/en/2.0/index.html) are the main resources to look into. In Django -lingo, the Evennia is a django "project" that consists of Django "applications". For the sake of web -implementation, the relevant django "applications" in default Evennia are `web/website` or -`web/webclient`. diff --git a/docs/0.9.5/_sources/Web-Tutorial.md.txt b/docs/0.9.5/_sources/Web-Tutorial.md.txt deleted file mode 100644 index ef4075d1ef..0000000000 --- a/docs/0.9.5/_sources/Web-Tutorial.md.txt +++ /dev/null @@ -1,127 +0,0 @@ -# Web Tutorial - - -Evennia uses the [Django](https://www.djangoproject.com/) web framework as the basis of both its -database configuration and the website it provides. While a full understanding of Django requires -reading the Django documentation, we have provided this tutorial to get you running with the basics -and how they pertain to Evennia. This text details getting everything set up. The [Web-based -Character view Tutorial](./Web-Character-View-Tutorial.md) gives a more explicit example of making a -custom web page connected to your game, and you may want to read that after finishing this guide. - -## A Basic Overview - -Django is a web framework. It gives you a set of development tools for building a website quickly -and easily. - -Django projects are split up into *apps* and these apps all contribute to one project. For instance, -you might have an app for conducting polls, or an app for showing news posts or, like us, one for -creating a web client. - -Each of these applications has a `urls.py` file, which specifies what -[URL](http://en.wikipedia.org/wiki/Uniform_resource_locator)s are used by the app, a `views.py` file -for the code that the URLs activate, a `templates` directory for displaying the results of that code -in [HTML](http://en.wikipedia.org/wiki/Html) for the user, and a `static` folder that holds assets -like [CSS](http://en.wikipedia.org/wiki/CSS), [Javascript](http://en.wikipedia.org/wiki/Javascript), -and Image files (You may note your mygame/web folder does not have a `static` or `template` folder. -This is intended and explained further below). Django applications may also have a `models.py` file -for storing information in the database. We "cmd: attr(locktest, 80, compare=gt)"will not change any -models here, take a look at the [New Models](./New-Models.md) page (as well as the [Django -docs](https://docs.djangoproject.com/en/1.7/topics/db/models/) on models) if you are interested. - -There is also a root `urls.py` that determines the URL structure for the entire project. A starter -`urls.py` is included in the default game template, and automatically imports all of Evennia's -default URLs for you. This is located in `web/urls.py`. - -## Changing the logo on the front page - -Evennia's default logo is a fun little googly-eyed snake wrapped around a gear globe. As cute as it -is, it probably doesn't represent your game. So one of the first things you may wish to do is -replace it with a logo of your own. - -Django web apps all have _static assets_: CSS files, Javascript files, and Image files. In order to -make sure the final project has all the static files it needs, the system collects the files from -every app's `static` folder and places it in the `STATIC_ROOT` defined in `settings.py`. By default, -the Evennia `STATIC_ROOT` is in `web/static`. - -Because Django pulls files from all of those separate places and puts them in one folder, it's -possible for one file to overwrite another. We will use this to plug in our own files without having -to change anything in the Evennia itself. - -By default, Evennia is configured to pull files you put in the `web/static_overrides` *after* all -other static files. That means that files in `static_overrides` folder will overwrite any previously -loaded files *having the same path under its static folder*. This last part is important to repeat: -To overload the static resource from a standard `static` folder you need to replicate the path of -folders and file names from that `static` folder in exactly the same way inside `static_overrides`. - -Let's see how this works for our logo. The default web application is in the Evennia library itself, -in `evennia/web/`. We can see that there is a `static` folder here. If we browse down, we'll -eventually find the full path to the Evennia logo file: -`evennia/web/website/static/website/images/evennia_logo.png`. - -Inside our `static_overrides` we must replicate the part of the path inside the website's `static` -folder, in other words, we must replicate `website/images/evennia_logo.png`. - -So, to change the logo, we need to create the folder path `website/images/` in `static_overrides`. -You may already have this folder structure prepared for you. We then rename our own logo file to -`evennia_logo.png` and copy it there. The final path for this file would thus be: -`mygame/web/static_overrides/website/images/evennia_logo.png`. - -To get this file pulled in, just change to your own game directory and reload the server: - -``` -evennia reload -``` - -This will reload the configuration and bring in the new static file(s). If you didn't want to reload -the server you could instead use - -``` -evennia collectstatic -``` - -to only update the static files without any other changes. - -> **Note**: Evennia will collect static files automatically during startup. So if `evennia -collectstatic` reports finding 0 files to collect, make sure you didn't start the engine at some -point - if so the collector has already done its work! To make sure, connect to the website and -check so the logo has actually changed to your own version. - -> **Note**: Sometimes the static asset collector can get confused. If no matter what you do, your -overridden files aren't getting copied over the defaults, try removing the target file (or -everything) in the `web/static` directory, and re-running `collectstatic` to gather everything from -scratch. - -## Changing the Front Page's Text - -The default front page for Evennia contains information about the Evennia project. You'll probably -want to replace this information with information about your own project. Changing the page template -is done in a similar way to changing static resources. - -Like static files, Django looks through a series of template folders to find the file it wants. The -difference is that Django does not copy all of the template files into one place, it just searches -through the template folders until it finds a template that matches what it's looking for. This -means that when you edit a template, the changes are instant. You don't have to reload the server or -run any extra commands to see these changes - reloading the web page in your browser is enough. - -To replace the index page's text, we'll need to find the template for it. We'll go into more detail -about how to determine which template is used for rendering a page in the [Web-based Character view -Tutorial](./Web-Character-View-Tutorial.md). For now, you should know that the template we want to change -is stored in `evennia/web/website/templates/website/index.html`. - -To replace this template file, you will put your changed template inside the -`web/template_overrides/website` directory in your game folder. In the same way as with static -resources you must replicate the path inside the default `template` directory exactly. So we must -copy our replacement template named `index.html` there (or create the `website` directory in -web/template_overrides` if it does not exist, first). The final path to the file should thus be: -`web/template_overrides/website/index.html` within your game directory. - -Note that it is usually easier to just copy the original template over and edit it in place. The -original file already has all the markup and tags, ready for editing. - -## Further reading - -For further hints on working with the web presence, you could now continue to the [Web-based -Character view Tutorial](./Web-Character-View-Tutorial.md) where you learn to make a web page that -displays in-game character stats. You can also look at [Django's own -tutorial](https://docs.djangoproject.com/en/3.1/) to get more insight in how Django works and what -possibilities exist. diff --git a/docs/0.9.5/_sources/Webclient-brainstorm.md.txt b/docs/0.9.5/_sources/Webclient-brainstorm.md.txt deleted file mode 100644 index 941338a73d..0000000000 --- a/docs/0.9.5/_sources/Webclient-brainstorm.md.txt +++ /dev/null @@ -1,354 +0,0 @@ -# Webclient brainstorm - -# Ideas for a future webclient gui - -*This is a brainstorming whitepage. Add your own comments in a named section below.* - -## From Chat on 2019/09/02 -``` - Griatch (IRC)APP @friarzen: Could one (with goldenlayout) programmatically provide pane positions -and sizes? -I recall it was not trivial for the old split.js solution. - friarzen take a look at the goldenlayout_default_config.js -It is kinda cryptic but that is the layout json. - Griatch (IRC)APP @friarzen: Hm, so dynamically replacing the goldenlayout_config in the global -scope at the right - thing would do it? - friarzen yep - friarzen the biggest pain in the butt is that goldenlayout_config needs to be set before the -goldenlayout init() -is called, which isn't trivial with the current structure, but it isn't impossible. - Griatch (IRC)APP One could in principle re-run init() at a later date though, right? - friarzen Hmm...not sure I've ever tried it... seems doable off the top of my head... -right now, that whole file exists to be overridden on page load as a separate -``` -Remember, plugins are load-order dependent, so make sure the new ` - - - - - - - - - - -
- -
-
-
-
- -
-

evennia

-
- -
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.accounts.accounts.html b/docs/0.9.5/api/evennia.accounts.accounts.html deleted file mode 100644 index 06dde45a4e..0000000000 --- a/docs/0.9.5/api/evennia.accounts.accounts.html +++ /dev/null @@ -1,1206 +0,0 @@ - - - - - - - - - evennia.accounts.accounts — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.accounts.accounts

-

Typeclass for Account objects.

-

Note that this object is primarily intended to -store OOC information, not game info! This -object represents the actual user (not their -character) and has NO actual presence in the -game world (this is handled by the associated -character object, so you should customize that -instead for most things).

-
-
-class evennia.accounts.accounts.DefaultAccount(*args, **kwargs)[source]
-

Bases: evennia.accounts.models.AccountDB

-

This is the base Typeclass for all Accounts. Accounts represent -the person playing the game and tracks account info, password -etc. They are OOC entities without presence in-game. An Account -can connect to a Character Object in order to “enter” the -game.

-

Account Typeclass API:

-
    -
  • Available properties (only available on initiated typeclass objects)

  • -
-
-
    -
  • key (string) - name of account

  • -
  • name (string)- wrapper for user.username

  • -
  • -
    aliases (list of strings) - aliases to the object. Will be saved to

    database as AliasDB entries but returned as strings.

    -
    -
    -
  • -
  • dbref (int, read-only) - unique #id-number. Also “id” can be used.

  • -
  • date_created (string) - time stamp of object creation

  • -
  • permissions (list of strings) - list of permission strings

  • -
  • user (User, read-only) - django User authorization object

  • -
  • -
    obj (Object) - game object controlled by account. ‘character’ can also

    be used.

    -
    -
    -
  • -
  • sessions (list of Sessions) - sessions connected to this account

  • -
  • is_superuser (bool, read-only) - if the connected user is a superuser

  • -
-
-
    -
  • Handlers

  • -
-
-
    -
  • locks - lock-handler: use locks.add() to add new lock strings

  • -
  • -
    db - attribute-handler: store/retrieve database attributes on this

    self.db.myattr=val, val=self.db.myattr

    -
    -
    -
  • -
  • -
    ndb - non-persistent attribute handler: same as db but does not

    create a database entry when storing data

    -
    -
    -
  • -
  • scripts - script-handler. Add new scripts to object with scripts.add()

  • -
  • cmdset - cmdset-handler. Use cmdset.add() to add new cmdsets to object

  • -
  • nicks - nick-handler. New nicks with nicks.add().

  • -
-
-
    -
  • Helper methods

  • -
-
-
    -
  • msg(text=None, from_obj=None, session=None, options=None, **kwargs)

  • -
  • execute_cmd(raw_string)

  • -
  • -
    search(ostring, global_search=False, attribute_name=None,

    use_nicks=False, location=None, -ignore_errors=False, account=False)

    -
    -
    -
  • -
  • is_typeclass(typeclass, exact=False)

  • -
  • swap_typeclass(new_typeclass, clean_attributes=False, no_default=True)

  • -
  • access(accessing_obj, access_type=’read’, default=False, no_superuser_bypass=False)

  • -
  • check_permstring(permstring)

  • -
-
-
    -
  • Hook methods

  • -
-
-

basetype_setup() -at_account_creation()

-
-
> note that the following hooks are also found on Objects and are

usually handled on the character level:

-
-
-
    -
  • at_init()

  • -
  • at_access()

  • -
  • at_cmdset_get(**kwargs)

  • -
  • at_first_login()

  • -
  • at_post_login(session=None)

  • -
  • at_disconnect()

  • -
  • at_message_receive()

  • -
  • at_message_send()

  • -
  • at_server_reload()

  • -
  • at_server_shutdown()

  • -
-
-
-
-objects = <evennia.accounts.manager.AccountManager object>
-
- -
-
-cmdset[source]
-
- -
-
-scripts[source]
-
- -
-
-nicks[source]
-
- -
-
-sessions[source]
-
- -
-
-options[source]
-
- -
-
-property characters
-
- -
-
-get_display_name(looker, **kwargs)[source]
-

This is used by channels and other OOC communications methods to give a -custom display of this account’s input.

-
-
Parameters
-
    -
  • looker (Account) – The one that will see this name.

  • -
  • **kwargs – Unused by default, can be used to pass game-specific data.

  • -
-
-
Returns
-

str – The name, possibly modified.

-
-
-
- -
-
-disconnect_session_from_account(session, reason=None)[source]
-

Access method for disconnecting a given session from the -account (connection happens automatically in the -sessionhandler)

-
-
Parameters
-
    -
  • session (Session) – Session to disconnect.

  • -
  • reason (str, optional) – Eventual reason for the disconnect.

  • -
-
-
-
- -
-
-puppet_object(session, obj)[source]
-

Use the given session to control (puppet) the given object (usually -a Character type).

-
-
Parameters
-
    -
  • session (Session) – session to use for puppeting

  • -
  • obj (Object) – the object to start puppeting

  • -
-
-
Raises
-

RuntimeError – If puppeting is not possible, the -exception.msg will contain the reason.

-
-
-
- -
-
-unpuppet_object(session)[source]
-

Disengage control over an object.

-
-
Parameters
-

session (Session or list) – The session or a list of -sessions to disengage from their puppets.

-
-
Raises
-

RuntimeError With message about error.

-
-
-
- -
-
-unpuppet_all()[source]
-

Disconnect all puppets. This is called by server before a -reset/shutdown.

-
- -
-
-get_puppet(session)[source]
-

Get an object puppeted by this session through this account. This is -the main method for retrieving the puppeted object from the -account’s end.

-
-
Parameters
-

session (Session) – Find puppeted object based on this session

-
-
Returns
-

puppet (Object) – The matching puppeted object, if any.

-
-
-
- -
-
-get_all_puppets()[source]
-

Get all currently puppeted objects.

-
-
Returns
-

puppets (list)

-
-
All puppeted objects currently controlled

by this Account.

-
-
-

-
-
-
- -
-
-property character
-

This is a legacy convenience link for use with MULTISESSION_MODE.

-
-
Returns
-

puppets (Object or list)

-
-
Users of MULTISESSION_MODE 0 or 1 will

always get the first puppet back. Users of higher **MULTISESSION_MODE**s will -get a list of all puppeted objects.

-
-
-

-
-
-
- -
-
-property puppet
-

This is a legacy convenience link for use with MULTISESSION_MODE.

-
-
Returns
-

puppets (Object or list)

-
-
Users of MULTISESSION_MODE 0 or 1 will

always get the first puppet back. Users of higher **MULTISESSION_MODE**s will -get a list of all puppeted objects.

-
-
-

-
-
-
- -
-
-classmethod is_banned(**kwargs)[source]
-

Checks if a given username or IP is banned.

-
-
Keyword Arguments
-
    -
  • ip (str, optional) – IP address.

  • -
  • username (str, optional) – Username.

  • -
-
-
Returns
-

is_banned (bool) – Whether either is banned or not.

-
-
-
- -
-
-classmethod get_username_validators(validator_config=[{'NAME': 'django.contrib.auth.validators.ASCIIUsernameValidator'}, {'NAME': 'django.core.validators.MinLengthValidator', 'OPTIONS': {'limit_value': 3}}, {'NAME': 'django.core.validators.MaxLengthValidator', 'OPTIONS': {'limit_value': 30}}, {'NAME': 'evennia.server.validators.EvenniaUsernameAvailabilityValidator'}])[source]
-

Retrieves and instantiates validators for usernames.

-
-
Parameters
-

validator_config (list) – List of dicts comprising the battery of -validators to apply to a username.

-
-
Returns
-

validators (list) – List of instantiated Validator objects.

-
-
-
- -
-
-classmethod authenticate(username, password, ip='', **kwargs)[source]
-

Checks the given username/password against the database to see if the -credentials are valid.

-

Note that this simply checks credentials and returns a valid reference -to the user– it does not log them in!

-

To finish the job: -After calling this from a Command, associate the account with a Session: -- session.sessionhandler.login(session, account)

-

…or after calling this from a View, associate it with an HttpRequest: -- django.contrib.auth.login(account, request)

-
-
Parameters
-
    -
  • username (str) – Username of account

  • -
  • password (str) – Password of account

  • -
  • ip (str, optional) – IP address of client

  • -
-
-
Keyword Arguments
-

session (Session, optional) – Session requesting authentication

-
-
Returns
-

account (DefaultAccount, None)

-
-
Account whose credentials were

provided if not banned.

-
-
-

errors (list): Error messages of any failures.

-

-
-
-
- -
-
-classmethod normalize_username(username)[source]
-

Django: Applies NFKC Unicode normalization to usernames so that visually -identical characters with different Unicode code points are considered -identical.

-

(This deals with the Turkish “i” problem and similar -annoyances. Only relevant if you go out of your way to allow Unicode -usernames though– Evennia accepts ASCII by default.)

-

In this case we’re simply piggybacking on this feature to apply -additional normalization per Evennia’s standards.

-
- -
-
-classmethod validate_username(username)[source]
-

Checks the given username against the username validator associated with -Account objects, and also checks the database to make sure it is unique.

-
-
Parameters
-

username (str) – Username to validate

-
-
Returns
-

valid (bool) – Whether or not the password passed validation -errors (list): Error messages of any failures

-
-
-
- -
-
-classmethod validate_password(password, account=None)[source]
-

Checks the given password against the list of Django validators enabled -in the server.conf file.

-
-
Parameters
-

password (str) – Password to validate

-
-
Keyword Arguments
-

account (DefaultAccount, optional) – Account object to validate the -password for. Optional, but Django includes some validators to -do things like making sure users aren’t setting passwords to the -same value as their username. If left blank, these user-specific -checks are skipped.

-
-
Returns
-

valid (bool) – Whether or not the password passed validation -error (ValidationError, None): Any validation error(s) raised. Multiple

-
-

errors can be nested within a single object.

-
-

-
-
-
- -
-
-set_password(password, **kwargs)[source]
-

Applies the given password to the account. Logs and triggers the at_password_change hook.

-
-
Parameters
-

password (str) – Password to set.

-
-
-

Notes

-

This is called by Django also when logging in; it should not be mixed up with -validation, since that would mean old passwords in the database (pre validation checks) -could get invalidated.

-
- -
-
-create_character(*args, **kwargs)[source]
-

Create a character linked to this account.

-
-
Parameters
-
    -
  • key (str, optional) – If not given, use the same name as the account.

  • -
  • typeclass (str, optional) – Typeclass to use for this character. If -not given, use settings.BASE_CHARACTER_TYPECLASS.

  • -
  • permissions (list, optional) – If not given, use the account’s permissions.

  • -
  • ip (str, optiona) – The client IP creating this character. Will fall back to the -one stored for the account if not given.

  • -
  • kwargs (any) – Other kwargs will be used in the create_call.

  • -
-
-
Returns
-

Object – A new character of the character_typeclass type. None on an error. -list or None: A list of errors, or None.

-
-
-
- -
-
-classmethod create(*args, **kwargs)[source]
-

Creates an Account (or Account/Character pair for MULTISESSION_MODE<2) -with default (or overridden) permissions and having joined them to the -appropriate default channels.

-
-
Keyword Arguments
-
    -
  • username (str) – Username of Account owner

  • -
  • password (str) – Password of Account owner

  • -
  • email (str, optional) – Email address of Account owner

  • -
  • ip (str, optional) – IP address of requesting connection

  • -
  • guest (bool, optional) – Whether or not this is to be a Guest account

  • -
  • permissions (str, optional) – Default permissions for the Account

  • -
  • typeclass (str, optional) – Typeclass to use for new Account

  • -
  • character_typeclass (str, optional) – Typeclass to use for new char -when applicable.

  • -
-
-
Returns
-

account (Account) – Account if successfully created; None if not -errors (list): List of error messages in string form

-
-
-
- -
-
-delete(*args, **kwargs)[source]
-

Deletes the account persistently.

-

Notes

-
-
*args and **kwargs are passed on to the base delete

mechanism (these are usually not used).

-
-
-
-
Returns
-

bool

-
-
If deletion was successful. Only time it fails would be

if the Account was already deleted. Note that even on a failure, -connected resources (nicks/aliases etc) will still have been -deleted.

-
-
-

-
-
-
- -
-
-msg(text=None, from_obj=None, session=None, options=None, **kwargs)[source]
-

Evennia -> User -This is the main route for sending data back to the user from the -server.

-
-
Parameters
-
    -
  • text (str or tuple, optional) – The message to send. This -is treated internally like any send-command, so its -value can be a tuple if sending multiple arguments to -the text oob command.

  • -
  • from_obj (Object or Account or list, optional) – Object sending. If given, its -at_msg_send() hook will be called. If iterable, call on all entities.

  • -
  • session (Session or list, optional) – Session object or a list of -Sessions to receive this send. If given, overrules the -default send behavior for the current -MULTISESSION_MODE.

  • -
  • options (list) – Protocol-specific options. Passed on to the protocol.

  • -
-
-
Keyword Arguments
-

any (dict) – All other keywords are passed on to the protocol.

-
-
-
- -
-
-execute_cmd(raw_string, session=None, **kwargs)[source]
-

Do something as this account. This method is never called normally, -but only when the account object itself is supposed to execute the -command. It takes account nicks into account, but not nicks of -eventual puppets.

-
-
Parameters
-
    -
  • raw_string (str) – Raw command input coming from the command line.

  • -
  • session (Session, optional) – The session to be responsible -for the command-send

  • -
-
-
Keyword Arguments
-

kwargs (any) – Other keyword arguments will be added to the -found command object instance as variables before it -executes. This is unused by default Evennia but may be -used to set flags and change operating paramaters for -commands at run-time.

-
-
-
- -
-
-at_pre_channel_msg(message, channel, senders=None, **kwargs)[source]
-

Called by the Channel just before passing a message into channel_msg. -This allows for tweak messages per-user and also to abort the -receive on the receiver-level.

-
-
Parameters
-
    -
  • message (str) – The message sent to the channel.

  • -
  • channel (Channel) – The sending channel.

  • -
  • senders (list, optional) – Accounts or Objects acting as senders. -For most normal messages, there is only a single sender. If -there are no senders, this may be a broadcasting message.

  • -
  • **kwargs – These are additional keywords passed into channel_msg. -If no_prefix=True or emit=True are passed, the channel -prefix will not be added (**[channelname]: ** by default)

  • -
-
-
Returns
-

str or None

-
-
Allows for customizing the message for this recipient.

If returning None (or False) message-receiving is aborted. -The returning string will be passed into self.channel_msg.

-
-
-

-
-
-

Notes

-

This support posing/emotes by starting channel-send with : or ;.

-
- -
-
-channel_msg(message, channel, senders=None, **kwargs)[source]
-

This performs the actions of receiving a message to an un-muted -channel.

-
-
Parameters
-
    -
  • message (str) – The message sent to the channel.

  • -
  • channel (Channel) – The sending channel.

  • -
  • senders (list, optional) – Accounts or Objects acting as senders. -For most normal messages, there is only a single sender. If -there are no senders, this may be a broadcasting message or -similar.

  • -
  • **kwargs – These are additional keywords originally passed into -Channel.msg.

  • -
-
-
-

Notes

-

Before this, Channel.at_pre_channel_msg will fire, which offers a way -to customize the message for the receiver on the channel-level.

-
- -
-
-at_post_channel_msg(message, channel, senders=None, **kwargs)[source]
-

Called by self.channel_msg after message was received.

-
-
Parameters
-
    -
  • message (str) – The message sent to the channel.

  • -
  • channel (Channel) – The sending channel.

  • -
  • senders (list, optional) – Accounts or Objects acting as senders. -For most normal messages, there is only a single sender. If -there are no senders, this may be a broadcasting message.

  • -
  • **kwargs – These are additional keywords passed into channel_msg.

  • -
-
-
-
- -
-
-search(searchdata, return_puppet=False, search_object=False, typeclass=None, nofound_string=None, multimatch_string=None, use_nicks=True, quiet=False, **kwargs)[source]
-

This is similar to DefaultObject.search but defaults to searching -for Accounts only.

-
-
Parameters
-
    -
  • searchdata (str or int) – Search criterion, the Account’s -key or dbref to search for.

  • -
  • return_puppet (bool, optional) – Instructs the method to -return matches as the object the Account controls rather -than the Account itself (or None) if nothing is puppeted).

  • -
  • search_object (bool, optional) – Search for Objects instead of -Accounts. This is used by e.g. the @examine command when -wanting to examine Objects while OOC.

  • -
  • typeclass (Account typeclass, optional) – Limit the search -only to this particular typeclass. This can be used to -limit to specific account typeclasses or to limit the search -to a particular Object typeclass if search_object is True.

  • -
  • nofound_string (str, optional) – A one-time error message -to echo if searchdata leads to no matches. If not given, -will fall back to the default handler.

  • -
  • multimatch_string (str, optional) – A one-time error -message to echo if searchdata leads to multiple matches. -If not given, will fall back to the default handler.

  • -
  • use_nicks (bool, optional) – Use account-level nick replacement.

  • -
  • quiet (bool, optional) – If set, will not show any error to the user, -and will also lead to returning a list of matches.

  • -
-
-
Returns
-

match (Account, Object or None) – A single Account or Object match. -list: If quiet=True this is a list of 0, 1 or more Account or Object matches.

-
-
-

Notes

-

Extra keywords are ignored, but are allowed in call in -order to make API more consistent with -objects.objects.DefaultObject.search.

-
- -
-
-access(accessing_obj, access_type='read', default=False, no_superuser_bypass=False, **kwargs)[source]
-

Determines if another object has permission to access this -object in whatever way.

-
-
Parameters
-
    -
  • accessing_obj (Object) – Object trying to access this one.

  • -
  • access_type (str, optional) – Type of access sought.

  • -
  • default (bool, optional) – What to return if no lock of -access_type was found

  • -
  • no_superuser_bypass (bool, optional) – Turn off superuser -lock bypassing. Be careful with this one.

  • -
-
-
Keyword Arguments
-

kwargs (any) – Passed to the at_access hook along with the result.

-
-
Returns
-

result (bool) – Result of access check.

-
-
-
- -
-
-property idle_time
-

Returns the idle time of the least idle session in seconds. If -no sessions are connected it returns nothing.

-
- -
-
-property connection_time
-

Returns the maximum connection time of all connected sessions -in seconds. Returns nothing if there are no sessions.

-
- -
-
-basetype_setup()[source]
-

This sets up the basic properties for an account. Overload this -with at_account_creation rather than changing this method.

-
- -
-
-at_account_creation()[source]
-

This is called once, the very first time the account is created -(i.e. first time they register with the game). It’s a good -place to store attributes all accounts should have, like -configuration values etc.

-
- -
-
-at_init()[source]
-

This is always called whenever this object is initiated – -that is, whenever it its typeclass is cached from memory. This -happens on-demand first time the object is used or activated -in some way after being created but also after each server -restart or reload. In the case of account objects, this usually -happens the moment the account logs in or reconnects after a -reload.

-
- -
-
-at_first_save()[source]
-

This is a generic hook called by Evennia when this object is -saved to the database the very first time. You generally -don’t override this method but the hooks called by it.

-
- -
-
-at_access(result, accessing_obj, access_type, **kwargs)[source]
-
-
This is triggered after an access-call on this Account has

completed.

-
-
-
-
Parameters
-
    -
  • result (bool) – The result of the access check.

  • -
  • accessing_obj (any) – The object requesting the access -check.

  • -
  • access_type (str) – The type of access checked.

  • -
-
-
Keyword Arguments
-

kwargs (any) – These are passed on from the access check -and can be used to relay custom instructions from the -check mechanism.

-
-
-

Notes

-

This method cannot affect the result of the lock check and -its return value is not used in any way. It can be used -e.g. to customize error messages in a central location or -create other effects based on the access result.

-
- -
-
-at_cmdset_get(**kwargs)[source]
-

Called just before cmdsets on this account are requested by -the command handler. The cmdsets are available as -self.cmdset. If changes need to be done on the fly to the -cmdset before passing them on to the cmdhandler, this is the -place to do it. This is called also if the account currently -have no cmdsets. kwargs are usually not used unless the -cmdset is generated dynamically.

-
- -
-
-at_first_login(**kwargs)[source]
-

Called the very first time this account logs into the game. -Note that this is called before at_pre_login, so no session -is established and usually no character is yet assigned at -this point. This hook is intended for account-specific setup -like configurations.

-
-
Parameters
-

**kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

-
-
-
- -
-
-at_password_change(**kwargs)[source]
-

Called after a successful password set/modify.

-
-
Parameters
-

**kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

-
-
-
- -
-
-at_pre_login(**kwargs)[source]
-

Called every time the user logs in, just before the actual -login-state is set.

-
-
Parameters
-

**kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

-
-
-
- -
-
-at_post_login(session=None, **kwargs)[source]
-

Called at the end of the login process, just before letting -the account loose.

-
-
Parameters
-
    -
  • session (Session, optional) – Session logging in, if any.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-

Notes

-

This is called before an eventual Character’s -at_post_login hook. By default it is used to set up -auto-puppeting based on MULTISESSION_MODE.

-
- -
-
-at_failed_login(session, **kwargs)[source]
-

Called by the login process if a user account is targeted correctly -but provided with an invalid password. By default it does nothing, -but exists to be overriden.

-
-
Parameters
-
    -
  • session (session) – Session logging in.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-
- -
-
-at_disconnect(reason=None, **kwargs)[source]
-

Called just before user is disconnected.

-
-
Parameters
-
    -
  • reason (str, optional) – The reason given for the disconnect, -(echoed to the connection channel by default).

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-
- -
-
-at_post_disconnect(**kwargs)[source]
-

This is called after disconnection is complete. No messages -can be relayed to the account from here. After this call, the -account should not be accessed any more, making this a good -spot for deleting it (in the case of a guest account account, -for example).

-
-
Parameters
-

**kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

-
-
-
- -
-
-at_msg_receive(text=None, from_obj=None, **kwargs)[source]
-

This hook is called whenever someone sends a message to this -object using the msg method.

-

Note that from_obj may be None if the sender did not include -itself as an argument to the obj.msg() call - so you have to -check for this. .

-

Consider this a pre-processing method before msg is passed on -to the user session. If this method returns False, the msg -will not be passed on.

-
-
Parameters
-
    -
  • text (str, optional) – The message received.

  • -
  • from_obj (any, optional) – The object sending the message.

  • -
-
-
Keyword Arguments
-

includes any keywords sent to the msg method. (This) –

-
-
Returns
-

receive (bool) – If this message should be received.

-
-
-

Notes

-

If this method returns False, the msg operation -will abort without sending the message.

-
- -
-
-at_msg_send(text=None, to_obj=None, **kwargs)[source]
-

This is a hook that is called when this object sends a -message to another object with obj.msg(text, to_obj=obj).

-
-
Parameters
-
    -
  • text (str, optional) – Text to send.

  • -
  • to_obj (any, optional) – The object to send to.

  • -
-
-
Keyword Arguments
-

passed from msg() (Keywords) –

-
-
-

Notes

-

Since this method is executed by from_obj, if no from_obj -was passed to DefaultCharacter.msg this hook will never -get called.

-
- -
-
-at_server_reload()[source]
-

This hook is called whenever the server is shutting down for -restart/reboot. If you want to, for example, save -non-persistent properties across a restart, this is the place -to do it.

-
- -
-
-at_server_shutdown()[source]
-

This hook is called whenever the server is shutting down fully -(i.e. not for a restart).

-
- -
-
-at_look(target=None, session=None, **kwargs)[source]
-

Called when this object executes a look. It allows to customize -just what this means.

-
-
Parameters
-
    -
  • target (Object or list, optional) – An object or a list -objects to inspect.

  • -
  • session (Session, optional) – The session doing this look.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
Returns
-

look_string (str)

-
-
A prepared look string, ready to send

off to any recipient (usually to ourselves)

-
-
-

-
-
-
- -
-
-exception DoesNotExist
-

Bases: evennia.accounts.models.AccountDB.DoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: evennia.accounts.models.AccountDB.MultipleObjectsReturned

-
- -
-
-path = 'evennia.accounts.accounts.DefaultAccount'
-
- -
-
-typename = 'DefaultAccount'
-
- -
- -
-
-class evennia.accounts.accounts.DefaultGuest(*args, **kwargs)[source]
-

Bases: evennia.accounts.accounts.DefaultAccount

-

This class is used for guest logins. Unlike Accounts, Guests and -their characters are deleted after disconnection.

-
-
-classmethod create(**kwargs)[source]
-

Forwards request to cls.authenticate(); returns a DefaultGuest object -if one is available for use.

-
- -
-
-classmethod authenticate(**kwargs)[source]
-

Gets or creates a Guest account object.

-
-
Keyword Arguments
-

ip (str, optional) – IP address of requestor; used for ban checking, -throttling and logging

-
-
Returns
-

account (Object) – Guest account object, if available -errors (list): List of error messages accrued during this request.

-
-
-
- -
-
-at_post_login(session=None, **kwargs)[source]
-

In theory, guests only have one character regardless of which -MULTISESSION_MODE we’re in. They don’t get a choice.

-
-
Parameters
-
    -
  • session (Session, optional) – Session connecting.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-
- -
-
-at_server_shutdown()[source]
-

We repeat the functionality of at_disconnect() here just to -be on the safe side.

-
- -
-
-at_post_disconnect(**kwargs)[source]
-

Once having disconnected, destroy the guest’s characters and

-
-
Parameters
-

**kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

-
-
-
- -
-
-exception DoesNotExist
-

Bases: evennia.accounts.accounts.DefaultAccount.DoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: evennia.accounts.accounts.DefaultAccount.MultipleObjectsReturned

-
- -
-
-path = 'evennia.accounts.accounts.DefaultGuest'
-
- -
-
-typename = 'DefaultGuest'
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.accounts.admin.html b/docs/0.9.5/api/evennia.accounts.admin.html deleted file mode 100644 index 552af8a570..0000000000 --- a/docs/0.9.5/api/evennia.accounts.admin.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.accounts.admin — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.accounts.admin

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.accounts.bots.html b/docs/0.9.5/api/evennia.accounts.bots.html deleted file mode 100644 index 60cf17a26f..0000000000 --- a/docs/0.9.5/api/evennia.accounts.bots.html +++ /dev/null @@ -1,521 +0,0 @@ - - - - - - - - - evennia.accounts.bots — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.accounts.bots

-

Bots are a special child typeclasses of -Account that are controlled by the server.

-
-
-class evennia.accounts.bots.BotStarter(*args, **kwargs)[source]
-

Bases: evennia.scripts.scripts.DefaultScript

-

This non-repeating script has the -sole purpose of kicking its bot -into gear when it is initialized.

-
-
-at_script_creation()[source]
-

Called once, when script is created.

-
- -
-
-at_start()[source]
-

Kick bot into gear.

-
- -
-
-at_repeat()[source]
-

Called self.interval seconds to keep connection. We cannot use -the IDLE command from inside the game since the system will -not catch it (commands executed from the server side usually -has no sessions). So we update the idle counter manually here -instead. This keeps the bot getting hit by IDLE_TIMEOUT.

-
- -
-
-at_server_reload()[source]
-

If server reloads we don’t need to reconnect the protocol -again, this is handled by the portal reconnect mechanism.

-
- -
-
-at_server_shutdown()[source]
-

Make sure we are shutdown.

-
- -
-
-exception DoesNotExist
-

Bases: evennia.scripts.scripts.DefaultScript.DoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: evennia.scripts.scripts.DefaultScript.MultipleObjectsReturned

-
- -
-
-path = 'evennia.accounts.bots.BotStarter'
-
- -
-
-typename = 'BotStarter'
-
- -
- -
-
-class evennia.accounts.bots.Bot(*args, **kwargs)[source]
-

Bases: evennia.accounts.accounts.DefaultAccount

-

A Bot will start itself when the server starts (it will generally -not do so on a reload - that will be handled by the normal Portal -session resync)

-
-
-basetype_setup()[source]
-

This sets up the basic properties for the bot.

-
- -
-
-start(**kwargs)[source]
-

This starts the bot, whatever that may mean.

-
- -
-
-msg(text=None, from_obj=None, session=None, options=None, **kwargs)[source]
-

Evennia -> outgoing protocol

-
- -
-
-execute_cmd(raw_string, session=None)[source]
-

Incoming protocol -> Evennia

-
- -
-
-at_server_shutdown()[source]
-

We need to handle this case manually since the shutdown may be -a reset.

-
- -
-
-exception DoesNotExist
-

Bases: evennia.accounts.accounts.DefaultAccount.DoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: evennia.accounts.accounts.DefaultAccount.MultipleObjectsReturned

-
- -
-
-path = 'evennia.accounts.bots.Bot'
-
- -
-
-typename = 'Bot'
-
- -
- -
-
-class evennia.accounts.bots.IRCBot(*args, **kwargs)[source]
-

Bases: evennia.accounts.bots.Bot

-

Bot for handling IRC connections.

-
-
-factory_path = 'evennia.server.portal.irc.IRCBotFactory'
-
- -
-
-start(ev_channel=None, irc_botname=None, irc_channel=None, irc_network=None, irc_port=None, irc_ssl=None)[source]
-

Start by telling the portal to start a new session.

-
-
Parameters
-
    -
  • ev_channel (str) – Key of the Evennia channel to connect to.

  • -
  • irc_botname (str) – Name of bot to connect to irc channel. If -not set, use self.key.

  • -
  • irc_channel (str) – Name of channel on the form #channelname.

  • -
  • irc_network (str) – URL of the IRC network, like irc.freenode.net.

  • -
  • irc_port (str) – Port number of the irc network, like 6667.

  • -
  • irc_ssl (bool) – Indicates whether to use SSL connection.

  • -
-
-
-
- -
-
-at_msg_send(**kwargs)[source]
-

Shortcut here or we can end up in infinite loop

-
- -
-
-get_nicklist(caller)[source]
-

Retrive the nick list from the connected channel.

-
-
Parameters
-

caller (Object or Account) – The requester of the list. This will -be stored and echoed to when the irc network replies with the -requested info.

-
-
-
-
Notes: Since the return is asynchronous, the caller is stored internally

in a list; all callers in this list will get the nick info once it -returns (it is a custom OOB inputfunc option). The callback will not -survive a reload (which should be fine, it’s very quick).

-
-
-
- -
-
-ping(caller)[source]
-

Fire a ping to the IRC server.

-
-
Parameters
-

caller (Object or Account) – The requester of the ping.

-
-
-
- -
-
-reconnect()[source]
-

Force a protocol-side reconnect of the client without -having to destroy/recreate the bot “account”.

-
- -
-
-msg(text=None, **kwargs)[source]
-

Takes text from connected channel (only).

-
-
Parameters
-

text (str, optional) – Incoming text from channel.

-
-
Keyword Arguments
-

options (dict) – Options dict with the following allowed keys: -- from_channel (str): dbid of a channel this text originated from. -- from_obj (list): list of objects sending this text.

-
-
-
- -
-
-execute_cmd(session=None, txt=None, **kwargs)[source]
-

Take incoming data and send it to connected channel. This is -triggered by the bot_data_in Inputfunc.

-
-
Parameters
-
    -
  • session (Session, optional) – Session responsible for this -command. Note that this is the bot.

  • -
  • txt (str, optional) – Command string.

  • -
-
-
Keyword Arguments
-
    -
  • user (str) – The name of the user who sent the message.

  • -
  • channel (str) – The name of channel the message was sent to.

  • -
  • type (str) – Nature of message. Either ‘msg’, ‘action’, ‘nicklist’ -or ‘ping’.

  • -
  • nicklist (list, optional) – Set if type=’nicklist’. This is a list -of nicks returned by calling the self.get_nicklist. It must look -for a list self._nicklist_callers which will contain all callers -waiting for the nicklist.

  • -
  • timings (float, optional) – Set if type=’ping’. This is the return -(in seconds) of a ping request triggered with self.ping. The -return must look for a list self._ping_callers which will contain -all callers waiting for the ping return.

  • -
-
-
-
- -
-
-exception DoesNotExist
-

Bases: evennia.accounts.bots.Bot.DoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: evennia.accounts.bots.Bot.MultipleObjectsReturned

-
- -
-
-path = 'evennia.accounts.bots.IRCBot'
-
- -
-
-typename = 'IRCBot'
-
- -
- -
-
-class evennia.accounts.bots.RSSBot(*args, **kwargs)[source]
-

Bases: evennia.accounts.bots.Bot

-

An RSS relayer. The RSS protocol itself runs a ticker to update -its feed at regular intervals.

-
-
-start(ev_channel=None, rss_url=None, rss_rate=None)[source]
-

Start by telling the portal to start a new RSS session

-
-
Parameters
-
    -
  • ev_channel (str) – Key of the Evennia channel to connect to.

  • -
  • rss_url (str) – Full URL to the RSS feed to subscribe to.

  • -
  • rss_rate (int) – How often for the feedreader to update.

  • -
-
-
Raises
-

RuntimeError – If ev_channel does not exist.

-
-
-
- -
-
-execute_cmd(txt=None, session=None, **kwargs)[source]
-

Take incoming data and send it to connected channel. This is -triggered by the bot_data_in Inputfunc.

-
-
Parameters
-
    -
  • session (Session, optional) – Session responsible for this -command.

  • -
  • txt (str, optional) – Command string.

  • -
  • kwargs (dict, optional) – Additional Information passed from bot. -Not used by the RSSbot by default.

  • -
-
-
-
- -
-
-exception DoesNotExist
-

Bases: evennia.accounts.bots.Bot.DoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: evennia.accounts.bots.Bot.MultipleObjectsReturned

-
- -
-
-path = 'evennia.accounts.bots.RSSBot'
-
- -
-
-typename = 'RSSBot'
-
- -
- -
-
-class evennia.accounts.bots.GrapevineBot(*args, **kwargs)[source]
-

Bases: evennia.accounts.bots.Bot

-

g Grapevine (https://grapevine.haus) relayer. The channel to connect to is the first -name in the settings.GRAPEVINE_CHANNELS list.

-
-
-factory_path = 'evennia.server.portal.grapevine.RestartingWebsocketServerFactory'
-
- -
-
-start(ev_channel=None, grapevine_channel=None)[source]
-

Start by telling the portal to connect to the grapevine network.

-
- -
-
-at_msg_send(**kwargs)[source]
-

Shortcut here or we can end up in infinite loop

-
- -
-
-msg(text=None, **kwargs)[source]
-

Takes text from connected channel (only).

-
-
Parameters
-

text (str, optional) – Incoming text from channel.

-
-
Keyword Arguments
-

options (dict) – Options dict with the following allowed keys: -- from_channel (str): dbid of a channel this text originated from. -- from_obj (list): list of objects sending this text.

-
-
-
- -
-
-execute_cmd(txt=None, session=None, event=None, grapevine_channel=None, sender=None, game=None, **kwargs)[source]
-

Take incoming data from protocol and send it to connected channel. This is -triggered by the bot_data_in Inputfunc.

-
- -
-
-exception DoesNotExist
-

Bases: evennia.accounts.bots.Bot.DoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: evennia.accounts.bots.Bot.MultipleObjectsReturned

-
- -
-
-path = 'evennia.accounts.bots.GrapevineBot'
-
- -
-
-typename = 'GrapevineBot'
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.accounts.html b/docs/0.9.5/api/evennia.accounts.html deleted file mode 100644 index cf142419f8..0000000000 --- a/docs/0.9.5/api/evennia.accounts.html +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - evennia.accounts — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.accounts

-

This sub-package defines the out-of-character entities known as -Accounts. These are equivalent to ‘accounts’ and can puppet one or -more Objects depending on settings. An Account has no in-game existence.

- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.accounts.manager.html b/docs/0.9.5/api/evennia.accounts.manager.html deleted file mode 100644 index 5bb1bb5e14..0000000000 --- a/docs/0.9.5/api/evennia.accounts.manager.html +++ /dev/null @@ -1,331 +0,0 @@ - - - - - - - - - evennia.accounts.manager — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.accounts.manager

-

The managers for the custom Account object and permissions.

-
-
-class evennia.accounts.manager.AccountManager(*args, **kwargs)[source]
-

Bases: evennia.accounts.manager.AccountDBManager, evennia.typeclasses.managers.TypeclassManager

-
- -
-
-class evennia.accounts.manager.AccountDBManager(*args, **kwargs)[source]
-

Bases: evennia.typeclasses.managers.TypedObjectManager, django.contrib.auth.models.UserManager

-

This AccountManager implements methods for searching -and manipulating Accounts directly from the database.

-

Evennia-specific search methods (will return Characters if -possible or a Typeclass/list of Typeclassed objects, whereas -Django-general methods will return Querysets or database objects):

-

dbref (converter) -dbref_search -get_dbref_range -object_totals -typeclass_search -num_total_accounts -get_connected_accounts -get_recently_created_accounts -get_recently_connected_accounts -get_account_from_email -get_account_from_uid -get_account_from_name -account_search (equivalent to evennia.search_account)

-
-
-num_total_accounts()[source]
-

Get total number of accounts.

-
-
Returns
-

count (int) – The total number of registered accounts.

-
-
-
- -
-
-get_connected_accounts()[source]
-

Get all currently connected accounts.

-
-
Returns
-

count (list)

-
-
Account objects with currently

connected sessions.

-
-
-

-
-
-
- -
-
-get_recently_created_accounts(days=7)[source]
-

Get accounts recently created.

-
-
Parameters
-

days (int, optional) – How many days in the past “recently” means.

-
-
Returns
-

accounts (list) – The Accounts created the last days interval.

-
-
-
- -
-
-get_recently_connected_accounts(days=7)[source]
-

Get accounts recently connected to the game.

-
-
Parameters
-

days (int, optional) – Number of days backwards to check

-
-
Returns
-

accounts (list)

-
-
The Accounts connected to the game in the

last days interval.

-
-
-

-
-
-
- -
-
-get_account_from_email(uemail)[source]
-

Search account by -Returns an account object based on email address.

-
-
Parameters
-

uemail (str) – An email address to search for.

-
-
Returns
-

account (Account) – A found account, if found.

-
-
-
- -
-
-get_account_from_uid(uid)[source]
-

Get an account by id.

-
-
Parameters
-

uid (int) – Account database id.

-
-
Returns
-

account (Account) – The result.

-
-
-
- -
-
-get_account_from_name(uname)[source]
-

Get account object based on name.

-
-
Parameters
-

uname (str) – The Account name to search for.

-
-
Returns
-

account (Account) – The found account.

-
-
-
- -
-
-search_account(ostring, exact=True, typeclass=None)[source]
-

Searches for a particular account by name or -database id.

-
-
Parameters
-
    -
  • ostring (str or int) – A key string or database id.

  • -
  • exact (bool, optional) – Only valid for string matches. If -True, requires exact (non-case-sensitive) match, -otherwise also match also keys containing the ostring -(non-case-sensitive fuzzy match).

  • -
  • typeclass (str or Typeclass, optional) – Limit the search only to -accounts of this typeclass.

  • -
-
-
Returns
-

Queryset – A queryset (an iterable) with 0, 1 or more matches.

-
-
-
- -
-
-create_account(key, email, password, typeclass=None, is_superuser=False, locks=None, permissions=None, tags=None, attributes=None, report_to=None)[source]
-

This creates a new account.

-
-
Parameters
-
    -
  • key (str) – The account’s name. This should be unique.

  • -
  • email (str or None) – Email on valid addr@addr.domain form. If -the empty string, will be set to None.

  • -
  • password (str) – Password in cleartext.

  • -
-
-
Keyword Arguments
-
    -
  • typeclass (str) – The typeclass to use for the account.

  • -
  • is_superuser (bool) – Wether or not this account is to be a superuser

  • -
  • locks (str) – Lockstring.

  • -
  • permission (list) – List of permission strings.

  • -
  • tags (list) – List of Tags on form (key, category[, data])

  • -
  • attributes (list) – List of Attributes on form -(key, value [, category, [,lockstring [, default_pass]]])

  • -
  • report_to (Object) – An object with a msg() method to report -errors to. If not given, errors will be logged.

  • -
-
-
Returns
-

Account – The newly created Account.

-
-
Raises
-

ValueError – If key already exists in database.

-
-
-

Notes

-

Usually only the server admin should need to be superuser, all -other access levels can be handled with more fine-grained -permissions or groups. A superuser bypasses all lock checking -operations and is thus not suitable for play-testing the game.

-
- -
- -

Searches for a particular account by name or -database id.

-
-
Parameters
-
    -
  • ostring (str or int) – A key string or database id.

  • -
  • exact (bool, optional) – Only valid for string matches. If -True, requires exact (non-case-sensitive) match, -otherwise also match also keys containing the ostring -(non-case-sensitive fuzzy match).

  • -
  • typeclass (str or Typeclass, optional) – Limit the search only to -accounts of this typeclass.

  • -
-
-
Returns
-

Queryset – A queryset (an iterable) with 0, 1 or more matches.

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.accounts.models.html b/docs/0.9.5/api/evennia.accounts.models.html deleted file mode 100644 index e89b4aa790..0000000000 --- a/docs/0.9.5/api/evennia.accounts.models.html +++ /dev/null @@ -1,439 +0,0 @@ - - - - - - - - - evennia.accounts.models — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.accounts.models

-

Account

-

The account class is an extension of the default Django user class, -and is customized for the needs of Evennia.

-

We use the Account to store a more mud-friendly style of permission -system as well as to allow the admin more flexibility by storing -attributes on the Account. Within the game we should normally use the -Account manager’s methods to create users so that permissions are set -correctly.

-

To make the Account model more flexible for your own game, it can also -persistently store attributes of its own. This is ideal for extra -account info and OOC account configuration variables etc.

-
-
-class evennia.accounts.models.AccountDB(*args, **kwargs)[source]
-

Bases: evennia.typeclasses.models.TypedObject, django.contrib.auth.models.AbstractUser

-

This is a special model using Django’s ‘profile’ functionality -and extends the default Django User model. It is defined as such -by use of the variable AUTH_PROFILE_MODULE in the settings. -One accesses the fields/methods. We try use this model as much -as possible rather than User, since we can customize this to -our liking.

-

The TypedObject supplies the following (inherited) properties:

-
-
    -
  • key - main name

  • -
  • typeclass_path - the path to the decorating typeclass

  • -
  • typeclass - auto-linked typeclass

  • -
  • date_created - time stamp of object creation

  • -
  • permissions - perm strings

  • -
  • dbref - #id of object

  • -
  • db - persistent attribute storage

  • -
  • ndb - non-persistent attribute storage

  • -
-
-

The AccountDB adds the following properties:

-
-
    -
  • is_connected - If any Session is currently connected to this Account

  • -
  • name - alias for user.username

  • -
  • sessions - sessions connected to this account

  • -
  • is_superuser - bool if this account is a superuser

  • -
  • is_bot - bool if this account is a bot and not a real account

  • -
-
-
-
-db_is_connected
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_cmdset_storage
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_is_bot
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-objects = <evennia.accounts.manager.AccountDBManager object>
-
- -
-
-property cmdset_storage
-

Getter. Allows for value = self.name. Returns a list of cmdset_storage.

-
- -
-
-property name
-
- -
-
-property key
-
- -
-
-property uid
-

Getter. Retrieves the user id

-
- -
-
-exception DoesNotExist
-

Bases: django.core.exceptions.ObjectDoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: django.core.exceptions.MultipleObjectsReturned

-
- -
-
-account_subscription_set
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-db_attributes
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-db_tags
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-get_next_by_date_joined(*, field=<django.db.models.fields.DateTimeField: date_joined>, is_next=True, **kwargs)
-
- -
-
-get_next_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=True, **kwargs)
-
- -
-
-get_previous_by_date_joined(*, field=<django.db.models.fields.DateTimeField: date_joined>, is_next=False, **kwargs)
-
- -
-
-get_previous_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=False, **kwargs)
-
- -
-
-groups
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-hide_from_accounts_set
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-id
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-property is_bot
-

A wrapper for getting database field db_is_bot.

-
- -
-
-property is_connected
-

A wrapper for getting database field db_is_connected.

-
- -
-
-logentry_set
-

Accessor to the related objects manager on the reverse side of a -many-to-one relation.

-

In the example:

-
class Child(Model):
-    parent = ForeignKey(Parent, related_name='children')
-
-
-

**Parent.children** is a **ReverseManyToOneDescriptor** instance.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-objectdb_set
-

Accessor to the related objects manager on the reverse side of a -many-to-one relation.

-

In the example:

-
class Child(Model):
-    parent = ForeignKey(Parent, related_name='children')
-
-
-

**Parent.children** is a **ReverseManyToOneDescriptor** instance.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-path = 'evennia.accounts.models.AccountDB'
-
- -
-
-receiver_account_set
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-scriptdb_set
-

Accessor to the related objects manager on the reverse side of a -many-to-one relation.

-

In the example:

-
class Child(Model):
-    parent = ForeignKey(Parent, related_name='children')
-
-
-

**Parent.children** is a **ReverseManyToOneDescriptor** instance.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-sender_account_set
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-typename = 'SharedMemoryModelBase'
-
- -
-
-user_permissions
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.cmdhandler.html b/docs/0.9.5/api/evennia.commands.cmdhandler.html deleted file mode 100644 index 8685dd6504..0000000000 --- a/docs/0.9.5/api/evennia.commands.cmdhandler.html +++ /dev/null @@ -1,197 +0,0 @@ - - - - - - - - - evennia.commands.cmdhandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.commands.cmdhandler

-

Command handler

-

This module contains the infrastructure for accepting commands on the -command line. The processing of a command works as follows:

-
    -
  1. The calling object (caller) is analyzed based on its callertype.

  2. -
  3. Cmdsets are gathered from different sources: -- object cmdsets: all objects at caller’s location are scanned for non-empty

    -
    -

    cmdsets. This includes cmdsets on exits.

    -
    -
      -
    • caller: the caller is searched for its own currently active cmdset.

    • -
    • account: lastly the cmdsets defined on caller.account are added.

    • -
    -
  4. -
  5. The collected cmdsets are merged together to a combined, current cmdset.

  6. -
  7. If the input string is empty -> check for CMD_NOINPUT command in -current cmdset or fallback to error message. Exit.

  8. -
  9. The Command Parser is triggered, using the current cmdset to analyze the -input string for possible command matches.

  10. -
  11. If multiple matches are found -> check for CMD_MULTIMATCH in current -cmdset, or fallback to error message. Exit.

  12. -
  13. If no match was found -> check for CMD_NOMATCH in current cmdset or -fallback to error message. Exit.

  14. -
  15. At this point we have found a normal command. We assign useful variables to it that -will be available to the command coder at run-time.

  16. -
  17. We have a unique cmdobject, primed for use. Call all hooks: -at_pre_cmd(), cmdobj.parse(), cmdobj.func() and finally at_post_cmd().

  18. -
  19. Return deferred that will fire with the return from cmdobj.func() (unused by default).

  20. -
-
-
-evennia.commands.cmdhandler.cmdhandler(called_by, raw_string, _testing=False, callertype='session', session=None, cmdobj=None, cmdobj_key=None, **kwargs)[source]
-

This is the main mechanism that handles any string sent to the engine.

-
-
Parameters
-
    -
  • called_by (Session, Account or Object) – Object from which this -command was called. which this was called from. What this is -depends on the game state.

  • -
  • raw_string (str) – The command string as given on the command line.

  • -
  • _testing (bool, optional) – Used for debug purposes and decides if we -should actually execute the command or not. If True, the -command instance will be returned.

  • -
  • callertype (str, optional) – One of “session”, “account” or -“object”. These are treated in decending order, so when the -Session is the caller, it will merge its own cmdset into -cmdsets from both Account and eventual puppeted Object (and -cmdsets in its room etc). An Account will only include its own -cmdset and the Objects and so on. Merge order is the same -order, so that Object cmdsets are merged in last, giving them -precendence for same-name and same-prio commands.

  • -
  • session (Session, optional) – Relevant if callertype is “account” - the session will help -retrieve the correct cmdsets from puppeted objects.

  • -
  • cmdobj (Command, optional) – If given a command instance, this will be executed using -called_by as the caller, raw_string representing its arguments and (optionally) -cmdobj_key as its input command name. No cmdset lookup will be performed but -all other options apply as normal. This allows for running a specific Command -within the command system mechanism.

  • -
  • cmdobj_key (string, optional) – Used together with cmdobj keyword to specify -which cmdname should be assigned when calling the specified Command instance. This -is made available as self.cmdstring when the Command runs. -If not given, the command will be assumed to be called as cmdobj.key.

  • -
-
-
Keyword Arguments
-

kwargs (any) – other keyword arguments will be assigned as named variables on the -retrieved command object before it is executed. This is unused -in default Evennia but may be used by code to set custom flags or -special operating conditions for a command as it executes.

-
-
Returns
-

deferred (Deferred) – This deferred is fired with the return -value of the command’s func method. This is not used in -default Evennia.

-
-
-
- -
-
-exception evennia.commands.cmdhandler.InterruptCommand[source]
-

Bases: Exception

-

Cleanly interrupt a command.

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.cmdparser.html b/docs/0.9.5/api/evennia.commands.cmdparser.html deleted file mode 100644 index ecf729ad76..0000000000 --- a/docs/0.9.5/api/evennia.commands.cmdparser.html +++ /dev/null @@ -1,233 +0,0 @@ - - - - - - - - - evennia.commands.cmdparser — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.commands.cmdparser

-

The default command parser. Use your own by assigning -settings.COMMAND_PARSER to a Python path to a module containing the -replacing cmdparser function. The replacement parser must accept the -same inputs as the default one.

-
-
-evennia.commands.cmdparser.create_match(cmdname, string, cmdobj, raw_cmdname)[source]
-

Builds a command match by splitting the incoming string and -evaluating the quality of the match.

-
-
Parameters
-
    -
  • cmdname (str) – Name of command to check for.

  • -
  • string (str) – The string to match against.

  • -
  • cmdobj (str) – The full Command instance.

  • -
  • raw_cmdname (str, optional) – If CMD_IGNORE_PREFIX is set and the cmdname starts with -one of the prefixes to ignore, this contains the raw, unstripped cmdname, -otherwise it is None.

  • -
-
-
Returns
-

match (tuple)

-
-
This is on the form (cmdname, args, cmdobj, cmdlen, mratio, raw_cmdname),

where cmdname is the command’s name and args is the rest of the incoming -string, without said command name. cmdobj is -the Command instance, the cmdlen is the same as len(cmdname) and mratio -is a measure of how big a part of the full input string the cmdname -takes up - an exact match would be 1.0. Finally, the raw_cmdname is -the cmdname unmodified by eventual prefix-stripping.

-
-
-

-
-
-
- -
-
-evennia.commands.cmdparser.build_matches(raw_string, cmdset, include_prefixes=False)[source]
-

Build match tuples by matching raw_string against available commands.

-
-
Parameters
-
    -
  • raw_string (str) – Input string that can look in any way; the only assumption is -that the sought command’s name/alias must be first in the string.

  • -
  • cmdset (CmdSet) – The current cmdset to pick Commands from.

  • -
  • include_prefixes (bool) – If set, include prefixes like @, ! etc (specified in settings) -in the match, otherwise strip them before matching.

  • -
-
-
Returns
-

matches (list) A list of match tuples created by cmdparser.create_match.

-
-
-
- -
-
-evennia.commands.cmdparser.try_num_differentiators(raw_string)[source]
-

Test if user tried to separate multi-matches with a number separator -(default 1-name, 2-name etc). This is usually called last, if no other -match was found.

-
-
Parameters
-

raw_string (str) – The user input to parse.

-
-
Returns
-

mindex, new_raw_string (tuple)

-
-
If a multimatch-separator was detected,

this is stripped out as an integer to separate between the matches. The -new_raw_string is the result of stripping out that identifier. If no -such form was found, returns (None, None).

-
-
-

-
-
-

Example

-

In the default configuration, entering 2-ball (e.g. in a room will more -than one ‘ball’ object), will lead to a multimatch and this function -will parse “2-ball” and return (2, “ball”).

-
- -
-
-evennia.commands.cmdparser.cmdparser(raw_string, cmdset, caller, match_index=None)[source]
-

This function is called by the cmdhandler once it has -gathered and merged all valid cmdsets valid for this particular parsing.

-
-
Parameters
-
    -
  • raw_string (str) – The unparsed text entered by the caller.

  • -
  • cmdset (CmdSet) – The merged, currently valid cmdset

  • -
  • caller (Session, Account or Object) – The caller triggering this parsing.

  • -
  • match_index (int, optional) – Index to pick a given match in a -list of same-named command matches. If this is given, it suggests -this is not the first time this function was called: normally -the first run resulted in a multimatch, and the index is given -to select between the results for the second run.

  • -
-
-
Returns
-

matches (list)

-
-
This is a list of match-tuples as returned by create_match.

If no matches were found, this is an empty list.

-
-
-

-
-
-

Notes

-

The cmdparser understand the following command combinations (where -[] marks optional parts.

-

[cmdname[ cmdname2 cmdname3 …] [the rest]

-

A command may consist of any number of space-separated words of any -length, and contain any character. It may also be empty.

-

The parser makes use of the cmdset to find command candidates. The -parser return a list of matches. Each match is a tuple with its -first three elements being the parsed cmdname (lower case), -the remaining arguments, and the matched cmdobject from the cmdset.

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.cmdset.html b/docs/0.9.5/api/evennia.commands.cmdset.html deleted file mode 100644 index fe3a7468ef..0000000000 --- a/docs/0.9.5/api/evennia.commands.cmdset.html +++ /dev/null @@ -1,450 +0,0 @@ - - - - - - - - - evennia.commands.cmdset — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.commands.cmdset

-

A Command Set (CmdSet) holds a set of commands. The Cmdsets can be -merged and combined to create new sets of commands in a -non-destructive way. This makes them very powerful for implementing -custom game states where different commands (or different variations -of commands) are available to the accounts depending on circumstance.

-

The available merge operations are partly borrowed from mathematical -Set theory.

-
    -
  • -
    Union The two command sets are merged so that as many commands as

    possible of each cmdset ends up in the merged cmdset. Same-name -commands are merged by priority. This is the most common default. -Ex: A1,A3 + B1,B2,B4,B5 = A1,B2,A3,B4,B5

    -
    -
    -
  • -
  • -
    Intersect - Only commands found in both cmdsets (i.e. which have

    same names) end up in the merged cmdset, with the higher-priority -cmdset replacing the lower one. Ex: A1,A3 + B1,B2,B4,B5 = A1

    -
    -
    -
  • -
  • -
    Replace - The commands of this cmdset completely replaces the

    lower-priority cmdset’s commands, regardless of if same-name commands -exist. Ex: A1,A3 + B1,B2,B4,B5 = A1,A3

    -
    -
    -
  • -
  • -
    Remove - This removes the relevant commands from the

    lower-priority cmdset completely. They are not replaced with -anything, so this in effects uses the high-priority cmdset as a filter -to affect the low-priority cmdset. Ex: A1,A3 + B1,B2,B4,B5 = B2,B4,B5

    -
    -
    -
  • -
-
-
-class evennia.commands.cmdset.CmdSet(cmdsetobj=None, key=None)[source]
-

Bases: object

-

This class describes a unique cmdset that understands priorities. -CmdSets can be merged and made to perform various set operations -on each other. CmdSets have priorities that affect which of their -ingoing commands gets used.

-

In the examples, cmdset A always have higher priority than cmdset B.

-

key - the name of the cmdset. This can be used on its own for game -operations

-

mergetype (partly from Set theory):

-
-
-
Union - The two command sets are merged so that as many

commands as possible of each cmdset ends up in the -merged cmdset. Same-name commands are merged by -priority. This is the most common default. -Ex: A1,A3 + B1,B2,B4,B5 = A1,B2,A3,B4,B5

-
-
Intersect - Only commands found in both cmdsets

(i.e. which have same names) end up in the merged -cmdset, with the higher-priority cmdset replacing the -lower one. Ex: A1,A3 + B1,B2,B4,B5 = A1

-
-
Replace - The commands of this cmdset completely replaces

the lower-priority cmdset’s commands, regardless -of if same-name commands exist. -Ex: A1,A3 + B1,B2,B4,B5 = A1,A3

-
-
Remove - This removes the relevant commands from the
-

lower-priority cmdset completely. They are not -replaced with anything, so this in effects uses the -high-priority cmdset as a filter to affect the -low-priority cmdset. -Ex: A1,A3 + B1,B2,B4,B5 = B2,B4,B5

-
-
-
Note: Commands longer than 2 characters and starting

with double underscrores, like ‘__noinput_command’ -are considered ‘system commands’ and are -excempt from all merge operations - they are -ALWAYS included across mergers and only affected -if same-named system commands replace them.

-
-
-
-
-
-
-
priority- All cmdsets are always merged in pairs of two so that

the higher set’s mergetype is applied to the -lower-priority cmdset. Default commands have priority 0, -high-priority ones like Exits and Channels have 10 and 9. -Priorities can be negative as well to give default -commands preference.

-
-
duplicates - determines what happens when two sets of equal
-

priority merge (only). Defaults to None and has the first of them in the -merger (i.e. A above) automatically taking -precedence. But if duplicates is true, the -result will be a merger with more than one of each -name match. This will usually lead to the account -receiving a multiple-match error higher up the road, -but can be good for things like cmdsets on non-account -objects in a room, to allow the system to warn that -more than one ‘ball’ in the room has the same ‘kick’ -command defined on it, so it may offer a chance to -select which ball to kick … Allowing duplicates -only makes sense for Union and Intersect, the setting -is ignored for the other mergetypes. -Note that the duplicates flag is not propagated in -a cmdset merger. So A + B = C will result in -a cmdset with duplicate commands, but C.duplicates will -be None. For duplication to apply to a whole cmdset -stack merge, _all_ cmdsets in the stack must have -.duplicates=True set.

-
-

Finally, if a final cmdset has .duplicates=None (the normal -unless created alone with another value), the cmdhandler -will assume True for object-based cmdsets and False for -all other. This is usually the most intuitive outcome.

-
-
key_mergetype (dict) - allows the cmdset to define a unique

mergetype for particular cmdsets. Format is -{CmdSetkeystring:mergetype}. Priorities still apply. -Example: {‘Myevilcmdset’,’Replace’} which would make -sure for this set to always use ‘Replace’ on -Myevilcmdset no matter what overall mergetype this set -has.

-
-
no_objs - don’t include any commands from nearby objects

when searching for suitable commands

-
-
no_exits - ignore the names of exits when matching against

commands

-
-
no_channels - ignore the name of channels when matching against

commands (WARNING- this is dangerous since the -account can then not even ask staff for help if -something goes wrong)

-
-
-
-
-mergetype = 'Union'
-
- -
-
-priority = 0
-
- -
-
-no_exits = None
-
- -
-
-no_objs = None
-
- -
-
-no_channels = None
-
- -
-
-duplicates = None
-
- -
-
-persistent = False
-
- -
-
-key_mergetypes = {}
-
- -
-
-errmessage = ''
-
- -
-
-to_duplicate = ('key', 'cmdsetobj', 'no_exits', 'no_objs', 'no_channels', 'persistent', 'mergetype', 'priority', 'duplicates', 'errmessage')
-
- -
-
-__init__(cmdsetobj=None, key=None)[source]
-

Creates a new CmdSet instance.

-
-
Parameters
-
    -
  • cmdsetobj (Session, Account, Object, optional) – This is the database object -to which this particular instance of cmdset is related. It -is often a character but may also be a regular object, Account -or Session.

  • -
  • key (str, optional) – The idenfier for this cmdset. This -helps if wanting to selectively remov cmdsets.

  • -
-
-
-
- -
-
-key = 'Unnamed CmdSet'
-
- -
-
-add(cmd, allow_duplicates=False)[source]
-

Add a new command or commands to this CmdSet, a list of -commands or a cmdset to this cmdset. Note that this is not -a merge operation (that is handled by the + operator).

-
-
Parameters
-
    -
  • cmd (Command, list, Cmdset) – This allows for adding one or -more commands to this Cmdset in one go. If another Cmdset -is given, all its commands will be added.

  • -
  • allow_duplicates (bool, optional) – If set, will not try to remove -duplicate cmds in the set. This is needed during the merge process -to avoid wiping commands coming from cmdsets with duplicate=True.

  • -
-
-
-

Notes

-

If cmd already exists in set, it will replace the old one -(no priority checking etc happens here). This is very useful -when overloading default commands).

-

If cmd is another cmdset class or -instance, the commands of -that command set is added to this one, as if they were part of -the original cmdset definition. No merging or priority checks -are made, rather later added commands will simply replace -existing ones to make a unique set.

-
- -
-
-remove(cmd)[source]
-

Remove a command instance from the cmdset.

-
-
Parameters
-

cmd (Command or str) – Either the Command object to remove -or the key of such a command.

-
-
-
- -
-
-get(cmd)[source]
-

Get a command from the cmdset. This is mostly useful to -check if the command is part of this cmdset or not.

-
-
Parameters
-

cmd (Command or str) – Either the Command object or its key.

-
-
Returns
-

cmd (Command) – The first matching Command in the set.

-
-
-
- -
-
-count()[source]
-

Number of commands in set.

-
-
Returns
-

N (int) – Number of commands in this Cmdset.

-
-
-
- -
-
-get_system_cmds()[source]
-

Get system commands in cmdset

-
-
Returns
-

sys_cmds (list) – The system commands in the set.

-
-
-

Notes

-

As far as the Cmdset is concerned, system commands are any -commands with a key starting with double underscore __. -These are excempt from merge operations.

-
- -
-
-make_unique(caller)[source]
-

Remove duplicate command-keys (unsafe)

-
-
Parameters
-

caller (object) – Commands on this object will -get preference in the duplicate removal.

-
-
-

Notes

-

This is an unsafe command meant to clean out a cmdset of -doublet commands after it has been created. It is useful -for commands inheriting cmdsets from the cmdhandler where -obj-based cmdsets always are added double. Doublets will -be weeded out with preference to commands defined on -caller, otherwise just by first-come-first-served.

-
- -
-
-get_all_cmd_keys_and_aliases(caller=None)[source]
-

Collects keys/aliases from commands

-
-
Parameters
-

caller (Object, optional) – If set, this is used to check access permissions -on each command. Only commands that pass are returned.

-
-
Returns
-

names (list)

-
-
A list of all command keys and aliases in this cmdset. If caller

was given, this list will only contain commands to which caller passed -the call locktype check.

-
-
-

-
-
-
- -
-
-at_cmdset_creation()[source]
-

Hook method - this should be overloaded in the inheriting -class, and should take care of populating the cmdset by use of -self.add().

-
- -
-
-path = 'evennia.commands.cmdset.CmdSet'
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.cmdsethandler.html b/docs/0.9.5/api/evennia.commands.cmdsethandler.html deleted file mode 100644 index d3babf9cd0..0000000000 --- a/docs/0.9.5/api/evennia.commands.cmdsethandler.html +++ /dev/null @@ -1,418 +0,0 @@ - - - - - - - - - evennia.commands.cmdsethandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.commands.cmdsethandler

-

CmdSethandler

-

The Cmdsethandler tracks an object’s ‘Current CmdSet’, which is the -current merged sum of all CmdSets added to it.

-

A CmdSet constitues a set of commands. The CmdSet works as a special -intelligent container that, when added to other CmdSet make sure that -same-name commands are treated correctly (usually so there are no -doublets). This temporary but up-to-date merger of CmdSet is jointly -called the Current Cmset. It is this Current CmdSet that the -commandhandler looks through whenever an account enters a command (it -also adds CmdSets from objects in the room in real-time). All account -objects have a ‘default cmdset’ containing all the normal in-game mud -commands (look etc).

-

So what is all this cmdset complexity good for?

-

In its simplest form, a CmdSet has no commands, only a key name. In -this case the cmdset’s use is up to each individual game - it can be -used by an AI module for example (mobs in cmdset ‘roam’ move from room -to room, in cmdset ‘attack’ they enter combat with accounts).

-

Defining commands in cmdsets offer some further powerful game-design -consequences however. Here are some examples:

-

As mentioned above, all accounts always have at least the Default -CmdSet. This contains the set of all normal-use commands in-game, -stuff like look and @desc etc. Now assume our players end up in a dark -room. You don’t want the player to be able to do much in that dark -room unless they light a candle. You could handle this by changing all -your normal commands to check if the player is in a dark room. This -rapidly goes unwieldly and error prone. Instead you just define a -cmdset with only those commands you want to be available in the ‘dark’ -cmdset - maybe a modified look command and a ‘light candle’ command - -and have this completely replace the default cmdset.

-

Another example: Say you want your players to be able to go -fishing. You could implement this as a ‘fish’ command that fails -whenever the account has no fishing rod. Easy enough. But what if you -want to make fishing more complex - maybe you want four-five different -commands for throwing your line, reeling in, etc? Most players won’t -(we assume) have fishing gear, and having all those detailed commands -is cluttering up the command list. And what if you want to use the -‘throw’ command also for throwing rocks etc instead of ‘using it up’ -for a minor thing like fishing?

-

So instead you put all those detailed fishing commands into their own -CommandSet called ‘Fishing’. Whenever the player gives the command -‘fish’ (presumably the code checks there is also water nearby), only -THEN this CommandSet is added to the Cmdhandler of the account. The -‘throw’ command (which normally throws rocks) is replaced by the -custom ‘fishing variant’ of throw. What has happened is that the -Fishing CommandSet was merged on top of the Default ones, and due to -how we defined it, its command overrules the default ones.

-

When we are tired of fishing, we give the ‘go home’ command (or -whatever) and the Cmdhandler simply removes the fishing CommandSet -so that we are back at defaults (and can throw rocks again).

-

Since any number of CommandSets can be piled on top of each other, you -can then implement separate sets for different situations. For -example, you can have a ‘On a boat’ set, onto which you then tack on -the ‘Fishing’ set. Fishing from a boat? No problem!

-
-
-evennia.commands.cmdsethandler.import_cmdset(path, cmdsetobj, emit_to_obj=None, no_logging=False)[source]
-

This helper function is used by the cmdsethandler to load a cmdset -instance from a python module, given a python_path. It’s usually accessed -through the cmdsethandler’s add() and add_default() methods. -path - This is the full path to the cmdset object on python dot-form

-
-
Parameters
-
    -
  • path (str) – The path to the command set to load.

  • -
  • cmdsetobj (CmdSet) – The database object/typeclass on which this cmdset is to be -assigned (this can be also channels and exits, as well as accounts -but there will always be such an object)

  • -
  • emit_to_obj (Object, optional) – If given, error is emitted to -this object (in addition to logging)

  • -
  • no_logging (bool, optional) – Don’t log/send error messages. -This can be useful if import_cmdset is just used to check if -this is a valid python path or not.

  • -
-
-
Returns
-

cmdset (CmdSet)

-
-
The imported command set. If an error was

encountered, commands.cmdsethandler._ErrorCmdSet is returned -for the benefit of the handler.

-
-
-

-
-
-
- -
-
-class evennia.commands.cmdsethandler.CmdSetHandler(obj, init_true=True)[source]
-

Bases: object

-

The CmdSetHandler is always stored on an object, this object is supplied -as an argument.

-

The ‘current’ cmdset is the merged set currently active for this object. -This is the set the game engine will retrieve when determining which -commands are available to the object. The cmdset_stack holds a history of -all CmdSets to allow the handler to remove/add cmdsets at will. Doing so -will re-calculate the ‘current’ cmdset.

-
-
-__init__(obj, init_true=True)[source]
-

This method is called whenever an object is recreated.

-
-
Parameters
-
    -
  • obj (Object) – An reference to the game object this handler -belongs to.

  • -
  • init_true (bool, optional) – Set when the handler is initializing -and loads the current cmdset.

  • -
-
-
-
- -
-
-update(init_mode=False)[source]
-

Re-adds all sets in the handler to have an updated current

-
-
Parameters
-

init_mode (bool, optional) – Used automatically right after -this handler was created; it imports all persistent cmdsets -from the database.

-
-
-

Notes

-

This method is necessary in order to always have a .current -cmdset when working with the cmdsethandler in code. But the -CmdSetHandler doesn’t (cannot) consider external cmdsets and game -state. This means that the .current calculated from this method -will likely not match the true current cmdset as determined at -run-time by cmdhandler.get_and_merge_cmdsets(). So in a running -game the responsibility of keeping .current upt-to-date belongs -to the central cmdhandler.get_and_merge_cmdsets()!

-
- -
-
-add(cmdset, emit_to_obj=None, persistent=False, default_cmdset=False, **kwargs)[source]
-

Add a cmdset to the handler, on top of the old ones, unless it -is set as the default one (it will then end up at the bottom of the stack)

-
-
Parameters
-
    -
  • cmdset (CmdSet or str) – Can be a cmdset object or the python path -to such an object.

  • -
  • emit_to_obj (Object, optional) – An object to receive error messages.

  • -
  • persistent (bool, optional) – Let cmdset remain across server reload.

  • -
  • default_cmdset (Cmdset, optional) – Insert this to replace the -default cmdset position (there is only one such position, -always at the bottom of the stack).

  • -
-
-
-

Notes

-

An interesting feature of this method is if you were to send -it an already instantiated cmdset (i.e. not a class), the -current cmdsethandler’s obj attribute will then not be -transferred over to this already instantiated set (this is -because it might be used elsewhere and can cause strange -effects). This means you could in principle have the -handler launch command sets tied to a different object -than the handler. Not sure when this would be useful, but -it’s a ‘quirk’ that has to be documented.

-
- -
-
-add_default(cmdset, emit_to_obj=None, persistent=True, **kwargs)[source]
-

Shortcut for adding a default cmdset.

-
-
Parameters
-
    -
  • cmdset (Cmdset) – The Cmdset to add.

  • -
  • emit_to_obj (Object, optional) – Gets error messages

  • -
  • persistent (bool, optional) – The new Cmdset should survive a server reboot.

  • -
-
-
-
- -
-
-remove(cmdset=None, default_cmdset=False)[source]
-

Remove a cmdset from the handler.

-
-
Parameters
-
    -
  • cmdset (CommandSet or str, optional) – This can can be supplied either as a cmdset-key, -an instance of the CmdSet or a python path to the cmdset. -If no key is given, the last cmdset in the stack is -removed. Whenever the cmdset_stack changes, the cmdset is -updated. If default_cmdset is set, this argument is ignored.

  • -
  • default_cmdset (bool, optional) – If set, this will remove the -default cmdset (at the bottom of the stack).

  • -
-
-
-
- -
-
-delete(cmdset=None, default_cmdset=False)
-

Remove a cmdset from the handler.

-
-
Parameters
-
    -
  • cmdset (CommandSet or str, optional) – This can can be supplied either as a cmdset-key, -an instance of the CmdSet or a python path to the cmdset. -If no key is given, the last cmdset in the stack is -removed. Whenever the cmdset_stack changes, the cmdset is -updated. If default_cmdset is set, this argument is ignored.

  • -
  • default_cmdset (bool, optional) – If set, this will remove the -default cmdset (at the bottom of the stack).

  • -
-
-
-
- -
-
-remove_default()[source]
-

This explicitly deletes only the default cmdset.

-
- -
-
-delete_default()
-

This explicitly deletes only the default cmdset.

-
- -
-
-get()[source]
-

Get all cmdsets.

-
-
Returns
-

cmdsets (list) – All the command sets currently in the handler.

-
-
-
- -
-
-all()
-

Get all cmdsets.

-
-
Returns
-

cmdsets (list) – All the command sets currently in the handler.

-
-
-
- -
-
-clear()[source]
-

Removes all Command Sets from the handler except the default one -(use self.remove_default to remove that).

-
- -
-
-has(cmdset, must_be_default=False)[source]
-

checks so the cmdsethandler contains a given cmdset

-
-
Parameters
-
    -
  • cmdset (str or Cmdset) – Cmdset key, pythonpath or -Cmdset to check the existence for.

  • -
  • must_be_default (bool, optional) – Only return True if -the checked cmdset is the default one.

  • -
-
-
Returns
-

has_cmdset (bool) – Whether or not the cmdset is in the handler.

-
-
-
- -
-
-has_cmdset(cmdset, must_be_default=False)
-

checks so the cmdsethandler contains a given cmdset

-
-
Parameters
-
    -
  • cmdset (str or Cmdset) – Cmdset key, pythonpath or -Cmdset to check the existence for.

  • -
  • must_be_default (bool, optional) – Only return True if -the checked cmdset is the default one.

  • -
-
-
Returns
-

has_cmdset (bool) – Whether or not the cmdset is in the handler.

-
-
-
- -
-
-reset()[source]
-

Force reload of all cmdsets in handler. This should be called -after _CACHED_CMDSETS have been cleared (normally this is -handled automatically by @reload).

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.command.html b/docs/0.9.5/api/evennia.commands.command.html deleted file mode 100644 index 46c081dff7..0000000000 --- a/docs/0.9.5/api/evennia.commands.command.html +++ /dev/null @@ -1,556 +0,0 @@ - - - - - - - - - evennia.commands.command — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.commands.command

-

The base Command class.

-

All commands in Evennia inherit from the ‘Command’ class in this module.

-
-
-exception evennia.commands.command.InterruptCommand[source]
-

Bases: Exception

-

Cleanly interrupt a command.

-
- -
-
-class evennia.commands.command.CommandMeta(*args, **kwargs)[source]
-

Bases: type

-

The metaclass cleans up all properties on the class

-
-
-__init__(*args, **kwargs)[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
- -
-
-class evennia.commands.command.Command(**kwargs)[source]
-

Bases: object

-

(you may see this if a child command had no help text defined)

-
-
Usage:

command [args]

-
-
-

This is the base command class. Inherit from this -to create new commands.

-

The cmdhandler makes the following variables available to the -command methods (so you can always assume them to be there): -self.caller - the game object calling the command -self.cmdstring - the command name used to trigger this command (allows

-
-

you to know which alias was used, for example)

-
-
-
cmd.args - everything supplied to the command following the cmdstring

(this is usually what is parsed in self.parse())

-
-
cmd.cmdset - the cmdset from which this command was matched (useful only

seldomly, notably for help-type commands, to create dynamic -help entries and lists)

-
-
cmd.obj - the object on which this command is defined. If a default command,

this is usually the same as caller.

-
-
-

cmd.rawstring - the full raw string input, including any args and no parsing.

-

The following class properties can/should be defined on your child class:

-

key - identifier for command (e.g. “look”) -aliases - (optional) list of aliases (e.g. [“l”, “loo”]) -locks - lock string (default is “cmd:all()”) -help_category - how to organize this help entry in help system

-
-

(default is “General”)

-
-

auto_help - defaults to True. Allows for turning off auto-help generation -arg_regex - (optional) raw string regex defining how the argument part of

-
-

the command should look in order to match for this command -(e.g. must it be a space between cmdname and arg?)

-
-
-
auto_help_display_key - (optional) if given, this replaces the string shown

in the auto-help listing. This is particularly useful for system-commands -whose actual key is not really meaningful.

-
-
-

(Note that if auto_help is on, this initial string is also used by the -system to create the help entry for the command, so it’s a good idea to -format it similar to this one). This behavior can be changed by -overriding the method ‘get_help’ of a command: by default, this -method returns cmd.__doc__ (that is, this very docstring, or -the docstring of your command). You can, however, extend or -replace this without disabling auto_help.

-
-
-key = 'command'
-
- -
-
-aliases = []
-
- -
-
-locks = 'cmd:all();'
-
- -
-
-help_category = 'general'
-
- -
-
-auto_help = True
-
- -
-
-is_exit = False
-
- -
-
-arg_regex = re.compile('^[ /]+.*$|$', re.IGNORECASE)
-
- -
-
-msg_all_sessions = False
-
- -
-
-retain_instance = False
-
- -
-
-__init__(**kwargs)[source]
-

The lockhandler works the same as for objects. -optional kwargs will be set as properties on the Command at runtime, -overloading evential same-named class properties.

-
- -
-
-lockhandler[source]
-
- -
-
-set_key(new_key)[source]
-

Update key.

-
-
Parameters
-

new_key (str) – The new key.

-
-
-

Notes

-

This is necessary to use to make sure the optimization -caches are properly updated as well.

-
- -
-
-set_aliases(new_aliases)[source]
-

Replace aliases with new ones.

-
-
Parameters
-

new_aliases (str or list) – Either a ;-separated string -or a list of aliases. These aliases will replace the -existing ones, if any.

-
-
-

Notes

-

This is necessary to use to make sure the optimization -caches are properly updated as well.

-
- -
-
-match(cmdname)[source]
-

This is called by the system when searching the available commands, -in order to determine if this is the one we wanted. cmdname was -previously extracted from the raw string by the system.

-
-
Parameters
-

cmdname (str) – Always lowercase when reaching this point.

-
-
Returns
-

result (bool) – Match result.

-
-
-
- -
-
-access(srcobj, access_type='cmd', default=False)[source]
-

This hook is called by the cmdhandler to determine if srcobj -is allowed to execute this command. It should return a boolean -value and is not normally something that need to be changed since -it’s using the Evennia permission system directly.

-
-
Parameters
-
    -
  • srcobj (Object) – Object trying to gain permission

  • -
  • access_type (str, optional) – The lock type to check.

  • -
  • default (bool, optional) – The fallback result if no lock -of matching access_type is found on this Command.

  • -
-
-
-
- -
-
-msg(text=None, to_obj=None, from_obj=None, session=None, **kwargs)[source]
-

This is a shortcut instead of calling msg() directly on an -object - it will detect if caller is an Object or an Account and -also appends self.session automatically if self.msg_all_sessions is False.

-
-
Parameters
-
    -
  • text (str, optional) – Text string of message to send.

  • -
  • to_obj (Object, optional) – Target object of message. Defaults to self.caller.

  • -
  • from_obj (Object, optional) – Source of message. Defaults to to_obj.

  • -
  • session (Session, optional) – Supply data only to a unique -session (ignores the value of self.msg_all_sessions).

  • -
-
-
Keyword Arguments
-
    -
  • options (dict) – Options to the protocol.

  • -
  • any (any) – All other keywords are interpreted as th -name of send-instructions.

  • -
-
-
-
- -
-
-execute_cmd(raw_string, session=None, obj=None, **kwargs)[source]
-

A shortcut of execute_cmd on the caller. It appends the -session automatically.

-
-
Parameters
-
    -
  • raw_string (str) – Execute this string as a command input.

  • -
  • session (Session, optional) – If not given, the current command’s Session will be used.

  • -
  • obj (Object or Account, optional) – Object or Account on which to call the execute_cmd. -If not given, self.caller will be used.

  • -
-
-
Keyword Arguments
-
    -
  • keyword arguments will be added to the found command (Other) –

  • -
  • instace as variables before it executes. This is (object) –

  • -
  • by default Evennia but may be used to set flags and (unused) –

  • -
  • operating paramaters for commands at run-time. (change) –

  • -
-
-
-
- -
-
-at_pre_cmd()[source]
-

This hook is called before self.parse() on all commands. If -this hook returns anything but False/None, the command -sequence is aborted.

-
- -
-
-at_post_cmd()[source]
-

This hook is called after the command has finished executing -(after self.func()).

-
- -
-
-parse()[source]
-

Once the cmdhandler has identified this as the command we -want, this function is run. If many of your commands have a -similar syntax (for example ‘cmd arg1 = arg2’) you should -simply define this once and just let other commands of the -same form inherit from this. See the docstring of this module -for which object properties are available to use (notably -self.args).

-
- -
-
-get_command_info()[source]
-

This is the default output of func() if no func() overload is done. -Provided here as a separate method so that it can be called for debugging -purposes when making commands.

-
- -
-
-func()[source]
-

This is the actual executing part of the command. It is -called directly after self.parse(). See the docstring of this -module for which object properties are available (beyond those -set in self.parse())

-
- -
-
-get_extra_info(caller, **kwargs)[source]
-

Display some extra information that may help distinguish this -command from others, for instance, in a disambiguity prompt.

-

If this command is a potential match in an ambiguous -situation, one distinguishing feature may be its attachment to -a nearby object, so we include this if available.

-
-
Parameters
-
    -
  • caller (TypedObject) – The caller who typed an ambiguous

  • -
  • handed to the search function. (term) –

  • -
-
-
Returns
-

A string with identifying information to disambiguate the -object, conventionally with a preceding space.

-
-
-
- -
-
-get_help(caller, cmdset)[source]
-

Return the help message for this command and this caller.

-

By default, return self.__doc__ (the docstring just under -the class definition). You can override this behavior, -though, and even customize it depending on the caller, or other -commands the caller can use.

-
-
Parameters
-
    -
  • caller (Object or Account) – the caller asking for help on the command.

  • -
  • cmdset (CmdSet) – the command set (if you need additional commands).

  • -
-
-
Returns
-

docstring (str) – the help text to provide the caller for this command.

-
-
-
- -
-
-web_get_detail_url()[source]
-

Returns the URI path for a View that allows users to view details for -this object.

-

ex. Oscar (Character) = ‘/characters/oscar/1/’

-

For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-detail’ would be referenced by this method.

-

ex.

-
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$',
-    CharDetailView.as_view(), name='character-detail')
-
-
-

If no View has been created and defined in urls.py, returns an -HTML anchor.

-

This method is naive and simply returns a path. Securing access to -the actual view and limiting who can view this object is the developer’s -responsibility.

-
-
Returns
-

path (str) – URI path to object detail page, if defined.

-
-
-
- -
-
-web_get_admin_url()[source]
-

Returns the URI path for the Django Admin page for this object.

-

ex. Account#1 = ‘/admin/accounts/accountdb/1/change/’

-
-
Returns
-

path (str) – URI path to Django Admin page for object.

-
-
-
- -
-
-client_width()[source]
-

Get the client screenwidth for the session using this command.

-
-
Returns
-

client width (int) – The width (in characters) of the client window.

-
-
-
- -
-
-styled_table(*args, **kwargs)[source]
-

Create an EvTable styled by on user preferences.

-
-
Parameters
-

*args (str) – Column headers. If not colored explicitly, these will get colors -from user options.

-
-
Keyword Arguments
-

any (str, int or dict) – EvTable options, including, optionally a table dict -detailing the contents of the table.

-
-
Returns
-

table (EvTable)

-
-
An initialized evtable entity, either complete (if using table kwarg)

or incomplete and ready for use with .add_row or .add_collumn.

-
-
-

-
-
-
- -
-
-styled_header(*args, **kwargs)[source]
-

Create a pretty header.

-
- -
-
-styled_separator(*args, **kwargs)[source]
-

Create a separator.

-
- -
- -

Create a pretty footer.

-
- -
-
-lock_storage = 'cmd:all();'
-
- -
-
-save_for_next = False
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'no_prefix': ' ', 'tags': '', 'text': '\n ## Base command\n\n (you may see this if a child command had no help text defined)\n\n Usage:\n command [args]\n\n This is the base command class. Inherit from this\n to create new commands.\n\n The cmdhandler makes the following variables available to the\n command methods (so you can always assume them to be there):\n self.caller - the game object calling the command\n self.cmdstring - the command name used to trigger this command (allows\n you to know which alias was used, for example)\n cmd.args - everything supplied to the command following the cmdstring\n (this is usually what is parsed in self.parse())\n cmd.cmdset - the cmdset from which this command was matched (useful only\n seldomly, notably for help-type commands, to create dynamic\n help entries and lists)\n cmd.obj - the object on which this command is defined. If a default command,\n this is usually the same as caller.\n cmd.rawstring - the full raw string input, including any args and no parsing.\n\n The following class properties can/should be defined on your child class:\n\n key - identifier for command (e.g. "look")\n aliases - (optional) list of aliases (e.g. ["l", "loo"])\n locks - lock string (default is "cmd:all()")\n help_category - how to organize this help entry in help system\n (default is "General")\n auto_help - defaults to True. Allows for turning off auto-help generation\n arg_regex - (optional) raw string regex defining how the argument part of\n the command should look in order to match for this command\n (e.g. must it be a space between cmdname and arg?)\n auto_help_display_key - (optional) if given, this replaces the string shown\n in the auto-help listing. This is particularly useful for system-commands\n whose actual key is not really meaningful.\n\n (Note that if auto_help is on, this initial string is also used by the\n system to create the help entry for the command, so it\'s a good idea to\n format it similar to this one). This behavior can be changed by\n overriding the method \'get_help\' of a command: by default, this\n method returns cmd.__doc__ (that is, this very docstring, or\n the docstring of your command). You can, however, extend or\n replace this without disabling auto_help.\n '}
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.default.account.html b/docs/0.9.5/api/evennia.commands.default.account.html deleted file mode 100644 index f5afee99de..0000000000 --- a/docs/0.9.5/api/evennia.commands.default.account.html +++ /dev/null @@ -1,886 +0,0 @@ - - - - - - - - - evennia.commands.default.account — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.commands.default.account

-

Account (OOC) commands. These are stored on the Account object -and self.caller is thus always an Account, not an Object/Character.

-

These commands go in the AccountCmdset and are accessible also -when puppeting a Character (although with lower priority)

-

These commands use the account_caller property which tells the command -parent (MuxCommand, usually) to setup caller correctly. They use -self.account to make sure to always use the account object rather than -self.caller (which change depending on the level you are calling from) -The property self.character can be used to access the character when -these commands are triggered with a connected character (such as the -case of the ooc command), it is None if we are OOC.

-

Note that under MULTISESSION_MODE > 2, Account commands should use -self.msg() and similar methods to reroute returns to the correct -method. Otherwise all text will be returned to all connected sessions.

-
-
-class evennia.commands.default.account.CmdOOCLook(**kwargs)[source]
-

Bases: evennia.commands.default.account.MuxAccountLookCommand

-

look while out-of-character

-
-
Usage:

look

-
-
-

Look in the ooc state.

-
-
-key = 'look'
-
- -
-
-aliases = ['l', 'ls']
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-help_category = 'general'
-
- -
-
-account_caller = True
-
- -
-
-func()[source]
-

implement the ooc look command

-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': 'l ls', 'category': 'general', 'key': 'look', 'no_prefix': ' l ls', 'tags': '', 'text': '\n look while out-of-character\n\n Usage:\n look\n\n Look in the ooc state.\n '}
-
- -
- -
-
-class evennia.commands.default.account.CmdIC(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

control an object you have permission to puppet

-
-
Usage:

ic <character>

-
-
-

Go in-character (IC) as a given Character.

-

This will attempt to “become” a different object assuming you have -the right to do so. Note that it’s the ACCOUNT character that puppets -characters/objects and which needs to have the correct permission!

-

You cannot become an object that is already controlled by another -account. In principle <character> can be any in-game object as long -as you the account have access right to puppet it.

-
-
-key = 'ic'
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-aliases = ['puppet']
-
- -
-
-help_category = 'general'
-
- -
-
-account_caller = True
-
- -
-
-func()[source]
-

Main puppet method

-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': 'puppet', 'category': 'general', 'key': 'ic', 'no_prefix': ' puppet', 'tags': '', 'text': '\n control an object you have permission to puppet\n\n Usage:\n ic <character>\n\n Go in-character (IC) as a given Character.\n\n This will attempt to "become" a different object assuming you have\n the right to do so. Note that it\'s the ACCOUNT character that puppets\n characters/objects and which needs to have the correct permission!\n\n You cannot become an object that is already controlled by another\n account. In principle <character> can be any in-game object as long\n as you the account have access right to puppet it.\n '}
-
- -
- -
-
-class evennia.commands.default.account.CmdOOC(**kwargs)[source]
-

Bases: evennia.commands.default.account.MuxAccountLookCommand

-

stop puppeting and go ooc

-
-
Usage:

ooc

-
-
-

Go out-of-character (OOC).

-

This will leave your current character and put you in a incorporeal OOC state.

-
-
-key = 'ooc'
-
- -
-
-locks = 'cmd:pperm(Player)'
-
- -
-
-aliases = ['unpuppet']
-
- -
-
-help_category = 'general'
-
- -
-
-account_caller = True
-
- -
-
-func()[source]
-

Implement function

-
- -
-
-lock_storage = 'cmd:pperm(Player)'
-
- -
-
-search_index_entry = {'aliases': 'unpuppet', 'category': 'general', 'key': 'ooc', 'no_prefix': ' unpuppet', 'tags': '', 'text': '\n stop puppeting and go ooc\n\n Usage:\n ooc\n\n Go out-of-character (OOC).\n\n This will leave your current character and put you in a incorporeal OOC state.\n '}
-
- -
- -
-
-class evennia.commands.default.account.CmdPassword(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

change your password

-
-
Usage:

password <old password> = <new password>

-
-
-

Changes your password. Make sure to pick a safe one.

-
-
-key = 'password'
-
- -
-
-locks = 'cmd:pperm(Player)'
-
- -
-
-account_caller = True
-
- -
-
-func()[source]
-

hook function.

-
- -
-
-aliases = []
-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:pperm(Player)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': 'password', 'no_prefix': ' ', 'tags': '', 'text': '\n change your password\n\n Usage:\n password <old password> = <new password>\n\n Changes your password. Make sure to pick a safe one.\n '}
-
- -
- -
-
-class evennia.commands.default.account.CmdQuit(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

quit the game

-
-
Usage:

quit

-
-
Switch:

all - disconnect all connected sessions

-
-
-

Gracefully disconnect your current session from the -game. Use the /all switch to disconnect from all sessions.

-
-
-key = 'quit'
-
- -
-
-switch_options = ('all',)
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-account_caller = True
-
- -
-
-func()[source]
-

hook function

-
- -
-
-aliases = []
-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': 'quit', 'no_prefix': ' ', 'tags': '', 'text': '\n quit the game\n\n Usage:\n quit\n\n Switch:\n all - disconnect all connected sessions\n\n Gracefully disconnect your current session from the\n game. Use the /all switch to disconnect from all sessions.\n '}
-
- -
- -
-
-class evennia.commands.default.account.CmdCharCreate(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

create a new character

-
-
Usage:

charcreate <charname> [= desc]

-
-
-

Create a new character, optionally giving it a description. You -may use upper-case letters in the name - you will nevertheless -always be able to access your character using lower-case letters -if you want.

-
-
-key = 'charcreate'
-
- -
-
-locks = 'cmd:pperm(Player)'
-
- -
-
-help_category = 'general'
-
- -
-
-account_caller = True
-
- -
-
-func()[source]
-

create the new character

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:pperm(Player)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': 'charcreate', 'no_prefix': ' ', 'tags': '', 'text': '\n create a new character\n\n Usage:\n charcreate <charname> [= desc]\n\n Create a new character, optionally giving it a description. You\n may use upper-case letters in the name - you will nevertheless\n always be able to access your character using lower-case letters\n if you want.\n '}
-
- -
- -
-
-class evennia.commands.default.account.CmdOption(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

Set an account option

-
-
Usage:

option[/save] [name = value]

-
-
Switches:

save - Save the current option settings for future logins. -clear - Clear the saved options.

-
-
-

This command allows for viewing and setting client interface -settings. Note that saved options may not be able to be used if -later connecting with a client with different capabilities.

-
-
-key = 'option'
-
- -
-
-aliases = ['options']
-
- -
-
-switch_options = ('save', 'clear')
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-account_caller = True
-
- -
-
-func()[source]
-

Implements the command

-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': 'options', 'category': 'general', 'key': 'option', 'no_prefix': ' options', 'tags': '', 'text': '\n Set an account option\n\n Usage:\n option[/save] [name = value]\n\n Switches:\n save - Save the current option settings for future logins.\n clear - Clear the saved options.\n\n This command allows for viewing and setting client interface\n settings. Note that saved options may not be able to be used if\n later connecting with a client with different capabilities.\n\n\n '}
-
- -
- -
-
-class evennia.commands.default.account.CmdSessions(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

check your connected session(s)

-
-
Usage:

sessions

-
-
-

Lists the sessions currently connected to your account.

-
-
-key = 'sessions'
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-help_category = 'general'
-
- -
-
-account_caller = True
-
- -
-
-func()[source]
-

Implement function

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': 'sessions', 'no_prefix': ' ', 'tags': '', 'text': '\n check your connected session(s)\n\n Usage:\n sessions\n\n Lists the sessions currently connected to your account.\n\n '}
-
- -
- -
-
-class evennia.commands.default.account.CmdWho(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

list who is currently online

-
-
Usage:

who -doing

-
-
-

Shows who is currently online. Doing is an alias that limits info -also for those with all permissions.

-
-
-key = 'who'
-
- -
-
-aliases = ['doing']
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-account_caller = True
-
- -
-
-func()[source]
-

Get all connected accounts by polling session.

-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': 'doing', 'category': 'general', 'key': 'who', 'no_prefix': ' doing', 'tags': '', 'text': '\n list who is currently online\n\n Usage:\n who\n doing\n\n Shows who is currently online. Doing is an alias that limits info\n also for those with all permissions.\n '}
-
- -
- -
-
-class evennia.commands.default.account.CmdColorTest(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

testing which colors your client support

-
-
Usage:

color ansi | xterm256

-
-
-

Prints a color map along with in-mud color codes to use to produce -them. It also tests what is supported in your client. Choices are -16-color ansi (supported in most muds) or the 256-color xterm256 -standard. No checking is done to determine your client supports -color - if not you will see rubbish appear.

-
-
-key = 'color'
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-help_category = 'general'
-
- -
-
-account_caller = True
-
- -
-
-slice_bright_fg = slice(7, 15, None)
-
- -
-
-slice_dark_fg = slice(15, 23, None)
-
- -
-
-slice_dark_bg = slice(-8, None, None)
-
- -
-
-slice_bright_bg = slice(None, None, None)
-
- -
-
-table_format(table)[source]
-

Helper method to format the ansi/xterm256 tables. -Takes a table of columns [[val,val,…],[val,val,…],…]

-
- -
-
-func()[source]
-

Show color tables

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': 'color', 'no_prefix': ' ', 'tags': '', 'text': '\n testing which colors your client support\n\n Usage:\n color ansi | xterm256\n\n Prints a color map along with in-mud color codes to use to produce\n them. It also tests what is supported in your client. Choices are\n 16-color ansi (supported in most muds) or the 256-color xterm256\n standard. No checking is done to determine your client supports\n color - if not you will see rubbish appear.\n '}
-
- -
- -
-
-class evennia.commands.default.account.CmdQuell(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

use character’s permissions instead of account’s

-
-
Usage:

quell -unquell

-
-
-

Normally the permission level of the Account is used when puppeting a -Character/Object to determine access. This command will switch the lock -system to make use of the puppeted Object’s permissions instead. This is -useful mainly for testing. -Hierarchical permission quelling only work downwards, thus an Account cannot -use a higher-permission Character to escalate their permission level. -Use the unquell command to revert back to normal operation.

-
-
-key = 'quell'
-
- -
-
-aliases = ['unquell']
-
- -
-
-locks = 'cmd:pperm(Player)'
-
- -
-
-help_category = 'general'
-
- -
-
-account_caller = True
-
- -
-
-func()[source]
-

Perform the command

-
- -
-
-lock_storage = 'cmd:pperm(Player)'
-
- -
-
-search_index_entry = {'aliases': 'unquell', 'category': 'general', 'key': 'quell', 'no_prefix': ' unquell', 'tags': '', 'text': "\n use character's permissions instead of account's\n\n Usage:\n quell\n unquell\n\n Normally the permission level of the Account is used when puppeting a\n Character/Object to determine access. This command will switch the lock\n system to make use of the puppeted Object's permissions instead. This is\n useful mainly for testing.\n Hierarchical permission quelling only work downwards, thus an Account cannot\n use a higher-permission Character to escalate their permission level.\n Use the unquell command to revert back to normal operation.\n "}
-
- -
- -
-
-class evennia.commands.default.account.CmdCharDelete(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

delete a character - this cannot be undone!

-
-
Usage:

chardelete <charname>

-
-
-

Permanently deletes one of your characters.

-
-
-key = 'chardelete'
-
- -
-
-locks = 'cmd:pperm(Player)'
-
- -
-
-help_category = 'general'
-
- -
-
-func()[source]
-

delete the character

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:pperm(Player)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': 'chardelete', 'no_prefix': ' ', 'tags': '', 'text': '\n delete a character - this cannot be undone!\n\n Usage:\n chardelete <charname>\n\n Permanently deletes one of your characters.\n '}
-
- -
- -
-
-class evennia.commands.default.account.CmdStyle(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

In-game style options

-
-
Usage:

style -style <option> = <value>

-
-
-

Configure stylings for in-game display elements like table borders, help -entriest etc. Use without arguments to see all available options.

-
-
-key = 'style'
-
- -
-
-switch_options = ['clear']
-
- -
-
-func()[source]
-

This is the hook function that actually does all the work. It is called -by the cmdhandler right after self.parser() finishes, and so has access -to all the variables defined therein.

-
- -
-
-list_styles()[source]
-
- -
-
-set()[source]
-
- -
-
-aliases = []
-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all();'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': 'style', 'no_prefix': ' ', 'tags': '', 'text': '\n In-game style options\n\n Usage:\n style\n style <option> = <value>\n\n Configure stylings for in-game display elements like table borders, help\n entriest etc. Use without arguments to see all available options.\n\n '}
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.default.admin.html b/docs/0.9.5/api/evennia.commands.default.admin.html deleted file mode 100644 index dc2b3f96fb..0000000000 --- a/docs/0.9.5/api/evennia.commands.default.admin.html +++ /dev/null @@ -1,571 +0,0 @@ - - - - - - - - - evennia.commands.default.admin — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.commands.default.admin

-

Admin commands

-
-
-class evennia.commands.default.admin.CmdBoot(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

kick an account from the server.

-
-
Usage

boot[/switches] <account obj> [: reason]

-
-
Switches:

quiet - Silently boot without informing account -sid - boot by session id instead of name or dbref

-
-
-

Boot an account object from the server. If a reason is -supplied it will be echoed to the user unless /quiet is set.

-
-
-key = 'boot'
-
- -
-
-switch_options = ('quiet', 'sid')
-
- -
-
-locks = 'cmd:perm(boot) or perm(Admin)'
-
- -
-
-help_category = 'admin'
-
- -
-
-func()[source]
-

Implementing the function

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:perm(boot) or perm(Admin)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'admin', 'key': 'boot', 'no_prefix': ' ', 'tags': '', 'text': '\n kick an account from the server.\n\n Usage\n boot[/switches] <account obj> [: reason]\n\n Switches:\n quiet - Silently boot without informing account\n sid - boot by session id instead of name or dbref\n\n Boot an account object from the server. If a reason is\n supplied it will be echoed to the user unless /quiet is set.\n '}
-
- -
- -
-
-class evennia.commands.default.admin.CmdBan(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

ban an account from the server

-
-
Usage:

ban [<name or ip> [: reason]]

-
-
-

Without any arguments, shows numbered list of active bans.

-

This command bans a user from accessing the game. Supply an optional -reason to be able to later remember why the ban was put in place.

-

It is often preferable to ban an account from the server than to -delete an account with accounts/delete. If banned by name, that account -account can no longer be logged into.

-

IP (Internet Protocol) address banning allows blocking all access -from a specific address or subnet. Use an asterisk (*) as a -wildcard.

-

Examples

-

ban thomas - ban account ‘thomas’ -ban/ip 134.233.2.111 - ban specific ip address -ban/ip 134.233.2.* - ban all in a subnet -ban/ip 134.233.*.* - even wider ban

-

A single IP filter can be easy to circumvent by changing computers -or requesting a new IP address. Setting a wide IP block filter with -wildcards might be tempting, but remember that it may also -accidentally block innocent users connecting from the same country -or region.

-
-
-key = 'ban'
-
- -
-
-aliases = ['bans']
-
- -
-
-locks = 'cmd:perm(ban) or perm(Developer)'
-
- -
-
-help_category = 'admin'
-
- -
-
-func()[source]
-

Bans are stored in a serverconf db object as a list of -dictionaries:

-
-
-
[ (name, ip, ipregex, date, reason),

(name, ip, ipregex, date, reason),… ]

-
-
-
-

where name and ip are set by the user and are shown in -lists. ipregex is a converted form of ip where the * is -replaced by an appropriate regex pattern for fast -matching. date is the time stamp the ban was instigated and -‘reason’ is any optional info given to the command. Unset -values in each tuple is set to the empty string.

-
- -
-
-lock_storage = 'cmd:perm(ban) or perm(Developer)'
-
- -
-
-search_index_entry = {'aliases': 'bans', 'category': 'admin', 'key': 'ban', 'no_prefix': ' bans', 'tags': '', 'text': "\n ban an account from the server\n\n Usage:\n ban [<name or ip> [: reason]]\n\n Without any arguments, shows numbered list of active bans.\n\n This command bans a user from accessing the game. Supply an optional\n reason to be able to later remember why the ban was put in place.\n\n It is often preferable to ban an account from the server than to\n delete an account with accounts/delete. If banned by name, that account\n account can no longer be logged into.\n\n IP (Internet Protocol) address banning allows blocking all access\n from a specific address or subnet. Use an asterisk (*) as a\n wildcard.\n\n Examples:\n ban thomas - ban account 'thomas'\n ban/ip 134.233.2.111 - ban specific ip address\n ban/ip 134.233.2.* - ban all in a subnet\n ban/ip 134.233.*.* - even wider ban\n\n A single IP filter can be easy to circumvent by changing computers\n or requesting a new IP address. Setting a wide IP block filter with\n wildcards might be tempting, but remember that it may also\n accidentally block innocent users connecting from the same country\n or region.\n\n "}
-
- -
- -
-
-class evennia.commands.default.admin.CmdUnban(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

remove a ban from an account

-
-
Usage:

unban <banid>

-
-
-

This will clear an account name/ip ban previously set with the ban -command. Use this command without an argument to view a numbered -list of bans. Use the numbers in this list to select which one to -unban.

-
-
-key = 'unban'
-
- -
-
-locks = 'cmd:perm(unban) or perm(Developer)'
-
- -
-
-help_category = 'admin'
-
- -
-
-func()[source]
-

Implement unbanning

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:perm(unban) or perm(Developer)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'admin', 'key': 'unban', 'no_prefix': ' ', 'tags': '', 'text': '\n remove a ban from an account\n\n Usage:\n unban <banid>\n\n This will clear an account name/ip ban previously set with the ban\n command. Use this command without an argument to view a numbered\n list of bans. Use the numbers in this list to select which one to\n unban.\n\n '}
-
- -
- -
-
-class evennia.commands.default.admin.CmdEmit(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

admin command for emitting message to multiple objects

-
-
Usage:

emit[/switches] [<obj>, <obj>, … =] <message> -remit [<obj>, <obj>, … =] <message> -pemit [<obj>, <obj>, … =] <message>

-
-
Switches:

room - limit emits to rooms only (default) -accounts - limit emits to accounts only -contents - send to the contents of matched objects too

-
-
-

Emits a message to the selected objects or to -your immediate surroundings. If the object is a room, -send to its contents. remit and pemit are just -limited forms of emit, for sending to rooms and -to accounts respectively.

-
-
-key = 'emit'
-
- -
-
-aliases = ['pemit', 'remit']
-
- -
-
-switch_options = ('room', 'accounts', 'contents')
-
- -
-
-locks = 'cmd:perm(emit) or perm(Builder)'
-
- -
-
-help_category = 'admin'
-
- -
-
-func()[source]
-

Implement the command

-
- -
-
-lock_storage = 'cmd:perm(emit) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': 'pemit remit', 'category': 'admin', 'key': 'emit', 'no_prefix': ' pemit remit', 'tags': '', 'text': '\n admin command for emitting message to multiple objects\n\n Usage:\n emit[/switches] [<obj>, <obj>, ... =] <message>\n remit [<obj>, <obj>, ... =] <message>\n pemit [<obj>, <obj>, ... =] <message>\n\n Switches:\n room - limit emits to rooms only (default)\n accounts - limit emits to accounts only\n contents - send to the contents of matched objects too\n\n Emits a message to the selected objects or to\n your immediate surroundings. If the object is a room,\n send to its contents. remit and pemit are just\n limited forms of emit, for sending to rooms and\n to accounts respectively.\n '}
-
- -
- -
-
-class evennia.commands.default.admin.CmdNewPassword(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

change the password of an account

-
-
Usage:

userpassword <user obj> = <new password>

-
-
-

Set an account’s password.

-
-
-key = 'userpassword'
-
- -
-
-locks = 'cmd:perm(newpassword) or perm(Admin)'
-
- -
-
-help_category = 'admin'
-
- -
-
-func()[source]
-

Implement the function.

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:perm(newpassword) or perm(Admin)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'admin', 'key': 'userpassword', 'no_prefix': ' ', 'tags': '', 'text': "\n change the password of an account\n\n Usage:\n userpassword <user obj> = <new password>\n\n Set an account's password.\n "}
-
- -
- -
-
-class evennia.commands.default.admin.CmdPerm(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

set the permissions of an account/object

-
-
Usage:

perm[/switch] <object> [= <permission>[,<permission>,…]] -perm[/switch] *<account> [= <permission>[,<permission>,…]]

-
-
Switches:

del - delete the given permission from <object> or <account>. -account - set permission on an account (same as adding * to name)

-
-
-

This command sets/clears individual permission strings on an object -or account. If no permission is given, list all permissions on <object>.

-
-
-key = 'perm'
-
- -
-
-aliases = ['setperm']
-
- -
-
-switch_options = ('del', 'account')
-
- -
-
-locks = 'cmd:perm(perm) or perm(Developer)'
-
- -
-
-help_category = 'admin'
-
- -
-
-func()[source]
-

Implement function

-
- -
-
-lock_storage = 'cmd:perm(perm) or perm(Developer)'
-
- -
-
-search_index_entry = {'aliases': 'setperm', 'category': 'admin', 'key': 'perm', 'no_prefix': ' setperm', 'tags': '', 'text': '\n set the permissions of an account/object\n\n Usage:\n perm[/switch] <object> [= <permission>[,<permission>,...]]\n perm[/switch] *<account> [= <permission>[,<permission>,...]]\n\n Switches:\n del - delete the given permission from <object> or <account>.\n account - set permission on an account (same as adding * to name)\n\n This command sets/clears individual permission strings on an object\n or account. If no permission is given, list all permissions on <object>.\n '}
-
- -
- -
-
-class evennia.commands.default.admin.CmdWall(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

make an announcement to all

-
-
Usage:

wall <message>

-
-
-

Announces a message to all connected sessions -including all currently unlogged in.

-
-
-key = 'wall'
-
- -
-
-locks = 'cmd:perm(wall) or perm(Admin)'
-
- -
-
-help_category = 'admin'
-
- -
-
-func()[source]
-

Implements command

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:perm(wall) or perm(Admin)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'admin', 'key': 'wall', 'no_prefix': ' ', 'tags': '', 'text': '\n make an announcement to all\n\n Usage:\n wall <message>\n\n Announces a message to all connected sessions\n including all currently unlogged in.\n '}
-
- -
- -
-
-class evennia.commands.default.admin.CmdForce(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

forces an object to execute a command

-
-
Usage:

force <object>=<command string>

-
-
-

Example

-

force bob=get stick

-
-
-key = 'force'
-
- -
-
-locks = 'cmd:perm(spawn) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-perm_used = 'edit'
-
- -
-
-func()[source]
-

Implements the force command

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:perm(spawn) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'building', 'key': 'force', 'no_prefix': ' ', 'tags': '', 'text': '\n forces an object to execute a command\n\n Usage:\n force <object>=<command string>\n\n Example:\n force bob=get stick\n '}
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.default.batchprocess.html b/docs/0.9.5/api/evennia.commands.default.batchprocess.html deleted file mode 100644 index 08f21bbe41..0000000000 --- a/docs/0.9.5/api/evennia.commands.default.batchprocess.html +++ /dev/null @@ -1,246 +0,0 @@ - - - - - - - - - evennia.commands.default.batchprocess — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.commands.default.batchprocess

-

Batch processors

-

These commands implements the ‘batch-command’ and ‘batch-code’ -processors, using the functionality in evennia.utils.batchprocessors. -They allow for offline world-building.

-

Batch-command is the simpler system. This reads a file (*.ev) -containing a list of in-game commands and executes them in sequence as -if they had been entered in the game (including permission checks -etc).

-

Batch-code is a full-fledged python code interpreter that reads blocks -of python code (*.py) and executes them in sequence. This allows for -much more power than Batch-command, but requires knowing Python and -the Evennia API. It is also a severe security risk and should -therefore always be limited to superusers only.

-
-
-class evennia.commands.default.batchprocess.CmdBatchCommands(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

build from batch-command file

-
-
Usage:

batchcommands[/interactive] <python.path.to.file>

-
-
Switch:
-
interactive - this mode will offer more control when

executing the batch file, like stepping, -skipping, reloading etc.

-
-
-
-
-

Runs batches of commands from a batch-cmd text file (*.ev).

-
-
-key = 'batchcommands'
-
- -
-
-aliases = ['batchcommand', 'batchcmd']
-
- -
-
-switch_options = ('interactive',)
-
- -
-
-locks = 'cmd:perm(batchcommands) or perm(Developer)'
-
- -
-
-help_category = 'building'
-
- -
-
-func()[source]
-

Starts the processor.

-
- -
-
-lock_storage = 'cmd:perm(batchcommands) or perm(Developer)'
-
- -
-
-search_index_entry = {'aliases': 'batchcommand batchcmd', 'category': 'building', 'key': 'batchcommands', 'no_prefix': ' batchcommand batchcmd', 'tags': '', 'text': '\n build from batch-command file\n\n Usage:\n batchcommands[/interactive] <python.path.to.file>\n\n Switch:\n interactive - this mode will offer more control when\n executing the batch file, like stepping,\n skipping, reloading etc.\n\n Runs batches of commands from a batch-cmd text file (*.ev).\n\n '}
-
- -
- -
-
-class evennia.commands.default.batchprocess.CmdBatchCode(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

build from batch-code file

-
-
Usage:

batchcode[/interactive] <python path to file>

-
-
Switch:
-
interactive - this mode will offer more control when

executing the batch file, like stepping, -skipping, reloading etc.

-
-
debug - auto-delete all objects that has been marked as

deletable in the script file (see example files for -syntax). This is useful so as to to not leave multiple -object copies behind when testing out the script.

-
-
-
-
-

Runs batches of commands from a batch-code text file (*.py).

-
-
-key = 'batchcode'
-
- -
-
-aliases = ['batchcodes']
-
- -
-
-switch_options = ('interactive', 'debug')
-
- -
-
-locks = 'cmd:superuser()'
-
- -
-
-help_category = 'building'
-
- -
-
-func()[source]
-

Starts the processor.

-
- -
-
-lock_storage = 'cmd:superuser()'
-
- -
-
-search_index_entry = {'aliases': 'batchcodes', 'category': 'building', 'key': 'batchcode', 'no_prefix': ' batchcodes', 'tags': '', 'text': '\n build from batch-code file\n\n Usage:\n batchcode[/interactive] <python path to file>\n\n Switch:\n interactive - this mode will offer more control when\n executing the batch file, like stepping,\n skipping, reloading etc.\n debug - auto-delete all objects that has been marked as\n deletable in the script file (see example files for\n syntax). This is useful so as to to not leave multiple\n object copies behind when testing out the script.\n\n Runs batches of commands from a batch-code text file (*.py).\n\n '}
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.default.building.html b/docs/0.9.5/api/evennia.commands.default.building.html deleted file mode 100644 index f216800fa0..0000000000 --- a/docs/0.9.5/api/evennia.commands.default.building.html +++ /dev/null @@ -1,2288 +0,0 @@ - - - - - - - - - evennia.commands.default.building — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.commands.default.building

-

Building and world design commands

-
-
-class evennia.commands.default.building.ObjManipCommand(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

This is a parent class for some of the defining objmanip commands -since they tend to have some more variables to define new objects.

-

Each object definition can have several components. First is -always a name, followed by an optional alias list and finally an -some optional data, such as a typeclass or a location. A comma ‘,’ -separates different objects. Like this:

-
-

name1;alias;alias;alias:option, name2;alias;alias …

-
-

Spaces between all components are stripped.

-

A second situation is attribute manipulation. Such commands -are simpler and offer combinations

-
-

objname/attr/attr/attr, objname/attr, …

-
-
-
-parse()[source]
-

We need to expand the default parsing to get all -the cases, see the module doc.

-
- -
-
-aliases = []
-
- -
-
-help_category = 'general'
-
- -
-
-key = 'command'
-
- -
-
-lock_storage = 'cmd:all();'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'no_prefix': ' ', 'tags': '', 'text': "\n This is a parent class for some of the defining objmanip commands\n since they tend to have some more variables to define new objects.\n\n Each object definition can have several components. First is\n always a name, followed by an optional alias list and finally an\n some optional data, such as a typeclass or a location. A comma ','\n separates different objects. Like this:\n\n name1;alias;alias;alias:option, name2;alias;alias ...\n\n Spaces between all components are stripped.\n\n A second situation is attribute manipulation. Such commands\n are simpler and offer combinations\n\n objname/attr/attr/attr, objname/attr, ...\n\n "}
-
- -
- -
-
-class evennia.commands.default.building.CmdSetObjAlias(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

adding permanent aliases for object

-
-
Usage:

alias <obj> [= [alias[,alias,alias,…]]] -alias <obj> = -alias/category <obj> = [alias[,alias,…]:<category>

-
-
Switches:
-
category - requires ending input with :category, to store the

given aliases with the given category.

-
-
-
-
-

Assigns aliases to an object so it can be referenced by more -than one name. Assign empty to remove all aliases from object. If -assigning a category, all aliases given will be using this category.

-

Observe that this is not the same thing as personal aliases -created with the ‘nick’ command! Aliases set with alias are -changing the object in question, making those aliases usable -by everyone.

-
-
-key = '@alias'
-
- -
-
-aliases = ['setobjalias']
-
- -
-
-switch_options = ('category',)
-
- -
-
-locks = 'cmd:perm(setobjalias) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-func()[source]
-

Set the aliases.

-
- -
-
-lock_storage = 'cmd:perm(setobjalias) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': 'setobjalias', 'category': 'building', 'key': '@alias', 'no_prefix': 'alias setobjalias', 'tags': '', 'text': "\n adding permanent aliases for object\n\n Usage:\n alias <obj> [= [alias[,alias,alias,...]]]\n alias <obj> =\n alias/category <obj> = [alias[,alias,...]:<category>\n\n Switches:\n category - requires ending input with :category, to store the\n given aliases with the given category.\n\n Assigns aliases to an object so it can be referenced by more\n than one name. Assign empty to remove all aliases from object. If\n assigning a category, all aliases given will be using this category.\n\n Observe that this is not the same thing as personal aliases\n created with the 'nick' command! Aliases set with alias are\n changing the object in question, making those aliases usable\n by everyone.\n "}
-
- -
- -
-
-class evennia.commands.default.building.CmdCopy(**kwargs)[source]
-

Bases: evennia.commands.default.building.ObjManipCommand

-

copy an object and its properties

-
-
Usage:

copy <original obj> [= <new_name>][;alias;alias..] -[:<new_location>] [,<new_name2> …]

-
-
-

Create one or more copies of an object. If you don’t supply any targets, -one exact copy of the original object will be created with the name *_copy.

-
-
-key = '@copy'
-
- -
-
-locks = 'cmd:perm(copy) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-func()[source]
-

Uses ObjManipCommand.parse()

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:perm(copy) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'building', 'key': '@copy', 'no_prefix': 'copy ', 'tags': '', 'text': "\n copy an object and its properties\n\n Usage:\n copy <original obj> [= <new_name>][;alias;alias..]\n [:<new_location>] [,<new_name2> ...]\n\n Create one or more copies of an object. If you don't supply any targets,\n one exact copy of the original object will be created with the name *_copy.\n "}
-
- -
- -
-
-class evennia.commands.default.building.CmdCpAttr(**kwargs)[source]
-

Bases: evennia.commands.default.building.ObjManipCommand

-

copy attributes between objects

-
-
Usage:

cpattr[/switch] <obj>/<attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,…] -cpattr[/switch] <obj>/<attr> = <obj1> [,<obj2>,<obj3>,…] -cpattr[/switch] <attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,…] -cpattr[/switch] <attr> = <obj1>[,<obj2>,<obj3>,…]

-
-
Switches:

move - delete the attribute from the source object after copying.

-
-
-

Example

-

cpattr coolness = Anna/chillout, Anna/nicety, Tom/nicety --> -copies the coolness attribute (defined on yourself), to attributes -on Anna and Tom.

-

Copy the attribute one object to one or more attributes on another object. -If you don’t supply a source object, yourself is used.

-
-
-key = '@cpattr'
-
- -
-
-switch_options = ('move',)
-
- -
-
-locks = 'cmd:perm(cpattr) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-check_from_attr(obj, attr, clear=False)[source]
-

Hook for overriding on subclassed commands. Checks to make sure a -caller can copy the attr from the object in question. If not, return a -false value and the command will abort. An error message should be -provided by this function.

-

If clear is True, user is attempting to move the attribute.

-
- -
-
-check_to_attr(obj, attr)[source]
-

Hook for overriding on subclassed commands. Checks to make sure a -caller can write to the specified attribute on the specified object. -If not, return a false value and the attribute will be skipped. An -error message should be provided by this function.

-
- -
-
-check_has_attr(obj, attr)[source]
-

Hook for overriding on subclassed commands. Do any preprocessing -required and verify an object has an attribute.

-
- -
-
-get_attr(obj, attr)[source]
-

Hook for overriding on subclassed commands. Do any preprocessing -required and get the attribute from the object.

-
- -
-
-func()[source]
-

Do the copying.

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:perm(cpattr) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'building', 'key': '@cpattr', 'no_prefix': 'cpattr ', 'tags': '', 'text': "\n copy attributes between objects\n\n Usage:\n cpattr[/switch] <obj>/<attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...]\n cpattr[/switch] <obj>/<attr> = <obj1> [,<obj2>,<obj3>,...]\n cpattr[/switch] <attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...]\n cpattr[/switch] <attr> = <obj1>[,<obj2>,<obj3>,...]\n\n Switches:\n move - delete the attribute from the source object after copying.\n\n Example:\n cpattr coolness = Anna/chillout, Anna/nicety, Tom/nicety\n ->\n copies the coolness attribute (defined on yourself), to attributes\n on Anna and Tom.\n\n Copy the attribute one object to one or more attributes on another object.\n If you don't supply a source object, yourself is used.\n "}
-
- -
- -
-
-class evennia.commands.default.building.CmdMvAttr(**kwargs)[source]
-

Bases: evennia.commands.default.building.ObjManipCommand

-

move attributes between objects

-
-
Usage:

mvattr[/switch] <obj>/<attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,…] -mvattr[/switch] <obj>/<attr> = <obj1> [,<obj2>,<obj3>,…] -mvattr[/switch] <attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,…] -mvattr[/switch] <attr> = <obj1>[,<obj2>,<obj3>,…]

-
-
Switches:

copy - Don’t delete the original after moving.

-
-
-

Move an attribute from one object to one or more attributes on another -object. If you don’t supply a source object, yourself is used.

-
-
-key = '@mvattr'
-
- -
-
-switch_options = ('copy',)
-
- -
-
-locks = 'cmd:perm(mvattr) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-func()[source]
-

Do the moving

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:perm(mvattr) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'building', 'key': '@mvattr', 'no_prefix': 'mvattr ', 'tags': '', 'text': "\n move attributes between objects\n\n Usage:\n mvattr[/switch] <obj>/<attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...]\n mvattr[/switch] <obj>/<attr> = <obj1> [,<obj2>,<obj3>,...]\n mvattr[/switch] <attr> = <obj1>/<attr1> [,<obj2>/<attr2>,<obj3>/<attr3>,...]\n mvattr[/switch] <attr> = <obj1>[,<obj2>,<obj3>,...]\n\n Switches:\n copy - Don't delete the original after moving.\n\n Move an attribute from one object to one or more attributes on another\n object. If you don't supply a source object, yourself is used.\n "}
-
- -
- -
-
-class evennia.commands.default.building.CmdCreate(**kwargs)[source]
-

Bases: evennia.commands.default.building.ObjManipCommand

-

create new objects

-
-
Usage:

create[/drop] <objname>[;alias;alias…][:typeclass], <objname>…

-
-
switch:
-
drop - automatically drop the new object into your current

location (this is not echoed). This also sets the new -object’s home to the current location rather than to you.

-
-
-
-
-

Creates one or more new objects. If typeclass is given, the object -is created as a child of this typeclass. The typeclass script is -assumed to be located under types/ and any further -directory structure is given in Python notation. So if you have a -correct typeclass ‘RedButton’ defined in -types/examples/red_button.py, you could create a new -object of this type like this:

-
-

create/drop button;red : examples.red_button.RedButton

-
-
-
-key = '@create'
-
- -
-
-switch_options = ('drop',)
-
- -
-
-locks = 'cmd:perm(create) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-new_obj_lockstring = 'control:id({id}) or perm(Admin);delete:id({id}) or perm(Admin)'
-
- -
-
-func()[source]
-

Creates the object.

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:perm(create) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'building', 'key': '@create', 'no_prefix': 'create ', 'tags': '', 'text': "\n create new objects\n\n Usage:\n create[/drop] <objname>[;alias;alias...][:typeclass], <objname>...\n\n switch:\n drop - automatically drop the new object into your current\n location (this is not echoed). This also sets the new\n object's home to the current location rather than to you.\n\n Creates one or more new objects. If typeclass is given, the object\n is created as a child of this typeclass. The typeclass script is\n assumed to be located under types/ and any further\n directory structure is given in Python notation. So if you have a\n correct typeclass 'RedButton' defined in\n types/examples/red_button.py, you could create a new\n object of this type like this:\n\n create/drop button;red : examples.red_button.RedButton\n\n "}
-
- -
- -
-
-class evennia.commands.default.building.CmdDesc(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

describe an object or the current room.

-
-
Usage:

desc [<obj> =] <description>

-
-
Switches:

edit - Open up a line editor for more advanced editing.

-
-
-

Sets the “desc” attribute on an object. If an object is not given, -describe the current room.

-
-
-key = '@desc'
-
- -
-
-switch_options = ('edit',)
-
- -
-
-locks = 'cmd:perm(desc) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-edit_handler()[source]
-
- -
-
-func()[source]
-

Define command

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:perm(desc) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'building', 'key': '@desc', 'no_prefix': 'desc ', 'tags': '', 'text': '\n describe an object or the current room.\n\n Usage:\n desc [<obj> =] <description>\n\n Switches:\n edit - Open up a line editor for more advanced editing.\n\n Sets the "desc" attribute on an object. If an object is not given,\n describe the current room.\n '}
-
- -
- -
-
-class evennia.commands.default.building.CmdDestroy(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

permanently delete objects

-
-
Usage:

destroy[/switches] [obj, obj2, obj3, [dbref-dbref], …]

-
-
Switches:
-
override - The destroy command will usually avoid accidentally

destroying account objects. This switch overrides this safety.

-
-
-

force - destroy without confirmation.

-
-
-

Examples

-

destroy house, roof, door, 44-78 -destroy 5-10, flower, 45 -destroy/force north

-

Destroys one or many objects. If dbrefs are used, a range to delete can be -given, e.g. 4-10. Also the end points will be deleted. This command -displays a confirmation before destroying, to make sure of your choice. -You can specify the /force switch to bypass this confirmation.

-
-
-key = '@destroy'
-
- -
-
-aliases = ['@delete', '@del']
-
- -
-
-switch_options = ('override', 'force')
-
- -
-
-locks = 'cmd:perm(destroy) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-confirm = True
-
- -
-
-default_confirm = 'yes'
-
- -
-
-func()[source]
-

Implements the command.

-
- -
-
-lock_storage = 'cmd:perm(destroy) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '@delete @del', 'category': 'building', 'key': '@destroy', 'no_prefix': 'destroy delete del', 'tags': '', 'text': '\n permanently delete objects\n\n Usage:\n destroy[/switches] [obj, obj2, obj3, [dbref-dbref], ...]\n\n Switches:\n override - The destroy command will usually avoid accidentally\n destroying account objects. This switch overrides this safety.\n force - destroy without confirmation.\n Examples:\n destroy house, roof, door, 44-78\n destroy 5-10, flower, 45\n destroy/force north\n\n Destroys one or many objects. If dbrefs are used, a range to delete can be\n given, e.g. 4-10. Also the end points will be deleted. This command\n displays a confirmation before destroying, to make sure of your choice.\n You can specify the /force switch to bypass this confirmation.\n '}
-
- -
- -
-
-class evennia.commands.default.building.CmdDig(**kwargs)[source]
-

Bases: evennia.commands.default.building.ObjManipCommand

-

build new rooms and connect them to the current location

-
-
Usage:
-
dig[/switches] <roomname>[;alias;alias…][:typeclass]
-
[= <exit_to_there>[;alias][:typeclass]]

[, <exit_to_here>[;alias][:typeclass]]

-
-
-
-
-
-
Switches:

tel or teleport - move yourself to the new room

-
-
-

Examples

-

dig kitchen = north;n, south;s -dig house:myrooms.MyHouseTypeclass -dig sheer cliff;cliff;sheer = climb up, climb down

-

This command is a convenient way to build rooms quickly; it creates the -new room and you can optionally set up exits back and forth between your -current room and the new one. You can add as many aliases as you -like to the name of the room and the exits in question; an example -would be ‘north;no;n’.

-
-
-key = '@dig'
-
- -
-
-switch_options = ('teleport',)
-
- -
-
-locks = 'cmd:perm(dig) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-new_room_lockstring = 'control:id({id}) or perm(Admin); delete:id({id}) or perm(Admin); edit:id({id}) or perm(Admin)'
-
- -
-
-func()[source]
-

Do the digging. Inherits variables from ObjManipCommand.parse()

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:perm(dig) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'building', 'key': '@dig', 'no_prefix': 'dig ', 'tags': '', 'text': "\n build new rooms and connect them to the current location\n\n Usage:\n dig[/switches] <roomname>[;alias;alias...][:typeclass]\n [= <exit_to_there>[;alias][:typeclass]]\n [, <exit_to_here>[;alias][:typeclass]]\n\n Switches:\n tel or teleport - move yourself to the new room\n\n Examples:\n dig kitchen = north;n, south;s\n dig house:myrooms.MyHouseTypeclass\n dig sheer cliff;cliff;sheer = climb up, climb down\n\n This command is a convenient way to build rooms quickly; it creates the\n new room and you can optionally set up exits back and forth between your\n current room and the new one. You can add as many aliases as you\n like to the name of the room and the exits in question; an example\n would be 'north;no;n'.\n "}
-
- -
- -
-
-class evennia.commands.default.building.CmdTunnel(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

create new rooms in cardinal directions only

-
-
Usage:

tunnel[/switch] <direction>[:typeclass] [= <roomname>[;alias;alias;…][:typeclass]]

-
-
Switches:

oneway - do not create an exit back to the current location -tel - teleport to the newly created room

-
-
-

Example

-

tunnel n -tunnel n = house;mike’s place;green building

-
-
This is a simple way to build using pre-defined directions:

|wn,ne,e,se,s,sw,w,nw|n (north, northeast etc) -|wu,d|n (up and down) -|wi,o|n (in and out)

-
-
-

The full names (north, in, southwest, etc) will always be put as -main name for the exit, using the abbreviation as an alias (so an -exit will always be able to be used with both “north” as well as -“n” for example). Opposite directions will automatically be -created back from the new room unless the /oneway switch is given. -For more flexibility and power in creating rooms, use dig.

-
-
-key = '@tunnel'
-
- -
-
-aliases = ['@tun']
-
- -
-
-switch_options = ('oneway', 'tel')
-
- -
-
-locks = 'cmd: perm(tunnel) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-directions = {'d': ('down', 'u'), 'e': ('east', 'w'), 'i': ('in', 'o'), 'n': ('north', 's'), 'ne': ('northeast', 'sw'), 'nw': ('northwest', 'se'), 'o': ('out', 'i'), 's': ('south', 'n'), 'se': ('southeast', 'nw'), 'sw': ('southwest', 'ne'), 'u': ('up', 'd'), 'w': ('west', 'e')}
-
- -
-
-func()[source]
-

Implements the tunnel command

-
- -
-
-lock_storage = 'cmd: perm(tunnel) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '@tun', 'category': 'building', 'key': '@tunnel', 'no_prefix': 'tunnel tun', 'tags': '', 'text': '\n create new rooms in cardinal directions only\n\n Usage:\n tunnel[/switch] <direction>[:typeclass] [= <roomname>[;alias;alias;...][:typeclass]]\n\n Switches:\n oneway - do not create an exit back to the current location\n tel - teleport to the newly created room\n\n Example:\n tunnel n\n tunnel n = house;mike\'s place;green building\n\n This is a simple way to build using pre-defined directions:\n |wn,ne,e,se,s,sw,w,nw|n (north, northeast etc)\n |wu,d|n (up and down)\n |wi,o|n (in and out)\n The full names (north, in, southwest, etc) will always be put as\n main name for the exit, using the abbreviation as an alias (so an\n exit will always be able to be used with both "north" as well as\n "n" for example). Opposite directions will automatically be\n created back from the new room unless the /oneway switch is given.\n For more flexibility and power in creating rooms, use dig.\n '}
-
- -
- -
- -

Bases: evennia.commands.default.muxcommand.MuxCommand

-

link existing rooms together with exits

-
-
Usage:

link[/switches] <object> = <target> -link[/switches] <object> = -link[/switches] <object>

-
-
Switch:
-
twoway - connect two exits. For this to work, BOTH <object>

and <target> must be exit objects.

-
-
-
-
-

If <object> is an exit, set its destination to <target>. Two-way operation -instead sets the destination to the locations of the respective given -arguments. -The second form (a lone =) sets the destination to None (same as -the unlink command) and the third form (without =) just shows the -currently set destination.

-
-
-key = '@link'
-
- -
-
-locks = 'cmd:perm(link) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-func()[source]
-

Perform the link

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:perm(link) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'building', 'key': '@link', 'no_prefix': 'link ', 'tags': '', 'text': '\n link existing rooms together with exits\n\n Usage:\n link[/switches] <object> = <target>\n link[/switches] <object> =\n link[/switches] <object>\n\n Switch:\n twoway - connect two exits. For this to work, BOTH <object>\n and <target> must be exit objects.\n\n If <object> is an exit, set its destination to <target>. Two-way operation\n instead sets the destination to the *locations* of the respective given\n arguments.\n The second form (a lone =) sets the destination to None (same as\n the unlink command) and the third form (without =) just shows the\n currently set destination.\n '}
-
- -
- -
- -

Bases: evennia.commands.default.building.CmdLink

-

remove exit-connections between rooms

-
-
Usage:

unlink <Object>

-
-
-

Unlinks an object, for example an exit, disconnecting -it from whatever it was connected to.

-
-
-key = 'unlink'
-
- -
-
-locks = 'cmd:perm(unlink) or perm(Builder)'
-
- -
-
-help_key = 'Building'
-
- -
-
-func()[source]
-

All we need to do here is to set the right command -and call func in CmdLink

-
- -
-
-aliases = []
-
- -
-
-help_category = 'building'
-
- -
-
-lock_storage = 'cmd:perm(unlink) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'building', 'key': 'unlink', 'no_prefix': ' ', 'tags': '', 'text': '\n remove exit-connections between rooms\n\n Usage:\n unlink <Object>\n\n Unlinks an object, for example an exit, disconnecting\n it from whatever it was connected to.\n '}
-
- -
- -
-
-class evennia.commands.default.building.CmdSetHome(**kwargs)[source]
-

Bases: evennia.commands.default.building.CmdLink

-

set an object’s home location

-
-
Usage:

sethome <obj> [= <home_location>] -sethom <obj>

-
-
-

The “home” location is a “safety” location for objects; they -will be moved there if their current location ceases to exist. All -objects should always have a home location for this reason. -It is also a convenient target of the “home” command.

-

If no location is given, just view the object’s home location.

-
-
-key = '@sethome'
-
- -
-
-locks = 'cmd:perm(sethome) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-func()[source]
-

implement the command

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:perm(sethome) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'building', 'key': '@sethome', 'no_prefix': 'sethome ', 'tags': '', 'text': '\n set an object\'s home location\n\n Usage:\n sethome <obj> [= <home_location>]\n sethom <obj>\n\n The "home" location is a "safety" location for objects; they\n will be moved there if their current location ceases to exist. All\n objects should always have a home location for this reason.\n It is also a convenient target of the "home" command.\n\n If no location is given, just view the object\'s home location.\n '}
-
- -
- -
-
-class evennia.commands.default.building.CmdListCmdSets(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

list command sets defined on an object

-
-
Usage:

cmdsets <obj>

-
-
-

This displays all cmdsets assigned -to a user. Defaults to yourself.

-
-
-key = '@cmdsets'
-
- -
-
-locks = 'cmd:perm(listcmdsets) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-func()[source]
-

list the cmdsets

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:perm(listcmdsets) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'building', 'key': '@cmdsets', 'no_prefix': 'cmdsets ', 'tags': '', 'text': '\n list command sets defined on an object\n\n Usage:\n cmdsets <obj>\n\n This displays all cmdsets assigned\n to a user. Defaults to yourself.\n '}
-
- -
- -
-
-class evennia.commands.default.building.CmdName(**kwargs)[source]
-

Bases: evennia.commands.default.building.ObjManipCommand

-

change the name and/or aliases of an object

-
-
Usage:

name <obj> = <newname>;alias1;alias2

-
-
-

Rename an object to something new. Use *obj to -rename an account.

-
-
-key = '@name'
-
- -
-
-aliases = ['@rename']
-
- -
-
-locks = 'cmd:perm(rename) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-func()[source]
-

change the name

-
- -
-
-lock_storage = 'cmd:perm(rename) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '@rename', 'category': 'building', 'key': '@name', 'no_prefix': 'name rename', 'tags': '', 'text': '\n change the name and/or aliases of an object\n\n Usage:\n name <obj> = <newname>;alias1;alias2\n\n Rename an object to something new. Use *obj to\n rename an account.\n\n '}
-
- -
- -
-
-class evennia.commands.default.building.CmdOpen(**kwargs)[source]
-

Bases: evennia.commands.default.building.ObjManipCommand

-

open a new exit from the current room

-
-
Usage:

open <new exit>[;alias;alias..][:typeclass] [,<return exit>[;alias;..][:typeclass]]] = <destination>

-
-
-

Handles the creation of exits. If a destination is given, the exit -will point there. The <return exit> argument sets up an exit at the -destination leading back to the current room. Destination name -can be given both as a #dbref and a name, if that name is globally -unique.

-
-
-key = '@open'
-
- -
-
-locks = 'cmd:perm(open) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-new_obj_lockstring = 'control:id({id}) or perm(Admin);delete:id({id}) or perm(Admin)'
-
- -
-
-create_exit(exit_name, location, destination, exit_aliases=None, typeclass=None)[source]
-

Helper function to avoid code duplication. -At this point we know destination is a valid location

-
- -
-
-parse()[source]
-

We need to expand the default parsing to get all -the cases, see the module doc.

-
- -
-
-func()[source]
-

This is where the processing starts. -Uses the ObjManipCommand.parser() for pre-processing -as well as the self.create_exit() method.

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:perm(open) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'building', 'key': '@open', 'no_prefix': 'open ', 'tags': '', 'text': '\n open a new exit from the current room\n\n Usage:\n open <new exit>[;alias;alias..][:typeclass] [,<return exit>[;alias;..][:typeclass]]] = <destination>\n\n Handles the creation of exits. If a destination is given, the exit\n will point there. The <return exit> argument sets up an exit at the\n destination leading back to the current room. Destination name\n can be given both as a #dbref and a name, if that name is globally\n unique.\n\n '}
-
- -
- -
-
-class evennia.commands.default.building.CmdSetAttribute(**kwargs)[source]
-

Bases: evennia.commands.default.building.ObjManipCommand

-

set attribute on an object or account

-
-
Usage:

set[/switch] <obj>/<attr>[:category] = <value> -set[/switch] <obj>/<attr>[:category] = # delete attribute -set[/switch] <obj>/<attr>[:category] # view attribute -set[/switch] *<account>/<attr>[:category] = <value>

-
-
Switch:

edit: Open the line editor (string values only) -script: If we’re trying to set an attribute on a script -channel: If we’re trying to set an attribute on a channel -account: If we’re trying to set an attribute on an account -room: Setting an attribute on a room (global search) -exit: Setting an attribute on an exit (global search) -char: Setting an attribute on a character (global search) -character: Alias for char, as above.

-
-
-

Example

-

set self/foo = “bar” -set/delete self/foo -set self/foo = $dbref(#53)

-

Sets attributes on objects. The second example form above clears a -previously set attribute while the third form inspects the current value of -the attribute (if any). The last one (with the star) is a shortcut for -operating on a player Account rather than an Object.

-

If you want <value> to be an object, use $dbef(#dbref) or -$search(key) to assign it. You need control or edit access to -the object you are adding.

-

The most common data to save with this command are strings and -numbers. You can however also set Python primitives such as lists, -dictionaries and tuples on objects (this might be important for -the functionality of certain custom objects). This is indicated -by you starting your value with one of |c’|n, |c”|n, |c(|n, |c[|n -or |c{ |n.

-

Once you have stored a Python primitive as noted above, you can include -|c[<key>]|n in <attr> to reference nested values in e.g. a list or dict.

-

Remember that if you use Python primitives like this, you must -write proper Python syntax too - notably you must include quotes -around your strings or you will get an error.

-
-
-key = '@set'
-
- -
-
-locks = 'cmd:perm(set) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-nested_re = re.compile('\\[.*?\\]')
-
- -
-
-not_found = <object object>
-
- -
-
-check_obj(obj)[source]
-

This may be overridden by subclasses in case restrictions need to be -placed on whether certain objects can have attributes set by certain -accounts.

-

This function is expected to display its own error message.

-

Returning False will abort the command.

-
- -
-
-check_attr(obj, attr_name, category)[source]
-

This may be overridden by subclasses in case restrictions need to be -placed on what attributes can be set by who beyond the normal lock.

-

This functions is expected to display its own error message. It is -run once for every attribute that is checked, blocking only those -attributes which are not permitted and letting the others through.

-
- -
-
-split_nested_attr(attr)[source]
-

Yields tuples of (possible attr name, nested keys on that attr). -For performance, this is biased to the deepest match, but allows compatability -with older attrs that might have been named with []’s.

-

> list(split_nested_attr(“nested[‘asdf’][0]”)) -[

-
-

(‘nested’, [‘asdf’, 0]), -(“nested[‘asdf’]”, [0]), -(“nested[‘asdf’][0]”, []),

-
-

]

-
- -
-
-do_nested_lookup(value, *keys)[source]
-
- -
-
-view_attr(obj, attr, category)[source]
-

Look up the value of an attribute and return a string displaying it.

-
- -
-
-rm_attr(obj, attr, category)[source]
-

Remove an attribute from the object, or a nested data structure, and report back.

-
- -
-
-set_attr(obj, attr, value, category)[source]
-
- -
-
-edit_handler(**kwargs)
-
- -
-
-search_for_obj(objname)[source]
-

Searches for an object matching objname. The object may be of different typeclasses. -:param objname: Name of the object we’re looking for

-
-
Returns
-

A typeclassed object, or None if nothing is found.

-
-
-
- -
-
-func()[source]
-

Implement the set attribute - a limited form of py.

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:perm(set) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'building', 'key': '@set', 'no_prefix': 'set ', 'tags': '', 'text': '\n set attribute on an object or account\n\n Usage:\n set[/switch] <obj>/<attr>[:category] = <value>\n set[/switch] <obj>/<attr>[:category] = # delete attribute\n set[/switch] <obj>/<attr>[:category] # view attribute\n set[/switch] *<account>/<attr>[:category] = <value>\n\n Switch:\n edit: Open the line editor (string values only)\n script: If we\'re trying to set an attribute on a script\n channel: If we\'re trying to set an attribute on a channel\n account: If we\'re trying to set an attribute on an account\n room: Setting an attribute on a room (global search)\n exit: Setting an attribute on an exit (global search)\n char: Setting an attribute on a character (global search)\n character: Alias for char, as above.\n\n Example:\n set self/foo = "bar"\n set/delete self/foo\n set self/foo = $dbref(#53)\n\n Sets attributes on objects. The second example form above clears a\n previously set attribute while the third form inspects the current value of\n the attribute (if any). The last one (with the star) is a shortcut for\n operating on a player Account rather than an Object.\n\n If you want <value> to be an object, use $dbef(#dbref) or\n $search(key) to assign it. You need control or edit access to\n the object you are adding.\n\n The most common data to save with this command are strings and\n numbers. You can however also set Python primitives such as lists,\n dictionaries and tuples on objects (this might be important for\n the functionality of certain custom objects). This is indicated\n by you starting your value with one of |c\'|n, |c"|n, |c(|n, |c[|n\n or |c{ |n.\n\n Once you have stored a Python primitive as noted above, you can include\n |c[<key>]|n in <attr> to reference nested values in e.g. a list or dict.\n\n Remember that if you use Python primitives like this, you must\n write proper Python syntax too - notably you must include quotes\n around your strings or you will get an error.\n\n '}
-
- -
- -
-
-class evennia.commands.default.building.CmdTypeclass(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

set or change an object’s typeclass

-
-
Usage:

typeclass[/switch] <object> [= typeclass.path] -typeclass/prototype <object> = prototype_key

-

typeclasses or typeclass/list/show [typeclass.path] -swap - this is a shorthand for using /force/reset flags. -update - this is a shorthand for using the /force/reload flag.

-
-
Switch:
-
show, examine - display the current typeclass of object (default) or, if

given a typeclass path, show the docstring of that typeclass.

-
-
update - only re-run at_object_creation on this object

meaning locks or other properties set later may remain.

-
-
reset - clean out all the attributes and properties on the

object - basically making this a new clean object. This will also -reset cmdsets!

-
-
force - change to the typeclass also if the object

already has a typeclass of the same name.

-
-
list - show available typeclasses. Only typeclasses in modules actually

imported or used from somewhere in the code will show up here -(those typeclasses are still available if you know the path)

-
-
prototype - clean and overwrite the object with the specified

prototype key - effectively making a whole new object.

-
-
-
-
-

Example

-

type button = examples.red_button.RedButton -type/prototype button=a red button

-

If the typeclass_path is not given, the current object’s typeclass is -assumed.

-

View or set an object’s typeclass. If setting, the creation hooks of the -new typeclass will be run on the object. If you have clashing properties on -the old class, use /reset. By default you are protected from changing to a -typeclass of the same name as the one you already have - use /force to -override this protection.

-

The given typeclass must be identified by its location using python -dot-notation pointing to the correct module and class. If no typeclass is -given (or a wrong typeclass is given). Errors in the path or new typeclass -will lead to the old typeclass being kept. The location of the typeclass -module is searched from the default typeclass directory, as defined in the -server settings.

-
-
-key = '@typeclass'
-
- -
-
-aliases = ['@typeclasses', '@type', '@update', '@parent', '@swap']
-
- -
-
-switch_options = ('show', 'examine', 'update', 'reset', 'force', 'list', 'prototype')
-
- -
-
-locks = 'cmd:perm(typeclass) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-func()[source]
-

Implements command

-
- -
-
-lock_storage = 'cmd:perm(typeclass) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '@typeclasses @type @update @parent @swap', 'category': 'building', 'key': '@typeclass', 'no_prefix': 'typeclass typeclasses type update parent swap', 'tags': '', 'text': "\n set or change an object's typeclass\n\n Usage:\n typeclass[/switch] <object> [= typeclass.path]\n typeclass/prototype <object> = prototype_key\n\n typeclasses or typeclass/list/show [typeclass.path]\n swap - this is a shorthand for using /force/reset flags.\n update - this is a shorthand for using the /force/reload flag.\n\n Switch:\n show, examine - display the current typeclass of object (default) or, if\n given a typeclass path, show the docstring of that typeclass.\n update - *only* re-run at_object_creation on this object\n meaning locks or other properties set later may remain.\n reset - clean out *all* the attributes and properties on the\n object - basically making this a new clean object. This will also\n reset cmdsets!\n force - change to the typeclass also if the object\n already has a typeclass of the same name.\n list - show available typeclasses. Only typeclasses in modules actually\n imported or used from somewhere in the code will show up here\n (those typeclasses are still available if you know the path)\n prototype - clean and overwrite the object with the specified\n prototype key - effectively making a whole new object.\n\n Example:\n type button = examples.red_button.RedButton\n type/prototype button=a red button\n\n If the typeclass_path is not given, the current object's typeclass is\n assumed.\n\n View or set an object's typeclass. If setting, the creation hooks of the\n new typeclass will be run on the object. If you have clashing properties on\n the old class, use /reset. By default you are protected from changing to a\n typeclass of the same name as the one you already have - use /force to\n override this protection.\n\n The given typeclass must be identified by its location using python\n dot-notation pointing to the correct module and class. If no typeclass is\n given (or a wrong typeclass is given). Errors in the path or new typeclass\n will lead to the old typeclass being kept. The location of the typeclass\n module is searched from the default typeclass directory, as defined in the\n server settings.\n\n "}
-
- -
- -
-
-class evennia.commands.default.building.CmdWipe(**kwargs)[source]
-

Bases: evennia.commands.default.building.ObjManipCommand

-

clear all attributes from an object

-
-
Usage:

wipe <object>[/<attr>[/<attr>…]]

-
-
-

Example

-

wipe box -wipe box/colour

-

Wipes all of an object’s attributes, or optionally only those -matching the given attribute-wildcard search string.

-
-
-key = '@wipe'
-
- -
-
-locks = 'cmd:perm(wipe) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-func()[source]
-

inp is the dict produced in ObjManipCommand.parse()

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:perm(wipe) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'building', 'key': '@wipe', 'no_prefix': 'wipe ', 'tags': '', 'text': "\n clear all attributes from an object\n\n Usage:\n wipe <object>[/<attr>[/<attr>...]]\n\n Example:\n wipe box\n wipe box/colour\n\n Wipes all of an object's attributes, or optionally only those\n matching the given attribute-wildcard search string.\n "}
-
- -
- -
-
-class evennia.commands.default.building.CmdLock(**kwargs)[source]
-

Bases: evennia.commands.default.building.ObjManipCommand

-

assign a lock definition to an object

-
-
Usage:

lock <object or *account>[ = <lockstring>] -or -lock[/switch] <object or *account>/<access_type>

-
-
Switch:

del - delete given access type -view - view lock associated with given access type (default)

-
-
-

If no lockstring is given, shows all locks on -object.

-
-
Lockstring is of the form

access_type:[NOT] func1(args)[ AND|OR][ NOT] func2(args) …]

-
-
-

Where func1, func2 … valid lockfuncs with or without arguments. -Separator expressions need not be capitalized.

-
-
For example:

‘get: id(25) or perm(Admin)’

-
-
-

The ‘get’ lock access_type is checked e.g. by the ‘get’ command. -An object locked with this example lock will only be possible to pick up -by Admins or by an object with id=25.

-

You can add several access_types after one another by separating -them by ‘;’, i.e:

-
-

‘get:id(25); delete:perm(Builder)’

-
-
-
-key = '@lock'
-
- -
-
-aliases = ['@locks']
-
- -
-
-locks = 'cmd: perm(locks) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-func()[source]
-

Sets up the command

-
- -
-
-lock_storage = 'cmd: perm(locks) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '@locks', 'category': 'building', 'key': '@lock', 'no_prefix': 'lock locks', 'tags': '', 'text': "\n assign a lock definition to an object\n\n Usage:\n lock <object or *account>[ = <lockstring>]\n or\n lock[/switch] <object or *account>/<access_type>\n\n Switch:\n del - delete given access type\n view - view lock associated with given access type (default)\n\n If no lockstring is given, shows all locks on\n object.\n\n Lockstring is of the form\n access_type:[NOT] func1(args)[ AND|OR][ NOT] func2(args) ...]\n Where func1, func2 ... valid lockfuncs with or without arguments.\n Separator expressions need not be capitalized.\n\n For example:\n 'get: id(25) or perm(Admin)'\n The 'get' lock access_type is checked e.g. by the 'get' command.\n An object locked with this example lock will only be possible to pick up\n by Admins or by an object with id=25.\n\n You can add several access_types after one another by separating\n them by ';', i.e:\n 'get:id(25); delete:perm(Builder)'\n "}
-
- -
- -
-
-class evennia.commands.default.building.CmdExamine(**kwargs)[source]
-

Bases: evennia.commands.default.building.ObjManipCommand

-

get detailed information about an object

-
-
Usage:

examine [<object>[/attrname]] -examine [*<account>[/attrname]]

-
-
Switch:

account - examine an Account (same as adding *) -object - examine an Object (useful when OOC) -script - examine a Script -channel - examine a Channel

-
-
-

The examine command shows detailed game info about an -object and optionally a specific attribute on it. -If object is not specified, the current location is examined.

-

Append a * before the search string to examine an account.

-
-
-key = '@examine'
-
- -
-
-aliases = ['@exam', '@ex']
-
- -
-
-locks = 'cmd:perm(examine) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-arg_regex = re.compile('(/\\w+?(\\s|$))|\\s|$', re.IGNORECASE)
-
- -
-
-switch_options = ['account', 'object', 'script', 'channel']
-
- -
-
-object_type = 'object'
-
- -
-
-detail_color = '|c'
-
- -
-
-header_color = '|w'
-
- -
-
-quell_color = '|r'
-
- -
-
-separator = '-'
-
- -
-
-msg(text)[source]
-

Central point for sending messages to the caller. This tags -the message as ‘examine’ for eventual custom markup in the client.

-
-
-text
-

The text to send.

-
-
Type
-

str

-
-
-
- -
- -
-
-format_key(obj)[source]
-
- -
-
-format_aliases(obj)[source]
-
- -
-
-format_typeclass(obj)[source]
-
- -
-
-format_sessions(obj)[source]
-
- -
-
-format_email(obj)[source]
-
- -
-
-format_account_key(account)[source]
-
- -
-
-format_account_typeclass(account)[source]
-
- -
-
-format_account_permissions(account)[source]
-
- -
-
-format_location(obj)[source]
-
- -
-
-format_home(obj)[source]
-
- -
-
-format_destination(obj)[source]
-
- -
-
-format_permissions(obj)[source]
-
- -
-
-format_locks(obj)[source]
-
- -
-
-format_scripts(obj)[source]
-
- -
-
-format_single_tag(tag)[source]
-
- -
-
-format_tags(obj)[source]
-
- -
-
-format_single_cmdset_options(cmdset)[source]
-
- -
-
-format_single_cmdset(cmdset)[source]
-
- -
-
-format_stored_cmdsets(obj)[source]
-
- -
-
-format_merged_cmdsets(obj, current_cmdset)[source]
-
- -
-
-format_current_cmds(obj, current_cmdset)[source]
-
- -
-
-format_single_attribute_detail(obj, attr)[source]
-
- -
-
-format_single_attribute(attr)[source]
-
- -
-
-format_attributes(obj)[source]
-
- -
-
-format_nattributes(obj)[source]
-
- -
-
-format_exits(obj)[source]
-
- -
-
-format_chars(obj)[source]
-
- -
-
-format_things(obj)[source]
-
- -
-
-format_script_desc(obj)[source]
-
- -
-
-format_script_is_persistent(obj)[source]
-
- -
-
-format_script_timer_data(obj)[source]
-
- -
-
-format_channel_sub_totals(obj)[source]
-
- -
-
-format_channel_account_subs(obj)[source]
-
- -
-
-format_channel_object_subs(obj)[source]
-
- -
-
-get_formatted_obj_data(obj, current_cmdset)[source]
-

Calls all other format_* methods.

-
- -
-
-format_output(obj, current_cmdset)[source]
-

Formats the full examine page return.

-
- -
-
-parse()[source]
-

We need to expand the default parsing to get all -the cases, see the module doc.

-
- -
-
-func()[source]
-

Process command

-
- -
-
-lock_storage = 'cmd:perm(examine) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '@exam @ex', 'category': 'building', 'key': '@examine', 'no_prefix': 'examine exam ex', 'tags': '', 'text': '\n get detailed information about an object\n\n Usage:\n examine [<object>[/attrname]]\n examine [*<account>[/attrname]]\n\n Switch:\n account - examine an Account (same as adding *)\n object - examine an Object (useful when OOC)\n script - examine a Script\n channel - examine a Channel\n\n The examine command shows detailed game info about an\n object and optionally a specific attribute on it.\n If object is not specified, the current location is examined.\n\n Append a * before the search string to examine an account.\n\n '}
-
- -
- -
-
-class evennia.commands.default.building.CmdFind(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

search the database for objects

-
-
Usage:

find[/switches] <name or dbref or *account> [= dbrefmin[-dbrefmax]] -locate - this is a shorthand for using the /loc switch.

-
-
Switches:

room - only look for rooms (location=None) -exit - only look for exits (destination!=None) -char - only look for characters (BASE_CHARACTER_TYPECLASS) -exact - only exact matches are returned. -loc - display object location if exists and match has one result -startswith - search for names starting with the string, rather than containing

-
-
-

Searches the database for an object of a particular name or exact #dbref. -Use *accountname to search for an account. The switches allows for -limiting object matches to certain game entities. Dbrefmin and dbrefmax -limits matches to within the given dbrefs range, or above/below if only -one is given.

-
-
-key = '@find'
-
- -
-
-aliases = ['@locate', '@search']
-
- -
-
-switch_options = ('room', 'exit', 'char', 'exact', 'loc', 'startswith')
-
- -
-
-locks = 'cmd:perm(find) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-func()[source]
-

Search functionality

-
- -
-
-lock_storage = 'cmd:perm(find) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '@locate @search', 'category': 'building', 'key': '@find', 'no_prefix': 'find locate search', 'tags': '', 'text': '\n search the database for objects\n\n Usage:\n find[/switches] <name or dbref or *account> [= dbrefmin[-dbrefmax]]\n locate - this is a shorthand for using the /loc switch.\n\n Switches:\n room - only look for rooms (location=None)\n exit - only look for exits (destination!=None)\n char - only look for characters (BASE_CHARACTER_TYPECLASS)\n exact - only exact matches are returned.\n loc - display object location if exists and match has one result\n startswith - search for names starting with the string, rather than containing\n\n Searches the database for an object of a particular name or exact #dbref.\n Use *accountname to search for an account. The switches allows for\n limiting object matches to certain game entities. Dbrefmin and dbrefmax\n limits matches to within the given dbrefs range, or above/below if only\n one is given.\n '}
-
- -
- -
-
-class evennia.commands.default.building.CmdTeleport(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

teleport object to another location

-
-
Usage:

tel/switch [<object> to||=] <target location>

-
-
-

Examples

-

tel Limbo -tel/quiet box = Limbo -tel/tonone box

-
-
Switches:
-
quiet - don’t echo leave/arrive messages to the source/target

locations for the move.

-
-
intoexit - if target is an exit, teleport INTO

the exit object instead of to its destination

-
-
tonone - if set, teleport the object to a None-location. If this

switch is set, <target location> is ignored. -Note that the only way to retrieve -an object from a None location is by direct #dbref -reference. A puppeted object cannot be moved to None.

-
-
-

loc - teleport object to the target’s location instead of its contents

-
-
-

Teleports an object somewhere. If no object is given, you yourself are -teleported to the target location.

-

To lock an object from being teleported, set its teleport lock, it will be -checked with the caller. To block -a destination from being teleported to, set the destination’s teleport_here -lock - it will be checked with the thing being teleported. Admins and -higher permissions can always teleport.

-
-
-key = '@teleport'
-
- -
-
-aliases = ['@tel']
-
- -
-
-switch_options = ('quiet', 'intoexit', 'tonone', 'loc')
-
- -
-
-rhs_split = ('=', ' to ')
-
- -
-
-locks = 'cmd:perm(teleport) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-parse()[source]
-

Breaking out searching here to make this easier to override.

-
- -
-
-func()[source]
-

Performs the teleport

-
- -
-
-lock_storage = 'cmd:perm(teleport) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '@tel', 'category': 'building', 'key': '@teleport', 'no_prefix': 'teleport tel', 'tags': '', 'text': "\n teleport object to another location\n\n Usage:\n tel/switch [<object> to||=] <target location>\n\n Examples:\n tel Limbo\n tel/quiet box = Limbo\n tel/tonone box\n\n Switches:\n quiet - don't echo leave/arrive messages to the source/target\n locations for the move.\n intoexit - if target is an exit, teleport INTO\n the exit object instead of to its destination\n tonone - if set, teleport the object to a None-location. If this\n switch is set, <target location> is ignored.\n Note that the only way to retrieve\n an object from a None location is by direct #dbref\n reference. A puppeted object cannot be moved to None.\n loc - teleport object to the target's location instead of its contents\n\n Teleports an object somewhere. If no object is given, you yourself are\n teleported to the target location.\n\n To lock an object from being teleported, set its `teleport` lock, it will be\n checked with the caller. To block\n a destination from being teleported to, set the destination's `teleport_here`\n lock - it will be checked with the thing being teleported. Admins and\n higher permissions can always teleport.\n\n "}
-
- -
- -
-
-class evennia.commands.default.building.CmdScripts(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

List and manage all running scripts. Allows for creating new global -scripts.

-
-
Usage:

script[/switches] [script-#dbref, key, script.path or <obj>] -script[/start||stop] <obj> = <script.path or script-key>

-
-
Switches:

start - start/unpause an existing script’s timer. -stop - stops an existing script’s timer -pause - pause a script’s timer -delete - deletes script. This will also stop the timer as needed

-
-
-

Examples

-

script - list scripts -script myobj - list all scripts on object -script foo.bar.Script - create a new global Script -script scriptname - examine named existing global script -script myobj = foo.bar.Script - create and assign script to object -script/stop myobj = scriptname - stop script on object -script/pause foo.Bar.Script - pause global script -script/delete myobj - delete ALL scripts on object -script/delete #dbref[-#dbref] - delete script or range by dbref

-

When given with an <obj> as left-hand-side, this creates and -assigns a new script to that object. Without an <obj>, this -manages and inspects global scripts

-

If no switches are given, this command just views all active -scripts. The argument can be either an object, at which point it -will be searched for all scripts defined on it, or a script name -or #dbref. For using the /stop switch, a unique script #dbref is -required since whole classes of scripts often have the same name.

-

Use the script build-level command for managing scripts attached to -objects.

-
-
-key = '@scripts'
-
- -
-
-aliases = ['@script']
-
- -
-
-switch_options = ('create', 'start', 'stop', 'pause', 'delete')
-
- -
-
-locks = 'cmd:perm(scripts) or perm(Builder)'
-
- -
-
-help_category = 'system'
-
- -
-
-excluded_typeclass_paths = ['evennia.prototypes.prototypes.DbPrototype']
-
- -
-
-switch_mapping = {'create': '|gCreated|n', 'delete': '|rDeleted|n', 'pause': '|Paused|n', 'start': '|gStarted|n', 'stop': '|RStopped|n'}
-
- -
-
-func()[source]
-

implement method

-
- -
-
-lock_storage = 'cmd:perm(scripts) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '@script', 'category': 'system', 'key': '@scripts', 'no_prefix': 'scripts script', 'tags': '', 'text': "\n List and manage all running scripts. Allows for creating new global\n scripts.\n\n Usage:\n script[/switches] [script-#dbref, key, script.path or <obj>]\n script[/start||stop] <obj> = <script.path or script-key>\n\n Switches:\n start - start/unpause an existing script's timer.\n stop - stops an existing script's timer\n pause - pause a script's timer\n delete - deletes script. This will also stop the timer as needed\n\n Examples:\n script - list scripts\n script myobj - list all scripts on object\n script foo.bar.Script - create a new global Script\n script scriptname - examine named existing global script\n script myobj = foo.bar.Script - create and assign script to object\n script/stop myobj = scriptname - stop script on object\n script/pause foo.Bar.Script - pause global script\n script/delete myobj - delete ALL scripts on object\n script/delete #dbref[-#dbref] - delete script or range by dbref\n\n When given with an `<obj>` as left-hand-side, this creates and\n assigns a new script to that object. Without an `<obj>`, this\n manages and inspects global scripts\n\n If no switches are given, this command just views all active\n scripts. The argument can be either an object, at which point it\n will be searched for all scripts defined on it, or a script name\n or #dbref. For using the /stop switch, a unique script #dbref is\n required since whole classes of scripts often have the same name.\n\n Use the `script` build-level command for managing scripts attached to\n objects.\n\n "}
-
- -
- -
-
-class evennia.commands.default.building.CmdObjects(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

statistics on objects in the database

-
-
Usage:

objects [<nr>]

-
-
-

Gives statictics on objects in database as well as -a list of <nr> latest objects in database. If not -given, <nr> defaults to 10.

-
-
-key = '@objects'
-
- -
-
-locks = 'cmd:perm(listobjects) or perm(Builder)'
-
- -
-
-help_category = 'system'
-
- -
-
-func()[source]
-

Implement the command

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:perm(listobjects) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'system', 'key': '@objects', 'no_prefix': 'objects ', 'tags': '', 'text': '\n statistics on objects in the database\n\n Usage:\n objects [<nr>]\n\n Gives statictics on objects in database as well as\n a list of <nr> latest objects in database. If not\n given, <nr> defaults to 10.\n '}
-
- -
- -
-
-class evennia.commands.default.building.CmdTag(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

handles the tags of an object

-
-
Usage:

tag[/del] <obj> [= <tag>[:<category>]] -tag/search <tag>[:<category]

-
-
Switches:

search - return all objects with a given Tag -del - remove the given tag. If no tag is specified,

-
-

clear all tags on object.

-
-
-
-

Manipulates and lists tags on objects. Tags allow for quick -grouping of and searching for objects. If only <obj> is given, -list all tags on the object. If /search is used, list objects -with the given tag. -The category can be used for grouping tags themselves, but it -should be used with restrain - tags on their own are usually -enough to for most grouping schemes.

-
-
-key = '@tag'
-
- -
-
-aliases = ['@tags']
-
- -
-
-options = ('search', 'del')
-
- -
-
-locks = 'cmd:perm(tag) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-arg_regex = re.compile('(/\\w+?(\\s|$))|\\s|$', re.IGNORECASE)
-
- -
-
-func()[source]
-

Implement the tag functionality

-
- -
-
-lock_storage = 'cmd:perm(tag) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '@tags', 'category': 'building', 'key': '@tag', 'no_prefix': 'tag tags', 'tags': '', 'text': '\n handles the tags of an object\n\n Usage:\n tag[/del] <obj> [= <tag>[:<category>]]\n tag/search <tag>[:<category]\n\n Switches:\n search - return all objects with a given Tag\n del - remove the given tag. If no tag is specified,\n clear all tags on object.\n\n Manipulates and lists tags on objects. Tags allow for quick\n grouping of and searching for objects. If only <obj> is given,\n list all tags on the object. If /search is used, list objects\n with the given tag.\n The category can be used for grouping tags themselves, but it\n should be used with restrain - tags on their own are usually\n enough to for most grouping schemes.\n '}
-
- -
- -
-
-class evennia.commands.default.building.CmdSpawn(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

spawn objects from prototype

-
-
Usage:

spawn[/noloc] <prototype_key> -spawn[/noloc] <prototype_dict>

-

spawn/search [prototype_keykey][;tag[,tag]] -spawn/list [tag, tag, …] -spawn/list modules - list only module-based prototypes -spawn/show [<prototype_key>] -spawn/update <prototype_key>

-

spawn/save <prototype_dict> -spawn/edit [<prototype_key>] -olc - equivalent to spawn/edit

-
-
Switches:
-
noloc - allow location to be None if not specified explicitly. Otherwise,

location will default to caller’s current location.

-
-
-

search - search prototype by name or tags. -list - list available prototypes, optionally limit by tags. -show, examine - inspect prototype by key. If not given, acts like list. -raw - show the raw dict of the prototype as a one-line string for manual editing. -save - save a prototype to the database. It will be listable by /list. -delete - remove a prototype from database, if allowed to. -update - find existing objects with the same prototype_key and update

-
-

them with latest version of given prototype. If given with /save, -will auto-update all objects with the old version of the prototype -without asking first.

-
-

edit, menu, olc - create/manipulate prototype in a menu interface.

-
-
-

Example

-

spawn GOBLIN -spawn {“key”:”goblin”, “typeclass”:”monster.Monster”, “location”:”#2”} -spawn/save {“key”: “grunt”, prototype: “goblin”};;mobs;edit:all()

-
-
Dictionary keys:
-
|wprototype_parent |n - name of parent prototype to use. Required if typeclass is

not set. Can be a path or a list for multiple inheritance (inherits -left to right). If set one of the parents must have a typeclass.

-
-
-

|wtypeclass |n - string. Required if prototype_parent is not set. -|wkey |n - string, the main object identifier -|wlocation |n - this should be a valid object or #dbref -|whome |n - valid object or #dbref -|wdestination|n - only valid for exits (object or dbref) -|wpermissions|n - string or list of permission strings -|wlocks |n - a lock-string -|waliases |n - string or list of strings. -|wndb_|n<name> - value of a nattribute (ndb_ is stripped)

-
-
|wprototype_key|n - name of this prototype. Unique. Used to store/retrieve from db

and update existing prototyped objects if desired.

-
-
-

|wprototype_desc|n - desc of this prototype. Used in listings -|wprototype_locks|n - locks of this prototype. Limits who may use prototype -|wprototype_tags|n - tags of this prototype. Used to find prototype

-

any other keywords are interpreted as Attributes and their values.

-
-
-

The available prototypes are defined globally in modules set in -settings.PROTOTYPE_MODULES. If spawn is used without arguments it -displays a list of available prototypes.

-
-
-key = '@spawn'
-
- -
-
-aliases = ['@olc']
-
- -
-
-switch_options = ('noloc', 'search', 'list', 'show', 'raw', 'examine', 'save', 'delete', 'menu', 'olc', 'update', 'edit')
-
- -
-
-locks = 'cmd:perm(spawn) or perm(Builder)'
-
- -
-
-help_category = 'building'
-
- -
-
-func()[source]
-

Implements the spawner

-
- -
-
-lock_storage = 'cmd:perm(spawn) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '@olc', 'category': 'building', 'key': '@spawn', 'no_prefix': 'spawn olc', 'tags': '', 'text': '\n spawn objects from prototype\n\n Usage:\n spawn[/noloc] <prototype_key>\n spawn[/noloc] <prototype_dict>\n\n spawn/search [prototype_keykey][;tag[,tag]]\n spawn/list [tag, tag, ...]\n spawn/list modules - list only module-based prototypes\n spawn/show [<prototype_key>]\n spawn/update <prototype_key>\n\n spawn/save <prototype_dict>\n spawn/edit [<prototype_key>]\n olc - equivalent to spawn/edit\n\n Switches:\n noloc - allow location to be None if not specified explicitly. Otherwise,\n location will default to caller\'s current location.\n search - search prototype by name or tags.\n list - list available prototypes, optionally limit by tags.\n show, examine - inspect prototype by key. If not given, acts like list.\n raw - show the raw dict of the prototype as a one-line string for manual editing.\n save - save a prototype to the database. It will be listable by /list.\n delete - remove a prototype from database, if allowed to.\n update - find existing objects with the same prototype_key and update\n them with latest version of given prototype. If given with /save,\n will auto-update all objects with the old version of the prototype\n without asking first.\n edit, menu, olc - create/manipulate prototype in a menu interface.\n\n Example:\n spawn GOBLIN\n spawn {"key":"goblin", "typeclass":"monster.Monster", "location":"#2"}\n spawn/save {"key": "grunt", prototype: "goblin"};;mobs;edit:all()\n \x0c\n Dictionary keys:\n |wprototype_parent |n - name of parent prototype to use. Required if typeclass is\n not set. Can be a path or a list for multiple inheritance (inherits\n left to right). If set one of the parents must have a typeclass.\n |wtypeclass |n - string. Required if prototype_parent is not set.\n |wkey |n - string, the main object identifier\n |wlocation |n - this should be a valid object or #dbref\n |whome |n - valid object or #dbref\n |wdestination|n - only valid for exits (object or dbref)\n |wpermissions|n - string or list of permission strings\n |wlocks |n - a lock-string\n |waliases |n - string or list of strings.\n |wndb_|n<name> - value of a nattribute (ndb_ is stripped)\n\n |wprototype_key|n - name of this prototype. Unique. Used to store/retrieve from db\n and update existing prototyped objects if desired.\n |wprototype_desc|n - desc of this prototype. Used in listings\n |wprototype_locks|n - locks of this prototype. Limits who may use prototype\n |wprototype_tags|n - tags of this prototype. Used to find prototype\n\n any other keywords are interpreted as Attributes and their values.\n\n The available prototypes are defined globally in modules set in\n settings.PROTOTYPE_MODULES. If spawn is used without arguments it\n displays a list of available prototypes.\n\n '}
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.default.cmdset_account.html b/docs/0.9.5/api/evennia.commands.default.cmdset_account.html deleted file mode 100644 index 5acff97eb8..0000000000 --- a/docs/0.9.5/api/evennia.commands.default.cmdset_account.html +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - - - - evennia.commands.default.cmdset_account — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.commands.default.cmdset_account

-

This is the cmdset for Account (OOC) commands. These are -stored on the Account object and should thus be able to handle getting -an Account object as caller rather than a Character.

-

Note - in order for session-rerouting (in MULTISESSION_MODE=2) to -function, all commands in this cmdset should use the self.msg() -command method rather than caller.msg().

-
-
-class evennia.commands.default.cmdset_account.AccountCmdSet(cmdsetobj=None, key=None)[source]
-

Bases: evennia.commands.cmdset.CmdSet

-

Implements the account command set.

-
-
-key = 'DefaultAccount'
-
- -
-
-priority = -10
-
- -
-
-at_cmdset_creation()[source]
-

Populates the cmdset

-
- -
-
-path = 'evennia.commands.default.cmdset_account.AccountCmdSet'
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.default.cmdset_character.html b/docs/0.9.5/api/evennia.commands.default.cmdset_character.html deleted file mode 100644 index 6e34fe7d16..0000000000 --- a/docs/0.9.5/api/evennia.commands.default.cmdset_character.html +++ /dev/null @@ -1,143 +0,0 @@ - - - - - - - - - evennia.commands.default.cmdset_character — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.commands.default.cmdset_character

-

This module ties together all the commands default Character objects have -available (i.e. IC commands). Note that some commands, such as -communication-commands are instead put on the account level, in the -Account cmdset. Account commands remain available also to Characters.

-
-
-class evennia.commands.default.cmdset_character.CharacterCmdSet(cmdsetobj=None, key=None)[source]
-

Bases: evennia.commands.cmdset.CmdSet

-

Implements the default command set.

-
-
-key = 'DefaultCharacter'
-
- -
-
-priority = 0
-
- -
-
-at_cmdset_creation()[source]
-

Populates the cmdset

-
- -
-
-path = 'evennia.commands.default.cmdset_character.CharacterCmdSet'
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.default.cmdset_session.html b/docs/0.9.5/api/evennia.commands.default.cmdset_session.html deleted file mode 100644 index 38d04898ce..0000000000 --- a/docs/0.9.5/api/evennia.commands.default.cmdset_session.html +++ /dev/null @@ -1,140 +0,0 @@ - - - - - - - - - evennia.commands.default.cmdset_session — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.commands.default.cmdset_session

-

This module stores session-level commands.

-
-
-class evennia.commands.default.cmdset_session.SessionCmdSet(cmdsetobj=None, key=None)[source]
-

Bases: evennia.commands.cmdset.CmdSet

-

Sets up the unlogged cmdset.

-
-
-key = 'DefaultSession'
-
- -
-
-priority = -20
-
- -
-
-at_cmdset_creation()[source]
-

Populate the cmdset

-
- -
-
-path = 'evennia.commands.default.cmdset_session.SessionCmdSet'
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.default.cmdset_unloggedin.html b/docs/0.9.5/api/evennia.commands.default.cmdset_unloggedin.html deleted file mode 100644 index fea4bcf9cc..0000000000 --- a/docs/0.9.5/api/evennia.commands.default.cmdset_unloggedin.html +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - - - - evennia.commands.default.cmdset_unloggedin — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.commands.default.cmdset_unloggedin

-

This module describes the unlogged state of the default game. -The setting STATE_UNLOGGED should be set to the python path -of the state instance in this module.

-
-
-class evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet(cmdsetobj=None, key=None)[source]
-

Bases: evennia.commands.cmdset.CmdSet

-

Sets up the unlogged cmdset.

-
-
-key = 'DefaultUnloggedin'
-
- -
-
-priority = 0
-
- -
-
-at_cmdset_creation()[source]
-

Populate the cmdset

-
- -
-
-path = 'evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet'
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.default.comms.html b/docs/0.9.5/api/evennia.commands.default.comms.html deleted file mode 100644 index 1abeae2df0..0000000000 --- a/docs/0.9.5/api/evennia.commands.default.comms.html +++ /dev/null @@ -1,1328 +0,0 @@ - - - - - - - - - evennia.commands.default.comms — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.commands.default.comms

-

Communication commands:

-
    -
  • channel

  • -
  • page

  • -
  • irc/rss/grapevine linking

  • -
-
-
-class evennia.commands.default.comms.CmdChannel(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

Use and manage in-game channels.

-
-
Usage:

channel channelname <msg> -channel channel name = <msg> -channel (show all subscription) -channel/all (show available channels) -channel/alias channelname = alias[;alias…] -channel/unalias alias -channel/who channelname -channel/history channelname [= index] -channel/sub channelname [= alias[;alias…]] -channel/unsub channelname[,channelname, …] -channel/mute channelname[,channelname,…] -channel/unmute channelname[,channelname,…]

-

channel/create channelname[;alias;alias[:typeclass]] [= description] -channel/destroy channelname [= reason] -channel/desc channelname = description -channel/lock channelname = lockstring -channel/unlock channelname = lockstring -channel/ban channelname (list bans) -channel/ban[/quiet] channelname[, channelname, …] = subscribername [: reason] -channel/unban[/quiet] channelname[, channelname, …] = subscribername -channel/boot[/quiet] channelname[,channelname,…] = subscribername [: reason]

-
-
-
-
Usage: channel channelname msg

channel channel name = msg (with space in channel name)

-
-
-

This sends a message to the channel. Note that you will rarely use this -command like this; instead you can use the alias

-
-

channelname <msg> -channelalias <msg>

-
-

For example

-
-

public Hello World -pub Hello World

-
-

(this shortcut doesn’t work for aliases containing spaces)

-

See channel/alias for help on setting channel aliases.

-
-
Usage: channel/alias channel = alias[;alias[;alias…]]

channel/unalias alias -channel - this will list your subs and aliases to each channel

-
-
-

Set one or more personal aliases for referencing a channel. For example:

-
-

channel/alias warrior’s guild = warrior;wguild;warchannel;warrior guild

-
-

You can now send to the channel using all of these:

-
-

warrior’s guild Hello -warrior Hello -wguild Hello -warchannel Hello

-
-

Note that this will not work if the alias has a space in it. So the -‘warrior guild’ alias must be used with the channel command:

-
-

channel warrior guild = Hello

-
-

Channel-aliases can be removed one at a time, using the ‘/unalias’ switch.

-

Usage: channel/who channelname

-

List the channel’s subscribers. Shows who are currently offline or are -muting the channel. Subscribers who are ‘muting’ will not see messages sent -to the channel (use channel/mute to mute a channel).

-

Usage: channel/history channel [= index]

-

This will display the last |c20|n lines of channel history. By supplying an -index number, you will step that many lines back before viewing those 20 lines.

-

For example:

-
-

channel/history public = 35

-
-

will go back 35 lines and show the previous 20 lines from that point (so -lines -35 to -55).

-
-
Usage: channel/sub channel [=alias[;alias;…]]

channel/unsub channel

-
-
-

This subscribes you to a channel and optionally assigns personal shortcuts -for you to use to send to that channel (see aliases). When you unsub, all -your personal aliases will also be removed.

-
-
Usage: channel/mute channelname

channel/unmute channelname

-
-
-

Muting silences all output from the channel without actually -un-subscribing. Other channel members will see that you are muted in the /who -list. Sending a message to the channel will automatically unmute you.

-
-
Usage: channel/create channelname[;alias;alias[:typeclass]] [= description]

channel/destroy channelname [= reason]

-
-
-

Creates a new channel (or destroys one you control). You will automatically -join the channel you create and everyone will be kicked and loose all aliases -to a destroyed channel.

-
-
Usage: channel/lock channelname = lockstring

channel/unlock channelname = lockstring

-
-
-

Note: this is an admin command.

-

A lockstring is on the form locktype:lockfunc(). Channels understand three -locktypes:

-
-

listen - who may listen or join the channel. -send - who may send messages to the channel -control - who controls the channel. This is usually the one creating

-
-

the channel.

-
-
-

Common lockfuncs are all() and perm(). To make a channel everyone can -listen to but only builders can talk on, use this:

-
-

listen:all() -send: perm(Builders)

-
-
-
Usage:

channel/boot[/quiet] channelname[,channelname,…] = subscribername [: reason] -channel/ban channelname[, channelname, …] = subscribername [: reason] -channel/unban channelname[, channelname, …] = subscribername -channel/unban channelname -channel/ban channelname (list bans)

-
-
-

Booting will kick a named subscriber from channel(s) temporarily. The -‘reason’ will be passed to the booted user. Unless the /quiet switch is -used, the channel will also be informed of the action. A booted user is -still able to re-connect, but they’ll have to set up their aliases again.

-

Banning will blacklist a user from (re)joining the provided channels. It -will then proceed to boot them from those channels if they were connected. -The ‘reason’ and /quiet works the same as for booting.

-

Example

-

boot mychannel1 = EvilUser : Kicking you to cool down a bit. -ban mychannel1,mychannel2= EvilUser : Was banned for spamming.

-
-
-key = '@channel'
-
- -
-
-aliases = ['@channels', '@chan']
-
- -
-
-help_category = 'comms'
-
- -
-
-locks = 'cmd:not pperm(channel_banned);admin:all();manage:all();changelocks:perm(Admin)'
-
- -
-
-switch_options = ('list', 'all', 'history', 'sub', 'unsub', 'mute', 'unmute', 'alias', 'unalias', 'create', 'destroy', 'desc', 'lock', 'unlock', 'boot', 'ban', 'unban', 'who')
-
- -
-
-account_caller = True
-
- -
-
-search_channel(channelname, exact=False, handle_errors=True)[source]
-

Helper function for searching for a single channel with some error -handling.

-
-
Parameters
-
    -
  • channelname (str) – Name, alias #dbref or partial name/alias to search -for.

  • -
  • exact (bool, optional) – If an exact or fuzzy-match of the name should be done. -Note that even for a fuzzy match, an exactly given, unique channel name -will always be returned.

  • -
  • handle_errors (bool) – If true, use self.msg to report errors if -there are non/multiple matches. If so, the return will always be -a single match or None.

  • -
-
-
Returns
-

object, list or None

-
-
If handle_errors is True, this is either a found Channel

or None. Otherwise it’s a list of zero, one or more channels found.

-
-
-

-
-
-

Notes

-

The ‘listen’ and ‘control’ accesses are checked before returning.

-
- -
-
-msg_channel(channel, message, **kwargs)[source]
-

Send a message to a given channel. This will check the ‘send’ -permission on the channel.

-
-
Parameters
-
    -
  • channel (Channel) – The channel to send to.

  • -
  • message (str) – The message to send.

  • -
  • **kwargs – Unused by default. These kwargs will be passed into -all channel messaging hooks for custom overriding.

  • -
-
-
-
- -
-
-get_channel_history(channel, start_index=0)[source]
-

View a channel’s history.

-
-
Parameters
-
    -
  • channel (Channel) – The channel to access.

  • -
  • message (str) – The message to send.

  • -
  • **kwargs – Unused by default. These kwargs will be passed into -all channel messaging hooks for custom overriding.

  • -
-
-
-
- -
-
-sub_to_channel(channel)[source]
-

Subscribe to a channel. Note that all permissions should -be checked before this step.

-
-
Parameters
-

channel (Channel) – The channel to access.

-
-
Returns
-

bool, str

-
-
True, None if connection failed. If False,

the second part is an error string.

-
-
-

-
-
-
- -
-
-unsub_from_channel(channel, **kwargs)[source]
-

Un-Subscribe to a channel. Note that all permissions should -be checked before this step.

-
-
Parameters
-
    -
  • channel (Channel) – The channel to unsub from.

  • -
  • **kwargs – Passed on to nick removal.

  • -
-
-
Returns
-

bool, str

-
-
True, None if un-connection succeeded. If False,

the second part is an error string.

-
-
-

-
-
-
- -
-
-add_alias(channel, alias, **kwargs)[source]
-

Add a new alias (nick) for the user to use with this channel.

-
-
Parameters
-
    -
  • channel (Channel) – The channel to alias.

  • -
  • alias (str) – The personal alias to use for this channel.

  • -
  • **kwargs – If given, passed into nicks.add.

  • -
-
-
-
-

Note

-

We add two nicks - one is a plain alias -> channel.key that -we need to be able to reference this channel easily. The other -is a templated nick to easily be able to send messages to the -channel without needing to give the full channel command. The -structure of this nick is given by self.channel_msg_pattern -and self.channel_msg_nick_replacement. By default it maps -alias <msg> -> channel <channelname> = <msg>, so that you can -for example just write pub Hello to send a message.

-

The alias created is alias $1 -> channel channel = $1, to allow -for sending to channel using the main channel command.

-
-
- -
-
-remove_alias(alias, **kwargs)[source]
-

Remove an alias from a channel.

-
-
Parameters
-

alias (str, optional) – The alias to remove. -The channel will be reverse-determined from the -alias, if it exists.

-
-
Returns
-

bool, str

-
-
True, None if removal succeeded. If False,

the second part is an error string.

-
-
-

**kwargs: If given, passed into nicks.get/add.

-

-
-
-
-

Note

-

This will remove two nicks - the plain channel alias and the templated -nick used for easily sending messages to the channel.

-
-
- -
-
-get_channel_aliases(channel)[source]
-

Get a user’s aliases for a given channel. The user is retrieved -through self.caller.

-
-
Parameters
-

channel (Channel) – The channel to act on.

-
-
Returns
-

list – A list of zero, one or more alias-strings.

-
-
-
- -
-
-mute_channel(channel)[source]
-

Temporarily mute a channel.

-
-
Parameters
-

channel (Channel) – The channel to alias.

-
-
Returns
-

bool, str

-
-
True, None if muting successful. If False,

the second part is an error string.

-
-
-

-
-
-
- -
-
-unmute_channel(channel)[source]
-

Unmute a channel.

-
-
Parameters
-

channel (Channel) – The channel to alias.

-
-
Returns
-

bool, str

-
-
True, None if unmuting successful. If False,

the second part is an error string.

-
-
-

-
-
-
- -
-
-create_channel(name, description, typeclass=None, aliases=None)[source]
-

Create a new channel. Its name must not previously exist -(users can alias as needed). Will also connect to the -new channel.

-
-
Parameters
-
    -
  • name (str) – The new channel name/key.

  • -
  • description (str) – This is used in listings.

  • -
  • aliases (list) – A list of strings - alternative aliases for the channel -(not to be confused with per-user aliases; these are available for -everyone).

  • -
-
-
Returns
-

channel, str

-
-
new_channel, “” if creation successful. If False,

the second part is an error string.

-
-
-

-
-
-
- -
-
-destroy_channel(channel, message=None)[source]
-

Destroy an existing channel. Access should be checked before -calling this function.

-
-
Parameters
-
    -
  • channel (Channel) – The channel to alias.

  • -
  • message (str, optional) – Final message to send onto the channel -before destroying it. If not given, a default message is -used. Set to the empty string for no message.

  • -
-
-
-
-
if typeclass:

pass

-
-
-
- -
-
-set_lock(channel, lockstring)[source]
-

Set a lockstring on a channel. Permissions must have been -checked before this call.

-
-
Parameters
-
    -
  • channel (Channel) – The channel to operate on.

  • -
  • lockstring (str) – A lockstring on the form ‘type:lockfunc();…’

  • -
-
-
Returns
-

bool, str

-
-
True, None if setting lock was successful. If False,

the second part is an error string.

-
-
-

-
-
-
- -
-
-unset_lock(channel, lockstring)[source]
-

Remove locks in a lockstring on a channel. Permissions must have been -checked before this call.

-
-
Parameters
-
    -
  • channel (Channel) – The channel to operate on.

  • -
  • lockstring (str) – A lockstring on the form ‘type:lockfunc();…’

  • -
-
-
Returns
-

bool, str

-
-
True, None if setting lock was successful. If False,

the second part is an error string.

-
-
-

-
-
-
- -
-
-set_desc(channel, description)[source]
-

Set a channel description. This is shown in listings etc.

-
-
Parameters
-
    -
  • caller (Object or Account) – The entity performing the action.

  • -
  • channel (Channel) – The channel to operate on.

  • -
  • description (str) – A short description of the channel.

  • -
-
-
Returns
-

bool, str

-
-
True, None if setting lock was successful. If False,

the second part is an error string.

-
-
-

-
-
-
- -
-
-boot_user(channel, target, quiet=False, reason='')[source]
-

Boot a user from a channel, with optional reason. This will -also remove all their aliases for this channel.

-
-
Parameters
-
    -
  • channel (Channel) – The channel to operate on.

  • -
  • target (Object or Account) – The entity to boot.

  • -
  • quiet (bool, optional) – Whether or not to announce to channel.

  • -
  • reason (str, optional) – A reason for the boot.

  • -
-
-
Returns
-

bool, str

-
-
True, None if setting lock was successful. If False,

the second part is an error string.

-
-
-

-
-
-
- -
-
-ban_user(channel, target, quiet=False, reason='')[source]
-

Ban a user from a channel, by locking them out. This will also -boot them, if they are currently connected.

-
-
Parameters
-
    -
  • channel (Channel) – The channel to operate on.

  • -
  • target (Object or Account) – The entity to ban

  • -
  • quiet (bool, optional) – Whether or not to announce to channel.

  • -
  • reason (str, optional) – A reason for the ban

  • -
-
-
Returns
-

bool, str

-
-
True, None if banning was successful. If False,

the second part is an error string.

-
-
-

-
-
-
- -
-
-unban_user(channel, target)[source]
-

Un-Ban a user from a channel. This will not reconnect them -to the channel, just allow them to connect again (assuming -they have the suitable ‘listen’ lock like everyone else).

-
-
Parameters
-
    -
  • channel (Channel) – The channel to operate on.

  • -
  • target (Object or Account) – The entity to unban

  • -
-
-
Returns
-

bool, str

-
-
True, None if unbanning was successful. If False,

the second part is an error string.

-
-
-

-
-
-
- -
-
-channel_list_bans(channel)[source]
-

Show a channel’s bans.

-
-
Parameters
-

channel (Channel) – The channel to operate on.

-
-
Returns
-

list – A list of strings, each the name of a banned user.

-
-
-
- -
-
-channel_list_who(channel)[source]
-

Show a list of online people is subscribing to a channel. This will check -the ‘control’ permission of caller to determine if only online users -should be returned or everyone.

-
-
Parameters
-

channel (Channel) – The channel to operate on.

-
-
Returns
-

list

-
-
A list of prepared strings, with name + markers for if they are

muted or offline.

-
-
-

-
-
-
- -
-
-list_channels(channelcls=<class 'evennia.comms.comms.DefaultChannel'>)[source]
-

Return a available channels.

-
-
Parameters
-

channelcls (Channel, optional) – The channel-class to query on. Defaults -to the default channel class from settings.

-
-
Returns
-

tuple

-
-
A tuple (subbed_chans, available_chans) with the channels

currently subscribed to, and those we have ‘listen’ access to but -don’t actually sub to yet.

-
-
-

-
-
-
- -
-
-display_subbed_channels(subscribed)[source]
-

Display channels subscribed to.

-
-
Parameters
-

subscribed (list) – List of subscribed channels

-
-
Returns
-

EvTable – Table to display.

-
-
-
- -
-
-display_all_channels(subscribed, available)[source]
-

Display all available channels

-
-
Parameters
-

subscribed (list) – List of subscribed channels

-
-
Returns
-

EvTable – Table to display.

-
-
-
- -
-
-func()[source]
-

Main functionality of command.

-
- -
-
-lock_storage = 'cmd:not pperm(channel_banned);admin:all();manage:all();changelocks:perm(Admin)'
-
- -
-
-search_index_entry = {'aliases': '@channels @chan', 'category': 'comms', 'key': '@channel', 'no_prefix': 'channel channels chan', 'tags': '', 'text': "\n Use and manage in-game channels.\n\n Usage:\n channel channelname <msg>\n channel channel name = <msg>\n channel (show all subscription)\n channel/all (show available channels)\n channel/alias channelname = alias[;alias...]\n channel/unalias alias\n channel/who channelname\n channel/history channelname [= index]\n channel/sub channelname [= alias[;alias...]]\n channel/unsub channelname[,channelname, ...]\n channel/mute channelname[,channelname,...]\n channel/unmute channelname[,channelname,...]\n\n channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n channel/desc channelname = description\n channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n channel/ban channelname (list bans)\n channel/ban[/quiet] channelname[, channelname, ...] = subscribername [: reason]\n channel/unban[/quiet] channelname[, channelname, ...] = subscribername\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n\n # subtopics\n\n ## sending\n\n Usage: channel channelname msg\n channel channel name = msg (with space in channel name)\n\n This sends a message to the channel. Note that you will rarely use this\n command like this; instead you can use the alias\n\n channelname <msg>\n channelalias <msg>\n\n For example\n\n public Hello World\n pub Hello World\n\n (this shortcut doesn't work for aliases containing spaces)\n\n See channel/alias for help on setting channel aliases.\n\n ## alias and unalias\n\n Usage: channel/alias channel = alias[;alias[;alias...]]\n channel/unalias alias\n channel - this will list your subs and aliases to each channel\n\n Set one or more personal aliases for referencing a channel. For example:\n\n channel/alias warrior's guild = warrior;wguild;warchannel;warrior guild\n\n You can now send to the channel using all of these:\n\n warrior's guild Hello\n warrior Hello\n wguild Hello\n warchannel Hello\n\n Note that this will not work if the alias has a space in it. So the\n 'warrior guild' alias must be used with the `channel` command:\n\n channel warrior guild = Hello\n\n Channel-aliases can be removed one at a time, using the '/unalias' switch.\n\n ## who\n\n Usage: channel/who channelname\n\n List the channel's subscribers. Shows who are currently offline or are\n muting the channel. Subscribers who are 'muting' will not see messages sent\n to the channel (use channel/mute to mute a channel).\n\n ## history\n\n Usage: channel/history channel [= index]\n\n This will display the last |c20|n lines of channel history. By supplying an\n index number, you will step that many lines back before viewing those 20 lines.\n\n For example:\n\n channel/history public = 35\n\n will go back 35 lines and show the previous 20 lines from that point (so\n lines -35 to -55).\n\n ## sub and unsub\n\n Usage: channel/sub channel [=alias[;alias;...]]\n channel/unsub channel\n\n This subscribes you to a channel and optionally assigns personal shortcuts\n for you to use to send to that channel (see aliases). When you unsub, all\n your personal aliases will also be removed.\n\n ## mute and unmute\n\n Usage: channel/mute channelname\n channel/unmute channelname\n\n Muting silences all output from the channel without actually\n un-subscribing. Other channel members will see that you are muted in the /who\n list. Sending a message to the channel will automatically unmute you.\n\n ## create and destroy\n\n Usage: channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n\n Creates a new channel (or destroys one you control). You will automatically\n join the channel you create and everyone will be kicked and loose all aliases\n to a destroyed channel.\n\n ## lock and unlock\n\n Usage: channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n\n Note: this is an admin command.\n\n A lockstring is on the form locktype:lockfunc(). Channels understand three\n locktypes:\n listen - who may listen or join the channel.\n send - who may send messages to the channel\n control - who controls the channel. This is usually the one creating\n the channel.\n\n Common lockfuncs are all() and perm(). To make a channel everyone can\n listen to but only builders can talk on, use this:\n\n listen:all()\n send: perm(Builders)\n\n ## boot and ban\n\n Usage:\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n channel/ban channelname[, channelname, ...] = subscribername [: reason]\n channel/unban channelname[, channelname, ...] = subscribername\n channel/unban channelname\n channel/ban channelname (list bans)\n\n Booting will kick a named subscriber from channel(s) temporarily. The\n 'reason' will be passed to the booted user. Unless the /quiet switch is\n used, the channel will also be informed of the action. A booted user is\n still able to re-connect, but they'll have to set up their aliases again.\n\n Banning will blacklist a user from (re)joining the provided channels. It\n will then proceed to boot them from those channels if they were connected.\n The 'reason' and `/quiet` works the same as for booting.\n\n Example:\n boot mychannel1 = EvilUser : Kicking you to cool down a bit.\n ban mychannel1,mychannel2= EvilUser : Was banned for spamming.\n\n "}
-
- -
- -
-
-class evennia.commands.default.comms.CmdObjectChannel(**kwargs)[source]
-

Bases: evennia.commands.default.comms.CmdChannel

-

Use and manage in-game channels.

-
-
Usage:

channel channelname <msg> -channel channel name = <msg> -channel (show all subscription) -channel/all (show available channels) -channel/alias channelname = alias[;alias…] -channel/unalias alias -channel/who channelname -channel/history channelname [= index] -channel/sub channelname [= alias[;alias…]] -channel/unsub channelname[,channelname, …] -channel/mute channelname[,channelname,…] -channel/unmute channelname[,channelname,…]

-

channel/create channelname[;alias;alias[:typeclass]] [= description] -channel/destroy channelname [= reason] -channel/desc channelname = description -channel/lock channelname = lockstring -channel/unlock channelname = lockstring -channel/ban channelname (list bans) -channel/ban[/quiet] channelname[, channelname, …] = subscribername [: reason] -channel/unban[/quiet] channelname[, channelname, …] = subscribername -channel/boot[/quiet] channelname[,channelname,…] = subscribername [: reason]

-
-
-
-
Usage: channel channelname msg

channel channel name = msg (with space in channel name)

-
-
-

This sends a message to the channel. Note that you will rarely use this -command like this; instead you can use the alias

-
-

channelname <msg> -channelalias <msg>

-
-

For example

-
-

public Hello World -pub Hello World

-
-

(this shortcut doesn’t work for aliases containing spaces)

-

See channel/alias for help on setting channel aliases.

-
-
Usage: channel/alias channel = alias[;alias[;alias…]]

channel/unalias alias -channel - this will list your subs and aliases to each channel

-
-
-

Set one or more personal aliases for referencing a channel. For example:

-
-

channel/alias warrior’s guild = warrior;wguild;warchannel;warrior guild

-
-

You can now send to the channel using all of these:

-
-

warrior’s guild Hello -warrior Hello -wguild Hello -warchannel Hello

-
-

Note that this will not work if the alias has a space in it. So the -‘warrior guild’ alias must be used with the channel command:

-
-

channel warrior guild = Hello

-
-

Channel-aliases can be removed one at a time, using the ‘/unalias’ switch.

-

Usage: channel/who channelname

-

List the channel’s subscribers. Shows who are currently offline or are -muting the channel. Subscribers who are ‘muting’ will not see messages sent -to the channel (use channel/mute to mute a channel).

-

Usage: channel/history channel [= index]

-

This will display the last |c20|n lines of channel history. By supplying an -index number, you will step that many lines back before viewing those 20 lines.

-

For example:

-
-

channel/history public = 35

-
-

will go back 35 lines and show the previous 20 lines from that point (so -lines -35 to -55).

-
-
Usage: channel/sub channel [=alias[;alias;…]]

channel/unsub channel

-
-
-

This subscribes you to a channel and optionally assigns personal shortcuts -for you to use to send to that channel (see aliases). When you unsub, all -your personal aliases will also be removed.

-
-
Usage: channel/mute channelname

channel/unmute channelname

-
-
-

Muting silences all output from the channel without actually -un-subscribing. Other channel members will see that you are muted in the /who -list. Sending a message to the channel will automatically unmute you.

-
-
Usage: channel/create channelname[;alias;alias[:typeclass]] [= description]

channel/destroy channelname [= reason]

-
-
-

Creates a new channel (or destroys one you control). You will automatically -join the channel you create and everyone will be kicked and loose all aliases -to a destroyed channel.

-
-
Usage: channel/lock channelname = lockstring

channel/unlock channelname = lockstring

-
-
-

Note: this is an admin command.

-

A lockstring is on the form locktype:lockfunc(). Channels understand three -locktypes:

-
-

listen - who may listen or join the channel. -send - who may send messages to the channel -control - who controls the channel. This is usually the one creating

-
-

the channel.

-
-
-

Common lockfuncs are all() and perm(). To make a channel everyone can -listen to but only builders can talk on, use this:

-
-

listen:all() -send: perm(Builders)

-
-
-
Usage:

channel/boot[/quiet] channelname[,channelname,…] = subscribername [: reason] -channel/ban channelname[, channelname, …] = subscribername [: reason] -channel/unban channelname[, channelname, …] = subscribername -channel/unban channelname -channel/ban channelname (list bans)

-
-
-

Booting will kick a named subscriber from channel(s) temporarily. The -‘reason’ will be passed to the booted user. Unless the /quiet switch is -used, the channel will also be informed of the action. A booted user is -still able to re-connect, but they’ll have to set up their aliases again.

-

Banning will blacklist a user from (re)joining the provided channels. It -will then proceed to boot them from those channels if they were connected. -The ‘reason’ and /quiet works the same as for booting.

-

Example

-

boot mychannel1 = EvilUser : Kicking you to cool down a bit. -ban mychannel1,mychannel2= EvilUser : Was banned for spamming.

-
-
-account_caller = False
-
- -
-
-aliases = ['@channels', '@chan']
-
- -
-
-help_category = 'comms'
-
- -
-
-key = '@channel'
-
- -
-
-lock_storage = 'cmd:not pperm(channel_banned);admin:all();manage:all();changelocks:perm(Admin)'
-
- -
-
-search_index_entry = {'aliases': '@channels @chan', 'category': 'comms', 'key': '@channel', 'no_prefix': 'channel channels chan', 'tags': '', 'text': "\n Use and manage in-game channels.\n\n Usage:\n channel channelname <msg>\n channel channel name = <msg>\n channel (show all subscription)\n channel/all (show available channels)\n channel/alias channelname = alias[;alias...]\n channel/unalias alias\n channel/who channelname\n channel/history channelname [= index]\n channel/sub channelname [= alias[;alias...]]\n channel/unsub channelname[,channelname, ...]\n channel/mute channelname[,channelname,...]\n channel/unmute channelname[,channelname,...]\n\n channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n channel/desc channelname = description\n channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n channel/ban channelname (list bans)\n channel/ban[/quiet] channelname[, channelname, ...] = subscribername [: reason]\n channel/unban[/quiet] channelname[, channelname, ...] = subscribername\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n\n # subtopics\n\n ## sending\n\n Usage: channel channelname msg\n channel channel name = msg (with space in channel name)\n\n This sends a message to the channel. Note that you will rarely use this\n command like this; instead you can use the alias\n\n channelname <msg>\n channelalias <msg>\n\n For example\n\n public Hello World\n pub Hello World\n\n (this shortcut doesn't work for aliases containing spaces)\n\n See channel/alias for help on setting channel aliases.\n\n ## alias and unalias\n\n Usage: channel/alias channel = alias[;alias[;alias...]]\n channel/unalias alias\n channel - this will list your subs and aliases to each channel\n\n Set one or more personal aliases for referencing a channel. For example:\n\n channel/alias warrior's guild = warrior;wguild;warchannel;warrior guild\n\n You can now send to the channel using all of these:\n\n warrior's guild Hello\n warrior Hello\n wguild Hello\n warchannel Hello\n\n Note that this will not work if the alias has a space in it. So the\n 'warrior guild' alias must be used with the `channel` command:\n\n channel warrior guild = Hello\n\n Channel-aliases can be removed one at a time, using the '/unalias' switch.\n\n ## who\n\n Usage: channel/who channelname\n\n List the channel's subscribers. Shows who are currently offline or are\n muting the channel. Subscribers who are 'muting' will not see messages sent\n to the channel (use channel/mute to mute a channel).\n\n ## history\n\n Usage: channel/history channel [= index]\n\n This will display the last |c20|n lines of channel history. By supplying an\n index number, you will step that many lines back before viewing those 20 lines.\n\n For example:\n\n channel/history public = 35\n\n will go back 35 lines and show the previous 20 lines from that point (so\n lines -35 to -55).\n\n ## sub and unsub\n\n Usage: channel/sub channel [=alias[;alias;...]]\n channel/unsub channel\n\n This subscribes you to a channel and optionally assigns personal shortcuts\n for you to use to send to that channel (see aliases). When you unsub, all\n your personal aliases will also be removed.\n\n ## mute and unmute\n\n Usage: channel/mute channelname\n channel/unmute channelname\n\n Muting silences all output from the channel without actually\n un-subscribing. Other channel members will see that you are muted in the /who\n list. Sending a message to the channel will automatically unmute you.\n\n ## create and destroy\n\n Usage: channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n\n Creates a new channel (or destroys one you control). You will automatically\n join the channel you create and everyone will be kicked and loose all aliases\n to a destroyed channel.\n\n ## lock and unlock\n\n Usage: channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n\n Note: this is an admin command.\n\n A lockstring is on the form locktype:lockfunc(). Channels understand three\n locktypes:\n listen - who may listen or join the channel.\n send - who may send messages to the channel\n control - who controls the channel. This is usually the one creating\n the channel.\n\n Common lockfuncs are all() and perm(). To make a channel everyone can\n listen to but only builders can talk on, use this:\n\n listen:all()\n send: perm(Builders)\n\n ## boot and ban\n\n Usage:\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n channel/ban channelname[, channelname, ...] = subscribername [: reason]\n channel/unban channelname[, channelname, ...] = subscribername\n channel/unban channelname\n channel/ban channelname (list bans)\n\n Booting will kick a named subscriber from channel(s) temporarily. The\n 'reason' will be passed to the booted user. Unless the /quiet switch is\n used, the channel will also be informed of the action. A booted user is\n still able to re-connect, but they'll have to set up their aliases again.\n\n Banning will blacklist a user from (re)joining the provided channels. It\n will then proceed to boot them from those channels if they were connected.\n The 'reason' and `/quiet` works the same as for booting.\n\n Example:\n boot mychannel1 = EvilUser : Kicking you to cool down a bit.\n ban mychannel1,mychannel2= EvilUser : Was banned for spamming.\n\n "}
-
- -
- -
-
-class evennia.commands.default.comms.CmdPage(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

send a private message to another account

-
-
Usage:

page <account> <message> -page[/switches] [<account>,<account>,… = <message>] -tell ‘’ -page <number>

-
-
Switches:

last - shows who you last messaged -list - show your last <number> of tells/pages (default)

-
-
-

Send a message to target user (if online). If no argument is given, you -will get a list of your latest messages. The equal sign is needed for -multiple targets or if sending to target with space in the name.

-
-
-key = 'page'
-
- -
-
-aliases = ['tell']
-
- -
-
-switch_options = ('last', 'list')
-
- -
-
-locks = 'cmd:not pperm(page_banned)'
-
- -
-
-help_category = 'comms'
-
- -
-
-account_caller = True
-
- -
-
-func()[source]
-

Implement function using the Msg methods

-
- -
-
-lock_storage = 'cmd:not pperm(page_banned)'
-
- -
-
-search_index_entry = {'aliases': 'tell', 'category': 'comms', 'key': 'page', 'no_prefix': ' tell', 'tags': '', 'text': "\n send a private message to another account\n\n Usage:\n page <account> <message>\n page[/switches] [<account>,<account>,... = <message>]\n tell ''\n page <number>\n\n Switches:\n last - shows who you last messaged\n list - show your last <number> of tells/pages (default)\n\n Send a message to target user (if online). If no argument is given, you\n will get a list of your latest messages. The equal sign is needed for\n multiple targets or if sending to target with space in the name.\n\n "}
-
- -
- -
-
-class evennia.commands.default.comms.CmdIRC2Chan(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

Link an evennia channel to an external IRC channel

-
-
Usage:

irc2chan[/switches] <evennia_channel> = <ircnetwork> <port> <#irchannel> <botname>[:typeclass] -irc2chan/delete botname|#dbid

-
-
Switches:
-
/delete
-
    -
  • this will delete the bot and remove the irc connection

  • -
-

to the channel. Requires the botname or #dbid as input.

-
-
/remove
-
    -
  • alias to /delete

  • -
-
-
-

/disconnect - alias to /delete -/list - show all irc<->evennia mappings -/ssl - use an SSL-encrypted connection

-
-
-

Example

-

irc2chan myircchan = irc.dalnet.net 6667 #mychannel evennia-bot -irc2chan public = irc.freenode.net 6667 #evgaming #evbot:accounts.mybot.MyBot

-

This creates an IRC bot that connects to a given IRC network and -channel. If a custom typeclass path is given, this will be used -instead of the default bot class. -The bot will relay everything said in the evennia channel to the -IRC channel and vice versa. The bot will automatically connect at -server start, so this command need only be given once. The -/disconnect switch will permanently delete the bot. To only -temporarily deactivate it, use the |wservices|n command instead. -Provide an optional bot class path to use a custom bot.

-
-
-key = 'irc2chan'
-
- -
-
-switch_options = ('delete', 'remove', 'disconnect', 'list', 'ssl')
-
- -
-
-locks = 'cmd:serversetting(IRC_ENABLED) and pperm(Developer)'
-
- -
-
-help_category = 'comms'
-
- -
-
-func()[source]
-

Setup the irc-channel mapping

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:serversetting(IRC_ENABLED) and pperm(Developer)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'irc2chan', 'no_prefix': ' ', 'tags': '', 'text': '\n Link an evennia channel to an external IRC channel\n\n Usage:\n irc2chan[/switches] <evennia_channel> = <ircnetwork> <port> <#irchannel> <botname>[:typeclass]\n irc2chan/delete botname|#dbid\n\n Switches:\n /delete - this will delete the bot and remove the irc connection\n to the channel. Requires the botname or #dbid as input.\n /remove - alias to /delete\n /disconnect - alias to /delete\n /list - show all irc<->evennia mappings\n /ssl - use an SSL-encrypted connection\n\n Example:\n irc2chan myircchan = irc.dalnet.net 6667 #mychannel evennia-bot\n irc2chan public = irc.freenode.net 6667 #evgaming #evbot:accounts.mybot.MyBot\n\n This creates an IRC bot that connects to a given IRC network and\n channel. If a custom typeclass path is given, this will be used\n instead of the default bot class.\n The bot will relay everything said in the evennia channel to the\n IRC channel and vice versa. The bot will automatically connect at\n server start, so this command need only be given once. The\n /disconnect switch will permanently delete the bot. To only\n temporarily deactivate it, use the |wservices|n command instead.\n Provide an optional bot class path to use a custom bot.\n '}
-
- -
- -
-
-class evennia.commands.default.comms.CmdIRCStatus(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

Check and reboot IRC bot.

-
-
Usage:

ircstatus [#dbref ping | nicklist | reconnect]

-
-
-

If not given arguments, will return a list of all bots (like -irc2chan/list). The ‘ping’ argument will ping the IRC network to -see if the connection is still responsive. The ‘nicklist’ argument -(aliases are ‘who’ and ‘users’) will return a list of users on the -remote IRC channel. Finally, ‘reconnect’ will force the client to -disconnect and reconnect again. This may be a last resort if the -client has silently lost connection (this may happen if the remote -network experience network issues). During the reconnection -messages sent to either channel will be lost.

-
-
-key = 'ircstatus'
-
- -
-
-locks = 'cmd:serversetting(IRC_ENABLED) and perm(ircstatus) or perm(Builder))'
-
- -
-
-help_category = 'comms'
-
- -
-
-func()[source]
-

Handles the functioning of the command.

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:serversetting(IRC_ENABLED) and perm(ircstatus) or perm(Builder))'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'ircstatus', 'no_prefix': ' ', 'tags': '', 'text': "\n Check and reboot IRC bot.\n\n Usage:\n ircstatus [#dbref ping | nicklist | reconnect]\n\n If not given arguments, will return a list of all bots (like\n irc2chan/list). The 'ping' argument will ping the IRC network to\n see if the connection is still responsive. The 'nicklist' argument\n (aliases are 'who' and 'users') will return a list of users on the\n remote IRC channel. Finally, 'reconnect' will force the client to\n disconnect and reconnect again. This may be a last resort if the\n client has silently lost connection (this may happen if the remote\n network experience network issues). During the reconnection\n messages sent to either channel will be lost.\n\n "}
-
- -
- -
-
-class evennia.commands.default.comms.CmdRSS2Chan(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

link an evennia channel to an external RSS feed

-
-
Usage:

rss2chan[/switches] <evennia_channel> = <rss_url>

-
-
Switches:
-
/disconnect - this will stop the feed and remove the connection to the

channel.

-
-
-
-
/remove
-
    -
  • -
-
-
/list
-
    -
  • show all rss->evennia mappings

  • -
-
-
-
-
-

Example

-

rss2chan rsschan = http://code.google.com/feeds/p/evennia/updates/basic

-

This creates an RSS reader that connects to a given RSS feed url. Updates -will be echoed as a title and news link to the given channel. The rate of -updating is set with the RSS_UPDATE_INTERVAL variable in settings (default -is every 10 minutes).

-

When disconnecting you need to supply both the channel and url again so as -to identify the connection uniquely.

-
-
-key = 'rss2chan'
-
- -
-
-switch_options = ('disconnect', 'remove', 'list')
-
- -
-
-locks = 'cmd:serversetting(RSS_ENABLED) and pperm(Developer)'
-
- -
-
-help_category = 'comms'
-
- -
-
-func()[source]
-

Setup the rss-channel mapping

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:serversetting(RSS_ENABLED) and pperm(Developer)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'rss2chan', 'no_prefix': ' ', 'tags': '', 'text': '\n link an evennia channel to an external RSS feed\n\n Usage:\n rss2chan[/switches] <evennia_channel> = <rss_url>\n\n Switches:\n /disconnect - this will stop the feed and remove the connection to the\n channel.\n /remove - "\n /list - show all rss->evennia mappings\n\n Example:\n rss2chan rsschan = http://code.google.com/feeds/p/evennia/updates/basic\n\n This creates an RSS reader that connects to a given RSS feed url. Updates\n will be echoed as a title and news link to the given channel. The rate of\n updating is set with the RSS_UPDATE_INTERVAL variable in settings (default\n is every 10 minutes).\n\n When disconnecting you need to supply both the channel and url again so as\n to identify the connection uniquely.\n '}
-
- -
- -
-
-class evennia.commands.default.comms.CmdGrapevine2Chan(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

Link an Evennia channel to an exteral Grapevine channel

-
-
Usage:

grapevine2chan[/switches] <evennia_channel> = <grapevine_channel> -grapevine2chan/disconnect <connection #id>

-
-
Switches:
-
/list
-
    -
  • (or no switch): show existing grapevine <-> Evennia

  • -
-

mappings and available grapevine chans

-
-
/remove
-
    -
  • alias to disconnect

  • -
-
-
/delete
-
    -
  • alias to disconnect

  • -
-
-
-
-
-

Example

-

grapevine2chan mygrapevine = gossip

-

This creates a link between an in-game Evennia channel and an external -Grapevine channel. The game must be registered with the Grapevine network -(register at https://grapevine.haus) and the GRAPEVINE_* auth information -must be added to game settings.

-
-
-key = 'grapevine2chan'
-
- -
-
-switch_options = ('disconnect', 'remove', 'delete', 'list')
-
- -
-
-locks = 'cmd:serversetting(GRAPEVINE_ENABLED) and pperm(Developer)'
-
- -
-
-help_category = 'comms'
-
- -
-
-func()[source]
-

Setup the Grapevine channel mapping

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:serversetting(GRAPEVINE_ENABLED) and pperm(Developer)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'comms', 'key': 'grapevine2chan', 'no_prefix': ' ', 'tags': '', 'text': '\n Link an Evennia channel to an exteral Grapevine channel\n\n Usage:\n grapevine2chan[/switches] <evennia_channel> = <grapevine_channel>\n grapevine2chan/disconnect <connection #id>\n\n Switches:\n /list - (or no switch): show existing grapevine <-> Evennia\n mappings and available grapevine chans\n /remove - alias to disconnect\n /delete - alias to disconnect\n\n Example:\n grapevine2chan mygrapevine = gossip\n\n This creates a link between an in-game Evennia channel and an external\n Grapevine channel. The game must be registered with the Grapevine network\n (register at https://grapevine.haus) and the GRAPEVINE_* auth information\n must be added to game settings.\n '}
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.default.general.html b/docs/0.9.5/api/evennia.commands.default.general.html deleted file mode 100644 index 1f61cf2d64..0000000000 --- a/docs/0.9.5/api/evennia.commands.default.general.html +++ /dev/null @@ -1,818 +0,0 @@ - - - - - - - - - evennia.commands.default.general — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.commands.default.general

-

General Character commands usually available to all characters

-
-
-class evennia.commands.default.general.CmdHome(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

move to your character’s home location

-
-
Usage:

home

-
-
-

Teleports you to your home location.

-
-
-key = 'home'
-
- -
-
-locks = 'cmd:perm(home) or perm(Builder)'
-
- -
-
-arg_regex = re.compile('$', re.IGNORECASE)
-
- -
-
-func()[source]
-

Implement the command

-
- -
-
-aliases = []
-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:perm(home) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': 'home', 'no_prefix': ' ', 'tags': '', 'text': "\n move to your character's home location\n\n Usage:\n home\n\n Teleports you to your home location.\n "}
-
- -
- -
-
-class evennia.commands.default.general.CmdLook(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

look at location or object

-
-
Usage:

look -look <obj> -look *<account>

-
-
-

Observes your location or objects in your vicinity.

-
-
-key = 'look'
-
- -
-
-aliases = ['l', 'ls']
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-arg_regex = re.compile('\\s|$', re.IGNORECASE)
-
- -
-
-func()[source]
-

Handle the looking.

-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': 'l ls', 'category': 'general', 'key': 'look', 'no_prefix': ' l ls', 'tags': '', 'text': '\n look at location or object\n\n Usage:\n look\n look <obj>\n look *<account>\n\n Observes your location or objects in your vicinity.\n '}
-
- -
- -
-
-class evennia.commands.default.general.CmdNick(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

define a personal alias/nick by defining a string to -match and replace it with another on the fly

-
-
Usage:

nick[/switches] <string> [= [replacement_string]] -nick[/switches] <template> = <replacement_template> -nick/delete <string> or number -nicks

-
-
Switches:

inputline - replace on the inputline (default) -object - replace on object-lookup -account - replace on account-lookup -list - show all defined aliases (also “nicks” works) -delete - remove nick by index in /list -clearall - clear all nicks

-
-
-

Examples

-

nick hi = say Hello, I’m Sarah! -nick/object tom = the tall man -nick build $1 $2 = create/drop $1;$2 -nick tell $1 $2=page $1=$2 -nick tm?$1=page tallman=$1 -nick tm=$1=page tallman=$1

-

A ‘nick’ is a personal string replacement. Use $1, $2, … to catch arguments. -Put the last $-marker without an ending space to catch all remaining text. You -can also use unix-glob matching for the left-hand side <string>:

-
-
    -
    • -
    • matches everything

    • -
    -
  • -
-

? - matches 0 or 1 single characters -[abcd] - matches these chars in any order -[!abcd] - matches everything not among these chars -= - escape literal ‘=’ you want in your <string>

-
-

Note that no objects are actually renamed or changed by this command - your nicks -are only available to you. If you want to permanently add keywords to an object -for everyone to use, you need build privileges and the alias command.

-
-
-key = 'nick'
-
- -
-
-switch_options = ('inputline', 'object', 'account', 'list', 'delete', 'clearall')
-
- -
-
-aliases = ['nicks', 'nickname']
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-parse()[source]
-

Support escaping of = with =

-
- -
-
-func()[source]
-

Create the nickname

-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': 'nicks nickname', 'category': 'general', 'key': 'nick', 'no_prefix': ' nicks nickname', 'tags': '', 'text': '\n define a personal alias/nick by defining a string to\n match and replace it with another on the fly\n\n Usage:\n nick[/switches] <string> [= [replacement_string]]\n nick[/switches] <template> = <replacement_template>\n nick/delete <string> or number\n nicks\n\n Switches:\n inputline - replace on the inputline (default)\n object - replace on object-lookup\n account - replace on account-lookup\n list - show all defined aliases (also "nicks" works)\n delete - remove nick by index in /list\n clearall - clear all nicks\n\n Examples:\n nick hi = say Hello, I\'m Sarah!\n nick/object tom = the tall man\n nick build $1 $2 = create/drop $1;$2\n nick tell $1 $2=page $1=$2\n nick tm?$1=page tallman=$1\n nick tm\\=$1=page tallman=$1\n\n A \'nick\' is a personal string replacement. Use $1, $2, ... to catch arguments.\n Put the last $-marker without an ending space to catch all remaining text. You\n can also use unix-glob matching for the left-hand side <string>:\n\n * - matches everything\n ? - matches 0 or 1 single characters\n [abcd] - matches these chars in any order\n [!abcd] - matches everything not among these chars\n \\= - escape literal \'=\' you want in your <string>\n\n Note that no objects are actually renamed or changed by this command - your nicks\n are only available to you. If you want to permanently add keywords to an object\n for everyone to use, you need build privileges and the alias command.\n\n '}
-
- -
- -
-
-class evennia.commands.default.general.CmdInventory(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

view inventory

-
-
Usage:

inventory -inv

-
-
-

Shows your inventory.

-
-
-key = 'inventory'
-
- -
-
-aliases = ['i', 'inv']
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-arg_regex = re.compile('$', re.IGNORECASE)
-
- -
-
-func()[source]
-

check inventory

-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': 'i inv', 'category': 'general', 'key': 'inventory', 'no_prefix': ' i inv', 'tags': '', 'text': '\n view inventory\n\n Usage:\n inventory\n inv\n\n Shows your inventory.\n '}
-
- -
- -
-
-class evennia.commands.default.general.CmdSetDesc(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

describe yourself

-
-
Usage:

setdesc <description>

-
-
-

Add a description to yourself. This -will be visible to people when they -look at you.

-
-
-key = 'setdesc'
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-arg_regex = re.compile('\\s|$', re.IGNORECASE)
-
- -
-
-func()[source]
-

add the description

-
- -
-
-aliases = []
-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': 'setdesc', 'no_prefix': ' ', 'tags': '', 'text': '\n describe yourself\n\n Usage:\n setdesc <description>\n\n Add a description to yourself. This\n will be visible to people when they\n look at you.\n '}
-
- -
- -
-
-class evennia.commands.default.general.CmdGet(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

pick up something

-
-
Usage:

get <obj>

-
-
-

Picks up an object from your location and puts it in -your inventory.

-
-
-key = 'get'
-
- -
-
-aliases = ['grab']
-
- -
-
-locks = 'cmd:all();view:perm(Developer);read:perm(Developer)'
-
- -
-
-arg_regex = re.compile('\\s|$', re.IGNORECASE)
-
- -
-
-func()[source]
-

implements the command.

-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all();view:perm(Developer);read:perm(Developer)'
-
- -
-
-search_index_entry = {'aliases': 'grab', 'category': 'general', 'key': 'get', 'no_prefix': ' grab', 'tags': '', 'text': '\n pick up something\n\n Usage:\n get <obj>\n\n Picks up an object from your location and puts it in\n your inventory.\n '}
-
- -
- -
-
-class evennia.commands.default.general.CmdDrop(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

drop something

-
-
Usage:

drop <obj>

-
-
-

Lets you drop an object from your inventory into the -location you are currently in.

-
-
-key = 'drop'
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-arg_regex = re.compile('\\s|$', re.IGNORECASE)
-
- -
-
-func()[source]
-

Implement command

-
- -
-
-aliases = []
-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': 'drop', 'no_prefix': ' ', 'tags': '', 'text': '\n drop something\n\n Usage:\n drop <obj>\n\n Lets you drop an object from your inventory into the\n location you are currently in.\n '}
-
- -
- -
-
-class evennia.commands.default.general.CmdGive(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

give away something to someone

-
-
Usage:

give <inventory obj> <to||=> <target>

-
-
-

Gives an items from your inventory to another character, -placing it in their inventory.

-
-
-key = 'give'
-
- -
-
-rhs_split = ('=', ' to ')
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-arg_regex = re.compile('\\s|$', re.IGNORECASE)
-
- -
-
-func()[source]
-

Implement give

-
- -
-
-aliases = []
-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': 'give', 'no_prefix': ' ', 'tags': '', 'text': '\n give away something to someone\n\n Usage:\n give <inventory obj> <to||=> <target>\n\n Gives an items from your inventory to another character,\n placing it in their inventory.\n '}
-
- -
- -
-
-class evennia.commands.default.general.CmdSay(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

speak as your character

-
-
Usage:

say <message>

-
-
-

Talk to those in your current location.

-
-
-key = 'say'
-
- -
-
-aliases = ["'", '"']
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-arg_regex = None
-
- -
-
-func()[source]
-

Run the say command

-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': '\' "', 'category': 'general', 'key': 'say', 'no_prefix': ' \' "', 'tags': '', 'text': '\n speak as your character\n\n Usage:\n say <message>\n\n Talk to those in your current location.\n '}
-
- -
- -
-
-class evennia.commands.default.general.CmdWhisper(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

Speak privately as your character to another

-
-
Usage:

whisper <character> = <message> -whisper <char1>, <char2> = <message>

-
-
-

Talk privately to one or more characters in your current location, without -others in the room being informed.

-
-
-key = 'whisper'
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-func()[source]
-

Run the whisper command

-
- -
-
-aliases = []
-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': 'whisper', 'no_prefix': ' ', 'tags': '', 'text': '\n Speak privately as your character to another\n\n Usage:\n whisper <character> = <message>\n whisper <char1>, <char2> = <message>\n\n Talk privately to one or more characters in your current location, without\n others in the room being informed.\n '}
-
- -
- -
-
-class evennia.commands.default.general.CmdPose(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

strike a pose

-
-
Usage:

pose <pose text> -pose’s <pose text>

-
-
-

Example

-
-
pose is standing by the wall, smiling.

-> others will see:

-
-
-

Tom is standing by the wall, smiling.

-

Describe an action being taken. The pose text will -automatically begin with your name.

-
-
-key = 'pose'
-
- -
-
-aliases = ['emote', ':']
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-arg_regex = None
-
- -
-
-parse()[source]
-

Custom parse the cases where the emote -starts with some special letter, such -as ‘s, at which we don’t want to separate -the caller’s name and the emote with a -space.

-
- -
-
-func()[source]
-

Hook function

-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': 'emote :', 'category': 'general', 'key': 'pose', 'no_prefix': ' emote :', 'tags': '', 'text': "\n strike a pose\n\n Usage:\n pose <pose text>\n pose's <pose text>\n\n Example:\n pose is standing by the wall, smiling.\n -> others will see:\n Tom is standing by the wall, smiling.\n\n Describe an action being taken. The pose text will\n automatically begin with your name.\n "}
-
- -
- -
-
-class evennia.commands.default.general.CmdAccess(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

show your current game access

-
-
Usage:

access

-
-
-

This command shows you the permission hierarchy and -which permission groups you are a member of.

-
-
-key = 'access'
-
- -
-
-aliases = ['hierarchy', 'groups']
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-arg_regex = re.compile('$', re.IGNORECASE)
-
- -
-
-func()[source]
-

Load the permission groups

-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': 'hierarchy groups', 'category': 'general', 'key': 'access', 'no_prefix': ' hierarchy groups', 'tags': '', 'text': '\n show your current game access\n\n Usage:\n access\n\n This command shows you the permission hierarchy and\n which permission groups you are a member of.\n '}
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.default.help.html b/docs/0.9.5/api/evennia.commands.default.help.html deleted file mode 100644 index a060bdce11..0000000000 --- a/docs/0.9.5/api/evennia.commands.default.help.html +++ /dev/null @@ -1,514 +0,0 @@ - - - - - - - - - evennia.commands.default.help — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.commands.default.help

-

The help command. The basic idea is that help texts for commands are best -written by those that write the commands - the developers. So command-help is -all auto-loaded and searched from the current command set. The normal, -database-tied help system is used for collaborative creation of other help -topics such as RP help or game-world aides. Help entries can also be created -outside the game in modules given by **settings.FILE_HELP_ENTRY_MODULES**.

-
-
-class evennia.commands.default.help.CmdHelp(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

Get help.

-
-
Usage:

help -help <topic, command or category> -help <topic>/<subtopic> -help <topic>/<subtopic>/<subsubtopic> …

-
-
-

Use the ‘help’ command alone to see an index of all help topics, organized -by category.eSome big topics may offer additional sub-topics.

-
-
-key = 'help'
-
- -
-
-aliases = ['?']
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-arg_regex = re.compile('\\s|$', re.IGNORECASE)
-
- -
-
-return_cmdset = True
-
- -
-
-help_more = True
-
- -
-
-index_type_separator_clr = '|w'
-
- -
-
-index_category_clr = '|W'
-
- -
-
-index_topic_clr = '|G'
-
- -
-
-suggestion_cutoff = 0.6
-
- -
-
-suggestion_maxnum = 5
-
- -
-
-subtopic_separator_char = '/'
-
- -
-
-clickable_topics = True
-
- -
-
-msg_help(text)[source]
-

messages text to the caller, adding an extra oob argument to indicate -that this is a help command result and could be rendered in a separate -help window

-
- -
-
-format_help_entry(topic='', help_text='', aliases=None, suggested=None, subtopics=None, click_topics=True)[source]
-

This visually formats the help entry. -This method can be overriden to customize the way a help -entry is displayed.

-
-
Parameters
-
    -
  • title (str, optional) – The title of the help entry.

  • -
  • help_text (str, optional) – Text of the help entry.

  • -
  • aliases (list, optional) – List of help-aliases (displayed in header).

  • -
  • suggested (list, optional) – Strings suggested reading (based on title).

  • -
  • subtopics (list, optional) – A list of strings - the subcategories available -for this entry.

  • -
  • click_topics (bool, optional) – Should help topics be clickable. Default is True.

  • -
-
-
Returns
-

help_message (str) – Help entry formated for console.

-
-
-
- -
-
-format_help_index(cmd_help_dict=None, db_help_dict=None, title_lone_category=False, click_topics=True)[source]
-

Output a category-ordered g for displaying the main help, grouped by -category.

-
-
Parameters
-
    -
  • cmd_help_dict (dict) – A dict {“category”: [topic, topic, …]} for -command-based help.

  • -
  • db_help_dict (dict) – A dict {“category”: [topic, topic], …]} for -database-based help.

  • -
  • title_lone_category (bool, optional) – If a lone category should -be titled with the category name or not. While pointless in a -general index, the title should probably show when explicitly -listing the category itself.

  • -
  • click_topics (bool, optional) – If help-topics are clickable or not -(for webclient or telnet clients with MXP support).

  • -
-
-
Returns
-

str – The help index organized into a grid.

-
-
-

Notes

-

The input are the pre-loaded help files for commands and database-helpfiles -respectively. You can override this method to return a custom display of the list of -commands and topics.

-
- -
-
-can_read_topic(cmd_or_topic, caller)[source]
-

Helper method. If this return True, the given help topic -be viewable in the help listing. Note that even if this returns False, -the entry will still be visible in the help index unless should_list_topic -is also returning False.

-
-
Parameters
-
    -
  • cmd_or_topic (Command, HelpEntry or FileHelpEntry) – The topic/command to test.

  • -
  • caller – the caller checking for access.

  • -
-
-
Returns
-

bool – If command can be viewed or not.

-
-
-

Notes

-

This uses the ‘read’ lock. If no ‘read’ lock is defined, the topic is assumed readable -by all.

-
- -
-
-can_list_topic(cmd_or_topic, caller)[source]
-

Should the specified command appear in the help table?

-

This method only checks whether a specified command should appear in the table of -topics/commands. The command can be used by the caller (see the ‘should_show_help’ method) -and the command will still be available, for instance, if a character type ‘help name of the -command’. However, if you return False, the specified command will not appear in the table. -This is sometimes useful to “hide” commands in the table, but still access them through the -help system.

-
-
Parameters
-
    -
  • cmd_or_topic (Command, HelpEntry or FileHelpEntry) – The topic/command to test.

  • -
  • caller – the caller checking for access.

  • -
-
-
Returns
-

bool – If command should be listed or not.

-
-
-

Notes

-

The .auto_help propery is checked for commands. For all help entries, -the ‘view’ lock will be checked, and if no such lock is defined, the ‘read’ -lock will be used. If neither lock is defined, the help entry is assumed to be -accessible to all.

-
- -
-
-collect_topics(caller, mode='list')[source]
-

Collect help topics from all sources (cmd/db/file).

-
-
Parameters
-
    -
  • caller (Object or Account) – The user of the Command.

  • -
  • mode (str) – One of ‘list’ or ‘query’, where the first means we are collecting to view -the help index and the second because of wanting to search for a specific help -entry/cmd to read. This determines which access should be checked.

  • -
-
-
Returns
-

tuple – A tuple of three dicts containing the different types of help entries -in the order cmd-help, db-help, file-help:

-
-

({key: cmd,…}, {key: dbentry,…}, {key: fileentry,…}

-
-

-
-
-
- -
- -

Perform a help-query search, default using Lunr search engine.

-
-
Parameters
-
    -
  • query (str) – The help entry to search for.

  • -
  • entries (list) – All possibilities. A mix of commands, HelpEntries and FileHelpEntries.

  • -
  • search_fields (list) – A list of dicts defining how Lunr will find the -search data on the elements. If not given, will use a default.

  • -
-
-
Returns
-

tuple – A tuple (match, suggestions).

-
-
-
- -
-
-parse()[source]
-

input is a string containing the command or topic to match.

-

The allowed syntax is

-
help <topic>[/<subtopic>[/<subtopic>[/...]]]
-
-
-

The database/command query is always for <topic>, and any subtopics -is then parsed from there. If a <topic> has spaces in it, it is -always matched before assuming the space begins a subtopic.

-
- -
-
-strip_cmd_prefix(key, all_keys)[source]
-

Conditional strip of a command prefix, such as @ in @desc. By default -this will be hidden unless there is a duplicate without the prefix -in the full command set (such as @open and open).

-
-
Parameters
-
    -
  • key (str) – Command key to analyze.

  • -
  • all_cmds (list) – All command-keys (and potentially aliases).

  • -
-
-
Returns
-

str – Potentially modified key to use in help display.

-
-
-
- -
-
-func()[source]
-

Run the dynamic help entry creator.

-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': '?', 'category': 'general', 'key': 'help', 'no_prefix': ' ?', 'tags': '', 'text': "\n Get help.\n\n Usage:\n help\n help <topic, command or category>\n help <topic>/<subtopic>\n help <topic>/<subtopic>/<subsubtopic> ...\n\n Use the 'help' command alone to see an index of all help topics, organized\n by category.eSome big topics may offer additional sub-topics.\n\n "}
-
- -
- -
-
-class evennia.commands.default.help.CmdSetHelp(**kwargs)[source]
-

Bases: evennia.commands.default.help.CmdHelp

-

Edit the help database.

-
-
Usage:

sethelp[/switches] <topic>[[;alias;alias][,category[,locks]] [= <text>]

-
-
Switches:

edit - open a line editor to edit the topic’s help text. -replace - overwrite existing help topic. -append - add text to the end of existing topic with a newline between. -extend - as append, but don’t add a newline. -delete - remove help topic.

-
-
-

Examples

-

sethelp lore = In the beginning was … -sethelp/append pickpocketing,Thievery = This steals … -sethelp/replace pickpocketing, ,attr(is_thief) = This steals … -sethelp/edit thievery

-

If not assigning a category, the settings.DEFAULT_HELP_CATEGORY category -will be used. If no lockstring is specified, everyone will be able to read -the help entry. Sub-topics are embedded in the help text.

-

Note that this cannot modify command-help entries - these are modified -in-code, outside the game.

-

Subtopics helps to break up a long help entry into sub-sections. Users can -access subtopics with |whelp topic/subtopic/…|n Subtopics are created and -stored together with the main topic.

-

To start adding subtopics, add the text ‘# SUBTOPICS’ on a new line at the -end of your help text. After this you can now add any number of subtopics, -each starting with ‘## <subtopic-name>’ on a line, followed by the -help-text of that subtopic. -Use ‘### <subsub-name>’ to add a sub-subtopic and so on. Max depth is 5. A -subtopic’s title is case-insensitive and can consist of multiple words - -the user will be able to enter a partial match to access it.

-

For example:

-
-
Main help text for <topic>
-

-
# SUBTOPICS
-

-
## about
-

-
Text for the ‘<topic>/about’ subtopic’
-

-
### more about-info
-

-
Text for the ‘<topic>/about/more about-info sub-subtopic
-

-
## extra
-

-
Text for the ‘<topic>/extra’ subtopic
-
-
-
-key = 'sethelp'
-
- -
-
-aliases = []
-
- -
-
-switch_options = ('edit', 'replace', 'append', 'extend', 'delete')
-
- -
-
-locks = 'cmd:perm(Helper)'
-
- -
-
-help_category = 'building'
-
- -
-
-arg_regex = None
-
- -
-
-parse()[source]
-

We want to use the default parser rather than the CmdHelp.parse

-
- -
-
-func()[source]
-

Implement the function

-
- -
-
-lock_storage = 'cmd:perm(Helper)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'building', 'key': 'sethelp', 'no_prefix': ' ', 'tags': '', 'text': "\n Edit the help database.\n\n Usage:\n sethelp[/switches] <topic>[[;alias;alias][,category[,locks]] [= <text>]\n\n Switches:\n edit - open a line editor to edit the topic's help text.\n replace - overwrite existing help topic.\n append - add text to the end of existing topic with a newline between.\n extend - as append, but don't add a newline.\n delete - remove help topic.\n\n Examples:\n sethelp lore = In the beginning was ...\n sethelp/append pickpocketing,Thievery = This steals ...\n sethelp/replace pickpocketing, ,attr(is_thief) = This steals ...\n sethelp/edit thievery\n\n If not assigning a category, the `settings.DEFAULT_HELP_CATEGORY` category\n will be used. If no lockstring is specified, everyone will be able to read\n the help entry. Sub-topics are embedded in the help text.\n\n Note that this cannot modify command-help entries - these are modified\n in-code, outside the game.\n\n # SUBTOPICS\n\n ## Adding subtopics\n\n Subtopics helps to break up a long help entry into sub-sections. Users can\n access subtopics with |whelp topic/subtopic/...|n Subtopics are created and\n stored together with the main topic.\n\n To start adding subtopics, add the text '# SUBTOPICS' on a new line at the\n end of your help text. After this you can now add any number of subtopics,\n each starting with '## <subtopic-name>' on a line, followed by the\n help-text of that subtopic.\n Use '### <subsub-name>' to add a sub-subtopic and so on. Max depth is 5. A\n subtopic's title is case-insensitive and can consist of multiple words -\n the user will be able to enter a partial match to access it.\n\n For example:\n\n | Main help text for <topic>\n |\n | # SUBTOPICS\n |\n | ## about\n |\n | Text for the '<topic>/about' subtopic'\n |\n | ### more about-info\n |\n | Text for the '<topic>/about/more about-info sub-subtopic\n |\n | ## extra\n |\n | Text for the '<topic>/extra' subtopic\n\n "}
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.default.html b/docs/0.9.5/api/evennia.commands.default.html deleted file mode 100644 index e382c7846a..0000000000 --- a/docs/0.9.5/api/evennia.commands.default.html +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - - - - evennia.commands.default — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.default.muxcommand.html b/docs/0.9.5/api/evennia.commands.default.muxcommand.html deleted file mode 100644 index ecb039b107..0000000000 --- a/docs/0.9.5/api/evennia.commands.default.muxcommand.html +++ /dev/null @@ -1,308 +0,0 @@ - - - - - - - - - evennia.commands.default.muxcommand — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.commands.default.muxcommand

-

The command template for the default MUX-style command set. There -is also an Account/OOC version that makes sure caller is an Account object.

-
-
-class evennia.commands.default.muxcommand.MuxCommand(**kwargs)[source]
-

Bases: evennia.commands.command.Command

-

This sets up the basis for a MUX command. The idea -is that most other Mux-related commands should just -inherit from this and don’t have to implement much -parsing of their own unless they do something particularly -advanced.

-

Note that the class’s __doc__ string (this text) is -used by Evennia to create the automatic help entry for -the command, so make sure to document consistently here.

-
-
-has_perm(srcobj)[source]
-

This is called by the cmdhandler to determine -if srcobj is allowed to execute this command. -We just show it here for completeness - we -are satisfied using the default check in Command.

-
- -
-
-at_pre_cmd()[source]
-

This hook is called before self.parse() on all commands

-
- -
-
-at_post_cmd()[source]
-

This hook is called after the command has finished executing -(after self.func()).

-
- -
-
-parse()[source]
-

This method is called by the cmdhandler once the command name -has been identified. It creates a new set of member variables -that can be later accessed from self.func() (see below)

-

The following variables are available for our use when entering this -method (from the command definition, and assigned on the fly by the -cmdhandler):

-
-

self.key - the name of this command (‘look’) -self.aliases - the aliases of this cmd (‘l’) -self.permissions - permission string for this command -self.help_category - overall category of command

-

self.caller - the object calling this command -self.cmdstring - the actual command name used to call this

-
-
-
(this allows you to know which alias was used,

for example)

-
-
-
-

self.args - the raw input; everything following self.cmdstring. -self.cmdset - the cmdset from which this command was picked. Not

-
-

often used (useful for commands like ‘help’ or to -list all available commands etc)

-
-
-
self.obj - the object on which this command was defined. It is often

the same as self.caller.

-
-
-
-

A MUX command has the following possible syntax:

-
-

name[ with several words][/switch[/switch..]] arg1[,arg2,…] [[=|,] arg[,..]]

-
-

The ‘name[ with several words]’ part is already dealt with by the -cmdhandler at this point, and stored in self.cmdname (we don’t use -it here). The rest of the command is stored in self.args, which can -start with the switch indicator /.

-
-
Optional variables to aid in parsing, if set:
-
self.switch_options - (tuple of valid /switches expected by this

command (without the /))

-
-
self.rhs_split - Alternate string delimiter or tuple of strings

to separate left/right hand sides. tuple form -gives priority split to first string delimiter.

-
-
-
-
-

This parser breaks self.args into its constituents and stores them in the -following variables:

-
-

self.switches = [list of /switches (without the /)] -self.raw = This is the raw argument input, including switches -self.args = This is re-defined to be everything except the switches -self.lhs = Everything to the left of = (lhs:’left-hand side’). If

-
-

no = is found, this is identical to self.args.

-
-
-
self.rhs: Everything to the right of = (rhs:’right-hand side’).

If no ‘=’ is found, this is None.

-
-
-

self.lhslist - [self.lhs split into a list by comma] -self.rhslist - [list of self.rhs split into a list by comma] -self.arglist = [list of space-separated args (stripped, including ‘=’ if it exists)]

-

All args and list members are stripped of excess whitespace around the -strings, but case is preserved.

-
-
- -
-
-get_command_info()[source]
-

Update of parent class’s get_command_info() for MuxCommand.

-
- -
-
-func()[source]
-
-
This is the hook function that actually does all the work. It is called

by the cmdhandler right after self.parser() finishes, and so has access -to all the variables defined therein.

-
-
-
- -
-
-aliases = []
-
- -
-
-help_category = 'general'
-
- -
-
-key = 'command'
-
- -
-
-lock_storage = 'cmd:all();'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'no_prefix': ' ', 'tags': '', 'text': "\n This sets up the basis for a MUX command. The idea\n is that most other Mux-related commands should just\n inherit from this and don't have to implement much\n parsing of their own unless they do something particularly\n advanced.\n\n Note that the class's __doc__ string (this text) is\n used by Evennia to create the automatic help entry for\n the command, so make sure to document consistently here.\n "}
-
- -
- -
-
-class evennia.commands.default.muxcommand.MuxAccountCommand(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

This is an on-Account version of the MuxCommand. Since these commands sit -on Accounts rather than on Characters/Objects, we need to check -this in the parser.

-

Account commands are available also when puppeting a Character, it’s -just that they are applied with a lower priority and are always -available, also when disconnected from a character (i.e. “ooc”).

-

This class makes sure that caller is always an Account object, while -creating a new property “character” that is set only if a -character is actually attached to this Account and Session.

-
-
-account_caller = True
-
- -
-
-aliases = []
-
- -
-
-help_category = 'general'
-
- -
-
-key = 'command'
-
- -
-
-lock_storage = 'cmd:all();'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'no_prefix': ' ', 'tags': '', 'text': '\n This is an on-Account version of the MuxCommand. Since these commands sit\n on Accounts rather than on Characters/Objects, we need to check\n this in the parser.\n\n Account commands are available also when puppeting a Character, it\'s\n just that they are applied with a lower priority and are always\n available, also when disconnected from a character (i.e. "ooc").\n\n This class makes sure that caller is always an Account object, while\n creating a new property "character" that is set only if a\n character is actually attached to this Account and Session.\n '}
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.default.syscommands.html b/docs/0.9.5/api/evennia.commands.default.syscommands.html deleted file mode 100644 index c586bd1326..0000000000 --- a/docs/0.9.5/api/evennia.commands.default.syscommands.html +++ /dev/null @@ -1,264 +0,0 @@ - - - - - - - - - evennia.commands.default.syscommands — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.commands.default.syscommands

-

System commands

-

These are the default commands called by the system commandhandler -when various exceptions occur. If one of these commands are not -implemented and part of the current cmdset, the engine falls back -to a default solution instead.

-

Some system commands are shown in this module -as a REFERENCE only (they are not all added to Evennia’s -default cmdset since they don’t currently do anything differently from the -default backup systems hard-wired in the engine).

-

Overloading these commands in a cmdset can be used to create -interesting effects. An example is using the NoMatch system command -to implement a line-editor where you don’t have to start each -line with a command (if there is no match to a known command, -the line is just added to the editor buffer).

-
-
-class evennia.commands.default.syscommands.SystemNoInput(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

This is called when there is no input given

-
-
-key = '__noinput_command'
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-func()[source]
-

Do nothing.

-
- -
-
-aliases = []
-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': '__noinput_command', 'no_prefix': ' ', 'tags': '', 'text': '\n This is called when there is no input given\n '}
-
- -
- -
-
-class evennia.commands.default.syscommands.SystemNoMatch(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

No command was found matching the given input.

-
-
-key = '__nomatch_command'
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-func()[source]
-

This is given the failed raw string as input.

-
- -
-
-aliases = []
-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': '__nomatch_command', 'no_prefix': ' ', 'tags': '', 'text': '\n No command was found matching the given input.\n '}
-
- -
- -
-
-class evennia.commands.default.syscommands.SystemMultimatch(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

Multiple command matches.

-

The cmdhandler adds a special attribute ‘matches’ to this -system command.

-
-

matches = [(cmdname, args, cmdobj, cmdlen, mratio, raw_cmdname) , (cmdname, …), …]

-
-

Here, cmdname is the command’s name and args the rest of the incoming string, -without said command name. cmdobj is the Command instance, the cmdlen is -the same as len(cmdname) and mratio is a measure of how big a part of the -full input string the cmdname takes up - an exact match would be 1.0. Finally, -the raw_cmdname is the cmdname unmodified by eventual prefix-stripping.

-
-
-key = '__multimatch_command'
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-func()[source]
-

Handle multiple-matches by using the at_search_result default handler.

-
- -
-
-aliases = []
-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': '__multimatch_command', 'no_prefix': ' ', 'tags': '', 'text': "\n Multiple command matches.\n\n The cmdhandler adds a special attribute 'matches' to this\n system command.\n\n matches = [(cmdname, args, cmdobj, cmdlen, mratio, raw_cmdname) , (cmdname, ...), ...]\n\n Here, `cmdname` is the command's name and `args` the rest of the incoming string,\n without said command name. `cmdobj` is the Command instance, the cmdlen is\n the same as len(cmdname) and mratio is a measure of how big a part of the\n full input string the cmdname takes up - an exact match would be 1.0. Finally,\n the `raw_cmdname` is the cmdname unmodified by eventual prefix-stripping.\n\n "}
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.default.system.html b/docs/0.9.5/api/evennia.commands.default.system.html deleted file mode 100644 index 56579098bc..0000000000 --- a/docs/0.9.5/api/evennia.commands.default.system.html +++ /dev/null @@ -1,795 +0,0 @@ - - - - - - - - - evennia.commands.default.system — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.commands.default.system

-

System commands

-
-
-class evennia.commands.default.system.CmdAccounts(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

Manage registered accounts

-
-
Usage:

accounts [nr] -accounts/delete <name or #id> [: reason]

-
-
Switches:

delete - delete an account from the server

-
-
-

By default, lists statistics about the Accounts registered with the game. -It will list the <nr> amount of latest registered accounts -If not given, <nr> defaults to 10.

-
-
-key = '@accounts'
-
- -
-
-aliases = ['@account']
-
- -
-
-switch_options = ('delete',)
-
- -
-
-locks = 'cmd:perm(listaccounts) or perm(Admin)'
-
- -
-
-help_category = 'system'
-
- -
-
-func()[source]
-

List the accounts

-
- -
-
-lock_storage = 'cmd:perm(listaccounts) or perm(Admin)'
-
- -
-
-search_index_entry = {'aliases': '@account', 'category': 'system', 'key': '@accounts', 'no_prefix': 'accounts account', 'tags': '', 'text': '\n Manage registered accounts\n\n Usage:\n accounts [nr]\n accounts/delete <name or #id> [: reason]\n\n Switches:\n delete - delete an account from the server\n\n By default, lists statistics about the Accounts registered with the game.\n It will list the <nr> amount of latest registered accounts\n If not given, <nr> defaults to 10.\n '}
-
- -
- -
-
-class evennia.commands.default.system.CmdReload(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

reload the server

-
-
Usage:

reload [reason]

-
-
-

This restarts the server. The Portal is not -affected. Non-persistent scripts will survive a reload (use -reset to purge) and at_reload() hooks will be called.

-
-
-key = '@reload'
-
- -
-
-aliases = ['@restart']
-
- -
-
-locks = 'cmd:perm(reload) or perm(Developer)'
-
- -
-
-help_category = 'system'
-
- -
-
-func()[source]
-

Reload the system.

-
- -
-
-lock_storage = 'cmd:perm(reload) or perm(Developer)'
-
- -
-
-search_index_entry = {'aliases': '@restart', 'category': 'system', 'key': '@reload', 'no_prefix': 'reload restart', 'tags': '', 'text': '\n reload the server\n\n Usage:\n reload [reason]\n\n This restarts the server. The Portal is not\n affected. Non-persistent scripts will survive a reload (use\n reset to purge) and at_reload() hooks will be called.\n '}
-
- -
- -
-
-class evennia.commands.default.system.CmdReset(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

reset and reboot the server

-
-
Usage:

reset

-
-
-

Notes

-

For normal updating you are recommended to use reload rather -than this command. Use shutdown for a complete stop of -everything.

-

This emulates a cold reboot of the Server component of Evennia. -The difference to shutdown is that the Server will auto-reboot -and that it does not affect the Portal, so no users will be -disconnected. Contrary to reload however, all shutdown hooks will -be called and any non-database saved scripts, ndb-attributes, -cmdsets etc will be wiped.

-
-
-key = '@reset'
-
- -
-
-aliases = ['@reboot']
-
- -
-
-locks = 'cmd:perm(reload) or perm(Developer)'
-
- -
-
-help_category = 'system'
-
- -
-
-func()[source]
-

Reload the system.

-
- -
-
-lock_storage = 'cmd:perm(reload) or perm(Developer)'
-
- -
-
-search_index_entry = {'aliases': '@reboot', 'category': 'system', 'key': '@reset', 'no_prefix': 'reset reboot', 'tags': '', 'text': '\n reset and reboot the server\n\n Usage:\n reset\n\n Notes:\n For normal updating you are recommended to use reload rather\n than this command. Use shutdown for a complete stop of\n everything.\n\n This emulates a cold reboot of the Server component of Evennia.\n The difference to shutdown is that the Server will auto-reboot\n and that it does not affect the Portal, so no users will be\n disconnected. Contrary to reload however, all shutdown hooks will\n be called and any non-database saved scripts, ndb-attributes,\n cmdsets etc will be wiped.\n\n '}
-
- -
- -
-
-class evennia.commands.default.system.CmdShutdown(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

stop the server completely

-
-
Usage:

shutdown [announcement]

-
-
-

Gracefully shut down both Server and Portal.

-
-
-key = '@shutdown'
-
- -
-
-locks = 'cmd:perm(shutdown) or perm(Developer)'
-
- -
-
-help_category = 'system'
-
- -
-
-func()[source]
-

Define function

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:perm(shutdown) or perm(Developer)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'system', 'key': '@shutdown', 'no_prefix': 'shutdown ', 'tags': '', 'text': '\n stop the server completely\n\n Usage:\n shutdown [announcement]\n\n Gracefully shut down both Server and Portal.\n '}
-
- -
- -
-
-class evennia.commands.default.system.CmdPy(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

execute a snippet of python code

-
-
Usage:

py [cmd] -py/edit -py/time <cmd> -py/clientraw <cmd> -py/noecho

-
-
Switches:

time - output an approximate execution time for <cmd> -edit - open a code editor for multi-line code experimentation -clientraw - turn off all client-specific escaping. Note that this may

-
-

lead to different output depending on prototocol (such as angular brackets -being parsed as HTML in the webclient but not in telnet clients)

-
-
-
noecho - in Python console mode, turn off the input echo (e.g. if your client

does this for you already)

-
-
-
-
-

Without argument, open a Python console in-game. This is a full console, -accepting multi-line Python code for testing and debugging. Type exit() to -return to the game. If Evennia is reloaded, the console will be closed.

-

Enter a line of instruction after the ‘py’ command to execute it -immediately. Separate multiple commands by ‘;’ or open the code editor -using the /edit switch (all lines added in editor will be executed -immediately when closing or using the execute command in the editor).

-

A few variables are made available for convenience in order to offer access -to the system (you can import more at execution time).

-
-
Available variables in py environment:

self, me : caller -here : caller.location -evennia : the evennia API -inherits_from(obj, parent) : check object inheritance

-
-
-

You can explore The evennia API from inside the game by calling -the __doc__ property on entities:

-
-

py evennia.__doc__ -py evennia.managers.__doc__

-
-

|rNote: In the wrong hands this command is a severe security risk. It -should only be accessible by trusted server admins/superusers.|n

-
-
-key = '@py'
-
- -
-
-aliases = ['@!']
-
- -
-
-switch_options = ('time', 'edit', 'clientraw', 'noecho')
-
- -
-
-locks = 'cmd:perm(py) or perm(Developer)'
-
- -
-
-help_category = 'system'
-
- -
-
-arg_regex = re.compile('', re.IGNORECASE)
-
- -
-
-func()[source]
-

hook function

-
- -
-
-lock_storage = 'cmd:perm(py) or perm(Developer)'
-
- -
-
-search_index_entry = {'aliases': '@!', 'category': 'system', 'key': '@py', 'no_prefix': 'py !', 'tags': '', 'text': "\n execute a snippet of python code\n\n Usage:\n py [cmd]\n py/edit\n py/time <cmd>\n py/clientraw <cmd>\n py/noecho\n\n Switches:\n time - output an approximate execution time for <cmd>\n edit - open a code editor for multi-line code experimentation\n clientraw - turn off all client-specific escaping. Note that this may\n lead to different output depending on prototocol (such as angular brackets\n being parsed as HTML in the webclient but not in telnet clients)\n noecho - in Python console mode, turn off the input echo (e.g. if your client\n does this for you already)\n\n Without argument, open a Python console in-game. This is a full console,\n accepting multi-line Python code for testing and debugging. Type `exit()` to\n return to the game. If Evennia is reloaded, the console will be closed.\n\n Enter a line of instruction after the 'py' command to execute it\n immediately. Separate multiple commands by ';' or open the code editor\n using the /edit switch (all lines added in editor will be executed\n immediately when closing or using the execute command in the editor).\n\n A few variables are made available for convenience in order to offer access\n to the system (you can import more at execution time).\n\n Available variables in py environment:\n self, me : caller\n here : caller.location\n evennia : the evennia API\n inherits_from(obj, parent) : check object inheritance\n\n You can explore The evennia API from inside the game by calling\n the `__doc__` property on entities:\n py evennia.__doc__\n py evennia.managers.__doc__\n\n |rNote: In the wrong hands this command is a severe security risk. It\n should only be accessible by trusted server admins/superusers.|n\n\n "}
-
- -
- -
-
-class evennia.commands.default.system.CmdService(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

manage system services

-
-
Usage:

service[/switch] <service>

-
-
Switches:

list - shows all available services (default) -start - activates or reactivate a service -stop - stops/inactivate a service (can often be restarted) -delete - tries to permanently remove a service

-
-
-

Service management system. Allows for the listing, -starting, and stopping of services. If no switches -are given, services will be listed. Note that to operate on the -service you have to supply the full (green or red) name as given -in the list.

-
-
-key = '@service'
-
- -
-
-aliases = ['@services']
-
- -
-
-switch_options = ('list', 'start', 'stop', 'delete')
-
- -
-
-locks = 'cmd:perm(service) or perm(Developer)'
-
- -
-
-help_category = 'system'
-
- -
-
-func()[source]
-

Implement command

-
- -
-
-lock_storage = 'cmd:perm(service) or perm(Developer)'
-
- -
-
-search_index_entry = {'aliases': '@services', 'category': 'system', 'key': '@service', 'no_prefix': 'service services', 'tags': '', 'text': '\n manage system services\n\n Usage:\n service[/switch] <service>\n\n Switches:\n list - shows all available services (default)\n start - activates or reactivate a service\n stop - stops/inactivate a service (can often be restarted)\n delete - tries to permanently remove a service\n\n Service management system. Allows for the listing,\n starting, and stopping of services. If no switches\n are given, services will be listed. Note that to operate on the\n service you have to supply the full (green or red) name as given\n in the list.\n '}
-
- -
- -
-
-class evennia.commands.default.system.CmdAbout(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

show Evennia info

-
-
Usage:

about

-
-
-

Display info about the game engine.

-
-
-key = '@about'
-
- -
-
-aliases = ['@version']
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-help_category = 'system'
-
- -
-
-func()[source]
-

Display information about server or target

-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': '@version', 'category': 'system', 'key': '@about', 'no_prefix': 'about version', 'tags': '', 'text': '\n show Evennia info\n\n Usage:\n about\n\n Display info about the game engine.\n '}
-
- -
- -
-
-class evennia.commands.default.system.CmdTime(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

show server time statistics

-
-
Usage:

time

-
-
-

List Server time statistics such as uptime -and the current time stamp.

-
-
-key = '@time'
-
- -
-
-aliases = ['@uptime']
-
- -
-
-locks = 'cmd:perm(time) or perm(Player)'
-
- -
-
-help_category = 'system'
-
- -
-
-func()[source]
-

Show server time data in a table.

-
- -
-
-lock_storage = 'cmd:perm(time) or perm(Player)'
-
- -
-
-search_index_entry = {'aliases': '@uptime', 'category': 'system', 'key': '@time', 'no_prefix': 'time uptime', 'tags': '', 'text': '\n show server time statistics\n\n Usage:\n time\n\n List Server time statistics such as uptime\n and the current time stamp.\n '}
-
- -
- -
-
-class evennia.commands.default.system.CmdServerLoad(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

show server load and memory statistics

-
-
Usage:

server[/mem]

-
-
Switches:

mem - return only a string of the current memory usage -flushmem - flush the idmapper cache

-
-
-

This command shows server load statistics and dynamic memory -usage. It also allows to flush the cache of accessed database -objects.

-

Some Important statistics in the table:

-

|wServer load|n is an average of processor usage. It’s usually -between 0 (no usage) and 1 (100% usage), but may also be -temporarily higher if your computer has multiple CPU cores.

-

The |wResident/Virtual memory|n displays the total memory used by -the server process.

-

Evennia |wcaches|n all retrieved database entities when they are -loaded by use of the idmapper functionality. This allows Evennia -to maintain the same instances of an entity and allowing -non-persistent storage schemes. The total amount of cached objects -are displayed plus a breakdown of database object types.

-

The |wflushmem|n switch allows to flush the object cache. Please -note that due to how Python’s memory management works, releasing -caches may not show you a lower Residual/Virtual memory footprint, -the released memory will instead be re-used by the program.

-
-
-key = '@server'
-
- -
-
-aliases = ['@serverload']
-
- -
-
-switch_options = ('mem', 'flushmem')
-
- -
-
-locks = 'cmd:perm(list) or perm(Developer)'
-
- -
-
-help_category = 'system'
-
- -
-
-func()[source]
-

Show list.

-
- -
-
-lock_storage = 'cmd:perm(list) or perm(Developer)'
-
- -
-
-search_index_entry = {'aliases': '@serverload', 'category': 'system', 'key': '@server', 'no_prefix': 'server serverload', 'tags': '', 'text': "\n show server load and memory statistics\n\n Usage:\n server[/mem]\n\n Switches:\n mem - return only a string of the current memory usage\n flushmem - flush the idmapper cache\n\n This command shows server load statistics and dynamic memory\n usage. It also allows to flush the cache of accessed database\n objects.\n\n Some Important statistics in the table:\n\n |wServer load|n is an average of processor usage. It's usually\n between 0 (no usage) and 1 (100% usage), but may also be\n temporarily higher if your computer has multiple CPU cores.\n\n The |wResident/Virtual memory|n displays the total memory used by\n the server process.\n\n Evennia |wcaches|n all retrieved database entities when they are\n loaded by use of the idmapper functionality. This allows Evennia\n to maintain the same instances of an entity and allowing\n non-persistent storage schemes. The total amount of cached objects\n are displayed plus a breakdown of database object types.\n\n The |wflushmem|n switch allows to flush the object cache. Please\n note that due to how Python's memory management works, releasing\n caches may not show you a lower Residual/Virtual memory footprint,\n the released memory will instead be re-used by the program.\n\n "}
-
- -
- -
-
-class evennia.commands.default.system.CmdTasks(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

Display or terminate active tasks (delays).

-
-
Usage:

tasks[/switch] [task_id or function_name]

-
-
Switches:

pause - Pause the callback of a task. -unpause - Process all callbacks made since pause() was called. -do_task - Execute the task (call its callback). -call - Call the callback of this task. -remove - Remove a task without executing it. -cancel - Stop a task from automatically executing.

-
-
-

Notes

-

A task is a single use method of delaying the call of a function. Calls are created -in code, using evennia.utils.delay. -See |luhttps://www.evennia.com/docs/latest/Command-Duration.html|ltthe docs|le for help.

-

By default, tasks that are canceled and never called are cleaned up after one minute.

-

Examples

-
    -
  • -
    tasks/cancel move_callback - Cancels all movement delays from the slow_exit contrib.

    In this example slow exits creates it’s tasks with -utils.delay(move_delay, move_callback)

    -
    -
    -
  • -
  • tasks/cancel 2 - Cancel task id 2.

  • -
-
-
-key = '@tasks'
-
- -
-
-aliases = ['@task', '@delays']
-
- -
-
-switch_options = ('pause', 'unpause', 'do_task', 'call', 'remove', 'cancel')
-
- -
-
-locks = 'cmd:all();perm(Developer)'
-
- -
-
-help_category = 'system'
-
- -
-
-static coll_date_func(task)[source]
-

Replace regex characters in date string and collect deferred function name.

-
- -
-
-do_task_action(*args, **kwargs)[source]
-

Process the action of a tasks command.

-

This exists to gain support with yes or no function from EvMenu.

-
- -
-
-func()[source]
-

This is the hook function that actually does all the work. It is called -by the cmdhandler right after self.parser() finishes, and so has access -to all the variables defined therein.

-
- -
-
-lock_storage = 'cmd:all();cmd:perm(Developer)'
-
- -
-
-search_index_entry = {'aliases': '@task @delays', 'category': 'system', 'key': '@tasks', 'no_prefix': 'tasks task delays', 'tags': '', 'text': "\n Display or terminate active tasks (delays).\n\n Usage:\n tasks[/switch] [task_id or function_name]\n\n Switches:\n pause - Pause the callback of a task.\n unpause - Process all callbacks made since pause() was called.\n do_task - Execute the task (call its callback).\n call - Call the callback of this task.\n remove - Remove a task without executing it.\n cancel - Stop a task from automatically executing.\n\n Notes:\n A task is a single use method of delaying the call of a function. Calls are created\n in code, using `evennia.utils.delay`.\n See |luhttps://www.evennia.com/docs/latest/Command-Duration.html|ltthe docs|le for help.\n\n By default, tasks that are canceled and never called are cleaned up after one minute.\n\n Examples:\n - `tasks/cancel move_callback` - Cancels all movement delays from the slow_exit contrib.\n In this example slow exits creates it's tasks with\n `utils.delay(move_delay, move_callback)`\n - `tasks/cancel 2` - Cancel task id 2.\n\n "}
-
- -
- -
-
-class evennia.commands.default.system.CmdTickers(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

View running tickers

-
-
Usage:

tickers

-
-
-

Note: Tickers are created, stopped and manipulated in Python code -using the TickerHandler. This is merely a convenience function for -inspecting the current status.

-
-
-key = '@tickers'
-
- -
-
-help_category = 'system'
-
- -
-
-locks = 'cmd:perm(tickers) or perm(Builder)'
-
- -
-
-func()[source]
-

This is the hook function that actually does all the work. It is called -by the cmdhandler right after self.parser() finishes, and so has access -to all the variables defined therein.

-
- -
-
-aliases = []
-
- -
-
-lock_storage = 'cmd:perm(tickers) or perm(Builder)'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'system', 'key': '@tickers', 'no_prefix': 'tickers ', 'tags': '', 'text': '\n View running tickers\n\n Usage:\n tickers\n\n Note: Tickers are created, stopped and manipulated in Python code\n using the TickerHandler. This is merely a convenience function for\n inspecting the current status.\n\n '}
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.default.tests.html b/docs/0.9.5/api/evennia.commands.default.tests.html deleted file mode 100644 index f7455b4af9..0000000000 --- a/docs/0.9.5/api/evennia.commands.default.tests.html +++ /dev/null @@ -1,955 +0,0 @@ - - - - - - - - - evennia.commands.default.tests — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.commands.default.tests

-

This is part of the Evennia unittest framework, for testing the -stability and integrity of the codebase during updates. This module -test the default command set. It is instantiated by the -evennia/objects/tests.py module, which in turn is run by as part of the -main test suite started with

-
-

> python game/manage.py test.

-
-
-
-class evennia.commands.default.tests.TestGeneral(methodName='runTest')[source]
-

Bases: evennia.utils.test_resources.BaseEvenniaCommandTest

-
-
-test_look()[source]
-
- -
-
-test_home()[source]
-
- -
-
-test_inventory()[source]
-
- -
-
-test_pose()[source]
-
- -
-
-test_nick()[source]
-
- -
-
-test_get_and_drop()[source]
-
- -
-
-test_give()[source]
-
- -
-
-test_mux_command()[source]
-
- -
-
-test_say()[source]
-
- -
-
-test_whisper()[source]
-
- -
-
-test_access()[source]
-
- -
- -
-
-class evennia.commands.default.tests.TestHelp(methodName='runTest')[source]
-

Bases: evennia.utils.test_resources.BaseEvenniaCommandTest

-
-
-maxDiff = None
-
- -
-
-setUp()[source]
-

Sets up testing environment

-
- -
-
-tearDown()[source]
-

Hook method for deconstructing the test fixture after testing it.

-
- -
-
-test_help()[source]
-
- -
-
-test_set_help()[source]
-
- -
-
-test_subtopic_fetch = None
-
- -
-
-test_subtopic_fetch_00_test()
-

Check retrieval of subtopics [with helparg=’test’, expected=’Help for testnnMain help text… test/something else test/more’].

-
- -
-
-test_subtopic_fetch_01_test_creating_extra_stuff()
-

Check retrieval of subtopics [with helparg=’test/creating extra stuff’, expected=’Help for test/creating extra st…ating extra stuff/subsubtopicn’].

-
- -
-
-test_subtopic_fetch_02_test_creating()
-

Check retrieval of subtopics [with helparg=’test/creating’, expected=’Help for test/creating extra st…ating extra stuff/subsubtopicn’].

-
- -
-
-test_subtopic_fetch_03_test_extra()
-

Check retrieval of subtopics [with helparg=’test/extra’, expected=’Help for test/creating extra st…ating extra stuff/subsubtopicn’].

-
- -
-
-test_subtopic_fetch_04_test_extra_subsubtopic()
-

Check retrieval of subtopics [with helparg=’test/extra/subsubtopic’, expected=’Help for test/creating extra st…bsubtopicnnA subsubtopic text’].

-
- -
-
-test_subtopic_fetch_05_test_creating_extra_subsub()
-

Check retrieval of subtopics [with helparg=’test/creating extra/subsub’, expected=’Help for test/creating extra st…bsubtopicnnA subsubtopic text’].

-
- -
-
-test_subtopic_fetch_06_test_Something_else()
-

Check retrieval of subtopics [with helparg=’test/Something else’, expected=’Help for test/something elsennSomething else’].

-
- -
-
-test_subtopic_fetch_07_test_More()
-

Check retrieval of subtopics [with helparg=’test/More’, expected=’Help for test/morennAnother t…opics:n test/more/second-more’].

-
- -
-
-test_subtopic_fetch_08_test_More_Second_more()
-

Check retrieval of subtopics [with helparg=’test/More/Second-more’, expected=’Help for test/more/second-more...est/more/second-more/third more’].

-
- -
-
-test_subtopic_fetch_09_test_More_more()
-

Check retrieval of subtopics [with helparg=’test/More/-more’, expected=’Help for test/more/second-more...est/more/second-more/third more’].

-
- -
-
-test_subtopic_fetch_10_test_more_second_more_again()
-

Check retrieval of subtopics [with helparg=’test/more/second/more again’, expected=’Help for test/more/second-more/more againnnEven more text.n’].

-
- -
-
-test_subtopic_fetch_11_test_more_second_third()
-

Check retrieval of subtopics [with helparg=’test/more/second/third’, expected=’Help for test/more/second-more/third morennThird more textn’].

-
- -
- -
-
-class evennia.commands.default.tests.TestSystem(methodName='runTest')[source]
-

Bases: evennia.utils.test_resources.BaseEvenniaCommandTest

-
-
-test_py()[source]
-
- -
-
-test_scripts()[source]
-
- -
-
-test_objects()[source]
-
- -
-
-test_about()[source]
-
- -
-
-test_server_load()[source]
-
- -
- -
-
-evennia.commands.default.tests.func_test_cmd_tasks()[source]
-
- -
-
-class evennia.commands.default.tests.TestCmdTasks(methodName='runTest')[source]
-

Bases: evennia.utils.test_resources.BaseEvenniaCommandTest

-
-
-setUp()[source]
-

Sets up testing environment

-
- -
-
-tearDown()[source]
-

Hook method for deconstructing the test fixture after testing it.

-
- -
-
-test_no_tasks()[source]
-
- -
-
-test_active_task()[source]
-
- -
-
-test_persistent_task()[source]
-
- -
-
-test_pause_unpause()[source]
-
- -
-
-test_do_task()[source]
-
- -
-
-test_remove()[source]
-
- -
-
-test_call()[source]
-
- -
-
-test_cancel()[source]
-
- -
-
-test_func_name_manipulation()[source]
-
- -
-
-test_wrong_func_name()[source]
-
- -
-
-test_no_input()[source]
-
- -
-
-test_responce_of_yes()[source]
-
- -
-
-test_task_complete_waiting_input()[source]
-

Test for task completing while waiting for input.

-
- -
-
-test_new_task_waiting_input()[source]
-

Test task completing than a new task with the same ID being made while waitinf for input.

-
- -
-
-test_misformed_command()[source]
-
- -
- -
-
-class evennia.commands.default.tests.TestAdmin(methodName='runTest')[source]
-

Bases: evennia.utils.test_resources.BaseEvenniaCommandTest

-
-
-test_emit()[source]
-
- -
-
-test_perm()[source]
-
- -
-
-test_wall()[source]
-
- -
-
-test_ban()[source]
-
- -
-
-test_force()[source]
-
- -
- -
-
-class evennia.commands.default.tests.TestAccount(methodName='runTest')[source]
-

Bases: evennia.utils.test_resources.BaseEvenniaCommandTest

-
-
-test_ooc_look()[source]
-
- -
-
-test_ooc()[source]
-
- -
-
-test_ic()[source]
-
- -
-
-test_ic__other_object()[source]
-
- -
-
-test_ic__nonaccess()[source]
-
- -
-
-test_password()[source]
-
- -
-
-test_option()[source]
-
- -
-
-test_who()[source]
-
- -
-
-test_quit()[source]
-
- -
-
-test_sessions()[source]
-
- -
-
-test_color_test()[source]
-
- -
-
-test_char_create()[source]
-
- -
-
-test_char_delete()[source]
-
- -
-
-test_quell()[source]
-
- -
- -
-
-class evennia.commands.default.tests.TestBuilding(methodName='runTest')[source]
-

Bases: evennia.utils.test_resources.BaseEvenniaCommandTest

-
-
-test_create()[source]
-
- -
-
-test_examine()[source]
-
- -
-
-test_set_obj_alias()[source]
-
- -
-
-test_copy()[source]
-
- -
-
-test_attribute_commands()[source]
-
- -
-
-test_nested_attribute_commands()[source]
-
- -
-
-test_split_nested_attr()[source]
-
- -
-
-test_do_nested_lookup()[source]
-
- -
-
-test_name()[source]
-
- -
-
-test_desc()[source]
-
- -
-
-test_empty_desc()[source]
-

empty desc sets desc as ‘’

-
- -
-
-test_desc_default_to_room()[source]
-

no rhs changes room’s desc

-
- -
-
-test_destroy()[source]
-
- -
-
-test_destroy_sequence()[source]
-
- -
-
-test_dig()[source]
-
- -
-
-test_tunnel()[source]
-
- -
-
-test_tunnel_exit_typeclass()[source]
-
- -
-
-test_exit_commands()[source]
-
- -
-
-test_set_home()[source]
-
- -
-
-test_list_cmdsets()[source]
-
- -
-
-test_typeclass()[source]
-
- -
-
-test_lock()[source]
-
- -
-
-test_find()[source]
-
- -
-
-test_script()[source]
-
- -
-
-test_script_multi_delete()[source]
-
- -
-
-test_teleport()[source]
-
- -
-
-test_tag()[source]
-
- -
-
-test_spawn()[source]
-
- -
- -
-
-class evennia.commands.default.tests.TestCommsChannel(methodName='runTest')[source]
-

Bases: evennia.utils.test_resources.BaseEvenniaCommandTest

-

Test the central channel command.

-
-
-setUp()[source]
-

Sets up testing environment

-
- -
-
-tearDown()[source]
-

Hook method for deconstructing the test fixture after testing it.

-
- -
-
-test_channel__noarg()[source]
-
- -
-
-test_channel__msg()[source]
-
- -
-
-test_channel__list()[source]
-
- -
-
-test_channel__all()[source]
-
- -
-
-test_channel__history()[source]
-
- -
-
-test_channel__sub()[source]
-
- -
-
-test_channel__unsub()[source]
-
- -
-
-test_channel__alias__unalias()[source]
-

Add and then remove a channel alias

-
- -
-
-test_channel__mute()[source]
-
- -
-
-test_channel__unmute()[source]
-
- -
-
-test_channel__create()[source]
-
- -
-
-test_channel__destroy()[source]
-
- -
-
-test_channel__desc()[source]
-
- -
-
-test_channel__lock()[source]
-
- -
-
-test_channel__unlock()[source]
-
- -
-
-test_channel__boot()[source]
-
- -
-
-test_channel__ban__unban()[source]
-

Test first ban and then unban

-
- -
-
-test_channel__who()[source]
-
- -
- -
-
-class evennia.commands.default.tests.TestComms(methodName='runTest')[source]
-

Bases: evennia.utils.test_resources.BaseEvenniaCommandTest

-
-
-test_page()[source]
-
- -
- -
-
-class evennia.commands.default.tests.TestBatchProcess(methodName='runTest')[source]
-

Bases: evennia.utils.test_resources.BaseEvenniaCommandTest

-

Test the batch processor.

-
-
-red_button = <module 'evennia.contrib.tutorials.red_button.red_button' from '/home/griatch/Devel/Home/evennia/evennia/evennia/contrib/tutorials/red_button/red_button.py'>
-
- -
-
-test_batch_commands(mock_tutorials, mock_repeat)[source]
-
- -
- -
-
-class evennia.commands.default.tests.CmdInterrupt(**kwargs)[source]
-

Bases: evennia.commands.command.Command

-

(you may see this if a child command had no help text defined)

-
-
Usage:

command [args]

-
-
-

This is the base command class. Inherit from this -to create new commands.

-

The cmdhandler makes the following variables available to the -command methods (so you can always assume them to be there): -self.caller - the game object calling the command -self.cmdstring - the command name used to trigger this command (allows

-
-

you to know which alias was used, for example)

-
-
-
cmd.args - everything supplied to the command following the cmdstring

(this is usually what is parsed in self.parse())

-
-
cmd.cmdset - the cmdset from which this command was matched (useful only

seldomly, notably for help-type commands, to create dynamic -help entries and lists)

-
-
cmd.obj - the object on which this command is defined. If a default command,

this is usually the same as caller.

-
-
-

cmd.rawstring - the full raw string input, including any args and no parsing.

-

The following class properties can/should be defined on your child class:

-

key - identifier for command (e.g. “look”) -aliases - (optional) list of aliases (e.g. [“l”, “loo”]) -locks - lock string (default is “cmd:all()”) -help_category - how to organize this help entry in help system

-
-

(default is “General”)

-
-

auto_help - defaults to True. Allows for turning off auto-help generation -arg_regex - (optional) raw string regex defining how the argument part of

-
-

the command should look in order to match for this command -(e.g. must it be a space between cmdname and arg?)

-
-
-
auto_help_display_key - (optional) if given, this replaces the string shown

in the auto-help listing. This is particularly useful for system-commands -whose actual key is not really meaningful.

-
-
-

(Note that if auto_help is on, this initial string is also used by the -system to create the help entry for the command, so it’s a good idea to -format it similar to this one). This behavior can be changed by -overriding the method ‘get_help’ of a command: by default, this -method returns cmd.__doc__ (that is, this very docstring, or -the docstring of your command). You can, however, extend or -replace this without disabling auto_help.

-
-
-key = 'interrupt'
-
- -
-
-parse()[source]
-

Once the cmdhandler has identified this as the command we -want, this function is run. If many of your commands have a -similar syntax (for example ‘cmd arg1 = arg2’) you should -simply define this once and just let other commands of the -same form inherit from this. See the docstring of this module -for which object properties are available to use (notably -self.args).

-
- -
-
-func()[source]
-

This is the actual executing part of the command. It is -called directly after self.parse(). See the docstring of this -module for which object properties are available (beyond those -set in self.parse())

-
- -
-
-aliases = []
-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all();'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': 'interrupt', 'no_prefix': ' ', 'tags': '', 'text': '\n ## Base command\n\n (you may see this if a child command had no help text defined)\n\n Usage:\n command [args]\n\n This is the base command class. Inherit from this\n to create new commands.\n\n The cmdhandler makes the following variables available to the\n command methods (so you can always assume them to be there):\n self.caller - the game object calling the command\n self.cmdstring - the command name used to trigger this command (allows\n you to know which alias was used, for example)\n cmd.args - everything supplied to the command following the cmdstring\n (this is usually what is parsed in self.parse())\n cmd.cmdset - the cmdset from which this command was matched (useful only\n seldomly, notably for help-type commands, to create dynamic\n help entries and lists)\n cmd.obj - the object on which this command is defined. If a default command,\n this is usually the same as caller.\n cmd.rawstring - the full raw string input, including any args and no parsing.\n\n The following class properties can/should be defined on your child class:\n\n key - identifier for command (e.g. "look")\n aliases - (optional) list of aliases (e.g. ["l", "loo"])\n locks - lock string (default is "cmd:all()")\n help_category - how to organize this help entry in help system\n (default is "General")\n auto_help - defaults to True. Allows for turning off auto-help generation\n arg_regex - (optional) raw string regex defining how the argument part of\n the command should look in order to match for this command\n (e.g. must it be a space between cmdname and arg?)\n auto_help_display_key - (optional) if given, this replaces the string shown\n in the auto-help listing. This is particularly useful for system-commands\n whose actual key is not really meaningful.\n\n (Note that if auto_help is on, this initial string is also used by the\n system to create the help entry for the command, so it\'s a good idea to\n format it similar to this one). This behavior can be changed by\n overriding the method \'get_help\' of a command: by default, this\n method returns cmd.__doc__ (that is, this very docstring, or\n the docstring of your command). You can, however, extend or\n replace this without disabling auto_help.\n '}
-
- -
- -
-
-class evennia.commands.default.tests.TestInterruptCommand(methodName='runTest')[source]
-

Bases: evennia.utils.test_resources.BaseEvenniaCommandTest

-
-
-test_interrupt_command()[source]
-
- -
- -
-
-class evennia.commands.default.tests.TestUnconnectedCommand(methodName='runTest')[source]
-

Bases: evennia.utils.test_resources.BaseEvenniaCommandTest

-
-
-test_info_command()[source]
-
- -
- -
-
-class evennia.commands.default.tests.TestSystemCommands(methodName='runTest')[source]
-

Bases: evennia.utils.test_resources.BaseEvenniaCommandTest

-
-
-test_simple_defaults()[source]
-
- -
-
-test_multimatch()[source]
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.default.unloggedin.html b/docs/0.9.5/api/evennia.commands.default.unloggedin.html deleted file mode 100644 index 27a707ffde..0000000000 --- a/docs/0.9.5/api/evennia.commands.default.unloggedin.html +++ /dev/null @@ -1,525 +0,0 @@ - - - - - - - - - evennia.commands.default.unloggedin — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.commands.default.unloggedin

-

Commands that are available from the connect screen.

-
-
-class evennia.commands.default.unloggedin.CmdUnconnectedConnect(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

connect to the game

-
-
Usage (at login screen):

connect accountname password -connect “account name” “pass word”

-
-
-

Use the create command to first create an account before logging in.

-

If you have spaces in your name, enclose it in double quotes.

-
-
-key = 'connect'
-
- -
-
-aliases = ['conn', 'co', 'con']
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-arg_regex = re.compile('\\s.*?|$', re.IGNORECASE)
-
- -
-
-func()[source]
-

Uses the Django admin api. Note that unlogged-in commands -have a unique position in that their func() receives -a session object instead of a source_object like all -other types of logged-in commands (this is because -there is no object yet before the account has logged in)

-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': 'conn co con', 'category': 'general', 'key': 'connect', 'no_prefix': ' conn co con', 'tags': '', 'text': '\n connect to the game\n\n Usage (at login screen):\n connect accountname password\n connect "account name" "pass word"\n\n Use the create command to first create an account before logging in.\n\n If you have spaces in your name, enclose it in double quotes.\n '}
-
- -
- -
-
-class evennia.commands.default.unloggedin.CmdUnconnectedCreate(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

create a new account account

-
-
Usage (at login screen):

create <accountname> <password> -create “account name” “pass word”

-
-
-

This creates a new account account.

-

If you have spaces in your name, enclose it in double quotes.

-
-
-key = 'create'
-
- -
-
-aliases = ['cr', 'cre']
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-arg_regex = re.compile('\\s.*?|$', re.IGNORECASE)
-
- -
-
-func()[source]
-

Do checks and create account

-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': 'cr cre', 'category': 'general', 'key': 'create', 'no_prefix': ' cr cre', 'tags': '', 'text': '\n create a new account account\n\n Usage (at login screen):\n create <accountname> <password>\n create "account name" "pass word"\n\n This creates a new account account.\n\n If you have spaces in your name, enclose it in double quotes.\n '}
-
- -
- -
-
-class evennia.commands.default.unloggedin.CmdUnconnectedQuit(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

quit when in unlogged-in state

-
-
Usage:

quit

-
-
-

We maintain a different version of the quit command -here for unconnected accounts for the sake of simplicity. The logged in -version is a bit more complicated.

-
-
-key = 'quit'
-
- -
-
-aliases = ['qu', 'q']
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-func()[source]
-

Simply close the connection.

-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': 'qu q', 'category': 'general', 'key': 'quit', 'no_prefix': ' qu q', 'tags': '', 'text': '\n quit when in unlogged-in state\n\n Usage:\n quit\n\n We maintain a different version of the quit command\n here for unconnected accounts for the sake of simplicity. The logged in\n version is a bit more complicated.\n '}
-
- -
- -
-
-class evennia.commands.default.unloggedin.CmdUnconnectedLook(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

look when in unlogged-in state

-
-
Usage:

look

-
-
-

This is an unconnected version of the look command for simplicity.

-

This is called by the server and kicks everything in gear. -All it does is display the connect screen.

-
-
-key = '__unloggedin_look_command'
-
- -
-
-aliases = ['l', 'look']
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-func()[source]
-

Show the connect screen.

-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': 'l look', 'category': 'general', 'key': '__unloggedin_look_command', 'no_prefix': ' l look', 'tags': '', 'text': '\n look when in unlogged-in state\n\n Usage:\n look\n\n This is an unconnected version of the look command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}
-
- -
- -
-
-class evennia.commands.default.unloggedin.CmdUnconnectedHelp(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

get help when in unconnected-in state

-
-
Usage:

help

-
-
-

This is an unconnected version of the help command, -for simplicity. It shows a pane of info.

-
-
-key = 'help'
-
- -
-
-aliases = ['?', 'h']
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-func()[source]
-

Shows help

-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': '? h', 'category': 'general', 'key': 'help', 'no_prefix': ' ? h', 'tags': '', 'text': '\n get help when in unconnected-in state\n\n Usage:\n help\n\n This is an unconnected version of the help command,\n for simplicity. It shows a pane of info.\n '}
-
- -
- -
-
-class evennia.commands.default.unloggedin.CmdUnconnectedEncoding(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

set which text encoding to use in unconnected-in state

-
-
Usage:

encoding/switches [<encoding>]

-
-
Switches:

clear - clear your custom encoding

-
-
-

This sets the text encoding for communicating with Evennia. This is mostly -an issue only if you want to use non-ASCII characters (i.e. letters/symbols -not found in English). If you see that your characters look strange (or you -get encoding errors), you should use this command to set the server -encoding to be the same used in your client program.

-

Common encodings are utf-8 (default), latin-1, ISO-8859-1 etc.

-

If you don’t submit an encoding, the current encoding will be displayed -instead.

-
-
-key = 'encoding'
-
- -
-
-aliases = ['encode']
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-func()[source]
-

Sets the encoding.

-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': 'encode', 'category': 'general', 'key': 'encoding', 'no_prefix': ' encode', 'tags': '', 'text': "\n set which text encoding to use in unconnected-in state\n\n Usage:\n encoding/switches [<encoding>]\n\n Switches:\n clear - clear your custom encoding\n\n\n This sets the text encoding for communicating with Evennia. This is mostly\n an issue only if you want to use non-ASCII characters (i.e. letters/symbols\n not found in English). If you see that your characters look strange (or you\n get encoding errors), you should use this command to set the server\n encoding to be the same used in your client program.\n\n Common encodings are utf-8 (default), latin-1, ISO-8859-1 etc.\n\n If you don't submit an encoding, the current encoding will be displayed\n instead.\n "}
-
- -
- -
-
-class evennia.commands.default.unloggedin.CmdUnconnectedInfo(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

Provides MUDINFO output, so that Evennia games can be added to Mudconnector -and Mudstats. Sadly, the MUDINFO specification seems to have dropped off the -face of the net, but it is still used by some crawlers. This implementation -was created by looking at the MUDINFO implementation in MUX2, TinyMUSH, Rhost, -and PennMUSH.

-
-
-key = 'info'
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-func()[source]
-

This is the hook function that actually does all the work. It is called -by the cmdhandler right after self.parser() finishes, and so has access -to all the variables defined therein.

-
- -
-
-aliases = []
-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': 'info', 'no_prefix': ' ', 'tags': '', 'text': '\n Provides MUDINFO output, so that Evennia games can be added to Mudconnector\n and Mudstats. Sadly, the MUDINFO specification seems to have dropped off the\n face of the net, but it is still used by some crawlers. This implementation\n was created by looking at the MUDINFO implementation in MUX2, TinyMUSH, Rhost,\n and PennMUSH.\n '}
-
- -
- -
-
-class evennia.commands.default.unloggedin.CmdUnconnectedScreenreader(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

Activate screenreader mode.

-
-
Usage:

screenreader

-
-
-

Used to flip screenreader mode on and off before logging in (when -logged in, use option screenreader on).

-
-
-key = 'screenreader'
-
- -
-
-func()[source]
-

Flips screenreader setting.

-
- -
-
-aliases = []
-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all();'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': 'screenreader', 'no_prefix': ' ', 'tags': '', 'text': '\n Activate screenreader mode.\n\n Usage:\n screenreader\n\n Used to flip screenreader mode on and off before logging in (when\n logged in, use option screenreader on).\n '}
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.commands.html b/docs/0.9.5/api/evennia.commands.html deleted file mode 100644 index 555435c6cf..0000000000 --- a/docs/0.9.5/api/evennia.commands.html +++ /dev/null @@ -1,148 +0,0 @@ - - - - - - - - - evennia.commands — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.comms.admin.html b/docs/0.9.5/api/evennia.comms.admin.html deleted file mode 100644 index 701e6b7b02..0000000000 --- a/docs/0.9.5/api/evennia.comms.admin.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.comms.admin — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.comms.admin

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.comms.channelhandler.html b/docs/0.9.5/api/evennia.comms.channelhandler.html deleted file mode 100644 index 6c35798bcd..0000000000 --- a/docs/0.9.5/api/evennia.comms.channelhandler.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.comms.channelhandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.comms.channelhandler

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.comms.comms.html b/docs/0.9.5/api/evennia.comms.comms.html deleted file mode 100644 index 75045bc373..0000000000 --- a/docs/0.9.5/api/evennia.comms.comms.html +++ /dev/null @@ -1,889 +0,0 @@ - - - - - - - - - evennia.comms.comms — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.comms.comms

-

Base typeclass for in-game Channels.

-
-
-class evennia.comms.comms.DefaultChannel(*args, **kwargs)[source]
-

Bases: evennia.comms.models.ChannelDB

-

This is the base class for all Channel Comms. Inherit from this to -create different types of communication channels.

-
-
Class-level variables:
    -
  • send_to_online_only (bool, default True) - if set, will only try to -send to subscribers that are actually active. This is a useful optimization.

  • -
  • log_file (str, default “channel_{channelname}.log”). This is the -log file to which the channel history will be saved. The {channelname} tag -will be replaced by the key of the Channel. If an Attribute ‘log_file’ -is set, this will be used instead. If this is None and no Attribute is found, -no history will be saved.

  • -
  • channel_prefix_string (str, default “[{channelname} ]”) - this is used -as a simple template to get the channel prefix with .channel_prefix().

  • -
-
-
-
-
-objects = <evennia.comms.managers.ChannelManager object>
-
- -
-
-send_to_online_only = True
-
- -
-
-log_file = 'channel_{channelname}.log'
-
- -
-
-channel_prefix_string = '[{channelname}] '
-
- -
-
-channel_msg_nick_pattern = '{alias}\\s*?|{alias}\\s+?(?P<arg1>.+?)'
-
- -
-
-channel_msg_nick_replacement = 'channel {channelname} = $1'
-
- -
-
-at_first_save()[source]
-

Called by the typeclass system the very first time the channel -is saved to the database. Generally, don’t overload this but -the hooks called by this method.

-
- -
-
-basetype_setup()[source]
-
- -
-
-at_channel_creation()[source]
-

Called once, when the channel is first created.

-
- -
-
-get_log_filename()[source]
-

File name to use for channel log.

-
-
Returns
-

str

-
-
The filename to use (this is always assumed to be inside

settings.LOG_DIR)

-
-
-

-
-
-
- -
-
-set_log_filename(filename)[source]
-

Set a custom log filename.

-
-
Parameters
-

filename (str) – The filename to set. This is a path starting from -inside the settings.LOG_DIR location.

-
-
-
- -
-
-has_connection(subscriber)[source]
-

Checks so this account is actually listening -to this channel.

-
-
Parameters
-

subscriber (Account or Object) – Entity to check.

-
-
Returns
-

has_sub (bool)

-
-
Whether the subscriber is subscribing to

this channel or not.

-
-
-

-
-
-

Notes

-
-
This will first try Account subscribers and only try Object

if the Account fails.

-
-
-
- -
-
-property mutelist
-
- -
-
-property banlist
-
- -
-
-property wholist
-
- -
-
-mute(subscriber, **kwargs)[source]
-

Adds an entity to the list of muted subscribers. -A muted subscriber will no longer see channel messages, -but may use channel commands.

-
-
Parameters
-
    -
  • subscriber (Object or Account) – Subscriber to mute.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
Returns
-

bool

-
-
True if muting was successful, False if we were already

muted.

-
-
-

-
-
-
- -
-
-unmute(subscriber, **kwargs)[source]
-

Removes an entity from the list of muted subscribers. A muted subscriber -will no longer see channel messages, but may use channel commands.

-
-
Parameters
-
    -
  • subscriber (Object or Account) – The subscriber to unmute.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
Returns
-

bool

-
-
True if unmuting was successful, False if we were already

unmuted.

-
-
-

-
-
-
- -
-
-ban(target, **kwargs)[source]
-

Ban a given user from connecting to the channel. This will not stop -users already connected, so the user must be booted for this to take -effect.

-
-
Parameters
-
    -
  • target (Object or Account) – The entity to unmute. This need not -be a subscriber.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
Returns
-

bool

-
-
True if banning was successful, False if target was already

banned.

-
-
-

-
-
-
- -
-
-unban(target, **kwargs)[source]
-

Un-Ban a given user. This will not reconnect them - they will still -have to reconnect and set up aliases anew.

-
-
Parameters
-
    -
  • target (Object or Account) – The entity to unmute. This need not -be a subscriber.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
Returns
-

bool

-
-
True if unbanning was successful, False if target was not

previously banned.

-
-
-

-
-
-
- -
-
-connect(subscriber, **kwargs)[source]
-

Connect the user to this channel. This checks access.

-
-
Parameters
-
    -
  • subscriber (Account or Object) – the entity to subscribe -to this channel.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
Returns
-

success (bool)

-
-
Whether or not the addition was

successful.

-
-
-

-
-
-
- -
-
-disconnect(subscriber, **kwargs)[source]
-

Disconnect entity from this channel.

-
-
Parameters
-
    -
  • subscriber (Account of Object) – the -entity to disconnect.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
Returns
-

success (bool)

-
-
Whether or not the removal was

successful.

-
-
-

-
-
-
- -
-
-access(accessing_obj, access_type='listen', default=False, no_superuser_bypass=False, **kwargs)[source]
-

Determines if another object has permission to access.

-
-
Parameters
-
    -
  • accessing_obj (Object) – Object trying to access this one.

  • -
  • access_type (str, optional) – Type of access sought.

  • -
  • default (bool, optional) – What to return if no lock of access_type was found

  • -
  • no_superuser_bypass (bool, optional) – Turns off superuser -lock bypass. Be careful with this one.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
Returns
-

return (bool) – Result of lock check.

-
-
-
- -
-
-classmethod create(key, creator=None, *args, **kwargs)[source]
-

Creates a basic Channel with default parameters, unless otherwise -specified or extended.

-

Provides a friendlier interface to the utils.create_channel() function.

-
-
Parameters
-
    -
  • key (str) – This must be unique.

  • -
  • creator (Account or Object) – Entity to associate with this channel -(used for tracking)

  • -
-
-
Keyword Arguments
-
    -
  • aliases (list of str) – List of alternative (likely shorter) keynames.

  • -
  • description (str) – A description of the channel, for use in listings.

  • -
  • locks (str) – Lockstring.

  • -
  • keep_log (bool) – Log channel throughput.

  • -
  • typeclass (str or class) – The typeclass of the Channel (not -often used).

  • -
  • ip (str) – IP address of creator (for object auditing).

  • -
-
-
Returns
-

channel (Channel) – A newly created Channel. -errors (list): A list of errors in string form, if any.

-
-
-
- -
-
-delete()[source]
-

Deletes channel.

-
-
Returns
-

bool

-
-
If deletion was successful. Only time it can fail would be

if channel was already deleted. Even if it were to fail, all subscribers -will be disconnected.

-
-
-

-
-
-
- -
-
-channel_prefix()[source]
-

Hook method. How the channel should prefix itself for users.

-
-
Returns
-

str – The channel prefix.

-
-
-
- -
-
-add_user_channel_alias(user, alias, **kwargs)[source]
-

Add a personal user-alias for this channel to a given subscriber.

-
-
Parameters
-
    -
  • user (Object or Account) – The one to alias this channel.

  • -
  • alias (str) – The desired alias.

  • -
-
-
-
-

Note

-

This is tightly coupled to the default channel command. If you -change that, you need to change this as well.

-

We add two nicks - one is a plain alias -> channel.key that -users need to be able to reference this channel easily. The other -is a templated nick to easily be able to send messages to the -channel without needing to give the full channel command. The -structure of this nick is given by self.channel_msg_nick_pattern -and self.channel_msg_nick_replacement. By default it maps -alias <msg> -> channel <channelname> = <msg>, so that you can -for example just write pub Hello to send a message.

-

The alias created is alias $1 -> channel channel = $1, to allow -for sending to channel using the main channel command.

-
-
- -
-
-classmethod remove_user_channel_alias(user, alias, **kwargs)[source]
-

Remove a personal channel alias from a user.

-
-
Parameters
-
    -
  • user (Object or Account) – The user to remove an alias from.

  • -
  • alias (str) – The alias to remove.

  • -
  • **kwargs – Unused by default. Can be used to pass extra variables -into a custom implementation.

  • -
-
-
-

Notes

-

The channel-alias actually consists of two aliases - one -channel-based one for searching channels with the alias and one -inputline one for doing the ‘channelalias msg’ - call.

-

This is a classmethod because it doesn’t actually operate on the -channel instance.

-

It sits on the channel because the nick structure for this is -pretty complex and needs to be located in a central place (rather -on, say, the channel command).

-
- -
-
-at_pre_msg(message, **kwargs)[source]
-

Called before the starting of sending the message to a receiver. This -is called before any hooks on the receiver itself. If this returns -None/False, the sending will be aborted.

-
-
Parameters
-
    -
  • message (str) – The message to send.

  • -
  • **kwargs (any) – Keywords passed on from .msg. This includes -senders.

  • -
-
-
Returns
-

str, False or None

-
-
Any custom changes made to the message. If

falsy, no message will be sent.

-
-
-

-
-
-
- -
-
-msg(message, senders=None, bypass_mute=False, **kwargs)[source]
-

Send message to channel, causing it to be distributed to all non-muted -subscribed users of that channel.

-
-
Parameters
-
    -
  • message (str) – The message to send.

  • -
  • senders (Object, Account or list, optional) – If not given, there is -no way to associate one or more senders with the message (like -a broadcast message or similar).

  • -
  • bypass_mute (bool, optional) – If set, always send, regardless of -individual mute-state of subscriber. This can be used for -global announcements or warnings/alerts.

  • -
  • **kwargs (any) – This will be passed on to all hooks. Use no_prefix -to exclude the channel prefix.

  • -
-
-
-

Notes

-

The call hook calling sequence is:

-
    -
  • msg = channel.at_pre_msg(message, **kwargs) (aborts for all if return None)

  • -
  • msg = receiver.at_pre_channel_msg(msg, channel, **kwargs) (aborts for receiver if return None)

  • -
  • receiver.at_channel_msg(msg, channel, **kwargs)

  • -
  • receiver.at_post_channel_msg(msg, channel, **kwargs)**

  • -
-

Called after all receivers are processed: -- channel.at_post_all_msg(message, **kwargs)

-

(where the senders/bypass_mute are embedded into **kwargs for -later access in hooks)

-
- -
-
-at_post_msg(message, **kwargs)[source]
-

This is called after sending to all valid recipients. It is normally -used for logging/channel history.

-
-
Parameters
-
    -
  • message (str) – The message sent.

  • -
  • **kwargs (any) – Keywords passed on from msg, including senders.

  • -
-
-
-
- -
-
-pre_join_channel(joiner, **kwargs)[source]
-

Hook method. Runs right before a channel is joined. If this -returns a false value, channel joining is aborted.

-
-
Parameters
-
    -
  • joiner (object) – The joining object.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
Returns
-

should_join (bool) – If False, channel joining is aborted.

-
-
-
- -
-
-post_join_channel(joiner, **kwargs)[source]
-

Hook method. Runs right after an object or account joins a channel.

-
-
Parameters
-
    -
  • joiner (object) – The joining object.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-

Notes

-

By default this adds the needed channel nicks to the joiner.

-
- -
-
-pre_leave_channel(leaver, **kwargs)[source]
-

Hook method. Runs right before a user leaves a channel. If this returns a false -value, leaving the channel will be aborted.

-
-
Parameters
-
    -
  • leaver (object) – The leaving object.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
Returns
-

should_leave (bool) – If False, channel parting is aborted.

-
-
-
- -
-
-post_leave_channel(leaver, **kwargs)[source]
-

Hook method. Runs right after an object or account leaves a channel.

-
-
Parameters
-
    -
  • leaver (object) – The leaving object.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-
- -
-
-at_init()[source]
-

Hook method. This is always called whenever this channel is -initiated – that is, whenever it its typeclass is cached from -memory. This happens on-demand first time the channel is used -or activated in some way after being created but also after -each server restart or reload.

-
- -
-
-web_get_admin_url()[source]
-

Returns the URI path for the Django Admin page for this object.

-

ex. Account#1 = ‘/admin/accounts/accountdb/1/change/’

-
-
Returns
-

path (str) – URI path to Django Admin page for object.

-
-
-
- -
-
-classmethod web_get_create_url()[source]
-

Returns the URI path for a View that allows users to create new -instances of this object.

-

ex. Chargen = ‘/characters/create/’

-

For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘channel-create’ would be referenced by this method.

-

ex. -url(r’channels/create/’, ChannelCreateView.as_view(), name=’channel-create’)

-

If no View has been created and defined in urls.py, returns an -HTML anchor.

-

This method is naive and simply returns a path. Securing access to -the actual view and limiting who can create new objects is the -developer’s responsibility.

-
-
Returns
-

path (str) – URI path to object creation page, if defined.

-
-
-
- -
-
-web_get_detail_url()[source]
-

Returns the URI path for a View that allows users to view details for -this object.

-

ex. Oscar (Character) = ‘/characters/oscar/1/’

-

For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘channel-detail’ would be referenced by this method.

-

ex.

-
url(r'channels/(?P<slug>[\w\d\-]+)/$',
-    ChannelDetailView.as_view(), name='channel-detail')
-
-
-

If no View has been created and defined in urls.py, returns an -HTML anchor.

-

This method is naive and simply returns a path. Securing access to -the actual view and limiting who can view this object is the developer’s -responsibility.

-
-
Returns
-

path (str) – URI path to object detail page, if defined.

-
-
-
- -
-
-web_get_update_url()[source]
-

Returns the URI path for a View that allows users to update this -object.

-

ex. Oscar (Character) = ‘/characters/oscar/1/change/’

-

For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘channel-update’ would be referenced by this method.

-

ex.

-
url(r'channels/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$',
-    ChannelUpdateView.as_view(), name='channel-update')
-
-
-

If no View has been created and defined in urls.py, returns an -HTML anchor.

-

This method is naive and simply returns a path. Securing access to -the actual view and limiting who can modify objects is the developer’s -responsibility.

-
-
Returns
-

path (str) – URI path to object update page, if defined.

-
-
-
- -
-
-web_get_delete_url()[source]
-

Returns the URI path for a View that allows users to delete this object.

-

ex. Oscar (Character) = ‘/characters/oscar/1/delete/’

-

For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘channel-delete’ would be referenced by this method.

-

ex. -url(r’channels/(?P<slug>[wd-]+)/(?P<pk>[0-9]+)/delete/$’,

-
-

ChannelDeleteView.as_view(), name=’channel-delete’)

-
-

If no View has been created and defined in urls.py, returns an -HTML anchor.

-

This method is naive and simply returns a path. Securing access to -the actual view and limiting who can delete this object is the developer’s -responsibility.

-
-
Returns
-

path (str) – URI path to object deletion page, if defined.

-
-
-
- -
-
-get_absolute_url()
-

Returns the URI path for a View that allows users to view details for -this object.

-

ex. Oscar (Character) = ‘/characters/oscar/1/’

-

For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘channel-detail’ would be referenced by this method.

-

ex.

-
url(r'channels/(?P<slug>[\w\d\-]+)/$',
-    ChannelDetailView.as_view(), name='channel-detail')
-
-
-

If no View has been created and defined in urls.py, returns an -HTML anchor.

-

This method is naive and simply returns a path. Securing access to -the actual view and limiting who can view this object is the developer’s -responsibility.

-
-
Returns
-

path (str) – URI path to object detail page, if defined.

-
-
-
- -
-
-message_transform(*args, **kwargs)[source]
-
- -
-
-distribute_message(msgobj, online=False, **kwargs)[source]
-
- -
-
-format_senders(senders=None, **kwargs)[source]
-
- -
-
-pose_transform(msgobj, sender_string, **kwargs)[source]
-
- -
-
-format_external(msgobj, senders, emit=False, **kwargs)[source]
-
- -
-
-format_message(msgobj, emit=False, **kwargs)[source]
-
- -
-
-pre_send_message(msg, **kwargs)[source]
-
- -
-
-post_send_message(msg, **kwargs)[source]
-
- -
-
-exception DoesNotExist
-

Bases: evennia.comms.models.ChannelDB.DoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: evennia.comms.models.ChannelDB.MultipleObjectsReturned

-
- -
-
-path = 'evennia.comms.comms.DefaultChannel'
-
- -
-
-typename = 'DefaultChannel'
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.comms.html b/docs/0.9.5/api/evennia.comms.html deleted file mode 100644 index 54a3b41133..0000000000 --- a/docs/0.9.5/api/evennia.comms.html +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - evennia.comms — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.comms

-

This sub-package contains Evennia’s comms-system, a set of models and -handlers for in-game communication via channels and messages as well -as code related to external communication like IRC or RSS.

- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.comms.managers.html b/docs/0.9.5/api/evennia.comms.managers.html deleted file mode 100644 index 0e2d3b4965..0000000000 --- a/docs/0.9.5/api/evennia.comms.managers.html +++ /dev/null @@ -1,448 +0,0 @@ - - - - - - - - - evennia.comms.managers — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.comms.managers

-

These managers define helper methods for accessing the database from -Comm system components.

-
-
-exception evennia.comms.managers.CommError[source]
-

Bases: Exception

-

Raised by comm system, to allow feedback to player when caught.

-
- -
-
-evennia.comms.managers.identify_object(inp)[source]
-

Helper function. Identifies if an object is an account or an object; -return its database model

-
-
Parameters
-

inp (any) – Entity to be idtified.

-
-
Returns
-

identified (tuple)

-
-
This is a tuple with (inp, identifier)

where identifier is one of “account”, “object”, “channel”, -“string”, “dbref” or None.

-
-
-

-
-
-
- -
-
-evennia.comms.managers.to_object(inp, objtype='account')[source]
-

Locates the object related to the given accountname or channel key. -If input was already the correct object, return it.

-
-
Parameters
-
    -
  • inp (any) – The input object/string

  • -
  • objtype (str) – Either ‘account’ or ‘channel’.

  • -
-
-
Returns
-

obj (object) – The correct object related to inp.

-
-
-
- -
-
-class evennia.comms.managers.MsgManager(*args, **kwargs)[source]
-

Bases: evennia.typeclasses.managers.TypedObjectManager

-

This MsgManager implements methods for searching and manipulating -Messages directly from the database.

-

These methods will all return database objects (or QuerySets) -directly.

-

A Message represents one unit of communication, be it over a -Channel or via some form of in-game mail system. Like an e-mail, -it always has a sender and can have any number of receivers (some -of which may be Channels).

-
-
-identify_object(inp)[source]
-

Wrapper to identify_object if accessing via the manager directly.

-
-
Parameters
-

inp (any) – Entity to be idtified.

-
-
Returns
-

identified (tuple)

-
-
This is a tuple with (inp, identifier)

where identifier is one of “account”, “object”, “channel”, -“string”, “dbref” or None.

-
-
-

-
-
-
- -
-
-get_message_by_id(idnum)[source]
-

Retrieve message by its id.

-
-
Parameters
-

idnum (int or str) – The dbref to retrieve.

-
-
Returns
-

message (Msg) – The message.

-
-
-
- -
-
-get_messages_by_sender(sender)[source]
-

Get all messages sent by one entity - this could be either a -account or an object

-
-
Parameters
-

sender (Account or Object) – The sender of the message.

-
-
Returns
-

QuerySet – Matching messages.

-
-
Raises
-

CommError – For incorrect sender types.

-
-
-
- -
-
-get_messages_by_receiver(recipient)[source]
-

Get all messages sent to one given recipient.

-
-
Parameters
-

recipient (Object, Account or Channel) – The recipient of the messages to search for.

-
-
Returns
-

Queryset – Matching messages.

-
-
Raises
-

CommError – If the recipient is not of a valid type.

-
-
-
- -
-
-search_message(sender=None, receiver=None, freetext=None, dbref=None)[source]
-

Search the message database for particular messages. At least -one of the arguments must be given to do a search.

-
-
Parameters
-
    -
  • sender (Object, Account or Script, optional) – Get messages sent by a particular sender.

  • -
  • receiver (Object, Account or Channel, optional) – Get messages -received by a certain account,object or channel

  • -
  • freetext (str) – Search for a text string in a message. NOTE: -This can potentially be slow, so make sure to supply one of -the other arguments to limit the search.

  • -
  • dbref (int) – The exact database id of the message. This will override -all other search criteria since it’s unique and -always gives only one match.

  • -
-
-
Returns
-

Queryset – Iterable with 0, 1 or more matches.

-
-
-
- -
- -

Search the message database for particular messages. At least -one of the arguments must be given to do a search.

-
-
Parameters
-
    -
  • sender (Object, Account or Script, optional) – Get messages sent by a particular sender.

  • -
  • receiver (Object, Account or Channel, optional) – Get messages -received by a certain account,object or channel

  • -
  • freetext (str) – Search for a text string in a message. NOTE: -This can potentially be slow, so make sure to supply one of -the other arguments to limit the search.

  • -
  • dbref (int) – The exact database id of the message. This will override -all other search criteria since it’s unique and -always gives only one match.

  • -
-
-
Returns
-

Queryset – Iterable with 0, 1 or more matches.

-
-
-
- -
-
-create_message(senderobj, message, receivers=None, locks=None, tags=None, header=None, **kwargs)[source]
-

Create a new communication Msg. Msgs represent a unit of -database-persistent communication between entites.

-
-
Parameters
-
    -
  • senderobj (Object, Account, Script, str or list) – The entity (or -entities) sending the Msg. If a str, this is the id-string -for an external sender type.

  • -
  • message (str) – Text with the message. Eventual headers, titles -etc should all be included in this text string. Formatting -will be retained.

  • -
  • receivers (Object, Account, Script, str or list) – An Account/Object to send -to, or a list of them. If a string, it’s an identifier for an external -receiver.

  • -
  • locks (str) – Lock definition string.

  • -
  • tags (list) – A list of tags or tuples (tag, category).

  • -
  • header (str) – Mime-type or other optional information for the message

  • -
-
-
-

Notes

-

The Comm system is created to be very open-ended, so it’s fully -possible to let a message both go several receivers at the same time, -it’s up to the command definitions to limit this as desired.

-
- -
- -
-
-class evennia.comms.managers.ChannelDBManager(*args, **kwargs)[source]
-

Bases: evennia.typeclasses.managers.TypedObjectManager

-

This ChannelManager implements methods for searching and -manipulating Channels directly from the database.

-

These methods will all return database objects (or QuerySets) -directly.

-

A Channel is an in-game venue for communication. It’s essentially -representation of a re-sender: Users sends Messages to the -Channel, and the Channel re-sends those messages to all users -subscribed to the Channel.

-
-
-get_all_channels()[source]
-

Get all channels.

-
-
Returns
-

channels (list) – All channels in game.

-
-
-
- -
-
-get_channel(channelkey)[source]
-

Return the channel object if given its key. -Also searches its aliases.

-
-
Parameters
-

channelkey (str) – Channel key to search for.

-
-
Returns
-

channel (Channel or None) – A channel match.

-
-
-
- -
-
-get_subscriptions(subscriber)[source]
-

Return all channels a given entity is subscribed to.

-
-
Parameters
-

subscriber (Object or Account) – The one subscribing.

-
-
Returns
-

subscriptions (list) – Channel subscribed to.

-
-
-
- -
-
-search_channel(ostring, exact=True)[source]
-

Search the channel database for a particular channel.

-
-
Parameters
-
    -
  • ostring (str) – The key or database id of the channel.

  • -
  • exact (bool, optional) – Require an exact (but not -case sensitive) match.

  • -
-
-
Returns
-

Queryset – Iterable with 0, 1 or more matches.

-
-
-
- -
-
-create_channel(key, aliases=None, desc=None, locks=None, keep_log=True, typeclass=None, tags=None)[source]
-

Create A communication Channel. A Channel serves as a central hub -for distributing Msgs to groups of people without specifying the -receivers explicitly. Instead accounts may ‘connect’ to the channel -and follow the flow of messages. By default the channel allows -access to all old messages, but this can be turned off with the -keep_log switch.

-
-
Parameters
-

key (str) – This must be unique.

-
-
Keyword Arguments
-
    -
  • aliases (list of str) – List of alternative (likely shorter) keynames.

  • -
  • desc (str) – A description of the channel, for use in listings.

  • -
  • locks (str) – Lockstring.

  • -
  • keep_log (bool) – Log channel throughput.

  • -
  • typeclass (str or class) – The typeclass of the Channel (not -often used).

  • -
  • tags (list) – A list of tags or tuples (tag, category).

  • -
-
-
Returns
-

channel (Channel) – A newly created channel.

-
-
-
- -
- -

Search the channel database for a particular channel.

-
-
Parameters
-
    -
  • ostring (str) – The key or database id of the channel.

  • -
  • exact (bool, optional) – Require an exact (but not -case sensitive) match.

  • -
-
-
Returns
-

Queryset – Iterable with 0, 1 or more matches.

-
-
-
- -
- -
-
-class evennia.comms.managers.ChannelManager(*args, **kwargs)[source]
-

Bases: evennia.comms.managers.ChannelDBManager, evennia.typeclasses.managers.TypeclassManager

-

Wrapper to group the typeclass manager to a consistent name.

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.comms.models.html b/docs/0.9.5/api/evennia.comms.models.html deleted file mode 100644 index 6acb0fc36c..0000000000 --- a/docs/0.9.5/api/evennia.comms.models.html +++ /dev/null @@ -1,815 +0,0 @@ - - - - - - - - - evennia.comms.models — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.comms.models

-

Models for the in-game communication system.

-

The comm system could take the form of channels, but can also be -adopted for storing tells or in-game mail.

-

The comsystem’s main component is the Message (Msg), which carries the -actual information between two parties. Msgs are stored in the -database and usually not deleted. A Msg always have one sender (a -user), but can have any number targets, both users and channels.

-

For non-persistent (and slightly faster) use one can also use the -TempMsg, which mimics the Msg API but without actually saving to the -database.

-

Channels are central objects that act as targets for Msgs. Accounts can -connect to channels by use of a ChannelConnect object (this object is -necessary to easily be able to delete connections on the fly).

-
-
-class evennia.comms.models.Msg(*args, **kwargs)[source]
-

Bases: evennia.utils.idmapper.models.SharedMemoryModel

-

A single message. This model describes all ooc messages -sent in-game, both to channels and between accounts.

-

The Msg class defines the following database fields (all -accessed via specific handler methods):

-
    -
  • db_sender_accounts: Account senders

  • -
  • db_sender_objects: Object senders

  • -
  • db_sender_scripts: Script senders

  • -
  • db_sender_external: External sender (defined as string name)

  • -
  • db_receivers_accounts: Receiving accounts

  • -
  • db_receivers_objects: Receiving objects

  • -
  • db_receivers_scripts: Receiveing scripts

  • -
  • db_receiver_external: External sender (defined as string name)

  • -
  • db_header: Header text

  • -
  • db_message: The actual message text

  • -
  • db_date_created: time message was created / sent

  • -
  • db_hide_from_sender: bool if message should be hidden from sender

  • -
  • db_hide_from_receivers: list of receiver objects to hide message from

  • -
  • db_lock_storage: Internal storage of lock strings.

  • -
-
-
-db_sender_accounts
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-db_sender_objects
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-db_sender_scripts
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-db_sender_external
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_receivers_accounts
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-db_receivers_objects
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-db_receivers_scripts
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-db_receiver_external
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_header
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_message
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_date_created
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_lock_storage
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_hide_from_accounts
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-db_hide_from_objects
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-db_tags
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-objects = <evennia.comms.managers.MsgManager object>
-
- -
-
-locks[source]
-
- -
-
-tags[source]
-
- -
-
-property senders
-

Getter. Allows for value = self.senders

-
- -
-
-remove_sender(senders)[source]
-

Remove a single sender or a list of senders.

-
-
Parameters
-

senders (Account, Object, str or list) – Senders to remove. -If a string, removes the external sender.

-
-
-
- -
-
-property receivers
-

Getter. Allows for value = self.receivers. -Returns four lists of receivers: accounts, objects, scripts and

-
-

external_receivers.

-
-
- -
-
-remove_receiver(receivers)[source]
-

Remove a single receiver, a list of receivers, or a single extral receiver.

-
-
Parameters
-

receivers (Account, Object, Script, list or str) – Receiver -to remove. A string removes the external receiver.

-
-
-
- -
-
-property hide_from
-

Getter. Allows for value = self.hide_from. -Returns two lists of accounts and objects.

-
- -
-
-access(accessing_obj, access_type='read', default=False)[source]
-

Checks lock access.

-
-
Parameters
-
    -
  • accessing_obj (Object or Account) – The object trying to gain access.

  • -
  • access_type (str, optional) – The type of lock access to check.

  • -
  • default (bool) – Fallback to use if access_type lock is not defined.

  • -
-
-
Returns
-

result (bool) – If access was granted or not.

-
-
-
- -
-
-exception DoesNotExist
-

Bases: django.core.exceptions.ObjectDoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: django.core.exceptions.MultipleObjectsReturned

-
- -
-
-property date_created
-

A wrapper for getting database field db_date_created.

-
- -
-
-get_next_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=True, **kwargs)
-
- -
-
-get_previous_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=False, **kwargs)
-
- -
-
-property header
-

A wrapper for getting database field db_header.

-
- -
-
-id
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-property lock_storage
-

A wrapper for getting database field db_lock_storage.

-
- -
-
-property message
-

A wrapper for getting database field db_message.

-
- -
-
-path = 'evennia.comms.models.Msg'
-
- -
-
-property receiver_external
-

A wrapper for getting database field db_receiver_external.

-
- -
-
-property sender_external
-

A wrapper for getting database field db_sender_external.

-
- -
-
-typename = 'SharedMemoryModelBase'
-
- -
- -
-
-class evennia.comms.models.TempMsg(senders=None, receivers=None, message='', header='', type='', lockstring='', hide_from=None)[source]
-

Bases: object

-

This is a non-persistent object for sending temporary messages that will not be stored. It -mimics the “real” Msg object, but doesn’t require sender to be given.

-
-
-__init__(senders=None, receivers=None, message='', header='', type='', lockstring='', hide_from=None)[source]
-

Creates the temp message.

-
-
Parameters
-
    -
  • senders (any or list, optional) – Senders of the message.

  • -
  • receivers (Account, Object, Script or list, optional) – Receivers of this message.

  • -
  • message (str, optional) – Message to send.

  • -
  • header (str, optional) – Header of message.

  • -
  • type (str, optional) – Message class, if any.

  • -
  • lockstring (str, optional) – Lock for the message.

  • -
  • hide_from (Account, Object, or list, optional) – Entities to hide this message from.

  • -
-
-
-
- -
-
-locks[source]
-
- -
-
-remove_sender(sender)[source]
-

Remove a sender or a list of senders.

-
-
Parameters
-

sender (Object, Account, str or list) – Senders to remove.

-
-
-
- -
-
-remove_receiver(receiver)[source]
-

Remove a receiver or a list of receivers

-
-
Parameters
-

receiver (Object, Account, Script, str or list) – Receivers to remove.

-
-
-
- -
-
-access(accessing_obj, access_type='read', default=False)[source]
-

Checks lock access.

-
-
Parameters
-
    -
  • accessing_obj (Object or Account) – The object trying to gain access.

  • -
  • access_type (str, optional) – The type of lock access to check.

  • -
  • default (bool) – Fallback to use if access_type lock is not defined.

  • -
-
-
Returns
-

result (bool) – If access was granted or not.

-
-
-
- -
- -
-
-class evennia.comms.models.ChannelDB(*args, **kwargs)[source]
-

Bases: evennia.typeclasses.models.TypedObject

-

This is the basis of a comm channel, only implementing -the very basics of distributing messages.

-

The Channel class defines the following database fields -beyond the ones inherited from TypedObject:

-
-
    -
  • db_account_subscriptions: The Account subscriptions.

  • -
  • db_object_subscriptions: The Object subscriptions.

  • -
-
-
-
-db_account_subscriptions
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-db_object_subscriptions
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-objects = <evennia.comms.managers.ChannelDBManager object>
-
- -
-
-exception DoesNotExist
-

Bases: django.core.exceptions.ObjectDoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: django.core.exceptions.MultipleObjectsReturned

-
- -
-
-db_attributes
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-db_tags
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-get_next_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=True, **kwargs)
-
- -
-
-get_previous_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=False, **kwargs)
-
- -
-
-id
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-path = 'evennia.comms.models.ChannelDB'
-
- -
-
-typename = 'SharedMemoryModelBase'
-
- -
-
-subscriptions[source]
-
- -
- -
-
-class evennia.comms.models.SubscriptionHandler(obj)[source]
-

Bases: object

-

This handler manages subscriptions to the -channel and hides away which type of entity is -subscribing (Account or Object)

-
-
-__init__(obj)[source]
-

Initialize the handler

-
-
Attr:

obj (ChannelDB): The channel the handler sits on.

-
-
-
- -
-
-has(entity)[source]
-

Check if the given entity subscribe to this channel

-
-
Parameters
-

entity (str, Account or Object) – The entity to return. If -a string, it assumed to be the key or the #dbref -of the entity.

-
-
Returns
-

subscriber (Account, Object or None)

-
-
The given

subscriber.

-
-
-

-
-
-
- -
-
-add(entity)[source]
-

Subscribe an entity to this channel.

-
-
Parameters
-

entity (Account, Object or list) – The entity or -list of entities to subscribe to this channel.

-
-
-
-

Note

-
-
No access-checking is done here, this must have

been done before calling this method. Also -no hooks will be called.

-
-
-
-
- -
-
-remove(entity)[source]
-

Remove a subscriber from the channel.

-
-
Parameters
-

entity (Account, Object or list) – The entity or -entities to un-subscribe from the channel.

-
-
-
- -
-
-all()[source]
-

Get all subscriptions to this channel.

-
-
Returns
-

subscribers (list)

-
-
The subscribers. This

may be a mix of Accounts and Objects!

-
-
-

-
-
-
- -
-
-get()
-

Get all subscriptions to this channel.

-
-
Returns
-

subscribers (list)

-
-
The subscribers. This

may be a mix of Accounts and Objects!

-
-
-

-
-
-
- -
-
-online()[source]
-

Get all online accounts from our cache -:returns: subscribers (list)

-
-
-
Subscribers who are online or

are puppeted by an online account.

-
-
-
-
- -
-
-clear()[source]
-

Remove all subscribers from channel.

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.barter.html b/docs/0.9.5/api/evennia.contrib.barter.html deleted file mode 100644 index 6c35f518e6..0000000000 --- a/docs/0.9.5/api/evennia.contrib.barter.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.barter — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.barter

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.building_menu.html b/docs/0.9.5/api/evennia.contrib.building_menu.html deleted file mode 100644 index afde878bd8..0000000000 --- a/docs/0.9.5/api/evennia.contrib.building_menu.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.building_menu — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.building_menu

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.chargen.html b/docs/0.9.5/api/evennia.contrib.chargen.html deleted file mode 100644 index 45b06e2398..0000000000 --- a/docs/0.9.5/api/evennia.contrib.chargen.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.chargen — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.chargen

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.clothing.html b/docs/0.9.5/api/evennia.contrib.clothing.html deleted file mode 100644 index 28bf50f427..0000000000 --- a/docs/0.9.5/api/evennia.contrib.clothing.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.clothing — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.clothing

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.color_markups.html b/docs/0.9.5/api/evennia.contrib.color_markups.html deleted file mode 100644 index fe71a26672..0000000000 --- a/docs/0.9.5/api/evennia.contrib.color_markups.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.color_markups — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.color_markups

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.custom_gametime.html b/docs/0.9.5/api/evennia.contrib.custom_gametime.html deleted file mode 100644 index 25e12f767a..0000000000 --- a/docs/0.9.5/api/evennia.contrib.custom_gametime.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.custom_gametime — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.custom_gametime

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.dice.html b/docs/0.9.5/api/evennia.contrib.dice.html deleted file mode 100644 index 34ea83cc6f..0000000000 --- a/docs/0.9.5/api/evennia.contrib.dice.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.dice — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.dice

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.email_login.html b/docs/0.9.5/api/evennia.contrib.email_login.html deleted file mode 100644 index dd7139b08a..0000000000 --- a/docs/0.9.5/api/evennia.contrib.email_login.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.email_login — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.email_login

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.extended_room.html b/docs/0.9.5/api/evennia.contrib.extended_room.html deleted file mode 100644 index 38829cec6f..0000000000 --- a/docs/0.9.5/api/evennia.contrib.extended_room.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.extended_room — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.extended_room

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.fieldfill.html b/docs/0.9.5/api/evennia.contrib.fieldfill.html deleted file mode 100644 index 040b948f1c..0000000000 --- a/docs/0.9.5/api/evennia.contrib.fieldfill.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.fieldfill — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.fieldfill

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.gendersub.html b/docs/0.9.5/api/evennia.contrib.gendersub.html deleted file mode 100644 index 83644073f8..0000000000 --- a/docs/0.9.5/api/evennia.contrib.gendersub.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.gendersub — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.gendersub

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.health_bar.html b/docs/0.9.5/api/evennia.contrib.health_bar.html deleted file mode 100644 index 3e86ddc781..0000000000 --- a/docs/0.9.5/api/evennia.contrib.health_bar.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.health_bar — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.health_bar

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.html b/docs/0.9.5/api/evennia.contrib.html deleted file mode 100644 index dd90442877..0000000000 --- a/docs/0.9.5/api/evennia.contrib.html +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - evennia.contrib — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib

-

This sub-package holds Evennia’s contributions - code that may be -useful but are deemed too game-specific to go into the core library.

-

See README.md for more info.

- - -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.ingame_python.callbackhandler.html b/docs/0.9.5/api/evennia.contrib.ingame_python.callbackhandler.html deleted file mode 100644 index a3dd1091ef..0000000000 --- a/docs/0.9.5/api/evennia.contrib.ingame_python.callbackhandler.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.ingame_python.callbackhandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.ingame_python.callbackhandler

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.ingame_python.commands.html b/docs/0.9.5/api/evennia.contrib.ingame_python.commands.html deleted file mode 100644 index 9f72ff56d8..0000000000 --- a/docs/0.9.5/api/evennia.contrib.ingame_python.commands.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.ingame_python.commands — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.ingame_python.commands

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.ingame_python.eventfuncs.html b/docs/0.9.5/api/evennia.contrib.ingame_python.eventfuncs.html deleted file mode 100644 index 6001e80de2..0000000000 --- a/docs/0.9.5/api/evennia.contrib.ingame_python.eventfuncs.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.ingame_python.eventfuncs — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.ingame_python.eventfuncs

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.ingame_python.html b/docs/0.9.5/api/evennia.contrib.ingame_python.html deleted file mode 100644 index a36bf9c92e..0000000000 --- a/docs/0.9.5/api/evennia.contrib.ingame_python.html +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - - - - evennia.contrib.ingame_python — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.ingame_python.scripts.html b/docs/0.9.5/api/evennia.contrib.ingame_python.scripts.html deleted file mode 100644 index 674777647c..0000000000 --- a/docs/0.9.5/api/evennia.contrib.ingame_python.scripts.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.ingame_python.scripts — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.ingame_python.scripts

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.ingame_python.tests.html b/docs/0.9.5/api/evennia.contrib.ingame_python.tests.html deleted file mode 100644 index a355f98e65..0000000000 --- a/docs/0.9.5/api/evennia.contrib.ingame_python.tests.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.ingame_python.tests — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.ingame_python.tests

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.ingame_python.typeclasses.html b/docs/0.9.5/api/evennia.contrib.ingame_python.typeclasses.html deleted file mode 100644 index 2efacbd973..0000000000 --- a/docs/0.9.5/api/evennia.contrib.ingame_python.typeclasses.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.ingame_python.typeclasses — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.ingame_python.typeclasses

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.ingame_python.utils.html b/docs/0.9.5/api/evennia.contrib.ingame_python.utils.html deleted file mode 100644 index 6683818a34..0000000000 --- a/docs/0.9.5/api/evennia.contrib.ingame_python.utils.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.ingame_python.utils — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.ingame_python.utils

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.mail.html b/docs/0.9.5/api/evennia.contrib.mail.html deleted file mode 100644 index feb71fe94a..0000000000 --- a/docs/0.9.5/api/evennia.contrib.mail.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.mail — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.mail

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.mapbuilder.html b/docs/0.9.5/api/evennia.contrib.mapbuilder.html deleted file mode 100644 index 215fc8554a..0000000000 --- a/docs/0.9.5/api/evennia.contrib.mapbuilder.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.mapbuilder — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.mapbuilder

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.menu_login.html b/docs/0.9.5/api/evennia.contrib.menu_login.html deleted file mode 100644 index 3da38f7442..0000000000 --- a/docs/0.9.5/api/evennia.contrib.menu_login.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.menu_login — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.menu_login

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.multidescer.html b/docs/0.9.5/api/evennia.contrib.multidescer.html deleted file mode 100644 index 71b35e35e8..0000000000 --- a/docs/0.9.5/api/evennia.contrib.multidescer.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.multidescer — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.multidescer

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.puzzles.html b/docs/0.9.5/api/evennia.contrib.puzzles.html deleted file mode 100644 index 3fb5e1c5ad..0000000000 --- a/docs/0.9.5/api/evennia.contrib.puzzles.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.puzzles — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.puzzles

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.random_string_generator.html b/docs/0.9.5/api/evennia.contrib.random_string_generator.html deleted file mode 100644 index 344f7cf124..0000000000 --- a/docs/0.9.5/api/evennia.contrib.random_string_generator.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.random_string_generator — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.random_string_generator

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.rplanguage.html b/docs/0.9.5/api/evennia.contrib.rplanguage.html deleted file mode 100644 index f7078030fe..0000000000 --- a/docs/0.9.5/api/evennia.contrib.rplanguage.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.rplanguage — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.rplanguage

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.rpsystem.html b/docs/0.9.5/api/evennia.contrib.rpsystem.html deleted file mode 100644 index db5b4739ca..0000000000 --- a/docs/0.9.5/api/evennia.contrib.rpsystem.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.rpsystem — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.rpsystem

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.security.auditing.html b/docs/0.9.5/api/evennia.contrib.security.auditing.html deleted file mode 100644 index 1e76eec053..0000000000 --- a/docs/0.9.5/api/evennia.contrib.security.auditing.html +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - - - evennia.contrib.security.auditing — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
- - -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.security.auditing.outputs.html b/docs/0.9.5/api/evennia.contrib.security.auditing.outputs.html deleted file mode 100644 index d2ebebc1e3..0000000000 --- a/docs/0.9.5/api/evennia.contrib.security.auditing.outputs.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.security.auditing.outputs — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.security.auditing.outputs

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.security.auditing.server.html b/docs/0.9.5/api/evennia.contrib.security.auditing.server.html deleted file mode 100644 index b9a70efc33..0000000000 --- a/docs/0.9.5/api/evennia.contrib.security.auditing.server.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.security.auditing.server — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.security.auditing.server

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.security.auditing.tests.html b/docs/0.9.5/api/evennia.contrib.security.auditing.tests.html deleted file mode 100644 index 100cec09a1..0000000000 --- a/docs/0.9.5/api/evennia.contrib.security.auditing.tests.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.security.auditing.tests — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.security.auditing.tests

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.security.html b/docs/0.9.5/api/evennia.contrib.security.html deleted file mode 100644 index 6fe0b7692d..0000000000 --- a/docs/0.9.5/api/evennia.contrib.security.html +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - evennia.contrib.security — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
- - -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.simpledoor.html b/docs/0.9.5/api/evennia.contrib.simpledoor.html deleted file mode 100644 index 224d481501..0000000000 --- a/docs/0.9.5/api/evennia.contrib.simpledoor.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.simpledoor — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.simpledoor

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.slow_exit.html b/docs/0.9.5/api/evennia.contrib.slow_exit.html deleted file mode 100644 index d437d0912f..0000000000 --- a/docs/0.9.5/api/evennia.contrib.slow_exit.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.slow_exit — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.slow_exit

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.talking_npc.html b/docs/0.9.5/api/evennia.contrib.talking_npc.html deleted file mode 100644 index 837fa41345..0000000000 --- a/docs/0.9.5/api/evennia.contrib.talking_npc.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.talking_npc — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.talking_npc

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.tree_select.html b/docs/0.9.5/api/evennia.contrib.tree_select.html deleted file mode 100644 index 2f4e57cb19..0000000000 --- a/docs/0.9.5/api/evennia.contrib.tree_select.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.tree_select — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.tree_select

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.turnbattle.html b/docs/0.9.5/api/evennia.contrib.turnbattle.html deleted file mode 100644 index 8ebbfa6ffd..0000000000 --- a/docs/0.9.5/api/evennia.contrib.turnbattle.html +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - evennia.contrib.turnbattle — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
- - -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.turnbattle.tb_basic.html b/docs/0.9.5/api/evennia.contrib.turnbattle.tb_basic.html deleted file mode 100644 index c56c71253e..0000000000 --- a/docs/0.9.5/api/evennia.contrib.turnbattle.tb_basic.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.turnbattle.tb_basic — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.turnbattle.tb_basic

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.turnbattle.tb_equip.html b/docs/0.9.5/api/evennia.contrib.turnbattle.tb_equip.html deleted file mode 100644 index 222eb4df38..0000000000 --- a/docs/0.9.5/api/evennia.contrib.turnbattle.tb_equip.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.turnbattle.tb_equip — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.turnbattle.tb_equip

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.turnbattle.tb_items.html b/docs/0.9.5/api/evennia.contrib.turnbattle.tb_items.html deleted file mode 100644 index 51f09fc270..0000000000 --- a/docs/0.9.5/api/evennia.contrib.turnbattle.tb_items.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.turnbattle.tb_items — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.turnbattle.tb_items

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.turnbattle.tb_magic.html b/docs/0.9.5/api/evennia.contrib.turnbattle.tb_magic.html deleted file mode 100644 index 5dd5719424..0000000000 --- a/docs/0.9.5/api/evennia.contrib.turnbattle.tb_magic.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.turnbattle.tb_magic — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.turnbattle.tb_magic

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.turnbattle.tb_range.html b/docs/0.9.5/api/evennia.contrib.turnbattle.tb_range.html deleted file mode 100644 index 6b09deb33f..0000000000 --- a/docs/0.9.5/api/evennia.contrib.turnbattle.tb_range.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.turnbattle.tb_range — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.turnbattle.tb_range

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_examples.bodyfunctions.html b/docs/0.9.5/api/evennia.contrib.tutorial_examples.bodyfunctions.html deleted file mode 100644 index acf296eaa2..0000000000 --- a/docs/0.9.5/api/evennia.contrib.tutorial_examples.bodyfunctions.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.tutorial_examples.bodyfunctions — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.tutorial_examples.bodyfunctions

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_examples.cmdset_red_button.html b/docs/0.9.5/api/evennia.contrib.tutorial_examples.cmdset_red_button.html deleted file mode 100644 index bb8b49afa4..0000000000 --- a/docs/0.9.5/api/evennia.contrib.tutorial_examples.cmdset_red_button.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.tutorial_examples.cmdset_red_button — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.tutorial_examples.cmdset_red_button

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_examples.example_batch_code.html b/docs/0.9.5/api/evennia.contrib.tutorial_examples.example_batch_code.html deleted file mode 100644 index 8f57f87131..0000000000 --- a/docs/0.9.5/api/evennia.contrib.tutorial_examples.example_batch_code.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.tutorial_examples.example_batch_code — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.tutorial_examples.example_batch_code

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_examples.html b/docs/0.9.5/api/evennia.contrib.tutorial_examples.html deleted file mode 100644 index 76fe742ba0..0000000000 --- a/docs/0.9.5/api/evennia.contrib.tutorial_examples.html +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - evennia.contrib.tutorial_examples — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_examples.red_button.html b/docs/0.9.5/api/evennia.contrib.tutorial_examples.red_button.html deleted file mode 100644 index 2fe14c0a06..0000000000 --- a/docs/0.9.5/api/evennia.contrib.tutorial_examples.red_button.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.tutorial_examples.red_button — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.tutorial_examples.red_button

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_examples.red_button_scripts.html b/docs/0.9.5/api/evennia.contrib.tutorial_examples.red_button_scripts.html deleted file mode 100644 index 0353ef852d..0000000000 --- a/docs/0.9.5/api/evennia.contrib.tutorial_examples.red_button_scripts.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.tutorial_examples.red_button_scripts — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.tutorial_examples.red_button_scripts

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_examples.tests.html b/docs/0.9.5/api/evennia.contrib.tutorial_examples.tests.html deleted file mode 100644 index 37b6e0380b..0000000000 --- a/docs/0.9.5/api/evennia.contrib.tutorial_examples.tests.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.tutorial_examples.tests — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.tutorial_examples.tests

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_world.html b/docs/0.9.5/api/evennia.contrib.tutorial_world.html deleted file mode 100644 index 5e2bd0ee48..0000000000 --- a/docs/0.9.5/api/evennia.contrib.tutorial_world.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - - - evennia.contrib.tutorial_world — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
- - -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_world.intro_menu.html b/docs/0.9.5/api/evennia.contrib.tutorial_world.intro_menu.html deleted file mode 100644 index 783b64eb29..0000000000 --- a/docs/0.9.5/api/evennia.contrib.tutorial_world.intro_menu.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.tutorial_world.intro_menu — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.tutorial_world.intro_menu

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_world.mob.html b/docs/0.9.5/api/evennia.contrib.tutorial_world.mob.html deleted file mode 100644 index d5aea9823b..0000000000 --- a/docs/0.9.5/api/evennia.contrib.tutorial_world.mob.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.tutorial_world.mob — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.tutorial_world.mob

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_world.objects.html b/docs/0.9.5/api/evennia.contrib.tutorial_world.objects.html deleted file mode 100644 index e12587691a..0000000000 --- a/docs/0.9.5/api/evennia.contrib.tutorial_world.objects.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.tutorial_world.objects — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.tutorial_world.objects

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.tutorial_world.rooms.html b/docs/0.9.5/api/evennia.contrib.tutorial_world.rooms.html deleted file mode 100644 index 643f931dd9..0000000000 --- a/docs/0.9.5/api/evennia.contrib.tutorial_world.rooms.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.tutorial_world.rooms — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.tutorial_world.rooms

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.unixcommand.html b/docs/0.9.5/api/evennia.contrib.unixcommand.html deleted file mode 100644 index 6118a8f5aa..0000000000 --- a/docs/0.9.5/api/evennia.contrib.unixcommand.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.unixcommand — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.unixcommand

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.contrib.wilderness.html b/docs/0.9.5/api/evennia.contrib.wilderness.html deleted file mode 100644 index 3dbd51bbb0..0000000000 --- a/docs/0.9.5/api/evennia.contrib.wilderness.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.contrib.wilderness — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.contrib.wilderness

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.help.admin.html b/docs/0.9.5/api/evennia.help.admin.html deleted file mode 100644 index ee591c9c2c..0000000000 --- a/docs/0.9.5/api/evennia.help.admin.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.help.admin — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.help.admin

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.help.html b/docs/0.9.5/api/evennia.help.html deleted file mode 100644 index 603c79d935..0000000000 --- a/docs/0.9.5/api/evennia.help.html +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - - - - evennia.help — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.help

-

This sub-package defines the help system of Evennia. It is pretty -simple, mainly consisting of a database model to hold help entries. -The auto-cmd-help is rather handled by the default ‘help’ command -itself.

- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.help.manager.html b/docs/0.9.5/api/evennia.help.manager.html deleted file mode 100644 index 18e87b9ae8..0000000000 --- a/docs/0.9.5/api/evennia.help.manager.html +++ /dev/null @@ -1,277 +0,0 @@ - - - - - - - - - evennia.help.manager — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.help.manager

-

Custom manager for HelpEntry objects.

-
-
-class evennia.help.manager.HelpEntryManager(*args, **kwargs)[source]
-

Bases: evennia.typeclasses.managers.TypedObjectManager

-

This HelpEntryManager implements methods for searching -and manipulating HelpEntries directly from the database.

-

These methods will all return database objects -(or QuerySets) directly.

-

Evennia-specific: -find_topicmatch -find_apropos -find_topicsuggestions -find_topics_with_category -all_to_category -search_help (equivalent to evennia.search_helpentry)

-
-
-find_topicmatch(topicstr, exact=False)[source]
-

Searches for matching topics or aliases based on player’s -input.

-
-
Parameters
-
    -
  • topcistr (str) – Help topic to search for.

  • -
  • exact (bool, optional) – Require exact match -(non-case-sensitive). If False (default), match -sub-parts of the string.

  • -
-
-
Returns
-

matches (HelpEntries) – Query results.

-
-
-
- -
-
-find_apropos(topicstr)[source]
-

Do a very loose search, returning all help entries containing -the search criterion in their titles.

-
-
Parameters
-

topicstr (str) – Search criterion.

-
-
Returns
-

matches (HelpEntries) – Query results.

-
-
-
- -
-
-find_topicsuggestions(topicstr)[source]
-

Do a fuzzy match, preferably within the category of the -current topic.

-
-
Parameters
-

topicstr (str) – Search criterion.

-
-
Returns
-

matches (Helpentries) – Query results.

-
-
-
- -
-
-find_topics_with_category(help_category)[source]
-

Search topics having a particular category.

-
-
Parameters
-

help_category (str) – Category query criterion.

-
-
Returns
-

matches (HelpEntries) – Query results.

-
-
-
- -
-
-get_all_topics()[source]
-

Get all topics.

-
-
Returns
-

all (HelpEntries) – All topics.

-
-
-
- -
-
-get_all_categories()[source]
-

Return all defined category names with at least one topic in -them.

-
-
Returns
-

matches (list)

-
-
Unique list of category names across all

topics.

-
-
-

-
-
-
- -
-
-all_to_category(default_category)[source]
-

Shifts all help entries in database to default_category. This -action cannot be reverted. It is used primarily by the engine -when importing a default help database, making sure this ends -up in one easily separated category.

-
-
Parameters
-

default_category (str) – Category to move entries to.

-
-
-
- -
-
-search_help(ostring, help_category=None)[source]
-

Retrieve a search entry object.

-
-
Parameters
-
    -
  • ostring (str) – The help topic to look for.

  • -
  • category (str) – Limit the search to a particular help topic

  • -
-
-
Returns
-

Queryset – An iterable with 0, 1 or more matches.

-
-
-
- -
-
-create_help(key, entrytext, category='General', locks=None, aliases=None, tags=None)[source]
-

Create a static help entry in the help database. Note that Command -help entries are dynamic and directly taken from the __doc__ -entries of the command. The database-stored help entries are -intended for more general help on the game, more extensive info, -in-game setting information and so on.

-
-
Parameters
-
    -
  • key (str) – The name of the help entry.

  • -
  • entrytext (str) – The body of te help entry

  • -
  • category (str, optional) – The help category of the entry.

  • -
  • locks (str, optional) – A lockstring to restrict access.

  • -
  • aliases (list of str, optional) – List of alternative (likely shorter) keynames.

  • -
  • tags (lst, optional) – List of tags or tuples (tag, category).

  • -
-
-
Returns
-

help (HelpEntry) – A newly created help entry.

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.help.models.html b/docs/0.9.5/api/evennia.help.models.html deleted file mode 100644 index 00e3160855..0000000000 --- a/docs/0.9.5/api/evennia.help.models.html +++ /dev/null @@ -1,440 +0,0 @@ - - - - - - - - - evennia.help.models — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.help.models

-

Models for the help system.

-

The database-tied help system is only half of Evennia’s help -functionality, the other one being the auto-generated command help -that is created on the fly from each command’s __doc__ string. The -persistent database system defined here is intended for all other -forms of help that do not concern commands, like information about the -game world, policy info, rules and similar.

-
-
-class evennia.help.models.HelpEntry(*args, **kwargs)[source]
-

Bases: evennia.utils.idmapper.models.SharedMemoryModel

-

A generic help entry.

-
-
An HelpEntry object has the following properties defined:

key - main name of entry -help_category - which category entry belongs to (defaults to General) -entrytext - the actual help text -permissions - perm strings

-
-
Method:

access

-
-
-
-
-db_key
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_help_category
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_entrytext
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_lock_storage
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_tags
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-db_date_created
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-objects = <evennia.help.manager.HelpEntryManager object>
-
- -
-
-locks[source]
-
- -
-
-tags[source]
-
- -
-
-aliases[source]
-
- -
-
-access(accessing_obj, access_type='read', default=True)[source]
-

Determines if another object has permission to access this help entry.

-
-
Accesses used by default:

‘read’ - read the help entry itself. -‘view’ - see help entry in help index.

-
-
-
-
Parameters
-
    -
  • accessing_obj (Object or Account) – Entity trying to access this one.

  • -
  • access_type (str) – type of access sought.

  • -
  • default (bool) – What to return if no lock of access_type was found.

  • -
-
-
-
- -
-
-property search_index_entry
-

Property for easily retaining a search index entry for this object.

-
- -
-
-web_get_admin_url()[source]
-

Returns the URI path for the Django Admin page for this object.

-

ex. Account#1 = ‘/admin/accounts/accountdb/1/change/’

-
-
Returns
-

path (str) – URI path to Django Admin page for object.

-
-
-
- -
-
-classmethod web_get_create_url()[source]
-

Returns the URI path for a View that allows users to create new -instances of this object.

-

ex. Chargen = ‘/characters/create/’

-

For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-create’ would be referenced by this method.

-

ex.

-
url(r'characters/create/', ChargenView.as_view(), name='character-create')
-
-
-

If no View has been created and defined in urls.py, returns an -HTML anchor.

-

This method is naive and simply returns a path. Securing access to -the actual view and limiting who can create new objects is the -developer’s responsibility.

-
-
Returns
-

path (str) – URI path to object creation page, if defined.

-
-
-
- -
-
-web_get_detail_url()[source]
-

Returns the URI path for a View that allows users to view details for -this object.

-

ex. Oscar (Character) = ‘/characters/oscar/1/’

-

For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-detail’ would be referenced by this method.

-

ex.

-
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$',
-    CharDetailView.as_view(), name='character-detail')
-
-
-

If no View has been created and defined in urls.py, returns an -HTML anchor.

-

This method is naive and simply returns a path. Securing access to -the actual view and limiting who can view this object is the developer’s -responsibility.

-
-
Returns
-

path (str) – URI path to object detail page, if defined.

-
-
-
- -
-
-web_get_update_url()[source]
-

Returns the URI path for a View that allows users to update this -object.

-

ex. Oscar (Character) = ‘/characters/oscar/1/change/’

-

For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-update’ would be referenced by this method.

-

ex.

-
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$',
-    CharUpdateView.as_view(), name='character-update')
-
-
-

If no View has been created and defined in urls.py, returns an -HTML anchor.

-

This method is naive and simply returns a path. Securing access to -the actual view and limiting who can modify objects is the developer’s -responsibility.

-
-
Returns
-

path (str) – URI path to object update page, if defined.

-
-
-
- -
-
-web_get_delete_url()[source]
-

Returns the URI path for a View that allows users to delete this object.

-

ex. Oscar (Character) = ‘/characters/oscar/1/delete/’

-

For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-detail’ would be referenced by this method.

-

ex.

-
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/delete/$',
-    CharDeleteView.as_view(), name='character-delete')
-
-
-

If no View has been created and defined in urls.py, returns an -HTML anchor.

-

This method is naive and simply returns a path. Securing access to -the actual view and limiting who can delete this object is the developer’s -responsibility.

-
-
Returns
-

path (str) – URI path to object deletion page, if defined.

-
-
-
- -
-
-get_absolute_url()
-

Returns the URI path for a View that allows users to view details for -this object.

-

ex. Oscar (Character) = ‘/characters/oscar/1/’

-

For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-detail’ would be referenced by this method.

-

ex.

-
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$',
-    CharDetailView.as_view(), name='character-detail')
-
-
-

If no View has been created and defined in urls.py, returns an -HTML anchor.

-

This method is naive and simply returns a path. Securing access to -the actual view and limiting who can view this object is the developer’s -responsibility.

-
-
Returns
-

path (str) – URI path to object detail page, if defined.

-
-
-
- -
-
-exception DoesNotExist
-

Bases: django.core.exceptions.ObjectDoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: django.core.exceptions.MultipleObjectsReturned

-
- -
-
-property date_created
-

A wrapper for getting database field db_date_created.

-
- -
-
-property entrytext
-

A wrapper for getting database field db_entrytext.

-
- -
-
-get_next_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=True, **kwargs)
-
- -
-
-get_previous_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=False, **kwargs)
-
- -
-
-property help_category
-

A wrapper for getting database field db_help_category.

-
- -
-
-id
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-property key
-

A wrapper for getting database field db_key.

-
- -
-
-property lock_storage
-

A wrapper for getting database field db_lock_storage.

-
- -
-
-path = 'evennia.help.models.HelpEntry'
-
- -
-
-typename = 'SharedMemoryModelBase'
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.html b/docs/0.9.5/api/evennia.html deleted file mode 100644 index 51dbd004cb..0000000000 --- a/docs/0.9.5/api/evennia.html +++ /dev/null @@ -1,504 +0,0 @@ - - - - - - - - - evennia — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia

-

Evennia MU* creation system.

-

Online manual and API docs are found at http://www.evennia.com.

-

Flat-API shortcut names:

-
    -
  • evennia.ANSIString

  • -
  • evennia.AccountDB

  • -
  • evennia.ChannelDB

  • -
  • evennia.CmdSet

  • -
  • evennia.Command

  • -
  • evennia.DefaultAccount

  • -
  • evennia.DefaultChannel

  • -
  • evennia.DefaultCharacter

  • -
  • evennia.DefaultExit

  • -
  • evennia.DefaultGuest

  • -
  • evennia.DefaultObject

  • -
  • evennia.DefaultRoom

  • -
  • evennia.DefaultScript

  • -
  • evennia.EvEditor

  • -
  • evennia.EvForm

  • -
  • evennia.EvMenu

  • -
  • evennia.EvMore

  • -
  • evennia.EvTable

  • -
  • evennia.GLOBAL_SCRIPTS

  • -
  • evennia.InterruptCommand

  • -
  • evennia.MONITOR_HANDLER

  • -
  • evennia.Msg

  • -
  • evennia.OPTION_CLASSES

  • -
  • evennia.ObjectDB

  • -
  • evennia.SESSION_HANDLER

  • -
  • evennia.ScriptDB

  • -
  • evennia.TASK_HANDLER

  • -
  • evennia.TICKER_HANDLER

  • -
  • evennia.ansi

  • -
  • evennia.contrib

  • -
  • evennia.create_account

  • -
  • evennia.create_channel

  • -
  • evennia.create_help_entry

  • -
  • evennia.create_message

  • -
  • evennia.create_object

  • -
  • evennia.create_script

  • -
  • evennia.default_cmds

  • -
  • evennia.gametime

  • -
  • evennia.inputhandler

  • -
  • evennia.lockfuncs

  • -
  • evennia.logger

  • -
  • evennia.managers

  • -
  • evennia.search_account

  • -
  • evennia.search_channel

  • -
  • evennia.search_help

  • -
  • evennia.search_message

  • -
  • evennia.search_object

  • -
  • evennia.search_script

  • -
  • evennia.search_tag

  • -
  • evennia.set_trace

  • -
  • evennia.settings

  • -
  • evennia.signals

  • -
  • evennia.spawn

  • -
  • evennia.syscmdkeys

  • -
-
-
-evennia.set_trace(term_size=140, 80, debugger='auto')[source]
-

Helper function for running a debugger inside the Evennia event loop.

-
-
Parameters
-
    -
  • term_size (tuple, optional) – Only used for Pudb and defines the size of the terminal -(width, height) in number of characters.

  • -
  • debugger (str, optional) – One of ‘auto’, ‘pdb’ or ‘pudb’. Pdb is the standard debugger. Pudb -is an external package with a different, more ‘graphical’, ncurses-based UI. With -‘auto’, will use pudb if possible, otherwise fall back to pdb. Pudb is available through -pip install pudb.

  • -
-
-
-

Notes

-

To use:

-
    -
  1. add this to a line to act as a breakpoint for entering the debugger:

    -
    -

    from evennia import set_trace; set_trace()

    -
    -
  2. -
  3. restart evennia in interactive mode

    -
    -

    evennia istart

    -
    -
  4. -
  5. debugger will appear in the interactive terminal when breakpoint is reached. Exit -with ‘q’, remove the break line and restart server when finished.

  6. -
-
- - -
- -
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.locks.html b/docs/0.9.5/api/evennia.locks.html deleted file mode 100644 index bbfd020273..0000000000 --- a/docs/0.9.5/api/evennia.locks.html +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - evennia.locks — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.locks

-

This sub-package defines the lock (access) mechanism of Evennia. All -lock strings are processed through the lockhandler in this package. It -also contains the default lock functions used in lock definitions.

- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.locks.lockfuncs.html b/docs/0.9.5/api/evennia.locks.lockfuncs.html deleted file mode 100644 index 6b3dd53ece..0000000000 --- a/docs/0.9.5/api/evennia.locks.lockfuncs.html +++ /dev/null @@ -1,464 +0,0 @@ - - - - - - - - - evennia.locks.lockfuncs — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.locks.lockfuncs

-

This module provides a set of permission lock functions for use -with Evennia’s permissions system.

-

To call these locks, make sure this module is included in the -settings tuple PERMISSION_FUNC_MODULES then define a lock on the form -‘<access_type>:func(args)’ and add it to the object’s lockhandler. -Run the access() method of the handler to execute the lock check.

-

Note that accessing_obj and accessed_obj can be any object type -with a lock variable/field, so be careful to not expect -a certain object type.

-
-
-evennia.locks.lockfuncs.true(*args, **kwargs)[source]
-

Always returns True.

-
- -
-
-evennia.locks.lockfuncs.all(*args, **kwargs)[source]
-
- -
-
-evennia.locks.lockfuncs.false(*args, **kwargs)[source]
-

Always returns False

-
- -
-
-evennia.locks.lockfuncs.none(*args, **kwargs)[source]
-
- -
-
-evennia.locks.lockfuncs.superuser(*args, **kwargs)[source]
-
- -
-
-evennia.locks.lockfuncs.self(accessing_obj, accessed_obj, *args, **kwargs)[source]
-

Check if accessing_obj is the same as accessed_obj

-
-
Usage:

self()

-
-
-

This can be used to lock specifically only to -the same object that the lock is defined on.

-
- -
-
-evennia.locks.lockfuncs.perm(accessing_obj, accessed_obj, *args, **kwargs)[source]
-

The basic permission-checker. Ignores case.

-
-
Usage:

perm(<permission>)

-
-
-

where <permission> is the permission accessing_obj must -have in order to pass the lock.

-

If the given permission is part of settings.PERMISSION_HIERARCHY, -permission is also granted to all ranks higher up in the hierarchy.

-

If accessing_object is an Object controlled by an Account, the -permissions of the Account is used unless the Attribute _quell -is set to True on the Object. In this case however, the -LOWEST hieararcy-permission of the Account/Object-pair will be used -(this is order to avoid Accounts potentially escalating their own permissions -by use of a higher-level Object)

-

For non-hierarchical permissions, a puppeted object’s account is checked first, -followed by the puppet (unless quelled, when only puppet’s access is checked).

-
- -
-
-evennia.locks.lockfuncs.perm_above(accessing_obj, accessed_obj, *args, **kwargs)[source]
-

Only allow objects with a permission higher in the permission -hierarchy than the one given. If there is no such higher rank, -it’s assumed we refer to superuser. If no hierarchy is defined, -this function has no meaning and returns False.

-
- -
-
-evennia.locks.lockfuncs.pperm(accessing_obj, accessed_obj, *args, **kwargs)[source]
-

The basic permission-checker only for Account objects. Ignores case.

-
-
Usage:

pperm(<permission>)

-
-
-

where <permission> is the permission accessing_obj must -have in order to pass the lock. If the given permission -is part of _PERMISSION_HIERARCHY, permission is also granted -to all ranks higher up in the hierarchy.

-
- -
-
-evennia.locks.lockfuncs.pperm_above(accessing_obj, accessed_obj, *args, **kwargs)[source]
-

Only allow Account objects with a permission higher in the permission -hierarchy than the one given. If there is no such higher rank, -it’s assumed we refer to superuser. If no hierarchy is defined, -this function has no meaning and returns False.

-
- -
-
-evennia.locks.lockfuncs.dbref(accessing_obj, accessed_obj, *args, **kwargs)[source]
-
-
Usage:

dbref(3)

-
-
-

This lock type checks if the checking object -has a particular dbref. Note that this only -works for checking objects that are stored -in the database (e.g. not for commands)

-
- -
-
-evennia.locks.lockfuncs.pdbref(accessing_obj, accessed_obj, *args, **kwargs)[source]
-

Same as dbref, but making sure accessing_obj is an account.

-
- -
-
-evennia.locks.lockfuncs.id(accessing_obj, accessed_obj, *args, **kwargs)[source]
-

Alias to dbref

-
- -
-
-evennia.locks.lockfuncs.pid(accessing_obj, accessed_obj, *args, **kwargs)[source]
-

Alias to dbref, for Accounts

-
- -
-
-evennia.locks.lockfuncs.attr(accessing_obj, accessed_obj, *args, **kwargs)[source]
-
-
Usage:

attr(attrname) -attr(attrname, value) -attr(attrname, value, compare=type)

-
-
-

where compare’s type is one of (eq,gt,lt,ge,le,ne) and signifies -how the value should be compared with one on accessing_obj (so -compare=gt means the accessing_obj must have a value greater than -the one given).

-

Searches attributes and properties stored on the accessing_obj. -if accessing_obj has a property “obj”, then this is used as -accessing_obj (this makes this usable for Commands too)

-

The first form works like a flag - if the attribute/property -exists on the object, the value is checked for True/False. The -second form also requires that the value of the attribute/property -matches. Note that all retrieved values will be converted to -strings before doing the comparison.

-
- -
-
-evennia.locks.lockfuncs.objattr(accessing_obj, accessed_obj, *args, **kwargs)[source]
-
-
Usage:

objattr(attrname) -objattr(attrname, value) -objattr(attrname, value, compare=type)

-
-
-

Works like attr, except it looks for an attribute on -accessed_obj instead.

-
- -
-
-evennia.locks.lockfuncs.locattr(accessing_obj, accessed_obj, *args, **kwargs)[source]
-
-
Usage:

locattr(attrname) -locattr(attrname, value) -locattr(attrname, value, compare=type)

-
-
-

Works like attr, except it looks for an attribute on -accessing_obj.location, if such an entity exists.

-

if accessing_obj has a property “.obj” (such as is the case for a -Command), then accessing_obj.obj.location is used instead.

-
- -
-
-evennia.locks.lockfuncs.objlocattr(accessing_obj, accessed_obj, *args, **kwargs)[source]
-
-
Usage:

locattr(attrname) -locattr(attrname, value) -locattr(attrname, value, compare=type)

-
-
-

Works like attr, except it looks for an attribute on -accessed_obj.location, if such an entity exists.

-

if accessed_obj has a property “.obj” (such as is the case for a -Command), then accessing_obj.obj.location is used instead.

-
- -
-
-evennia.locks.lockfuncs.attr_eq(accessing_obj, accessed_obj, *args, **kwargs)[source]
-
-
Usage:

attr_gt(attrname, 54)

-
-
-
- -
-
-evennia.locks.lockfuncs.attr_gt(accessing_obj, accessed_obj, *args, **kwargs)[source]
-
-
Usage:

attr_gt(attrname, 54)

-
-
-

Only true if access_obj’s attribute > the value given.

-
- -
-
-evennia.locks.lockfuncs.attr_ge(accessing_obj, accessed_obj, *args, **kwargs)[source]
-
-
Usage:

attr_gt(attrname, 54)

-
-
-

Only true if access_obj’s attribute >= the value given.

-
- -
-
-evennia.locks.lockfuncs.attr_lt(accessing_obj, accessed_obj, *args, **kwargs)[source]
-
-
Usage:

attr_gt(attrname, 54)

-
-
-

Only true if access_obj’s attribute < the value given.

-
- -
-
-evennia.locks.lockfuncs.attr_le(accessing_obj, accessed_obj, *args, **kwargs)[source]
-
-
Usage:

attr_gt(attrname, 54)

-
-
-

Only true if access_obj’s attribute <= the value given.

-
- -
-
-evennia.locks.lockfuncs.attr_ne(accessing_obj, accessed_obj, *args, **kwargs)[source]
-
-
Usage:

attr_gt(attrname, 54)

-
-
-

Only true if access_obj’s attribute != the value given.

-
- -
-
-evennia.locks.lockfuncs.tag(accessing_obj, accessed_obj, *args, **kwargs)[source]
-
-
Usage:

tag(tagkey) -tag(tagkey, category)

-
-
-

Only true if accessing_obj has the specified tag and optional -category. -If accessing_obj has the “.obj” property (such as is the case for -a command), then accessing_obj.obj is used instead.

-
- -
-
-evennia.locks.lockfuncs.objtag(accessing_obj, accessed_obj, *args, **kwargs)[source]
-
-
Usage:

objtag(tagkey) -objtag(tagkey, category)

-
-
-

Only true if accessed_obj has the specified tag and optional -category.

-
- -
-
-evennia.locks.lockfuncs.inside(accessing_obj, accessed_obj, *args, **kwargs)[source]
-
-
Usage:

inside()

-
-
-

True if accessing_obj is ‘inside’ accessing_obj. Note that this only checks -one level down. So if if the lock is on a room, you will pass but not your -inventory (since their location is you, not the locked object). If you -want also nested objects to pass the lock, use the insiderecursive -lockfunc.

-
- -
-
-evennia.locks.lockfuncs.inside_rec(accessing_obj, accessed_obj, *args, **kwargs)[source]
-
-
Usage:

inside_rec()

-
-
-

True if accessing_obj is inside the accessed obj, at up to 10 levels -of recursion (so if this lock is on a room, then an object inside a box -in your inventory will also pass the lock).

-
- -
-
-evennia.locks.lockfuncs.holds(accessing_obj, accessed_obj, *args, **kwargs)[source]
-
-
Usage:
-
holds() checks if accessed_obj or accessed_obj.obj

is held by accessing_obj

-
-
holds(key/dbref) checks if accessing_obj holds an object

with given key/dbref

-
-
holds(attrname, value) checks if accessing_obj holds an

object with the given attrname and value

-
-
-
-
-

This is passed if accessed_obj is carried by accessing_obj (that is, -accessed_obj.location == accessing_obj), or if accessing_obj itself holds -an object matching the given key.

-
- -
-
-evennia.locks.lockfuncs.has_account(accessing_obj, accessed_obj, *args, **kwargs)[source]
-

Only returns true if accessing_obj has_account is true, that is, -this is an account-controlled object. It fails on actual accounts!

-

This is a useful lock for traverse-locking Exits to restrain NPC -mobiles from moving outside their areas.

-
- -
-
-evennia.locks.lockfuncs.serversetting(accessing_obj, accessed_obj, *args, **kwargs)[source]
-

Only returns true if the Evennia settings exists, alternatively has -a certain value.

-
-
Usage:

serversetting(IRC_ENABLED) -serversetting(BASE_SCRIPT_PATH, [‘types’])

-
-
-

A given True/False or integers will be converted properly. Note that -everything will enter this function as strings, so they have to be -unpacked to their real value. We only support basic properties.

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.locks.lockhandler.html b/docs/0.9.5/api/evennia.locks.lockhandler.html deleted file mode 100644 index 7390146696..0000000000 --- a/docs/0.9.5/api/evennia.locks.lockhandler.html +++ /dev/null @@ -1,483 +0,0 @@ - - - - - - - - - evennia.locks.lockhandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.locks.lockhandler

-

A lock defines access to a particular subsystem or property of -Evennia. For example, the “owner” property can be impmemented as a -lock. Or the disability to lift an object or to ban users.

-

A lock consists of three parts:

-
-
    -
  • access_type - this defines what kind of access this lock regulates. This -just a string.

  • -
  • function call - this is one or many calls to functions that will determine -if the lock is passed or not.

  • -
  • lock function(s). These are regular python functions with a special -set of allowed arguments. They should always return a boolean depending -on if they allow access or not.

  • -
-
-

A lock function is defined by existing in one of the modules -listed by settings.LOCK_FUNC_MODULES. It should also always -take four arguments looking like this:

-
-
-
funcname(accessing_obj, accessed_obj, *args, **kwargs):

[…]

-
-
-
-

The accessing object is the object wanting to gain access. -The accessed object is the object this lock resides on -args and kwargs will hold optional arguments and/or keyword arguments -to the function as a list and a dictionary respectively.

-

Example

-
-
perm(accessing_obj, accessed_obj, *args, **kwargs):

“Checking if the object has a particular, desired permission” -if args:

-
-

desired_perm = args[0] -return desired_perm in accessing_obj.permissions.all()

-
-

return False

-
-
-

Lock functions should most often be pretty general and ideally possible to -re-use and combine in various ways to build clever locks.

-

Lock definition (“Lock string”)

-

A lock definition is a string with a special syntax. It is added to -each object’s lockhandler, making that lock available from then on.

-

The lock definition looks like this:

-
-

‘access_type:[NOT] func1(args)[ AND|OR][NOT] func2() …’

-
-

That is, the access_type, a colon followed by calls to lock functions -combined with AND or OR. NOT negates the result of the following call.

-

Example

-

We want to limit who may edit a particular object (let’s call this access_type

-

for ‘edit’, it depends on what the command is looking for). We want this to -only work for those with the Permission ‘Builder’. So we use our lock -function above and define it like this:

-
-

‘edit:perm(Builder)’

-
-

Here, the lock-function perm() will be called with the string -‘Builder’ (accessing_obj and accessed_obj are added automatically, -you only need to add the args/kwargs, if any).

-

If we wanted to make sure the accessing object was BOTH a Builder and a -GoodGuy, we could use AND:

-
-

‘edit:perm(Builder) AND perm(GoodGuy)’

-
-

To allow EITHER Builder and GoodGuys, we replace AND with OR. perm() is just -one example, the lock function can do anything and compare any properties of -the calling object to decide if the lock is passed or not.

-
-

‘lift:attrib(very_strong) AND NOT attrib(bad_back)’

-
-

To make these work, add the string to the lockhandler of the object you want -to apply the lock to:

-
-

obj.lockhandler.add(‘edit:perm(Builder)’)

-
-

From then on, a command that wants to check for ‘edit’ access on this -object would do something like this:

-
-
-
if not target_obj.lockhandler.has_perm(caller, ‘edit’):

caller.msg(“Sorry, you cannot edit that.”)

-
-
-
-

All objects also has a shortcut called ‘access’ that is recommended to -use instead:

-
-
-
if not target_obj.access(caller, ‘edit’):

caller.msg(“Sorry, you cannot edit that.”)

-
-
-
-

Permissions

-

Permissions are just text strings stored in a comma-separated list on -typeclassed objects. The default perm() lock function uses them, -taking into account settings.PERMISSION_HIERARCHY. Also, the -restricted @perm command sets them, but otherwise they are identical -to any other identifier you can use.

-
-
-class evennia.locks.lockhandler.LockHandler(obj)[source]
-

Bases: object

-

This handler should be attached to all objects implementing -permission checks, under the property ‘lockhandler’.

-
-
-__init__(obj)[source]
-

Loads and pre-caches all relevant locks and their functions.

-
-
Parameters
-
    -
  • obj (object) – The object on which the lockhandler is

  • -
  • defined.

  • -
-
-
-
- -
-
-cache_lock_bypass(obj)[source]
-

We cache superuser bypass checks here for efficiency. This -needs to be re-run when an account is assigned to a character. -We need to grant access to superusers. We need to check both -directly on the object (accounts), through obj.account and using -the get_account() method (this sits on serversessions, in some -rare cases where a check is done before the login process has -yet been fully finalized)

-
-
Parameters
-

obj (object) – This is checked for the is_superuser property.

-
-
-
- -
-
-add(lockstring, validate_only=False)[source]
-

Add a new lockstring to handler.

-
-
Parameters
-
    -
  • lockstring (str or list) – A string on the form -“<access_type>:<functions>”. Multiple access types -should be separated by semicolon (;). Alternatively, -a list with lockstrings.

  • -
  • validate_only (bool, optional) – If True, validate the lockstring but -don’t actually store it.

  • -
-
-
Returns
-

success (bool)

-
-
The outcome of the addition, False on

error. If validate_only is True, this will be a tuple -(bool, error), for pass/fail and a string error.

-
-
-

-
-
-
- -
-
-validate(lockstring)[source]
-

Validate lockstring syntactically, without saving it.

-
-
Parameters
-

lockstring (str) – Lockstring to validate.

-
-
Returns
-

valid (bool) – If validation passed or not.

-
-
-
- -
-
-replace(lockstring)[source]
-

Replaces the lockstring entirely.

-
-
Parameters
-

lockstring (str) – The new lock definition.

-
-
Returns
-

success (bool) – False if an error occurred.

-
-
Raises
-

LockException – If a critical error occurred. -If so, the old string is recovered.

-
-
-
- -
-
-get(access_type=None)[source]
-

Get the full lockstring or the lockstring of a particular -access type.

-
-
Parameters
-

access_type (str, optional) –

-
-
Returns
-

lockstring (str)

-
-
The matched lockstring, or the full

lockstring if no access_type was given.

-
-
-

-
-
-
- -
-
-all()[source]
-

Return all lockstrings

-
-
Returns
-

lockstrings (list) – All separate lockstrings

-
-
-
- -
-
-remove(access_type)[source]
-

Remove a particular lock from the handler

-
-
Parameters
-

access_type (str) – The type of lock to remove.

-
-
Returns
-

success (bool)

-
-
If the access_type was not found

in the lock, this returns False.

-
-
-

-
-
-
- -
-
-delete(access_type)
-

Remove a particular lock from the handler

-
-
Parameters
-

access_type (str) – The type of lock to remove.

-
-
Returns
-

success (bool)

-
-
If the access_type was not found

in the lock, this returns False.

-
-
-

-
-
-
- -
-
-clear()[source]
-

Remove all locks in the handler.

-
- -
-
-reset()[source]
-

Set the reset flag, so the the lock will be re-cached at next -checking. This is usually called by @reload.

-
- -
-
-append(access_type, lockstring, op='or')[source]
-

Append a lock definition to access_type if it doesn’t already exist.

-
-
Parameters
-
    -
  • access_type (str) – Access type.

  • -
  • lockstring (str) – A valid lockstring, without the operator to -link it to an eventual existing lockstring.

  • -
  • op (str) – An operator ‘and’, ‘or’, ‘and not’, ‘or not’ used -for appending the lockstring to an existing access-type.

  • -
-
-
-
-

Note

-

The most common use of this method is for use in commands where -the user can specify their own lockstrings. This method allows -the system to auto-add things like Admin-override access.

-
-
- -
-
-check(accessing_obj, access_type, default=False, no_superuser_bypass=False)[source]
-

Checks a lock of the correct type by passing execution off to -the lock function(s).

-
-
Parameters
-
    -
  • accessing_obj (object) – The object seeking access.

  • -
  • access_type (str) – The type of access wanted.

  • -
  • default (bool, optional) – If no suitable lock type is -found, default to this result.

  • -
  • no_superuser_bypass (bool) – Don’t use this unless you -really, really need to, it makes supersusers susceptible -to the lock check.

  • -
-
-
-

Notes

-

A lock is executed in the follwoing way:

-

Parsing the lockstring, we (during cache) extract the valid -lock functions and store their function objects in the right -order along with their args/kwargs. These are now executed in -sequence, creating a list of True/False values. This is put -into the evalstring, which is a string of AND/OR/NOT entries -separated by placeholders where each function result should -go. We just put those results in and evaluate the string to -get a final, combined True/False value for the lockstring.

-

The important bit with this solution is that the full -lockstring is never blindly evaluated, and thus there (should -be) no way to sneak in malign code in it. Only “safe” lock -functions (as defined by your settings) are executed.

-
- -
-
-check_lockstring(accessing_obj, lockstring, no_superuser_bypass=False, default=False, access_type=None)[source]
-

Do a direct check against a lockstring (‘atype:func()..’), -without any intermediary storage on the accessed object.

-
-
Parameters
-
    -
  • accessing_obj (object or None) – The object seeking access. -Importantly, this can be left unset if the lock functions -don’t access it, no updating or storage of locks are made -against this object in this method.

  • -
  • lockstring (str) – Lock string to check, on the form -“access_type:lock_definition” where the access_type -part can potentially be set to a dummy value to just check -a lock condition.

  • -
  • no_superuser_bypass (bool, optional) – Force superusers to heed lock.

  • -
  • default (bool, optional) – Fallback result to use if access_type is set -but no such access_type is found in the given lockstring.

  • -
  • access_type (str, bool) – If set, only this access_type will be looked up -among the locks defined by lockstring.

  • -
-
-
Returns
-

access (bool) – If check is passed or not.

-
-
-
- -
- -
-
-exception evennia.locks.lockhandler.LockException[source]
-

Bases: Exception

-

Raised during an error in a lock.

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.objects.admin.html b/docs/0.9.5/api/evennia.objects.admin.html deleted file mode 100644 index eb840436fa..0000000000 --- a/docs/0.9.5/api/evennia.objects.admin.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.objects.admin — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.objects.admin

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.objects.html b/docs/0.9.5/api/evennia.objects.html deleted file mode 100644 index 36d251aba0..0000000000 --- a/docs/0.9.5/api/evennia.objects.html +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - evennia.objects — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.objects

-

This sub-package defines the basic in-game “Object”. All in-game -objects inherit from classes in this package.

- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.objects.manager.html b/docs/0.9.5/api/evennia.objects.manager.html deleted file mode 100644 index 7874ff422b..0000000000 --- a/docs/0.9.5/api/evennia.objects.manager.html +++ /dev/null @@ -1,519 +0,0 @@ - - - - - - - - - evennia.objects.manager — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.objects.manager

-

Custom manager for Objects.

-
-
-class evennia.objects.manager.ObjectManager(*args, **kwargs)[source]
-

Bases: evennia.objects.manager.ObjectDBManager, evennia.typeclasses.managers.TypeclassManager

-
- -
-
-class evennia.objects.manager.ObjectDBManager(*args, **kwargs)[source]
-

Bases: evennia.typeclasses.managers.TypedObjectManager

-

This ObjectManager implements methods for searching -and manipulating Objects directly from the database.

-

Evennia-specific search methods (will return Typeclasses or -lists of Typeclasses, whereas Django-general methods will return -Querysets or database objects).

-

dbref (converter) -dbref_search -get_dbref_range -object_totals -typeclass_search -get_object_with_account -get_objs_with_key_and_typeclass -get_objs_with_attr -get_objs_with_attr_match -get_objs_with_db_property -get_objs_with_db_property_match -get_objs_with_key_or_alias -get_contents -object_search (interface to many of the above methods,

-
-

equivalent to evennia.search_object)

-
-

copy_object

-
-
-get_object_with_account(ostring, exact=True, candidates=None)[source]
-

Search for an object based on its account’s name or dbref.

-
-
Parameters
-
    -
  • ostring (str or int) – Search criterion or dbref. Searching -for an account is sometimes initiated by appending an * to -the beginning of the search criterion (e.g. in -local_and_global_search). This is stripped here.

  • -
  • exact (bool, optional) – Require an exact account match.

  • -
  • candidates (list, optional) – Only search among this list of possible -object candidates.

  • -
-
-
Returns
-

match (query) – Matching query.

-
-
-
- -
-
-get_objs_with_key_and_typeclass(oname, otypeclass_path, candidates=None)[source]
-

Returns objects based on simultaneous key and typeclass match.

-
-
Parameters
-
    -
  • oname (str) – Object key to search for

  • -
  • otypeclass_path (str) – Full Python path to tyepclass to search for

  • -
  • candidates (list, optional) – Only match among the given list of candidates.

  • -
-
-
Returns
-

matches (query) – The matching objects.

-
-
-
- -
-
-get_objs_with_attr(attribute_name, candidates=None)[source]
-

Get objects based on having a certain Attribute defined.

-
-
Parameters
-
    -
  • attribute_name (str) – Attribute name to search for.

  • -
  • candidates (list, optional) – Only match among the given list of object -candidates.

  • -
-
-
Returns
-

matches (query) – All objects having the given attribute_name defined at all.

-
-
-
- -
-
-get_objs_with_attr_value(attribute_name, attribute_value, candidates=None, typeclasses=None)[source]
-

Get all objects having the given attrname set to the given value.

-
-
Parameters
-
    -
  • attribute_name (str) – Attribute key to search for.

  • -
  • attribute_value (any) – Attribute value to search for. This can also be database -objects.

  • -
  • candidates (list, optional) – Candidate objects to limit search to.

  • -
  • typeclasses (list, optional) – Python pats to restrict matches with.

  • -
-
-
Returns
-

Queryset

-
-
Iterable with 0, 1 or more matches fullfilling both the attribute_name and

attribute_value criterions.

-
-
-

-
-
-

Notes

-

This uses the Attribute’s PickledField to transparently search the database by matching -the internal representation. This is reasonably effective but since Attribute values -cannot be indexed, searching by Attribute key is to be preferred whenever possible.

-
- -
-
-get_objs_with_db_property(property_name, candidates=None)[source]
-

Get all objects having a given db field property.

-
-
Parameters
-
    -
  • property_name (str) – The name of the field to match for.

  • -
  • candidates (list, optional) – Only search among th egiven candidates.

  • -
-
-
Returns
-

matches (list) – The found matches.

-
-
-
- -
-
-get_objs_with_db_property_value(property_name, property_value, candidates=None, typeclasses=None)[source]
-

Get objects with a specific field name and value.

-
-
Parameters
-
    -
  • property_name (str) – Field name to search for.

  • -
  • property_value (any) – Value required for field with property_name to have.

  • -
  • candidates (list, optional) – List of objects to limit search to.

  • -
  • typeclasses (list, optional) – List of typeclass-path strings to restrict matches with

  • -
-
-
Returns
-

Queryset – Iterable with 0, 1 or more matches.

-
-
-
- -
-
-get_contents(location, excludeobj=None)[source]
-

Get all objects that has a location set to this one.

-
-
Parameters
-
    -
  • location (Object) – Where to get contents from.

  • -
  • excludeobj (Object or list, optional) – One or more objects -to exclude from the match.

  • -
-
-
Returns
-

Queryset – Iterable with 0, 1 or more matches.

-
-
-
- -
-
-get_objs_with_key_or_alias(ostring, exact=True, candidates=None, typeclasses=None)[source]
-
-
Parameters
-
    -
  • ostring (str) – A search criterion.

  • -
  • exact (bool, optional) – Require exact match of ostring -(still case-insensitive). If False, will do fuzzy matching -using evennia.utils.utils.string_partial_matching algorithm.

  • -
  • candidates (list) – Only match among these candidates.

  • -
  • typeclasses (list) – Only match objects with typeclasses having thess path strings.

  • -
-
-
Returns
-

Queryset – An iterable with 0, 1 or more matches.

-
-
-
- -
-
-search_object(searchdata, attribute_name=None, typeclass=None, candidates=None, exact=True, use_dbref=True)[source]
-

Search as an object globally or in a list of candidates and -return results. The result is always an Object. Always returns -a list.

-
-
Parameters
-
    -
  • searchdata (str or Object) – The entity to match for. This is -usually a key string but may also be an object itself. -By default (if no attribute_name is set), this will -search object.key and object.aliases in order. -Can also be on the form #dbref, which will (if -exact=True) be matched against primary key.

  • -
  • attribute_name (str) – Use this named Attribute to -match searchdata against, instead of the defaults. If -this is the name of a database field (with or without -the db_ prefix), that will be matched too.

  • -
  • typeclass (str or TypeClass) – restrict matches to objects -having this typeclass. This will help speed up global -searches.

  • -
  • candidates (list) – If supplied, search will -only be performed among the candidates in this list. A -common list of candidates is the contents of the -current location searched.

  • -
  • exact (bool) – Match names/aliases exactly or partially. -Partial matching matches the beginning of words in the -names/aliases, using a matching routine to separate -multiple matches in names with multiple components (so -“bi sw” will match “Big sword”). Since this is more -expensive than exact matching, it is recommended to be -used together with the candidates keyword to limit the -number of possibilities. This value has no meaning if -searching for attributes/properties.

  • -
  • use_dbref (bool) – If False, bypass direct lookup of a string -on the form #dbref and treat it like any string.

  • -
-
-
Returns
-

matches (list) – Matching objects

-
-
-
- -
- -

Search as an object globally or in a list of candidates and -return results. The result is always an Object. Always returns -a list.

-
-
Parameters
-
    -
  • searchdata (str or Object) – The entity to match for. This is -usually a key string but may also be an object itself. -By default (if no attribute_name is set), this will -search object.key and object.aliases in order. -Can also be on the form #dbref, which will (if -exact=True) be matched against primary key.

  • -
  • attribute_name (str) – Use this named Attribute to -match searchdata against, instead of the defaults. If -this is the name of a database field (with or without -the db_ prefix), that will be matched too.

  • -
  • typeclass (str or TypeClass) – restrict matches to objects -having this typeclass. This will help speed up global -searches.

  • -
  • candidates (list) – If supplied, search will -only be performed among the candidates in this list. A -common list of candidates is the contents of the -current location searched.

  • -
  • exact (bool) – Match names/aliases exactly or partially. -Partial matching matches the beginning of words in the -names/aliases, using a matching routine to separate -multiple matches in names with multiple components (so -“bi sw” will match “Big sword”). Since this is more -expensive than exact matching, it is recommended to be -used together with the candidates keyword to limit the -number of possibilities. This value has no meaning if -searching for attributes/properties.

  • -
  • use_dbref (bool) – If False, bypass direct lookup of a string -on the form #dbref and treat it like any string.

  • -
-
-
Returns
-

matches (list) – Matching objects

-
-
-
- -
-
-search(searchdata, attribute_name=None, typeclass=None, candidates=None, exact=True, use_dbref=True)
-

Search as an object globally or in a list of candidates and -return results. The result is always an Object. Always returns -a list.

-
-
Parameters
-
    -
  • searchdata (str or Object) – The entity to match for. This is -usually a key string but may also be an object itself. -By default (if no attribute_name is set), this will -search object.key and object.aliases in order. -Can also be on the form #dbref, which will (if -exact=True) be matched against primary key.

  • -
  • attribute_name (str) – Use this named Attribute to -match searchdata against, instead of the defaults. If -this is the name of a database field (with or without -the db_ prefix), that will be matched too.

  • -
  • typeclass (str or TypeClass) – restrict matches to objects -having this typeclass. This will help speed up global -searches.

  • -
  • candidates (list) – If supplied, search will -only be performed among the candidates in this list. A -common list of candidates is the contents of the -current location searched.

  • -
  • exact (bool) – Match names/aliases exactly or partially. -Partial matching matches the beginning of words in the -names/aliases, using a matching routine to separate -multiple matches in names with multiple components (so -“bi sw” will match “Big sword”). Since this is more -expensive than exact matching, it is recommended to be -used together with the candidates keyword to limit the -number of possibilities. This value has no meaning if -searching for attributes/properties.

  • -
  • use_dbref (bool) – If False, bypass direct lookup of a string -on the form #dbref and treat it like any string.

  • -
-
-
Returns
-

matches (list) – Matching objects

-
-
-
- -
-
-copy_object(original_object, new_key=None, new_location=None, new_home=None, new_permissions=None, new_locks=None, new_aliases=None, new_destination=None)[source]
-

Create and return a new object as a copy of the original object. All -will be identical to the original except for the arguments given -specifically to this method. Object contents will not be copied.

-
-
Parameters
-
    -
  • original_object (Object) – The object to make a copy from.

  • -
  • new_key (str, optional) – Name of the copy, if different -from the original.

  • -
  • new_location (Object, optional) – Alternate location.

  • -
  • new_home (Object, optional) – Change the home location

  • -
  • new_aliases (list, optional) – Give alternate object -aliases as a list of strings.

  • -
  • new_destination (Object, optional) – Used only by exits.

  • -
-
-
Returns
-

copy (Object or None)

-
-
The copy of original_object,

optionally modified as per the ingoing keyword -arguments. None if an error was encountered.

-
-
-

-
-
-
- -
-
-clear_all_sessids()[source]
-

Clear the db_sessid field of all objects having also the -db_account field set.

-
- -
-
-create_object(typeclass=None, key=None, location=None, home=None, permissions=None, locks=None, aliases=None, tags=None, destination=None, report_to=None, nohome=False, attributes=None, nattributes=None)[source]
-

Create a new in-game object.

-
-
Keyword Arguments
-
    -
  • typeclass (class or str) – Class or python path to a typeclass.

  • -
  • key (str) – Name of the new object. If not set, a name of -#dbref will be set.

  • -
  • location (Object or str) – Obj or #dbref to use as the location of the new object.

  • -
  • home (Object or str) – Obj or #dbref to use as the object’s home location.

  • -
  • permissions (list) – A list of permission strings or tuples (permstring, category).

  • -
  • locks (str) – one or more lockstrings, separated by semicolons.

  • -
  • aliases (list) – A list of alternative keys or tuples (aliasstring, category).

  • -
  • tags (list) – List of tag keys or tuples (tagkey, category) or (tagkey, category, data).

  • -
  • destination (Object or str) – Obj or #dbref to use as an Exit’s target.

  • -
  • report_to (Object) – The object to return error messages to.

  • -
  • nohome (bool) – This allows the creation of objects without a -default home location; only used when creating the default -location itself or during unittests.

  • -
  • attributes (list) – Tuples on the form (key, value) or (key, value, category), -(key, value, lockstring) or (key, value, lockstring, default_access). -to set as Attributes on the new object.

  • -
  • nattributes (list) – Non-persistent tuples on the form (key, value). Note that -adding this rarely makes sense since this data will not survive a reload.

  • -
-
-
Returns
-

object (Object) – A newly created object of the given typeclass.

-
-
Raises
-

ObjectDB.DoesNotExist – If trying to create an Object with -location or home that can’t be found.

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.objects.models.html b/docs/0.9.5/api/evennia.objects.models.html deleted file mode 100644 index 63fa22518c..0000000000 --- a/docs/0.9.5/api/evennia.objects.models.html +++ /dev/null @@ -1,591 +0,0 @@ - - - - - - - - - evennia.objects.models — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.objects.models

-

This module defines the database models for all in-game objects, that -is, all objects that has an actual existence in-game.

-

Each database object is ‘decorated’ with a ‘typeclass’, a normal -python class that implements all the various logics needed by the game -in question. Objects created of this class transparently communicate -with its related database object for storing all attributes. The -admin should usually not have to deal directly with this database -object layer.

-

Attributes are separate objects that store values persistently onto -the database object. Like everything else, they can be accessed -transparently through the decorating TypeClass.

-
-
-class evennia.objects.models.ContentsHandler(obj)[source]
-

Bases: object

-

Handles and caches the contents of an object to avoid excessive -lookups (this is done very often due to cmdhandler needing to look -for object-cmdsets). It is stored on the ‘contents_cache’ property -of the ObjectDB.

-
-
-__init__(obj)[source]
-

Sets up the contents handler.

-
-
Parameters
-

obj (Object) – The object on which the -handler is defined

-
-
-
- -
-
-load()[source]
-

Retrieves all objects from database. Used for initializing.

-
-
Returns
-

Objects (list of ObjectDB)

-
-
-
- -
-
-init()[source]
-

Re-initialize the content cache

-
- -
-
-get(exclude=None, content_type=None)[source]
-

Return the contents of the cache.

-
-
Parameters
-
    -
  • exclude (Object or list of Object) – object(s) to ignore

  • -
  • content_type (str or None) – Filter list by a content-type. If None, don’t filter.

  • -
-
-
Returns
-

objects (list) – the Objects inside this location

-
-
-
- -
-
-add(obj)[source]
-

Add a new object to this location

-
-
Parameters
-

obj (Object) – object to add

-
-
-
- -
-
-remove(obj)[source]
-

Remove object from this location

-
-
Parameters
-

obj (Object) – object to remove

-
-
-
- -
-
-clear()[source]
-

Clear the contents cache and re-initialize

-
- -
- -
-
-class evennia.objects.models.ObjectDB(*args, **kwargs)[source]
-

Bases: evennia.typeclasses.models.TypedObject

-

All objects in the game use the ObjectDB model to store -data in the database. This is handled transparently through -the typeclass system.

-

Note that the base objectdb is very simple, with -few defined fields. Use attributes to extend your -type class with new database-stored variables.

-

The TypedObject supplies the following (inherited) properties:

-
-
    -
  • key - main name

  • -
  • name - alias for key

  • -
  • db_typeclass_path - the path to the decorating typeclass

  • -
  • db_date_created - time stamp of object creation

  • -
  • permissions - perm strings

  • -
  • locks - lock definitions (handler)

  • -
  • dbref - #id of object

  • -
  • db - persistent attribute storage

  • -
  • ndb - non-persistent attribute storage

  • -
-
-

The ObjectDB adds the following properties:

-
-
    -
  • account - optional connected account (always together with sessid)

  • -
  • sessid - optional connection session id (always together with account)

  • -
  • location - in-game location of object

  • -
  • home - safety location for object (handler)

  • -
  • scripts - scripts assigned to object (handler from typeclass)

  • -
  • cmdset - active cmdset on object (handler from typeclass)

  • -
  • aliases - aliases for this object (property)

  • -
  • nicks - nicknames for other things in Evennia (handler)

  • -
  • sessions - sessions connected to this object (see also account)

  • -
  • has_account - bool if an active account is currently connected

  • -
  • contents - other objects having this object as location

  • -
  • exits - exits from this object

  • -
-
-
-
-db_account
-

Accessor to the related object on the forward side of a many-to-one or -one-to-one (via ForwardOneToOneDescriptor subclass) relation.

-

In the example:

-
class Child(Model):
-    parent = ForeignKey(Parent, related_name='children')
-
-
-

**Child.parent** is a **ForwardManyToOneDescriptor** instance.

-
- -
-
-db_sessid
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_location
-

Accessor to the related object on the forward side of a many-to-one or -one-to-one (via ForwardOneToOneDescriptor subclass) relation.

-

In the example:

-
class Child(Model):
-    parent = ForeignKey(Parent, related_name='children')
-
-
-

**Child.parent** is a **ForwardManyToOneDescriptor** instance.

-
- -
-
-db_home
-

Accessor to the related object on the forward side of a many-to-one or -one-to-one (via ForwardOneToOneDescriptor subclass) relation.

-

In the example:

-
class Child(Model):
-    parent = ForeignKey(Parent, related_name='children')
-
-
-

**Child.parent** is a **ForwardManyToOneDescriptor** instance.

-
- -
-
-db_destination
-

Accessor to the related object on the forward side of a many-to-one or -one-to-one (via ForwardOneToOneDescriptor subclass) relation.

-

In the example:

-
class Child(Model):
-    parent = ForeignKey(Parent, related_name='children')
-
-
-

**Child.parent** is a **ForwardManyToOneDescriptor** instance.

-
- -
-
-db_cmdset_storage
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-objects = <evennia.objects.manager.ObjectDBManager object>
-
- -
-
-contents_cache[source]
-
- -
-
-property cmdset_storage
-

getter

-
- -
-
-property location
-

Get location

-
- -
-
-at_db_location_postsave(new)[source]
-

This is called automatically after the location field was -saved, no matter how. It checks for a variable -_safe_contents_update to know if the save was triggered via -the location handler (which updates the contents cache) or -not.

-
-
Parameters
-

new (bool) – Set if this location has not yet been saved before.

-
-
-
- -
-
-exception DoesNotExist
-

Bases: django.core.exceptions.ObjectDoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: django.core.exceptions.MultipleObjectsReturned

-
- -
-
-property account
-

A wrapper for getting database field db_account.

-
- -
-
-db_account_id
-
- -
-
-db_attributes
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-db_destination_id
-
- -
-
-db_home_id
-
- -
-
-db_location_id
-
- -
-
-db_tags
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-property destination
-

A wrapper for getting database field db_destination.

-
- -
-
-destinations_set
-

Accessor to the related objects manager on the reverse side of a -many-to-one relation.

-

In the example:

-
class Child(Model):
-    parent = ForeignKey(Parent, related_name='children')
-
-
-

**Parent.children** is a **ReverseManyToOneDescriptor** instance.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-get_next_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=True, **kwargs)
-
- -
-
-get_previous_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=False, **kwargs)
-
- -
-
-hide_from_objects_set
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-property home
-

A wrapper for getting database field db_home.

-
- -
-
-homes_set
-

Accessor to the related objects manager on the reverse side of a -many-to-one relation.

-

In the example:

-
class Child(Model):
-    parent = ForeignKey(Parent, related_name='children')
-
-
-

**Parent.children** is a **ReverseManyToOneDescriptor** instance.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-id
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-locations_set
-

Accessor to the related objects manager on the reverse side of a -many-to-one relation.

-

In the example:

-
class Child(Model):
-    parent = ForeignKey(Parent, related_name='children')
-
-
-

**Parent.children** is a **ReverseManyToOneDescriptor** instance.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-object_subscription_set
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-path = 'evennia.objects.models.ObjectDB'
-
- -
-
-receiver_object_set
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-scriptdb_set
-

Accessor to the related objects manager on the reverse side of a -many-to-one relation.

-

In the example:

-
class Child(Model):
-    parent = ForeignKey(Parent, related_name='children')
-
-
-

**Parent.children** is a **ReverseManyToOneDescriptor** instance.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-sender_object_set
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-property sessid
-

A wrapper for getting database field db_sessid.

-
- -
-
-typename = 'SharedMemoryModelBase'
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.objects.objects.html b/docs/0.9.5/api/evennia.objects.objects.html deleted file mode 100644 index dbea22c1cf..0000000000 --- a/docs/0.9.5/api/evennia.objects.objects.html +++ /dev/null @@ -1,2270 +0,0 @@ - - - - - - - - - evennia.objects.objects — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.objects.objects

-

This module defines the basic DefaultObject and its children -DefaultCharacter, DefaultAccount, DefaultRoom and DefaultExit. -These are the (default) starting points for all in-game visible -entities.

-

This is the v1.0 develop version (for ref in doc building).

-
-
-class evennia.objects.objects.ObjectSessionHandler(obj)[source]
-

Bases: object

-

Handles the get/setting of the sessid comma-separated integer field

-
-
-__init__(obj)[source]
-

Initializes the handler.

-
-
Parameters
-

obj (Object) – The object on which the handler is defined.

-
-
-
- -
-
-get(sessid=None)[source]
-

Get the sessions linked to this Object.

-
-
Parameters
-

sessid (int, optional) – A specific session id.

-
-
Returns
-

sessions (list)

-
-
The sessions connected to this object. If sessid is given,

this is a list of one (or zero) elements.

-
-
-

-
-
-

Notes

-

Aliased to self.all().

-
- -
-
-all()[source]
-

Alias to get(), returning all sessions.

-
-
Returns
-

sessions (list) – All sessions.

-
-
-
- -
-
-add(session)[source]
-

Add session to handler.

-
-
Parameters
-

session (Session or int) – Session or session id to add.

-
-
-

Notes

-

We will only add a session/sessid if this actually also exists -in the the core sessionhandler.

-
- -
-
-remove(session)[source]
-

Remove session from handler.

-
-
Parameters
-

session (Session or int) – Session or session id to remove.

-
-
-
- -
-
-clear()[source]
-

Clear all handled sessids.

-
- -
-
-count()[source]
-

Get amount of sessions connected.

-
-
Returns
-

sesslen (int) – Number of sessions handled.

-
-
-
- -
- -
-
-class evennia.objects.objects.DefaultObject(*args, **kwargs)[source]
-

Bases: evennia.objects.models.ObjectDB

-

This is the root typeclass object, representing all entities that -have an actual presence in-game. DefaultObjects generally have a -location. They can also be manipulated and looked at. Game -entities you define should inherit from DefaultObject at some distance.

-

It is recommended to create children of this class using the -evennia.create_object() function rather than to initialize the class -directly - this will both set things up and efficiently save the object -without obj.save() having to be called explicitly.

-
-
-lockstring = 'control:id({account_id}) or perm(Admin);delete:id({account_id}) or perm(Admin)'
-
- -
-
-objects = <evennia.objects.manager.ObjectManager object>
-
- -
-
-appearance_template = '\n{header}\n|c{name}|n\n{desc}\n{exits}{characters}{things}\n{footer}\n '
-
- -
-
-cmdset[source]
-
- -
-
-scripts[source]
-
- -
-
-nicks[source]
-
- -
-
-sessions[source]
-
- -
-
-property is_connected
-
- -
-
-property has_account
-

Convenience property for checking if an active account is -currently connected to this object.

-
- -
-
-property is_superuser
-

Check if user has an account, and if so, if it is a superuser.

-
- -
-
-contents_get(exclude=None, content_type=None)[source]
-

Returns the contents of this object, i.e. all -objects that has this object set as its location. -This should be publically available.

-
-
Parameters
-
    -
  • exclude (Object) – Object to exclude from returned -contents list

  • -
  • content_type (str) – A content_type to filter by. None for no -filtering.

  • -
-
-
Returns
-

contents (list) – List of contents of this Object.

-
-
-

Notes

-

Also available as the contents property, minus exclusion -and filtering.

-
- -
-
-contents_set(*args)[source]
-

You cannot replace this property

-
- -
-
-property contents
-

Returns the contents of this object, i.e. all -objects that has this object set as its location. -This should be publically available.

-
-
Parameters
-
    -
  • exclude (Object) – Object to exclude from returned -contents list

  • -
  • content_type (str) – A content_type to filter by. None for no -filtering.

  • -
-
-
Returns
-

contents (list) – List of contents of this Object.

-
-
-

Notes

-

Also available as the contents property, minus exclusion -and filtering.

-
- -
-
-property exits
-

Returns all exits from this object, i.e. all objects at this -location having the property destination != None.

-
- -
-
-get_display_name(looker=None, **kwargs)[source]
-

Displays the name of the object in a viewer-aware manner.

-
-
Parameters
-

looker (TypedObject) – The object or account that is looking -at/getting inforamtion for this object.

-
-
Returns
-

name (str)

-
-
A string containing the name of the object,

including the DBREF if this user is privileged to control -said object.

-
-
-

-
-
-

Notes

-

This function could be extended to change how object names -appear to users in character, but be wary. This function -does not change an object’s keys or aliases when -searching, and is expected to produce something useful for -builders.

-
- -
-
-get_numbered_name(count, looker, **kwargs)[source]
-

Return the numbered (singular, plural) forms of this object’s key. This is by default called -by return_appearance and is used for grouping multiple same-named of this object. Note that -this will be called on every member of a group even though the plural name will be only -shown once. Also the singular display version, such as ‘an apple’, ‘a tree’ is determined -from this method.

-
-
Parameters
-
    -
  • count (int) – Number of objects of this type

  • -
  • looker (Object) – Onlooker. Not used by default.

  • -
-
-
Keyword Arguments
-

key (str) – Optional key to pluralize, if given, use this instead of the object’s key.

-
-
Returns
-

singular (str) – The singular form to display. -plural (str): The determined plural form of the key, including the count.

-
-
-
- -
-
-search(searchdata, global_search=False, use_nicks=True, typeclass=None, location=None, attribute_name=None, quiet=False, exact=False, candidates=None, nofound_string=None, multimatch_string=None, use_dbref=None, stacked=0)[source]
-

Returns an Object matching a search string/condition

-

Perform a standard object search in the database, handling -multiple results and lack thereof gracefully. By default, only -objects in the current location of self or its inventory are searched for.

-
-
Parameters
-
    -
  • searchdata (str or obj) –

    Primary search criterion. Will be matched -against object.key (with object.aliases second) unless -the keyword attribute_name specifies otherwise.

    -

    Special keywords:

    -
      -
    • #<num>: search by unique dbref. This is always a global search.

    • -
    • me,self: self-reference to this object

    • -
    • -
      <num>-<string> - can be used to differentiate

      between multiple same-named matches. The exact form of this input -is given by settings.SEARCH_MULTIMATCH_REGEX.

      -
      -
      -
    • -
    -

  • -
  • global_search (bool) – Search all objects globally. This overrules ‘location’ data.

  • -
  • use_nicks (bool) – Use nickname-replace (nicktype “object”) on searchdata.

  • -
  • typeclass (str or Typeclass, or list of either) – Limit search only -to Objects with this typeclass. May be a list of typeclasses -for a broader search.

  • -
  • location (Object or list) – Specify a location or multiple locations -to search. Note that this is used to query the contents of a -location and will not match for the location itself - -if you want that, don’t set this or use candidates to specify -exactly which objects should be searched. If this nor candidates are -given, candidates will include caller’s inventory, current location and -all objects in the current location.

  • -
  • attribute_name (str) – Define which property to search. If set, no -key+alias search will be performed. This can be used -to search database fields (db_ will be automatically -prepended), and if that fails, it will try to return -objects having Attributes with this name and value -equal to searchdata. A special use is to search for -“key” here if you want to do a key-search without -including aliases.

  • -
  • quiet (bool) – don’t display default error messages - this tells the -search method that the user wants to handle all errors -themselves. It also changes the return value type, see -below.

  • -
  • exact (bool) – if unset (default) - prefers to match to beginning of -string rather than not matching at all. If set, requires -exact matching of entire string.

  • -
  • candidates (list of objects) – this is an optional custom list of objects -to search (filter) between. It is ignored if global_search -is given. If not set, this list will automatically be defined -to include the location, the contents of location and the -caller’s contents (inventory).

  • -
  • nofound_string (str) – optional custom string for not-found error message.

  • -
  • multimatch_string (str) – optional custom string for multimatch error header.

  • -
  • use_dbref (bool or None, optional) – If True, allow to enter e.g. a query “#123” -to find an object (globally) by its database-id 123. If False, the string “#123” -will be treated like a normal string. If None (default), the ability to query by -#dbref is turned on if self has the permission ‘Builder’ and is turned off -otherwise.

  • -
  • stacked (int, optional) – If > 0, multimatches will be analyzed to determine if they -only contains identical objects; these are then assumed ‘stacked’ and no multi-match -error will be generated, instead stacked number of matches will be returned. If -stacked is larger than number of matches, returns that number of matches. If -the found stack is a mix of objects, return None and handle the multi-match -error depending on the value of quiet.

  • -
-
-
Returns
-

Object, None or list – Will return an Object or None if quiet=False. Will return -a list with 0, 1 or more matches if quiet=True. If stacked is a positive integer, -this list may contain all stacked identical matches.

-
-
-

Notes

-

To find Accounts, use eg. evennia.account_search. If -quiet=False, error messages will be handled by -settings.SEARCH_AT_RESULT and echoed automatically (on -error, return will be None). If quiet=True, the error -messaging is assumed to be handled by the caller.

-
- -
-
-search_account(searchdata, quiet=False)[source]
-

Simple shortcut wrapper to search for accounts, not characters.

-
-
Parameters
-
    -
  • searchdata (str) – Search criterion - the key or dbref of the account -to search for. If this is “here” or “me”, search -for the account connected to this object.

  • -
  • quiet (bool) – Returns the results as a list rather than -echo eventual standard error messages. Default False.

  • -
-
-
Returns
-

result (Account, None or list)

-
-
Just what is returned depends on
-
the quiet setting:
    -
  • quiet=True: No match or multumatch auto-echoes errors -to self.msg, then returns None. The esults are passed -through settings.SEARCH_AT_RESULT and -settings.SEARCH_AT_MULTIMATCH_INPUT. If there is a -unique match, this will be returned.

  • -
  • quiet=True: No automatic error messaging is done, and -what is returned is always a list with 0, 1 or more -matching Accounts.

  • -
-
-
-
-
-

-
-
-
- -
-
-execute_cmd(raw_string, session=None, **kwargs)[source]
-

Do something as this object. This is never called normally, -it’s only used when wanting specifically to let an object be -the caller of a command. It makes use of nicks of eventual -connected accounts as well.

-
-
Parameters
-
    -
  • raw_string (string) – Raw command input

  • -
  • session (Session, optional) – Session to -return results to

  • -
-
-
Keyword Arguments
-
    -
  • keyword arguments will be added to the found command (Other) –

  • -
  • instace as variables before it executes. This is (object) –

  • -
  • by default Evennia but may be used to set flags and (unused) –

  • -
  • operating paramaters for commands at run-time. (change) –

  • -
-
-
Returns
-

defer (Deferred)

-
-
This is an asynchronous Twisted object that

will not fire until the command has actually finished -executing. To overload this one needs to attach -callback functions to it, with addCallback(function). -This function will be called with an eventual return -value from the command execution. This return is not -used at all by Evennia by default, but might be useful -for coders intending to implement some sort of nested -command structure.

-
-
-

-
-
-
- -
-
-msg(text=None, from_obj=None, session=None, options=None, **kwargs)[source]
-

Emits something to a session attached to the object.

-
-
Parameters
-
    -
  • text (str or tuple, optional) – The message to send. This -is treated internally like any send-command, so its -value can be a tuple if sending multiple arguments to -the text oob command.

  • -
  • from_obj (obj or list, optional) – object that is sending. If -given, at_msg_send will be called. This value will be -passed on to the protocol. If iterable, will execute hook -on all entities in it.

  • -
  • session (Session or list, optional) – Session or list of -Sessions to relay data to, if any. If set, will force send -to these sessions. If unset, who receives the message -depends on the MULTISESSION_MODE.

  • -
  • options (dict, optional) – Message-specific option-value -pairs. These will be applied at the protocol level.

  • -
-
-
Keyword Arguments
-

any (string or tuples) – All kwarg keys not listed above -will be treated as send-command names and their arguments -(which can be a string or a tuple).

-
-
-

Notes

-

at_msg_receive will be called on this Object. -All extra kwargs will be passed on to the protocol.

-
- -
-
-for_contents(func, exclude=None, **kwargs)[source]
-

Runs a function on every object contained within this one.

-
-
Parameters
-
    -
  • func (callable) – Function to call. This must have the -formal call sign func(obj, kwargs), where obj is the -object currently being processed and ****kwargs are -passed on from the call to for_contents.

  • -
  • exclude (list, optional) – A list of object not to call the -function on.

  • -
-
-
Keyword Arguments
-

arguments will be passed to the function for all objects. (Keyword) –

-
-
-
- -
-
-msg_contents(text=None, exclude=None, from_obj=None, mapping=None, **kwargs)[source]
-

Emits a message to all objects inside this object.

-
-
Parameters
-
    -
  • text (str or tuple) – Message to send. If a tuple, this should be -on the valid OOB outmessage form (message, {kwargs}), -where kwargs are optional data passed to the text -outputfunc. The message will be parsed for {key} formatting and -$You/$you()/$You(), $obj(name), $conj(verb) and $pron(pronoun, option) -inline function callables. -The name is taken from the mapping kwarg {“name”: object, …}**. -The mapping[key].get_display_name(looker=recipient) will be called -for that key for every recipient of the string.

  • -
  • exclude (list, optional) – A list of objects not to send to.

  • -
  • from_obj (Object, optional) – An object designated as the -“sender” of the message. See DefaultObject.msg() for -more info.

  • -
  • mapping (dict, optional) – A mapping of formatting keys -{“key”:<object>, “key2”:<object2>,…}. -The keys must either match **{key} or $You(key)/$you(key) markers -in the text string. If <object> doesn’t have a get_display_name -method, it will be returned as a string. If not set, a key you will -be auto-added to point to from_obj if given, otherwise to self.

  • -
  • **kwargs – Keyword arguments will be passed on to obj.msg() for all -messaged objects.

  • -
-
-
-

Notes

-

For ‘actor-stance’ reporting (You say/Name says), use the -$You()/$you()/$You(key) and $conj(verb) (verb-conjugation) -inline callables. This will use the respective get_display_name() -for all onlookers except for from_obj or self, which will become -‘You/you’. If you use $You/you(key), the key must be in mapping.

-

For ‘director-stance’ reporting (Name says/Name says), use {key} -syntax directly. For both {key} and You/you(key), -mapping[key].get_display_name(looker=recipient) may be called -depending on who the recipient is.

-

Examples

-

Let’s assume -- player1.key -> “Player1”,

-
-

player1.get_display_name(looker=player2) -> “The First girl”

-
-
    -
  • player2.key -> “Player2”, -player2.get_display_name(looker=player1) -> “The Second girl”

  • -
-

Actor-stance:

-
char.location.msg_contents(
-    "$You() $conj(attack) $you(defender).",
-    mapping={"defender": player2})
-
-
-
    -
  • player1 will see You attack The Second girl.

  • -
  • player2 will see ‘The First girl attacks you.’

  • -
-

Director-stance:

-
char.location.msg_contents(
-    "{attacker} attacks {defender}.",
-    mapping={"attacker:player1, "defender":player2})
-
-
-
    -
  • player1 will see: ‘Player1 attacks The Second girl.’

  • -
  • player2 will see: ‘The First girl attacks Player2’

  • -
-
- -
-
-move_to(destination, quiet=False, emit_to_obj=None, use_destination=True, to_none=False, move_hooks=True, **kwargs)[source]
-

Moves this object to a new location.

-
-
Parameters
-
    -
  • destination (Object) – Reference to the object to move to. This -can also be an exit object, in which case the -destination property is used as destination.

  • -
  • quiet (bool) – If true, turn off the calling of the emit hooks -(announce_move_to/from etc)

  • -
  • emit_to_obj (Object) – object to receive error messages

  • -
  • use_destination (bool) – Default is for objects to use the “destination” -property of destinations as the target to move to. Turning off this -keyword allows objects to move “inside” exit objects.

  • -
  • to_none (bool) – Allow destination to be None. Note that no hooks are run when -moving to a None location. If you want to run hooks, run them manually -(and make sure they can manage None locations).

  • -
  • move_hooks (bool) – If False, turn off the calling of move-related hooks -(at_pre/post_move etc) with quiet=True, this is as quiet a move -as can be done.

  • -
-
-
Keyword Arguments
-

on to announce_move_to and announce_move_from hooks. (Passed) –

-
-
Returns
-

result (bool)

-
-
True/False depending on if there were problems with the move.

This method may also return various error messages to the -emit_to_obj.

-
-
-

-
-
-

Notes

-

No access checks are done in this method, these should be handled before -calling move_to.

-

The DefaultObject hooks called (if move_hooks=True) are, in order:

-
-
    -
  1. self.at_pre_move(destination) (if this returns False, move is aborted)

  2. -
  3. source_location.at_object_leave(self, destination)

  4. -
  5. self.announce_move_from(destination)

  6. -
  7. (move happens here)

  8. -
  9. self.announce_move_to(source_location)

  10. -
  11. destination.at_object_receive(self, source_location)

  12. -
  13. self.at_post_move(source_location)

  14. -
-
-
- -
-
-clear_exits()[source]
-

Destroys all of the exits and any exits pointing to this -object as a destination.

-
- -
-
-clear_contents()[source]
-

Moves all objects (accounts/things) to their home location or -to default home.

-
- -
-
-classmethod create(key, account=None, **kwargs)[source]
-

Creates a basic object with default parameters, unless otherwise -specified or extended.

-

Provides a friendlier interface to the utils.create_object() function.

-
-
Parameters
-
    -
  • key (str) – Name of the new object.

  • -
  • account (Account) – Account to attribute this object to.

  • -
-
-
Keyword Arguments
-
    -
  • description (str) – Brief description for this object.

  • -
  • ip (str) – IP address of creator (for object auditing).

  • -
-
-
Returns
-

object (Object) – A newly created object of the given typeclass. -errors (list): A list of errors in string form, if any.

-
-
-
- -
-
-copy(new_key=None, **kwargs)[source]
-

Makes an identical copy of this object, identical except for a -new dbref in the database. If you want to customize the copy -by changing some settings, use ObjectDB.object.copy_object() -directly.

-
-
Parameters
-

new_key (string) – New key/name of copied object. If new_key is not -specified, the copy will be named <old_key>_copy by default.

-
-
Returns
-

copy (Object) – A copy of this object.

-
-
-
- -
-
-at_object_post_copy(new_obj, **kwargs)[source]
-

Called by DefaultObject.copy(). Meant to be overloaded. In case there’s extra data not -covered by .copy(), this can be used to deal with it.

-
-
Parameters
-

new_obj (Object) – The new Copy of this object.

-
-
Returns
-

None

-
-
-
- -
-
-delete()[source]
-

Deletes this object. Before deletion, this method makes sure -to move all contained objects to their respective home -locations, as well as clean up all exits to/from the object.

-
-
Returns
-

noerror (bool)

-
-
Returns whether or not the delete completed

successfully or not.

-
-
-

-
-
-
- -
-
-access(accessing_obj, access_type='read', default=False, no_superuser_bypass=False, **kwargs)[source]
-

Determines if another object has permission to access this object -in whatever way.

-
-
Parameters
-
    -
  • accessing_obj (Object) – Object trying to access this one.

  • -
  • access_type (str, optional) – Type of access sought.

  • -
  • default (bool, optional) – What to return if no lock of access_type was found.

  • -
  • no_superuser_bypass (bool, optional) – If True, don’t skip -lock check for superuser (be careful with this one).

  • -
-
-
Keyword Arguments
-

on to the at_access hook along with the result of the access check. (Passed) –

-
-
-
- -
-
-at_first_save()[source]
-

This is called by the typeclass system whenever an instance of -this class is saved for the first time. It is a generic hook -for calling the startup hooks for the various game entities. -When overloading you generally don’t overload this but -overload the hooks called by this method.

-
- -
-
-basetype_setup()[source]
-

This sets up the default properties of an Object, just before -the more general at_object_creation.

-

You normally don’t need to change this unless you change some -fundamental things like names of permission groups.

-
- -
-
-basetype_posthook_setup()[source]
-

Called once, after basetype_setup and at_object_creation. This -should generally not be overloaded unless you are redefining -how a room/exit/object works. It allows for basetype-like -setup after the object is created. An example of this is -EXITs, who need to know keys, aliases, locks etc to set up -their exit-cmdsets.

-
- -
-
-at_object_creation()[source]
-

Called once, when this object is first created. This is the -normal hook to overload for most object types.

-
- -
-
-at_object_delete()[source]
-

Called just before the database object is persistently -delete()d from the database. If this method returns False, -deletion is aborted.

-
- -
-
-at_init()[source]
-

This is always called whenever this object is initiated – -that is, whenever it its typeclass is cached from memory. This -happens on-demand first time the object is used or activated -in some way after being created but also after each server -restart or reload.

-
- -
-
-at_cmdset_get(**kwargs)[source]
-

Called just before cmdsets on this object are requested by the -command handler. If changes need to be done on the fly to the -cmdset before passing them on to the cmdhandler, this is the -place to do it. This is called also if the object currently -have no cmdsets.

-
-
Keyword Arguments
-

caller (Session, Object or Account) – The caller requesting -this cmdset.

-
-
-
- -
-
-at_pre_puppet(account, session=None, **kwargs)[source]
-

Called just before an Account connects to this object to puppet -it.

-
-
Parameters
-
    -
  • account (Account) – This is the connecting account.

  • -
  • session (Session) – Session controlling the connection.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-
- -
-
-at_post_puppet(**kwargs)[source]
-

Called just after puppeting has been completed and all -Account<->Object links have been established.

-
-
Parameters
-

**kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

-
-
-
-

Note

-

You can use self.account and self.sessions.get() to get -account and sessions at this point; the last entry in the -list from self.sessions.get() is the latest Session -puppeting this Object.

-
-
- -
-
-at_pre_unpuppet(**kwargs)[source]
-

Called just before beginning to un-connect a puppeting from -this Account.

-
-
Parameters
-

**kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

-
-
-
-

Note

-

You can use self.account and self.sessions.get() to get -account and sessions at this point; the last entry in the -list from self.sessions.get() is the latest Session -puppeting this Object.

-
-
- -
-
-at_post_unpuppet(account, session=None, **kwargs)[source]
-

Called just after the Account successfully disconnected from -this object, severing all connections.

-
-
Parameters
-
    -
  • account (Account) – The account object that just disconnected -from this object.

  • -
  • session (Session) – Session id controlling the connection that -just disconnected.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-
- -
-
-at_server_reload()[source]
-

This hook is called whenever the server is shutting down for -restart/reboot. If you want to, for example, save non-persistent -properties across a restart, this is the place to do it.

-
- -
-
-at_server_shutdown()[source]
-

This hook is called whenever the server is shutting down fully -(i.e. not for a restart).

-
- -
-
-at_access(result, accessing_obj, access_type, **kwargs)[source]
-

This is called with the result of an access call, along with -any kwargs used for that call. The return of this method does -not affect the result of the lock check. It can be used e.g. to -customize error messages in a central location or other effects -based on the access result.

-
-
Parameters
-
    -
  • result (bool) – The outcome of the access call.

  • -
  • accessing_obj (Object or Account) – The entity trying to gain access.

  • -
  • access_type (str) – The type of access that was requested.

  • -
-
-
Keyword Arguments
-
    -
  • used by default, added for possible expandability in a (Not) –

  • -
  • game.

  • -
-
-
-
- -
-
-at_pre_move(destination, **kwargs)[source]
-

Called just before starting to move this object to -destination.

-
-
Parameters
-
    -
  • destination (Object) – The object we are moving to

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
Returns
-

shouldmove (bool) – If we should move or not.

-
-
-

Notes

-

If this method returns False/None, the move is cancelled -before it is even started.

-
- -
-
-at_before_move(destination, **kwargs)
-

Called just before starting to move this object to -destination.

-
-
Parameters
-
    -
  • destination (Object) – The object we are moving to

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
Returns
-

shouldmove (bool) – If we should move or not.

-
-
-

Notes

-

If this method returns False/None, the move is cancelled -before it is even started.

-
- -
-
-announce_move_from(destination, msg=None, mapping=None, **kwargs)[source]
-

Called if the move is to be announced. This is -called while we are still standing in the old -location.

-
-
Parameters
-
    -
  • destination (Object) – The place we are going to.

  • -
  • msg (str, optional) – a replacement message.

  • -
  • mapping (dict, optional) – additional mapping objects.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-

You can override this method and call its parent with a -message to simply change the default message. In the string, -you can use the following as mappings (between braces):

-
-

object: the object which is moving. -exit: the exit from which the object is moving (if found). -origin: the location of the object before the move. -destination: the location of the object after moving.

-
-
- -
-
-announce_move_to(source_location, msg=None, mapping=None, **kwargs)[source]
-

Called after the move if the move was not quiet. At this point -we are standing in the new location.

-
-
Parameters
-
    -
  • source_location (Object) – The place we came from

  • -
  • msg (str, optional) – the replacement message if location.

  • -
  • mapping (dict, optional) – additional mapping objects.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-

Notes

-

You can override this method and call its parent with a -message to simply change the default message. In the string, -you can use the following as mappings (between braces):

-
-

object: the object which is moving. -exit: the exit from which the object is moving (if found). -origin: the location of the object before the move. -destination: the location of the object after moving.

-
-
- -
-
-at_post_move(source_location, **kwargs)[source]
-

Called after move has completed, regardless of quiet mode or -not. Allows changes to the object due to the location it is -now in.

-
-
Parameters
-
    -
  • source_location (Object) – Wwhere we came from. This may be None.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-
- -
-
-at_after_move(source_location, **kwargs)
-

Called after move has completed, regardless of quiet mode or -not. Allows changes to the object due to the location it is -now in.

-
-
Parameters
-
    -
  • source_location (Object) – Wwhere we came from. This may be None.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-
- -
-
-at_object_leave(moved_obj, target_location, **kwargs)[source]
-

Called just before an object leaves from inside this object

-
-
Parameters
-
    -
  • moved_obj (Object) – The object leaving

  • -
  • target_location (Object) – Where moved_obj is going.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-
- -
-
-at_object_receive(moved_obj, source_location, **kwargs)[source]
-

Called after an object has been moved into this object.

-
-
Parameters
-
    -
  • moved_obj (Object) – The object moved into this one

  • -
  • source_location (Object) – Where moved_object came from. -Note that this could be None.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-
- -
-
-at_traverse(traversing_object, target_location, **kwargs)[source]
-

This hook is responsible for handling the actual traversal, -normally by calling -traversing_object.move_to(target_location). It is normally -only implemented by Exit objects. If it returns False (usually -because move_to returned False), at_post_traverse below -should not be called and instead at_failed_traverse should be -called.

-
-
Parameters
-
    -
  • traversing_object (Object) – Object traversing us.

  • -
  • target_location (Object) – Where target is going.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-
- -
-
-at_post_traverse(traversing_object, source_location, **kwargs)[source]
-

Called just after an object successfully used this object to -traverse to another object (i.e. this object is a type of -Exit)

-
-
Parameters
-
    -
  • traversing_object (Object) – The object traversing us.

  • -
  • source_location (Object) – Where traversing_object came from.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-

Notes

-

The target location should normally be available as self.destination.

-
- -
-
-at_after_traverse(traversing_object, source_location, **kwargs)
-

Called just after an object successfully used this object to -traverse to another object (i.e. this object is a type of -Exit)

-
-
Parameters
-
    -
  • traversing_object (Object) – The object traversing us.

  • -
  • source_location (Object) – Where traversing_object came from.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-

Notes

-

The target location should normally be available as self.destination.

-
- -
-
-at_failed_traverse(traversing_object, **kwargs)[source]
-

This is called if an object fails to traverse this object for -some reason.

-
-
Parameters
-
    -
  • traversing_object (Object) – The object that failed traversing us.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-

Notes

-

Using the default exits, this hook will not be called if an -Attribute err_traverse is defined - this will in that case be -read for an error string instead.

-
- -
-
-at_msg_receive(text=None, from_obj=None, **kwargs)[source]
-

This hook is called whenever someone sends a message to this -object using the msg method.

-

Note that from_obj may be None if the sender did not include -itself as an argument to the obj.msg() call - so you have to -check for this. .

-

Consider this a pre-processing method before msg is passed on -to the user session. If this method returns False, the msg -will not be passed on.

-
-
Parameters
-
    -
  • text (str, optional) – The message received.

  • -
  • from_obj (any, optional) – The object sending the message.

  • -
-
-
Keyword Arguments
-

includes any keywords sent to the msg method. (This) –

-
-
Returns
-

receive (bool) – If this message should be received.

-
-
-

Notes

-

If this method returns False, the msg operation -will abort without sending the message.

-
- -
-
-at_msg_send(text=None, to_obj=None, **kwargs)[source]
-

This is a hook that is called when this object sends a -message to another object with obj.msg(text, to_obj=obj).

-
-
Parameters
-
    -
  • text (str, optional) – Text to send.

  • -
  • to_obj (any, optional) – The object to send to.

  • -
-
-
Keyword Arguments
-

passed from msg() (Keywords) –

-
-
-

Notes

-

Since this method is executed by from_obj, if no from_obj -was passed to DefaultCharacter.msg this hook will never -get called.

-
- -
-
-get_visible_contents(looker, **kwargs)[source]
-

Get all contents of this object that a looker can see (whatever that means, by default it -checks the ‘view’ lock), grouped by type. Helper method to return_appearance.

-
-
Parameters
-
    -
  • looker (Object) – The entity looking.

  • -
  • **kwargs (any) – Passed from return_appearance. Unused by default.

  • -
-
-
Returns
-

dict

-
-
A dict of lists categorized by type. Byt default this

contains ‘exits’, ‘characters’ and ‘things’. The elements of these -lists are the actual objects.

-
-
-

-
-
-
- -
-
-get_content_names(looker, **kwargs)[source]
-

Get the proper names for all contents of this object. Helper method -for return_appearance.

-
-
Parameters
-
    -
  • looker (Object) – The entity looking.

  • -
  • **kwargs (any) – Passed from return_appearance. Passed into -get_display_name for each found entity.

  • -
-
-
Returns
-

dict

-
-
A dict of lists categorized by type. Byt default this

contains ‘exits’, ‘characters’ and ‘things’. The elements -of these lists are strings - names of the objects that -can depend on the looker and also be grouped in the case -of multiple same-named things etc.

-
-
-

-
-
-

Notes

-

This method shouldn’t add extra coloring to the names beyond what is -already given by the .get_display_name() (and the .name field) already. -Per-type coloring can be applied in return_apperance.

-
- -
-
-return_appearance(looker, **kwargs)[source]
-

Main callback used by ‘look’ for the object to describe itself. -This formats a description. By default, this looks for the appearance_template -string set on this class and populates it with formatting keys

-
-

‘name’, ‘desc’, ‘exits’, ‘characters’, ‘things’ as well as -(currently empty) ‘header’/’footer’.

-
-
-
Parameters
-
    -
  • looker (Object) – Object doing the looking.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call. This is passed into the helper -methods and into get_display_name calls.

  • -
-
-
Returns
-

str

-
-
The description of this entity. By default this includes

the entity’s name, description and any contents inside it.

-
-
-

-
-
-

Notes

-

To simply change the layout of how the object displays itself (like -adding some line decorations or change colors of different sections), -you can simply edit .appearance_template. You only need to override -this method (and/or its helpers) if you want to change what is passed -into the template or want the most control over output.

-
- -
-
-at_look(target, **kwargs)[source]
-

Called when this object performs a look. It allows to -customize just what this means. It will not itself -send any data.

-
-
Parameters
-
    -
  • target (Object) – The target being looked at. This is -commonly an object or the current location. It will -be checked for the “view” type access.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call. This will be passed into -return_appearance, get_display_name and at_desc but is not used -by default.

  • -
-
-
Returns
-

lookstring (str)

-
-
A ready-processed look string

potentially ready to return to the looker.

-
-
-

-
-
-
- -
-
-at_desc(looker=None, **kwargs)[source]
-

This is called whenever someone looks at this object.

-
-
Parameters
-
    -
  • looker (Object, optional) – The object requesting the description.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-
- -
-
-at_pre_get(getter, **kwargs)[source]
-

Called by the default get command before this object has been -picked up.

-
-
Parameters
-
    -
  • getter (Object) – The object about to get this object.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
Returns
-

shouldget (bool) – If the object should be gotten or not.

-
-
-

Notes

-

If this method returns False/None, the getting is cancelled -before it is even started.

-
- -
-
-at_before_get(getter, **kwargs)
-

Called by the default get command before this object has been -picked up.

-
-
Parameters
-
    -
  • getter (Object) – The object about to get this object.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
Returns
-

shouldget (bool) – If the object should be gotten or not.

-
-
-

Notes

-

If this method returns False/None, the getting is cancelled -before it is even started.

-
- -
-
-at_get(getter, **kwargs)[source]
-

Called by the default get command when this object has been -picked up.

-
-
Parameters
-
    -
  • getter (Object) – The object getting this object.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-

Notes

-

This hook cannot stop the pickup from happening. Use -permissions or the at_pre_get() hook for that.

-
- -
-
-at_pre_give(giver, getter, **kwargs)[source]
-

Called by the default give command before this object has been -given.

-
-
Parameters
-
    -
  • giver (Object) – The object about to give this object.

  • -
  • getter (Object) – The object about to get this object.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
Returns
-

shouldgive (bool) – If the object should be given or not.

-
-
-

Notes

-

If this method returns False/None, the giving is cancelled -before it is even started.

-
- -
-
-at_before_give(giver, getter, **kwargs)
-

Called by the default give command before this object has been -given.

-
-
Parameters
-
    -
  • giver (Object) – The object about to give this object.

  • -
  • getter (Object) – The object about to get this object.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
Returns
-

shouldgive (bool) – If the object should be given or not.

-
-
-

Notes

-

If this method returns False/None, the giving is cancelled -before it is even started.

-
- -
-
-at_give(giver, getter, **kwargs)[source]
-

Called by the default give command when this object has been -given.

-
-
Parameters
-
    -
  • giver (Object) – The object giving this object.

  • -
  • getter (Object) – The object getting this object.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-

Notes

-

This hook cannot stop the give from happening. Use -permissions or the at_pre_give() hook for that.

-
- -
-
-at_pre_drop(dropper, **kwargs)[source]
-

Called by the default drop command before this object has been -dropped.

-
-
Parameters
-
    -
  • dropper (Object) – The object which will drop this object.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
Returns
-

shoulddrop (bool) – If the object should be dropped or not.

-
-
-

Notes

-

If this method returns False/None, the dropping is cancelled -before it is even started.

-
- -
-
-at_before_drop(dropper, **kwargs)
-

Called by the default drop command before this object has been -dropped.

-
-
Parameters
-
    -
  • dropper (Object) – The object which will drop this object.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
Returns
-

shoulddrop (bool) – If the object should be dropped or not.

-
-
-

Notes

-

If this method returns False/None, the dropping is cancelled -before it is even started.

-
- -
-
-at_drop(dropper, **kwargs)[source]
-

Called by the default drop command when this object has been -dropped.

-
-
Parameters
-
    -
  • dropper (Object) – The object which just dropped this object.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-

Notes

-

This hook cannot stop the drop from happening. Use -permissions or the at_pre_drop() hook for that.

-
- -
-
-at_pre_say(message, **kwargs)[source]
-

Before the object says something.

-

This hook is by default used by the ‘say’ and ‘whisper’ -commands as used by this command it is called before the text -is said/whispered and can be used to customize the outgoing -text from the object. Returning None aborts the command.

-
-
Parameters
-

message (str) – The suggested say/whisper text spoken by self.

-
-
Keyword Arguments
-
    -
  • whisper (bool) – If True, this is a whisper rather than -a say. This is sent by the whisper command by default. -Other verbal commands could use this hook in similar -ways.

  • -
  • receivers (Object or iterable) – If set, this is the target or targets for the -say/whisper.

  • -
-
-
Returns
-

message (str) – The (possibly modified) text to be spoken.

-
-
-
- -
-
-at_before_say(message, **kwargs)
-

Before the object says something.

-

This hook is by default used by the ‘say’ and ‘whisper’ -commands as used by this command it is called before the text -is said/whispered and can be used to customize the outgoing -text from the object. Returning None aborts the command.

-
-
Parameters
-

message (str) – The suggested say/whisper text spoken by self.

-
-
Keyword Arguments
-
    -
  • whisper (bool) – If True, this is a whisper rather than -a say. This is sent by the whisper command by default. -Other verbal commands could use this hook in similar -ways.

  • -
  • receivers (Object or iterable) – If set, this is the target or targets for the -say/whisper.

  • -
-
-
Returns
-

message (str) – The (possibly modified) text to be spoken.

-
-
-
- -
-
-at_say(message, msg_self=None, msg_location=None, receivers=None, msg_receivers=None, **kwargs)[source]
-

Display the actual say (or whisper) of self.

-

This hook should display the actual say/whisper of the object in its -location. It should both alert the object (self) and its -location that some text is spoken. The overriding of messages or -mapping allows for simple customization of the hook without -re-writing it completely.

-
-
Parameters
-
    -
  • message (str) – The message to convey.

  • -
  • msg_self (bool or str, optional) – If boolean True, echo message to self. If a string, -return that message. If False or unset, don’t echo to self.

  • -
  • msg_location (str, optional) – The message to echo to self’s location.

  • -
  • receivers (Object or iterable, optional) – An eventual receiver or receivers of the -message (by default only used by whispers).

  • -
  • msg_receivers (str) – Specific message to pass to the receiver(s). This will parsed -with the {receiver} placeholder replaced with the given receiver.

  • -
-
-
Keyword Arguments
-
    -
  • whisper (bool) – If this is a whisper rather than a say. Kwargs -can be used by other verbal commands in a similar way.

  • -
  • mapping (dict) – Pass an additional mapping to the message.

  • -
-
-
-

Notes

-

Messages can contain {} markers. These are substituted against the values -passed in the mapping argument.

-
-

msg_self = ‘You say: “{speech}”’ -msg_location = ‘{object} says: “{speech}”’ -msg_receivers = ‘{object} whispers: “{speech}”’

-
-
-
Supported markers by default:

{self}: text to self-reference with (default ‘You’) -{speech}: the text spoken/whispered by self. -{object}: the object speaking. -{receiver}: replaced with a single receiver only for strings meant for a specific

-
-

receiver (otherwise ‘None’).

-
-
-
{all_receivers}: comma-separated list of all receivers,

if more than one, otherwise same as receiver

-
-
-

{location}: the location where object is.

-
-
-
- -
-
-exception DoesNotExist
-

Bases: evennia.objects.models.ObjectDB.DoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: evennia.objects.models.ObjectDB.MultipleObjectsReturned

-
- -
-
-path = 'evennia.objects.objects.DefaultObject'
-
- -
-
-typename = 'DefaultObject'
-
- -
- -
-
-class evennia.objects.objects.DefaultCharacter(*args, **kwargs)[source]
-

Bases: evennia.objects.objects.DefaultObject

-

This implements an Object puppeted by a Session - that is, -a character avatar controlled by an account.

-
-
-lockstring = 'puppet:id({character_id}) or pid({account_id}) or perm(Developer) or pperm(Developer);delete:id({account_id}) or perm(Admin)'
-
- -
-
-classmethod create(key, account=None, **kwargs)[source]
-

Creates a basic Character with default parameters, unless otherwise -specified or extended.

-

Provides a friendlier interface to the utils.create_character() function.

-
-
Parameters
-
    -
  • key (str) – Name of the new Character.

  • -
  • account (obj, optional) – Account to associate this Character with. -If unset supplying None– it will -change the default lockset and skip creator attribution.

  • -
-
-
Keyword Arguments
-
    -
  • description (str) – Brief description for this object.

  • -
  • ip (str) – IP address of creator (for object auditing).

  • -
  • other kwargs will be passed into the create_object call. (All) –

  • -
-
-
Returns
-

character (Object) – A newly created Character of the given typeclass. -errors (list): A list of errors in string form, if any.

-
-
-
- -
-
-classmethod normalize_name(name)[source]
-

Normalize the character name prior to creating. Note that this should be refactored to -support i18n for non-latin scripts, but as we (currently) have no bug reports requesting -better support of non-latin character sets, requiring character names to be latinified is an -acceptable option.

-
-
Parameters
-

name (str) – The name of the character

-
-
Returns
-

latin_name (str) – A valid name.

-
-
-
- -
-
-classmethod validate_name(name)[source]
-

Validate the character name prior to creating. Overload this function to add custom validators

-
-
Parameters
-

name (str) – The name of the character

-
-
Returns
-

valid (bool) – True if character creation should continue; False if it should fail

-
-
-
- -
-
-basetype_setup()[source]
-

Setup character-specific security.

-

You should normally not need to overload this, but if you do, -make sure to reproduce at least the two last commands in this -method (unless you want to fundamentally change how a -Character object works).

-
- -
-
-at_post_move(source_location, **kwargs)[source]
-

We make sure to look around after a move.

-
- -
-
-at_after_move(source_location, **kwargs)
-

We make sure to look around after a move.

-
- -
-
-at_pre_puppet(account, session=None, **kwargs)[source]
-

Return the character from storage in None location in at_post_unpuppet. -:param account: This is the connecting account. -:type account: Account -:param session: Session controlling the connection. -:type session: Session

-
- -
-
-at_post_puppet(**kwargs)[source]
-

Called just after puppeting has been completed and all -Account<->Object links have been established.

-
-
Parameters
-

**kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

-
-
-
-

Note

-

You can use self.account and self.sessions.get() to get -account and sessions at this point; the last entry in the -list from self.sessions.get() is the latest Session -puppeting this Object.

-
-
- -
-
-at_post_unpuppet(account, session=None, **kwargs)[source]
-

We stove away the character when the account goes ooc/logs off, -otherwise the character object will remain in the room also -after the account logged off (“headless”, so to say).

-
-
Parameters
-
    -
  • account (Account) – The account object that just disconnected -from this object.

  • -
  • session (Session) – Session controlling the connection that -just disconnected.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-
- -
-
-property idle_time
-

Returns the idle time of the least idle session in seconds. If -no sessions are connected it returns nothing.

-
- -
-
-property connection_time
-

Returns the maximum connection time of all connected sessions -in seconds. Returns nothing if there are no sessions.

-
- -
-
-exception DoesNotExist
-

Bases: evennia.objects.objects.DefaultObject.DoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: evennia.objects.objects.DefaultObject.MultipleObjectsReturned

-
- -
-
-path = 'evennia.objects.objects.DefaultCharacter'
-
- -
-
-typename = 'DefaultCharacter'
-
- -
- -
-
-class evennia.objects.objects.DefaultRoom(*args, **kwargs)[source]
-

Bases: evennia.objects.objects.DefaultObject

-

This is the base room object. It’s just like any Object except its -location is always None.

-
-
-lockstring = 'control:id({id}) or perm(Admin); delete:id({id}) or perm(Admin); edit:id({id}) or perm(Admin)'
-
- -
-
-classmethod create(key, account=None, **kwargs)[source]
-

Creates a basic Room with default parameters, unless otherwise -specified or extended.

-

Provides a friendlier interface to the utils.create_object() function.

-
-
Parameters
-
    -
  • key (str) – Name of the new Room.

  • -
  • account (obj, optional) – Account to associate this Room with. If -given, it will be given specific control/edit permissions to this -object (along with normal Admin perms). If not given, default

  • -
-
-
Keyword Arguments
-
    -
  • description (str) – Brief description for this object.

  • -
  • ip (str) – IP address of creator (for object auditing).

  • -
-
-
Returns
-

room (Object) – A newly created Room of the given typeclass. -errors (list): A list of errors in string form, if any.

-
-
-
- -
-
-basetype_setup()[source]
-

Simple room setup setting locks to make sure the room -cannot be picked up.

-
- -
-
-exception DoesNotExist
-

Bases: evennia.objects.objects.DefaultObject.DoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: evennia.objects.objects.DefaultObject.MultipleObjectsReturned

-
- -
-
-path = 'evennia.objects.objects.DefaultRoom'
-
- -
-
-typename = 'DefaultRoom'
-
- -
- -
-
-class evennia.objects.objects.ExitCommand(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

This is a command that simply cause the caller to traverse -the object it is attached to.

-
-
-obj = None
-
- -
-
-func()[source]
-

Default exit traverse if no syscommand is defined.

-
- -
-
-get_extra_info(caller, **kwargs)[source]
-

Shows a bit of information on where the exit leads.

-
-
Parameters
-
    -
  • caller (Object) – The object (usually a character) that entered an ambiguous command.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
Returns
-

A string with identifying information to disambiguate the command, conventionally with a -preceding space.

-
-
-
- -
-
-aliases = []
-
- -
-
-help_category = 'general'
-
- -
-
-key = 'command'
-
- -
-
-lock_storage = 'cmd:all();'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'no_prefix': ' ', 'tags': '', 'text': '\n This is a command that simply cause the caller to traverse\n the object it is attached to.\n\n '}
-
- -
- -
-
-class evennia.objects.objects.DefaultExit(*args, **kwargs)[source]
-

Bases: evennia.objects.objects.DefaultObject

-

This is the base exit object - it connects a location to another. -This is done by the exit assigning a “command” on itself with the -same name as the exit object (to do this we need to remember to -re-create the command when the object is cached since it must be -created dynamically depending on what the exit is called). This -command (which has a high priority) will thus allow us to traverse -exits simply by giving the exit-object’s name on its own.

-
-
-exit_command
-

alias of ExitCommand

-
- -
-
-priority = 101
-
- -
-
-lockstring = 'control:id({id}) or perm(Admin); delete:id({id}) or perm(Admin); edit:id({id}) or perm(Admin)'
-
- -
-
-create_exit_cmdset(exidbobj)[source]
-

Helper function for creating an exit command set + command.

-

The command of this cmdset has the same name as the Exit -object and allows the exit to react when the account enter the -exit’s name, triggering the movement between rooms.

-
-
Parameters
-

exidbobj (Object) – The DefaultExit object to base the command on.

-
-
-
- -
-
-classmethod create(key, source, dest, account=None, **kwargs)[source]
-

Creates a basic Exit with default parameters, unless otherwise -specified or extended.

-

Provides a friendlier interface to the utils.create_object() function.

-
-
Parameters
-
    -
  • key (str) – Name of the new Exit, as it should appear from the -source room.

  • -
  • account (obj) – Account to associate this Exit with.

  • -
  • source (Room) – The room to create this exit in.

  • -
  • dest (Room) – The room to which this exit should go.

  • -
-
-
Keyword Arguments
-
    -
  • description (str) – Brief description for this object.

  • -
  • ip (str) – IP address of creator (for object auditing).

  • -
-
-
Returns
-

exit (Object) – A newly created Room of the given typeclass. -errors (list): A list of errors in string form, if any.

-
-
-
- -
-
-basetype_setup()[source]
-

Setup exit-security

-

You should normally not need to overload this - if you do make -sure you include all the functionality in this method.

-
- -
-
-at_cmdset_get(**kwargs)[source]
-

Called just before cmdsets on this object are requested by the -command handler. If changes need to be done on the fly to the -cmdset before passing them on to the cmdhandler, this is the -place to do it. This is called also if the object currently -has no cmdsets.

-
-
Keyword Arguments
-

force_init (bool) – If True, force a re-build of the cmdset -(for example to update aliases).

-
-
-
- -
-
-at_init()[source]
-

This is called when this objects is re-loaded from cache. When -that happens, we make sure to remove any old ExitCmdSet cmdset -(this most commonly occurs when renaming an existing exit)

-
- -
-
-at_traverse(traversing_object, target_location, **kwargs)[source]
-

This implements the actual traversal. The traverse lock has -already been checked (in the Exit command) at this point.

-
-
Parameters
-
    -
  • traversing_object (Object) – Object traversing us.

  • -
  • target_location (Object) – Where target is going.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-
- -
-
-at_failed_traverse(traversing_object, **kwargs)[source]
-

Overloads the default hook to implement a simple default error message.

-
-
Parameters
-
    -
  • traversing_object (Object) – The object that failed traversing us.

  • -
  • **kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

  • -
-
-
-

Notes

-

Using the default exits, this hook will not be called if an -Attribute err_traverse is defined - this will in that case be -read for an error string instead.

-
- -
-
-exception DoesNotExist
-

Bases: evennia.objects.objects.DefaultObject.DoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: evennia.objects.objects.DefaultObject.MultipleObjectsReturned

-
- -
-
-path = 'evennia.objects.objects.DefaultExit'
-
- -
-
-typename = 'DefaultExit'
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.prototypes.html b/docs/0.9.5/api/evennia.prototypes.html deleted file mode 100644 index 2e369df729..0000000000 --- a/docs/0.9.5/api/evennia.prototypes.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - - - evennia.prototypes — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
- - -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.prototypes.menus.html b/docs/0.9.5/api/evennia.prototypes.menus.html deleted file mode 100644 index b9e665ad86..0000000000 --- a/docs/0.9.5/api/evennia.prototypes.menus.html +++ /dev/null @@ -1,224 +0,0 @@ - - - - - - - - - evennia.prototypes.menus — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.prototypes.menus

-

OLC Prototype menu nodes

-
-
-evennia.prototypes.menus.node_validate_prototype(caller, raw_string, **kwargs)[source]
-

General node to view and validate a protototype

-
- -
-
-evennia.prototypes.menus.node_examine_entity(caller, raw_string, **kwargs)[source]
-

General node to view a text and then return to previous node. Kwargs should contain “text” for -the text to show and ‘back” pointing to the node to return to.

-
- -
-
-evennia.prototypes.menus.node_index(caller)[source]
-
- -
-
-evennia.prototypes.menus.node_prototype_key(caller)[source]
-
- -
-
-evennia.prototypes.menus.node_key(caller)[source]
-
- -
-
-evennia.prototypes.menus.node_location(caller)[source]
-
- -
-
-evennia.prototypes.menus.node_home(caller)[source]
-
- -
-
-evennia.prototypes.menus.node_destination(caller)[source]
-
- -
-
-evennia.prototypes.menus.node_prototype_desc(caller)[source]
-
- -
-
-evennia.prototypes.menus.node_apply_diff(caller, **kwargs)[source]
-

Offer options for updating objects

-
- -
-
-evennia.prototypes.menus.node_prototype_save(caller, **kwargs)[source]
-

Save prototype to disk

-
- -
-
-evennia.prototypes.menus.node_prototype_spawn(caller, **kwargs)[source]
-

Submenu for spawning the prototype

-
- -
-
-class evennia.prototypes.menus.OLCMenu(caller, menudata, startnode='start', cmdset_mergetype='Replace', cmdset_priority=1, auto_quit=True, auto_look=True, auto_help=True, cmd_on_exit='look', persistent=False, startnode_input='', session=None, debug=False, **kwargs)[source]
-

Bases: evennia.utils.evmenu.EvMenu

-

A custom EvMenu with a different formatting for the options.

-
-
-nodetext_formatter(nodetext)[source]
-

Format the node text itself.

-
- -
-
-options_formatter(optionlist)[source]
-

Split the options into two blocks - olc options and normal options

-
- -
-
-helptext_formatter(helptext)[source]
-

Show help text

-
- -
-
-display_helptext()[source]
-
- -
- -
-
-evennia.prototypes.menus.start_olc(caller, session=None, prototype=None)[source]
-

Start menu-driven olc system for prototypes.

-
-
Parameters
-
    -
  • caller (Object or Account) – The entity starting the menu.

  • -
  • session (Session, optional) – The individual session to get data.

  • -
  • prototype (dict, optional) – Given when editing an existing -prototype rather than creating a new one.

  • -
-
-
-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.prototypes.protfuncs.html b/docs/0.9.5/api/evennia.prototypes.protfuncs.html deleted file mode 100644 index 1afd494381..0000000000 --- a/docs/0.9.5/api/evennia.prototypes.protfuncs.html +++ /dev/null @@ -1,148 +0,0 @@ - - - - - - - - - evennia.prototypes.protfuncs — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.prototypes.protfuncs

-

Protfuncs are FuncParser-callables that can be embedded in a prototype to -provide custom logic without having access to Python. The protfunc is parsed at -the time of spawning, using the creating object’s session as input. If the -protfunc returns a non-string, this is what will be added to the prototype.

-

In the prototype dict, the protfunc is specified as a string inside the prototype, e.g.:

-
-

{ …

-

“key”: “$funcname(args, kwargs)”

-

… }

-
-

Available protfuncs are either all callables in one of the modules of settings.PROT_FUNC_MODULES -or all callables added to a dict FUNCPARSER_CALLABLES in such a module.

-
-

def funcname (*args, **kwargs)

-
-

At spawn-time the spawner passes the following extra kwargs into each callable (in addition to -what is added in the call itself):

-
-
    -
  • session (Session): The Session of the entity spawning using this prototype.

  • -
  • prototype (dict): The dict this protfunc is a part of.

  • -
  • current_key (str): The active key this value belongs to in the prototype.

  • -
-
-

Any traceback raised by this function will be handled at the time of spawning and abort the spawn -before any object is created/updated. It must otherwise return the value to store for the specified -prototype key (this value must be possible to serialize in an Attribute).

-
-
-evennia.prototypes.protfuncs.protfunc_callable_protkey(*args, **kwargs)[source]
-

Usage: $protkey(keyname) -Returns the value of another key in this prototoype. Will raise an error if

-
-

the key is not found in this prototype.

-
-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.prototypes.prototypes.html b/docs/0.9.5/api/evennia.prototypes.prototypes.html deleted file mode 100644 index fdb9fd3cc3..0000000000 --- a/docs/0.9.5/api/evennia.prototypes.prototypes.html +++ /dev/null @@ -1,545 +0,0 @@ - - - - - - - - - evennia.prototypes.prototypes — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.prototypes.prototypes

-

Handling storage of prototypes, both database-based ones (DBPrototypes) and those defined in modules -(Read-only prototypes). Also contains utility functions, formatters and manager functions.

-
-
-exception evennia.prototypes.prototypes.PermissionError[source]
-

Bases: RuntimeError

-
- -
-
-exception evennia.prototypes.prototypes.ValidationError[source]
-

Bases: RuntimeError

-

Raised on prototype validation errors

-
- -
-
-evennia.prototypes.prototypes.homogenize_prototype(prototype, custom_keys=None)[source]
-

Homogenize the more free-form prototype supported pre Evennia 0.7 into the stricter form.

-
-
Parameters
-
    -
  • prototype (dict) – Prototype.

  • -
  • custom_keys (list, optional) – Custom keys which should not be interpreted as attrs, beyond -the default reserved keys.

  • -
-
-
Returns
-

homogenized (dict)

-
-
Prototype where all non-identified keys grouped as attributes and other

homogenizations like adding missing prototype_keys and setting a default typeclass.

-
-
-

-
-
-
- -
-
-evennia.prototypes.prototypes.load_module_prototypes(*mod_or_prototypes, override=True)[source]
-

Load module prototypes. Also prototype-dicts passed directly to this function are considered -‘module’ prototypes (they are impossible to change) but will have a module of None.

-
-
Parameters
-
    -
  • *mod_or_prototypes (module or dict) – Each arg should be a separate module or -prototype-dict to load. If none are given, settings.PROTOTYPE_MODULES will be used.

  • -
  • override (bool, optional) – If prototypes should override existing ones already loaded. -Disabling this can allow for injecting prototypes into the system dynamically while -still allowing same prototype-keys to be overridden from settings (even though settings -is usually loaded before dynamic loading).

  • -
-
-
-
-

Note

-

This is called (without arguments) by evennia.__init__ as Evennia initializes. It’s -important to do this late so as to not interfere with evennia initialization. But it can -also be used later to add more prototypes to the library on the fly. This is requried -before a module-based prototype can be accessed by prototype-key.

-
-
- -
-
-class evennia.prototypes.prototypes.DbPrototype(*args, **kwargs)[source]
-

Bases: evennia.scripts.scripts.DefaultScript

-

This stores a single prototype, in an Attribute prototype.

-
-
-at_script_creation()[source]
-

Only called once, when script is first created.

-
- -
-
-property prototype
-

Make sure to decouple from db!

-
- -
-
-exception DoesNotExist
-

Bases: evennia.scripts.scripts.DefaultScript.DoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: evennia.scripts.scripts.DefaultScript.MultipleObjectsReturned

-
- -
-
-path = 'evennia.prototypes.prototypes.DbPrototype'
-
- -
-
-typename = 'DbPrototype'
-
- -
- -
-
-evennia.prototypes.prototypes.save_prototype(prototype)[source]
-

Create/Store a prototype persistently.

-
-
Parameters
-

prototype (dict) – The prototype to save. A prototype_key key is -required.

-
-
Returns
-

prototype (dict or None) – The prototype stored using the given kwargs, None if deleting.

-
-
Raises
-

prototypes.ValidationError – If prototype does not validate.

-
-
-
-

Note

-

No edit/spawn locks will be checked here - if this function is called the caller -is expected to have valid permissions.

-
-
- -
-
-evennia.prototypes.prototypes.create_prototype(prototype)
-

Create/Store a prototype persistently.

-
-
Parameters
-

prototype (dict) – The prototype to save. A prototype_key key is -required.

-
-
Returns
-

prototype (dict or None) – The prototype stored using the given kwargs, None if deleting.

-
-
Raises
-

prototypes.ValidationError – If prototype does not validate.

-
-
-
-

Note

-

No edit/spawn locks will be checked here - if this function is called the caller -is expected to have valid permissions.

-
-
- -
-
-evennia.prototypes.prototypes.delete_prototype(prototype_key, caller=None)[source]
-

Delete a stored prototype

-
-
Parameters
-
    -
  • key (str) – The persistent prototype to delete.

  • -
  • caller (Account or Object, optionsl) – Caller aiming to delete a prototype. -Note that no locks will be checked if**caller** is not passed.

  • -
-
-
Returns
-

success (bool) – If deletion worked or not.

-
-
Raises
-

PermissionError – If ‘edit’ lock was not passed or deletion failed for some other reason.

-
-
-
- -
-
-evennia.prototypes.prototypes.search_prototype(key=None, tags=None, require_single=False, return_iterators=False, no_db=False)[source]
-

Find prototypes based on key and/or tags, or all prototypes.

-
-
Keyword Arguments
-
    -
  • key (str) – An exact or partial key to query for.

  • -
  • tags (str or list) – Tag key or keys to query for. These -will always be applied with the ‘db_protototype’ -tag category.

  • -
  • require_single (bool) – If set, raise KeyError if the result -was not found or if there are multiple matches.

  • -
  • return_iterators (bool) – Optimized return for large numbers of db-prototypes. -If set, separate returns of module based prototypes and paginate -the db-prototype return.

  • -
  • no_db (bool) – Optimization. If set, skip querying for database-generated prototypes and only -include module-based prototypes. This can lead to a dramatic speedup since -module-prototypes are static and require no db-lookup.

  • -
-
-
Returns
-

matches (list)

-
-
Default return, all found prototype dicts. Empty list if

no match was found. Note that if neither key nor tags -were given, all available prototypes will be returned.

-
-
list, queryset: If return_iterators are found, this is a list of

module-based prototypes followed by a paginated queryset of -db-prototypes.

-
-
-

-
-
Raises
-

KeyError – If require_single is True and there are 0 or >1 matches.

-
-
-
-

Note

-

The available prototypes is a combination of those supplied in -PROTOTYPE_MODULES and those stored in the database. Note that if -tags are given and the prototype has no tags defined, it will not -be found as a match.

-
-
- -
-
-evennia.prototypes.prototypes.search_objects_with_prototype(prototype_key)[source]
-

Retrieve all object instances created by a given prototype.

-
-
Parameters
-

prototype_key (str) – The exact (and unique) prototype identifier to query for.

-
-
Returns
-

matches (Queryset) – All matching objects spawned from this prototype.

-
-
-
- -
-
-class evennia.prototypes.prototypes.PrototypeEvMore(caller, *args, session=None, **kwargs)[source]
-

Bases: evennia.utils.evmore.EvMore

-

Listing 1000+ prototypes can be very slow. So we customize EvMore to -display an EvTable per paginated page rather than to try creating an -EvTable for the entire dataset and then paginate it.

-
-
-__init__(caller, *args, session=None, **kwargs)[source]
-

Store some extra properties on the EvMore class

-
- -
-
-init_pages(inp)[source]
-

This will be initialized with a tuple (mod_prototype_list, paginated_db_query) -and we must handle these separately since they cannot be paginated in the same -way. We will build the prototypes so that the db-prototypes come first (they -are likely the most volatile), followed by the mod-prototypes.

-
- -
-
-prototype_paginator(pageno)[source]
-

The listing is separated in db/mod prototypes, so we need to figure out which -one to pick based on the page number. Also, pageno starts from 0.

-
- -
-
-page_formatter(page)[source]
-

Input is a queryset page from django.Paginator

-
- -
- -
-
-evennia.prototypes.prototypes.list_prototypes(caller, key=None, tags=None, show_non_use=False, show_non_edit=True, session=None)[source]
-

Collate a list of found prototypes based on search criteria and access.

-
-
Parameters
-
    -
  • caller (Account or Object) – The object requesting the list.

  • -
  • key (str, optional) – Exact or partial prototype key to query for.

  • -
  • tags (str or list, optional) – Tag key or keys to query for.

  • -
  • show_non_use (bool, optional) – Show also prototypes the caller may not use.

  • -
  • show_non_edit (bool, optional) – Show also prototypes the caller may not edit.

  • -
  • session (Session, optional) – If given, this is used for display formatting.

  • -
-
-
Returns
-

PrototypeEvMore – An EvMore subclass optimized for prototype listings. -None: If no matches were found. In this case the caller has already been notified.

-
-
-
- -
-
-evennia.prototypes.prototypes.validate_prototype(prototype, protkey=None, protparents=None, is_prototype_base=True, strict=True, _flags=None)[source]
-

Run validation on a prototype, checking for inifinite regress.

-
-
Parameters
-
    -
  • prototype (dict) – Prototype to validate.

  • -
  • protkey (str, optional) – The name of the prototype definition. If not given, the prototype -dict needs to have the prototype_key field set.

  • -
  • protpartents (dict, optional) – The available prototype parent library. If -note given this will be determined from settings/database.

  • -
  • is_prototype_base (bool, optional) – We are trying to create a new object based on this -object. This means we can’t allow ‘mixin’-style prototypes without typeclass/parent -etc.

  • -
  • strict (bool, optional) – If unset, don’t require needed keys, only check against infinite -recursion etc.

  • -
  • _flags (dict, optional) – Internal work dict that should not be set externally.

  • -
-
-
Raises
-
    -
  • RuntimeError – If prototype has invalid structure.

  • -
  • RuntimeWarning – If prototype has issues that would make it unsuitable to build an object -with (it may still be useful as a mix-in prototype).

  • -
-
-
-
- -
-
-evennia.prototypes.prototypes.protfunc_parser(value, available_functions=None, testing=False, stacktrace=False, caller=None, **kwargs)[source]
-

Parse a prototype value string for a protfunc and process it.

-

Available protfuncs are specified as callables in one of the modules of -settings.PROTFUNC_MODULES, or specified on the command line.

-
-
Parameters
-
    -
  • value (any) – The value to test for a parseable protfunc. Only strings will be parsed for -protfuncs, all other types are returned as-is.

  • -
  • available_functions (dict, optional) – Mapping of name:protfunction to use for this parsing. -If not set, use default sources.

  • -
  • stacktrace (bool, optional) – If set, print the stack parsing process of the protfunc-parser.

  • -
-
-
Keyword Arguments
-
    -
  • session (Session) – Passed to protfunc. Session of the entity spawning the prototype.

  • -
  • protototype (dict) – Passed to protfunc. The dict this protfunc is a part of.

  • -
  • current_key (str) – Passed to protfunc. The key in the prototype that will hold this value.

  • -
  • caller (Object or Account) – This is necessary for certain protfuncs that perform object -searches and have to check permissions.

  • -
  • any (any) – Passed on to the protfunc.

  • -
-
-
Returns
-

any – A structure to replace the string on the prototype leve. Note -that FunctionParser functions $funcname(*args, **kwargs) can return any -data type to insert into the prototype.

-
-
-
- -
-
-evennia.prototypes.prototypes.format_available_protfuncs()[source]
-

Get all protfuncs in a pretty-formatted form.

-
-
Parameters
-

clr (str, optional) – What coloration tag to use.

-
-
-
- -
-
-evennia.prototypes.prototypes.prototype_to_str(prototype)[source]
-

Format a prototype to a nice string representation.

-
-
Parameters
-

prototype (dict) – The prototype.

-
-
-
- -
-
-evennia.prototypes.prototypes.check_permission(prototype_key, action, default=True)[source]
-

Helper function to check access to actions on given prototype.

-
-
Parameters
-
    -
  • prototype_key (str) – The prototype to affect.

  • -
  • action (str) – One of “spawn” or “edit”.

  • -
  • default (str) – If action is unknown or prototype has no locks

  • -
-
-
Returns
-

passes (bool) – If permission for action is granted or not.

-
-
-
- -
-
-evennia.prototypes.prototypes.init_spawn_value(value, validator=None, caller=None, prototype=None)[source]
-

Analyze the prototype value and produce a value useful at the point of spawning.

-
-
Parameters
-

value (any) –

This can be: -callable - will be called as callable() -(callable, (args,)) - will be called as callable(*args) -other - will be assigned depending on the variable type -validator (callable, optional): If given, this will be called with the value to

-
-

check and guarantee the outcome is of a given type.

-
-
-
caller (Object or Account): This is necessary for certain protfuncs that perform object

searches and have to check permissions.

-
-
-

prototype (dict): Prototype this is to be used for. Necessary for certain protfuncs.

-

-
-
Returns
-

any (any) – The (potentially pre-processed value to use for this prototype key)

-
-
-
- -
-
-evennia.prototypes.prototypes.value_to_obj_or_any(value)[source]
-

Convert value(s) to Object if possible, otherwise keep original value

-
- -
-
-evennia.prototypes.prototypes.value_to_obj(value, force=True)[source]
-

Always convert value(s) to Object, or None

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.prototypes.spawner.html b/docs/0.9.5/api/evennia.prototypes.spawner.html deleted file mode 100644 index 7183c9f0f4..0000000000 --- a/docs/0.9.5/api/evennia.prototypes.spawner.html +++ /dev/null @@ -1,549 +0,0 @@ - - - - - - - - - evennia.prototypes.spawner — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.prototypes.spawner

-

Spawner

-

The spawner takes input files containing object definitions in -dictionary forms. These use a prototype architecture to define -unique objects without having to make a Typeclass for each.

-

There main function is spawn(*prototype), where the prototype -is a dictionary like this:

-
from evennia.prototypes import prototypes, spawner
-
-prot = {
- "prototype_key": "goblin",
- "typeclass": "types.objects.Monster",
- "key": "goblin grunt",
- "health": lambda: randint(20,30),
- "resists": ["cold", "poison"],
- "attacks": ["fists"],
- "weaknesses": ["fire", "light"]
- "tags": ["mob", "evil", ('greenskin','mob')]
- "attrs": [("weapon", "sword")]
-}
-# spawn something with the prototype
-goblin = spawner.spawn(prot)
-
-# make this into a db-saved prototype (optional)
-prot = prototypes.create_prototype(prot)
-
-
-
-
Possible keywords are:
-
prototype_key (str): name of this prototype. This is used when storing prototypes and should

be unique. This should always be defined but for prototypes defined in modules, the -variable holding the prototype dict will become the prototype_key if it’s not explicitly -given.

-
-
-

prototype_desc (str, optional): describes prototype in listings -prototype_locks (str, optional): locks for restricting access to this prototype. Locktypes

-
-

supported are ‘edit’ and ‘use’.

-
-
-
prototype_tags(list, optional): List of tags or tuples (tag, category) used to group prototype

in listings

-
-
prototype_parent (str, tuple or callable, optional): name (prototype_key) of eventual parent

prototype, or a list of parents, for multiple left-to-right inheritance.

-
-
-

prototype: Deprecated. Same meaning as ‘parent’.

-
-
typeclass (str or callable, optional): if not set, will use typeclass of parent prototype or use

settings.BASE_OBJECT_TYPECLASS

-
-
key (str or callable, optional): the name of the spawned object. If not given this will set to a

random hash

-
-
-

location (obj, str or callable, optional): location of the object - a valid object or #dbref -home (obj, str or callable, optional): valid object or #dbref -destination (obj, str or callable, optional): only valid for exits (object or #dbref)

-

permissions (str, list or callable, optional): which permissions for spawned object to have -locks (str or callable, optional): lock-string for the spawned object -aliases (str, list or callable, optional): Aliases for the spawned object -exec (str or callable, optional): this is a string of python code to execute or a list of such

-
-

codes. This can be used e.g. to trigger custom handlers on the object. The execution -namespace contains ‘evennia’ for the library and ‘obj’. All default spawn commands limit -this functionality to Developer/superusers. Usually it’s better to use callables or -prototypefuncs instead of this.

-
-
-
tags (str, tuple, list or callable, optional): string or list of strings or tuples

(tagstr, category). Plain strings will be result in tags with no category (default tags).

-
-
attrs (tuple, list or callable, optional): tuple or list of tuples of Attributes to add. This

form allows more complex Attributes to be set. Tuples at least specify (key, value) -but can also specify up to (key, value, category, lockstring). If you want to specify a -lockstring but not a category, set the category to None.

-
-
-

ndb_<name> (any): value of a nattribute (ndb_ is stripped) - this is of limited use. -other (any): any other name is interpreted as the key of an Attribute with

-
-

its value. Such Attributes have no categories.

-
-
-
-

Each value can also be a callable that takes no arguments. It should -return the value to enter into the field and will be called every time -the prototype is used to spawn an object. Note, if you want to store -a callable in an Attribute, embed it in a tuple to the args keyword.

-

By specifying the “prototype_parent” key, the prototype becomes a child of -the given prototype, inheritng all prototype slots it does not explicitly -define itself, while overloading those that it does specify.

-
import random
-
-
-{
- "prototype_key": "goblin_wizard",
- "prototype_parent": "GOBLIN",
- "key": "goblin wizard",
- "spells": ["fire ball", "lighting bolt"]
- }
-
-GOBLIN_ARCHER = {
- "prototype_parent": "GOBLIN",
- "key": "goblin archer",
- "attack_skill": (random, (5, 10))"
- "attacks": ["short bow"]
-}
-
-
-

One can also have multiple prototypes. These are inherited from the -left, with the ones further to the right taking precedence.

-
ARCHWIZARD = {
- "attack": ["archwizard staff", "eye of doom"]
-
-GOBLIN_ARCHWIZARD = {
- "key" : "goblin archwizard"
- "prototype_parent": ("GOBLIN_WIZARD", "ARCHWIZARD"),
-}
-
-
-

The goblin archwizard will have some different attacks, but will -otherwise have the same spells as a goblin wizard who in turn shares -many traits with a normal goblin.

-

Storage mechanism:

-

This sets up a central storage for prototypes. The idea is to make these -available in a repository for buildiers to use. Each prototype is stored -in a Script so that it can be tagged for quick sorting/finding and locked for limiting -access.

-

This system also takes into consideration prototypes defined and stored in modules. -Such prototypes are considered ‘read-only’ to the system and can only be modified -in code. To replace a default prototype, add the same-name prototype in a -custom module read later in the settings.PROTOTYPE_MODULES list. To remove a default -prototype, override its name with an empty dict.

-
-
-class evennia.prototypes.spawner.Unset[source]
-

Bases: object

-

Helper class representing a non-set diff element.

-
- -
-
-evennia.prototypes.spawner.flatten_prototype(prototype, validate=False, no_db=False)[source]
-

Produce a ‘flattened’ prototype, where all prototype parents in the inheritance tree have been -merged into a final prototype.

-
-
Parameters
-
    -
  • prototype (dict) – Prototype to flatten. Its prototype_parent field will be parsed.

  • -
  • validate (bool, optional) – Validate for valid keys etc.

  • -
  • no_db (bool, optional) – Don’t search db-based prototypes. This can speed up -searching dramatically since module-based prototypes are static.

  • -
-
-
Returns
-

flattened (dict) – The final, flattened prototype.

-
-
-
- -
-
-evennia.prototypes.spawner.prototype_from_object(obj)[source]
-

Guess a minimal prototype from an existing object.

-
-
Parameters
-

obj (Object) – An object to analyze.

-
-
Returns
-

prototype (dict) – A prototype estimating the current state of the object.

-
-
-
- -
-
-evennia.prototypes.spawner.prototype_diff(prototype1, prototype2, maxdepth=2, homogenize=False, implicit_keep=False)[source]
-

A ‘detailed’ diff specifies differences down to individual sub-sections -of the prototype, like individual attributes, permissions etc. It is used -by the menu to allow a user to customize what should be kept.

-
-
Parameters
-
    -
  • prototype1 (dict) – Original prototype.

  • -
  • prototype2 (dict) – Comparison prototype.

  • -
  • maxdepth (int, optional) – The maximum depth into the diff we go before treating the elements -of iterables as individual entities to compare. This is important since a single -attr/tag (for example) are represented by a tuple.

  • -
  • homogenize (bool, optional) – Auto-homogenize both prototypes for the best comparison. -This is most useful for displaying.

  • -
  • implicit_keep (bool, optional) – If set, the resulting diff will assume KEEP unless the new -prototype explicitly change them. That is, if a key exists in prototype1 and -not in prototype2, it will not be REMOVEd but set to KEEP instead. This is -particularly useful for auto-generated prototypes when updating objects.

  • -
-
-
Returns
-

diff (dict)

-
-
A structure detailing how to convert prototype1 to prototype2. All

nested structures are dicts with keys matching either the prototype’s matching -key or the first element in the tuple describing the prototype value (so for -a tag tuple (tagname, category) the second-level key in the diff would be tagname). -The the bottom level of the diff consist of tuples (old, new, instruction), where -instruction can be one of “REMOVE”, “ADD”, “UPDATE” or “KEEP”.

-
-
-

-
-
-
- -
-
-evennia.prototypes.spawner.flatten_diff(diff)[source]
-

For spawning, a ‘detailed’ diff is not necessary, rather we just want instructions on how to -handle each root key.

-
-
Parameters
-

diff (dict) – Diff produced by prototype_diff and -possibly modified by the user. Note that also a pre-flattened diff will come out -unchanged by this function.

-
-
Returns
-

flattened_diff (dict)

-
-
A flat structure detailing how to operate on each

root component of the prototype.

-
-
-

-
-
-

Notes

-
-
The flattened diff has the following possible instructions:

UPDATE, REPLACE, REMOVE

-
-
-

Many of the detailed diff’s values can hold nested structures with their own -individual instructions. A detailed diff can have the following instructions:

-
-

REMOVE, ADD, UPDATE, KEEP

-
-
-
Here’s how they are translated:
    -
  • All REMOVE -> REMOVE

  • -
  • All ADD|UPDATE -> UPDATE

  • -
  • All KEEP -> KEEP

  • -
  • Mix KEEP, UPDATE, ADD -> UPDATE

  • -
  • Mix REMOVE, KEEP, UPDATE, ADD -> REPLACE

  • -
-
-
-
- -
-
-evennia.prototypes.spawner.prototype_diff_from_object(prototype, obj, implicit_keep=True)[source]
-

Get a simple diff for a prototype compared to an object which may or may not already have a -prototype (or has one but changed locally). For more complex migratations a manual diff may be -needed.

-
-
Parameters
-
    -
  • prototype (dict) – New prototype.

  • -
  • obj (Object) – Object to compare prototype against.

  • -
-
-
Returns
-

diff (dict) – Mapping for every prototype key: {“keyname”: “REMOVE|UPDATE|KEEP”, …} -obj_prototype (dict): The prototype calculated for the given object. The diff is how to

-
-

convert this prototype into the new prototype.

-
-
-
implicit_keep (bool, optional): This is usually what one wants for object updating. When

set, this means the prototype diff will assume KEEP on differences -between the object-generated prototype and that which is not explicitly set in the -new prototype. This means e.g. that even though the object has a location, and the -prototype does not specify the location, it will not be unset.

-
-
-

-
-
-

Notes

-

The diff is on the following form:

-
-
-
{“key”: (old, new, “KEEP|REPLACE|UPDATE|REMOVE”),
-
“attrs”: {“attrkey”: (old, new, “KEEP|REPLACE|UPDATE|REMOVE”),

“attrkey”: (old, new, “KEEP|REPLACE|UPDATE|REMOVE”), …},

-
-
-

“aliases”: {“aliasname”: (old, new, “KEEP…”, …}, -… }

-
-
-
-
- -
-
-evennia.prototypes.spawner.format_diff(diff, minimal=True)[source]
-

Reformat a diff for presentation. This is a shortened version -of the olc _format_diff_text_and_options without the options.

-
-
Parameters
-
    -
  • diff (dict) – A diff as produced by prototype_diff.

  • -
  • minimal (bool, optional) – Only show changes (remove KEEPs)

  • -
-
-
Returns
-

texts (str) – The formatted text.

-
-
-
- -
-
-evennia.prototypes.spawner.batch_update_objects_with_prototype(prototype, diff=None, objects=None, exact=False, caller=None)[source]
-

Update existing objects with the latest version of the prototype.

-
-
Parameters
-
    -
  • prototype (str or dict) – Either the prototype_key to use or the -prototype dict itself.

  • -
  • diff (dict, optional) – This a diff structure that describes how to update the protototype. -If not given this will be constructed from the first object found.

  • -
  • objects (list, optional) – List of objects to update. If not given, query for these -objects using the prototype’s prototype_key.

  • -
  • exact (bool, optional) – By default (False), keys not explicitly in the prototype will -not be applied to the object, but will be retained as-is. This is usually what is -expected - for example, one usually do not want to remove the object’s location even -if it’s not set in the prototype. With exact=True, all un-specified properties of the -objects will be removed if they exist. This will lead to a more accurate 1:1 correlation -between the object and the prototype but is usually impractical.

  • -
  • caller (Object or Account, optional) – This may be used by protfuncs to do permission checks.

  • -
-
-
Returns
-

changed (int) – The number of objects that had changes applied to them.

-
-
-
- -
-
-evennia.prototypes.spawner.batch_create_object(*objparams)[source]
-

This is a cut-down version of the create_object() function, -optimized for speed. It does NOT check and convert various input -so make sure the spawned Typeclass works before using this!

-
-
Parameters
-

objsparams (tuple) –

Each paremter tuple will create one object instance using the parameters -within. -The parameters should be given in the following order:

-
-
    -
  • create_kwargs (dict): For use as new_obj = ObjectDB(**create_kwargs).

  • -
  • permissions (str): Permission string used with new_obj.batch_add(permission).

  • -
  • lockstring (str): Lockstring used with new_obj.locks.add(lockstring).

  • -
  • -
    aliases (list): A list of alias strings for

    adding with new_object.aliases.batch_add(*aliases).

    -
    -
    -
  • -
  • -
    nattributes (list): list of tuples (key, value) to be loop-added to

    add with new_obj.nattributes.add(*tuple).

    -
    -
    -
  • -
  • -
    attributes (list): list of tuples (key, value[,category[,lockstring]]) for

    adding with new_obj.attributes.batch_add(*attributes).

    -
    -
    -
  • -
  • -
    tags (list): list of tuples (key, category) for adding

    with new_obj.tags.batch_add(*tags).

    -
    -
    -
  • -
  • -
    execs (list): Code strings to execute together with the creation
    -
    of each object. They will be executed with evennia and obj

    (the newly created object) available in the namespace. Execution -will happend after all other properties have been assigned and -is intended for calling custom handlers etc.

    -
    -
    -
    -
    -
  • -
-
-

-
-
Returns
-

objects (list) – A list of created objects

-
-
-

Notes

-

The exec list will execute arbitrary python code so don’t allow this to be available to -unprivileged users!

-
- -
-
-evennia.prototypes.spawner.spawn(*prototypes, caller=None, **kwargs)[source]
-

Spawn a number of prototyped objects.

-
-
Parameters
-

prototypes (str or dict) – Each argument should either be a -prototype_key (will be used to find the prototype) or a full prototype -dictionary. These will be batched-spawned as one object each.

-
-
Keyword Arguments
-
    -
  • caller (Object or Account, optional) – This may be used by protfuncs to do access checks.

  • -
  • prototype_modules (str or list) – A python-path to a prototype -module, or a list of such paths. These will be used to build -the global protparents dictionary accessible by the input -prototypes. If not given, it will instead look for modules -defined by settings.PROTOTYPE_MODULES.

  • -
  • prototype_parents (dict) – A dictionary holding a custom -prototype-parent dictionary. Will overload same-named -prototypes from prototype_modules.

  • -
  • return_parents (bool) – Return a dict of the entire prototype-parent tree -available to this prototype (no object creation happens). This is a -merged result between the globally found protparents and whatever -custom prototype_parents are given to this function.

  • -
  • only_validate (bool) – Only run validation of prototype/parents -(no object creation) and return the create-kwargs.

  • -
-
-
Returns
-

object (Object, dict or list)

-
-
Spawned object(s). If only_validate is given, return

a list of the creation kwargs to build the object(s) without actually creating it. If -return_parents is set, instead return dict of prototype parents.

-
-
-

-
-
-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.scripts.admin.html b/docs/0.9.5/api/evennia.scripts.admin.html deleted file mode 100644 index 60ab9c1a0f..0000000000 --- a/docs/0.9.5/api/evennia.scripts.admin.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.scripts.admin — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.scripts.admin

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.scripts.html b/docs/0.9.5/api/evennia.scripts.html deleted file mode 100644 index d6882a0ce3..0000000000 --- a/docs/0.9.5/api/evennia.scripts.html +++ /dev/null @@ -1,127 +0,0 @@ - - - - - - - - - evennia.scripts — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.scripts

-

This sub-package holds the Scripts system. Scripts are database -entities that can store data both in connection to Objects and Accounts -or globally. They may also have a timer-component to execute various -timed effects.

- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.scripts.manager.html b/docs/0.9.5/api/evennia.scripts.manager.html deleted file mode 100644 index 8b6160777d..0000000000 --- a/docs/0.9.5/api/evennia.scripts.manager.html +++ /dev/null @@ -1,308 +0,0 @@ - - - - - - - - - evennia.scripts.manager — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.scripts.manager

-

The custom manager for Scripts.

-
-
-class evennia.scripts.manager.ScriptManager(*args, **kwargs)[source]
-

Bases: evennia.scripts.manager.ScriptDBManager, evennia.typeclasses.managers.TypeclassManager

-
- -
-
-class evennia.scripts.manager.ScriptDBManager(*args, **kwargs)[source]
-

Bases: evennia.typeclasses.managers.TypedObjectManager

-

This Scriptmanager implements methods for searching -and manipulating Scripts directly from the database.

-

Evennia-specific search methods (will return Typeclasses or -lists of Typeclasses, whereas Django-general methods will return -Querysets or database objects).

-

dbref (converter) -dbref_search -get_dbref_range -object_totals -typeclass_search -get_all_scripts_on_obj -get_all_scripts -delete_script -remove_non_persistent -validate -script_search (equivalent to evennia.search_script) -copy_script

-
-
-get_all_scripts_on_obj(obj, key=None)[source]
-

Find all Scripts related to a particular object.

-
-
Parameters
-
    -
  • obj (Object) – Object whose Scripts we are looking for.

  • -
  • key (str, optional) – Script identifier - can be given as a -dbref or name string. If given, only scripts matching the -key on the object will be returned.

  • -
-
-
Returns
-

matches (list) – Matching scripts.

-
-
-
- -
-
-get_all_scripts(key=None)[source]
-

Get all scripts in the database.

-
-
Parameters
-

key (str or int, optional) – Restrict result to only those -with matching key or dbref.

-
-
Returns
-

scripts (list) – All scripts found, or those matching key.

-
-
-
- -
-
-delete_script(dbref)[source]
-

This stops and deletes a specific script directly from the -script database.

-
-
Parameters
-

dbref (int) – Database unique id.

-
-
-

Notes

-

This might be needed for global scripts not tied to a -specific game object

-
- -
-
-update_scripts_after_server_start()[source]
-

Update/sync/restart/delete scripts after server shutdown/restart.

-
- -
-
-search_script(ostring, obj=None, only_timed=False, typeclass=None)[source]
-

Search for a particular script.

-
-
Parameters
-
    -
  • ostring (str) – Search criterion - a script dbef or key.

  • -
  • obj (Object, optional) – Limit search to scripts defined on -this object

  • -
  • only_timed (bool) – Limit search only to scripts that run -on a timer.

  • -
  • typeclass (class or str) – Typeclass or path to typeclass.

  • -
-
-
Returns
-

Queryset – An iterable with 0, 1 or more results.

-
-
-
- -
- -

Search for a particular script.

-
-
Parameters
-
    -
  • ostring (str) – Search criterion - a script dbef or key.

  • -
  • obj (Object, optional) – Limit search to scripts defined on -this object

  • -
  • only_timed (bool) – Limit search only to scripts that run -on a timer.

  • -
  • typeclass (class or str) – Typeclass or path to typeclass.

  • -
-
-
Returns
-

Queryset – An iterable with 0, 1 or more results.

-
-
-
- -
-
-copy_script(original_script, new_key=None, new_obj=None, new_locks=None)[source]
-

Make an identical copy of the original_script.

-
-
Parameters
-
    -
  • original_script (Script) – The Script to copy.

  • -
  • new_key (str, optional) – Rename the copy.

  • -
  • new_obj (Object, optional) – Place copy on different Object.

  • -
  • new_locks (str, optional) – Give copy different locks from -the original.

  • -
-
-
Returns
-

script_copy (Script)

-
-
A new Script instance, copied from

the original.

-
-
-

-
-
-
- -
-
-create_script(typeclass=None, key=None, obj=None, account=None, locks=None, interval=None, start_delay=None, repeats=None, persistent=None, autostart=True, report_to=None, desc=None, tags=None, attributes=None)[source]
-

Create a new script. All scripts are a combination of a database -object that communicates with the database, and an typeclass that -‘decorates’ the database object into being different types of -scripts. It’s behaviour is similar to the game objects except -scripts has a time component and are more limited in scope.

-
-
Keyword Arguments
-
    -
  • typeclass (class or str) – Class or python path to a typeclass.

  • -
  • key (str) – Name of the new object. If not set, a name of -#dbref will be set.

  • -
  • obj (Object) – The entity on which this Script sits. If this -is None, we are creating a “global” script.

  • -
  • account (Account) – The account on which this Script sits. It is -exclusiv to obj.

  • -
  • locks (str) – one or more lockstrings, separated by semicolons.

  • -
  • interval (int) – The triggering interval for this Script, in -seconds. If unset, the Script will not have a timing -component.

  • -
  • start_delay (bool) – If True, will wait interval seconds -before triggering the first time.

  • -
  • repeats (int) – The number of times to trigger before stopping. -If unset, will repeat indefinitely.

  • -
  • persistent (bool) – If this Script survives a server shutdown -or not (all Scripts will survive a reload).

  • -
  • autostart (bool) – If this Script will start immediately when -created or if the start method must be called explicitly.

  • -
  • report_to (Object) – The object to return error messages to.

  • -
  • desc (str) – Optional description of script

  • -
  • tags (list) – List of tags or tuples (tag, category).

  • -
  • attributes (list) – List if tuples (key, value) or (key, value, category) -(key, value, lockstring) or (key, value, lockstring, default_access).

  • -
-
-
Returns
-

script (obj) – An instance of the script created

-
-
-

See evennia.scripts.manager for methods to manipulate existing -scripts in the database.

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.scripts.models.html b/docs/0.9.5/api/evennia.scripts.models.html deleted file mode 100644 index 7c142a7f0b..0000000000 --- a/docs/0.9.5/api/evennia.scripts.models.html +++ /dev/null @@ -1,405 +0,0 @@ - - - - - - - - - evennia.scripts.models — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.scripts.models

-

Scripts are entities that perform some sort of action, either only -once or repeatedly. They can be directly linked to a particular -Evennia Object or be stand-alonw (in the latter case it is considered -a ‘global’ script). Scripts can indicate both actions related to the -game world as well as pure behind-the-scenes events and effects. -Everything that has a time component in the game (i.e. is not -hard-coded at startup or directly created/controlled by players) is -handled by Scripts.

-

Scripts have to check for themselves that they should be applied at a -particular moment of time; this is handled by the is_valid() hook. -Scripts can also implement at_start and at_end hooks for preparing and -cleaning whatever effect they have had on the game object.

-

Common examples of uses of Scripts:

-
    -
  • Load the default cmdset to the account object’s cmdhandler -when logging in.

  • -
  • Switch to a different state, such as entering a text editor, -start combat or enter a dark room.

  • -
  • Merge a new cmdset with the default one for changing which -commands are available at a particular time

  • -
  • Give the account/object a time-limited bonus/effect

  • -
-
-
-class evennia.scripts.models.ScriptDB(*args, **kwargs)[source]
-

Bases: evennia.typeclasses.models.TypedObject

-

The Script database representation.

-
-
The TypedObject supplies the following (inherited) properties:

key - main name -name - alias for key -typeclass_path - the path to the decorating typeclass -typeclass - auto-linked typeclass -date_created - time stamp of object creation -permissions - perm strings -dbref - #id of object -db - persistent attribute storage -ndb - non-persistent attribute storage

-
-
The ScriptDB adds the following properties:

desc - optional description of script -obj - the object the script is linked to, if any -account - the account the script is linked to (exclusive with obj) -interval - how often script should run -start_delay - if the script should start repeating right away -repeats - how many times the script should repeat -persistent - if script should survive a server reboot -is_active - bool if script is currently running

-
-
-
-
-db_desc
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_obj
-

Accessor to the related object on the forward side of a many-to-one or -one-to-one (via ForwardOneToOneDescriptor subclass) relation.

-

In the example:

-
class Child(Model):
-    parent = ForeignKey(Parent, related_name='children')
-
-
-

**Child.parent** is a **ForwardManyToOneDescriptor** instance.

-
- -
-
-db_account
-

Accessor to the related object on the forward side of a many-to-one or -one-to-one (via ForwardOneToOneDescriptor subclass) relation.

-

In the example:

-
class Child(Model):
-    parent = ForeignKey(Parent, related_name='children')
-
-
-

**Child.parent** is a **ForwardManyToOneDescriptor** instance.

-
- -
-
-db_interval
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_start_delay
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_repeats
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_persistent
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_is_active
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-objects = <evennia.scripts.manager.ScriptDBManager object>
-
- -
-
-property obj
-

Property wrapper that homogenizes access to either the -db_account or db_obj field, using the same object property -name.

-
- -
-
-property object
-

Property wrapper that homogenizes access to either the -db_account or db_obj field, using the same object property -name.

-
- -
-
-exception DoesNotExist
-

Bases: django.core.exceptions.ObjectDoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: django.core.exceptions.MultipleObjectsReturned

-
- -
-
-property account
-

A wrapper for getting database field db_account.

-
- -
-
-db_account_id
-
- -
-
-db_attributes
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-db_obj_id
-
- -
-
-db_tags
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-property desc
-

A wrapper for getting database field db_desc.

-
- -
-
-get_next_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=True, **kwargs)
-
- -
-
-get_previous_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=False, **kwargs)
-
- -
-
-id
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-property interval
-

A wrapper for getting database field db_interval.

-
- -
-
-property is_active
-

A wrapper for getting database field db_is_active.

-
- -
-
-path = 'evennia.scripts.models.ScriptDB'
-
- -
-
-property persistent
-

A wrapper for getting database field db_persistent.

-
- -
-
-receiver_script_set
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-property repeats
-

A wrapper for getting database field db_repeats.

-
- -
-
-sender_script_set
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-property start_delay
-

A wrapper for getting database field db_start_delay.

-
- -
-
-typename = 'SharedMemoryModelBase'
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.scripts.monitorhandler.html b/docs/0.9.5/api/evennia.scripts.monitorhandler.html deleted file mode 100644 index 8f91323580..0000000000 --- a/docs/0.9.5/api/evennia.scripts.monitorhandler.html +++ /dev/null @@ -1,230 +0,0 @@ - - - - - - - - - evennia.scripts.monitorhandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.scripts.monitorhandler

-

Monitors - catch changes to model fields and Attributes.

-

The MONITOR_HANDLER singleton from this module offers the following -functionality:

-
    -
  • -
    Field-monitor - track a object’s specific database field and perform

    an action whenever that field changes for whatever reason.

    -
    -
    -
  • -
  • -
    Attribute-monitor tracks an object’s specific Attribute and perform

    an action whenever that Attribute changes for whatever reason.

    -
    -
    -
  • -
-
-
-class evennia.scripts.monitorhandler.MonitorHandler[source]
-

Bases: object

-

This is a resource singleton that allows for registering -callbacks for when a field or Attribute is updated (saved).

-
-
-__init__()[source]
-

Initialize the handler.

-
- -
-
-save()[source]
-

Store our monitors to the database. This is called -by the server process.

-

Since dbserialize can’t handle defaultdicts, we convert to an -intermediary save format ((obj,fieldname, idstring, callback, kwargs), …)

-
- -
-
-restore(server_reload=True)[source]
-

Restore our monitors after a reload. This is called -by the server process.

-
-
Parameters
-

server_reload (bool, optional) – If this is False, it means -the server went through a cold reboot and all -non-persistent tickers must be killed.

-
-
-
- -
-
-at_update(obj, fieldname)[source]
-

Called by the field/attribute as it saves.

-
- -
-
-add(obj, fieldname, callback, idstring='', persistent=False, category=None, **kwargs)[source]
-

Add monitoring to a given field or Attribute. A field must -be specified with the full db_* name or it will be assumed -to be an Attribute (so db_key, not just key).

-
-
Parameters
-
    -
  • obj (Typeclassed Entity) – The entity on which to monitor a -field or Attribute.

  • -
  • fieldname (str) – Name of field (db_*) or Attribute to monitor.

  • -
  • callback (callable) – A callable on the form **callable(**kwargs), -where kwargs holds keys fieldname and obj.

  • -
  • idstring (str, optional) – An id to separate this monitor from other monitors -of the same field and object.

  • -
  • persistent (bool, optional) – If False, the monitor will survive -a server reload but not a cold restart. This is default.

  • -
  • category (str, optional) – This is only used if fieldname refers to -an Attribute (i.e. it does not start with db_). You must specify this -if you want to target an Attribute with a category.

  • -
-
-
Keyword Arguments
-
    -
  • session (Session) – If this keyword is given, the monitorhandler will -correctly analyze it and remove the monitor if after a reload/reboot -the session is no longer valid.

  • -
  • any (any) – Any other kwargs are passed on to the callback. Remember that -all kwargs must be possible to pickle!

  • -
-
-
-
- -
-
-remove(obj, fieldname, idstring='', category=None)[source]
-

Remove a monitor.

-
- -
-
-clear()[source]
-

Delete all monitors.

-
- -
-
-all(obj=None)[source]
-

List all monitors or all monitors of a given object.

-
-
Parameters
-

obj (Object) – The object on which to list all monitors.

-
-
Returns
-

monitors (list) – The handled monitors.

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.scripts.scripthandler.html b/docs/0.9.5/api/evennia.scripts.scripthandler.html deleted file mode 100644 index b751a2fd19..0000000000 --- a/docs/0.9.5/api/evennia.scripts.scripthandler.html +++ /dev/null @@ -1,212 +0,0 @@ - - - - - - - - - evennia.scripts.scripthandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.scripts.scripthandler

-

The script handler makes sure to check through all stored scripts to -make sure they are still relevant. A scripthandler is automatically -added to all game objects. You access it through the property -scripts on the game object.

-
-
-class evennia.scripts.scripthandler.ScriptHandler(obj)[source]
-

Bases: object

-

Implements the handler. This sits on each game object.

-
-
-__init__(obj)[source]
-

Set up internal state.

-
-
Parameters
-

obj (Object) – A reference to the object this handler is -attached to.

-
-
-
- -
-
-add(scriptclass, key=None, autostart=True)[source]
-

Add a script to this object.

-
-
Parameters
-
    -
  • scriptclass (Scriptclass, Script or str) – Either a class -object inheriting from DefaultScript, an instantiated -script object or a python path to such a class object.

  • -
  • key (str, optional) – Identifier for the script (often set -in script definition and listings)

  • -
  • autostart (bool, optional) – Start the script upon adding it.

  • -
-
-
-
- -
-
-start(key)[source]
-

Find scripts and force-start them

-
-
Parameters
-

key (str) – The script’s key or dbref.

-
-
Returns
-

nr_started (int) – The number of started scripts found.

-
-
-
- -
-
-get(key)[source]
-

Search scripts on this object.

-
-
Parameters
-

key (str) – Search criterion, the script’s key or dbref.

-
-
Returns
-

scripts (list) – The found scripts matching key.

-
-
-
- -
-
-delete(key=None)[source]
-

Forcibly delete a script from this object.

-
-
Parameters
-

key (str, optional) – A script key or the path to a script (in the -latter case all scripts with this path will be deleted!) -If no key is given, delete all scripts on the object!

-
-
-
- -
-
-stop(key=None)
-

Forcibly delete a script from this object.

-
-
Parameters
-

key (str, optional) – A script key or the path to a script (in the -latter case all scripts with this path will be deleted!) -If no key is given, delete all scripts on the object!

-
-
-
- -
-
-all()[source]
-

Get all scripts stored in this handler.

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.scripts.scripts.html b/docs/0.9.5/api/evennia.scripts.scripts.html deleted file mode 100644 index b9c0f62daf..0000000000 --- a/docs/0.9.5/api/evennia.scripts.scripts.html +++ /dev/null @@ -1,332 +0,0 @@ - - - - - - - - - evennia.scripts.scripts — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.scripts.scripts

-

This module defines Scripts, out-of-character entities that can store -data both on themselves and on other objects while also having the -ability to run timers.

-
-
-class evennia.scripts.scripts.DefaultScript(*args, **kwargs)[source]
-

Bases: evennia.scripts.scripts.ScriptBase

-

This is the base TypeClass for all Scripts. Scripts describe -events, timers and states in game, they can have a time component -or describe a state that changes under certain conditions.

-
-
-classmethod create(key, **kwargs)[source]
-

Provides a passthrough interface to the utils.create_script() function.

-
-
Parameters
-

key (str) – Name of the new object.

-
-
Returns
-

object (Object) – A newly created object of the given typeclass. -errors (list): A list of errors in string form, if any.

-
-
-
- -
-
-at_script_creation()[source]
-

Only called once, when script is first created.

-
- -
-
-is_valid()[source]
-

Is called to check if the script’s timer is valid to run at this time. -Should return a boolean. If False, the timer will be stopped.

-
- -
-
-at_start(**kwargs)[source]
-

Called whenever the script timer is started, which for persistent -timed scripts is at least once every server start. It will also be -called when starting again after a pause (including after a -server reload).

-
-
Parameters
-

**kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

-
-
-
- -
-
-at_repeat(**kwargs)[source]
-

Called repeatedly if this Script is set to repeat regularly.

-
-
Parameters
-

**kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

-
-
-
- -
-
-at_pause(manual_pause=True, **kwargs)[source]
-

Called when this script’s timer pauses.

-
-
Parameters
-

manual_pause (bool) – If set, pausing was done by a direct call. The -non-manual pause indicates the script was paused as part of -the server reload.

-
-
-
- -
-
-at_stop(**kwargs)[source]
-

Called whenever when it’s time for this script’s timer to stop (either -because is_valid returned False, it ran out of iterations or it was manuallys -stopped.

-
-
Parameters
-

**kwargs (dict) – Arbitrary, optional arguments for users -overriding the call (unused by default).

-
-
-
- -
-
-at_script_delete()[source]
-

Called when the Script is deleted, before stopping the timer.

-
-
Returns
-

bool – If False, the deletion is aborted.

-
-
-
- -
-
-at_server_reload()[source]
-

This hook is called whenever the server is shutting down for -restart/reboot. If you want to, for example, save -non-persistent properties across a restart, this is the place -to do it.

-
- -
-
-at_server_shutdown()[source]
-

This hook is called whenever the server is shutting down fully -(i.e. not for a restart).

-
- -
-
-at_server_start()[source]
-

This hook is called after the server has started. It can be used to add -post-startup setup for Scripts without a timer component (for which at_start -could be used).

-
- -
-
-exception DoesNotExist
-

Bases: evennia.scripts.scripts.ScriptBase.DoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: evennia.scripts.scripts.ScriptBase.MultipleObjectsReturned

-
- -
-
-path = 'evennia.scripts.scripts.DefaultScript'
-
- -
-
-typename = 'DefaultScript'
-
- -
- -
-
-class evennia.scripts.scripts.DoNothing(*args, **kwargs)[source]
-

Bases: evennia.scripts.scripts.DefaultScript

-

A script that does nothing. Used as default fallback.

-
-
-at_script_creation()[source]
-

Setup the script

-
- -
-
-exception DoesNotExist
-

Bases: evennia.scripts.scripts.DefaultScript.DoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: evennia.scripts.scripts.DefaultScript.MultipleObjectsReturned

-
- -
-
-path = 'evennia.scripts.scripts.DoNothing'
-
- -
-
-typename = 'DoNothing'
-
- -
- -
-
-class evennia.scripts.scripts.Store(*args, **kwargs)[source]
-

Bases: evennia.scripts.scripts.DefaultScript

-

Simple storage script

-
-
-at_script_creation()[source]
-

Setup the script

-
- -
-
-exception DoesNotExist
-

Bases: evennia.scripts.scripts.DefaultScript.DoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: evennia.scripts.scripts.DefaultScript.MultipleObjectsReturned

-
- -
-
-path = 'evennia.scripts.scripts.Store'
-
- -
-
-typename = 'Store'
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.scripts.taskhandler.html b/docs/0.9.5/api/evennia.scripts.taskhandler.html deleted file mode 100644 index 6011d9c07e..0000000000 --- a/docs/0.9.5/api/evennia.scripts.taskhandler.html +++ /dev/null @@ -1,590 +0,0 @@ - - - - - - - - - evennia.scripts.taskhandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.scripts.taskhandler

-

Module containing the task handler for Evennia deferred tasks, persistent or not.

-
-
-evennia.scripts.taskhandler.handle_error(*args, **kwargs)[source]
-

Handle errors within deferred objects.

-
- -
-
-class evennia.scripts.taskhandler.TaskHandlerTask(task_id)[source]
-

Bases: object

-

An object to represent a single TaskHandler task.

-
-
Instance Attributes:

task_id (int): the global id for this task -deferred (deferred): a reference to this task’s deferred

-
-
Property Attributes:

paused (bool): check if the deferred instance of a task has been paused. -called(self): A task attribute to check if the deferred instance of a task has been called.

-
-
-
-
-pause()[source]
-

Pause the callback of a task.

-
- -
-
-unpause()[source]
-

Process all callbacks made since pause() was called.

-
- -
-
-do_task()[source]
-

Execute the task (call its callback).

-
- -
-
-call()[source]
-

Call the callback of this task.

-
- -
-
-remove()[source]
-

Remove a task without executing it.

-
- -
-
-cancel()[source]
-

Stop a task from automatically executing.

-
- -
-
-active()[source]
-

Check if a task is active (has not been called yet).

-
- -
-
-exists()[source]
-

Check if a task exists.

-
- -
-
-get_id()[source]
-

Returns the global id for this task. For use with

-
- -
-
-__init__(task_id)[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
-
-get_deferred()[source]
-

Return the instance of the deferred the task id is using.

-
-
Returns
-

bool or deferred

-
-
An instance of a deferred or False if there is no task with the id.

None is returned if there is no deferred affiliated with this id.

-
-
-

-
-
-
- -
-
-pause()[source]
-

Pause the callback of a task. -To resume use TaskHandlerTask.unpause.

-
- -
-
-unpause()[source]
-

Unpause a task, run the task if it has passed delay time.

-
- -
-
-property paused
-

A task attribute to check if the deferred instance of a task has been paused.

-

This exists to mock usage of a twisted deferred object.

-
-
Returns
-

bool or None

-
-
True if the task was properly paused. None if the task does not have

a deferred instance.

-
-
-

-
-
-
- -
-
-do_task()[source]
-

Execute the task (call its callback). -If calling before timedelay, cancel the deferred instance affliated to this task. -Remove the task from the dictionary of current tasks on a successful -callback.

-
-
Returns
-

bool or any – Set to False if the task does not exist in task -handler. Otherwise it will be the return of the task’s callback.

-
-
-
- -
-
-call()[source]
-

Call the callback of a task. -Leave the task unaffected otherwise. -This does not use the task’s deferred instance. -The only requirement is that the task exist in task handler.

-
-
Returns
-

bool or any – Set to False if the task does not exist in task -handler. Otherwise it will be the return of the task’s callback.

-
-
-
- -
-
-remove()[source]
-

Remove a task without executing it. -Deletes the instance of the task’s deferred.

-
-
Parameters
-

task_id (int) – an existing task ID.

-
-
Returns
-

bool – True if the removal completed successfully.

-
-
-
- -
-
-cancel()[source]
-

Stop a task from automatically executing. -This will not remove the task.

-
-
Returns
-

bool

-
-
True if the cancel completed successfully.

False if the cancel did not complete successfully.

-
-
-

-
-
-
- -
-
-active()[source]
-

Check if a task is active (has not been called yet).

-
-
Returns
-

bool

-
-
True if a task is active (has not been called yet). False if

it is not (has been called) or if the task does not exist.

-
-
-

-
-
-
- -
-
-property called
-

A task attribute to check if the deferred instance of a task has been called.

-

This exists to mock usage of a twisted deferred object. -It will not set to True if Task.call has been called. This only happens if -task’s deferred instance calls the callback.

-
-
Returns
-

bool

-
-
True if the deferred instance of this task has called the callback.

False if the deferred instnace of this task has not called the callback.

-
-
-

-
-
-
- -
-
-exists()[source]
-

Check if a task exists. -Most task handler methods check for existence for you.

-
-
Returns
-

bool – True the task exists False if it does not.

-
-
-
- -
-
-get_id()[source]
-

Returns the global id for this task. For use with -evennia.scripts.taskhandler.TASK_HANDLER.

-
-
Returns
-

task_id (int) – global task id for this task.

-
-
-
- -
- -
-
-class evennia.scripts.taskhandler.TaskHandler[source]
-

Bases: object

-

A light singleton wrapper allowing to access permanent tasks.

-

When utils.delay is called, the task handler is used to create -the task.

-

Task handler will automatically remove uncalled but canceled from task -handler. By default this will not occur until a canceled task -has been uncalled for 60 second after the time it should have been called. -To adjust this time use TASK_HANDLER.stale_timeout. If stale_timeout is 0 -stale tasks will not be automatically removed. -This is not done on a timer. I is done as new tasks are added or the load method is called.

-
-
-__init__()[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
-
-load()[source]
-

Load from the ServerConfig.

-

This should be automatically called when Evennia starts. -It populates self.tasks according to the ServerConfig.

-
- -
-
-clean_stale_tasks()[source]
-

remove uncalled but canceled from task handler.

-

By default this will not occur until a canceled task -has been uncalled for 60 second after the time it should have been called. -To adjust this time use TASK_HANDLER.stale_timeout.

-
- -
-
-save()[source]
-

Save the tasks in ServerConfig.

-
- -
-
-add(timedelay, callback, *args, **kwargs)[source]
-

Add a new task.

-

If the persistent kwarg is truthy: -The callback, args and values for kwarg will be serialized. Type -and attribute errors during the serialization will be logged, -but will not throw exceptions. -For persistent tasks do not use memory references in the callback -function or arguments. After a restart those memory references are no -longer accurate.

-
-
Parameters
-
    -
  • timedelay (int or float) – time in seconds before calling the callback.

  • -
  • callback (function or instance method) – the callback itself

  • -
  • any (any) – any additional positional arguments to send to the callback

  • -
  • *args – positional arguments to pass to callback.

  • -
  • **kwargs

    keyword arguments to pass to callback. -- persistent (bool, optional): persist the task (stores it).

    -
    -

    Persistent key and value is removed from kwargs it will -not be passed to callback.

    -
    -

  • -
-
-
Returns
-

TaskHandlerTask

-
-
An object to represent a task.

Reference evennia.scripts.taskhandler.TaskHandlerTask for complete details.

-
-
-

-
-
-
- -
-
-exists(task_id)[source]
-

Check if a task exists. -Most task handler methods check for existence for you.

-
-
Parameters
-

task_id (int) – an existing task ID.

-
-
Returns
-

bool – True the task exists False if it does not.

-
-
-
- -
-
-active(task_id)[source]
-

Check if a task is active (has not been called yet).

-
-
Parameters
-

task_id (int) – an existing task ID.

-
-
Returns
-

bool

-
-
True if a task is active (has not been called yet). False if

it is not (has been called) or if the task does not exist.

-
-
-

-
-
-
- -
-
-cancel(task_id)[source]
-

Stop a task from automatically executing. -This will not remove the task.

-
-
Parameters
-

task_id (int) – an existing task ID.

-
-
Returns
-

bool

-
-
True if the cancel completed successfully.

False if the cancel did not complete successfully.

-
-
-

-
-
-
- -
-
-remove(task_id)[source]
-

Remove a task without executing it. -Deletes the instance of the task’s deferred.

-
-
Parameters
-

task_id (int) – an existing task ID.

-
-
Returns
-

bool – True if the removal completed successfully.

-
-
-
- -
-
-clear(save=True, cancel=True)[source]
-

Clear all tasks. By default tasks are canceled and removed from the database as well.

-
-
Parameters
-
    -
  • save=True (bool) – Should changes to persistent tasks be saved to database.

  • -
  • cancel=True (bool) – Cancel scheduled tasks before removing it from task handler.

  • -
-
-
Returns
-

True (bool) – if the removal completed successfully.

-
-
-
- -
-
-call_task(task_id)[source]
-

Call the callback of a task. -Leave the task unaffected otherwise. -This does not use the task’s deferred instance. -The only requirement is that the task exist in task handler.

-
-
Parameters
-

task_id (int) – an existing task ID.

-
-
Returns
-

bool or any – Set to False if the task does not exist in task -handler. Otherwise it will be the return of the task’s callback.

-
-
-
- -
-
-do_task(task_id)[source]
-

Execute the task (call its callback). -If calling before timedelay cancel the deferred instance affliated to this task. -Remove the task from the dictionary of current tasks on a successful -callback.

-
-
Parameters
-

task_id (int) – a valid task ID.

-
-
Returns
-

bool or any – Set to False if the task does not exist in task -handler. Otherwise it will be the return of the task’s callback.

-
-
-
- -
-
-get_deferred(task_id)[source]
-

Return the instance of the deferred the task id is using.

-
-
Parameters
-

task_id (int) – a valid task ID.

-
-
Returns
-

bool or deferred

-
-
An instance of a deferred or False if there is no task with the id.

None is returned if there is no deferred affiliated with this id.

-
-
-

-
-
-
- -
-
-create_delays()[source]
-

Create the delayed tasks for the persistent tasks. -This method should be automatically called when Evennia starts.

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.scripts.tickerhandler.html b/docs/0.9.5/api/evennia.scripts.tickerhandler.html deleted file mode 100644 index 5024ef4914..0000000000 --- a/docs/0.9.5/api/evennia.scripts.tickerhandler.html +++ /dev/null @@ -1,455 +0,0 @@ - - - - - - - - - evennia.scripts.tickerhandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.scripts.tickerhandler

-

TickerHandler

-

This implements an efficient Ticker which uses a subscription -model to ‘tick’ subscribed objects at regular intervals.

-

The ticker mechanism is used by importing and accessing -the instantiated TICKER_HANDLER instance in this module. This -instance is run by the server; it will save its status across -server reloads and be started automaticall on boot.

-

Example:

-
from evennia.scripts.tickerhandler import TICKER_HANDLER
-
-# call tick myobj.at_tick(*args, **kwargs) every 15 seconds
-TICKER_HANDLER.add(15, myobj.at_tick, *args, **kwargs)
-
-
-

You supply the interval to tick and a callable to call regularly with -any extra args/kwargs. The callable should either be a stand-alone -function in a module or the method on a typeclassed entity (that -is, on an object that can be safely and stably returned from the -database). Functions that are dynamically created or sits on -in-memory objects cannot be used by the tickerhandler (there is no way -to reference them safely across reboots and saves).

-

The handler will transparently set -up and add new timers behind the scenes to tick at given intervals, -using a TickerPool - all callables with the same interval will share -the interval ticker.

-

To remove:

-
TICKER_HANDLER.remove(15, myobj.at_tick)
-
-
-

Both interval and callable must be given since a single object can be subscribed -to many different tickers at the same time. You can also supply idstring -as an identifying string if you ever want to tick the callable at the same interval -but with different arguments (args/kwargs are not used for identifying the ticker). There -is also persistent=False if you don’t want to make a ticker that don’t survive a reload. -If either or both idstring or persistent has been changed from their defaults, they -must be supplied to the TICKER_HANDLER.remove call to properly identify the ticker -to remove.

-

The TickerHandler’s functionality can be overloaded by modifying the -Ticker class and then changing TickerPool and TickerHandler to use the -custom classes

-
class MyTicker(Ticker):
-    # [doing custom stuff]
-
-class MyTickerPool(TickerPool):
-    ticker_class = MyTicker
-class MyTickerHandler(TickerHandler):
-    ticker_pool_class = MyTickerPool
-
-
-

If one wants to duplicate TICKER_HANDLER’s auto-saving feature in -a custom handler one can make a custom AT_STARTSTOP_MODULE entry to -call the handler’s save() and restore() methods when the server reboots.

-
-
-class evennia.scripts.tickerhandler.Ticker(interval)[source]
-

Bases: object

-

Represents a repeatedly running task that calls -hooks repeatedly. Overload _callback to change the -way it operates.

-
-
-__init__(interval)[source]
-

Set up the ticker

-
-
Parameters
-

interval (int) – The stepping interval.

-
-
-
- -
-
-validate(start_delay=None)[source]
-

Start/stop the task depending on how many subscribers we have -using it.

-
-
Parameters
-

start_delay (int) – Time to way before starting.

-
-
-
- -
-
-add(store_key, *args, **kwargs)[source]
-

Sign up a subscriber to this ticker. -:param store_key: Unique storage hash for this ticker subscription. -:type store_key: str -:param args: Arguments to call the hook method with. -:type args: any, optional

-
-
Keyword Arguments
-

_start_delay (int) – If set, this will be -used to delay the start of the trigger instead of -interval.

-
-
-
- -
-
-remove(store_key)[source]
-

Unsubscribe object from this ticker

-
-
Parameters
-

store_key (str) – Unique store key.

-
-
-
- -
-
-stop()[source]
-

Kill the Task, regardless of subscriptions.

-
- -
- -
-
-class evennia.scripts.tickerhandler.TickerPool[source]
-

Bases: object

-

This maintains a pool of -evennia.scripts.scripts.ExtendedLoopingCall tasks for calling -subscribed objects at given times.

-
-
-ticker_class
-

alias of Ticker

-
- -
-
-__init__()[source]
-

Initialize the pool.

-
- -
-
-add(store_key, *args, **kwargs)[source]
-

Add new ticker subscriber.

-
-
Parameters
-
    -
  • store_key (str) – Unique storage hash.

  • -
  • args (any, optional) – Arguments to send to the hook method.

  • -
-
-
-
- -
-
-remove(store_key)[source]
-

Remove subscription from pool.

-
-
Parameters
-

store_key (str) – Unique storage hash to remove

-
-
-
- -
-
-stop(interval=None)[source]
-

Stop all scripts in pool. This is done at server reload since -restoring the pool will automatically re-populate the pool.

-
-
Parameters
-

interval (int, optional) – Only stop tickers with this -interval.

-
-
-
- -
- -
-
-class evennia.scripts.tickerhandler.TickerHandler(save_name='ticker_storage')[source]
-

Bases: object

-

The Tickerhandler maintains a pool of tasks for subscribing -objects to various tick rates. The pool maintains creation -instructions and and re-applies them at a server restart.

-
-
-ticker_pool_class
-

alias of TickerPool

-
- -
-
-__init__(save_name='ticker_storage')[source]
-

Initialize handler

-
-
save_name (str, optional): The name of the ServerConfig

instance to store the handler state persistently.

-
-
-
- -
-
-save()[source]
-

Save ticker_storage as a serialized string into a temporary -ServerConf field. Whereas saving is done on the fly, if called -by server when it shuts down, the current timer of each ticker -will be saved so it can start over from that point.

-
- -
-
-restore(server_reload=True)[source]
-

Restore ticker_storage from database and re-initialize the -handler from storage. This is triggered by the server at -restart.

-
-
Parameters
-

server_reload (bool, optional) – If this is False, it means -the server went through a cold reboot and all -non-persistent tickers must be killed.

-
-
-
- -
-
-add(interval=60, callback=None, idstring='', persistent=True, *args, **kwargs)[source]
-

Add subscription to tickerhandler

-
-
Parameters
-
    -
  • interval (int, optional) – Interval in seconds between calling -callable(*args, **kwargs)

  • -
  • callable (callable function or method, optional) – This -should either be a stand-alone function or a method on a -typeclassed entity (that is, one that can be saved to the -database).

  • -
  • idstring (str, optional) – Identifier for separating -this ticker-subscription from others with the same -interval. Allows for managing multiple calls with -the same time interval and callback.

  • -
  • persistent (bool, optional) – A ticker will always survive -a server reload. If this is unset, the ticker will be -deleted by a server shutdown.

  • -
  • args (optional) – These will be passed into the -callback every time it is called. This must be data possible -to pickle!

  • -
  • kwargs (optional) – These will be passed into the -callback every time it is called. This must be data possible -to pickle!

  • -
-
-
Returns
-

store_key (tuple)

-
-
The immutable store-key for this ticker. This can

be stored and passed into .remove(store_key=store_key) later to -easily stop this ticker later.

-
-
-

-
-
-

Notes

-

The callback will be identified by type and stored either as -as combination of serialized database object + methodname or -as a python-path to the module + funcname. These strings will -be combined iwth interval and idstring to define a -unique storage key for saving. These must thus all be supplied -when wanting to modify/remove the ticker later.

-
- -
-
-remove(interval=60, callback=None, idstring='', persistent=True, store_key=None)[source]
-

Remove ticker subscription from handler.

-
-
Parameters
-
    -
  • interval (int, optional) – Interval of ticker to remove.

  • -
  • callback (callable function or method) – Either a function or -the method of a typeclassed object.

  • -
  • idstring (str, optional) – Identifier id of ticker to remove.

  • -
  • persistent (bool, optional) – Whether this ticker is persistent or not.

  • -
  • store_key (str, optional) – If given, all other kwargs are ignored and only -this is used to identify the ticker.

  • -
-
-
Raises
-

KeyError – If no matching ticker was found to remove.

-
-
-

Notes

-

The store-key is normally built from the interval/callback/idstring/persistent values; -but if the store_key is explicitly given, this is used instead.

-
- -
-
-clear(interval=None)[source]
-

Stop/remove tickers from handler.

-
-
Parameters
-

interval (int) – Only stop tickers with this interval.

-
-
-

Notes

-

This is the only supported way to kill tickers related to -non-db objects.

-
- -
-
-all(interval=None)[source]
-

Get all subscriptions.

-
-
Parameters
-

interval (int) – Limit match to tickers with this interval.

-
-
Returns
-

tickers (list)

-
-
If interval was given, this is a list of

tickers using that interval.

-
-
tickerpool_layout (dict): If interval was not given,

this is a dict {interval1: [ticker1, ticker2, …], …}

-
-
-

-
-
-
- -
-
-all_display()[source]
-

Get all tickers on an easily displayable form.

-
-
Returns
-

tickers (dict) – A list of all storekeys

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.admin.html b/docs/0.9.5/api/evennia.server.admin.html deleted file mode 100644 index b9eeaeff47..0000000000 --- a/docs/0.9.5/api/evennia.server.admin.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.server.admin — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.admin

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.amp_client.html b/docs/0.9.5/api/evennia.server.amp_client.html deleted file mode 100644 index b43bfbb7ff..0000000000 --- a/docs/0.9.5/api/evennia.server.amp_client.html +++ /dev/null @@ -1,293 +0,0 @@ - - - - - - - - - evennia.server.amp_client — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.amp_client

-

The Evennia Server service acts as an AMP-client when talking to the -Portal. This module sets up the Client-side communication.

-
-
-class evennia.server.amp_client.AMPClientFactory(server)[source]
-

Bases: twisted.internet.protocol.ReconnectingClientFactory

-

This factory creates an instance of an AMP client connection. This handles communication from -the be the Evennia ‘Server’ service to the ‘Portal’. The client will try to auto-reconnect on a -connection error.

-
-
-initialDelay = 1
-
- -
-
-factor = 1.5
-
- -
-
-noisy = False
-
- -
-
-__init__(server)[source]
-

Initializes the client factory.

-
-
Parameters
-

server (server) – server instance.

-
-
-
- -
-
-maxDelay = 1
-
- -
-
-startedConnecting(connector)[source]
-

Called when starting to try to connect to the Portal AMP server.

-
-
Parameters
-

connector (Connector) – Twisted Connector instance representing -this connection.

-
-
-
- -
-
-buildProtocol(addr)[source]
-

Creates an AMPProtocol instance when connecting to the AMP server.

-
-
Parameters
-

addr (str) – Connection address. Not used.

-
-
-
- -
-
-clientConnectionLost(connector, reason)[source]
-

Called when the AMP connection to the MUD server is lost.

-
-
Parameters
-
    -
  • connector (Connector) – Twisted Connector instance representing -this connection.

  • -
  • reason (str) – Eventual text describing why connection was lost.

  • -
-
-
-
- -
-
-clientConnectionFailed(connector, reason)[source]
-

Called when an AMP connection attempt to the MUD server fails.

-
-
Parameters
-
    -
  • connector (Connector) – Twisted Connector instance representing -this connection.

  • -
  • reason (str) – Eventual text describing why connection failed.

  • -
-
-
-
- -
- -
-
-class evennia.server.amp_client.AMPServerClientProtocol(*args, **kwargs)[source]
-

Bases: evennia.server.portal.amp.AMPMultiConnectionProtocol

-

This protocol describes the Server service (acting as an AMP-client)’s communication with the -Portal (which acts as the AMP-server)

-
-
-connectionMade()[source]
-

Called when a new connection is established.

-
- -
-
-data_to_portal(command, sessid, **kwargs)[source]
-

Send data across the wire to the Portal

-
-
Parameters
-
    -
  • command (AMP Command) – A protocol send command.

  • -
  • sessid (int) – A unique Session id.

  • -
  • kwargs (any) – Any data to pickle into the command.

  • -
-
-
Returns
-

deferred (deferred or None) – A deferred with an errback.

-
-
-

Notes

-

Data will be sent across the wire pickled as a tuple -(sessid, kwargs).

-
- -
-
-send_MsgServer2Portal(session, **kwargs)[source]
-
-
Access method - executed on the Server for sending data

to Portal.

-
-
-
-
Parameters
-
    -
  • session (Session) – Unique Session.

  • -
  • kwargs (any, optiona) – Extra data.

  • -
-
-
-
- -
-
-send_AdminServer2Portal(session, operation='', **kwargs)[source]
-

Administrative access method called by the Server to send an -instruction to the Portal.

-
-
Parameters
-
    -
  • session (Session) – Session.

  • -
  • operation (char, optional) – Identifier for the server -operation, as defined by the global variables in -evennia/server/amp.py.

  • -
  • kwargs (dict, optional) – Data going into the adminstrative.

  • -
-
-
-
- -
-
-server_receive_status(question)[source]
-
- -
-
-server_receive_msgportal2server()
-

Helper decorator

-
- -
-
-server_receive_adminportal2server()
-

Helper decorator

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.connection_wizard.html b/docs/0.9.5/api/evennia.server.connection_wizard.html deleted file mode 100644 index 13b884935b..0000000000 --- a/docs/0.9.5/api/evennia.server.connection_wizard.html +++ /dev/null @@ -1,232 +0,0 @@ - - - - - - - - - evennia.server.connection_wizard — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.connection_wizard

-

Link Evennia to external resources (wizard plugin for evennia_launcher)

-
-
-class evennia.server.connection_wizard.ConnectionWizard[source]
-

Bases: object

-
-
-__init__()[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
-
-display(text)[source]
-

Show text

-
- -
-
-ask_continue()[source]
-

‘Press return to continue’-prompt

-
- -
-
-ask_node(options, prompt='Enter choice: ', default=None)[source]
-

Retrieve options and jump to different menu nodes

-
-
Parameters
-
    -
  • options (dict) – Node options on the form {key: (desc, callback), }

  • -
  • prompt (str, optional) – Question to ask

  • -
  • default (str, optional) – Default value to use if user hits return.

  • -
-
-
-
- -
-
-ask_yesno(prompt, default='yes')[source]
-

Ask a yes/no question inline.

-
-
Keyword Arguments
-
    -
  • prompt (str) – The prompt to ask.

  • -
  • default (str) – “yes” or “no”, used if pressing return.

  • -
-
-
Returns
-

reply (str) – Either ‘yes’ or ‘no’.

-
-
-
- -
-
-ask_choice(prompt=' > ', options=None, default=None)[source]
-

Ask multiple-choice question, get response inline.

-
-
Keyword Arguments
-
    -
  • prompt (str) – Input prompt.

  • -
  • options (list) – List of options. Will be indexable by sequence number 1…

  • -
  • default (int) – The list index+1 of the default choice, if any

  • -
-
-
Returns
-

reply (str) – The answered reply.

-
-
-
- -
-
-ask_input(prompt=' > ', default=None, validator=None)[source]
-

Get arbitrary input inline.

-
-
Keyword Arguments
-
    -
  • prompt (str) – The display prompt.

  • -
  • default (str) – If empty input, use this.

  • -
  • validator (callable) – If given, the input will be passed -into this callable. It should return True unless validation -fails (and is expected to echo why if so).

  • -
-
-
Returns
-

inp (str) – The input given, or default.

-
-
-
- -
- -
-
-evennia.server.connection_wizard.node_start(wizard)[source]
-
- -
-
-evennia.server.connection_wizard.node_game_index_start(wizard, **kwargs)[source]
-
- -
-
-evennia.server.connection_wizard.node_game_index_fields(wizard, status=None)[source]
-
- -
-
-evennia.server.connection_wizard.node_mssp_start(wizard)[source]
-
- -
-
-evennia.server.connection_wizard.node_view_and_apply_settings(wizard)[source]
-

Inspect and save the data gathered in the other nodes

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.deprecations.html b/docs/0.9.5/api/evennia.server.deprecations.html deleted file mode 100644 index da96e29656..0000000000 --- a/docs/0.9.5/api/evennia.server.deprecations.html +++ /dev/null @@ -1,136 +0,0 @@ - - - - - - - - - evennia.server.deprecations — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.deprecations

-

This module contains historical deprecations that the Evennia launcher -checks for.

-

These all print to the terminal.

-
-
-evennia.server.deprecations.check_errors(settings)[source]
-

Check for deprecations that are critical errors and should stop -the launcher.

-
-
Parameters
-

settings (Settings) – The Django settings file

-
-
Raises
-

DeprecationWarning if a critical deprecation is found.

-
-
-
- -
-
-evennia.server.deprecations.check_warnings(settings)[source]
-

Check conditions and deprecations that should produce warnings but which -does not stop launch.

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.evennia_launcher.html b/docs/0.9.5/api/evennia.server.evennia_launcher.html deleted file mode 100644 index a08c02b67b..0000000000 --- a/docs/0.9.5/api/evennia.server.evennia_launcher.html +++ /dev/null @@ -1,639 +0,0 @@ - - - - - - - - - evennia.server.evennia_launcher — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.evennia_launcher

-

Evennia launcher program

-

This is the start point for running Evennia.

-

Sets the appropriate environmental variables for managing an Evennia game. It will start and connect -to the Portal, through which the Server is also controlled. This pprogram

-

Run the script with the -h flag to see usage information.

-
-
-class evennia.server.evennia_launcher.MsgStatus(**kw)[source]
-

Bases: twisted.protocols.amp.Command

-

Ping between AMP services

-
-
-key = 'MsgStatus'
-
- -
-
-arguments: List[Tuple[bytes, twisted.protocols.amp.Argument]] = [(b'status', <twisted.protocols.amp.String object>)]
-
- -
-
-errors: Dict[Type[Exception], bytes] = {<class 'Exception'>: b'EXCEPTION'}
-
- -
-
-response: List[Tuple[bytes, twisted.protocols.amp.Argument]] = [(b'status', <twisted.protocols.amp.String object>)]
-
- -
-
-allErrors = {<class 'Exception'>: b'EXCEPTION'}
-
- -
-
-commandName = b'MsgStatus'
-
- -
-
-reverseErrors = {b'EXCEPTION': <class 'Exception'>}
-
- -
- -
-
-class evennia.server.evennia_launcher.MsgLauncher2Portal(**kw)[source]
-

Bases: twisted.protocols.amp.Command

-

Message Launcher -> Portal

-
-
-key = 'MsgLauncher2Portal'
-
- -
-
-arguments: List[Tuple[bytes, twisted.protocols.amp.Argument]] = [(b'operation', <twisted.protocols.amp.String object>), (b'arguments', <twisted.protocols.amp.String object>)]
-
- -
-
-errors: Dict[Type[Exception], bytes] = {<class 'Exception'>: b'EXCEPTION'}
-
- -
-
-response: List[Tuple[bytes, twisted.protocols.amp.Argument]] = []
-
- -
-
-allErrors = {<class 'Exception'>: b'EXCEPTION'}
-
- -
-
-commandName = b'MsgLauncher2Portal'
-
- -
-
-reverseErrors = {b'EXCEPTION': <class 'Exception'>}
-
- -
- -
-
-class evennia.server.evennia_launcher.AMPLauncherProtocol[source]
-

Bases: twisted.protocols.amp.AMP

-

Defines callbacks to the launcher

-
-
-__init__()[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
-
-wait_for_status(callback)[source]
-

Register a waiter for a status return.

-
- -
-
-receive_status_from_portal(status)[source]
-

Get a status signal from portal - fire next queued -callback

-
- -
- -
-
-evennia.server.evennia_launcher.send_instruction(operation, arguments, callback=None, errback=None)[source]
-

Send instruction and handle the response.

-
- -
-
-evennia.server.evennia_launcher.query_status(callback=None)[source]
-

Send status ping to portal

-
- -
-
-evennia.server.evennia_launcher.wait_for_status_reply(callback)[source]
-

Wait for an explicit STATUS signal to be sent back from Evennia.

-
- -
-
-evennia.server.evennia_launcher.wait_for_status(portal_running=True, server_running=True, callback=None, errback=None, rate=0.5, retries=20)[source]
-

Repeat the status ping until the desired state combination is achieved.

-
-
Parameters
-
    -
  • portal_running (bool or None) – Desired portal run-state. If None, any state -is accepted.

  • -
  • server_running (bool or None) – Desired server run-state. If None, any state -is accepted. The portal must be running.

  • -
  • callback (callable) – Will be called with portal_state, server_state when -condition is fulfilled.

  • -
  • errback (callable) – Will be called with portal_state, server_state if the -request is timed out.

  • -
  • rate (float) – How often to retry.

  • -
  • retries (int) – How many times to retry before timing out and calling errback.

  • -
-
-
-
- -
-
-evennia.server.evennia_launcher.collectstatic()[source]
-

Run the collectstatic django command

-
- -
-
-evennia.server.evennia_launcher.start_evennia(pprofiler=False, sprofiler=False)[source]
-

This will start Evennia anew by launching the Evennia Portal (which in turn -will start the Server)

-
- -
-
-evennia.server.evennia_launcher.reload_evennia(sprofiler=False, reset=False)[source]
-

This will instruct the Portal to reboot the Server component. We -do this manually by telling the server to shutdown (in reload mode) -and wait for the portal to report back, at which point we start the -server again. This way we control the process exactly.

-
- -
-
-evennia.server.evennia_launcher.stop_evennia()[source]
-

This instructs the Portal to stop the Server and then itself.

-
- -
-
-evennia.server.evennia_launcher.reboot_evennia(pprofiler=False, sprofiler=False)[source]
-

This is essentially an evennia stop && evennia start except we make sure -the system has successfully shut down before starting it again.

-

If evennia was not running, start it.

-
- -
-
-evennia.server.evennia_launcher.start_only_server()[source]
-

Tell portal to start server (debug)

-
- -
-
-evennia.server.evennia_launcher.start_server_interactive()[source]
-

Start the Server under control of the launcher process (foreground)

-
- -
-
-evennia.server.evennia_launcher.start_portal_interactive()[source]
-

Start the Portal under control of the launcher process (foreground)

-

Notes

-

In a normal start, the launcher waits for the Portal to start, then -tells it to start the Server. Since we can’t do this here, we instead -start the Server first and then starts the Portal - the Server will -auto-reconnect to the Portal. To allow the Server to be reloaded, this -relies on a fixed server server-cmdline stored as a fallback on the -portal application in evennia/server/portal/portal.py.

-
- -
-
-evennia.server.evennia_launcher.stop_server_only(when_stopped=None, interactive=False)[source]
-

Only stop the Server-component of Evennia (this is not useful except for debug)

-
-
Parameters
-
    -
  • when_stopped (callable) – This will be called with no arguments when Server has stopped (or -if it had already stopped when this is called).

  • -
  • interactive (bool, optional) – Set if this is called as part of the interactive reload -mechanism.

  • -
-
-
-
- -
-
-evennia.server.evennia_launcher.query_info()[source]
-

Display the info strings from the running Evennia

-
- -
-
-evennia.server.evennia_launcher.tail_log_files(filename1, filename2, start_lines1=20, start_lines2=20, rate=1)[source]
-

Tail two logfiles interactively, combining their output to stdout

-

When first starting, this will display the tail of the log files. After -that it will poll the log files repeatedly and display changes.

-
-
Parameters
-
    -
  • filename1 (str) – Path to first log file.

  • -
  • filename2 (str) – Path to second log file.

  • -
  • start_lines1 (int) – How many lines to show from existing first log.

  • -
  • start_lines2 (int) – How many lines to show from existing second log.

  • -
  • rate (int, optional) – How often to poll the log file.

  • -
-
-
-
- -
-
-evennia.server.evennia_launcher.evennia_version()[source]
-

Get the Evennia version info from the main package.

-
- -
-
-evennia.server.evennia_launcher.check_main_evennia_dependencies()[source]
-

Checks and imports the Evennia dependencies. This must be done -already before the paths are set up.

-
-
Returns
-

not_error (bool) – True if no dependency error was found.

-
-
-
- -
-
-evennia.server.evennia_launcher.set_gamedir(path)[source]
-

Set GAMEDIR based on path, by figuring out where the setting file -is inside the directory tree. This allows for running the launcher -from elsewhere than the top of the gamedir folder.

-
- -
-
-evennia.server.evennia_launcher.create_secret_key()[source]
-

Randomly create the secret key for the settings file

-
- -
-
-evennia.server.evennia_launcher.create_settings_file(init=True, secret_settings=False)[source]
-

Uses the template settings file to build a working settings file.

-
-
Parameters
-
    -
  • init (bool) – This is part of the normal evennia –init -operation. If false, this function will copy a fresh -template file in (asking if it already exists).

  • -
  • secret_settings (bool, optional) – If False, create settings.py, otherwise -create the secret_settings.py file.

  • -
-
-
-
- -
-
-evennia.server.evennia_launcher.create_game_directory(dirname)[source]
-

Initialize a new game directory named dirname -at the current path. This means copying the -template directory from evennia’s root.

-
-
Parameters
-

dirname (str) – The directory name to create.

-
-
-
- -
-
-evennia.server.evennia_launcher.create_superuser()[source]
-

Create the superuser account

-
- -
-
-evennia.server.evennia_launcher.check_database(always_return=False)[source]
-

Check so the database exists.

-
-
Parameters
-

always_return (bool, optional) – If set, will always return True/False -also on critical errors. No output will be printed.

-
-
Returns
-

exists (bool)True if the database exists, otherwise False.

-
-
-
- -
-
-evennia.server.evennia_launcher.getenv()[source]
-

Get current environment and add PYTHONPATH.

-
-
Returns
-

env (dict) – Environment global dict.

-
-
-
- -
-
-evennia.server.evennia_launcher.get_pid(pidfile, default=None)[source]
-

Get the PID (Process ID) by trying to access an PID file.

-
-
Parameters
-
    -
  • pidfile (str) – The path of the pid file.

  • -
  • default (int, optional) – What to return if file does not exist.

  • -
-
-
Returns
-

pid (str) – The process id or default.

-
-
-
- -
-
-evennia.server.evennia_launcher.del_pid(pidfile)[source]
-

The pidfile should normally be removed after a process has -finished, but when sending certain signals they remain, so we need -to clean them manually.

-
-
Parameters
-

pidfile (str) – The path of the pid file.

-
-
-
- -
-
-evennia.server.evennia_launcher.kill(pidfile, component='Server', callback=None, errback=None, killsignal=<Signals.SIGINT: 2>)[source]
-

Send a kill signal to a process based on PID. A customized -success/error message will be returned. If clean=True, the system -will attempt to manually remove the pid file. On Windows, no arguments -are useful since Windows has no ability to direct signals except to all -children of a console.

-
-
Parameters
-
    -
  • pidfile (str) – The path of the pidfile to get the PID from. This is ignored -on Windows.

  • -
  • component (str, optional) – Usually one of ‘Server’ or ‘Portal’. This is -ignored on Windows.

  • -
  • errback (callable, optional) – Called if signal failed to send. This -is ignored on Windows.

  • -
  • callback (callable, optional) – Called if kill signal was sent successfully. -This is ignored on Windows.

  • -
  • killsignal (int, optional) – Signal identifier for signal to send. This is -ignored on Windows.

  • -
-
-
-
- -
-
-evennia.server.evennia_launcher.show_version_info(about=False)[source]
-

Display version info.

-
-
Parameters
-

about (bool) – Include ABOUT info as well as version numbers.

-
-
Returns
-

version_info (str) – A complete version info string.

-
-
-
- -
-
-evennia.server.evennia_launcher.error_check_python_modules(show_warnings=False)[source]
-

Import settings modules in settings. This will raise exceptions on -pure python-syntax issues which are hard to catch gracefully with -exceptions in the engine (since they are formatting errors in the -python source files themselves). Best they fail already here -before we get any further.

-
-
Keyword Arguments
-

show_warnings (bool) – If non-fatal warning messages should be shown.

-
-
-
- -
-
-evennia.server.evennia_launcher.init_game_directory(path, check_db=True, need_gamedir=True)[source]
-

Try to analyze the given path to find settings.py - this defines -the game directory and also sets PYTHONPATH as well as the django -path.

-
-
Parameters
-
    -
  • path (str) – Path to new game directory, including its name.

  • -
  • check_db (bool, optional) – Check if the databae exists.

  • -
  • need_gamedir (bool, optional) – set to False if Evennia doesn’t require to -be run in a valid game directory.

  • -
-
-
-
- -
-
-evennia.server.evennia_launcher.run_dummyrunner(number_of_dummies)[source]
-

Start an instance of the dummyrunner

-
-
Parameters
-

number_of_dummies (int) – The number of dummy accounts to start.

-
-
-

Notes

-

The dummy accounts’ behavior can be customized by adding a -dummyrunner_settings.py config file in the game’s conf/ -directory.

-
- -
-
-evennia.server.evennia_launcher.run_connect_wizard()[source]
-

Run the linking wizard, for adding new external connections.

-
- -
-
-evennia.server.evennia_launcher.list_settings(keys)[source]
-

Display the server settings. We only display the Evennia specific -settings here. The result will be printed to the terminal.

-
-
Parameters
-

keys (str or list) – Setting key or keys to inspect.

-
-
-
- -
-
-evennia.server.evennia_launcher.run_custom_commands(option, *args)[source]
-

Inject a custom option into the evennia launcher command chain.

-
-
Parameters
-
    -
  • option (str) – Incoming option - the first argument after evennia on -the command line.

  • -
  • *args – All args will passed to a found callable.__dict__

  • -
-
-
Returns
-

bool – If a custom command was found and handled the option.

-
-
-

Notes

-

Provide new commands in settings with

-
-

CUSTOM_EVENNIA_LAUNCHER_COMMANDS = {“mycmd”: “path.to.callable”, …}

-
-

The callable will be passed any *args given on the command line and is expected to -handle/validate the input correctly. Use like any other evennia command option on -in the terminal/console, for example:

-
-

evennia mycmd foo bar

-
-
- -
-
-evennia.server.evennia_launcher.run_menu()[source]
-

This launches an interactive menu.

-
- -
-
-evennia.server.evennia_launcher.main()[source]
-

Run the evennia launcher main program.

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.game_index_client.client.html b/docs/0.9.5/api/evennia.server.game_index_client.client.html deleted file mode 100644 index 74df19398a..0000000000 --- a/docs/0.9.5/api/evennia.server.game_index_client.client.html +++ /dev/null @@ -1,222 +0,0 @@ - - - - - - - - - evennia.server.game_index_client.client — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.game_index_client.client

-

The client for sending data to the Evennia Game Index

-
-
-class evennia.server.game_index_client.client.EvenniaGameIndexClient(on_bad_request=None)[source]
-

Bases: object

-

This client class is used for gathering and sending game details to the -Evennia Game Index. Since EGI is in the early goings, this isn’t -incredibly configurable as far as to what is being sent.

-
-
-__init__(on_bad_request=None)[source]
-
-
Parameters
-

on_bad_request – Optional callable to trigger when a bad request -was sent. This is almost always going to be due to bad config.

-
-
-
- -
-
-send_game_details()[source]
-

This is where the magic happens. Send details about the game to the -Evennia Game Index.

-
- -
-
-handle_egd_response(response)[source]
-
- -
- -
-
-class evennia.server.game_index_client.client.SimpleResponseReceiver(status_code, d)[source]
-

Bases: twisted.internet.protocol.Protocol

-

Used for pulling the response body out of an HTTP response.

-
-
-__init__(status_code, d)[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
-
-dataReceived(data)[source]
-

Called whenever data is received.

-

Use this method to translate to a higher-level message. Usually, some -callback will be made upon the receipt of each complete protocol -message.

-
-
@param data: a string of indeterminate length. Please keep in mind

that you will probably need to buffer some data, as partial -(or multiple) protocol messages may be received! I recommend -that unit tests for protocols call through to this method with -differing chunk sizes, down to one byte at a time.

-
-
-
- -
-
-connectionLost(reason=<twisted.python.failure.Failure twisted.internet.error.ConnectionDone: Connection was closed cleanly.>)[source]
-

Called when the connection is shut down.

-

Clear any circular references here, and any external references -to this Protocol. The connection has been closed.

-

@type reason: L{twisted.python.failure.Failure}

-
- -
- -
-
-class evennia.server.game_index_client.client.StringProducer(body)[source]
-

Bases: object

-

Used for feeding a request body to the tx HTTP client.

-
-
-__init__(body)[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
-
-startProducing(consumer)[source]
-
- -
-
-pauseProducing()[source]
-
- -
-
-stopProducing()[source]
-
- -
- -
-
-class evennia.server.game_index_client.client.QuietHTTP11ClientFactory(quiescentCallback, metadata)[source]
-

Bases: twisted.web.client._HTTP11ClientFactory

-

Silences the obnoxious factory start/stop messages in the default client.

-
-
-noisy = False
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.game_index_client.html b/docs/0.9.5/api/evennia.server.game_index_client.html deleted file mode 100644 index 84523e71c5..0000000000 --- a/docs/0.9.5/api/evennia.server.game_index_client.html +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - evennia.server.game_index_client — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.game_index_client

- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.game_index_client.service.html b/docs/0.9.5/api/evennia.server.game_index_client.service.html deleted file mode 100644 index 044b203a71..0000000000 --- a/docs/0.9.5/api/evennia.server.game_index_client.service.html +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - evennia.server.game_index_client.service — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.game_index_client.service

-

Service for integrating the Evennia Game Index client into Evennia.

-
-
-class evennia.server.game_index_client.service.EvenniaGameIndexService[source]
-

Bases: twisted.application.service.Service

-

Twisted Service that contains a LoopingCall for regularly sending game details -to the Evennia Game Index.

-
-
-name = 'GameIndexClient'
-
- -
-
-__init__()[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
-
-startService()[source]
-
- -
-
-stopService()[source]
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.html b/docs/0.9.5/api/evennia.server.html deleted file mode 100644 index d455c81a23..0000000000 --- a/docs/0.9.5/api/evennia.server.html +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - - - - evennia.server — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server

-

This sub-package holds the Server and Portal programs - the “core” of -Evennia. It also contains the SessionHandler that manages all -connected users as well as defines all the connection protocols used -to connect to the game.

- - -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.initial_setup.html b/docs/0.9.5/api/evennia.server.initial_setup.html deleted file mode 100644 index ea055d9795..0000000000 --- a/docs/0.9.5/api/evennia.server.initial_setup.html +++ /dev/null @@ -1,159 +0,0 @@ - - - - - - - - - evennia.server.initial_setup — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.initial_setup

-

This module handles initial database propagation, which is only run the first time the game starts. -It will create some default objects (notably give #1 its evennia-specific properties, and create the -Limbo room). It will also hooks, and then perform an initial restart.

-

Everything starts at handle_setup()

-
-
-evennia.server.initial_setup.create_objects()[source]
-

Creates the #1 account and Limbo room.

-
- -
-
-evennia.server.initial_setup.at_initial_setup()[source]
-

Custom hook for users to overload some or all parts of the initial -setup. Called very last in the sequence. It tries to import and -srun a module settings.AT_INITIAL_SETUP_HOOK_MODULE and will fail -silently if this does not exist or fails to load.

-
- -
-
-evennia.server.initial_setup.collectstatic()[source]
-

Run collectstatic to make sure all web assets are loaded.

-
- -
-
-evennia.server.initial_setup.reset_server()[source]
-

We end the initialization by resetting the server. This makes sure -the first login is the same as all the following ones, -particularly it cleans all caches for the special objects. It -also checks so the warm-reset mechanism works as it should.

-
- -
-
-evennia.server.initial_setup.handle_setup(last_step=None)[source]
-

Main logic for the module. It allows for restarting the -initialization at any point if one of the modules should crash.

-
-
Parameters
-

last_step (str, None) – The last stored successful step, for starting -over on errors. None if starting from scratch. If this is ‘done’, -the function will exit immediately.

-
-
-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.inputfuncs.html b/docs/0.9.5/api/evennia.server.inputfuncs.html deleted file mode 100644 index 76639fc92e..0000000000 --- a/docs/0.9.5/api/evennia.server.inputfuncs.html +++ /dev/null @@ -1,420 +0,0 @@ - - - - - - - - - evennia.server.inputfuncs — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.inputfuncs

-

Functions for processing input commands.

-

All global functions in this module whose name does not start with “_” -is considered an inputfunc. Each function must have the following -callsign (where inputfunc name is always lower-case, no matter what the -OOB input name looked like):

-
-

inputfunc(session, *args, **kwargs)

-
-

Where “options” is always one of the kwargs, containing eventual -protocol-options. -There is one special function, the “default” function, which is called -on a no-match. It has this callsign:

-
-

default(session, cmdname, *args, **kwargs)

-
-

Evennia knows which modules to use for inputfuncs by -settings.INPUT_FUNC_MODULES.

-
-
-evennia.server.inputfuncs.text(session, *args, **kwargs)[source]
-

Main text input from the client. This will execute a command -string on the server.

-
-
Parameters
-
    -
  • session (Session) – The active Session to receive the input.

  • -
  • text (str) – First arg is used as text-command input. Other -arguments are ignored.

  • -
-
-
-
- -
-
-evennia.server.inputfuncs.bot_data_in(session, *args, **kwargs)[source]
-

Text input from the IRC and RSS bots. -This will trigger the execute_cmd method on the bots in-game counterpart.

-
-
Parameters
-
    -
  • session (Session) – The active Session to receive the input.

  • -
  • text (str) – First arg is text input. Other arguments are ignored.

  • -
-
-
-
- -
-
-evennia.server.inputfuncs.echo(session, *args, **kwargs)[source]
-

Echo test function

-
- -
-
-evennia.server.inputfuncs.default(session, cmdname, *args, **kwargs)[source]
-

Default catch-function. This is like all other input functions except -it will get cmdname as the first argument.

-
- -
-
-evennia.server.inputfuncs.client_options(session, *args, **kwargs)[source]
-

This allows the client an OOB way to inform us about its name and capabilities. -This will be integrated into the session settings

-
-
Keyword Arguments
-
    -
  • get (bool) – If this is true, return the settings as a dict -(ignore all other kwargs).

  • -
  • client (str) – A client identifier, like “mushclient”.

  • -
  • version (str) – A client version

  • -
  • ansi (bool) – Supports ansi colors

  • -
  • xterm256 (bool) – Supports xterm256 colors or not

  • -
  • mxp (bool) – Supports MXP or not

  • -
  • utf-8 (bool) – Supports UTF-8 or not

  • -
  • screenreader (bool) – Screen-reader mode on/off

  • -
  • mccp (bool) – MCCP compression on/off

  • -
  • screenheight (int) – Screen height in lines

  • -
  • screenwidth (int) – Screen width in characters

  • -
  • inputdebug (bool) – Debug input functions

  • -
  • nocolor (bool) – Strip color

  • -
  • raw (bool) – Turn off parsing

  • -
  • localecho (bool) – Turn on server-side echo (for clients not supporting it)

  • -
-
-
-
- -
-
-evennia.server.inputfuncs.get_client_options(session, *args, **kwargs)[source]
-

Alias wrapper for getting options.

-
- -
-
-evennia.server.inputfuncs.get_inputfuncs(session, *args, **kwargs)[source]
-

Get the keys of all available inputfuncs. Note that we don’t get -it from this module alone since multiple modules could be added. -So we get it from the sessionhandler.

-
- -
-
-evennia.server.inputfuncs.login(session, *args, **kwargs)[source]
-

Peform a login. This only works if session is currently not logged -in. This will also automatically throttle too quick attempts.

-
-
Keyword Arguments
-
    -
  • name (str) – Account name

  • -
  • password (str) – Plain-text password

  • -
-
-
-
- -
-
-evennia.server.inputfuncs.get_value(session, *args, **kwargs)[source]
-

Return the value of a given attribute or db_property on the -session’s current account or character.

-
-
Keyword Arguments
-

name (str) – Name of info value to return. Only names -in the _gettable dictionary earlier in this module -are accepted.

-
-
-
- -
-
-evennia.server.inputfuncs.repeat(session, *args, **kwargs)[source]
-

Call a named function repeatedly. Note that -this is meant as an example of limiting the number of -possible call functions.

-
-
Keyword Arguments
-
    -
  • callback (str) – The function to call. Only functions -from the _repeatable dictionary earlier in this -module are available.

  • -
  • interval (int) –

    How often to call function (s). -Defaults to once every 60 seconds with a minimum

    -
    -

    of 5 seconds.

    -
    -

  • -
  • stop (bool) – Stop a previously assigned ticker with -the above settings.

  • -
-
-
-
- -
-
-evennia.server.inputfuncs.unrepeat(session, *args, **kwargs)[source]
-

Wrapper for OOB use

-
- -
-
-evennia.server.inputfuncs.monitor(session, *args, **kwargs)[source]
-

Adds monitoring to a given property or Attribute.

-
-
Keyword Arguments
-
    -
  • name (str) – The name of the property or Attribute -to report. No db_* prefix is needed. Only names -in the _monitorable dict earlier in this module -are accepted.

  • -
  • stop (bool) – Stop monitoring the above name.

  • -
  • outputfunc_name (str, optional) – Change the name of -the outputfunc name. This is used e.g. by MSDP which -has its own specific output format.

  • -
-
-
-
- -
-
-evennia.server.inputfuncs.unmonitor(session, *args, **kwargs)[source]
-

Wrapper for turning off monitoring

-
- -
-
-evennia.server.inputfuncs.monitored(session, *args, **kwargs)[source]
-

Report on what is being monitored

-
- -
-
-evennia.server.inputfuncs.webclient_options(session, *args, **kwargs)[source]
-

Handles retrieving and changing of options related to the webclient.

-

If kwargs is empty (or contains just a “cmdid”), the saved options will be -sent back to the session. -A monitor handler will be created to inform the client of any future options -that changes.

-

If kwargs is not empty, the key/values stored in there will be persisted -to the account object.

-
-
Keyword Arguments
-

name> (<option) – an option to save

-
-
-
- -
-
-evennia.server.inputfuncs.hello(session, *args, **kwargs)
-

This allows the client an OOB way to inform us about its name and capabilities. -This will be integrated into the session settings

-
-
Keyword Arguments
-
    -
  • get (bool) – If this is true, return the settings as a dict -(ignore all other kwargs).

  • -
  • client (str) – A client identifier, like “mushclient”.

  • -
  • version (str) – A client version

  • -
  • ansi (bool) – Supports ansi colors

  • -
  • xterm256 (bool) – Supports xterm256 colors or not

  • -
  • mxp (bool) – Supports MXP or not

  • -
  • utf-8 (bool) – Supports UTF-8 or not

  • -
  • screenreader (bool) – Screen-reader mode on/off

  • -
  • mccp (bool) – MCCP compression on/off

  • -
  • screenheight (int) – Screen height in lines

  • -
  • screenwidth (int) – Screen width in characters

  • -
  • inputdebug (bool) – Debug input functions

  • -
  • nocolor (bool) – Strip color

  • -
  • raw (bool) – Turn off parsing

  • -
  • localecho (bool) – Turn on server-side echo (for clients not supporting it)

  • -
-
-
-
- -
-
-evennia.server.inputfuncs.supports_set(session, *args, **kwargs)
-

This allows the client an OOB way to inform us about its name and capabilities. -This will be integrated into the session settings

-
-
Keyword Arguments
-
    -
  • get (bool) – If this is true, return the settings as a dict -(ignore all other kwargs).

  • -
  • client (str) – A client identifier, like “mushclient”.

  • -
  • version (str) – A client version

  • -
  • ansi (bool) – Supports ansi colors

  • -
  • xterm256 (bool) – Supports xterm256 colors or not

  • -
  • mxp (bool) – Supports MXP or not

  • -
  • utf-8 (bool) – Supports UTF-8 or not

  • -
  • screenreader (bool) – Screen-reader mode on/off

  • -
  • mccp (bool) – MCCP compression on/off

  • -
  • screenheight (int) – Screen height in lines

  • -
  • screenwidth (int) – Screen width in characters

  • -
  • inputdebug (bool) – Debug input functions

  • -
  • nocolor (bool) – Strip color

  • -
  • raw (bool) – Turn off parsing

  • -
  • localecho (bool) – Turn on server-side echo (for clients not supporting it)

  • -
-
-
-
- -
-
-evennia.server.inputfuncs.msdp_list(session, *args, **kwargs)[source]
-

MSDP LIST command

-
- -
-
-evennia.server.inputfuncs.msdp_report(session, *args, **kwargs)[source]
-

MSDP REPORT command

-
- -
-
-evennia.server.inputfuncs.msdp_unreport(session, *args, **kwargs)[source]
-

MSDP UNREPORT command

-
- -
-
-evennia.server.inputfuncs.msdp_send(session, *args, **kwargs)[source]
-

MSDP SEND command

-
- -
-
-evennia.server.inputfuncs.external_discord_hello(session, *args, **kwargs)
-

Dummy used to swallow missing-inputfunc errors for -common clients.

-
- -
-
-evennia.server.inputfuncs.client_gui(session, *args, **kwargs)
-

Dummy used to swallow missing-inputfunc errors for -common clients.

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.manager.html b/docs/0.9.5/api/evennia.server.manager.html deleted file mode 100644 index dd35bc6ae2..0000000000 --- a/docs/0.9.5/api/evennia.server.manager.html +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - - - - evennia.server.manager — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.manager

-

Custom manager for ServerConfig objects.

-
-
-class evennia.server.manager.ServerConfigManager(*args, **kwargs)[source]
-

Bases: django.db.models.manager.Manager

-

This ServerConfigManager implements methods for searching and -manipulating ServerConfigs directly from the database.

-

These methods will all return database objects (or QuerySets) -directly.

-

ServerConfigs are used to store certain persistent settings for -the server at run-time.

-
-
-conf(key=None, value=None, delete=False, default=None)[source]
-

Add, retrieve and manipulate config values.

-
-
Parameters
-
    -
  • key (str, optional) – Name of config.

  • -
  • value (str, optional) – Data to store in this config value.

  • -
  • delete (bool, optional) – If True, delete config with key.

  • -
  • default (str, optional) – Use when retrieving a config value -by a key that does not exist.

  • -
-
-
Returns
-

all (list) – If key was not given - all stored config values. -value (str): If key was given, this is the stored value, or

-
-

default if no matching key was found.

-
-

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.models.html b/docs/0.9.5/api/evennia.server.models.html deleted file mode 100644 index 4a1994a7ec..0000000000 --- a/docs/0.9.5/api/evennia.server.models.html +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - - - evennia.server.models — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.models

-

Server Configuration flags

-

This holds persistent server configuration flags.

-

Config values should usually be set through the -manager’s conf() method.

-
-
-class evennia.server.models.ServerConfig(*args, **kwargs)[source]
-

Bases: evennia.utils.idmapper.models.WeakSharedMemoryModel

-

On-the fly storage of global settings.

-

Properties defined on ServerConfig:

-
-
    -
  • key: Main identifier

  • -
  • value: Value stored in key. This is a pickled storage.

  • -
-
-
-
-db_key
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_value
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-objects = <evennia.server.manager.ServerConfigManager object>
-
- -
-
-property key
-

Getter. Allows for value = self.key

-
- -
-
-property value
-

Getter. Allows for value = self.value

-
- -
-
-store(key, value)[source]
-

Wrap the storage.

-
-
Parameters
-
    -
  • key (str) – The name of this store.

  • -
  • value (str) – The data to store with this key.

  • -
-
-
-
- -
-
-exception DoesNotExist
-

Bases: django.core.exceptions.ObjectDoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: django.core.exceptions.MultipleObjectsReturned

-
- -
-
-id
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-path = 'evennia.server.models.ServerConfig'
-
- -
-
-typename = 'WeakSharedMemoryModelBase'
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.portal.amp.html b/docs/0.9.5/api/evennia.server.portal.amp.html deleted file mode 100644 index 2b7db46567..0000000000 --- a/docs/0.9.5/api/evennia.server.portal.amp.html +++ /dev/null @@ -1,586 +0,0 @@ - - - - - - - - - evennia.server.portal.amp — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.portal.amp

-

The AMP (Asynchronous Message Protocol)-communication commands and constants used by Evennia.

-

This module acts as a central place for AMP-servers and -clients to get commands to use.

-
-
-evennia.server.portal.amp.dumps(data)[source]
-
- -
-
-evennia.server.portal.amp.loads(data)[source]
-
- -
-
-class evennia.server.portal.amp.Compressed(optional=False)[source]
-

Bases: twisted.protocols.amp.String

-

This is a custom AMP command Argument that both handles too-long -sends as well as uses zlib for compression across the wire. The -batch-grouping of too-long sends is borrowed from the “mediumbox” -recipy at twisted-hacks’s ~glyph/+junk/amphacks/mediumbox.

-
-
-fromBox(name, strings, objects, proto)[source]
-

Converts from box string representation to python. We read back too-long batched data and -put it back together here.

-
- -
-
-toBox(name, strings, objects, proto)[source]
-

Convert from python object to string box representation. -we break up too-long data snippets into multiple batches here.

-
- -
-
-toString(inObject)[source]
-

Convert to send as a bytestring on the wire, with compression.

-

Note: In Py3 this is really a byte stream.

-
- -
-
-fromString(inString)[source]
-

Convert (decompress) from the string-representation on the wire to Python.

-
- -
- -
-
-class evennia.server.portal.amp.MsgLauncher2Portal(**kw)[source]
-

Bases: twisted.protocols.amp.Command

-

Message Launcher -> Portal

-
-
-key = 'MsgLauncher2Portal'
-
- -
-
-arguments: List[Tuple[bytes, twisted.protocols.amp.Argument]] = [(b'operation', <twisted.protocols.amp.String object>), (b'arguments', <twisted.protocols.amp.String object>)]
-
- -
-
-errors: Dict[Type[Exception], bytes] = {<class 'Exception'>: b'EXCEPTION'}
-
- -
-
-response: List[Tuple[bytes, twisted.protocols.amp.Argument]] = []
-
- -
-
-allErrors = {<class 'Exception'>: b'EXCEPTION'}
-
- -
-
-commandName = b'MsgLauncher2Portal'
-
- -
-
-reverseErrors = {b'EXCEPTION': <class 'Exception'>}
-
- -
- -
-
-class evennia.server.portal.amp.MsgPortal2Server(**kw)[source]
-

Bases: twisted.protocols.amp.Command

-

Message Portal -> Server

-
-
-key = b'MsgPortal2Server'
-
- -
-
-arguments: List[Tuple[bytes, twisted.protocols.amp.Argument]] = [(b'packed_data', <evennia.server.portal.amp.Compressed object>)]
-
- -
-
-errors: Dict[Type[Exception], bytes] = {<class 'Exception'>: b'EXCEPTION'}
-
- -
-
-response: List[Tuple[bytes, twisted.protocols.amp.Argument]] = []
-
- -
-
-allErrors = {<class 'Exception'>: b'EXCEPTION'}
-
- -
-
-commandName = b'MsgPortal2Server'
-
- -
-
-reverseErrors = {b'EXCEPTION': <class 'Exception'>}
-
- -
- -
-
-class evennia.server.portal.amp.MsgServer2Portal(**kw)[source]
-

Bases: twisted.protocols.amp.Command

-

Message Server -> Portal

-
-
-key = 'MsgServer2Portal'
-
- -
-
-arguments: List[Tuple[bytes, twisted.protocols.amp.Argument]] = [(b'packed_data', <evennia.server.portal.amp.Compressed object>)]
-
- -
-
-errors: Dict[Type[Exception], bytes] = {<class 'Exception'>: b'EXCEPTION'}
-
- -
-
-response: List[Tuple[bytes, twisted.protocols.amp.Argument]] = []
-
- -
-
-allErrors = {<class 'Exception'>: b'EXCEPTION'}
-
- -
-
-commandName = b'MsgServer2Portal'
-
- -
-
-reverseErrors = {b'EXCEPTION': <class 'Exception'>}
-
- -
- -
-
-class evennia.server.portal.amp.AdminPortal2Server(**kw)[source]
-

Bases: twisted.protocols.amp.Command

-

Administration Portal -> Server

-

Sent when the portal needs to perform admin operations on the -server, such as when a new session connects or resyncs

-
-
-key = 'AdminPortal2Server'
-
- -
-
-arguments: List[Tuple[bytes, twisted.protocols.amp.Argument]] = [(b'packed_data', <evennia.server.portal.amp.Compressed object>)]
-
- -
-
-errors: Dict[Type[Exception], bytes] = {<class 'Exception'>: b'EXCEPTION'}
-
- -
-
-response: List[Tuple[bytes, twisted.protocols.amp.Argument]] = []
-
- -
-
-allErrors = {<class 'Exception'>: b'EXCEPTION'}
-
- -
-
-commandName = b'AdminPortal2Server'
-
- -
-
-reverseErrors = {b'EXCEPTION': <class 'Exception'>}
-
- -
- -
-
-class evennia.server.portal.amp.AdminServer2Portal(**kw)[source]
-

Bases: twisted.protocols.amp.Command

-

Administration Server -> Portal

-

Sent when the server needs to perform admin operations on the -portal.

-
-
-key = 'AdminServer2Portal'
-
- -
-
-arguments: List[Tuple[bytes, twisted.protocols.amp.Argument]] = [(b'packed_data', <evennia.server.portal.amp.Compressed object>)]
-
- -
-
-errors: Dict[Type[Exception], bytes] = {<class 'Exception'>: b'EXCEPTION'}
-
- -
-
-response: List[Tuple[bytes, twisted.protocols.amp.Argument]] = []
-
- -
-
-allErrors = {<class 'Exception'>: b'EXCEPTION'}
-
- -
-
-commandName = b'AdminServer2Portal'
-
- -
-
-reverseErrors = {b'EXCEPTION': <class 'Exception'>}
-
- -
- -
-
-class evennia.server.portal.amp.MsgStatus(**kw)[source]
-

Bases: twisted.protocols.amp.Command

-

Check Status between AMP services

-
-
-key = 'MsgStatus'
-
- -
-
-arguments: List[Tuple[bytes, twisted.protocols.amp.Argument]] = [(b'status', <twisted.protocols.amp.String object>)]
-
- -
-
-errors: Dict[Type[Exception], bytes] = {<class 'Exception'>: b'EXCEPTION'}
-
- -
-
-response: List[Tuple[bytes, twisted.protocols.amp.Argument]] = [(b'status', <twisted.protocols.amp.String object>)]
-
- -
-
-allErrors = {<class 'Exception'>: b'EXCEPTION'}
-
- -
-
-commandName = b'MsgStatus'
-
- -
-
-reverseErrors = {b'EXCEPTION': <class 'Exception'>}
-
- -
- -
-
-class evennia.server.portal.amp.FunctionCall(**kw)[source]
-

Bases: twisted.protocols.amp.Command

-

Bidirectional Server <-> Portal

-

Sent when either process needs to call an arbitrary function in -the other. This does not use the batch-send functionality.

-
-
-key = 'FunctionCall'
-
- -
-
-arguments: List[Tuple[bytes, twisted.protocols.amp.Argument]] = [(b'module', <twisted.protocols.amp.String object>), (b'function', <twisted.protocols.amp.String object>), (b'args', <twisted.protocols.amp.String object>), (b'kwargs', <twisted.protocols.amp.String object>)]
-
- -
-
-errors: Dict[Type[Exception], bytes] = {<class 'Exception'>: b'EXCEPTION'}
-
- -
-
-response: List[Tuple[bytes, twisted.protocols.amp.Argument]] = [(b'result', <twisted.protocols.amp.String object>)]
-
- -
-
-allErrors = {<class 'Exception'>: b'EXCEPTION'}
-
- -
-
-commandName = b'FunctionCall'
-
- -
-
-reverseErrors = {b'EXCEPTION': <class 'Exception'>}
-
- -
- -
-
-class evennia.server.portal.amp.AMPMultiConnectionProtocol(*args, **kwargs)[source]
-

Bases: twisted.protocols.amp.AMP

-

AMP protocol that safely handle multiple connections to the same -server without dropping old ones - new clients will receive -all server returns (broadcast). Will also correctly handle -erroneous HTTP requests on the port and return a HTTP error response.

-
-
-__init__(*args, **kwargs)[source]
-

Initialize protocol with some things that need to be in place -already before connecting both on portal and server.

-
- -
-
-dataReceived(data)[source]
-

Handle non-AMP messages, such as HTTP communication.

-
- -
-
-makeConnection(transport)[source]
-

Swallow connection log message here. Copied from original -in the amp protocol.

-
- -
-
-connectionMade()[source]
-

This is called when an AMP connection is (re-)established. AMP calls it on both sides.

-
- -
-
-connectionLost(reason)[source]
-

We swallow connection errors here. The reason is that during a -normal reload/shutdown there will almost always be cases where -either the portal or server shuts down before a message has -returned its (empty) return, triggering a connectionLost error -that is irrelevant. If a true connection error happens, the -portal will continuously try to reconnect, showing the problem -that way.

-
- -
-
-errback(err, info)[source]
-

Error callback. -Handles errors to avoid dropping connections on server tracebacks.

-
-
Parameters
-
    -
  • err (Failure) – Deferred error instance.

  • -
  • info (str) – Error string.

  • -
-
-
-
- -
-
-data_in(packed_data)[source]
-

Process incoming packed data.

-
-
Parameters
-

packed_data (bytes) – Pickled data.

-
-
Returns
-

unpaced_data (any) – Unpickled package

-
-
-
- -
-
-broadcast(command, sessid, **kwargs)[source]
-

Send data across the wire to all connections.

-
-
Parameters
-
    -
  • command (AMP Command) – A protocol send command.

  • -
  • sessid (int) – A unique Session id.

  • -
-
-
Returns
-

deferred (deferred or None) – A deferred with an errback.

-
-
-

Notes

-

Data will be sent across the wire pickled as a tuple -(sessid, kwargs).

-
- -
-
-send_FunctionCall(modulepath, functionname, *args, **kwargs)[source]
-

Access method called by either process. This will call an arbitrary -function on the other process (On Portal if calling from Server and -vice versa).

-
-
Inputs:

modulepath (str) - python path to module holding function to call -functionname (str) - name of function in given module -*args, **kwargs will be used as arguments/keyword args for the

-
-

remote function call

-
-
-
-
-
Returns
-

A deferred that fires with the return value of the remote -function call

-
-
-
- -
-
-receive_functioncall()[source]
-

Helper decorator

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.portal.amp_server.html b/docs/0.9.5/api/evennia.server.portal.amp_server.html deleted file mode 100644 index 92cf8057c9..0000000000 --- a/docs/0.9.5/api/evennia.server.portal.amp_server.html +++ /dev/null @@ -1,334 +0,0 @@ - - - - - - - - - evennia.server.portal.amp_server — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.portal.amp_server

-

The Evennia Portal service acts as an AMP-server, handling AMP -communication to the AMP clients connecting to it (by default -these are the Evennia Server and the evennia launcher).

-
-
-evennia.server.portal.amp_server.getenv()[source]
-

Get current environment and add PYTHONPATH.

-
-
Returns
-

env (dict) – Environment global dict.

-
-
-
- -
-
-class evennia.server.portal.amp_server.AMPServerFactory(portal)[source]
-

Bases: twisted.internet.protocol.ServerFactory

-

This factory creates AMP Server connection. This acts as the ‘Portal’-side communication to the -‘Server’ process.

-
-
-noisy = False
-
- -
-
-logPrefix()[source]
-

How this is named in logs

-
- -
-
-__init__(portal)[source]
-

Initialize the factory. This is called as the Portal service starts.

-
-
Parameters
-
    -
  • portal (Portal) – The Evennia Portal service instance.

  • -
  • protocol (Protocol) – The protocol the factory creates -instances of.

  • -
-
-
-
- -
-
-buildProtocol(addr)[source]
-

Start a new connection, and store it on the service object.

-
-
Parameters
-

addr (str) – Connection address. Not used.

-
-
Returns
-

protocol (Protocol) – The created protocol.

-
-
-
- -
- -
-
-class evennia.server.portal.amp_server.AMPServerProtocol(*args, **kwargs)[source]
-

Bases: evennia.server.portal.amp.AMPMultiConnectionProtocol

-

Protocol subclass for the AMP-server run by the Portal.

-
-
-connectionLost(reason)[source]
-

Set up a simple callback mechanism to let the amp-server wait for a connection to close.

-
- -
-
-get_status()[source]
-

Return status for the Evennia infrastructure.

-
-
Returns
-

status (tuple)

-
-
The portal/server status and pids

(portal_live, server_live, portal_PID, server_PID).

-
-
-

-
-
-
- -
-
-data_to_server(command, sessid, **kwargs)[source]
-

Send data across the wire to the Server.

-
-
Parameters
-
    -
  • command (AMP Command) – A protocol send command.

  • -
  • sessid (int) – A unique Session id.

  • -
  • kwargs (any) – Data to send. This will be pickled.

  • -
-
-
Returns
-

deferred (deferred or None) – A deferred with an errback.

-
-
-

Notes

-

Data will be sent across the wire pickled as a tuple -(sessid, kwargs).

-
- -
-
-start_server(server_twistd_cmd)[source]
-

(Re-)Launch the Evennia server.

-
-
Parameters
-

server_twisted_cmd (list) – The server start instruction -to pass to POpen to start the server.

-
-
-
- -
-
-wait_for_disconnect(callback, *args, **kwargs)[source]
-

Add a callback for when this connection is lost.

-
-
Parameters
-

callback (callable) – Will be called with *args, **kwargs -once this protocol is disconnected.

-
-
-
- -
-
-wait_for_server_connect(callback, *args, **kwargs)[source]
-

Add a callback for when the Server is sure to have connected.

-
-
Parameters
-

callback (callable) – Will be called with *args, **kwargs -once the Server handshake with Portal is complete.

-
-
-
- -
-
-stop_server(mode='shutdown')[source]
-

Shut down server in one or more modes.

-
-
Parameters
-

mode (str) – One of ‘shutdown’, ‘reload’ or ‘reset’.

-
-
-
- -
-
-send_Status2Launcher()[source]
-

Send a status stanza to the launcher.

-
- -
-
-send_MsgPortal2Server(session, **kwargs)[source]
-

Access method called by the Portal and executed on the Portal.

-
-
Parameters
-
    -
  • session (session) – Session

  • -
  • kwargs (any, optional) – Optional data.

  • -
-
-
Returns
-

deferred (Deferred) – Asynchronous return.

-
-
-
- -
-
-send_AdminPortal2Server(session, operation='', **kwargs)[source]
-

Send Admin instructions from the Portal to the Server. -Executed on the Portal.

-
-
Parameters
-
    -
  • session (Session) – Session.

  • -
  • operation (char, optional) – Identifier for the server operation, as defined by the -global variables in evennia/server/amp.py.

  • -
  • data (str or dict, optional) – Data used in the administrative operation.

  • -
-
-
-
- -
-
-portal_receive_status()
-

Helper decorator

-
- -
-
-portal_receive_launcher2portal()
-

Helper decorator

-
- -
-
-portal_receive_server2portal()
-

Helper decorator

-
- -
-
-portal_receive_adminserver2portal()
-

Helper decorator

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.portal.grapevine.html b/docs/0.9.5/api/evennia.server.portal.grapevine.html deleted file mode 100644 index 8b42baf210..0000000000 --- a/docs/0.9.5/api/evennia.server.portal.grapevine.html +++ /dev/null @@ -1,331 +0,0 @@ - - - - - - - - - evennia.server.portal.grapevine — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.portal.grapevine

-

Grapevine network connection

-

This is an implementation of the Grapevine Websocket protocol v 1.0.0 as -outlined here: https://grapevine.haus/docs

-

This will allow the linked game to transfer status as well as connects -the grapevine client to in-game channels.

-
-
-class evennia.server.portal.grapevine.RestartingWebsocketServerFactory(sessionhandler, *args, **kwargs)[source]
-

Bases: autobahn.twisted.websocket.WebSocketClientFactory, twisted.internet.protocol.ReconnectingClientFactory

-

A variant of the websocket-factory that auto-reconnects.

-
-
-initialDelay = 1
-
- -
-
-factor = 1.5
-
- -
-
-maxDelay = 60
-
- -
-
-__init__(sessionhandler, *args, **kwargs)[source]
-

In addition to all arguments to the constructor of -:func:autobahn.websocket.interfaces.IWebSocketClientChannelFactory, -you can supply a **reactor** keyword argument to specify the -Twisted reactor to be used.

-
- -
-
-buildProtocol(addr)[source]
-

Build new instance of protocol

-
-
Parameters
-

addr (str) – Not used, using factory/settings data

-
-
-
- -
-
-startedConnecting(connector)[source]
-

Tracks reconnections for debugging.

-
-
Parameters
-

connector (Connector) – Represents the connection.

-
-
-
- -
-
-clientConnectionFailed(connector, reason)[source]
-

Called when Client failed to connect.

-
-
Parameters
-
    -
  • connector (Connection) – Represents the connection.

  • -
  • reason (str) – The reason for the failure.

  • -
-
-
-
- -
-
-clientConnectionLost(connector, reason)[source]
-

Called when Client loses connection.

-
-
Parameters
-
    -
  • connector (Connection) – Represents the connection.

  • -
  • reason (str) – The reason for the failure.

  • -
-
-
-
- -
-
-reconnect()[source]
-

Force a reconnection of the bot protocol. This requires -de-registering the session and then reattaching a new one, -otherwise you end up with an ever growing number of bot -sessions.

-
- -
-
-start()[source]
-

Connect protocol to remote server

-
- -
- -
-
-class evennia.server.portal.grapevine.GrapevineClient[source]
-

Bases: autobahn.twisted.websocket.WebSocketClientProtocol, evennia.server.session.Session

-

Implements the grapevine client

-
-
-__init__()[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
-
-at_login()[source]
-
- -
-
-onOpen()[source]
-

Called when connection is established.

-
- -
-
-onMessage(payload, isBinary)[source]
-

Callback fired when a complete WebSocket message was received.

-
-
Parameters
-
    -
  • payload (bytes) – The WebSocket message received.

  • -
  • isBinary (bool) – Flag indicating whether payload is binary or -UTF-8 encoded text.

  • -
-
-
-
- -
-
-onClose(wasClean, code=None, reason=None)[source]
-

This is executed when the connection is lost for whatever -reason. it can also be called directly, from the disconnect -method.

-
-
Parameters
-
    -
  • wasClean (bool) – **True** if the WebSocket was closed cleanly.

  • -
  • code (int or None) – Close status as sent by the WebSocket peer.

  • -
  • reason (str or None) – Close reason as sent by the WebSocket peer.

  • -
-
-
-
- -
-
-disconnect(reason=None)[source]
-

Generic hook for the engine to call in order to -disconnect this protocol.

-
-
Parameters
-

reason (str or None) – Motivation for the disconnection.

-
-
-
- -
-
-send_authenticate(*args, **kwargs)[source]
-

Send grapevine authentication. This should be send immediately upon connection.

-
- -
-
-send_heartbeat(*args, **kwargs)[source]
-

Send heartbeat to remote grapevine server.

-
- -
-
-send_subscribe(channelname, *args, **kwargs)[source]
-

Subscribe to new grapevine channel

-

Use with session.msg(subscribe=”channelname”)

-
- -
-
-send_unsubscribe(channelname, *args, **kwargs)[source]
-

Un-subscribe to a grapevine channel

-

Use with session.msg(unsubscribe=”channelname”)

-
- -
-
-send_channel(text, channel, sender, *args, **kwargs)[source]
-

Send text type Evennia -> grapevine

-

This is the channels/send message type

-

Use with session.msg(channel=(message, channel, sender))

-
- -
-
-send_default(*args, **kwargs)[source]
-

Ignore other outputfuncs

-
- -
-
-data_in(data, **kwargs)[source]
-

Send data grapevine -> Evennia

-
-
Keyword Arguments
-

data (dict) – Converted json data.

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.portal.html b/docs/0.9.5/api/evennia.server.portal.html deleted file mode 100644 index 9c5f1305f0..0000000000 --- a/docs/0.9.5/api/evennia.server.portal.html +++ /dev/null @@ -1,136 +0,0 @@ - - - - - - - - - evennia.server.portal — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.portal.irc.html b/docs/0.9.5/api/evennia.server.portal.irc.html deleted file mode 100644 index 49da471abd..0000000000 --- a/docs/0.9.5/api/evennia.server.portal.irc.html +++ /dev/null @@ -1,447 +0,0 @@ - - - - - - - - - evennia.server.portal.irc — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.portal.irc

-

This connects to an IRC network/channel and launches an ‘bot’ onto it. -The bot then pipes what is being said between the IRC channel and one or -more Evennia channels.

-
-
-evennia.server.portal.irc.parse_ansi_to_irc(string)[source]
-

Parse |-type syntax and replace with IRC color markers

-
-
Parameters
-

string (str) – String to parse for ANSI colors.

-
-
Returns
-

parsed_string (str) – String with replaced ANSI colors.

-
-
-
- -
-
-evennia.server.portal.irc.parse_irc_to_ansi(string)[source]
-

Parse IRC mIRC color syntax and replace with Evennia ANSI color markers

-
-
Parameters
-

string (str) – String to parse for IRC colors.

-
-
Returns
-

parsed_string (str) – String with replaced IRC colors.

-
-
-
- -
-
-class evennia.server.portal.irc.IRCBot[source]
-

Bases: twisted.words.protocols.irc.IRCClient, evennia.server.session.Session

-

An IRC bot that tracks activity in a channel as well -as sends text to it when prompted

-
-
-lineRate = 1
-
- -
-
-nickname = None
-
- -
-
-logger = None
-
- -
-
-factory: Optional[twisted.internet.protocol.Factory] = None
-
- -
-
-channel = None
-
- -
-
-sourceURL = 'http://code.evennia.com'
-
- -
-
-signedOn()[source]
-

This is called when we successfully connect to the network. We -make sure to now register with the game as a full session.

-
- -
-
-disconnect(reason='')[source]
-

Called by sessionhandler to disconnect this protocol.

-
-
Parameters
-

reason (str) – Motivation for the disconnect.

-
-
-
- -
-
-at_login()[source]
-
- -
-
-privmsg(user, channel, msg)[source]
-

Called when the connected channel receives a message.

-
-
Parameters
-
    -
  • user (str) – User name sending the message.

  • -
  • channel (str) – Channel name seeing the message.

  • -
  • msg (str) – The message arriving from channel.

  • -
-
-
-
- -
-
-action(user, channel, msg)[source]
-

Called when an action is detected in channel.

-
-
Parameters
-
    -
  • user (str) – User name sending the message.

  • -
  • channel (str) – Channel name seeing the message.

  • -
  • msg (str) – The message arriving from channel.

  • -
-
-
-
- -
-
-get_nicklist()[source]
-

Retrieve name list from the channel. The return -is handled by the catch methods below.

-
- -
-
-irc_RPL_NAMREPLY(prefix, params)[source]
-

“Handles IRC NAME request returns (nicklist)

-
- -
-
-irc_RPL_ENDOFNAMES(prefix, params)[source]
-

Called when the nicklist has finished being returned.

-
- -
-
-pong(user, time)[source]
-

Called with the return timing from a PING.

-
-
Parameters
-
    -
  • user (str) – Name of user

  • -
  • time (float) – Ping time in secs.

  • -
-
-
-
- -
-
-data_in(text=None, **kwargs)[source]
-

Data IRC -> Server.

-
-
Keyword Arguments
-
    -
  • text (str) – Ingoing text.

  • -
  • kwargs (any) – Other data from protocol.

  • -
-
-
-
- -
-
-send_channel(*args, **kwargs)[source]
-

Send channel text to IRC channel (visible to all). Note that -we don’t handle the “text” send (it’s rerouted to send_default -which does nothing) - this is because the IRC bot is a normal -session and would otherwise report anything that happens to it -to the IRC channel (such as it seeing server reload messages).

-
-
Parameters
-

text (str) – Outgoing text

-
-
-
- -
-
-send_privmsg(*args, **kwargs)[source]
-

Send message only to specific user.

-
-
Parameters
-

text (str) – Outgoing text.

-
-
Keyword Arguments
-

user (str) – the nick to send -privately to.

-
-
-
- -
-
-send_request_nicklist(*args, **kwargs)[source]
-

Send a request for the channel nicklist. The return (handled -by self.irc_RPL_ENDOFNAMES) will be sent back as a message -with type **nicklist’.

-
- -
-
-send_ping(*args, **kwargs)[source]
-

Send a ping. The return (handled by self.pong) will be sent -back as a message of type ‘ping’.

-
- -
-
-send_reconnect(*args, **kwargs)[source]
-

The server instructs us to rebuild the connection by force, -probably because the client silently lost connection.

-
- -
-
-send_default(*args, **kwargs)[source]
-

Ignore other types of sends.

-
- -
- -
-
-class evennia.server.portal.irc.IRCBotFactory(sessionhandler, uid=None, botname=None, channel=None, network=None, port=None, ssl=None)[source]
-

Bases: twisted.internet.protocol.ReconnectingClientFactory

-

Creates instances of IRCBot, connecting with a staggered -increase in delay

-
-
-initialDelay = 1
-
- -
-
-factor = 1.5
-
- -
-
-maxDelay = 60
-
- -
-
-__init__(sessionhandler, uid=None, botname=None, channel=None, network=None, port=None, ssl=None)[source]
-

Storing some important protocol properties.

-
-
Parameters
-

sessionhandler (SessionHandler) – Reference to the main Sessionhandler.

-
-
Keyword Arguments
-
    -
  • uid (int) – Bot user id.

  • -
  • botname (str) – Bot name (seen in IRC channel).

  • -
  • channel (str) – IRC channel to connect to.

  • -
  • network (str) – Network address to connect to.

  • -
  • port (str) – Port of the network.

  • -
  • ssl (bool) – Indicates SSL connection.

  • -
-
-
-
- -
-
-buildProtocol(addr)[source]
-

Build the protocol and assign it some properties.

-
-
Parameters
-

addr (str) – Not used; using factory data.

-
-
-
- -
-
-startedConnecting(connector)[source]
-

Tracks reconnections for debugging.

-
-
Parameters
-

connector (Connector) – Represents the connection.

-
-
-
- -
-
-clientConnectionFailed(connector, reason)[source]
-

Called when Client failed to connect.

-
-
Parameters
-
    -
  • connector (Connection) – Represents the connection.

  • -
  • reason (str) – The reason for the failure.

  • -
-
-
-
- -
-
-clientConnectionLost(connector, reason)[source]
-

Called when Client loses connection.

-
-
Parameters
-
    -
  • connector (Connection) – Represents the connection.

  • -
  • reason (str) – The reason for the failure.

  • -
-
-
-
- -
-
-reconnect()[source]
-

Force a reconnection of the bot protocol. This requires -de-registering the session and then reattaching a new one, -otherwise you end up with an ever growing number of bot -sessions.

-
- -
-
-start()[source]
-

Connect session to sessionhandler.

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.portal.mccp.html b/docs/0.9.5/api/evennia.server.portal.mccp.html deleted file mode 100644 index 49fd4ae958..0000000000 --- a/docs/0.9.5/api/evennia.server.portal.mccp.html +++ /dev/null @@ -1,181 +0,0 @@ - - - - - - - - - evennia.server.portal.mccp — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.portal.mccp

-

MCCP - Mud Client Compression Protocol

-

This implements the MCCP v2 telnet protocol as per -http://tintin.sourceforge.net/mccp/. MCCP allows for the server to -compress data when sending to supporting clients, reducing bandwidth -by 70-90%.. The compression is done using Python’s builtin zlib -library. If the client doesn’t support MCCP, server sends uncompressed -as normal. Note: On modern hardware you are not likely to notice the -effect of MCCP unless you have extremely heavy traffic or sits on a -terribly slow connection.

-

This protocol is implemented by the telnet protocol importing -mccp_compress and calling it from its write methods.

-
-
-evennia.server.portal.mccp.mccp_compress(protocol, data)[source]
-

Handles zlib compression, if applicable.

-
-
Parameters
-

data (str) – Incoming data to compress.

-
-
Returns
-

stream (binary) – Zlib-compressed data.

-
-
-
- -
-
-class evennia.server.portal.mccp.Mccp(protocol)[source]
-

Bases: object

-

Implements the MCCP protocol. Add this to a -variable on the telnet protocol to set it up.

-
-
-__init__(protocol)[source]
-

initialize MCCP by storing protocol on -ourselves and calling the client to see if -it supports MCCP. Sets callbacks to -start zlib compression in that case.

-
-
Parameters
-

protocol (Protocol) – The active protocol instance.

-
-
-
- -
-
-no_mccp(option)[source]
-

Called if client doesn’t support mccp or chooses to turn it off.

-
-
Parameters
-

option (Option) – Option dict (not used).

-
-
-
- -
-
-do_mccp(option)[source]
-

The client supports MCCP. Set things up by -creating a zlib compression stream.

-
-
Parameters
-

option (Option) – Option dict (not used).

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.portal.mssp.html b/docs/0.9.5/api/evennia.server.portal.mssp.html deleted file mode 100644 index 101585d0b5..0000000000 --- a/docs/0.9.5/api/evennia.server.portal.mssp.html +++ /dev/null @@ -1,182 +0,0 @@ - - - - - - - - - evennia.server.portal.mssp — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.portal.mssp

-

MSSP - Mud Server Status Protocol

-

This implements the MSSP telnet protocol as per -http://tintin.sourceforge.net/mssp/. MSSP allows web portals and -listings to have their crawlers find the mud and automatically -extract relevant information about it, such as genre, how many -active players and so on.

-
-
-class evennia.server.portal.mssp.Mssp(protocol)[source]
-

Bases: object

-

Implements the MSSP protocol. Add this to a variable on the telnet -protocol to set it up.

-
-
-__init__(protocol)[source]
-

initialize MSSP by storing protocol on ourselves and calling -the client to see if it supports MSSP.

-
-
Parameters
-

protocol (Protocol) – The active protocol instance.

-
-
-
- -
-
-get_player_count()[source]
-

Get number of logged-in players.

-
-
Returns
-

count (int) – The number of players in the MUD.

-
-
-
- -
-
-get_uptime()[source]
-

Get how long the portal has been online (reloads are not counted).

-
-
Returns
-

uptime (int) – Number of seconds of uptime.

-
-
-
- -
-
-no_mssp(option)[source]
-

Called when mssp is not requested. This is the normal -operation.

-
-
Parameters
-

option (Option) – Not used.

-
-
-
- -
-
-do_mssp(option)[source]
-

Negotiate all the information.

-
-
Parameters
-

option (Option) – Not used.

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.portal.mxp.html b/docs/0.9.5/api/evennia.server.portal.mxp.html deleted file mode 100644 index fee3005711..0000000000 --- a/docs/0.9.5/api/evennia.server.portal.mxp.html +++ /dev/null @@ -1,174 +0,0 @@ - - - - - - - - - evennia.server.portal.mxp — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.portal.mxp

-

MXP - Mud eXtension Protocol.

-

Partial implementation of the MXP protocol. -The MXP protocol allows more advanced formatting options for telnet clients -that supports it (mudlet, zmud, mushclient are a few)

-

This only implements the SEND tag.

-

More information can be found on the following links: -http://www.zuggsoft.com/zmud/mxp.htm -http://www.mushclient.com/mushclient/mxp.htm -http://www.gammon.com.au/mushclient/addingservermxp.htm

-
-
-evennia.server.portal.mxp.mxp_parse(text)[source]
-

Replaces links to the correct format for MXP.

-
-
Parameters
-

text (str) – The text to parse.

-
-
Returns
-

parsed (str) – The parsed text.

-
-
-
- -
-
-class evennia.server.portal.mxp.Mxp(protocol)[source]
-

Bases: object

-

Implements the MXP protocol.

-
-
-__init__(protocol)[source]
-

Initializes the protocol by checking if the client supports it.

-
-
Parameters
-

protocol (Protocol) – The active protocol instance.

-
-
-
- -
-
-no_mxp(option)[source]
-

Called when the Client reports to not support MXP.

-
-
Parameters
-

option (Option) – Not used.

-
-
-
- -
-
-do_mxp(option)[source]
-

Called when the Client reports to support MXP.

-
-
Parameters
-

option (Option) – Not used.

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.portal.naws.html b/docs/0.9.5/api/evennia.server.portal.naws.html deleted file mode 100644 index dedde63cfc..0000000000 --- a/docs/0.9.5/api/evennia.server.portal.naws.html +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - evennia.server.portal.naws — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.portal.naws

-

NAWS - Negotiate About Window Size

-

This implements the NAWS telnet option as per -https://www.ietf.org/rfc/rfc1073.txt

-

NAWS allows telnet clients to report their current window size to the -client and update it when the size changes

-
-
-class evennia.server.portal.naws.Naws(protocol)[source]
-

Bases: object

-

Implements the NAWS protocol. Add this to a variable on the telnet -protocol to set it up.

-
-
-__init__(protocol)[source]
-

initialize NAWS by storing protocol on ourselves and calling -the client to see if it supports NAWS.

-
-
Parameters
-

protocol (Protocol) – The active protocol instance.

-
-
-
- -
-
-no_naws(option)[source]
-

Called when client is not reporting NAWS. This is the normal -operation.

-
-
Parameters
-

option (Option) – Not used.

-
-
-
- -
-
-do_naws(option)[source]
-

Client wants to negotiate all the NAWS information.

-
-
Parameters
-

option (Option) – Not used.

-
-
-
- -
-
-negotiate_sizes(options)[source]
-

Step through the NAWS handshake.

-
-
Parameters
-

option (list) – The incoming NAWS options.

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.portal.portal.html b/docs/0.9.5/api/evennia.server.portal.portal.html deleted file mode 100644 index a30cef5fb8..0000000000 --- a/docs/0.9.5/api/evennia.server.portal.portal.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - - - evennia.server.portal.portal — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.portal.portal

-

This module implements the main Evennia server process, the core of -the game engine.

-

This module should be started with the ‘twistd’ executable since it -sets up all the networking features. (this is done automatically -by game/evennia.py).

-
-
-class evennia.server.portal.portal.Portal(application)[source]
-

Bases: object

-

The main Portal server handler. This object sets up the database -and tracks and interlinks all the twisted network services that -make up Portal.

-
-
-__init__(application)[source]
-

Setup the server.

-
-
Parameters
-

application (Application) – An instantiated Twisted application

-
-
-
- -
-
-get_info_dict()[source]
-

Return the Portal info, for display.

-
- -
-
-shutdown(_reactor_stopping=False, _stop_server=False)[source]
-

Shuts down the server from inside it.

-
-
Parameters
-
    -
  • _reactor_stopping (bool, optional) – This is set if server -is already in the process of shutting down; in this case -we don’t need to stop it again.

  • -
  • _stop_server (bool, optional) – Only used in portal-interactive mode; -makes sure to stop the Server cleanly.

  • -
-
-
-

Note that restarting (regardless of the setting) will not work -if the Portal is currently running in daemon mode. In that -case it always needs to be restarted manually.

-
- -
- -
-
-class evennia.server.portal.portal.Websocket(*args, **kwargs)[source]
-

Bases: autobahn.twisted.websocket.WebSocketServerFactory

-

Only here for better naming in logs

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.portal.portalsessionhandler.html b/docs/0.9.5/api/evennia.server.portal.portalsessionhandler.html deleted file mode 100644 index 6637a657f1..0000000000 --- a/docs/0.9.5/api/evennia.server.portal.portalsessionhandler.html +++ /dev/null @@ -1,370 +0,0 @@ - - - - - - - - - evennia.server.portal.portalsessionhandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.portal.portalsessionhandler

-

Sessionhandler for portal sessions.

-
-
-class evennia.server.portal.portalsessionhandler.PortalSessionHandler(*args, **kwargs)[source]
-

Bases: evennia.server.sessionhandler.SessionHandler

-

This object holds the sessions connected to the portal at any time. -It is synced with the server’s equivalent SessionHandler over the AMP -connection.

-

Sessions register with the handler using the connect() method. This -will assign a new unique sessionid to the session and send that sessid -to the server using the AMP connection.

-
-
-__init__(*args, **kwargs)[source]
-

Init the handler

-
- -
-
-at_server_connection()[source]
-

Called when the Portal establishes connection with the Server. -At this point, the AMP connection is already established.

-
- -
-
-generate_sessid()[source]
-

Simply generates a sessid that’s guaranteed to be unique for this Portal run.

-
-
Returns
-

sessid

-
-
-
- -
-
-connect(session)[source]
-

Called by protocol at first connect. This adds a not-yet -authenticated session using an ever-increasing counter for -sessid.

-
-
Parameters
-

session (PortalSession) – The Session connecting.

-
-
-

Notes

-

We implement a throttling mechanism here to limit the speed at -which new connections are accepted - this is both a stop -against DoS attacks as well as helps using the Dummyrunner -tester with a large number of connector dummies.

-
- -
-
-sync(session)[source]
-

Called by the protocol of an already connected session. This -can be used to sync the session info in a delayed manner, such -as when negotiation and handshakes are delayed.

-
-
Parameters
-

session (PortalSession) – Session to sync.

-
-
-
- -
-
-disconnect(session)[source]
-

Called from portal when the connection is closed from the -portal side.

-
-
Parameters
-
    -
  • session (PortalSession) – Session to disconnect.

  • -
  • delete (bool, optional) – Delete the session from -the handler. Only time to not do this is when -this is called from a loop, such as from -self.disconnect_all().

  • -
-
-
-
- -
-
-disconnect_all()[source]
-

Disconnect all sessions, informing the Server.

-
- -
-
-server_connect(protocol_path='', config={})[source]
-

Called by server to force the initialization of a new protocol -instance. Server wants this instance to get a unique sessid and to be -connected back as normal. This is used to initiate irc/rss etc -connections.

-
-
Parameters
-
    -
  • protocol_path (str) – Full python path to the class factory -for the protocol used, eg -‘evennia.server.portal.irc.IRCClientFactory’

  • -
  • config (dict) – Dictionary of configuration options, fed as -**kwarg to protocol class __init__ method.

  • -
-
-
Raises
-

RuntimeError – If The correct factory class is not found.

-
-
-

Notes

-

The called protocol class must have a method start() -that calls the portalsession.connect() as a normal protocol.

-
- -
-
-server_disconnect(session, reason='')[source]
-

Called by server to force a disconnect by sessid.

-
-
Parameters
-
    -
  • session (portalsession) – Session to disconnect.

  • -
  • reason (str, optional) – Motivation for disconnect.

  • -
-
-
-
- -
-
-server_disconnect_all(reason='')[source]
-

Called by server when forcing a clean disconnect for everyone.

-
-
Parameters
-

reason (str, optional) – Motivation for disconnect.

-
-
-
- -
-
-server_logged_in(session, data)[source]
-

The server tells us that the session has been authenticated. -Update it. Called by the Server.

-
-
Parameters
-
    -
  • session (Session) – Session logging in.

  • -
  • data (dict) – The session sync data.

  • -
-
-
-
- -
-
-server_session_sync(serversessions, clean=True)[source]
-

Server wants to save data to the portal, maybe because it’s -about to shut down. We don’t overwrite any sessions here, just -update them in-place.

-
-
Parameters
-
    -
  • serversessions (dict) –

    This is a dictionary

    -

    {sessid:{property:value},…} describing -the properties to sync on all sessions.

    -

  • -
  • clean (bool) – If True, remove any Portal sessions that are -not included in serversessions.

  • -
-
-
-
- -
-
-count_loggedin(include_unloggedin=False)[source]
-

Count loggedin connections, alternatively count all connections.

-
-
Parameters
-
    -
  • include_unloggedin (bool) – Also count sessions that have

  • -
  • yet authenticated. (not) –

  • -
-
-
Returns
-

count (int) – Number of sessions.

-
-
-
- -
-
-sessions_from_csessid(csessid)[source]
-

Given a session id, retrieve the session (this is primarily -intended to be called by web clients)

-
-
Parameters
-

csessid (int) – Session id.

-
-
Returns
-

session (list) – The matching session, if found.

-
-
-
- -
-
-announce_all(message)[source]
-

Send message to all connected sessions.

-
-
Parameters
-

message (str) – Message to relay.

-
-
-

Notes

-

This will create an on-the fly text-type -send command.

-
- -
-
-data_in(session, **kwargs)[source]
-

Called by portal sessions for relaying data coming -in from the protocol to the server.

-
-
Parameters
-

session (PortalSession) – Session receiving data.

-
-
Keyword Arguments
-

kwargs (any) – Other data from protocol.

-
-
-

Notes

-

Data is serialized before passed on.

-
- -
-
-data_out(session, **kwargs)[source]
-

Called by server for having the portal relay messages and data -to the correct session protocol.

-
-
Parameters
-

session (Session) – Session sending data.

-
-
Keyword Arguments
-

kwargs (any) – Each key is a command instruction to the -protocol on the form key = [[args],{kwargs}]. This will -call a method send_<key> on the protocol. If no such -method exixts, it sends the data to a method send_default.

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.portal.rss.html b/docs/0.9.5/api/evennia.server.portal.rss.html deleted file mode 100644 index 0f5683d0ed..0000000000 --- a/docs/0.9.5/api/evennia.server.portal.rss.html +++ /dev/null @@ -1,211 +0,0 @@ - - - - - - - - - evennia.server.portal.rss — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.portal.rss

-

RSS parser for Evennia

-

This connects an RSS feed to an in-game Evennia channel, sending messages -to the channel whenever the feed updates.

-
-
-class evennia.server.portal.rss.RSSReader(factory, url, rate)[source]
-

Bases: evennia.server.session.Session

-

A simple RSS reader using the feedparser module.

-
-
-__init__(factory, url, rate)[source]
-

Initialize the reader.

-
-
Parameters
-
    -
  • factory (RSSFactory) – The protocol factory.

  • -
  • url (str) – The RSS url.

  • -
  • rate (int) – The seconds between RSS lookups.

  • -
-
-
-
- -
-
-get_new()[source]
-

Returns list of new items.

-
- -
-
-disconnect(reason=None)[source]
-

Disconnect from feed.

-
-
Parameters
-

reason (str, optional) – Motivation for the disconnect.

-
-
-
- -
-
-data_in(text=None, **kwargs)[source]
-

Data RSS -> Evennia.

-
-
Keyword Arguments
-
    -
  • text (str) – Incoming text

  • -
  • kwargs (any) – Options from protocol.

  • -
-
-
-
- -
-
-update(init=False)[source]
-

Request the latest version of feed.

-
-
Parameters
-

init (bool, optional) – If this is an initialization call -or not (during init, all entries are conidered new).

-
-
-

Notes

-

This call is done in a separate thread to avoid blocking -on slow connections.

-
- -
- -
-
-class evennia.server.portal.rss.RSSBotFactory(sessionhandler, uid=None, url=None, rate=None)[source]
-

Bases: object

-

Initializes new bots.

-
-
-__init__(sessionhandler, uid=None, url=None, rate=None)[source]
-

Initialize the bot.

-
-
Parameters
-
    -
  • sessionhandler (PortalSessionHandler) – The main sessionhandler object.

  • -
  • uid (int) – User id for the bot.

  • -
  • url (str) – The RSS URL.

  • -
  • rate (int) – How often for the RSS to request the latest RSS entries.

  • -
-
-
-
- -
-
-start()[source]
-

Called by portalsessionhandler. Starts the bot.

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.portal.ssh.html b/docs/0.9.5/api/evennia.server.portal.ssh.html deleted file mode 100644 index dca0956141..0000000000 --- a/docs/0.9.5/api/evennia.server.portal.ssh.html +++ /dev/null @@ -1,432 +0,0 @@ - - - - - - - - - evennia.server.portal.ssh — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.portal.ssh

-

This module implements the ssh (Secure SHell) protocol for encrypted -connections.

-

This depends on a generic session module that implements the actual -login procedure of the game, tracks sessions etc.

-

Using standard ssh client,

-
-
-class evennia.server.portal.ssh.SSHServerFactory[source]
-

Bases: twisted.internet.protocol.ServerFactory

-

This is only to name this better in logs

-
-
-noisy = False
-
- -
-
-logPrefix()[source]
-

Describe this factory for log messages.

-
- -
- -
-
-class evennia.server.portal.ssh.SshProtocol(starttuple)[source]
-

Bases: twisted.conch.manhole.Manhole, evennia.server.session.Session

-

Each account connecting over ssh gets this protocol assigned to -them. All communication between game and account goes through -here.

-
-
-noisy = False
-
- -
-
-__init__(starttuple)[source]
-

For setting up the account. If account is not None then we’ll -login automatically.

-
-
Parameters
-

starttuple (tuple) – A (account, factory) tuple.

-
-
-
- -
-
-terminalSize(width, height)[source]
-

Initialize the terminal and connect to the new session.

-
-
Parameters
-
    -
  • width (int) – Width of terminal.

  • -
  • height (int) – Height of terminal.

  • -
-
-
-
- -
-
-connectionMade()[source]
-

This is called when the connection is first established.

-
- -
-
-handle_INT()[source]
-

Handle ^C as an interrupt keystroke by resetting the current -input variables to their initial state.

-
- -
-
-handle_EOF()[source]
-

Handles EOF generally used to exit.

-
- -
-
-handle_FF()[source]
-

Handle a ‘form feed’ byte - generally used to request a screen -refresh/redraw.

-
- -
-
-handle_QUIT()[source]
-

Quit, end, and lose the connection.

-
- -
-
-connectionLost(reason=None)[source]
-

This is executed when the connection is lost for whatever -reason. It can also be called directly, from the disconnect -method.

-
-
Parameters
-

reason (str) – Motivation for loosing connection.

-
-
-
- -
-
-getClientAddress()[source]
-

Get client address.

-
-
Returns
-

address_and_port (tuple)

-
-
The client’s address and port in

a tuple. For example (‘127.0.0.1’, 41917).

-
-
-

-
-
-
- -
-
-lineReceived(string)[source]
-

Communication User -> Evennia. Any line return indicates a -command for the purpose of the MUD. So we take the user input -and pass it on to the game engine.

-
-
Parameters
-

string (str) – Input text.

-
-
-
- -
-
-sendLine(string)[source]
-

Communication Evennia -> User. Any string sent should -already have been properly formatted and processed before -reaching this point.

-
-
Parameters
-

string (str) – Output text.

-
-
-
- -
-
-at_login()[source]
-

Called when this session gets authenticated by the server.

-
- -
-
-disconnect(reason='Connection closed. Goodbye for now.')[source]
-

Disconnect from server.

-
-
Parameters
-

reason (str) – Motivation for disconnect.

-
-
-
- -
-
-data_out(**kwargs)[source]
-

Data Evennia -> User

-
-
Keyword Arguments
-

kwargs (any) – Options to the protocol.

-
-
-
- -
-
-send_text(*args, **kwargs)[source]
-

Send text data. This is an in-band telnet operation.

-
-
Parameters
-

text (str) – The first argument is always the text string to send. No other arguments -are considered.

-
-
Keyword Arguments
-

options (dict) –

Send-option flags (booleans)

-
    -
  • mxp: enforce mxp link support.

  • -
  • ansi: enforce no ansi colors.

  • -
  • xterm256: enforce xterm256 colors, regardless of ttype setting.

  • -
  • nocolor: strip all colors.

  • -
  • raw: pass string through without any ansi processing -(i.e. include evennia ansi markers but do not -convert them into ansi tokens)

  • -
  • echo: turn on/off line echo on the client. turn -off line echo for client, for example for password. -note that it must be actively turned back on again!

  • -
-

-
-
-
- -
-
-send_prompt(*args, **kwargs)[source]
-
- -
-
-send_default(*args, **kwargs)[source]
-
- -
- -
-
-class evennia.server.portal.ssh.ExtraInfoAuthServer[source]
-

Bases: twisted.conch.ssh.userauth.SSHUserAuthServer

-
-
-noisy = False
-
- -
-
-auth_password(packet)[source]
-

Password authentication.

-

Used mostly for setting up the transport so we can query -username and password later.

-
-
Parameters
-

packet (Packet) – Auth packet.

-
-
-
- -
- -
-
-class evennia.server.portal.ssh.AccountDBPasswordChecker(factory)[source]
-

Bases: object

-

Checks the django db for the correct credentials for -username/password otherwise it returns the account or None which is -useful for the Realm.

-
-
-noisy = False
-
- -
-
-credentialInterfaces = (<InterfaceClass twisted.cred.credentials.IUsernamePassword>,)
-
- -
-
-__init__(factory)[source]
-

Initialize the factory.

-
-
Parameters
-

factory (SSHFactory) – Checker factory.

-
-
-
- -
-
-requestAvatarId(c)[source]
-

Generic credentials.

-
- -
- -
-
-class evennia.server.portal.ssh.PassAvatarIdTerminalRealm(transportFactory=None)[source]
-

Bases: twisted.conch.manhole_ssh.TerminalRealm

-

Returns an avatar that passes the avatarId through to the -protocol. This is probably not the best way to do it.

-
-
-noisy = False
-
- -
- -
-
-class evennia.server.portal.ssh.TerminalSessionTransport_getPeer(proto, chainedProtocol, avatar, width, height)[source]
-

Bases: object

-

Taken from twisted’s TerminalSessionTransport which doesn’t -provide getPeer to the transport. This one does.

-
-
-noisy = False
-
- -
-
-__init__(proto, chainedProtocol, avatar, width, height)[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
- -
-
-evennia.server.portal.ssh.getKeyPair(pubkeyfile, privkeyfile)[source]
-

This function looks for RSA keypair files in the current directory. If they -do not exist, the keypair is created.

-
- -
-
-evennia.server.portal.ssh.makeFactory(configdict)[source]
-

Creates the ssh server factory.

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.portal.ssl.html b/docs/0.9.5/api/evennia.server.portal.ssl.html deleted file mode 100644 index 220192ca87..0000000000 --- a/docs/0.9.5/api/evennia.server.portal.ssl.html +++ /dev/null @@ -1,152 +0,0 @@ - - - - - - - - - evennia.server.portal.ssl — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.portal.ssl

-

This is a simple context factory for auto-creating -SSL keys and certificates.

-
-
-class evennia.server.portal.ssl.SSLProtocol(*args, **kwargs)[source]
-

Bases: evennia.server.portal.telnet.TelnetProtocol

-

Communication is the same as telnet, except data transfer -is done with encryption.

-
-
-__init__(*args, **kwargs)[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
- -
-
-evennia.server.portal.ssl.verify_SSL_key_and_cert(keyfile, certfile)[source]
-

This function looks for RSA key and certificate in the current -directory. If files ssl.key and ssl.cert does not exist, they -are created.

-
- -
-
-evennia.server.portal.ssl.getSSLContext()[source]
-

This is called by the portal when creating the SSL context -server-side.

-
-
Returns
-

ssl_context (tuple)

-
-
A key and certificate that is either

existing previously or or created on the fly.

-
-
-

-
-
-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.portal.suppress_ga.html b/docs/0.9.5/api/evennia.server.portal.suppress_ga.html deleted file mode 100644 index 9e4a946c2a..0000000000 --- a/docs/0.9.5/api/evennia.server.portal.suppress_ga.html +++ /dev/null @@ -1,160 +0,0 @@ - - - - - - - - - evennia.server.portal.suppress_ga — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.portal.suppress_ga

-

SUPPRESS-GO-AHEAD

-

This supports suppressing or activating Evennia -the GO-AHEAD telnet operation after every server reply. -If the client sends no explicit DONT SUPRESS GO-AHEAD, -Evennia will default to supressing it since many clients -will fail to use it and has no knowledge of this standard.

-

It is set as the NOGOAHEAD protocol_flag option.

-

http://www.faqs.org/rfcs/rfc858.html

-
-
-class evennia.server.portal.suppress_ga.SuppressGA(protocol)[source]
-

Bases: object

-

Implements the SUPRESS-GO-AHEAD protocol. Add this to a variable on the telnet -protocol to set it up.

-
-
-__init__(protocol)[source]
-

Initialize suppression of GO-AHEADs.

-
-
Parameters
-

protocol (Protocol) – The active protocol instance.

-
-
-
- -
-
-wont_suppress_ga(option)[source]
-

Called when client requests to not suppress GA.

-
-
Parameters
-

option (Option) – Not used.

-
-
-
- -
-
-will_suppress_ga(option)[source]
-

Client will suppress GA

-
-
Parameters
-

option (Option) – Not used.

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.portal.telnet.html b/docs/0.9.5/api/evennia.server.portal.telnet.html deleted file mode 100644 index 69d6354f15..0000000000 --- a/docs/0.9.5/api/evennia.server.portal.telnet.html +++ /dev/null @@ -1,353 +0,0 @@ - - - - - - - - - evennia.server.portal.telnet — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.portal.telnet

-

This module implements the telnet protocol.

-

This depends on a generic session module that implements -the actual login procedure of the game, tracks -sessions etc.

-
-
-class evennia.server.portal.telnet.TelnetServerFactory[source]
-

Bases: twisted.internet.protocol.ServerFactory

-

This exists only to name this better in logs.

-
-
-noisy = False
-
- -
-
-logPrefix()[source]
-

Describe this factory for log messages.

-
- -
- -
-
-class evennia.server.portal.telnet.TelnetProtocol(*args, **kwargs)[source]
-

Bases: twisted.conch.telnet.Telnet, twisted.conch.telnet.StatefulTelnetProtocol, evennia.server.session.Session

-

Each player connecting over telnet (ie using most traditional mud -clients) gets a telnet protocol instance assigned to them. All -communication between game and player goes through here.

-
-
-__init__(*args, **kwargs)[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
-
-dataReceived(data)[source]
-

Unused by default, but a good place to put debug printouts -of incoming data.

-
- -
-
-connectionMade()[source]
-

This is called when the connection is first established.

-
- -
-
-toggle_nop_keepalive()[source]
-

Allow to toggle the NOP keepalive for those sad clients that -can’t even handle a NOP instruction. This is turned off by the -protocol_flag NOPKEEPALIVE (settable e.g. by the default -option command).

-
- -
-
-handshake_done(timeout=False)[source]
-

This is called by all telnet extensions once they are finished. -When all have reported, a sync with the server is performed. -The system will force-call this sync after a small time to handle -clients that don’t reply to handshakes at all.

-
- -
-
-at_login()[source]
-

Called when this session gets authenticated by the server.

-
- -
-
-enableRemote(option)[source]
-

This sets up the remote-activated options we allow for this protocol.

-
-
Parameters
-

option (char) – The telnet option to enable.

-
-
Returns
-

enable (bool) – If this option should be enabled.

-
-
-
- -
-
-disableRemote(option)[source]
-

Signal a programming error by raising an exception.

-

L{enableRemote} must return true for the given value of C{option} in -order for this method to be called. If a subclass of L{Telnet} -overrides enableRemote to allow certain options to be enabled, it must -also override disableRemote tto disable those options.

-

@raise NotImplementedError: Always raised.

-
- -
-
-enableLocal(option)[source]
-

Call to allow the activation of options for this protocol

-
-
Parameters
-

option (char) – The telnet option to enable locally.

-
-
Returns
-

enable (bool) – If this option should be enabled.

-
-
-
- -
-
-disableLocal(option)[source]
-

Disable a given option locally.

-
-
Parameters
-

option (char) – The telnet option to disable locally.

-
-
-
- -
-
-connectionLost(reason)[source]
-

this is executed when the connection is lost for whatever -reason. it can also be called directly, from the disconnect -method

-
-
Parameters
-

reason (str) – Motivation for losing connection.

-
-
-
- -
-
-applicationDataReceived(data)[source]
-

Telnet method called when non-telnet-command data is coming in -over the telnet connection. We pass it on to the game engine -directly.

-
-
Parameters
-

data (str) – Incoming data.

-
-
-
- -
-
-sendLine(line)[source]
-

Hook overloading the one used by linereceiver.

-
-
Parameters
-

line (str) – Line to send.

-
-
-
- -
-
-disconnect(reason='')[source]
-

Generic hook for the engine to call in order to -disconnect this protocol.

-
-
Parameters
-

reason (str, optional) – Reason for disconnecting.

-
-
-
- -
-
-data_in(**kwargs)[source]
-

Data User -> Evennia

-
-
Keyword Arguments
-

kwargs (any) – Options from the protocol.

-
-
-
- -
-
-data_out(**kwargs)[source]
-

Data Evennia -> User

-
-
Keyword Arguments
-

kwargs (any) – Options to the protocol

-
-
-
- -
-
-send_text(*args, **kwargs)[source]
-

Send text data. This is an in-band telnet operation.

-
-
Parameters
-

text (str) – The first argument is always the text string to send. No other arguments -are considered.

-
-
Keyword Arguments
-

options (dict) –

Send-option flags

-
    -
  • mxp: Enforce MXP link support.

  • -
  • ansi: Enforce no ANSI colors.

  • -
  • xterm256: Enforce xterm256 colors, regardless of TTYPE.

  • -
  • noxterm256: Enforce no xterm256 color support, regardless of TTYPE.

  • -
  • nocolor: Strip all Color, regardless of ansi/xterm256 setting.

  • -
  • -
    raw: Pass string through without any ansi processing

    (i.e. include Evennia ansi markers but do not -convert them into ansi tokens)

    -
    -
    -
  • -
  • -
    echo: Turn on/off line echo on the client. Turn

    off line echo for client, for example for password. -Note that it must be actively turned back on again!

    -
    -
    -
  • -
-

-
-
-
- -
-
-send_prompt(*args, **kwargs)[source]
-

Send a prompt - a text without a line end. See send_text for argument options.

-
- -
-
-send_default(cmdname, *args, **kwargs)[source]
-

Send other oob data

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.portal.telnet_oob.html b/docs/0.9.5/api/evennia.server.portal.telnet_oob.html deleted file mode 100644 index 0ff8caf28e..0000000000 --- a/docs/0.9.5/api/evennia.server.portal.telnet_oob.html +++ /dev/null @@ -1,326 +0,0 @@ - - - - - - - - - evennia.server.portal.telnet_oob — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.portal.telnet_oob

-

Telnet OOB (Out of band communication)

-

OOB protocols allow for asynchronous communication between Evennia and -compliant telnet clients. The “text” type of send command will always -be sent “in-band”, appearing in the client’s main text output. OOB -commands, by contrast, can have many forms and it is up to the client -how and if they are handled. Examples of OOB instructions could be to -instruct the client to play sounds or to update a graphical health -bar.

-

Note that in Evennia’s Web client, all send commands are “OOB -commands”, (including the “text” one), there is no equivalence to -MSDP/GMCP for the webclient since it doesn’t need it.

-

This implements the following telnet OOB communication protocols:

- -
-
-
-class evennia.server.portal.telnet_oob.TelnetOOB(protocol)[source]
-

Bases: object

-

Implements the MSDP and GMCP protocols.

-
-
-__init__(protocol)[source]
-

Initiates by storing the protocol on itself and trying to -determine if the client supports MSDP.

-
-
Parameters
-

protocol (Protocol) – The active protocol.

-
-
-
- -
-
-no_msdp(option)[source]
-

Client reports No msdp supported or wanted.

-
-
Parameters
-

option (Option) – Not used.

-
-
-
- -
-
-do_msdp(option)[source]
-

Client reports that it supports msdp.

-
-
Parameters
-

option (Option) – Not used.

-
-
-
- -
-
-no_gmcp(option)[source]
-

If this is reached, it means neither MSDP nor GMCP is -supported.

-
-
Parameters
-

option (Option) – Not used.

-
-
-
- -
-
-do_gmcp(option)[source]
-

Called when client confirms that it can do MSDP or GMCP.

-
-
Parameters
-

option (Option) – Not used.

-
-
-
- -
-
-encode_msdp(cmdname, *args, **kwargs)[source]
-

Encode into a valid MSDP command.

-
-
Parameters
-
    -
  • cmdname (str) – Name of send instruction.

  • -
  • args (any) – Arguments to OOB command.

  • -
  • kwargs (any) – Arguments to OOB command.

  • -
-
-
-

Notes

-

The output of this encoding will be -MSDP structures on these forms:

-
[cmdname, [], {}]           -> VAR cmdname VAL ""
-[cmdname, [arg], {}]        -> VAR cmdname VAL arg
-[cmdname, [args],{}]        -> VAR cmdname VAL ARRAYOPEN VAL arg VAL arg ... ARRAYCLOSE
-[cmdname, [], {kwargs}]     -> VAR cmdname VAL TABLEOPEN VAR key VAL val ... TABLECLOSE
-[cmdname, [args], {kwargs}] -> VAR cmdname VAL ARRAYOPEN VAL arg VAL arg ... ARRAYCLOSE
-                               VAR cmdname VAL TABLEOPEN VAR key VAL val ... TABLECLOSE
-
-
-

Further nesting is not supported, so if an array argument -consists of an array (for example), that array will be -json-converted to a string.

-
- -
-
-encode_gmcp(cmdname, *args, **kwargs)[source]
-

Encode into GMCP messages.

-
-
Parameters
-
    -
  • cmdname (str) – GMCP OOB command name.

  • -
  • args (any) – Arguments to OOB command.

  • -
  • kwargs (any) – Arguments to OOB command.

  • -
-
-
-

Notes

-

GMCP messages will be outgoing on the following -form (the non-JSON cmdname at the start is what -IRE games use, supposedly, and what clients appear -to have adopted). A cmdname without Package will end -up in the Core package, while Core package names will -be stripped on the Evennia side.

-
[cmd_name, [], {}]          -> Cmd.Name
-[cmd_name, [arg], {}]       -> Cmd.Name arg
-[cmd_name, [args],{}]       -> Cmd.Name [args]
-[cmd_name, [], {kwargs}]    -> Cmd.Name {kwargs}
-[cmdname, [args, {kwargs}]  -> Core.Cmdname [[args],{kwargs}]
-
-
-

For more flexibility with certain clients, if cmd_name is capitalized, -Evennia will leave its current capitalization (So CMD_nAmE would be sent -as CMD.nAmE but cMD_Name would be Cmd.Name)

-

Notes

-

There are also a few default mappings between evennia outputcmds and GMCP:

-
client_options -> Core.Supports.Get
-get_inputfuncs -> Core.Commands.Get
-get_value      -> Char.Value.Get
-repeat         -> Char.Repeat.Update
-monitor        -> Char.Monitor.Update
-
-
-
- -
-
-decode_msdp(data)[source]
-

Decodes incoming MSDP data.

-
-
Parameters
-

data (str or list) – MSDP data.

-
-
-

Notes

-

Clients should always send MSDP data on -one of the following forms:

-
cmdname ''          -> [cmdname, [], {}]
-cmdname val         -> [cmdname, [val], {}]
-cmdname array       -> [cmdname, [array], {}]
-cmdname table       -> [cmdname, [], {table}]
-cmdname array cmdname table -> [cmdname, [array], {table}]
-
-
-

Observe that all MSDP_VARS are used to identify cmdnames, -so if there are multiple arrays with the same cmdname -given, they will be merged into one argument array, same -for tables. Different MSDP_VARS (outside tables) will be -identified as separate cmdnames.

-
- -
-
-decode_gmcp(data)[source]
-

Decodes incoming GMCP data on the form ‘varname <structure>’.

-
-
Parameters
-

data (str or list) – GMCP data.

-
-
-

Notes

-

Clients send data on the form “Module.Submodule.Cmdname <structure>”. -We assume the structure is valid JSON.

-

The following is parsed into Evennia’s formal structure:

-
Core.Name                         -> [name, [], {}]
-Core.Name string                  -> [name, [string], {}]
-Core.Name [arg, arg,...]          -> [name, [args], {}]
-Core.Name {key:arg, key:arg, ...} -> [name, [], {kwargs}]
-Core.Name [[args], {kwargs}]      -> [name, [args], {kwargs}]
-
-
-
- -
-
-data_out(cmdname, *args, **kwargs)[source]
-

Return a MSDP- or GMCP-valid subnegotiation across the protocol.

-
-
Parameters
-
    -
  • cmdname (str) – OOB-command name.

  • -
  • args (any) – Arguments to OOB command.

  • -
  • kwargs (any) – Arguments to OOB command.

  • -
-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.portal.telnet_ssl.html b/docs/0.9.5/api/evennia.server.portal.telnet_ssl.html deleted file mode 100644 index 0ba9662321..0000000000 --- a/docs/0.9.5/api/evennia.server.portal.telnet_ssl.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - - - - - evennia.server.portal.telnet_ssl — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.portal.telnet_ssl

-

This allows for running the telnet communication over an encrypted SSL tunnel. To use it, requires a -client supporting Telnet SSL.

-

The protocol will try to automatically create the private key and certificate on the server side -when starting and will warn if this was not possible. These will appear as files ssl.key and -ssl.cert in mygame/server/.

-
-
-class evennia.server.portal.telnet_ssl.SSLProtocol(*args, **kwargs)[source]
-

Bases: evennia.server.portal.telnet.TelnetProtocol

-

Communication is the same as telnet, except data transfer -is done with encryption set up by the portal at start time.

-
-
-__init__(*args, **kwargs)[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
- -
-
-evennia.server.portal.telnet_ssl.verify_or_create_SSL_key_and_cert(keyfile, certfile)[source]
-

Verify or create new key/certificate files.

-
-
Parameters
-
    -
  • keyfile (str) – Path to ssl.key file.

  • -
  • certfile (str) – Parth to ssl.cert file.

  • -
-
-
-

Notes

-

If files don’t already exist, they are created.

-
- -
-
-evennia.server.portal.telnet_ssl.getSSLContext()[source]
-

This is called by the portal when creating the SSL context -server-side.

-
-
Returns
-

ssl_context (tuple)

-
-
A key and certificate that is either

existing previously or created on the fly.

-
-
-

-
-
-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.portal.tests.html b/docs/0.9.5/api/evennia.server.portal.tests.html deleted file mode 100644 index 07fa5c89d9..0000000000 --- a/docs/0.9.5/api/evennia.server.portal.tests.html +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - - - - evennia.server.portal.tests — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.portal.tests

-
-
-class evennia.server.portal.tests.TestAMPServer(methodName='runTest')[source]
-

Bases: twisted.trial._asynctest.TestCase

-

Test AMP communication

-
-
-setUp()[source]
-

Hook method for setting up the test fixture before exercising it.

-
- -
-
-test_amp_out()[source]
-
- -
-
-test_amp_in()[source]
-
- -
-
-test_large_msg()[source]
-

Send message larger than AMP_MAXLEN - should be split into several

-
- -
- -
-
-class evennia.server.portal.tests.TestIRC(methodName='runTest')[source]
-

Bases: django.test.testcases.TestCase

-
-
-test_plain_ansi()[source]
-

Test that printable characters do not get mangled.

-
- -
-
-test_bold()[source]
-
- -
-
-test_italic()[source]
-
- -
-
-test_colors()[source]
-
- -
-
-test_identity()[source]
-

Test that the composition of the function and -its inverse gives the correct string.

-
- -
- -
-
-class evennia.server.portal.tests.TestTelnet(methodName='runTest')[source]
-

Bases: twisted.trial._asynctest.TestCase

-
-
-setUp()[source]
-

Hook method for setting up the test fixture before exercising it.

-
- -
-
-test_mudlet_ttype()[source]
-
- -
- -
-
-class evennia.server.portal.tests.TestWebSocket(methodName='runTest')[source]
-

Bases: evennia.utils.test_resources.BaseEvenniaTest

-
-
-setUp()[source]
-

Sets up testing environment

-
- -
-
-tearDown()[source]
-

Hook method for deconstructing the test fixture after testing it.

-
- -
-
-test_data_in()[source]
-
- -
-
-test_data_out()[source]
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.portal.ttype.html b/docs/0.9.5/api/evennia.server.portal.ttype.html deleted file mode 100644 index 867c096e1b..0000000000 --- a/docs/0.9.5/api/evennia.server.portal.ttype.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - - - evennia.server.portal.ttype — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.portal.ttype

-

TTYPE (MTTS) - Mud Terminal Type Standard

-

This module implements the TTYPE telnet protocol as per -http://tintin.sourceforge.net/mtts/. It allows the server to ask the -client about its capabilities. If the client also supports TTYPE, it -will return with information such as its name, if it supports colour -etc. If the client does not support TTYPE, this will be ignored.

-

All data will be stored on the protocol’s protocol_flags dictionary, -under the ‘TTYPE’ key.

-
-
-class evennia.server.portal.ttype.Ttype(protocol)[source]
-

Bases: object

-

Handles ttype negotiations. Called and initiated by the -telnet protocol.

-
-
-__init__(protocol)[source]
-

Initialize ttype by storing protocol on ourselves and calling -the client to see if it supporst ttype.

-
-
Parameters
-

protocol (Protocol) – The protocol instance.

-
-
-

Notes

-

The self.ttype_step indicates how far in the data -retrieval we’ve gotten.

-
- -
-
-wont_ttype(option)[source]
-

Callback if ttype is not supported by client.

-
-
Parameters
-

option (Option) – Not used.

-
-
-
- -
-
-will_ttype(option)[source]
-

Handles negotiation of the ttype protocol once the client has -confirmed that it will respond with the ttype protocol.

-
-
Parameters
-

option (Option) – Not used.

-
-
-

Notes

-

The negotiation proceeds in several steps, each returning a -certain piece of information about the client. All data is -stored on protocol.protocol_flags under the TTYPE key.

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.portal.webclient.html b/docs/0.9.5/api/evennia.server.portal.webclient.html deleted file mode 100644 index 989b385193..0000000000 --- a/docs/0.9.5/api/evennia.server.portal.webclient.html +++ /dev/null @@ -1,286 +0,0 @@ - - - - - - - - - evennia.server.portal.webclient — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.portal.webclient

-

Webclient based on websockets.

-

This implements a webclient with WebSockets (http://en.wikipedia.org/wiki/WebSocket) -by use of the autobahn-python package’s implementation (https://github.com/crossbario/autobahn-python). -It is used together with evennia/web/media/javascript/evennia_websocket_webclient.js.

-

All data coming into the webclient is in the form of valid JSON on the form

-

[“inputfunc_name”, [args], {kwarg}]

-

which represents an “inputfunc” to be called on the Evennia side with args, **kwargs. -The most common inputfunc is “text”, which takes just the text input -from the command line and interprets it as an Evennia Command: **[“text”, [“look”], {}]*

-
-
-class evennia.server.portal.webclient.WebSocketClient(*args, **kwargs)[source]
-

Bases: autobahn.twisted.websocket.WebSocketServerProtocol, evennia.server.session.Session

-

Implements the server-side of the Websocket connection.

-
-
-nonce = 0
-
- -
-
-__init__(*args, **kwargs)[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
-
-get_client_session()[source]
-

Get the Client browser session (used for auto-login based on browser session)

-
-
Returns
-

csession (ClientSession)

-
-
This is a django-specific internal representation

of the browser session.

-
-
-

-
-
-
- -
-
-onOpen()[source]
-

This is called when the WebSocket connection is fully established.

-
- -
-
-disconnect(reason=None)[source]
-

Generic hook for the engine to call in order to -disconnect this protocol.

-
-
Parameters
-

reason (str or None) – Motivation for the disconnection.

-
-
-
- -
-
-onClose(wasClean, code=None, reason=None)[source]
-

This is executed when the connection is lost for whatever -reason. it can also be called directly, from the disconnect -method.

-
-
Parameters
-
    -
  • wasClean (bool) – **True** if the WebSocket was closed cleanly.

  • -
  • code (int or None) – Close status as sent by the WebSocket peer.

  • -
  • reason (str or None) – Close reason as sent by the WebSocket peer.

  • -
-
-
-
- -
-
-onMessage(payload, isBinary)[source]
-

Callback fired when a complete WebSocket message was received.

-
-
Parameters
-
    -
  • payload (bytes) – The WebSocket message received.

  • -
  • isBinary (bool) – Flag indicating whether payload is binary or -UTF-8 encoded text.

  • -
-
-
-
- -
-
-sendLine(line)[source]
-

Send data to client.

-
-
Parameters
-

line (str) – Text to send.

-
-
-
- -
-
-at_login()[source]
-
- -
-
-data_in(**kwargs)[source]
-

Data User > Evennia.

-
-
Parameters
-
    -
  • text (str) – Incoming text.

  • -
  • kwargs (any) – Options from protocol.

  • -
-
-
-

Notes

-

At initilization, the client will send the special -‘csessid’ command to identify its browser session hash -with the Evennia side.

-

The websocket client will also pass ‘websocket_close’ command -to report that the client has been closed and that the -session should be disconnected.

-

Both those commands are parsed and extracted already at -this point.

-
- -
-
-send_text(*args, **kwargs)[source]
-

Send text data. This will pre-process the text for -color-replacement, conversion to html etc.

-
-
Parameters
-

text (str) – Text to send.

-
-
Keyword Arguments
-

options (dict) – Options-dict with the following keys understood: -- raw (bool): No parsing at all (leave ansi-to-html markers unparsed). -- nocolor (bool): Clean out all color. -- screenreader (bool): Use Screenreader mode. -- send_prompt (bool): Send a prompt with parsed html

-
-
-
- -
-
-send_prompt(*args, **kwargs)[source]
-
- -
-
-send_default(cmdname, *args, **kwargs)[source]
-

Data Evennia -> User.

-
-
Parameters
-
    -
  • cmdname (str) – The first argument will always be the oob cmd name.

  • -
  • *args (any) – Remaining args will be arguments for cmd.

  • -
-
-
Keyword Arguments
-

options (dict) – These are ignored for oob commands. Use command -arguments (which can hold dicts) to send instructions to the -client instead.

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.portal.webclient_ajax.html b/docs/0.9.5/api/evennia.server.portal.webclient_ajax.html deleted file mode 100644 index 12d3c70070..0000000000 --- a/docs/0.9.5/api/evennia.server.portal.webclient_ajax.html +++ /dev/null @@ -1,430 +0,0 @@ - - - - - - - - - evennia.server.portal.webclient_ajax — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.portal.webclient_ajax

-

AJAX/COMET fallback webclient

-

The AJAX/COMET web client consists of two components running on -twisted and django. They are both a part of the Evennia website url -tree (so the testing website might be located on -http://localhost:4001/, whereas the webclient can be found on -http://localhost:4001/webclient.)

-
-
/webclient - this url is handled through django’s template

system and serves the html page for the client -itself along with its javascript chat program.

-
-
/webclientdata - this url is called by the ajax chat using

POST requests (long-polling when necessary) -The WebClient resource in this module will -handle these requests and act as a gateway -to sessions connected over the webclient.

-
-
-
-
-class evennia.server.portal.webclient_ajax.LazyEncoder(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None)[source]
-

Bases: json.encoder.JSONEncoder

-
-
-default(obj)[source]
-

Implement this method in a subclass such that it returns -a serializable object for **o**, or calls the base implementation -(to raise a **TypeError**).

-

For example, to support arbitrary iterators, you could -implement default like this:

-
def default(self, o):
-    try:
-        iterable = iter(o)
-    except TypeError:
-        pass
-    else:
-        return list(iterable)
-    # Let the base class default method raise the TypeError
-    return JSONEncoder.default(self, o)
-
-
-
- -
- -
-
-evennia.server.portal.webclient_ajax.jsonify(obj)[source]
-
- -
-
-class evennia.server.portal.webclient_ajax.AjaxWebClient[source]
-

Bases: twisted.web.resource.Resource

-

An ajax/comet long-polling transport

-
-
-isLeaf = True
-
- -
-
-allowedMethods = ('POST',)
-
- -
-
-__init__()[source]
-

Initialize.

-
- -
-
-get_client_sessid(request)[source]
-

Helper to get the client session id out of the request.

-
-
Parameters
-

request (Request) – Incoming request object.

-
-
Returns
-

csessid (int) – The client-session id.

-
-
-
- -
-
-get_browserstr(request)[source]
-

Get browser-string out of the request.

-
-
Parameters
-

request (Request) – Incoming request object.

-
-
Returns
-

str – The browser name.

-
-
-
- -
-
-at_login()[source]
-

Called when this session gets authenticated by the server.

-
- -
-
-lineSend(csessid, data)[source]
-

This adds the data to the buffer and/or sends it to the client -as soon as possible.

-
-
Parameters
-
    -
  • csessid (int) – Session id.

  • -
  • data (list) – A send structure [cmdname, [args], {kwargs}].

  • -
-
-
-
- -
-
-client_disconnect(csessid)[source]
-

Disconnect session with given csessid.

-
-
Parameters
-

csessid (int) – Session id.

-
-
-
- -
-
-mode_init(request)[source]
-

This is called by render_POST when the client requests an init -mode operation (at startup)

-
-
Parameters
-

request (Request) – Incoming request.

-
-
-
- -
-
-mode_keepalive(request)[source]
-

This is called by render_POST when the -client is replying to the keepalive.

-
-
Parameters
-

request (Request) – Incoming request.

-
-
-
- -
-
-mode_input(request)[source]
-

This is called by render_POST when the client -is sending data to the server.

-
-
Parameters
-

request (Request) – Incoming request.

-
-
-
- -
-
-mode_receive(request)[source]
-

This is called by render_POST when the client is telling us -that it is ready to receive data as soon as it is available. -This is the basis of a long-polling (comet) mechanism: the -server will wait to reply until data is available.

-
-
Parameters
-

request (Request) – Incoming request.

-
-
-
- -
-
-mode_close(request)[source]
-

This is called by render_POST when the client is signalling -that it is about to be closed.

-
-
Parameters
-

request (Request) – Incoming request.

-
-
-
- -
-
-render_POST(request)[source]
-

This function is what Twisted calls with POST requests coming -in from the ajax client. The requests should be tagged with -different modes depending on what needs to be done, such as -initializing or sending/receving data through the request. It -uses a long-polling mechanism to avoid sending data unless -there is actual data available.

-
-
Parameters
-

request (Request) – Incoming request.

-
-
-
- -
- -
-
-class evennia.server.portal.webclient_ajax.AjaxWebClientSession(*args, **kwargs)[source]
-

Bases: evennia.server.session.Session

-

This represents a session running in an AjaxWebclient.

-
-
-__init__(*args, **kwargs)[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
-
-get_client_session()[source]
-

Get the Client browser session (used for auto-login based on browser session)

-
-
Returns
-

csession (ClientSession)

-
-
This is a django-specific internal representation

of the browser session.

-
-
-

-
-
-
- -
-
-disconnect(reason='Server disconnected.')[source]
-

Disconnect from server.

-
-
Parameters
-

reason (str) – Motivation for the disconnect.

-
-
-
- -
-
-at_login()[source]
-
- -
-
-data_in(**kwargs)[source]
-

Data User -> Evennia

-
-
Keyword Arguments
-

kwargs (any) – Incoming data.

-
-
-
- -
-
-data_out(**kwargs)[source]
-

Data Evennia -> User

-
-
Keyword Arguments
-

kwargs (any) – Options to the protocol

-
-
-
- -
-
-send_text(*args, **kwargs)[source]
-

Send text data. This will pre-process the text for -color-replacement, conversion to html etc.

-
-
Parameters
-

text (str) – Text to send.

-
-
Keyword Arguments
-

options (dict) – Options-dict with the following keys understood: -- raw (bool): No parsing at all (leave ansi-to-html markers unparsed). -- nocolor (bool): Remove all color. -- screenreader (bool): Use Screenreader mode. -- send_prompt (bool): Send a prompt with parsed html

-
-
-
- -
-
-send_prompt(*args, **kwargs)[source]
-
- -
-
-send_default(cmdname, *args, **kwargs)[source]
-

Data Evennia -> User.

-
-
Parameters
-
    -
  • cmdname (str) – The first argument will always be the oob cmd name.

  • -
  • *args (any) – Remaining args will be arguments for cmd.

  • -
-
-
Keyword Arguments
-

options (dict) – These are ignored for oob commands. Use command -arguments (which can hold dicts) to send instructions to the -client instead.

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.profiling.dummyrunner.html b/docs/0.9.5/api/evennia.server.profiling.dummyrunner.html deleted file mode 100644 index 1200a8eb0d..0000000000 --- a/docs/0.9.5/api/evennia.server.profiling.dummyrunner.html +++ /dev/null @@ -1,368 +0,0 @@ - - - - - - - - - evennia.server.profiling.dummyrunner — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.profiling.dummyrunner

-

Dummy client runner

-

This module implements a stand-alone launcher for stress-testing -an Evennia game. It will launch any number of fake clients. These -clients will log into the server and start doing random operations. -Customizing and weighing these operations differently depends on -which type of game is tested. The module contains a testing module -for plain Evennia.

-

Please note that you shouldn’t run this on a production server! -Launch the program without any arguments or options to see a -full step-by-step setup help.

-

Basically (for testing default Evennia):

-
-
    -
  • Use an empty/testing database.

  • -
  • set PERMISSION_ACCOUNT_DEFAULT = “Builder”

  • -
  • start server, eventually with profiling active

  • -
  • launch this client runner

  • -
-
-

If you want to customize the runner’s client actions -(because you changed the cmdset or needs to better -match your use cases or add more actions), you can -change which actions by adding a path to

-
-

DUMMYRUNNER_ACTIONS_MODULE = <path.to.your.module>

-
-

in your settings. See utils.dummyrunner_actions.py -for instructions on how to define this module.

-
-
-class evennia.server.profiling.dummyrunner.CmdDummyRunnerEchoResponse(**kwargs)[source]
-

Bases: evennia.commands.command.Command

-

Dummyrunner command measuring the round-about response time -from sending to receiving a result.

-
-
Usage:

dummyrunner_echo_response <timestamp>

-
-
Responds with

dummyrunner_echo_response:<timestamp>,<current_time>

-
-
-

The dummyrunner will send this and then compare the send time -with the receive time on both ends.

-
-
-key = 'dummyrunner_echo_response'
-
- -
-
-func()[source]
-

This is the actual executing part of the command. It is -called directly after self.parse(). See the docstring of this -module for which object properties are available (beyond those -set in self.parse())

-
- -
-
-aliases = []
-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all();'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': 'dummyrunner_echo_response', 'no_prefix': ' ', 'tags': '', 'text': '\n Dummyrunner command measuring the round-about response time\n from sending to receiving a result.\n\n Usage:\n dummyrunner_echo_response <timestamp>\n\n Responds with\n dummyrunner_echo_response:<timestamp>,<current_time>\n\n The dummyrunner will send this and then compare the send time\n with the receive time on both ends.\n\n '}
-
- -
- -
-
-class evennia.server.profiling.dummyrunner.DummyRunnerCmdSet(cmdsetobj=None, key=None)[source]
-

Bases: evennia.commands.cmdset.CmdSet

-

Dummyrunner injected cmdset.

-
-
-at_cmdset_creation()[source]
-

Hook method - this should be overloaded in the inheriting -class, and should take care of populating the cmdset by use of -self.add().

-
- -
-
-path = 'evennia.server.profiling.dummyrunner.DummyRunnerCmdSet'
-
- -
- -
-
-evennia.server.profiling.dummyrunner.idcounter()[source]
-

Makes unique ids.

-
-
Returns
-

str – A globally unique id.

-
-
-
- -
-
-evennia.server.profiling.dummyrunner.gidcounter()[source]
-

Makes globally unique ids.

-
-
Returns
-

count (int); A globally unique counter.

-
-
-
- -
-
-evennia.server.profiling.dummyrunner.makeiter(obj)[source]
-

Makes everything iterable.

-
-
Parameters
-

obj (any) – Object to turn iterable.

-
-
Returns
-

iterable (iterable) – An iterable object.

-
-
-
- -
-
-class evennia.server.profiling.dummyrunner.DummyClient[source]
-

Bases: twisted.conch.telnet.StatefulTelnetProtocol

-

Handles connection to a running Evennia server, -mimicking a real account by sending commands on -a timer.

-
-
-report(text, clientkey)[source]
-
- -
-
-connectionMade()[source]
-

Called when connection is first established.

-
- -
-
-dataReceived(data)[source]
-

Called when data comes in over the protocol. We wait to start -stepping until the server actually responds

-
-
Parameters
-

data (str) – Incoming data.

-
-
-
- -
-
-connectionLost(reason)[source]
-

Called when loosing the connection.

-
-
Parameters
-

reason (str) – Reason for loosing connection.

-
-
-
- -
-
-error(err)[source]
-

Error callback.

-
-
Parameters
-

err (Failure) – Error instance.

-
-
-
- -
-
-counter()[source]
-

Produces a unique id, also between clients.

-
-
Returns
-

counter (int) – A unique counter.

-
-
-
- -
-
-logout()[source]
-

Causes the client to log out of the server. Triggered by ctrl-c signal.

-
- -
-
-step()[source]
-

Perform a step. This is called repeatedly by the runner and -causes the client to issue commands to the server. This holds -all “intelligence” of the dummy client.

-
- -
- -
-
-class evennia.server.profiling.dummyrunner.DummyFactory(actions)[source]
-

Bases: twisted.internet.protocol.ReconnectingClientFactory

-
-
-protocol
-

alias of DummyClient

-
- -
-
-initialDelay = 1
-
- -
-
-maxDelay = 1
-
- -
-
-noisy = False
-
- -
-
-__init__(actions)[source]
-

Setup the factory base (shared by all clients)

-
- -
- -
-
-evennia.server.profiling.dummyrunner.start_all_dummy_clients(nclients)[source]
-

Initialize all clients, connect them and start to step them

-
-
Parameters
-

nclients (int) – Number of dummy clients to connect.

-
-
-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.profiling.dummyrunner_settings.html b/docs/0.9.5/api/evennia.server.profiling.dummyrunner_settings.html deleted file mode 100644 index 30966a0d63..0000000000 --- a/docs/0.9.5/api/evennia.server.profiling.dummyrunner_settings.html +++ /dev/null @@ -1,251 +0,0 @@ - - - - - - - - - evennia.server.profiling.dummyrunner_settings — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.profiling.dummyrunner_settings

-

Settings and actions for the dummyrunner

-

This module defines dummyrunner settings and sets up -the actions available to dummy accounts.

-

The settings are global variables:

-
    -
  • TIMESTEP - time in seconds between each ‘tick’. 1 is a good start.

  • -
  • CHANCE_OF_ACTION - chance 0-1 of action happening. Default is 0.5.

  • -
  • CHANCE_OF_LOGIN - chance 0-1 of login happening. 0.01 is a good number.

  • -
  • TELNET_PORT - port to use, defaults to settings.TELNET_PORT

  • -
  • ACTIONS - see below

  • -
-

ACTIONS is a tuple

-
(login_func, logout_func, (0.3, func1), (0.1, func2) ... )
-
-
-

where the first entry is the function to call on first connect, with a -chance of occurring given by CHANCE_OF_LOGIN. This function is usually -responsible for logging in the account. The second entry is always -called when the dummyrunner disconnects from the server and should -thus issue a logout command. The other entries are tuples (chance, -func). They are picked randomly, their commonality based on the -cumulative chance given (the chance is normalized between all options -so if will still work also if the given chances don’t add up to 1).

-

The PROFILE variable define pre-made ACTION tuples for convenience.

-

Each function should return an iterable of one or more command-call -strings (like “look here”), so each can group multiple command operations.

-

An action-function is called with a “client” argument which is a -reference to the dummy client currently performing the action.

-

The client object has the following relevant properties and methods:

-
    -
  • key - an optional client key. This is only used for dummyrunner output. -Default is “Dummy-<cid>”

  • -
  • cid - client id

  • -
  • gid - globally unique id, hashed with time stamp

  • -
  • istep - the current step

  • -
  • exits - an empty list. Can be used to store exit names

  • -
  • objs - an empty list. Can be used to store object names

  • -
  • counter() - returns a unique increasing id, hashed with time stamp -to make it unique also between dummyrunner instances.

  • -
-

The return should either be a single command string or a tuple of -command strings. This list of commands will always be executed every -TIMESTEP with a chance given by CHANCE_OF_ACTION by in the order given -(no randomness) and allows for setting up a more complex chain of -commands (such as creating an account and logging in).

-
-
-
-evennia.server.profiling.dummyrunner_settings.c_login(client)[source]
-

logins to the game

-
- -
-
-evennia.server.profiling.dummyrunner_settings.c_login_nodig(client)[source]
-

logins, don’t dig its own room

-
- -
-
-evennia.server.profiling.dummyrunner_settings.c_logout(client)[source]
-

logouts of the game

-
- -
-
-evennia.server.profiling.dummyrunner_settings.c_looks(client)[source]
-

looks at various objects

-
- -
-
-evennia.server.profiling.dummyrunner_settings.c_examines(client)[source]
-

examines various objects

-
- -
-
-evennia.server.profiling.dummyrunner_settings.c_idles(client)[source]
-

idles

-
- -
-
-evennia.server.profiling.dummyrunner_settings.c_help(client)[source]
-

reads help files

-
- -
-
-evennia.server.profiling.dummyrunner_settings.c_digs(client)[source]
-

digs a new room, storing exit names on client

-
- -
-
-evennia.server.profiling.dummyrunner_settings.c_creates_obj(client)[source]
-

creates normal objects, storing their name on client

-
- -
-
-evennia.server.profiling.dummyrunner_settings.c_creates_button(client)[source]
-

creates example button, storing name on client

-
- -
-
-evennia.server.profiling.dummyrunner_settings.c_socialize(client)[source]
-

socializechats on channel

-
- -
-
-evennia.server.profiling.dummyrunner_settings.c_moves(client)[source]
-

moves to a previously created room, using the stored exits

-
- -
-
-evennia.server.profiling.dummyrunner_settings.c_moves_n(client)[source]
-

move through north exit if available

-
- -
-
-evennia.server.profiling.dummyrunner_settings.c_moves_s(client)[source]
-

move through south exit if available

-
- -
-
-evennia.server.profiling.dummyrunner_settings.c_measure_lag(client)[source]
-

Special dummyrunner command, injected in c_login. It measures -response time. Including this in the ACTION tuple will give more -dummyrunner output about just how fast commands are being processed.

-

The dummyrunner will treat this special and inject the -{timestamp} just before sending.

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.profiling.html b/docs/0.9.5/api/evennia.server.profiling.html deleted file mode 100644 index ae5f5cda90..0000000000 --- a/docs/0.9.5/api/evennia.server.profiling.html +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - - - - evennia.server.profiling — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.profiling.memplot.html b/docs/0.9.5/api/evennia.server.profiling.memplot.html deleted file mode 100644 index 31596815e4..0000000000 --- a/docs/0.9.5/api/evennia.server.profiling.memplot.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - - - - - - evennia.server.profiling.memplot — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.profiling.memplot

-

Script that saves memory and idmapper data over time.

-

Data will be saved to game/logs/memoryusage.log. Note that -the script will append to this file if it already exists.

-

Call this module directly to plot the log (requires matplotlib and numpy).

-
-
-class evennia.server.profiling.memplot.Memplot(*args, **kwargs)[source]
-

Bases: evennia.scripts.scripts.DefaultScript

-

Describes a memory plotting action.

-
-
-at_script_creation()[source]
-

Called at script creation

-
- -
-
-at_repeat()[source]
-

Regularly save memory statistics.

-
- -
-
-exception DoesNotExist
-

Bases: evennia.scripts.scripts.DefaultScript.DoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: evennia.scripts.scripts.DefaultScript.MultipleObjectsReturned

-
- -
-
-path = 'evennia.server.profiling.memplot.Memplot'
-
- -
-
-typename = 'Memplot'
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.profiling.settings_mixin.html b/docs/0.9.5/api/evennia.server.profiling.settings_mixin.html deleted file mode 100644 index 872b397e80..0000000000 --- a/docs/0.9.5/api/evennia.server.profiling.settings_mixin.html +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - - - evennia.server.profiling.settings_mixin — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.profiling.settings_mixin

-

Dummyrunner mixin. Add this at the end of the settings file before -running dummyrunner, like this:

-
-

from evennia.server.profiling.settings_mixin import *

-
-

Note that these mixin-settings are not suitable for production -servers!

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.profiling.test_queries.html b/docs/0.9.5/api/evennia.server.profiling.test_queries.html deleted file mode 100644 index c656eace24..0000000000 --- a/docs/0.9.5/api/evennia.server.profiling.test_queries.html +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - evennia.server.profiling.test_queries — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.profiling.test_queries

-

This is a little routine for viewing the sql queries that are executed by a given -query as well as count them for optimization testing.

-
-
-evennia.server.profiling.test_queries.count_queries(exec_string, setup_string)[source]
-

Display queries done by exec_string. Use setup_string -to setup the environment to test.

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.profiling.tests.html b/docs/0.9.5/api/evennia.server.profiling.tests.html deleted file mode 100644 index a241458547..0000000000 --- a/docs/0.9.5/api/evennia.server.profiling.tests.html +++ /dev/null @@ -1,214 +0,0 @@ - - - - - - - - - evennia.server.profiling.tests — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.profiling.tests

-
-
-class evennia.server.profiling.tests.TestDummyrunnerSettings(methodName='runTest')[source]
-

Bases: django.test.testcases.TestCase

-
-
-setUp()[source]
-

Hook method for setting up the test fixture before exercising it.

-
- -
-
-clear_client_lists()[source]
-
- -
-
-test_c_login()[source]
-
- -
-
-test_c_login_no_dig()[source]
-
- -
-
-test_c_logout()[source]
-
- -
-
-perception_method_tests(func, verb, alone_suffix='')[source]
-
- -
-
-test_c_looks()[source]
-
- -
-
-test_c_examines()[source]
-
- -
-
-test_idles()[source]
-
- -
-
-test_c_help()[source]
-
- -
-
-test_c_digs()[source]
-
- -
-
-test_c_creates_obj()[source]
-
- -
-
-test_c_creates_button()[source]
-
- -
-
-test_c_socialize()[source]
-
- -
-
-test_c_moves()[source]
-
- -
-
-test_c_move_n()[source]
-
- -
-
-test_c_move_s()[source]
-
- -
- -
-
-class evennia.server.profiling.tests.TestMemPlot(methodName='runTest')[source]
-

Bases: django.test.testcases.TestCase

-
-
-test_memplot(mock_time, mocked_open, mocked_os, mocked_idmapper)[source]
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.profiling.timetrace.html b/docs/0.9.5/api/evennia.server.profiling.timetrace.html deleted file mode 100644 index 52748765f5..0000000000 --- a/docs/0.9.5/api/evennia.server.profiling.timetrace.html +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - evennia.server.profiling.timetrace — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.profiling.timetrace

-

Trace a message through the messaging system

-
-
-evennia.server.profiling.timetrace.timetrace(message, idstring, tracemessage='TEST_MESSAGE', final=False)[source]
-

Trace a message with time stamps.

-
-
Parameters
-
    -
  • message (str) – The actual message coming through

  • -
  • idstring (str) – An identifier string specifying where this trace is happening.

  • -
  • tracemessage (str) – The start of the message to tag. -This message will get attached time stamp.

  • -
  • final (bool) – This is the final leg in the path - include total time in message

  • -
-
-
-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.server.html b/docs/0.9.5/api/evennia.server.server.html deleted file mode 100644 index 0122067599..0000000000 --- a/docs/0.9.5/api/evennia.server.server.html +++ /dev/null @@ -1,254 +0,0 @@ - - - - - - - - - evennia.server.server — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.server

-

This module implements the main Evennia server process, the core of the game -engine.

-

This module should be started with the ‘twistd’ executable since it sets up all -the networking features. (this is done automatically by -evennia/server/server_runner.py).

-
-
-class evennia.server.server.Evennia(application)[source]
-

Bases: object

-

The main Evennia server handler. This object sets up the database and -tracks and interlinks all the twisted network services that make up -evennia.

-
-
-__init__(application)[source]
-

Setup the server.

-

application - an instantiated Twisted application

-
- -
-
-sqlite3_prep()[source]
-

Optimize some SQLite stuff at startup since we -can’t save it to the database.

-
- -
-
-update_defaults()[source]
-

We make sure to store the most important object defaults here, so -we can catch if they change and update them on-objects automatically. -This allows for changing default cmdset locations and default -typeclasses in the settings file and have them auto-update all -already existing objects.

-
- -
-
-run_initial_setup()[source]
-

This is triggered by the amp protocol when the connection -to the portal has been established. -This attempts to run the initial_setup script of the server. -It returns if this is not the first time the server starts. -Once finished the last_initial_setup_step is set to ‘done’

-
- -
-
-create_default_channels()[source]
-

check so default channels exist on every restart, create if not.

-
- -
-
-run_init_hooks(mode)[source]
-

Called by the amp client once receiving sync back from Portal

-
-
Parameters
-

mode (str) – One of shutdown, reload or reset

-
-
-
- -
-
-shutdown(mode='reload', _reactor_stopping=False)[source]
-

Shuts down the server from inside it.

-
-
mode - sets the server restart mode.
    -
  • ‘reload’ - server restarts, no “persistent” scripts -are stopped, at_reload hooks called.

  • -
  • ‘reset’ - server restarts, non-persistent scripts stopped, -at_shutdown hooks called but sessions will not -be disconnected.

  • -
  • ‘shutdown’ - like reset, but server will not auto-restart.

  • -
-
-
_reactor_stopping - this is set if server is stopped by a kill

command OR this method was already called -once - in both cases the reactor is -dead/stopping already.

-
-
-
- -
-
-get_info_dict()[source]
-

Return the server info, for display.

-
- -
-
-at_server_start()[source]
-

This is called every time the server starts up, regardless of -how it was shut down.

-
- -
-
-at_server_stop()[source]
-

This is called just before a server is shut down, regardless -of it is fore a reload, reset or shutdown.

-
- -
-
-at_server_reload_start()[source]
-

This is called only when server starts back up after a reload.

-
- -
-
-at_post_portal_sync(mode)[source]
-

This is called just after the portal has finished syncing back data to the server -after reconnecting.

-
-
Parameters
-

mode (str) – One of ‘reload’, ‘reset’ or ‘shutdown’.

-
-
-
- -
-
-at_server_reload_stop()[source]
-

This is called only time the server stops before a reload.

-
- -
-
-at_server_cold_start()[source]
-

This is called only when the server starts “cold”, i.e. after a -shutdown or a reset.

-
- -
-
-at_server_cold_stop()[source]
-

This is called only when the server goes down due to a shutdown or reset.

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.serversession.html b/docs/0.9.5/api/evennia.server.serversession.html deleted file mode 100644 index 0c20e6ea75..0000000000 --- a/docs/0.9.5/api/evennia.server.serversession.html +++ /dev/null @@ -1,419 +0,0 @@ - - - - - - - - - evennia.server.serversession — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.serversession

-

This defines a the Server’s generic session object. This object represents -a connection to the outside world but don’t know any details about how the -connection actually happens (so it’s the same for telnet, web, ssh etc).

-

It is stored on the Server side (as opposed to protocol-specific sessions which -are stored on the Portal side)

-
-
-class evennia.server.serversession.ServerSession[source]
-

Bases: evennia.server.session.Session

-

This class represents an account’s session and is a template for -individual protocols to communicate with Evennia.

-

Each account gets a session assigned to them whenever they connect -to the game server. All communication between game and account goes -through their session.

-
-
-__init__()[source]
-

Initiate to avoid AttributeErrors down the line

-
- -
-
-property cmdset_storage
-
- -
-
-property id
-
- -
-
-at_sync()[source]
-

This is called whenever a session has been resynced with the -portal. At this point all relevant attributes have already -been set and self.account been assigned (if applicable).

-

Since this is often called after a server restart we need to -set up the session as it was.

-
- -
-
-at_login(account)[source]
-

Hook called by sessionhandler when the session becomes authenticated.

-
-
Parameters
-

account (Account) – The account associated with the session.

-
-
-
- -
-
-at_disconnect(reason=None)[source]
-

Hook called by sessionhandler when disconnecting this session.

-
- -
-
-get_account()[source]
-

Get the account associated with this session

-
-
Returns
-

account (Account) – The associated Account.

-
-
-
- -
-
-get_puppet()[source]
-

Get the in-game character associated with this session.

-
-
Returns
-

puppet (Object) – The puppeted object, if any.

-
-
-
- -
-
-get_character()
-

Get the in-game character associated with this session.

-
-
Returns
-

puppet (Object) – The puppeted object, if any.

-
-
-
- -
-
-get_puppet_or_account()[source]
-

Get puppet or account.

-
-
Returns
-

controller (Object or Account)

-
-
The puppet if one exists,

otherwise return the account.

-
-
-

-
-
-
- -
-
-log(message, channel=True)[source]
-

Emits session info to the appropriate outputs and info channels.

-
-
Parameters
-
    -
  • message (str) – The message to log.

  • -
  • channel (bool, optional) – Log to the CHANNEL_CONNECTINFO channel -in addition to the server log.

  • -
-
-
-
- -
-
-get_client_size()[source]
-

Return eventual eventual width and height reported by the -client. Note that this currently only deals with a single -client window (windowID==0) as in a traditional telnet session.

-
- -
-
-update_session_counters(idle=False)[source]
-

Hit this when the user enters a command in order to update -idle timers and command counters.

-
- -
-
-update_flags(**kwargs)[source]
-

Update the protocol_flags and sync them with Portal.

-
-
Keyword Arguments
-

protocol_flag (any) – A key and value to set in the -protocol_flags dictionary.

-
-
-

Notes

-

Since protocols can vary, no checking is done -as to the existene of the flag or not. The input -data should have been validated before this call.

-
- -
-
-data_out(**kwargs)[source]
-

Sending data from Evennia->Client

-
-
Keyword Arguments
-
    -
  • text (str or tuple) –

  • -
  • any (str or tuple) – Send-commands identified -by their keys. Or “options”, carrying options -for the protocol(s).

  • -
-
-
-
- -
-
-data_in(**kwargs)[source]
-

Receiving data from the client, sending it off to -the respective inputfuncs.

-
-
Keyword Arguments
-

kwargs (any) – Incoming data from protocol on -the form {“commandname”: ((args), {kwargs}),…}

-
-
-

Notes

-

This method is here in order to give the user -a single place to catch and possibly process all incoming data from -the client. It should usually always end by sending -this data off to self.sessionhandler.call_inputfuncs(self, **kwargs).

-
- -
-
-msg(text=None, **kwargs)[source]
-

Wrapper to mimic msg() functionality of Objects and Accounts.

-
-
Parameters
-

text (str) – String input.

-
-
Keyword Arguments
-

any (str or tuple) – Send-commands identified -by their keys. Or “options”, carrying options -for the protocol(s).

-
-
-
- -
-
-execute_cmd(raw_string, session=None, **kwargs)[source]
-

Do something as this object. This method is normally never -called directly, instead incoming command instructions are -sent to the appropriate inputfunc already at the sessionhandler -level. This method allows Python code to inject commands into -this stream, and will lead to the text inputfunc be called.

-
-
Parameters
-
    -
  • raw_string (string) – Raw command input

  • -
  • session (Session) – This is here to make API consistent with -Account/Object.execute_cmd. If given, data is passed to -that Session, otherwise use self.

  • -
-
-
Keyword Arguments
-
    -
  • keyword arguments will be added to the found command (Other) –

  • -
  • instace as variables before it executes. This is (object) –

  • -
  • by default Evennia but may be used to set flags and (unused) –

  • -
  • operating paramaters for commands at run-time. (change) –

  • -
-
-
-
- -
-
-at_cmdset_get(**kwargs)[source]
-

A dummy hook all objects with cmdsets need to have

-
- -
-
-nattributes[source]
-
- -
-
-attributes[source]
-
- -
-
-ndb_get()[source]
-

A non-persistent store (ndb: NonDataBase). Everything stored -to this is guaranteed to be cleared when a server is shutdown. -Syntax is same as for the _get_db_holder() method and -property, e.g. obj.ndb.attr = value etc.

-
- -
-
-ndb_set(value)[source]
-

Stop accidentally replacing the db object

-
-
Parameters
-

value (any) – A value to store in the ndb.

-
-
-
- -
-
-ndb_del()[source]
-

Stop accidental deletion.

-
- -
-
-property ndb
-

NonDataBase). Everything stored -to this is guaranteed to be cleared when a server is shutdown. -Syntax is same as for the _get_db_holder() method and -property, e.g. obj.ndb.attr = value etc.

-
-
Type
-

A non-persistent store (ndb

-
-
-
- -
-
-property db
-

NonDataBase). Everything stored -to this is guaranteed to be cleared when a server is shutdown. -Syntax is same as for the _get_db_holder() method and -property, e.g. obj.ndb.attr = value etc.

-
-
Type
-

A non-persistent store (ndb

-
-
-
- -
-
-access(*args, **kwargs)[source]
-

Dummy method to mimic the logged-in API.

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.session.html b/docs/0.9.5/api/evennia.server.session.html deleted file mode 100644 index 71f34c68e5..0000000000 --- a/docs/0.9.5/api/evennia.server.session.html +++ /dev/null @@ -1,224 +0,0 @@ - - - - - - - - - evennia.server.session — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.session

-

This module defines a generic session class. All connection instances -(both on Portal and Server side) should inherit from this class.

-
-
-class evennia.server.session.Session[source]
-

Bases: object

-

This class represents a player’s session and is a template for -both portal- and server-side sessions.

-

Each connection will see two session instances created:

-
-
    -
  1. A Portal session. This is customized for the respective connection -protocols that Evennia supports, like Telnet, SSH etc. The Portal -session must call init_session() as part of its initialization. The -respective hook methods should be connected to the methods unique -for the respective protocol so that there is a unified interface -to Evennia.

  2. -
  3. A Server session. This is the same for all connected accounts, -regardless of how they connect.

  4. -
-
-

The Portal and Server have their own respective sessionhandlers. These -are synced whenever new connections happen or the Server restarts etc, -which means much of the same information must be stored in both places -e.g. the portal can re-sync with the server when the server reboots.

-
-
-init_session(protocol_key, address, sessionhandler)[source]
-

Initialize the Session. This should be called by the protocol when -a new session is established.

-
-
Parameters
-
    -
  • protocol_key (str) – By default, one of ‘telnet’, ‘telnet/ssl’, ‘ssh’, -‘webclient/websocket’ or ‘webclient/ajax’.

  • -
  • address (str) – Client address.

  • -
  • sessionhandler (SessionHandler) – Reference to the -main sessionhandler instance.

  • -
-
-
-
- -
-
-get_sync_data()[source]
-

Get all data relevant to sync the session.

-
-
Parameters
-

syncdata (dict) – All syncdata values, based on -the keys given by self._attrs_to_sync.

-
-
-
- -
-
-load_sync_data(sessdata)[source]
-

Takes a session dictionary, as created by get_sync_data, and -loads it into the correct properties of the session.

-
-
Parameters
-

sessdata (dict) – Session data dictionary.

-
-
-
- -
-
-at_sync()[source]
-

Called after a session has been fully synced (including -secondary operations such as setting self.account based -on uid etc).

-
- -
-
-disconnect(reason=None)[source]
-

generic hook called from the outside to disconnect this session -should be connected to the protocols actual disconnect mechanism.

-
-
Parameters
-

reason (str) – Eventual text motivating the disconnect.

-
-
-
- -
-
-data_out(**kwargs)[source]
-

Generic hook for sending data out through the protocol. Server -protocols can use this right away. Portal sessions -should overload this to format/handle the outgoing data as needed.

-
-
Keyword Arguments
-

kwargs (any) – Other data to the protocol.

-
-
-
- -
-
-data_in(**kwargs)[source]
-

Hook for protocols to send incoming data to the engine.

-
-
Keyword Arguments
-

kwargs (any) – Other data from the protocol.

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.sessionhandler.html b/docs/0.9.5/api/evennia.server.sessionhandler.html deleted file mode 100644 index 2848cb1f99..0000000000 --- a/docs/0.9.5/api/evennia.server.sessionhandler.html +++ /dev/null @@ -1,631 +0,0 @@ - - - - - - - - - evennia.server.sessionhandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.sessionhandler

-

This module defines handlers for storing sessions when handles -sessions of users connecting to the server.

-

There are two similar but separate stores of sessions:

-
    -
  • -
    ServerSessionHandler - this stores generic game sessions

    for the game. These sessions has no knowledge about -how they are connected to the world.

    -
    -
    -
  • -
  • -
    PortalSessionHandler - this stores sessions created by

    twisted protocols. These are dumb connectors that -handle network communication but holds no game info.

    -
    -
    -
  • -
-
-
-class evennia.server.sessionhandler.DummySession[source]
-

Bases: object

-
-
-sessid = 0
-
- -
- -
-
-evennia.server.sessionhandler.delayed_import()[source]
-

Helper method for delayed import of all needed entities.

-
- -
-
-class evennia.server.sessionhandler.SessionHandler[source]
-

Bases: dict

-

This handler holds a stack of sessions.

-
-
-get(key, default=None)[source]
-

Clean out None-sessions automatically.

-
- -
-
-get_sessions(include_unloggedin=False)[source]
-

Returns the connected session objects.

-
-
Parameters
-

include_unloggedin (bool, optional) – Also list Sessions -that have not yet authenticated.

-
-
Returns
-

sessions (list) – A list of Session objects.

-
-
-
- -
-
-get_all_sync_data()[source]
-

Create a dictionary of sessdata dicts representing all -sessions in store.

-
-
Returns
-

syncdata (dict) – A dict of sync data.

-
-
-
- -
-
-clean_senddata(session, kwargs)[source]
-

Clean up data for sending across the AMP wire. Also apply the -FuncParser using callables from settings.FUNCPARSER_OUTGOING_MESSAGES_MODULES.

-
-
Parameters
-
    -
  • session (Session) – The relevant session instance.

  • -
  • kwargs (dict) – the name of the instruction (like “text”). Suitable values for each keyword are: -- arg -> [[arg], {}] -- [args] -> [[args], {}] -- {kwargs} -> [[], {kwargs}] -- [args, {kwargs}] -> [[arg], {kwargs}] -- [[args], {kwargs}] -> [[args], {kwargs}]

  • -
-
-
Returns
-

kwargs (dict) – A cleaned dictionary of cmdname:[[args],{kwargs}] pairs, -where the keys, args and kwargs have all been converted to -send-safe entities (strings or numbers), and funcparser parsing has been -applied.

-
-
-
- -
- -
-
-class evennia.server.sessionhandler.ServerSessionHandler(*args, **kwargs)[source]
-

Bases: evennia.server.sessionhandler.SessionHandler

-

This object holds the stack of sessions active in the game at any time.

-

A session register with the handler in two steps, first by registering itself with the connect() -method. This indicates an non-authenticated session. Whenever the session is authenticated the -session together with the related account is sent to the login() method.

-
-
-__init__(*args, **kwargs)[source]
-

Init the handler.

-
- -
-
-portal_connect(portalsessiondata)[source]
-

Called by Portal when a new session has connected. -Creates a new, unlogged-in game session.

-
-
Parameters
-

portalsessiondata (dict) – a dictionary of all property:value -keys defining the session and which is marked to be -synced.

-
-
-
- -
-
-portal_session_sync(portalsessiondata)[source]
-

Called by Portal when it wants to update a single session (e.g. -because of all negotiation protocols have finally replied)

-
-
Parameters
-

portalsessiondata (dict) – a dictionary of all property:value -keys defining the session and which is marked to be -synced.

-
-
-
- -
-
-portal_sessions_sync(portalsessionsdata)[source]
-

Syncing all session ids of the portal with the ones of the -server. This is instantiated by the portal when reconnecting.

-
-
Parameters
-

portalsessionsdata (dict) – A dictionary -{sessid: {property:value},…} defining each session and -the properties in it which should be synced.

-
-
-
- -
-
-portal_disconnect(session)[source]
-

Called from Portal when Portal session closed from the portal -side. There is no message to report in this case.

-
-
Parameters
-

session (Session) – The Session to disconnect

-
-
-
- -
-
-portal_disconnect_all()[source]
-

Called from Portal when Portal is closing down. All -Sessions should die. The Portal should not be informed.

-
- -
-
-start_bot_session(protocol_path, configdict)[source]
-

This method allows the server-side to force the Portal to -create a new bot session.

-
-
Parameters
-
    -
  • protocol_path (str) – The full python path to the bot’s -class.

  • -
  • configdict (dict) – This dict will be used to configure -the bot (this depends on the bot protocol).

  • -
-
-
-

Examples

-
-
start_bot_session(“evennia.server.portal.irc.IRCClient”,
-
{“uid”:1, “botname”:”evbot”, “channel”:”#evennia”,

“network:”irc.freenode.net”, “port”: 6667})

-
-
-
-
-

Notes

-

The new session will use the supplied account-bot uid to -initiate an already logged-in connection. The Portal will -treat this as a normal connection and henceforth so will -the Server.

-
- -
-
-portal_restart_server()[source]
-

Called by server when reloading. We tell the portal to start a new server instance.

-
- -
-
-portal_reset_server()[source]
-

Called by server when reloading. We tell the portal to start a new server instance.

-
- -
-
-portal_shutdown()[source]
-

Called by server when it’s time to shut down (the portal will shut us down and then shut -itself down)

-
- -
-
-login(session, account, force=False, testmode=False)[source]
-

Log in the previously unloggedin session and the account we by now should know is connected -to it. After this point we assume the session to be logged in one way or another.

-
-
Parameters
-
    -
  • session (Session) – The Session to authenticate.

  • -
  • account (Account) – The Account identified as associated with this Session.

  • -
  • force (bool) – Login also if the session thinks it’s already logged in -(this can happen for auto-authenticating protocols)

  • -
  • testmode (bool, optional) – This is used by unittesting for -faking login without any AMP being actually active.

  • -
-
-
-
- -
-
-disconnect(session, reason='', sync_portal=True)[source]
-

Called from server side to remove session and inform portal -of this fact.

-
-
Parameters
-
    -
  • session (Session) – The Session to disconnect.

  • -
  • reason (str, optional) – A motivation for the disconnect.

  • -
  • sync_portal (bool, optional) – Sync the disconnect to -Portal side. This should be done unless this was -called by self.portal_disconnect().

  • -
-
-
-
- -
-
-all_sessions_portal_sync()[source]
-

This is called by the server when it reboots. It syncs all session data -to the portal. Returns a deferred!

-
- -
-
-session_portal_sync(session)[source]
-

This is called by the server when it wants to sync a single session -with the Portal for whatever reason. Returns a deferred!

-
- -
-
-session_portal_partial_sync(session_data)[source]
-

Call to make a partial update of the session, such as only a particular property.

-
-
Parameters
-

session_data (dict) – Store {sessid: {property:value}, …} defining one or -more sessions in detail.

-
-
-
- -
-
-disconnect_all_sessions(reason='You have been disconnected.')[source]
-

Cleanly disconnect all of the connected sessions.

-
-
Parameters
-

reason (str, optional) – The reason for the disconnection.

-
-
-
- -
-
-disconnect_duplicate_sessions(curr_session, reason='Logged in from elsewhere. Disconnecting.')[source]
-

Disconnects any existing sessions with the same user.

-
-
Parameters
-
    -
  • curr_session (Session) – Disconnect all Sessions matching this one.

  • -
  • reason (str, optional) – A motivation for disconnecting.

  • -
-
-
-
- -
-
-validate_sessions()[source]
-

Check all currently connected sessions (logged in and not) and -see if any are dead or idle.

-
- -
-
-account_count()[source]
-

Get the number of connected accounts (not sessions since a -account may have more than one session depending on settings). -Only logged-in accounts are counted here.

-
-
Returns
-

naccount (int) – Number of connected accounts

-
-
-
- -
-
-all_connected_accounts()[source]
-

Get a unique list of connected and logged-in Accounts.

-
-
Returns
-

accounts (list)

-
-
All conected Accounts (which may be fewer than the

amount of Sessions due to multi-playing).

-
-
-

-
-
-
- -
-
-session_from_sessid(sessid)[source]
-

Get session based on sessid, or None if not found

-
-
Parameters
-

sessid (int or list) – Session id(s).

-
-
Returns
-

sessions (Session or list)

-
-
Session(s) found. This

is a list if input was a list.

-
-
-

-
-
-
- -
-
-session_from_account(account, sessid)[source]
-

Given an account and a session id, return the actual session -object.

-
-
Parameters
-
    -
  • account (Account) – The Account to get the Session from.

  • -
  • sessid (int or list) – Session id(s).

  • -
-
-
Returns
-

sessions (Session or list) – Session(s) found.

-
-
-
- -
-
-sessions_from_account(account)[source]
-

Given an account, return all matching sessions.

-
-
Parameters
-

account (Account) – Account to get sessions from.

-
-
Returns
-

sessions (list) – All Sessions associated with this account.

-
-
-
- -
-
-sessions_from_puppet(puppet)[source]
-

Given a puppeted object, return all controlling sessions.

-
-
Parameters
-

puppet (Object) – Object puppeted

-
-
-
-
Returns.
-
sessions (Session or list): Can be more than one of Object is controlled by more than

one Session (MULTISESSION_MODE > 1).

-
-
-
-
-
- -
-
-sessions_from_character(puppet)
-

Given a puppeted object, return all controlling sessions.

-
-
Parameters
-

puppet (Object) – Object puppeted

-
-
-
-
Returns.
-
sessions (Session or list): Can be more than one of Object is controlled by more than

one Session (MULTISESSION_MODE > 1).

-
-
-
-
-
- -
-
-sessions_from_csessid(csessid)[source]
-

Given a client identification hash (for session types that offer them) -return all sessions with a matching hash.

-
-
Args

csessid (str): The session hash.

-
-
-
-
Returns
-

sessions (list) – The sessions with matching .csessid, if any.

-
-
-
- -
-
-announce_all(message)[source]
-

Send message to all connected sessions

-
-
Parameters
-

message (str) – Message to send.

-
-
-
- -
-
-data_out(session, **kwargs)[source]
-

Sending data Server -> Portal

-
-
Parameters
-
    -
  • session (Session) – Session to relay to.

  • -
  • text (str, optional) – text data to return

  • -
-
-
-

Notes

-

The outdata will be scrubbed for sending across -the wire here.

-
- -
-
-get_inputfuncs()[source]
-

Get all registered inputfuncs (access function)

-
-
Returns
-

inputfuncs (dict) – A dict of {key:inputfunc,…}

-
-
-
- -
-
-data_in(session, **kwargs)[source]
-

We let the data take a “detour” to session.data_in -so the user can override and see it all in one place. -That method is responsible to in turn always call -this class’ sessionhandler.call_inputfunc with the -(possibly processed) data.

-
- -
-
-call_inputfuncs(session, **kwargs)[source]
-

Split incoming data into its inputfunc counterparts. This should be -called by the serversession.data_in as -sessionhandler.call_inputfunc(self, **kwargs).

-

We also intercept OOB communication here.

-
-
Parameters
-

sessions (Session) – Session.

-
-
Keyword Arguments
-

any (tuple) – Incoming data from protocol, each -on the form commandname=((args), {kwargs}).

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.signals.html b/docs/0.9.5/api/evennia.server.signals.html deleted file mode 100644 index d6972f89b4..0000000000 --- a/docs/0.9.5/api/evennia.server.signals.html +++ /dev/null @@ -1,125 +0,0 @@ - - - - - - - - - evennia.server.signals — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.signals

-

This module brings Django Signals into Evennia. These are events that can be -subscribed to by importing a given Signal and using the following code.

-
THIS_SIGNAL.connect(callback, sender_object)
-
-
-

When other code calls THIS_SIGNAL.send(sender, **kwargs), the callback will -be triggered.

-

Callbacks must be on the following format:

-
def my_callback(sender, **kwargs):
-    # ...
-
-
-

This is used on top of hooks to make certain features easier to add to contribs -without necessitating a full takeover of hooks that may be in high demand.

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.throttle.html b/docs/0.9.5/api/evennia.server.throttle.html deleted file mode 100644 index f7fc336574..0000000000 --- a/docs/0.9.5/api/evennia.server.throttle.html +++ /dev/null @@ -1,264 +0,0 @@ - - - - - - - - - evennia.server.throttle — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.throttle

-
-
-class evennia.server.throttle.Throttle(**kwargs)[source]
-

Bases: object

-

Keeps a running count of failed actions per IP address.

-

Available methods indicate whether or not the number of failures exceeds a -particular threshold.

-

This version of the throttle is usable by both the terminal server as well -as the web server, imposes limits on memory consumption by using deques -with length limits instead of open-ended lists, and uses native Django -caches for automatic key eviction and persistence configurability.

-
-
-error_msg = 'Too many failed attempts; you must wait a few minutes before trying again.'
-
- -
-
-__init__(**kwargs)[source]
-

Allows setting of throttle parameters.

-
-
Keyword Arguments
-
    -
  • name (str) – Name of this throttle.

  • -
  • limit (int) – Max number of failures before imposing limiter. If None, -the throttle is disabled.

  • -
  • timeout (int) – number of timeout seconds after -max number of tries has been reached.

  • -
  • cache_size (int) – Max number of attempts to record per IP within a -rolling window; this is NOT the same as the limit after which -the throttle is imposed!

  • -
-
-
-
- -
-
-get_cache_key(*args, **kwargs)[source]
-

Creates a ‘prefixed’ key containing arbitrary terms to prevent key -collisions in the same namespace.

-
- -
-
-touch(key, *args, **kwargs)[source]
-

Refreshes the timeout on a given key and ensures it is recorded in the -key register.

-
-
Parameters
-

key (str) – Key of entry to renew.

-
-
-
- -
-
-get(ip=None)[source]
-

Convenience function that returns the storage table, or part of.

-
-
Parameters
-

ip (str, optional) – IP address of requestor

-
-
Returns
-

storage (dict)

-
-
When no IP is provided, returns a dict of all

current IPs being tracked and the timestamps of their recent -failures.

-
-
timestamps (deque): When an IP is provided, returns a deque of

timestamps of recent failures only for that IP.

-
-
-

-
-
-
- -
-
-update(ip, failmsg='Exceeded threshold.')[source]
-

Store the time of the latest failure.

-
-
Parameters
-
    -
  • ip (str) – IP address of requestor

  • -
  • failmsg (str, optional) – Message to display in logs upon activation -of throttle.

  • -
-
-
Returns
-

None

-
-
-
- -
-
-remove(ip, *args, **kwargs)[source]
-

Clears data stored for an IP from the throttle.

-
-
Parameters
-

ip (str) – IP to clear.

-
-
-
- -
-
-record_ip(ip, *args, **kwargs)[source]
-

Tracks keys as they are added to the cache (since there is no way to -get a list of keys after-the-fact).

-
-
Parameters
-

ip (str) – IP being added to cache. This should be the original -IP, not the cache-prefixed key.

-
-
-
- -
-
-unrecord_ip(ip, *args, **kwargs)[source]
-

Forces removal of a key from the key registry.

-
-
Parameters
-

ip (str) – IP to remove from list of keys.

-
-
-
- -
-
-check(ip)[source]
-

This will check the session’s address against the -storage dictionary to check they haven’t spammed too many -fails recently.

-
-
Parameters
-

ip (str) – IP address of requestor

-
-
Returns
-

throttled (bool)

-
-
True if throttling is active,

False otherwise.

-
-
-

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.validators.html b/docs/0.9.5/api/evennia.server.validators.html deleted file mode 100644 index c12a271a47..0000000000 --- a/docs/0.9.5/api/evennia.server.validators.html +++ /dev/null @@ -1,173 +0,0 @@ - - - - - - - - - evennia.server.validators — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.validators

-
-
-class evennia.server.validators.EvenniaUsernameAvailabilityValidator[source]
-

Bases: object

-

Checks to make sure a given username is not taken or otherwise reserved.

-
- -
-
-class evennia.server.validators.EvenniaPasswordValidator(regex="^[\\w. @+\\-',]+$", policy="Password should contain a mix of letters, spaces, digits and @/./+/-/_/'/, only.")[source]
-

Bases: object

-
-
-__init__(regex="^[\\w. @+\\-',]+$", policy="Password should contain a mix of letters, spaces, digits and @/./+/-/_/'/, only.")[source]
-

Constructs a standard Django password validator.

-
-
Parameters
-
    -
  • regex (str) – Regex pattern of valid characters to allow.

  • -
  • policy (str) – Brief explanation of what the defined regex permits.

  • -
-
-
-
- -
-
-validate(password, user=None)[source]
-

Validates a password string to make sure it meets predefined Evennia -acceptable character policy.

-
-
Parameters
-
    -
  • password (str) – Password to validate

  • -
  • user (None) – Unused argument but required by Django

  • -
-
-
Returns
-

None (None)

-
-
None if password successfully validated,

raises ValidationError otherwise.

-
-
-

-
-
-
- -
-
-get_help_text()[source]
-

Returns a user-facing explanation of the password policy defined -by this validator.

-
-
Returns
-

text (str) – Explanation of password policy.

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.server.webserver.html b/docs/0.9.5/api/evennia.server.webserver.html deleted file mode 100644 index 43143c620b..0000000000 --- a/docs/0.9.5/api/evennia.server.webserver.html +++ /dev/null @@ -1,331 +0,0 @@ - - - - - - - - - evennia.server.webserver — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.server.webserver

-

This implements resources for Twisted webservers using the WSGI -interface of Django. This alleviates the need of running e.g. an -Apache server to serve Evennia’s web presence (although you could do -that too if desired).

-

The actual servers are started inside server.py as part of the Evennia -application.

-

(Lots of thanks to http://github.com/clemesha/twisted-wsgi-django for -a great example/aid on how to do this.)

-
-
-class evennia.server.webserver.LockableThreadPool(*args, **kwargs)[source]
-

Bases: twisted.python.threadpool.ThreadPool

-

Threadpool that can be locked from accepting new requests.

-
-
-__init__(*args, **kwargs)[source]
-

Create a new threadpool.

-

@param minthreads: minimum number of threads in the pool -@type minthreads: L{int}

-

@param maxthreads: maximum number of threads in the pool -@type maxthreads: L{int}

-

@param name: The name to give this threadpool; visible in log messages. -@type name: native L{str}

-
- -
-
-lock()[source]
-
- -
-
-callInThread(func, *args, **kwargs)[source]
-

called in the main reactor thread. Makes sure the pool -is not locked before continuing.

-
- -
- -
-
-class evennia.server.webserver.HTTPChannelWithXForwardedFor[source]
-

Bases: twisted.web.http.HTTPChannel

-

HTTP xforward class

-
-
-allHeadersReceived()[source]
-

Check to see if this is a reverse proxied connection.

-
- -
- -
-
-class evennia.server.webserver.EvenniaReverseProxyResource(host, port, path, reactor=<twisted.internet.epollreactor.EPollReactor object>)[source]
-

Bases: twisted.web.proxy.ReverseProxyResource

-
-
-getChild(path, request)[source]
-

Create and return a proxy resource with the same proxy configuration -as this one, except that its path also contains the segment given by -path at the end.

-
-
Parameters
-
    -
  • path (str) – Url path.

  • -
  • request (Request object) – Incoming request.

  • -
-
-
Returns
-

resource (EvenniaReverseProxyResource) – A proxy resource.

-
-
-
- -
-
-render(request)[source]
-

Render a request by forwarding it to the proxied server.

-
-
Parameters
-

request (Request) – Incoming request.

-
-
Returns
-

not_done (char) – Indicator to note request not yet finished.

-
-
-
- -
- -
-
-class evennia.server.webserver.DjangoWebRoot(pool)[source]
-

Bases: twisted.web.resource.Resource

-

This creates a web root (/) that Django -understands by tweaking the way -child instances are recognized.

-
-
-__init__(pool)[source]
-

Setup the django+twisted resource.

-
-
Parameters
-

pool (ThreadPool) – The twisted threadpool.

-
-
-
- -
-
-empty_threadpool()[source]
-

Converts our _pending_requests list of deferreds into a DeferredList

-
-
Returns
-

deflist (DeferredList) – Contains all deferreds of pending requests.

-
-
-
- -
-
-getChild(path, request)[source]
-

To make things work we nudge the url tree to make this the -root.

-
-
Parameters
-
    -
  • path (str) – Url path.

  • -
  • request (Request object) – Incoming request.

  • -
-
-
-

Notes

-

We make sure to save the request queue so -that we can safely kill the threadpool -on a server reload.

-
- -
- -
-
-class evennia.server.webserver.Website(resource, requestFactory=None, *args, **kwargs)[source]
-

Bases: twisted.web.server.Site

-

This class will only log http requests if settings.DEBUG is True.

-
-
-noisy = False
-
- -
-
-logPrefix()[source]
-

How to be named in logs

-
- -
-
-log(request)[source]
-

Conditional logging

-
- -
- -
-
-class evennia.server.webserver.WSGIWebServer(pool, *args, **kwargs)[source]
-

Bases: twisted.application.internet.TCPServer

-

This is a WSGI webserver. It makes sure to start -the threadpool after the service itself started, -so as to register correctly with the twisted daemon.

-

call with WSGIWebServer(threadpool, port, wsgi_resource)

-
-
-__init__(pool, *args, **kwargs)[source]
-

This just stores the threadpool.

-
-
Parameters
-
    -
  • pool (ThreadPool) – The twisted threadpool.

  • -
  • args (any) – Passed on to the TCPServer.

  • -
  • kwargs (any) – Passed on to the TCPServer.

  • -
-
-
-
- -
-
-startService()[source]
-

Start the pool after the service starts.

-
- -
-
-stopService()[source]
-

Safely stop the pool after the service stops.

-
- -
- -
-
-class evennia.server.webserver.PrivateStaticRoot(path, defaultType='text/html', ignoredExts=(), registry=None, allowExt=0)[source]
-

Bases: twisted.web.static.File

-

This overrides the default static file resource so as to not make the -directory listings public (that is, if you go to /media or /static you -won’t see an index of all static/media files on the server).

-
-
-directoryListing()[source]
-

Return a resource that generates an HTML listing of the -directory this path represents.

-

@return: A resource that renders the directory to HTML. -@rtype: L{DirectoryLister}

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.settings_default.html b/docs/0.9.5/api/evennia.settings_default.html deleted file mode 100644 index d122a8b83d..0000000000 --- a/docs/0.9.5/api/evennia.settings_default.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - - - evennia.settings_default — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.settings_default

-

Master configuration file for Evennia.

-

NOTE: NO MODIFICATIONS SHOULD BE MADE TO THIS FILE!

-

All settings changes should be done by copy-pasting the variable and -its value to <gamedir>/server/conf/settings.py.

-

Hint: Don’t copy&paste over more from this file than you actually want -to change. Anything you don’t copy&paste will thus retain its default -value - which may change as Evennia is developed. This way you can -always be sure of what you have changed and what is default behaviour.

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.typeclasses.admin.html b/docs/0.9.5/api/evennia.typeclasses.admin.html deleted file mode 100644 index d008341604..0000000000 --- a/docs/0.9.5/api/evennia.typeclasses.admin.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.typeclasses.admin — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.typeclasses.admin

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.typeclasses.attributes.html b/docs/0.9.5/api/evennia.typeclasses.attributes.html deleted file mode 100644 index 2b6829eeee..0000000000 --- a/docs/0.9.5/api/evennia.typeclasses.attributes.html +++ /dev/null @@ -1,1541 +0,0 @@ - - - - - - - - - evennia.typeclasses.attributes — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.typeclasses.attributes

-

Attributes are arbitrary data stored on objects. Attributes supports -both pure-string values and pickled arbitrary data.

-

Attributes are also used to implement Nicks. This module also contains -the Attribute- and NickHandlers as well as the NAttributeHandler, -which is a non-db version of Attributes.

-
-
-class evennia.typeclasses.attributes.IAttribute[source]
-

Bases: object

-

Attributes are things that are specific to different types of objects. For -example, a drink container needs to store its fill level, whereas an exit -needs to store its open/closed/locked/unlocked state. These are done via -attributes, rather than making different classes for each object type and -storing them directly. The added benefit is that we can add/remove -attributes on the fly as we like.

-
-
The Attribute class defines the following properties:
    -
  • key (str): Primary identifier.

  • -
  • lock_storage (str): Perm strings.

  • -
  • -
    model (str): A string defining the model this is connected to. This

    is a natural_key, like “objects.objectdb”

    -
    -
    -
  • -
  • date_created (datetime): When the attribute was created.

  • -
  • -
    value (any): The data stored in the attribute, in pickled form

    using wrappers to be able to store/retrieve models.

    -
    -
    -
  • -
  • -
    strvalue (str): String-only data. This data is not pickled and

    is thus faster to search for in the database.

    -
    -
    -
  • -
  • -
    category (str): Optional character string for grouping the

    Attribute.

    -
    -
    -
  • -
-
-
-

This class is an API/Interface/Abstract base class; do not instantiate it directly.

-
-
-locks[source]
-
- -
-
-property key
-
- -
-
-property strvalue
-
- -
-
-property category
-
- -
-
-property model
-
- -
-
-property attrtype
-
- -
-
-property date_created
-
- -
-
-property lock_storage
-
- -
-
-access(accessing_obj, access_type='read', default=False, **kwargs)[source]
-

Determines if another object has permission to access.

-
-
Parameters
-
    -
  • accessing_obj (object) – Entity trying to access this one.

  • -
  • access_type (str, optional) – Type of access sought, see -the lock documentation.

  • -
  • default (bool, optional) – What result to return if no lock -of access_type was found. The default, False, means a lockdown -policy, only allowing explicit access.

  • -
  • kwargs (any, optional) – Not used; here to make the API consistent with -other access calls.

  • -
-
-
Returns
-

result (bool) – If the lock was passed or not.

-
-
-
- -
- -
-
-class evennia.typeclasses.attributes.InMemoryAttribute(pk, **kwargs)[source]
-

Bases: evennia.typeclasses.attributes.IAttribute

-

This Attribute is used purely for NAttributes/NAttributeHandler. It has no database backend.

-
-
-__init__(pk, **kwargs)[source]
-

Create an Attribute that exists only in Memory.

-
-
Parameters
-
    -
  • pk (int) – This is a fake ‘primary key’ / id-field. It doesn’t actually have to be -unique, but is fed an incrementing number from the InMemoryBackend by default. This -is needed only so Attributes can be sorted. Some parts of the API also see the lack -of a .pk field as a sign that the Attribute was deleted.

  • -
  • **kwargs – Other keyword arguments are used to construct the actual Attribute.

  • -
-
-
-
- -
-
-property value
-
- -
- -
-
-class evennia.typeclasses.attributes.AttributeProperty(default=None, category=None, strattr=False, lockstring='', autocreate=False)[source]
-

Bases: object

-

Attribute property descriptor. Allows for specifying Attributes as Django-like ‘fields’ -on the class level. Note that while one can set a lock on the Attribute, -there is no way to check said lock when accessing via the property - use -the full AttributeHandler if you need to do access checks.

-

Example:

-
class Character(DefaultCharacter):
-    foo = AttributeProperty(default="Bar")
-
-
-
-
-attrhandler_name = 'attributes'
-
- -
-
-__init__(default=None, category=None, strattr=False, lockstring='', autocreate=False)[source]
-

Initialize an Attribute as a property descriptor.

-
-
Keyword Arguments
-
    -
  • default (any) – A default value if the attr is not set.

  • -
  • category (str) – The attribute’s category. If unset, use class default.

  • -
  • strattr (bool) – If set, this Attribute must be a simple string, and will be -stored more efficiently.

  • -
  • lockstring (str) – This is not itself useful with the property, but only if -using the full AttributeHandler.get(accessing_obj=…) to access the -Attribute.

  • -
  • autocreate (bool) – If an un-found Attr should lead to auto-creating the -Attribute (with the default value). If False, the property will -return the default value until it has been explicitly set. This means -less database accesses, but also means the property will have no -corresponding Attribute if wanting to access it directly via the -AttributeHandler (it will also not show up in examine).

  • -
-
-
-
- -
- -
-
-class evennia.typeclasses.attributes.NAttributeProperty(default=None, category=None, strattr=False, lockstring='', autocreate=False)[source]
-

Bases: evennia.typeclasses.attributes.AttributeProperty

-

NAttribute property descriptor. Allows for specifying NAttributes as Django-like ‘fields’ -on the class level.

-

Example:

-
class Character(DefaultCharacter):
-    foo = NAttributeProperty(default="Bar")
-
-
-
-
-attrhandler_name = 'nattributes'
-
- -
- -
-
-class evennia.typeclasses.attributes.Attribute(*args, **kwargs)[source]
-

Bases: evennia.typeclasses.attributes.IAttribute, evennia.utils.idmapper.models.SharedMemoryModel

-

This attribute is stored via Django. Most Attributes will be using this class.

-
-
-db_key
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_value
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_strvalue
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_category
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_lock_storage
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_model
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_attrtype
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_date_created
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-property lock_storage
-
- -
-
-property value
-

Getter. Allows for value = self.value. -We cannot cache here since it makes certain cases (such -as storing a dbobj which is then deleted elsewhere) out-of-sync. -The overhead of unpickling seems hard to avoid.

-
- -
-
-exception DoesNotExist
-

Bases: django.core.exceptions.ObjectDoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: django.core.exceptions.MultipleObjectsReturned

-
- -
-
-accountdb_set
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-property attrtype
-

A wrapper for getting database field db_attrtype.

-
- -
-
-property category
-

A wrapper for getting database field db_category.

-
- -
-
-channeldb_set
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-property date_created
-

A wrapper for getting database field db_date_created.

-
- -
-
-get_next_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=True, **kwargs)
-
- -
-
-get_previous_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=False, **kwargs)
-
- -
-
-id
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-property key
-

A wrapper for getting database field db_key.

-
- -
-
-property model
-

A wrapper for getting database field db_model.

-
- -
-
-objectdb_set
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-path = 'evennia.typeclasses.attributes.Attribute'
-
- -
-
-scriptdb_set
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-property strvalue
-

A wrapper for getting database field db_strvalue.

-
- -
-
-typename = 'SharedMemoryModelBase'
-
- -
- -
-
-class evennia.typeclasses.attributes.IAttributeBackend(handler, attrtype)[source]
-

Bases: object

-

Abstract interface for the backends used by the Attribute Handler.

-

All Backends must implement this base class.

-
-
-__init__(handler, attrtype)[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
-
-query_all()[source]
-

Fetch all Attributes from this object.

-
-
Returns
-

attrlist (list) – A list of Attribute objects.

-
-
-
- -
-
-query_key(key, category)[source]
-
-
Parameters
-
    -
  • key (str) – The key of the Attribute being searched for.

  • -
  • category (str or None) – The category of the desired Attribute.

  • -
-
-
Returns
-

attribute (IAttribute) – A single Attribute.

-
-
-
- -
-
-query_category(category)[source]
-

Returns every matching Attribute as a list, given a category.

-

This method calls up whatever storage the backend uses.

-
-
Parameters
-

category (str or None) – The category to query.

-
-
Returns
-

attrs (list) – The discovered Attributes.

-
-
-
- -
-
-get(key=None, category=None)[source]
-

Frontend for .get_cache. Retrieves Attribute(s).

-
-
Parameters
-
    -
  • key (str, optional) – Attribute key to query for

  • -
  • category (str, optional) – Attribiute category

  • -
-
-
Returns
-

args (list)

-
-
Returns a list of zero or more matches

found from cache or database.

-
-
-

-
-
-
- -
-
-reset_cache()[source]
-

Reset cache from the outside.

-
- -
-
-do_create_attribute(key, category, lockstring, value, strvalue)[source]
-

Does the hard work of actually creating Attributes, whatever is needed.

-
-
Parameters
-
    -
  • key (str) – The Attribute’s key.

  • -
  • category (str or None) – The Attribute’s category, or None

  • -
  • lockstring (str) – Any locks for the Attribute.

  • -
  • value (obj) – The Value of the Attribute.

  • -
  • strvalue (bool) – Signifies if this is a strvalue Attribute. Value MUST be a string or -this will lead to Trouble. Ignored for InMemory attributes.

  • -
-
-
Returns
-

attr (IAttribute) – The new Attribute.

-
-
-
- -
-
-create_attribute(key, category, lockstring, value, strvalue=False, cache=True)[source]
-

Creates Attribute (using the class specified for the backend), (optionally) caches it, and -returns it.

-

This MUST actively save the Attribute to whatever database backend is used, AND -call self.set_cache(key, category, new_attrobj)

-
-
Parameters
-
    -
  • key (str) – The Attribute’s key.

  • -
  • category (str or None) – The Attribute’s category, or None

  • -
  • lockstring (str) – Any locks for the Attribute.

  • -
  • value (obj) – The Value of the Attribute.

  • -
  • strvalue (bool) – Signifies if this is a strvalue Attribute. Value MUST be a string or -this will lead to Trouble. Ignored for InMemory attributes.

  • -
  • cache (bool) – Whether to cache the new Attribute

  • -
-
-
Returns
-

attr (IAttribute) – The new Attribute.

-
-
-
- -
-
-do_update_attribute(attr, value)[source]
-

Simply sets a new Value to an Attribute.

-
-
Parameters
-
    -
  • attr (IAttribute) – The Attribute being changed.

  • -
  • value (obj) – The Value for the Attribute.

  • -
-
-
-
- -
-
-do_batch_update_attribute(attr_obj, category, lock_storage, new_value, strvalue)[source]
-

Called opnly by batch add. For the database backend, this is a method -of updating that can alter category and lock-storage.

-
-
Parameters
-
    -
  • attr_obj (IAttribute) – The Attribute being altered.

  • -
  • category (str or None) – The attribute’s (new) category.

  • -
  • lock_storage (str) – The attribute’s new locks.

  • -
  • new_value (obj) – The Attribute’s new value.

  • -
  • strvalue (bool) – Signifies if this is a strvalue Attribute. Value MUST be a string or -this will lead to Trouble. Ignored for InMemory attributes.

  • -
-
-
-
- -
-
-do_batch_finish(attr_objs)[source]
-

Called after batch_add completed. Used for handling database operations -and/or caching complications.

-
-
Parameters
-

attr_objs (list of IAttribute) – The Attributes created/updated thus far.

-
-
-
- -
-
-batch_add(*args, **kwargs)[source]
-

Batch-version of .add(). This is more efficient than repeat-calling -.add when having many Attributes to add.

-
-
Parameters
-

*args (tuple) –

Tuples of varying length representing the -Attribute to add to this object. Supported tuples are

-
    -
  • (key, value)

  • -
  • (key, value, category)

  • -
  • (key, value, category, lockstring)

  • -
  • (key, value, category, lockstring, default_access)

  • -
-

-
-
Raises
-

RuntimeError – If trying to pass a non-iterable as argument.

-
-
-

Notes

-

The indata tuple order matters, so if you want a lockstring but no -category, set the category to None. This method does not have the -ability to check editing permissions and is mainly used internally. -It does not use the normal self.add but applies the Attributes -directly to the database.

-
- -
-
-do_delete_attribute(attr)[source]
-

Does the hard work of actually deleting things.

-
-
Parameters
-

attr (IAttribute) – The attribute to delete.

-
-
-
- -
-
-delete_attribute(attr)[source]
-

Given an Attribute, deletes it. Also remove it from cache.

-
-
Parameters
-

attr (IAttribute) – The attribute to delete.

-
-
-
- -
-
-update_attribute(attr, value)[source]
-

Simply updates an Attribute.

-
-
Parameters
-
    -
  • attr (IAttribute) – The attribute to delete.

  • -
  • value (obj) – The new value.

  • -
-
-
-
- -
-
-do_batch_delete(attribute_list)[source]
-

Given a list of attributes, deletes them all. -The default implementation is fine, but this is overridable since some databases may allow -for a better method.

-
-
Parameters
-

attribute_list (list of IAttribute) –

-
-
-
- -
-
-clear_attributes(category, accessing_obj, default_access)[source]
-

Remove all Attributes on this object.

-
-
Parameters
-
    -
  • category (str, optional) – If given, clear only Attributes -of this category.

  • -
  • accessing_obj (object, optional) – If given, check the -attredit lock on each Attribute before continuing.

  • -
  • default_access (bool, optional) – Use this permission as -fallback if access_obj is given but there is no lock of -type attredit on the Attribute in question.

  • -
-
-
-
- -
-
-get_all_attributes()[source]
-

Simply returns all Attributes of this object, sorted by their IDs.

-
-
Returns
-

attributes (list of IAttribute)

-
-
-
- -
- -
-
-class evennia.typeclasses.attributes.InMemoryAttributeBackend(handler, attrtype)[source]
-

Bases: evennia.typeclasses.attributes.IAttributeBackend

-

This Backend for Attributes stores NOTHING in the database. Everything is kept in memory, and -normally lost on a crash, reload, shared memory flush, etc. It generates IDs for the Attributes -it manages, but these are of little importance beyond sorting and satisfying the caching logic -to know an Attribute hasn’t been deleted out from under the cache’s nose.

-
-
-__init__(handler, attrtype)[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
-
-query_all()[source]
-

Fetch all Attributes from this object.

-
-
Returns
-

attrlist (list) – A list of Attribute objects.

-
-
-
- -
-
-query_key(key, category)[source]
-
-
Parameters
-
    -
  • key (str) – The key of the Attribute being searched for.

  • -
  • category (str or None) – The category of the desired Attribute.

  • -
-
-
Returns
-

attribute (IAttribute) – A single Attribute.

-
-
-
- -
-
-query_category(category)[source]
-

Returns every matching Attribute as a list, given a category.

-

This method calls up whatever storage the backend uses.

-
-
Parameters
-

category (str or None) – The category to query.

-
-
Returns
-

attrs (list) – The discovered Attributes.

-
-
-
- -
-
-do_create_attribute(key, category, lockstring, value, strvalue)[source]
-

See parent class.

-

strvalue has no meaning for InMemory attributes.

-
- -
-
-do_update_attribute(attr, value)[source]
-

Simply sets a new Value to an Attribute.

-
-
Parameters
-
    -
  • attr (IAttribute) – The Attribute being changed.

  • -
  • value (obj) – The Value for the Attribute.

  • -
-
-
-
- -
-
-do_batch_update_attribute(attr_obj, category, lock_storage, new_value, strvalue)[source]
-

No need to bother saving anything. Just set some values.

-
- -
-
-do_batch_finish(attr_objs)[source]
-

Nothing to do here for In-Memory.

-
-
Parameters
-

attr_objs (list of IAttribute) – The Attributes created/updated thus far.

-
-
-
- -
-
-do_delete_attribute(attr)[source]
-

Removes the Attribute from local storage. Once it’s out of the cache, garbage collection -will handle the rest.

-
-
Parameters
-

attr (IAttribute) – The attribute to delete.

-
-
-
- -
- -
-
-class evennia.typeclasses.attributes.ModelAttributeBackend(handler, attrtype)[source]
-

Bases: evennia.typeclasses.attributes.IAttributeBackend

-

Uses Django models for storing Attributes.

-
-
-__init__(handler, attrtype)[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
-
-query_all()[source]
-

Fetch all Attributes from this object.

-
-
Returns
-

attrlist (list) – A list of Attribute objects.

-
-
-
- -
-
-query_key(key, category)[source]
-
-
Parameters
-
    -
  • key (str) – The key of the Attribute being searched for.

  • -
  • category (str or None) – The category of the desired Attribute.

  • -
-
-
Returns
-

attribute (IAttribute) – A single Attribute.

-
-
-
- -
-
-query_category(category)[source]
-

Returns every matching Attribute as a list, given a category.

-

This method calls up whatever storage the backend uses.

-
-
Parameters
-

category (str or None) – The category to query.

-
-
Returns
-

attrs (list) – The discovered Attributes.

-
-
-
- -
-
-do_create_attribute(key, category, lockstring, value, strvalue)[source]
-

Does the hard work of actually creating Attributes, whatever is needed.

-
-
Parameters
-
    -
  • key (str) – The Attribute’s key.

  • -
  • category (str or None) – The Attribute’s category, or None

  • -
  • lockstring (str) – Any locks for the Attribute.

  • -
  • value (obj) – The Value of the Attribute.

  • -
  • strvalue (bool) – Signifies if this is a strvalue Attribute. Value MUST be a string or -this will lead to Trouble. Ignored for InMemory attributes.

  • -
-
-
Returns
-

attr (IAttribute) – The new Attribute.

-
-
-
- -
-
-do_update_attribute(attr, value)[source]
-

Simply sets a new Value to an Attribute.

-
-
Parameters
-
    -
  • attr (IAttribute) – The Attribute being changed.

  • -
  • value (obj) – The Value for the Attribute.

  • -
-
-
-
- -
-
-do_batch_update_attribute(attr_obj, category, lock_storage, new_value, strvalue)[source]
-

Called opnly by batch add. For the database backend, this is a method -of updating that can alter category and lock-storage.

-
-
Parameters
-
    -
  • attr_obj (IAttribute) – The Attribute being altered.

  • -
  • category (str or None) – The attribute’s (new) category.

  • -
  • lock_storage (str) – The attribute’s new locks.

  • -
  • new_value (obj) – The Attribute’s new value.

  • -
  • strvalue (bool) – Signifies if this is a strvalue Attribute. Value MUST be a string or -this will lead to Trouble. Ignored for InMemory attributes.

  • -
-
-
-
- -
-
-do_batch_finish(attr_objs)[source]
-

Called after batch_add completed. Used for handling database operations -and/or caching complications.

-
-
Parameters
-

attr_objs (list of IAttribute) – The Attributes created/updated thus far.

-
-
-
- -
-
-do_delete_attribute(attr)[source]
-

Does the hard work of actually deleting things.

-
-
Parameters
-

attr (IAttribute) – The attribute to delete.

-
-
-
- -
- -
-
-class evennia.typeclasses.attributes.AttributeHandler(obj, backend_class)[source]
-

Bases: object

-

Handler for adding Attributes to the object.

-
-
-__init__(obj, backend_class)[source]
-

Setup the AttributeHandler.

-
-
Parameters
-

obj (TypedObject) – An Account, Object, Channel, ServerSession (not technically a typed -object), etc. backend_class (IAttributeBackend class): The class of the backend to -use.

-
-
-
- -
-
-has(key=None, category=None)[source]
-

Checks if the given Attribute (or list of Attributes) exists on -the object.

-
-
Parameters
-
    -
  • key (str or iterable) – The Attribute key or keys to check for. -If None, search by category.

  • -
  • category (str or None) – Limit the check to Attributes with this -category (note, that None is the default category).

  • -
-
-
Returns
-

has_attribute (bool or list)

-
-
If the Attribute exists on

this object or not. If key was given as an iterable then -the return is a list of booleans.

-
-
-

-
-
-
- -
-
-get(key=None, default=None, category=None, return_obj=False, strattr=False, raise_exception=False, accessing_obj=None, default_access=True, return_list=False)[source]
-

Get the Attribute.

-
-
Parameters
-
    -
  • key (str or list, optional) – the attribute identifier or -multiple attributes to get. if a list of keys, the -method will return a list.

  • -
  • default (any, optional) – The value to return if an -Attribute was not defined. If set, it will be returned in -a one-item list.

  • -
  • category (str, optional) – the category within which to -retrieve attribute(s).

  • -
  • return_obj (bool, optional) – If set, the return is not the value of the -Attribute but the Attribute object itself.

  • -
  • strattr (bool, optional) – Return the strvalue field of -the Attribute rather than the usual value, this is a -string-only value for quick database searches.

  • -
  • raise_exception (bool, optional) – When an Attribute is not -found, the return from this is usually default. If this -is set, an exception is raised instead.

  • -
  • accessing_obj (object, optional) – If set, an attrread -permission lock will be checked before returning each -looked-after Attribute.

  • -
  • default_access (bool, optional) – If no attrread lock is set on -object, this determines if the lock should then be passed or not.

  • -
  • return_list (bool, optional) – Always return a list, also if there is only -one or zero matches found.

  • -
-
-
Returns
-

result (any or list)

-
-
One or more matches for keys and/or

categories. Each match will be the value of the found Attribute(s) -unless return_obj is True, at which point it will be the -attribute object itself or None. If return_list is True, this -will always be a list, regardless of the number of elements.

-
-
-

-
-
Raises
-

AttributeError – If raise_exception is set and no matching Attribute -was found matching key.

-
-
-
- -
-
-add(key, value, category=None, lockstring='', strattr=False, accessing_obj=None, default_access=True)[source]
-

Add attribute to object, with optional lockstring.

-
-
Parameters
-
    -
  • key (str) – An Attribute name to add.

  • -
  • value (any or str) – The value of the Attribute. If -strattr keyword is set, this must be a string.

  • -
  • category (str, optional) – The category for the Attribute. -The default None is the normal category used.

  • -
  • lockstring (str, optional) – A lock string limiting access -to the attribute.

  • -
  • strattr (bool, optional) – Make this a string-only Attribute. -This is only ever useful for optimization purposes.

  • -
  • accessing_obj (object, optional) – An entity to check for -the attrcreate access-type. If not passing, this method -will be exited.

  • -
  • default_access (bool, optional) – What access to grant if -accessing_obj is given but no lock of the type -attrcreate is defined on the Attribute in question.

  • -
-
-
-
- -
-
-batch_add(*args, **kwargs)[source]
-

Batch-version of add(). This is more efficient than -repeat-calling add when having many Attributes to add.

-
-
Parameters
-

*args (tuple) –

Each argument should be a tuples (can be of varying -length) representing the Attribute to add to this object. -Supported tuples are

-
    -
  • (key, value)

  • -
  • (key, value, category)

  • -
  • (key, value, category, lockstring)

  • -
  • (key, value, category, lockstring, default_access)

  • -
-

-
-
Keyword Arguments
-

strattr (bool) – If True, value must be a string. This -will save the value without pickling which is less -flexible but faster to search (not often used except -internally).

-
-
Raises
-

RuntimeError – If trying to pass a non-iterable as argument.

-
-
-

Notes

-

The indata tuple order matters, so if you want a lockstring -but no category, set the category to None. This method -does not have the ability to check editing permissions like -normal .add does, and is mainly used internally. It does not -use the normal self.add but apply the Attributes directly -to the database.

-
- -
-
-remove(key=None, category=None, raise_exception=False, accessing_obj=None, default_access=True)[source]
-

Remove attribute or a list of attributes from object.

-
-
Parameters
-
    -
  • key (str or list, optional) – An Attribute key to remove or a list of keys. If -multiple keys, they must all be of the same category. If None and -category is not given, remove all Attributes.

  • -
  • category (str, optional) – The category within which to -remove the Attribute.

  • -
  • raise_exception (bool, optional) – If set, not finding the -Attribute to delete will raise an exception instead of -just quietly failing.

  • -
  • accessing_obj (object, optional) – An object to check -against the attredit lock. If not given, the check will -be skipped.

  • -
  • default_access (bool, optional) – The fallback access to -grant if accessing_obj is given but there is no -attredit lock set on the Attribute in question.

  • -
-
-
Raises
-

AttributeError – If raise_exception is set and no matching Attribute -was found matching key.

-
-
-

Notes

-

If neither key nor category is given, this acts as clear().

-
- -
-
-clear(category=None, accessing_obj=None, default_access=True)[source]
-

Remove all Attributes on this object.

-
-
Parameters
-
    -
  • category (str, optional) – If given, clear only Attributes -of this category.

  • -
  • accessing_obj (object, optional) – If given, check the -attredit lock on each Attribute before continuing.

  • -
  • default_access (bool, optional) – Use this permission as -fallback if access_obj is given but there is no lock of -type attredit on the Attribute in question.

  • -
-
-
-
- -
-
-all(accessing_obj=None, default_access=True)[source]
-

Return all Attribute objects on this object, regardless of category.

-
-
Parameters
-
    -
  • accessing_obj (object, optional) – Check the attrread -lock on each attribute before returning them. If not -given, this check is skipped.

  • -
  • default_access (bool, optional) – Use this permission as a -fallback if accessing_obj is given but one or more -Attributes has no lock of type attrread defined on them.

  • -
-
-
Returns
-

Attributes (list)

-
-
All the Attribute objects (note: Not

their values!) in the handler.

-
-
-

-
-
-
- -
-
-reset_cache()[source]
-
- -
- -
-
-class evennia.typeclasses.attributes.DbHolder(obj, name, manager_name='attributes')[source]
-

Bases: object

-

Holder for allowing property access of attributes

-
-
-__init__(obj, name, manager_name='attributes')[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
-
-get_all()[source]
-
- -
-
-property all
-
- -
- -
-
-exception evennia.typeclasses.attributes.NickTemplateInvalid[source]
-

Bases: ValueError

-
- -
-
-evennia.typeclasses.attributes.initialize_nick_templates(pattern, replacement, pattern_is_regex=False)[source]
-

Initialize the nick templates for matching and remapping a string.

-
-
Parameters
-
    -
  • pattern (str) – The pattern to be used for nick recognition. This will -be parsed for shell patterns into a regex, unless pattern_is_regex -is True, in which case it must be an already valid regex string. In -this case, instead of $N, numbered arguments must instead be given -as matching groups named as argN, such as (?P<arg1>.+?).

  • -
  • replacement (str) – The template to be used to replace the string -matched by the pattern. This can contain $N markers and is never -parsed into a regex.

  • -
  • pattern_is_regex (bool) – If set, pattern is a full regex string -instead of containing shell patterns.

  • -
-
-
Returns
-

regex, template (str)

-
-
Regex to match against strings and template

with markers **{arg1}, {arg2}**, etc for replacement using the standard -.format method.

-
-
-

-
-
Raises
-
    -
  • evennia.typecalasses.attributes.NickTemplateInvalid – If the in/out

  • -
  • template does not have a matching number of $args.

  • -
-
-
-

Examples

-
    -
  • pattern (shell syntax): “grin $1”

  • -
  • pattern (regex): “grin (?P<arg1.+?>)”

  • -
  • replacement: “emote gives a wicked grin to $1”

  • -
-
- -
-
-evennia.typeclasses.attributes.parse_nick_template(string, template_regex, outtemplate)[source]
-

Parse a text using a template and map it to another template

-
-
Parameters
-
    -
  • string (str) – The input string to process

  • -
  • template_regex (regex) – A template regex created with -initialize_nick_template.

  • -
  • outtemplate (str) – The template to which to map the matches -produced by the template_regex. This should have $1, $2, -etc to match the template-regex. Un-found $N-markers (possible if -the regex has optional matching groups) are replaced with empty -strings.

  • -
-
-
-
- -
-
-class evennia.typeclasses.attributes.NickHandler(*args, **kwargs)[source]
-

Bases: evennia.typeclasses.attributes.AttributeHandler

-

Handles the addition and removal of Nicks. Nicks are special -versions of Attributes with an _attrtype hardcoded to nick. -They also always use the strvalue fields for their data.

-
-
-__init__(*args, **kwargs)[source]
-

Setup the AttributeHandler.

-
-
Parameters
-

obj (TypedObject) – An Account, Object, Channel, ServerSession (not technically a typed -object), etc. backend_class (IAttributeBackend class): The class of the backend to -use.

-
-
-
- -
-
-has(key, category='inputline')[source]
-
-
Parameters
-
    -
  • key (str or iterable) – The Nick key or keys to check for.

  • -
  • category (str) – Limit the check to Nicks with this -category (note, that None is the default category).

  • -
-
-
Returns
-

has_nick (bool or list)

-
-
If the Nick exists on this object

or not. If key was given as an iterable then the return -is a list of booleans.

-
-
-

-
-
-
- -
-
-get(key=None, category='inputline', return_tuple=False, **kwargs)[source]
-

Get the replacement value matching the given key and category

-
-
Parameters
-
    -
  • key (str or list, optional) – the attribute identifier or -multiple attributes to get. if a list of keys, the -method will return a list.

  • -
  • category (str, optional) – the category within which to -retrieve the nick. The “inputline” means replacing data -sent by the user.

  • -
  • return_tuple (bool, optional) – return the full nick tuple rather -than just the replacement. For non-template nicks this is just -a string.

  • -
  • kwargs (any, optional) – These are passed on to AttributeHandler.get.

  • -
-
-
Returns
-

str or tuple – The nick replacement string or nick tuple.

-
-
-
- -
-
-add(pattern, replacement, category='inputline', pattern_is_regex=False, **kwargs)[source]
-

Add a new nick, a mapping pattern -> replacement.

-
-
Parameters
-
    -
  • pattern (str) – A pattern to match for. This will be parsed for -shell patterns using the fnmatch library and can contain -$N-markers to indicate the locations of arguments to catch. If -pattern_is_regex=True, this must instead be a valid regular -expression and the $N-markers must be named argN that matches -numbered regex groups (see examples).

  • -
  • replacement (str) – The string (or template) to replace key with -(the “nickname”). This may contain $N markers to indicate where to -place the argument-matches

  • -
  • category (str, optional) – the category within which to -retrieve the nick. The “inputline” means replacing data -sent by the user.

  • -
  • pattern_is_regex (bool) – If True, the pattern will be parsed as a -raw regex string. Instead of using $N markers in this string, one -then must mark numbered arguments as a named regex-groupd named argN. -For example, (?P<arg1>.+?) will match the behavior of using $1 -in the shell pattern.

  • -
  • **kwargs (any, optional) – These are passed on to AttributeHandler.get.

  • -
-
-
-

Notes

-

For most cases, the shell-pattern is much shorter and easier. The -regex pattern form can be useful for more complex matchings though, -for example in order to add optional arguments, such as with -(?P<argN>.*?).

-

Example

-
    -
  • pattern (default shell syntax): “gr $1 at $2”

  • -
  • pattern (with pattern_is_regex=True): r”gr (?P<arg1>.+?) at (?P<arg2>.+?)”

  • -
  • replacement: “emote With a flourish, $1 grins at $2.”

  • -
-
- -
-
-remove(key, category='inputline', **kwargs)[source]
-

Remove Nick with matching category.

-
-
Parameters
-
    -
  • key (str) – A key for the nick to match for.

  • -
  • category (str, optional) – the category within which to -removethe nick. The “inputline” means replacing data -sent by the user.

  • -
  • kwargs (any, optional) – These are passed on to AttributeHandler.get.

  • -
-
-
-
- -
-
-nickreplace(raw_string, categories='inputline', 'channel', include_account=True)[source]
-

Apply nick replacement of entries in raw_string with nick replacement.

-
-
Parameters
-
    -
  • raw_string (str) – The string in which to perform nick -replacement.

  • -
  • categories (tuple, optional) – Replacement categories in -which to perform the replacement, such as “inputline”, -“channel” etc.

  • -
  • include_account (bool, optional) – Also include replacement -with nicks stored on the Account level.

  • -
  • kwargs (any, optional) – Not used.

  • -
-
-
Returns
-

string (str)

-
-
A string with matching keys replaced with

their nick equivalents.

-
-
-

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.typeclasses.html b/docs/0.9.5/api/evennia.typeclasses.html deleted file mode 100644 index 1963a324c3..0000000000 --- a/docs/0.9.5/api/evennia.typeclasses.html +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - evennia.typeclasses — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.typeclasses

-

This sub-package defines the typeclass-system, a way to wrap database -access into almost-normal Python classes. Using typeclasses one can -work in normal Python while having the luxury of persistent data -storage at every turn. ObjectDB, ChannelDB, AccountDB and ScriptDB all -inherit from the models in this package. Here is also were the -Attribute and Tag models are defined along with their handlers.

- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.typeclasses.managers.html b/docs/0.9.5/api/evennia.typeclasses.managers.html deleted file mode 100644 index 00e3b966be..0000000000 --- a/docs/0.9.5/api/evennia.typeclasses.managers.html +++ /dev/null @@ -1,518 +0,0 @@ - - - - - - - - - evennia.typeclasses.managers — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.typeclasses.managers

-

This implements the common managers that are used by the -abstract models in dbobjects.py (and which are thus shared by -all Attributes and TypedObjects).

-
-
-class evennia.typeclasses.managers.TypedObjectManager(*args, **kwargs)[source]
-

Bases: evennia.utils.idmapper.manager.SharedMemoryManager

-

Common ObjectManager for all dbobjects.

-
-
-get_attribute(key=None, category=None, value=None, strvalue=None, obj=None, attrtype=None, **kwargs)[source]
-

Return Attribute objects by key, by category, by value, by strvalue, by -object (it is stored on) or with a combination of those criteria.

-
-
Parameters
-
    -
  • key (str, optional) – The attribute’s key to search for

  • -
  • category (str, optional) – The category of the attribute(s) to search for.

  • -
  • value (str, optional) – The attribute value to search for. -Note that this is not a very efficient operation since it -will query for a pickled entity. Mutually exclusive to -strvalue.

  • -
  • strvalue (str, optional) – The str-value to search for. -Most Attributes will not have strvalue set. This is -mutually exclusive to the value keyword and will take -precedence if given.

  • -
  • obj (Object, optional) – On which object the Attribute to -search for is.

  • -
  • attrype (str, optional) – An attribute-type to search for. -By default this is either None (normal Attributes) or -“nick”.

  • -
  • **kwargs (any) – Currently unused. Reserved for future use.

  • -
-
-
Returns
-

list – The matching Attributes.

-
-
-
- -
-
-get_nick(key=None, category=None, value=None, strvalue=None, obj=None)[source]
-

Get a nick, in parallel to get_attribute.

-
-
Parameters
-
    -
  • key (str, optional) – The nicks’s key to search for

  • -
  • category (str, optional) – The category of the nicks(s) to search for.

  • -
  • value (str, optional) – The attribute value to search for. Note that this -is not a very efficient operation since it will query for a pickled -entity. Mutually exclusive to strvalue.

  • -
  • strvalue (str, optional) – The str-value to search for. Most Attributes -will not have strvalue set. This is mutually exclusive to the value -keyword and will take precedence if given.

  • -
  • obj (Object, optional) – On which object the Attribute to search for is.

  • -
-
-
Returns
-

nicks (list) – The matching Nicks.

-
-
-
- -
-
-get_by_attribute(key=None, category=None, value=None, strvalue=None, attrtype=None, **kwargs)[source]
-

Return objects having attributes with the given key, category, -value, strvalue or combination of those criteria.

-
-
Parameters
-
    -
  • key (str, optional) – The attribute’s key to search for

  • -
  • category (str, optional) – The category of the attribute -to search for.

  • -
  • value (str, optional) – The attribute value to search for. -Note that this is not a very efficient operation since it -will query for a pickled entity. Mutually exclusive to -strvalue.

  • -
  • strvalue (str, optional) – The str-value to search for. -Most Attributes will not have strvalue set. This is -mutually exclusive to the value keyword and will take -precedence if given.

  • -
  • attrype (str, optional) – An attribute-type to search for. -By default this is either None (normal Attributes) or -“nick”.

  • -
  • kwargs (any) – Currently unused. Reserved for future use.

  • -
-
-
Returns
-

obj (list) – Objects having the matching Attributes.

-
-
-
- -
-
-get_by_nick(key=None, nick=None, category='inputline')[source]
-

Get object based on its key or nick.

-
-
Parameters
-
    -
  • key (str, optional) – The attribute’s key to search for

  • -
  • nick (str, optional) – The nickname to search for

  • -
  • category (str, optional) – The category of the nick -to search for.

  • -
-
-
Returns
-

obj (list) – Objects having the matching Nicks.

-
-
-
- -
-
-get_tag(key=None, category=None, obj=None, tagtype=None, global_search=False)[source]
-

Return Tag objects by key, by category, by object (it is -stored on) or with a combination of those criteria.

-
-
Parameters
-
    -
  • key (str, optional) – The Tag’s key to search for

  • -
  • category (str, optional) – The Tag of the attribute(s) -to search for.

  • -
  • obj (Object, optional) – On which object the Tag to -search for is.

  • -
  • tagtype (str, optional) – One of None (normal tags), -“alias” or “permission”

  • -
  • global_search (bool, optional) – Include all possible tags, -not just tags on this object

  • -
-
-
Returns
-

tag (list) – The matching Tags.

-
-
-
- -
-
-get_permission(key=None, category=None, obj=None)[source]
-

Get a permission from the database.

-
-
Parameters
-
    -
  • key (str, optional) – The permission’s identifier.

  • -
  • category (str, optional) – The permission’s category.

  • -
  • obj (object, optional) – The object on which this Tag is set.

  • -
-
-
Returns
-

permission (list) – Permission objects.

-
-
-
- -
-
-get_alias(key=None, category=None, obj=None)[source]
-

Get an alias from the database.

-
-
Parameters
-
    -
  • key (str, optional) – The permission’s identifier.

  • -
  • category (str, optional) – The permission’s category.

  • -
  • obj (object, optional) – The object on which this Tag is set.

  • -
-
-
Returns
-

alias (list) – Alias objects.

-
-
-
- -
-
-get_by_tag(key=None, category=None, tagtype=None, **kwargs)[source]
-

Return objects having tags with a given key or category or combination of the two. -Also accepts multiple tags/category/tagtype

-
-
Parameters
-
    -
  • key (str or list, optional) – Tag key or list of keys. Not case sensitive.

  • -
  • category (str or list, optional) – Tag category. Not case sensitive. -If key is a list, a single category can either apply to all -keys in that list or this must be a list matching the key -list element by element. If no key is given, all objects with -tags of this category are returned.

  • -
  • tagtype (str, optional) – ‘type’ of Tag, by default -this is either None (a normal Tag), alias or -permission. This always apply to all queried tags.

  • -
-
-
Keyword Arguments
-

match (str) – “all” (default) or “any”; determines whether the -target object must be tagged with ALL of the provided -tags/categories or ANY single one. ANY will perform a weighted -sort, so objects with more tag matches will outrank those with -fewer tag matches.

-
-
Returns
-

objects (list) – Objects with matching tag.

-
-
Raises
-

IndexError – If key and category are both lists and category is shorter -than key.

-
-
-
- -
-
-get_by_permission(key=None, category=None)[source]
-

Return objects having permissions with a given key or category or -combination of the two.

-
-
Parameters
-
    -
  • key (str, optional) – Permissions key. Not case sensitive.

  • -
  • category (str, optional) – Permission category. Not case sensitive.

  • -
-
-
Returns
-

objects (list) – Objects with matching permission.

-
-
-
- -
-
-get_by_alias(key=None, category=None)[source]
-

Return objects having aliases with a given key or category or -combination of the two.

-
-
Parameters
-
    -
  • key (str, optional) – Alias key. Not case sensitive.

  • -
  • category (str, optional) – Alias category. Not case sensitive.

  • -
-
-
Returns
-

objects (list) – Objects with matching alias.

-
-
-
- -
-
-create_tag(key=None, category=None, data=None, tagtype=None)[source]
-

Create a new Tag of the base type associated with this -object. This makes sure to create case-insensitive tags. -If the exact same tag configuration (key+category+tagtype+dbmodel) -exists on the model, a new tag will not be created, but an old -one returned.

-
-
Parameters
-
    -
  • key (str, optional) – Tag key. Not case sensitive.

  • -
  • category (str, optional) – Tag category. Not case sensitive.

  • -
  • data (str, optional) – Extra information about the tag.

  • -
  • tagtype (str or None, optional) – ‘type’ of Tag, by default -this is either None (a normal Tag), alias or -permission.

  • -
-
-
-

Notes

-

The data field is not part of the uniqueness of the tag: -Setting data on an existing tag will overwrite the old -data field. It is intended only as a way to carry -information about the tag (like a help text), not to carry -any information about the tagged objects themselves.

-
- -
-
-dbref(dbref, reqhash=True)[source]
-

Determing if input is a valid dbref.

-
-
Parameters
-
    -
  • dbref (str or int) – A possible dbref.

  • -
  • reqhash (bool, optional) – If the “#” is required for this -to be considered a valid hash.

  • -
-
-
Returns
-

dbref (int or None) – The integer part of the dbref.

-
-
-

Notes

-

Valid forms of dbref (database reference number) are -either a string ‘#N’ or an integer N.

-
- -
-
-get_id(dbref)[source]
-

Find object with given dbref.

-
-
Parameters
-

dbref (str or int) – The id to search for.

-
-
Returns
-

object (TypedObject) – The matched object.

-
-
-
- -
- -

Alias to get_id.

-
-
Parameters
-

dbref (str or int) – The id to search for.

-
-
Returns
-

Queryset – Queryset with 0 or 1 match.

-
-
-
- -
-
-get_dbref_range(min_dbref=None, max_dbref=None)[source]
-

Get objects within a certain range of dbrefs.

-
-
Parameters
-
    -
  • min_dbref (int) – Start of dbref range.

  • -
  • max_dbref (int) – End of dbref range (inclusive)

  • -
-
-
Returns
-

objects (list)

-
-
TypedObjects with dbrefs within

the given dbref ranges.

-
-
-

-
-
-
- -
-
-get_typeclass_totals(*args, **kwargs) → object[source]
-

Returns a queryset of typeclass composition statistics.

-
-
Returns
-

qs (Queryset)

-
-
A queryset of dicts containing the typeclass (name),

the count of objects with that typeclass and a float representing -the percentage of objects associated with the typeclass.

-
-
-

-
-
-
- -
-
-object_totals()[source]
-

Get info about database statistics.

-
-
Returns
-

census (dict)

-
-
A dictionary {typeclass_path: number, …} with

all the typeclasses active in-game as well as the number -of such objects defined (i.e. the number of database -object having that typeclass set on themselves).

-
-
-

-
-
-
- -
- -

Searches through all objects returning those which has a -certain typeclass. If location is set, limit search to objects -in that location.

-
-
Parameters
-
    -
  • typeclass (str or class) – A typeclass class or a python path to a typeclass.

  • -
  • include_children (bool, optional) – Return objects with -given typeclass and all children inheriting from this -typeclass. Mutuall exclusive to include_parents.

  • -
  • include_parents (bool, optional) – Return objects with -given typeclass and all parents to this typeclass. -Mutually exclusive to include_children.

  • -
-
-
Returns
-

objects (list) – The objects found with the given typeclasses.

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.typeclasses.models.html b/docs/0.9.5/api/evennia.typeclasses.models.html deleted file mode 100644 index 214c157fe9..0000000000 --- a/docs/0.9.5/api/evennia.typeclasses.models.html +++ /dev/null @@ -1,797 +0,0 @@ - - - - - - - - - evennia.typeclasses.models — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.typeclasses.models

-

This is the abstract django models for many of the database objects -in Evennia. A django abstract (obs, not the same as a Python metaclass!) is -a model which is not actually created in the database, but which only exists -for other models to inherit from, to avoid code duplication. Any model can -import and inherit from these classes.

-

Attributes are database objects stored on other objects. The implementing -class needs to supply a ForeignKey field attr_object pointing to the kind -of object being mapped. Attributes storing iterables actually store special -types of iterables named PackedList/PackedDict respectively. These make -sure to save changes to them to database - this is criticial in order to -allow for obj.db.mylist[2] = data. Also, all dbobjects are saved as -dbrefs but are also aggressively cached.

-

TypedObjects are objects ‘decorated’ with a typeclass - that is, the typeclass -(which is a normal Python class implementing some special tricks with its -get/set attribute methods, allows for the creation of all sorts of different -objects all with the same database object underneath. Usually attributes are -used to permanently store things not hard-coded as field on the database object. -The admin should usually not have to deal directly with the database object -layer.

-

This module also contains the Managers for the respective models; inherit from -these to create custom managers.

-
-
-class evennia.typeclasses.models.TypedObject(*args, **kwargs)[source]
-

Bases: evennia.utils.idmapper.models.SharedMemoryModel

-

Abstract Django model.

-

This is the basis for a typed object. It also contains all the -mechanics for managing connected attributes.

-

The TypedObject has the following properties:

-
    -
  • key - main name

  • -
  • name - alias for key

  • -
  • typeclass_path - the path to the decorating typeclass

  • -
  • typeclass - auto-linked typeclass

  • -
  • date_created - time stamp of object creation

  • -
  • permissions - perm strings

  • -
  • dbref - #id of object

  • -
  • db - persistent attribute storage

  • -
  • ndb - non-persistent attribute storage

  • -
-
-
-db_key
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_typeclass_path
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_date_created
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_lock_storage
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_attributes
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-db_tags
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-objects
-
- -
-
-set_class_from_typeclass(typeclass_path=None)[source]
-
- -
-
-__init__(*args, **kwargs)[source]
-

The __init__ method of typeclasses is the core operational -code of the typeclass system, where it dynamically re-applies -a class based on the db_typeclass_path database field rather -than use the one in the model.

-
-
Parameters
-

through to parent. (Passed) –

-
-
Keyword Arguments
-

through to parent. (Passed) –

-
-
-

Notes

-

The loading mechanism will attempt the following steps:

-
    -
  1. Attempt to load typeclass given on command line

  2. -
  3. Attempt to load typeclass stored in db_typeclass_path

  4. -
  5. Attempt to load __settingsclasspath__, which is by the -default classes defined to be the respective user-set -base typeclass settings, like BASE_OBJECT_TYPECLASS.

  6. -
  7. Attempt to load __defaultclasspath__, which is the -base classes in the library, like DefaultObject etc.

  8. -
  9. If everything else fails, use the database model.

  10. -
-

Normal operation is to load successfully at either step 1 -or 2 depending on how the class was called. Tracebacks -will be logged for every step the loader must take beyond -2.

-
- -
-
-attributes[source]
-
- -
-
-locks[source]
-
- -
-
-tags[source]
-
- -
-
-aliases[source]
-
- -
-
-permissions[source]
-
- -
-
-nattributes[source]
-
- -
-
-class Meta[source]
-

Bases: object

-

Django setup info.

-
-
-abstract = False
-
- -
-
-verbose_name = 'Evennia Database Object'
-
- -
-
-ordering = ['-db_date_created', 'id', 'db_typeclass_path', 'db_key']
-
- -
- -
-
-property name
-
- -
-
-property key
-
- -
-
-property dbid
-

Caches and returns the unique id of the object. -Use this instead of self.id, which is not cached.

-
- -
-
-property dbref
-

Returns the object’s dbref on the form #NN.

-
- -
-
-at_idmapper_flush()[source]
-

This is called when the idmapper cache is flushed and -allows customized actions when this happens.

-
-
Returns
-

do_flush (bool)

-
-
If True, flush this object as normal. If

False, don’t flush and expect this object to handle -the flushing on its own.

-
-
-

-
-
-

Notes

-

The default implementation relies on being able to clear -Django’s Foreignkey cache on objects not affected by the -flush (notably objects with an NAttribute stored). We rely -on this cache being stored on the format “_<fieldname>_cache”. -If Django were to change this name internally, we need to -update here (unlikely, but marking just in case).

-
- -
-
-classmethod search(query, **kwargs)[source]
-

Overridden by class children. This implements a common API.

-
-
Parameters
-
    -
  • query (str) – A search query.

  • -
  • **kwargs – Other search parameters.

  • -
-
-
Returns
-

list – A list of 0, 1 or more matches, only of this typeclass.

-
-
-
- -
-
-is_typeclass(typeclass, exact=False)[source]
-

Returns true if this object has this type OR has a typeclass -which is an subclass of the given typeclass. This operates on -the actually loaded typeclass (this is important since a -failing typeclass may instead have its default currently -loaded) typeclass - can be a class object or the python path -to such an object to match against.

-
-
Parameters
-
    -
  • typeclass (str or class) – A class or the full python path -to the class to check.

  • -
  • exact (bool, optional) – Returns true only if the object’s -type is exactly this typeclass, ignoring parents.

  • -
-
-
Returns
-

is_typeclass (bool)

-
-
If this typeclass matches the given

typeclass.

-
-
-

-
-
-
- -
-
-swap_typeclass(new_typeclass, clean_attributes=False, run_start_hooks='all', no_default=True, clean_cmdsets=False)[source]
-

This performs an in-situ swap of the typeclass. This means -that in-game, this object will suddenly be something else. -Account will not be affected. To ‘move’ an account to a different -object entirely (while retaining this object’s type), use -self.account.swap_object().

-

Note that this might be an error prone operation if the -old/new typeclass was heavily customized - your code -might expect one and not the other, so be careful to -bug test your code if using this feature! Often its easiest -to create a new object and just swap the account over to -that one instead.

-
-
Parameters
-
    -
  • new_typeclass (str or classobj) – Type to switch to.

  • -
  • clean_attributes (bool or list, optional) – Will delete all -attributes stored on this object (but not any of the -database fields such as name or location). You can’t get -attributes back, but this is often the safest bet to make -sure nothing in the new typeclass clashes with the old -one. If you supply a list, only those named attributes -will be cleared.

  • -
  • run_start_hooks (str or None, optional) – This is either None, -to not run any hooks, “all” to run all hooks defined by -at_first_start, or a string with space-separated hook-names to run -(for example ‘at_object_creation’). This will -always be called without arguments.

  • -
  • no_default (bool, optiona) – If set, the swapper will not -allow for swapping to a default typeclass in case the -given one fails for some reason. Instead the old one will -be preserved.

  • -
  • clean_cmdsets (bool, optional) – Delete all cmdsets on the object.

  • -
-
-
-
- -
-
-access(accessing_obj, access_type='read', default=False, no_superuser_bypass=False, **kwargs)[source]
-

Determines if another object has permission to access this one.

-
-
Parameters
-
    -
  • accessing_obj (str) – Object trying to access this one.

  • -
  • access_type (str, optional) – Type of access sought.

  • -
  • default (bool, optional) – What to return if no lock of -access_type was found

  • -
  • no_superuser_bypass (bool, optional) – Turn off the -superuser lock bypass (be careful with this one).

  • -
-
-
Keyword Arguments
-

kwar (any) – Ignored, but is there to make the api -consistent with the object-typeclass method access, which -use it to feed to its hook methods.

-
-
-
- -
-
-check_permstring(permstring)[source]
-

This explicitly checks if we hold particular permission -without involving any locks.

-
-
Parameters
-

permstring (str) – The permission string to check against.

-
-
Returns
-

result (bool) – If the permstring is passed or not.

-
-
-
- -
-
-delete()[source]
-

Cleaning up handlers on the typeclass level

-
- -
-
-property db
-

Attribute handler wrapper. Allows for the syntax

-
obj.db.attrname = value
-# and
-value = obj.db.attrname
-# and
-del obj.db.attrname
-# and
-all_attr = obj.db.all()
-# (unless there is an attribute
-#  named 'all', in which case that will be returned instead).
-
-
-
- -
-
-property ndb
-

NonDataBase). Everything stored -to this is guaranteed to be cleared when a server is shutdown. -Syntax is same as for the _get_db_holder() method and -property, e.g. obj.ndb.attr = value etc.

-
-
Type
-

A non-attr_obj store (ndb

-
-
-
- -
-
-get_display_name(looker, **kwargs)[source]
-

Displays the name of the object in a viewer-aware manner.

-
-
Parameters
-

looker (TypedObject, optional) – The object or account that is looking -at/getting inforamtion for this object. If not given, some -‘safe’ minimum level should be returned.

-
-
Returns
-

name (str)

-
-
A string containing the name of the object,

including the DBREF if this user is privileged to control -said object.

-
-
-

-
-
-

Notes

-

This function could be extended to change how object names -appear to users in character, but be wary. This function -does not change an object’s keys or aliases when -searching, and is expected to produce something useful for -builders.

-
- -
-
-get_extra_info(looker, **kwargs)[source]
-

Used when an object is in a list of ambiguous objects as an -additional information tag.

-

For instance, if you had potions which could have varying -levels of liquid left in them, you might want to display how -many drinks are left in each when selecting which to drop, but -not in your normal inventory listing.

-
-
Parameters
-

looker (TypedObject) – The object or account that is looking -at/getting information for this object.

-
-
Returns
-

info (str)

-
-
A string with disambiguating information,

conventionally with a leading space.

-
-
-

-
-
-
- -
-
-at_rename(oldname, newname)[source]
-

This Hook is called by @name on a successful rename.

-
-
Parameters
-
    -
  • oldname (str) – The instance’s original name.

  • -
  • newname (str) – The new name for the instance.

  • -
-
-
-
- -
-
-web_get_admin_url()[source]
-

Returns the URI path for the Django Admin page for this object.

-

ex. Account#1 = ‘/admin/accounts/accountdb/1/change/’

-
-
Returns
-

path (str) – URI path to Django Admin page for object.

-
-
-
- -
-
-classmethod web_get_create_url()[source]
-

Returns the URI path for a View that allows users to create new -instances of this object.

-

ex. Chargen = ‘/characters/create/’

-

For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-create’ would be referenced by this method.

-

ex. -url(r’characters/create/’, ChargenView.as_view(), name=’character-create’)

-

If no View has been created and defined in urls.py, returns an -HTML anchor.

-

This method is naive and simply returns a path. Securing access to -the actual view and limiting who can create new objects is the -developer’s responsibility.

-
-
Returns
-

path (str) – URI path to object creation page, if defined.

-
-
-
- -
-
-property date_created
-

A wrapper for getting database field db_date_created.

-
- -
-
-get_next_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=True, **kwargs)
-
- -
-
-get_previous_by_db_date_created(*, field=<django.db.models.fields.DateTimeField: db_date_created>, is_next=False, **kwargs)
-
- -
-
-property lock_storage
-

A wrapper for getting database field db_lock_storage.

-
- -
-
-path = 'evennia.typeclasses.models.TypedObject'
-
- -
-
-property typeclass_path
-

A wrapper for getting database field db_typeclass_path.

-
- -
-
-typename = 'SharedMemoryModelBase'
-
- -
-
-web_get_detail_url()[source]
-

Returns the URI path for a View that allows users to view details for -this object.

-
-
Returns
-

path (str) – URI path to object detail page, if defined.

-
-
-

Examples

-
Oscar (Character) = '/characters/oscar/1/'
-
-
-

For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-detail’ would be referenced by this method.

-
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$',
-    CharDetailView.as_view(), name='character-detail')
-
-
-

If no View has been created and defined in urls.py, returns an -HTML anchor.

-

This method is naive and simply returns a path. Securing access to -the actual view and limiting who can view this object is the -developer’s responsibility.

-
- -
-
-web_get_puppet_url()[source]
-

Returns the URI path for a View that allows users to puppet a specific -object.

-
-
Returns
-

str – URI path to object puppet page, if defined.

-
-
-

Examples

-
Oscar (Character) = '/characters/oscar/1/puppet/'
-
-
-

For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-puppet’ would be referenced by this method.

-
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/puppet/$',
-    CharPuppetView.as_view(), name='character-puppet')
-
-
-

If no View has been created and defined in urls.py, returns an -HTML anchor.

-

This method is naive and simply returns a path. Securing access to -the actual view and limiting who can view this object is the developer’s -responsibility.

-
- -
-
-web_get_update_url()[source]
-

Returns the URI path for a View that allows users to update this -object.

-
-
Returns
-

str – URI path to object update page, if defined.

-
-
-

Examples

-
Oscar (Character) = '/characters/oscar/1/change/'
-
-
-

For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-update’ would be referenced by this method.

-
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/change/$',
-CharUpdateView.as_view(), name='character-update')
-
-
-

If no View has been created and defined in urls.py, returns an -HTML anchor.

-

This method is naive and simply returns a path. Securing access to -the actual view and limiting who can modify objects is the developer’s -responsibility.

-
- -
-
-web_get_delete_url()[source]
-

Returns the URI path for a View that allows users to delete this object.

-
-
Returns
-

path (str) – URI path to object deletion page, if defined.

-
-
-

Examples

-
Oscar (Character) = '/characters/oscar/1/delete/'
-
-
-

For this to work, the developer must have defined a named view -somewhere in urls.py that follows the format ‘modelname-action’, so -in this case a named view of ‘character-detail’ would be referenced -by this method.

-
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/delete/$',
-CharDeleteView.as_view(), name='character-delete')
-
-
-

If no View has been created and defined in urls.py, returns an HTML -anchor.

-

This method is naive and simply returns a path. Securing access to -the actual view and limiting who can delete this object is the -developer’s responsibility.

-
- -
-
-get_absolute_url()
-

Returns the URI path for a View that allows users to view details for -this object.

-
-
Returns
-

path (str) – URI path to object detail page, if defined.

-
-
-

Examples

-
Oscar (Character) = '/characters/oscar/1/'
-
-
-

For this to work, the developer must have defined a named view somewhere -in urls.py that follows the format ‘modelname-action’, so in this case -a named view of ‘character-detail’ would be referenced by this method.

-
url(r'characters/(?P<slug>[\w\d\-]+)/(?P<pk>[0-9]+)/$',
-    CharDetailView.as_view(), name='character-detail')
-
-
-

If no View has been created and defined in urls.py, returns an -HTML anchor.

-

This method is naive and simply returns a path. Securing access to -the actual view and limiting who can view this object is the -developer’s responsibility.

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.typeclasses.tags.html b/docs/0.9.5/api/evennia.typeclasses.tags.html deleted file mode 100644 index 94d148edcc..0000000000 --- a/docs/0.9.5/api/evennia.typeclasses.tags.html +++ /dev/null @@ -1,536 +0,0 @@ - - - - - - - - - evennia.typeclasses.tags — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.typeclasses.tags

-

Tags are entities that are attached to objects in the same way as -Attributes. But contrary to Attributes, which are unique to an -individual object, a single Tag can be attached to any number of -objects at the same time.

-

Tags are used for tagging, obviously, but the data structure is also -used for storing Aliases and Permissions. This module contains the -respective handlers.

-
-
-class evennia.typeclasses.tags.Tag(*args, **kwargs)[source]
-

Bases: django.db.models.base.Model

-

Tags are quick markers for objects in-game. An typeobject can have -any number of tags, stored via its db_tags property. Tagging -similar objects will make it easier to quickly locate the group -later (such as when implementing zones). The main advantage of -tagging as opposed to using tags is speed; a tag is very -limited in what data it can hold, and the tag key+category is -indexed for efficient lookup in the database. Tags are shared -between objects - a new tag is only created if the key+category -combination did not previously exist, making them unsuitable for -storing object-related data (for this a regular Attribute should be -used).

-

The ‘db_data’ field is intended as a documentation field for the -tag itself, such as to document what this tag+category stands for -and display that in a web interface or similar.

-

The main default use for Tags is to implement Aliases for objects. -this uses the ‘aliases’ tag category, which is also checked by the -default search functions of Evennia to allow quick searches by alias.

-
-
-db_key
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_category
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_data
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_model
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-db_tagtype
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-exception DoesNotExist
-

Bases: django.core.exceptions.ObjectDoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: django.core.exceptions.MultipleObjectsReturned

-
- -
-
-accountdb_set
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-channeldb_set
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-helpentry_set
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-id
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-msg_set
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-objectdb_set
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-objects = <django.db.models.manager.Manager object>
-
- -
-
-scriptdb_set
-

Accessor to the related objects manager on the forward and reverse sides of -a many-to-many relation.

-

In the example:

-
class Pizza(Model):
-    toppings = ManyToManyField(Topping, related_name='pizzas')
-
-
-

**Pizza.toppings** and **Topping.pizzas** are **ManyToManyDescriptor** -instances.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
- -
-
-class evennia.typeclasses.tags.TagHandler(obj)[source]
-

Bases: object

-

Generic tag-handler. Accessed via TypedObject.tags.

-
-
-__init__(obj)[source]
-

Tags are stored internally in the TypedObject.db_tags m2m -field with an tag.db_model based on the obj the taghandler is -stored on and with a tagtype given by self.handlertype

-
-
Parameters
-

obj (object) – The object on which the handler is set.

-
-
-
- -
-
-reset_cache()[source]
-

Reset the cache from the outside.

-
- -
-
-add(key=None, category=None, data=None)[source]
-

Add a new tag to the handler.

-
-
Parameters
-
    -
  • key (str or list) – The name of the tag to add. If a list, -add several Tags.

  • -
  • category (str, optional) – Category of Tag. None is the default category.

  • -
  • data (str, optional) – Info text about the tag(s) added. -This can not be used to store object-unique info but only -eventual info about the tag itself.

  • -
-
-
-

Notes

-

If the tag + category combination matches an already -existing Tag object, this will be re-used and no new Tag -will be created.

-
- -
-
-has(key=None, category=None, return_list=False)[source]
-

Checks if the given Tag (or list of Tags) exists on the object.

-
-
Parameters
-
    -
  • key (str or iterable) – The Tag key or tags to check for. -If None, search by category.

  • -
  • category (str, optional) – Limit the check to Tags with this -category (note, that None is the default category).

  • -
-
-
Returns
-

has_tag (bool or list)

-
-
If the Tag exists on this object or not.

If tag was given as an iterable then the return is a list of booleans.

-
-
-

-
-
Raises
-

ValueError – If neither tag nor category is given.

-
-
-
- -
-
-get(key=None, default=None, category=None, return_tagobj=False, return_list=False)[source]
-

Get the tag for the given key, category or combination of the two.

-
-
Parameters
-
    -
  • key (str or list, optional) – The tag or tags to retrieve.

  • -
  • default (any, optional) – The value to return in case of no match.

  • -
  • category (str, optional) – The Tag category to limit the -request to. Note that None is the valid, default -category. If no key is given, all tags of this category will be -returned.

  • -
  • return_tagobj (bool, optional) – Return the Tag object itself -instead of a string representation of the Tag.

  • -
  • return_list (bool, optional) – Always return a list, regardless -of number of matches.

  • -
-
-
Returns
-

tags (list)

-
-
The matches, either string

representations of the tags or the Tag objects themselves -depending on return_tagobj. If ‘default’ is set, this -will be a list with the default value as its only element.

-
-
-

-
-
-
- -
-
-remove(key=None, category=None)[source]
-

Remove a tag from the handler based ond key and/or category.

-
-
Parameters
-
    -
  • key (str or list, optional) – The tag or tags to retrieve.

  • -
  • category (str, optional) – The Tag category to limit the -request to. Note that None is the valid, default -category

  • -
-
-
-

Notes

-

If neither key nor category is specified, this acts -as .clear().

-
- -
-
-clear(category=None)[source]
-

Remove all tags from the handler.

-
-
Parameters
-

category (str, optional) – The Tag category to limit the -request to. Note that None is the valid, default -category.

-
-
-
- -
-
-all(return_key_and_category=False, return_objs=False)[source]
-

Get all tags in this handler, regardless of category.

-
-
Parameters
-
    -
  • return_key_and_category (bool, optional) – Return a list of -tuples [(key, category), …].

  • -
  • return_objs (bool, optional) – Return tag objects.

  • -
-
-
Returns
-

tags (list)

-
-
A list of tag keys [tagkey, tagkey, …] or

a list of tuples [(key, category), …] if -return_key_and_category is set.

-
-
-

-
-
-
- -
-
-batch_add(*args)[source]
-

Batch-add tags from a list of tuples.

-
-
Parameters
-

*args (tuple or str) – Each argument should be a tagstr keys or tuple -(keystr, category) or (keystr, category, data). It’s possible to mix input -types.

-
-
-

Notes

-

This will generate a mimimal number of self.add calls, -based on the number of categories involved (including -None) (data is not unique and may be overwritten by the content -of a latter tuple with the same category).

-
- -
- -
-
-class evennia.typeclasses.tags.AliasHandler(obj)[source]
-

Bases: evennia.typeclasses.tags.TagHandler

-

A handler for the Alias Tag type.

-
- -
-
-class evennia.typeclasses.tags.PermissionHandler(obj)[source]
-

Bases: evennia.typeclasses.tags.TagHandler

-

A handler for the Permission Tag type.

-
-
-check(*permissions, require_all=False)[source]
-

Straight-up check the provided permission against this handler. The check will pass if

-
    -
  • any/all given permission exists on the handler (depending on if require_all is set).

  • -
  • If handler sits on puppeted object and this is a hierarachical perm, the puppeting -Account’s permission will also be included in the check, prioritizing the Account’s perm -(this avoids escalation exploits by puppeting a too-high prio character)

  • -
  • a permission is also considered to exist on the handler, if it is lower than -a permission on the handler and this is a ‘hierarchical’ permission given -in settings.PERMISSION_HIERARCHY. Example: If the ‘Developer’ hierarchical -perm perm is set on the handler, and we check for the ‘Builder’ perm, the -check will pass.

  • -
-
-
Parameters
-
    -
  • *permissions (str) – Any number of permissions to check. By default, -the permission is passed if any of these (or higher, if a -hierarchical permission defined in settings.PERMISSION_HIERARCHY) -exists in the handler. Permissions are not case-sensitive.

  • -
  • require_all (bool) – If set, all provided permissions much pass -the check for the entire check to pass. By default only one -needs to pass.

  • -
-
-
Returns
-

bool – If the provided permission(s) pass the check on this handler.

-
-
-

Example

-
-
::

can_enter = obj.permissions.check(“Blacksmith”, “Builder”)

-
-
-

Notes

-

This works the same way as the perms lockfunc and could be -replicated with a lock check against the lockstring

-
-

“locktype: perm(perm1) OR perm(perm2) OR …”

-
-

(using AND for the require_all condition).

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.ansi.html b/docs/0.9.5/api/evennia.utils.ansi.html deleted file mode 100644 index d1ec31f1fb..0000000000 --- a/docs/0.9.5/api/evennia.utils.ansi.html +++ /dev/null @@ -1,1001 +0,0 @@ - - - - - - - - - evennia.utils.ansi — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.ansi

-

ANSI - Gives colour to text.

-

Use the codes defined in the ANSIParser class to apply colour to text. The -parse_ansi function in this module parses text for markup and strip_ansi -removes it.

-

You should usually not need to call parse_ansi explicitly; it is run by -Evennia just before returning data to/from the user. Alternative markup is -possible by overriding the parser class (see also contrib/ for deprecated -markup schemes).

-

Supported standards:

-
    -
  • ANSI 8 bright and 8 dark fg (foreground) colors

  • -
  • ANSI 8 dark bg (background) colors

  • -
  • ‘ANSI’ 8 bright bg colors ‘faked’ with xterm256 (bright bg not included in ANSI standard)

  • -
  • Xterm256 - 255 fg/bg colors + 26 greyscale fg/bg colors

  • -
-
-

Markup

-

ANSI colors: r ed, g reen, y ellow, b lue, m agenta, c yan, n ormal (no color). -Capital letters indicate the ‘dark’ variant.

-
    -
  • |r fg bright red

  • -
  • |R fg dark red

  • -
  • |[r bg bright red

  • -
  • |[R bg dark red

  • -
  • |[R|g bg dark red, fg bright green

  • -
-
"This is |rRed text|n and this is normal again."
-
-
-

Xterm256 colors are given as RGB (Red-Green-Blue), with values 0-5:

-
    -
  • |500 fg bright red

  • -
  • |050 fg bright green

  • -
  • |005 fg bright blue

  • -
  • |110 fg dark brown

  • -
  • |425 fg pink

  • -
  • |[431 bg orange

  • -
-

Xterm256 greyscale:

-
    -
  • |=a fg black

  • -
  • |=g fg dark grey

  • -
  • |=o fg middle grey

  • -
  • |=v fg bright grey

  • -
  • |=z fg white

  • -
  • |[=r bg middle grey

  • -
-
"This is |500Red text|n and this is normal again."
-"This is |[=jText on dark grey background"
-
-
-
-
-
-class evennia.utils.ansi.ANSIParser[source]
-

Bases: object

-

A class that parses ANSI markup -to ANSI command sequences

-

We also allow to escape colour codes -by prepending with an extra |.

-
-
-ansi_map = [('|n', '\x1b[0m'), ('|/', '\r\n'), ('|-', '\t'), ('|>', ' '), ('|_', ' '), ('|*', '\x1b[7m'), ('|^', '\x1b[5m'), ('|u', '\x1b[4m'), ('|r', '\x1b[1m\x1b[31m'), ('|g', '\x1b[1m\x1b[32m'), ('|y', '\x1b[1m\x1b[33m'), ('|b', '\x1b[1m\x1b[34m'), ('|m', '\x1b[1m\x1b[35m'), ('|c', '\x1b[1m\x1b[36m'), ('|w', '\x1b[1m\x1b[37m'), ('|x', '\x1b[1m\x1b[30m'), ('|R', '\x1b[22m\x1b[31m'), ('|G', '\x1b[22m\x1b[32m'), ('|Y', '\x1b[22m\x1b[33m'), ('|B', '\x1b[22m\x1b[34m'), ('|M', '\x1b[22m\x1b[35m'), ('|C', '\x1b[22m\x1b[36m'), ('|W', '\x1b[22m\x1b[37m'), ('|X', '\x1b[22m\x1b[30m'), ('|h', '\x1b[1m'), ('|H', '\x1b[22m'), ('|!R', '\x1b[31m'), ('|!G', '\x1b[32m'), ('|!Y', '\x1b[33m'), ('|!B', '\x1b[34m'), ('|!M', '\x1b[35m'), ('|!C', '\x1b[36m'), ('|!W', '\x1b[37m'), ('|!X', '\x1b[30m'), ('|[R', '\x1b[41m'), ('|[G', '\x1b[42m'), ('|[Y', '\x1b[43m'), ('|[B', '\x1b[44m'), ('|[M', '\x1b[45m'), ('|[C', '\x1b[46m'), ('|[W', '\x1b[47m'), ('|[X', '\x1b[40m')]
-
- -
-
-ansi_xterm256_bright_bg_map = [('|[r', '|[500'), ('|[g', '|[050'), ('|[y', '|[550'), ('|[b', '|[005'), ('|[m', '|[505'), ('|[c', '|[055'), ('|[w', '|[555'), ('|[x', '|[222')]
-
- -
-
-xterm256_fg = ['\\|([0-5])([0-5])([0-5])']
-
- -
-
-xterm256_bg = ['\\|\\[([0-5])([0-5])([0-5])']
-
- -
-
-xterm256_gfg = ['\\|=([a-z])']
-
- -
-
-xterm256_gbg = ['\\|\\[=([a-z])']
-
- -
-
-mxp_re = '\\|lc(.*?)\\|lt(.*?)\\|le'
-
- -
-
-mxp_url_re = '\\|lu(.*?)\\|lt(.*?)\\|le'
-
- -
-
-brightbg_sub = re.compile('(?<!\\|)\\|\\[r|(?<!\\|)\\|\\[g|(?<!\\|)\\|\\[y|(?<!\\|)\\|\\[b|(?<!\\|)\\|\\[m|(?<!\\|)\\|\\[c|(?<!\\|)\\|\\[w|(?<!\\|)\\|\\[x', re.DOTALL)
-
- -
-
-xterm256_fg_sub = re.compile('\\|([0-5])([0-5])([0-5])', re.DOTALL)
-
- -
-
-xterm256_bg_sub = re.compile('\\|\\[([0-5])([0-5])([0-5])', re.DOTALL)
-
- -
-
-xterm256_gfg_sub = re.compile('\\|=([a-z])', re.DOTALL)
-
- -
-
-xterm256_gbg_sub = re.compile('\\|\\[=([a-z])', re.DOTALL)
-
- -
-
-ansi_sub = re.compile('\\|n|\\|/|\\|\\-|\\|>|\\|_|\\|\\*|\\|\\^|\\|u|\\|r|\\|g|\\|y|\\|b|\\|m|\\|c|\\|w|\\|x|\\|R|\\|G|\\|Y|\\|B|\\|M|\\|C|\\|W|\\|X|\\|h|\\|H|\\|!R|\\|!G|\\|!Y|\\|!B|\\|!M|\\|!C|\\|!W|\\|!X|\\|\\[R|\\|\\[G, re.DOTALL)
-
- -
-
-mxp_sub = re.compile('\\|lc(.*?)\\|lt(.*?)\\|le', re.DOTALL)
-
- -
-
-mxp_url_sub = re.compile('\\|lu(.*?)\\|lt(.*?)\\|le', re.DOTALL)
-
- -
-
-ansi_map_dict = {'|!B': '\x1b[34m', '|!C': '\x1b[36m', '|!G': '\x1b[32m', '|!M': '\x1b[35m', '|!R': '\x1b[31m', '|!W': '\x1b[37m', '|!X': '\x1b[30m', '|!Y': '\x1b[33m', '|*': '\x1b[7m', '|-': '\t', '|/': '\r\n', '|>': ' ', '|B': '\x1b[22m\x1b[34m', '|C': '\x1b[22m\x1b[36m', '|G': '\x1b[22m\x1b[32m', '|H': '\x1b[22m', '|M': '\x1b[22m\x1b[35m', '|R': '\x1b[22m\x1b[31m', '|W': '\x1b[22m\x1b[37m', '|X': '\x1b[22m\x1b[30m', '|Y': '\x1b[22m\x1b[33m', '|[B': '\x1b[44m', '|[C': '\x1b[46m', '|[G': '\x1b[42m', '|[M': '\x1b[45m', '|[R': '\x1b[41m', '|[W': '\x1b[47m', '|[X': '\x1b[40m', '|[Y': '\x1b[43m', '|^': '\x1b[5m', '|_': ' ', '|b': '\x1b[1m\x1b[34m', '|c': '\x1b[1m\x1b[36m', '|g': '\x1b[1m\x1b[32m', '|h': '\x1b[1m', '|m': '\x1b[1m\x1b[35m', '|n': '\x1b[0m', '|r': '\x1b[1m\x1b[31m', '|u': '\x1b[4m', '|w': '\x1b[1m\x1b[37m', '|x': '\x1b[1m\x1b[30m', '|y': '\x1b[1m\x1b[33m'}
-
- -
-
-ansi_xterm256_bright_bg_map_dict = {'|[b': '|[005', '|[c': '|[055', '|[g': '|[050', '|[m': '|[505', '|[r': '|[500', '|[w': '|[555', '|[x': '|[222', '|[y': '|[550'}
-
- -
-
-ansi_re = '\\033\\[[0-9;]+m'
-
- -
-
-ansi_regex = re.compile('\\033\\[[0-9;]+m')
-
- -
-
-ansi_escapes = re.compile('({{|\\\\|\\|\\|)', re.DOTALL)
-
- -
-
-unsafe_tokens = re.compile('\\|\\/|\\|-', re.DOTALL)
-
- -
-
-sub_ansi(ansimatch)[source]
-

Replacer used by re.sub to replace ANSI -markers with correct ANSI sequences

-
-
Parameters
-

ansimatch (re.matchobject) – The match.

-
-
Returns
-

processed (str) – The processed match string.

-
-
-
- -
-
-sub_brightbg(ansimatch)[source]
-

Replacer used by re.sub to replace ANSI -bright background markers with Xterm256 replacement

-
-
Parameters
-

ansimatch (re.matchobject) – The match.

-
-
Returns
-

processed (str) – The processed match string.

-
-
-
- -
-
-sub_xterm256(rgbmatch, use_xterm256=False, color_type='fg')[source]
-

This is a replacer method called by re.sub with the matched -tag. It must return the correct ansi sequence.

-

It checks self.do_xterm256 to determine if conversion -to standard ANSI should be done or not.

-
-
Parameters
-
    -
  • rgbmatch (re.matchobject) – The match.

  • -
  • use_xterm256 (bool, optional) – Don’t convert 256-colors to 16.

  • -
  • color_type (str) – One of ‘fg’, ‘bg’, ‘gfg’, ‘gbg’.

  • -
-
-
Returns
-

processed (str) – The processed match string.

-
-
-
- -
-
-strip_raw_codes(string)[source]
-

Strips raw ANSI codes from a string.

-
-
Parameters
-

string (str) – The string to strip.

-
-
Returns
-

string (str) – The processed string.

-
-
-
- -
-
-strip_mxp(string)[source]
-

Strips all MXP codes from a string.

-
-
Parameters
-

string (str) – The string to strip.

-
-
Returns
-

string (str) – The processed string.

-
-
-
- -
-
-strip_unsafe_tokens(string)[source]
-

Strip explicitly ansi line breaks and tabs.

-
- -
-
-parse_ansi(string, strip_ansi=False, xterm256=False, mxp=False)[source]
-

Parses a string, subbing color codes according to the stored -mapping.

-
-
Parameters
-
    -
  • string (str) – The string to parse.

  • -
  • strip_ansi (boolean, optional) – Strip all found ansi markup.

  • -
  • xterm256 (boolean, optional) – If actually using xterm256 or if -these values should be converted to 16-color ANSI.

  • -
  • mxp (boolean, optional) – Parse MXP commands in string.

  • -
-
-
Returns
-

string (str) – The parsed string.

-
-
-
- -
- -
-
-evennia.utils.ansi.parse_ansi(string, strip_ansi=False, parser=<evennia.utils.ansi.ANSIParser object>, xterm256=False, mxp=False)[source]
-

Parses a string, subbing color codes as needed.

-
-
Parameters
-
    -
  • string (str) – The string to parse.

  • -
  • strip_ansi (bool, optional) – Strip all ANSI sequences.

  • -
  • parser (ansi.AnsiParser, optional) – A parser instance to use.

  • -
  • xterm256 (bool, optional) – Support xterm256 or not.

  • -
  • mxp (bool, optional) – Support MXP markup or not.

  • -
-
-
Returns
-

string (str) – The parsed string.

-
-
-
- -
-
-evennia.utils.ansi.strip_ansi(string, parser=<evennia.utils.ansi.ANSIParser object>)[source]
-

Strip all ansi from the string. This handles the Evennia-specific -markup.

-
-
Parameters
-
    -
  • string (str) – The string to strip.

  • -
  • parser (ansi.AnsiParser, optional) – The parser to use.

  • -
-
-
Returns
-

string (str) – The stripped string.

-
-
-
- -
-
-evennia.utils.ansi.strip_raw_ansi(string, parser=<evennia.utils.ansi.ANSIParser object>)[source]
-

Remove raw ansi codes from string. This assumes pure -ANSI-bytecodes in the string.

-
-
Parameters
-
    -
  • string (str) – The string to parse.

  • -
  • parser (bool, optional) – The parser to use.

  • -
-
-
Returns
-

string (str) – the stripped string.

-
-
-
- -
-
-evennia.utils.ansi.strip_unsafe_tokens(string, parser=<evennia.utils.ansi.ANSIParser object>)[source]
-

Strip markup that can be used to create visual exploits -(notably linebreaks and tags)

-
- -
-
-evennia.utils.ansi.strip_mxp(string, parser=<evennia.utils.ansi.ANSIParser object>)[source]
-

Strip MXP markup.

-
- -
-
-evennia.utils.ansi.raw(string)[source]
-

Escapes a string into a form which won’t be colorized by the ansi -parser.

-
-
Returns
-

string (str) – The raw, escaped string.

-
-
-
- -
-
-class evennia.utils.ansi.ANSIMeta(*args, **kwargs)[source]
-

Bases: type

-

Many functions on ANSIString are just light wrappers around the string -base class. We apply them here, as part of the classes construction.

-
-
-__init__(*args, **kwargs)[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
- -
-
-class evennia.utils.ansi.ANSIString(*args, **kwargs)[source]
-

Bases: str

-

Unicode-like object that is aware of ANSI codes.

-

This class can be used nearly identically to strings, in that it will -report string length, handle slices, etc, much like a string object -would. The methods should be used identically as string methods are.

-

There is at least one exception to this (and there may be more, though -they have not come up yet). When using ‘’.join() or u’’.join() on an -ANSIString, color information will get lost. You must use -ANSIString(‘’).join() to preserve color information.

-

This implementation isn’t perfectly clean, as it doesn’t really have an -understanding of what the codes mean in order to eliminate -redundant characters– though cleaning up the strings might end up being -inefficient and slow without some C code when dealing with larger values. -Such enhancements could be made as an enhancement to ANSI_PARSER -if needed, however.

-

If one is going to use ANSIString, one should generally avoid converting -away from it until one is about to send information on the wire. This is -because escape sequences in the string may otherwise already be decoded, -and taken literally the second time around.

-
-
-re_format = re.compile('(?i)(?P<just>(?P<fill>.)?(?P<align>\\<|\\>|\\=|\\^))?(?P<sign>\\+|\\-| )?(?P<alt>\\#)?(?P<zero>0)?(?P<width>\\d+)?(?P<grouping>\\_|\\,)?(?:\\.(?P<precision>\\d+))?(?P<type>b|c|d|e|E|f|F|g|G|n|o|s|x|X, re.IGNORECASE)
-
- -
-
-__init__(*_, **kwargs)[source]
-

When the ANSIString is first initialized, a few internal variables -have to be set.

-

The first is the parser. It is possible to replace Evennia’s standard -ANSI parser with one of your own syntax if you wish, so long as it -implements the same interface.

-

The second is the _raw_string. This is the original “dumb” string -with ansi escapes that ANSIString represents.

-

The third thing to set is the _clean_string. This is a string that is -devoid of all ANSI Escapes.

-

Finally, _code_indexes and _char_indexes are defined. These are lookup -tables for which characters in the raw string are related to ANSI -escapes, and which are for the readable text.

-
- -
-
-clean()[source]
-

Return a string object without the ANSI escapes.

-
-
Returns
-

clean_string (str) – A unicode object with no ANSI escapes.

-
-
-
- -
-
-raw()[source]
-

Return a string object with the ANSI escapes.

-
-
Returns
-

raw (str) – A unicode object with the raw ANSI escape sequences.

-
-
-
- -
-
-partition(sep, reverse=False)[source]
-

Splits once into three sections (with the separator being the middle section)

-

We use the same techniques we used in split() to make sure each are -colored.

-
-
Parameters
-
    -
  • sep (str) – The separator to split the string on.

  • -
  • reverse (boolean) – Whether to split the string on the last -occurrence of the separator rather than the first.

  • -
-
-
Returns
-

ANSIString – The part of the string before the separator -ANSIString: The separator itself -ANSIString: The part of the string after the separator.

-
-
-
- -
-
-split(by=None, maxsplit=- 1)[source]
-

Splits a string based on a separator.

-

Stolen from PyPy’s pure Python string implementation, tweaked for -ANSIString.

-

PyPy is distributed under the MIT licence. -http://opensource.org/licenses/MIT

-
-
Parameters
-
    -
  • by (str) – A string to search for which will be used to split -the string. For instance, ‘,’ for ‘Hello,world’ would -result in [‘Hello’, ‘world’]

  • -
  • maxsplit (int) – The maximum number of times to split the string. -For example, a maxsplit of 2 with a by of ‘,’ on the string -‘Hello,world,test,string’ would result in -[‘Hello’, ‘world’, ‘test,string’]

  • -
-
-
Returns
-

result (list of ANSIStrings)

-
-
A list of ANSIStrings derived from

this string.

-
-
-

-
-
-
- -
-
-rsplit(by=None, maxsplit=- 1)[source]
-

Like split, but starts from the end of the string rather than the -beginning.

-

Stolen from PyPy’s pure Python string implementation, tweaked for -ANSIString.

-

PyPy is distributed under the MIT licence. -http://opensource.org/licenses/MIT

-
-
Parameters
-
    -
  • by (str) – A string to search for which will be used to split -the string. For instance, ‘,’ for ‘Hello,world’ would -result in [‘Hello’, ‘world’]

  • -
  • maxsplit (int) – The maximum number of times to split the string. -For example, a maxsplit of 2 with a by of ‘,’ on the string -‘Hello,world,test,string’ would result in -[‘Hello,world’, ‘test’, ‘string’]

  • -
-
-
Returns
-

result (list of ANSIStrings)

-
-
A list of ANSIStrings derived from

this string.

-
-
-

-
-
-
- -
-
-strip(chars=None)[source]
-

Strip from both ends, taking ANSI markers into account.

-
-
Parameters
-

chars (str, optional) – A string containing individual characters -to strip off of both ends of the string. By default, any blank -spaces are trimmed.

-
-
Returns
-

result (ANSIString)

-
-
A new ANSIString with the ends trimmed of the

relevant characters.

-
-
-

-
-
-
- -
-
-lstrip(chars=None)[source]
-

Strip from the left, taking ANSI markers into account.

-
-
Parameters
-

chars (str, optional) – A string containing individual characters -to strip off of the left end of the string. By default, any -blank spaces are trimmed.

-
-
Returns
-

result (ANSIString)

-
-
A new ANSIString with the left end trimmed of

the relevant characters.

-
-
-

-
-
-
- -
-
-capitalize(*args, **kwargs)
-

Return a capitalized version of the string.

-

More specifically, make the first character have upper case and the rest lower -case.

-
- -
-
-count(sub[, start[, end]]) → int
-

Return the number of non-overlapping occurrences of substring sub in -string S[start:end]. Optional arguments start and end are -interpreted as in slice notation.

-
- -
-
-decode(*args, **kwargs)
-
- -
-
-encode(*args, **kwargs)
-

Encode the string using the codec registered for encoding.

-
-
encoding

The encoding in which to encode the string.

-
-
errors

The error handling scheme to use for encoding errors. -The default is ‘strict’ meaning that encoding errors raise a -UnicodeEncodeError. Other possible values are ‘ignore’, ‘replace’ and -‘xmlcharrefreplace’ as well as any other name registered with -codecs.register_error that can handle UnicodeEncodeErrors.

-
-
-
- -
-
-endswith(suffix[, start[, end]]) → bool
-

Return True if S ends with the specified suffix, False otherwise. -With optional start, test S beginning at that position. -With optional end, stop comparing S at that position. -suffix can also be a tuple of strings to try.

-
- -
-
-expandtabs(*args, **kwargs)
-

Return a copy where all tab characters are expanded using spaces.

-

If tabsize is not given, a tab size of 8 characters is assumed.

-
- -
-
-find(sub[, start[, end]]) → int
-

Return the lowest index in S where substring sub is found, -such that sub is contained within S[start:end]. Optional -arguments start and end are interpreted as in slice notation.

-

Return -1 on failure.

-
- -
-
-format(*args, **kwargs) → str
-

Return a formatted version of S, using substitutions from args and kwargs. -The substitutions are identified by braces (‘{’ and ‘}’).

-
- -
-
-index(sub[, start[, end]]) → int
-

Return the lowest index in S where substring sub is found, -such that sub is contained within S[start:end]. Optional -arguments start and end are interpreted as in slice notation.

-

Raises ValueError when the substring is not found.

-
- -
-
-isalnum(*args, **kwargs)
-

Return True if the string is an alpha-numeric string, False otherwise.

-

A string is alpha-numeric if all characters in the string are alpha-numeric and -there is at least one character in the string.

-
- -
-
-isalpha(*args, **kwargs)
-

Return True if the string is an alphabetic string, False otherwise.

-

A string is alphabetic if all characters in the string are alphabetic and there -is at least one character in the string.

-
- -
-
-isdigit(*args, **kwargs)
-

Return True if the string is a digit string, False otherwise.

-

A string is a digit string if all characters in the string are digits and there -is at least one character in the string.

-
- -
-
-islower(*args, **kwargs)
-

Return True if the string is a lowercase string, False otherwise.

-

A string is lowercase if all cased characters in the string are lowercase and -there is at least one cased character in the string.

-
- -
-
-isspace(*args, **kwargs)
-

Return True if the string is a whitespace string, False otherwise.

-

A string is whitespace if all characters in the string are whitespace and there -is at least one character in the string.

-
- -
-
-istitle(*args, **kwargs)
-

Return True if the string is a title-cased string, False otherwise.

-

In a title-cased string, upper- and title-case characters may only -follow uncased characters and lowercase characters only cased ones.

-
- -
-
-isupper(*args, **kwargs)
-

Return True if the string is an uppercase string, False otherwise.

-

A string is uppercase if all cased characters in the string are uppercase and -there is at least one cased character in the string.

-
- -
-
-lower(*args, **kwargs)
-

Return a copy of the string converted to lowercase.

-
- -
-
-replace(*args, **kwargs)
-

Return a copy with all occurrences of substring old replaced by new.

-
-
-
count

Maximum number of occurrences to replace. --1 (the default value) means replace all occurrences.

-
-
-
-

If the optional argument count is given, only the first count occurrences are -replaced.

-
- -
-
-rfind(sub[, start[, end]]) → int
-

Return the highest index in S where substring sub is found, -such that sub is contained within S[start:end]. Optional -arguments start and end are interpreted as in slice notation.

-

Return -1 on failure.

-
- -
-
-rindex(sub[, start[, end]]) → int
-

Return the highest index in S where substring sub is found, -such that sub is contained within S[start:end]. Optional -arguments start and end are interpreted as in slice notation.

-

Raises ValueError when the substring is not found.

-
- -
-
-rstrip(chars=None)[source]
-

Strip from the right, taking ANSI markers into account.

-
-
Parameters
-

chars (str, optional) – A string containing individual characters -to strip off of the right end of the string. By default, any -blank spaces are trimmed.

-
-
Returns
-

result (ANSIString)

-
-
A new ANSIString with the right end trimmed of

the relevant characters.

-
-
-

-
-
-
- -
-
-startswith(prefix[, start[, end]]) → bool
-

Return True if S starts with the specified prefix, False otherwise. -With optional start, test S beginning at that position. -With optional end, stop comparing S at that position. -prefix can also be a tuple of strings to try.

-
- -
-
-swapcase(*args, **kwargs)
-

Convert uppercase characters to lowercase and lowercase characters to uppercase.

-
- -
-
-translate(*args, **kwargs)
-

Replace each character in the string using the given translation table.

-
-
-
table

Translation table, which must be a mapping of Unicode ordinals to -Unicode ordinals, strings, or None.

-
-
-
-

The table must implement lookup/indexing via __getitem__, for instance a -dictionary or list. If this operation raises LookupError, the character is -left untouched. Characters mapped to None are deleted.

-
- -
-
-upper(*args, **kwargs)
-

Return a copy of the string converted to uppercase.

-
- -
-
-join(iterable)[source]
-

Joins together strings in an iterable, using this string between each -one.

-

NOTE: This should always be used for joining strings when ANSIStrings -are involved. Otherwise color information will be discarded by python, -due to details in the C implementation of strings.

-
-
Parameters
-

iterable (list of strings) – A list of strings to join together

-
-
Returns
-

ANSIString

-
-
A single string with all of the iterable’s

contents concatenated, with this string between each.

-
-
-

-
-
-

Examples

-
>>> ANSIString(', ').join(['up', 'right', 'left', 'down'])
-ANSIString('up, right, left, down')
-
-
-
- -
-
-center(width, fillchar, _difference)[source]
-

Center some text with some spaces padding both sides.

-
-
Parameters
-
    -
  • width (int) – The target width of the output string.

  • -
  • fillchar (str) – A single character string to pad the output string -with.

  • -
-
-
Returns
-

result (ANSIString) – A string padded on both ends with fillchar.

-
-
-
- -
-
-ljust(width, fillchar, _difference)[source]
-

Left justify some text.

-
-
Parameters
-
    -
  • width (int) – The target width of the output string.

  • -
  • fillchar (str) – A single character string to pad the output string -with.

  • -
-
-
Returns
-

result (ANSIString) – A string padded on the right with fillchar.

-
-
-
- -
-
-rjust(width, fillchar, _difference)[source]
-

Right justify some text.

-
-
Parameters
-
    -
  • width (int) – The target width of the output string.

  • -
  • fillchar (str) – A single character string to pad the output string -with.

  • -
-
-
Returns
-

result (ANSIString) – A string padded on the left with fillchar.

-
-
-
- -
- -
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.batchprocessors.html b/docs/0.9.5/api/evennia.utils.batchprocessors.html deleted file mode 100644 index 86dbe59780..0000000000 --- a/docs/0.9.5/api/evennia.utils.batchprocessors.html +++ /dev/null @@ -1,423 +0,0 @@ - - - - - - - - - evennia.utils.batchprocessors — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.batchprocessors

-

This module contains the core methods for the Batch-command- and -Batch-code-processors respectively. In short, these are two different ways to -build a game world using a normal text-editor without having to do so ‘on the -fly’ in-game. They also serve as an automatic backup so you can quickly -recreate a world also after a server reset. The functions in this module is -meant to form the backbone of a system called and accessed through game -commands.

-

The Batch-command processor is the simplest. It simply runs a list of in-game -commands in sequence by reading them from a text file. The advantage of this is -that the builder only need to remember the normal in-game commands. They are -also executing with full permission checks etc, making it relatively safe for -builders to use. The drawback is that in-game there is really a -builder-character walking around building things, and it can be important to -create rooms and objects in the right order, so the character can move between -them. Also objects that affects players (such as mobs, dark rooms etc) will -affect the building character too, requiring extra care to turn off/on.

-

The Batch-code processor is a more advanced system that accepts full -Python code, executing in chunks. The advantage of this is much more -power; practically anything imaginable can be coded and handled using -the batch-code processor. There is no in-game character that moves and -that can be affected by what is being built - the database is -populated on the fly. The drawback is safety and entry threshold - the -code is executed as would any server code, without mud-specific -permission-checks, and you have full access to modifying objects -etc. You also need to know Python and Evennia’s API. Hence it’s -recommended that the batch-code processor is limited only to -superusers or highly trusted staff.

-
-

Batch-command processor file syntax

-

The batch-command processor accepts ‘batchcommand files’ e.g -batch.ev, containing a sequence of valid Evennia commands in a -simple format. The engine runs each command in sequence, as if they -had been run at the game prompt.

-

Each Evennia command must be delimited by a line comment to mark its -end.

-
look
-# delimiting comment
-create/drop box
-# another required comment
-
-
-

One can also inject another batchcmdfile:

-
#INSERT path.batchcmdfile
-
-
-

This way entire game worlds can be created and planned offline; it is -especially useful in order to create long room descriptions where a -real offline text editor is often much better than any online text -editor or prompt.

-
-

Example of batch.ev file:

-
# batch file
-# all lines starting with # are comments; they also indicate
-# that a command definition is over.
-
-create box
-
-# this comment ends the @create command.
-
-set box/desc = A large box.
-
-Inside are some scattered piles of clothing.
-
-
-It seems the bottom of the box is a bit loose.
-
-# Again, this comment indicates the @set command is over. Note how
-# the description could be freely added. Excess whitespace on a line
-# is ignored.  An empty line in the command definition is parsed as a
-
-# (so two empty lines becomes a new paragraph).
-
-teleport #221
-
-# (Assuming #221 is a warehouse or something.)
-# (remember, this comment ends the @teleport command! Don'f forget it)
-
-# Example of importing another file at this point.
-#IMPORT examples.batch
-
-drop box
-
-# Done, the box is in the warehouse! (this last comment is not necessary to
-# close the drop command since it's the end of the file)
-
-
-

An example batch file is contrib/examples/batch_example.ev.

-
-
-
-

Batch-code processor file syntax

-

The Batch-code processor accepts full python modules (e.g. batch.py) -that looks identical to normal Python files. The difference from -importing and running any Python module is that the batch-code module -is loaded as a file and executed directly, so changes to the file will -apply immediately without a server @reload.

-

Optionally, one can add some special commented tokens to split the -execution of the code for the benefit of the batchprocessor’s -interactive- and debug-modes. This allows to conveniently step through -the code and re-run sections of it easily during development.

-

Code blocks are marked by commented tokens alone on a line:

-
    -
  • #HEADER - This denotes code that should be pasted at the top of all -other code. Multiple HEADER statements - regardless of where -it exists in the file - is the same as one big block. -Observe that changes to variables made in one block is not -preserved between blocks!

  • -
  • #CODE - This designates a code block that will be executed like a -stand-alone piece of code together with any HEADER(s) -defined. It is mainly used as a way to mark stop points for -the interactive mode of the batchprocessor. If no CODE block -is defined in the module, the entire module (including HEADERS) -is assumed to be a CODE block.

  • -
  • #INSERT path.filename - This imports another batch_code.py file and -runs it in the given position. The inserted file will retain -its own HEADERs which will not be mixed with the headers of -this file.

  • -
-

Importing works as normal. The following variables are automatically -made available in the script namespace.

-
    -
  • caller - The object executing the batchscript

  • -
  • -
    DEBUG - This is a boolean marking if the batchprocessor is running

    in debug mode. It can be checked to e.g. delete created objects -when running a CODE block multiple times during testing. -(avoids creating a slew of same-named db objects)

    -
    -
    -
  • -
-
-

Example batch.py file

-
#HEADER
-
-from django.conf import settings
-from evennia.utils import create
-from types import basetypes
-
-GOLD = 10
-
-#CODE
-
-obj = create.create_object(basetypes.Object)
-obj2 = create.create_object(basetypes.Object)
-obj.location = caller.location
-obj.db.gold = GOLD
-caller.msg("The object was created!")
-
-if DEBUG:
-    obj.delete()
-    obj2.delete()
-
-#INSERT another_batch_file
-
-#CODE
-
-script = create.create_script()
-
-
-
-
-evennia.utils.batchprocessors.read_batchfile(pythonpath, file_ending='.py')[source]
-

This reads the contents of a batch-file. Filename is considered -to be a python path to a batch file relative the directory -specified in settings.py.

-

file_ending specify which batchfile ending should be assumed (.ev -or .py). The ending should not be included in the python path.

-
-
Parameters
-
    -
  • pythonpath (str) – A dot-python path to a file.

  • -
  • file_ending (str) – The file ending of this file (.ev or .py)

  • -
-
-
Returns
-

text (str) – The text content of the batch file.

-
-
Raises
-

IOError – If problems reading file.

-
-
-
- -
-
-class evennia.utils.batchprocessors.BatchCommandProcessor[source]
-

Bases: object

-

This class implements a batch-command processor.

-
-
-parse_file(pythonpath)[source]
-

This parses the lines of a batch-command-file.

-
-
Parameters
-

pythonpath (str) – The dot-python path to the file.

-
-
Returns
-

list – A list of all parsed commands with arguments, as strings.

-
-
-

Notes

-

Parsing follows the following rules:

-
    -
  1. A # at the beginning of a line marks the end of the command before -it. It is also a comment and any number of # can exist on -subsequent lines (but not inside comments).

  2. -
  3. #INSERT at the beginning of a line imports another -batch-cmd file file and pastes it into the batch file as if -it was written there.

  4. -
  5. Commands are placed alone at the beginning of a line and their -arguments are considered to be everything following (on any -number of lines) until the next comment line beginning with #.

  6. -
  7. Newlines are ignored in command definitions

  8. -
  9. A completely empty line in a command line definition is condered -a newline (so two empty lines is a paragraph).

  10. -
  11. Excess spaces and indents inside arguments are stripped.

  12. -
-
- -
- -
-
-evennia.utils.batchprocessors.tb_filename(tb)[source]
-

Helper to get filename from traceback

-
- -
-
-evennia.utils.batchprocessors.tb_iter(tb)[source]
-

Traceback iterator.

-
- -
-
-class evennia.utils.batchprocessors.BatchCodeProcessor[source]
-

Bases: object

-

This implements a batch-code processor

-
-
-parse_file(pythonpath)[source]
-

This parses the lines of a batch-code file

-
-
Parameters
-

pythonpath (str) – The dot-python path to the file.

-
-
Returns
-

list

-
-
A list of all #CODE blocks, each with

prepended #HEADER block data. If no #CODE -blocks were found, this will be a list of one element -containing all code in the file (so a normal Python file).

-
-
-

-
-
-

Notes

-

Parsing is done according to the following rules:

-
    -
  1. Code before a #CODE/HEADER block are considered part of -the first code/header block or is the ONLY block if no -#CODE/HEADER blocks are defined.

  2. -
  3. Lines starting with #HEADER starts a header block (ends other blocks)

  4. -
  5. Lines starting with #CODE begins a code block (ends other blocks)

  6. -
  7. Lines starting with #INSERT are on form #INSERT filename. Code from -this file are processed with their headers separately before -being inserted at the point of the #INSERT.

  8. -
  9. Code after the last block is considered part of the last header/code -block

  10. -
-
- -
-
-code_exec(code, extra_environ=None, debug=False)[source]
-

Execute a single code block, including imports and appending -global vars.

-
-
Parameters
-
    -
  • code (str) – Code to run.

  • -
  • extra_environ (dict) – Environment variables to run with code.

  • -
  • debug (bool, optional) – Set the DEBUG variable in the execution -namespace.

  • -
-
-
Returns
-

err (str or None) – An error code or None (ok).

-
-
-
- -
- -
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.containers.html b/docs/0.9.5/api/evennia.utils.containers.html deleted file mode 100644 index 696db6aece..0000000000 --- a/docs/0.9.5/api/evennia.utils.containers.html +++ /dev/null @@ -1,258 +0,0 @@ - - - - - - - - - evennia.utils.containers — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.containers

-

Containers

-

Containers are storage classes usually initialized from a setting. They -represent Singletons and acts as a convenient place to find resources ( -available as properties on the singleton)

-

evennia.GLOBAL_SCRIPTS -evennia.OPTION_CLASSES

-
-
-class evennia.utils.containers.Container[source]
-

Bases: object

-

Base container class. A container is simply a storage object whose -properties can be acquired as a property on it. This is generally -considered a read-only affair.

-

The container is initialized by a list of modules containing callables.

-
-
-storage_modules = []
-
- -
-
-__init__()[source]
-

Read data from module.

-
- -
-
-load_data()[source]
-

Delayed import to avoid eventual circular imports from inside -the storage modules.

-
- -
-
-get(key, default=None)[source]
-

Retrive data by key (in case of not knowing it beforehand).

-
-
Parameters
-
    -
  • key (str) – The name of the script.

  • -
  • default (any, optional) – Value to return if key is not found.

  • -
-
-
Returns
-

any (any) – The data loaded on this container.

-
-
-
- -
-
-all()[source]
-

Get all stored data

-
-
Returns
-

scripts (list) – All global script objects stored on the container.

-
-
-
- -
- -
-
-class evennia.utils.containers.OptionContainer[source]
-

Bases: evennia.utils.containers.Container

-

Loads and stores the final list of OPTION CLASSES.

-

Can access these as properties or dictionary-contents.

-
-
-storage_modules = ['evennia.utils.optionclasses']
-
- -
- -
-
-class evennia.utils.containers.GlobalScriptContainer[source]
-

Bases: evennia.utils.containers.Container

-

Simple Handler object loaded by the Evennia API to contain and manage a -game’s Global Scripts. This will list global Scripts created on their own -but will also auto-(re)create scripts defined in settings.GLOBAL_SCRIPTS.

-

Example

-

import evennia -evennia.GLOBAL_SCRIPTS.scriptname

-
-

Note

-

This does not use much of the BaseContainer since it’s not loading -callables from settings but a custom dict of tuples.

-
-
-
-__init__()[source]
-

Note: We must delay loading of typeclasses since this module may get -initialized before Scripts are actually initialized.

-
- -
-
-start()[source]
-

Called last in evennia.__init__ to initialize the container late -(after script typeclasses have finished loading).

-

We include all global scripts in the handler and -make sure to auto-load time-based scripts.

-
- -
-
-load_data()[source]
-

This delayed import avoids trying to load Scripts before they are -initialized.

-
- -
-
-get(key, default=None)[source]
-

Retrive data by key (in case of not knowing it beforehand). Any -scripts that are in settings.GLOBAL_SCRIPTS that are not found -will be recreated on-demand.

-
-
Parameters
-
    -
  • key (str) – The name of the script.

  • -
  • default (any, optional) – Value to return if key is not found -at all on this container (i.e it cannot be loaded at all).

  • -
-
-
Returns
-

any (any) – The data loaded on this container.

-
-
-
- -
-
-all()[source]
-

Get all global scripts. Note that this will not auto-start -scripts defined in settings.

-
-
Returns
-

scripts (list) – All global script objects stored on the container.

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.create.html b/docs/0.9.5/api/evennia.utils.create.html deleted file mode 100644 index 17baa8f397..0000000000 --- a/docs/0.9.5/api/evennia.utils.create.html +++ /dev/null @@ -1,327 +0,0 @@ - - - - - - - - - evennia.utils.create — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.create

-

This module gathers all the essential database-creation functions for the game -engine’s various object types.

-

Only objects created ‘stand-alone’ are in here. E.g. object Attributes are -always created through their respective objects handlers.

-

Each creation_* function also has an alias named for the entity being created, -such as create_object() and object(). This is for consistency with the -utils.search module and allows you to do the shorter create.object().

-

The respective object managers hold more methods for manipulating and searching -objects already existing in the database.

-
-
-evennia.utils.create.create_object(typeclass=None, key=None, location=None, home=None, permissions=None, locks=None, aliases=None, tags=None, destination=None, report_to=None, nohome=False, attributes=None, nattributes=None)
-

Create a new in-game object.

-
-
Keyword Arguments
-
    -
  • typeclass (class or str) – Class or python path to a typeclass.

  • -
  • key (str) – Name of the new object. If not set, a name of -#dbref will be set.

  • -
  • location (Object or str) – Obj or #dbref to use as the location of the new object.

  • -
  • home (Object or str) – Obj or #dbref to use as the object’s home location.

  • -
  • permissions (list) – A list of permission strings or tuples (permstring, category).

  • -
  • locks (str) – one or more lockstrings, separated by semicolons.

  • -
  • aliases (list) – A list of alternative keys or tuples (aliasstring, category).

  • -
  • tags (list) – List of tag keys or tuples (tagkey, category) or (tagkey, category, data).

  • -
  • destination (Object or str) – Obj or #dbref to use as an Exit’s target.

  • -
  • report_to (Object) – The object to return error messages to.

  • -
  • nohome (bool) – This allows the creation of objects without a -default home location; only used when creating the default -location itself or during unittests.

  • -
  • attributes (list) – Tuples on the form (key, value) or (key, value, category), -(key, value, lockstring) or (key, value, lockstring, default_access). -to set as Attributes on the new object.

  • -
  • nattributes (list) – Non-persistent tuples on the form (key, value). Note that -adding this rarely makes sense since this data will not survive a reload.

  • -
-
-
Returns
-

object (Object) – A newly created object of the given typeclass.

-
-
Raises
-

ObjectDB.DoesNotExist – If trying to create an Object with -location or home that can’t be found.

-
-
-
- -
-
-evennia.utils.create.create_script(typeclass=None, key=None, obj=None, account=None, locks=None, interval=None, start_delay=None, repeats=None, persistent=None, autostart=True, report_to=None, desc=None, tags=None, attributes=None)
-

Create a new script. All scripts are a combination of a database -object that communicates with the database, and an typeclass that -‘decorates’ the database object into being different types of -scripts. It’s behaviour is similar to the game objects except -scripts has a time component and are more limited in scope.

-
-
Keyword Arguments
-
    -
  • typeclass (class or str) – Class or python path to a typeclass.

  • -
  • key (str) – Name of the new object. If not set, a name of -#dbref will be set.

  • -
  • obj (Object) – The entity on which this Script sits. If this -is None, we are creating a “global” script.

  • -
  • account (Account) – The account on which this Script sits. It is -exclusiv to obj.

  • -
  • locks (str) – one or more lockstrings, separated by semicolons.

  • -
  • interval (int) – The triggering interval for this Script, in -seconds. If unset, the Script will not have a timing -component.

  • -
  • start_delay (bool) – If True, will wait interval seconds -before triggering the first time.

  • -
  • repeats (int) – The number of times to trigger before stopping. -If unset, will repeat indefinitely.

  • -
  • persistent (bool) – If this Script survives a server shutdown -or not (all Scripts will survive a reload).

  • -
  • autostart (bool) – If this Script will start immediately when -created or if the start method must be called explicitly.

  • -
  • report_to (Object) – The object to return error messages to.

  • -
  • desc (str) – Optional description of script

  • -
  • tags (list) – List of tags or tuples (tag, category).

  • -
  • attributes (list) – List if tuples (key, value) or (key, value, category) -(key, value, lockstring) or (key, value, lockstring, default_access).

  • -
-
-
Returns
-

script (obj) – An instance of the script created

-
-
-

See evennia.scripts.manager for methods to manipulate existing -scripts in the database.

-
- -
-
-evennia.utils.create.create_help_entry(key, entrytext, category='General', locks=None, aliases=None, tags=None)
-

Create a static help entry in the help database. Note that Command -help entries are dynamic and directly taken from the __doc__ -entries of the command. The database-stored help entries are -intended for more general help on the game, more extensive info, -in-game setting information and so on.

-
-
Parameters
-
    -
  • key (str) – The name of the help entry.

  • -
  • entrytext (str) – The body of te help entry

  • -
  • category (str, optional) – The help category of the entry.

  • -
  • locks (str, optional) – A lockstring to restrict access.

  • -
  • aliases (list of str, optional) – List of alternative (likely shorter) keynames.

  • -
  • tags (lst, optional) – List of tags or tuples (tag, category).

  • -
-
-
Returns
-

help (HelpEntry) – A newly created help entry.

-
-
-
- -
-
-evennia.utils.create.create_message(senderobj, message, receivers=None, locks=None, tags=None, header=None, **kwargs)
-

Create a new communication Msg. Msgs represent a unit of -database-persistent communication between entites.

-
-
Parameters
-
    -
  • senderobj (Object, Account, Script, str or list) – The entity (or -entities) sending the Msg. If a str, this is the id-string -for an external sender type.

  • -
  • message (str) – Text with the message. Eventual headers, titles -etc should all be included in this text string. Formatting -will be retained.

  • -
  • receivers (Object, Account, Script, str or list) – An Account/Object to send -to, or a list of them. If a string, it’s an identifier for an external -receiver.

  • -
  • locks (str) – Lock definition string.

  • -
  • tags (list) – A list of tags or tuples (tag, category).

  • -
  • header (str) – Mime-type or other optional information for the message

  • -
-
-
-

Notes

-

The Comm system is created to be very open-ended, so it’s fully -possible to let a message both go several receivers at the same time, -it’s up to the command definitions to limit this as desired.

-
- -
-
-evennia.utils.create.create_channel(key, aliases=None, desc=None, locks=None, keep_log=True, typeclass=None, tags=None)
-

Create A communication Channel. A Channel serves as a central hub -for distributing Msgs to groups of people without specifying the -receivers explicitly. Instead accounts may ‘connect’ to the channel -and follow the flow of messages. By default the channel allows -access to all old messages, but this can be turned off with the -keep_log switch.

-
-
Parameters
-

key (str) – This must be unique.

-
-
Keyword Arguments
-
    -
  • aliases (list of str) – List of alternative (likely shorter) keynames.

  • -
  • desc (str) – A description of the channel, for use in listings.

  • -
  • locks (str) – Lockstring.

  • -
  • keep_log (bool) – Log channel throughput.

  • -
  • typeclass (str or class) – The typeclass of the Channel (not -often used).

  • -
  • tags (list) – A list of tags or tuples (tag, category).

  • -
-
-
Returns
-

channel (Channel) – A newly created channel.

-
-
-
- -
-
-evennia.utils.create.create_account(key, email, password, typeclass=None, is_superuser=False, locks=None, permissions=None, tags=None, attributes=None, report_to=None)
-

This creates a new account.

-
-
Parameters
-
    -
  • key (str) – The account’s name. This should be unique.

  • -
  • email (str or None) – Email on valid addr@addr.domain form. If -the empty string, will be set to None.

  • -
  • password (str) – Password in cleartext.

  • -
-
-
Keyword Arguments
-
    -
  • typeclass (str) – The typeclass to use for the account.

  • -
  • is_superuser (bool) – Wether or not this account is to be a superuser

  • -
  • locks (str) – Lockstring.

  • -
  • permission (list) – List of permission strings.

  • -
  • tags (list) – List of Tags on form (key, category[, data])

  • -
  • attributes (list) – List of Attributes on form -(key, value [, category, [,lockstring [, default_pass]]])

  • -
  • report_to (Object) – An object with a msg() method to report -errors to. If not given, errors will be logged.

  • -
-
-
Returns
-

Account – The newly created Account.

-
-
Raises
-

ValueError – If key already exists in database.

-
-
-

Notes

-

Usually only the server admin should need to be superuser, all -other access levels can be handled with more fine-grained -permissions or groups. A superuser bypasses all lock checking -operations and is thus not suitable for play-testing the game.

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.dbserialize.html b/docs/0.9.5/api/evennia.utils.dbserialize.html deleted file mode 100644 index f5745524ab..0000000000 --- a/docs/0.9.5/api/evennia.utils.dbserialize.html +++ /dev/null @@ -1,193 +0,0 @@ - - - - - - - - - evennia.utils.dbserialize — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.dbserialize

-

This module handles serialization of arbitrary python structural data, -intended primarily to be stored in the database. It also supports -storing Django model instances (which plain pickle cannot do).

-

This serialization is used internally by the server, notably for -storing data in Attributes and for piping data to process pools.

-

The purpose of dbserialize is to handle all forms of data. For -well-structured non-arbitrary exchange, such as communicating with a -rich web client, a simpler JSON serialization makes more sense.

-

This module also implements the SaverList, SaverDict and SaverSet -classes. These are iterables that track their position in a nested -structure and makes sure to send updates up to their root. This is -used by Attributes - without it, one would not be able to update mutables -in-situ, e.g obj.db.mynestedlist[3][5] = 3 would never be saved and -be out of sync with the database.

-
-
-evennia.utils.dbserialize.to_pickle(data)[source]
-

This prepares data on arbitrary form to be pickled. It handles any -nested structure and returns data on a form that is safe to pickle -(including having converted any database models to their internal -representation). We also convert any Saver*-type objects back to -their normal representations, they are not pickle-safe.

-
-
Parameters
-

data (any) – Data to pickle.

-
-
Returns
-

data (any) – Pickled data.

-
-
-
- -
-
-evennia.utils.dbserialize.from_pickle(data, db_obj=None)[source]
-

This should be fed a just de-pickled data object. It will be converted back -to a form that may contain database objects again. Note that if a database -object was removed (or changed in-place) in the database, None will be -returned.

-
-
Parameters
-
    -
  • data (any) – Pickled data to unpickle.

  • -
  • db_obj (Atribute, any) – This is the model instance (normally -an Attribute) that _Saver*-type iterables (_SaverList etc) -will save to when they update. It must have a ‘value’ property -that saves assigned data to the database. Skip if not -serializing onto a given object. If db_obj is given, this -function will convert lists, dicts and sets to their -_SaverList, _SaverDict and _SaverSet counterparts.

  • -
-
-
Returns
-

data (any) – Unpickled data.

-
-
-
- -
-
-evennia.utils.dbserialize.do_pickle(data)[source]
-

Perform pickle to string

-
- -
-
-evennia.utils.dbserialize.do_unpickle(data)[source]
-

Retrieve pickle from pickled string

-
- -
-
-evennia.utils.dbserialize.dbserialize(data)[source]
-

Serialize to pickled form in one step

-
- -
-
-evennia.utils.dbserialize.dbunserialize(data, db_obj=None)[source]
-

Un-serialize in one step. See from_pickle for help db_obj.

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.eveditor.html b/docs/0.9.5/api/evennia.utils.eveditor.html deleted file mode 100644 index 5d6f360bfa..0000000000 --- a/docs/0.9.5/api/evennia.utils.eveditor.html +++ /dev/null @@ -1,560 +0,0 @@ - - - - - - - - - evennia.utils.eveditor — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.eveditor

-

EvEditor (Evennia Line Editor)

-

This implements an advanced line editor for editing longer texts in-game. The -editor mimics the command mechanisms of the “VI” editor (a famous line-by-line -editor) as far as reasonable.

-

Features of the editor:

-
    -
  • undo/redo.

  • -
  • edit/replace on any line of the buffer.

  • -
  • search&replace text anywhere in buffer.

  • -
  • formatting of buffer, or selection, to certain width + indentations.

  • -
  • allow to echo the input or not, depending on your client.

  • -
  • in-built help

  • -
-

To use the editor, just import EvEditor from this module and initialize it:

-
from evennia.utils.eveditor import EvEditor
-
-# set up an editor to edit the caller's 'desc' Attribute
-def _loadfunc(caller):
-    return caller.db.desc
-
-def _savefunc(caller, buffer):
-    caller.db.desc = buffer.strip()
-    return True
-
-def _quitfunc(caller):
-    caller.msg("Custom quit message")
-
-# start the editor
-EvEditor(caller, loadfunc=None, savefunc=None, quitfunc=None, key="",
-         persistent=True, code=False)
-
-
-

The editor can also be used to format Python code and be made to -survive a reload. See the EvEditor class for more details.

-
-
-class evennia.utils.eveditor.CmdSaveYesNo(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

Save the editor state on quit. This catches -nomatches (defaults to Yes), and avoid saves only if -command was given specifically as “no” or “n”.

-
-
-key = '__nomatch_command'
-
- -
-
-aliases = ['__noinput_command']
-
- -
-
-locks = 'cmd:all()'
-
- -
-
-help_cateogory = 'LineEditor'
-
- -
-
-func()[source]
-

Implement the yes/no choice.

-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': '__noinput_command', 'category': 'general', 'key': '__nomatch_command', 'no_prefix': ' __noinput_command', 'tags': '', 'text': '\n Save the editor state on quit. This catches\n nomatches (defaults to Yes), and avoid saves only if\n command was given specifically as "no" or "n".\n '}
-
- -
- -
-
-class evennia.utils.eveditor.SaveYesNoCmdSet(cmdsetobj=None, key=None)[source]
-

Bases: evennia.commands.cmdset.CmdSet

-

Stores the yesno question

-
-
-key = 'quitsave_yesno'
-
- -
-
-priority = 150
-
- -
-
-mergetype = 'Replace'
-
- -
-
-at_cmdset_creation()[source]
-

at cmdset creation

-
- -
-
-path = 'evennia.utils.eveditor.SaveYesNoCmdSet'
-
- -
- -
-
-class evennia.utils.eveditor.CmdEditorBase(**kwargs)[source]
-

Bases: evennia.commands.default.muxcommand.MuxCommand

-

Base parent for editor commands

-
-
-locks = 'cmd:all()'
-
- -
-
-help_entry = 'LineEditor'
-
- -
-
-editor = None
-
- -
-
-parse()[source]
-

Handles pre-parsing. Editor commands are on the form

-
:cmd [li] [w] [txt]
-
-
-

Where all arguments are optional.

-
    -
  • -
    li - line number (int), starting from 1. This could also

    be a range given as <l>:<l>.

    -
    -
    -
  • -
  • w - word(s) (string), could be encased in quotes.

  • -
  • txt - extra text (string), could be encased in quotes.

  • -
-
- -
-
-aliases = []
-
- -
-
-help_category = 'general'
-
- -
-
-key = 'command'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': 'command', 'no_prefix': ' ', 'tags': '', 'text': '\n Base parent for editor commands\n '}
-
- -
- -
-
-class evennia.utils.eveditor.CmdLineInput(**kwargs)[source]
-

Bases: evennia.utils.eveditor.CmdEditorBase

-

No command match - Inputs line of text into buffer.

-
-
-key = '__nomatch_command'
-
- -
-
-aliases = ['__noinput_command']
-
- -
-
-func()[source]
-

Adds the line without any formatting changes.

-

If the editor handles code, it might add automatic -indentation.

-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': '__noinput_command', 'category': 'general', 'key': '__nomatch_command', 'no_prefix': ' __noinput_command', 'tags': '', 'text': '\n No command match - Inputs line of text into buffer.\n\n '}
-
- -
- -
-
-class evennia.utils.eveditor.CmdEditorGroup(**kwargs)[source]
-

Bases: evennia.utils.eveditor.CmdEditorBase

-

Commands for the editor

-
-
-key = ':editor_command_group'
-
- -
-
-aliases = [':q!', ':::', ':dw', ':<', ':x', ':f', ':uu', ':DD', ':q', ':w', ':S', ':h', ':r', ':p', ':I', ':y', ':A', ':echo', ':j', ':', ':u', ':=', ':i', ':wq', '::', ':s', ':fd', ':fi', ':dd', ':UU', ':!', ':>']
-
- -
-
-arg_regex = re.compile('\\s.*?|$', re.IGNORECASE)
-
- -
-
-func()[source]
-

This command handles all the in-editor :-style commands. Since -each command is small and very limited, this makes for a more -efficient presentation.

-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all()'
-
- -
-
-search_index_entry = {'aliases': ':q! ::: :dw :< :x :f :uu :DD :q :w :S :h :r :p :I :y :A :echo :j : :u := :i :wq :: :s :fd :fi :dd :UU :! :>', 'category': 'general', 'key': ':editor_command_group', 'no_prefix': ' :q! ::: :dw :< :x :f :uu :DD :q :w :S :h :r :p :I :y :A :echo :j : :u := :i :wq :: :s :fd :fi :dd :UU :! :>', 'tags': '', 'text': '\n Commands for the editor\n '}
-
- -
- -
-
-class evennia.utils.eveditor.EvEditorCmdSet(cmdsetobj=None, key=None)[source]
-

Bases: evennia.commands.cmdset.CmdSet

-

CmdSet for the editor commands

-
-
-key = 'editorcmdset'
-
- -
-
-mergetype = 'Replace'
-
- -
-
-at_cmdset_creation()[source]
-

Hook method - this should be overloaded in the inheriting -class, and should take care of populating the cmdset by use of -self.add().

-
- -
-
-path = 'evennia.utils.eveditor.EvEditorCmdSet'
-
- -
- -
-
-class evennia.utils.eveditor.EvEditor(caller, loadfunc=None, savefunc=None, quitfunc=None, key='', persistent=False, codefunc=False)[source]
-

Bases: object

-

This defines a line editor object. It creates all relevant commands -and tracks the current state of the buffer. It also cleans up after -itself.

-
-
-__init__(caller, loadfunc=None, savefunc=None, quitfunc=None, key='', persistent=False, codefunc=False)[source]
-

Launches a full in-game line editor, mimicking the functionality of VIM.

-
-
Parameters
-
    -
  • caller (Object) – Who is using the editor.

  • -
  • loadfunc (callable, optional) – This will be called as -loadfunc(caller) when the editor is first started. Its -return will be used as the editor’s starting buffer.

  • -
  • savefunc (callable, optional) – This will be called as -savefunc(caller, buffer) when the save-command is given and -is used to actually determine where/how result is saved. -It should return True if save was successful and also -handle any feedback to the user.

  • -
  • quitfunc (callable, optional) – This will optionally be -called as quitfunc(caller) when the editor is -exited. If defined, it should handle all wanted feedback -to the user.

  • -
  • quitfunc_args (tuple, optional) – Optional tuple of arguments to -supply to quitfunc.

  • -
  • key (str, optional) – An optional key for naming this -session and make it unique from other editing sessions.

  • -
  • persistent (bool, optional) – Make the editor survive a reboot. Note -that if this is set, all callables must be possible to pickle

  • -
  • codefunc (bool, optional) – If given, will run the editor in code mode. -This will be called as codefunc(caller, buf).

  • -
-
-
-

Notes

-

In persistent mode, all the input callables (savefunc etc) -must be possible to be pickled, this excludes e.g. -callables that are class methods or functions defined -dynamically or as part of another function. In -non-persistent mode no such restrictions exist.

-
- -
-
-load_buffer()[source]
-

Load the buffer using the load function hook.

-
- -
-
-get_buffer()[source]
-
-
Returns
-

buffer (str) – The current buffer.

-
-
-
- -
-
-update_buffer(buf)[source]
-

This should be called when the buffer has been changed -somehow. It will handle unsaved flag and undo updating.

-
-
Parameters
-

buf (str) – The text to update the buffer with.

-
-
-
- -
-
-quit()[source]
-

Cleanly exit the editor.

-
- -
-
-save_buffer()[source]
-

Saves the content of the buffer.

-
- -
-
-update_undo(step=None)[source]
-

This updates the undo position.

-
-
Parameters
-

step (int, optional) – The amount of steps -to progress the undo position to. This -may be a negative value for undo and -a positive value for redo.

-
-
-
- -
-
-display_buffer(buf=None, offset=0, linenums=True, options={'raw': False})[source]
-

This displays the line editor buffer, or selected parts of it.

-
-
Parameters
-
    -
  • buf (str, optional) – The buffer or part of buffer to display.

  • -
  • offset (int, optional) – If buf is set and is not the full buffer, -offset should define the actual starting line number, to -get the linenum display right.

  • -
  • linenums (bool, optional) – Show line numbers in buffer.

  • -
  • options – raw (bool, optional): Tell protocol to not parse -formatting information.

  • -
-
-
-
- -
-
-display_help()[source]
-

Shows the help entry for the editor.

-
- -
-
-deduce_indent(line, buffer)[source]
-

Try to deduce the level of indentation of the given line.

-
- -
-
-decrease_indent()[source]
-

Decrease automatic indentation by 1 level.

-
- -
-
-increase_indent()[source]
-

Increase automatic indentation by 1 level.

-
- -
-
-swap_autoindent()[source]
-

Swap automatic indentation on or off.

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.evform.html b/docs/0.9.5/api/evennia.utils.evform.html deleted file mode 100644 index e2246a0409..0000000000 --- a/docs/0.9.5/api/evennia.utils.evform.html +++ /dev/null @@ -1,289 +0,0 @@ - - - - - - - - - evennia.utils.evform — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.evform

-

EvForm - a way to create advanced ASCII forms

-

This is intended for creating advanced ASCII game forms, such as a -large pretty character sheet or info document.

-

The system works on the basis of a readin template that is given in a -separate Python file imported into the handler. This file contains -some optional settings and a string mapping out the form. The template -has markers in it to denounce fields to fill. The markers map the -absolute size of the field and will be filled with an evtable.EvCell -object when displaying the form.

-

Example of input file testform.py:

-
FORMCHAR = "x"
-TABLECHAR = "c"
-
-FORM = '''
-.------------------------------------------------.
-|                                                |
-|  Name: xxxxx1xxxxx    Player: xxxxxxx2xxxxxxx  |
-|        xxxxxxxxxxx                             |
-|                                                |
- >----------------------------------------------<
-|                                                |
-| Desc:  xxxxxxxxxxx    STR: x4x    DEX: x5x     |
-|        xxxxx3xxxxx    INT: x6x    STA: x7x     |
-|        xxxxxxxxxxx    LUC: x8x    MAG: x9x     |
-|                                                |
- >----------------------------------------------<
-|          |                                     |
-| cccccccc | ccccccccccccccccccccccccccccccccccc |
-| cccccccc | ccccccccccccccccccccccccccccccccccc |
-| cccAcccc | ccccccccccccccccccccccccccccccccccc |
-| cccccccc | ccccccccccccccccccccccccccccccccccc |
-| cccccccc | cccccccccccccccccBccccccccccccccccc |
-|          |                                     |
--------------------------------------------------
-'''
-
-
-

The first line of the FORM string is ignored. The forms and table -markers must mark out complete, unbroken rectangles, each containing -one embedded single-character identifier (so the smallest element -possible is a 3-character wide form). The identifier can be any -character except for the FORM_CHAR and TABLE_CHAR and some of the -common ASCII-art elements, like space, _ | * etc (see -INVALID_FORMCHARS in this module). Form Rectangles can have any size, -but must be separated from each other by at least one other -character’s width.

-

Use as follows:

-
from evennia import EvForm, EvTable
-
-# create a new form from the template
-form = EvForm("path/to/testform.py")
-
-(MudForm can also take a dictionary holding
- the required keys FORMCHAR, TABLECHAR and FORM)
-
-# add data to each tagged form cell
-form.map(cells={1: "Tom the Bouncer",
-                2: "Griatch",
-                3: "A sturdy fellow",
-                4: 12,
-                5: 10,
-                6:  5,
-                7: 18,
-                8: 10,
-                9:  3})
-# create the EvTables
-tableA = EvTable("HP","MV","MP",
-                           table=[["**"], ["*****"], ["***"]],
-                           border="incols")
-tableB = EvTable("Skill", "Value", "Exp",
-                           table=[["Shooting", "Herbalism", "Smithing"],
-                                  [12,14,9],["550/1200", "990/1400", "205/900"]],
-                           border="incols")
-# add the tables to the proper ids in the form
-form.map(tables={"A": tableA,
-                 "B": tableB})
-
-print(form)
-
-
-

This produces the following result:

-
.------------------------------------------------.
-|                                                |
-|  Name: Tom the        Player: Griatch          |
-|        Bouncer                                 |
-|                                                |
- >----------------------------------------------<
-|                                                |
-| Desc:  A sturdy       STR: 12     DEX: 10      |
-|        fellow         INT: 5      STA: 18      |
-|                       LUC: 10     MAG: 3       |
-|                                                |
- >----------------------------------------------<
-|          |                                     |
-| HP|MV|MP | Skill      |Value      |Exp         |
-| ~~+~~+~~ | ~~~~~~~~~~~+~~~~~~~~~~~+~~~~~~~~~~~ |
-| **|**|** | Shooting   |12         |550/1200    |
-|   |**|*  | Herbalism  |14         |990/1400    |
-|   |* |   | Smithing   |9          |205/900     |
-|          |                                     |
- ------------------------------------------------
-
-
-

The marked forms have been replaced with EvCells of text and with -EvTables. The form can be updated by simply re-applying form.map() -with the updated data.

-

When working with the template ASCII file, you can use form.reload() -to re-read the template and re-apply all existing mappings.

-

Each component is restrained to the width and height specified by the -template, so it will resize to fit (or crop text if the area is too -small for it). If you try to fit a table into an area it cannot fit -into (when including its borders and at least one line of text), the -form will raise an error.

-
-
-
-class evennia.utils.evform.EvForm(filename=None, cells=None, tables=None, form=None, **kwargs)[source]
-

Bases: object

-

This object is instantiated with a text file and parses -it for rectangular form fields. It can then be fed a -mapping so as to populate the fields with fixed-width -EvCell or Tables.

-
-
-__init__(filename=None, cells=None, tables=None, form=None, **kwargs)[source]
-

Initiate the form

-
-
Keyword Arguments
-
    -
  • filename (str) – Path to template file.

  • -
  • cells (dict) – A dictionary mapping {id: text}

  • -
  • tables (dict) – A dictionary mapping {id: EvTable}.

  • -
  • form (dict) – A dictionary -{“FORMCHAR”:char, “TABLECHAR”:char, “FORM”:templatestring}. -If this is given, filename is not read.

  • -
-
-
-

Notes

-

Other kwargs are fed as options to the EvCells and EvTables -(see evtable.EvCell and evtable.EvTable for more info).

-
- -
-
-map(cells=None, tables=None, **kwargs)[source]
-

Add mapping for form.

-
-
Parameters
-
    -
  • cells (dict) – A dictionary of {identifier:celltext}

  • -
  • tables (dict) – A dictionary of {identifier:table}

  • -
-
-
-

Notes

-

kwargs will be forwarded to tables/cells. See -evtable.EvCell and evtable.EvTable for info.

-
- -
-
-reload(filename=None, form=None, **kwargs)[source]
-

Creates the form from a stored file name.

-
-
Parameters
-
    -
  • filename (str) – The file to read from.

  • -
  • form (dict) – A mapping for the form.

  • -
-
-
-

Notes

-

Kwargs are passed through to Cel creation.

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.evmenu.html b/docs/0.9.5/api/evennia.utils.evmenu.html deleted file mode 100644 index 8daea11b9e..0000000000 --- a/docs/0.9.5/api/evennia.utils.evmenu.html +++ /dev/null @@ -1,1199 +0,0 @@ - - - - - - - - - evennia.utils.evmenu — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.evmenu

-

EvMenu

-

This implements a full menu system for Evennia.

-

To start the menu, just import the EvMenu class from this module. -Example usage:

-
from evennia.utils.evmenu import EvMenu
-
-EvMenu(caller, menu_module_path,
-     startnode="node1",
-     cmdset_mergetype="Replace", cmdset_priority=1,
-     auto_quit=True, cmd_on_exit="look", persistent=True)
-
-
-

Where caller is the Object to use the menu on - it will get a new -cmdset while using the Menu. The menu_module_path is the python path -to a python module containing function definitions. By adjusting the -keyword options of the Menu() initialization call you can start the -menu at different places in the menu definition file, adjust if the -menu command should overload the normal commands or not, etc.

-

The persistent keyword will make the menu survive a server reboot. -It is False by default. Note that if using persistent mode, every -node and callback in the menu must be possible to be pickled, this -excludes e.g. callables that are class methods or functions defined -dynamically or as part of another function. In non-persistent mode -no such restrictions exist.

-

The menu is defined in a module (this can be the same module as the -command definition too) with function definitions:

-
def node1(caller):
-    # (this is the start node if called like above)
-    # code
-    return text, options
-
-def node_with_other_name(caller, input_string):
-    # code
-    return text, options
-
-def another_node(caller, input_string, **kwargs):
-    # code
-    return text, options
-
-
-

Where caller is the object using the menu and input_string is the -command entered by the user on the previous node (the command -entered to get to this node). The node function code will only be -executed once per node-visit and the system will accept nodes with -both one or two arguments interchangeably. It also accepts nodes -that takes **kwargs.

-

The menu tree itself is available on the caller as -caller.ndb._evmenu. This makes it a convenient place to store -temporary state variables between nodes, since this NAttribute is -deleted when the menu is exited.

-

The return values must be given in the above order, but each can be -returned as None as well. If the options are returned as None, the -menu is immediately exited and the default “look” command is called.

-
    -
  • -
    text (str, tuple or None): Text shown at this node. If a tuple, the

    second element in the tuple is a help text to display at this -node when the user enters the menu help command there.

    -
    -
    -
  • -
  • options (tuple, dict or None): If None, this exits the menu. -If a single dict, this is a single-option node. If a tuple, -it should be a tuple of option dictionaries. Option dicts have the following keys:

    -
      -
    • key (str or tuple, optional): What to enter to choose this option. -If a tuple, it must be a tuple of strings, where the first string is the -key which will be shown to the user and the others are aliases. -If unset, the options’ number will be used. The special key _default -marks this option as the default fallback when no other option matches -the user input. There can only be one _default option per node. It -will not be displayed in the list.

    • -
    • desc (str, optional): This describes what choosing the option will do.

    • -
    • goto (str, tuple or callable): If string, should be the name of node to go to -when this option is selected. If a callable, it has the signature -callable(caller[,raw_input][,**kwargs]). If a tuple, the first element -is the callable and the second is a dict with the **kwargs to pass to -the callable. Those kwargs will also be passed into the next node if possible. -Such a callable should return either a str or a (str, dict), where the -string is the name of the next node to go to and the dict is the new, -(possibly modified) kwarg to pass into the next node. If the callable returns -None or the empty string, the current node will be revisited.

    • -
    • exec (str, callable or tuple, optional): This takes the same input as goto above -and runs before it. If given a node name, the node will be executed but will not -be considered the next node. If node/callback returns str or (str, dict), these will -replace the goto step (goto callbacks will not fire), with the string being the -next node name and the optional dict acting as the kwargs-input for the next node. -If an exec callable returns the empty string (only), the current node is re-run.

    • -
    -
  • -
-

If key is not given, the option will automatically be identified by -its number 1..N.

-

Example:

-
# in menu_module.py
-
-def node1(caller):
-    text = ("This is a node text",
-            "This is help text for this node")
-    options = ({"key": "testing",
-                "desc": "Select this to go to node 2",
-                "goto": ("node2", {"foo": "bar"}),
-                "exec": "callback1"},
-               {"desc": "Go to node 3.",
-                "goto": "node3"})
-    return text, options
-
-def callback1(caller):
-    # this is called when choosing the "testing" option in node1
-    # (before going to node2). If it returned a string, say 'node3',
-    # then the next node would be node3 instead of node2 as specified
-    # by the normal 'goto' option key above.
-    caller.msg("Callback called!")
-
-def node2(caller, **kwargs):
-    text = '''
-        This is node 2. It only allows you to go back
-        to the original node1. This extra indent will
-        be stripped. We don't include a help text but
-        here are the variables passed to us: {}
-        '''.format(kwargs)
-    options = {"goto": "node1"}
-    return text, options
-
-def node3(caller):
-    text = "This ends the menu since there are no options."
-    return text, None
-
-
-

When starting this menu with Menu(caller, “path.to.menu_module”), -the first node will look something like this:

-
This is a node text
-______________________________________
-
-testing: Select this to go to node 2
-2: Go to node 3
-
-
-

Where you can both enter “testing” and “1” to select the first option. -If the client supports MXP, they may also mouse-click on “testing” to -do the same. When making this selection, a function “callback1” in the -same Using help will show the help text, otherwise a list of -available commands while in menu mode.

-

The menu tree is exited either by using the in-menu quit command or by -reaching a node without any options.

-

For a menu demo, import CmdTestMenu from this module and add it to -your default cmdset. Run it with this module, like testmenu evennia.utils.evmenu.

- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.evmore.html b/docs/0.9.5/api/evennia.utils.evmore.html deleted file mode 100644 index 268380d053..0000000000 --- a/docs/0.9.5/api/evennia.utils.evmore.html +++ /dev/null @@ -1,570 +0,0 @@ - - - - - - - - - evennia.utils.evmore — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.evmore

-

EvMore - pager mechanism

-

This is a pager for displaying long texts and allows stepping up and down in -the text (the name comes from the traditional ‘more’ unix command).

-

To use, simply pass the text through the EvMore object:

-
from evennia.utils.evmore import EvMore
-
-text = some_long_text_output()
-EvMore(caller, text, always_page=False, session=None, justify_kwargs=None, **kwargs)
-
-
-

One can also use the convenience function msg from this module to avoid -having to set up the EvMenu object manually:

-
from evennia.utils import evmore
-
-text = some_long_text_output()
-evmore.msg(caller, text, always_page=False, session=None, justify_kwargs=None, **kwargs)
-
-
-

The always_page argument decides if the pager is used also if the text is not long -enough to need to scroll, session is used to determine which session to relay -to and justify_kwargs are kwargs to pass to utils.utils.justify in order to -change the formatting of the text. The remaining **kwargs will be passed on to -the caller.msg() construct every time the page is updated.

-
-
-
-class evennia.utils.evmore.CmdMore(**kwargs)[source]
-

Bases: evennia.commands.command.Command

-

Manipulate the text paging. Catch no-input with aliases.

-
-
-key = '__noinput_command'
-
- -
-
-aliases = ['quit', 't', 'n', 'p', 'abort', 'top', 'a', 'q', 'end', 'e', 'next', 'previous']
-
- -
-
-auto_help = False
-
- -
-
-func()[source]
-

Implement the command

-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all();'
-
- -
-
-search_index_entry = {'aliases': 'quit t n p abort top a q end e next previous', 'category': 'general', 'key': '__noinput_command', 'no_prefix': ' quit t n p abort top a q end e next previous', 'tags': '', 'text': '\n Manipulate the text paging. Catch no-input with aliases.\n '}
-
- -
- -
-
-class evennia.utils.evmore.CmdMoreExit(**kwargs)[source]
-

Bases: evennia.commands.command.Command

-

Any non-more command will exit the pager.

-
-
-key = '__nomatch_command'
-
- -
-
-func()[source]
-

Exit pager and re-fire the failed command.

-
- -
-
-aliases = []
-
- -
-
-help_category = 'general'
-
- -
-
-lock_storage = 'cmd:all();'
-
- -
-
-search_index_entry = {'aliases': '', 'category': 'general', 'key': '__nomatch_command', 'no_prefix': ' ', 'tags': '', 'text': '\n Any non-more command will exit the pager.\n\n '}
-
- -
- -
-
-class evennia.utils.evmore.CmdSetMore(cmdsetobj=None, key=None)[source]
-

Bases: evennia.commands.cmdset.CmdSet

-

Stores the more command

-
-
-key = 'more_commands'
-
- -
-
-priority = 110
-
- -
-
-mergetype = 'Replace'
-
- -
-
-at_cmdset_creation()[source]
-

Hook method - this should be overloaded in the inheriting -class, and should take care of populating the cmdset by use of -self.add().

-
- -
-
-path = 'evennia.utils.evmore.CmdSetMore'
-
- -
- -
-
-evennia.utils.evmore.queryset_maxsize(qs)[source]
-
- -
-
-class evennia.utils.evmore.EvMore(caller, inp, always_page=False, session=None, justify=False, justify_kwargs=None, exit_on_lastpage=False, exit_cmd=None, page_formatter=<class 'str'>, **kwargs)[source]
-

Bases: object

-

The main pager object

-
-
-__init__(caller, inp, always_page=False, session=None, justify=False, justify_kwargs=None, exit_on_lastpage=False, exit_cmd=None, page_formatter=<class 'str'>, **kwargs)[source]
-

Initialization of the EvMore pager.

-
-
Parameters
-
    -
  • caller (Object or Account) – Entity reading the text.

  • -
  • inp (str, EvTable, Paginator or iterator) –

    The text or data to put under paging.

    -
      -
    • If a string, paginage normally. If this text contains -one or more \f format symbol, automatic pagination and justification -are force-disabled and page-breaks will only happen after each \f.

    • -
    • If EvTable, the EvTable will be paginated with the same -setting on each page if it is too long. The table -decorations will be considered in the size of the page.

    • -
    • Otherwise inp is converted to an iterator, where each step is -expected to be a line in the final display. Each line -will be run through iter_callable.

    • -
    -

  • -
  • always_page (bool, optional) – If False, the -pager will only kick in if inp is too big -to fit the screen.

  • -
  • session (Session, optional) – If given, this session will be used -to determine the screen width and will receive all output.

  • -
  • justify (bool, optional) – If set, auto-justify long lines. This must be turned -off for fixed-width or formatted output, like tables. It’s force-disabled -if inp is an EvTable.

  • -
  • justify_kwargs (dict, optional) – Keywords for the justifiy function. Used only -if justify is True. If this is not set, default arguments will be used.

  • -
  • exit_on_lastpage (bool, optional) – If reaching the last page without the -page being completely filled, exit pager immediately. If unset, -another move forward is required to exit. If set, the pager -exit message will not be shown.

  • -
  • exit_cmd (str, optional) – If given, this command-string will be executed on -the caller when the more page exits. Note that this will be using whatever -cmdset the user had before the evmore pager was activated (so none of -the evmore commands will be available when this is run).

  • -
  • kwargs (any, optional) – These will be passed on to the caller.msg method.

  • -
-
-
-

Examples

-
super_long_text = " ... "
-EvMore(caller, super_long_text)
-
-
-

Paginator

-
from django.core.paginator import Paginator
-query = ObjectDB.objects.all()
-pages = Paginator(query, 10)  # 10 objs per page
-EvMore(caller, pages)
-
-
-

Every page an EvTable

-
from evennia import EvTable
-def _to_evtable(page):
-    table = ... # convert page to a table
-    return EvTable(*headers, table=table, ...)
-EvMore(caller, pages, page_formatter=_to_evtable)
-
-
-
- -
-
-display(show_footer=True)[source]
-

Pretty-print the page.

-
- -
-
-page_top()[source]
-

Display the top page

-
- -
-
-page_end()[source]
-

Display the bottom page.

-
- -
-
-page_next()[source]
-

Scroll the text to the next page. Quit if already at the end -of the page.

-
- -
-
-page_back()[source]
-

Scroll the text back up, at the most to the top.

-
- -
-
-page_quit(quiet=False)[source]
-

Quit the pager

-
- -
-
-start()[source]
-

Starts the pagination

-
- -
-
-paginator_index(pageno)[source]
-

Paginate to specific, known index

-
- -
-
-paginator_slice(pageno)[source]
-

Paginate by slice. This is done with an eye on memory efficiency (usually for -querysets); to avoid fetching all objects at the same time.

-
- -
-
-paginator_django(pageno)[source]
-

Paginate using the django queryset Paginator API. Note that his is indexed from 1.

-
- -
-
-init_evtable(table)[source]
-

The input is an EvTable.

-
- -
-
-init_queryset(qs)[source]
-

The input is a queryset

-
- -
-
-init_django_paginator(pages)[source]
-

The input is a django Paginator object.

-
- -
-
-init_iterable(inp)[source]
-

The input is something other than a string - convert to iterable of strings

-
- -
-
-init_f_str(text)[source]
-

The input contains f markers. We use f to indicate the user wants to -enforce their line breaks on their own. If so, we do no automatic -line-breaking/justification at all.

-
-
Parameters
-

text (str) – The string to format with f-markers.

-
-
-
- -
-
-init_str(text)[source]
-

The input is a string

-
- -
-
-init_pages(inp)[source]
-

Initialize the pagination. By default, will analyze input type to determine -how pagination automatically.

-
-
Parameters
-

inp (any) – Incoming data to be paginated. By default, handles pagination of -strings, querysets, django.Paginator, EvTables and any iterables with strings.

-
-
-

Notes

-

If overridden, this method must perform the following actions:

-
    -
  • read and re-store self._data (the incoming data set) if needed for pagination to -work.

  • -
  • set self._npages to the total number of pages. Default is 1.

  • -
  • set self._paginator to a callable that will take a page number 1…N and return -the data to display on that page (not any decorations or next/prev buttons). If only -wanting to change the paginator, override self.paginator instead.

  • -
  • set self._page_formatter to a callable that will receive the page from -self._paginator and format it with one element per line. Default is str. Or -override self.page_formatter directly instead.

  • -
-

By default, helper methods are called that perform these actions -depending on supported inputs.

-
- -
-
-paginator(pageno)[source]
-

Paginator. The data operated upon is in self._data.

-
-
Parameters
-

pageno (int) – The page number to view, from 0…N-1

-
-
Returns
-

str

-
-
The page to display (without any decorations, those are added

by EvMore).

-
-
-

-
-
-
- -
-
-page_formatter(page)[source]
-

Page formatter. Every page passes through this method. Override -it to customize behvaior per-page. A common use is to generate a new -EvTable for every page (this is more efficient than to generate one huge -EvTable across many pages and feed it into EvMore all at once).

-
-
Parameters
-

page (any) – A piece of data representing one page to display. This must

-
-
Returns
-

str

-
-
A ready-formatted page to display. Extra footer with help about

switching to the next/prev page will be added automatically

-
-
-

-
-
-
- -
- -
-
-evennia.utils.evmore.msg(caller, text='', always_page=False, session=None, justify=False, justify_kwargs=None, exit_on_lastpage=True, **kwargs)[source]
-
-

EvMore-supported version of msg, mimicking the normal msg method.

-
-

Initialization of the EvMore pager.

-
-
Parameters
-
    -
  • caller (Object or Account) – Entity reading the text.

  • -
  • inp (str, EvTable, Paginator or iterator) –

    The text or data to put under paging.

    -
      -
    • If a string, paginage normally. If this text contains -one or more \f format symbol, automatic pagination and justification -are force-disabled and page-breaks will only happen after each \f.

    • -
    • If EvTable, the EvTable will be paginated with the same -setting on each page if it is too long. The table -decorations will be considered in the size of the page.

    • -
    • Otherwise inp is converted to an iterator, where each step is -expected to be a line in the final display. Each line -will be run through iter_callable.

    • -
    -

  • -
  • always_page (bool, optional) – If False, the -pager will only kick in if inp is too big -to fit the screen.

  • -
  • session (Session, optional) – If given, this session will be used -to determine the screen width and will receive all output.

  • -
  • justify (bool, optional) – If set, auto-justify long lines. This must be turned -off for fixed-width or formatted output, like tables. It’s force-disabled -if inp is an EvTable.

  • -
  • justify_kwargs (dict, optional) – Keywords for the justifiy function. Used only -if justify is True. If this is not set, default arguments will be used.

  • -
  • exit_on_lastpage (bool, optional) – If reaching the last page without the -page being completely filled, exit pager immediately. If unset, -another move forward is required to exit. If set, the pager -exit message will not be shown.

  • -
  • exit_cmd (str, optional) – If given, this command-string will be executed on -the caller when the more page exits. Note that this will be using whatever -cmdset the user had before the evmore pager was activated (so none of -the evmore commands will be available when this is run).

  • -
  • kwargs (any, optional) – These will be passed on to the caller.msg method.

  • -
-
-
-

Examples

-
super_long_text = " ... "
-EvMore(caller, super_long_text)
-
-
-

Paginator

-
from django.core.paginator import Paginator
-query = ObjectDB.objects.all()
-pages = Paginator(query, 10)  # 10 objs per page
-EvMore(caller, pages)
-
-
-

Every page an EvTable

-
from evennia import EvTable
-def _to_evtable(page):
-    table = ... # convert page to a table
-    return EvTable(*headers, table=table, ...)
-EvMore(caller, pages, page_formatter=_to_evtable)
-
-
-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.evtable.html b/docs/0.9.5/api/evennia.utils.evtable.html deleted file mode 100644 index d4c3b6f476..0000000000 --- a/docs/0.9.5/api/evennia.utils.evtable.html +++ /dev/null @@ -1,679 +0,0 @@ - - - - - - - - - evennia.utils.evtable — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.evtable

-

This is an advanced ASCII table creator. It was inspired by Prettytable -(https://code.google.com/p/prettytable/) but shares no code and is considerably -more advanced, supporting auto-balancing of incomplete tables and ANSI colors among -other things.

-

Example usage:

-
from evennia.utils import evtable
-
-table = evtable.EvTable("Heading1", "Heading2",
-                table=[[1,2,3],[4,5,6],[7,8,9]], border="cells")
-table.add_column("This is long data", "This is even longer data")
-table.add_row("This is a single row")
-print table
-
-
-

Result:

-
+----------------------+----------+---+--------------------------+
-|       Heading1       | Heading2 |   |                          |
-+~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~~+~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~+
-|           1          |     4    | 7 |     This is long data    |
-+----------------------+----------+---+--------------------------+
-|           2          |     5    | 8 | This is even longer data |
-+----------------------+----------+---+--------------------------+
-|           3          |     6    | 9 |                          |
-+----------------------+----------+---+--------------------------+
-| This is a single row |          |   |                          |
-+----------------------+----------+---+--------------------------+
-
-
-

As seen, the table will automatically expand with empty cells to make -the table symmetric. Tables can be restricted to a given width:

-
table.reformat(width=50, align="l")
-
-
-

(We could just have added these keywords to the table creation call)

-

This yields the following result:

-
+-----------+------------+-----------+-----------+
-| Heading1  | Heading2   |           |           |
-+~~~~~~~~~~~+~~~~~~~~~~~~+~~~~~~~~~~~+~~~~~~~~~~~+
-| 1         | 4          | 7         | This is   |
-|           |            |           | long data |
-+-----------+------------+-----------+-----------+
-|           |            |           | This is   |
-| 2         | 5          | 8         | even      |
-|           |            |           | longer    |
-|           |            |           | data      |
-+-----------+------------+-----------+-----------+
-| 3         | 6          | 9         |           |
-+-----------+------------+-----------+-----------+
-| This is a |            |           |           |
-|  single   |            |           |           |
-| row       |            |           |           |
-+-----------+------------+-----------+-----------+
-
-
-

Table-columns can be individually formatted. Note that if an -individual column is set with a specific width, table auto-balancing -will not affect this column (this may lead to the full table being too -wide, so be careful mixing fixed-width columns with auto- balancing). -Here we change the width and alignment of the column at index 3 -(Python starts from 0):

-
table.reformat_column(3, width=30, align="r")
-print table
-
-
-
+-----------+-------+-----+-----------------------------+---------+
-| Heading1  | Headi |     |                             |         |
-|           | ng2   |     |                             |         |
-+~~~~~~~~~~~+~~~~~~~+~~~~~+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+~~~~~~~~~+
-| 1         | 4     | 7   |           This is long data | Test1   |
-+-----------+-------+-----+-----------------------------+---------+
-| 2         | 5     | 8   |    This is even longer data | Test3   |
-+-----------+-------+-----+-----------------------------+---------+
-| 3         | 6     | 9   |                             | Test4   |
-+-----------+-------+-----+-----------------------------+---------+
-| This is a |       |     |                             |         |
-|  single   |       |     |                             |         |
-| row       |       |     |                             |         |
-+-----------+-------+-----+-----------------------------+---------+
-
-
-

When adding new rows/columns their data can have its own alignments -(left/center/right, top/center/bottom).

-

If the height is restricted, cells will be restricted from expanding -vertically. This will lead to text contents being cropped. Each cell -can only shrink to a minimum width and height of 1.

-

EvTable is intended to be used with ANSIString for supporting ANSI-coloured -string types.

-

When a cell is auto-wrapped across multiple lines, ANSI-reset sequences will be -put at the end of each wrapped line. This means that the colour of a wrapped -cell will not “bleed”, but it also means that eventual colour outside the table -will not transfer “across” a table, you need to re-set the color to have it -appear on both sides of the table string.

-
-
-
-class evennia.utils.evtable.ANSITextWrapper(width=70, initial_indent='', subsequent_indent='', expand_tabs=True, replace_whitespace=True, fix_sentence_endings=False, break_long_words=True, drop_whitespace=True, break_on_hyphens=True, tabsize=8, *, max_lines=None, placeholder=' [...]')[source]
-

Bases: textwrap.TextWrapper

-

This is a wrapper work class for handling strings with ANSI tags -in it. It overloads the standard library TextWrapper class and -is used internally in EvTable and has no public methods.

-
- -
-
-evennia.utils.evtable.wrap(text, width=78, **kwargs)[source]
-

Wrap a single paragraph of text, returning a list of wrapped lines.

-

Reformat the single paragraph in ‘text’ so it fits in lines of no -more than ‘width’ columns, and return a list of wrapped lines. By -default, tabs in ‘text’ are expanded with string.expandtabs(), and -all other whitespace characters (including newline) are converted to

-
-
Parameters
-
    -
  • text (str) – Text to wrap.

  • -
  • width (int, optional) – Width to wrap text to.

  • -
-
-
Keyword Arguments
-
    -
  • TextWrapper class for available keyword args to customize (See) –

  • -
  • behaviour. (wrapping) –

  • -
-
-
-
- -
-
-evennia.utils.evtable.fill(text, width=78, **kwargs)[source]
-

Fill a single paragraph of text, returning a new string.

-

Reformat the single paragraph in ‘text’ to fit in lines of no more -than ‘width’ columns, and return a new string containing the entire -wrapped paragraph. As with wrap(), tabs are expanded and other -whitespace characters converted to space.

-
-
Parameters
-
    -
  • text (str) – Text to fill.

  • -
  • width (int, optional) – Width of fill area.

  • -
-
-
Keyword Arguments
-
    -
  • TextWrapper class for available keyword args to customize (See) –

  • -
  • behaviour. (filling) –

  • -
-
-
-
- -
-
-class evennia.utils.evtable.EvCell(data, **kwargs)[source]
-

Bases: object

-

Holds a single data cell for the table. A cell has a certain width -and height and contains one or more lines of data. It can shrink -and resize as needed.

-
-
-__init__(data, **kwargs)[source]
-
-
Parameters
-

data (str) – The un-padded data of the entry.

-
-
Keyword Arguments
-
    -
  • width (int) – Desired width of cell. It will pad -to this size.

  • -
  • height (int) – Desired height of cell. it will pad -to this size.

  • -
  • pad_width (int) – General padding width. This can be overruled -by individual settings below.

  • -
  • pad_left (int) – Number of extra pad characters on the left.

  • -
  • pad_right (int) – Number of extra pad characters on the right.

  • -
  • pad_top (int) – Number of extra pad lines top (will pad with vpad_char).

  • -
  • pad_bottom (int) – Number of extra pad lines bottom (will pad with vpad_char).

  • -
  • pad_char (str) – by individual settings below (default ” “).

  • -
  • hpad_char (str) – Pad character to use both for extra horizontal -padding (default ” “).

  • -
  • vpad_char (str) – Pad character to use for extra vertical padding -and for vertical fill (default ” “).

  • -
  • fill_char (str) – Character used to filling (expanding cells to -desired size). This can be overruled by individual settings below.

  • -
  • hfill_char (str) – Character used for horizontal fill (default ” “).

  • -
  • vfill_char (str) – Character used for vertical fill (default ” “).

  • -
  • align (str) – Should be one of “l”, “r” or “c” for left-, right- or center -horizontal alignment respectively. Default is left-aligned.

  • -
  • valign (str) – Should be one of “t”, “b” or “c” for top-, bottom and center -vertical alignment respectively. Default is centered.

  • -
  • border_width (int) – General border width. This is overruled -by individual settings below.

  • -
  • border_left (int) – Left border width.

  • -
  • border_right (int) – Right border width.

  • -
  • border_top (int) – Top border width.

  • -
  • border_bottom (int) – Bottom border width.

  • -
  • border_char (str) – This will use a single border char for all borders. -overruled by individual settings below.

  • -
  • border_left_char (str) – Char used for left border.

  • -
  • border_right_char (str) – Char used for right border.

  • -
  • border_top_char (str) – Char used for top border.

  • -
  • border_bottom_char (str) – Char user for bottom border.

  • -
  • corner_char (str) – Character used when two borders cross. (default is “”). -This is overruled by individual settings below.

  • -
  • corner_top_left_char (str) – Char used for “nw” corner.

  • -
  • corner_top_right_char (str) – Char used for “ne” corner.

  • -
  • corner_bottom_left_char (str) – Char used for “sw” corner.

  • -
  • corner_bottom_right_char (str) – Char used for “se” corner.

  • -
  • crop_string (str) – String to use when cropping sideways, default is ‘[…]’.

  • -
  • crop (bool) – Crop contentof cell rather than expand vertically, default=**False**.

  • -
  • enforce_size (bool) – If true, the width/height of the cell is -strictly enforced and extra text will be cropped rather than the -cell growing vertically.

  • -
-
-
Raises
-

Exception – for impossible cell size requirements where the -border width or height cannot fit, or the content is too -small.

-
-
-
- -
-
-get_min_height()[source]
-

Get the minimum possible height of cell, including at least -one line for data.

-
-
Returns
-

min_height (int) – The mininum height of cell.

-
-
-
- -
-
-get_min_width()[source]
-

Get the minimum possible width of cell, including at least one -character-width for data.

-
-
Returns
-

min_width (int) – The minimum width of cell.

-
-
-
- -
-
-get_height()[source]
-

Get natural height of cell, including padding.

-
-
Returns
-

natural_height (int) – Height of cell.

-
-
-
- -
-
-get_width()[source]
-

Get natural width of cell, including padding.

-
-
Returns
-

natural_width (int) – Width of cell.

-
-
-
- -
-
-replace_data(data, **kwargs)[source]
-

Replace cell data. This causes a full reformat of the cell.

-
-
Parameters
-

data (str) – Cell data.

-
-
-

Notes

-

The available keyword arguments are the same as for -EvCell.__init__.

-
- -
-
-reformat(**kwargs)[source]
-

Reformat the EvCell with new options

-
-
Keyword Arguments
-

available keyword arguments are the same as for EvCell.__init__. (The) –

-
-
Raises
-

Exception – If the cells cannot shrink enough to accomodate -the options or the data given.

-
-
-
- -
-
-get()[source]
-

Get data, padded and aligned in the form of a list of lines.

-
- -
- -
-
-class evennia.utils.evtable.EvColumn(*args, **kwargs)[source]
-

Bases: object

-

This class holds a list of Cells to represent a column of a table. -It holds operations and settings that affect all cells in the -column.

-

Columns are not intended to be used stand-alone; they should be -incorporated into an EvTable (like EvCells)

-
-
-__init__(*args, **kwargs)[source]
-
-
Parameters
-

for each row in the column (Text) –

-
-
Keyword Arguments
-
    -
  • EvCell.__init_ keywords are available, these (All) –

  • -
  • will be persistently applied to every Cell in the (settings) –

  • -
  • column.

  • -
-
-
-
- -
-
-add_rows(*args, **kwargs)[source]
-

Add new cells to column. They will be inserted as -a series of rows. It will inherit the options -of the rest of the column’s cells (use update to change -options).

-
-
Parameters
-
    -
  • for the new cells (Texts) –

  • -
  • ypos (int, optional) – Index position in table before which to insert the -new column. Uses Python indexing, so to insert at the top, -use ypos=0. If not given, data will be inserted at the end -of the column.

  • -
-
-
Keyword Arguments
-

keywods as per EvCell.__init__. (Available) –

-
-
-
- -
-
-reformat(**kwargs)[source]
-

Change the options for the column.

-
-
Keyword Arguments
-

as per EvCell.__init__. (Keywords) –

-
-
-
- -
-
-reformat_cell(index, **kwargs)[source]
-

reformat cell at given index, keeping column options if -necessary.

-
-
Parameters
-

index (int) – Index location of the cell in the column, -starting from 0 for the first row to Nrows-1.

-
-
Keyword Arguments
-

as per EvCell.__init__. (Keywords) –

-
-
-
- -
- -
-
-class evennia.utils.evtable.EvTable(*args, **kwargs)[source]
-

Bases: object

-

The table class holds a list of EvColumns, each consisting of EvCells so -that the result is a 2D matrix.

-
-
-__init__(*args, **kwargs)[source]
-
-
Parameters
-

texts for the table. (Header) –

-
-
Keyword Arguments
-
    -
  • table (list of lists or list of EvColumns, optional) – This is used to build the table in a quick way. If not -given, the table will start out empty and add_ methods -need to be used to add rows/columns.

  • -
  • header (bool, optional) – True/False - turn off the -header texts (*args) being treated as a header (such as -not adding extra underlining)

  • -
  • pad_width (int, optional) – How much empty space to pad your cells with -(default is 1)

  • -
  • border (str, optional)) – The border style to use. This is one of -- None - No border drawing at all. -- “table” - only a border around the whole table. -- “tablecols” - table and column borders. (default) -- “header” - only border under header. -- “cols” - only vertical borders. -- “incols” - vertical borders, no outer edges. -- “rows” - only borders between rows. -- “cells” - border around all cells.

  • -
  • border_width (int, optional) – Width of table borders, if border is active. -Note that widths wider than 1 may give artifacts in the corners. Default is 1.

  • -
  • corner_char (str, optional) – Character to use in corners when border is active. -Default is +.

  • -
  • corner_top_left_char (str, optional) – Character used for “nw” corner of table. -Defaults to corner_char.

  • -
  • corner_top_right_char (str, optional) – Character used for “ne” corner of table. -Defaults to corner_char.

  • -
  • corner_bottom_left_char (str, optional) – Character used for “sw” corner of table. -Defaults to corner_char.

  • -
  • corner_bottom_right_char (str, optional) – Character used for “se” corner of table. -Defaults to corner_char.

  • -
  • pretty_corners (bool, optional) – Use custom characters to -make the table corners look “rounded”. Uses UTF-8 -characters. Defaults to False for maximum compatibility with various displays -that may occationally have issues with UTF-8 characters.

  • -
  • header_line_char (str, optional) – Character to use for underlining -the header row (default is ‘~’). Requires border to not be None.

  • -
  • width (int, optional) – Fixed width of table. If not set, -width is set by the total width of each column. This will -resize individual columns in the vertical direction to fit.

  • -
  • height (int, optional) – Fixed height of table. Defaults to being unset. Width is -still given precedence. If given, table cells will crop text rather -than expand vertically.

  • -
  • evenwidth (bool, optional) – Used with the width keyword. Adjusts columns to have as -even width as possible. This often looks best also for mixed-length tables. Default -is False.

  • -
  • maxwidth (int, optional) – This will set a maximum width -of the table while allowing it to be smaller. Only if it grows wider than this -size will it be resized by expanding horizontally (or crop height is given). -This keyword has no meaning if width is set.

  • -
-
-
Raises
-

Exception – If given erroneous input or width settings for the data.

-
-
-

Notes

-

Beyond those table-specific keywords, the non-overlapping keywords -of EvCell.__init__ are also available. These will be passed down -to every cell in the table.

-
- -
-
-add_header(*args, **kwargs)[source]
-

Add header to table. This is a number of texts to be put at -the top of the table. They will replace an existing header.

-
-
Parameters
-

args (str) – These strings will be used as the header texts.

-
-
Keyword Arguments
-
    -
  • keywords as per EvTable.__init__. Will be applied (Same) –

  • -
  • the new header's cells. (to) –

  • -
-
-
-
- -
-
-add_column(*args, **kwargs)[source]
-

Add a column to table. If there are more rows in new column -than there are rows in the current table, the table will -expand with empty rows in the other columns. If too few, the -new column with get new empty rows. All filling rows are added -to the end.

-
-
Parameters
-
    -
  • args (EvColumn or multiple strings) – Either a single EvColumn instance or -a number of data string arguments to be used to create a new column.

  • -
  • header (str, optional) – The header text for the column

  • -
  • xpos (int, optional) – Index position in table before which -to input new column. If not given, column will be added to the end -of the table. Uses Python indexing (so first column is xpos=0)

  • -
-
-
Keyword Arguments
-

keywords as per Cell.__init__. (Other) –

-
-
-
- -
-
-add_row(*args, **kwargs)[source]
-

Add a row to table (not a header). If there are more cells in -the given row than there are cells in the current table the -table will be expanded with empty columns to match. These will -be added to the end of the table. In the same way, adding a -line with too few cells will lead to the last ones getting -padded.

-
-
Parameters
-
    -
  • args (str) – Any number of string argumnets to use as the -data in the row (one cell per argument).

  • -
  • ypos (int, optional) – Index position in table before which to -input new row. If not given, will be added to the end of the table. -Uses Python indexing (so first row is ypos=0)

  • -
-
-
Keyword Arguments
-

keywords are as per EvCell.__init__. (Other) –

-
-
-
- -
-
-reformat(**kwargs)[source]
-

Force a re-shape of the entire table.

-
-
Keyword Arguments
-

options as per EvTable.__init__. (Table) –

-
-
-
- -
-
-reformat_column(index, **kwargs)[source]
-

Sends custom options to a specific column in the table.

-
-
Parameters
-

index (int) – Which column to reformat. The column index is -given from 0 to Ncolumns-1.

-
-
Keyword Arguments
-

options as per EvCell.__init__. (Column) –

-
-
Raises
-

Exception – if an invalid index is found.

-
-
-
- -
-
-get()[source]
-

Return lines of table as a list.

-
-
Returns
-

table_lines (list) – The lines of the table, in order.

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.gametime.html b/docs/0.9.5/api/evennia.utils.gametime.html deleted file mode 100644 index 809319a527..0000000000 --- a/docs/0.9.5/api/evennia.utils.gametime.html +++ /dev/null @@ -1,308 +0,0 @@ - - - - - - - - - evennia.utils.gametime — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.gametime

-

The gametime module handles the global passage of time in the mud.

-

It also supplies some useful methods to convert between -in-mud time and real-world time as well allows to get the -total runtime of the server and the current uptime.

-
-
-class evennia.utils.gametime.TimeScript(*args, **kwargs)[source]
-

Bases: evennia.scripts.scripts.DefaultScript

-

Gametime-sensitive script.

-
-
-at_script_creation()[source]
-

The script is created.

-
- -
-
-at_repeat()[source]
-

Call the callback and reset interval.

-
- -
-
-exception DoesNotExist
-

Bases: evennia.scripts.scripts.DefaultScript.DoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: evennia.scripts.scripts.DefaultScript.MultipleObjectsReturned

-
- -
-
-path = 'evennia.utils.gametime.TimeScript'
-
- -
-
-typename = 'TimeScript'
-
- -
- -
-
-evennia.utils.gametime.runtime()[source]
-

Get the total runtime of the server since first start (minus -downtimes)

-
-
Parameters
-

format (bool, optional) – Format into a time representation.

-
-
Returns
-

time (float or tuple)

-
-
The runtime or the same time split up

into time units.

-
-
-

-
-
-
- -
-
-evennia.utils.gametime.server_epoch()[source]
-

Get the server epoch. We may need to calculate this on the fly.

-
- -
-
-evennia.utils.gametime.uptime()[source]
-

Get the current uptime of the server since last reload

-
-
Parameters
-

format (bool, optional) – Format into time representation.

-
-
Returns
-

time (float or tuple)

-
-
The uptime or the same time split up

into time units.

-
-
-

-
-
-
- -
-
-evennia.utils.gametime.portal_uptime()[source]
-

Get the current uptime of the portal.

-
-
Returns
-

time (float) – The uptime of the portal.

-
-
-
- -
-
-evennia.utils.gametime.game_epoch()[source]
-

Get the game epoch.

-
- -
-
-evennia.utils.gametime.gametime(absolute=False)[source]
-

Get the total gametime of the server since first start (minus downtimes)

-
-
Parameters
-

absolute (bool, optional) – Get the absolute game time, including -the epoch. This could be converted to an absolute in-game -date.

-
-
Returns
-

time (float) – The gametime as a virtual timestamp.

-
-
-

Notes

-

If one is using a standard calendar, one could convert the unformatted -return to a date using Python’s standard datetime module like this: -datetime.datetime.fromtimestamp(gametime(absolute=True))

-
- -
-
-evennia.utils.gametime.real_seconds_until(sec=None, min=None, hour=None, day=None, month=None, year=None)[source]
-

Return the real seconds until game time.

-
-
Parameters
-
    -
  • sec (int or None) – number of absolute seconds.

  • -
  • min (int or None) – number of absolute minutes.

  • -
  • hour (int or None) – number of absolute hours.

  • -
  • day (int or None) – number of absolute days.

  • -
  • month (int or None) – number of absolute months.

  • -
  • year (int or None) – number of absolute years.

  • -
-
-
Returns
-

The number of real seconds before the given game time is up.

-
-
-

Example

-

real_seconds_until(hour=5, min=10, sec=0)

-

If the game time is 5:00, TIME_FACTOR is set to 2 and you ask -the number of seconds until it’s 5:10, then this function should -return 300 (5 minutes).

-
- -
-
-evennia.utils.gametime.schedule(callback, repeat=False, sec=None, min=None, hour=None, day=None, month=None, year=None, *args, **kwargs)[source]
-

Call a callback at a given in-game time.

-
-
Parameters
-
    -
  • callback (function) – The callback function that will be called. Note -that the callback must be a module-level function, since the script will -be persistent. The callable should be on form callable(*args, **kwargs) -where args/kwargs are passed into this schedule.

  • -
  • repeat (bool, optional) – Defines if the callback should be called regularly -at the specified time.

  • -
  • sec (int or None) – Number of absolute game seconds at which to run repeat.

  • -
  • min (int or None) – Number of absolute minutes.

  • -
  • hour (int or None) – Number of absolute hours.

  • -
  • day (int or None) – Number of absolute days.

  • -
  • month (int or None) – Number of absolute months.

  • -
  • year (int or None) – Number of absolute years.

  • -
  • *args – Will be passed into the callable. These must be possible -to store in Attributes on the generated scheduling Script.

  • -
  • **kwargs

    Will be passed into the callable. These must be possible -to store in Attributes on the generated scheduling Script.

    -

  • -
-
-
Returns
-

Script – The created Script handling the scheduling.

-
-
-

Examples

-
schedule(func, min=5, sec=0)  # Will call 5 minutes past the next (in-game) hour.
-schedule(func, hour=2, min=30, sec=0)  # Will call the next (in-game) day at 02:30.
-
-
-
- -
-
-evennia.utils.gametime.reset_gametime()[source]
-

Resets the game time to make it start from the current time. Note that -the epoch set by settings.TIME_GAME_EPOCH will still apply.

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.html b/docs/0.9.5/api/evennia.utils.html deleted file mode 100644 index 3051f5f2b8..0000000000 --- a/docs/0.9.5/api/evennia.utils.html +++ /dev/null @@ -1,165 +0,0 @@ - - - - - - - - - evennia.utils — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.idmapper.html b/docs/0.9.5/api/evennia.utils.idmapper.html deleted file mode 100644 index d7c88f6e76..0000000000 --- a/docs/0.9.5/api/evennia.utils.idmapper.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - - - evennia.utils.idmapper — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.idmapper

-

The idmapper holds the main database caching mechanism.

- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.idmapper.manager.html b/docs/0.9.5/api/evennia.utils.idmapper.manager.html deleted file mode 100644 index 23ce252599..0000000000 --- a/docs/0.9.5/api/evennia.utils.idmapper.manager.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - evennia.utils.idmapper.manager — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.idmapper.manager

-

IDmapper extension to the default manager.

-
-
-class evennia.utils.idmapper.manager.SharedMemoryManager(*args, **kwargs)[source]
-

Bases: django.db.models.manager.Manager

-
-
-get(*args, **kwargs)[source]
-

Data entity lookup.

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.idmapper.models.html b/docs/0.9.5/api/evennia.utils.idmapper.models.html deleted file mode 100644 index 047c68527e..0000000000 --- a/docs/0.9.5/api/evennia.utils.idmapper.models.html +++ /dev/null @@ -1,336 +0,0 @@ - - - - - - - - - evennia.utils.idmapper.models — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.idmapper.models

-

Django ID mapper

-

Modified for Evennia by making sure that no model references -leave caching unexpectedly (no use of WeakRefs).

-

Also adds cache_size() for monitoring the size of the cache.

-
-
-class evennia.utils.idmapper.models.SharedMemoryModelBase(name, bases, attrs)[source]
-

Bases: django.db.models.base.ModelBase

-
- -
-
-class evennia.utils.idmapper.models.SharedMemoryModel(*args, **kwargs)[source]
-

Bases: django.db.models.base.Model

-

Base class for idmapped objects. Inherit from this.

-
-
-objects
-
- -
-
-class Meta[source]
-

Bases: object

-
-
-abstract = False
-
- -
- -
-
-classmethod get_cached_instance(id)[source]
-

Method to retrieve a cached instance by pk value. Returns None -when not found (which will always be the case when caching is -disabled for this class). Please note that the lookup will be -done even when instance caching is disabled.

-
- -
-
-classmethod cache_instance(instance, new=False)[source]
-

Method to store an instance in the cache.

-
-
Parameters
-
    -
  • instance (Class instance) – the instance to cache.

  • -
  • new (bool, optional) – this is the first time this instance is -cached (i.e. this is not an update operation like after a -db save).

  • -
-
-
-
- -
-
-classmethod get_all_cached_instances()[source]
-

Return the objects so far cached by idmapper for this class.

-
- -
-
-classmethod flush_cached_instance(instance, force=True)[source]
-

Method to flush an instance from the cache. The instance will -always be flushed from the cache, since this is most likely -called from delete(), and we want to make sure we don’t cache -dead objects.

-
- -
-
-classmethod flush_instance_cache(force=False)[source]
-

This will clean safe objects from the cache. Use force -keyword to remove all objects, safe or not.

-
- -
-
-at_idmapper_flush()[source]
-

This is called when the idmapper cache is flushed and -allows customized actions when this happens.

-
-
Returns
-

do_flush (bool)

-
-
If True, flush this object as normal. If

False, don’t flush and expect this object to handle -the flushing on its own.

-
-
-

-
-
-
- -
-
-flush_from_cache(force=False)[source]
-

Flush this instance from the instance cache. Use -force to override the result of at_idmapper_flush() for the object.

-
- -
-
-delete(*args, **kwargs)[source]
-

Delete the object, clearing cache.

-
- -
-
-save(*args, **kwargs)[source]
-

Central database save operation.

-

Notes

-

Arguments as per Django documentation. -Calls self.at_<fieldname>_postsave(new) -(this is a wrapper set by oobhandler: -self._oob_at_<fieldname>_postsave())

-
- -
-
-path = 'evennia.utils.idmapper.models.SharedMemoryModel'
-
- -
-
-typename = 'SharedMemoryModelBase'
-
- -
- -
-
-class evennia.utils.idmapper.models.WeakSharedMemoryModelBase(name, bases, attrs)[source]
-

Bases: evennia.utils.idmapper.models.SharedMemoryModelBase

-

Uses a WeakValue dictionary for caching instead of a regular one.

-
- -
-
-class evennia.utils.idmapper.models.WeakSharedMemoryModel(*args, **kwargs)[source]
-

Bases: evennia.utils.idmapper.models.SharedMemoryModel

-

Uses a WeakValue dictionary for caching instead of a regular one

-
-
-class Meta[source]
-

Bases: object

-
-
-abstract = False
-
- -
- -
-
-path = 'evennia.utils.idmapper.models.WeakSharedMemoryModel'
-
- -
-
-typename = 'WeakSharedMemoryModelBase'
-
- -
- -
-
-evennia.utils.idmapper.models.flush_cache(**kwargs)[source]
-

Flush idmapper cache. When doing so the cache will fire the -at_idmapper_flush hook to allow the object to optionally handle -its own flushing.

-

Uses a signal so we make sure to catch cascades.

-
- -
-
-evennia.utils.idmapper.models.flush_cached_instance(sender, instance, **kwargs)[source]
-

Flush the idmapper cache only for a given instance.

-
- -
-
-evennia.utils.idmapper.models.update_cached_instance(sender, instance, **kwargs)[source]
-

Re-cache the given instance in the idmapper cache.

-
- -
-
-evennia.utils.idmapper.models.conditional_flush(max_rmem, force=False)[source]
-

Flush the cache if the estimated memory usage exceeds max_rmem.

-

The flusher has a timeout to avoid flushing over and over -in particular situations (this means that for some setups -the memory usage will exceed the requirement and a server with -more memory is probably required for the given game).

-
-
Parameters
-
    -
  • max_rmem (int) – memory-usage estimation-treshold after which -cache is flushed.

  • -
  • force (bool, optional) – forces a flush, regardless of timeout. -Defaults to False.

  • -
-
-
-
- -
-
-evennia.utils.idmapper.models.cache_size(mb=True)[source]
-

Calculate statistics about the cache.

-

Note: we cannot get reliable memory statistics from the cache - -whereas we could do getsizof each object in cache, the result is -highly imprecise and for a large number of objects the result is -many times larger than the actual memory usage of the entire server; -Python is clearly reusing memory behind the scenes that we cannot -catch in an easy way here. Ideas are appreciated. /Griatch

-
-
Returns
-

total_num, {objclass – total_num, …}

-
-
-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.idmapper.tests.html b/docs/0.9.5/api/evennia.utils.idmapper.tests.html deleted file mode 100644 index c6f3d71840..0000000000 --- a/docs/0.9.5/api/evennia.utils.idmapper.tests.html +++ /dev/null @@ -1,433 +0,0 @@ - - - - - - - - - evennia.utils.idmapper.tests — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.idmapper.tests

-
-
-class evennia.utils.idmapper.tests.Category(id, name)[source]
-

Bases: evennia.utils.idmapper.models.SharedMemoryModel

-
-
-name
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-exception DoesNotExist
-

Bases: django.core.exceptions.ObjectDoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: django.core.exceptions.MultipleObjectsReturned

-
- -
-
-article_set
-

Accessor to the related objects manager on the reverse side of a -many-to-one relation.

-

In the example:

-
class Child(Model):
-    parent = ForeignKey(Parent, related_name='children')
-
-
-

**Parent.children** is a **ReverseManyToOneDescriptor** instance.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-id
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-path = 'evennia.utils.idmapper.tests.Category'
-
- -
-
-regulararticle_set
-

Accessor to the related objects manager on the reverse side of a -many-to-one relation.

-

In the example:

-
class Child(Model):
-    parent = ForeignKey(Parent, related_name='children')
-
-
-

**Parent.children** is a **ReverseManyToOneDescriptor** instance.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-typename = 'SharedMemoryModelBase'
-
- -
- -
-
-class evennia.utils.idmapper.tests.RegularCategory(id, name)[source]
-

Bases: django.db.models.base.Model

-
-
-name
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-exception DoesNotExist
-

Bases: django.core.exceptions.ObjectDoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: django.core.exceptions.MultipleObjectsReturned

-
- -
-
-article_set
-

Accessor to the related objects manager on the reverse side of a -many-to-one relation.

-

In the example:

-
class Child(Model):
-    parent = ForeignKey(Parent, related_name='children')
-
-
-

**Parent.children** is a **ReverseManyToOneDescriptor** instance.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
-
-id
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-objects = <django.db.models.manager.Manager object>
-
- -
-
-regulararticle_set
-

Accessor to the related objects manager on the reverse side of a -many-to-one relation.

-

In the example:

-
class Child(Model):
-    parent = ForeignKey(Parent, related_name='children')
-
-
-

**Parent.children** is a **ReverseManyToOneDescriptor** instance.

-

Most of the implementation is delegated to a dynamically defined manager -class built by **create_forward_many_to_many_manager()** defined below.

-
- -
- -
-
-class evennia.utils.idmapper.tests.Article(id, name, category, category2)[source]
-

Bases: evennia.utils.idmapper.models.SharedMemoryModel

-
-
-name
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-category
-

Accessor to the related object on the forward side of a many-to-one or -one-to-one (via ForwardOneToOneDescriptor subclass) relation.

-

In the example:

-
class Child(Model):
-    parent = ForeignKey(Parent, related_name='children')
-
-
-

**Child.parent** is a **ForwardManyToOneDescriptor** instance.

-
- -
-
-category2
-

Accessor to the related object on the forward side of a many-to-one or -one-to-one (via ForwardOneToOneDescriptor subclass) relation.

-

In the example:

-
class Child(Model):
-    parent = ForeignKey(Parent, related_name='children')
-
-
-

**Child.parent** is a **ForwardManyToOneDescriptor** instance.

-
- -
-
-exception DoesNotExist
-

Bases: django.core.exceptions.ObjectDoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: django.core.exceptions.MultipleObjectsReturned

-
- -
-
-category2_id
-
- -
-
-category_id
-
- -
-
-id
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-path = 'evennia.utils.idmapper.tests.Article'
-
- -
-
-typename = 'SharedMemoryModelBase'
-
- -
- -
-
-class evennia.utils.idmapper.tests.RegularArticle(id, name, category, category2)[source]
-

Bases: django.db.models.base.Model

-
-
-name
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-category
-

Accessor to the related object on the forward side of a many-to-one or -one-to-one (via ForwardOneToOneDescriptor subclass) relation.

-

In the example:

-
class Child(Model):
-    parent = ForeignKey(Parent, related_name='children')
-
-
-

**Child.parent** is a **ForwardManyToOneDescriptor** instance.

-
- -
-
-category2
-

Accessor to the related object on the forward side of a many-to-one or -one-to-one (via ForwardOneToOneDescriptor subclass) relation.

-

In the example:

-
class Child(Model):
-    parent = ForeignKey(Parent, related_name='children')
-
-
-

**Child.parent** is a **ForwardManyToOneDescriptor** instance.

-
- -
-
-exception DoesNotExist
-

Bases: django.core.exceptions.ObjectDoesNotExist

-
- -
-
-exception MultipleObjectsReturned
-

Bases: django.core.exceptions.MultipleObjectsReturned

-
- -
-
-category2_id
-
- -
-
-category_id
-
- -
-
-id
-

A wrapper for a deferred-loading field. When the value is read from this -object the first time, the query is executed.

-
- -
-
-objects = <django.db.models.manager.Manager object>
-
- -
- -
-
-class evennia.utils.idmapper.tests.SharedMemorysTest(methodName='runTest')[source]
-

Bases: django.test.testcases.TestCase

-
-
-setUp()[source]
-

Hook method for setting up the test fixture before exercising it.

-
- -
-
-testSharedMemoryReferences()[source]
-
- -
-
-testRegularReferences()[source]
-
- -
-
-testMixedReferences()[source]
-
- -
-
-testObjectDeletion()[source]
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.inlinefuncs.html b/docs/0.9.5/api/evennia.utils.inlinefuncs.html deleted file mode 100644 index b8e6d404a7..0000000000 --- a/docs/0.9.5/api/evennia.utils.inlinefuncs.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.utils.inlinefuncs — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.inlinefuncs

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.logger.html b/docs/0.9.5/api/evennia.utils.logger.html deleted file mode 100644 index 274ac060b1..0000000000 --- a/docs/0.9.5/api/evennia.utils.logger.html +++ /dev/null @@ -1,507 +0,0 @@ - - - - - - - - - evennia.utils.logger — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.logger

-

Logging facilities

-

These are thin wrappers on top of Twisted’s logging facilities; logs -are all directed either to stdout (if Evennia is running in -interactive mode) or to $GAME_DIR/server/logs.

-

The log_file() function uses its own threading system to log to -arbitrary files in $GAME_DIR/server/logs.

-

Note: All logging functions have two aliases, log_type() and -log_typemsg(). This is for historical, back-compatible reasons.

-
-
-evennia.utils.logger.timeformat(when=None)[source]
-

This helper function will format the current time in the same -way as the twisted logger does, including time zone info. Only -difference from official logger is that we only use two digits -for the year and don’t show timezone for CET times.

-
-
Parameters
-

when (int, optional) – This is a time in POSIX seconds on the form -given by time.time(). If not given, this function will -use the current time.

-
-
Returns
-

timestring (str) – A formatted string of the given time.

-
-
-
- -
-
-class evennia.utils.logger.WeeklyLogFile(name, directory, defaultMode=None, day_rotation=7, max_size=1000000)[source]
-

Bases: twisted.python.logfile.DailyLogFile

-

Log file that rotates once per week by default. Overrides key methods to change format.

-
-
-__init__(name, directory, defaultMode=None, day_rotation=7, max_size=1000000)[source]
-
-
Parameters
-
    -
  • name (str) – Name of log file.

  • -
  • directory (str) – Directory holding the file.

  • -
  • defaultMode (str) – Permissions used to create file. Defaults to -current permissions of this file if it exists.

  • -
  • day_rotation (int) – How often to rotate the file.

  • -
  • max_size (int) – Max size of log file before rotation (regardless of -time). Defaults to 1M.

  • -
-
-
-
- -
-
-shouldRotate()[source]
-

Rotate when the date has changed since last write

-
- -
-
-suffix(tupledate)[source]
-

Return the suffix given a (year, month, day) tuple or unixtime. -Format changed to have 03 for march instead of 3 etc (retaining unix -file order)

-

If we get duplicate suffixes in location (due to hitting size limit), -we append __1, __2 etc.

-

Examples

-

server.log.2020_01_29 -server.log.2020_01_29__1 -server.log.2020_01_29__2

-
- -
-
-write(data)[source]
-

Write data to log file

-
- -
- -
-
-class evennia.utils.logger.PortalLogObserver(f)[source]
-

Bases: twisted.python.log.FileLogObserver

-

Reformat logging

-
-
-timeFormat: Optional[str] = None
-
- -
-
-prefix = ' |Portal| '
-
- -
-
-emit(eventDict)[source]
-

Copied from Twisted parent, to change logging output

-
- -
- -
-
-class evennia.utils.logger.ServerLogObserver(f)[source]
-

Bases: evennia.utils.logger.PortalLogObserver

-
-
-prefix = ' '
-
- -
- -
-
-evennia.utils.logger.log_msg(msg)[source]
-

Wrapper around log.msg call to catch any exceptions that might -occur in logging. If an exception is raised, we’ll print to -stdout instead.

-
-
Parameters
-

msg – The message that was passed to log.msg

-
-
-
- -
-
-evennia.utils.logger.log_trace(errmsg=None)[source]
-

Log a traceback to the log. This should be called from within an -exception.

-
-
Parameters
-

errmsg (str, optional) – Adds an extra line with added info -at the end of the traceback in the log.

-
-
-
- -
-
-evennia.utils.logger.log_tracemsg(errmsg=None)
-

Log a traceback to the log. This should be called from within an -exception.

-
-
Parameters
-

errmsg (str, optional) – Adds an extra line with added info -at the end of the traceback in the log.

-
-
-
- -
-
-evennia.utils.logger.log_err(errmsg)[source]
-

Prints/logs an error message to the server log.

-
-
Parameters
-

errmsg (str) – The message to be logged.

-
-
-
- -
-
-evennia.utils.logger.log_errmsg(errmsg)
-

Prints/logs an error message to the server log.

-
-
Parameters
-

errmsg (str) – The message to be logged.

-
-
-
- -
-
-evennia.utils.logger.log_server(servermsg)[source]
-

This is for the Portal to log captured Server stdout messages (it’s -usually only used during startup, before Server log is open)

-
- -
-
-evennia.utils.logger.log_warn(warnmsg)[source]
-

Prints/logs any warnings that aren’t critical but should be noted.

-
-
Parameters
-

warnmsg (str) – The message to be logged.

-
-
-
- -
-
-evennia.utils.logger.log_warnmsg(warnmsg)
-

Prints/logs any warnings that aren’t critical but should be noted.

-
-
Parameters
-

warnmsg (str) – The message to be logged.

-
-
-
- -
-
-evennia.utils.logger.log_info(infomsg)[source]
-

Prints any generic debugging/informative info that should appear in the log.

-

infomsg: (string) The message to be logged.

-
- -
-
-evennia.utils.logger.log_infomsg(infomsg)
-

Prints any generic debugging/informative info that should appear in the log.

-

infomsg: (string) The message to be logged.

-
- -
-
-evennia.utils.logger.log_dep(depmsg)[source]
-

Prints a deprecation message.

-
-
Parameters
-

depmsg (str) – The deprecation message to log.

-
-
-
- -
-
-evennia.utils.logger.log_depmsg(depmsg)
-

Prints a deprecation message.

-
-
Parameters
-

depmsg (str) – The deprecation message to log.

-
-
-
- -
-
-evennia.utils.logger.log_sec(secmsg)[source]
-

Prints a security-related message.

-
-
Parameters
-

secmsg (str) – The security message to log.

-
-
-
- -
-
-evennia.utils.logger.log_secmsg(secmsg)
-

Prints a security-related message.

-
-
Parameters
-

secmsg (str) – The security message to log.

-
-
-
- -
-
-class evennia.utils.logger.EvenniaLogFile(name, directory, rotateLength=1000000, defaultMode=None, maxRotatedFiles=None)[source]
-

Bases: twisted.python.logfile.LogFile

-

A rotating logfile based off Twisted’s LogFile. It overrides -the LogFile’s rotate method in order to append some of the last -lines of the previous log to the start of the new log, in order -to preserve a continuous chat history for channel log files.

-
-
-settings = <LazySettings "evennia.settings_default">
-
- -
-
-num_lines_to_append = 20
-
- -
-
-rotate(num_lines_to_append=None)[source]
-

Rotates our log file and appends some number of lines from -the previous log to the start of the new one.

-
- -
-
-seek(*args, **kwargs)[source]
-

Convenience method for accessing our _file attribute’s seek method, -which is used in tail_log_function.

-
-
Parameters
-
    -
  • *args – Same args as file.seek

  • -
  • **kwargs – Same kwargs as file.seek

  • -
-
-
-
- -
-
-readlines(*args, **kwargs)[source]
-

Convenience method for accessing our _file attribute’s readlines method, -which is used in tail_log_function.

-
-
Parameters
-
    -
  • *args – same args as file.readlines

  • -
  • **kwargs – same kwargs as file.readlines

  • -
-
-
Returns
-

lines (list) – lines from our _file attribute.

-
-
-
- -
- -
-
-evennia.utils.logger.log_file(msg, filename='game.log')[source]
-

Arbitrary file logger using threads.

-
-
Parameters
-
    -
  • msg (str) – String to append to logfile.

  • -
  • filename (str, optional) – Defaults to ‘game.log’. All logs -will appear in the logs directory and log entries will start -on new lines following datetime info.

  • -
-
-
-
- -
-
-evennia.utils.logger.log_file_exists(filename='game.log')[source]
-

Determine if a log-file already exists.

-
-
Parameters
-

filename (str) – The filename (within the log-dir).

-
-
Returns
-

bool – If the log file exists or not.

-
-
-
- -
-
-evennia.utils.logger.rotate_log_file(filename='game.log', num_lines_to_append=None)[source]
-

Force-rotate a log-file, without

-
-
Parameters
-
    -
  • filename (str) – The log file, located in settings.LOG_DIR.

  • -
  • num_lines_to_append (int, optional) – Include N number of -lines from previous file in new one. If None, use default. -Set to 0 to include no lines.

  • -
-
-
-
- -
-
-evennia.utils.logger.tail_log_file(filename, offset, nlines, callback=None)[source]
-

Return the tail of the log file.

-
-
Parameters
-
    -
  • filename (str) – The name of the log file, presumed to be in -the Evennia log dir.

  • -
  • offset (int) – The line offset from the end of the file to start -reading from. 0 means to start at the latest entry.

  • -
  • nlines (int) – How many lines to return, counting backwards -from the offset. If file is shorter, will get all lines.

  • -
  • callback (callable, optional) – A function to manage the result of the -asynchronous file access. This will get a list of lines. If unset, -the tail will happen synchronously.

  • -
-
-
Returns
-

lines (deferred or list)

-
-
This will be a deferred if callable is given,

otherwise it will be a list with The nline entries from the end of the file, or -all if the file is shorter than nlines.

-
-
-

-
-
-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.optionclasses.html b/docs/0.9.5/api/evennia.utils.optionclasses.html deleted file mode 100644 index 93df26142e..0000000000 --- a/docs/0.9.5/api/evennia.utils.optionclasses.html +++ /dev/null @@ -1,926 +0,0 @@ - - - - - - - - - evennia.utils.optionclasses — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.optionclasses

-
-
-class evennia.utils.optionclasses.BaseOption(handler, key, description, default)[source]
-

Bases: object

-

Abstract Class to deal with encapsulating individual Options. An Option has -a name/key, a description to display in relevant commands and menus, and a -default value. It saves to the owner’s Attributes using its Handler’s save -category.

-

Designed to be extremely overloadable as some options can be cantankerous.

-
-
Properties:

valid: Shortcut to the loaded VALID_HANDLER. -validator_key (str): The key of the Validator this uses.

-
-
-
-
-__init__(handler, key, description, default)[source]
-
-
Parameters
-
    -
  • handler (OptionHandler) – The OptionHandler that ‘owns’ this Option.

  • -
  • key (str) – The name this will be used for storage in a dictionary. -Must be unique per OptionHandler.

  • -
  • description (str) – What this Option’s text will show in commands and menus.

  • -
  • default – A default value for this Option.

  • -
-
-
-
- -
-
-property changed
-
- -
-
-property default
-
- -
-
-property value
-
- -
-
-set(value, **kwargs)[source]
-

Takes user input and stores appropriately. This method allows for -passing extra instructions into the validator.

-
-
Parameters
-
    -
  • value (str) – The new value of this Option.

  • -
  • kwargs (any) – Any kwargs will be passed into -self.validate(value, **kwargs) and self.save(**kwargs).

  • -
-
-
-
- -
-
-load()[source]
-

Takes the provided save data, validates it, and gets this Option ready to use.

-
-
Returns
-

Boolean – Whether loading was successful.

-
-
-
- -
-
-save(**kwargs)[source]
-

Stores the current value using .handler.save_handler(self.key, value, **kwargs) -where kwargs are a combination of those passed into this function and -the ones specified by the OptionHandler.

-
-
Keyword Arguments
-

any (any) – Not used by default. These are passed in from self.set -and allows the option to let the caller customize saving by -overriding or extend the default save kwargs

-
-
-
- -
-
-deserialize(save_data)[source]
-

Perform sanity-checking on the save data as it is loaded from storage. -This isn’t the same as what validator-functions provide (those work on -user input). For example, save data might be a timedelta or a list or -some other object.

-
-
Parameters
-

save_data – The data to check.

-
-
Returns
-

any (any)

-
-
Whatever the Option needs to track, like a string or a

datetime. The display hook is responsible for what is actually -displayed to user.

-
-
-

-
-
-
- -
-
-serialize()[source]
-

Serializes the save data for Attribute storage.

-
-
Returns
-

any (any) – Whatever is best for storage.

-
-
-
- -
-
-validate(value, **kwargs)[source]
-

Validate user input, which is presumed to be a string.

-
-
Parameters
-
    -
  • value (str) – User input.

  • -
  • account (AccountDB) – The Account that is performing the validation. -This is necessary because of other settings which may affect the -check, such as an Account’s timezone affecting how their datetime -entries are processed.

  • -
-
-
Returns
-

any (any) – The results of the validation.

-
-
Raises
-

ValidationError – If input value failed validation.

-
-
-
- -
-
-display(**kwargs)[source]
-

Renders the Option’s value as something pretty to look at.

-
-
Keyword Arguments
-

any (any) – These are options passed by the caller to potentially -customize display dynamically.

-
-
Returns
-

str

-
-
How the stored value should be projected to users (e.g. a raw

timedelta is pretty ugly).

-
-
-

-
-
-
- -
- -
-
-class evennia.utils.optionclasses.Text(handler, key, description, default)[source]
-

Bases: evennia.utils.optionclasses.BaseOption

-
-
-deserialize(save_data)[source]
-

Perform sanity-checking on the save data as it is loaded from storage. -This isn’t the same as what validator-functions provide (those work on -user input). For example, save data might be a timedelta or a list or -some other object.

-
-
Parameters
-

save_data – The data to check.

-
-
Returns
-

any (any)

-
-
Whatever the Option needs to track, like a string or a

datetime. The display hook is responsible for what is actually -displayed to user.

-
-
-

-
-
-
- -
- -
-
-class evennia.utils.optionclasses.Email(handler, key, description, default)[source]
-

Bases: evennia.utils.optionclasses.BaseOption

-
-
-validate(value, **kwargs)[source]
-

Validate user input, which is presumed to be a string.

-
-
Parameters
-
    -
  • value (str) – User input.

  • -
  • account (AccountDB) – The Account that is performing the validation. -This is necessary because of other settings which may affect the -check, such as an Account’s timezone affecting how their datetime -entries are processed.

  • -
-
-
Returns
-

any (any) – The results of the validation.

-
-
Raises
-

ValidationError – If input value failed validation.

-
-
-
- -
-
-deserialize(save_data)[source]
-

Perform sanity-checking on the save data as it is loaded from storage. -This isn’t the same as what validator-functions provide (those work on -user input). For example, save data might be a timedelta or a list or -some other object.

-
-
Parameters
-

save_data – The data to check.

-
-
Returns
-

any (any)

-
-
Whatever the Option needs to track, like a string or a

datetime. The display hook is responsible for what is actually -displayed to user.

-
-
-

-
-
-
- -
- -
-
-class evennia.utils.optionclasses.Boolean(handler, key, description, default)[source]
-

Bases: evennia.utils.optionclasses.BaseOption

-
-
-validate(value, **kwargs)[source]
-

Validate user input, which is presumed to be a string.

-
-
Parameters
-
    -
  • value (str) – User input.

  • -
  • account (AccountDB) – The Account that is performing the validation. -This is necessary because of other settings which may affect the -check, such as an Account’s timezone affecting how their datetime -entries are processed.

  • -
-
-
Returns
-

any (any) – The results of the validation.

-
-
Raises
-

ValidationError – If input value failed validation.

-
-
-
- -
-
-display(**kwargs)[source]
-

Renders the Option’s value as something pretty to look at.

-
-
Keyword Arguments
-

any (any) – These are options passed by the caller to potentially -customize display dynamically.

-
-
Returns
-

str

-
-
How the stored value should be projected to users (e.g. a raw

timedelta is pretty ugly).

-
-
-

-
-
-
- -
-
-serialize()[source]
-

Serializes the save data for Attribute storage.

-
-
Returns
-

any (any) – Whatever is best for storage.

-
-
-
- -
-
-deserialize(save_data)[source]
-

Perform sanity-checking on the save data as it is loaded from storage. -This isn’t the same as what validator-functions provide (those work on -user input). For example, save data might be a timedelta or a list or -some other object.

-
-
Parameters
-

save_data – The data to check.

-
-
Returns
-

any (any)

-
-
Whatever the Option needs to track, like a string or a

datetime. The display hook is responsible for what is actually -displayed to user.

-
-
-

-
-
-
- -
- -
-
-class evennia.utils.optionclasses.Color(handler, key, description, default)[source]
-

Bases: evennia.utils.optionclasses.BaseOption

-
-
-validate(value, **kwargs)[source]
-

Validate user input, which is presumed to be a string.

-
-
Parameters
-
    -
  • value (str) – User input.

  • -
  • account (AccountDB) – The Account that is performing the validation. -This is necessary because of other settings which may affect the -check, such as an Account’s timezone affecting how their datetime -entries are processed.

  • -
-
-
Returns
-

any (any) – The results of the validation.

-
-
Raises
-

ValidationError – If input value failed validation.

-
-
-
- -
-
-display(**kwargs)[source]
-

Renders the Option’s value as something pretty to look at.

-
-
Keyword Arguments
-

any (any) – These are options passed by the caller to potentially -customize display dynamically.

-
-
Returns
-

str

-
-
How the stored value should be projected to users (e.g. a raw

timedelta is pretty ugly).

-
-
-

-
-
-
- -
-
-deserialize(save_data)[source]
-

Perform sanity-checking on the save data as it is loaded from storage. -This isn’t the same as what validator-functions provide (those work on -user input). For example, save data might be a timedelta or a list or -some other object.

-
-
Parameters
-

save_data – The data to check.

-
-
Returns
-

any (any)

-
-
Whatever the Option needs to track, like a string or a

datetime. The display hook is responsible for what is actually -displayed to user.

-
-
-

-
-
-
- -
- -
-
-class evennia.utils.optionclasses.Timezone(handler, key, description, default)[source]
-

Bases: evennia.utils.optionclasses.BaseOption

-
-
-validate(value, **kwargs)[source]
-

Validate user input, which is presumed to be a string.

-
-
Parameters
-
    -
  • value (str) – User input.

  • -
  • account (AccountDB) – The Account that is performing the validation. -This is necessary because of other settings which may affect the -check, such as an Account’s timezone affecting how their datetime -entries are processed.

  • -
-
-
Returns
-

any (any) – The results of the validation.

-
-
Raises
-

ValidationError – If input value failed validation.

-
-
-
- -
-
-property default
-
- -
-
-deserialize(save_data)[source]
-

Perform sanity-checking on the save data as it is loaded from storage. -This isn’t the same as what validator-functions provide (those work on -user input). For example, save data might be a timedelta or a list or -some other object.

-
-
Parameters
-

save_data – The data to check.

-
-
Returns
-

any (any)

-
-
Whatever the Option needs to track, like a string or a

datetime. The display hook is responsible for what is actually -displayed to user.

-
-
-

-
-
-
- -
-
-serialize()[source]
-

Serializes the save data for Attribute storage.

-
-
Returns
-

any (any) – Whatever is best for storage.

-
-
-
- -
- -
-
-class evennia.utils.optionclasses.UnsignedInteger(handler, key, description, default)[source]
-

Bases: evennia.utils.optionclasses.BaseOption

-
-
-validator_key = 'unsigned_integer'
-
- -
-
-validate(value, **kwargs)[source]
-

Validate user input, which is presumed to be a string.

-
-
Parameters
-
    -
  • value (str) – User input.

  • -
  • account (AccountDB) – The Account that is performing the validation. -This is necessary because of other settings which may affect the -check, such as an Account’s timezone affecting how their datetime -entries are processed.

  • -
-
-
Returns
-

any (any) – The results of the validation.

-
-
Raises
-

ValidationError – If input value failed validation.

-
-
-
- -
-
-deserialize(save_data)[source]
-

Perform sanity-checking on the save data as it is loaded from storage. -This isn’t the same as what validator-functions provide (those work on -user input). For example, save data might be a timedelta or a list or -some other object.

-
-
Parameters
-

save_data – The data to check.

-
-
Returns
-

any (any)

-
-
Whatever the Option needs to track, like a string or a

datetime. The display hook is responsible for what is actually -displayed to user.

-
-
-

-
-
-
- -
- -
-
-class evennia.utils.optionclasses.SignedInteger(handler, key, description, default)[source]
-

Bases: evennia.utils.optionclasses.BaseOption

-
-
-validate(value, **kwargs)[source]
-

Validate user input, which is presumed to be a string.

-
-
Parameters
-
    -
  • value (str) – User input.

  • -
  • account (AccountDB) – The Account that is performing the validation. -This is necessary because of other settings which may affect the -check, such as an Account’s timezone affecting how their datetime -entries are processed.

  • -
-
-
Returns
-

any (any) – The results of the validation.

-
-
Raises
-

ValidationError – If input value failed validation.

-
-
-
- -
-
-deserialize(save_data)[source]
-

Perform sanity-checking on the save data as it is loaded from storage. -This isn’t the same as what validator-functions provide (those work on -user input). For example, save data might be a timedelta or a list or -some other object.

-
-
Parameters
-

save_data – The data to check.

-
-
Returns
-

any (any)

-
-
Whatever the Option needs to track, like a string or a

datetime. The display hook is responsible for what is actually -displayed to user.

-
-
-

-
-
-
- -
- -
-
-class evennia.utils.optionclasses.PositiveInteger(handler, key, description, default)[source]
-

Bases: evennia.utils.optionclasses.BaseOption

-
-
-validate(value, **kwargs)[source]
-

Validate user input, which is presumed to be a string.

-
-
Parameters
-
    -
  • value (str) – User input.

  • -
  • account (AccountDB) – The Account that is performing the validation. -This is necessary because of other settings which may affect the -check, such as an Account’s timezone affecting how their datetime -entries are processed.

  • -
-
-
Returns
-

any (any) – The results of the validation.

-
-
Raises
-

ValidationError – If input value failed validation.

-
-
-
- -
-
-deserialize(save_data)[source]
-

Perform sanity-checking on the save data as it is loaded from storage. -This isn’t the same as what validator-functions provide (those work on -user input). For example, save data might be a timedelta or a list or -some other object.

-
-
Parameters
-

save_data – The data to check.

-
-
Returns
-

any (any)

-
-
Whatever the Option needs to track, like a string or a

datetime. The display hook is responsible for what is actually -displayed to user.

-
-
-

-
-
-
- -
- -
-
-class evennia.utils.optionclasses.Duration(handler, key, description, default)[source]
-

Bases: evennia.utils.optionclasses.BaseOption

-
-
-validate(value, **kwargs)[source]
-

Validate user input, which is presumed to be a string.

-
-
Parameters
-
    -
  • value (str) – User input.

  • -
  • account (AccountDB) – The Account that is performing the validation. -This is necessary because of other settings which may affect the -check, such as an Account’s timezone affecting how their datetime -entries are processed.

  • -
-
-
Returns
-

any (any) – The results of the validation.

-
-
Raises
-

ValidationError – If input value failed validation.

-
-
-
- -
-
-deserialize(save_data)[source]
-

Perform sanity-checking on the save data as it is loaded from storage. -This isn’t the same as what validator-functions provide (those work on -user input). For example, save data might be a timedelta or a list or -some other object.

-
-
Parameters
-

save_data – The data to check.

-
-
Returns
-

any (any)

-
-
Whatever the Option needs to track, like a string or a

datetime. The display hook is responsible for what is actually -displayed to user.

-
-
-

-
-
-
- -
-
-serialize()[source]
-

Serializes the save data for Attribute storage.

-
-
Returns
-

any (any) – Whatever is best for storage.

-
-
-
- -
- -
-
-class evennia.utils.optionclasses.Datetime(handler, key, description, default)[source]
-

Bases: evennia.utils.optionclasses.BaseOption

-
-
-validate(value, **kwargs)[source]
-

Validate user input, which is presumed to be a string.

-
-
Parameters
-
    -
  • value (str) – User input.

  • -
  • account (AccountDB) – The Account that is performing the validation. -This is necessary because of other settings which may affect the -check, such as an Account’s timezone affecting how their datetime -entries are processed.

  • -
-
-
Returns
-

any (any) – The results of the validation.

-
-
Raises
-

ValidationError – If input value failed validation.

-
-
-
- -
-
-deserialize(save_data)[source]
-

Perform sanity-checking on the save data as it is loaded from storage. -This isn’t the same as what validator-functions provide (those work on -user input). For example, save data might be a timedelta or a list or -some other object.

-
-
Parameters
-

save_data – The data to check.

-
-
Returns
-

any (any)

-
-
Whatever the Option needs to track, like a string or a

datetime. The display hook is responsible for what is actually -displayed to user.

-
-
-

-
-
-
- -
-
-serialize()[source]
-

Serializes the save data for Attribute storage.

-
-
Returns
-

any (any) – Whatever is best for storage.

-
-
-
- -
- -
-
-class evennia.utils.optionclasses.Future(handler, key, description, default)[source]
-

Bases: evennia.utils.optionclasses.Datetime

-
-
-validate(value, **kwargs)[source]
-

Validate user input, which is presumed to be a string.

-
-
Parameters
-
    -
  • value (str) – User input.

  • -
  • account (AccountDB) – The Account that is performing the validation. -This is necessary because of other settings which may affect the -check, such as an Account’s timezone affecting how their datetime -entries are processed.

  • -
-
-
Returns
-

any (any) – The results of the validation.

-
-
Raises
-

ValidationError – If input value failed validation.

-
-
-
- -
- -
-
-class evennia.utils.optionclasses.Lock(handler, key, description, default)[source]
-

Bases: evennia.utils.optionclasses.Text

-
-
-validate(value, **kwargs)[source]
-

Validate user input, which is presumed to be a string.

-
-
Parameters
-
    -
  • value (str) – User input.

  • -
  • account (AccountDB) – The Account that is performing the validation. -This is necessary because of other settings which may affect the -check, such as an Account’s timezone affecting how their datetime -entries are processed.

  • -
-
-
Returns
-

any (any) – The results of the validation.

-
-
Raises
-

ValidationError – If input value failed validation.

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.optionhandler.html b/docs/0.9.5/api/evennia.utils.optionhandler.html deleted file mode 100644 index fa94e6feae..0000000000 --- a/docs/0.9.5/api/evennia.utils.optionhandler.html +++ /dev/null @@ -1,234 +0,0 @@ - - - - - - - - - evennia.utils.optionhandler — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.optionhandler

-
-
-class evennia.utils.optionhandler.InMemorySaveHandler[source]
-

Bases: object

-

Fallback SaveHandler, implementing a minimum of the required save mechanism -and storing data in memory.

-
-
-__init__()[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
-
-add(key, value=None, **kwargs)[source]
-
- -
-
-get(key, default=None, **kwargs)[source]
-
- -
- -
-
-class evennia.utils.optionhandler.OptionHandler(obj, options_dict=None, savefunc=None, loadfunc=None, save_kwargs=None, load_kwargs=None)[source]
-

Bases: object

-

This is a generic Option handler. Retrieve options either as properties on -this handler or by using the .get method.

-

This is used for Account.options but it could be used by Scripts or Objects -just as easily. All it needs to be provided is an options_dict.

-
-
-__init__(obj, options_dict=None, savefunc=None, loadfunc=None, save_kwargs=None, load_kwargs=None)[source]
-

Initialize an OptionHandler.

-
-
Parameters
-
    -
  • obj (object) – The object this handler sits on. This is usually a TypedObject.

  • -
  • options_dict (dict) – A dictionary of option keys, where the values -are options. The format of those tuples is: (‘key’, “Description to -show”, ‘option_type’, <default value>)

  • -
  • savefunc (callable) – A callable for all options to call when saving itself. -It will be called as savefunc(key, value, **save_kwargs). A common one -to pass would be AttributeHandler.add.

  • -
  • loadfunc (callable) – A callable for all options to call when loading data into -itself. It will be called as loadfunc(key, default=default, **load_kwargs). -A common one to pass would be AttributeHandler.get.

  • -
  • save_kwargs (any) – Optional extra kwargs to pass into savefunc above.

  • -
  • load_kwargs (any) – Optional extra kwargs to pass into loadfunc above.

  • -
-
-
-

Notes

-

Both loadfunc and savefunc must be specified. If only one is given, the other -will be ignored and in-memory storage will be used.

-
- -
-
-get(key, default=None, return_obj=False, raise_error=False)[source]
-

Retrieves an Option stored in the handler. Will load it if it doesn’t exist.

-
-
Parameters
-
    -
  • key (str) – The option key to retrieve.

  • -
  • default (any) – What to return if the option is defined.

  • -
  • return_obj (bool, optional) – If True, returns the actual option -object instead of its value.

  • -
  • raise_error (bool, optional) – Raise Exception if key is not found in options.

  • -
-
-
Returns
-

option_value (any or Option) – An option value the Option itself.

-
-
Raises
-

KeyError – If option is not defined.

-
-
-
- -
-
-set(key, value, **kwargs)[source]
-

Change an individual option.

-
-
Parameters
-
    -
  • key (str) – The key of an option that can be changed. Allows partial matching.

  • -
  • value (str) – The value that should be checked, coerced, and stored.:

  • -
  • kwargs (any, optional) – These are passed into the Option’s validation function, -save function and display function and allows to customize either.

  • -
-
-
Returns
-

value (any) – Value stored in option, after validation.

-
-
-
- -
-
-all(return_objs=False)[source]
-

Get all options defined on this handler.

-
-
Parameters
-

return_objs (bool, optional) – Return the actual Option objects rather -than their values.

-
-
Returns
-

all_options (dict)

-
-
All options on this handler, either {key: value}

or {key: <Option>} if return_objs is True.

-
-
-

-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.picklefield.html b/docs/0.9.5/api/evennia.utils.picklefield.html deleted file mode 100644 index 2dfa75d2b9..0000000000 --- a/docs/0.9.5/api/evennia.utils.picklefield.html +++ /dev/null @@ -1,278 +0,0 @@ - - - - - - - - - evennia.utils.picklefield — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.picklefield

-

Pickle field implementation for Django.

-

Modified for Evennia by Griatch and the Evennia community.

-
-
-class evennia.utils.picklefield.PickledObject[source]
-

Bases: str

-

A subclass of string so it can be told whether a string is a pickled -object or not (if the object is an instance of this class then it must -[well, should] be a pickled one).

-

Only really useful for passing pre-encoded values to **default** -with **dbsafe_encode**, not that doing so is necessary. If you -remove PickledObject and its references, you won’t be able to pass -in pre-encoded values anymore, but you can always just pass in the -python objects themselves.

-
- -
-
-evennia.utils.picklefield.wrap_conflictual_object(obj)[source]
-
- -
-
-evennia.utils.picklefield.dbsafe_encode(value, compress_object=False, pickle_protocol=4)[source]
-
- -
-
-evennia.utils.picklefield.dbsafe_decode(value, compress_object=False)[source]
-
- -
-
-class evennia.utils.picklefield.PickledWidget(attrs=None)[source]
-

Bases: django.forms.widgets.Textarea

-

This is responsible for outputting HTML representing a given field.

-
-
-render(name, value, attrs=None, renderer=None)[source]
-

Display of the PickledField in django admin

-
- -
-
-value_from_datadict(data, files, name)[source]
-

Given a dictionary of data and this widget’s name, return the value -of this widget or None if it’s not provided.

-
- -
-
-property media
-
- -
- -
-
-class evennia.utils.picklefield.PickledFormField(*args, **kwargs)[source]
-

Bases: django.forms.fields.CharField

-

This represents one input field for the form.

-
-
-widget
-

alias of PickledWidget

-
- -
-
-default_error_messages = {'invalid': 'This is not a Python Literal. You can store things like strings, integers, or floats, but you must do it by typing them as you would type them in the Python Interpreter. For instance, strings must be surrounded by quote marks. We have converted it to a string for your convenience. If it is acceptable, please hit save again.', 'required': 'This field is required.'}
-
- -
-
-__init__(*args, **kwargs)[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
-
-clean(value)[source]
-

Validate the given value and return its “cleaned” value as an -appropriate Python object. Raise ValidationError for any errors.

-
- -
- -
-
-class evennia.utils.picklefield.PickledObjectField(*args, **kwargs)[source]
-

Bases: django.db.models.fields.Field

-

A field that will accept any python object and store it in the -database. PickledObjectField will optionally compress its values if -declared with the keyword argument **compress=True**.

-

Does not actually encode and compress **None** objects (although you -can still do lookups using None). This way, it is still possible to -use the **isnull** lookup type correctly.

-
-
-__init__(*args, **kwargs)[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
-
-get_default()[source]
-

Returns the default value for this field.

-

The default implementation on models.Field calls force_str -on the default, which means you can’t set arbitrary Python -objects as the default. To fix this, we just return the value -without calling force_str on it. Note that if you set a -callable as a default, the field will still call it. It will -not try to pickle and encode it.

-
- -
-
-from_db_value(value, *args)[source]
-

B64decode and unpickle the object, optionally decompressing it.

-

If an error is raised in de-pickling and we’re sure the value is -a definite pickle, the error is allowed to propagate. If we -aren’t sure if the value is a pickle or not, then we catch the -error and return the original value instead.

-
- -
-
-formfield(**kwargs)[source]
-

Return a django.forms.Field instance for this field.

-
- -
-
-pre_save(model_instance, add)[source]
-

Return field’s value just before saving.

-
- -
-
-get_db_prep_value(value, connection=None, prepared=False)[source]
-

Pickle and b64encode the object, optionally compressing it.

-

The pickling protocol is specified explicitly (by default 2), -rather than as -1 or HIGHEST_PROTOCOL, because we don’t want the -protocol to change over time. If it did, **exact** and **in** -lookups would likely fail, since pickle would now be generating -a different string.

-
- -
-
-value_to_string(obj)[source]
-

Return a string value of this field from the passed obj. -This is used by the serialization framework.

-
- -
-
-get_internal_type()[source]
-
- -
-
-get_db_prep_lookup(lookup_type, value, connection=None, prepared=False)[source]
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.search.html b/docs/0.9.5/api/evennia.utils.search.html deleted file mode 100644 index 4b265225c8..0000000000 --- a/docs/0.9.5/api/evennia.utils.search.html +++ /dev/null @@ -1,397 +0,0 @@ - - - - - - - - - evennia.utils.search — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.search

-

This is a convenient container gathering all the main -search methods for the various database tables.

-

It is intended to be used e.g. as

-

> from evennia.utils import search -> match = search.objects(…)

-

Note that this is not intended to be a complete listing of all search -methods! You need to refer to the respective manager to get all -possible search methods. To get to the managers from your code, import -the database model and call its ‘objects’ property.

-

Also remember that all commands in this file return lists (also if -there is only one match) unless noted otherwise.

-
-
Example: To reach the search method ‘get_object_with_account’

in evennia/objects/managers.py:

-
-
-

> from evennia.objects.models import ObjectDB -> match = Object.objects.get_object_with_account(…)

-
-
-evennia.utils.search.search_object(searchdata, attribute_name=None, typeclass=None, candidates=None, exact=True, use_dbref=True)
-

Search as an object globally or in a list of candidates and -return results. The result is always an Object. Always returns -a list.

-
-
Parameters
-
    -
  • searchdata (str or Object) – The entity to match for. This is -usually a key string but may also be an object itself. -By default (if no attribute_name is set), this will -search object.key and object.aliases in order. -Can also be on the form #dbref, which will (if -exact=True) be matched against primary key.

  • -
  • attribute_name (str) – Use this named Attribute to -match searchdata against, instead of the defaults. If -this is the name of a database field (with or without -the db_ prefix), that will be matched too.

  • -
  • typeclass (str or TypeClass) – restrict matches to objects -having this typeclass. This will help speed up global -searches.

  • -
  • candidates (list) – If supplied, search will -only be performed among the candidates in this list. A -common list of candidates is the contents of the -current location searched.

  • -
  • exact (bool) – Match names/aliases exactly or partially. -Partial matching matches the beginning of words in the -names/aliases, using a matching routine to separate -multiple matches in names with multiple components (so -“bi sw” will match “Big sword”). Since this is more -expensive than exact matching, it is recommended to be -used together with the candidates keyword to limit the -number of possibilities. This value has no meaning if -searching for attributes/properties.

  • -
  • use_dbref (bool) – If False, bypass direct lookup of a string -on the form #dbref and treat it like any string.

  • -
-
-
Returns
-

matches (list) – Matching objects

-
-
-
- -
-
-evennia.utils.search.search_account(ostring, exact=True, typeclass=None)
-

Searches for a particular account by name or -database id.

-
-
Parameters
-
    -
  • ostring (str or int) – A key string or database id.

  • -
  • exact (bool, optional) – Only valid for string matches. If -True, requires exact (non-case-sensitive) match, -otherwise also match also keys containing the ostring -(non-case-sensitive fuzzy match).

  • -
  • typeclass (str or Typeclass, optional) – Limit the search only to -accounts of this typeclass.

  • -
-
-
Returns
-

Queryset – A queryset (an iterable) with 0, 1 or more matches.

-
-
-
- -
-
-evennia.utils.search.search_script(ostring, obj=None, only_timed=False, typeclass=None)
-

Search for a particular script.

-
-
Parameters
-
    -
  • ostring (str) – Search criterion - a script dbef or key.

  • -
  • obj (Object, optional) – Limit search to scripts defined on -this object

  • -
  • only_timed (bool) – Limit search only to scripts that run -on a timer.

  • -
  • typeclass (class or str) – Typeclass or path to typeclass.

  • -
-
-
Returns
-

Queryset – An iterable with 0, 1 or more results.

-
-
-
- -
-
-evennia.utils.search.search_message(sender=None, receiver=None, freetext=None, dbref=None)
-

Search the message database for particular messages. At least -one of the arguments must be given to do a search.

-
-
Parameters
-
    -
  • sender (Object, Account or Script, optional) – Get messages sent by a particular sender.

  • -
  • receiver (Object, Account or Channel, optional) – Get messages -received by a certain account,object or channel

  • -
  • freetext (str) – Search for a text string in a message. NOTE: -This can potentially be slow, so make sure to supply one of -the other arguments to limit the search.

  • -
  • dbref (int) – The exact database id of the message. This will override -all other search criteria since it’s unique and -always gives only one match.

  • -
-
-
Returns
-

Queryset – Iterable with 0, 1 or more matches.

-
-
-
- -
-
-evennia.utils.search.search_channel(ostring, exact=True)
-

Search the channel database for a particular channel.

-
-
Parameters
-
    -
  • ostring (str) – The key or database id of the channel.

  • -
  • exact (bool, optional) – Require an exact (but not -case sensitive) match.

  • -
-
-
Returns
-

Queryset – Iterable with 0, 1 or more matches.

-
-
-
- -
-
-evennia.utils.search.search_help_entry(ostring, help_category=None)
-

Retrieve a search entry object.

-
-
Parameters
-
    -
  • ostring (str) – The help topic to look for.

  • -
  • category (str) – Limit the search to a particular help topic

  • -
-
-
Returns
-

Queryset – An iterable with 0, 1 or more matches.

-
-
-
- -
-
-evennia.utils.search.search_tag(key=None, category=None, tagtype=None, **kwargs)
-

Find object based on tag or category.

-
-
Parameters
-
    -
  • key (str, optional) – The tag key to search for.

  • -
  • category (str, optional) – The category of tag -to search for. If not set, uncategorized -tags will be searched.

  • -
  • tagtype (str, optional) – ‘type’ of Tag, by default -this is either None (a normal Tag), alias or -permission. This always apply to all queried tags.

  • -
  • kwargs (any) – Other optional parameter that may be supported -by the manager method.

  • -
-
-
Returns
-

matches (list)

-
-
List of Objects with tags matching

the search criteria, or an empty list if no -matches were found.

-
-
-

-
-
-
- -
-
-evennia.utils.search.search_script_tag(key=None, category=None, tagtype=None, **kwargs)[source]
-

Find script based on tag or category.

-
-
Parameters
-
    -
  • key (str, optional) – The tag key to search for.

  • -
  • category (str, optional) – The category of tag -to search for. If not set, uncategorized -tags will be searched.

  • -
  • tagtype (str, optional) – ‘type’ of Tag, by default -this is either None (a normal Tag), alias or -permission. This always apply to all queried tags.

  • -
  • kwargs (any) – Other optional parameter that may be supported -by the manager method.

  • -
-
-
Returns
-

matches (list)

-
-
List of Scripts with tags matching

the search criteria, or an empty list if no -matches were found.

-
-
-

-
-
-
- -
-
-evennia.utils.search.search_account_tag(key=None, category=None, tagtype=None, **kwargs)[source]
-

Find account based on tag or category.

-
-
Parameters
-
    -
  • key (str, optional) – The tag key to search for.

  • -
  • category (str, optional) – The category of tag -to search for. If not set, uncategorized -tags will be searched.

  • -
  • tagtype (str, optional) – ‘type’ of Tag, by default -this is either None (a normal Tag), alias or -permission. This always apply to all queried tags.

  • -
  • kwargs (any) – Other optional parameter that may be supported -by the manager method.

  • -
-
-
Returns
-

matches (list)

-
-
List of Accounts with tags matching

the search criteria, or an empty list if no -matches were found.

-
-
-

-
-
-
- -
-
-evennia.utils.search.search_channel_tag(key=None, category=None, tagtype=None, **kwargs)[source]
-

Find channel based on tag or category.

-
-
Parameters
-
    -
  • key (str, optional) – The tag key to search for.

  • -
  • category (str, optional) – The category of tag -to search for. If not set, uncategorized -tags will be searched.

  • -
  • tagtype (str, optional) – ‘type’ of Tag, by default -this is either None (a normal Tag), alias or -permission. This always apply to all queried tags.

  • -
  • kwargs (any) – Other optional parameter that may be supported -by the manager method.

  • -
-
-
Returns
-

matches (list)

-
-
List of Channels with tags matching

the search criteria, or an empty list if no -matches were found.

-
-
-

-
-
-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.test_resources.html b/docs/0.9.5/api/evennia.utils.test_resources.html deleted file mode 100644 index 348e0ed5de..0000000000 --- a/docs/0.9.5/api/evennia.utils.test_resources.html +++ /dev/null @@ -1,450 +0,0 @@ - - - - - - - - - evennia.utils.test_resources — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.test_resources

-

Various helper resources for writing unittests.

-

Classes for testing Evennia core:

-
    -
  • BaseEvenniaTestCase - no default objects, only enforced default settings

  • -
  • BaseEvenniaTest - all default objects, enforced default settings

  • -
  • BaseEvenniaCommandTest - for testing Commands, enforced default settings

  • -
-

Classes for testing game folder content:

-
    -
  • -
    EvenniaTestCase - no default objects, using gamedir settings (identical to

    standard Python TestCase)

    -
    -
    -
  • -
  • EvenniaTest - all default objects, using gamedir settings

  • -
  • EvenniaCommandTest - for testing game folder commands, using gamedir settings

  • -
-

Other:

-
    -
  • EvenniaTestMixin - A class mixin for creating the test environment objects, for -making custom tests.

  • -
  • EvenniaCommandMixin - A class mixin that adds support for command testing with the .call() -helper. Used by the command-test classes, but can be used for making a customt test class.

  • -
-
-
-evennia.utils.test_resources.mockdelay(timedelay, callback, *args, **kwargs)[source]
-
- -
-
-evennia.utils.test_resources.mockdeferLater(reactor, timedelay, callback, *args, **kwargs)[source]
-
- -
-
-evennia.utils.test_resources.unload_module(module)[source]
-

Reset import so one can mock global constants.

-
-
Parameters
-

module (module, object or str) – The module will -be removed so it will have to be imported again. If given -an object, the module in which that object sits will be unloaded. A string -should directly give the module pathname to unload.

-
-
-

Example

-
# (in a test method)
-unload_module(foo)
-with mock.patch("foo.GLOBALTHING", "mockval"):
-    import foo
-    ... # test code using foo.GLOBALTHING, now set to 'mockval'
-
-
-

This allows for mocking constants global to the module, since -otherwise those would not be mocked (since a module is only -loaded once).

-
- -
-
-class evennia.utils.test_resources.EvenniaTestMixin[source]
-

Bases: object

-

Evennia test environment mixin

-
-
-account_typeclass
-

alias of evennia.accounts.accounts.DefaultAccount

-
- -
-
-object_typeclass
-

alias of evennia.objects.objects.DefaultObject

-
- -
-
-character_typeclass
-

alias of evennia.objects.objects.DefaultCharacter

-
- -
-
-exit_typeclass
-

alias of evennia.objects.objects.DefaultExit

-
- -
-
-room_typeclass
-

alias of evennia.objects.objects.DefaultRoom

-
- -
-
-script_typeclass
-

alias of evennia.scripts.scripts.DefaultScript

-
- -
-
-create_accounts()[source]
-
- -
-
-teardown_accounts()[source]
-
- -
-
-create_rooms()[source]
-
- -
-
-create_objs()[source]
-
- -
-
-create_chars()[source]
-
- -
-
-create_script()[source]
-
- -
-
-setup_session()[source]
-
- -
-
-teardown_session()[source]
-
- -
-
-setUp()[source]
-

Sets up testing environment

-
- -
-
-tearDown()[source]
-
- -
- -
-
-class evennia.utils.test_resources.EvenniaCommandTestMixin[source]
-

Bases: object

-

Mixin to add to a test in order to provide the .call helper for -testing the execution and returns of a command.

-

Tests a Command by running it and comparing what messages it sends with -expected values. This tests without actually spinning up the cmdhandler -for every test, which is more controlled.

-

Example:

-
from commands.echo import CmdEcho
-
-class MyCommandTest(EvenniaTest, CommandTestMixin):
-
-    def test_echo(self):
-        '''
-        Test that the echo command really returns
-        what you pass into it.
-        '''
-        self.call(MyCommand(), "hello world!",
-                  "You hear your echo: 'Hello world!'")
-
-
-
-
-call(cmdobj, input_args, msg=None, cmdset=None, noansi=True, caller=None, receiver=None, cmdstring=None, obj=None, inputs=None, raw_string=None)[source]
-

Test a command by assigning all the needed properties to a cmdobj and -running the sequence. The resulting .msg calls will be mocked and -the text= calls to them compared to a expected output.

-
-
Parameters
-
    -
  • cmdobj (Command) – The command object to use.

  • -
  • input_args (str) – This should be the full input the Command should -see, such as ‘look here’. This will become .args for the Command -instance to parse.

  • -
  • msg (str or dict, optional) – This is the expected return value(s) -returned through caller.msg(text=…) calls in the command. If a string, the -receiver is controlled with the receiver kwarg (defaults to caller). -If this is a dict, it is a mapping -{receiver1: “expected1”, receiver2: “expected2”,…} and receiver is -ignored. The message(s) are compared with the actual messages returned -to the receiver(s) as the Command runs. Each check uses .startswith, -so you can choose to only include the first part of the -returned message if that’s enough to verify a correct result. EvMenu -decorations (like borders) are stripped and should not be included. This -should also not include color tags unless noansi=False. -If the command returns texts in multiple separate .msg- -calls to a receiver, separate these with | if noansi=True -(default) and || if noansi=False. If no msg is given (None), -then no automatic comparison will be done.

  • -
  • cmdset (str, optional) – If given, make .cmdset available on the Command -instance as it runs. While .cmdset is normally available on the -Command instance by default, this is usually only used by -commands that explicitly operates/displays cmdsets, like -examine.

  • -
  • noansi (str, optional) – By default the color tags of the msg is -ignored, this makes them significant. If unset, msg must contain -the same color tags as the actual return message.

  • -
  • caller (Object or Account, optional) – By default self.char1 is used as the -command-caller (the .caller property on the Command). This allows to -execute with another caller, most commonly an Account.

  • -
  • receiver (Object or Account, optional) – This is the object to receive the -return messages we want to test. By default this is the same as caller -(which in turn defaults to is self.char1). Note that if msg is -a dict, this is ignored since the receiver is already specified there.

  • -
  • cmdstring (str, optional) – Normally this is the Command’s key. -This allows for tweaking the .cmdname property of the -Command**. This isb used for commands with multiple aliases, -where the command explicitly checs which alias was used to -determine its functionality.

  • -
  • obj (str, optional) – This sets the .obj property of the Command - the -object on which the Command ‘sits’. By default this is the same as caller. -This can be used for testing on-object Command interactions.

  • -
  • inputs (list, optional) – A list of strings to pass to functions that pause to -take input from the user (normally using @interactive and -ret = yield(question) or evmenu.get_input). Each element of the -list will be passed into the command as if the user wrote that at the prompt.

  • -
  • raw_string (str, optional) – Normally the .raw_string property is set as -a combination of your key/cmdname and input_args. This allows -direct control of what this is, for example for testing edge cases -or malformed inputs.

  • -
-
-
Returns
-

str or dict

-
-
The message sent to receiver, or a dict of

{receiver: “msg”, …} if multiple are given. This is usually -only used with msg=None to do the validation externally.

-
-
-

-
-
Raises
-

AssertionError – If the returns of .msg calls (tested with .startswith) does not -match expected_input.

-
-
-

Notes

-

As part of the tests, all methods of the Command will be called in -the proper order:

-
    -
  • cmdobj.at_pre_cmd()

  • -
  • cmdobj.parse()

  • -
  • cmdobj.func()

  • -
  • cmdobj.at_post_cmd()

  • -
-
- -
- -
-
-class evennia.utils.test_resources.BaseEvenniaTestCase(methodName='runTest')[source]
-

Bases: django.test.testcases.TestCase

-

Base test (with no default objects) but with enforced default settings.

-
- -
-
-class evennia.utils.test_resources.EvenniaTestCase(methodName='runTest')[source]
-

Bases: django.test.testcases.TestCase

-

For use with gamedir settings; Just like the normal test case, only for naming consistency.

-
- -
-
-class evennia.utils.test_resources.BaseEvenniaTest(methodName='runTest')[source]
-

Bases: evennia.utils.test_resources.EvenniaTestMixin, django.test.testcases.TestCase

-

This class parent has all default objects and uses only default settings.

-
- -
-
-class evennia.utils.test_resources.EvenniaTest(methodName='runTest')[source]
-

Bases: evennia.utils.test_resources.EvenniaTestMixin, django.test.testcases.TestCase

-

This test class is intended for inheriting in mygame tests. -It helps ensure your tests are run with your own objects -and settings from your game folder.

-
-
-account_typeclass = 'typeclasses.accounts.Account'
-
- -
-
-object_typeclass = 'typeclasses.objects.Object'
-
- -
-
-character_typeclass = 'typeclasses.characters.Character'
-
- -
-
-exit_typeclass = 'typeclasses.exits.Exit'
-
- -
-
-room_typeclass = 'typeclasses.rooms.Room'
-
- -
-
-script_typeclass = 'typeclasses.scripts.Script'
-
- -
- -
-
-class evennia.utils.test_resources.BaseEvenniaCommandTest(methodName='runTest')[source]
-

Bases: evennia.utils.test_resources.BaseEvenniaTest, evennia.utils.test_resources.EvenniaCommandTestMixin

-

Commands only using the default settings.

-
- -
-
-class evennia.utils.test_resources.EvenniaCommandTest(methodName='runTest')[source]
-

Bases: evennia.utils.test_resources.EvenniaTest, evennia.utils.test_resources.EvenniaCommandTestMixin

-

Parent class to inherit from - makes tests use your own -classes and settings in mygame.

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.text2html.html b/docs/0.9.5/api/evennia.utils.text2html.html deleted file mode 100644 index 19d1248522..0000000000 --- a/docs/0.9.5/api/evennia.utils.text2html.html +++ /dev/null @@ -1,487 +0,0 @@ - - - - - - - - - evennia.utils.text2html — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.text2html

-

ANSI -> html converter

-

Credit for original idea and implementation -goes to Muhammad Alkarouri and his -snippet #577349 on http://code.activestate.com.

-

(extensively modified by Griatch 2010)

-
-
-class evennia.utils.text2html.TextToHTMLparser[source]
-

Bases: object

-

This class describes a parser for converting from ANSI to html.

-
-
-tabstop = 4
-
- -
-
-hilite = '\x1b[1m'
-
- -
-
-unhilite = '\x1b[22m'
-
- -
-
-normal = '\x1b[0m'
-
- -
-
-underline = '\x1b[4m'
-
- -
- -
- -
-
-inverse = '\x1b[7m'
-
- -
-
-colorcodes = [('color-000', '\x1b[22m\x1b[30m'), ('color-001', '\x1b[22m\x1b[31m'), ('color-002', '\x1b[22m\x1b[32m'), ('color-003', '\x1b[22m\x1b[33m'), ('color-004', '\x1b[22m\x1b[34m'), ('color-005', '\x1b[22m\x1b[35m'), ('color-006', '\x1b[22m\x1b[36m'), ('color-007', '\x1b[22m\x1b[37m'), ('color-008', '\x1b[1m\x1b[30m'), ('color-009', '\x1b[1m\x1b[31m'), ('color-010', '\x1b[1m\x1b[32m'), ('color-011', '\x1b[1m\x1b[33m'), ('color-012', '\x1b[1m\x1b[34m'), ('color-013', '\x1b[1m\x1b[35m'), ('color-014', '\x1b[1m\x1b[36m'), ('color-015', '\x1b[1m\x1b[37m'), ('color-016', '\x1b[38;5;16m'), ('color-017', '\x1b[38;5;17m'), ('color-018', '\x1b[38;5;18m'), ('color-019', '\x1b[38;5;19m'), ('color-020', '\x1b[38;5;20m'), ('color-021', '\x1b[38;5;21m'), ('color-022', '\x1b[38;5;22m'), ('color-023', '\x1b[38;5;23m'), ('color-024', '\x1b[38;5;24m'), ('color-025', '\x1b[38;5;25m'), ('color-026', '\x1b[38;5;26m'), ('color-027', '\x1b[38;5;27m'), ('color-028', '\x1b[38;5;28m'), ('color-029', '\x1b[38;5;29m'), ('color-030', '\x1b[38;5;30m'), ('color-031', '\x1b[38;5;31m'), ('color-032', '\x1b[38;5;32m'), ('color-033', '\x1b[38;5;33m'), ('color-034', '\x1b[38;5;34m'), ('color-035', '\x1b[38;5;35m'), ('color-036', '\x1b[38;5;36m'), ('color-037', '\x1b[38;5;37m'), ('color-038', '\x1b[38;5;38m'), ('color-039', '\x1b[38;5;39m'), ('color-040', '\x1b[38;5;40m'), ('color-041', '\x1b[38;5;41m'), ('color-042', '\x1b[38;5;42m'), ('color-043', '\x1b[38;5;43m'), ('color-044', '\x1b[38;5;44m'), ('color-045', '\x1b[38;5;45m'), ('color-046', '\x1b[38;5;46m'), ('color-047', '\x1b[38;5;47m'), ('color-048', '\x1b[38;5;48m'), ('color-049', '\x1b[38;5;49m'), ('color-050', '\x1b[38;5;50m'), ('color-051', '\x1b[38;5;51m'), ('color-052', '\x1b[38;5;52m'), ('color-053', '\x1b[38;5;53m'), ('color-054', '\x1b[38;5;54m'), ('color-055', '\x1b[38;5;55m'), ('color-056', '\x1b[38;5;56m'), ('color-057', '\x1b[38;5;57m'), ('color-058', '\x1b[38;5;58m'), ('color-059', '\x1b[38;5;59m'), ('color-060', '\x1b[38;5;60m'), ('color-061', '\x1b[38;5;61m'), ('color-062', '\x1b[38;5;62m'), ('color-063', '\x1b[38;5;63m'), ('color-064', '\x1b[38;5;64m'), ('color-065', '\x1b[38;5;65m'), ('color-066', '\x1b[38;5;66m'), ('color-067', '\x1b[38;5;67m'), ('color-068', '\x1b[38;5;68m'), ('color-069', '\x1b[38;5;69m'), ('color-070', '\x1b[38;5;70m'), ('color-071', '\x1b[38;5;71m'), ('color-072', '\x1b[38;5;72m'), ('color-073', '\x1b[38;5;73m'), ('color-074', '\x1b[38;5;74m'), ('color-075', '\x1b[38;5;75m'), ('color-076', '\x1b[38;5;76m'), ('color-077', '\x1b[38;5;77m'), ('color-078', '\x1b[38;5;78m'), ('color-079', '\x1b[38;5;79m'), ('color-080', '\x1b[38;5;80m'), ('color-081', '\x1b[38;5;81m'), ('color-082', '\x1b[38;5;82m'), ('color-083', '\x1b[38;5;83m'), ('color-084', '\x1b[38;5;84m'), ('color-085', '\x1b[38;5;85m'), ('color-086', '\x1b[38;5;86m'), ('color-087', '\x1b[38;5;87m'), ('color-088', '\x1b[38;5;88m'), ('color-089', '\x1b[38;5;89m'), ('color-090', '\x1b[38;5;90m'), ('color-091', '\x1b[38;5;91m'), ('color-092', '\x1b[38;5;92m'), ('color-093', '\x1b[38;5;93m'), ('color-094', '\x1b[38;5;94m'), ('color-095', '\x1b[38;5;95m'), ('color-096', '\x1b[38;5;96m'), ('color-097', '\x1b[38;5;97m'), ('color-098', '\x1b[38;5;98m'), ('color-099', '\x1b[38;5;99m'), ('color-100', '\x1b[38;5;100m'), ('color-101', '\x1b[38;5;101m'), ('color-102', '\x1b[38;5;102m'), ('color-103', '\x1b[38;5;103m'), ('color-104', '\x1b[38;5;104m'), ('color-105', '\x1b[38;5;105m'), ('color-106', '\x1b[38;5;106m'), ('color-107', '\x1b[38;5;107m'), ('color-108', '\x1b[38;5;108m'), ('color-109', '\x1b[38;5;109m'), ('color-110', '\x1b[38;5;110m'), ('color-111', '\x1b[38;5;111m'), ('color-112', '\x1b[38;5;112m'), ('color-113', '\x1b[38;5;113m'), ('color-114', '\x1b[38;5;114m'), ('color-115', '\x1b[38;5;115m'), ('color-116', '\x1b[38;5;116m'), ('color-117', '\x1b[38;5;117m'), ('color-118', '\x1b[38;5;118m'), ('color-119', '\x1b[38;5;119m'), ('color-120', '\x1b[38;5;120m'), ('color-121', '\x1b[38;5;121m'), ('color-122', '\x1b[38;5;122m'), ('color-123', '\x1b[38;5;123m'), ('color-124', '\x1b[38;5;124m'), ('color-125', '\x1b[38;5;125m'), ('color-126', '\x1b[38;5;126m'), ('color-127', '\x1b[38;5;127m'), ('color-128', '\x1b[38;5;128m'), ('color-129', '\x1b[38;5;129m'), ('color-130', '\x1b[38;5;130m'), ('color-131', '\x1b[38;5;131m'), ('color-132', '\x1b[38;5;132m'), ('color-133', '\x1b[38;5;133m'), ('color-134', '\x1b[38;5;134m'), ('color-135', '\x1b[38;5;135m'), ('color-136', '\x1b[38;5;136m'), ('color-137', '\x1b[38;5;137m'), ('color-138', '\x1b[38;5;138m'), ('color-139', '\x1b[38;5;139m'), ('color-140', '\x1b[38;5;140m'), ('color-141', '\x1b[38;5;141m'), ('color-142', '\x1b[38;5;142m'), ('color-143', '\x1b[38;5;143m'), ('color-144', '\x1b[38;5;144m'), ('color-145', '\x1b[38;5;145m'), ('color-146', '\x1b[38;5;146m'), ('color-147', '\x1b[38;5;147m'), ('color-148', '\x1b[38;5;148m'), ('color-149', '\x1b[38;5;149m'), ('color-150', '\x1b[38;5;150m'), ('color-151', '\x1b[38;5;151m'), ('color-152', '\x1b[38;5;152m'), ('color-153', '\x1b[38;5;153m'), ('color-154', '\x1b[38;5;154m'), ('color-155', '\x1b[38;5;155m'), ('color-156', '\x1b[38;5;156m'), ('color-157', '\x1b[38;5;157m'), ('color-158', '\x1b[38;5;158m'), ('color-159', '\x1b[38;5;159m'), ('color-160', '\x1b[38;5;160m'), ('color-161', '\x1b[38;5;161m'), ('color-162', '\x1b[38;5;162m'), ('color-163', '\x1b[38;5;163m'), ('color-164', '\x1b[38;5;164m'), ('color-165', '\x1b[38;5;165m'), ('color-166', '\x1b[38;5;166m'), ('color-167', '\x1b[38;5;167m'), ('color-168', '\x1b[38;5;168m'), ('color-169', '\x1b[38;5;169m'), ('color-170', '\x1b[38;5;170m'), ('color-171', '\x1b[38;5;171m'), ('color-172', '\x1b[38;5;172m'), ('color-173', '\x1b[38;5;173m'), ('color-174', '\x1b[38;5;174m'), ('color-175', '\x1b[38;5;175m'), ('color-176', '\x1b[38;5;176m'), ('color-177', '\x1b[38;5;177m'), ('color-178', '\x1b[38;5;178m'), ('color-179', '\x1b[38;5;179m'), ('color-180', '\x1b[38;5;180m'), ('color-181', '\x1b[38;5;181m'), ('color-182', '\x1b[38;5;182m'), ('color-183', '\x1b[38;5;183m'), ('color-184', '\x1b[38;5;184m'), ('color-185', '\x1b[38;5;185m'), ('color-186', '\x1b[38;5;186m'), ('color-187', '\x1b[38;5;187m'), ('color-188', '\x1b[38;5;188m'), ('color-189', '\x1b[38;5;189m'), ('color-190', '\x1b[38;5;190m'), ('color-191', '\x1b[38;5;191m'), ('color-192', '\x1b[38;5;192m'), ('color-193', '\x1b[38;5;193m'), ('color-194', '\x1b[38;5;194m'), ('color-195', '\x1b[38;5;195m'), ('color-196', '\x1b[38;5;196m'), ('color-197', '\x1b[38;5;197m'), ('color-198', '\x1b[38;5;198m'), ('color-199', '\x1b[38;5;199m'), ('color-200', '\x1b[38;5;200m'), ('color-201', '\x1b[38;5;201m'), ('color-202', '\x1b[38;5;202m'), ('color-203', '\x1b[38;5;203m'), ('color-204', '\x1b[38;5;204m'), ('color-205', '\x1b[38;5;205m'), ('color-206', '\x1b[38;5;206m'), ('color-207', '\x1b[38;5;207m'), ('color-208', '\x1b[38;5;208m'), ('color-209', '\x1b[38;5;209m'), ('color-210', '\x1b[38;5;210m'), ('color-211', '\x1b[38;5;211m'), ('color-212', '\x1b[38;5;212m'), ('color-213', '\x1b[38;5;213m'), ('color-214', '\x1b[38;5;214m'), ('color-215', '\x1b[38;5;215m'), ('color-216', '\x1b[38;5;216m'), ('color-217', '\x1b[38;5;217m'), ('color-218', '\x1b[38;5;218m'), ('color-219', '\x1b[38;5;219m'), ('color-220', '\x1b[38;5;220m'), ('color-221', '\x1b[38;5;221m'), ('color-222', '\x1b[38;5;222m'), ('color-223', '\x1b[38;5;223m'), ('color-224', '\x1b[38;5;224m'), ('color-225', '\x1b[38;5;225m'), ('color-226', '\x1b[38;5;226m'), ('color-227', '\x1b[38;5;227m'), ('color-228', '\x1b[38;5;228m'), ('color-229', '\x1b[38;5;229m'), ('color-230', '\x1b[38;5;230m'), ('color-231', '\x1b[38;5;231m'), ('color-232', '\x1b[38;5;232m'), ('color-233', '\x1b[38;5;233m'), ('color-234', '\x1b[38;5;234m'), ('color-235', '\x1b[38;5;235m'), ('color-236', '\x1b[38;5;236m'), ('color-237', '\x1b[38;5;237m'), ('color-238', '\x1b[38;5;238m'), ('color-239', '\x1b[38;5;239m'), ('color-240', '\x1b[38;5;240m'), ('color-241', '\x1b[38;5;241m'), ('color-242', '\x1b[38;5;242m'), ('color-243', '\x1b[38;5;243m'), ('color-244', '\x1b[38;5;244m'), ('color-245', '\x1b[38;5;245m'), ('color-246', '\x1b[38;5;246m'), ('color-247', '\x1b[38;5;247m'), ('color-248', '\x1b[38;5;248m'), ('color-249', '\x1b[38;5;249m'), ('color-250', '\x1b[38;5;250m'), ('color-251', '\x1b[38;5;251m'), ('color-252', '\x1b[38;5;252m'), ('color-253', '\x1b[38;5;253m'), ('color-254', '\x1b[38;5;254m'), ('color-255', '\x1b[38;5;255m')]
-
- -
-
-colorback = [('bgcolor-000', '\x1b[40m'), ('bgcolor-001', '\x1b[41m'), ('bgcolor-002', '\x1b[42m'), ('bgcolor-003', '\x1b[43m'), ('bgcolor-004', '\x1b[44m'), ('bgcolor-005', '\x1b[45m'), ('bgcolor-006', '\x1b[46m'), ('bgcolor-007', '\x1b[47m'), ('bgcolor-008', '\x1b[1m\x1b[40m'), ('bgcolor-009', '\x1b[1m\x1b[41m'), ('bgcolor-010', '\x1b[1m\x1b[42m'), ('bgcolor-011', '\x1b[1m\x1b[43m'), ('bgcolor-012', '\x1b[1m\x1b[44m'), ('bgcolor-013', '\x1b[1m\x1b[45m'), ('bgcolor-014', '\x1b[1m\x1b[46m'), ('bgcolor-015', '\x1b[1m\x1b[47m'), ('bgcolor-016', '\x1b[48;5;16m'), ('bgcolor-017', '\x1b[48;5;17m'), ('bgcolor-018', '\x1b[48;5;18m'), ('bgcolor-019', '\x1b[48;5;19m'), ('bgcolor-020', '\x1b[48;5;20m'), ('bgcolor-021', '\x1b[48;5;21m'), ('bgcolor-022', '\x1b[48;5;22m'), ('bgcolor-023', '\x1b[48;5;23m'), ('bgcolor-024', '\x1b[48;5;24m'), ('bgcolor-025', '\x1b[48;5;25m'), ('bgcolor-026', '\x1b[48;5;26m'), ('bgcolor-027', '\x1b[48;5;27m'), ('bgcolor-028', '\x1b[48;5;28m'), ('bgcolor-029', '\x1b[48;5;29m'), ('bgcolor-030', '\x1b[48;5;30m'), ('bgcolor-031', '\x1b[48;5;31m'), ('bgcolor-032', '\x1b[48;5;32m'), ('bgcolor-033', '\x1b[48;5;33m'), ('bgcolor-034', '\x1b[48;5;34m'), ('bgcolor-035', '\x1b[48;5;35m'), ('bgcolor-036', '\x1b[48;5;36m'), ('bgcolor-037', '\x1b[48;5;37m'), ('bgcolor-038', '\x1b[48;5;38m'), ('bgcolor-039', '\x1b[48;5;39m'), ('bgcolor-040', '\x1b[48;5;40m'), ('bgcolor-041', '\x1b[48;5;41m'), ('bgcolor-042', '\x1b[48;5;42m'), ('bgcolor-043', '\x1b[48;5;43m'), ('bgcolor-044', '\x1b[48;5;44m'), ('bgcolor-045', '\x1b[48;5;45m'), ('bgcolor-046', '\x1b[48;5;46m'), ('bgcolor-047', '\x1b[48;5;47m'), ('bgcolor-048', '\x1b[48;5;48m'), ('bgcolor-049', '\x1b[48;5;49m'), ('bgcolor-050', '\x1b[48;5;50m'), ('bgcolor-051', '\x1b[48;5;51m'), ('bgcolor-052', '\x1b[48;5;52m'), ('bgcolor-053', '\x1b[48;5;53m'), ('bgcolor-054', '\x1b[48;5;54m'), ('bgcolor-055', '\x1b[48;5;55m'), ('bgcolor-056', '\x1b[48;5;56m'), ('bgcolor-057', '\x1b[48;5;57m'), ('bgcolor-058', '\x1b[48;5;58m'), ('bgcolor-059', '\x1b[48;5;59m'), ('bgcolor-060', '\x1b[48;5;60m'), ('bgcolor-061', '\x1b[48;5;61m'), ('bgcolor-062', '\x1b[48;5;62m'), ('bgcolor-063', '\x1b[48;5;63m'), ('bgcolor-064', '\x1b[48;5;64m'), ('bgcolor-065', '\x1b[48;5;65m'), ('bgcolor-066', '\x1b[48;5;66m'), ('bgcolor-067', '\x1b[48;5;67m'), ('bgcolor-068', '\x1b[48;5;68m'), ('bgcolor-069', '\x1b[48;5;69m'), ('bgcolor-070', '\x1b[48;5;70m'), ('bgcolor-071', '\x1b[48;5;71m'), ('bgcolor-072', '\x1b[48;5;72m'), ('bgcolor-073', '\x1b[48;5;73m'), ('bgcolor-074', '\x1b[48;5;74m'), ('bgcolor-075', '\x1b[48;5;75m'), ('bgcolor-076', '\x1b[48;5;76m'), ('bgcolor-077', '\x1b[48;5;77m'), ('bgcolor-078', '\x1b[48;5;78m'), ('bgcolor-079', '\x1b[48;5;79m'), ('bgcolor-080', '\x1b[48;5;80m'), ('bgcolor-081', '\x1b[48;5;81m'), ('bgcolor-082', '\x1b[48;5;82m'), ('bgcolor-083', '\x1b[48;5;83m'), ('bgcolor-084', '\x1b[48;5;84m'), ('bgcolor-085', '\x1b[48;5;85m'), ('bgcolor-086', '\x1b[48;5;86m'), ('bgcolor-087', '\x1b[48;5;87m'), ('bgcolor-088', '\x1b[48;5;88m'), ('bgcolor-089', '\x1b[48;5;89m'), ('bgcolor-090', '\x1b[48;5;90m'), ('bgcolor-091', '\x1b[48;5;91m'), ('bgcolor-092', '\x1b[48;5;92m'), ('bgcolor-093', '\x1b[48;5;93m'), ('bgcolor-094', '\x1b[48;5;94m'), ('bgcolor-095', '\x1b[48;5;95m'), ('bgcolor-096', '\x1b[48;5;96m'), ('bgcolor-097', '\x1b[48;5;97m'), ('bgcolor-098', '\x1b[48;5;98m'), ('bgcolor-099', '\x1b[48;5;99m'), ('bgcolor-100', '\x1b[48;5;100m'), ('bgcolor-101', '\x1b[48;5;101m'), ('bgcolor-102', '\x1b[48;5;102m'), ('bgcolor-103', '\x1b[48;5;103m'), ('bgcolor-104', '\x1b[48;5;104m'), ('bgcolor-105', '\x1b[48;5;105m'), ('bgcolor-106', '\x1b[48;5;106m'), ('bgcolor-107', '\x1b[48;5;107m'), ('bgcolor-108', '\x1b[48;5;108m'), ('bgcolor-109', '\x1b[48;5;109m'), ('bgcolor-110', '\x1b[48;5;110m'), ('bgcolor-111', '\x1b[48;5;111m'), ('bgcolor-112', '\x1b[48;5;112m'), ('bgcolor-113', '\x1b[48;5;113m'), ('bgcolor-114', '\x1b[48;5;114m'), ('bgcolor-115', '\x1b[48;5;115m'), ('bgcolor-116', '\x1b[48;5;116m'), ('bgcolor-117', '\x1b[48;5;117m'), ('bgcolor-118', '\x1b[48;5;118m'), ('bgcolor-119', '\x1b[48;5;119m'), ('bgcolor-120', '\x1b[48;5;120m'), ('bgcolor-121', '\x1b[48;5;121m'), ('bgcolor-122', '\x1b[48;5;122m'), ('bgcolor-123', '\x1b[48;5;123m'), ('bgcolor-124', '\x1b[48;5;124m'), ('bgcolor-125', '\x1b[48;5;125m'), ('bgcolor-126', '\x1b[48;5;126m'), ('bgcolor-127', '\x1b[48;5;127m'), ('bgcolor-128', '\x1b[48;5;128m'), ('bgcolor-129', '\x1b[48;5;129m'), ('bgcolor-130', '\x1b[48;5;130m'), ('bgcolor-131', '\x1b[48;5;131m'), ('bgcolor-132', '\x1b[48;5;132m'), ('bgcolor-133', '\x1b[48;5;133m'), ('bgcolor-134', '\x1b[48;5;134m'), ('bgcolor-135', '\x1b[48;5;135m'), ('bgcolor-136', '\x1b[48;5;136m'), ('bgcolor-137', '\x1b[48;5;137m'), ('bgcolor-138', '\x1b[48;5;138m'), ('bgcolor-139', '\x1b[48;5;139m'), ('bgcolor-140', '\x1b[48;5;140m'), ('bgcolor-141', '\x1b[48;5;141m'), ('bgcolor-142', '\x1b[48;5;142m'), ('bgcolor-143', '\x1b[48;5;143m'), ('bgcolor-144', '\x1b[48;5;144m'), ('bgcolor-145', '\x1b[48;5;145m'), ('bgcolor-146', '\x1b[48;5;146m'), ('bgcolor-147', '\x1b[48;5;147m'), ('bgcolor-148', '\x1b[48;5;148m'), ('bgcolor-149', '\x1b[48;5;149m'), ('bgcolor-150', '\x1b[48;5;150m'), ('bgcolor-151', '\x1b[48;5;151m'), ('bgcolor-152', '\x1b[48;5;152m'), ('bgcolor-153', '\x1b[48;5;153m'), ('bgcolor-154', '\x1b[48;5;154m'), ('bgcolor-155', '\x1b[48;5;155m'), ('bgcolor-156', '\x1b[48;5;156m'), ('bgcolor-157', '\x1b[48;5;157m'), ('bgcolor-158', '\x1b[48;5;158m'), ('bgcolor-159', '\x1b[48;5;159m'), ('bgcolor-160', '\x1b[48;5;160m'), ('bgcolor-161', '\x1b[48;5;161m'), ('bgcolor-162', '\x1b[48;5;162m'), ('bgcolor-163', '\x1b[48;5;163m'), ('bgcolor-164', '\x1b[48;5;164m'), ('bgcolor-165', '\x1b[48;5;165m'), ('bgcolor-166', '\x1b[48;5;166m'), ('bgcolor-167', '\x1b[48;5;167m'), ('bgcolor-168', '\x1b[48;5;168m'), ('bgcolor-169', '\x1b[48;5;169m'), ('bgcolor-170', '\x1b[48;5;170m'), ('bgcolor-171', '\x1b[48;5;171m'), ('bgcolor-172', '\x1b[48;5;172m'), ('bgcolor-173', '\x1b[48;5;173m'), ('bgcolor-174', '\x1b[48;5;174m'), ('bgcolor-175', '\x1b[48;5;175m'), ('bgcolor-176', '\x1b[48;5;176m'), ('bgcolor-177', '\x1b[48;5;177m'), ('bgcolor-178', '\x1b[48;5;178m'), ('bgcolor-179', '\x1b[48;5;179m'), ('bgcolor-180', '\x1b[48;5;180m'), ('bgcolor-181', '\x1b[48;5;181m'), ('bgcolor-182', '\x1b[48;5;182m'), ('bgcolor-183', '\x1b[48;5;183m'), ('bgcolor-184', '\x1b[48;5;184m'), ('bgcolor-185', '\x1b[48;5;185m'), ('bgcolor-186', '\x1b[48;5;186m'), ('bgcolor-187', '\x1b[48;5;187m'), ('bgcolor-188', '\x1b[48;5;188m'), ('bgcolor-189', '\x1b[48;5;189m'), ('bgcolor-190', '\x1b[48;5;190m'), ('bgcolor-191', '\x1b[48;5;191m'), ('bgcolor-192', '\x1b[48;5;192m'), ('bgcolor-193', '\x1b[48;5;193m'), ('bgcolor-194', '\x1b[48;5;194m'), ('bgcolor-195', '\x1b[48;5;195m'), ('bgcolor-196', '\x1b[48;5;196m'), ('bgcolor-197', '\x1b[48;5;197m'), ('bgcolor-198', '\x1b[48;5;198m'), ('bgcolor-199', '\x1b[48;5;199m'), ('bgcolor-200', '\x1b[48;5;200m'), ('bgcolor-201', '\x1b[48;5;201m'), ('bgcolor-202', '\x1b[48;5;202m'), ('bgcolor-203', '\x1b[48;5;203m'), ('bgcolor-204', '\x1b[48;5;204m'), ('bgcolor-205', '\x1b[48;5;205m'), ('bgcolor-206', '\x1b[48;5;206m'), ('bgcolor-207', '\x1b[48;5;207m'), ('bgcolor-208', '\x1b[48;5;208m'), ('bgcolor-209', '\x1b[48;5;209m'), ('bgcolor-210', '\x1b[48;5;210m'), ('bgcolor-211', '\x1b[48;5;211m'), ('bgcolor-212', '\x1b[48;5;212m'), ('bgcolor-213', '\x1b[48;5;213m'), ('bgcolor-214', '\x1b[48;5;214m'), ('bgcolor-215', '\x1b[48;5;215m'), ('bgcolor-216', '\x1b[48;5;216m'), ('bgcolor-217', '\x1b[48;5;217m'), ('bgcolor-218', '\x1b[48;5;218m'), ('bgcolor-219', '\x1b[48;5;219m'), ('bgcolor-220', '\x1b[48;5;220m'), ('bgcolor-221', '\x1b[48;5;221m'), ('bgcolor-222', '\x1b[48;5;222m'), ('bgcolor-223', '\x1b[48;5;223m'), ('bgcolor-224', '\x1b[48;5;224m'), ('bgcolor-225', '\x1b[48;5;225m'), ('bgcolor-226', '\x1b[48;5;226m'), ('bgcolor-227', '\x1b[48;5;227m'), ('bgcolor-228', '\x1b[48;5;228m'), ('bgcolor-229', '\x1b[48;5;229m'), ('bgcolor-230', '\x1b[48;5;230m'), ('bgcolor-231', '\x1b[48;5;231m'), ('bgcolor-232', '\x1b[48;5;232m'), ('bgcolor-233', '\x1b[48;5;233m'), ('bgcolor-234', '\x1b[48;5;234m'), ('bgcolor-235', '\x1b[48;5;235m'), ('bgcolor-236', '\x1b[48;5;236m'), ('bgcolor-237', '\x1b[48;5;237m'), ('bgcolor-238', '\x1b[48;5;238m'), ('bgcolor-239', '\x1b[48;5;239m'), ('bgcolor-240', '\x1b[48;5;240m'), ('bgcolor-241', '\x1b[48;5;241m'), ('bgcolor-242', '\x1b[48;5;242m'), ('bgcolor-243', '\x1b[48;5;243m'), ('bgcolor-244', '\x1b[48;5;244m'), ('bgcolor-245', '\x1b[48;5;245m'), ('bgcolor-246', '\x1b[48;5;246m'), ('bgcolor-247', '\x1b[48;5;247m'), ('bgcolor-248', '\x1b[48;5;248m'), ('bgcolor-249', '\x1b[48;5;249m'), ('bgcolor-250', '\x1b[48;5;250m'), ('bgcolor-251', '\x1b[48;5;251m'), ('bgcolor-252', '\x1b[48;5;252m'), ('bgcolor-253', '\x1b[48;5;253m'), ('bgcolor-254', '\x1b[48;5;254m'), ('bgcolor-255', '\x1b[48;5;255m')]
-
- -
-
-fg_colormap = {'\x1b[1m\x1b[30m': 'color-008', '\x1b[1m\x1b[31m': 'color-009', '\x1b[1m\x1b[32m': 'color-010', '\x1b[1m\x1b[33m': 'color-011', '\x1b[1m\x1b[34m': 'color-012', '\x1b[1m\x1b[35m': 'color-013', '\x1b[1m\x1b[36m': 'color-014', '\x1b[1m\x1b[37m': 'color-015', '\x1b[22m\x1b[30m': 'color-000', '\x1b[22m\x1b[31m': 'color-001', '\x1b[22m\x1b[32m': 'color-002', '\x1b[22m\x1b[33m': 'color-003', '\x1b[22m\x1b[34m': 'color-004', '\x1b[22m\x1b[35m': 'color-005', '\x1b[22m\x1b[36m': 'color-006', '\x1b[22m\x1b[37m': 'color-007', '\x1b[38;5;100m': 'color-100', '\x1b[38;5;101m': 'color-101', '\x1b[38;5;102m': 'color-102', '\x1b[38;5;103m': 'color-103', '\x1b[38;5;104m': 'color-104', '\x1b[38;5;105m': 'color-105', '\x1b[38;5;106m': 'color-106', '\x1b[38;5;107m': 'color-107', '\x1b[38;5;108m': 'color-108', '\x1b[38;5;109m': 'color-109', '\x1b[38;5;110m': 'color-110', '\x1b[38;5;111m': 'color-111', '\x1b[38;5;112m': 'color-112', '\x1b[38;5;113m': 'color-113', '\x1b[38;5;114m': 'color-114', '\x1b[38;5;115m': 'color-115', '\x1b[38;5;116m': 'color-116', '\x1b[38;5;117m': 'color-117', '\x1b[38;5;118m': 'color-118', '\x1b[38;5;119m': 'color-119', '\x1b[38;5;120m': 'color-120', '\x1b[38;5;121m': 'color-121', '\x1b[38;5;122m': 'color-122', '\x1b[38;5;123m': 'color-123', '\x1b[38;5;124m': 'color-124', '\x1b[38;5;125m': 'color-125', '\x1b[38;5;126m': 'color-126', '\x1b[38;5;127m': 'color-127', '\x1b[38;5;128m': 'color-128', '\x1b[38;5;129m': 'color-129', '\x1b[38;5;130m': 'color-130', '\x1b[38;5;131m': 'color-131', '\x1b[38;5;132m': 'color-132', '\x1b[38;5;133m': 'color-133', '\x1b[38;5;134m': 'color-134', '\x1b[38;5;135m': 'color-135', '\x1b[38;5;136m': 'color-136', '\x1b[38;5;137m': 'color-137', '\x1b[38;5;138m': 'color-138', '\x1b[38;5;139m': 'color-139', '\x1b[38;5;140m': 'color-140', '\x1b[38;5;141m': 'color-141', '\x1b[38;5;142m': 'color-142', '\x1b[38;5;143m': 'color-143', '\x1b[38;5;144m': 'color-144', '\x1b[38;5;145m': 'color-145', '\x1b[38;5;146m': 'color-146', '\x1b[38;5;147m': 'color-147', '\x1b[38;5;148m': 'color-148', '\x1b[38;5;149m': 'color-149', '\x1b[38;5;150m': 'color-150', '\x1b[38;5;151m': 'color-151', '\x1b[38;5;152m': 'color-152', '\x1b[38;5;153m': 'color-153', '\x1b[38;5;154m': 'color-154', '\x1b[38;5;155m': 'color-155', '\x1b[38;5;156m': 'color-156', '\x1b[38;5;157m': 'color-157', '\x1b[38;5;158m': 'color-158', '\x1b[38;5;159m': 'color-159', '\x1b[38;5;160m': 'color-160', '\x1b[38;5;161m': 'color-161', '\x1b[38;5;162m': 'color-162', '\x1b[38;5;163m': 'color-163', '\x1b[38;5;164m': 'color-164', '\x1b[38;5;165m': 'color-165', '\x1b[38;5;166m': 'color-166', '\x1b[38;5;167m': 'color-167', '\x1b[38;5;168m': 'color-168', '\x1b[38;5;169m': 'color-169', '\x1b[38;5;16m': 'color-016', '\x1b[38;5;170m': 'color-170', '\x1b[38;5;171m': 'color-171', '\x1b[38;5;172m': 'color-172', '\x1b[38;5;173m': 'color-173', '\x1b[38;5;174m': 'color-174', '\x1b[38;5;175m': 'color-175', '\x1b[38;5;176m': 'color-176', '\x1b[38;5;177m': 'color-177', '\x1b[38;5;178m': 'color-178', '\x1b[38;5;179m': 'color-179', '\x1b[38;5;17m': 'color-017', '\x1b[38;5;180m': 'color-180', '\x1b[38;5;181m': 'color-181', '\x1b[38;5;182m': 'color-182', '\x1b[38;5;183m': 'color-183', '\x1b[38;5;184m': 'color-184', '\x1b[38;5;185m': 'color-185', '\x1b[38;5;186m': 'color-186', '\x1b[38;5;187m': 'color-187', '\x1b[38;5;188m': 'color-188', '\x1b[38;5;189m': 'color-189', '\x1b[38;5;18m': 'color-018', '\x1b[38;5;190m': 'color-190', '\x1b[38;5;191m': 'color-191', '\x1b[38;5;192m': 'color-192', '\x1b[38;5;193m': 'color-193', '\x1b[38;5;194m': 'color-194', '\x1b[38;5;195m': 'color-195', '\x1b[38;5;196m': 'color-196', '\x1b[38;5;197m': 'color-197', '\x1b[38;5;198m': 'color-198', '\x1b[38;5;199m': 'color-199', '\x1b[38;5;19m': 'color-019', '\x1b[38;5;200m': 'color-200', '\x1b[38;5;201m': 'color-201', '\x1b[38;5;202m': 'color-202', '\x1b[38;5;203m': 'color-203', '\x1b[38;5;204m': 'color-204', '\x1b[38;5;205m': 'color-205', '\x1b[38;5;206m': 'color-206', '\x1b[38;5;207m': 'color-207', '\x1b[38;5;208m': 'color-208', '\x1b[38;5;209m': 'color-209', '\x1b[38;5;20m': 'color-020', '\x1b[38;5;210m': 'color-210', '\x1b[38;5;211m': 'color-211', '\x1b[38;5;212m': 'color-212', '\x1b[38;5;213m': 'color-213', '\x1b[38;5;214m': 'color-214', '\x1b[38;5;215m': 'color-215', '\x1b[38;5;216m': 'color-216', '\x1b[38;5;217m': 'color-217', '\x1b[38;5;218m': 'color-218', '\x1b[38;5;219m': 'color-219', '\x1b[38;5;21m': 'color-021', '\x1b[38;5;220m': 'color-220', '\x1b[38;5;221m': 'color-221', '\x1b[38;5;222m': 'color-222', '\x1b[38;5;223m': 'color-223', '\x1b[38;5;224m': 'color-224', '\x1b[38;5;225m': 'color-225', '\x1b[38;5;226m': 'color-226', '\x1b[38;5;227m': 'color-227', '\x1b[38;5;228m': 'color-228', '\x1b[38;5;229m': 'color-229', '\x1b[38;5;22m': 'color-022', '\x1b[38;5;230m': 'color-230', '\x1b[38;5;231m': 'color-231', '\x1b[38;5;232m': 'color-232', '\x1b[38;5;233m': 'color-233', '\x1b[38;5;234m': 'color-234', '\x1b[38;5;235m': 'color-235', '\x1b[38;5;236m': 'color-236', '\x1b[38;5;237m': 'color-237', '\x1b[38;5;238m': 'color-238', '\x1b[38;5;239m': 'color-239', '\x1b[38;5;23m': 'color-023', '\x1b[38;5;240m': 'color-240', '\x1b[38;5;241m': 'color-241', '\x1b[38;5;242m': 'color-242', '\x1b[38;5;243m': 'color-243', '\x1b[38;5;244m': 'color-244', '\x1b[38;5;245m': 'color-245', '\x1b[38;5;246m': 'color-246', '\x1b[38;5;247m': 'color-247', '\x1b[38;5;248m': 'color-248', '\x1b[38;5;249m': 'color-249', '\x1b[38;5;24m': 'color-024', '\x1b[38;5;250m': 'color-250', '\x1b[38;5;251m': 'color-251', '\x1b[38;5;252m': 'color-252', '\x1b[38;5;253m': 'color-253', '\x1b[38;5;254m': 'color-254', '\x1b[38;5;255m': 'color-255', '\x1b[38;5;25m': 'color-025', '\x1b[38;5;26m': 'color-026', '\x1b[38;5;27m': 'color-027', '\x1b[38;5;28m': 'color-028', '\x1b[38;5;29m': 'color-029', '\x1b[38;5;30m': 'color-030', '\x1b[38;5;31m': 'color-031', '\x1b[38;5;32m': 'color-032', '\x1b[38;5;33m': 'color-033', '\x1b[38;5;34m': 'color-034', '\x1b[38;5;35m': 'color-035', '\x1b[38;5;36m': 'color-036', '\x1b[38;5;37m': 'color-037', '\x1b[38;5;38m': 'color-038', '\x1b[38;5;39m': 'color-039', '\x1b[38;5;40m': 'color-040', '\x1b[38;5;41m': 'color-041', '\x1b[38;5;42m': 'color-042', '\x1b[38;5;43m': 'color-043', '\x1b[38;5;44m': 'color-044', '\x1b[38;5;45m': 'color-045', '\x1b[38;5;46m': 'color-046', '\x1b[38;5;47m': 'color-047', '\x1b[38;5;48m': 'color-048', '\x1b[38;5;49m': 'color-049', '\x1b[38;5;50m': 'color-050', '\x1b[38;5;51m': 'color-051', '\x1b[38;5;52m': 'color-052', '\x1b[38;5;53m': 'color-053', '\x1b[38;5;54m': 'color-054', '\x1b[38;5;55m': 'color-055', '\x1b[38;5;56m': 'color-056', '\x1b[38;5;57m': 'color-057', '\x1b[38;5;58m': 'color-058', '\x1b[38;5;59m': 'color-059', '\x1b[38;5;60m': 'color-060', '\x1b[38;5;61m': 'color-061', '\x1b[38;5;62m': 'color-062', '\x1b[38;5;63m': 'color-063', '\x1b[38;5;64m': 'color-064', '\x1b[38;5;65m': 'color-065', '\x1b[38;5;66m': 'color-066', '\x1b[38;5;67m': 'color-067', '\x1b[38;5;68m': 'color-068', '\x1b[38;5;69m': 'color-069', '\x1b[38;5;70m': 'color-070', '\x1b[38;5;71m': 'color-071', '\x1b[38;5;72m': 'color-072', '\x1b[38;5;73m': 'color-073', '\x1b[38;5;74m': 'color-074', '\x1b[38;5;75m': 'color-075', '\x1b[38;5;76m': 'color-076', '\x1b[38;5;77m': 'color-077', '\x1b[38;5;78m': 'color-078', '\x1b[38;5;79m': 'color-079', '\x1b[38;5;80m': 'color-080', '\x1b[38;5;81m': 'color-081', '\x1b[38;5;82m': 'color-082', '\x1b[38;5;83m': 'color-083', '\x1b[38;5;84m': 'color-084', '\x1b[38;5;85m': 'color-085', '\x1b[38;5;86m': 'color-086', '\x1b[38;5;87m': 'color-087', '\x1b[38;5;88m': 'color-088', '\x1b[38;5;89m': 'color-089', '\x1b[38;5;90m': 'color-090', '\x1b[38;5;91m': 'color-091', '\x1b[38;5;92m': 'color-092', '\x1b[38;5;93m': 'color-093', '\x1b[38;5;94m': 'color-094', '\x1b[38;5;95m': 'color-095', '\x1b[38;5;96m': 'color-096', '\x1b[38;5;97m': 'color-097', '\x1b[38;5;98m': 'color-098', '\x1b[38;5;99m': 'color-099'}
-
- -
-
-bg_colormap = {'\x1b[1m\x1b[40m': 'bgcolor-008', '\x1b[1m\x1b[41m': 'bgcolor-009', '\x1b[1m\x1b[42m': 'bgcolor-010', '\x1b[1m\x1b[43m': 'bgcolor-011', '\x1b[1m\x1b[44m': 'bgcolor-012', '\x1b[1m\x1b[45m': 'bgcolor-013', '\x1b[1m\x1b[46m': 'bgcolor-014', '\x1b[1m\x1b[47m': 'bgcolor-015', '\x1b[40m': 'bgcolor-000', '\x1b[41m': 'bgcolor-001', '\x1b[42m': 'bgcolor-002', '\x1b[43m': 'bgcolor-003', '\x1b[44m': 'bgcolor-004', '\x1b[45m': 'bgcolor-005', '\x1b[46m': 'bgcolor-006', '\x1b[47m': 'bgcolor-007', '\x1b[48;5;100m': 'bgcolor-100', '\x1b[48;5;101m': 'bgcolor-101', '\x1b[48;5;102m': 'bgcolor-102', '\x1b[48;5;103m': 'bgcolor-103', '\x1b[48;5;104m': 'bgcolor-104', '\x1b[48;5;105m': 'bgcolor-105', '\x1b[48;5;106m': 'bgcolor-106', '\x1b[48;5;107m': 'bgcolor-107', '\x1b[48;5;108m': 'bgcolor-108', '\x1b[48;5;109m': 'bgcolor-109', '\x1b[48;5;110m': 'bgcolor-110', '\x1b[48;5;111m': 'bgcolor-111', '\x1b[48;5;112m': 'bgcolor-112', '\x1b[48;5;113m': 'bgcolor-113', '\x1b[48;5;114m': 'bgcolor-114', '\x1b[48;5;115m': 'bgcolor-115', '\x1b[48;5;116m': 'bgcolor-116', '\x1b[48;5;117m': 'bgcolor-117', '\x1b[48;5;118m': 'bgcolor-118', '\x1b[48;5;119m': 'bgcolor-119', '\x1b[48;5;120m': 'bgcolor-120', '\x1b[48;5;121m': 'bgcolor-121', '\x1b[48;5;122m': 'bgcolor-122', '\x1b[48;5;123m': 'bgcolor-123', '\x1b[48;5;124m': 'bgcolor-124', '\x1b[48;5;125m': 'bgcolor-125', '\x1b[48;5;126m': 'bgcolor-126', '\x1b[48;5;127m': 'bgcolor-127', '\x1b[48;5;128m': 'bgcolor-128', '\x1b[48;5;129m': 'bgcolor-129', '\x1b[48;5;130m': 'bgcolor-130', '\x1b[48;5;131m': 'bgcolor-131', '\x1b[48;5;132m': 'bgcolor-132', '\x1b[48;5;133m': 'bgcolor-133', '\x1b[48;5;134m': 'bgcolor-134', '\x1b[48;5;135m': 'bgcolor-135', '\x1b[48;5;136m': 'bgcolor-136', '\x1b[48;5;137m': 'bgcolor-137', '\x1b[48;5;138m': 'bgcolor-138', '\x1b[48;5;139m': 'bgcolor-139', '\x1b[48;5;140m': 'bgcolor-140', '\x1b[48;5;141m': 'bgcolor-141', '\x1b[48;5;142m': 'bgcolor-142', '\x1b[48;5;143m': 'bgcolor-143', '\x1b[48;5;144m': 'bgcolor-144', '\x1b[48;5;145m': 'bgcolor-145', '\x1b[48;5;146m': 'bgcolor-146', '\x1b[48;5;147m': 'bgcolor-147', '\x1b[48;5;148m': 'bgcolor-148', '\x1b[48;5;149m': 'bgcolor-149', '\x1b[48;5;150m': 'bgcolor-150', '\x1b[48;5;151m': 'bgcolor-151', '\x1b[48;5;152m': 'bgcolor-152', '\x1b[48;5;153m': 'bgcolor-153', '\x1b[48;5;154m': 'bgcolor-154', '\x1b[48;5;155m': 'bgcolor-155', '\x1b[48;5;156m': 'bgcolor-156', '\x1b[48;5;157m': 'bgcolor-157', '\x1b[48;5;158m': 'bgcolor-158', '\x1b[48;5;159m': 'bgcolor-159', '\x1b[48;5;160m': 'bgcolor-160', '\x1b[48;5;161m': 'bgcolor-161', '\x1b[48;5;162m': 'bgcolor-162', '\x1b[48;5;163m': 'bgcolor-163', '\x1b[48;5;164m': 'bgcolor-164', '\x1b[48;5;165m': 'bgcolor-165', '\x1b[48;5;166m': 'bgcolor-166', '\x1b[48;5;167m': 'bgcolor-167', '\x1b[48;5;168m': 'bgcolor-168', '\x1b[48;5;169m': 'bgcolor-169', '\x1b[48;5;16m': 'bgcolor-016', '\x1b[48;5;170m': 'bgcolor-170', '\x1b[48;5;171m': 'bgcolor-171', '\x1b[48;5;172m': 'bgcolor-172', '\x1b[48;5;173m': 'bgcolor-173', '\x1b[48;5;174m': 'bgcolor-174', '\x1b[48;5;175m': 'bgcolor-175', '\x1b[48;5;176m': 'bgcolor-176', '\x1b[48;5;177m': 'bgcolor-177', '\x1b[48;5;178m': 'bgcolor-178', '\x1b[48;5;179m': 'bgcolor-179', '\x1b[48;5;17m': 'bgcolor-017', '\x1b[48;5;180m': 'bgcolor-180', '\x1b[48;5;181m': 'bgcolor-181', '\x1b[48;5;182m': 'bgcolor-182', '\x1b[48;5;183m': 'bgcolor-183', '\x1b[48;5;184m': 'bgcolor-184', '\x1b[48;5;185m': 'bgcolor-185', '\x1b[48;5;186m': 'bgcolor-186', '\x1b[48;5;187m': 'bgcolor-187', '\x1b[48;5;188m': 'bgcolor-188', '\x1b[48;5;189m': 'bgcolor-189', '\x1b[48;5;18m': 'bgcolor-018', '\x1b[48;5;190m': 'bgcolor-190', '\x1b[48;5;191m': 'bgcolor-191', '\x1b[48;5;192m': 'bgcolor-192', '\x1b[48;5;193m': 'bgcolor-193', '\x1b[48;5;194m': 'bgcolor-194', '\x1b[48;5;195m': 'bgcolor-195', '\x1b[48;5;196m': 'bgcolor-196', '\x1b[48;5;197m': 'bgcolor-197', '\x1b[48;5;198m': 'bgcolor-198', '\x1b[48;5;199m': 'bgcolor-199', '\x1b[48;5;19m': 'bgcolor-019', '\x1b[48;5;200m': 'bgcolor-200', '\x1b[48;5;201m': 'bgcolor-201', '\x1b[48;5;202m': 'bgcolor-202', '\x1b[48;5;203m': 'bgcolor-203', '\x1b[48;5;204m': 'bgcolor-204', '\x1b[48;5;205m': 'bgcolor-205', '\x1b[48;5;206m': 'bgcolor-206', '\x1b[48;5;207m': 'bgcolor-207', '\x1b[48;5;208m': 'bgcolor-208', '\x1b[48;5;209m': 'bgcolor-209', '\x1b[48;5;20m': 'bgcolor-020', '\x1b[48;5;210m': 'bgcolor-210', '\x1b[48;5;211m': 'bgcolor-211', '\x1b[48;5;212m': 'bgcolor-212', '\x1b[48;5;213m': 'bgcolor-213', '\x1b[48;5;214m': 'bgcolor-214', '\x1b[48;5;215m': 'bgcolor-215', '\x1b[48;5;216m': 'bgcolor-216', '\x1b[48;5;217m': 'bgcolor-217', '\x1b[48;5;218m': 'bgcolor-218', '\x1b[48;5;219m': 'bgcolor-219', '\x1b[48;5;21m': 'bgcolor-021', '\x1b[48;5;220m': 'bgcolor-220', '\x1b[48;5;221m': 'bgcolor-221', '\x1b[48;5;222m': 'bgcolor-222', '\x1b[48;5;223m': 'bgcolor-223', '\x1b[48;5;224m': 'bgcolor-224', '\x1b[48;5;225m': 'bgcolor-225', '\x1b[48;5;226m': 'bgcolor-226', '\x1b[48;5;227m': 'bgcolor-227', '\x1b[48;5;228m': 'bgcolor-228', '\x1b[48;5;229m': 'bgcolor-229', '\x1b[48;5;22m': 'bgcolor-022', '\x1b[48;5;230m': 'bgcolor-230', '\x1b[48;5;231m': 'bgcolor-231', '\x1b[48;5;232m': 'bgcolor-232', '\x1b[48;5;233m': 'bgcolor-233', '\x1b[48;5;234m': 'bgcolor-234', '\x1b[48;5;235m': 'bgcolor-235', '\x1b[48;5;236m': 'bgcolor-236', '\x1b[48;5;237m': 'bgcolor-237', '\x1b[48;5;238m': 'bgcolor-238', '\x1b[48;5;239m': 'bgcolor-239', '\x1b[48;5;23m': 'bgcolor-023', '\x1b[48;5;240m': 'bgcolor-240', '\x1b[48;5;241m': 'bgcolor-241', '\x1b[48;5;242m': 'bgcolor-242', '\x1b[48;5;243m': 'bgcolor-243', '\x1b[48;5;244m': 'bgcolor-244', '\x1b[48;5;245m': 'bgcolor-245', '\x1b[48;5;246m': 'bgcolor-246', '\x1b[48;5;247m': 'bgcolor-247', '\x1b[48;5;248m': 'bgcolor-248', '\x1b[48;5;249m': 'bgcolor-249', '\x1b[48;5;24m': 'bgcolor-024', '\x1b[48;5;250m': 'bgcolor-250', '\x1b[48;5;251m': 'bgcolor-251', '\x1b[48;5;252m': 'bgcolor-252', '\x1b[48;5;253m': 'bgcolor-253', '\x1b[48;5;254m': 'bgcolor-254', '\x1b[48;5;255m': 'bgcolor-255', '\x1b[48;5;25m': 'bgcolor-025', '\x1b[48;5;26m': 'bgcolor-026', '\x1b[48;5;27m': 'bgcolor-027', '\x1b[48;5;28m': 'bgcolor-028', '\x1b[48;5;29m': 'bgcolor-029', '\x1b[48;5;30m': 'bgcolor-030', '\x1b[48;5;31m': 'bgcolor-031', '\x1b[48;5;32m': 'bgcolor-032', '\x1b[48;5;33m': 'bgcolor-033', '\x1b[48;5;34m': 'bgcolor-034', '\x1b[48;5;35m': 'bgcolor-035', '\x1b[48;5;36m': 'bgcolor-036', '\x1b[48;5;37m': 'bgcolor-037', '\x1b[48;5;38m': 'bgcolor-038', '\x1b[48;5;39m': 'bgcolor-039', '\x1b[48;5;40m': 'bgcolor-040', '\x1b[48;5;41m': 'bgcolor-041', '\x1b[48;5;42m': 'bgcolor-042', '\x1b[48;5;43m': 'bgcolor-043', '\x1b[48;5;44m': 'bgcolor-044', '\x1b[48;5;45m': 'bgcolor-045', '\x1b[48;5;46m': 'bgcolor-046', '\x1b[48;5;47m': 'bgcolor-047', '\x1b[48;5;48m': 'bgcolor-048', '\x1b[48;5;49m': 'bgcolor-049', '\x1b[48;5;50m': 'bgcolor-050', '\x1b[48;5;51m': 'bgcolor-051', '\x1b[48;5;52m': 'bgcolor-052', '\x1b[48;5;53m': 'bgcolor-053', '\x1b[48;5;54m': 'bgcolor-054', '\x1b[48;5;55m': 'bgcolor-055', '\x1b[48;5;56m': 'bgcolor-056', '\x1b[48;5;57m': 'bgcolor-057', '\x1b[48;5;58m': 'bgcolor-058', '\x1b[48;5;59m': 'bgcolor-059', '\x1b[48;5;60m': 'bgcolor-060', '\x1b[48;5;61m': 'bgcolor-061', '\x1b[48;5;62m': 'bgcolor-062', '\x1b[48;5;63m': 'bgcolor-063', '\x1b[48;5;64m': 'bgcolor-064', '\x1b[48;5;65m': 'bgcolor-065', '\x1b[48;5;66m': 'bgcolor-066', '\x1b[48;5;67m': 'bgcolor-067', '\x1b[48;5;68m': 'bgcolor-068', '\x1b[48;5;69m': 'bgcolor-069', '\x1b[48;5;70m': 'bgcolor-070', '\x1b[48;5;71m': 'bgcolor-071', '\x1b[48;5;72m': 'bgcolor-072', '\x1b[48;5;73m': 'bgcolor-073', '\x1b[48;5;74m': 'bgcolor-074', '\x1b[48;5;75m': 'bgcolor-075', '\x1b[48;5;76m': 'bgcolor-076', '\x1b[48;5;77m': 'bgcolor-077', '\x1b[48;5;78m': 'bgcolor-078', '\x1b[48;5;79m': 'bgcolor-079', '\x1b[48;5;80m': 'bgcolor-080', '\x1b[48;5;81m': 'bgcolor-081', '\x1b[48;5;82m': 'bgcolor-082', '\x1b[48;5;83m': 'bgcolor-083', '\x1b[48;5;84m': 'bgcolor-084', '\x1b[48;5;85m': 'bgcolor-085', '\x1b[48;5;86m': 'bgcolor-086', '\x1b[48;5;87m': 'bgcolor-087', '\x1b[48;5;88m': 'bgcolor-088', '\x1b[48;5;89m': 'bgcolor-089', '\x1b[48;5;90m': 'bgcolor-090', '\x1b[48;5;91m': 'bgcolor-091', '\x1b[48;5;92m': 'bgcolor-092', '\x1b[48;5;93m': 'bgcolor-093', '\x1b[48;5;94m': 'bgcolor-094', '\x1b[48;5;95m': 'bgcolor-095', '\x1b[48;5;96m': 'bgcolor-096', '\x1b[48;5;97m': 'bgcolor-097', '\x1b[48;5;98m': 'bgcolor-098', '\x1b[48;5;99m': 'bgcolor-099'}
-
- -
-
-fgstop = '(?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[3[0-8].*?m|\x1b\\[0m|$'
-
- -
-
-bgstop = '(?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[4[0-8].*?m|\x1b\\[0m|$'
-
- -
-
-bgfgstop = '(?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[4[0-8].*?m|\x1b\\[0m(\\s*)(?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[3[0-8].*?m|\x1b\\[0m|$'
-
- -
-
-fgstart = '((?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[3[0-8].*?m)'
-
- -
-
-bgstart = '((?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[4[0-8].*?m)'
-
- -
-
-bgfgstart = '((?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[4[0-8].*?m)(\\s*)((?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[[3-4][0-8].*?m){0,1}'
-
- -
-
-re_fgs = re.compile('((?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[3[0-8].*?m)(.*?)(?=(?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[3[0-8].*?m|\x1b\\[0m|$)')
-
- -
-
-re_bgs = re.compile('((?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[4[0-8].*?m)(.*?)(?=(?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[4[0-8].*?m|\x1b\\[0m|$)')
-
- -
-
-re_bgfg = re.compile('((?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[4[0-8].*?m)(\\s*)((?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[[3-4][0-8].*?m){0,1}(.*?)(?=(?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[4[0-8].*?m|\x1b\\[0m(\\s*)(?:\x1b\\[1m|\x1b\)
-
- -
-
-re_normal = re.compile('\x1b\\[0m')
-
- -
-
-re_hilite = re.compile('(?:\x1b\\[1m)(.*)(?=(?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[3[0-8].*?m|\x1b\\[0m|$|(?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[4[0-8].*?m|\x1b\\[0m|$)')
-
- -
-
-re_unhilite = re.compile('(?:\x1b\\[22m)(.*)(?=(?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[3[0-8].*?m|\x1b\\[0m|$|(?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[4[0-8].*?m|\x1b\\[0m|$)')
-
- -
-
-re_uline = re.compile('(?:\x1b\\[4m)(.*?)(?=(?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[3[0-8].*?m|\x1b\\[0m|$|(?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[4[0-8].*?m|\x1b\\[0m|$)')
-
- -
- -
- -
-
-re_inverse = re.compile('(?:\x1b\\[7m)(.*?)(?=(?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[3[0-8].*?m|\x1b\\[0m|$|(?:\x1b\\[1m|\x1b\\[22m){0,1}\x1b\\[4[0-8].*?m|\x1b\\[0m|$)')
-
- -
-
-re_string = re.compile('(?P<htmlchars>[<&>])|(?P<tab>[\\t]+)|(?P<space> +)|(?P<spacestart>^ )|(?P<lineend>\\r\\n|\\r|\\n)', re.IGNORECASE|re.MULTILINE|re.DOTALL)
-
- -
-
-re_dblspace = re.compile(' {2,}', re.MULTILINE)
-
- -
-
-re_url = re.compile('(?<!=")((?:ftp|www|https?)\\W+(?:(?!\\.(?:\\s|$)|&\\w+;)[^"\\\',;$*^\\\\(){}<>\\[\\]\\s])+)(\\.(?:\\s|$)|&\\w+;|)')
-
- -
- -
- -
-
-re_mxpurl = re.compile('\\|lu(.*?)\\|lt(.*?)\\|le', re.DOTALL)
-
- -
-
-re_color(text)[source]
-

Replace ansi colors with html color class names. Let the -client choose how it will display colors, if it wishes to.

-
-
Parameters
-

text (str) – the string with color to replace.

-
-
Returns
-

text (str) – Re-colored text.

-
-
-
- -
-
-re_bold(text)[source]
-

Clean out superfluous hilights rather than set <strong>to make -it match the look of telnet.

-
-
Parameters
-

text (str) – Text to process.

-
-
Returns
-

text (str) – Processed text.

-
-
-
- -
-
-re_underline(text)[source]
-

Replace ansi underline with html underline class name.

-
-
Parameters
-

text (str) – Text to process.

-
-
Returns
-

text (str) – Processed text.

-
-
-
- -
-
-re_blinking(text)[source]
-

Replace ansi blink with custom blink css class

-
-
Parameters
-

text (str) – Text to process.

-
-
Returns
-

text (str) – Processed text.

-
-
-
- -
-
-re_inversing(text)[source]
-

Replace ansi inverse with custom inverse css class

-
-
Parameters
-

text (str) – Text to process.

-
-
Returns
-

text (str) – Processed text.

-
-
-
- -
-
-remove_bells(text)[source]
-

Remove ansi specials

-
-
Parameters
-

text (str) – Text to process.

-
-
Returns
-

text (str) – Processed text.

-
-
-
- -
-
-remove_backspaces(text)[source]
-

Removes special escape sequences

-
-
Parameters
-

text (str) – Text to process.

-
-
Returns
-

text (str) – Processed text.

-
-
-
- -
-
-convert_linebreaks(text)[source]
-

Extra method for cleaning linebreaks

-
-
Parameters
-

text (str) – Text to process.

-
-
Returns
-

text (str) – Processed text.

-
-
-
- -
-
-convert_urls(text)[source]
-

Replace urls (http://…) by valid HTML.

-
-
Parameters
-

text (str) – Text to process.

-
-
Returns
-

text (str) – Processed text.

-
-
-
- -
-
-re_double_space(text)[source]
-

HTML will swallow any normal space after the first, so if any slipped -through we must make sure to replace them with ” &nbsp;”

-
- -
- -

Helper method to be passed to re.sub, -replaces MXP links with HTML code.

-
-
Parameters
-

match (re.Matchobject) – Match for substitution.

-
-
Returns
-

text (str) – Processed text.

-
-
-
- -
-
-sub_mxp_urls(match)[source]
-

Helper method to be passed to re.sub, -replaces MXP links with HTML code. -:param match: Match for substitution. -:type match: re.Matchobject

-
-
Returns
-

text (str) – Processed text.

-
-
-
- -
-
-sub_text(match)[source]
-

Helper method to be passed to re.sub, -for handling all substitutions.

-
-
Parameters
-

match (re.Matchobject) – Match for substitution.

-
-
Returns
-

text (str) – Processed text.

-
-
-
- -
-
-sub_dblspace(match)[source]
-

clean up double-spaces

-
- -
-
-parse(text, strip_ansi=False)[source]
-

Main access function, converts a text containing ANSI codes -into html statements.

-
-
Parameters
-
    -
  • text (str) – Text to process.

  • -
  • strip_ansi (bool, optional) –

  • -
-
-
Returns
-

text (str) – Parsed text.

-
-
-
- -
- -
-
-evennia.utils.text2html.parse_html(string, strip_ansi=False, parser=<evennia.utils.text2html.TextToHTMLparser object>)[source]
-

Parses a string, replace ANSI markup with html

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.utils.html b/docs/0.9.5/api/evennia.utils.utils.html deleted file mode 100644 index e7c631a779..0000000000 --- a/docs/0.9.5/api/evennia.utils.utils.html +++ /dev/null @@ -1,1755 +0,0 @@ - - - - - - - - - evennia.utils.utils — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.utils

-

General helper functions that don’t fit neatly under any given category.

-

They provide some useful string and conversion methods that might -be of use when designing your own game.

-
-
-evennia.utils.utils.is_iter(obj)[source]
-

Checks if an object behaves iterably.

-
-
Parameters
-

obj (any) – Entity to check for iterability.

-
-
Returns
-

is_iterable (bool) – If obj is iterable or not.

-
-
-

Notes

-

Strings are not accepted as iterable (although they are -actually iterable), since string iterations are usually not -what we want to do with a string.

-
- -
-
-evennia.utils.utils.make_iter(obj)[source]
-

Makes sure that the object is always iterable.

-
-
Parameters
-

obj (any) – Object to make iterable.

-
-
Returns
-

iterable (list or iterable)

-
-
The same object

passed-through or made iterable.

-
-
-

-
-
-
- -
-
-evennia.utils.utils.wrap(text, width=None, indent=0)[source]
-

Safely wrap text to a certain number of characters.

-
-
Parameters
-
    -
  • text (str) – The text to wrap.

  • -
  • width (int, optional) – The number of characters to wrap to.

  • -
  • indent (int) – How much to indent each line (with whitespace).

  • -
-
-
Returns
-

text (str) – Properly wrapped text.

-
-
-
- -
-
-evennia.utils.utils.fill(text, width=None, indent=0)
-

Safely wrap text to a certain number of characters.

-
-
Parameters
-
    -
  • text (str) – The text to wrap.

  • -
  • width (int, optional) – The number of characters to wrap to.

  • -
  • indent (int) – How much to indent each line (with whitespace).

  • -
-
-
Returns
-

text (str) – Properly wrapped text.

-
-
-
- -
-
-evennia.utils.utils.pad(text, width=None, align='c', fillchar=' ')[source]
-

Pads to a given width.

-
-
Parameters
-
    -
  • text (str) – Text to pad.

  • -
  • width (int, optional) – The width to pad to, in characters.

  • -
  • align (str, optional) – This is one of ‘c’, ‘l’ or ‘r’ (center, -left or right).

  • -
  • fillchar (str, optional) – The character to fill with.

  • -
-
-
Returns
-

text (str) – The padded text.

-
-
-
- -
-
-evennia.utils.utils.crop(text, width=None, suffix='[...]')[source]
-

Crop text to a certain width, throwing away text from too-long -lines.

-
-
Parameters
-
    -
  • text (str) – Text to crop.

  • -
  • width (int, optional) – Width of line to crop, in characters.

  • -
  • suffix (str, optional) – This is appended to the end of cropped -lines to show that the line actually continues. Cropping -will be done so that the suffix will also fit within the -given width. If width is too small to fit both crop and -suffix, the suffix will be dropped.

  • -
-
-
Returns
-

text (str) – The cropped text.

-
-
-
- -
-
-evennia.utils.utils.dedent(text, baseline_index=None, indent=None)[source]
-

Safely clean all whitespace at the left of a paragraph.

-
-
Parameters
-
    -
  • text (str) – The text to dedent.

  • -
  • baseline_index (int, optional) – Which row to use as a ‘base’ -for the indentation. Lines will be dedented to this level but -no further. If None, indent so as to completely deindent the -least indented text.

  • -
  • indent (int, optional) – If given, force all lines to this indent. -This bypasses baseline_index.

  • -
-
-
Returns
-

text (str) – Dedented string.

-
-
-

Notes

-

This is useful for preserving triple-quoted string indentation -while still shifting it all to be next to the left edge of the -display.

-
- -
-
-evennia.utils.utils.justify(text, width=None, align='f', indent=0)[source]
-

Fully justify a text so that it fits inside width. When using -full justification (default) this will be done by padding between -words with extra whitespace where necessary. Paragraphs will -be retained.

-
-
Parameters
-
    -
  • text (str) – Text to justify.

  • -
  • width (int, optional) – The length of each line, in characters.

  • -
  • align (str, optional) – The alignment, ‘l’, ‘c’, ‘r’ or ‘f’ -for left, center, right or full justification respectively.

  • -
  • indent (int, optional) – Number of characters indentation of -entire justified text block.

  • -
-
-
Returns
-

justified (str) – The justified and indented block of text.

-
-
-
- -
-
-evennia.utils.utils.columnize(string, columns=2, spacing=4, align='l', width=None)[source]
-

Break a string into a number of columns, using as little -vertical space as possible.

-
-
Parameters
-
    -
  • string (str) – The string to columnize.

  • -
  • columns (int, optional) – The number of columns to use.

  • -
  • spacing (int, optional) – How much space to have between columns.

  • -
  • width (int, optional) – The max width of the columns. -Defaults to client’s default width.

  • -
-
-
Returns
-

columns (str) – Text divided into columns.

-
-
Raises
-

RuntimeError – If given invalid values.

-
-
-
- -
-
-evennia.utils.utils.iter_to_str(iterable, endsep=', and', addquote=False)[source]
-

This pretty-formats an iterable list as string output, adding an optional -alternative separator to the second to last entry. If addquote -is True, the outgoing strings will be surrounded by quotes.

-
-
Parameters
-
    -
  • iterable (any) – Usually an iterable to print. Each element must be possible to -present with a string. Note that if this is a generator, it will be -consumed by this operation.

  • -
  • endsep (str, optional) – If set, the last item separator will -be replaced with this value.

  • -
  • addquote (bool, optional) – This will surround all outgoing -values with double quotes.

  • -
-
-
Returns
-

str – The list represented as a string.

-
-
-

Notes

-

Default is to use ‘Oxford comma’, like 1, 2, 3, and 4. To remove, give -endsep as just and.

-

Examples

-
>>> list_to_string([1,2,3], endsep='')
-'1, 2, 3'
->>> list_to_string([1,2,3], ensdep='and')
-'1, 2 and 3'
->>> list_to_string([1,2,3], endsep=', and', addquote=True)
-'"1", "2", and "3"'
-
-
-
- -
-
-evennia.utils.utils.list_to_string(iterable, endsep=', and', addquote=False)
-

This pretty-formats an iterable list as string output, adding an optional -alternative separator to the second to last entry. If addquote -is True, the outgoing strings will be surrounded by quotes.

-
-
Parameters
-
    -
  • iterable (any) – Usually an iterable to print. Each element must be possible to -present with a string. Note that if this is a generator, it will be -consumed by this operation.

  • -
  • endsep (str, optional) – If set, the last item separator will -be replaced with this value.

  • -
  • addquote (bool, optional) – This will surround all outgoing -values with double quotes.

  • -
-
-
Returns
-

str – The list represented as a string.

-
-
-

Notes

-

Default is to use ‘Oxford comma’, like 1, 2, 3, and 4. To remove, give -endsep as just and.

-

Examples

-
>>> list_to_string([1,2,3], endsep='')
-'1, 2, 3'
->>> list_to_string([1,2,3], ensdep='and')
-'1, 2 and 3'
->>> list_to_string([1,2,3], endsep=', and', addquote=True)
-'"1", "2", and "3"'
-
-
-
- -
-
-evennia.utils.utils.iter_to_string(iterable, endsep=', and', addquote=False)
-

This pretty-formats an iterable list as string output, adding an optional -alternative separator to the second to last entry. If addquote -is True, the outgoing strings will be surrounded by quotes.

-
-
Parameters
-
    -
  • iterable (any) – Usually an iterable to print. Each element must be possible to -present with a string. Note that if this is a generator, it will be -consumed by this operation.

  • -
  • endsep (str, optional) – If set, the last item separator will -be replaced with this value.

  • -
  • addquote (bool, optional) – This will surround all outgoing -values with double quotes.

  • -
-
-
Returns
-

str – The list represented as a string.

-
-
-

Notes

-

Default is to use ‘Oxford comma’, like 1, 2, 3, and 4. To remove, give -endsep as just and.

-

Examples

-
>>> list_to_string([1,2,3], endsep='')
-'1, 2, 3'
->>> list_to_string([1,2,3], ensdep='and')
-'1, 2 and 3'
->>> list_to_string([1,2,3], endsep=', and', addquote=True)
-'"1", "2", and "3"'
-
-
-
- -
-
-evennia.utils.utils.wildcard_to_regexp(instring)[source]
-

Converts a player-supplied string that may have wildcards in it to -regular expressions. This is useful for name matching.

-
-
Parameters
-

instring (string) – A string that may potentially contain -wildcards (* or ?).

-
-
Returns
-

regex (str)

-
-
A string where wildcards were replaced with

regular expressions.

-
-
-

-
-
-
- -
-
-evennia.utils.utils.time_format(seconds, style=0)[source]
-

Function to return a ‘prettified’ version of a value in seconds.

-
-
Parameters
-
    -
  • seconds (int) – Number if seconds to format.

  • -
  • style (int) – One of the following styles: -0. “1d 08:30” -1. “1d” -2. “1 day, 8 hours, 30 minutes” -3. “1 day, 8 hours, 30 minutes, 10 seconds” -4. highest unit (like “3 years” or “8 months” or “1 second”)

  • -
-
-
Returns
-

timeformatted (str) – A pretty time string.

-
-
-
- -
-
-evennia.utils.utils.datetime_format(dtobj)[source]
-

Pretty-prints the time since a given time.

-
-
Parameters
-

dtobj (datetime) – An datetime object, e.g. from Django’s -DateTimeField.

-
-
Returns
-

deltatime (str)

-
-
A string describing how long ago dtobj

took place.

-
-
-

-
-
-
- -
-
-evennia.utils.utils.host_os_is(osname)[source]
-

Check to see if the host OS matches the query.

-
-
Parameters
-
    -
  • osname (str) – Common names are “posix” (linux/unix/mac) and -“nt” (windows).

  • -
  • is_os (bool) – If the os matches or not.

  • -
-
-
-
- -
-
-evennia.utils.utils.get_evennia_version(mode='long')[source]
-

Helper method for getting the current evennia version.

-
-
Parameters
-

mode (str, optional) – One of: -- long: 0.9.0 rev342453534 -- short: 0.9.0 -- pretty: Evennia 0.9.0

-
-
Returns
-

version (str) – The version string.

-
-
-
- -
-
-evennia.utils.utils.pypath_to_realpath(python_path, file_ending='.py', pypath_prefixes=None)[source]
-

Converts a dotted Python path to an absolute path under the -Evennia library directory or under the current game directory.

-
-
Parameters
-
    -
  • python_path (str) – A dot-python path

  • -
  • file_ending (str) – A file ending, including the period.

  • -
  • pypath_prefixes (list) – A list of paths to test for existence. These -should be on python.path form. EVENNIA_DIR and GAME_DIR are automatically -checked, they need not be added to this list.

  • -
-
-
Returns
-

abspaths (list)

-
-
All existing, absolute paths created by

converting python_path to an absolute paths and/or -prepending python_path by settings.EVENNIA_DIR, -settings.GAME_DIR and by**pypath_prefixes** respectively.

-
-
-

-
-
-

Notes

-

This will also try a few combinations of paths to allow cases -where pypath is given including the “evennia.” or “mygame.” -prefixes.

-
- -
-
-evennia.utils.utils.dbref(inp, reqhash=True)[source]
-

Converts/checks if input is a valid dbref.

-
-
Parameters
-
    -
  • inp (int, str) – A database ref on the form N or #N.

  • -
  • reqhash (bool, optional) – Require the #N form to accept -input as a valid dbref.

  • -
-
-
Returns
-

dbref (int or None)

-
-
The integer part of the dbref or None

if input was not a valid dbref.

-
-
-

-
-
-
- -
-
-evennia.utils.utils.dbref_to_obj(inp, objclass, raise_errors=True)[source]
-

Convert a #dbref to a valid object.

-
-
Parameters
-
    -
  • inp (str or int) – A valid #dbref.

  • -
  • objclass (class) – A valid django model to filter against.

  • -
  • raise_errors (bool, optional) – Whether to raise errors -or return None on errors.

  • -
-
-
Returns
-

obj (Object or None) – An entity loaded from the dbref.

-
-
Raises
-

Exception – If raise_errors is True and -objclass.objects.get(id=dbref) did not return a valid -object.

-
-
-
- -
-
-evennia.utils.utils.dbid_to_obj(inp, objclass, raise_errors=True)
-

Convert a #dbref to a valid object.

-
-
Parameters
-
    -
  • inp (str or int) – A valid #dbref.

  • -
  • objclass (class) – A valid django model to filter against.

  • -
  • raise_errors (bool, optional) – Whether to raise errors -or return None on errors.

  • -
-
-
Returns
-

obj (Object or None) – An entity loaded from the dbref.

-
-
Raises
-

Exception – If raise_errors is True and -objclass.objects.get(id=dbref) did not return a valid -object.

-
-
-
- -
-
-evennia.utils.utils.latinify(string, default='?', pure_ascii=False)[source]
-

Convert a unicode string to “safe” ascii/latin-1 characters. -This is used as a last resort when normal encoding does not work.

-
-
Parameters
-
    -
  • string (str) – A string to convert to ‘safe characters’ convertable -to an latin-1 bytestring later.

  • -
  • default (str, optional) – Characters resisting mapping will be replaced -with this character or string. The intent is to apply an encode operation -on the string soon after.

  • -
-
-
Returns
-

string (str)

-
-
A ‘latinified’ string where each unicode character has been

replaced with a ‘safe’ equivalent available in the ascii/latin-1 charset.

-
-
-

-
-
-

Notes

-
-
This is inspired by the gist by Ricardo Murri:

https://gist.github.com/riccardomurri/3c3ccec30f037be174d3

-
-
-
- -
-
-evennia.utils.utils.to_bytes(text, session=None)[source]
-

Try to encode the given text to bytes, using encodings from settings or from Session. Will -always return a bytes, even if given something that is not str or bytes.

-
-
Parameters
-
    -
  • text (any) – The text to encode to bytes. If bytes, return unchanged. If not a str, convert -to str before converting.

  • -
  • session (Session, optional) – A Session to get encoding info from. Will try this before -falling back to settings.ENCODINGS.

  • -
-
-
Returns
-

encoded_text (bytes)

-
-
the encoded text following the session’s protocol flag followed by the

encodings specified in settings.ENCODINGS. If all attempt fail, log the error and send -the text with “?” in place of problematic characters. If the specified encoding cannot -be found, the protocol flag is reset to utf-8. In any case, returns bytes.

-
-
-

-
-
-

Notes

-

If text is already bytes, return it as is.

-
- -
-
-evennia.utils.utils.to_str(text, session=None)[source]
-

Try to decode a bytestream to a python str, using encoding schemas from settings -or from Session. Will always return a str(), also if not given a str/bytes.

-
-
Parameters
-
    -
  • text (any) – The text to encode to bytes. If a str, return it. If also not bytes, convert -to str using str() or repr() as a fallback.

  • -
  • session (Session, optional) – A Session to get encoding info from. Will try this before -falling back to settings.ENCODINGS.

  • -
-
-
Returns
-

decoded_text (str) – The decoded text.

-
-
-

Notes

-

If text is already str, return it as is.

-
- -
-
-evennia.utils.utils.validate_email_address(emailaddress)[source]
-

Checks if an email address is syntactically correct. Makes use -of the django email-validator for consistency.

-
-
Parameters
-

emailaddress (str) – Email address to validate.

-
-
Returns
-

bool – If this is a valid email or not.

-
-
-
- -
-
-evennia.utils.utils.inherits_from(obj, parent)[source]
-

Takes an object and tries to determine if it inherits at any -distance from parent.

-
-
Parameters
-
    -
  • obj (any) – Object to analyze. This may be either an instance or -a class.

  • -
  • parent (any) – Can be either an instance, a class or the python -path to the class.

  • -
-
-
Returns
-

inherits_from (bool) – If parent is a parent to obj or not.

-
-
-

Notes

-

What differentiates this function from Python’s isinstance() is the -flexibility in the types allowed for the object and parent being compared.

-
- -
-
-evennia.utils.utils.server_services()[source]
-

Lists all services active on the Server. Observe that since -services are launched in memory, this function will only return -any results if called from inside the game.

-
-
Returns
-

services (dict) – A dict of available services.

-
-
-
- -
-
-evennia.utils.utils.uses_database(name='sqlite3')[source]
-

Checks if the game is currently using a given database. This is a -shortcut to having to use the full backend name.

-
-
Parameters
-

name (str) – One of ‘sqlite3’, ‘mysql’, ‘postgresql’ or ‘oracle’.

-
-
Returns
-

uses (bool) – If the given database is used or not.

-
-
-
- -
-
-evennia.utils.utils.delay(timedelay, callback, *args, **kwargs)[source]
-

Delay the calling of a callback (function).

-
-
Parameters
-
    -
  • timedelay (int or float) – The delay in seconds.

  • -
  • callback (callable) – Will be called as callback(*args, **kwargs) -after timedelay seconds.

  • -
  • *args – Will be used as arguments to callback

  • -
-
-
Keyword Arguments
-
    -
  • persistent (bool, optional) – If True the delay remains after a server restart. -persistent is False by default.

  • -
  • any (any) – Will be used as keyword arguments to callback.

  • -
-
-
Returns
-

task (TaskHandlerTask)

-
-
An instance of a task.

Refer to, evennia.scripts.taskhandler.TaskHandlerTask

-
-
-

-
-
-

Notes

-

The task handler (evennia.scripts.taskhandler.TASK_HANDLER) will -be called for persistent or non-persistent tasks. -If persistent is set to True, the callback, its arguments -and other keyword arguments will be saved (serialized) in the database, -assuming they can be. The callback will be executed even after -a server restart/reload, taking into account the specified delay -(and server down time). -Keep in mind that persistent tasks arguments and callback should not -use memory references. -If persistent is set to True the delay function will return an int -which is the task’s id itended for use with TASK_HANDLER’s do_task -and remove methods. -All persistent tasks whose time delays have passed will be called on server startup.

-
- -
-
-evennia.utils.utils.repeat(interval, callback, persistent=True, idstring='', stop=False, store_key=None, *args, **kwargs)[source]
-

Start a repeating task using the TickerHandler.

-
-
Parameters
-
    -
  • interval (int) – How often to call callback.

  • -
  • callback (callable) – This will be called with *args, **kwargs every -interval seconds. This must be possible to pickle regardless -of if persistent is set or not!

  • -
  • persistent (bool, optional) – If ticker survives a server reload.

  • -
  • idstring (str, optional) – Separates multiple tickers. This is useful -mainly if wanting to set up multiple repeats for the same -interval/callback but with different args/kwargs.

  • -
  • stop (bool, optional) – If set, use the given parameters to _stop_ a running -ticker instead of creating a new one.

  • -
  • store_key (tuple, optional) – This is only used in combination with stop and -should be the return given from the original repeat call. If this -is given, all other args except stop are ignored.

  • -
  • *args – Used as arguments to callback.

  • -
  • **kwargs – Keyword-arguments to pass to callback.

  • -
-
-
Returns
-

tuple or None – The tuple is the store_key - the identifier for the -created ticker. Store this and pass into unrepat() in order to to stop -this ticker later. Returns None if stop=True.

-
-
Raises
-

KeyError – If trying to stop a ticker that was not found.

-
-
-
- -
-
-evennia.utils.utils.unrepeat(store_key)[source]
-

This is used to stop a ticker previously started with repeat.

-
-
Parameters
-

store_key (tuple) – This is the return from repeat, used to uniquely -identify the ticker to stop. Without the store_key, the ticker -must be stopped by passing its parameters to TICKER_HANDLER.remove -directly.

-
-
Returns
-

bool

-
-
True if a ticker was stopped, False if not (for example because no

matching ticker was found or it was already stopped).

-
-
-

-
-
-
- -
-
-evennia.utils.utils.run_async(to_execute, *args, **kwargs)[source]
-

Runs a function or executes a code snippet asynchronously.

-
-
Parameters
-

to_execute (callable) – If this is a callable, it will be -executed with *args and non-reserved **kwargs as arguments. -The callable will be executed using ProcPool, or in a thread -if ProcPool is not available.

-
-
Keyword Arguments
-
    -
  • at_return (callable) – Should point to a callable with one -argument. It will be called with the return value from -to_execute.

  • -
  • at_return_kwargs (dict) – This dictionary will be used as -keyword arguments to the at_return callback.

  • -
  • at_err (callable) – This will be called with a Failure instance -if there is an error in to_execute.

  • -
  • at_err_kwargs (dict) – This dictionary will be used as keyword -arguments to the at_err errback.

  • -
-
-
-

Notes

-

All other *args and **kwargs will be passed on to -to_execute. Run_async will relay executed code to a thread -or procpool.

-

Use this function with restrain and only for features/commands -that you know has no influence on the cause-and-effect order of your -game (commands given after the async function might be executed before -it has finished). Accessing the same property from different threads -can lead to unpredicted behaviour if you are not careful (this is called a -“race condition”).

-

Also note that some databases, notably sqlite3, don’t support access from -multiple threads simultaneously, so if you do heavy database access from -your to_execute under sqlite3 you will probably run very slow or even get -tracebacks.

-
- -
-
-evennia.utils.utils.check_evennia_dependencies()[source]
-

Checks the versions of Evennia’s dependencies including making -some checks for runtime libraries.

-
-
Returns
-

result (bool)

-
-
False if a show-stopping version mismatch is

found.

-
-
-

-
-
-
- -
-
-evennia.utils.utils.has_parent(basepath, obj)[source]
-

Checks if basepath is somewhere in obj’s parent tree.

-
-
Parameters
-
    -
  • basepath (str) – Python dotpath to compare against obj path.

  • -
  • obj (any) – Object whose path is to be checked.

  • -
-
-
Returns
-

has_parent (bool) – If the check was successful or not.

-
-
-
- -
-
-evennia.utils.utils.mod_import_from_path(path)[source]
-

Load a Python module at the specified path.

-
-
Parameters
-

path (str) – An absolute path to a Python module to load.

-
-
Returns
-

(module or None) – An imported module if the path was a valid -Python module. Returns None if the import failed.

-
-
-
- -
-
-evennia.utils.utils.mod_import(module)[source]
-

A generic Python module loader.

-
-
Parameters
-

module (str, module) – This can be either a Python path -(dot-notation like evennia.objects.models), an absolute path -(e.g. /home/eve/evennia/evennia/objects/models.py) or an -already imported module object (e.g. models)

-
-
Returns
-

(module or None) – An imported module. If the input argument was -already a module, this is returned as-is, otherwise the path is -parsed and imported. Returns None and logs error if import failed.

-
-
-
- -
-
-evennia.utils.utils.all_from_module(module)[source]
-

Return all global-level variables defined in a module.

-
-
Parameters
-

module (str, module) – This can be either a Python path -(dot-notation like evennia.objects.models), an absolute path -(e.g. /home/eve/evennia/evennia/objects.models.py) or an -already imported module object (e.g. models)

-
-
Returns
-

dict

-
-
A dict of {variablename: variable} for all

variables in the given module.

-
-
-

-
-
-

Notes

-

Ignores modules and variable names starting with an underscore, as well -as variables imported into the module from other modules.

-
- -
-
-evennia.utils.utils.callables_from_module(module)[source]
-

Return all global-level callables defined in a module.

-
-
Parameters
-

module (str, module) – A python-path to a module or an actual -module object.

-
-
Returns
-

callables (dict) – A dict of {name: callable, …} from the module.

-
-
-

Notes

-

Will ignore callables whose names start with underscore “_”.

-
- -
-
-evennia.utils.utils.variable_from_module(module, variable=None, default=None)[source]
-

Retrieve a variable or list of variables from a module. The -variable(s) must be defined globally in the module. If no variable -is given (or a list entry is None), all global variables are -extracted from the module.

-
-
Parameters
-
    -
  • module (string or module) – Python path, absolute path or a module.

  • -
  • variable (string or iterable, optional) – Single variable name or iterable -of variable names to extract. If not given, all variables in -the module will be returned.

  • -
  • default (string, optional) – Default value to use if a variable fails to -be extracted. Ignored if variable is not given.

  • -
-
-
Returns
-

variables (value or list) – A single value or a list of values -depending on if variable is given or not. Errors in lists -are replaced by the default argument.

-
-
-
- -
-
-evennia.utils.utils.string_from_module(module, variable=None, default=None)[source]
-

This is a wrapper for variable_from_module that requires return -value to be a string to pass. It’s primarily used by login screen.

-
-
Parameters
-
    -
  • module (string or module) – Python path, absolute path or a module.

  • -
  • variable (string or iterable, optional) – Single variable name or iterable -of variable names to extract. If not given, all variables in -the module will be returned.

  • -
  • default (string, optional) – Default value to use if a variable fails to -be extracted. Ignored if variable is not given.

  • -
-
-
Returns
-

variables (value or list) – A single (string) value or a list of values -depending on if variable is given or not. Errors in lists (such -as the value not being a string) are replaced by the default argument.

-
-
-
- -
-
-evennia.utils.utils.random_string_from_module(module)[source]
-

Returns a random global string from a module.

-
-
Parameters
-

module (string or module) – Python path, absolute path or a module.

-
-
Returns
-

random (string) – A random stribg variable from module.

-
-
-
- -
-
-evennia.utils.utils.fuzzy_import_from_module(path, variable, default=None, defaultpaths=None)[source]
-

Import a variable based on a fuzzy path. First the literal -path will be tried, then all given defaultpaths will be -prepended to see a match is found.

-
-
Parameters
-
    -
  • path (str) – Full or partial python path.

  • -
  • variable (str) – Name of variable to import from module.

  • -
  • default (string, optional) – Default value to use if a variable fails to -be extracted. Ignored if variable is not given.

  • -
  • defaultpaths (iterable, options) – Python paths to attempt in order if -importing directly from path doesn’t work.

  • -
-
-
Returns
-

value (any)

-
-
The variable imported from the module, or default, if

not found.

-
-
-

-
-
-
- -
-
-evennia.utils.utils.class_from_module(path, defaultpaths=None, fallback=None)[source]
-

Return a class from a module, given the class’ full python path. This is -primarily used to convert db_typeclass_path:s to classes.

-
-
Parameters
-
    -
  • path (str) – Full Python dot-path to module.

  • -
  • defaultpaths (iterable, optional) – If a direct import from path fails, -try subsequent imports by prepending those paths to path.

  • -
  • fallback (str) – If all other attempts fail, use this path as a fallback. -This is intended as a last-resport. In the example of Evennia -loading, this would be a path to a default parent class in the -evennia repo itself.

  • -
-
-
Returns
-

class (Class) – An uninstatiated class recovered from path.

-
-
Raises
-

ImportError – If all loading failed.

-
-
-
- -
-
-evennia.utils.utils.object_from_module(path, defaultpaths=None, fallback=None)
-

Return a class from a module, given the class’ full python path. This is -primarily used to convert db_typeclass_path:s to classes.

-
-
Parameters
-
    -
  • path (str) – Full Python dot-path to module.

  • -
  • defaultpaths (iterable, optional) – If a direct import from path fails, -try subsequent imports by prepending those paths to path.

  • -
  • fallback (str) – If all other attempts fail, use this path as a fallback. -This is intended as a last-resport. In the example of Evennia -loading, this would be a path to a default parent class in the -evennia repo itself.

  • -
-
-
Returns
-

class (Class) – An uninstatiated class recovered from path.

-
-
Raises
-

ImportError – If all loading failed.

-
-
-
- -
-
-evennia.utils.utils.init_new_account(account)[source]
-

Deprecated.

-
- -
-
-evennia.utils.utils.string_similarity(string1, string2)[source]
-

This implements a “cosine-similarity” algorithm as described for example in -Proceedings of the 22nd International Conference on Computation -Linguistics (Coling 2008), pages 593-600, Manchester, August 2008. -The measure-vectors used is simply a “bag of words” type histogram -(but for letters).

-
-
Parameters
-
    -
  • string1 (str) – String to compare (may contain any number of words).

  • -
  • string2 (str) – Second string to compare (any number of words).

  • -
-
-
Returns
-

similarity (float)

-
-
A value 0…1 rating how similar the two

strings are.

-
-
-

-
-
-
- -
-
-evennia.utils.utils.string_suggestions(string, vocabulary, cutoff=0.6, maxnum=3)[source]
-

Given a string and a vocabulary, return a match or a list of -suggestions based on string similarity.

-
-
Parameters
-
    -
  • string (str) – A string to search for.

  • -
  • vocabulary (iterable) – A list of available strings.

  • -
  • cutoff (int, 0-1) – Limit the similarity matches (the higher -the value, the more exact a match is required).

  • -
  • maxnum (int) – Maximum number of suggestions to return.

  • -
-
-
Returns
-

suggestions (list) – Suggestions from vocabulary with a -similarity-rating that higher than or equal to cutoff. -Could be empty if there are no matches.

-
-
-
- -
-
-evennia.utils.utils.string_partial_matching(alternatives, inp, ret_index=True)[source]
-

Partially matches a string based on a list of alternatives. -Matching is made from the start of each subword in each -alternative. Case is not important. So e.g. “bi sh sw” or just -“big” or “shiny” or “sw” will match “Big shiny sword”. Scoring is -done to allow to separate by most common demoninator. You will get -multiple matches returned if appropriate.

-
-
Parameters
-
    -
  • alternatives (list of str) – A list of possible strings to -match.

  • -
  • inp (str) – Search criterion.

  • -
  • ret_index (bool, optional) – Return list of indices (from alternatives -array) instead of strings.

  • -
-
-
Returns
-

matches (list) – String-matches or indices if ret_index is True.

-
-
-
- -
-
-evennia.utils.utils.format_table(table, extra_space=1)[source]
-

Format a 2D array of strings into a multi-column table.

-
-
Parameters
-
    -
  • table (list) – A list of lists to represent columns in the -table: [[val,val,val,…], [val,val,val,…], …], where -each val will be placed on a separate row in the -column. All columns must have the same number of rows (some -positions may be empty though).

  • -
  • extra_space (int, optional) – Sets how much minimum extra -padding (in characters) should be left between columns.

  • -
-
-
Returns
-

list – A list of lists representing the rows to print out one by one.

-
-
-

Notes

-

The function formats the columns to be as wide as the widest member -of each column.

-

evennia.utils.evtable is more powerful than this, but this -function can be useful when the number of columns and rows are -unknown and must be calculated on the fly.

-

Examples:

-
ftable = format_table([[1,2,3], [4,5,6]])
-string = ""
-for ir, row in enumarate(ftable):
-    if ir == 0:
-        # make first row white
-        string += "\n|w" + "".join(row) + "|n"
-    else:
-        string += "\n" + "".join(row)
-print(string)
-
-
-
- -
-
-evennia.utils.utils.percent(value, minval, maxval, formatting='{:3.1f}%')[source]
-

Get a value in an interval as a percentage of its position -in that interval. This also understands negative numbers.

-
-
Parameters
-
    -
  • value (number) – This should be a value minval<=value<=maxval.

  • -
  • minval (number or None) – Smallest value in interval. This could be None -for an open interval (then return will always be 100%)

  • -
  • maxval (number or None) – Biggest value in interval. This could be None -for an open interval (then return will always be 100%)

  • -
  • formatted (str, optional) – This is a string that should -accept one formatting tag. This will receive the -current value as a percentage. If None, the -raw float will be returned instead.

  • -
-
-
Returns
-

str or float – The formatted value or the raw percentage as a float.

-
-
-

Notes

-

We try to handle a weird interval gracefully.

-
    -
  • If either maxval or minval is None (open interval), we (aribtrarily) assume 100%.

  • -
  • If minval > maxval, we return 0%.

  • -
  • If minval == maxval == value we are looking at a single value match and return 100%.

  • -
  • If minval == maxval != value we return 0%.

  • -
  • If value not in [minval..maxval], we set value to the closest -boundary, so the result will be 0% or 100%, respectively.

  • -
-
- -
-
-evennia.utils.utils.percentile(iterable, percent, key=<function <lambda>>)[source]
-

Find the percentile of a list of values.

-
-
Parameters
-
    -
  • iterable (iterable) – A list of values. Note N MUST BE already sorted.

  • -
  • percent (float) – A value from 0.0 to 1.0.

  • -
  • key (callable, optional) –

  • -
-
-
Returns
-

float – The percentile of the values

-
-
-
- -
-
-evennia.utils.utils.format_grid(elements, width=78, sep=' ', verbatim_elements=None)[source]
-

This helper function makes a ‘grid’ output, where it distributes the given -string-elements as evenly as possible to fill out the given width. -will not work well if the variation of length is very big!

-
-
Parameters
-
    -
  • elements (iterable) – A 1D list of string elements to put in the grid.

  • -
  • width (int, optional) – The width of the grid area to fill.

  • -
  • sep (str, optional) – The extra separator to put between words. If -set to the empty string, words may run into each other.

  • -
  • verbatim_elements (list, optional) – This is a list of indices pointing to -specific items in the elements list. An element at this index will -not be included in the calculation of the slot sizes. It will still -be inserted into the grid at the correct position and may be surrounded -by padding unless filling the entire line. This is useful for embedding -decorations in the grid, such as horizontal bars.

  • -
  • ignore_ansi (bool, optional) – Ignore ansi markups when calculating white spacing.

  • -
-
-
Returns
-

list – The grid as a list of ready-formatted rows. We return it -like this to make it easier to insert decorations between rows, such -as horizontal bars.

-
-
-
- -
-
-evennia.utils.utils.get_evennia_pids()[source]
-

Get the currently valid PIDs (Process IDs) of the Portal and -Server by trying to access a PID file.

-
-
Returns
-

server, portal (tuple)

-
-
The PIDs of the respective processes,

or two None values if not found.

-
-
-

-
-
-

Examples

-

This can be used to determine if we are in a subprocess by

-
self_pid = os.getpid()
-server_pid, portal_pid = get_evennia_pids()
-is_subprocess = self_pid not in (server_pid, portal_pid)
-
-
-
- -
-
-evennia.utils.utils.deepsize(obj, max_depth=4)[source]
-

Get not only size of the given object, but also the size of -objects referenced by the object, down to max_depth distance -from the object.

-
-
Parameters
-
    -
  • obj (object) – the object to be measured.

  • -
  • max_depth (int, optional) – maximum referential distance -from obj that deepsize() should cover for -measuring objects referenced by obj.

  • -
-
-
Returns
-

size (int) – deepsize of obj in Bytes.

-
-
-

Notes

-

This measure is necessarily approximate since some -memory is shared between objects. The max_depth of 4 is roughly -tested to give reasonable size information about database models -and their handlers.

-
- -
-
-class evennia.utils.utils.lazy_property(func, name=None, doc=None)[source]
-

Bases: object

-

Delays loading of property until first access. Credit goes to the -Implementation in the werkzeug suite: -http://werkzeug.pocoo.org/docs/utils/#werkzeug.utils.cached_property

-

This should be used as a decorator in a class and in Evennia is -mainly used to lazy-load handlers:

-
-
@lazy_property
-def attributes(self):
-    return AttributeHandler(self)
-
-
-
-

Once initialized, the AttributeHandler will be available as a -property “attributes” on the object. This is read-only since -this functionality is pretty much exclusively used by handlers.

-
-
-__init__(func, name=None, doc=None)[source]
-

Store all properties for now

-
- -
- -
-
-evennia.utils.utils.strip_control_sequences(string)[source]
-

Remove non-print text sequences.

-
-
Parameters
-

string (str) – Text to strip.

-
-
-
-
Returns.

text (str): Stripped text.

-
-
-
- -
-
-evennia.utils.utils.calledby(callerdepth=1)[source]
-

Only to be used for debug purposes. Insert this debug function in -another function; it will print which function called it.

-
-
Parameters
-

callerdepth (int) – Must be larger than 0. When > 1, it will -print the caller of the caller etc.

-
-
Returns
-

calledby (str)

-
-
A debug string detailing which routine called

us.

-
-
-

-
-
-
- -
-
-evennia.utils.utils.m_len(target)[source]
-

Provides length checking for strings with MXP patterns, and falls -back to normal len for other objects.

-
-
Parameters
-

target (str) – A string with potential MXP components -to search.

-
-
Returns
-

length (int) – The length of target, ignoring MXP components.

-
-
-
- -
-
-evennia.utils.utils.display_len(target)[source]
-

Calculate the ‘visible width’ of text. This is not necessarily the same as the -number of characters in the case of certain asian characters. This will also -strip MXP patterns.

-
-
Parameters
-

target (any) – Something to measure the length of. If a string, it will be -measured keeping asian-character and MXP links in mind.

-
-
Returns
-

int – The visible width of the target.

-
-
-
- -
-
-evennia.utils.utils.at_search_result(matches, caller, query='', quiet=False, **kwargs)[source]
-

This is a generic hook for handling all processing of a search -result, including error reporting. This is also called by the cmdhandler -to manage errors in command lookup.

-
-
Parameters
-
    -
  • matches (list) – This is a list of 0, 1 or more typeclass -instances or Command instances, the matched result of the -search. If 0, a nomatch error should be echoed, and if >1, -multimatch errors should be given. Only if a single match -should the result pass through.

  • -
  • caller (Object) – The object performing the search and/or which should

  • -
  • error messages. (receive) –

  • -
  • query (str, optional) – The search query used to produce matches.

  • -
  • quiet (bool, optional) – If True, no messages will be echoed to caller -on errors.

  • -
-
-
Keyword Arguments
-
    -
  • nofound_string (str) – Replacement string to echo on a notfound error.

  • -
  • multimatch_string (str) – Replacement string to echo on a multimatch error.

  • -
-
-
Returns
-

processed_result (Object or None) – This is always a single result -or None. If None, any error reporting/handling should -already have happened. The returned object is of the type we are -checking multimatches for (e.g. Objects or Commands)

-
-
-
- -
-
-class evennia.utils.utils.LimitedSizeOrderedDict(*args, **kwargs)[source]
-

Bases: collections.OrderedDict

-

This dictionary subclass is both ordered and limited to a maximum -number of elements. Its main use is to hold a cache that can never -grow out of bounds.

-
-
-__init__(*args, **kwargs)[source]
-

Limited-size ordered dict.

-
-
Keyword Arguments
-
    -
  • size_limit (int) – Use this to limit the number of elements -alloweds to be in this list. By default the overshooting elements -will be removed in FIFO order.

  • -
  • fifo (bool, optional) – Defaults to True. Remove overshooting elements -in FIFO order. If False, remove in FILO order.

  • -
-
-
-
- -
-
-update([E, ]**F) → None. Update D from dict/iterable E and F.[source]
-

If E is present and has a .keys() method, then does: for k in E: D[k] = E[k] -If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v -In either case, this is followed by: for k in F: D[k] = F[k]

-
- -
- -
-
-evennia.utils.utils.get_game_dir_path()[source]
-

This is called by settings_default in order to determine the path -of the game directory.

-
-
Returns
-

path (str) – Full OS path to the game dir

-
-
-
- -
-
-evennia.utils.utils.get_all_typeclasses(parent=None)[source]
-

List available typeclasses from all available modules.

-
-
Parameters
-

parent (str, optional) – If given, only return typeclasses inheriting -(at any distance) from this parent.

-
-
Returns
-

dict – On the form {“typeclass.path”: typeclass, …}

-
-
-

Notes

-

This will dynamically retrieve all abstract django models inheriting at -any distance from the TypedObject base (aka a Typeclass) so it will -work fine with any custom classes being added.

-
- -
-
-evennia.utils.utils.get_all_cmdsets(parent=None)[source]
-

List available cmdsets from all available modules.

-
-
Parameters
-

parent (str, optional) – If given, only return cmdsets inheriting (at -any distance) from this parent.

-
-
Returns
-

dict – On the form {“cmdset.path”: cmdset, …}

-
-
-

Notes

-

This will dynamically retrieve all abstract django models inheriting at -any distance from the CmdSet base so it will work fine with any custom -classes being added.

-
- -
-
-evennia.utils.utils.interactive(func)[source]
-

Decorator to make a method pausable with yield(seconds) -and able to ask for user-input with response=yield(question). -For the question-asking to work, one of the args or kwargs to the -decorated function must be named ‘caller’.

-
-
Raises
-
    -
  • ValueError – If asking an interactive question but the decorated -function has no arg or kwarg named ‘caller’.

  • -
  • ValueError – If passing non int/float to yield using for pausing.

  • -
-
-
-

Examples

-
@interactive
-def myfunc(caller):
-    caller.msg("This is a test")
-    # wait five seconds
-    yield(5)
-    # ask user (caller) a question
-    response = yield("Do you want to continue waiting?")
-    if response == "yes":
-        yield(5)
-    else:
-        # ...
-
-
-

Notes

-

This turns the decorated function or method into a generator.

-
- -
-
-evennia.utils.utils.safe_convert_to_types(converters, *args, raise_errors=True, **kwargs)[source]
-

Helper function to safely convert inputs to expected data types.

-
-
Parameters
-
    -
  • converters (tuple) – A tuple ((converter, converter,…), {kwarg: converter, …}) to -match a converter to each element in *args and **kwargs. -Each converter will will be called with the arg/kwarg-value as the only argument. -If there are too few converters given, the others will simply not be converter. If the -converter is given as the string ‘py’, it attempts to run -safe_eval/literal_eval on the input arg or kwarg value. It’s possible to -skip the arg/kwarg part of the tuple, an empty tuple/dict will then be assumed.

  • -
  • *args – The arguments to convert with argtypes.

  • -
  • raise_errors (bool, optional) – If set, raise any errors. This will -abort the conversion at that arg/kwarg. Otherwise, just skip the -conversion of the failing arg/kwarg. This will be set by the FuncParser if -this is used as a part of a FuncParser callable.

  • -
  • **kwargs – The kwargs to convert with kwargtypes

  • -
-
-
Returns
-

tuple(args, kwargs) in converted form.

-
-
Raises
-
    -
  • utils.funcparser.ParsingError – If parsing failed in the ‘py’ -converter. This also makes this compatible with the FuncParser -interface.

  • -
  • any – Any other exception raised from other converters, if raise_errors is True.

  • -
-
-
-

Notes

-

This function is often used to validate/convert input from untrusted sources. For -security, the “py”-converter is deliberately limited and uses safe_eval/literal_eval -which only supports simple expressions or simple containers with literals. NEVER -use the python eval or exec methods as a converter for any untrusted input! Allowing -untrusted sources to execute arbitrary python on your server is a severe security risk,

-

Example:

-
$funcname(1, 2, 3.0, c=[1,2,3])
-
-def _funcname(*args, **kwargs):
-    args, kwargs = safe_convert_input(((int, int, float), {'c': 'py'}), *args, **kwargs)
-    # ...
-
-
-
- -
-
-evennia.utils.utils.strip_unsafe_input(txt, session=None, bypass_perms=None)[source]
-

Remove ‘unsafe’ text codes from text; these are used to elimitate -exploits in user-provided data, such as html-tags, line breaks etc.

-
-
Parameters
-
    -
  • txt (str) – The text to clean.

  • -
  • session (Session, optional) – A Session in order to determine if -the check should be bypassed by permission (will be checked -with the ‘perm’ lock, taking permission hierarchies into account).

  • -
  • bypass_perms (list, optional) – Iterable of permission strings -to check for bypassing the strip. If not given, use -settings.INPUT_CLEANUP_BYPASS_PERMISSIONS.

  • -
-
-
Returns
-

str – The cleaned string.

-
-
-

Notes

-

The INPUT_CLEANUP_BYPASS_PERMISSIONS list defines what account -permissions are required to bypass this strip.

-
- -
-
-evennia.utils.utils.copy_word_case(base_word, new_word)[source]
-

Converts a word to use the same capitalization as a first word.

-
-
Parameters
-
    -
  • base_word (str) – A word to get the capitalization from.

  • -
  • new_word (str) – A new word to capitalize in the same way as base_word.

  • -
-
-
Returns
-

str – The new_word with capitalization matching the first word.

-
-
-

Notes

-

This is meant for words. Longer sentences may get unexpected results.

-

If the two words have a mix of capital/lower letters _and_ new_word -is longer than base_word, the excess will retain its original case.

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.utils.validatorfuncs.html b/docs/0.9.5/api/evennia.utils.validatorfuncs.html deleted file mode 100644 index 23827d9fd1..0000000000 --- a/docs/0.9.5/api/evennia.utils.validatorfuncs.html +++ /dev/null @@ -1,234 +0,0 @@ - - - - - - - - - evennia.utils.validatorfuncs — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.utils.validatorfuncs

-

Contains all the validation functions.

-

All validation functions must have a checker (probably a session) and entry arg.

-

They can employ more paramters at your leisure.

-
-
-evennia.utils.validatorfuncs.text(entry, option_key='Text', **kwargs)[source]
-
- -
-
-evennia.utils.validatorfuncs.color(entry, option_key='Color', **kwargs)[source]
-

The color should be just a color character, so ‘r’ if red color is desired.

-
- -
-
-evennia.utils.validatorfuncs.datetime(entry, option_key='Datetime', account=None, from_tz=None, **kwargs)[source]
-

Process a datetime string in standard forms while accounting for the -inputer’s timezone. Always returns a result in UTC.

-
-
Parameters
-
    -
  • entry (str) – A date string from a user.

  • -
  • option_key (str) – Name to display this datetime as.

  • -
  • account (AccountDB) – The Account performing this lookup. Unless from_tz is provided, -the account’s timezone option will be used.

  • -
  • from_tz (pytz.timezone) – An instance of a pytz timezone object from the -user. If not provided, tries to use the timezone option of account. -If neither one is provided, defaults to UTC.

  • -
-
-
Returns
-

datetime in UTC.

-
-
Raises
-

ValueError – If encountering a malformed timezone, date string or other format error.

-
-
-
- -
-
-evennia.utils.validatorfuncs.duration(entry, option_key='Duration', **kwargs)[source]
-

Take a string and derive a datetime timedelta from it.

-
-
Parameters
-
    -
  • entry (string) – This is a string from user-input. The intended format is, for example: -“5d 2w 90s” for ‘five days, two weeks, and ninety seconds.’ Invalid sections are -ignored.

  • -
  • option_key (str) – Name to display this query as.

  • -
-
-
Returns
-

timedelta

-
-
-
- -
-
-evennia.utils.validatorfuncs.future(entry, option_key='Future Datetime', from_tz=None, **kwargs)[source]
-
- -
-
-evennia.utils.validatorfuncs.signed_integer(entry, option_key='Signed Integer', **kwargs)[source]
-
- -
-
-evennia.utils.validatorfuncs.positive_integer(entry, option_key='Positive Integer', **kwargs)[source]
-
- -
-
-evennia.utils.validatorfuncs.unsigned_integer(entry, option_key='Unsigned Integer', **kwargs)[source]
-
- -
-
-evennia.utils.validatorfuncs.boolean(entry, option_key='True/False', **kwargs)[source]
-

Simplest check in computer logic, right? This will take user input to flick the switch on or off

-
-
Parameters
-
    -
  • entry (str) – A value such as True, On, Enabled, Disabled, False, 0, or 1.

  • -
  • option_key (str) – What kind of Boolean we are setting. What Option is this for?

  • -
-
-
Returns
-

Boolean

-
-
-
- -
-
-evennia.utils.validatorfuncs.timezone(entry, option_key='Timezone', **kwargs)[source]
-

Takes user input as string, and partial matches a Timezone.

-
-
Parameters
-
    -
  • entry (str) – The name of the Timezone.

  • -
  • option_key (str) – What this Timezone is used for.

  • -
-
-
Returns
-

A PYTZ timezone.

-
-
-
- -
-
-evennia.utils.validatorfuncs.email(entry, option_key='Email Address', **kwargs)[source]
-
- -
-
-evennia.utils.validatorfuncs.lock(entry, option_key='locks', access_options=None, **kwargs)[source]
-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.web.html b/docs/0.9.5/api/evennia.web.html deleted file mode 100644 index cfbe926a38..0000000000 --- a/docs/0.9.5/api/evennia.web.html +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - - - - evennia.web — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
- - -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.web.urls.html b/docs/0.9.5/api/evennia.web.urls.html deleted file mode 100644 index a6b69a3db9..0000000000 --- a/docs/0.9.5/api/evennia.web.urls.html +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - evennia.web.urls — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.web.urls

-

File that determines what each URL points to. This uses Python regular expressions. -This is the starting point when a user enters an URL.

-
    -
  1. The URL is matched with a regex, tying it to a given view. Note that this central url.py -file includes url.py from all the various web-components found in views/ so the search -space is much larger than what is shown here.

  2. -
  3. The view (a Python function or class is executed)

  4. -
  5. The view uses a template (a HTML file which may contain template markers for dynamically -modifying its contents; the locations of such templates are given by -settings.TEMPLATES[0][‘DIRS’]) and which may in turn may include static -assets (CSS, images etc).

  6. -
  7. The view ‘renders’ the template into a finished HTML page, replacing all -dynamic content as appropriate.

  8. -
  9. The HTML page is returned to the user.

  10. -
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.web.utils.backends.html b/docs/0.9.5/api/evennia.web.utils.backends.html deleted file mode 100644 index 416d1a0c35..0000000000 --- a/docs/0.9.5/api/evennia.web.utils.backends.html +++ /dev/null @@ -1,137 +0,0 @@ - - - - - - - - - evennia.web.utils.backends — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.web.utils.backends

-
-
-class evennia.web.utils.backends.CaseInsensitiveModelBackend[source]
-

Bases: django.contrib.auth.backends.ModelBackend

-

By default ModelBackend does case _sensitive_ username -authentication, which isn’t what is generally expected. This -backend supports case insensitive username authentication.

-
-
-authenticate(request, username=None, password=None, autologin=None)[source]
-

Custom authenticate with bypass for auto-logins

-
-
Parameters
-
    -
  • request (Request) – Request object.

  • -
  • username (str, optional) – Name of user to authenticate.

  • -
  • password (str, optional) – Password of user

  • -
  • autologin (Account, optional) – If given, assume this is -an already authenticated account and bypass authentication.

  • -
-
-
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.web.utils.general_context.html b/docs/0.9.5/api/evennia.web.utils.general_context.html deleted file mode 100644 index 7146cdaee7..0000000000 --- a/docs/0.9.5/api/evennia.web.utils.general_context.html +++ /dev/null @@ -1,128 +0,0 @@ - - - - - - - - - evennia.web.utils.general_context — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.web.utils.general_context

-

This file defines global variables that will always be available in a view -context without having to repeatedly include it.

-

For this to work, this file is included in the settings file, in the -TEMPLATES[“OPTIONS”][“context_processors”] list.

-
-
-evennia.web.utils.general_context.load_game_settings()[source]
-

Load and cache game settings.

-
- -
-
-evennia.web.utils.general_context.general_context(request)[source]
-

Returns common Evennia-related context stuff, which is automatically added -to context of all views.

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.web.utils.html b/docs/0.9.5/api/evennia.web.utils.html deleted file mode 100644 index e9fc6ae57c..0000000000 --- a/docs/0.9.5/api/evennia.web.utils.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - - - evennia.web.utils — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
- - -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.web.utils.middleware.html b/docs/0.9.5/api/evennia.web.utils.middleware.html deleted file mode 100644 index 0df33f520e..0000000000 --- a/docs/0.9.5/api/evennia.web.utils.middleware.html +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - evennia.web.utils.middleware — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.web.utils.middleware

-
-
-class evennia.web.utils.middleware.SharedLoginMiddleware(get_response)[source]
-

Bases: object

-

Handle the shared login between website and webclient.

-
-
-__init__(get_response)[source]
-

Initialize self. See help(type(self)) for accurate signature.

-
- -
-
-classmethod make_shared_login(request)[source]
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.web.utils.tests.html b/docs/0.9.5/api/evennia.web.utils.tests.html deleted file mode 100644 index 5728b561e2..0000000000 --- a/docs/0.9.5/api/evennia.web.utils.tests.html +++ /dev/null @@ -1,127 +0,0 @@ - - - - - - - - - evennia.web.utils.tests — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.web.utils.tests

-
-
-class evennia.web.utils.tests.TestGeneralContext(methodName='runTest')[source]
-

Bases: django.test.testcases.TestCase

-
-
-maxDiff = None
-
- -
-
-test_general_context()[source]
-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.web.webclient.html b/docs/0.9.5/api/evennia.web.webclient.html deleted file mode 100644 index d9e55a2359..0000000000 --- a/docs/0.9.5/api/evennia.web.webclient.html +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - evennia.web.webclient — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.web.webclient

- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.web.webclient.urls.html b/docs/0.9.5/api/evennia.web.webclient.urls.html deleted file mode 100644 index 679abcc491..0000000000 --- a/docs/0.9.5/api/evennia.web.webclient.urls.html +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - - - evennia.web.webclient.urls — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.web.webclient.urls

-

This structures the (simple) structure of the webpage ‘application’.

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.web.webclient.views.html b/docs/0.9.5/api/evennia.web.webclient.views.html deleted file mode 100644 index ad42ce31a2..0000000000 --- a/docs/0.9.5/api/evennia.web.webclient.views.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - - - evennia.web.webclient.views — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.web.webclient.views

-

This contains a simple view for rendering the webclient -page and serve it eventual static content.

-
-
-evennia.web.webclient.views.webclient(request)[source]
-

Webclient page template loading.

-
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.web.website.forms.html b/docs/0.9.5/api/evennia.web.website.forms.html deleted file mode 100644 index c0189ba575..0000000000 --- a/docs/0.9.5/api/evennia.web.website.forms.html +++ /dev/null @@ -1,349 +0,0 @@ - - - - - - - - - evennia.web.website.forms — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.web.website.forms

-
-
-class evennia.web.website.forms.EvenniaForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, field_order=None, use_required_attribute=None, renderer=None)[source]
-

Bases: django.forms.forms.Form

-

This is a stock Django form, but modified so that all values provided -through it are escaped (sanitized). Validation is performed by the fields -you define in the form.

-

This has little to do with Evennia itself and is more general web security- -related.

-

https://www.owasp.org/index.php/Input_Validation_Cheat_Sheet#Goals_of_Input_Validation

-
-
-clean()[source]
-

Django hook. Performed on form submission.

-
-
Returns
-

cleaned (dict) – Dictionary of key:value pairs submitted on the form.

-
-
-
- -
-
-base_fields = {}
-
- -
-
-declared_fields = {}
-
- -
-
-property media
-

Return all media required to render the widgets on this form.

-
- -
- -
-
-class evennia.web.website.forms.AccountForm(*args, **kwargs)[source]
-

Bases: django.contrib.auth.forms.UserCreationForm

-

This is a generic Django form tailored to the Account model.

-

In this incarnation it does not allow getting/setting of attributes, only -core User model fields (username, email, password).

-
-
-class Meta[source]
-

Bases: object

-

This is a Django construct that provides additional configuration to -the form.

-
-
-model
-

alias of evennia.accounts.accounts.DefaultAccount

-
- -
-
-fields = ('username', 'email')
-
- -
-
-field_classes = {'username': <class 'django.contrib.auth.forms.UsernameField'>}
-
- -
- -
-
-base_fields = {'email': <django.forms.fields.EmailField object>, 'password1': <django.forms.fields.CharField object>, 'password2': <django.forms.fields.CharField object>, 'username': <django.contrib.auth.forms.UsernameField object>}
-
- -
-
-declared_fields = {'email': <django.forms.fields.EmailField object>, 'password1': <django.forms.fields.CharField object>, 'password2': <django.forms.fields.CharField object>}
-
- -
-
-property media
-

Return all media required to render the widgets on this form.

-
- -
- -
-
-class evennia.web.website.forms.ObjectForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, instance=None, use_required_attribute=None, renderer=None)[source]
-

Bases: evennia.web.website.forms.EvenniaForm, django.forms.models.ModelForm

-

This is a Django form for generic Evennia Objects that allows modification -of attributes when called from a descendent of ObjectUpdate or ObjectCreate -views.

-

It defines no fields by default; you have to do that by extending this class -and defining what fields you want to be recorded. See the CharacterForm for -a simple example of how to do this.

-
-
-class Meta[source]
-

Bases: object

-

This is a Django construct that provides additional configuration to -the form.

-
-
-model
-

alias of evennia.objects.objects.DefaultObject

-
- -
-
-fields = ('db_key',)
-
- -
-
-labels = {'db_key': 'Name'}
-
- -
- -
-
-base_fields = {'db_key': <django.forms.fields.CharField object>}
-
- -
-
-declared_fields = {}
-
- -
-
-property media
-

Return all media required to render the widgets on this form.

-
- -
- -
-
-class evennia.web.website.forms.CharacterForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, instance=None, use_required_attribute=None, renderer=None)[source]
-

Bases: evennia.web.website.forms.ObjectForm

-

This is a Django form for Evennia Character objects.

-

Since Evennia characters only have one attribute by default, this form only -defines a field for that single attribute. The names of fields you define should -correspond to their names as stored in the dbhandler; you can display -‘prettier’ versions of the fieldname on the form using the ‘label’ kwarg.

-

The basic field types are CharFields and IntegerFields, which let you enter -text and numbers respectively. IntegerFields have some neat validation tricks -they can do, like mandating values fall within a certain range.

-

For example, a complete “age” field (which stores its value to -character.db.age might look like:

-
-
age = forms.IntegerField(

label=”Your Age”, -min_value=18, max_value=9000, -help_text=”Years since your birth.”)

-
-
-

Default input fields are generic single-line text boxes. You can control what -sort of input field users will see by specifying a “widget.” An example of -this is used for the ‘desc’ field to show a Textarea box instead of a Textbox.

-

For help in building out your form, please see: -https://docs.djangoproject.com/en/1.11/topics/forms/#building-a-form-in-django

-

For more information on fields and their capabilities, see: -https://docs.djangoproject.com/en/1.11/ref/forms/fields/

-

For more on widgets, see: -https://docs.djangoproject.com/en/1.11/ref/forms/widgets/

-
-
-class Meta[source]
-

Bases: object

-

This is a Django construct that provides additional configuration to -the form.

-
-
-model
-

alias of evennia.objects.objects.DefaultCharacter

-
- -
-
-fields = ('db_key',)
-
- -
-
-labels = {'db_key': 'Name'}
-
- -
- -
-
-base_fields = {'db_key': <django.forms.fields.CharField object>, 'desc': <django.forms.fields.CharField object>}
-
- -
-
-declared_fields = {'desc': <django.forms.fields.CharField object>}
-
- -
-
-property media
-

Return all media required to render the widgets on this form.

-
- -
- -
-
-class evennia.web.website.forms.CharacterUpdateForm(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=None, empty_permitted=False, instance=None, use_required_attribute=None, renderer=None)[source]
-

Bases: evennia.web.website.forms.CharacterForm

-

This is a Django form for updating Evennia Character objects.

-

By default it is the same as the CharacterForm, but if there are circumstances -in which you don’t want to let players edit all the same attributes they had -access to during creation, you can redefine this form with those fields you do -wish to allow.

-
-
-base_fields = {'db_key': <django.forms.fields.CharField object>, 'desc': <django.forms.fields.CharField object>}
-
- -
-
-declared_fields = {'desc': <django.forms.fields.CharField object>}
-
- -
-
-property media
-

Return all media required to render the widgets on this form.

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.web.website.html b/docs/0.9.5/api/evennia.web.website.html deleted file mode 100644 index 7261611712..0000000000 --- a/docs/0.9.5/api/evennia.web.website.html +++ /dev/null @@ -1,127 +0,0 @@ - - - - - - - - - evennia.web.website — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
- - -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.web.website.templatetags.addclass.html b/docs/0.9.5/api/evennia.web.website.templatetags.addclass.html deleted file mode 100644 index 7b37b2a2aa..0000000000 --- a/docs/0.9.5/api/evennia.web.website.templatetags.addclass.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - evennia.web.website.templatetags.addclass — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.web.website.templatetags.addclass

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.web.website.templatetags.html b/docs/0.9.5/api/evennia.web.website.templatetags.html deleted file mode 100644 index ded6076e63..0000000000 --- a/docs/0.9.5/api/evennia.web.website.templatetags.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - - - evennia.web.website.templatetags — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.web.website.templatetags

- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.web.website.tests.html b/docs/0.9.5/api/evennia.web.website.tests.html deleted file mode 100644 index 1dd12273b0..0000000000 --- a/docs/0.9.5/api/evennia.web.website.tests.html +++ /dev/null @@ -1,557 +0,0 @@ - - - - - - - - - evennia.web.website.tests — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.web.website.tests

-
-
-class evennia.web.website.tests.EvenniaWebTest(methodName='runTest')[source]
-

Bases: evennia.utils.test_resources.BaseEvenniaTest

-
-
-account_typeclass = 'typeclasses.accounts.Account'
-
- -
-
-object_typeclass = 'typeclasses.objects.Object'
-
- -
-
-character_typeclass = 'typeclasses.characters.Character'
-
- -
-
-exit_typeclass = 'typeclasses.exits.Exit'
-
- -
-
-room_typeclass = 'typeclasses.rooms.Room'
-
- -
-
-script_typeclass = 'typeclasses.scripts.Script'
-
- -
-
-channel_typeclass = 'typeclasses.channels.Channel'
-
- -
-
-url_name = 'index'
-
- -
-
-unauthenticated_response = 200
-
- -
-
-authenticated_response = 200
-
- -
-
-setUp()[source]
-

Sets up testing environment

-
- -
-
-test_valid_chars()[source]
-

Make sure account has playable characters

-
- -
-
-get_kwargs()[source]
-
- -
-
-test_get()[source]
-
- -
-
-login()[source]
-
- -
-
-test_get_authenticated()[source]
-
- -
- -
-
-class evennia.web.website.tests.AdminTest(methodName='runTest')[source]
-

Bases: evennia.web.website.tests.EvenniaWebTest

-
-
-url_name = 'django_admin'
-
- -
-
-unauthenticated_response = 302
-
- -
- -
-
-class evennia.web.website.tests.IndexTest(methodName='runTest')[source]
-

Bases: evennia.web.website.tests.EvenniaWebTest

-
-
-url_name = 'index'
-
- -
- -
-
-class evennia.web.website.tests.RegisterTest(methodName='runTest')[source]
-

Bases: evennia.web.website.tests.EvenniaWebTest

-
-
-url_name = 'register'
-
- -
- -
-
-class evennia.web.website.tests.LoginTest(methodName='runTest')[source]
-

Bases: evennia.web.website.tests.EvenniaWebTest

-
-
-url_name = 'login'
-
- -
- -
-
-class evennia.web.website.tests.LogoutTest(methodName='runTest')[source]
-

Bases: evennia.web.website.tests.EvenniaWebTest

-
-
-url_name = 'logout'
-
- -
- -
-
-class evennia.web.website.tests.PasswordResetTest(methodName='runTest')[source]
-

Bases: evennia.web.website.tests.EvenniaWebTest

-
-
-url_name = 'password_change'
-
- -
-
-unauthenticated_response = 302
-
- -
- -
-
-class evennia.web.website.tests.WebclientTest(methodName='runTest')[source]
-

Bases: evennia.web.website.tests.EvenniaWebTest

-
-
-url_name = 'webclient:index'
-
- -
-
-test_get()[source]
-
- -
-
-test_get_disabled()[source]
-
- -
- -
-
-class evennia.web.website.tests.ChannelListTest(methodName='runTest')[source]
-

Bases: evennia.web.website.tests.EvenniaWebTest

-
-
-url_name = 'channels'
-
- -
- -
-
-class evennia.web.website.tests.ChannelDetailTest(methodName='runTest')[source]
-

Bases: evennia.web.website.tests.EvenniaWebTest

-
-
-url_name = 'channel-detail'
-
- -
-
-setUp()[source]
-

Sets up testing environment

-
- -
-
-get_kwargs()[source]
-
- -
- -
-
-class evennia.web.website.tests.HelpListTest(methodName='runTest')[source]
-

Bases: evennia.web.website.tests.EvenniaWebTest

-
-
-url_name = 'help'
-
- -
- -
-
-class evennia.web.website.tests.HelpDetailTest(methodName='runTest')[source]
-

Bases: evennia.web.website.tests.EvenniaWebTest

-
-
-url_name = 'help-entry-detail'
-
- -
-
-setUp()[source]
-

Sets up testing environment

-
- -
-
-get_kwargs()[source]
-
- -
-
-test_view()[source]
-
- -
-
-test_object_cache()[source]
-
- -
- -
-
-class evennia.web.website.tests.HelpLockedDetailTest(methodName='runTest')[source]
-

Bases: evennia.web.website.tests.EvenniaWebTest

-
-
-url_name = 'help-entry-detail'
-
- -
-
-setUp()[source]
-

Sets up testing environment

-
- -
-
-get_kwargs()[source]
-
- -
-
-test_locked_entry()[source]
-
- -
-
-test_lock_with_perm()[source]
-
- -
- -
-
-class evennia.web.website.tests.CharacterCreateView(methodName='runTest')[source]
-

Bases: evennia.web.website.tests.EvenniaWebTest

-
-
-url_name = 'character-create'
-
- -
-
-unauthenticated_response = 302
-
- -
-
-test_valid_access_multisession_0()[source]
-

Account1 with no characters should be able to create a new one

-
- -
-
-test_valid_access_multisession_2()[source]
-

Account1 should be able to create a new character

-
- -
- -
-
-class evennia.web.website.tests.CharacterPuppetView(methodName='runTest')[source]
-

Bases: evennia.web.website.tests.EvenniaWebTest

-
-
-url_name = 'character-puppet'
-
- -
-
-unauthenticated_response = 302
-
- -
-
-get_kwargs()[source]
-
- -
-
-test_invalid_access()[source]
-

Account1 should not be able to puppet Account2:Char2

-
- -
- -
-
-class evennia.web.website.tests.CharacterListView(methodName='runTest')[source]
-

Bases: evennia.web.website.tests.EvenniaWebTest

-
-
-url_name = 'characters'
-
- -
-
-unauthenticated_response = 302
-
- -
- -
-
-class evennia.web.website.tests.CharacterManageView(methodName='runTest')[source]
-

Bases: evennia.web.website.tests.EvenniaWebTest

-
-
-url_name = 'character-manage'
-
- -
-
-unauthenticated_response = 302
-
- -
- -
-
-class evennia.web.website.tests.CharacterUpdateView(methodName='runTest')[source]
-

Bases: evennia.web.website.tests.EvenniaWebTest

-
-
-url_name = 'character-update'
-
- -
-
-unauthenticated_response = 302
-
- -
-
-get_kwargs()[source]
-
- -
-
-test_valid_access()[source]
-

Account1 should be able to update Account1:Char1

-
- -
-
-test_invalid_access()[source]
-

Account1 should not be able to update Account2:Char2

-
- -
- -
-
-class evennia.web.website.tests.CharacterDeleteView(methodName='runTest')[source]
-

Bases: evennia.web.website.tests.EvenniaWebTest

-
-
-url_name = 'character-delete'
-
- -
-
-unauthenticated_response = 302
-
- -
-
-get_kwargs()[source]
-
- -
-
-test_valid_access()[source]
-

Account1 should be able to delete Account1:Char1

-
- -
-
-test_invalid_access()[source]
-

Account1 should not be able to delete Account2:Char2

-
- -
- -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.web.website.urls.html b/docs/0.9.5/api/evennia.web.website.urls.html deleted file mode 100644 index 65dc8b6d9e..0000000000 --- a/docs/0.9.5/api/evennia.web.website.urls.html +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - - - evennia.web.website.urls — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.web.website.urls

-

This redirects to website sub-pages.

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/api/evennia.web.website.views.html b/docs/0.9.5/api/evennia.web.website.views.html deleted file mode 100644 index 1b83fba3f7..0000000000 --- a/docs/0.9.5/api/evennia.web.website.views.html +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - - - evennia.web.website.views — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
-

evennia.web.website.views

-

Website views.

-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/genindex.html b/docs/0.9.5/genindex.html deleted file mode 100644 index d79c52bd34..0000000000 --- a/docs/0.9.5/genindex.html +++ /dev/null @@ -1,9733 +0,0 @@ - - - - - - - - Index — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- - -

Index

- -
- _ - | A - | B - | C - | D - | E - | F - | G - | H - | I - | J - | K - | L - | M - | N - | O - | P - | Q - | R - | S - | T - | U - | V - | W - | X - | Y - -
-

_

- - -
- -

A

- - - -
- -

B

- - - -
- -

C

- - - -
- -

D

- - - -
- -

E

- - - -
- -

F

- - - -
- -

G

- - - -
- -

H

- - - -
- -

I

- - - -
- -

J

- - - -
- -

K

- - - -
- -

L

- - - -
- -

M

- - - -
- -

N

- - - -
- -

O

- - - -
- -

P

- - - -
- -

Q

- - - -
- -

R

- - - -
- -

S

- - - -
- -

T

- - - -
- -

U

- - - -
- -

V

- - - -
- -

W

- - - -
- -

X

- - - -
- -

Y

- - -
- - - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/index.html b/docs/0.9.5/index.html deleted file mode 100644 index cc116156ff..0000000000 --- a/docs/0.9.5/index.html +++ /dev/null @@ -1,148 +0,0 @@ - - - - - - - - - Evennia Documentation — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - - -
-
-
-
- -
-

Important

-

This is the v0.9.5 documentation of Evennia, originally converted from the old -evennia wiki at 2020-10-11 18:06:03.062022. -While we will fix outright mistakes, minor typos and visual conversion issues will not be -addressed in this version. -A new and refactored version of the docs is being prepared for version 1.0 of Evennia.

-
-
-

Evennia Documentation

-

This is the manual of Evennia, the open source Python MU* creation -system. -You can Search the documentation on the left. If you have trouble with unclear documentation, please -let us know on our mailing list, over IRC or by making a new documentation issue.

-

There is a lengthier introduction to read. You might also want to read about -how to get and give help.

-
    -
  • The Getting Started page helps installing and starting Evennia for the first -time.

  • -
  • The Admin Docs covers running and maintaining an Evennia server.

  • -
  • The Builder Docs helps for starting to build a game world using Evennia.

  • -
  • The Developer Central describes how Evennia works and is used by coders.

  • -
  • The Tutorials & Examples contains help pages on a step-by-step or tutorial format.

  • -
  • The Documentation-Contributing page helps with how to write and contribute to these docs.

  • -
  • The API documentation is created from the latest source code.

  • -
  • The TOC lists all regular documentation pages.

  • -
-
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/objects.inv b/docs/0.9.5/objects.inv deleted file mode 100644 index 25dd32304d..0000000000 Binary files a/docs/0.9.5/objects.inv and /dev/null differ diff --git a/docs/0.9.5/py-modindex.html b/docs/0.9.5/py-modindex.html deleted file mode 100644 index 3d8e3789df..0000000000 --- a/docs/0.9.5/py-modindex.html +++ /dev/null @@ -1,876 +0,0 @@ - - - - - - - - Python Module Index — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - - - - -
-
-
-
- - -

Python Module Index

- -
- e -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
- e
- evennia -
    - evennia.accounts -
    - evennia.accounts.accounts -
    - evennia.accounts.bots -
    - evennia.accounts.manager -
    - evennia.accounts.models -
    - evennia.commands -
    - evennia.commands.cmdhandler -
    - evennia.commands.cmdparser -
    - evennia.commands.cmdset -
    - evennia.commands.cmdsethandler -
    - evennia.commands.command -
    - evennia.commands.default -
    - evennia.commands.default.account -
    - evennia.commands.default.admin -
    - evennia.commands.default.batchprocess -
    - evennia.commands.default.building -
    - evennia.commands.default.cmdset_account -
    - evennia.commands.default.cmdset_character -
    - evennia.commands.default.cmdset_session -
    - evennia.commands.default.cmdset_unloggedin -
    - evennia.commands.default.comms -
    - evennia.commands.default.general -
    - evennia.commands.default.help -
    - evennia.commands.default.muxcommand -
    - evennia.commands.default.syscommands -
    - evennia.commands.default.system -
    - evennia.commands.default.unloggedin -
    - evennia.comms -
    - evennia.comms.comms -
    - evennia.comms.managers -
    - evennia.comms.models -
    - evennia.contrib -
    - evennia.help -
    - evennia.help.manager -
    - evennia.help.models -
    - evennia.locks -
    - evennia.locks.lockfuncs -
    - evennia.locks.lockhandler -
    - evennia.objects -
    - evennia.objects.manager -
    - evennia.objects.models -
    - evennia.objects.objects -
    - evennia.prototypes -
    - evennia.prototypes.menus -
    - evennia.prototypes.protfuncs -
    - evennia.prototypes.prototypes -
    - evennia.prototypes.spawner -
    - evennia.scripts -
    - evennia.scripts.manager -
    - evennia.scripts.models -
    - evennia.scripts.monitorhandler -
    - evennia.scripts.scripthandler -
    - evennia.scripts.scripts -
    - evennia.scripts.taskhandler -
    - evennia.scripts.tickerhandler -
    - evennia.server -
    - evennia.server.amp_client -
    - evennia.server.connection_wizard -
    - evennia.server.deprecations -
    - evennia.server.evennia_launcher -
    - evennia.server.game_index_client -
    - evennia.server.game_index_client.client -
    - evennia.server.game_index_client.service -
    - evennia.server.initial_setup -
    - evennia.server.inputfuncs -
    - evennia.server.manager -
    - evennia.server.models -
    - evennia.server.portal -
    - evennia.server.portal.amp -
    - evennia.server.portal.amp_server -
    - evennia.server.portal.grapevine -
    - evennia.server.portal.irc -
    - evennia.server.portal.mccp -
    - evennia.server.portal.mssp -
    - evennia.server.portal.mxp -
    - evennia.server.portal.naws -
    - evennia.server.portal.portal -
    - evennia.server.portal.portalsessionhandler -
    - evennia.server.portal.rss -
    - evennia.server.portal.ssh -
    - evennia.server.portal.ssl -
    - evennia.server.portal.suppress_ga -
    - evennia.server.portal.telnet -
    - evennia.server.portal.telnet_oob -
    - evennia.server.portal.telnet_ssl -
    - evennia.server.portal.tests -
    - evennia.server.portal.ttype -
    - evennia.server.portal.webclient -
    - evennia.server.portal.webclient_ajax -
    - evennia.server.profiling -
    - evennia.server.profiling.dummyrunner -
    - evennia.server.profiling.dummyrunner_settings -
    - evennia.server.profiling.memplot -
    - evennia.server.profiling.settings_mixin -
    - evennia.server.profiling.test_queries -
    - evennia.server.profiling.tests -
    - evennia.server.profiling.timetrace -
    - evennia.server.server -
    - evennia.server.serversession -
    - evennia.server.session -
    - evennia.server.sessionhandler -
    - evennia.server.signals -
    - evennia.server.throttle -
    - evennia.server.validators -
    - evennia.server.webserver -
    - evennia.settings_default -
    - evennia.typeclasses -
    - evennia.typeclasses.attributes -
    - evennia.typeclasses.managers -
    - evennia.typeclasses.models -
    - evennia.typeclasses.tags -
    - evennia.utils -
    - evennia.utils.ansi -
    - evennia.utils.batchprocessors -
    - evennia.utils.containers -
    - evennia.utils.create -
    - evennia.utils.dbserialize -
    - evennia.utils.eveditor -
    - evennia.utils.evform -
    - evennia.utils.evmenu -
    - evennia.utils.evmore -
    - evennia.utils.evtable -
    - evennia.utils.gametime -
    - evennia.utils.idmapper -
    - evennia.utils.idmapper.manager -
    - evennia.utils.idmapper.models -
    - evennia.utils.idmapper.tests -
    - evennia.utils.logger -
    - evennia.utils.optionclasses -
    - evennia.utils.optionhandler -
    - evennia.utils.picklefield -
    - evennia.utils.search -
    - evennia.utils.test_resources -
    - evennia.utils.text2html -
    - evennia.utils.utils -
    - evennia.utils.validatorfuncs -
    - evennia.web -
    - evennia.web.urls -
    - evennia.web.utils -
    - evennia.web.utils.backends -
    - evennia.web.utils.general_context -
    - evennia.web.utils.middleware -
    - evennia.web.utils.tests -
    - evennia.web.webclient -
    - evennia.web.webclient.urls -
    - evennia.web.webclient.views -
    - evennia.web.website -
    - evennia.web.website.forms -
    - evennia.web.website.tests -
    - evennia.web.website.urls -
    - evennia.web.website.views -
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/search.html b/docs/0.9.5/search.html deleted file mode 100644 index 6345e5702b..0000000000 --- a/docs/0.9.5/search.html +++ /dev/null @@ -1,115 +0,0 @@ - - - - - - - - Search — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - - - - - - -
-
-
-
- -

Search

-
- -

- Please activate JavaScript to enable the search - functionality. -

-
-

- Searching for multiple words only shows matches that contain - all words. -

-
- - - -
- -
- -
- -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/0.9.5/searchindex.js b/docs/0.9.5/searchindex.js deleted file mode 100644 index 0341a9c865..0000000000 --- a/docs/0.9.5/searchindex.js +++ /dev/null @@ -1 +0,0 @@ -Search.setIndex({docnames:["A-voice-operated-elevator-using-events","API-refactoring","Accounts","Add-a-simple-new-web-page","Add-a-wiki-on-your-website","Adding-Command-Tutorial","Adding-Object-Typeclass-Tutorial","Administrative-Docs","Apache-Config","Arxcode-installing-help","Async-Process","Attributes","Banning","Batch-Code-Processor","Batch-Command-Processor","Batch-Processors","Bootstrap-&-Evennia","Bootstrap-Components-and-Utilities","Builder-Docs","Building-Permissions","Building-Quickstart","Building-a-mech-tutorial","Building-menus","Choosing-An-SQL-Server","Client-Support-Grid","Coding-FAQ","Coding-Introduction","Coding-Utils","Command-Cooldown","Command-Duration","Command-Prompt","Command-Sets","Command-System","Commands","Communications","Connection-Screen","Continuous-Integration","Contributing","Contributing-Docs","Coordinates","Custom-Protocols","Customize-channels","Debugging","Default-Commands","Default-Exit-Errors","Developer-Central","Dialogues-in-events","Directory-Overview","Docs-refactoring","Dynamic-In-Game-Map","EvEditor","EvMenu","EvMore","Evennia-API","Evennia-Game-Index","Evennia-Introduction","Evennia-for-Diku-Users","Evennia-for-MUSH-Users","Evennia-for-roleplaying-sessions","Execute-Python-Code","First-Steps-Coding","Game-Planning","Gametime-Tutorial","Getting-Started","Glossary","Grapevine","Guest-Logins","HAProxy-Config","Help-System","Help-System-Tutorial","How-To-Get-And-Give-Help","How-to-connect-Evennia-to-Twitter","IRC","Implementing-a-game-rule-system","Inputfuncs","Installing-on-Android","Internationalization","Learn-Python-for-Evennia-The-Hard-Way","Licensing","Links","Locks","Manually-Configuring-Color","Mass-and-weight-for-objects","Messagepath","MonitorHandler","NPC-shop-Tutorial","New-Models","Nicks","OOB","Objects","Online-Setup","Parsing-command-arguments,-theory-and-best-practices","Portal-And-Server","Profiling","Python-3","Python-basic-introduction","Python-basic-tutorial-part-two","Quirks","RSS","Roadmap","Running-Evennia-in-Docker","Screenshot","Scripts","Security","Server-Conf","Sessions","Setting-up-PyCharm","Signals","Soft-Code","Spawner-and-Prototypes","Start-Stop-Reload","Static-In-Game-Map","Tags","Text-Encodings","TextTags","TickerHandler","Turn-based-Combat-System","Tutorial-Aggressive-NPCs","Tutorial-NPCs-listening","Tutorial-Searching-For-Objects","Tutorial-Tweeting-Game-Stats","Tutorial-Vehicles","Tutorial-World-Introduction","Tutorial-for-basic-MUSH-like-game","Tutorials","Typeclasses","Understanding-Color-Tags","Unit-Testing","Updating-Your-Game","Using-MUX-as-a-Standard","Using-Travis","Version-Control","Weather-Tutorial","Web-Character-Generation","Web-Character-View-Tutorial","Web-Features","Web-Tutorial","Webclient","Webclient-brainstorm","Wiki-Index","Zones","api/evennia","api/evennia-api","api/evennia.accounts","api/evennia.accounts.accounts","api/evennia.accounts.admin","api/evennia.accounts.bots","api/evennia.accounts.manager","api/evennia.accounts.models","api/evennia.commands","api/evennia.commands.cmdhandler","api/evennia.commands.cmdparser","api/evennia.commands.cmdset","api/evennia.commands.cmdsethandler","api/evennia.commands.command","api/evennia.commands.default","api/evennia.commands.default.account","api/evennia.commands.default.admin","api/evennia.commands.default.batchprocess","api/evennia.commands.default.building","api/evennia.commands.default.cmdset_account","api/evennia.commands.default.cmdset_character","api/evennia.commands.default.cmdset_session","api/evennia.commands.default.cmdset_unloggedin","api/evennia.commands.default.comms","api/evennia.commands.default.general","api/evennia.commands.default.help","api/evennia.commands.default.muxcommand","api/evennia.commands.default.syscommands","api/evennia.commands.default.system","api/evennia.commands.default.tests","api/evennia.commands.default.unloggedin","api/evennia.comms","api/evennia.comms.admin","api/evennia.comms.channelhandler","api/evennia.comms.comms","api/evennia.comms.managers","api/evennia.comms.models","api/evennia.contrib","api/evennia.contrib.barter","api/evennia.contrib.building_menu","api/evennia.contrib.chargen","api/evennia.contrib.clothing","api/evennia.contrib.color_markups","api/evennia.contrib.custom_gametime","api/evennia.contrib.dice","api/evennia.contrib.email_login","api/evennia.contrib.extended_room","api/evennia.contrib.fieldfill","api/evennia.contrib.gendersub","api/evennia.contrib.health_bar","api/evennia.contrib.ingame_python","api/evennia.contrib.ingame_python.callbackhandler","api/evennia.contrib.ingame_python.commands","api/evennia.contrib.ingame_python.eventfuncs","api/evennia.contrib.ingame_python.scripts","api/evennia.contrib.ingame_python.tests","api/evennia.contrib.ingame_python.typeclasses","api/evennia.contrib.ingame_python.utils","api/evennia.contrib.mail","api/evennia.contrib.mapbuilder","api/evennia.contrib.menu_login","api/evennia.contrib.multidescer","api/evennia.contrib.puzzles","api/evennia.contrib.random_string_generator","api/evennia.contrib.rplanguage","api/evennia.contrib.rpsystem","api/evennia.contrib.security","api/evennia.contrib.security.auditing","api/evennia.contrib.security.auditing.outputs","api/evennia.contrib.security.auditing.server","api/evennia.contrib.security.auditing.tests","api/evennia.contrib.simpledoor","api/evennia.contrib.slow_exit","api/evennia.contrib.talking_npc","api/evennia.contrib.tree_select","api/evennia.contrib.turnbattle","api/evennia.contrib.turnbattle.tb_basic","api/evennia.contrib.turnbattle.tb_equip","api/evennia.contrib.turnbattle.tb_items","api/evennia.contrib.turnbattle.tb_magic","api/evennia.contrib.turnbattle.tb_range","api/evennia.contrib.tutorial_examples","api/evennia.contrib.tutorial_examples.bodyfunctions","api/evennia.contrib.tutorial_examples.cmdset_red_button","api/evennia.contrib.tutorial_examples.example_batch_code","api/evennia.contrib.tutorial_examples.red_button","api/evennia.contrib.tutorial_examples.red_button_scripts","api/evennia.contrib.tutorial_examples.tests","api/evennia.contrib.tutorial_world","api/evennia.contrib.tutorial_world.intro_menu","api/evennia.contrib.tutorial_world.mob","api/evennia.contrib.tutorial_world.objects","api/evennia.contrib.tutorial_world.rooms","api/evennia.contrib.unixcommand","api/evennia.contrib.wilderness","api/evennia.help","api/evennia.help.admin","api/evennia.help.manager","api/evennia.help.models","api/evennia.locks","api/evennia.locks.lockfuncs","api/evennia.locks.lockhandler","api/evennia.objects","api/evennia.objects.admin","api/evennia.objects.manager","api/evennia.objects.models","api/evennia.objects.objects","api/evennia.prototypes","api/evennia.prototypes.menus","api/evennia.prototypes.protfuncs","api/evennia.prototypes.prototypes","api/evennia.prototypes.spawner","api/evennia.scripts","api/evennia.scripts.admin","api/evennia.scripts.manager","api/evennia.scripts.models","api/evennia.scripts.monitorhandler","api/evennia.scripts.scripthandler","api/evennia.scripts.scripts","api/evennia.scripts.taskhandler","api/evennia.scripts.tickerhandler","api/evennia.server","api/evennia.server.admin","api/evennia.server.amp_client","api/evennia.server.connection_wizard","api/evennia.server.deprecations","api/evennia.server.evennia_launcher","api/evennia.server.game_index_client","api/evennia.server.game_index_client.client","api/evennia.server.game_index_client.service","api/evennia.server.initial_setup","api/evennia.server.inputfuncs","api/evennia.server.manager","api/evennia.server.models","api/evennia.server.portal","api/evennia.server.portal.amp","api/evennia.server.portal.amp_server","api/evennia.server.portal.grapevine","api/evennia.server.portal.irc","api/evennia.server.portal.mccp","api/evennia.server.portal.mssp","api/evennia.server.portal.mxp","api/evennia.server.portal.naws","api/evennia.server.portal.portal","api/evennia.server.portal.portalsessionhandler","api/evennia.server.portal.rss","api/evennia.server.portal.ssh","api/evennia.server.portal.ssl","api/evennia.server.portal.suppress_ga","api/evennia.server.portal.telnet","api/evennia.server.portal.telnet_oob","api/evennia.server.portal.telnet_ssl","api/evennia.server.portal.tests","api/evennia.server.portal.ttype","api/evennia.server.portal.webclient","api/evennia.server.portal.webclient_ajax","api/evennia.server.profiling","api/evennia.server.profiling.dummyrunner","api/evennia.server.profiling.dummyrunner_settings","api/evennia.server.profiling.memplot","api/evennia.server.profiling.settings_mixin","api/evennia.server.profiling.test_queries","api/evennia.server.profiling.tests","api/evennia.server.profiling.timetrace","api/evennia.server.server","api/evennia.server.serversession","api/evennia.server.session","api/evennia.server.sessionhandler","api/evennia.server.signals","api/evennia.server.throttle","api/evennia.server.validators","api/evennia.server.webserver","api/evennia.settings_default","api/evennia.typeclasses","api/evennia.typeclasses.admin","api/evennia.typeclasses.attributes","api/evennia.typeclasses.managers","api/evennia.typeclasses.models","api/evennia.typeclasses.tags","api/evennia.utils","api/evennia.utils.ansi","api/evennia.utils.batchprocessors","api/evennia.utils.containers","api/evennia.utils.create","api/evennia.utils.dbserialize","api/evennia.utils.eveditor","api/evennia.utils.evform","api/evennia.utils.evmenu","api/evennia.utils.evmore","api/evennia.utils.evtable","api/evennia.utils.gametime","api/evennia.utils.idmapper","api/evennia.utils.idmapper.manager","api/evennia.utils.idmapper.models","api/evennia.utils.idmapper.tests","api/evennia.utils.inlinefuncs","api/evennia.utils.logger","api/evennia.utils.optionclasses","api/evennia.utils.optionhandler","api/evennia.utils.picklefield","api/evennia.utils.search","api/evennia.utils.test_resources","api/evennia.utils.text2html","api/evennia.utils.utils","api/evennia.utils.validatorfuncs","api/evennia.web","api/evennia.web.urls","api/evennia.web.utils","api/evennia.web.utils.backends","api/evennia.web.utils.general_context","api/evennia.web.utils.middleware","api/evennia.web.utils.tests","api/evennia.web.webclient","api/evennia.web.webclient.urls","api/evennia.web.webclient.views","api/evennia.web.website","api/evennia.web.website.forms","api/evennia.web.website.templatetags","api/evennia.web.website.templatetags.addclass","api/evennia.web.website.tests","api/evennia.web.website.urls","api/evennia.web.website.views","index","toc"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":3,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":2,"sphinx.domains.rst":2,"sphinx.domains.std":1,"sphinx.ext.todo":2,"sphinx.ext.viewcode":1,sphinx:56},filenames:["A-voice-operated-elevator-using-events.md","API-refactoring.md","Accounts.md","Add-a-simple-new-web-page.md","Add-a-wiki-on-your-website.md","Adding-Command-Tutorial.md","Adding-Object-Typeclass-Tutorial.md","Administrative-Docs.md","Apache-Config.md","Arxcode-installing-help.md","Async-Process.md","Attributes.md","Banning.md","Batch-Code-Processor.md","Batch-Command-Processor.md","Batch-Processors.md","Bootstrap-&-Evennia.md","Bootstrap-Components-and-Utilities.md","Builder-Docs.md","Building-Permissions.md","Building-Quickstart.md","Building-a-mech-tutorial.md","Building-menus.md","Choosing-An-SQL-Server.md","Client-Support-Grid.md","Coding-FAQ.md","Coding-Introduction.md","Coding-Utils.md","Command-Cooldown.md","Command-Duration.md","Command-Prompt.md","Command-Sets.md","Command-System.md","Commands.md","Communications.md","Connection-Screen.md","Continuous-Integration.md","Contributing.md","Contributing-Docs.md","Coordinates.md","Custom-Protocols.md","Customize-channels.md","Debugging.md","Default-Commands.md","Default-Exit-Errors.md","Developer-Central.md","Dialogues-in-events.md","Directory-Overview.md","Docs-refactoring.md","Dynamic-In-Game-Map.md","EvEditor.md","EvMenu.md","EvMore.md","Evennia-API.md","Evennia-Game-Index.md","Evennia-Introduction.md","Evennia-for-Diku-Users.md","Evennia-for-MUSH-Users.md","Evennia-for-roleplaying-sessions.md","Execute-Python-Code.md","First-Steps-Coding.md","Game-Planning.md","Gametime-Tutorial.md","Getting-Started.md","Glossary.md","Grapevine.md","Guest-Logins.md","HAProxy-Config.md","Help-System.md","Help-System-Tutorial.md","How-To-Get-And-Give-Help.md","How-to-connect-Evennia-to-Twitter.md","IRC.md","Implementing-a-game-rule-system.md","Inputfuncs.md","Installing-on-Android.md","Internationalization.md","Learn-Python-for-Evennia-The-Hard-Way.md","Licensing.md","Links.md","Locks.md","Manually-Configuring-Color.md","Mass-and-weight-for-objects.md","Messagepath.md","MonitorHandler.md","NPC-shop-Tutorial.md","New-Models.md","Nicks.md","OOB.md","Objects.md","Online-Setup.md","Parsing-command-arguments,-theory-and-best-practices.md","Portal-And-Server.md","Profiling.md","Python-3.md","Python-basic-introduction.md","Python-basic-tutorial-part-two.md","Quirks.md","RSS.md","Roadmap.md","Running-Evennia-in-Docker.md","Screenshot.md","Scripts.md","Security.md","Server-Conf.md","Sessions.md","Setting-up-PyCharm.md","Signals.md","Soft-Code.md","Spawner-and-Prototypes.md","Start-Stop-Reload.md","Static-In-Game-Map.md","Tags.md","Text-Encodings.md","TextTags.md","TickerHandler.md","Turn-based-Combat-System.md","Tutorial-Aggressive-NPCs.md","Tutorial-NPCs-listening.md","Tutorial-Searching-For-Objects.md","Tutorial-Tweeting-Game-Stats.md","Tutorial-Vehicles.md","Tutorial-World-Introduction.md","Tutorial-for-basic-MUSH-like-game.md","Tutorials.md","Typeclasses.md","Understanding-Color-Tags.md","Unit-Testing.md","Updating-Your-Game.md","Using-MUX-as-a-Standard.md","Using-Travis.md","Version-Control.md","Weather-Tutorial.md","Web-Character-Generation.md","Web-Character-View-Tutorial.md","Web-Features.md","Web-Tutorial.md","Webclient.md","Webclient-brainstorm.md","Wiki-Index.md","Zones.md","api/evennia.md","api/evennia-api.md","api/evennia.accounts.md","api/evennia.accounts.accounts.md","api/evennia.accounts.admin.md","api/evennia.accounts.bots.md","api/evennia.accounts.manager.md","api/evennia.accounts.models.md","api/evennia.commands.md","api/evennia.commands.cmdhandler.md","api/evennia.commands.cmdparser.md","api/evennia.commands.cmdset.md","api/evennia.commands.cmdsethandler.md","api/evennia.commands.command.md","api/evennia.commands.default.md","api/evennia.commands.default.account.md","api/evennia.commands.default.admin.md","api/evennia.commands.default.batchprocess.md","api/evennia.commands.default.building.md","api/evennia.commands.default.cmdset_account.md","api/evennia.commands.default.cmdset_character.md","api/evennia.commands.default.cmdset_session.md","api/evennia.commands.default.cmdset_unloggedin.md","api/evennia.commands.default.comms.md","api/evennia.commands.default.general.md","api/evennia.commands.default.help.md","api/evennia.commands.default.muxcommand.md","api/evennia.commands.default.syscommands.md","api/evennia.commands.default.system.md","api/evennia.commands.default.tests.md","api/evennia.commands.default.unloggedin.md","api/evennia.comms.md","api/evennia.comms.admin.md","api/evennia.comms.channelhandler.md","api/evennia.comms.comms.md","api/evennia.comms.managers.md","api/evennia.comms.models.md","api/evennia.contrib.md","api/evennia.contrib.barter.md","api/evennia.contrib.building_menu.md","api/evennia.contrib.chargen.md","api/evennia.contrib.clothing.md","api/evennia.contrib.color_markups.md","api/evennia.contrib.custom_gametime.md","api/evennia.contrib.dice.md","api/evennia.contrib.email_login.md","api/evennia.contrib.extended_room.md","api/evennia.contrib.fieldfill.md","api/evennia.contrib.gendersub.md","api/evennia.contrib.health_bar.md","api/evennia.contrib.ingame_python.md","api/evennia.contrib.ingame_python.callbackhandler.md","api/evennia.contrib.ingame_python.commands.md","api/evennia.contrib.ingame_python.eventfuncs.md","api/evennia.contrib.ingame_python.scripts.md","api/evennia.contrib.ingame_python.tests.md","api/evennia.contrib.ingame_python.typeclasses.md","api/evennia.contrib.ingame_python.utils.md","api/evennia.contrib.mail.md","api/evennia.contrib.mapbuilder.md","api/evennia.contrib.menu_login.md","api/evennia.contrib.multidescer.md","api/evennia.contrib.puzzles.md","api/evennia.contrib.random_string_generator.md","api/evennia.contrib.rplanguage.md","api/evennia.contrib.rpsystem.md","api/evennia.contrib.security.md","api/evennia.contrib.security.auditing.md","api/evennia.contrib.security.auditing.outputs.md","api/evennia.contrib.security.auditing.server.md","api/evennia.contrib.security.auditing.tests.md","api/evennia.contrib.simpledoor.md","api/evennia.contrib.slow_exit.md","api/evennia.contrib.talking_npc.md","api/evennia.contrib.tree_select.md","api/evennia.contrib.turnbattle.md","api/evennia.contrib.turnbattle.tb_basic.md","api/evennia.contrib.turnbattle.tb_equip.md","api/evennia.contrib.turnbattle.tb_items.md","api/evennia.contrib.turnbattle.tb_magic.md","api/evennia.contrib.turnbattle.tb_range.md","api/evennia.contrib.tutorial_examples.md","api/evennia.contrib.tutorial_examples.bodyfunctions.md","api/evennia.contrib.tutorial_examples.cmdset_red_button.md","api/evennia.contrib.tutorial_examples.example_batch_code.md","api/evennia.contrib.tutorial_examples.red_button.md","api/evennia.contrib.tutorial_examples.red_button_scripts.md","api/evennia.contrib.tutorial_examples.tests.md","api/evennia.contrib.tutorial_world.md","api/evennia.contrib.tutorial_world.intro_menu.md","api/evennia.contrib.tutorial_world.mob.md","api/evennia.contrib.tutorial_world.objects.md","api/evennia.contrib.tutorial_world.rooms.md","api/evennia.contrib.unixcommand.md","api/evennia.contrib.wilderness.md","api/evennia.help.md","api/evennia.help.admin.md","api/evennia.help.manager.md","api/evennia.help.models.md","api/evennia.locks.md","api/evennia.locks.lockfuncs.md","api/evennia.locks.lockhandler.md","api/evennia.objects.md","api/evennia.objects.admin.md","api/evennia.objects.manager.md","api/evennia.objects.models.md","api/evennia.objects.objects.md","api/evennia.prototypes.md","api/evennia.prototypes.menus.md","api/evennia.prototypes.protfuncs.md","api/evennia.prototypes.prototypes.md","api/evennia.prototypes.spawner.md","api/evennia.scripts.md","api/evennia.scripts.admin.md","api/evennia.scripts.manager.md","api/evennia.scripts.models.md","api/evennia.scripts.monitorhandler.md","api/evennia.scripts.scripthandler.md","api/evennia.scripts.scripts.md","api/evennia.scripts.taskhandler.md","api/evennia.scripts.tickerhandler.md","api/evennia.server.md","api/evennia.server.admin.md","api/evennia.server.amp_client.md","api/evennia.server.connection_wizard.md","api/evennia.server.deprecations.md","api/evennia.server.evennia_launcher.md","api/evennia.server.game_index_client.md","api/evennia.server.game_index_client.client.md","api/evennia.server.game_index_client.service.md","api/evennia.server.initial_setup.md","api/evennia.server.inputfuncs.md","api/evennia.server.manager.md","api/evennia.server.models.md","api/evennia.server.portal.md","api/evennia.server.portal.amp.md","api/evennia.server.portal.amp_server.md","api/evennia.server.portal.grapevine.md","api/evennia.server.portal.irc.md","api/evennia.server.portal.mccp.md","api/evennia.server.portal.mssp.md","api/evennia.server.portal.mxp.md","api/evennia.server.portal.naws.md","api/evennia.server.portal.portal.md","api/evennia.server.portal.portalsessionhandler.md","api/evennia.server.portal.rss.md","api/evennia.server.portal.ssh.md","api/evennia.server.portal.ssl.md","api/evennia.server.portal.suppress_ga.md","api/evennia.server.portal.telnet.md","api/evennia.server.portal.telnet_oob.md","api/evennia.server.portal.telnet_ssl.md","api/evennia.server.portal.tests.md","api/evennia.server.portal.ttype.md","api/evennia.server.portal.webclient.md","api/evennia.server.portal.webclient_ajax.md","api/evennia.server.profiling.md","api/evennia.server.profiling.dummyrunner.md","api/evennia.server.profiling.dummyrunner_settings.md","api/evennia.server.profiling.memplot.md","api/evennia.server.profiling.settings_mixin.md","api/evennia.server.profiling.test_queries.md","api/evennia.server.profiling.tests.md","api/evennia.server.profiling.timetrace.md","api/evennia.server.server.md","api/evennia.server.serversession.md","api/evennia.server.session.md","api/evennia.server.sessionhandler.md","api/evennia.server.signals.md","api/evennia.server.throttle.md","api/evennia.server.validators.md","api/evennia.server.webserver.md","api/evennia.settings_default.md","api/evennia.typeclasses.md","api/evennia.typeclasses.admin.md","api/evennia.typeclasses.attributes.md","api/evennia.typeclasses.managers.md","api/evennia.typeclasses.models.md","api/evennia.typeclasses.tags.md","api/evennia.utils.md","api/evennia.utils.ansi.md","api/evennia.utils.batchprocessors.md","api/evennia.utils.containers.md","api/evennia.utils.create.md","api/evennia.utils.dbserialize.md","api/evennia.utils.eveditor.md","api/evennia.utils.evform.md","api/evennia.utils.evmenu.md","api/evennia.utils.evmore.md","api/evennia.utils.evtable.md","api/evennia.utils.gametime.md","api/evennia.utils.idmapper.md","api/evennia.utils.idmapper.manager.md","api/evennia.utils.idmapper.models.md","api/evennia.utils.idmapper.tests.md","api/evennia.utils.inlinefuncs.md","api/evennia.utils.logger.md","api/evennia.utils.optionclasses.md","api/evennia.utils.optionhandler.md","api/evennia.utils.picklefield.md","api/evennia.utils.search.md","api/evennia.utils.test_resources.md","api/evennia.utils.text2html.md","api/evennia.utils.utils.md","api/evennia.utils.validatorfuncs.md","api/evennia.web.md","api/evennia.web.urls.md","api/evennia.web.utils.md","api/evennia.web.utils.backends.md","api/evennia.web.utils.general_context.md","api/evennia.web.utils.middleware.md","api/evennia.web.utils.tests.md","api/evennia.web.webclient.md","api/evennia.web.webclient.urls.md","api/evennia.web.webclient.views.md","api/evennia.web.website.md","api/evennia.web.website.forms.md","api/evennia.web.website.templatetags.md","api/evennia.web.website.templatetags.addclass.md","api/evennia.web.website.tests.md","api/evennia.web.website.urls.md","api/evennia.web.website.views.md","index.md","toc.md"],objects:{"":{evennia:[141,0,0,"-"]},"evennia.accounts":{accounts:[144,0,0,"-"],bots:[146,0,0,"-"],manager:[147,0,0,"-"],models:[148,0,0,"-"]},"evennia.accounts.accounts":{DefaultAccount:[144,1,1,""],DefaultGuest:[144,1,1,""]},"evennia.accounts.accounts.DefaultAccount":{"delete":[144,3,1,""],DoesNotExist:[144,2,1,""],MultipleObjectsReturned:[144,2,1,""],access:[144,3,1,""],at_access:[144,3,1,""],at_account_creation:[144,3,1,""],at_cmdset_get:[144,3,1,""],at_disconnect:[144,3,1,""],at_failed_login:[144,3,1,""],at_first_login:[144,3,1,""],at_first_save:[144,3,1,""],at_init:[144,3,1,""],at_look:[144,3,1,""],at_msg_receive:[144,3,1,""],at_msg_send:[144,3,1,""],at_password_change:[144,3,1,""],at_post_channel_msg:[144,3,1,""],at_post_disconnect:[144,3,1,""],at_post_login:[144,3,1,""],at_pre_channel_msg:[144,3,1,""],at_pre_login:[144,3,1,""],at_server_reload:[144,3,1,""],at_server_shutdown:[144,3,1,""],authenticate:[144,3,1,""],basetype_setup:[144,3,1,""],channel_msg:[144,3,1,""],character:[144,3,1,""],characters:[144,3,1,""],cmdset:[144,4,1,""],connection_time:[144,3,1,""],create:[144,3,1,""],create_character:[144,3,1,""],disconnect_session_from_account:[144,3,1,""],execute_cmd:[144,3,1,""],get_all_puppets:[144,3,1,""],get_display_name:[144,3,1,""],get_puppet:[144,3,1,""],get_username_validators:[144,3,1,""],idle_time:[144,3,1,""],is_banned:[144,3,1,""],msg:[144,3,1,""],nicks:[144,4,1,""],normalize_username:[144,3,1,""],objects:[144,4,1,""],options:[144,4,1,""],path:[144,4,1,""],puppet:[144,3,1,""],puppet_object:[144,3,1,""],scripts:[144,4,1,""],search:[144,3,1,""],sessions:[144,4,1,""],set_password:[144,3,1,""],typename:[144,4,1,""],unpuppet_all:[144,3,1,""],unpuppet_object:[144,3,1,""],validate_password:[144,3,1,""],validate_username:[144,3,1,""]},"evennia.accounts.accounts.DefaultGuest":{DoesNotExist:[144,2,1,""],MultipleObjectsReturned:[144,2,1,""],at_post_disconnect:[144,3,1,""],at_post_login:[144,3,1,""],at_server_shutdown:[144,3,1,""],authenticate:[144,3,1,""],create:[144,3,1,""],path:[144,4,1,""],typename:[144,4,1,""]},"evennia.accounts.bots":{Bot:[146,1,1,""],BotStarter:[146,1,1,""],GrapevineBot:[146,1,1,""],IRCBot:[146,1,1,""],RSSBot:[146,1,1,""]},"evennia.accounts.bots.Bot":{DoesNotExist:[146,2,1,""],MultipleObjectsReturned:[146,2,1,""],at_server_shutdown:[146,3,1,""],basetype_setup:[146,3,1,""],execute_cmd:[146,3,1,""],msg:[146,3,1,""],path:[146,4,1,""],start:[146,3,1,""],typename:[146,4,1,""]},"evennia.accounts.bots.BotStarter":{DoesNotExist:[146,2,1,""],MultipleObjectsReturned:[146,2,1,""],at_repeat:[146,3,1,""],at_script_creation:[146,3,1,""],at_server_reload:[146,3,1,""],at_server_shutdown:[146,3,1,""],at_start:[146,3,1,""],path:[146,4,1,""],typename:[146,4,1,""]},"evennia.accounts.bots.GrapevineBot":{DoesNotExist:[146,2,1,""],MultipleObjectsReturned:[146,2,1,""],at_msg_send:[146,3,1,""],execute_cmd:[146,3,1,""],factory_path:[146,4,1,""],msg:[146,3,1,""],path:[146,4,1,""],start:[146,3,1,""],typename:[146,4,1,""]},"evennia.accounts.bots.IRCBot":{DoesNotExist:[146,2,1,""],MultipleObjectsReturned:[146,2,1,""],at_msg_send:[146,3,1,""],execute_cmd:[146,3,1,""],factory_path:[146,4,1,""],get_nicklist:[146,3,1,""],msg:[146,3,1,""],path:[146,4,1,""],ping:[146,3,1,""],reconnect:[146,3,1,""],start:[146,3,1,""],typename:[146,4,1,""]},"evennia.accounts.bots.RSSBot":{DoesNotExist:[146,2,1,""],MultipleObjectsReturned:[146,2,1,""],execute_cmd:[146,3,1,""],path:[146,4,1,""],start:[146,3,1,""],typename:[146,4,1,""]},"evennia.accounts.manager":{AccountDBManager:[147,1,1,""],AccountManager:[147,1,1,""]},"evennia.accounts.manager.AccountDBManager":{account_search:[147,3,1,""],create_account:[147,3,1,""],get_account_from_email:[147,3,1,""],get_account_from_name:[147,3,1,""],get_account_from_uid:[147,3,1,""],get_connected_accounts:[147,3,1,""],get_recently_connected_accounts:[147,3,1,""],get_recently_created_accounts:[147,3,1,""],num_total_accounts:[147,3,1,""],search_account:[147,3,1,""]},"evennia.accounts.models":{AccountDB:[148,1,1,""]},"evennia.accounts.models.AccountDB":{DoesNotExist:[148,2,1,""],MultipleObjectsReturned:[148,2,1,""],account_subscription_set:[148,4,1,""],cmdset_storage:[148,3,1,""],db_attributes:[148,4,1,""],db_cmdset_storage:[148,4,1,""],db_is_bot:[148,4,1,""],db_is_connected:[148,4,1,""],db_tags:[148,4,1,""],get_next_by_date_joined:[148,3,1,""],get_next_by_db_date_created:[148,3,1,""],get_previous_by_date_joined:[148,3,1,""],get_previous_by_db_date_created:[148,3,1,""],groups:[148,4,1,""],hide_from_accounts_set:[148,4,1,""],id:[148,4,1,""],is_bot:[148,3,1,""],is_connected:[148,3,1,""],key:[148,3,1,""],logentry_set:[148,4,1,""],name:[148,3,1,""],objectdb_set:[148,4,1,""],objects:[148,4,1,""],path:[148,4,1,""],receiver_account_set:[148,4,1,""],scriptdb_set:[148,4,1,""],sender_account_set:[148,4,1,""],typename:[148,4,1,""],uid:[148,3,1,""],user_permissions:[148,4,1,""]},"evennia.commands":{"default":[155,0,0,"-"],cmdhandler:[150,0,0,"-"],cmdparser:[151,0,0,"-"],cmdset:[152,0,0,"-"],cmdsethandler:[153,0,0,"-"],command:[154,0,0,"-"]},"evennia.commands.cmdhandler":{InterruptCommand:[150,2,1,""],cmdhandler:[150,5,1,""]},"evennia.commands.cmdparser":{build_matches:[151,5,1,""],cmdparser:[151,5,1,""],create_match:[151,5,1,""],try_num_differentiators:[151,5,1,""]},"evennia.commands.cmdset":{CmdSet:[152,1,1,""]},"evennia.commands.cmdset.CmdSet":{__init__:[152,3,1,""],add:[152,3,1,""],at_cmdset_creation:[152,3,1,""],count:[152,3,1,""],duplicates:[152,4,1,""],errmessage:[152,4,1,""],get:[152,3,1,""],get_all_cmd_keys_and_aliases:[152,3,1,""],get_system_cmds:[152,3,1,""],key:[152,4,1,""],key_mergetypes:[152,4,1,""],make_unique:[152,3,1,""],mergetype:[152,4,1,""],no_channels:[152,4,1,""],no_exits:[152,4,1,""],no_objs:[152,4,1,""],path:[152,4,1,""],persistent:[152,4,1,""],priority:[152,4,1,""],remove:[152,3,1,""],to_duplicate:[152,4,1,""]},"evennia.commands.cmdsethandler":{CmdSetHandler:[153,1,1,""],import_cmdset:[153,5,1,""]},"evennia.commands.cmdsethandler.CmdSetHandler":{"delete":[153,3,1,""],__init__:[153,3,1,""],add:[153,3,1,""],add_default:[153,3,1,""],all:[153,3,1,""],clear:[153,3,1,""],delete_default:[153,3,1,""],get:[153,3,1,""],has:[153,3,1,""],has_cmdset:[153,3,1,""],remove:[153,3,1,""],remove_default:[153,3,1,""],reset:[153,3,1,""],update:[153,3,1,""]},"evennia.commands.command":{Command:[154,1,1,""],CommandMeta:[154,1,1,""],InterruptCommand:[154,2,1,""]},"evennia.commands.command.Command":{__init__:[154,3,1,""],access:[154,3,1,""],aliases:[154,4,1,""],arg_regex:[154,4,1,""],at_post_cmd:[154,3,1,""],at_pre_cmd:[154,3,1,""],auto_help:[154,4,1,""],client_width:[154,3,1,""],execute_cmd:[154,3,1,""],func:[154,3,1,""],get_command_info:[154,3,1,""],get_extra_info:[154,3,1,""],get_help:[154,3,1,""],help_category:[154,4,1,""],is_exit:[154,4,1,""],key:[154,4,1,""],lock_storage:[154,4,1,""],lockhandler:[154,4,1,""],locks:[154,4,1,""],match:[154,3,1,""],msg:[154,3,1,""],msg_all_sessions:[154,4,1,""],parse:[154,3,1,""],retain_instance:[154,4,1,""],save_for_next:[154,4,1,""],search_index_entry:[154,4,1,""],set_aliases:[154,3,1,""],set_key:[154,3,1,""],styled_footer:[154,3,1,""],styled_header:[154,3,1,""],styled_separator:[154,3,1,""],styled_table:[154,3,1,""],web_get_admin_url:[154,3,1,""],web_get_detail_url:[154,3,1,""]},"evennia.commands.command.CommandMeta":{__init__:[154,3,1,""]},"evennia.commands.default":{account:[156,0,0,"-"],admin:[157,0,0,"-"],batchprocess:[158,0,0,"-"],building:[159,0,0,"-"],cmdset_account:[160,0,0,"-"],cmdset_character:[161,0,0,"-"],cmdset_session:[162,0,0,"-"],cmdset_unloggedin:[163,0,0,"-"],comms:[164,0,0,"-"],general:[165,0,0,"-"],help:[166,0,0,"-"],muxcommand:[167,0,0,"-"],syscommands:[168,0,0,"-"],system:[169,0,0,"-"],unloggedin:[171,0,0,"-"]},"evennia.commands.default.account":{CmdCharCreate:[156,1,1,""],CmdCharDelete:[156,1,1,""],CmdColorTest:[156,1,1,""],CmdIC:[156,1,1,""],CmdOOC:[156,1,1,""],CmdOOCLook:[156,1,1,""],CmdOption:[156,1,1,""],CmdPassword:[156,1,1,""],CmdQuell:[156,1,1,""],CmdQuit:[156,1,1,""],CmdSessions:[156,1,1,""],CmdStyle:[156,1,1,""],CmdWho:[156,1,1,""]},"evennia.commands.default.account.CmdCharCreate":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""]},"evennia.commands.default.account.CmdCharDelete":{aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""]},"evennia.commands.default.account.CmdColorTest":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""],slice_bright_bg:[156,4,1,""],slice_bright_fg:[156,4,1,""],slice_dark_bg:[156,4,1,""],slice_dark_fg:[156,4,1,""],table_format:[156,3,1,""]},"evennia.commands.default.account.CmdIC":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""]},"evennia.commands.default.account.CmdOOC":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""]},"evennia.commands.default.account.CmdOOCLook":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""]},"evennia.commands.default.account.CmdOption":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""],switch_options:[156,4,1,""]},"evennia.commands.default.account.CmdPassword":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""]},"evennia.commands.default.account.CmdQuell":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""]},"evennia.commands.default.account.CmdQuit":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""],switch_options:[156,4,1,""]},"evennia.commands.default.account.CmdSessions":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""]},"evennia.commands.default.account.CmdStyle":{aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],list_styles:[156,3,1,""],lock_storage:[156,4,1,""],search_index_entry:[156,4,1,""],set:[156,3,1,""],switch_options:[156,4,1,""]},"evennia.commands.default.account.CmdWho":{account_caller:[156,4,1,""],aliases:[156,4,1,""],func:[156,3,1,""],help_category:[156,4,1,""],key:[156,4,1,""],lock_storage:[156,4,1,""],locks:[156,4,1,""],search_index_entry:[156,4,1,""]},"evennia.commands.default.admin":{CmdBan:[157,1,1,""],CmdBoot:[157,1,1,""],CmdEmit:[157,1,1,""],CmdForce:[157,1,1,""],CmdNewPassword:[157,1,1,""],CmdPerm:[157,1,1,""],CmdUnban:[157,1,1,""],CmdWall:[157,1,1,""]},"evennia.commands.default.admin.CmdBan":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""],search_index_entry:[157,4,1,""]},"evennia.commands.default.admin.CmdBoot":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""],search_index_entry:[157,4,1,""],switch_options:[157,4,1,""]},"evennia.commands.default.admin.CmdEmit":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""],search_index_entry:[157,4,1,""],switch_options:[157,4,1,""]},"evennia.commands.default.admin.CmdForce":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""],perm_used:[157,4,1,""],search_index_entry:[157,4,1,""]},"evennia.commands.default.admin.CmdNewPassword":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""],search_index_entry:[157,4,1,""]},"evennia.commands.default.admin.CmdPerm":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""],search_index_entry:[157,4,1,""],switch_options:[157,4,1,""]},"evennia.commands.default.admin.CmdUnban":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""],search_index_entry:[157,4,1,""]},"evennia.commands.default.admin.CmdWall":{aliases:[157,4,1,""],func:[157,3,1,""],help_category:[157,4,1,""],key:[157,4,1,""],lock_storage:[157,4,1,""],locks:[157,4,1,""],search_index_entry:[157,4,1,""]},"evennia.commands.default.batchprocess":{CmdBatchCode:[158,1,1,""],CmdBatchCommands:[158,1,1,""]},"evennia.commands.default.batchprocess.CmdBatchCode":{aliases:[158,4,1,""],func:[158,3,1,""],help_category:[158,4,1,""],key:[158,4,1,""],lock_storage:[158,4,1,""],locks:[158,4,1,""],search_index_entry:[158,4,1,""],switch_options:[158,4,1,""]},"evennia.commands.default.batchprocess.CmdBatchCommands":{aliases:[158,4,1,""],func:[158,3,1,""],help_category:[158,4,1,""],key:[158,4,1,""],lock_storage:[158,4,1,""],locks:[158,4,1,""],search_index_entry:[158,4,1,""],switch_options:[158,4,1,""]},"evennia.commands.default.building":{CmdCopy:[159,1,1,""],CmdCpAttr:[159,1,1,""],CmdCreate:[159,1,1,""],CmdDesc:[159,1,1,""],CmdDestroy:[159,1,1,""],CmdDig:[159,1,1,""],CmdExamine:[159,1,1,""],CmdFind:[159,1,1,""],CmdLink:[159,1,1,""],CmdListCmdSets:[159,1,1,""],CmdLock:[159,1,1,""],CmdMvAttr:[159,1,1,""],CmdName:[159,1,1,""],CmdObjects:[159,1,1,""],CmdOpen:[159,1,1,""],CmdScripts:[159,1,1,""],CmdSetAttribute:[159,1,1,""],CmdSetHome:[159,1,1,""],CmdSetObjAlias:[159,1,1,""],CmdSpawn:[159,1,1,""],CmdTag:[159,1,1,""],CmdTeleport:[159,1,1,""],CmdTunnel:[159,1,1,""],CmdTypeclass:[159,1,1,""],CmdUnLink:[159,1,1,""],CmdWipe:[159,1,1,""],ObjManipCommand:[159,1,1,""]},"evennia.commands.default.building.CmdCopy":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.building.CmdCpAttr":{aliases:[159,4,1,""],check_from_attr:[159,3,1,""],check_has_attr:[159,3,1,""],check_to_attr:[159,3,1,""],func:[159,3,1,""],get_attr:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdCreate":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],new_obj_lockstring:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdDesc":{aliases:[159,4,1,""],edit_handler:[159,3,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdDestroy":{aliases:[159,4,1,""],confirm:[159,4,1,""],default_confirm:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdDig":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],new_room_lockstring:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdExamine":{aliases:[159,4,1,""],arg_regex:[159,4,1,""],detail_color:[159,4,1,""],format_account_key:[159,3,1,""],format_account_permissions:[159,3,1,""],format_account_typeclass:[159,3,1,""],format_aliases:[159,3,1,""],format_attributes:[159,3,1,""],format_channel_account_subs:[159,3,1,""],format_channel_object_subs:[159,3,1,""],format_channel_sub_totals:[159,3,1,""],format_chars:[159,3,1,""],format_current_cmds:[159,3,1,""],format_destination:[159,3,1,""],format_email:[159,3,1,""],format_exits:[159,3,1,""],format_home:[159,3,1,""],format_key:[159,3,1,""],format_location:[159,3,1,""],format_locks:[159,3,1,""],format_merged_cmdsets:[159,3,1,""],format_nattributes:[159,3,1,""],format_output:[159,3,1,""],format_permissions:[159,3,1,""],format_script_desc:[159,3,1,""],format_script_is_persistent:[159,3,1,""],format_script_timer_data:[159,3,1,""],format_scripts:[159,3,1,""],format_sessions:[159,3,1,""],format_single_attribute:[159,3,1,""],format_single_attribute_detail:[159,3,1,""],format_single_cmdset:[159,3,1,""],format_single_cmdset_options:[159,3,1,""],format_single_tag:[159,3,1,""],format_stored_cmdsets:[159,3,1,""],format_tags:[159,3,1,""],format_things:[159,3,1,""],format_typeclass:[159,3,1,""],func:[159,3,1,""],get_formatted_obj_data:[159,3,1,""],header_color:[159,4,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],msg:[159,3,1,""],object_type:[159,4,1,""],parse:[159,3,1,""],quell_color:[159,4,1,""],search_index_entry:[159,4,1,""],separator:[159,4,1,""],switch_options:[159,4,1,""],text:[159,4,1,""]},"evennia.commands.default.building.CmdFind":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdLink":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.building.CmdListCmdSets":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.building.CmdLock":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.building.CmdMvAttr":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdName":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.building.CmdObjects":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.building.CmdOpen":{aliases:[159,4,1,""],create_exit:[159,3,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],new_obj_lockstring:[159,4,1,""],parse:[159,3,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.building.CmdScripts":{aliases:[159,4,1,""],excluded_typeclass_paths:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""],switch_mapping:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdSetAttribute":{aliases:[159,4,1,""],check_attr:[159,3,1,""],check_obj:[159,3,1,""],do_nested_lookup:[159,3,1,""],edit_handler:[159,3,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],nested_re:[159,4,1,""],not_found:[159,4,1,""],rm_attr:[159,3,1,""],search_for_obj:[159,3,1,""],search_index_entry:[159,4,1,""],set_attr:[159,3,1,""],split_nested_attr:[159,3,1,""],view_attr:[159,3,1,""]},"evennia.commands.default.building.CmdSetHome":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.building.CmdSetObjAlias":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdSpawn":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdTag":{aliases:[159,4,1,""],arg_regex:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],options:[159,4,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.building.CmdTeleport":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],parse:[159,3,1,""],rhs_split:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdTunnel":{aliases:[159,4,1,""],directions:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdTypeclass":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""],switch_options:[159,4,1,""]},"evennia.commands.default.building.CmdUnLink":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],help_key:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.building.CmdWipe":{aliases:[159,4,1,""],func:[159,3,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],locks:[159,4,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.building.ObjManipCommand":{aliases:[159,4,1,""],help_category:[159,4,1,""],key:[159,4,1,""],lock_storage:[159,4,1,""],parse:[159,3,1,""],search_index_entry:[159,4,1,""]},"evennia.commands.default.cmdset_account":{AccountCmdSet:[160,1,1,""]},"evennia.commands.default.cmdset_account.AccountCmdSet":{at_cmdset_creation:[160,3,1,""],key:[160,4,1,""],path:[160,4,1,""],priority:[160,4,1,""]},"evennia.commands.default.cmdset_character":{CharacterCmdSet:[161,1,1,""]},"evennia.commands.default.cmdset_character.CharacterCmdSet":{at_cmdset_creation:[161,3,1,""],key:[161,4,1,""],path:[161,4,1,""],priority:[161,4,1,""]},"evennia.commands.default.cmdset_session":{SessionCmdSet:[162,1,1,""]},"evennia.commands.default.cmdset_session.SessionCmdSet":{at_cmdset_creation:[162,3,1,""],key:[162,4,1,""],path:[162,4,1,""],priority:[162,4,1,""]},"evennia.commands.default.cmdset_unloggedin":{UnloggedinCmdSet:[163,1,1,""]},"evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet":{at_cmdset_creation:[163,3,1,""],key:[163,4,1,""],path:[163,4,1,""],priority:[163,4,1,""]},"evennia.commands.default.comms":{CmdChannel:[164,1,1,""],CmdGrapevine2Chan:[164,1,1,""],CmdIRC2Chan:[164,1,1,""],CmdIRCStatus:[164,1,1,""],CmdObjectChannel:[164,1,1,""],CmdPage:[164,1,1,""],CmdRSS2Chan:[164,1,1,""]},"evennia.commands.default.comms.CmdChannel":{account_caller:[164,4,1,""],add_alias:[164,3,1,""],aliases:[164,4,1,""],ban_user:[164,3,1,""],boot_user:[164,3,1,""],channel_list_bans:[164,3,1,""],channel_list_who:[164,3,1,""],create_channel:[164,3,1,""],destroy_channel:[164,3,1,""],display_all_channels:[164,3,1,""],display_subbed_channels:[164,3,1,""],func:[164,3,1,""],get_channel_aliases:[164,3,1,""],get_channel_history:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],list_channels:[164,3,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],msg_channel:[164,3,1,""],mute_channel:[164,3,1,""],remove_alias:[164,3,1,""],search_channel:[164,3,1,""],search_index_entry:[164,4,1,""],set_desc:[164,3,1,""],set_lock:[164,3,1,""],sub_to_channel:[164,3,1,""],switch_options:[164,4,1,""],unban_user:[164,3,1,""],unmute_channel:[164,3,1,""],unset_lock:[164,3,1,""],unsub_from_channel:[164,3,1,""]},"evennia.commands.default.comms.CmdGrapevine2Chan":{aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],search_index_entry:[164,4,1,""],switch_options:[164,4,1,""]},"evennia.commands.default.comms.CmdIRC2Chan":{aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],search_index_entry:[164,4,1,""],switch_options:[164,4,1,""]},"evennia.commands.default.comms.CmdIRCStatus":{aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],search_index_entry:[164,4,1,""]},"evennia.commands.default.comms.CmdObjectChannel":{account_caller:[164,4,1,""],aliases:[164,4,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],search_index_entry:[164,4,1,""]},"evennia.commands.default.comms.CmdPage":{account_caller:[164,4,1,""],aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],search_index_entry:[164,4,1,""],switch_options:[164,4,1,""]},"evennia.commands.default.comms.CmdRSS2Chan":{aliases:[164,4,1,""],func:[164,3,1,""],help_category:[164,4,1,""],key:[164,4,1,""],lock_storage:[164,4,1,""],locks:[164,4,1,""],search_index_entry:[164,4,1,""],switch_options:[164,4,1,""]},"evennia.commands.default.general":{CmdAccess:[165,1,1,""],CmdDrop:[165,1,1,""],CmdGet:[165,1,1,""],CmdGive:[165,1,1,""],CmdHome:[165,1,1,""],CmdInventory:[165,1,1,""],CmdLook:[165,1,1,""],CmdNick:[165,1,1,""],CmdPose:[165,1,1,""],CmdSay:[165,1,1,""],CmdSetDesc:[165,1,1,""],CmdWhisper:[165,1,1,""]},"evennia.commands.default.general.CmdAccess":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],search_index_entry:[165,4,1,""]},"evennia.commands.default.general.CmdDrop":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],search_index_entry:[165,4,1,""]},"evennia.commands.default.general.CmdGet":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],search_index_entry:[165,4,1,""]},"evennia.commands.default.general.CmdGive":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],rhs_split:[165,4,1,""],search_index_entry:[165,4,1,""]},"evennia.commands.default.general.CmdHome":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],search_index_entry:[165,4,1,""]},"evennia.commands.default.general.CmdInventory":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],search_index_entry:[165,4,1,""]},"evennia.commands.default.general.CmdLook":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],search_index_entry:[165,4,1,""]},"evennia.commands.default.general.CmdNick":{aliases:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],parse:[165,3,1,""],search_index_entry:[165,4,1,""],switch_options:[165,4,1,""]},"evennia.commands.default.general.CmdPose":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],parse:[165,3,1,""],search_index_entry:[165,4,1,""]},"evennia.commands.default.general.CmdSay":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],search_index_entry:[165,4,1,""]},"evennia.commands.default.general.CmdSetDesc":{aliases:[165,4,1,""],arg_regex:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],search_index_entry:[165,4,1,""]},"evennia.commands.default.general.CmdWhisper":{aliases:[165,4,1,""],func:[165,3,1,""],help_category:[165,4,1,""],key:[165,4,1,""],lock_storage:[165,4,1,""],locks:[165,4,1,""],search_index_entry:[165,4,1,""]},"evennia.commands.default.help":{CmdHelp:[166,1,1,""],CmdSetHelp:[166,1,1,""]},"evennia.commands.default.help.CmdHelp":{aliases:[166,4,1,""],arg_regex:[166,4,1,""],can_list_topic:[166,3,1,""],can_read_topic:[166,3,1,""],clickable_topics:[166,4,1,""],collect_topics:[166,3,1,""],do_search:[166,3,1,""],format_help_entry:[166,3,1,""],format_help_index:[166,3,1,""],func:[166,3,1,""],help_category:[166,4,1,""],help_more:[166,4,1,""],index_category_clr:[166,4,1,""],index_topic_clr:[166,4,1,""],index_type_separator_clr:[166,4,1,""],key:[166,4,1,""],lock_storage:[166,4,1,""],locks:[166,4,1,""],msg_help:[166,3,1,""],parse:[166,3,1,""],return_cmdset:[166,4,1,""],search_index_entry:[166,4,1,""],strip_cmd_prefix:[166,3,1,""],subtopic_separator_char:[166,4,1,""],suggestion_cutoff:[166,4,1,""],suggestion_maxnum:[166,4,1,""]},"evennia.commands.default.help.CmdSetHelp":{aliases:[166,4,1,""],arg_regex:[166,4,1,""],func:[166,3,1,""],help_category:[166,4,1,""],key:[166,4,1,""],lock_storage:[166,4,1,""],locks:[166,4,1,""],parse:[166,3,1,""],search_index_entry:[166,4,1,""],switch_options:[166,4,1,""]},"evennia.commands.default.muxcommand":{MuxAccountCommand:[167,1,1,""],MuxCommand:[167,1,1,""]},"evennia.commands.default.muxcommand.MuxAccountCommand":{account_caller:[167,4,1,""],aliases:[167,4,1,""],help_category:[167,4,1,""],key:[167,4,1,""],lock_storage:[167,4,1,""],search_index_entry:[167,4,1,""]},"evennia.commands.default.muxcommand.MuxCommand":{aliases:[167,4,1,""],at_post_cmd:[167,3,1,""],at_pre_cmd:[167,3,1,""],func:[167,3,1,""],get_command_info:[167,3,1,""],has_perm:[167,3,1,""],help_category:[167,4,1,""],key:[167,4,1,""],lock_storage:[167,4,1,""],parse:[167,3,1,""],search_index_entry:[167,4,1,""]},"evennia.commands.default.syscommands":{SystemMultimatch:[168,1,1,""],SystemNoInput:[168,1,1,""],SystemNoMatch:[168,1,1,""]},"evennia.commands.default.syscommands.SystemMultimatch":{aliases:[168,4,1,""],func:[168,3,1,""],help_category:[168,4,1,""],key:[168,4,1,""],lock_storage:[168,4,1,""],locks:[168,4,1,""],search_index_entry:[168,4,1,""]},"evennia.commands.default.syscommands.SystemNoInput":{aliases:[168,4,1,""],func:[168,3,1,""],help_category:[168,4,1,""],key:[168,4,1,""],lock_storage:[168,4,1,""],locks:[168,4,1,""],search_index_entry:[168,4,1,""]},"evennia.commands.default.syscommands.SystemNoMatch":{aliases:[168,4,1,""],func:[168,3,1,""],help_category:[168,4,1,""],key:[168,4,1,""],lock_storage:[168,4,1,""],locks:[168,4,1,""],search_index_entry:[168,4,1,""]},"evennia.commands.default.system":{CmdAbout:[169,1,1,""],CmdAccounts:[169,1,1,""],CmdPy:[169,1,1,""],CmdReload:[169,1,1,""],CmdReset:[169,1,1,""],CmdServerLoad:[169,1,1,""],CmdService:[169,1,1,""],CmdShutdown:[169,1,1,""],CmdTasks:[169,1,1,""],CmdTickers:[169,1,1,""],CmdTime:[169,1,1,""]},"evennia.commands.default.system.CmdAbout":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],search_index_entry:[169,4,1,""]},"evennia.commands.default.system.CmdAccounts":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],search_index_entry:[169,4,1,""],switch_options:[169,4,1,""]},"evennia.commands.default.system.CmdPy":{aliases:[169,4,1,""],arg_regex:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],search_index_entry:[169,4,1,""],switch_options:[169,4,1,""]},"evennia.commands.default.system.CmdReload":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],search_index_entry:[169,4,1,""]},"evennia.commands.default.system.CmdReset":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],search_index_entry:[169,4,1,""]},"evennia.commands.default.system.CmdServerLoad":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],search_index_entry:[169,4,1,""],switch_options:[169,4,1,""]},"evennia.commands.default.system.CmdService":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],search_index_entry:[169,4,1,""],switch_options:[169,4,1,""]},"evennia.commands.default.system.CmdShutdown":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],search_index_entry:[169,4,1,""]},"evennia.commands.default.system.CmdTasks":{aliases:[169,4,1,""],coll_date_func:[169,3,1,""],do_task_action:[169,3,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],search_index_entry:[169,4,1,""],switch_options:[169,4,1,""]},"evennia.commands.default.system.CmdTickers":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],search_index_entry:[169,4,1,""]},"evennia.commands.default.system.CmdTime":{aliases:[169,4,1,""],func:[169,3,1,""],help_category:[169,4,1,""],key:[169,4,1,""],lock_storage:[169,4,1,""],locks:[169,4,1,""],search_index_entry:[169,4,1,""]},"evennia.commands.default.tests":{CmdInterrupt:[170,1,1,""],TestAccount:[170,1,1,""],TestAdmin:[170,1,1,""],TestBatchProcess:[170,1,1,""],TestBuilding:[170,1,1,""],TestCmdTasks:[170,1,1,""],TestComms:[170,1,1,""],TestCommsChannel:[170,1,1,""],TestGeneral:[170,1,1,""],TestHelp:[170,1,1,""],TestInterruptCommand:[170,1,1,""],TestSystem:[170,1,1,""],TestSystemCommands:[170,1,1,""],TestUnconnectedCommand:[170,1,1,""],func_test_cmd_tasks:[170,5,1,""]},"evennia.commands.default.tests.CmdInterrupt":{aliases:[170,4,1,""],func:[170,3,1,""],help_category:[170,4,1,""],key:[170,4,1,""],lock_storage:[170,4,1,""],parse:[170,3,1,""],search_index_entry:[170,4,1,""]},"evennia.commands.default.tests.TestAccount":{test_char_create:[170,3,1,""],test_char_delete:[170,3,1,""],test_color_test:[170,3,1,""],test_ic:[170,3,1,""],test_ic__nonaccess:[170,3,1,""],test_ic__other_object:[170,3,1,""],test_ooc:[170,3,1,""],test_ooc_look:[170,3,1,""],test_option:[170,3,1,""],test_password:[170,3,1,""],test_quell:[170,3,1,""],test_quit:[170,3,1,""],test_sessions:[170,3,1,""],test_who:[170,3,1,""]},"evennia.commands.default.tests.TestAdmin":{test_ban:[170,3,1,""],test_emit:[170,3,1,""],test_force:[170,3,1,""],test_perm:[170,3,1,""],test_wall:[170,3,1,""]},"evennia.commands.default.tests.TestBatchProcess":{red_button:[170,4,1,""],test_batch_commands:[170,3,1,""]},"evennia.commands.default.tests.TestBuilding":{test_attribute_commands:[170,3,1,""],test_copy:[170,3,1,""],test_create:[170,3,1,""],test_desc:[170,3,1,""],test_desc_default_to_room:[170,3,1,""],test_destroy:[170,3,1,""],test_destroy_sequence:[170,3,1,""],test_dig:[170,3,1,""],test_do_nested_lookup:[170,3,1,""],test_empty_desc:[170,3,1,""],test_examine:[170,3,1,""],test_exit_commands:[170,3,1,""],test_find:[170,3,1,""],test_list_cmdsets:[170,3,1,""],test_lock:[170,3,1,""],test_name:[170,3,1,""],test_nested_attribute_commands:[170,3,1,""],test_script:[170,3,1,""],test_script_multi_delete:[170,3,1,""],test_set_home:[170,3,1,""],test_set_obj_alias:[170,3,1,""],test_spawn:[170,3,1,""],test_split_nested_attr:[170,3,1,""],test_tag:[170,3,1,""],test_teleport:[170,3,1,""],test_tunnel:[170,3,1,""],test_tunnel_exit_typeclass:[170,3,1,""],test_typeclass:[170,3,1,""]},"evennia.commands.default.tests.TestCmdTasks":{setUp:[170,3,1,""],tearDown:[170,3,1,""],test_active_task:[170,3,1,""],test_call:[170,3,1,""],test_cancel:[170,3,1,""],test_do_task:[170,3,1,""],test_func_name_manipulation:[170,3,1,""],test_misformed_command:[170,3,1,""],test_new_task_waiting_input:[170,3,1,""],test_no_input:[170,3,1,""],test_no_tasks:[170,3,1,""],test_pause_unpause:[170,3,1,""],test_persistent_task:[170,3,1,""],test_remove:[170,3,1,""],test_responce_of_yes:[170,3,1,""],test_task_complete_waiting_input:[170,3,1,""],test_wrong_func_name:[170,3,1,""]},"evennia.commands.default.tests.TestComms":{test_page:[170,3,1,""]},"evennia.commands.default.tests.TestCommsChannel":{setUp:[170,3,1,""],tearDown:[170,3,1,""],test_channel__alias__unalias:[170,3,1,""],test_channel__all:[170,3,1,""],test_channel__ban__unban:[170,3,1,""],test_channel__boot:[170,3,1,""],test_channel__create:[170,3,1,""],test_channel__desc:[170,3,1,""],test_channel__destroy:[170,3,1,""],test_channel__history:[170,3,1,""],test_channel__list:[170,3,1,""],test_channel__lock:[170,3,1,""],test_channel__msg:[170,3,1,""],test_channel__mute:[170,3,1,""],test_channel__noarg:[170,3,1,""],test_channel__sub:[170,3,1,""],test_channel__unlock:[170,3,1,""],test_channel__unmute:[170,3,1,""],test_channel__unsub:[170,3,1,""],test_channel__who:[170,3,1,""]},"evennia.commands.default.tests.TestGeneral":{test_access:[170,3,1,""],test_get_and_drop:[170,3,1,""],test_give:[170,3,1,""],test_home:[170,3,1,""],test_inventory:[170,3,1,""],test_look:[170,3,1,""],test_mux_command:[170,3,1,""],test_nick:[170,3,1,""],test_pose:[170,3,1,""],test_say:[170,3,1,""],test_whisper:[170,3,1,""]},"evennia.commands.default.tests.TestHelp":{maxDiff:[170,4,1,""],setUp:[170,3,1,""],tearDown:[170,3,1,""],test_help:[170,3,1,""],test_set_help:[170,3,1,""],test_subtopic_fetch:[170,4,1,""],test_subtopic_fetch_00_test:[170,3,1,""],test_subtopic_fetch_01_test_creating_extra_stuff:[170,3,1,""],test_subtopic_fetch_02_test_creating:[170,3,1,""],test_subtopic_fetch_03_test_extra:[170,3,1,""],test_subtopic_fetch_04_test_extra_subsubtopic:[170,3,1,""],test_subtopic_fetch_05_test_creating_extra_subsub:[170,3,1,""],test_subtopic_fetch_06_test_Something_else:[170,3,1,""],test_subtopic_fetch_07_test_More:[170,3,1,""],test_subtopic_fetch_08_test_More_Second_more:[170,3,1,""],test_subtopic_fetch_09_test_More_more:[170,3,1,""],test_subtopic_fetch_10_test_more_second_more_again:[170,3,1,""],test_subtopic_fetch_11_test_more_second_third:[170,3,1,""]},"evennia.commands.default.tests.TestInterruptCommand":{test_interrupt_command:[170,3,1,""]},"evennia.commands.default.tests.TestSystem":{test_about:[170,3,1,""],test_objects:[170,3,1,""],test_py:[170,3,1,""],test_scripts:[170,3,1,""],test_server_load:[170,3,1,""]},"evennia.commands.default.tests.TestSystemCommands":{test_multimatch:[170,3,1,""],test_simple_defaults:[170,3,1,""]},"evennia.commands.default.tests.TestUnconnectedCommand":{test_info_command:[170,3,1,""]},"evennia.commands.default.unloggedin":{CmdUnconnectedConnect:[171,1,1,""],CmdUnconnectedCreate:[171,1,1,""],CmdUnconnectedEncoding:[171,1,1,""],CmdUnconnectedHelp:[171,1,1,""],CmdUnconnectedInfo:[171,1,1,""],CmdUnconnectedLook:[171,1,1,""],CmdUnconnectedQuit:[171,1,1,""],CmdUnconnectedScreenreader:[171,1,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedConnect":{aliases:[171,4,1,""],arg_regex:[171,4,1,""],func:[171,3,1,""],help_category:[171,4,1,""],key:[171,4,1,""],lock_storage:[171,4,1,""],locks:[171,4,1,""],search_index_entry:[171,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedCreate":{aliases:[171,4,1,""],arg_regex:[171,4,1,""],func:[171,3,1,""],help_category:[171,4,1,""],key:[171,4,1,""],lock_storage:[171,4,1,""],locks:[171,4,1,""],search_index_entry:[171,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedEncoding":{aliases:[171,4,1,""],func:[171,3,1,""],help_category:[171,4,1,""],key:[171,4,1,""],lock_storage:[171,4,1,""],locks:[171,4,1,""],search_index_entry:[171,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedHelp":{aliases:[171,4,1,""],func:[171,3,1,""],help_category:[171,4,1,""],key:[171,4,1,""],lock_storage:[171,4,1,""],locks:[171,4,1,""],search_index_entry:[171,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedInfo":{aliases:[171,4,1,""],func:[171,3,1,""],help_category:[171,4,1,""],key:[171,4,1,""],lock_storage:[171,4,1,""],locks:[171,4,1,""],search_index_entry:[171,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedLook":{aliases:[171,4,1,""],func:[171,3,1,""],help_category:[171,4,1,""],key:[171,4,1,""],lock_storage:[171,4,1,""],locks:[171,4,1,""],search_index_entry:[171,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedQuit":{aliases:[171,4,1,""],func:[171,3,1,""],help_category:[171,4,1,""],key:[171,4,1,""],lock_storage:[171,4,1,""],locks:[171,4,1,""],search_index_entry:[171,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedScreenreader":{aliases:[171,4,1,""],func:[171,3,1,""],help_category:[171,4,1,""],key:[171,4,1,""],lock_storage:[171,4,1,""],search_index_entry:[171,4,1,""]},"evennia.comms":{comms:[175,0,0,"-"],managers:[176,0,0,"-"],models:[177,0,0,"-"]},"evennia.comms.comms":{DefaultChannel:[175,1,1,""]},"evennia.comms.comms.DefaultChannel":{"delete":[175,3,1,""],DoesNotExist:[175,2,1,""],MultipleObjectsReturned:[175,2,1,""],access:[175,3,1,""],add_user_channel_alias:[175,3,1,""],at_channel_creation:[175,3,1,""],at_first_save:[175,3,1,""],at_init:[175,3,1,""],at_post_msg:[175,3,1,""],at_pre_msg:[175,3,1,""],ban:[175,3,1,""],banlist:[175,3,1,""],basetype_setup:[175,3,1,""],channel_msg_nick_pattern:[175,4,1,""],channel_msg_nick_replacement:[175,4,1,""],channel_prefix:[175,3,1,""],channel_prefix_string:[175,4,1,""],connect:[175,3,1,""],create:[175,3,1,""],disconnect:[175,3,1,""],distribute_message:[175,3,1,""],format_external:[175,3,1,""],format_message:[175,3,1,""],format_senders:[175,3,1,""],get_absolute_url:[175,3,1,""],get_log_filename:[175,3,1,""],has_connection:[175,3,1,""],log_file:[175,4,1,""],message_transform:[175,3,1,""],msg:[175,3,1,""],mute:[175,3,1,""],mutelist:[175,3,1,""],objects:[175,4,1,""],path:[175,4,1,""],pose_transform:[175,3,1,""],post_join_channel:[175,3,1,""],post_leave_channel:[175,3,1,""],post_send_message:[175,3,1,""],pre_join_channel:[175,3,1,""],pre_leave_channel:[175,3,1,""],pre_send_message:[175,3,1,""],remove_user_channel_alias:[175,3,1,""],send_to_online_only:[175,4,1,""],set_log_filename:[175,3,1,""],typename:[175,4,1,""],unban:[175,3,1,""],unmute:[175,3,1,""],web_get_admin_url:[175,3,1,""],web_get_create_url:[175,3,1,""],web_get_delete_url:[175,3,1,""],web_get_detail_url:[175,3,1,""],web_get_update_url:[175,3,1,""],wholist:[175,3,1,""]},"evennia.comms.managers":{ChannelDBManager:[176,1,1,""],ChannelManager:[176,1,1,""],CommError:[176,2,1,""],MsgManager:[176,1,1,""],identify_object:[176,5,1,""],to_object:[176,5,1,""]},"evennia.comms.managers.ChannelDBManager":{channel_search:[176,3,1,""],create_channel:[176,3,1,""],get_all_channels:[176,3,1,""],get_channel:[176,3,1,""],get_subscriptions:[176,3,1,""],search_channel:[176,3,1,""]},"evennia.comms.managers.MsgManager":{create_message:[176,3,1,""],get_message_by_id:[176,3,1,""],get_messages_by_receiver:[176,3,1,""],get_messages_by_sender:[176,3,1,""],identify_object:[176,3,1,""],message_search:[176,3,1,""],search_message:[176,3,1,""]},"evennia.comms.models":{ChannelDB:[177,1,1,""],Msg:[177,1,1,""],SubscriptionHandler:[177,1,1,""],TempMsg:[177,1,1,""]},"evennia.comms.models.ChannelDB":{DoesNotExist:[177,2,1,""],MultipleObjectsReturned:[177,2,1,""],db_account_subscriptions:[177,4,1,""],db_attributes:[177,4,1,""],db_object_subscriptions:[177,4,1,""],db_tags:[177,4,1,""],get_next_by_db_date_created:[177,3,1,""],get_previous_by_db_date_created:[177,3,1,""],id:[177,4,1,""],objects:[177,4,1,""],path:[177,4,1,""],subscriptions:[177,4,1,""],typename:[177,4,1,""]},"evennia.comms.models.Msg":{DoesNotExist:[177,2,1,""],MultipleObjectsReturned:[177,2,1,""],access:[177,3,1,""],date_created:[177,3,1,""],db_date_created:[177,4,1,""],db_header:[177,4,1,""],db_hide_from_accounts:[177,4,1,""],db_hide_from_objects:[177,4,1,""],db_lock_storage:[177,4,1,""],db_message:[177,4,1,""],db_receiver_external:[177,4,1,""],db_receivers_accounts:[177,4,1,""],db_receivers_objects:[177,4,1,""],db_receivers_scripts:[177,4,1,""],db_sender_accounts:[177,4,1,""],db_sender_external:[177,4,1,""],db_sender_objects:[177,4,1,""],db_sender_scripts:[177,4,1,""],db_tags:[177,4,1,""],get_next_by_db_date_created:[177,3,1,""],get_previous_by_db_date_created:[177,3,1,""],header:[177,3,1,""],hide_from:[177,3,1,""],id:[177,4,1,""],lock_storage:[177,3,1,""],locks:[177,4,1,""],message:[177,3,1,""],objects:[177,4,1,""],path:[177,4,1,""],receiver_external:[177,3,1,""],receivers:[177,3,1,""],remove_receiver:[177,3,1,""],remove_sender:[177,3,1,""],sender_external:[177,3,1,""],senders:[177,3,1,""],tags:[177,4,1,""],typename:[177,4,1,""]},"evennia.comms.models.SubscriptionHandler":{__init__:[177,3,1,""],add:[177,3,1,""],all:[177,3,1,""],clear:[177,3,1,""],get:[177,3,1,""],has:[177,3,1,""],online:[177,3,1,""],remove:[177,3,1,""]},"evennia.comms.models.TempMsg":{__init__:[177,3,1,""],access:[177,3,1,""],locks:[177,4,1,""],remove_receiver:[177,3,1,""],remove_sender:[177,3,1,""]},"evennia.help":{manager:[238,0,0,"-"],models:[239,0,0,"-"]},"evennia.help.manager":{HelpEntryManager:[238,1,1,""]},"evennia.help.manager.HelpEntryManager":{all_to_category:[238,3,1,""],create_help:[238,3,1,""],find_apropos:[238,3,1,""],find_topicmatch:[238,3,1,""],find_topics_with_category:[238,3,1,""],find_topicsuggestions:[238,3,1,""],get_all_categories:[238,3,1,""],get_all_topics:[238,3,1,""],search_help:[238,3,1,""]},"evennia.help.models":{HelpEntry:[239,1,1,""]},"evennia.help.models.HelpEntry":{DoesNotExist:[239,2,1,""],MultipleObjectsReturned:[239,2,1,""],access:[239,3,1,""],aliases:[239,4,1,""],date_created:[239,3,1,""],db_date_created:[239,4,1,""],db_entrytext:[239,4,1,""],db_help_category:[239,4,1,""],db_key:[239,4,1,""],db_lock_storage:[239,4,1,""],db_tags:[239,4,1,""],entrytext:[239,3,1,""],get_absolute_url:[239,3,1,""],get_next_by_db_date_created:[239,3,1,""],get_previous_by_db_date_created:[239,3,1,""],help_category:[239,3,1,""],id:[239,4,1,""],key:[239,3,1,""],lock_storage:[239,3,1,""],locks:[239,4,1,""],objects:[239,4,1,""],path:[239,4,1,""],search_index_entry:[239,3,1,""],tags:[239,4,1,""],typename:[239,4,1,""],web_get_admin_url:[239,3,1,""],web_get_create_url:[239,3,1,""],web_get_delete_url:[239,3,1,""],web_get_detail_url:[239,3,1,""],web_get_update_url:[239,3,1,""]},"evennia.locks":{lockfuncs:[241,0,0,"-"],lockhandler:[242,0,0,"-"]},"evennia.locks.lockfuncs":{"false":[241,5,1,""],"true":[241,5,1,""],all:[241,5,1,""],attr:[241,5,1,""],attr_eq:[241,5,1,""],attr_ge:[241,5,1,""],attr_gt:[241,5,1,""],attr_le:[241,5,1,""],attr_lt:[241,5,1,""],attr_ne:[241,5,1,""],dbref:[241,5,1,""],has_account:[241,5,1,""],holds:[241,5,1,""],id:[241,5,1,""],inside:[241,5,1,""],inside_rec:[241,5,1,""],locattr:[241,5,1,""],none:[241,5,1,""],objattr:[241,5,1,""],objlocattr:[241,5,1,""],objtag:[241,5,1,""],pdbref:[241,5,1,""],perm:[241,5,1,""],perm_above:[241,5,1,""],pid:[241,5,1,""],pperm:[241,5,1,""],pperm_above:[241,5,1,""],self:[241,5,1,""],serversetting:[241,5,1,""],superuser:[241,5,1,""],tag:[241,5,1,""]},"evennia.locks.lockhandler":{LockException:[242,2,1,""],LockHandler:[242,1,1,""]},"evennia.locks.lockhandler.LockHandler":{"delete":[242,3,1,""],__init__:[242,3,1,""],add:[242,3,1,""],all:[242,3,1,""],append:[242,3,1,""],cache_lock_bypass:[242,3,1,""],check:[242,3,1,""],check_lockstring:[242,3,1,""],clear:[242,3,1,""],get:[242,3,1,""],remove:[242,3,1,""],replace:[242,3,1,""],reset:[242,3,1,""],validate:[242,3,1,""]},"evennia.objects":{manager:[245,0,0,"-"],models:[246,0,0,"-"],objects:[247,0,0,"-"]},"evennia.objects.manager":{ObjectDBManager:[245,1,1,""],ObjectManager:[245,1,1,""]},"evennia.objects.manager.ObjectDBManager":{clear_all_sessids:[245,3,1,""],copy_object:[245,3,1,""],create_object:[245,3,1,""],get_contents:[245,3,1,""],get_object_with_account:[245,3,1,""],get_objs_with_attr:[245,3,1,""],get_objs_with_attr_value:[245,3,1,""],get_objs_with_db_property:[245,3,1,""],get_objs_with_db_property_value:[245,3,1,""],get_objs_with_key_and_typeclass:[245,3,1,""],get_objs_with_key_or_alias:[245,3,1,""],object_search:[245,3,1,""],search:[245,3,1,""],search_object:[245,3,1,""]},"evennia.objects.models":{ContentsHandler:[246,1,1,""],ObjectDB:[246,1,1,""]},"evennia.objects.models.ContentsHandler":{__init__:[246,3,1,""],add:[246,3,1,""],clear:[246,3,1,""],get:[246,3,1,""],init:[246,3,1,""],load:[246,3,1,""],remove:[246,3,1,""]},"evennia.objects.models.ObjectDB":{DoesNotExist:[246,2,1,""],MultipleObjectsReturned:[246,2,1,""],account:[246,3,1,""],at_db_location_postsave:[246,3,1,""],cmdset_storage:[246,3,1,""],contents_cache:[246,4,1,""],db_account:[246,4,1,""],db_account_id:[246,4,1,""],db_attributes:[246,4,1,""],db_cmdset_storage:[246,4,1,""],db_destination:[246,4,1,""],db_destination_id:[246,4,1,""],db_home:[246,4,1,""],db_home_id:[246,4,1,""],db_location:[246,4,1,""],db_location_id:[246,4,1,""],db_sessid:[246,4,1,""],db_tags:[246,4,1,""],destination:[246,3,1,""],destinations_set:[246,4,1,""],get_next_by_db_date_created:[246,3,1,""],get_previous_by_db_date_created:[246,3,1,""],hide_from_objects_set:[246,4,1,""],home:[246,3,1,""],homes_set:[246,4,1,""],id:[246,4,1,""],location:[246,3,1,""],locations_set:[246,4,1,""],object_subscription_set:[246,4,1,""],objects:[246,4,1,""],path:[246,4,1,""],receiver_object_set:[246,4,1,""],scriptdb_set:[246,4,1,""],sender_object_set:[246,4,1,""],sessid:[246,3,1,""],typename:[246,4,1,""]},"evennia.objects.objects":{DefaultCharacter:[247,1,1,""],DefaultExit:[247,1,1,""],DefaultObject:[247,1,1,""],DefaultRoom:[247,1,1,""],ExitCommand:[247,1,1,""],ObjectSessionHandler:[247,1,1,""]},"evennia.objects.objects.DefaultCharacter":{DoesNotExist:[247,2,1,""],MultipleObjectsReturned:[247,2,1,""],at_after_move:[247,3,1,""],at_post_move:[247,3,1,""],at_post_puppet:[247,3,1,""],at_post_unpuppet:[247,3,1,""],at_pre_puppet:[247,3,1,""],basetype_setup:[247,3,1,""],connection_time:[247,3,1,""],create:[247,3,1,""],idle_time:[247,3,1,""],lockstring:[247,4,1,""],normalize_name:[247,3,1,""],path:[247,4,1,""],typename:[247,4,1,""],validate_name:[247,3,1,""]},"evennia.objects.objects.DefaultExit":{DoesNotExist:[247,2,1,""],MultipleObjectsReturned:[247,2,1,""],at_cmdset_get:[247,3,1,""],at_failed_traverse:[247,3,1,""],at_init:[247,3,1,""],at_traverse:[247,3,1,""],basetype_setup:[247,3,1,""],create:[247,3,1,""],create_exit_cmdset:[247,3,1,""],exit_command:[247,4,1,""],lockstring:[247,4,1,""],path:[247,4,1,""],priority:[247,4,1,""],typename:[247,4,1,""]},"evennia.objects.objects.DefaultObject":{"delete":[247,3,1,""],DoesNotExist:[247,2,1,""],MultipleObjectsReturned:[247,2,1,""],access:[247,3,1,""],announce_move_from:[247,3,1,""],announce_move_to:[247,3,1,""],appearance_template:[247,4,1,""],at_access:[247,3,1,""],at_after_move:[247,3,1,""],at_after_traverse:[247,3,1,""],at_before_drop:[247,3,1,""],at_before_get:[247,3,1,""],at_before_give:[247,3,1,""],at_before_move:[247,3,1,""],at_before_say:[247,3,1,""],at_cmdset_get:[247,3,1,""],at_desc:[247,3,1,""],at_drop:[247,3,1,""],at_failed_traverse:[247,3,1,""],at_first_save:[247,3,1,""],at_get:[247,3,1,""],at_give:[247,3,1,""],at_init:[247,3,1,""],at_look:[247,3,1,""],at_msg_receive:[247,3,1,""],at_msg_send:[247,3,1,""],at_object_creation:[247,3,1,""],at_object_delete:[247,3,1,""],at_object_leave:[247,3,1,""],at_object_post_copy:[247,3,1,""],at_object_receive:[247,3,1,""],at_post_move:[247,3,1,""],at_post_puppet:[247,3,1,""],at_post_traverse:[247,3,1,""],at_post_unpuppet:[247,3,1,""],at_pre_drop:[247,3,1,""],at_pre_get:[247,3,1,""],at_pre_give:[247,3,1,""],at_pre_move:[247,3,1,""],at_pre_puppet:[247,3,1,""],at_pre_say:[247,3,1,""],at_pre_unpuppet:[247,3,1,""],at_say:[247,3,1,""],at_server_reload:[247,3,1,""],at_server_shutdown:[247,3,1,""],at_traverse:[247,3,1,""],basetype_posthook_setup:[247,3,1,""],basetype_setup:[247,3,1,""],clear_contents:[247,3,1,""],clear_exits:[247,3,1,""],cmdset:[247,4,1,""],contents:[247,3,1,""],contents_get:[247,3,1,""],contents_set:[247,3,1,""],copy:[247,3,1,""],create:[247,3,1,""],execute_cmd:[247,3,1,""],exits:[247,3,1,""],for_contents:[247,3,1,""],get_content_names:[247,3,1,""],get_display_name:[247,3,1,""],get_numbered_name:[247,3,1,""],get_visible_contents:[247,3,1,""],has_account:[247,3,1,""],is_connected:[247,3,1,""],is_superuser:[247,3,1,""],lockstring:[247,4,1,""],move_to:[247,3,1,""],msg:[247,3,1,""],msg_contents:[247,3,1,""],nicks:[247,4,1,""],objects:[247,4,1,""],path:[247,4,1,""],return_appearance:[247,3,1,""],scripts:[247,4,1,""],search:[247,3,1,""],search_account:[247,3,1,""],sessions:[247,4,1,""],typename:[247,4,1,""]},"evennia.objects.objects.DefaultRoom":{DoesNotExist:[247,2,1,""],MultipleObjectsReturned:[247,2,1,""],basetype_setup:[247,3,1,""],create:[247,3,1,""],lockstring:[247,4,1,""],path:[247,4,1,""],typename:[247,4,1,""]},"evennia.objects.objects.ExitCommand":{aliases:[247,4,1,""],func:[247,3,1,""],get_extra_info:[247,3,1,""],help_category:[247,4,1,""],key:[247,4,1,""],lock_storage:[247,4,1,""],obj:[247,4,1,""],search_index_entry:[247,4,1,""]},"evennia.objects.objects.ObjectSessionHandler":{__init__:[247,3,1,""],add:[247,3,1,""],all:[247,3,1,""],clear:[247,3,1,""],count:[247,3,1,""],get:[247,3,1,""],remove:[247,3,1,""]},"evennia.prototypes":{menus:[249,0,0,"-"],protfuncs:[250,0,0,"-"],prototypes:[251,0,0,"-"],spawner:[252,0,0,"-"]},"evennia.prototypes.menus":{OLCMenu:[249,1,1,""],node_apply_diff:[249,5,1,""],node_destination:[249,5,1,""],node_examine_entity:[249,5,1,""],node_home:[249,5,1,""],node_index:[249,5,1,""],node_key:[249,5,1,""],node_location:[249,5,1,""],node_prototype_desc:[249,5,1,""],node_prototype_key:[249,5,1,""],node_prototype_save:[249,5,1,""],node_prototype_spawn:[249,5,1,""],node_validate_prototype:[249,5,1,""],start_olc:[249,5,1,""]},"evennia.prototypes.menus.OLCMenu":{display_helptext:[249,3,1,""],helptext_formatter:[249,3,1,""],nodetext_formatter:[249,3,1,""],options_formatter:[249,3,1,""]},"evennia.prototypes.protfuncs":{protfunc_callable_protkey:[250,5,1,""]},"evennia.prototypes.prototypes":{DbPrototype:[251,1,1,""],PermissionError:[251,2,1,""],PrototypeEvMore:[251,1,1,""],ValidationError:[251,2,1,""],check_permission:[251,5,1,""],create_prototype:[251,5,1,""],delete_prototype:[251,5,1,""],format_available_protfuncs:[251,5,1,""],homogenize_prototype:[251,5,1,""],init_spawn_value:[251,5,1,""],list_prototypes:[251,5,1,""],load_module_prototypes:[251,5,1,""],protfunc_parser:[251,5,1,""],prototype_to_str:[251,5,1,""],save_prototype:[251,5,1,""],search_objects_with_prototype:[251,5,1,""],search_prototype:[251,5,1,""],validate_prototype:[251,5,1,""],value_to_obj:[251,5,1,""],value_to_obj_or_any:[251,5,1,""]},"evennia.prototypes.prototypes.DbPrototype":{DoesNotExist:[251,2,1,""],MultipleObjectsReturned:[251,2,1,""],at_script_creation:[251,3,1,""],path:[251,4,1,""],prototype:[251,3,1,""],typename:[251,4,1,""]},"evennia.prototypes.prototypes.PrototypeEvMore":{__init__:[251,3,1,""],init_pages:[251,3,1,""],page_formatter:[251,3,1,""],prototype_paginator:[251,3,1,""]},"evennia.prototypes.spawner":{Unset:[252,1,1,""],batch_create_object:[252,5,1,""],batch_update_objects_with_prototype:[252,5,1,""],flatten_diff:[252,5,1,""],flatten_prototype:[252,5,1,""],format_diff:[252,5,1,""],prototype_diff:[252,5,1,""],prototype_diff_from_object:[252,5,1,""],prototype_from_object:[252,5,1,""],spawn:[252,5,1,""]},"evennia.scripts":{manager:[255,0,0,"-"],models:[256,0,0,"-"],monitorhandler:[257,0,0,"-"],scripthandler:[258,0,0,"-"],scripts:[259,0,0,"-"],taskhandler:[260,0,0,"-"],tickerhandler:[261,0,0,"-"]},"evennia.scripts.manager":{ScriptDBManager:[255,1,1,""],ScriptManager:[255,1,1,""]},"evennia.scripts.manager.ScriptDBManager":{copy_script:[255,3,1,""],create_script:[255,3,1,""],delete_script:[255,3,1,""],get_all_scripts:[255,3,1,""],get_all_scripts_on_obj:[255,3,1,""],script_search:[255,3,1,""],search_script:[255,3,1,""],update_scripts_after_server_start:[255,3,1,""]},"evennia.scripts.models":{ScriptDB:[256,1,1,""]},"evennia.scripts.models.ScriptDB":{DoesNotExist:[256,2,1,""],MultipleObjectsReturned:[256,2,1,""],account:[256,3,1,""],db_account:[256,4,1,""],db_account_id:[256,4,1,""],db_attributes:[256,4,1,""],db_desc:[256,4,1,""],db_interval:[256,4,1,""],db_is_active:[256,4,1,""],db_obj:[256,4,1,""],db_obj_id:[256,4,1,""],db_persistent:[256,4,1,""],db_repeats:[256,4,1,""],db_start_delay:[256,4,1,""],db_tags:[256,4,1,""],desc:[256,3,1,""],get_next_by_db_date_created:[256,3,1,""],get_previous_by_db_date_created:[256,3,1,""],id:[256,4,1,""],interval:[256,3,1,""],is_active:[256,3,1,""],obj:[256,3,1,""],object:[256,3,1,""],objects:[256,4,1,""],path:[256,4,1,""],persistent:[256,3,1,""],receiver_script_set:[256,4,1,""],repeats:[256,3,1,""],sender_script_set:[256,4,1,""],start_delay:[256,3,1,""],typename:[256,4,1,""]},"evennia.scripts.monitorhandler":{MonitorHandler:[257,1,1,""]},"evennia.scripts.monitorhandler.MonitorHandler":{__init__:[257,3,1,""],add:[257,3,1,""],all:[257,3,1,""],at_update:[257,3,1,""],clear:[257,3,1,""],remove:[257,3,1,""],restore:[257,3,1,""],save:[257,3,1,""]},"evennia.scripts.scripthandler":{ScriptHandler:[258,1,1,""]},"evennia.scripts.scripthandler.ScriptHandler":{"delete":[258,3,1,""],__init__:[258,3,1,""],add:[258,3,1,""],all:[258,3,1,""],get:[258,3,1,""],start:[258,3,1,""],stop:[258,3,1,""]},"evennia.scripts.scripts":{DefaultScript:[259,1,1,""],DoNothing:[259,1,1,""],Store:[259,1,1,""]},"evennia.scripts.scripts.DefaultScript":{DoesNotExist:[259,2,1,""],MultipleObjectsReturned:[259,2,1,""],at_pause:[259,3,1,""],at_repeat:[259,3,1,""],at_script_creation:[259,3,1,""],at_script_delete:[259,3,1,""],at_server_reload:[259,3,1,""],at_server_shutdown:[259,3,1,""],at_server_start:[259,3,1,""],at_start:[259,3,1,""],at_stop:[259,3,1,""],create:[259,3,1,""],is_valid:[259,3,1,""],path:[259,4,1,""],typename:[259,4,1,""]},"evennia.scripts.scripts.DoNothing":{DoesNotExist:[259,2,1,""],MultipleObjectsReturned:[259,2,1,""],at_script_creation:[259,3,1,""],path:[259,4,1,""],typename:[259,4,1,""]},"evennia.scripts.scripts.Store":{DoesNotExist:[259,2,1,""],MultipleObjectsReturned:[259,2,1,""],at_script_creation:[259,3,1,""],path:[259,4,1,""],typename:[259,4,1,""]},"evennia.scripts.taskhandler":{TaskHandler:[260,1,1,""],TaskHandlerTask:[260,1,1,""],handle_error:[260,5,1,""]},"evennia.scripts.taskhandler.TaskHandler":{__init__:[260,3,1,""],active:[260,3,1,""],add:[260,3,1,""],call_task:[260,3,1,""],cancel:[260,3,1,""],clean_stale_tasks:[260,3,1,""],clear:[260,3,1,""],create_delays:[260,3,1,""],do_task:[260,3,1,""],exists:[260,3,1,""],get_deferred:[260,3,1,""],load:[260,3,1,""],remove:[260,3,1,""],save:[260,3,1,""]},"evennia.scripts.taskhandler.TaskHandlerTask":{__init__:[260,3,1,""],active:[260,3,1,"id6"],call:[260,3,1,"id3"],called:[260,3,1,""],cancel:[260,3,1,"id5"],do_task:[260,3,1,"id2"],exists:[260,3,1,"id7"],get_deferred:[260,3,1,""],get_id:[260,3,1,"id8"],pause:[260,3,1,"id0"],paused:[260,3,1,""],remove:[260,3,1,"id4"],unpause:[260,3,1,"id1"]},"evennia.scripts.tickerhandler":{Ticker:[261,1,1,""],TickerHandler:[261,1,1,""],TickerPool:[261,1,1,""]},"evennia.scripts.tickerhandler.Ticker":{__init__:[261,3,1,""],add:[261,3,1,""],remove:[261,3,1,""],stop:[261,3,1,""],validate:[261,3,1,""]},"evennia.scripts.tickerhandler.TickerHandler":{__init__:[261,3,1,""],add:[261,3,1,""],all:[261,3,1,""],all_display:[261,3,1,""],clear:[261,3,1,""],remove:[261,3,1,""],restore:[261,3,1,""],save:[261,3,1,""],ticker_pool_class:[261,4,1,""]},"evennia.scripts.tickerhandler.TickerPool":{__init__:[261,3,1,""],add:[261,3,1,""],remove:[261,3,1,""],stop:[261,3,1,""],ticker_class:[261,4,1,""]},"evennia.server":{amp_client:[264,0,0,"-"],connection_wizard:[265,0,0,"-"],deprecations:[266,0,0,"-"],evennia_launcher:[267,0,0,"-"],game_index_client:[268,0,0,"-"],initial_setup:[271,0,0,"-"],inputfuncs:[272,0,0,"-"],manager:[273,0,0,"-"],models:[274,0,0,"-"],portal:[275,0,0,"-"],profiling:[297,0,0,"-"],server:[305,0,0,"-"],serversession:[306,0,0,"-"],session:[307,0,0,"-"],sessionhandler:[308,0,0,"-"],signals:[309,0,0,"-"],throttle:[310,0,0,"-"],validators:[311,0,0,"-"],webserver:[312,0,0,"-"]},"evennia.server.amp_client":{AMPClientFactory:[264,1,1,""],AMPServerClientProtocol:[264,1,1,""]},"evennia.server.amp_client.AMPClientFactory":{__init__:[264,3,1,""],buildProtocol:[264,3,1,""],clientConnectionFailed:[264,3,1,""],clientConnectionLost:[264,3,1,""],factor:[264,4,1,""],initialDelay:[264,4,1,""],maxDelay:[264,4,1,""],noisy:[264,4,1,""],startedConnecting:[264,3,1,""]},"evennia.server.amp_client.AMPServerClientProtocol":{connectionMade:[264,3,1,""],data_to_portal:[264,3,1,""],send_AdminServer2Portal:[264,3,1,""],send_MsgServer2Portal:[264,3,1,""],server_receive_adminportal2server:[264,3,1,""],server_receive_msgportal2server:[264,3,1,""],server_receive_status:[264,3,1,""]},"evennia.server.connection_wizard":{ConnectionWizard:[265,1,1,""],node_game_index_fields:[265,5,1,""],node_game_index_start:[265,5,1,""],node_mssp_start:[265,5,1,""],node_start:[265,5,1,""],node_view_and_apply_settings:[265,5,1,""]},"evennia.server.connection_wizard.ConnectionWizard":{__init__:[265,3,1,""],ask_choice:[265,3,1,""],ask_continue:[265,3,1,""],ask_input:[265,3,1,""],ask_node:[265,3,1,""],ask_yesno:[265,3,1,""],display:[265,3,1,""]},"evennia.server.deprecations":{check_errors:[266,5,1,""],check_warnings:[266,5,1,""]},"evennia.server.evennia_launcher":{AMPLauncherProtocol:[267,1,1,""],MsgLauncher2Portal:[267,1,1,""],MsgStatus:[267,1,1,""],check_database:[267,5,1,""],check_main_evennia_dependencies:[267,5,1,""],collectstatic:[267,5,1,""],create_game_directory:[267,5,1,""],create_secret_key:[267,5,1,""],create_settings_file:[267,5,1,""],create_superuser:[267,5,1,""],del_pid:[267,5,1,""],error_check_python_modules:[267,5,1,""],evennia_version:[267,5,1,""],get_pid:[267,5,1,""],getenv:[267,5,1,""],init_game_directory:[267,5,1,""],kill:[267,5,1,""],list_settings:[267,5,1,""],main:[267,5,1,""],query_info:[267,5,1,""],query_status:[267,5,1,""],reboot_evennia:[267,5,1,""],reload_evennia:[267,5,1,""],run_connect_wizard:[267,5,1,""],run_custom_commands:[267,5,1,""],run_dummyrunner:[267,5,1,""],run_menu:[267,5,1,""],send_instruction:[267,5,1,""],set_gamedir:[267,5,1,""],show_version_info:[267,5,1,""],start_evennia:[267,5,1,""],start_only_server:[267,5,1,""],start_portal_interactive:[267,5,1,""],start_server_interactive:[267,5,1,""],stop_evennia:[267,5,1,""],stop_server_only:[267,5,1,""],tail_log_files:[267,5,1,""],wait_for_status:[267,5,1,""],wait_for_status_reply:[267,5,1,""]},"evennia.server.evennia_launcher.AMPLauncherProtocol":{__init__:[267,3,1,""],receive_status_from_portal:[267,3,1,""],wait_for_status:[267,3,1,""]},"evennia.server.evennia_launcher.MsgLauncher2Portal":{allErrors:[267,4,1,""],arguments:[267,4,1,""],commandName:[267,4,1,""],errors:[267,4,1,""],key:[267,4,1,""],response:[267,4,1,""],reverseErrors:[267,4,1,""]},"evennia.server.evennia_launcher.MsgStatus":{allErrors:[267,4,1,""],arguments:[267,4,1,""],commandName:[267,4,1,""],errors:[267,4,1,""],key:[267,4,1,""],response:[267,4,1,""],reverseErrors:[267,4,1,""]},"evennia.server.game_index_client":{client:[269,0,0,"-"],service:[270,0,0,"-"]},"evennia.server.game_index_client.client":{EvenniaGameIndexClient:[269,1,1,""],QuietHTTP11ClientFactory:[269,1,1,""],SimpleResponseReceiver:[269,1,1,""],StringProducer:[269,1,1,""]},"evennia.server.game_index_client.client.EvenniaGameIndexClient":{__init__:[269,3,1,""],handle_egd_response:[269,3,1,""],send_game_details:[269,3,1,""]},"evennia.server.game_index_client.client.QuietHTTP11ClientFactory":{noisy:[269,4,1,""]},"evennia.server.game_index_client.client.SimpleResponseReceiver":{__init__:[269,3,1,""],connectionLost:[269,3,1,""],dataReceived:[269,3,1,""]},"evennia.server.game_index_client.client.StringProducer":{__init__:[269,3,1,""],pauseProducing:[269,3,1,""],startProducing:[269,3,1,""],stopProducing:[269,3,1,""]},"evennia.server.game_index_client.service":{EvenniaGameIndexService:[270,1,1,""]},"evennia.server.game_index_client.service.EvenniaGameIndexService":{__init__:[270,3,1,""],name:[270,4,1,""],startService:[270,3,1,""],stopService:[270,3,1,""]},"evennia.server.initial_setup":{at_initial_setup:[271,5,1,""],collectstatic:[271,5,1,""],create_objects:[271,5,1,""],handle_setup:[271,5,1,""],reset_server:[271,5,1,""]},"evennia.server.inputfuncs":{"default":[272,5,1,""],bot_data_in:[272,5,1,""],client_gui:[272,5,1,""],client_options:[272,5,1,""],echo:[272,5,1,""],external_discord_hello:[272,5,1,""],get_client_options:[272,5,1,""],get_inputfuncs:[272,5,1,""],get_value:[272,5,1,""],hello:[272,5,1,""],login:[272,5,1,""],monitor:[272,5,1,""],monitored:[272,5,1,""],msdp_list:[272,5,1,""],msdp_report:[272,5,1,""],msdp_send:[272,5,1,""],msdp_unreport:[272,5,1,""],repeat:[272,5,1,""],supports_set:[272,5,1,""],text:[272,5,1,""],unmonitor:[272,5,1,""],unrepeat:[272,5,1,""],webclient_options:[272,5,1,""]},"evennia.server.manager":{ServerConfigManager:[273,1,1,""]},"evennia.server.manager.ServerConfigManager":{conf:[273,3,1,""]},"evennia.server.models":{ServerConfig:[274,1,1,""]},"evennia.server.models.ServerConfig":{DoesNotExist:[274,2,1,""],MultipleObjectsReturned:[274,2,1,""],db_key:[274,4,1,""],db_value:[274,4,1,""],id:[274,4,1,""],key:[274,3,1,""],objects:[274,4,1,""],path:[274,4,1,""],store:[274,3,1,""],typename:[274,4,1,""],value:[274,3,1,""]},"evennia.server.portal":{amp:[276,0,0,"-"],amp_server:[277,0,0,"-"],grapevine:[278,0,0,"-"],irc:[279,0,0,"-"],mccp:[280,0,0,"-"],mssp:[281,0,0,"-"],mxp:[282,0,0,"-"],naws:[283,0,0,"-"],portal:[284,0,0,"-"],portalsessionhandler:[285,0,0,"-"],rss:[286,0,0,"-"],ssh:[287,0,0,"-"],ssl:[288,0,0,"-"],suppress_ga:[289,0,0,"-"],telnet:[290,0,0,"-"],telnet_oob:[291,0,0,"-"],telnet_ssl:[292,0,0,"-"],tests:[293,0,0,"-"],ttype:[294,0,0,"-"],webclient:[295,0,0,"-"],webclient_ajax:[296,0,0,"-"]},"evennia.server.portal.amp":{AMPMultiConnectionProtocol:[276,1,1,""],AdminPortal2Server:[276,1,1,""],AdminServer2Portal:[276,1,1,""],Compressed:[276,1,1,""],FunctionCall:[276,1,1,""],MsgLauncher2Portal:[276,1,1,""],MsgPortal2Server:[276,1,1,""],MsgServer2Portal:[276,1,1,""],MsgStatus:[276,1,1,""],dumps:[276,5,1,""],loads:[276,5,1,""]},"evennia.server.portal.amp.AMPMultiConnectionProtocol":{__init__:[276,3,1,""],broadcast:[276,3,1,""],connectionLost:[276,3,1,""],connectionMade:[276,3,1,""],dataReceived:[276,3,1,""],data_in:[276,3,1,""],errback:[276,3,1,""],makeConnection:[276,3,1,""],receive_functioncall:[276,3,1,""],send_FunctionCall:[276,3,1,""]},"evennia.server.portal.amp.AdminPortal2Server":{allErrors:[276,4,1,""],arguments:[276,4,1,""],commandName:[276,4,1,""],errors:[276,4,1,""],key:[276,4,1,""],response:[276,4,1,""],reverseErrors:[276,4,1,""]},"evennia.server.portal.amp.AdminServer2Portal":{allErrors:[276,4,1,""],arguments:[276,4,1,""],commandName:[276,4,1,""],errors:[276,4,1,""],key:[276,4,1,""],response:[276,4,1,""],reverseErrors:[276,4,1,""]},"evennia.server.portal.amp.Compressed":{fromBox:[276,3,1,""],fromString:[276,3,1,""],toBox:[276,3,1,""],toString:[276,3,1,""]},"evennia.server.portal.amp.FunctionCall":{allErrors:[276,4,1,""],arguments:[276,4,1,""],commandName:[276,4,1,""],errors:[276,4,1,""],key:[276,4,1,""],response:[276,4,1,""],reverseErrors:[276,4,1,""]},"evennia.server.portal.amp.MsgLauncher2Portal":{allErrors:[276,4,1,""],arguments:[276,4,1,""],commandName:[276,4,1,""],errors:[276,4,1,""],key:[276,4,1,""],response:[276,4,1,""],reverseErrors:[276,4,1,""]},"evennia.server.portal.amp.MsgPortal2Server":{allErrors:[276,4,1,""],arguments:[276,4,1,""],commandName:[276,4,1,""],errors:[276,4,1,""],key:[276,4,1,""],response:[276,4,1,""],reverseErrors:[276,4,1,""]},"evennia.server.portal.amp.MsgServer2Portal":{allErrors:[276,4,1,""],arguments:[276,4,1,""],commandName:[276,4,1,""],errors:[276,4,1,""],key:[276,4,1,""],response:[276,4,1,""],reverseErrors:[276,4,1,""]},"evennia.server.portal.amp.MsgStatus":{allErrors:[276,4,1,""],arguments:[276,4,1,""],commandName:[276,4,1,""],errors:[276,4,1,""],key:[276,4,1,""],response:[276,4,1,""],reverseErrors:[276,4,1,""]},"evennia.server.portal.amp_server":{AMPServerFactory:[277,1,1,""],AMPServerProtocol:[277,1,1,""],getenv:[277,5,1,""]},"evennia.server.portal.amp_server.AMPServerFactory":{__init__:[277,3,1,""],buildProtocol:[277,3,1,""],logPrefix:[277,3,1,""],noisy:[277,4,1,""]},"evennia.server.portal.amp_server.AMPServerProtocol":{connectionLost:[277,3,1,""],data_to_server:[277,3,1,""],get_status:[277,3,1,""],portal_receive_adminserver2portal:[277,3,1,""],portal_receive_launcher2portal:[277,3,1,""],portal_receive_server2portal:[277,3,1,""],portal_receive_status:[277,3,1,""],send_AdminPortal2Server:[277,3,1,""],send_MsgPortal2Server:[277,3,1,""],send_Status2Launcher:[277,3,1,""],start_server:[277,3,1,""],stop_server:[277,3,1,""],wait_for_disconnect:[277,3,1,""],wait_for_server_connect:[277,3,1,""]},"evennia.server.portal.grapevine":{GrapevineClient:[278,1,1,""],RestartingWebsocketServerFactory:[278,1,1,""]},"evennia.server.portal.grapevine.GrapevineClient":{__init__:[278,3,1,""],at_login:[278,3,1,""],data_in:[278,3,1,""],disconnect:[278,3,1,""],onClose:[278,3,1,""],onMessage:[278,3,1,""],onOpen:[278,3,1,""],send_authenticate:[278,3,1,""],send_channel:[278,3,1,""],send_default:[278,3,1,""],send_heartbeat:[278,3,1,""],send_subscribe:[278,3,1,""],send_unsubscribe:[278,3,1,""]},"evennia.server.portal.grapevine.RestartingWebsocketServerFactory":{__init__:[278,3,1,""],buildProtocol:[278,3,1,""],clientConnectionFailed:[278,3,1,""],clientConnectionLost:[278,3,1,""],factor:[278,4,1,""],initialDelay:[278,4,1,""],maxDelay:[278,4,1,""],reconnect:[278,3,1,""],start:[278,3,1,""],startedConnecting:[278,3,1,""]},"evennia.server.portal.irc":{IRCBot:[279,1,1,""],IRCBotFactory:[279,1,1,""],parse_ansi_to_irc:[279,5,1,""],parse_irc_to_ansi:[279,5,1,""]},"evennia.server.portal.irc.IRCBot":{action:[279,3,1,""],at_login:[279,3,1,""],channel:[279,4,1,""],data_in:[279,3,1,""],disconnect:[279,3,1,""],factory:[279,4,1,""],get_nicklist:[279,3,1,""],irc_RPL_ENDOFNAMES:[279,3,1,""],irc_RPL_NAMREPLY:[279,3,1,""],lineRate:[279,4,1,""],logger:[279,4,1,""],nickname:[279,4,1,""],pong:[279,3,1,""],privmsg:[279,3,1,""],send_channel:[279,3,1,""],send_default:[279,3,1,""],send_ping:[279,3,1,""],send_privmsg:[279,3,1,""],send_reconnect:[279,3,1,""],send_request_nicklist:[279,3,1,""],signedOn:[279,3,1,""],sourceURL:[279,4,1,""]},"evennia.server.portal.irc.IRCBotFactory":{__init__:[279,3,1,""],buildProtocol:[279,3,1,""],clientConnectionFailed:[279,3,1,""],clientConnectionLost:[279,3,1,""],factor:[279,4,1,""],initialDelay:[279,4,1,""],maxDelay:[279,4,1,""],reconnect:[279,3,1,""],start:[279,3,1,""],startedConnecting:[279,3,1,""]},"evennia.server.portal.mccp":{Mccp:[280,1,1,""],mccp_compress:[280,5,1,""]},"evennia.server.portal.mccp.Mccp":{__init__:[280,3,1,""],do_mccp:[280,3,1,""],no_mccp:[280,3,1,""]},"evennia.server.portal.mssp":{Mssp:[281,1,1,""]},"evennia.server.portal.mssp.Mssp":{__init__:[281,3,1,""],do_mssp:[281,3,1,""],get_player_count:[281,3,1,""],get_uptime:[281,3,1,""],no_mssp:[281,3,1,""]},"evennia.server.portal.mxp":{Mxp:[282,1,1,""],mxp_parse:[282,5,1,""]},"evennia.server.portal.mxp.Mxp":{__init__:[282,3,1,""],do_mxp:[282,3,1,""],no_mxp:[282,3,1,""]},"evennia.server.portal.naws":{Naws:[283,1,1,""]},"evennia.server.portal.naws.Naws":{__init__:[283,3,1,""],do_naws:[283,3,1,""],negotiate_sizes:[283,3,1,""],no_naws:[283,3,1,""]},"evennia.server.portal.portal":{Portal:[284,1,1,""],Websocket:[284,1,1,""]},"evennia.server.portal.portal.Portal":{__init__:[284,3,1,""],get_info_dict:[284,3,1,""],shutdown:[284,3,1,""]},"evennia.server.portal.portalsessionhandler":{PortalSessionHandler:[285,1,1,""]},"evennia.server.portal.portalsessionhandler.PortalSessionHandler":{__init__:[285,3,1,""],announce_all:[285,3,1,""],at_server_connection:[285,3,1,""],connect:[285,3,1,""],count_loggedin:[285,3,1,""],data_in:[285,3,1,""],data_out:[285,3,1,""],disconnect:[285,3,1,""],disconnect_all:[285,3,1,""],generate_sessid:[285,3,1,""],server_connect:[285,3,1,""],server_disconnect:[285,3,1,""],server_disconnect_all:[285,3,1,""],server_logged_in:[285,3,1,""],server_session_sync:[285,3,1,""],sessions_from_csessid:[285,3,1,""],sync:[285,3,1,""]},"evennia.server.portal.rss":{RSSBotFactory:[286,1,1,""],RSSReader:[286,1,1,""]},"evennia.server.portal.rss.RSSBotFactory":{__init__:[286,3,1,""],start:[286,3,1,""]},"evennia.server.portal.rss.RSSReader":{__init__:[286,3,1,""],data_in:[286,3,1,""],disconnect:[286,3,1,""],get_new:[286,3,1,""],update:[286,3,1,""]},"evennia.server.portal.ssh":{AccountDBPasswordChecker:[287,1,1,""],ExtraInfoAuthServer:[287,1,1,""],PassAvatarIdTerminalRealm:[287,1,1,""],SSHServerFactory:[287,1,1,""],SshProtocol:[287,1,1,""],TerminalSessionTransport_getPeer:[287,1,1,""],getKeyPair:[287,5,1,""],makeFactory:[287,5,1,""]},"evennia.server.portal.ssh.AccountDBPasswordChecker":{__init__:[287,3,1,""],credentialInterfaces:[287,4,1,""],noisy:[287,4,1,""],requestAvatarId:[287,3,1,""]},"evennia.server.portal.ssh.ExtraInfoAuthServer":{auth_password:[287,3,1,""],noisy:[287,4,1,""]},"evennia.server.portal.ssh.PassAvatarIdTerminalRealm":{noisy:[287,4,1,""]},"evennia.server.portal.ssh.SSHServerFactory":{logPrefix:[287,3,1,""],noisy:[287,4,1,""]},"evennia.server.portal.ssh.SshProtocol":{__init__:[287,3,1,""],at_login:[287,3,1,""],connectionLost:[287,3,1,""],connectionMade:[287,3,1,""],data_out:[287,3,1,""],disconnect:[287,3,1,""],getClientAddress:[287,3,1,""],handle_EOF:[287,3,1,""],handle_FF:[287,3,1,""],handle_INT:[287,3,1,""],handle_QUIT:[287,3,1,""],lineReceived:[287,3,1,""],noisy:[287,4,1,""],sendLine:[287,3,1,""],send_default:[287,3,1,""],send_prompt:[287,3,1,""],send_text:[287,3,1,""],terminalSize:[287,3,1,""]},"evennia.server.portal.ssh.TerminalSessionTransport_getPeer":{__init__:[287,3,1,""],noisy:[287,4,1,""]},"evennia.server.portal.ssl":{SSLProtocol:[288,1,1,""],getSSLContext:[288,5,1,""],verify_SSL_key_and_cert:[288,5,1,""]},"evennia.server.portal.ssl.SSLProtocol":{__init__:[288,3,1,""]},"evennia.server.portal.suppress_ga":{SuppressGA:[289,1,1,""]},"evennia.server.portal.suppress_ga.SuppressGA":{__init__:[289,3,1,""],will_suppress_ga:[289,3,1,""],wont_suppress_ga:[289,3,1,""]},"evennia.server.portal.telnet":{TelnetProtocol:[290,1,1,""],TelnetServerFactory:[290,1,1,""]},"evennia.server.portal.telnet.TelnetProtocol":{__init__:[290,3,1,""],applicationDataReceived:[290,3,1,""],at_login:[290,3,1,""],connectionLost:[290,3,1,""],connectionMade:[290,3,1,""],dataReceived:[290,3,1,""],data_in:[290,3,1,""],data_out:[290,3,1,""],disableLocal:[290,3,1,""],disableRemote:[290,3,1,""],disconnect:[290,3,1,""],enableLocal:[290,3,1,""],enableRemote:[290,3,1,""],handshake_done:[290,3,1,""],sendLine:[290,3,1,""],send_default:[290,3,1,""],send_prompt:[290,3,1,""],send_text:[290,3,1,""],toggle_nop_keepalive:[290,3,1,""]},"evennia.server.portal.telnet.TelnetServerFactory":{logPrefix:[290,3,1,""],noisy:[290,4,1,""]},"evennia.server.portal.telnet_oob":{TelnetOOB:[291,1,1,""]},"evennia.server.portal.telnet_oob.TelnetOOB":{__init__:[291,3,1,""],data_out:[291,3,1,""],decode_gmcp:[291,3,1,""],decode_msdp:[291,3,1,""],do_gmcp:[291,3,1,""],do_msdp:[291,3,1,""],encode_gmcp:[291,3,1,""],encode_msdp:[291,3,1,""],no_gmcp:[291,3,1,""],no_msdp:[291,3,1,""]},"evennia.server.portal.telnet_ssl":{SSLProtocol:[292,1,1,""],getSSLContext:[292,5,1,""],verify_or_create_SSL_key_and_cert:[292,5,1,""]},"evennia.server.portal.telnet_ssl.SSLProtocol":{__init__:[292,3,1,""]},"evennia.server.portal.tests":{TestAMPServer:[293,1,1,""],TestIRC:[293,1,1,""],TestTelnet:[293,1,1,""],TestWebSocket:[293,1,1,""]},"evennia.server.portal.tests.TestAMPServer":{setUp:[293,3,1,""],test_amp_in:[293,3,1,""],test_amp_out:[293,3,1,""],test_large_msg:[293,3,1,""]},"evennia.server.portal.tests.TestIRC":{test_bold:[293,3,1,""],test_colors:[293,3,1,""],test_identity:[293,3,1,""],test_italic:[293,3,1,""],test_plain_ansi:[293,3,1,""]},"evennia.server.portal.tests.TestTelnet":{setUp:[293,3,1,""],test_mudlet_ttype:[293,3,1,""]},"evennia.server.portal.tests.TestWebSocket":{setUp:[293,3,1,""],tearDown:[293,3,1,""],test_data_in:[293,3,1,""],test_data_out:[293,3,1,""]},"evennia.server.portal.ttype":{Ttype:[294,1,1,""]},"evennia.server.portal.ttype.Ttype":{__init__:[294,3,1,""],will_ttype:[294,3,1,""],wont_ttype:[294,3,1,""]},"evennia.server.portal.webclient":{WebSocketClient:[295,1,1,""]},"evennia.server.portal.webclient.WebSocketClient":{__init__:[295,3,1,""],at_login:[295,3,1,""],data_in:[295,3,1,""],disconnect:[295,3,1,""],get_client_session:[295,3,1,""],nonce:[295,4,1,""],onClose:[295,3,1,""],onMessage:[295,3,1,""],onOpen:[295,3,1,""],sendLine:[295,3,1,""],send_default:[295,3,1,""],send_prompt:[295,3,1,""],send_text:[295,3,1,""]},"evennia.server.portal.webclient_ajax":{AjaxWebClient:[296,1,1,""],AjaxWebClientSession:[296,1,1,""],LazyEncoder:[296,1,1,""],jsonify:[296,5,1,""]},"evennia.server.portal.webclient_ajax.AjaxWebClient":{__init__:[296,3,1,""],allowedMethods:[296,4,1,""],at_login:[296,3,1,""],client_disconnect:[296,3,1,""],get_browserstr:[296,3,1,""],get_client_sessid:[296,3,1,""],isLeaf:[296,4,1,""],lineSend:[296,3,1,""],mode_close:[296,3,1,""],mode_init:[296,3,1,""],mode_input:[296,3,1,""],mode_keepalive:[296,3,1,""],mode_receive:[296,3,1,""],render_POST:[296,3,1,""]},"evennia.server.portal.webclient_ajax.AjaxWebClientSession":{__init__:[296,3,1,""],at_login:[296,3,1,""],data_in:[296,3,1,""],data_out:[296,3,1,""],disconnect:[296,3,1,""],get_client_session:[296,3,1,""],send_default:[296,3,1,""],send_prompt:[296,3,1,""],send_text:[296,3,1,""]},"evennia.server.portal.webclient_ajax.LazyEncoder":{"default":[296,3,1,""]},"evennia.server.profiling":{dummyrunner:[298,0,0,"-"],dummyrunner_settings:[299,0,0,"-"],memplot:[300,0,0,"-"],settings_mixin:[301,0,0,"-"],test_queries:[302,0,0,"-"],tests:[303,0,0,"-"],timetrace:[304,0,0,"-"]},"evennia.server.profiling.dummyrunner":{CmdDummyRunnerEchoResponse:[298,1,1,""],DummyClient:[298,1,1,""],DummyFactory:[298,1,1,""],DummyRunnerCmdSet:[298,1,1,""],gidcounter:[298,5,1,""],idcounter:[298,5,1,""],makeiter:[298,5,1,""],start_all_dummy_clients:[298,5,1,""]},"evennia.server.profiling.dummyrunner.CmdDummyRunnerEchoResponse":{aliases:[298,4,1,""],func:[298,3,1,""],help_category:[298,4,1,""],key:[298,4,1,""],lock_storage:[298,4,1,""],search_index_entry:[298,4,1,""]},"evennia.server.profiling.dummyrunner.DummyClient":{connectionLost:[298,3,1,""],connectionMade:[298,3,1,""],counter:[298,3,1,""],dataReceived:[298,3,1,""],error:[298,3,1,""],logout:[298,3,1,""],report:[298,3,1,""],step:[298,3,1,""]},"evennia.server.profiling.dummyrunner.DummyFactory":{__init__:[298,3,1,""],initialDelay:[298,4,1,""],maxDelay:[298,4,1,""],noisy:[298,4,1,""],protocol:[298,4,1,""]},"evennia.server.profiling.dummyrunner.DummyRunnerCmdSet":{at_cmdset_creation:[298,3,1,""],path:[298,4,1,""]},"evennia.server.profiling.dummyrunner_settings":{c_creates_button:[299,5,1,""],c_creates_obj:[299,5,1,""],c_digs:[299,5,1,""],c_examines:[299,5,1,""],c_help:[299,5,1,""],c_idles:[299,5,1,""],c_login:[299,5,1,""],c_login_nodig:[299,5,1,""],c_logout:[299,5,1,""],c_looks:[299,5,1,""],c_measure_lag:[299,5,1,""],c_moves:[299,5,1,""],c_moves_n:[299,5,1,""],c_moves_s:[299,5,1,""],c_socialize:[299,5,1,""]},"evennia.server.profiling.memplot":{Memplot:[300,1,1,""]},"evennia.server.profiling.memplot.Memplot":{DoesNotExist:[300,2,1,""],MultipleObjectsReturned:[300,2,1,""],at_repeat:[300,3,1,""],at_script_creation:[300,3,1,""],path:[300,4,1,""],typename:[300,4,1,""]},"evennia.server.profiling.test_queries":{count_queries:[302,5,1,""]},"evennia.server.profiling.tests":{TestDummyrunnerSettings:[303,1,1,""],TestMemPlot:[303,1,1,""]},"evennia.server.profiling.tests.TestDummyrunnerSettings":{clear_client_lists:[303,3,1,""],perception_method_tests:[303,3,1,""],setUp:[303,3,1,""],test_c_creates_button:[303,3,1,""],test_c_creates_obj:[303,3,1,""],test_c_digs:[303,3,1,""],test_c_examines:[303,3,1,""],test_c_help:[303,3,1,""],test_c_login:[303,3,1,""],test_c_login_no_dig:[303,3,1,""],test_c_logout:[303,3,1,""],test_c_looks:[303,3,1,""],test_c_move_n:[303,3,1,""],test_c_move_s:[303,3,1,""],test_c_moves:[303,3,1,""],test_c_socialize:[303,3,1,""],test_idles:[303,3,1,""]},"evennia.server.profiling.tests.TestMemPlot":{test_memplot:[303,3,1,""]},"evennia.server.profiling.timetrace":{timetrace:[304,5,1,""]},"evennia.server.server":{Evennia:[305,1,1,""]},"evennia.server.server.Evennia":{__init__:[305,3,1,""],at_post_portal_sync:[305,3,1,""],at_server_cold_start:[305,3,1,""],at_server_cold_stop:[305,3,1,""],at_server_reload_start:[305,3,1,""],at_server_reload_stop:[305,3,1,""],at_server_start:[305,3,1,""],at_server_stop:[305,3,1,""],create_default_channels:[305,3,1,""],get_info_dict:[305,3,1,""],run_init_hooks:[305,3,1,""],run_initial_setup:[305,3,1,""],shutdown:[305,3,1,""],sqlite3_prep:[305,3,1,""],update_defaults:[305,3,1,""]},"evennia.server.serversession":{ServerSession:[306,1,1,""]},"evennia.server.serversession.ServerSession":{__init__:[306,3,1,""],access:[306,3,1,""],at_cmdset_get:[306,3,1,""],at_disconnect:[306,3,1,""],at_login:[306,3,1,""],at_sync:[306,3,1,""],attributes:[306,4,1,""],cmdset_storage:[306,3,1,""],data_in:[306,3,1,""],data_out:[306,3,1,""],db:[306,3,1,""],execute_cmd:[306,3,1,""],get_account:[306,3,1,""],get_character:[306,3,1,""],get_client_size:[306,3,1,""],get_puppet:[306,3,1,""],get_puppet_or_account:[306,3,1,""],id:[306,3,1,""],log:[306,3,1,""],msg:[306,3,1,""],nattributes:[306,4,1,""],ndb:[306,3,1,""],ndb_del:[306,3,1,""],ndb_get:[306,3,1,""],ndb_set:[306,3,1,""],update_flags:[306,3,1,""],update_session_counters:[306,3,1,""]},"evennia.server.session":{Session:[307,1,1,""]},"evennia.server.session.Session":{at_sync:[307,3,1,""],data_in:[307,3,1,""],data_out:[307,3,1,""],disconnect:[307,3,1,""],get_sync_data:[307,3,1,""],init_session:[307,3,1,""],load_sync_data:[307,3,1,""]},"evennia.server.sessionhandler":{DummySession:[308,1,1,""],ServerSessionHandler:[308,1,1,""],SessionHandler:[308,1,1,""],delayed_import:[308,5,1,""]},"evennia.server.sessionhandler.DummySession":{sessid:[308,4,1,""]},"evennia.server.sessionhandler.ServerSessionHandler":{__init__:[308,3,1,""],account_count:[308,3,1,""],all_connected_accounts:[308,3,1,""],all_sessions_portal_sync:[308,3,1,""],announce_all:[308,3,1,""],call_inputfuncs:[308,3,1,""],data_in:[308,3,1,""],data_out:[308,3,1,""],disconnect:[308,3,1,""],disconnect_all_sessions:[308,3,1,""],disconnect_duplicate_sessions:[308,3,1,""],get_inputfuncs:[308,3,1,""],login:[308,3,1,""],portal_connect:[308,3,1,""],portal_disconnect:[308,3,1,""],portal_disconnect_all:[308,3,1,""],portal_reset_server:[308,3,1,""],portal_restart_server:[308,3,1,""],portal_session_sync:[308,3,1,""],portal_sessions_sync:[308,3,1,""],portal_shutdown:[308,3,1,""],session_from_account:[308,3,1,""],session_from_sessid:[308,3,1,""],session_portal_partial_sync:[308,3,1,""],session_portal_sync:[308,3,1,""],sessions_from_account:[308,3,1,""],sessions_from_character:[308,3,1,""],sessions_from_csessid:[308,3,1,""],sessions_from_puppet:[308,3,1,""],start_bot_session:[308,3,1,""],validate_sessions:[308,3,1,""]},"evennia.server.sessionhandler.SessionHandler":{clean_senddata:[308,3,1,""],get:[308,3,1,""],get_all_sync_data:[308,3,1,""],get_sessions:[308,3,1,""]},"evennia.server.throttle":{Throttle:[310,1,1,""]},"evennia.server.throttle.Throttle":{__init__:[310,3,1,""],check:[310,3,1,""],error_msg:[310,4,1,""],get:[310,3,1,""],get_cache_key:[310,3,1,""],record_ip:[310,3,1,""],remove:[310,3,1,""],touch:[310,3,1,""],unrecord_ip:[310,3,1,""],update:[310,3,1,""]},"evennia.server.validators":{EvenniaPasswordValidator:[311,1,1,""],EvenniaUsernameAvailabilityValidator:[311,1,1,""]},"evennia.server.validators.EvenniaPasswordValidator":{__init__:[311,3,1,""],get_help_text:[311,3,1,""],validate:[311,3,1,""]},"evennia.server.webserver":{DjangoWebRoot:[312,1,1,""],EvenniaReverseProxyResource:[312,1,1,""],HTTPChannelWithXForwardedFor:[312,1,1,""],LockableThreadPool:[312,1,1,""],PrivateStaticRoot:[312,1,1,""],WSGIWebServer:[312,1,1,""],Website:[312,1,1,""]},"evennia.server.webserver.DjangoWebRoot":{__init__:[312,3,1,""],empty_threadpool:[312,3,1,""],getChild:[312,3,1,""]},"evennia.server.webserver.EvenniaReverseProxyResource":{getChild:[312,3,1,""],render:[312,3,1,""]},"evennia.server.webserver.HTTPChannelWithXForwardedFor":{allHeadersReceived:[312,3,1,""]},"evennia.server.webserver.LockableThreadPool":{__init__:[312,3,1,""],callInThread:[312,3,1,""],lock:[312,3,1,""]},"evennia.server.webserver.PrivateStaticRoot":{directoryListing:[312,3,1,""]},"evennia.server.webserver.WSGIWebServer":{__init__:[312,3,1,""],startService:[312,3,1,""],stopService:[312,3,1,""]},"evennia.server.webserver.Website":{log:[312,3,1,""],logPrefix:[312,3,1,""],noisy:[312,4,1,""]},"evennia.typeclasses":{attributes:[316,0,0,"-"],managers:[317,0,0,"-"],models:[318,0,0,"-"],tags:[319,0,0,"-"]},"evennia.typeclasses.attributes":{Attribute:[316,1,1,""],AttributeHandler:[316,1,1,""],AttributeProperty:[316,1,1,""],DbHolder:[316,1,1,""],IAttribute:[316,1,1,""],IAttributeBackend:[316,1,1,""],InMemoryAttribute:[316,1,1,""],InMemoryAttributeBackend:[316,1,1,""],ModelAttributeBackend:[316,1,1,""],NAttributeProperty:[316,1,1,""],NickHandler:[316,1,1,""],NickTemplateInvalid:[316,2,1,""],initialize_nick_templates:[316,5,1,""],parse_nick_template:[316,5,1,""]},"evennia.typeclasses.attributes.Attribute":{DoesNotExist:[316,2,1,""],MultipleObjectsReturned:[316,2,1,""],accountdb_set:[316,4,1,""],attrtype:[316,3,1,""],category:[316,3,1,""],channeldb_set:[316,4,1,""],date_created:[316,3,1,""],db_attrtype:[316,4,1,""],db_category:[316,4,1,""],db_date_created:[316,4,1,""],db_key:[316,4,1,""],db_lock_storage:[316,4,1,""],db_model:[316,4,1,""],db_strvalue:[316,4,1,""],db_value:[316,4,1,""],get_next_by_db_date_created:[316,3,1,""],get_previous_by_db_date_created:[316,3,1,""],id:[316,4,1,""],key:[316,3,1,""],lock_storage:[316,3,1,""],model:[316,3,1,""],objectdb_set:[316,4,1,""],path:[316,4,1,""],scriptdb_set:[316,4,1,""],strvalue:[316,3,1,""],typename:[316,4,1,""],value:[316,3,1,""]},"evennia.typeclasses.attributes.AttributeHandler":{__init__:[316,3,1,""],add:[316,3,1,""],all:[316,3,1,""],batch_add:[316,3,1,""],clear:[316,3,1,""],get:[316,3,1,""],has:[316,3,1,""],remove:[316,3,1,""],reset_cache:[316,3,1,""]},"evennia.typeclasses.attributes.AttributeProperty":{__init__:[316,3,1,""],attrhandler_name:[316,4,1,""]},"evennia.typeclasses.attributes.DbHolder":{__init__:[316,3,1,""],all:[316,3,1,""],get_all:[316,3,1,""]},"evennia.typeclasses.attributes.IAttribute":{access:[316,3,1,""],attrtype:[316,3,1,""],category:[316,3,1,""],date_created:[316,3,1,""],key:[316,3,1,""],lock_storage:[316,3,1,""],locks:[316,4,1,""],model:[316,3,1,""],strvalue:[316,3,1,""]},"evennia.typeclasses.attributes.IAttributeBackend":{__init__:[316,3,1,""],batch_add:[316,3,1,""],clear_attributes:[316,3,1,""],create_attribute:[316,3,1,""],delete_attribute:[316,3,1,""],do_batch_delete:[316,3,1,""],do_batch_finish:[316,3,1,""],do_batch_update_attribute:[316,3,1,""],do_create_attribute:[316,3,1,""],do_delete_attribute:[316,3,1,""],do_update_attribute:[316,3,1,""],get:[316,3,1,""],get_all_attributes:[316,3,1,""],query_all:[316,3,1,""],query_category:[316,3,1,""],query_key:[316,3,1,""],reset_cache:[316,3,1,""],update_attribute:[316,3,1,""]},"evennia.typeclasses.attributes.InMemoryAttribute":{__init__:[316,3,1,""],value:[316,3,1,""]},"evennia.typeclasses.attributes.InMemoryAttributeBackend":{__init__:[316,3,1,""],do_batch_finish:[316,3,1,""],do_batch_update_attribute:[316,3,1,""],do_create_attribute:[316,3,1,""],do_delete_attribute:[316,3,1,""],do_update_attribute:[316,3,1,""],query_all:[316,3,1,""],query_category:[316,3,1,""],query_key:[316,3,1,""]},"evennia.typeclasses.attributes.ModelAttributeBackend":{__init__:[316,3,1,""],do_batch_finish:[316,3,1,""],do_batch_update_attribute:[316,3,1,""],do_create_attribute:[316,3,1,""],do_delete_attribute:[316,3,1,""],do_update_attribute:[316,3,1,""],query_all:[316,3,1,""],query_category:[316,3,1,""],query_key:[316,3,1,""]},"evennia.typeclasses.attributes.NAttributeProperty":{attrhandler_name:[316,4,1,""]},"evennia.typeclasses.attributes.NickHandler":{__init__:[316,3,1,""],add:[316,3,1,""],get:[316,3,1,""],has:[316,3,1,""],nickreplace:[316,3,1,""],remove:[316,3,1,""]},"evennia.typeclasses.managers":{TypedObjectManager:[317,1,1,""]},"evennia.typeclasses.managers.TypedObjectManager":{create_tag:[317,3,1,""],dbref:[317,3,1,""],dbref_search:[317,3,1,""],get_alias:[317,3,1,""],get_attribute:[317,3,1,""],get_by_alias:[317,3,1,""],get_by_attribute:[317,3,1,""],get_by_nick:[317,3,1,""],get_by_permission:[317,3,1,""],get_by_tag:[317,3,1,""],get_dbref_range:[317,3,1,""],get_id:[317,3,1,""],get_nick:[317,3,1,""],get_permission:[317,3,1,""],get_tag:[317,3,1,""],get_typeclass_totals:[317,3,1,""],object_totals:[317,3,1,""],typeclass_search:[317,3,1,""]},"evennia.typeclasses.models":{TypedObject:[318,1,1,""]},"evennia.typeclasses.models.TypedObject":{"delete":[318,3,1,""],Meta:[318,1,1,""],__init__:[318,3,1,""],access:[318,3,1,""],aliases:[318,4,1,""],at_idmapper_flush:[318,3,1,""],at_rename:[318,3,1,""],attributes:[318,4,1,""],check_permstring:[318,3,1,""],date_created:[318,3,1,""],db:[318,3,1,""],db_attributes:[318,4,1,""],db_date_created:[318,4,1,""],db_key:[318,4,1,""],db_lock_storage:[318,4,1,""],db_tags:[318,4,1,""],db_typeclass_path:[318,4,1,""],dbid:[318,3,1,""],dbref:[318,3,1,""],get_absolute_url:[318,3,1,""],get_display_name:[318,3,1,""],get_extra_info:[318,3,1,""],get_next_by_db_date_created:[318,3,1,""],get_previous_by_db_date_created:[318,3,1,""],is_typeclass:[318,3,1,""],key:[318,3,1,""],lock_storage:[318,3,1,""],locks:[318,4,1,""],name:[318,3,1,""],nattributes:[318,4,1,""],ndb:[318,3,1,""],objects:[318,4,1,""],path:[318,4,1,""],permissions:[318,4,1,""],search:[318,3,1,""],set_class_from_typeclass:[318,3,1,""],swap_typeclass:[318,3,1,""],tags:[318,4,1,""],typeclass_path:[318,3,1,""],typename:[318,4,1,""],web_get_admin_url:[318,3,1,""],web_get_create_url:[318,3,1,""],web_get_delete_url:[318,3,1,""],web_get_detail_url:[318,3,1,""],web_get_puppet_url:[318,3,1,""],web_get_update_url:[318,3,1,""]},"evennia.typeclasses.models.TypedObject.Meta":{"abstract":[318,4,1,""],ordering:[318,4,1,""],verbose_name:[318,4,1,""]},"evennia.typeclasses.tags":{AliasHandler:[319,1,1,""],PermissionHandler:[319,1,1,""],Tag:[319,1,1,""],TagHandler:[319,1,1,""]},"evennia.typeclasses.tags.PermissionHandler":{check:[319,3,1,""]},"evennia.typeclasses.tags.Tag":{DoesNotExist:[319,2,1,""],MultipleObjectsReturned:[319,2,1,""],accountdb_set:[319,4,1,""],channeldb_set:[319,4,1,""],db_category:[319,4,1,""],db_data:[319,4,1,""],db_key:[319,4,1,""],db_model:[319,4,1,""],db_tagtype:[319,4,1,""],helpentry_set:[319,4,1,""],id:[319,4,1,""],msg_set:[319,4,1,""],objectdb_set:[319,4,1,""],objects:[319,4,1,""],scriptdb_set:[319,4,1,""]},"evennia.typeclasses.tags.TagHandler":{__init__:[319,3,1,""],add:[319,3,1,""],all:[319,3,1,""],batch_add:[319,3,1,""],clear:[319,3,1,""],get:[319,3,1,""],has:[319,3,1,""],remove:[319,3,1,""],reset_cache:[319,3,1,""]},"evennia.utils":{ansi:[321,0,0,"-"],batchprocessors:[322,0,0,"-"],containers:[323,0,0,"-"],create:[324,0,0,"-"],dbserialize:[325,0,0,"-"],eveditor:[326,0,0,"-"],evform:[327,0,0,"-"],evmenu:[328,0,0,"-"],evmore:[329,0,0,"-"],evtable:[330,0,0,"-"],gametime:[331,0,0,"-"],idmapper:[332,0,0,"-"],logger:[337,0,0,"-"],optionclasses:[338,0,0,"-"],optionhandler:[339,0,0,"-"],picklefield:[340,0,0,"-"],search:[341,0,0,"-"],test_resources:[342,0,0,"-"],text2html:[343,0,0,"-"],utils:[344,0,0,"-"],validatorfuncs:[345,0,0,"-"]},"evennia.utils.ansi":{ANSIMeta:[321,1,1,""],ANSIParser:[321,1,1,""],ANSIString:[321,1,1,""],parse_ansi:[321,5,1,""],raw:[321,5,1,""],strip_ansi:[321,5,1,""],strip_mxp:[321,5,1,""],strip_raw_ansi:[321,5,1,""],strip_unsafe_tokens:[321,5,1,""]},"evennia.utils.ansi.ANSIMeta":{__init__:[321,3,1,""]},"evennia.utils.ansi.ANSIParser":{ansi_escapes:[321,4,1,""],ansi_map:[321,4,1,""],ansi_map_dict:[321,4,1,""],ansi_re:[321,4,1,""],ansi_regex:[321,4,1,""],ansi_sub:[321,4,1,""],ansi_xterm256_bright_bg_map:[321,4,1,""],ansi_xterm256_bright_bg_map_dict:[321,4,1,""],brightbg_sub:[321,4,1,""],mxp_re:[321,4,1,""],mxp_sub:[321,4,1,""],mxp_url_re:[321,4,1,""],mxp_url_sub:[321,4,1,""],parse_ansi:[321,3,1,""],strip_mxp:[321,3,1,""],strip_raw_codes:[321,3,1,""],strip_unsafe_tokens:[321,3,1,""],sub_ansi:[321,3,1,""],sub_brightbg:[321,3,1,""],sub_xterm256:[321,3,1,""],unsafe_tokens:[321,4,1,""],xterm256_bg:[321,4,1,""],xterm256_bg_sub:[321,4,1,""],xterm256_fg:[321,4,1,""],xterm256_fg_sub:[321,4,1,""],xterm256_gbg:[321,4,1,""],xterm256_gbg_sub:[321,4,1,""],xterm256_gfg:[321,4,1,""],xterm256_gfg_sub:[321,4,1,""]},"evennia.utils.ansi.ANSIString":{__init__:[321,3,1,""],capitalize:[321,3,1,""],center:[321,3,1,""],clean:[321,3,1,""],count:[321,3,1,""],decode:[321,3,1,""],encode:[321,3,1,""],endswith:[321,3,1,""],expandtabs:[321,3,1,""],find:[321,3,1,""],format:[321,3,1,""],index:[321,3,1,""],isalnum:[321,3,1,""],isalpha:[321,3,1,""],isdigit:[321,3,1,""],islower:[321,3,1,""],isspace:[321,3,1,""],istitle:[321,3,1,""],isupper:[321,3,1,""],join:[321,3,1,""],ljust:[321,3,1,""],lower:[321,3,1,""],lstrip:[321,3,1,""],partition:[321,3,1,""],raw:[321,3,1,""],re_format:[321,4,1,""],replace:[321,3,1,""],rfind:[321,3,1,""],rindex:[321,3,1,""],rjust:[321,3,1,""],rsplit:[321,3,1,""],rstrip:[321,3,1,""],split:[321,3,1,""],startswith:[321,3,1,""],strip:[321,3,1,""],swapcase:[321,3,1,""],translate:[321,3,1,""],upper:[321,3,1,""]},"evennia.utils.batchprocessors":{BatchCodeProcessor:[322,1,1,""],BatchCommandProcessor:[322,1,1,""],read_batchfile:[322,5,1,""],tb_filename:[322,5,1,""],tb_iter:[322,5,1,""]},"evennia.utils.batchprocessors.BatchCodeProcessor":{code_exec:[322,3,1,""],parse_file:[322,3,1,""]},"evennia.utils.batchprocessors.BatchCommandProcessor":{parse_file:[322,3,1,""]},"evennia.utils.containers":{Container:[323,1,1,""],GlobalScriptContainer:[323,1,1,""],OptionContainer:[323,1,1,""]},"evennia.utils.containers.Container":{__init__:[323,3,1,""],all:[323,3,1,""],get:[323,3,1,""],load_data:[323,3,1,""],storage_modules:[323,4,1,""]},"evennia.utils.containers.GlobalScriptContainer":{__init__:[323,3,1,""],all:[323,3,1,""],get:[323,3,1,""],load_data:[323,3,1,""],start:[323,3,1,""]},"evennia.utils.containers.OptionContainer":{storage_modules:[323,4,1,""]},"evennia.utils.create":{create_account:[324,5,1,""],create_channel:[324,5,1,""],create_help_entry:[324,5,1,""],create_message:[324,5,1,""],create_object:[324,5,1,""],create_script:[324,5,1,""]},"evennia.utils.dbserialize":{dbserialize:[325,5,1,""],dbunserialize:[325,5,1,""],do_pickle:[325,5,1,""],do_unpickle:[325,5,1,""],from_pickle:[325,5,1,""],to_pickle:[325,5,1,""]},"evennia.utils.eveditor":{CmdEditorBase:[326,1,1,""],CmdEditorGroup:[326,1,1,""],CmdLineInput:[326,1,1,""],CmdSaveYesNo:[326,1,1,""],EvEditor:[326,1,1,""],EvEditorCmdSet:[326,1,1,""],SaveYesNoCmdSet:[326,1,1,""]},"evennia.utils.eveditor.CmdEditorBase":{aliases:[326,4,1,""],editor:[326,4,1,""],help_category:[326,4,1,""],help_entry:[326,4,1,""],key:[326,4,1,""],lock_storage:[326,4,1,""],locks:[326,4,1,""],parse:[326,3,1,""],search_index_entry:[326,4,1,""]},"evennia.utils.eveditor.CmdEditorGroup":{aliases:[326,4,1,""],arg_regex:[326,4,1,""],func:[326,3,1,""],help_category:[326,4,1,""],key:[326,4,1,""],lock_storage:[326,4,1,""],search_index_entry:[326,4,1,""]},"evennia.utils.eveditor.CmdLineInput":{aliases:[326,4,1,""],func:[326,3,1,""],help_category:[326,4,1,""],key:[326,4,1,""],lock_storage:[326,4,1,""],search_index_entry:[326,4,1,""]},"evennia.utils.eveditor.CmdSaveYesNo":{aliases:[326,4,1,""],func:[326,3,1,""],help_category:[326,4,1,""],help_cateogory:[326,4,1,""],key:[326,4,1,""],lock_storage:[326,4,1,""],locks:[326,4,1,""],search_index_entry:[326,4,1,""]},"evennia.utils.eveditor.EvEditor":{__init__:[326,3,1,""],decrease_indent:[326,3,1,""],deduce_indent:[326,3,1,""],display_buffer:[326,3,1,""],display_help:[326,3,1,""],get_buffer:[326,3,1,""],increase_indent:[326,3,1,""],load_buffer:[326,3,1,""],quit:[326,3,1,""],save_buffer:[326,3,1,""],swap_autoindent:[326,3,1,""],update_buffer:[326,3,1,""],update_undo:[326,3,1,""]},"evennia.utils.eveditor.EvEditorCmdSet":{at_cmdset_creation:[326,3,1,""],key:[326,4,1,""],mergetype:[326,4,1,""],path:[326,4,1,""]},"evennia.utils.eveditor.SaveYesNoCmdSet":{at_cmdset_creation:[326,3,1,""],key:[326,4,1,""],mergetype:[326,4,1,""],path:[326,4,1,""],priority:[326,4,1,""]},"evennia.utils.evform":{EvForm:[327,1,1,""]},"evennia.utils.evform.EvForm":{__init__:[327,3,1,""],map:[327,3,1,""],reload:[327,3,1,""]},"evennia.utils.evmenu":{CmdEvMenuNode:[328,1,1,""],CmdGetInput:[328,1,1,""],CmdYesNoQuestion:[328,1,1,""],EvMenu:[328,1,1,""],EvMenuCmdSet:[328,1,1,""],EvMenuError:[328,2,1,""],EvMenuGotoAbortMessage:[328,2,1,""],InputCmdSet:[328,1,1,""],YesNoQuestionCmdSet:[328,1,1,""],ask_yes_no:[328,5,1,""],get_input:[328,5,1,""],list_node:[328,5,1,""],parse_menu_template:[328,5,1,""],template2menu:[328,5,1,""]},"evennia.utils.evmenu.CmdEvMenuNode":{aliases:[328,4,1,""],auto_help_display_key:[328,4,1,""],func:[328,3,1,""],get_help:[328,3,1,""],help_category:[328,4,1,""],key:[328,4,1,""],lock_storage:[328,4,1,""],locks:[328,4,1,""],search_index_entry:[328,4,1,""]},"evennia.utils.evmenu.CmdGetInput":{aliases:[328,4,1,""],func:[328,3,1,""],help_category:[328,4,1,""],key:[328,4,1,""],lock_storage:[328,4,1,""],search_index_entry:[328,4,1,""]},"evennia.utils.evmenu.CmdYesNoQuestion":{aliases:[328,4,1,""],arg_regex:[328,4,1,""],func:[328,3,1,""],help_category:[328,4,1,""],key:[328,4,1,""],lock_storage:[328,4,1,""],search_index_entry:[328,4,1,""]},"evennia.utils.evmenu.EvMenu":{"goto":[328,3,1,""],__init__:[328,3,1,""],close_menu:[328,3,1,""],display_helptext:[328,3,1,""],display_nodetext:[328,3,1,""],extract_goto_exec:[328,3,1,""],helptext_formatter:[328,3,1,""],msg:[328,3,1,""],node_border_char:[328,4,1,""],node_formatter:[328,3,1,""],nodetext_formatter:[328,3,1,""],options_formatter:[328,3,1,""],parse_input:[328,3,1,""],print_debug_info:[328,3,1,""],run_exec:[328,3,1,""],run_exec_then_goto:[328,3,1,""]},"evennia.utils.evmenu.EvMenuCmdSet":{at_cmdset_creation:[328,3,1,""],key:[328,4,1,""],mergetype:[328,4,1,""],no_channels:[328,4,1,""],no_exits:[328,4,1,""],no_objs:[328,4,1,""],path:[328,4,1,""],priority:[328,4,1,""]},"evennia.utils.evmenu.InputCmdSet":{at_cmdset_creation:[328,3,1,""],key:[328,4,1,""],mergetype:[328,4,1,""],no_channels:[328,4,1,""],no_exits:[328,4,1,""],no_objs:[328,4,1,""],path:[328,4,1,""],priority:[328,4,1,""]},"evennia.utils.evmenu.YesNoQuestionCmdSet":{at_cmdset_creation:[328,3,1,""],key:[328,4,1,""],mergetype:[328,4,1,""],no_channels:[328,4,1,""],no_exits:[328,4,1,""],no_objs:[328,4,1,""],path:[328,4,1,""],priority:[328,4,1,""]},"evennia.utils.evmore":{CmdMore:[329,1,1,""],CmdMoreExit:[329,1,1,""],CmdSetMore:[329,1,1,""],EvMore:[329,1,1,""],msg:[329,5,1,""],queryset_maxsize:[329,5,1,""]},"evennia.utils.evmore.CmdMore":{aliases:[329,4,1,""],auto_help:[329,4,1,""],func:[329,3,1,""],help_category:[329,4,1,""],key:[329,4,1,""],lock_storage:[329,4,1,""],search_index_entry:[329,4,1,""]},"evennia.utils.evmore.CmdMoreExit":{aliases:[329,4,1,""],func:[329,3,1,""],help_category:[329,4,1,""],key:[329,4,1,""],lock_storage:[329,4,1,""],search_index_entry:[329,4,1,""]},"evennia.utils.evmore.CmdSetMore":{at_cmdset_creation:[329,3,1,""],key:[329,4,1,""],mergetype:[329,4,1,""],path:[329,4,1,""],priority:[329,4,1,""]},"evennia.utils.evmore.EvMore":{__init__:[329,3,1,""],display:[329,3,1,""],init_django_paginator:[329,3,1,""],init_evtable:[329,3,1,""],init_f_str:[329,3,1,""],init_iterable:[329,3,1,""],init_pages:[329,3,1,""],init_queryset:[329,3,1,""],init_str:[329,3,1,""],page_back:[329,3,1,""],page_end:[329,3,1,""],page_formatter:[329,3,1,""],page_next:[329,3,1,""],page_quit:[329,3,1,""],page_top:[329,3,1,""],paginator:[329,3,1,""],paginator_django:[329,3,1,""],paginator_index:[329,3,1,""],paginator_slice:[329,3,1,""],start:[329,3,1,""]},"evennia.utils.evtable":{ANSITextWrapper:[330,1,1,""],EvCell:[330,1,1,""],EvColumn:[330,1,1,""],EvTable:[330,1,1,""],fill:[330,5,1,""],wrap:[330,5,1,""]},"evennia.utils.evtable.EvCell":{__init__:[330,3,1,""],get:[330,3,1,""],get_height:[330,3,1,""],get_min_height:[330,3,1,""],get_min_width:[330,3,1,""],get_width:[330,3,1,""],reformat:[330,3,1,""],replace_data:[330,3,1,""]},"evennia.utils.evtable.EvColumn":{__init__:[330,3,1,""],add_rows:[330,3,1,""],reformat:[330,3,1,""],reformat_cell:[330,3,1,""]},"evennia.utils.evtable.EvTable":{__init__:[330,3,1,""],add_column:[330,3,1,""],add_header:[330,3,1,""],add_row:[330,3,1,""],get:[330,3,1,""],reformat:[330,3,1,""],reformat_column:[330,3,1,""]},"evennia.utils.gametime":{TimeScript:[331,1,1,""],game_epoch:[331,5,1,""],gametime:[331,5,1,""],portal_uptime:[331,5,1,""],real_seconds_until:[331,5,1,""],reset_gametime:[331,5,1,""],runtime:[331,5,1,""],schedule:[331,5,1,""],server_epoch:[331,5,1,""],uptime:[331,5,1,""]},"evennia.utils.gametime.TimeScript":{DoesNotExist:[331,2,1,""],MultipleObjectsReturned:[331,2,1,""],at_repeat:[331,3,1,""],at_script_creation:[331,3,1,""],path:[331,4,1,""],typename:[331,4,1,""]},"evennia.utils.idmapper":{manager:[333,0,0,"-"],models:[334,0,0,"-"],tests:[335,0,0,"-"]},"evennia.utils.idmapper.manager":{SharedMemoryManager:[333,1,1,""]},"evennia.utils.idmapper.manager.SharedMemoryManager":{get:[333,3,1,""]},"evennia.utils.idmapper.models":{SharedMemoryModel:[334,1,1,""],SharedMemoryModelBase:[334,1,1,""],WeakSharedMemoryModel:[334,1,1,""],WeakSharedMemoryModelBase:[334,1,1,""],cache_size:[334,5,1,""],conditional_flush:[334,5,1,""],flush_cache:[334,5,1,""],flush_cached_instance:[334,5,1,""],update_cached_instance:[334,5,1,""]},"evennia.utils.idmapper.models.SharedMemoryModel":{"delete":[334,3,1,""],Meta:[334,1,1,""],at_idmapper_flush:[334,3,1,""],cache_instance:[334,3,1,""],flush_cached_instance:[334,3,1,""],flush_from_cache:[334,3,1,""],flush_instance_cache:[334,3,1,""],get_all_cached_instances:[334,3,1,""],get_cached_instance:[334,3,1,""],objects:[334,4,1,""],path:[334,4,1,""],save:[334,3,1,""],typename:[334,4,1,""]},"evennia.utils.idmapper.models.SharedMemoryModel.Meta":{"abstract":[334,4,1,""]},"evennia.utils.idmapper.models.WeakSharedMemoryModel":{Meta:[334,1,1,""],path:[334,4,1,""],typename:[334,4,1,""]},"evennia.utils.idmapper.models.WeakSharedMemoryModel.Meta":{"abstract":[334,4,1,""]},"evennia.utils.idmapper.tests":{Article:[335,1,1,""],Category:[335,1,1,""],RegularArticle:[335,1,1,""],RegularCategory:[335,1,1,""],SharedMemorysTest:[335,1,1,""]},"evennia.utils.idmapper.tests.Article":{DoesNotExist:[335,2,1,""],MultipleObjectsReturned:[335,2,1,""],category2:[335,4,1,""],category2_id:[335,4,1,""],category:[335,4,1,""],category_id:[335,4,1,""],id:[335,4,1,""],name:[335,4,1,""],path:[335,4,1,""],typename:[335,4,1,""]},"evennia.utils.idmapper.tests.Category":{DoesNotExist:[335,2,1,""],MultipleObjectsReturned:[335,2,1,""],article_set:[335,4,1,""],id:[335,4,1,""],name:[335,4,1,""],path:[335,4,1,""],regulararticle_set:[335,4,1,""],typename:[335,4,1,""]},"evennia.utils.idmapper.tests.RegularArticle":{DoesNotExist:[335,2,1,""],MultipleObjectsReturned:[335,2,1,""],category2:[335,4,1,""],category2_id:[335,4,1,""],category:[335,4,1,""],category_id:[335,4,1,""],id:[335,4,1,""],name:[335,4,1,""],objects:[335,4,1,""]},"evennia.utils.idmapper.tests.RegularCategory":{DoesNotExist:[335,2,1,""],MultipleObjectsReturned:[335,2,1,""],article_set:[335,4,1,""],id:[335,4,1,""],name:[335,4,1,""],objects:[335,4,1,""],regulararticle_set:[335,4,1,""]},"evennia.utils.idmapper.tests.SharedMemorysTest":{setUp:[335,3,1,""],testMixedReferences:[335,3,1,""],testObjectDeletion:[335,3,1,""],testRegularReferences:[335,3,1,""],testSharedMemoryReferences:[335,3,1,""]},"evennia.utils.logger":{EvenniaLogFile:[337,1,1,""],PortalLogObserver:[337,1,1,""],ServerLogObserver:[337,1,1,""],WeeklyLogFile:[337,1,1,""],log_dep:[337,5,1,""],log_depmsg:[337,5,1,""],log_err:[337,5,1,""],log_errmsg:[337,5,1,""],log_file:[337,5,1,""],log_file_exists:[337,5,1,""],log_info:[337,5,1,""],log_infomsg:[337,5,1,""],log_msg:[337,5,1,""],log_sec:[337,5,1,""],log_secmsg:[337,5,1,""],log_server:[337,5,1,""],log_trace:[337,5,1,""],log_tracemsg:[337,5,1,""],log_warn:[337,5,1,""],log_warnmsg:[337,5,1,""],rotate_log_file:[337,5,1,""],tail_log_file:[337,5,1,""],timeformat:[337,5,1,""]},"evennia.utils.logger.EvenniaLogFile":{num_lines_to_append:[337,4,1,""],readlines:[337,3,1,""],rotate:[337,3,1,""],seek:[337,3,1,""],settings:[337,4,1,""]},"evennia.utils.logger.PortalLogObserver":{emit:[337,3,1,""],prefix:[337,4,1,""],timeFormat:[337,4,1,""]},"evennia.utils.logger.ServerLogObserver":{prefix:[337,4,1,""]},"evennia.utils.logger.WeeklyLogFile":{__init__:[337,3,1,""],shouldRotate:[337,3,1,""],suffix:[337,3,1,""],write:[337,3,1,""]},"evennia.utils.optionclasses":{BaseOption:[338,1,1,""],Boolean:[338,1,1,""],Color:[338,1,1,""],Datetime:[338,1,1,""],Duration:[338,1,1,""],Email:[338,1,1,""],Future:[338,1,1,""],Lock:[338,1,1,""],PositiveInteger:[338,1,1,""],SignedInteger:[338,1,1,""],Text:[338,1,1,""],Timezone:[338,1,1,""],UnsignedInteger:[338,1,1,""]},"evennia.utils.optionclasses.BaseOption":{"default":[338,3,1,""],__init__:[338,3,1,""],changed:[338,3,1,""],deserialize:[338,3,1,""],display:[338,3,1,""],load:[338,3,1,""],save:[338,3,1,""],serialize:[338,3,1,""],set:[338,3,1,""],validate:[338,3,1,""],value:[338,3,1,""]},"evennia.utils.optionclasses.Boolean":{deserialize:[338,3,1,""],display:[338,3,1,""],serialize:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.Color":{deserialize:[338,3,1,""],display:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.Datetime":{deserialize:[338,3,1,""],serialize:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.Duration":{deserialize:[338,3,1,""],serialize:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.Email":{deserialize:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.Future":{validate:[338,3,1,""]},"evennia.utils.optionclasses.Lock":{validate:[338,3,1,""]},"evennia.utils.optionclasses.PositiveInteger":{deserialize:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.SignedInteger":{deserialize:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.Text":{deserialize:[338,3,1,""]},"evennia.utils.optionclasses.Timezone":{"default":[338,3,1,""],deserialize:[338,3,1,""],serialize:[338,3,1,""],validate:[338,3,1,""]},"evennia.utils.optionclasses.UnsignedInteger":{deserialize:[338,3,1,""],validate:[338,3,1,""],validator_key:[338,4,1,""]},"evennia.utils.optionhandler":{InMemorySaveHandler:[339,1,1,""],OptionHandler:[339,1,1,""]},"evennia.utils.optionhandler.InMemorySaveHandler":{__init__:[339,3,1,""],add:[339,3,1,""],get:[339,3,1,""]},"evennia.utils.optionhandler.OptionHandler":{__init__:[339,3,1,""],all:[339,3,1,""],get:[339,3,1,""],set:[339,3,1,""]},"evennia.utils.picklefield":{PickledFormField:[340,1,1,""],PickledObject:[340,1,1,""],PickledObjectField:[340,1,1,""],PickledWidget:[340,1,1,""],dbsafe_decode:[340,5,1,""],dbsafe_encode:[340,5,1,""],wrap_conflictual_object:[340,5,1,""]},"evennia.utils.picklefield.PickledFormField":{__init__:[340,3,1,""],clean:[340,3,1,""],default_error_messages:[340,4,1,""],widget:[340,4,1,""]},"evennia.utils.picklefield.PickledObjectField":{__init__:[340,3,1,""],formfield:[340,3,1,""],from_db_value:[340,3,1,""],get_db_prep_lookup:[340,3,1,""],get_db_prep_value:[340,3,1,""],get_default:[340,3,1,""],get_internal_type:[340,3,1,""],pre_save:[340,3,1,""],value_to_string:[340,3,1,""]},"evennia.utils.picklefield.PickledWidget":{media:[340,3,1,""],render:[340,3,1,""],value_from_datadict:[340,3,1,""]},"evennia.utils.search":{search_account:[341,5,1,""],search_account_tag:[341,5,1,""],search_channel:[341,5,1,""],search_channel_tag:[341,5,1,""],search_help_entry:[341,5,1,""],search_message:[341,5,1,""],search_object:[341,5,1,""],search_script:[341,5,1,""],search_script_tag:[341,5,1,""],search_tag:[341,5,1,""]},"evennia.utils.test_resources":{BaseEvenniaCommandTest:[342,1,1,""],BaseEvenniaTest:[342,1,1,""],BaseEvenniaTestCase:[342,1,1,""],EvenniaCommandTest:[342,1,1,""],EvenniaCommandTestMixin:[342,1,1,""],EvenniaTest:[342,1,1,""],EvenniaTestCase:[342,1,1,""],EvenniaTestMixin:[342,1,1,""],mockdeferLater:[342,5,1,""],mockdelay:[342,5,1,""],unload_module:[342,5,1,""]},"evennia.utils.test_resources.EvenniaCommandTestMixin":{call:[342,3,1,""]},"evennia.utils.test_resources.EvenniaTest":{account_typeclass:[342,4,1,""],character_typeclass:[342,4,1,""],exit_typeclass:[342,4,1,""],object_typeclass:[342,4,1,""],room_typeclass:[342,4,1,""],script_typeclass:[342,4,1,""]},"evennia.utils.test_resources.EvenniaTestMixin":{account_typeclass:[342,4,1,""],character_typeclass:[342,4,1,""],create_accounts:[342,3,1,""],create_chars:[342,3,1,""],create_objs:[342,3,1,""],create_rooms:[342,3,1,""],create_script:[342,3,1,""],exit_typeclass:[342,4,1,""],object_typeclass:[342,4,1,""],room_typeclass:[342,4,1,""],script_typeclass:[342,4,1,""],setUp:[342,3,1,""],setup_session:[342,3,1,""],tearDown:[342,3,1,""],teardown_accounts:[342,3,1,""],teardown_session:[342,3,1,""]},"evennia.utils.text2html":{TextToHTMLparser:[343,1,1,""],parse_html:[343,5,1,""]},"evennia.utils.text2html.TextToHTMLparser":{bg_colormap:[343,4,1,""],bgfgstart:[343,4,1,""],bgfgstop:[343,4,1,""],bgstart:[343,4,1,""],bgstop:[343,4,1,""],blink:[343,4,1,""],colorback:[343,4,1,""],colorcodes:[343,4,1,""],convert_linebreaks:[343,3,1,""],convert_urls:[343,3,1,""],fg_colormap:[343,4,1,""],fgstart:[343,4,1,""],fgstop:[343,4,1,""],hilite:[343,4,1,""],inverse:[343,4,1,""],normal:[343,4,1,""],parse:[343,3,1,""],re_bgfg:[343,4,1,""],re_bgs:[343,4,1,""],re_blink:[343,4,1,""],re_blinking:[343,3,1,""],re_bold:[343,3,1,""],re_color:[343,3,1,""],re_dblspace:[343,4,1,""],re_double_space:[343,3,1,""],re_fgs:[343,4,1,""],re_hilite:[343,4,1,""],re_inverse:[343,4,1,""],re_inversing:[343,3,1,""],re_mxplink:[343,4,1,""],re_mxpurl:[343,4,1,""],re_normal:[343,4,1,""],re_string:[343,4,1,""],re_uline:[343,4,1,""],re_underline:[343,3,1,""],re_unhilite:[343,4,1,""],re_url:[343,4,1,""],remove_backspaces:[343,3,1,""],remove_bells:[343,3,1,""],sub_dblspace:[343,3,1,""],sub_mxp_links:[343,3,1,""],sub_mxp_urls:[343,3,1,""],sub_text:[343,3,1,""],tabstop:[343,4,1,""],underline:[343,4,1,""],unhilite:[343,4,1,""]},"evennia.utils.utils":{LimitedSizeOrderedDict:[344,1,1,""],all_from_module:[344,5,1,""],at_search_result:[344,5,1,""],callables_from_module:[344,5,1,""],calledby:[344,5,1,""],check_evennia_dependencies:[344,5,1,""],class_from_module:[344,5,1,""],columnize:[344,5,1,""],copy_word_case:[344,5,1,""],crop:[344,5,1,""],datetime_format:[344,5,1,""],dbid_to_obj:[344,5,1,""],dbref:[344,5,1,""],dbref_to_obj:[344,5,1,""],dedent:[344,5,1,""],deepsize:[344,5,1,""],delay:[344,5,1,""],display_len:[344,5,1,""],fill:[344,5,1,""],format_grid:[344,5,1,""],format_table:[344,5,1,""],fuzzy_import_from_module:[344,5,1,""],get_all_cmdsets:[344,5,1,""],get_all_typeclasses:[344,5,1,""],get_evennia_pids:[344,5,1,""],get_evennia_version:[344,5,1,""],get_game_dir_path:[344,5,1,""],has_parent:[344,5,1,""],host_os_is:[344,5,1,""],inherits_from:[344,5,1,""],init_new_account:[344,5,1,""],interactive:[344,5,1,""],is_iter:[344,5,1,""],iter_to_str:[344,5,1,""],iter_to_string:[344,5,1,""],justify:[344,5,1,""],latinify:[344,5,1,""],lazy_property:[344,1,1,""],list_to_string:[344,5,1,""],m_len:[344,5,1,""],make_iter:[344,5,1,""],mod_import:[344,5,1,""],mod_import_from_path:[344,5,1,""],object_from_module:[344,5,1,""],pad:[344,5,1,""],percent:[344,5,1,""],percentile:[344,5,1,""],pypath_to_realpath:[344,5,1,""],random_string_from_module:[344,5,1,""],repeat:[344,5,1,""],run_async:[344,5,1,""],safe_convert_to_types:[344,5,1,""],server_services:[344,5,1,""],string_from_module:[344,5,1,""],string_partial_matching:[344,5,1,""],string_similarity:[344,5,1,""],string_suggestions:[344,5,1,""],strip_control_sequences:[344,5,1,""],strip_unsafe_input:[344,5,1,""],time_format:[344,5,1,""],to_bytes:[344,5,1,""],to_str:[344,5,1,""],unrepeat:[344,5,1,""],uses_database:[344,5,1,""],validate_email_address:[344,5,1,""],variable_from_module:[344,5,1,""],wildcard_to_regexp:[344,5,1,""],wrap:[344,5,1,""]},"evennia.utils.utils.LimitedSizeOrderedDict":{__init__:[344,3,1,""],update:[344,3,1,""]},"evennia.utils.utils.lazy_property":{__init__:[344,3,1,""]},"evennia.utils.validatorfuncs":{"boolean":[345,5,1,""],color:[345,5,1,""],datetime:[345,5,1,""],duration:[345,5,1,""],email:[345,5,1,""],future:[345,5,1,""],lock:[345,5,1,""],positive_integer:[345,5,1,""],signed_integer:[345,5,1,""],text:[345,5,1,""],timezone:[345,5,1,""],unsigned_integer:[345,5,1,""]},"evennia.web":{urls:[347,0,0,"-"],utils:[348,0,0,"-"],webclient:[353,0,0,"-"],website:[356,0,0,"-"]},"evennia.web.utils":{backends:[349,0,0,"-"],general_context:[350,0,0,"-"],middleware:[351,0,0,"-"],tests:[352,0,0,"-"]},"evennia.web.utils.backends":{CaseInsensitiveModelBackend:[349,1,1,""]},"evennia.web.utils.backends.CaseInsensitiveModelBackend":{authenticate:[349,3,1,""]},"evennia.web.utils.general_context":{general_context:[350,5,1,""],load_game_settings:[350,5,1,""]},"evennia.web.utils.middleware":{SharedLoginMiddleware:[351,1,1,""]},"evennia.web.utils.middleware.SharedLoginMiddleware":{__init__:[351,3,1,""],make_shared_login:[351,3,1,""]},"evennia.web.utils.tests":{TestGeneralContext:[352,1,1,""]},"evennia.web.utils.tests.TestGeneralContext":{maxDiff:[352,4,1,""],test_general_context:[352,3,1,""]},"evennia.web.webclient":{urls:[354,0,0,"-"],views:[355,0,0,"-"]},"evennia.web.webclient.views":{webclient:[355,5,1,""]},"evennia.web.website":{forms:[357,0,0,"-"],tests:[360,0,0,"-"],urls:[361,0,0,"-"],views:[362,0,0,"-"]},"evennia.web.website.forms":{AccountForm:[357,1,1,""],CharacterForm:[357,1,1,""],CharacterUpdateForm:[357,1,1,""],EvenniaForm:[357,1,1,""],ObjectForm:[357,1,1,""]},"evennia.web.website.forms.AccountForm":{Meta:[357,1,1,""],base_fields:[357,4,1,""],declared_fields:[357,4,1,""],media:[357,3,1,""]},"evennia.web.website.forms.AccountForm.Meta":{field_classes:[357,4,1,""],fields:[357,4,1,""],model:[357,4,1,""]},"evennia.web.website.forms.CharacterForm":{Meta:[357,1,1,""],base_fields:[357,4,1,""],declared_fields:[357,4,1,""],media:[357,3,1,""]},"evennia.web.website.forms.CharacterForm.Meta":{fields:[357,4,1,""],labels:[357,4,1,""],model:[357,4,1,""]},"evennia.web.website.forms.CharacterUpdateForm":{base_fields:[357,4,1,""],declared_fields:[357,4,1,""],media:[357,3,1,""]},"evennia.web.website.forms.EvenniaForm":{base_fields:[357,4,1,""],clean:[357,3,1,""],declared_fields:[357,4,1,""],media:[357,3,1,""]},"evennia.web.website.forms.ObjectForm":{Meta:[357,1,1,""],base_fields:[357,4,1,""],declared_fields:[357,4,1,""],media:[357,3,1,""]},"evennia.web.website.forms.ObjectForm.Meta":{fields:[357,4,1,""],labels:[357,4,1,""],model:[357,4,1,""]},"evennia.web.website.tests":{AdminTest:[360,1,1,""],ChannelDetailTest:[360,1,1,""],ChannelListTest:[360,1,1,""],CharacterCreateView:[360,1,1,""],CharacterDeleteView:[360,1,1,""],CharacterListView:[360,1,1,""],CharacterManageView:[360,1,1,""],CharacterPuppetView:[360,1,1,""],CharacterUpdateView:[360,1,1,""],EvenniaWebTest:[360,1,1,""],HelpDetailTest:[360,1,1,""],HelpListTest:[360,1,1,""],HelpLockedDetailTest:[360,1,1,""],IndexTest:[360,1,1,""],LoginTest:[360,1,1,""],LogoutTest:[360,1,1,""],PasswordResetTest:[360,1,1,""],RegisterTest:[360,1,1,""],WebclientTest:[360,1,1,""]},"evennia.web.website.tests.AdminTest":{unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.ChannelDetailTest":{get_kwargs:[360,3,1,""],setUp:[360,3,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.ChannelListTest":{url_name:[360,4,1,""]},"evennia.web.website.tests.CharacterCreateView":{test_valid_access_multisession_0:[360,3,1,""],test_valid_access_multisession_2:[360,3,1,""],unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.CharacterDeleteView":{get_kwargs:[360,3,1,""],test_invalid_access:[360,3,1,""],test_valid_access:[360,3,1,""],unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.CharacterListView":{unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.CharacterManageView":{unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.CharacterPuppetView":{get_kwargs:[360,3,1,""],test_invalid_access:[360,3,1,""],unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.CharacterUpdateView":{get_kwargs:[360,3,1,""],test_invalid_access:[360,3,1,""],test_valid_access:[360,3,1,""],unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.EvenniaWebTest":{account_typeclass:[360,4,1,""],authenticated_response:[360,4,1,""],channel_typeclass:[360,4,1,""],character_typeclass:[360,4,1,""],exit_typeclass:[360,4,1,""],get_kwargs:[360,3,1,""],login:[360,3,1,""],object_typeclass:[360,4,1,""],room_typeclass:[360,4,1,""],script_typeclass:[360,4,1,""],setUp:[360,3,1,""],test_get:[360,3,1,""],test_get_authenticated:[360,3,1,""],test_valid_chars:[360,3,1,""],unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.HelpDetailTest":{get_kwargs:[360,3,1,""],setUp:[360,3,1,""],test_object_cache:[360,3,1,""],test_view:[360,3,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.HelpListTest":{url_name:[360,4,1,""]},"evennia.web.website.tests.HelpLockedDetailTest":{get_kwargs:[360,3,1,""],setUp:[360,3,1,""],test_lock_with_perm:[360,3,1,""],test_locked_entry:[360,3,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.IndexTest":{url_name:[360,4,1,""]},"evennia.web.website.tests.LoginTest":{url_name:[360,4,1,""]},"evennia.web.website.tests.LogoutTest":{url_name:[360,4,1,""]},"evennia.web.website.tests.PasswordResetTest":{unauthenticated_response:[360,4,1,""],url_name:[360,4,1,""]},"evennia.web.website.tests.RegisterTest":{url_name:[360,4,1,""]},"evennia.web.website.tests.WebclientTest":{test_get:[360,3,1,""],test_get_disabled:[360,3,1,""],url_name:[360,4,1,""]},evennia:{accounts:[143,0,0,"-"],commands:[149,0,0,"-"],comms:[172,0,0,"-"],contrib:[178,0,0,"-"],help:[236,0,0,"-"],locks:[240,0,0,"-"],objects:[243,0,0,"-"],prototypes:[248,0,0,"-"],scripts:[253,0,0,"-"],server:[262,0,0,"-"],set_trace:[141,5,1,""],settings_default:[313,0,0,"-"],typeclasses:[314,0,0,"-"],utils:[320,0,0,"-"],web:[346,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","exception","Python exception"],"3":["py","method","Python method"],"4":["py","attribute","Python attribute"],"5":["py","function","Python function"]},objtypes:{"0":"py:module","1":"py:class","2":"py:exception","3":"py:method","4":"py:attribute","5":"py:function"},terms:{"000":[0,25,46,82,114,343],"0000":[0,46],"0004":22,"001":[22,127,343],"002":343,"003":343,"004":343,"005":[114,321,343],"006":343,"007":343,"008":343,"009":343,"00sc":124,"010":[25,343],"011":343,"012":343,"013":343,"014":343,"015":343,"015public":25,"016":343,"017":343,"018":343,"019":343,"020":343,"020t":25,"021":343,"022":343,"023":343,"024":343,"0247":22,"025":343,"026":343,"027":343,"028":343,"029":343,"030":343,"030a":25,"031":343,"032":343,"033":[321,343],"034":[22,343],"035":343,"036":343,"037":343,"038":343,"039":343,"040":343,"040f":25,"041":343,"042":343,"043":343,"044":343,"045":343,"046":343,"047":343,"048":343,"049":343,"050":[321,343],"050f":25,"051":343,"052":343,"053":343,"054":[114,343],"055":[321,343],"056":343,"057":343,"058":343,"059":343,"060":343,"061":343,"062":343,"062022":363,"063":343,"064":343,"065":343,"066":343,"067":343,"068":343,"069":343,"070":343,"071":343,"072":343,"073":343,"074":343,"075":343,"076":343,"077":343,"078":343,"079":343,"080":343,"081":343,"082":343,"083":343,"084":343,"085":343,"086":343,"087":343,"088":343,"089":343,"090":343,"091":343,"092":343,"093":343,"094":343,"095":343,"096":343,"097":343,"098":343,"099":343,"0b16":24,"0d0":56,"0x045a0990":42,"0x852be2c":59,"100":[31,56,73,85,93,111,125,169,343,344],"1000":[56,93,100,116,251],"1000000":[82,93,337],"100m":343,"100mb":90,"101":[31,247,343],"101m":343,"102":343,"102m":343,"103":343,"103m":343,"104":343,"104m":343,"105":343,"105m":343,"106":343,"106m":343,"107":343,"107m":343,"108":343,"108m":343,"109":343,"1098":125,"109m":343,"10m":67,"110":[321,329,343],"110m":343,"111":[12,114,157,343],"111m":343,"112":343,"112m":343,"113":[90,343],"113m":343,"114":343,"114m":343,"115":343,"115600":56,"115m":343,"116":343,"116m":343,"117":343,"1172":138,"117m":343,"118":[115,343],"1184":23,"118m":343,"119":343,"119m":343,"120":[31,343],"1200":327,"120m":343,"121":343,"121m":343,"122":343,"122m":343,"123":[131,134,247,343],"1234":[54,109],"123dark":81,"123m":343,"124":343,"12400":82,"124m":343,"125":343,"125m":343,"126":343,"126m":343,"127":[8,9,24,63,67,90,287,343],"127m":343,"128":343,"128m":343,"129":343,"129m":343,"12s":27,"130":343,"130m":343,"131":343,"131m":343,"132":343,"132m":343,"133":343,"133m":343,"134":[12,157,343],"134m":343,"135":343,"135m":343,"136":343,"136m":343,"137":343,"137m":343,"138":343,"138m":343,"139":343,"139m":343,"140":[25,42,141,343],"1400":327,"140313967648552":33,"140m":343,"141":[139,343],"141m":343,"142":[22,343],"1424724909023":70,"142m":343,"143":343,"143m":343,"144":343,"144m":343,"145":343,"145m":343,"146":343,"146m":343,"147":343,"147m":343,"148":343,"148m":343,"149":343,"149m":343,"150":[326,343],"150m":343,"151":343,"151m":343,"152":343,"152m":343,"153":343,"153m":343,"154":343,"154m":343,"155":343,"155m":343,"156":[127,343],"156m":343,"157":343,"1577865600":62,"157m":343,"158":343,"158m":343,"159":343,"159m":343,"160":343,"160m":343,"161":343,"161m":343,"162":343,"162m":343,"163":343,"163m":343,"164":343,"164m":343,"165":343,"165m":343,"166":343,"166m":343,"167":343,"167m":343,"168":343,"168m":343,"169":343,"169m":343,"16m":343,"170":343,"170m":343,"171":343,"171m":343,"172":343,"172m":343,"173":343,"1730":79,"173m":343,"174":343,"174m":343,"175":343,"175m":343,"176":343,"1764":119,"176m":343,"177":343,"177m":343,"178":343,"178m":343,"179":343,"179m":343,"17m":343,"180":343,"180m":343,"181":343,"181m":343,"182":343,"182m":343,"183":343,"183m":343,"184":343,"184m":343,"185":343,"185m":343,"186":343,"186m":343,"187":343,"187m":343,"188":343,"188m":343,"189":343,"189m":343,"18m":343,"190":343,"1903":119,"190m":343,"191":343,"191m":343,"192":343,"192m":343,"193":343,"193m":343,"194":343,"194m":343,"195":343,"195m":343,"196":343,"196m":343,"197":343,"1970":62,"197m":343,"198":343,"198m":343,"199":343,"1996":79,"1998":79,"199m":343,"19m":343,"1_7":127,"1d100":73,"1d2":56,"1d6":73,"1gb":90,"1st":62,"200":[343,360],"2001":79,"2003":79,"2004":79,"2008":344,"200m":343,"201":343,"2010":343,"2011":124,"2014":21,"2015":24,"2016":99,"2017":[62,90,97,364],"2018":9,"2019":[79,364],"201m":343,"202":343,"2020":[12,62,363],"2020_01_29":337,"2020_01_29__1":337,"2020_01_29__2":337,"202m":343,"203":[90,343],"203m":343,"204":343,"2048":67,"204m":343,"205":[327,343],"205m":343,"206":343,"206m":343,"207":343,"2076":119,"207m":343,"208":[91,343],"208m":343,"209":343,"209m":343,"20m":343,"210":343,"210m":343,"211":343,"211m":343,"212":[12,343],"2128":56,"212m":343,"213":343,"213m":343,"214":343,"214m":343,"215":343,"215m":343,"216":343,"216m":343,"217":343,"217m":343,"218":343,"218m":343,"219":[9,343],"219m":343,"21m":343,"220":343,"220m":343,"221":[322,343],"221m":343,"222":[114,321,343],"222m":343,"223":[12,343],"223m":343,"224":343,"224m":343,"225":[12,343],"225m":343,"226":343,"226m":343,"227":343,"227m":343,"228":343,"228m":343,"229":343,"229m":343,"22m":[321,343],"22nd":344,"230":[114,343],"230m":343,"231":343,"231m":343,"232":343,"232m":343,"233":[12,157,343],"233m":343,"234":343,"234m":343,"235":343,"235m":343,"236":343,"236m":343,"237":[12,343],"237m":343,"238":343,"238m":343,"239":343,"239m":343,"23m":343,"240":343,"240m":343,"241":343,"241m":343,"242":343,"242m":343,"243":343,"243m":343,"244":343,"244m":343,"245":343,"245m":343,"246":343,"246m":343,"247":343,"247m":343,"248":343,"248m":343,"249":343,"249m":343,"24m":343,"250":343,"250m":343,"251":343,"251m":343,"252":343,"252m":343,"253":343,"253m":343,"254":343,"254m":343,"255":[24,321,343],"255m":343,"256":[12,114,156,321],"25m":343,"26m":343,"27m":343,"280":71,"28gmcp":291,"28m":343,"29m":343,"2d6":58,"2gb":90,"300":[114,126,331],"3000000":82,"302":360,"30m":[321,343],"31m":[321,343],"31st":62,"32bit":[24,63],"32m":[321,343],"32nd":58,"333":[12,114],"33333":59,"33m":[321,343],"340":56,"34m":[321,343],"358283996582031":93,"35m":[321,343],"360":62,"3600":62,"36m":[321,343],"37m":[321,343],"3872":119,"38m":343,"39m":343,"3c3ccec30f037be174d3":344,"3rd":[62,364],"4000":[9,36,63,67,75,90,95,100,101,103],"4001":[3,4,8,9,36,63,67,69,75,90,95,100,101,103,133,134,135,137,296],"4002":[8,36,67,90,100],"4003":90,"4004":90,"4005":90,"4006":90,"403":131,"404":69,"40m":[321,343],"41917":287,"41m":[321,343],"4201":90,"425":321,"4280":55,"42m":[321,343],"430000":62,"431":321,"43m":[321,343],"443":[8,67,103],"444":114,"44m":[321,343],"45m":[27,321,343],"46m":[321,343],"47m":[321,343],"48m":343,"49m":343,"4er43233fwefwfw":9,"4th":[38,79],"500":[114,126,321],"50000":82,"500red":321,"505":321,"50m":343,"50mb":90,"516106":56,"51m":343,"520":114,"52m":343,"53m":343,"54m":343,"550":[321,327],"550n":25,"551e":25,"552w":25,"553b":25,"554i":25,"555":[114,321],"555e":25,"55m":343,"565000":62,"56m":343,"577349":343,"57m":343,"5885d80a13c0db1f8e263663d3faee8d66f31424b43e9a70645c907a6cbd8fb4":37,"58m":343,"593":344,"59m":343,"5d5":56,"5fdonatecc":70,"5flg":70,"5fu":70,"5x5":111,"600":344,"60m":343,"614":138,"61m":343,"62m":343,"63m":343,"64m":343,"65m":343,"6666":40,"6667":[72,79,146,164,308],"66m":343,"67m":343,"68m":343,"69m":343,"6d6":56,"70982813835144":93,"70m":343,"71m":343,"72m":343,"73m":343,"74m":343,"75m":343,"760000":62,"76m":343,"775":36,"77m":343,"78m":343,"79m":343,"8080":90,"80m":343,"8111":36,"81m":343,"82m":343,"83m":343,"84m":343,"85000":82,"85m":343,"86400":120,"86m":343,"87m":343,"8859":[15,113,171],"88m":343,"89m":343,"8f64fec2670c":90,"900":327,"9000":357,"90m":343,"90s":345,"91m":343,"92m":343,"93m":343,"94m":343,"95m":343,"96m":343,"97m":343,"98m":343,"990":327,"99999":61,"99m":343,"9th":364,"\u6d4b\u8bd5":25,"abstract":[47,64,86,119,316,317,318,334,338,344],"boolean":[13,33,133,137,154,242,247,259,287,316,319,321,322,338,345],"break":[10,12,14,30,37,42,51,54,57,58,61,91,96,103,108,111,114,125,137,141,159,166,167,276,321,328,329,344],"byte":[15,27,113,267,269,276,278,287,295,344],"case":[1,6,8,10,11,12,13,14,15,21,22,25,27,28,29,31,33,34,37,38,40,41,42,44,46,49,51,55,58,59,60,61,62,64,69,74,79,80,81,82,83,86,88,89,91,95,96,100,102,103,105,107,108,109,110,111,113,114,116,119,120,121,123,125,127,128,131,133,137,144,146,147,151,153,154,156,159,165,166,167,175,176,238,239,241,242,245,247,251,256,258,272,276,280,284,298,305,308,316,317,318,319,321,323,334,341,342,344,349,364],"catch":[15,26,27,30,51,58,87,91,97,102,115,118,146,165,257,267,272,279,305,306,316,326,328,329,334,337,340],"char":[56,58,71,73,85,88,105,111,116,119,120,133,144,159,165,247,264,277,290,291,312,321,327,330],"class":[1,2,3,5,6,10,11,12,16,17,20,21,25,26,28,29,30,31,38,39,40,42,44,47,49,50,52,53,55,56,57,58,60,61,62,64,68,71,73,77,81,82,85,86,89,91,97,102,105,109,116,117,118,119,120,121,123,124,132,133,134,135,144,146,147,148,149,152,153,154,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,175,176,177,238,239,242,243,245,246,247,249,251,252,255,256,257,258,259,260,261,264,265,267,269,270,273,274,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,298,300,303,305,306,307,308,310,311,312,314,316,317,318,319,321,322,323,324,325,326,327,328,329,330,331,333,334,335,337,338,339,340,341,342,343,344,347,349,351,352,357,360,364],"default":[0,1,2,3,4,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,27,29,31,32,33,34,35,36,38,39,40,41,42,45,46,47,49,50,51,53,56,57,58,59,62,63,64,65,66,67,68,69,71,72,75,76,77,81,82,83,85,86,87,88,89,90,91,93,95,96,97,100,101,102,103,104,105,106,107,109,111,112,113,114,116,117,118,119,121,123,124,125,126,127,128,129,131,133,134,135,136,138,139,140,141,142,144,146,148,149,150,151,152,153,154,175,176,177,236,238,239,240,242,245,247,251,252,256,257,259,260,261,265,267,269,271,272,273,277,289,290,291,296,298,299,305,306,307,308,312,313,316,317,318,319,321,323,324,326,328,329,330,333,334,337,338,339,340,341,342,344,345,349,357,364],"export":75,"final":[10,23,26,27,29,33,36,38,39,41,58,63,67,68,69,70,73,76,80,83,85,86,102,103,105,109,114,116,123,125,126,127,133,134,136,150,151,152,159,164,168,242,252,304,308,321,323,328,329,364],"float":[38,49,114,146,260,267,279,317,331,340,344],"function":[3,4,5,6,9,10,11,13,14,18,19,20,21,23,25,26,27,29,33,34,37,38,40,41,44,46,48,50,52,55,57,58,59,60,61,62,63,64,68,69,73,74,75,77,81,82,83,85,86,88,91,93,96,104,106,107,108,109,110,111,115,118,119,121,122,123,124,125,127,128,133,134,135,137,138,140,141,144,148,151,153,154,156,157,158,159,160,164,165,166,167,169,170,171,175,176,239,240,241,242,247,250,251,252,257,259,260,261,267,271,272,276,287,288,293,296,299,306,308,310,318,319,320,321,322,324,325,326,328,329,331,337,338,339,342,343,344,345,347,364],"g\u00e9n\u00e9ral":79,"goto":[85,328,364],"import":[0,2,3,4,5,6,9,10,11,13,14,15,16,19,20,21,22,25,27,28,29,30,31,33,39,40,42,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,68,69,71,72,73,74,76,77,80,81,82,83,84,85,86,89,90,91,93,96,97,102,103,104,105,106,107,110,111,112,113,114,115,116,117,118,119,120,121,123,125,126,127,132,133,134,135,136,137,138,140,141,153,159,169,238,242,251,252,261,267,271,279,280,301,305,308,309,316,318,322,323,326,327,328,329,330,341,342,344,364],"int":[11,25,31,39,49,51,56,58,74,85,91,114,123,125,134,144,146,147,151,152,154,176,245,247,252,255,258,260,261,264,265,267,272,276,277,278,279,281,285,286,287,295,296,298,308,310,312,316,317,321,324,326,327,328,329,330,331,334,337,341,344],"long":[9,10,15,20,22,23,25,26,27,29,33,37,38,40,44,46,49,51,52,55,58,60,62,64,68,71,72,73,78,79,80,81,85,86,87,90,105,108,111,113,115,118,121,125,126,127,129,131,133,135,138,139,156,166,276,281,296,321,322,329,330,344],"new":[0,2,5,9,11,12,13,14,16,19,20,21,22,23,24,25,26,27,29,31,33,34,35,36,37,38,39,40,41,43,44,45,49,50,51,54,55,57,61,62,63,64,65,67,68,70,71,72,73,75,76,77,78,79,80,81,82,83,84,85,88,89,90,91,92,93,95,96,98,100,101,104,105,106,107,108,109,111,112,116,117,118,121,122,123,124,128,129,131,132,134,135,136,137,138,139,144,146,147,152,153,154,156,157,159,164,166,167,170,171,175,176,239,242,245,246,247,249,251,252,255,256,259,260,261,264,267,276,277,278,279,285,286,287,292,299,307,308,312,316,317,318,319,321,322,324,327,328,329,330,334,337,338,344,360,363,364],"null":[8,86],"public":[25,34,41,58,65,67,72,90,93,100,103,131,134,164,247,312,330,364],"return":[3,4,6,10,11,15,20,21,22,25,27,28,29,30,33,36,39,40,41,42,44,48,49,50,52,58,60,62,64,68,69,71,73,74,76,77,80,81,82,83,85,89,91,93,95,96,97,100,102,103,107,108,109,110,111,112,114,116,117,118,119,121,123,125,127,129,133,134,137,138,144,146,147,148,150,151,152,153,154,156,159,164,166,169,170,175,176,177,238,239,241,242,245,246,247,249,250,251,252,255,257,258,259,260,261,264,265,267,272,273,276,277,279,280,281,282,284,285,286,287,288,290,291,292,294,295,296,298,299,305,306,308,310,311,312,316,317,318,319,321,322,323,324,325,326,328,329,330,331,334,337,338,339,340,341,342,343,344,345,347,350,357,364],"short":[20,22,29,39,42,46,51,54,57,58,61,62,70,71,83,87,89,95,96,103,110,112,114,123,129,137,140,164,252,322,344],"static":[38,49,58,83,124,127,135,136,137,139,169,238,251,252,312,324,347,355,364],"super":[5,22,25,31,40,41,49,57,58,60,62,81,89,96,118,121,123,125,364],"switch":[0,2,9,10,13,14,16,19,20,23,25,31,33,34,46,50,58,65,68,72,76,80,81,82,88,90,98,114,116,121,122,123,125,126,129,131,137,138,156,157,158,159,164,165,166,167,169,171,176,256,318,324,329,345,364],"th\u00ed":20,"throw":[11,22,66,75,109,131,133,153,260,344],"true":[1,2,4,5,10,11,13,20,21,22,25,26,27,29,31,33,34,40,41,49,50,51,54,56,58,62,65,66,68,69,72,74,76,80,81,83,84,85,86,87,90,91,96,98,100,102,105,114,115,116,117,120,121,122,123,125,126,127,133,135,137,138,144,147,148,150,152,153,154,156,159,164,166,167,170,175,176,177,239,241,242,245,246,247,249,251,252,255,256,257,258,259,260,261,265,267,272,273,276,278,285,290,295,296,306,308,310,312,316,317,318,321,324,326,328,329,330,331,334,339,340,341,342,344,345],"try":[0,4,5,6,8,9,10,11,12,13,15,16,20,21,22,23,25,26,27,29,30,38,39,42,44,46,48,49,50,51,54,55,56,57,58,60,61,63,64,65,66,67,68,69,73,74,75,77,80,81,86,90,91,93,95,96,97,102,103,108,109,110,111,113,118,119,120,121,123,124,126,127,133,134,135,136,137,138,140,144,148,152,154,159,175,177,239,245,247,251,264,267,276,291,292,296,310,316,318,321,323,324,326,327,340,344,364],"var":[67,83,88,137,291,322],"void":56,"while":[0,9,10,11,13,14,20,22,23,25,28,29,31,33,35,37,38,41,49,50,51,55,56,57,58,62,63,70,75,83,86,90,91,93,95,96,103,108,109,110,111,114,116,118,119,121,122,124,127,129,133,134,136,137,138,144,156,159,166,167,170,247,251,252,259,291,314,316,318,328,330,342,344,345,363],AIs:79,AND:[73,80,119,159,242,316,319],ARE:77,AWS:[90,100],Adding:[18,32,33,45,60,71,82,85,108,116,124,139,166,328,364],Age:357,And:[0,4,9,10,11,21,22,25,26,29,33,36,41,42,46,51,57,61,62,69,73,80,86,91,96,105,111,126,133,138,153,364],Are:[33,61,79,82,328],Aye:46,BGs:126,Being:[58,81,122,123],But:[0,6,10,11,13,15,20,21,22,25,26,27,28,29,31,33,37,38,39,41,42,44,51,54,55,57,59,60,61,62,64,69,72,73,80,82,83,85,86,91,95,96,100,102,104,107,109,111,114,119,125,126,127,133,134,138,152,153,251,319],DNS:[67,90],DoS:285,Doing:[29,33,55,73,134,153,156],For:[0,2,5,6,8,9,12,13,14,16,17,19,20,21,22,23,25,27,29,31,33,36,37,38,39,41,42,46,49,51,55,56,57,58,59,62,63,64,69,72,73,76,79,80,81,83,85,86,88,90,91,93,95,96,98,100,102,103,105,109,110,111,113,114,116,121,123,126,127,129,131,132,133,134,135,136,138,139,140,144,152,153,154,159,164,166,169,175,176,177,239,241,242,247,252,260,287,291,296,316,318,321,325,328,338,340,342,344,350,357,364],GMs:58,Has:24,His:57,IDE:[38,48,106],IDEs:57,IDs:[0,100,133,134,316,344],INTO:159,IOS:24,IPs:[12,103,310],IRE:[88,291],Its:[41,62,69,80,83,86,89,105,164,252,326,328,344],LTS:97,NOT:[11,25,33,80,90,103,119,137,159,242,252,310,364],Not:[8,24,30,41,54,57,61,74,90,108,112,115,127,131,132,133,137,146,153,167,247,264,277,278,279,281,282,283,289,291,294,316,317,338],OBS:19,ONE:103,Obs:127,One:[0,8,12,20,22,25,29,34,36,38,46,49,51,57,58,60,63,64,69,76,79,80,87,91,95,102,105,110,115,117,121,123,126,128,130,131,132,138,141,148,150,166,245,251,252,277,305,316,317,321,322,328,329,344],PMs:364,PRs:131,Such:[6,13,28,33,37,48,51,57,64,73,127,159,252,321,328],THAT:91,THEN:153,TLS:[103,364],That:[0,3,4,9,10,15,21,22,25,26,31,33,39,41,42,46,49,55,57,62,64,68,69,73,74,77,91,93,95,96,98,102,105,111,112,115,119,122,125,127,131,134,136,138,140,242,252,308,328],The:[0,2,4,5,6,7,8,9,12,15,17,20,21,23,24,25,27,28,30,31,33,34,36,37,38,39,40,42,43,44,45,48,52,53,54,55,56,57,59,60,61,62,63,64,66,67,68,70,72,73,74,75,76,78,79,80,81,82,84,86,87,88,89,90,91,92,95,97,98,100,101,102,103,104,105,106,107,108,110,111,112,113,114,115,118,119,120,121,122,124,125,126,127,128,129,131,132,133,134,136,137,138,139,140,144,146,147,148,150,151,152,153,154,156,159,163,164,165,166,167,168,169,170,171,175,176,177,236,238,239,241,242,245,246,247,249,250,251,252,255,256,257,258,259,260,261,264,265,266,267,269,271,272,274,276,277,278,279,280,281,282,283,284,285,286,287,289,290,291,292,294,295,296,298,299,304,305,306,307,308,312,316,317,318,319,321,322,323,324,325,326,327,328,329,330,331,332,334,337,338,339,340,341,342,344,345,347,357,363,364],Their:[51,73,103,109,114,124],Then:[0,9,15,22,38,39,41,42,46,56,61,63,69,91,93,100,107,127,131,137],There:[0,5,8,10,11,13,14,15,19,20,21,22,23,25,26,27,31,33,34,38,41,46,49,51,55,57,58,60,61,62,64,68,69,72,73,77,79,80,81,85,86,88,89,90,91,93,95,96,97,98,102,103,104,105,107,108,111,112,113,114,116,117,118,119,121,123,125,127,128,133,136,138,139,167,252,261,272,291,308,321,322,328,363],These:[0,4,5,9,11,13,17,22,25,33,34,35,38,39,40,47,49,51,59,61,65,68,69,73,74,83,86,88,90,91,95,96,100,102,103,105,107,109,110,111,112,114,119,121,122,124,125,127,131,133,137,138,139,143,144,150,152,154,156,158,160,164,168,176,238,242,247,251,252,261,266,273,292,295,296,298,307,308,309,316,318,321,325,328,329,330,331,337,338,339,344],USE:364,Use:[1,2,4,5,8,9,12,13,14,20,22,23,24,25,31,38,48,51,54,58,60,63,65,69,70,89,90,93,95,96,100,105,109,114,116,122,123,125,127,131,137,144,151,156,157,159,164,165,166,169,171,175,245,246,247,267,269,273,278,295,296,298,302,316,318,321,327,328,330,334,341,344,364],Used:[33,121,139,150,153,159,171,245,246,259,269,287,316,318,329,330,342,344],Useful:[12,51,90],Uses:[114,159,171,267,316,330,334],Using:[18,22,27,46,51,55,58,60,62,68,80,91,96,115,121,123,139,247,287,314,328,364],VCS:36,VPS:90,WILL:[24,91],WIS:58,WITH:23,Was:164,Will:[31,74,110,114,144,164,247,250,252,265,267,276,277,318,328,330,331,339,344,364],With:[8,11,15,19,23,55,57,77,87,100,111,114,122,123,141,144,252,316,321],Yes:[33,138,326,328,364],__1:337,__2:337,_________________:125,_________________________:51,______________________________:51,________________________________:51,_________________________________:125,______________________________________:328,______________________________________________:51,_______________________________________________:51,____________________________________________________:51,_________________________________________________________:85,__________________________________________________________:85,__defaultclasspath__:318,__dict__:267,__doc__:[33,59,68,154,167,169,170,238,239,324,328],__example__:97,__ge__:97,__getitem__:321,__init_:330,__init__:[3,6,11,40,47,49,53,96,97,107,125,152,153,154,177,242,246,247,251,257,258,260,261,264,265,267,269,270,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,294,295,296,298,305,306,308,310,311,312,316,318,319,321,323,326,327,328,329,330,337,338,339,340,344,351],__iter__:11,__multimatch_command:168,__noinput_command:[152,168,326,328,329],__nomatch_command:[168,326,328,329],__settingsclasspath__:318,__unloggedin_look_command:[43,171],_action_thre:51,_action_two:51,_all_:152,_and_:344,_asynctest:293,_attrs_to_sync:307,_attrtyp:316,_cach:318,_cached_cmdset:153,_callable_no:328,_callable_y:328,_callback:[27,261],_char_index:321,_check_password:51,_check_usernam:51,_clean_str:321,_cleanup_charact:116,_code_index:321,_copi:[159,247],_create_charact:133,_creation:125,_data:329,_default:[51,328],_defend:51,_differ:321,_errorcmdset:153,_evmenu:328,_famili:119,_file:337,_flag:251,_footer:33,_format_diff_text_and_opt:252,_funcnam:344,_get_a_random_goblin_nam:109,_get_db_hold:[306,318],_get_top:69,_getinput:328,_gettabl:272,_http11clientfactori:269,_init_charact:116,_is_fight:29,_is_in_mage_guild:51,_ital:38,_italic_:54,_loadfunc:326,_menutre:[25,51,328],_monitor:272,_monitor_callback:84,_nicklist_cal:146,_npage:329,_oob_at_:334,_option:51,_overrid:[135,137],_page_formatt:329,_pagin:329,_pending_request:312,_permission_hierarchi:241,_ping_cal:146,_playable_charact:[69,133],_postsav:334,_quell:241,_quitfunc:326,_raw_str:321,_reactor_stop:[284,305],_repeat:272,_safe_contents_upd:246,_savefunc:326,_saver:[11,325],_saverdict:[11,325],_saverlist:[11,325],_saverset:325,_select:51,_sensitive_:349,_session:328,_set:119,_set_attribut:51,_set_nam:51,_some_other_monitor_callback:84,_start_delai:261,_static:38,_stop_:344,_stop_serv:284,_templat:38,_test:150,_to_evt:329,_validate_fieldnam:58,_yes_no_quest:328,a2enmod:8,a8oc3d5b:100,aardwolf:88,abbrevi:[76,114,159],abcd:165,abi:60,abid:126,abil:[6,10,20,31,33,52,55,56,57,58,60,64,73,77,80,90,100,102,108,109,123,127,134,137,138,139,247,259,267,316],abl:[0,3,4,5,8,11,13,14,19,20,21,22,23,26,27,28,29,31,33,36,38,41,42,47,49,51,52,55,57,58,59,60,61,63,64,69,71,73,75,76,81,83,85,86,87,89,90,91,93,95,96,100,103,104,106,109,111,112,114,116,121,122,123,130,131,133,134,138,140,153,156,157,159,160,164,166,175,177,316,318,325,340,344,360],abort:[25,27,33,51,52,77,89,122,144,154,159,175,247,250,259,328,329,344,364],about:[0,3,9,10,11,12,13,14,15,16,17,20,21,22,23,24,25,26,30,31,33,36,37,38,39,41,42,43,44,45,46,48,51,54,55,57,59,60,61,63,64,68,69,70,71,73,75,76,77,78,79,81,83,85,86,90,91,93,95,96,97,100,101,103,104,108,109,110,112,113,114,116,118,119,120,123,124,126,127,131,134,135,136,138,139,144,159,166,169,239,247,267,269,272,281,283,285,294,296,298,299,306,308,317,319,321,329,334,344,363,364],abov:[2,4,8,9,10,11,12,13,14,21,23,24,27,28,29,30,31,33,36,37,38,40,44,46,49,50,51,56,57,58,59,60,62,63,64,67,68,69,74,80,81,84,85,86,90,91,93,95,96,100,102,105,106,109,110,111,112,114,116,118,119,121,123,125,127,131,132,133,135,137,138,140,152,153,159,242,245,247,272,328,339],abridg:41,absolut:[27,38,56,62,79,91,327,331,344],absorb:74,abspath:344,abstractus:148,abus:[7,103,364],academi:79,accept:[11,14,22,23,27,31,37,51,54,58,59,74,80,88,90,95,96,109,114,115,125,131,133,134,138,144,150,151,169,247,267,272,285,311,312,317,322,328,340,344],access:[0,4,7,8,11,12,13,14,19,21,22,23,25,27,29,31,33,38,39,40,41,43,47,49,51,52,53,56,57,58,59,60,63,64,66,68,69,71,73,74,80,83,84,85,86,87,90,91,95,96,100,101,102,103,104,105,107,108,109,111,112,114,116,119,121,123,124,125,126,127,128,131,133,134,135,137,139,144,147,148,152,153,154,156,157,159,164,165,166,167,169,171,175,176,177,238,239,240,241,242,246,247,250,251,252,256,258,260,261,264,267,276,277,306,308,314,316,318,319,322,323,324,337,343,344,357],access_obj:[241,316],access_object:80,access_opt:345,access_token_kei:[71,120],access_token_secret:[71,120],access_typ:[34,68,89,144,154,159,175,177,239,241,242,247,316,318,364],accessed_obj:[25,80,121,241,242],accessing_obj:[1,11,25,80,121,144,175,177,239,241,242,247,316,318],accessing_object:[11,80,241],accessor:[148,177,239,246,256,316,318,319,335],accessori:63,accident:[15,31,38,123,138,157,159,306],accommod:4,accomod:[101,330],accompani:123,accomplish:[12,25,41,49,55],accord:[31,33,111,116,126,260,321,322],accordingli:[49,58,90,106],account1:360,account2:360,account:[0,4,6,9,11,12,14,17,19,20,21,22,24,25,31,33,34,35,37,38,41,43,45,47,49,50,51,52,53,55,56,57,61,62,65,66,69,71,74,80,81,83,87,89,90,91,92,96,100,104,105,107,108,109,110,111,112,114,119,120,122,123,125,126,127,129,131,133,134,135,138,139,141,142,149,150,151,152,153,154,155,157,159,160,161,164,165,166,167,169,171,175,176,177,239,241,242,245,246,247,249,251,252,253,255,256,267,271,272,287,298,299,306,307,308,316,318,319,321,324,328,329,338,339,341,342,344,345,349,357,360,364],account_cal:[156,164,167],account_count:308,account_id:[133,247],account_nam:56,account_search:[147,247],account_subscription_set:148,account_typeclass:[342,360],accountcmdset:[2,22,31,41,43,57,58,62,156,160],accountdb:[53,119,125,133,141,144,148,154,175,239,314,318,338,345],accountdb_set:[316,319],accountdbmanag:[147,148],accountdbpasswordcheck:287,accountform:357,accountid:133,accountlist:58,accountmanag:[144,147],accountnam:[58,159,171,176],accru:144,accur:[22,154,252,260,265,267,269,270,278,287,288,290,292,295,296,316,321,339,340,351],accuraci:[46,91],accus:73,accustom:[87,124],achiev:[0,22,27,33,38,57,114,124,126,138,267],ack:52,acquaint:57,acquir:323,across:[16,20,40,51,56,61,86,91,102,105,108,109,125,144,152,153,238,247,259,261,264,276,277,291,308,329,330],act:[2,8,13,23,29,31,34,37,49,51,56,58,61,70,77,95,102,105,110,111,123,139,141,144,159,164,177,264,276,277,296,316,319,323,328],action1:116,action2:116,action:[0,11,22,29,39,41,42,46,51,55,57,61,62,64,73,88,90,91,93,102,114,116,117,118,123,133,138,144,146,154,164,165,169,175,238,239,251,256,257,279,298,299,300,310,318,328,329,334],action_count:116,actiondict:116,activ:[4,9,12,13,26,27,28,31,33,36,38,61,62,63,64,65,66,72,75,76,79,80,81,83,89,90,93,95,98,102,105,110,114,128,131,135,136,138,144,150,153,157,159,169,171,175,246,247,250,260,272,279,280,281,282,283,287,289,290,291,298,308,310,316,317,328,329,330,344,364],activest:343,actor:247,actual:[2,5,8,10,11,13,14,19,20,21,22,26,27,29,34,36,40,41,42,44,46,47,49,51,58,59,60,61,63,64,68,69,71,73,79,80,81,83,85,86,87,88,89,90,91,93,95,96,97,100,104,105,106,109,111,112,113,114,115,116,119,121,123,126,127,128,130,133,134,136,137,138,144,150,154,156,159,164,165,167,169,170,171,175,177,239,241,242,246,247,252,287,290,296,298,304,306,307,308,312,313,316,318,321,323,326,328,334,338,339,340,342,344,364],actual_return:127,adapt:[0,4,21,40,69,73,133],add:[0,2,5,6,8,9,10,11,13,14,15,16,17,19,20,21,22,24,26,29,30,31,33,34,35,36,37,38,39,40,41,42,43,44,46,47,48,49,50,51,54,55,57,58,61,62,64,65,66,67,68,69,71,73,74,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,93,95,96,98,100,102,104,105,106,109,111,112,113,114,115,116,117,118,119,120,121,123,124,125,127,128,131,132,133,134,135,137,138,139,140,141,144,148,152,153,159,164,165,166,168,170,175,177,241,242,246,247,251,252,256,257,258,259,260,261,267,272,273,277,280,281,283,285,289,296,298,299,301,309,316,319,322,326,327,328,329,330,334,337,339,340,342,364],add_:330,add_act:116,add_alia:164,add_charact:116,add_choic:364,add_choice_edit:22,add_choice_quit:22,add_collumn:154,add_column:[58,330],add_default:[21,31,85,96,121,153],add_head:330,add_row:[58,82,154,330],add_user_channel_alia:175,add_xp:73,addcallback:[33,247],addclass:[137,141,142,346,356,358,364],addcom:[43,58],added:[0,4,5,17,21,22,24,25,27,31,33,34,36,38,40,41,42,51,55,57,58,60,65,69,70,73,75,77,78,80,86,88,91,96,100,102,106,108,109,110,111,112,114,116,117,119,121,123,128,131,132,133,138,144,150,152,153,154,164,168,169,171,242,247,250,252,258,260,272,306,310,316,319,322,328,329,330,337,344,350],addendum:37,adding:[0,3,5,9,14,17,21,22,25,27,29,31,35,36,38,40,43,46,51,57,58,62,69,76,80,81,85,86,91,97,102,104,106,108,109,112,114,115,116,121,123,125,126,128,131,133,137,138,139,152,153,157,159,166,245,247,251,252,258,267,298,316,324,330,344,364],addingservermxp:282,addit:[4,8,22,25,31,36,37,38,46,49,50,51,58,62,69,76,82,88,90,91,103,104,109,114,119,134,144,146,153,154,166,175,242,247,250,260,278,306,316,318,328,357,364],addition:[25,111,119],additionalcmdset:31,addquot:344,addr:[147,264,277,278,279,324],address:[3,9,12,23,33,40,49,67,87,90,91,103,105,131,135,144,147,157,175,247,264,277,279,287,307,310,344,345,363,364],address_and_port:287,addscript:43,addservic:40,adject:97,adjust:[0,33,37,63,126,133,260,328,330],admin:[2,9,11,12,15,19,21,33,34,41,49,58,61,68,69,72,80,85,86,98,101,110,119,121,123,133,134,138,141,142,143,147,148,149,154,155,159,164,169,171,172,175,236,239,242,243,246,247,253,262,276,277,314,318,324,340,363,364],administr:[10,23,33,36,38,41,55,58,63,64,68,80,103,129,139,264,276,277,364],adminportal2serv:276,adminserver2port:276,adminstr:264,admintest:360,admit:39,adopt:[21,22,26,57,64,177,291],advanc:[10,12,13,22,28,31,33,39,40,44,51,55,58,64,79,86,93,104,105,108,109,111,119,123,124,125,139,159,167,282,322,326,327,328,330,364],advantag:[3,14,15,28,36,39,46,51,55,56,58,59,62,68,69,73,90,103,104,109,116,118,123,133,319,322],adventur:[20,41,77,111,122,124],advic:79,advis:[0,22,25,77],aeioui:119,aesthet:50,affair:323,affect:[11,13,14,19,25,31,33,61,62,73,80,81,105,112,114,116,126,127,128,131,138,144,152,169,247,251,318,322,330,338],affili:260,affliat:260,afford:[85,105],afraid:90,after:[0,5,8,9,10,11,14,15,20,21,22,25,27,28,29,30,31,33,36,38,39,41,44,46,49,50,51,55,58,60,63,67,68,76,77,79,80,83,85,86,90,91,96,100,102,103,107,114,116,117,121,122,123,126,127,128,130,131,133,136,138,139,144,152,153,154,155,156,159,166,167,169,170,171,175,246,247,252,255,257,259,260,267,289,290,293,298,305,306,307,308,310,312,316,321,322,323,326,328,329,334,339,343,344],afterthought:48,afterward:[20,29,69,86,91,119,131],again:[0,6,12,13,14,20,21,22,23,28,29,33,39,41,42,47,48,49,51,54,56,57,58,60,61,62,63,64,67,69,73,76,80,81,85,86,90,91,93,95,96,98,100,102,105,106,110,111,114,116,119,121,123,126,128,131,133,138,146,153,164,170,259,267,284,287,290,310,321,322,325,340,342],againnneven:170,against:[6,11,21,31,33,37,57,58,83,90,103,116,119,125,127,144,151,152,242,245,247,251,252,285,310,316,318,319,341,344],age:357,agenc:103,agent:36,agenta:[114,321],aggreg:79,aggress:[11,14,75,122,124,139,318,364],agi:[11,60,127],agil:[11,60],agnost:[37,64],ago:[25,100,344],agre:[1,73,113],ahead:[14,22,24,36,49,61,90,108,121,289],aid:[113,166,167,312],aim:[7,55,58,61,73,85,86,90,95,108,126,251],ain:46,ainnev:[73,119],air:[20,21,111],ajax:[40,55,90,137,296,307],ajaxwebcli:296,ajaxwebclientsess:296,aka:[9,11,93,344],alarm:[20,82],alert:[175,247],alexandrian:79,algebra:49,algorithm:[245,344],alia:[2,6,9,20,21,22,31,33,41,43,44,48,51,57,58,59,60,63,87,89,90,95,105,111,112,119,125,127,129,131,148,151,154,156,159,164,165,166,167,170,175,241,246,247,252,256,261,272,298,317,318,319,324,340,341,342,357,364],alias1:159,alias2:159,alias:[2,13,20,21,22,25,27,29,31,33,34,41,44,45,48,51,58,60,74,81,82,85,87,89,109,111,116,119,123,129,131,140,144,152,154,156,157,158,159,164,165,166,167,168,169,170,171,175,176,238,239,245,246,247,252,298,317,318,319,324,326,328,329,337,341,342,364],aliaschan:43,aliasdb:144,aliashandl:319,aliasnam:252,aliasstr:[245,324],align:[41,58,109,114,321,330,344],alik:68,alist:97,aliv:55,alkarouri:343,all:[0,1,2,3,5,6,8,9,10,11,12,13,14,15,16,17,19,20,21,22,23,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,43,44,46,47,48,49,50,53,54,55,56,57,58,59,60,61,62,63,64,68,70,72,73,74,75,76,77,78,79,80,81,82,83,85,86,87,88,89,90,91,93,95,96,97,98,100,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,121,122,123,124,125,126,127,128,129,131,132,133,134,135,136,137,138,139,140,144,146,147,149,150,151,152,153,154,155,156,157,158,159,160,161,164,165,166,167,168,169,170,171,175,176,177,238,239,240,241,242,243,245,246,247,250,251,252,255,257,258,259,260,261,262,266,267,271,272,273,276,278,279,281,283,284,285,286,287,290,291,294,295,296,298,299,305,306,307,308,310,312,313,314,316,317,318,319,321,322,323,324,325,326,327,328,329,330,334,337,339,341,342,343,344,345,347,350,357,363,364],all_alias:112,all_attr:318,all_cmd:166,all_connected_account:308,all_displai:261,all_famili:119,all_from_modul:344,all_kei:166,all_opt:339,all_receiv:247,all_room:13,all_script:102,all_sessions_portal_sync:308,all_to_categori:238,allcom:43,allerror:[267,276],allevi:[11,108,127,312],allheadersreceiv:312,alloc:90,allow:[0,2,3,4,6,8,9,10,11,12,13,14,15,16,19,21,22,23,25,26,27,29,30,31,33,34,36,38,39,41,42,44,46,47,49,51,53,54,55,57,58,59,61,63,64,65,68,71,72,73,74,75,76,78,80,81,85,86,87,89,90,91,92,95,96,97,98,100,101,102,103,104,106,108,109,111,112,113,114,116,119,121,123,125,126,129,131,133,134,135,137,138,144,146,148,150,152,153,154,156,157,158,159,164,166,167,169,170,175,176,177,239,241,242,245,247,251,252,257,260,261,267,271,272,274,278,280,281,282,283,290,291,292,294,299,305,306,308,310,311,316,318,319,321,322,324,326,328,329,330,331,334,338,339,340,342,344,357],allow_abort:328,allow_dupl:152,allow_nan:296,allow_quit:328,allowed_attr:58,allowed_fieldnam:58,allowed_host:[90,103],allowed_propnam:123,allowedmethod:296,allowext:312,almost:[19,33,41,95,115,119,125,269,276,314],alon:[13,29,49,51,56,58,73,80,86,87,116,127,138,152,166,261,272,298,322,324,330],alone_suffix:303,along:[5,12,33,48,51,60,64,70,74,78,88,91,93,96,100,104,107,114,121,122,139,144,156,242,247,296,314],alongsid:[5,67],alonw:256,alpha:[54,90,321,364],alphabet:[15,111,113,321],alreadi:[0,2,5,6,9,11,13,15,21,22,25,27,29,31,33,34,38,40,41,46,49,50,51,54,56,57,58,60,61,63,64,68,69,70,72,73,77,80,81,82,85,88,89,91,95,96,100,102,103,105,106,109,110,112,116,117,118,119,120,121,123,125,127,128,131,133,134,135,136,137,138,139,144,147,152,153,156,159,167,169,175,176,242,247,251,252,267,276,284,285,287,292,295,300,305,306,308,316,319,321,324,329,337,342,344,349],alredi:40,also:[0,1,2,3,5,6,8,9,10,11,12,13,14,15,16,17,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,44,46,47,48,49,50,51,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,72,73,74,75,77,79,80,81,82,83,84,85,86,87,88,89,90,91,93,95,96,97,98,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,121,122,123,124,125,126,127,128,129,131,132,133,134,135,136,137,138,140,144,147,148,151,152,153,154,156,157,158,159,161,164,165,166,167,169,170,175,176,177,240,241,242,245,246,247,251,252,253,256,259,261,262,267,271,272,276,278,285,287,290,291,294,295,298,299,308,312,314,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,334,341,342,344,363],alt:321,alter:[0,4,23,41,64,111,137,316],altern:[23,29,33,34,38,51,55,57,63,64,68,72,76,81,87,90,111,112,114,118,119,122,131,133,138,140,164,167,175,176,238,241,242,245,285,321,324,344,364],although:[22,29,39,42,63,119,156,312,340,344],althougn:46,altogeth:[50,103,114],alu:33,alwai:[0,2,4,6,8,11,12,13,14,20,21,23,25,27,30,31,33,34,37,38,39,47,49,51,57,58,61,62,63,64,69,72,73,74,77,80,85,86,88,89,90,91,95,96,102,105,107,109,112,114,115,121,123,125,126,127,128,131,134,135,137,144,152,153,154,156,158,159,164,166,167,170,175,176,177,241,242,245,246,247,251,252,261,267,269,272,276,284,287,290,291,295,296,299,306,308,313,316,317,318,319,321,324,334,340,341,344,345,350],always_pag:329,always_return:267,amaz:75,amazon:[79,90],ambianc:108,ambigu:[41,154,247,318],ambiti:[108,129],amend:131,amfl:14,ammo:21,among:[2,35,36,62,64,79,89,104,111,123,127,165,242,245,330,341],amongst:77,amount:[11,16,37,61,68,73,102,103,114,123,169,247,308,326],amp:[40,83,92,105,141,142,262,264,267,275,277,285,293,305,308,364],amp_client:[141,142,262,364],amp_maxlen:293,amp_port:90,amp_serv:[141,142,262,275,364],ampclientfactori:264,ampersand:108,amphack:276,ampl:124,amplauncherprotocol:267,ampmulticonnectionprotocol:[264,276,277],ampprotocol:264,ampserverclientprotocol:264,ampserverfactori:277,ampserverprotocol:277,amsterdam:90,anaconda:9,analog:[49,83],analys:51,analyz:[15,33,41,51,80,118,150,166,247,251,252,257,267,329,344,364],anchor:[154,175,239,318],ancient:114,andr:24,android:[139,364],anew:[63,111,175,267],angl:129,angri:41,angular:169,ani:[0,1,2,5,6,8,10,11,12,14,15,16,19,20,21,22,23,24,25,27,30,31,33,34,36,37,38,39,40,41,42,44,48,49,50,51,54,56,57,58,59,60,61,63,64,65,68,70,72,73,74,76,77,79,80,81,82,83,84,85,86,87,88,89,90,91,95,96,97,98,100,102,103,104,105,107,109,112,114,115,116,117,118,119,121,122,123,125,126,127,128,129,131,133,134,135,136,137,138,139,140,144,148,150,151,152,153,154,156,157,159,165,166,169,170,175,176,177,241,242,245,247,250,251,252,256,257,259,260,261,264,265,267,269,271,272,276,277,279,285,286,287,290,291,295,296,298,306,307,308,312,316,317,318,319,321,322,323,325,326,327,328,329,330,337,338,339,340,341,343,344,364],anim:[27,52],anna:[58,63,72,117,118,123,159],annoi:[12,85,91],annot:[79,364],announc:[25,37,79,116,123,128,157,164,169,175,247],announce_al:[285,308],announce_move_from:[25,77,89,247],announce_move_to:[25,77,89,247],annoy:144,anonym:[4,66,69],anoth:[0,8,10,11,13,14,16,21,22,29,31,33,36,39,42,46,49,51,56,57,58,62,63,64,67,69,77,78,80,89,90,91,96,97,98,102,105,106,108,109,111,112,113,114,116,121,123,127,131,132,136,137,138,139,140,144,152,153,156,159,164,165,175,239,247,250,308,316,318,322,326,328,329,342,344,364],another_batch_fil:322,another_nod:328,another_script:102,anotherscript:102,ansi:[24,53,55,74,81,137,141,142,156,272,279,287,290,295,296,320,330,343,344,364],ansi_escap:321,ansi_map:321,ansi_map_dict:321,ansi_pars:321,ansi_r:321,ansi_regex:321,ansi_sub:321,ansi_xterm256_bright_bg_map:321,ansi_xterm256_bright_bg_map_dict:321,ansimatch:321,ansimeta:321,ansipars:321,ansistr:[141,321,330],ansitextwrapp:330,answer:[0,11,21,25,26,33,46,51,61,63,67,69,70,73,95,96,103,127,265,328],anti:63,anul:8,anwer:44,any_options_her:38,anybodi:[59,103],anymor:[4,328,340],anyon:[1,4,12,21,25,29,41,42,54,58,60,76,80,85,90,116,118,119,123,138],anyth:[0,1,5,11,13,16,19,20,22,23,26,29,31,33,34,40,41,42,46,49,51,56,61,63,64,69,73,80,82,83,85,87,89,90,91,95,96,100,102,104,106,111,116,118,121,123,125,127,128,130,131,133,135,136,137,138,152,154,168,242,279,313,316,322,328],anywai:[0,4,14,20,51,55,75,76,91,95,108,114,140],anywher:[33,51,60,64,95,96,125,134,326],apach:[7,23,90,103,139,312,364],apache2:8,apache_wsgi:8,apart:[2,11,20,27,34,47,55,63,80,81,100,104,125,126,127,134],api:[13,15,26,27,34,42,47,48,52,59,60,71,73,89,96,105,109,111,120,125,133,138,139,141,144,158,169,171,177,306,316,318,322,323,329,363,364],api_kei:71,api_secret:71,apostroph:15,app:[4,40,71,80,86,90,134,135,136,138,139,364],app_id:133,appar:[48,58,126],appeal:[51,61,114],appear:[9,10,21,22,25,26,27,30,38,47,51,60,63,65,66,68,72,80,82,90,95,96,100,102,104,106,111,114,123,126,127,131,137,138,141,156,166,247,291,292,318,330,337],appearance_templ:247,append:[20,22,25,27,31,39,40,49,50,51,68,69,80,85,88,89,90,91,93,96,97,116,123,127,133,138,154,159,166,242,245,300,322,337,344],appendto:137,appform:133,appl:247,appli:[0,8,9,13,16,22,23,31,33,36,37,51,60,80,81,102,106,111,115,121,125,126,128,133,144,150,152,167,242,247,251,252,256,261,308,316,317,318,321,322,327,330,331,341,344],applic:[8,40,63,79,80,86,100,103,112,124,128,133,134,135,136,144,267,270,280,284,305,306,312,354],applicationdatareceiv:290,applied_d:133,appnam:[11,80],appreci:[22,37,70,78,334],approach:[22,25,39,56,77,91,106,115,133],appropri:[8,9,23,31,33,36,55,71,91,106,119,121,129,133,138,144,157,267,306,338,340,344,347],approrpri:40,approv:[133,134,138],approxim:[5,169,344],april:62,apt:[8,63,67,75,90,103,131],arbitr:61,arbitrari:[11,13,19,27,46,59,64,80,96,97,100,111,125,137,138,139,140,144,175,247,252,259,265,276,296,310,316,325,337,340,344,364],arcan:129,archer:252,architectur:[80,252],archiv:[79,103],archwizard:252,area:[2,22,24,48,49,51,58,61,79,117,122,127,138,241,327,328,330,344,364],aren:[0,4,29,39,69,103,127,131,133,136,138,144,337,340],arg1:[80,154,167,170,175,316],arg2:[154,167,170,316],arg:[1,5,10,21,22,25,29,30,33,38,39,40,41,42,51,58,59,68,71,73,74,80,81,83,85,88,96,109,114,115,116,119,121,123,129,132,137,144,146,147,148,151,154,159,167,168,169,170,175,176,177,238,239,241,242,245,246,247,250,251,252,255,256,259,260,261,264,267,272,273,274,276,277,278,279,284,285,287,288,290,291,292,295,296,300,306,308,310,312,316,317,318,319,321,328,330,331,333,334,337,340,342,344,345,357,364],arg_regex:[5,41,44,154,159,165,166,169,170,171,326,328,364],arglist:167,argn:316,argtyp:344,argu:11,argument:[3,4,5,10,12,14,20,21,22,23,25,27,29,31,33,34,40,41,42,46,48,50,52,57,58,59,62,69,74,80,81,83,85,87,88,89,93,95,96,102,109,111,114,115,119,123,124,125,127,129,134,139,144,146,147,150,151,153,154,156,157,159,164,165,166,167,169,170,175,176,242,245,247,251,252,255,257,259,260,261,265,267,272,276,278,279,285,286,287,290,291,295,296,298,299,306,307,308,310,311,316,317,318,319,321,322,324,326,327,328,329,330,334,338,340,341,344,364],argumnet:330,aribtrarili:344,aris:103,arm:[26,33,364],armi:85,armor:[29,82],armour:29,armouri:77,armscii:[15,113],arnold:87,around:[0,4,10,13,14,15,21,23,29,31,34,38,39,42,49,55,58,61,63,64,69,70,71,73,77,79,80,85,89,90,91,96,109,111,113,114,116,117,119,121,123,129,136,138,139,159,167,247,321,322,330,337],arrai:[88,91,291,344],arrang:22,arrayclos:[88,291],arrayopen:[88,291],arriv:[0,25,29,73,77,83,105,159,279],arrow:[42,137],art:[114,327],articl:[4,15,21,39,41,48,57,79,113,127,131,335],article_set:335,artifact:330,artifici:73,arx:[79,364],arxcod:[79,139,364],as_view:[154,175,239,318],ascii:[9,15,111,113,144,171,327,330,344,364],asciiusernamevalid:144,asdf:159,asian:344,asid:9,ask:[1,10,21,23,26,34,37,42,46,48,50,54,58,63,67,68,69,70,73,84,90,91,93,97,119,124,131,133,152,154,159,265,267,294,328,331,344,364],ask_choic:265,ask_continu:265,ask_input:265,ask_nod:265,ask_yes_no:328,ask_yesno:265,aspect:[48,51,57,60,64,68,73,86,109,127],assert:[116,127],assertequ:127,assertionerror:342,assertregex:127,asserttru:127,asset:[103,136,271,347],assetown:9,assign:[2,6,11,12,13,20,36,51,56,58,80,87,89,97,102,109,112,115,116,119,121,123,131,137,138,144,150,151,153,159,164,166,167,242,246,247,251,252,272,279,285,287,290,306,325,342,364],assist:90,associ:[4,11,29,51,79,83,90,105,122,135,138,144,149,159,175,247,306,308,317],assort:364,assum:[0,3,5,9,12,13,14,15,19,20,21,22,25,27,28,29,31,33,34,37,38,39,40,41,44,46,47,49,51,55,56,58,60,62,68,73,74,75,80,81,82,84,85,89,90,95,96,97,100,102,103,105,106,108,109,110,111,113,115,116,117,118,120,121,123,127,128,132,133,134,138,150,152,153,154,156,159,164,166,170,175,177,241,247,252,257,291,308,321,322,328,344,349],assumpt:151,assur:[49,125],asterisk:[2,12,38,157],astronaut:77,astronom:62,async:[133,139,344,364],asynccommand:10,asynchron:[27,28,29,33,45,55,64,92,93,139,146,247,276,277,291,337,344,364],at_:[125,334],at_access:[144,247],at_account_cr:[2,144],at_after_mov:[77,89,96,117,247],at_after_travers:[89,247],at_before_drop:247,at_before_g:247,at_before_get:247,at_before_mov:[25,77,89,247],at_before_sai:[96,247],at_channel_cr:175,at_channel_msg:175,at_char_ent:117,at_cmdset_cr:[5,21,22,25,30,31,33,41,44,57,58,62,81,85,116,121,123,152,160,161,162,163,298,326,328,329],at_cmdset_get:[144,247,306],at_db_location_postsav:246,at_desc:247,at_disconnect:[144,306],at_drop:247,at_end:256,at_err:[10,344],at_err_funct:10,at_err_kwarg:[10,344],at_failed_login:144,at_failed_travers:[89,247],at_first_login:144,at_first_sav:[144,175,247],at_first_start:318,at_get:247,at_giv:247,at_heard_sai:118,at_idmapper_flush:[318,334],at_init:[6,107,125,144,175,247],at_initial_setup:[104,271],at_initial_setup_hook_modul:271,at_login:[40,125,278,279,287,290,295,296,306],at_look:[48,96,144,247],at_message_rec:144,at_message_send:144,at_msg_rec:[144,247],at_msg_send:[144,146,247],at_now_add:86,at_object_cr:[5,6,21,25,31,39,49,58,60,73,80,81,85,89,96,121,123,125,132,159,247,318],at_object_delet:247,at_object_leav:[89,247],at_object_post_copi:247,at_object_rec:[89,117,247],at_password_chang:144,at_paus:259,at_post_all_msg:175,at_post_channel_msg:[144,175],at_post_cmd:[30,33,150,154,167,342],at_post_command:33,at_post_disconnect:144,at_post_login:[25,144],at_post_mov:247,at_post_msg:175,at_post_portal_sync:305,at_post_puppet:[96,247],at_post_travers:247,at_post_unpuppet:[96,247],at_pr:247,at_pre_channel_msg:[144,175],at_pre_cmd:[33,150,154,167,342],at_pre_command:33,at_pre_drop:247,at_pre_g:247,at_pre_get:247,at_pre_login:144,at_pre_mov:247,at_pre_msg:175,at_pre_puppet:[96,247],at_pre_sai:247,at_pre_unpuppet:247,at_reload:[169,305],at_renam:318,at_repeat:[102,116,120,121,125,146,259,300,331],at_return:[10,344],at_return_funct:10,at_return_kwarg:[10,344],at_sai:[118,247],at_script_cr:[102,116,120,121,146,251,259,300,331],at_script_delet:259,at_search:104,at_search_result:[168,344],at_server_cold_start:305,at_server_cold_stop:305,at_server_connect:285,at_server_reload:[102,110,144,146,247,259],at_server_reload_start:305,at_server_reload_stop:[25,305],at_server_shutdown:[102,110,144,146,247,259],at_server_start:[259,305],at_server_startstop:[25,104],at_server_stop:305,at_shutdown:305,at_start:[102,116,146,256,259],at_startstop_modul:261,at_stop:[102,116,121,259],at_sunris:62,at_sync:[306,307],at_tick:[115,261],at_travers:[89,247],at_upd:257,at_weather_upd:132,ating:170,atlanti:24,atom:98,atribut:325,att:51,attach:[4,11,21,41,56,58,64,77,89,95,102,105,110,112,119,140,154,159,167,242,247,258,304,319,364],attachmentsconfig:4,attack:[14,28,29,30,46,51,77,90,103,116,119,122,134,139,153,247,252,285,364],attack_messag:73,attack_skil:252,attack_summari:73,attempt:[0,2,22,24,29,31,51,60,61,87,91,103,106,119,120,135,156,159,264,267,272,305,310,318,344],attent:[38,56,58,89,103,111],attitud:57,attr1:159,attr2:159,attr3:159,attr:[11,22,49,51,58,80,109,119,136,137,159,166,177,241,251,252,306,316,318,334,340],attr_eq:241,attr_g:[80,241],attr_gt:[80,241],attr_l:[80,241],attr_lt:[80,241],attr_n:[80,241],attr_nam:159,attr_obj:[316,318],attr_object:318,attract:37,attrcreat:[80,316],attread:11,attredit:[11,80,316],attrhandler_nam:316,attrib:242,attribiut:316,attribut:[0,2,6,12,20,22,25,27,28,30,39,41,42,45,46,49,50,51,56,57,58,60,61,69,73,74,77,80,81,82,84,85,86,87,89,91,95,102,105,108,109,112,115,116,119,123,125,127,133,134,138,139,141,142,144,147,148,153,159,168,169,175,241,245,246,247,250,251,252,255,256,257,260,272,306,314,317,318,319,324,325,326,331,337,338,341,344,357,364],attribute1:123,attribute2:123,attribute_list:316,attribute_nam:[144,245,247,341],attribute_valu:245,attributeerror:[42,60,86,306,316],attributehandl:[1,125,316,339,344,364],attributeobject:11,attributeproperti:316,attrkei:252,attrlist:316,attrnam:[11,51,80,109,125,159,241,245,318],attrread:[11,80,316],attrtyp:[11,316,317],attrvalu:51,attryp:317,atttribut:49,atyp:242,audio:137,audit:[141,142,175,178,207,247,364],aug:[9,364],august:[9,344],aut:52,auth:[144,147,148,164,287,349,357],auth_password:287,auth_profile_modul:148,authent:[40,103,105,107,133,138,144,278,285,287,290,296,306,308,349],authenticated_respons:360,author:[41,90,126,144],auto:[0,5,12,14,21,31,32,33,34,38,42,43,45,51,63,67,71,89,95,96,105,122,131,133,138,141,144,148,154,158,159,166,169,170,236,239,242,247,252,256,261,264,267,278,288,295,296,305,308,316,318,323,328,329,330,349,364],auto_help:[33,41,44,51,68,69,154,166,170,249,328,329],auto_help_display_kei:[154,170,328],auto_id:357,auto_look:[51,249,328],auto_now_add:86,auto_quit:[51,249,328],autobahn:[278,284,295],autocr:316,autodoc:38,autofield:133,autologin:349,autom:[14,36,57,58,67,79,86,100,103,110],automat:[0,6,10,14,19,22,23,27,30,31,34,37,41,46,47,50,51,55,58,60,62,64,65,66,67,68,71,72,80,81,84,85,86,90,96,97,100,102,104,105,109,111,116,117,118,119,121,122,123,124,125,126,128,131,135,136,139,140,144,152,153,154,159,164,165,167,169,242,246,247,258,260,261,272,281,284,287,292,305,308,310,322,326,328,329,330,342,344,350,364],automatical:261,autostart:[255,258,324],autumn:[97,99],avail:[0,5,7,8,10,11,13,16,21,22,23,25,26,31,33,36,38,39,40,41,42,44,46,48,49,51,53,57,58,60,62,63,64,65,72,74,75,76,77,78,79,80,81,82,85,88,89,90,91,95,96,98,100,102,104,105,106,108,109,110,111,113,114,116,119,121,122,123,125,127,128,130,131,133,134,137,138,139,141,144,150,151,152,153,154,156,159,161,164,165,166,167,169,170,171,242,247,250,251,252,256,272,296,298,299,310,322,323,328,329,330,342,344,350,364],available_chan:164,available_choic:[51,328],available_funct:251,avatar:[64,88,96,247,287],avatarid:287,averag:[13,90,93,169],avoid:[8,11,23,26,27,31,33,37,40,42,51,80,81,85,95,97,100,109,111,114,125,126,127,129,131,138,139,152,159,241,246,276,286,296,306,316,318,319,321,322,323,326,329,334],awai:[0,9,10,11,14,15,21,26,29,42,46,49,51,55,66,68,69,73,80,86,90,96,102,105,109,111,121,123,131,165,177,247,256,307,321,344],await:10,awar:[11,14,26,31,33,44,51,88,95,96,110,125,126,132,133,247,318,321],awesom:[63,135],aws:90,azur:[90,100],b64decod:340,b64encod:340,baaaad:127,babi:138,bacground:67,back:[0,3,5,10,11,12,13,14,20,21,22,23,25,26,27,29,31,33,34,36,38,46,49,50,51,56,58,60,61,63,64,67,69,73,74,81,83,85,86,87,90,91,95,96,97,100,102,105,106,110,111,113,116,118,119,121,122,123,125,126,131,133,135,137,141,144,153,156,159,164,168,249,267,272,276,279,285,287,290,305,318,325,328,329,337,344],back_exit:0,backbon:[133,322],backend:[23,36,109,127,135,141,142,316,344,346,348,364],backend_class:316,background:[10,17,29,51,67,90,103,110,114,126,133,321],backpack:31,backslash:114,backtick:[38,131],backtrack:131,backup:[10,89,90,105,131,168,322],backward:[50,51,58,121,147,337],bad:[0,22,24,37,41,58,64,70,76,85,119,127,269],bad_back:242,badg:130,bag:344,bake:100,balanc:[29,56,61,79,116,330],balk:95,ball:[31,59,104,151,152,252],ban:[7,25,80,139,144,157,164,170,175,242,364],ban_us:164,band:[45,88,118,137,287,290,291],bandit:46,bandwidth:280,banid:157,bank:61,banlist:175,bar:[51,82,83,84,88,112,135,137,159,267,291,316,328,344],bare:[33,55,58,73,104],barehandattack:56,bargain:86,barkeep:42,barter:[61,63,102,117,141,142,178,364],bartl:79,bas:120,base:[3,4,6,9,13,16,17,20,21,22,23,30,33,36,38,39,41,42,49,51,53,55,56,57,58,60,61,63,64,67,69,72,73,75,77,79,80,83,85,86,89,90,96,100,102,103,105,108,111,113,115,119,120,123,124,125,126,127,129,130,133,134,136,137,138,139,141,144,146,147,148,150,152,153,154,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,175,176,177,238,239,242,245,246,247,249,251,252,255,256,257,258,259,260,261,264,265,267,269,270,273,274,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,298,299,300,303,305,306,307,308,310,311,312,316,317,318,319,321,322,323,326,327,328,329,330,331,333,334,335,337,338,339,340,341,342,343,344,349,351,352,357,360,364],base_account_typeclass:2,base_channel_typeclass:34,base_char_typeclass:120,base_character_typeclass:[81,120,133,134,144,159],base_field:357,base_guest_typeclass:66,base_object_typeclass:[109,252,318],base_script_path:241,base_script_typeclass:102,base_set:9,base_word:344,basecommand:60,basecontain:323,baseevenniacommandtest:[170,342],baseevenniatest:[293,342,360],baseevenniatestcas:342,baseline_index:344,baseobject:125,baseopt:338,basepath:344,basetyp:[247,322],basetype_posthook_setup:247,basetype_setup:[39,80,96,144,146,175,247],bash:[36,63,67],basi:[4,33,37,62,90,136,138,167,177,296,318,327],basic:[0,2,3,6,9,15,16,17,19,20,22,26,29,31,33,34,36,39,40,46,47,48,56,57,58,60,61,62,69,73,77,79,80,81,83,86,87,110,111,113,116,117,118,121,122,124,126,128,133,134,135,137,139,144,146,159,164,166,175,177,241,243,247,298,357,364],bat:[9,63],batch:[18,20,43,48,63,79,111,122,124,139,141,142,158,170,252,276,316,319,320,364],batch_add:[252,316,319],batch_cmd:14,batch_cod:[13,322],batch_code_insert:13,batch_create_object:252,batch_exampl:322,batch_import_path:[13,14],batch_insert_fil:14,batch_update_objects_with_prototyp:252,batchcmd:[43,158],batchcmdfil:[14,322],batchcod:[14,43,79,111,158,364],batchcode_map:111,batchcode_world:111,batchcodefil:13,batchcodeprocessor:322,batchcommand:[14,20,22,43,63,122,158,322],batchcommandprocessor:322,batchfil:[14,15,111,322],batchprocess:[141,142,149,155,364],batchprocessor:[13,141,142,158,320,364],batchscript:[13,322],batteri:144,battl:[79,103,116,122],bazaar:108,beach:111,beat:[61,116],beaten:116,beauti:[22,49,133],beazlei:79,becam:[29,126],becaus:[0,2,6,8,9,10,11,12,13,15,16,21,22,25,29,31,36,38,40,41,42,44,46,51,54,56,59,64,68,73,76,77,80,89,91,95,96,107,108,109,111,115,116,117,119,125,126,130,133,134,136,153,166,171,175,247,259,279,285,298,308,321,338,340,344],becom:[0,5,10,22,37,38,41,42,47,49,51,56,59,61,64,70,73,78,80,81,86,87,88,95,96,102,104,109,111,119,128,156,247,252,306,322,328,342],bed:61,been:[0,4,5,6,13,14,19,21,22,23,36,38,41,42,46,49,51,58,69,70,76,79,85,91,93,96,103,105,116,117,123,126,128,131,133,134,135,138,144,152,153,154,158,159,164,167,175,177,239,242,246,247,251,252,260,261,269,281,285,287,295,305,306,307,308,310,316,318,322,326,327,344],befit:125,befor:[1,4,10,11,12,13,14,15,20,21,22,25,27,28,29,31,33,37,41,42,46,48,49,51,56,57,58,60,61,67,69,71,75,77,79,80,81,84,85,86,90,91,93,96,97,100,102,103,104,106,107,108,109,111,112,113,114,115,116,117,118,119,121,123,124,125,126,127,131,132,133,134,135,137,138,139,144,150,151,154,159,164,166,167,171,175,177,241,242,246,247,250,251,252,255,259,260,261,267,276,285,287,293,299,301,303,305,306,310,312,316,321,322,323,324,328,329,330,331,335,337,340,344,364],beforehand:[11,131,323],beg:14,beggar:0,begin:[0,4,6,10,13,14,20,22,25,33,38,41,42,46,50,51,55,58,61,69,72,80,91,95,96,106,107,111,116,117,119,127,132,134,165,166,245,247,321,322,328,341],beginn:[55,60,77,79,91,95,124],behav:[11,13,20,22,29,69,91,95,107,110,127,344],behavior:[0,5,11,31,33,41,50,68,69,93,96,102,109,114,126,135,137,138,144,154,170,267,316,328],behaviour:[11,31,33,80,126,255,313,324,330,344],behind:[11,12,21,33,49,51,55,59,61,63,74,97,109,112,114,122,126,131,158,256,261,334],behvaior:329,being:[0,5,6,10,11,13,20,21,22,25,28,31,33,34,36,37,42,51,54,56,59,61,63,64,69,83,88,90,91,93,95,96,102,103,107,109,111,115,118,125,126,127,129,131,133,138,144,151,159,165,169,170,175,239,247,255,269,272,279,299,308,310,316,318,321,322,324,328,329,330,344,363],beipmu:24,belong:[4,14,64,83,95,103,112,119,133,140,153,239,250],below:[0,1,5,8,9,10,11,12,13,14,15,19,20,22,23,25,27,29,31,33,34,36,38,39,42,48,49,50,51,57,58,59,60,61,62,63,64,67,69,70,74,80,81,87,88,90,95,96,100,102,105,106,109,110,111,114,117,118,119,123,125,127,131,133,134,136,138,140,148,159,167,177,239,246,247,256,279,299,316,318,319,328,330,335],belt:77,beneath:27,benefici:49,benefit:[78,90,100,103,108,127,153,316,322,328],besid:[0,14,31,106,111],best:[9,22,24,26,37,50,51,57,58,59,61,72,76,102,103,104,108,133,135,139,166,252,267,287,330,338,364],bet:[31,105,138,318],beta:[35,54,90,364],betray:51,better:[0,9,15,23,25,34,38,41,42,44,45,51,55,58,59,61,64,68,70,73,81,85,86,91,93,95,108,109,112,114,133,134,247,252,284,287,290,298,316,322],bettween:73,between:[0,2,10,14,22,25,28,31,33,36,38,39,40,41,46,49,56,57,58,64,67,69,73,76,83,85,87,88,90,91,100,102,105,109,112,113,114,116,120,121,122,123,124,126,131,137,138,140,151,154,159,164,166,169,170,176,177,247,252,261,267,276,279,286,287,290,291,298,299,306,319,321,322,324,328,330,331,344,351,364],bewar:39,beyond:[1,2,9,22,25,33,37,52,57,64,88,89,90,102,127,134,154,159,170,177,247,251,298,316,318,328,330],bg_colormap:343,bgcolor:343,bgfgstart:343,bgfgstop:343,bgstart:343,bgstop:343,bias:159,bidirect:276,big:[9,11,13,14,20,25,28,29,33,37,45,57,73,80,96,122,138,140,151,166,168,245,322,329,341,344],bigger:[21,37,40,69,119,123],biggest:[72,138,344],biggui:33,bigmech:21,bigsw:29,bikesh:119,bill:[90,103],bin:[4,9,36,47,63,64,75,96,100],binari:[23,47,63,93,95,278,280,295],bind:67,birth:357,bit:[0,4,9,12,17,22,26,29,35,39,41,42,46,59,61,62,63,69,75,76,81,96,102,106,109,121,122,127,131,134,137,138,164,171,242,247,322],bitbucket:57,bite:[61,111],black:[73,114,126,321],blackbird:79,blackbox:138,blacklist:[103,164],blacksmith:319,blank:[51,86,117,134,144,321],blarg:83,blargh:109,blatant:12,blaufeuer:119,bleed:[114,131,330],bless:138,blind:[114,118],blindli:242,blink:[20,343],blist:97,blob:[37,38,95,104,138],block:[3,12,25,28,50,51,55,58,64,69,80,90,91,97,102,103,110,114,123,129,133,134,139,157,158,159,249,286,322,328,344,364],blocking_cmdset:25,blockingcmdset:25,blockingroom:25,blockquot:364,blocktitl:69,blog:[37,55,79,90,98],blowtorch:24,blue:[13,57,81,114,126,321],blueprint:[57,96,111,137],blurb:54,board:[34,49,61,79,80,121],boat:[31,121,153],bob:[33,81,138,157],bodi:[3,17,22,27,33,41,46,51,58,95,109,127,129,133,238,269,324],bodyfunct:[20,102,141,142,178,222,364],bog:21,boi:112,boiler:125,bold:[54,364],bolt:252,bone:[55,73],bonu:[41,73,90,256],bonus:29,book:[3,49,62,73,79,91,95,109,135],bool:[2,31,33,34,51,74,84,102,144,146,147,148,150,151,152,153,154,164,166,175,176,177,238,239,242,245,246,247,251,252,255,256,257,258,259,260,261,267,272,273,278,279,284,285,286,290,295,296,304,306,308,310,316,317,318,319,321,322,324,326,328,329,330,331,334,337,339,341,343,344],booleanfield:133,boom:[21,51],boot:[80,100,110,157,164,175,261,364],boot_us:164,bootstrap:[4,124,138,139,364],border:[58,111,156,327,330,342,364],border_bottom:330,border_bottom_char:330,border_char:330,border_left:330,border_left_char:330,border_right:330,border_right_char:330,border_top:330,border_top_char:330,border_width:330,borderless:58,bore:[12,55,103],borrow:[31,63,152,276],bort:[52,328],boss:58,bot:[47,65,72,93,103,119,133,141,142,143,148,164,272,278,279,286,308,364],bot_data_in:[146,272],both:[0,11,15,19,22,23,25,26,27,31,33,34,36,37,38,40,44,49,51,56,57,58,62,65,69,71,74,79,84,85,86,87,88,90,91,95,97,103,104,105,106,110,111,116,119,121,124,125,127,128,131,133,134,136,138,150,152,159,164,169,176,177,242,245,247,251,252,253,256,259,261,276,285,295,296,298,305,307,310,316,317,321,324,328,330,339,344],bother:[29,103,128,316],botnam:[72,164,279,308],botnet:103,botstart:146,bottom:[4,39,41,52,54,57,58,60,69,85,95,101,106,111,125,127,133,137,153,252,322,329,330],bought:85,bouncer:[27,103,327],bound:[6,27,38,57,108,344],boundari:344,bounti:70,bountysourc:70,bow:252,box:[0,3,8,20,42,46,58,63,66,69,70,71,73,80,87,90,104,106,109,111,123,135,138,159,241,276,322,357],brace:[0,22,25,41,91,247,321],bracket:[38,96,129,169],brainstorm:[139,364],branch:[9,36,37,38,41,63,100,364],branchnam:131,bread:16,break_long_word:330,break_on_hyphen:330,breakdown:169,breakpoint:[16,106,141],breez:[102,132],breviti:58,bribe:51,brick:82,bridg:[22,23,53,79,83,105,364],brief:[3,16,19,20,21,25,46,58,60,85,86,95,96,101,110,124,131,139,247,311,364],briefer:[89,110],briefli:[16,90,110,364],bright:[81,114,126,321],brightbg_sub:321,brighten:114,brighter:114,brilliant:131,bring:[23,49,96,100,103,121,123,133,136,309],broad:39,broadcast:[144,175,276],broader:[39,247],broken:[38,61,108,114],brought:102,brown:321,brows:[3,9,25,39,55,58,62,69,85,90,91,103,106,123,131,136,137,138],browser:[3,8,9,16,38,55,63,64,67,69,70,75,77,90,95,96,101,103,133,134,135,136,137,138,295,296],bsd:78,bsubtopicnna:170,btest:114,btn:[17,70],buf:326,buffer:[22,33,50,137,168,269,296,326],bug:[10,13,26,37,42,54,57,60,61,70,78,95,96,110,123,127,131,247,318,364],buggi:[11,328],bui:[85,138],build:[1,6,7,9,10,11,13,14,15,27,31,36,43,47,51,55,57,60,63,64,68,69,75,77,79,80,81,86,87,89,96,100,105,106,108,109,112,113,119,120,122,123,125,129,130,136,137,139,140,141,142,149,151,155,157,158,165,166,242,247,251,252,267,278,279,322,330,357,363,364],build_match:151,builder:[2,4,14,19,22,25,56,58,60,61,68,80,85,108,109,112,114,123,124,139,157,159,164,165,169,242,247,298,318,319,322,363,364],buildier:252,building_menu:[141,142,178,364],buildingmenu:22,buildprotocol:[264,277,278,279],buildshop:85,built:[13,16,20,27,38,40,51,54,55,57,58,61,63,64,73,75,77,95,96,100,103,121,122,123,135,138,139,148,177,239,246,256,261,316,318,319,322,326,328,335],builtin:280,bulk:[96,103],bullet:[38,61],bulletin:[61,79,80],bulletpoint:38,bunch:[15,27,58,108,113],burden:82,buri:[108,122],burn:[61,73,90],busi:[64,70,90,364],butch:96,butt:138,butter:16,button:[9,13,14,31,33,80,83,87,88,106,131,133,134,135,137,138,159,299,329,364],buy_ware_result:85,bypass:[4,10,19,20,58,80,116,126,144,147,159,175,242,245,318,324,341,344,349],bypass_mut:175,bypass_perm:344,bypass_superus:80,byt:247,bytecod:321,bytestr:[276,344],bytestream:344,c20:164,c_creates_button:299,c_creates_obj:299,c_dig:299,c_examin:299,c_help:299,c_idl:299,c_login:299,c_login_nodig:299,c_logout:299,c_look:299,c_measure_lag:299,c_move:299,c_moves_:299,c_moves_n:299,c_social:299,cabl:82,cach:[6,8,11,12,28,33,39,86,119,125,127,130,137,144,154,169,175,177,242,246,247,271,310,316,318,319,320,332,334,344,350],cache_inst:334,cache_lock_bypass:242,cache_s:[310,334],cached_properti:344,cake:31,calcul:[10,25,27,39,73,116,119,123,139,153,252,331,334,344],calculated_node_to_go_to:51,calculu:56,calendar:[331,364],call:[0,2,3,4,5,6,10,11,13,14,16,20,21,22,23,25,26,27,28,29,30,31,36,38,39,40,41,42,46,47,48,49,50,51,55,56,57,58,59,60,61,62,63,64,65,69,71,72,73,74,75,80,81,83,84,85,86,88,89,90,91,93,95,96,100,102,104,105,107,108,109,110,111,114,115,116,117,118,119,120,121,122,123,125,126,127,128,131,132,133,134,135,137,138,144,146,150,151,152,153,154,156,159,164,167,168,169,170,171,175,177,241,242,246,247,250,251,252,255,257,259,260,261,264,267,269,271,272,276,277,278,279,280,281,282,283,285,286,287,288,289,290,291,292,294,295,296,298,299,300,305,306,307,308,309,312,316,318,319,321,322,323,324,326,328,329,330,331,334,337,339,340,341,342,344,357,364],call_async:10,call_command:127,call_ev:0,call_inputfunc:[83,306,308],call_task:260,callabl:[49,50,84,109,115,123,247,250,251,252,257,261,265,267,269,277,308,323,326,328,329,331,337,339,340,344,364],callables_from_modul:344,callbac:22,callback1:328,callback:[4,10,22,27,29,33,50,51,62,74,84,115,138,146,169,247,257,260,261,265,267,269,272,276,277,278,280,294,295,298,309,328,331,337,342,344,364],callbackhandl:[141,142,178,191,364],called_bi:150,calledbi:344,caller:[5,10,11,13,21,22,25,27,28,29,30,33,38,41,42,44,49,50,56,58,59,60,71,73,80,81,82,83,85,86,87,88,89,91,111,115,116,119,121,123,125,129,137,146,150,151,152,154,156,159,160,164,165,166,167,169,170,242,247,249,251,252,322,326,328,329,338,342,344,364],callerdepth:344,callertyp:150,callinthread:312,callsign:[51,272],calm:111,came:[9,21,25,55,79,111,132,138,247],camp:111,campfir:111,campsit:111,can:[0,1,2,3,4,5,6,9,10,12,13,14,15,17,19,20,21,23,24,25,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,42,44,46,48,49,50,51,54,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,95,96,97,98,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,130,131,133,134,135,136,137,138,139,140,143,144,146,147,148,151,152,153,154,156,157,159,164,165,166,167,168,169,170,171,175,176,177,239,241,242,245,246,247,250,251,252,253,255,256,257,259,261,267,278,282,285,287,290,291,295,296,298,299,305,306,307,308,309,312,313,314,316,317,318,319,321,322,323,324,326,327,328,329,330,338,339,340,341,342,344,345,357,363,364],can_ent:319,can_list_top:166,can_read_top:166,cancel:[27,29,74,169,247,260],candid:[22,33,119,133,151,245,247,341],candl:153,cannot:[5,9,10,11,13,14,19,21,22,25,27,28,29,31,33,39,44,46,50,51,56,60,61,63,69,70,73,76,80,85,90,104,109,112,114,122,123,127,128,133,139,144,146,153,156,159,166,238,242,245,247,251,261,316,323,325,327,330,334,344],cantanker:338,cantillon:79,cantmov:25,canva:49,capabl:[6,36,49,58,64,80,83,88,105,156,272,294,357],capcha:364,cape:57,capfirst:69,capit:[9,12,25,29,64,88,95,123,159,291,321,344],captcha:133,caption:38,captur:[25,91,138,337],car:[87,121],card:[103,364],cardin:[44,49,58,159],care:[0,4,10,12,23,33,38,44,49,51,56,57,62,64,78,86,91,110,116,121,126,132,144,152,175,241,247,298,318,322,326,328,329,330,344,364],carefulli:[55,93,105,111,133],carri:[20,31,61,80,82,85,116,117,177,241,306,317],cascad:334,caseinsensitivemodelbackend:349,cast:[28,109,112],caster:28,castl:[13,111,122],cat:[67,75],catchi:4,categor:[112,247],categori:[1,11,33,36,38,39,43,51,68,69,86,109,112,119,127,140,147,154,155,156,157,158,159,164,165,166,167,168,169,170,171,176,238,239,241,245,247,251,252,255,257,298,316,317,319,324,326,328,329,335,338,341,344],categoris:56,category2:335,category2_id:335,category_id:335,cater:29,caught:[42,51,97,176],caus:[11,12,29,30,31,42,60,61,64,77,80,90,96,114,116,117,119,123,127,137,140,153,175,247,298,328,330,344],caution:[62,137,328],cave:46,caveat:[5,10,364],caveman:56,cblue:131,cboot:[12,43],cc1:63,cccacccc:327,ccccc2ccccc:58,cccccccc:327,ccccccccccc:58,cccccccccccccccccbccccccccccccccccc:327,ccccccccccccccccccccccccccccccccccc:327,ccreat:[41,43,58,65,72,98],cdesc:[41,43],cdestroi:43,cdmset:31,cdn:103,ceas:[77,159],cel:327,celebr:61,cell:[58,69,111,327,330],celltext:327,cemit:43,censu:317,center:[4,16,39,49,109,111,114,321,330,344],center_justifi:109,centos7:67,centr:111,central:[26,55,61,64,74,100,111,123,124,127,132,138,139,144,153,159,170,175,176,177,247,252,276,324,328,334,347,363,364],centre_east:111,centre_north:111,centre_south:111,centre_west:111,centric:[9,80,105,123],cert:[8,288,292],certain:[13,14,16,19,25,29,31,33,37,38,48,64,75,80,88,90,97,102,105,107,108,114,115,121,138,159,176,241,245,251,259,267,273,290,291,294,309,316,317,326,330,341,344,357],certainli:[15,44,138],certbot:[67,90,103],certfil:[288,292],certif:[8,90,288,292,364],certonli:67,cet:337,cfg:67,cflag:75,cgi:90,cha:[51,58],chain:[0,10,29,46,51,109,119,267,299,328],chain_1:0,chain_2:0,chain_:0,chain_open_door:0,chain_x:0,chainedprotocol:287,chainsol:[119,364],chair:[13,61,89,91,112,125],challeng:[73,79],chan:164,chanalia:43,chanc:[21,22,28,31,54,61,66,73,115,116,122,131,152,299],chance_of_act:299,chance_of_login:299,chandler:116,chang:[2,3,4,7,8,9,11,12,13,14,15,16,19,20,21,22,23,26,29,30,31,33,34,35,36,37,39,41,42,45,47,49,50,51,53,54,57,61,62,63,64,66,67,68,71,73,74,75,77,78,80,81,83,84,85,86,87,89,90,91,95,96,100,102,104,105,107,109,110,111,112,114,115,116,118,121,123,125,126,127,132,133,134,135,137,138,139,144,153,154,156,157,159,165,170,175,239,245,247,251,252,256,257,259,260,261,267,272,283,298,305,306,313,316,318,322,325,326,329,330,337,338,339,340,364],changeabl:76,changelock:164,changelog:96,changepag:134,changepassword:12,chanlist:43,channam:41,channel:[2,6,7,11,12,19,31,33,43,45,53,55,65,70,71,72,79,80,82,86,87,90,98,107,112,119,123,124,125,138,139,144,146,152,153,159,164,170,172,175,176,177,278,279,286,299,305,306,308,316,324,337,341,360,364],channel_:[34,175],channel_ban:[41,164],channel_color:25,channel_command_class:[34,41],channel_connectinfo:306,channel_handl:53,channel_list_ban:164,channel_list_who:164,channel_msg:144,channel_msg_nick_pattern:175,channel_msg_nick_replac:[164,175],channel_msg_pattern:164,channel_prefix:[25,175],channel_prefix_str:175,channel_search:176,channel_typeclass:360,channelalia:[164,175],channelcl:164,channelcmdset:31,channelcommand:[34,41],channelconnect:177,channelcr:43,channelcreateview:175,channeldb:[41,53,125,141,175,177,314],channeldb_set:[316,319],channeldbmanag:[176,177],channeldeleteview:175,channeldesc:41,channeldetailtest:360,channeldetailview:175,channelhandl:[34,41,141,142,172,364],channelkei:[41,176],channellist:43,channellisttest:360,channelmanag:[175,176],channelnam:[34,41,72,144,146,164,175,278],channelupdateview:175,char1:[73,127,165,342,360],char2:[73,127,165,360],char_nam:133,charac:84,charact:[0,2,5,9,11,14,15,17,19,20,21,22,23,27,28,29,30,31,33,34,36,39,40,41,42,45,47,49,50,51,53,55,56,57,62,68,69,71,74,76,77,80,81,83,85,86,87,88,91,95,97,102,105,111,113,114,116,117,118,119,120,121,122,124,125,127,129,135,136,138,139,141,143,144,147,151,152,154,156,159,160,161,165,166,167,169,171,175,239,242,247,259,272,293,306,311,316,318,319,321,322,327,328,330,342,344,345,357,360,364],character1:73,character2:73,character_id:247,character_typeclass:[127,144,342,360],charactercmdset:[5,21,22,25,30,31,41,43,44,57,58,60,62,81,123,161],charactercreateview:360,characterdeleteview:360,characterform:357,characterlistview:360,charactermanageview:360,characternam:114,characterpuppetview:360,charactersheet:51,characterupdateform:357,characterupdateview:360,charapp:133,charcreat:[0,43,46,69,156],chardata:58,chardelet:[43,156],chardeleteview:[239,318],chardetailview:[154,239,318],charfield:[86,133,340,357],charg:90,chargen:[133,139,141,142,175,178,239,318,364],chargencmdset:123,chargenroom:123,chargenview:[239,318],charnam:[58,156],charpuppetview:318,charset:344,charsheet:58,charsheetform:58,charupdateview:[239,318],chase:122,chat:[1,2,9,26,34,37,48,55,58,60,63,65,70,72,79,80,98,123,131,139,296,337,364],chatroom:57,chatzilla:72,cheap:131,cheaper:[61,115],cheapest:90,cheat:[23,38,73,364],cheatsheet:48,chec:342,check:[0,4,5,12,13,14,19,22,25,26,27,28,29,31,33,36,37,38,39,40,41,42,44,46,49,51,54,56,58,60,63,65,67,68,69,70,71,73,77,81,82,85,86,87,89,90,91,95,97,98,100,102,103,106,109,110,111,112,114,115,116,117,118,119,121,123,125,127,128,130,131,133,136,138,139,144,147,150,151,152,153,154,156,158,159,164,165,166,167,169,170,171,175,177,241,242,246,247,251,252,256,258,259,260,266,267,271,276,282,287,305,306,308,310,311,312,316,318,319,321,322,324,338,339,342,344,345,364],check_attr:159,check_circular:296,check_databas:267,check_db:267,check_defeat:73,check_end_turn:116,check_error:266,check_evennia_depend:344,check_from_attr:159,check_grid:49,check_has_attr:159,check_lockstr:[4,80,242],check_main_evennia_depend:267,check_obj:159,check_permiss:251,check_permstr:[144,318],check_to_attr:159,check_warn:266,checkbox:133,checker:[15,49,241,287,345,364],checkout:[9,100,131],checkoutdir:36,checkpoint:364,chest:[80,91],child:[6,33,51,64,80,96,116,146,148,154,159,170,246,252,256,312,335],childhood:51,children:[21,33,64,96,112,117,119,125,148,246,247,256,267,317,318,335],chillout:159,chime:27,chines:[25,79,113],chip:58,chmod:36,chocol:60,choic:[4,15,23,33,51,55,60,78,90,91,95,105,107,109,113,116,119,124,127,129,132,144,156,159,265,326,328,364],choice1:129,choice2:129,choice3:129,choos:[7,9,10,13,38,49,51,57,62,64,67,72,73,85,101,106,116,120,123,126,133,135,138,139,140,280,328,342,343,364],chop:33,chore:68,chose:[54,58,86,103,133,328],chosen:[22,51,88,106,116,132,138,328],chown:100,christin:96,chrome:24,chroot:67,chug:33,chunk:[13,69,111,269,322],church:27,church_clock:27,cid:299,cillum:52,circl:39,circuit:137,circular:[269,323],circumst:[46,51,57,85,119,152,357],circumv:157,claim:83,clang:75,clank:0,clarif:[1,48],clarifi:25,clariti:[75,86,91,123],clash:[23,31,90,159,318,328],class_from_modul:344,classic:[3,13,79,105,112,115,116],classmethod:[39,144,175,239,247,259,318,334,351],classnam:11,classobj:318,claus:[78,118],clean:[1,4,17,25,28,48,51,76,110,111,114,116,122,131,152,154,159,169,247,256,267,271,285,295,308,318,321,326,328,334,340,343,344,357,364],clean_attribut:[125,144,318],clean_cmdset:[125,318],clean_senddata:308,clean_stale_task:260,clean_str:321,cleaned_data:133,cleaner:[91,123],cleanli:[64,102,105,110,150,154,269,278,284,295,308,326],cleanup:[1,11,22,33,40,45,50,51,102,127,328],clear:[1,4,11,12,15,22,29,33,37,38,40,48,50,59,61,64,69,70,73,81,104,110,111,112,113,115,125,128,129,131,132,137,138,153,156,157,159,165,171,177,242,245,246,247,257,260,261,269,306,310,316,318,319,328,334],clear_all_sessid:245,clear_attribut:316,clear_client_list:303,clear_cont:[89,247],clear_exit:[89,247],clearal:[129,165],clearli:[12,37,48,128,334],cleartext:[147,324],clemesha:312,clever:[10,31,51,95,242],cleverli:105,click:[36,38,69,90,101,106,114,128,131,133,135,137,138,328],click_top:166,clickabl:[18,38,166,364],clickable_top:166,client:[3,7,8,9,12,22,23,25,30,33,36,38,40,45,50,52,54,55,60,63,64,65,67,72,74,75,79,81,84,91,95,96,100,101,103,104,105,107,108,111,113,114,116,117,126,128,136,138,139,141,142,144,146,154,156,159,164,166,169,171,262,264,268,270,272,276,277,278,279,280,281,282,283,285,287,289,290,291,292,294,295,296,298,299,305,306,307,308,325,326,328,343,344,364],client_address:40,client_default_height:52,client_disconnect:296,client_encod:23,client_gui:272,client_opt:[88,272,291,364],client_secret:65,client_width:[33,154],clientconnectionfail:[264,278,279],clientconnectionlost:[264,278,279],clienthelp:137,clientkei:298,clientraw:169,clientsess:[295,296],cliff:[20,159],climat:112,climb:[33,55,77,93,159],clipboard:[1,48],clist:43,clock:[12,27,33,43,73],clone:[38,47,63,64,76,96,128,130,364],close:[0,14,22,25,38,39,40,41,46,48,50,51,64,69,76,90,96,100,103,105,106,110,125,131,133,137,169,171,269,277,278,285,287,295,296,308,316,322,328],close_menu:328,closest:[39,114,344],cloth:[141,142,178,322,364],cloud9:364,cloud:[90,100,102,103,132],cloudi:102,clr:[114,251],cls:[39,144],clunki:131,clutter:[38,153],cma:131,cmd:[12,14,22,25,28,29,31,33,41,44,58,60,62,71,80,82,85,88,95,121,123,136,152,154,156,157,158,159,164,165,166,167,168,169,170,171,236,247,291,295,296,298,322,326,328,329],cmd_abil_result:127,cmd_arg:91,cmd_channel:33,cmd_help_dict:166,cmd_ignore_prefix:151,cmd_kei:91,cmd_last:105,cmd_last_vis:105,cmd_loginstart:33,cmd_multimatch:[33,150],cmd_na_m:88,cmd_name:[88,291],cmd_noinput:[33,150,328],cmd_nomatch:[33,150,328],cmd_noperm:33,cmd_on_exit:[51,249,328],cmd_or_top:166,cmd_total:105,cmdabil:[60,127],cmdabout:169,cmdaccess:165,cmdaccount:169,cmdasync:10,cmdattack:[29,73,116,123],cmdban:157,cmdbatchcod:158,cmdbatchcommand:158,cmdbigsw:29,cmdblock:25,cmdboot:157,cmdbui:85,cmdbuildshop:85,cmdchannel:164,cmdcharcreat:156,cmdchardelet:156,cmdcolortest:156,cmdconfigcolor:81,cmdconfirm:33,cmdconnect:41,cmdcopi:159,cmdcpattr:159,cmdcraftarmour:29,cmdcreat:159,cmdcreatenpc:123,cmddefend:116,cmddesc:159,cmddestroi:159,cmddiagnos:30,cmddice:58,cmddig:159,cmddisconnect:41,cmddisengag:116,cmddrop:165,cmddummyrunnerechorespons:298,cmdecho:[5,29,33,38,342],cmdeditnpc:123,cmdeditorbas:326,cmdeditorgroup:326,cmdemit:157,cmdentertrain:121,cmdevmenunod:328,cmdexamin:159,cmdexiterror:44,cmdexiterroreast:44,cmdexiterrornorth:44,cmdexiterrorsouth:44,cmdexiterrorwest:44,cmdfeint:116,cmdfind:159,cmdforc:157,cmdget:[25,165],cmdgetinput:328,cmdgive:165,cmdgmsheet:58,cmdgrapevine2chan:164,cmdhandler:[31,33,83,89,141,142,144,149,151,152,153,154,156,167,168,169,170,171,246,247,256,342,344,364],cmdhelp:[116,166],cmdhit:116,cmdhome:165,cmdic:156,cmdid:272,cmdinsid:121,cmdinterrupt:170,cmdinventori:[82,165],cmdirc2chan:164,cmdircstatu:164,cmdlaunch:21,cmdleavetrain:121,cmdlen:[151,168],cmdline:267,cmdlineinput:326,cmdlink:159,cmdlistcmdset:159,cmdlisthangout:119,cmdlock:159,cmdlook:[30,127,165],cmdmakegm:58,cmdmore:329,cmdmoreexit:329,cmdmultidesc:57,cmdmvattr:159,cmdmycmd:[56,68],cmdname2:151,cmdname3:151,cmdname:[40,59,74,83,88,123,137,150,151,154,159,167,168,170,272,290,291,295,296,308,342],cmdnewpassword:157,cmdnick:165,cmdnpc:123,cmdobj:[150,151,168,342],cmdobj_kei:150,cmdobject:[150,151,159],cmdobjectchannel:164,cmdooc:156,cmdooclook:156,cmdopen:159,cmdoption:156,cmdpage:164,cmdparri:116,cmdparser:[104,141,142,149,364],cmdpassword:156,cmdperm:157,cmdpoke:119,cmdpose:[116,165],cmdpy:169,cmdquell:156,cmdquit:156,cmdreload:169,cmdreset:169,cmdroll:91,cmdrss2chan:164,cmdsai:[116,165],cmdsaveyesno:326,cmdscript:159,cmdser:328,cmdserverload:169,cmdservic:169,cmdsession:156,cmdset:[2,7,14,21,22,25,31,33,34,40,41,42,43,44,47,51,53,57,60,62,68,69,81,85,89,96,97,105,116,121,123,141,142,144,149,150,151,153,154,159,160,161,162,163,167,168,169,170,246,247,256,298,305,306,318,326,328,329,342,344,364],cmdset_account:[2,141,142,149,155,364],cmdset_charact:[5,96,141,142,149,155,364],cmdset_mergetyp:[51,249,328],cmdset_prior:[51,249,328],cmdset_red_button:[141,142,178,222,364],cmdset_sess:[105,141,142,149,155,364],cmdset_stack:153,cmdset_storag:[148,246,306],cmdset_unloggedin:[33,141,142,149,155,364],cmdsetattribut:159,cmdsetdesc:165,cmdsethandl:[105,141,142,149,364],cmdsethelp:166,cmdsethom:159,cmdsetkei:31,cmdsetkeystr:152,cmdsetmor:329,cmdsetobj:[152,153,160,161,162,163,298,326,328,329],cmdsetobjalia:159,cmdsetpow:123,cmdsettestattr:50,cmdsettrain:121,cmdsheet:58,cmdshoot:21,cmdshutdown:169,cmdsmile:33,cmdspawn:159,cmdspellfirestorm:28,cmdstring:[33,58,150,154,167,170,342],cmdstyle:156,cmdtag:159,cmdtask:169,cmdteleport:159,cmdtest:[29,42,91],cmdtestid:33,cmdtestinput:51,cmdtestmenu:[51,328],cmdticker:169,cmdtime:[62,169],cmdtunnel:159,cmdtweet:71,cmdtypeclass:159,cmdunban:157,cmdunconnectedconnect:171,cmdunconnectedcr:171,cmdunconnectedencod:171,cmdunconnectedhelp:171,cmdunconnectedinfo:171,cmdunconnectedlook:171,cmdunconnectedquit:171,cmdunconnectedscreenread:171,cmdunlink:159,cmdwait:33,cmdwall:157,cmdwerewolf:25,cmdwhisper:165,cmdwho:156,cmdwipe:159,cmdyesnoquest:328,cmset:153,cmsg:43,cmud:24,cnf:[23,36],cnt:119,coast:[111,122],coastal:111,cockpit:21,code:[0,1,2,4,5,6,7,9,10,11,12,14,15,16,18,19,20,29,31,33,34,36,37,39,40,45,46,47,48,49,51,53,55,56,57,58,62,63,64,68,69,70,76,77,79,80,83,84,86,88,89,91,93,95,96,97,98,100,102,103,104,105,106,109,110,111,112,114,115,116,117,118,119,121,122,123,125,126,127,129,132,134,135,136,139,141,142,144,149,150,153,156,158,159,164,166,169,172,178,242,252,256,278,279,295,306,309,318,320,321,326,328,330,341,342,343,344,363,364],code_exec:322,codebas:[38,55,56,127,129,131,139,140,170],codeblock:38,codec:321,codefunc:326,coder:[22,26,56,61,79,96,124,150,247,363],codestyl:37,coding_styl:[37,38,95],coerc:339,coexist:126,coin:[61,70],col:[3,16,330],cold:[12,110,169,252,257,261,305],cole:344,coll_date_func:169,collabor:[4,61,64,90,131,166,364],collat:[83,251],collect:[11,26,31,136,150,152,166,169,316,344],collect_top:166,collector:136,collectstat:[136,137,267,271],collid:[31,54,90,328],collis:[31,131,310],colon:[27,41,60,80,95,242],color:[16,18,20,33,38,43,49,51,53,58,59,63,69,74,79,95,109,111,114,124,129,137,139,154,156,247,251,272,279,287,290,295,296,321,330,338,342,343,345,364],color_markup:[141,142,178,364],color_typ:321,colorablecharact:81,colorback:343,colorcod:343,colour:[27,55,139,159,294,321,330,364],column:[16,38,46,49,58,64,69,86,111,137,154,156,330,344],com:[8,9,22,23,37,38,45,54,55,63,67,70,75,79,90,95,98,100,103,104,108,128,130,131,133,135,138,141,164,169,279,282,291,295,312,330,343,344,357],comb:1,combat:[11,14,25,28,31,46,55,63,64,73,79,102,108,109,111,117,122,124,125,131,139,153,256,364],combat_cmdset:116,combat_handl:116,combat_handler_:116,combat_scor:123,combatcmdset:116,combathandl:116,combatscor:123,combatt:11,combin:[8,11,12,20,27,28,30,31,33,34,41,55,57,58,84,90,109,112,114,115,118,119,121,127,150,151,152,159,242,251,255,261,267,317,319,324,338,342,344],combo:105,come:[0,2,3,4,6,10,11,15,16,20,21,23,25,27,29,33,34,40,46,49,51,52,55,57,58,61,62,64,69,73,80,83,85,88,91,93,100,105,111,114,116,118,119,121,123,124,126,129,131,133,134,135,137,144,152,251,252,285,290,295,296,298,304,321,329],comet:[40,55,137,296],comfort:[15,55,69,91,131,364],comlist:43,comm:[33,34,41,43,47,53,64,68,71,141,142,149,155,324,364],comma:[20,46,86,95,114,134,159,167,242,247,344],command:[0,2,4,6,8,9,10,11,12,13,15,18,19,20,21,23,24,26,27,34,36,38,40,46,47,48,49,50,51,52,55,56,57,59,61,63,64,65,66,69,72,74,75,76,77,79,80,82,83,86,87,89,90,92,93,95,96,98,102,103,104,105,106,108,109,110,111,112,113,114,117,118,119,120,122,124,125,126,128,129,130,131,136,137,138,139,140,141,142,144,146,175,176,178,191,236,238,239,241,242,247,251,252,256,264,267,272,276,277,285,287,290,291,295,296,298,299,305,306,318,320,321,324,326,328,329,338,341,342,344,364],command_default_arg_regex:33,command_default_class:25,command_pars:151,commandhandl:[74,153,168],commandmeta:154,commandnam:[33,74,83,267,276,306,308],commandset:[5,80,89,153],commandtest:127,commandtestmixin:342,comment:[8,9,13,14,24,25,37,41,48,51,60,90,96,118,125,138,322,328,364],commerc:79,commerci:[90,106],commerror:176,commit:[15,23,25,36,37,38,64,66,98,100,108,128,130,364],common:[1,6,10,12,15,16,20,26,27,30,33,38,40,41,51,53,59,60,61,62,63,64,68,69,73,74,79,80,83,88,90,91,97,105,107,109,112,113,115,116,119,123,124,125,131,133,139,152,159,164,171,242,245,256,272,295,299,317,318,327,329,339,341,344,350],commonli:[23,63,64,83,86,87,96,104,105,107,115,119,128,247,342],commonmark:38,commun:[8,22,23,33,40,41,45,47,53,55,57,60,64,70,72,79,83,88,90,91,92,103,106,113,114,137,139,144,161,164,171,172,175,176,177,246,255,264,276,277,287,288,290,291,292,293,306,308,324,325,340,364],compact:[85,134],compani:[64,88],compar:[4,9,13,15,27,28,29,31,41,44,58,73,83,85,91,97,116,119,123,127,131,136,241,242,252,298,321,342,344],comparison:[13,93,241,252,328,342],compartment:58,compass:20,compat:[14,21,51,159,330,337,344],compet:[15,88],compil:[9,33,38,47,56,63,75,76,90,95,108,154,159,165,166,169,171,321,326,328,343],compilemessag:76,complain:[42,60,86,91,110,128],complement:[26,107],complementari:113,complet:[2,10,11,13,14,15,22,23,25,27,31,33,36,37,44,49,50,58,59,61,62,64,67,70,77,81,85,88,89,90,95,96,102,104,105,107,109,110,111,122,123,127,128,131,139,144,152,153,154,167,169,170,247,260,267,269,277,278,295,316,322,327,328,329,341,344,357,364],complex:[11,14,15,20,31,33,38,51,59,61,62,64,73,76,77,86,93,96,100,104,108,111,115,116,123,127,138,153,175,252,299,316,364],complianc:24,compliant:[39,291],complic:[0,10,22,29,41,49,69,90,91,111,133,134,171,316],compon:[29,33,38,40,49,58,90,93,96,102,110,114,116,124,127,135,137,138,139,159,169,176,177,245,252,253,255,256,259,267,296,324,327,341,344,347,364],componentid:137,componentnam:137,componentst:[137,138],compos:100,composit:[293,317],comprehens:[34,55,63,80,93,96,103,124,125,127],compress:[74,272,276,280,340],compress_object:340,compris:144,compromis:103,comput:[10,12,37,49,56,60,63,64,72,73,100,113,115,124,131,132,157,169,344,345,364],computation:115,comsystem:177,con:[43,58,79,171],concaten:[67,321],concept:[11,37,38,39,40,46,57,61,69,76,77,92,96,115,124,131,139,364],conceptu:[49,51],concern:[25,44,63,76,88,95,96,152,239],conch:[287,290,298],conclud:[96,328,364],conclus:364,concurr:23,conda:9,conder:322,condit:[8,46,49,55,61,73,85,91,93,96,123,124,150,166,242,247,259,266,267,312,319,344,364],condition:25,conditional_flush:334,conduct:136,conductor:121,conect:308,conf:[4,8,9,23,25,35,36,38,40,41,47,54,62,65,67,69,74,76,80,81,86,90,93,102,103,109,114,120,121,127,130,131,133,134,135,139,144,267,273,274,313,322,364],confer:[79,344],confid:[37,39,42],config:[2,4,9,36,40,59,63,90,98,106,130,131,138,139,267,269,273,274,285,364],config_1:2,config_2:2,config_3:2,config_color:81,config_fil:67,configcmd:81,configdict:[287,308],configur:[0,2,7,25,36,38,45,47,54,59,62,63,64,69,90,100,103,114,120,124,127,136,138,139,144,148,151,156,269,274,285,308,310,312,313,317,357,364],configut:106,configvalu:59,confirm:[8,33,63,103,137,159,291,294],conflict:[41,42,126],confus:[10,22,26,31,44,58,59,60,64,77,80,87,90,91,93,97,114,119,126,131,136,137,140,164],congratul:364,conid:286,conj:247,conjug:247,conn:[43,171],conn_tim:105,connect:[0,2,4,7,8,9,11,12,13,17,18,23,24,25,31,33,34,40,41,43,46,47,49,55,57,60,63,64,65,66,67,69,72,74,76,77,80,83,85,88,89,91,92,93,96,98,100,101,102,103,104,105,107,110,111,114,120,123,125,126,127,136,137,139,144,146,147,148,156,157,159,164,171,175,176,177,246,247,253,262,264,267,269,276,277,278,279,280,285,286,287,290,295,296,298,299,305,306,307,308,309,312,316,318,324,340,364],connection_cr:107,connection_screen:[35,104],connection_set:54,connection_tim:[144,247],connection_wizard:[141,142,262,364],connectiondon:269,connectionlost:[269,276,277,287,290,298],connectionmad:[264,276,287,290,298],connectionwizard:265,connector:[264,278,279,285,308],consecut:51,consequ:[90,153],consid:[0,4,10,12,13,14,23,26,27,31,33,37,39,40,44,46,51,55,57,61,63,64,70,74,78,80,82,85,86,90,93,96,97,102,103,105,109,112,113,114,115,119,121,125,131,133,134,135,144,152,153,247,251,252,256,272,287,290,317,319,322,323,328,329],consider:[68,86,104,111,118,252,330],consist:[2,11,17,33,38,44,46,48,51,68,80,86,92,95,96,109,110,114,116,122,123,135,137,144,151,166,167,175,176,236,242,252,291,296,306,316,318,324,330,342,344],consol:[9,19,23,26,38,42,60,63,64,75,83,90,93,95,96,97,100,106,114,123,137,138,166,169,267],constant:[0,88,276,342],constantli:[96,117],constitu:[153,167],constraint:[0,23],construct:[20,29,34,36,51,64,119,133,138,252,311,316,321,329,357],constructor:[22,33,278],consum:[10,269,344],consumer_kei:[71,120],consumer_secret:[71,120],consumpt:[23,310],contact:[89,90,100],contain:[0,5,7,9,10,11,13,14,16,17,18,20,21,22,25,26,31,33,34,37,38,39,40,41,43,46,47,51,53,55,56,57,62,63,64,68,69,70,75,79,80,86,89,91,95,96,97,101,102,104,105,114,118,119,122,123,124,126,127,128,129,133,134,136,137,138,139,141,142,144,146,147,149,150,151,152,153,155,158,159,164,166,172,238,240,247,249,251,252,260,262,266,270,272,298,310,311,312,316,317,318,319,320,321,322,325,327,328,329,330,341,342,343,344,345,347,355,363,364],container:100,contempl:56,content:[3,4,13,16,17,21,27,38,39,48,49,51,56,58,69,77,79,82,85,89,90,91,93,95,96,117,119,121,123,125,131,133,134,137,138,139,154,157,159,245,246,247,319,321,322,323,326,328,330,341,342,346,347,355,364],content_typ:[246,247],contentof:330,contents_cach:246,contents_get:[119,247],contents_set:247,contentshandl:246,context:[46,51,55,69,91,114,119,126,133,288,292,350],context_processor:350,contextu:112,continu:[7,10,11,21,27,29,33,37,42,45,46,49,51,55,58,60,69,71,75,85,86,90,95,96,112,114,115,116,119,123,124,127,136,139,247,265,276,312,316,328,337,344,364],contrari:[0,41,62,169,319],contrast:[56,90,96,113,138,291],contrib:[4,13,14,20,38,47,53,57,58,62,63,73,78,102,116,122,141,142,144,147,148,169,170,309,321,322,349,357,364],contribut:[1,4,22,26,45,55,64,70,78,82,124,127,131,136,139,178,363,364],contributor:78,control:[2,5,7,9,11,12,13,14,19,20,21,31,33,34,36,37,38,42,47,50,51,52,53,55,57,58,61,63,64,67,68,73,74,80,81,83,86,89,90,92,93,96,102,103,105,108,109,110,114,118,121,123,124,128,135,138,139,144,146,156,158,159,164,241,247,256,267,306,308,318,328,342,357,364],convei:247,convenei:107,conveni:[8,9,10,11,21,34,36,38,40,41,51,55,57,59,69,74,80,86,89,96,98,102,106,108,109,110,125,127,133,140,144,159,169,247,299,310,322,323,328,329,337,340,341],convent:[0,31,86,96,107,119,126],convention:[41,154,247,318],convers:[51,87,121,127,138,295,296,321,344,363],convert:[11,27,39,40,49,51,59,62,64,79,81,83,85,87,88,103,109,113,114,119,126,128,147,157,241,245,251,252,255,257,276,278,287,290,291,308,312,321,325,328,329,330,331,340,343,344,363,364],convert_linebreak:343,convert_url:343,convinc:[51,90],cool:[3,9,21,22,26,61,79,159,164],cool_gui:80,cooldown:[29,116,124,139,364],coord:39,coordi:39,coordin:[49,124,137,139,364],coordx:39,coordz:39,copi:[0,1,4,13,14,20,25,26,33,36,43,47,48,50,51,62,64,81,90,93,96,100,104,105,109,111,123,128,131,133,135,136,137,138,158,159,245,247,255,267,276,313,321,337,364],copy_object:[245,247],copy_script:255,copy_word_cas:344,copyright:[78,90],cor:138,core:[19,37,47,49,76,78,88,89,96,104,106,125,127,131,139,144,148,169,177,178,239,246,247,256,262,274,284,291,305,316,318,319,322,329,335,342,357,364],corner:[17,39,57,79,138,330],corner_bottom_left_char:330,corner_bottom_right_char:330,corner_char:330,corner_top_left_char:330,corner_top_right_char:330,correct:[10,11,14,21,23,27,30,31,33,37,38,48,50,60,80,91,113,114,121,123,126,150,156,159,176,242,282,285,287,293,307,321,342,344],correctli:[4,8,9,27,29,33,36,38,42,44,49,50,51,61,62,72,77,80,85,90,91,97,110,112,115,121,122,123,126,144,148,153,156,257,267,276,312,340],correl:252,correspond:[20,33,80,83,85,105,135,316,357],correspondingli:128,corrupt:56,cosi:111,cosin:344,cost:[28,85,90],cottag:[111,114],could:[0,1,2,3,4,5,6,9,10,11,12,13,14,15,19,20,21,22,25,28,29,30,31,33,34,36,37,38,39,40,41,42,44,46,47,48,49,51,55,57,58,60,61,62,63,64,65,68,69,71,72,73,79,80,81,82,83,84,85,86,87,88,89,90,91,93,95,96,98,102,106,108,109,111,112,113,114,115,116,117,118,119,120,121,123,125,126,127,128,129,132,133,135,136,138,140,144,153,159,166,176,177,242,247,259,272,291,296,312,318,319,321,322,326,330,331,334,339,344],couldn:[11,19,39,44,64,76,91,126,134,140],count:[64,102,104,116,119,120,147,152,247,281,285,298,302,308,310,317,321,328,337],count_loggedin:285,count_queri:302,countdown:[20,29],counter:[6,22,29,69,85,105,116,128,146,285,298,299,306,328],counterpart:[13,114,272,308,325],countless:95,countnod:51,countri:157,coupl:[22,48,69,100,117,131,175],cours:[0,4,9,12,15,21,22,26,33,38,41,46,57,61,64,77,78,91,93,106,108,114,115,122,123,124,132,140],courtesi:12,cousin:[91,129],cover:[6,8,9,13,14,23,29,37,40,48,51,57,59,63,79,80,86,90,95,96,120,127,131,247,344,363],coverag:127,coveral:127,cpanel:90,cpattr:[43,159],cprofil:364,cpu:[12,90,103,169],cpython:93,crack:[61,86],craft:[29,80,111],crank:115,crash:[26,60,61,79,103,111,271,316],crate:[20,87,124],crawl:103,crawler:[171,281],cre:[43,171],creat:[4,9,11,13,14,15,16,19,22,23,25,26,29,31,34,35,37,38,39,40,41,42,43,44,46,47,49,50,54,55,56,57,58,60,61,62,63,64,65,66,67,68,70,71,72,73,75,76,77,78,79,80,81,83,85,87,90,91,93,95,96,102,103,104,105,106,107,108,109,112,116,117,118,119,120,122,124,127,129,130,131,132,134,135,136,137,138,139,140,141,142,144,146,147,148,151,152,153,154,156,159,164,165,166,167,168,169,170,171,175,176,177,238,239,242,245,246,247,249,250,251,252,255,256,259,260,261,264,267,271,272,277,279,280,285,287,288,292,299,305,307,308,310,312,316,317,318,319,320,321,322,323,326,327,328,330,331,337,342,344,360,363,364],create_:[89,125],create_account:[27,53,107,125,141,147,324,342],create_attribut:316,create_cal:144,create_channel:[27,34,53,141,164,175,176,324],create_char:342,create_charact:[144,247],create_default_channel:305,create_delai:260,create_exit:159,create_exit_cmdset:247,create_forward_many_to_many_manag:[148,177,239,246,256,316,318,319,335],create_game_directori:267,create_grid:49,create_help:238,create_help_entri:[27,53,68,141,324],create_kwarg:252,create_match:151,create_messag:[27,34,53,141,176,324],create_obj:342,create_object:[13,27,53,80,85,89,111,123,125,133,141,245,247,252,271,322,324],create_prototyp:[251,252],create_room:342,create_script:[27,53,56,102,116,125,141,255,259,322,324,342],create_secret_kei:267,create_settings_fil:267,create_superus:267,create_tag:317,createnpc:364,creater:53,creation:[11,14,20,21,38,47,51,58,60,61,79,80,81,86,89,97,105,111,123,125,131,133,139,140,141,144,148,159,164,166,175,239,245,246,247,252,256,261,300,318,324,326,327,328,330,357,363],creation_:324,creativ:[79,108],creator:[51,53,79,80,111,123,140,166,175,247,330],creatur:364,cred:[131,287],credenti:[90,103,131,144,287],credentialinterfac:287,credit:[90,103,131,343,344,364],creset:131,crew:119,criteria:[51,119,176,251,317,341],criterion:[119,131,144,238,245,247,255,258,341,344],critic:[19,26,31,60,63,67,97,102,105,114,128,242,266,267,337],critici:318,cron:67,crontab:67,crop:[58,114,327,330,344,364],crop_str:330,cross:[111,138,330],crossbario:295,crossbow:29,crossroad:111,crowd:[61,103],crt:[8,67],crucial:[91,115],crude:0,cruft:1,crush:21,cryptic:138,cryptocurr:103,cscore:123,csessid:[285,295,296,308],csession:[295,296],csrf_token:133,css:[17,55,124,135,136,137,343,347],cssclass:137,ctrl:[48,63,67,90,93,95,100,110,298],culpa:52,cumbersom:[51,121,128],cumul:299,cup:70,cupidatat:52,curi:49,curiou:108,curli:[41,96],curr_sess:308,currenc:[85,120],current:[0,2,9,11,12,13,14,19,20,21,22,25,27,28,29,31,33,41,43,46,48,49,50,51,58,59,60,64,68,74,76,77,79,80,85,86,89,97,100,102,104,105,106,112,114,115,116,119,120,121,123,124,127,128,131,133,137,138,144,147,148,150,151,153,154,156,157,159,164,165,166,168,169,171,238,245,246,247,252,256,260,261,267,272,277,283,284,287,288,291,299,306,308,310,317,318,326,328,330,331,337,338,341,344,364],current_cmdset:159,current_kei:[250,251],current_tim:298,current_us:133,current_weath:102,currentroom:121,curriculum:79,curs:42,curv:[55,56],curx:49,custom:[0,2,6,11,12,14,15,16,17,18,20,21,25,26,27,30,31,33,34,35,43,49,53,55,56,58,60,61,64,65,66,68,69,71,73,74,78,79,83,85,86,87,89,90,97,100,102,104,109,110,112,114,116,117,118,119,121,122,123,125,126,132,133,136,138,139,140,144,146,147,148,150,152,153,154,159,164,165,166,171,175,238,245,247,249,250,251,252,255,261,267,271,273,276,298,307,318,323,326,328,329,330,334,338,339,342,343,344,349,364],custom_evennia_launcher_command:267,custom_gametim:[62,141,142,178,364],custom_kei:251,custom_pattern:[3,4,69,133,134],customfunc:83,customiz:[17,41],customlog:8,customt:342,cut:[20,40,49,50,55,91,111,123,252],cute:136,cutoff:344,cwho:43,cyan:[114,126],cyberspac:79,cycl:[13,14,25,56,61,62,132],cyril:15,daemon:[8,67,93,100,103,110,284,312],dai:[25,27,36,56,61,62,100,103,108,120,126,131,132,139,147,331,337,344,345],daili:87,dailylogfil:337,dalnet:164,dam:56,damag:[14,21,28,61,73,85,103,116,122],damage_taken:56,damnedscholar:48,dandi:140,danger:[13,31,38,82,97,105,152],dare:33,dark:[13,14,17,31,73,79,111,114,122,126,153,256,321,322],darker:[114,126],darkgrai:126,dash:[38,119],data:[2,10,13,15,22,23,25,27,56,57,58,59,61,64,75,83,86,87,88,90,93,96,97,100,102,104,109,112,113,119,125,128,133,134,135,137,138,139,144,146,147,154,159,166,169,245,246,247,249,251,253,259,261,264,265,269,273,274,276,277,278,279,280,285,286,287,288,290,291,292,294,295,296,298,300,305,306,307,308,310,314,316,317,318,319,321,322,323,324,325,327,328,329,330,333,337,338,339,340,344,357,364],data_in:[40,83,276,278,279,285,286,290,295,296,306,307,308],data_out:[40,285,287,290,291,296,306,307,308],data_to_port:264,data_to_serv:277,databa:267,databas:[0,4,5,6,7,11,12,13,15,17,19,20,21,23,25,27,28,29,31,34,36,38,39,45,47,55,56,57,58,59,60,61,63,64,74,77,80,84,87,89,91,93,100,101,102,104,105,107,110,111,112,115,116,119,123,124,125,127,131,133,134,135,136,138,139,140,144,147,148,152,153,159,166,169,175,176,177,236,238,239,241,245,246,247,251,253,255,256,257,260,261,267,271,273,284,298,305,314,316,317,318,319,322,324,325,332,334,340,341,344,346,364],datareceiv:[269,276,290,298],dataset:251,datastor:86,datbas:119,date:[7,11,12,23,34,49,62,68,75,76,86,126,128,131,133,138,153,157,169,331,337,345],date_appli:133,date_cr:[125,144,148,177,239,256,316,318],date_join:148,date_s:34,datetim:[62,125,133,316,331,337,338,344,345],datetime_format:344,datetimefield:[86,133,148,177,239,246,256,316,318,344],david:79,day_rot:337,db3:[23,111,128,131],db_:[84,86,119,125,245,247,257,272,341],db_account:[245,246,256],db_account_id:[246,256],db_account_subscript:177,db_attribut:[107,119,148,177,246,256,318],db_attrtyp:316,db_attryp:87,db_categori:[86,316,319],db_category__iequ:86,db_cmdset_storag:[148,246],db_data:319,db_date_cr:[86,148,177,239,246,256,316,318],db_desc:256,db_destin:246,db_destination__isnul:120,db_destination_id:246,db_entrytext:239,db_header:177,db_help_categori:239,db_help_dict:166,db_hide_from_account:177,db_hide_from_object:177,db_hide_from_receiv:177,db_hide_from_send:177,db_home:246,db_home_id:246,db_index:86,db_interv:256,db_is_act:256,db_is_bot:148,db_is_connect:148,db_kei:[69,84,86,119,125,239,257,274,316,318,319,357],db_key__contain:125,db_key__icontain:86,db_key__istartswith:119,db_key__startswith:[119,125],db_locat:[84,119,246],db_location__db_tags__db_kei:119,db_location__isnul:120,db_location_id:246,db_lock_storag:[177,239,316,318],db_messag:177,db_model:[316,319],db_obj:[256,325],db_obj_id:256,db_object_subscript:177,db_permiss:86,db_persist:256,db_properti:272,db_protototyp:251,db_receiver_extern:177,db_receivers_account:177,db_receivers_object:177,db_receivers_script:177,db_repeat:256,db_sender_account:177,db_sender_extern:177,db_sender_object:177,db_sender_script:177,db_sessid:[245,246],db_start_delai:256,db_strvalu:316,db_tag:[119,148,177,239,246,256,318,319],db_tags__db_categori:[39,119],db_tags__db_kei:[39,119],db_tags__db_key__in:39,db_tagtyp:319,db_text:86,db_typeclass_path:[86,120,246,318,344],db_valu:[84,87,274,316],dbef:[159,255,341],dbentri:166,dbhandler:357,dbholder:316,dbid:[125,146,164,318],dbid_to_obj:344,dbmodel:317,dbobj:[11,316],dbobject:[11,317,318],dbprototyp:[159,251],dbref:[12,13,20,58,66,80,109,111,116,119,121,122,125,128,144,147,148,157,159,164,176,177,241,245,246,247,252,255,256,258,317,318,324,341,344,364],dbref_search:[147,245,255,317],dbref_to_obj:344,dbrefmax:159,dbrefmin:159,dbsafe_decod:340,dbsafe_encod:340,dbserial:[11,97,141,142,257,320,364],dbshell:[23,86,110,128],dbunseri:325,ddesc:56,deactiv:[63,64,81,117,164,328],dead:[112,305,308,334],deadli:122,deal:[10,11,12,15,41,51,64,69,73,91,103,105,112,113,116,124,126,127,131,134,138,139,144,246,247,306,318,321,338,364],dealt:167,death:[51,73,120],debat:91,debian:[8,23,63,67,131],debug:[14,27,45,51,59,72,74,91,95,102,106,135,139,150,154,158,169,249,267,272,278,279,290,312,322,328,337,344,364],debugg:[15,42,110,141,364],decemb:90,decend:[51,150],decent:93,decid:[4,14,15,25,33,41,46,58,61,69,73,85,86,88,90,103,105,112,114,116,126,138,150,242,329],deciph:48,decis:[73,115],declar:[114,340],declared_field:357,declin:51,decod:[15,291,321,344],decode_gmcp:291,decode_msdp:291,decoded_text:344,decompos:133,decompress:[276,340],deconstruct:[122,170,293],decor:[0,29,33,46,107,131,148,246,247,255,256,264,276,277,318,324,328,329,342,344,364],decoupl:[9,251],decoupled_mut:11,decreas:326,decrease_ind:326,dedent:[50,344,364],dedic:[73,90,127,364],deduc:326,deduce_ind:326,deduct:[73,85],deem:[37,57,129,131,178],deep:79,deeper:41,deepest:159,deepli:11,deepsiz:344,def:[1,3,4,5,6,10,11,21,22,25,27,28,29,30,31,33,38,39,40,41,42,44,48,49,50,51,56,57,58,60,62,69,71,73,74,79,80,81,82,84,85,89,91,95,96,102,107,109,111,114,116,117,118,119,120,121,123,125,127,132,133,134,250,296,309,326,328,329,342,344],defalt_cmdset:71,default_access:[1,11,245,255,316,324],default_categori:238,default_channel:34,default_cmd:[5,21,22,25,28,29,30,41,44,53,57,58,62,81,116,119,141],default_cmdset:[5,22,25,30,35,41,44,57,58,60,62,81,82,105,123,153],default_command:25,default_confirm:159,default_error_messag:340,default_help_categori:166,default_hom:[59,109],default_in:137,default_out:137,default_pass:[147,324],default_screen_width:33,default_set:[3,127],default_transaction_isol:23,default_unload:137,defaultaccount:[2,41,53,64,125,141,144,146,160,247,342,357],defaultchannel:[6,53,125,141,164,175],defaultcharact:[5,6,22,25,53,57,58,60,62,73,81,86,89,96,123,125,127,141,144,161,247,316,342,357],defaultdict:257,defaultexit:[6,53,85,89,125,141,247,342],defaultguest:[53,141,144],defaultmod:337,defaultobject:[5,6,26,38,53,60,64,82,85,86,89,96,111,117,119,121,125,141,144,247,318,342,357,364],defaultpath:344,defaultroom:[6,39,49,53,56,85,89,125,132,141,247,342],defaultscript:[53,56,102,116,120,121,125,141,146,251,258,259,300,331,342],defaultsess:162,defaulttyp:312,defaultunloggedin:163,defeat:[73,116,122],defend:[51,116,122,247],defens:116,defer:[10,27,29,33,133,148,150,169,177,239,246,247,256,260,264,274,276,277,308,312,316,318,319,335,337],deferredlist:312,defin:[0,2,4,5,10,11,12,13,14,20,21,22,25,27,30,35,36,40,42,44,46,49,50,53,55,56,57,58,59,61,62,64,68,69,73,74,77,78,81,83,85,88,89,91,95,96,97,104,106,109,111,113,114,115,117,119,121,123,125,126,127,129,133,135,136,137,138,139,141,143,148,150,152,153,154,156,159,165,166,167,169,170,171,175,176,177,236,238,239,240,241,242,243,245,246,247,251,252,255,256,259,261,262,264,267,274,277,298,299,306,307,308,311,314,316,317,318,319,321,322,323,326,328,331,335,339,341,344,350,357,364],define_charact:51,definit:[0,2,5,10,12,14,20,33,34,39,41,42,55,60,61,68,69,82,83,87,88,89,109,114,115,124,127,152,154,159,167,176,240,242,246,251,252,258,322,324,328,340,364],defit:51,deflist:312,degrad:127,deindent:344,del:[11,12,29,43,58,80,116,122,157,159,318],del_pid:267,delai:[0,28,33,45,120,169,260,261,279,285,308,323,344,364],delaliaschan:43,delayed_import:308,delchanalia:43,delcom:[43,58],deleg:[148,177,239,246,256,316,318,319,335],delet:[2,4,7,11,12,13,20,22,23,31,43,50,51,63,66,68,80,87,89,98,100,102,105,107,111,112,116,122,128,131,144,153,156,157,158,159,164,165,166,169,175,177,239,242,247,251,255,257,258,259,260,261,273,285,306,316,318,321,322,328,334,360],delete_attribut:316,delete_default:[31,153],delete_prototyp:251,delete_script:255,deliber:[11,42,129,344],delimit:[91,167,322,364],delin:48,deliv:90,deltatim:344,delux:90,demand:[30,58,61,73,90,115,117,144,175,247,309,323],demo:[22,55,79,138,328,364],demon:109,demonin:344,demonstr:[0,4,22,126,133],demowiki:4,deni:[8,103],denot:[56,114,134,322],denounc:327,depart:49,depend:[0,4,10,11,12,14,15,16,22,27,31,33,34,37,40,46,49,51,55,57,58,61,63,64,69,72,73,74,75,83,85,88,90,93,95,97,100,102,103,104,105,106,111,114,115,116,118,123,125,131,133,134,137,138,143,150,152,154,156,169,242,247,251,261,267,287,290,296,298,308,318,319,326,328,329,344,364],deploi:[38,46,90,103,364],deploy:[36,38,79,90,100,106],depmsg:337,deprec:[27,51,94,109,141,142,252,262,321,328,337,344,364],deprecationwarn:266,depth:[16,17,36,95,114,122,124,166,252],dequ:[11,310],deriv:[23,56,63,67,100,108,119,125,127,321,345],desc:[14,20,21,22,34,41,43,57,58,60,69,74,80,84,85,89,102,109,111,116,120,134,153,156,159,164,166,170,176,247,255,256,265,322,324,326,327,328,357,364],descend:[119,357],descer:364,describ:[5,9,11,13,14,20,21,22,30,31,33,37,38,43,46,51,55,58,62,63,64,68,69,71,75,76,79,80,85,86,88,90,92,96,102,109,110,111,113,114,116,124,125,127,128,131,133,135,137,139,152,159,163,165,177,247,252,259,264,285,287,290,300,328,343,344,363],descript:[0,14,15,20,21,22,34,38,39,41,46,49,51,54,55,57,58,60,61,68,74,77,85,90,96,102,109,111,112,126,129,131,133,134,135,139,156,159,164,165,175,176,247,255,256,322,324,328,338,339,364],description_str:111,descriptor:316,deseri:[11,97,338],deserunt:52,design:[14,16,23,26,33,37,39,41,55,57,61,79,89,91,108,109,111,112,117,118,119,124,129,133,138,153,159,247,322,338,344,364],desir:[1,4,27,28,29,49,57,58,59,91,108,112,114,115,119,121,123,133,137,159,175,176,242,267,312,316,324,330,345],desired_perm:242,desktop:[15,16,138],despit:[11,13,57,63,64,79,81,105],dest:247,destin:[0,22,25,33,49,74,77,85,89,91,109,111,119,121,159,245,246,247,252,324],destinations_set:246,destroi:[0,20,43,89,103,116,127,144,146,159,164,247],destroy_channel:164,destruct:[31,152],detach:106,detail:[2,5,9,12,15,19,20,22,26,30,33,34,37,38,41,46,51,58,60,61,63,64,80,88,89,90,91,93,95,96,105,109,111,114,116,118,122,124,125,128,129,131,134,135,136,139,153,154,159,175,239,252,260,269,270,306,308,318,321,326,344,360,364],detail_color:159,detect:[31,33,36,38,61,81,88,89,103,105,118,151,154,279],determ:317,determin:[2,4,13,15,20,27,29,31,33,34,39,44,49,50,51,52,63,73,80,82,83,85,87,93,102,109,110,116,123,136,137,144,152,153,154,156,164,166,167,175,239,242,247,251,291,316,317,318,321,326,329,337,342,344,347],detour:[21,83,308],dev:[1,23,37,55,57,63,64,67,71,76,79,90,95,98,138],devel:170,develop:[3,9,15,16,19,20,25,26,27,33,36,37,38,42,48,54,55,56,58,60,61,63,64,68,70,71,72,76,77,80,86,88,90,91,93,96,97,99,104,106,108,109,111,114,123,126,131,133,135,136,137,138,139,154,157,158,164,165,166,169,175,239,247,252,313,318,319,322,328,363,364],devoid:321,dex:[11,51,58,327],diagnos:[30,97],diagram:125,dialog:137,dialogu:[0,124,139,364],dice:[63,73,91,116,141,142,178,364],dict:[0,11,13,25,31,46,51,53,88,107,109,119,127,144,146,152,154,159,166,175,247,249,250,251,252,259,261,264,265,267,272,276,277,278,280,285,287,290,295,296,307,308,310,317,322,323,325,327,328,329,339,342,344,357],dictat:[31,62,117],dictionari:[0,10,11,13,25,31,49,55,56,62,69,73,80,96,97,102,109,116,124,134,138,157,159,242,252,260,272,285,294,306,307,308,310,317,321,323,327,328,334,338,339,340,344,357,364],did:[2,21,22,29,57,60,64,68,91,95,96,104,111,123,131,144,247,260,319,340,344],didn:[5,20,22,38,41,42,44,49,51,58,59,61,72,80,91,100,104,119,121,126,127,133,136,140],die:[73,91,106,114,117,308],diff:[75,131,252],differ:[0,2,8,9,11,13,14,15,16,19,20,21,22,24,25,27,31,33,37,38,39,40,41,42,44,46,47,49,50,51,54,55,57,58,61,62,63,64,66,68,69,70,73,79,80,82,83,84,87,88,91,93,95,96,100,102,103,105,106,107,109,110,111,112,113,114,115,116,118,119,120,121,124,126,127,129,131,133,136,137,138,139,140,141,144,150,152,153,156,159,166,168,169,171,175,245,247,249,252,255,256,261,265,269,291,296,298,316,318,322,324,328,337,340,344,364],differenti:[56,57,58,247,344],differet:61,difficult:[4,39,93,103,133],difficulti:133,dig:[0,20,31,33,40,43,57,58,89,93,96,109,121,123,140,159,299],digit:[12,90,114,127,311,321,337],digitalocean:[67,90],diku:[55,64,124,139,364],dikumud:129,dime:108,dimens:[49,55],dimension:58,diminish:114,dimli:111,dinner:46,dip:96,dir:[9,21,23,36,38,54,58,63,64,67,75,79,90,96,100,102,127,128,130,131,134,337,344,347],direct:[0,3,8,10,11,12,20,22,31,44,45,49,51,58,70,74,88,90,100,109,111,116,118,119,121,128,137,138,139,159,242,245,259,267,328,330,337,341,342,344,364],directli:[2,5,8,13,14,20,21,23,27,29,30,33,37,38,40,42,44,46,50,51,55,56,58,59,61,62,64,72,80,88,89,90,93,95,96,100,102,104,109,110,111,114,116,118,119,123,125,128,131,137,138,147,154,170,176,238,242,245,246,247,251,255,256,273,278,287,290,295,298,300,306,316,318,322,324,328,329,342,344],director:247,directori:[4,8,9,13,20,25,27,36,37,45,58,59,62,63,64,69,75,76,95,96,100,106,123,125,127,128,130,131,133,134,135,136,137,139,159,267,287,288,312,322,337,344,364],directorylist:312,dirnam:267,dirti:55,disabl:[0,4,24,25,50,63,80,81,106,114,127,137,154,170,242,251,290,310,329,334,345,364],disableloc:290,disableremot:290,disadvantag:[58,90,116],disambigu:[41,72,119,154,247,318],disappear:103,discard:321,disconcert:41,disconnect:[2,11,12,40,41,55,57,60,92,97,105,107,110,112,116,123,128,137,144,156,159,164,167,169,175,247,277,278,279,285,286,287,290,295,296,299,305,306,307,308],disconnect_al:285,disconnect_all_sess:308,disconnect_duplicate_sess:308,disconnect_session_from_account:144,discontinu:24,discord:[9,63,72,79],discordia:108,discourag:[64,75],discov:[91,122,316],discrimin:103,discuss:[1,4,25,26,33,37,45,48,55,63,69,70,116,138,139,364],discworld:88,disengag:[116,144],disk:[11,27,86,100,108,110,249],dislik:57,disonnect:11,dispatch:37,dispel:126,displai:[0,17,22,25,30,31,33,38,42,46,50,51,58,59,60,61,68,69,73,80,81,82,83,85,88,89,91,93,101,102,103,104,111,114,116,119,123,124,133,134,135,136,137,138,139,144,154,156,159,164,166,169,171,247,251,252,265,267,284,302,305,310,318,319,326,327,328,329,330,338,339,340,342,343,344,345,357,364],display:261,display_all_channel:164,display_buff:326,display_help:326,display_helptext:[249,328],display_len:344,display_nodetext:328,display_subbed_channel:164,dispos:111,disput:116,disregard:33,dist:[63,130],distanc:[6,27,39,46,49,64,125,247,344],distance_to_room:39,distant:[49,138],distinct:[55,64,105,140],distinguish:[22,154],distribut:[8,9,15,23,31,34,42,63,64,78,96,97,124,127,128,175,176,177,321,324,344],distribute_messag:175,distributor:34,distro:[8,23,63,67,72],disturb:[27,140],distutil:63,distutilserror:63,ditto:63,div:[3,16,17,38,109,137],dive:[22,41,63],diverg:83,divid:[13,64,69,344],divisiblebi:69,django:[2,3,4,9,12,15,23,25,36,39,55,63,69,73,76,79,86,101,103,104,107,112,113,120,124,125,127,128,134,136,137,139,144,147,148,154,171,175,177,239,245,246,251,255,256,266,267,273,274,287,293,295,296,303,309,310,311,312,316,318,319,322,325,329,333,334,335,340,342,344,346,349,352,357,364],django_admin:360,django_nyt:4,djangonytconfig:4,djangoproject:[23,357],djangowebroot:312,dmg:73,dnf:[8,63,67],do_batch_delet:316,do_batch_finish:316,do_batch_update_attribut:316,do_create_attribut:316,do_delete_attribut:316,do_flush:[318,334],do_gmcp:291,do_mccp:280,do_msdp:291,do_mssp:281,do_mxp:282,do_naw:283,do_nested_lookup:159,do_not_exce:25,do_pickl:325,do_search:166,do_task:[169,260,344],do_task_act:169,do_unpickl:325,do_update_attribut:316,do_xterm256:321,doabl:[14,138],doc:[16,17,23,25,33,45,51,53,60,64,68,70,79,86,95,96,109,110,125,129,130,136,139,141,159,169,247,278,344,357,363,364],docker:[7,63,79,90,139,364],dockerfil:100,dockerhub:100,docstr:[1,5,25,41,68,74,96,154,159,170,298,328,364],documen:96,document:[0,3,5,6,9,16,17,20,22,23,24,25,26,29,41,43,46,47,48,52,55,57,58,60,64,68,70,76,79,83,86,90,96,103,104,106,111,114,118,121,122,123,124,125,127,131,133,135,136,139,153,167,316,319,327,334,364],doe:[2,4,5,9,11,20,21,23,24,25,26,29,31,33,37,38,39,40,41,49,51,54,55,56,57,58,60,61,63,64,68,69,73,78,80,85,88,89,91,95,96,100,102,104,109,110,111,112,113,114,116,117,118,119,121,123,125,126,127,129,131,132,133,136,137,138,140,144,146,156,167,169,171,247,251,252,257,259,260,266,267,271,272,273,276,279,287,288,294,316,318,323,328,337,340,342,344,349,357],doesn:[0,4,9,11,13,15,22,25,26,29,33,36,37,39,44,46,49,51,57,60,61,63,69,71,72,73,75,76,78,86,88,89,90,91,95,96,103,110,111,121,123,125,126,127,128,133,136,137,138,153,164,175,177,242,247,267,280,287,291,316,321,328,339,344],doesnotexist:[144,146,148,175,177,239,245,246,247,251,256,259,274,300,316,319,324,331,335],dog:[27,96],doing:[2,4,10,11,27,29,31,33,36,38,39,43,46,49,51,57,58,59,60,61,64,69,70,79,80,89,90,95,96,97,105,110,114,115,119,125,126,127,133,134,137,138,144,156,175,241,247,261,298,328,334,340],dolor:52,dom:137,domain:[8,55,67,90,103,138,147,324],domexcept:90,dominion:9,dompc:9,don:[0,1,3,4,6,9,10,11,20,21,22,23,25,26,27,29,30,31,33,34,37,38,39,41,42,44,46,47,50,51,54,58,59,61,62,63,64,67,68,69,70,72,73,75,80,81,82,83,85,86,88,90,91,93,95,96,97,102,103,104,105,106,111,114,116,119,122,123,125,126,127,128,131,132,133,134,135,136,138,140,144,146,152,153,159,164,165,166,167,168,171,175,242,246,247,251,252,261,272,279,284,285,290,292,299,306,313,318,321,322,328,334,337,340,344,357,364],donald:93,donat:[70,90,364],done:[1,4,6,9,10,11,20,21,22,25,29,30,31,33,34,36,37,38,39,41,44,49,51,55,56,57,58,59,61,62,63,64,67,69,70,73,76,80,82,85,87,90,91,93,100,107,108,110,115,116,117,118,119,120,121,123,126,128,131,133,136,137,144,154,156,164,177,242,246,247,259,260,261,267,271,280,284,286,288,292,296,302,305,306,308,313,316,321,322,329,334,342,344],donoth:259,dont:289,doom:252,door:[0,20,22,27,49,61,80,85,89,103,159],dot:[22,119,153,159,322,344],dotal:[321,343],dotpath:344,doubl:[22,38,57,97,119,133,152,171,343,344],doublet:[152,153],doubt:[22,138],down:[0,4,6,11,12,21,22,29,31,33,36,38,39,41,49,50,51,55,57,58,61,63,73,81,85,86,90,91,93,96,100,102,103,104,106,108,111,114,119,122,123,136,137,144,159,164,169,241,247,252,259,261,267,269,276,277,284,285,305,306,308,321,329,330,344,364],download:[5,9,23,26,63,64,72,75,79,90,100,101,128,130,131,139],downtim:[29,103,331],downward:156,dozen:[25,55,108],drag:137,draggabl:138,dragon:56,dramat:[11,61,251,252],draw:[14,38,39,49,73,119,330],draw_room_on_map:49,drawback:[14,23,28,29,51,58,73,86,138,322],drawn:[49,58,111],drawtext:73,dream:[26,55,61,129],drink:[316,318],drive:[9,19,21,61,63,64,96,100,121,131,133],driven:[25,79,123,249],driver:23,drizzl:[102,132],drop:[6,9,14,20,21,23,25,33,37,40,43,55,57,58,60,69,70,73,80,85,86,87,88,89,90,117,118,121,128,137,138,159,165,171,247,276,318,322,344],drop_whitespac:330,dropdown:[106,138],droplet:67,dropper:247,drum:90,dry:67,dtobj:344,duck:[27,95],duckclient:24,due:[5,6,12,22,29,31,33,40,58,60,62,63,64,76,90,91,93,95,96,104,107,125,126,140,153,169,246,247,269,305,308,321,337],duh:108,dull:[20,26,111],dumb:[20,138,308,321],dummi:[9,33,54,59,80,93,127,242,267,272,285,298,299,306,364],dummycli:298,dummyfactori:298,dummyrunn:[141,142,262,267,285,297,299,301,364],dummyrunner_act:298,dummyrunner_actions_modul:298,dummyrunner_echo_respons:298,dummyrunner_set:[93,141,142,262,267,297,364],dummyrunner_settings_modul:93,dummyrunnercmdset:298,dummysess:308,dump:[34,276],dungeon:[55,77,112],dupic:31,duplic:[31,37,96,152,159,166,261,318,337],durat:[10,28,132,139,169,338,345,364],dure:[9,11,29,31,38,40,55,60,61,63,66,68,79,80,95,97,100,102,105,107,116,123,132,135,136,137,140,144,152,164,170,242,245,260,276,286,322,324,328,337,357,364],duti:64,dwarf:111,dynam:[2,3,34,38,68,82,86,90,111,114,115,124,133,137,138,139,144,148,154,166,169,170,177,238,239,246,247,251,256,261,316,318,319,324,326,328,335,338,344,347,364],dyndns_system:90,e_char_typeclass:120,each:[0,1,2,4,5,10,11,13,19,20,22,27,29,31,33,34,36,38,39,40,42,48,49,51,55,56,57,58,59,61,62,64,69,73,77,80,82,83,85,86,95,96,97,100,102,104,105,108,109,111,112,114,115,116,119,121,123,124,125,126,127,132,133,136,137,138,140,144,151,152,153,157,159,164,166,168,175,239,242,246,247,250,251,252,258,261,269,272,285,287,290,294,299,306,307,308,316,318,319,321,322,324,326,327,328,329,330,334,342,344,347],earli:[36,138,269,364],earlier:[3,9,13,31,36,51,54,58,60,61,62,64,74,85,95,96,106,119,121,123,131,134,272],earn:124,earnest:124,earth:[82,103],eas:[31,33,39,86,90,100,126],easi:[0,5,10,13,17,22,23,26,29,33,38,39,46,51,55,56,61,62,67,68,69,72,73,76,79,81,82,85,88,89,90,100,102,106,108,111,113,116,118,123,125,126,127,128,131,133,134,138,140,153,157,328,334],easier:[1,4,10,11,12,22,25,37,39,47,51,55,56,57,58,61,62,69,73,86,90,91,95,96,102,109,126,136,159,309,316,319,344],easiest:[0,5,12,15,25,27,30,46,58,63,67,70,76,123,128,131,133,135,318],easili:[0,3,4,11,12,13,14,17,20,25,27,28,33,34,37,38,39,46,48,49,51,55,58,60,61,62,63,68,70,73,80,83,85,88,90,91,96,98,100,103,105,106,107,108,109,111,112,119,122,123,131,133,136,137,138,140,164,175,177,238,239,261,322,328,339],east:[25,44,49,111,159],east_west:111,eastern:[62,111],echo1:29,echo2:29,echo3:29,echo:[5,10,12,20,26,27,28,29,33,36,38,44,49,50,55,59,65,71,90,95,96,98,100,104,109,110,116,118,123,132,140,144,146,157,159,164,169,247,265,272,287,290,326,328,342,344,364],echotest:5,econom:[55,79,86],economi:[61,73,102,108,120],ecosystem:100,ect:96,edg:[16,27,131,330,342,344],edgi:49,edit:[0,1,4,5,6,9,11,13,14,23,25,26,30,33,35,37,40,41,43,46,48,54,56,58,59,60,61,62,67,68,69,70,75,76,79,80,81,86,95,96,97,100,101,104,106,109,111,114,128,133,134,135,136,137,138,157,159,166,169,242,247,249,251,252,316,326,357,364],edit_handl:159,editcmd:22,editnpc:364,editor:[0,5,9,15,21,22,33,38,45,46,53,57,60,63,67,76,79,95,96,97,108,109,111,131,139,159,166,168,169,256,322,326,364],editor_command_group:326,editorcmdset:326,editsheet:58,edu:124,effect:[6,10,11,14,27,28,29,31,35,38,39,56,57,58,61,73,87,95,104,107,110,111,114,115,116,117,124,126,127,128,129,138,140,144,152,153,159,168,175,245,247,253,256,280,344],effici:[11,26,28,29,39,55,56,64,76,79,86,87,93,95,103,112,115,119,125,132,242,247,261,316,317,319,326,329],effort:[37,56,131,134],egg:75,egg_info:63,egi:269,egiven:245,either:[0,4,9,12,13,17,23,27,29,31,33,34,37,39,41,44,46,49,51,56,57,58,69,73,80,83,90,91,93,95,97,102,103,105,109,110,111,112,114,116,119,121,122,123,125,126,128,131,137,138,144,146,152,153,154,159,164,176,242,247,250,252,256,258,259,261,265,276,288,292,299,317,318,319,328,330,337,339,341,344],elabor:[4,22,38,85,91,123],electr:[90,124],eleg:37,element:[16,17,22,41,51,55,91,114,151,156,166,247,252,316,317,319,322,327,328,329,342,344],elev:[46,82,124,139,364],elif:[0,41,49,51,58,73,102,116,117,123],elimin:[96,100,321],elimit:344,ellipsi:96,ellow:[114,321],els:[0,1,2,5,9,10,12,19,20,21,22,23,25,27,29,30,33,38,39,41,42,46,48,49,51,58,60,68,69,73,80,81,82,84,85,90,91,95,102,103,111,114,115,116,117,120,121,123,127,131,133,134,137,164,170,246,296,318,328,344],elsennsometh:170,elsewher:[2,29,31,58,70,96,112,133,138,153,267,308,316],emac:[14,79],email:[63,64,67,131,144,147,324,338,344,345,357],email_login:[141,142,178,364],emailaddress:344,emailfield:357,emb:[38,58,109,114,252],embark:121,embed:[109,114,125,138,166,175,250,327,344],emerg:[76,80,103],emit:[25,34,108,137,144,153,157,175,247,306,337],emit_to_obj:[153,247],emitt:83,emo:21,emoji:24,emot:[33,41,43,55,68,116,144,165,316],emphas:[38,61],emphasi:38,emploi:345,empti:[0,2,3,6,9,10,14,25,31,33,38,41,42,47,49,51,54,58,60,63,64,69,73,77,84,86,88,89,91,96,97,100,114,115,117,119,123,125,127,128,131,134,137,138,147,150,151,157,159,164,170,247,251,252,265,272,276,298,299,316,322,324,328,330,341,344],empty_permit:357,empty_threadpool:312,emptyset:31,emul:[64,75,105,123,129,169,364],enabl:[8,24,71,100,103,106,114,126,134,137,144,290,345],enableloc:290,enableremot:290,encamp:46,encapsul:338,encarnia:79,encas:326,enclos:[35,50,171],encod:[7,27,43,58,111,139,171,278,291,295,296,321,340,344,364],encode_gmcp:291,encode_msdp:291,encoded_text:344,encompass:27,encount:[60,95,153,245,345],encourag:[3,22,24,39,70,91],encrypt:[7,8,83,103,164,287,288,292,364],end:[1,5,6,8,9,10,11,13,14,19,20,21,22,23,25,27,28,29,31,33,34,38,39,40,47,50,51,54,55,58,60,62,64,65,67,69,73,76,80,81,83,86,87,88,90,91,93,95,96,100,105,107,108,109,114,116,118,119,121,122,123,126,128,131,133,134,135,137,138,140,144,146,152,153,159,165,166,176,238,271,278,279,287,290,291,298,301,306,310,312,317,321,322,324,328,329,330,337,344,364],end_convers:51,end_turn:116,endblock:[3,69,133,134],endclr:114,endfor:[69,133,134],endhour:25,endif:[69,133,134],endlessli:103,endpoint:103,endsep:344,endswith:321,enemi:[11,29,51,61,109,116,122],enemynam:51,enforc:[10,33,41,61,73,80,114,126,138,287,290,329,330,342],enforce_s:330,engag:55,engin:[22,23,33,36,55,56,64,68,73,77,79,89,102,103,104,122,127,131,136,140,150,153,166,168,169,238,267,278,284,287,290,295,305,307,322,324,364],english:[15,76,79,97,113,139,171],enhanc:[59,81,114,321],enigmat:20,enjoi:[61,63,91,106,364],enough:[4,6,21,29,38,39,41,42,51,55,57,58,61,63,64,69,70,80,84,85,87,90,91,96,108,112,115,119,123,126,136,153,159,328,329,330,342],ensdep:344,ensur:[49,69,100,106,117,126,127,310,342],ensure_ascii:296,enter:[0,1,3,5,9,12,13,14,15,20,21,22,23,25,26,27,29,31,33,35,36,41,42,44,46,51,58,62,63,64,66,69,75,77,80,83,85,87,89,91,95,96,100,109,111,114,116,117,119,122,123,124,128,129,131,133,135,138,139,141,144,151,153,158,166,167,169,241,247,252,256,265,306,328,347,357,364],enter_guild:51,enter_nam:51,enterpris:36,entir:[10,11,13,14,19,22,27,29,33,46,49,50,51,60,61,69,80,86,90,91,108,111,114,115,123,125,127,136,242,247,251,252,318,319,322,328,330,334,344,364],entireti:[51,73,328],entit:[176,324],entiti:[6,11,27,34,47,51,53,55,59,61,64,80,84,87,89,102,105,107,109,112,116,119,125,126,139,143,144,154,159,164,169,175,176,177,239,241,245,247,249,250,251,252,253,255,256,257,259,261,308,316,317,319,324,328,329,333,341,344],entitii:107,entitl:90,entranc:111,entri:[4,5,11,15,24,25,27,31,33,34,47,48,51,54,58,59,63,69,70,72,77,80,83,91,95,107,119,121,131,138,139,144,154,166,167,170,236,238,239,242,247,261,286,299,310,316,322,324,326,328,330,337,338,341,344,345,360,364],entriest:156,entrust:59,entrypoint:100,entrytext:[69,238,239,324],enul:8,enumar:344,enumer:134,env:[267,277],environ:[4,7,9,13,25,36,38,45,59,61,63,64,65,82,90,95,100,103,128,169,170,267,277,293,302,322,328,342,360],environment:267,eof:287,epic:79,epoch:[27,62,331],epollreactor:312,epub:79,equal:[0,16,19,20,25,31,33,39,46,91,93,96,97,114,121,152,164,247,344],equip:[14,57,114],equival:[10,11,13,40,47,63,87,88,101,103,104,110,114,128,143,147,159,238,245,255,285,291,316,344],eras:[9,95],err:[58,276,298,322],err_travers:[89,247],errback:[10,264,267,276,277,344],errmessag:152,errmsg:[123,337],erron:[113,123,276,330],error:[1,5,6,8,9,10,11,14,15,20,22,23,24,26,27,31,33,37,38,42,51,56,57,58,59,60,63,64,67,71,74,75,76,80,83,86,87,89,90,91,97,103,104,105,109,111,113,114,118,119,120,122,123,125,127,128,131,133,135,139,144,147,150,152,153,159,164,171,175,242,245,247,250,251,255,259,260,264,266,267,269,271,272,276,290,298,318,321,322,324,327,328,337,340,344,345,364],error_check_python_modul:267,error_class:357,error_cmd:44,error_msg:310,errorlist:357,errorlog:8,escal:[2,19,80,156,241,319],escap:[69,114,165,169,321,343,357],escript:22,esom:166,especi:[1,8,15,22,23,29,60,61,63,67,80,105,111,112,124,322],ess:52,essai:79,essenti:[28,49,56,67,75,79,106,113,176,267,324],est:[52,170],establish:[33,61,73,105,144,247,264,276,278,285,287,290,295,298,305,307],estim:[30,252,334],esult:247,etc:[2,5,6,8,11,12,20,22,23,25,27,29,30,33,35,38,40,41,47,48,49,51,53,55,56,57,58,61,62,63,64,67,73,79,80,83,84,86,87,88,89,95,96,100,102,103,105,107,108,109,110,112,116,119,120,125,126,127,131,132,137,138,144,148,150,151,152,153,156,158,159,164,167,169,171,176,247,251,252,285,287,290,294,295,296,306,307,316,318,321,322,324,325,326,327,328,337,344,347],etern:51,ev_channel:146,eval:[109,344,364],evalstr:242,evalu:[33,38,51,119,151,242,328],evbot:[164,308],evcast:79,evcel:[327,330],evcolor:79,evcolumn:330,eve:344,eveditor:[22,43,45,53,139,141,142,320,364],eveditorcmdset:326,even:[1,4,6,9,11,12,14,19,21,22,25,26,27,29,31,37,39,41,42,46,49,50,51,54,55,56,57,58,60,61,62,63,64,69,70,73,77,80,85,86,90,91,93,97,102,103,105,106,108,110,114,115,116,118,119,122,123,125,126,129,131,135,138,144,152,154,157,164,166,175,247,251,252,290,328,330,334,344],evenli:[27,344],evenn:100,evenna:9,evenni:4,evennia:[0,1,2,3,6,10,11,12,13,14,15,17,19,20,21,22,24,27,28,29,30,31,33,34,35,36,37,39,40,43,44,48,49,50,51,52,53,59,60,61,62,63,64,65,66,68,69,70,72,73,74,78,80,81,82,83,84,85,86,87,88,89,92,93,94,97,98,99,101,102,103,104,105,107,108,111,112,113,114,115,116,117,118,119,120,121,122,123,125,129,130,132,133,134,135,136,138,139,364],evennia_access:8,evennia_channel:[65,72,98,164],evennia_dir:344,evennia_error:8,evennia_launch:[106,141,142,262,265,364],evennia_logo:136,evennia_patreon_100x100:70,evennia_runn:106,evennia_vers:267,evennia_websocket_webcli:295,evennia_wsgi_apach:8,evenniacommandmixin:342,evenniacommandtest:342,evenniacommandtestmixin:342,evenniaform:357,evenniagameindexcli:269,evenniagameindexservic:270,evennialogfil:337,evenniapasswordvalid:311,evenniareverseproxyresourc:312,evenniatest:[342,364],evenniatestcas:342,evenniatestmixin:342,evenniausernameavailabilityvalid:[144,311],evenniawebtest:360,event:[51,64,73,103,107,137,139,141,146,256,259,309,364],eventdict:337,eventfunc:[0,141,142,178,191,364],eventi:154,eventu:[4,11,12,19,25,29,33,41,58,61,70,76,80,83,88,90,110,116,119,123,133,136,144,150,151,159,168,176,242,247,252,264,272,298,306,307,319,323,324,328,330,355],evenv:[4,36,63,64,75,97,106],evenwidth:330,ever:[11,12,13,14,15,22,23,25,33,41,57,64,73,86,91,102,105,110,111,112,113,118,125,128,131,138,261,278,279,285,316,328],everi:[0,4,6,11,13,20,21,25,26,27,28,31,33,36,37,38,39,41,46,48,49,51,57,62,63,64,69,73,74,75,77,85,86,90,91,96,100,102,104,108,109,111,112,113,114,115,116,119,120,121,122,123,125,127,128,130,131,132,133,134,135,136,138,144,159,164,247,252,259,261,272,289,299,305,314,316,318,328,329,330,342,344,364],everybodi:41,everyon:[19,21,24,33,34,51,58,61,64,71,73,77,78,80,87,98,102,110,112,114,116,121,123,127,128,131,132,159,164,165,166,285],everyth:[9,11,19,21,26,28,31,36,38,42,47,49,51,55,58,61,63,64,67,69,72,73,75,79,80,81,83,85,87,90,91,97,100,103,104,109,110,111,113,115,116,119,122,127,128,131,135,136,137,138,139,149,154,164,165,167,169,170,171,241,246,256,271,298,306,316,318,322,328,364],everywher:[9,56],evform:[27,45,53,141,142,320,364],evgam:164,evgamedir:38,evict:310,evid:72,evil:[14,93,252],evilus:164,evmenu:[22,27,33,45,53,58,85,124,139,141,142,169,249,320,329,342,364],evmenucmdset:328,evmenuerror:328,evmenugotoabortmessag:328,evmenugotomessag:328,evmor:[43,45,139,141,142,251,320,364],evtabl:[27,33,45,49,53,82,111,141,142,154,164,251,320,327,329,344,364],exact:[33,41,51,80,93,95,96,119,129,138,144,147,151,159,164,168,176,238,245,247,251,252,317,318,340,341,344],exactli:[2,10,19,20,38,40,42,46,58,62,63,64,69,73,76,83,86,91,95,96,100,102,110,111,114,115,123,128,131,136,138,164,245,247,267,318,341],exam:[43,159],examin:[2,11,12,20,22,33,43,58,60,73,80,83,85,91,96,106,115,122,123,131,137,140,144,159,299,316,342,364],exampl:[0,2,4,5,6,8,10,11,13,14,15,17,19,20,21,22,25,27,28,29,30,31,33,36,37,38,40,41,43,44,48,49,55,56,57,58,59,60,61,62,63,64,67,68,71,74,77,81,82,84,85,86,87,88,89,91,93,95,96,97,98,100,103,104,105,106,109,110,111,112,114,115,117,118,119,121,122,123,124,125,126,129,130,131,132,133,135,136,138,139,140,141,142,144,148,151,152,153,154,157,158,159,164,165,166,167,168,169,170,175,177,239,242,246,247,252,256,259,261,267,272,287,290,291,296,299,308,312,316,318,319,320,321,323,327,328,329,330,331,335,337,338,341,342,344,345,357,363,364],example_batch_cod:[13,141,142,178,222,364],exapmpl:5,excalibur:85,exce:[82,310,334],exceed:310,excel:[56,67,79,80,102,108],excempt:152,except:[4,9,10,11,14,19,20,21,22,27,28,29,31,33,38,39,41,46,50,58,63,64,75,80,83,89,90,91,95,97,102,109,111,114,116,118,119,120,121,123,126,133,134,144,146,148,150,153,154,167,168,175,176,177,239,241,242,245,246,247,251,255,256,259,260,267,272,274,276,288,290,292,296,300,312,316,319,321,324,327,328,330,331,335,337,339,344],excepteur:52,excerpt:50,excess:[22,80,109,167,246,322,344],exchang:[13,90,102,325],excit:[20,35,54],exclam:21,exclud:[64,119,120,123,175,245,246,247,326,328],excluded_typeclass_path:159,excludeobj:245,exclus:[51,61,80,83,247,256,317,328,344],exclusiv:[255,324],exe:[63,106,128],exec:[51,85,109,252,328,344],exec_kwarg:328,exec_str:302,execcgi:8,execut:[0,9,10,12,13,14,19,22,25,28,29,31,33,36,45,46,47,50,51,55,62,63,64,69,75,83,85,87,89,91,95,102,106,109,111,114,119,127,128,137,139,144,146,148,149,150,154,157,158,167,169,170,177,239,241,242,246,247,252,253,256,260,264,272,274,277,278,284,287,290,295,298,299,302,305,306,316,318,319,322,328,329,335,342,344,347,364],execute_cmd:[2,33,89,117,118,123,144,146,154,247,272,306],execute_command:33,executor:36,exemplifi:[28,40,122],exercis:[21,41,42,58,85,95,96,111,116,123,132,293,303,335,364],exhaust:22,exidbobj:247,exis:44,exist:[0,2,3,5,11,12,13,20,21,22,25,27,31,33,35,36,39,40,41,43,44,46,48,49,51,56,57,58,60,61,64,65,68,69,70,72,76,80,86,96,97,100,102,105,109,111,112,115,116,117,123,124,128,131,134,136,138,139,143,144,146,147,152,153,154,159,164,166,167,169,241,242,246,247,249,251,252,255,260,267,271,273,287,288,290,292,300,305,306,308,316,317,318,319,322,324,326,327,328,330,337,339,344,364],existen:306,exit:[20,21,22,23,31,39,41,45,49,50,51,53,55,58,63,80,85,86,91,100,106,109,111,119,121,122,123,124,125,128,139,141,150,152,153,159,169,241,245,246,247,252,271,287,299,316,324,326,328,329,342,360,364],exit_alias:159,exit_back:58,exit_cmd:[51,329],exit_command:247,exit_nam:[49,159],exit_on_lastpag:329,exit_ther:58,exit_to_her:159,exit_to_ther:159,exit_typeclass:[342,360],exitbuildingmenu:22,exitcmdset:[31,247],exitcommand:247,exitobject:44,exixt:285,exot:33,exp:327,expand:[0,1,4,5,6,20,21,23,49,55,57,58,61,64,70,74,81,85,89,90,104,111,114,117,120,123,124,131,132,135,139,140,159,247,321,330,364],expand_tab:330,expandtab:[321,330],expans:[44,61],expect:[0,1,6,9,10,33,34,37,38,47,56,58,61,67,75,80,83,87,88,89,90,91,95,96,97,107,113,114,115,122,123,124,126,127,128,134,138,159,167,170,241,247,251,252,265,267,318,328,329,334,342,344,349],expected1:342,expected2:342,expected_input:342,expected_return:127,expedit:96,expens:[90,115,119,245,341],experi:[26,42,51,57,60,61,62,63,73,77,81,90,95,100,111,122,131,135,139,164],experienc:[51,61,64,79,95],experienced_betray:51,experienced_viol:51,experiment:[74,169],explain:[20,22,33,39,43,48,51,55,58,64,71,79,86,119,121,124,126,127,129,131,134,136,139],explan:[25,31,33,39,64,69,77,114,124,139,311,364],explicit:[0,1,22,31,38,40,48,69,71,88,91,104,129,136,267,289,316,328],explicitli:[4,9,21,30,31,58,59,63,68,80,83,84,85,86,87,96,97,109,112,114,115,124,125,153,154,159,166,176,247,252,255,261,316,318,321,324,340,342],exploit:[319,321,344],explor:[0,2,10,20,42,59,63,69,83,95,104,111,116,122,125,169,364],expos:[103,134],express:[3,33,38,51,56,80,109,119,127,134,135,140,159,316,344,347],ext:51,extend:[1,3,5,27,34,38,39,55,56,69,73,79,85,86,108,109,111,117,118,125,133,134,148,154,166,170,175,246,247,318,338,357],extended_room:[141,142,178,364],extendedloopingcal:261,extens:[1,3,9,23,38,51,55,56,61,63,64,88,96,97,104,111,114,127,138,148,238,282,290,324,333,343],extent:[22,56,73],exter:164,extern:[8,15,23,34,40,41,54,55,57,63,65,72,90,98,106,108,109,111,124,139,141,153,164,172,176,177,251,265,267,269,324,342,364],external_discord_hello:272,external_receiv:177,extra:[1,6,8,14,16,21,23,25,29,31,33,37,38,41,51,57,58,80,89,90,93,95,96,107,114,119,123,125,126,127,134,136,137,138,144,148,154,166,170,175,247,250,251,261,264,317,321,322,326,328,329,330,337,338,339,343,344],extra_environ:322,extra_opt:328,extra_spac:344,extract:[11,41,56,91,96,97,107,138,154,242,281,295,344],extract_goto_exec:328,extrainfoauthserv:287,extral:177,extrem:[26,56,91,110,128,280,338],eye:[60,97,111,114,252,329],eyed:136,eyes:[33,37,57],eyesight:[58,80,114],f6d4ca9b2b22:100,face:[90,103,122,171,311,328],facil:337,fact:[10,11,14,21,29,33,55,57,58,61,76,83,89,103,106,114,117,123,125,126,134,138,140,308,310],facter:138,factor:[0,62,82,114,264,278,279],factori:[40,96,264,269,277,278,279,285,286,287,288,290,298],factory_path:146,fade:108,fail:[4,9,10,11,12,13,14,24,27,31,41,51,60,61,63,89,91,103,107,109,110,113,116,117,121,127,144,153,164,168,175,241,242,247,251,264,265,267,271,278,279,289,310,316,318,329,338,340,344],failmsg:310,failtext:73,failur:[10,14,63,73,119,127,144,269,276,278,279,298,310,321,344],faint:102,fair:73,fairli:[39,69,75],fake:[298,308,316,321],fall:[26,31,38,60,62,64,73,97,102,111,113,141,144,168,344,357],fallback:[44,49,55,150,154,177,242,259,267,296,316,328,339,344],fals:[1,2,4,6,11,20,21,22,25,27,29,31,33,41,44,49,50,51,58,62,68,74,77,80,81,84,86,89,96,102,103,115,116,118,120,121,123,125,127,133,137,144,147,148,150,151,152,153,154,159,164,166,175,177,238,239,241,242,245,246,247,249,251,252,255,256,257,259,260,261,264,267,269,273,276,277,284,285,286,287,290,296,298,304,305,306,308,310,312,316,317,318,319,321,322,324,326,328,329,330,331,334,339,340,341,342,343,344,345,357],falsi:175,falter:61,fame:122,famili:[9,51,57],familiar:[3,9,20,29,31,33,39,58,60,63,85,90,91,95,96,111,119,124,125,133,364],famou:[52,326],fan:79,fanci:[15,17,36,73,138],fanclub:119,faq:[38,45,124,139,289,364],far:[0,13,20,21,22,31,33,39,41,44,46,49,51,54,55,57,59,61,75,88,90,91,95,96,100,106,111,114,119,131,138,152,269,294,316,326,334],fashion:111,fast:[11,15,23,26,27,29,56,62,64,82,89,108,115,131,157,299],faster:[23,62,93,119,177,316,364],fastest:[5,38],fatal:267,faulti:95,favor:27,favorit:[21,37],fear:27,featgmcp:291,featur:[0,4,12,15,17,20,22,25,26,27,31,33,34,36,37,38,42,45,46,47,48,49,50,56,57,59,61,62,63,64,70,72,78,81,85,91,96,103,107,109,111,114,119,122,123,124,125,128,129,131,138,139,144,153,154,261,284,305,309,318,326,344,364],februari:62,fed:[10,33,80,285,316,325,327],fedora:[8,63,67,131],feed:[7,15,49,51,55,73,98,109,128,139,146,164,269,286,287,318,329],feedback:[37,42,61,70,89,118,176,326],feedpars:[98,286],feedread:146,feel:[0,10,17,22,37,38,39,46,55,57,60,61,63,64,69,70,71,73,77,90,91,108,118,122,123,125,131,133,138,364],feint:116,felin:27,fellow:327,felt:[102,132],fetch:[11,63,90,100,128,131,133,316,329],few:[0,4,6,9,10,11,15,17,20,23,31,33,34,36,38,41,42,49,50,55,59,60,61,64,66,73,74,79,80,86,88,89,91,103,110,114,116,119,121,122,123,126,127,131,138,169,246,282,291,310,321,330,344],fewer:[108,308,317],fg_colormap:343,fgstart:343,fgstop:343,fiction:[51,55,62,77,328],fido:96,fie:102,field:[3,11,23,34,54,56,58,74,84,86,87,89,102,106,107,112,119,125,128,133,135,148,177,239,241,245,246,247,251,252,256,257,261,274,316,317,318,319,327,335,340,341,357,364],field_class:357,field_or_argnam:74,field_ord:357,fieldfil:[141,142,178,364],fieldnam:[58,84,257,318,334,357],fifi:96,fifo:344,fifth:49,fight:[29,31,61,116,122],figur:[3,12,26,33,37,42,49,80,83,90,91,93,96,97,119,121,131,133,138,251,267],file:[2,3,4,5,6,8,9,19,20,21,22,23,25,26,27,31,34,36,37,40,41,42,43,44,47,48,54,56,57,58,59,60,62,63,64,65,66,67,68,69,72,75,76,79,80,81,82,83,85,86,90,93,95,96,97,98,100,102,103,106,109,110,111,114,117,119,120,121,123,128,130,133,134,135,136,137,138,139,141,142,144,158,166,175,252,266,267,287,288,291,292,299,300,301,305,312,313,320,327,328,337,340,341,344,347,350,357,364],file_end:[322,344],file_help_entry_modul:166,fileentri:166,filehelpentri:166,filelogobserv:337,filenam:[27,60,131,175,322,327,337],filename1:267,filename2:267,filesystem:[63,100,103],fill:[36,41,49,50,58,61,65,70,106,111,114,119,133,135,316,321,327,328,329,330,344,364],fill_char:330,fillchar:[114,321,344],filo:344,filter:[31,34,39,69,86,106,114,119,120,125,133,138,152,157,246,247,344],filter_famili:[119,125],filthi:78,final_valu:10,find:[0,3,4,6,10,11,12,13,14,17,20,21,22,23,24,25,26,27,29,31,33,34,37,38,40,41,42,43,46,47,48,49,50,55,56,57,58,60,61,62,63,67,68,69,70,73,74,75,76,78,79,80,84,86,87,89,90,91,93,95,96,97,100,102,103,108,109,110,112,114,119,122,123,124,125,127,128,131,133,134,135,136,139,140,144,151,159,166,247,251,252,255,258,267,281,316,317,321,323,341,344,364],find_apropo:238,find_topicmatch:238,find_topics_with_categori:238,find_topicsuggest:238,fine:[12,15,20,33,38,41,44,46,64,85,86,89,95,105,112,115,118,122,123,138,146,147,316,324,344],finer:12,finish:[10,14,29,33,38,58,59,61,100,107,122,123,124,128,133,136,141,144,154,156,167,169,171,247,267,279,290,305,312,323,328,344,347],finish_chargen:51,finit:91,fire:[2,20,21,27,28,29,33,46,51,58,61,96,102,106,107,111,115,118,120,132,139,144,146,150,247,252,267,276,278,295,328,329,334],firebreath:58,firefox:72,firestorm:28,firestorm_lastcast:28,firewal:[67,90,364],first:[2,3,4,5,6,7,9,10,11,12,13,14,15,16,19,20,21,23,24,26,27,29,31,33,35,38,39,40,41,42,45,48,49,50,51,55,56,58,59,61,62,63,65,68,69,70,71,73,75,76,77,80,81,83,85,86,89,90,91,93,96,97,98,100,102,103,104,105,106,107,108,109,110,113,114,116,118,119,120,121,122,123,125,126,127,128,131,132,133,134,135,136,137,138,139,144,146,148,151,152,159,166,167,170,171,175,177,239,241,246,247,251,252,255,256,259,267,271,272,274,285,287,290,295,296,298,299,305,308,316,318,319,321,322,324,326,327,328,330,331,334,335,342,343,344,363,364],first_lin:123,firsthand:80,firstli:[9,89,90,96,97],fish:[73,153],fist:252,fit:[11,23,39,47,51,58,80,88,121,129,130,133,327,329,330,344],five:[28,33,90,111,119,153,344,345],fix:[13,14,16,26,27,33,37,42,51,57,60,61,63,64,70,75,78,83,85,90,95,96,97,109,110,121,123,125,127,138,267,327,329,330,340,363,364],fix_sentence_end:330,fixer:119,fixing_strange_bug:131,fixtur:[170,293,303,335],flag:[9,13,14,20,28,29,30,31,33,40,41,51,58,61,74,76,83,86,108,115,123,131,144,150,152,154,159,241,242,247,267,274,278,287,290,295,306,326,328,344],flame:28,flash:14,flat:[22,26,27,45,47,48,53,56,59,60,96,125,141,252],flatfil:56,flaticon:79,flatten:252,flatten_diff:252,flatten_prototyp:252,flattened_diff:252,flatul:102,flavor:[20,90],flavour:[87,126],flaw:121,fled:116,fledg:[15,90,108,123,133,158],flee:[116,117],fleevalu:116,flesh:[20,58],flexibl:[1,13,21,22,29,39,51,57,59,73,88,90,102,108,109,111,116,134,138,148,159,291,316,328,344,364],flick:345,flip:[43,51,81,171],flood:[27,50],floor:[0,82],flourish:316,flow:[17,36,40,55,61,83,86,115,131,137,176,324,328],flower:[12,20,61,87,89,119,159],flowerpot:[12,57],fluent:79,fluid:[16,17],flush:[23,33,111,128,169,316,318,334],flush_cach:334,flush_cached_inst:334,flush_from_cach:334,flush_instance_cach:334,flusher:334,flushmem:169,fly:[3,12,21,27,31,33,34,51,55,64,85,102,109,119,138,144,165,167,177,239,247,251,261,274,285,288,292,316,322,331,344],fnmatch:316,focu:[4,61,70,116,124],focus:[56,57,77,79,106,123,124],folder:[3,5,8,13,14,21,27,30,38,47,49,55,57,58,60,63,64,69,73,75,76,86,95,96,100,103,106,110,111,116,117,118,123,127,128,130,133,134,135,136,137,267,342,364],folder_nam:64,foldernam:60,follow:[0,2,4,5,7,8,9,10,11,13,14,16,17,19,20,22,23,25,31,33,34,37,38,39,40,41,42,46,47,48,49,50,51,54,58,60,61,62,63,65,67,68,69,71,73,74,75,76,79,80,82,85,86,88,89,90,91,93,95,96,97,100,102,103,106,110,112,114,116,117,119,120,121,123,125,127,128,131,133,134,135,137,144,146,148,150,151,154,159,166,167,170,175,176,177,239,241,242,246,247,250,251,252,256,257,271,272,282,291,295,296,299,309,316,318,321,322,324,327,328,329,330,337,344],follwo:242,follwow:51,fond:62,font:[25,38,111,137],foo:[33,40,51,83,84,88,95,107,112,119,127,159,267,316,328,342],foo_bar:88,foobarfoo:12,fooerror:328,footer:[69,133,154,247,329],footnot:[15,38],footprint:169,footwear:57,for_cont:247,forai:96,forbid:41,forbidden:131,forc:[0,6,8,10,31,33,58,60,63,73,81,82,91,100,103,110,116,121,123,125,127,138,146,153,157,159,164,242,247,251,258,278,279,285,290,308,310,329,330,334,337,344],force_init:247,force_repeat:[102,116],force_str:340,forcibl:[102,258],fore:305,foreground:[42,100,114,126,267,321,364],foreign:125,foreignkei:[148,246,256,318,335],forest:[13,111,112,140],forest_meadow:112,forest_room:112,forestobj:140,forev:[61,102],forget:[3,9,10,13,25,27,33,41,54,62,72,82,85,86,95,96,100,123,131,322,364],forgotten:[28,49,77,85],fork:[9,79,364],forloop:69,form:[11,13,27,31,33,34,38,45,51,53,55,58,59,61,64,68,70,74,76,77,80,83,88,89,93,96,97,109,112,113,114,115,116,118,123,124,125,127,129,135,141,142,144,146,147,151,153,154,157,159,164,167,170,175,176,177,239,241,242,245,247,251,252,257,259,261,265,285,287,291,295,306,308,316,317,318,321,322,324,325,326,327,328,330,331,337,340,341,344,345,346,356,364],form_char:327,formal:[61,80,96,138,247,291],format:[0,14,17,19,22,23,27,31,33,37,38,41,42,46,48,55,58,62,68,69,76,79,81,83,88,96,98,103,108,109,111,113,114,119,124,129,131,133,138,152,154,156,159,166,170,175,176,239,247,249,251,252,257,267,272,282,287,307,309,316,318,321,322,324,326,328,329,330,331,337,339,344,345,363,364],format_:159,format_account_kei:159,format_account_permiss:159,format_account_typeclass:159,format_alias:159,format_attribut:159,format_available_protfunc:251,format_channel_account_sub:159,format_channel_object_sub:159,format_channel_sub_tot:159,format_char:159,format_current_cmd:159,format_destin:159,format_diff:252,format_email:159,format_exit:159,format_extern:175,format_grid:344,format_help_entri:166,format_help_index:166,format_hom:159,format_kei:159,format_loc:159,format_lock:159,format_merged_cmdset:159,format_messag:175,format_nattribut:159,format_output:159,format_permiss:159,format_script:159,format_script_desc:159,format_script_is_persist:159,format_script_timer_data:159,format_send:175,format_sess:159,format_single_attribut:159,format_single_attribute_detail:159,format_single_cmdset:159,format_single_cmdset_opt:159,format_single_tag:159,format_stored_cmdset:159,format_t:344,format_tag:159,format_th:159,format_typeclass:159,formatt:[251,328,329],formchar:[58,327],former:[17,23,64,126,328],formfield:340,formstr:58,formul:134,forth:[27,131,159],fortress:111,fortun:[4,33,39,48,69,122,128],forum:[1,9,37,48,55,57,63,90,98,128,364],forward:[13,14,20,42,45,50,51,62,69,90,121,126,144,148,177,239,246,256,312,316,318,319,327,329,335],forwardfor:67,forwardmanytoonedescriptor:[246,256,335],forwardonetoonedescriptor:[246,256,335],foul:109,found:[2,4,6,9,10,13,14,15,20,22,23,25,27,31,33,38,39,40,41,42,49,51,55,57,58,59,63,68,73,74,76,78,80,83,85,89,90,91,97,103,104,109,112,116,119,122,123,125,127,128,134,135,137,138,141,144,147,149,150,151,152,154,159,164,167,168,171,175,239,242,245,247,250,251,252,255,258,261,266,267,273,282,285,296,306,308,316,317,318,321,322,323,324,328,330,334,339,341,344,347],foundat:[49,55,77,79],four:[4,14,27,38,39,40,68,73,82,86,87,111,114,119,153,177,242],fourth:39,fqdn:90,fractal:56,fraction:127,frame:[137,138],framework:[3,16,64,124,133,136,137,170,340,364],frankli:129,free:[0,22,29,37,48,55,57,60,61,64,76,77,79,90,106,112,116,123,124,126,130,133,139,251],freedn:90,freedom:[14,26,44,63],freeform:[73,116],freeli:[55,77,100,103,322],freenod:[9,63,70,72,79,90,146,164,308],freepik:79,freetext:[176,341],freez:[29,33,42],frequent:91,fresh:[11,31,58,128,267],freshli:111,fri:12,friarzen:138,friend:[37,58,61,82,103],friendli:[22,38,78,95,133,138,148],friendlier:[175,247],from:[0,2,3,5,6,8,9,10,11,12,13,14,15,16,17,19,21,22,23,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,42,44,46,47,48,49,50,52,54,56,57,58,59,61,62,63,64,66,67,68,69,70,71,72,73,74,75,76,79,80,81,82,83,84,85,86,87,89,91,92,93,95,97,98,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,134,135,136,139,140,141,142,144,146,147,148,149,150,151,152,153,154,156,157,158,159,164,165,166,167,168,169,170,171,175,176,177,238,239,241,242,243,245,246,247,251,252,255,256,257,258,260,261,264,267,271,272,273,274,276,277,278,279,280,284,285,286,287,290,295,296,298,299,301,305,306,307,308,310,312,313,314,316,317,318,319,320,321,322,323,324,325,326,327,329,330,331,334,335,337,338,340,341,342,343,344,345,347,357,363,364],from_channel:146,from_db_valu:340,from_nod:[51,328],from_obj:[81,83,118,144,146,154,247],from_pickl:325,from_tz:345,frombox:276,fromstr:276,fromtimestamp:331,front:[8,13,20,73,80,85,96,103,109,131,137,139,364],frontend:316,frozen:[29,33,122],ftabl:344,ftp:343,fuel:21,fugiat:52,fulfil:267,full:[4,9,13,14,15,16,17,20,21,23,24,25,26,27,33,37,38,43,51,55,57,58,59,60,61,64,73,75,80,84,88,89,90,95,96,97,100,101,102,105,108,109,110,111,115,116,117,119,121,123,124,125,127,128,131,133,134,135,136,146,151,153,154,158,159,164,166,168,169,170,175,242,245,252,257,279,285,298,308,309,316,318,322,326,328,330,342,344,364],full_justifi:109,full_nam:87,fullchain:67,fuller:58,fullfil:245,fullhost:67,fulli:[4,11,19,33,51,55,58,59,61,63,85,86,90,93,103,110,122,144,176,242,247,259,295,307,324,344],fun:[20,26,61,79,81,111,136],func1:[159,242,299],func2:[159,242,299],func:[5,10,21,22,25,28,29,30,33,38,42,44,50,51,56,58,60,62,71,73,80,81,82,83,85,91,116,119,121,123,150,154,156,157,158,159,164,165,166,167,168,169,170,171,241,242,247,278,298,299,303,312,326,328,329,331,342,344,364],func_test_cmd_task:170,funcnam:[74,114,242,250,251,261,328,344],funcpars:[250,308,344],funcparser_cal:250,funcparser_outgoing_messages_modul:308,function_nam:169,functioncal:276,functionnam:276,functionpars:251,functool:63,fund:70,fundament:[33,57,77,89,95,96,112,247],furnitur:[13,112,125],further:[0,9,11,27,31,34,38,42,44,49,57,83,85,86,90,91,96,100,102,104,105,106,109,110,111,119,124,125,130,131,138,153,159,252,267,291,344,364],furthermor:[37,38,124,126],fuss:100,futur:[9,10,11,20,23,38,45,50,55,58,60,61,62,63,76,87,95,100,123,139,156,272,317,338,345,364],futurist:62,fuzzi:[76,147,164,238,245,341,344],fuzzy_import_from_modul:344,gadget:70,gag:24,gain:[11,29,61,73,93,154,169,177,242,247],game:[0,2,3,4,5,6,8,9,10,11,13,14,15,17,18,19,20,21,22,23,24,25,28,29,30,31,33,34,35,36,37,38,41,42,43,44,46,50,51,52,53,56,60,63,64,65,66,67,68,69,71,72,75,76,77,78,79,80,81,83,85,86,87,88,89,91,92,93,95,96,97,98,101,102,103,104,105,106,107,108,109,110,112,113,114,115,116,117,118,119,121,122,125,129,130,132,133,134,135,136,137,138,139,140,143,144,146,147,148,150,152,153,154,156,157,158,159,163,164,165,166,169,170,171,172,175,176,177,178,238,239,243,245,246,247,255,256,258,259,262,267,269,270,271,272,278,279,284,286,287,290,291,298,299,300,305,306,308,317,318,319,322,323,324,326,327,331,334,337,342,344,350,363,364],game_dir:[337,344],game_epoch:[27,331],game_index_cli:[141,142,262,364],game_index_en:54,game_index_list:54,game_nam:54,game_slogan:9,game_statu:54,game_templ:47,game_websit:54,gamedir:[51,100,109,267,313,342,364],gamedirnam:58,gameindexcli:270,gameplai:[90,364],gamer:[65,72],gamesrc:27,gametim:[27,53,59,139,141,142,320,364],gammon:[79,282],gandalf:51,gap:364,garbag:316,garden:79,gatewai:[110,296],gather:[24,33,48,83,119,127,132,136,150,151,265,269,324,341],gave:[5,21,60,64,91,102,126],gbg:321,gcc:63,gcreat:159,gear:[90,106,136,146,153,171],gen:17,gendersub:[141,142,178,364],gener:[0,1,5,9,10,11,12,20,23,25,29,31,33,34,36,37,38,43,48,49,51,55,57,58,59,60,62,63,64,68,70,73,76,80,83,86,87,88,90,93,96,104,105,106,109,111,112,114,116,126,127,134,137,138,139,141,142,144,146,147,149,154,155,156,159,166,167,168,170,171,175,238,239,242,245,247,249,251,252,255,278,285,287,290,291,295,298,306,307,308,312,316,319,320,321,323,324,326,329,330,331,337,339,340,344,349,357,364],general_context:[141,142,346,348,364],generate_sessid:285,generic_mud_communication_protocol:291,genesi:90,genr:[37,64,281],geograph:140,geographi:39,geometr:111,geometri:111,get:[0,1,2,3,5,6,7,8,9,10,11,12,13,15,17,21,22,23,25,26,28,29,30,31,33,38,39,40,41,42,43,44,45,46,47,48,49,50,54,55,56,57,58,59,60,61,62,64,65,68,69,71,72,73,74,75,76,77,80,81,82,83,84,85,86,87,88,90,91,92,93,95,96,97,100,102,103,104,105,106,107,110,111,112,114,116,118,121,122,123,125,126,127,128,130,131,133,134,135,136,137,138,139,144,146,147,148,152,153,154,156,157,159,160,164,165,166,171,175,176,177,238,239,242,245,246,247,249,251,252,255,256,258,261,265,267,272,276,277,281,285,287,290,291,293,295,296,304,306,307,308,310,316,317,318,319,321,322,323,326,328,330,331,333,334,337,338,339,341,344,357,363,364],get_abl:60,get_absolute_url:[134,175,239,318],get_account:[242,306],get_account_from_email:147,get_account_from_nam:147,get_account_from_uid:147,get_al:316,get_alia:317,get_all_attribut:316,get_all_cached_inst:334,get_all_categori:238,get_all_channel:176,get_all_cmd_keys_and_alias:152,get_all_cmdset:344,get_all_puppet:144,get_all_script:255,get_all_scripts_on_obj:255,get_all_sync_data:308,get_all_top:238,get_all_typeclass:344,get_and_merge_cmdset:153,get_attr:159,get_attribut:317,get_browserstr:296,get_buff:326,get_by_alia:317,get_by_attribut:317,get_by_nick:317,get_by_permiss:317,get_by_tag:317,get_cach:316,get_cache_kei:310,get_cached_inst:334,get_channel:[41,176],get_channel_alias:164,get_channel_histori:164,get_charact:306,get_client_opt:[272,364],get_client_s:306,get_client_sess:[295,296],get_client_sessid:296,get_command_info:[154,167],get_connected_account:147,get_cont:245,get_content_nam:247,get_db_prep_lookup:340,get_db_prep_valu:340,get_dbref_rang:[147,245,255,317],get_def:260,get_default:340,get_display_nam:[22,42,46,58,144,247,318],get_err_msg:[6,20,80],get_evennia_pid:344,get_evennia_vers:344,get_extra_info:[41,154,247,318],get_famili:[119,125],get_formatted_obj_data:159,get_game_dir_path:344,get_height:330,get_help:[33,68,69,154,170,328],get_help_text:311,get_id:[133,260,317],get_info_dict:[284,305],get_input:[328,342,364],get_inputfunc:[88,272,291,308,364],get_internal_typ:340,get_kwarg:360,get_log_filenam:175,get_mass:82,get_message_by_id:176,get_messages_by_receiv:176,get_messages_by_send:176,get_min_height:330,get_min_width:330,get_new:286,get_next_by_date_join:148,get_next_by_db_date_cr:[148,177,239,246,256,316,318],get_nick:317,get_nicklist:[146,279],get_numbered_nam:247,get_object_with_account:[245,341],get_objs_with_attr:245,get_objs_with_attr_match:245,get_objs_with_attr_valu:245,get_objs_with_db_properti:245,get_objs_with_db_property_match:245,get_objs_with_db_property_valu:245,get_objs_with_key_and_typeclass:245,get_objs_with_key_or_alia:245,get_permiss:317,get_pid:267,get_player_count:281,get_previous_by_date_join:148,get_previous_by_db_date_cr:[148,177,239,246,256,316,318],get_puppet:[2,144,306],get_puppet_or_account:306,get_recently_connected_account:147,get_recently_created_account:147,get_respons:351,get_room_at:39,get_rooms_around:39,get_sess:308,get_statu:277,get_subscript:176,get_sync_data:307,get_system_cmd:152,get_tag:317,get_typeclass_tot:317,get_uptim:281,get_username_valid:144,get_valu:[88,272,291,364],get_visible_cont:247,get_width:330,getattr:84,getchild:312,getclientaddress:[40,287],getel:137,getenv:[267,277],getgl:137,getinput:328,getkeypair:287,getloadavg:75,getpeer:287,getpid:344,getsizof:334,getsslcontext:[288,292],getston:33,getter:[148,177,246,247,274,316],gettext:76,gfg:321,giant:[21,124],gid:[45,100,299],gidcount:298,gif:70,gift:69,girl:247,gist:344,git:[9,23,25,36,38,45,47,63,75,76,79,86,90,100,108,124,128,130,364],github:[9,25,37,38,41,45,57,63,70,75,76,79,95,96,98,104,130,131,138,295,312,344,364],gitignor:131,give:[0,1,2,3,4,5,9,10,11,12,13,15,18,19,20,21,22,23,25,26,27,30,33,38,39,41,43,46,48,51,52,55,57,58,59,60,61,62,63,64,68,69,73,75,77,79,80,82,85,88,89,90,91,93,96,98,100,102,103,105,107,109,110,111,112,113,114,115,116,117,118,119,122,123,124,125,127,128,133,134,136,138,139,140,144,150,152,153,156,159,164,165,167,175,176,245,247,255,256,271,293,299,306,312,316,321,328,330,341,342,344,363,364],given:[0,2,4,10,11,12,13,14,20,21,22,25,27,31,33,34,38,39,42,46,49,50,51,58,62,64,70,73,74,80,83,84,85,86,88,89,90,93,97,100,102,105,109,110,113,114,115,116,117,119,122,123,125,126,127,131,133,134,135,138,140,144,147,150,151,152,153,154,156,157,159,164,166,168,169,170,175,176,177,241,242,245,247,249,251,252,255,257,258,259,261,265,267,272,273,276,285,290,291,296,299,302,306,307,308,309,310,311,312,316,317,318,319,321,322,324,325,326,327,328,329,330,331,334,337,339,340,341,342,344,347,349,364],giver:247,glad:91,glanc:[22,27,31,33,39,48,58,61,91,96],glance_exit:22,glob:[51,165,328],global:[13,22,33,34,35,45,51,56,61,64,67,74,85,89,100,104,105,108,109,114,115,120,125,131,132,137,138,140,159,175,245,247,252,253,255,256,260,264,267,272,274,277,298,299,322,323,324,328,331,341,342,344,350,364],global_script:[102,141,323],global_search:[13,22,27,58,91,144,247,317],globalscript:43,globalscriptcontain:323,globalth:342,globe:[90,136],gloss:61,glossari:[63,139,364],glow:111,glu:92,glyph:276,gmcp:[55,74,83,291,364],gmsheet:58,gmud:24,gno:22,gnome:24,gnu:14,go_back:[51,328],go_back_func:51,goal:[38,61,76,79,91,102,103,122,124],goals_of_input_valid:357,goblin:[51,109,159,252],goblin_arch:252,goblin_archwizard:252,goblin_shaman:109,goblin_wizard:252,goblinwieldingclub:109,god:[20,80],godhood:364,goe:[0,5,9,22,26,29,33,37,40,42,49,64,69,73,75,86,90,95,96,118,121,122,123,139,152,153,247,287,290,305,306,343,344],going:[0,3,20,25,26,40,45,46,49,51,58,61,62,65,69,70,82,88,90,91,95,96,100,111,116,121,127,133,138,139,247,264,269,321,328],goings:269,gold:[51,82,85,109,322],gold_valu:85,golden:138,goldenlayout:[138,364],goldenlayout_config:[137,138],goldenlayout_default_config:[137,138],gone:[5,12,77,80,85,100,102,131],good:[0,2,4,5,9,11,12,14,20,21,22,25,26,27,31,33,37,38,39,40,41,46,48,49,51,54,55,56,57,60,61,63,69,70,72,73,79,80,85,87,90,91,93,95,96,97,100,102,103,104,106,109,110,111,114,119,121,123,125,126,127,131,133,134,138,144,152,153,154,170,290,299,328],goodby:287,goodgui:242,googl:[38,75,79,90,164,330,364],googleusercont:70,googli:136,gossip:[65,79,164],got:[10,13,95,96,116,128,138],goto_cal:[51,328],goto_kwarg:328,goto_next_room:121,goto_node2:51,goto_str_or_cal:51,gotostr_or_func:328,gotten:[55,95,131,247,294],graaah:117,grab:[20,33,43,73,133,165],gracefulli:[26,156,169,247,267,344],gradual:[13,14,29,61,79,96],grai:[114,126],grain:[115,147,324],gram:82,grand:11,grant:[19,23,80,131,177,241,242,251,316,364],grapevin:[7,139,141,142,146,164,262,275,364],grapevine2chan:[43,65,164],grapevine_:164,grapevine_channel:[65,146,164],grapevine_client_id:65,grapevine_client_secret:65,grapevine_en:[65,164],grapevinebot:146,grapevinecli:278,graph:[49,131],graphic:[42,58,80,83,84,93,111,128,135,141,291],grasp:[126,133],grave:60,great:[0,4,14,16,21,22,29,37,39,51,57,61,69,70,73,77,79,91,95,107,108,123,127,131,134,312],greater:[22,31,73,80,97,105,119,241,328],greatli:78,greek:15,green:[31,80,109,114,126,131,159,169,321],greenskin:252,greet:[9,35,46,95,104,105,117],greetjack:87,greg:79,grei:[109,126,321],grenad:89,grep:[75,131],greyscal:[114,321],greyskinnedgoblin:109,griatch:[21,70,86,119,170,327,334,340,343,364],grid:[7,16,111,123,139,166,344,364],grief:12,griefer:134,grin:[33,41,316],grip:38,gritti:33,ground:[20,21,55,111],group:[4,9,10,12,19,21,26,33,37,41,43,46,55,64,68,70,79,91,100,102,109,112,125,127,139,140,147,148,155,159,165,166,176,247,251,252,276,299,316,319,321,324,364],groupd:316,grow:[13,25,26,61,63,79,110,278,279,330,344],grown:[9,25,51,129],grudg:73,grumbl:60,grunt:[159,252],gstart:159,gthi:81,guarante:[11,37,61,67,80,86,90,102,251,285,306,318],guard:51,guess:[15,22,46,50,69,91,103,113,138,252],guest1:66,guest9:66,guest:[7,53,80,139,144,364],guest_en:[66,80],guest_hom:[66,133],guest_list:66,guest_start_loc:66,guestaccount:112,gui:[45,57,83,137,364],guid:[36,37,45,81,95,96,128,133,136,364],guidelin:[37,38,79],guild:[79,86,112,118,164],guild_memb:51,gun:[21,77],guru:55,habit:56,habitu:115,hack:[55,73,116,276],hacker:[79,103],had:[8,9,14,15,19,20,21,29,31,37,55,61,90,95,96,100,102,119,123,128,135,138,154,158,170,252,256,267,318,322,329,357],hadn:[61,62,131],half:[108,138,239],hall:49,hallwai:49,halt:[102,111],hand:[1,15,37,40,51,55,56,57,58,61,70,73,87,89,96,105,108,119,134,154,159,165,167,169],handi:[42,75,119,133],handl:[0,2,4,5,7,8,9,11,13,15,22,24,27,33,34,37,40,41,44,47,49,50,51,53,55,56,60,61,62,64,67,68,74,75,80,83,85,86,87,88,89,91,93,95,97,100,104,105,108,115,116,117,124,125,126,128,129,131,132,137,138,139,144,146,147,149,150,152,153,159,160,164,165,168,236,246,247,250,251,252,256,257,260,264,267,271,272,276,277,279,280,287,290,291,294,296,298,307,308,316,318,321,322,324,325,326,328,329,330,331,334,343,344,351,364],handle_egd_respons:269,handle_eof:287,handle_error:[164,260],handle_ff:287,handle_foo_messag:[51,328],handle_int:287,handle_messag:[51,328],handle_message2:51,handle_numb:[51,328],handle_quit:287,handle_setup:271,handler:[2,11,31,33,41,47,64,73,80,83,84,86,87,89,102,104,105,112,115,125,139,144,150,153,168,172,177,241,242,246,247,252,257,258,260,261,272,284,285,305,308,314,316,318,319,323,324,327,328,338,339,344,364],handlertyp:319,handshak:[24,52,83,277,283,285,290],handshake_don:290,hang:[3,38,61,70,124],hangout:119,happen:[0,6,12,19,20,26,27,31,33,37,39,41,42,44,51,54,55,57,58,60,61,62,64,72,73,77,80,83,86,88,90,91,95,96,97,102,105,107,108,110,111,114,115,116,119,122,123,126,127,128,131,133,138,144,152,153,164,175,247,252,260,269,276,279,299,304,306,307,308,318,328,329,334,337,344],happend:252,happi:[13,119,328],happier:91,happili:96,haproxi:[90,139,364],hard:[9,10,11,13,15,19,26,27,31,33,38,40,41,58,61,63,64,76,79,88,90,93,96,97,100,102,109,112,115,119,121,127,131,133,138,139,168,256,267,316,318,328,364],hardcod:[57,58,77,100,111,140,316],harden:63,harder:[12,56,61,93,119,127],hardwar:[90,280],hare:79,harm:[11,29],harri:59,has:[0,2,4,8,9,10,11,12,13,14,15,16,19,20,21,22,23,25,27,28,29,31,33,34,36,37,38,39,40,41,42,44,46,47,49,50,51,53,54,56,57,58,59,60,61,62,63,64,65,67,68,69,70,71,74,75,76,77,78,79,80,83,85,86,87,88,89,90,91,93,95,96,97,100,101,102,103,104,105,107,109,110,112,113,114,115,116,117,118,119,121,122,123,125,126,127,128,129,131,132,133,134,135,136,137,138,139,143,144,146,151,152,153,154,156,158,159,164,166,167,169,170,171,175,176,177,239,241,242,245,246,247,251,252,255,256,259,260,261,267,269,272,276,279,281,285,289,294,295,299,305,306,307,308,310,316,317,318,319,324,326,327,328,330,334,337,338,341,342,344,357,360],has_account:[89,241,246,247],has_attribut:316,has_cmdset:153,has_connect:[41,175],has_drawn:49,has_nick:316,has_par:344,has_perm:[167,242],has_sub:175,has_tag:319,has_thorn:11,hasattr:[28,33],hash:[14,90,109,252,261,295,299,308,317],hasn:[22,49,316],hassl:62,hat:[37,70],hau:[65,146,164,278],have:[0,1,2,3,4,5,6,9,10,11,12,13,14,15,16,19,20,21,22,23,25,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,42,44,46,47,48,49,50,51,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,80,81,82,83,84,85,86,87,88,89,90,91,92,93,95,96,97,98,100,102,103,104,105,106,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,144,146,150,152,153,154,156,159,161,164,167,168,169,170,171,175,176,177,238,239,241,245,246,247,250,251,252,253,255,256,259,260,261,272,277,280,281,285,287,290,291,305,306,307,308,313,314,316,317,318,319,321,322,323,324,325,327,328,329,330,337,340,341,342,344,345,350,357,363,364],haven:[4,22,29,42,62,67,77,109,111,117,118,120,127,128,133,134,138,310],head:[20,21,31,46,69,76,77,96,106,119,121,123,138,139,364],headach:[61,138],header:[9,13,14,27,34,37,38,63,89,95,103,129,138,154,166,176,177,247,322,324,329,330],header_color:159,header_line_char:330,headi:330,heading1:[38,330],heading2:[38,330],heading3:38,headless:[96,247],headlong:63,health:[30,61,73,84,88,90,109,116,252,291],health_bar:[141,142,178,364],hear:[29,46,61,342],heard:[111,122],heart:126,heartbeat:[115,278],heavi:[6,11,20,23,27,33,64,73,80,82,96,116,123,280,344],heavili:[9,27,37,40,57,75,86,104,318],heed:[105,242],heh:138,hei:20,height:[52,74,137,141,272,287,306,327,330],held:[1,31,48,116,241],hello:[0,29,34,41,46,51,72,74,83,87,88,91,96,105,108,123,129,164,165,175,272,321,342,364],hello_funct:95,hello_valu:108,hello_world:[95,96,108],helmet:[29,77],help:[0,1,4,5,12,13,14,15,19,22,23,27,29,32,33,35,38,39,41,42,43,44,45,46,47,48,49,50,51,53,57,58,60,61,63,64,67,71,72,76,77,79,80,86,90,91,93,96,105,107,108,109,110,111,112,113,116,119,122,123,124,126,127,131,133,137,138,139,141,142,149,150,152,154,155,156,164,167,169,170,171,245,249,260,265,267,269,270,278,285,287,288,290,292,295,296,298,299,316,317,321,324,325,326,328,329,339,340,341,342,351,357,360,363,364],help_categori:[5,22,33,41,58,60,68,69,71,85,116,123,154,156,157,158,159,164,165,166,167,168,169,170,171,238,239,247,298,326,328,329,341],help_cateogori:326,help_entri:326,help_kei:159,help_messag:166,help_mor:166,help_system:69,help_text:[166,357],helparg:170,helpdetailtest:360,helpentri:[69,80,166,238,239,324],helpentry_set:319,helpentrymanag:[238,239],helper:[19,41,51,58,67,80,109,119,141,144,153,156,159,164,166,176,247,251,252,264,276,277,296,308,322,328,329,337,342,343,344],helpfil:166,helplisttest:360,helplockeddetailtest:360,helptext:[51,249,328],helptext_formatt:[51,249,328],henc:[0,22,46,76,95,106,322],henceforth:[13,44,60,66,80,90,95,97,102,105,111,123,131,132,140,308],her:[122,127],herbal:327,herd:23,here:[0,2,3,4,5,9,10,11,13,14,15,16,17,19,20,21,22,23,24,25,27,29,30,33,36,37,38,39,40,41,42,43,44,46,47,48,49,51,53,56,57,58,59,61,62,63,64,65,67,69,70,71,72,73,74,75,76,77,79,80,81,83,84,85,86,87,88,89,91,92,95,98,100,101,102,103,104,105,106,107,108,109,110,111,113,114,115,116,117,118,119,120,121,123,125,126,127,128,129,130,131,133,134,135,136,137,144,146,152,153,154,159,167,168,169,171,177,239,242,245,247,251,252,267,269,276,278,284,285,287,290,299,305,306,308,314,316,318,321,324,328,330,334,342,347,364],hesit:[22,39],hfill_char:330,hidden:[11,49,61,64,96,122,131,137,166,177],hide:[9,11,20,31,33,34,41,61,73,80,96,111,138,166,177],hide_from:[34,177],hide_from_accounts_set:148,hide_from_objects_set:246,hieararci:241,hierarach:319,hierarch:[2,19,80,156,241,319],hierarchi:[4,19,22,43,61,66,69,80,119,139,165,241,344,364],high:[4,8,20,31,55,63,80,122,152,247,309,319],higher:[7,19,25,31,41,44,51,56,58,62,63,73,80,90,105,108,119,123,128,144,152,156,159,169,241,269,319,328,344],highest:[31,58,321,344],highest_protocol:340,highli:[9,17,51,55,56,64,80,86,107,115,117,322,334],highlight:[14,38,57,58,114,126],hijack:134,hilight:343,hilit:343,hill:87,him:[41,46,51],hint:[1,25,38,55,63,79,93,95,109,110,123,124,128,136,139,313,364],hire:[85,103],his:[46,51,58,77,96,109,127,329,343],histogram:344,histor:[62,129,266,337],histori:[4,23,34,41,50,58,64,95,100,131,137,138,139,153,164,175,337],hit:[6,9,21,29,52,61,73,116,119,122,131,146,265,306,337,340],hite:114,hmm:138,hnow:114,hobbi:[61,90],hobbit:62,hobbyist:90,hoc:55,hold:[2,6,9,13,14,16,21,26,31,34,36,38,41,47,49,51,58,61,63,64,66,73,77,80,85,89,96,97,100,102,104,105,106,109,111,112,114,116,119,123,125,131,133,136,140,152,153,178,236,241,242,251,252,253,257,262,274,276,285,295,296,298,308,318,319,320,324,327,328,330,332,337,344,346],holder:[9,69,90,316],home:[8,16,26,43,63,64,66,70,79,89,90,103,109,131,133,139,153,159,165,170,245,246,247,252,324,344],home_loc:159,homepag:[27,63,79,90,93],homes_set:246,homogen:[27,251,252,256],homogenize_prototyp:251,hood:[20,33,51,57,60,61,64,86,87,119,122,125,128],hook:[2,25,30,33,49,55,60,61,73,74,76,80,81,89,96,102,107,110,115,116,117,118,120,121,123,127,132,144,150,152,154,156,159,164,165,167,169,170,171,175,177,247,256,259,261,271,278,290,293,295,298,303,305,306,307,309,318,326,329,334,335,338,344,357,364],hooligan:12,hop:55,hope:[42,58,91],hopefulli:[8,26,41,49,90,111,133,137],horizon:62,horizont:[138,330,344],hors:27,host1plu:90,host:[7,12,23,26,27,61,64,67,89,98,100,102,103,131,135,312,344,364],host_os_i:344,hostnam:67,hotbutton:137,hotel:90,hotspot:103,hour:[27,62,132,331,344],hous:[90,109,159,364],housecat:27,hover:138,how:[0,1,3,4,5,6,7,8,10,11,12,13,14,15,17,19,20,21,22,25,26,27,28,29,30,31,35,37,38,39,40,41,42,43,44,45,46,48,49,51,55,56,57,60,61,62,63,64,66,68,69,72,73,75,77,80,81,82,83,84,85,86,87,88,90,91,93,95,96,97,102,103,104,105,106,108,109,110,111,112,116,117,118,119,120,123,124,126,127,128,130,131,132,133,134,135,136,137,138,139,140,146,147,151,153,154,166,168,169,170,175,241,246,247,252,256,261,267,272,277,281,286,291,294,298,299,305,306,307,308,312,318,322,326,328,329,330,337,338,343,344,357,363,364],howev:[0,2,4,5,10,11,12,13,14,15,17,20,22,23,29,30,31,33,37,38,40,41,44,46,50,55,58,59,60,62,70,73,77,80,85,88,90,91,108,109,110,111,113,114,115,120,123,125,128,129,131,132,135,153,154,159,166,169,170,241,321],howto:38,hpad_char:330,href:[17,69,133],htm:282,html5:55,html:[24,38,55,64,69,79,83,96,103,114,134,135,136,137,138,154,169,175,239,289,291,295,296,312,318,340,343,344,347,364],htmlchar:343,htop:110,http404:[69,134],http:[3,4,9,22,23,36,37,38,45,54,55,63,65,69,70,75,83,90,95,98,103,104,107,108,124,128,130,131,133,134,135,137,138,141,146,164,269,276,278,279,280,281,282,283,289,291,294,295,296,312,321,330,343,344,357,364],http_request:[103,135],httpchannel:312,httpchannelwithxforwardedfor:312,httpd:8,httprequest:144,httpresponseredirect:133,huawei:90,hub:[79,100,139,176,324],hue:114,huge:[3,16,21,29,39,61,62,86,127,329],huh:[22,33],human:[4,12,40,51,57,61,64,73,85,93,96,117,133],humanizeconfig:4,hundr:[72,113,133],hungri:86,hunt:73,hunting_skil:73,hurdl:49,hurt:30,huzzah:9,hwejfpoiwjrpw09:9,hybrid:73,i18n:[47,76,247],iac:88,iattribut:316,iattributebackend:316,icon:[79,106,138],id_:357,id_str:84,idcount:298,idea:[0,9,12,26,33,37,38,39,45,49,55,56,60,61,63,69,71,72,73,77,80,85,106,107,108,119,121,123,127,131,133,134,139,154,166,167,170,252,334,343,364],ideal:[1,6,33,37,46,48,90,129,138,148,242],idenfi:152,ident:[9,31,33,44,57,61,83,96,97,110,114,144,167,242,245,247,255,321,322,342],identif:[27,115,308],identifi:[0,8,23,28,30,31,33,39,41,42,49,50,51,58,61,69,74,83,84,88,93,97,102,109,115,116,119,125,134,138,151,154,159,164,167,170,176,242,247,251,255,258,261,264,267,272,274,277,291,295,304,306,308,316,317,321,324,327,328,344],identify_object:176,idl:[12,105,144,146,247,299,306,308],idle_command:33,idle_tim:[144,247],idle_timeout:146,idmap:334,idmapp:[86,125,141,142,169,177,239,274,300,316,317,318,320,364],idnum:176,ids:[12,58,121,298,308,327],idstr:[84,115,257,261,304,344],idtifi:176,idx:121,ietf:283,ifconfig:67,ifram:[137,138],ignor:[6,14,20,23,27,29,31,33,34,38,42,51,58,73,74,80,83,86,90,91,95,96,105,114,117,121,122,125,131,144,151,152,153,154,159,241,246,247,261,267,272,278,279,294,295,296,316,318,321,322,327,328,339,342,344,345],ignore_ansi:344,ignore_error:144,ignorecas:[154,159,165,166,169,171,321,326,328,343],ignoredext:312,illumin:111,illus:[10,96],imag:[4,17,63,69,70,90,101,106,133,135,136,137,138,347,364],imagesconfig:4,imagin:[14,29,31,46,48,51,61,77,116,117,122,132,138,322],imaginari:[21,79],imc2:34,img:[17,70],immedi:[0,5,15,27,29,33,48,49,51,64,70,74,83,90,95,100,102,109,116,120,133,134,157,169,255,271,278,322,324,328,329],immobil:25,immut:[11,261],imo:1,impact:126,impati:63,imper:102,implement:[1,6,11,21,25,26,28,29,31,33,34,37,40,41,49,51,55,56,57,58,60,61,78,79,80,81,86,88,89,96,97,108,111,112,114,115,116,117,118,119,120,123,124,125,127,128,131,135,137,138,139,140,147,148,152,153,156,157,158,159,160,161,164,165,166,167,168,169,171,175,176,177,238,239,242,245,246,247,255,256,258,261,273,278,280,281,282,283,284,285,287,289,290,291,294,295,296,298,305,312,316,317,318,319,321,322,325,326,328,329,335,339,340,343,344,364],impli:[22,112],implicit:[91,114,126],implicit_keep:252,impmement:242,import_cmdset:153,importantli:[51,133,242],importerror:[4,9,344],impos:[55,79,310],imposs:[15,19,38,49,51,90,111,113,121,133,138,251,330],impract:[33,109,252],imprecis:334,impress:[42,111],improv:[0,11,37,61,70,76,91,128,364],in_game_error:[26,103],inabl:[63,103],inaccess:[0,80],inact:102,inactiv:169,inadyn:90,inarticul:108,inbuilt:[67,112,123],incant:75,incarn:357,includ:[2,4,6,9,12,13,16,20,21,22,27,30,31,33,36,37,38,39,41,43,44,48,51,53,55,58,60,61,62,63,64,69,73,74,75,78,79,80,84,85,88,89,91,93,95,96,100,101,102,104,105,106,107,108,109,111,112,114,115,116,119,121,125,127,131,133,134,135,136,137,138,144,150,151,152,154,157,158,159,167,170,175,176,241,247,251,259,267,285,287,290,291,299,304,307,316,317,318,319,321,322,323,324,325,327,328,330,331,337,342,344,347,350],include_account:316,include_children:317,include_par:317,include_prefix:151,include_unloggedin:[285,308],inclus:317,incoher:126,incol:[58,327,330],incom:[33,40,88,90,96,104,139,146,151,168,267,276,280,283,286,290,291,295,296,298,306,307,308,312,328,329],incomplet:[154,330],inconsist:[10,97],incorpor:[156,330],incorrect:176,increas:[25,62,73,80,103,114,119,125,279,285,299,326,328],increase_ind:326,incred:269,increment:[63,316],incur:27,indata:[40,316],inde:[9,55,90,91],indefinit:[102,255,324],indent:[0,9,13,14,27,38,50,51,57,60,95,129,137,296,322,326,328,344],independ:[0,56,64,102,126],indetermin:269,index:[7,38,49,56,61,68,79,85,86,90,108,121,135,136,151,164,165,166,239,245,265,269,270,312,319,321,329,330,344,357,360,364],index_category_clr:166,index_topic_clr:166,index_type_separator_clr:166,indexerror:[134,317],indextest:360,indic:[0,8,22,38,49,51,62,64,85,91,95,111,119,146,159,166,167,256,259,278,279,287,294,295,308,310,312,316,321,322,328,329,344],individu:[0,11,13,14,18,21,22,33,34,41,46,48,49,55,57,58,59,71,73,78,85,88,90,96,109,111,132,153,157,175,249,252,306,319,321,330,338,339],ineffici:[115,117,321],infact:33,infinit:[0,61,63,146,251],inflict:102,influenc:[10,16,22,46,51,102,123,344],influenti:79,info:[3,5,11,13,16,17,20,23,24,25,26,27,33,35,37,43,52,55,58,59,63,64,68,78,86,88,89,95,100,101,102,104,105,106,112,124,125,131,138,139,144,146,148,156,157,159,166,169,171,178,238,239,247,267,272,276,284,285,305,306,308,317,318,319,324,327,337,344,364],infomsg:337,inforamt:[247,318],inform:[0,2,3,6,8,9,18,20,22,23,25,27,28,33,34,36,38,41,46,48,51,55,60,65,66,68,69,73,83,84,85,86,91,95,96,100,102,103,104,105,109,112,114,116,117,119,120,123,124,127,131,132,133,134,135,136,137,138,139,144,146,154,157,159,164,165,169,176,177,238,239,247,267,272,281,282,283,285,294,307,308,317,318,321,324,326,337,344,357,364],infrastructur:[38,64,83,90,103,150,277,364],infrequ:46,ing:[9,14,58],ingame_python:[141,142,178,364],ingame_tim:62,ingo:[31,51,58,74,114,152,245,279,364],inher:[4,10,87,108],inherit:[2,5,6,22,27,30,31,33,36,40,42,57,60,64,69,81,86,89,96,102,109,114,117,119,123,125,127,148,152,154,159,167,169,170,175,177,243,246,247,252,256,258,298,307,314,317,318,326,329,330,334,342,344,364],inheritng:252,inherits_from:[117,134,169,344,364],inifinit:251,init:[6,9,22,38,40,47,49,58,60,63,75,83,95,104,106,131,137,138,246,267,285,286,296,308],init_django_pagin:329,init_evt:329,init_f_str:329,init_game_directori:267,init_iter:329,init_mod:153,init_new_account:344,init_pag:[251,329],init_queryset:329,init_sess:[40,307],init_spawn_valu:251,init_str:329,init_tru:153,initi:[5,9,11,21,29,33,38,47,49,50,51,58,60,61,64,68,73,85,97,105,107,110,120,123,127,130,131,133,137,138,144,146,153,154,170,175,177,245,246,247,251,257,260,261,264,265,267,269,270,271,276,277,278,280,281,282,283,285,286,287,288,289,290,291,292,294,295,296,298,306,307,308,316,321,323,326,327,328,329,339,340,344,351,357,364],initial_ind:330,initial_setup:[141,142,262,305,364],initialdelai:[264,278,279,298],initialize_nick_templ:316,initil:295,inject:[96,103,251,267,298,299,306,322,328],inlin:[18,57,85,104,137,247,265,364],inlinefunc:[45,83,104,109,141,142,320,364],inlinefunc_en:114,inlinefunc_modul:114,inlinefunc_stack_maxs:114,inlinefunct:114,inmemori:316,inmemoryattribut:316,inmemoryattributebackend:316,inmemorybackend:316,inmemorysavehandl:339,inner:77,innoc:[12,157],innocu:103,inobject:276,inp:[51,159,176,251,265,329,344],inpect:51,input:[1,5,9,10,14,15,17,20,22,27,30,31,40,41,50,53,55,57,58,70,74,79,83,87,91,95,96,104,105,109,110,111,113,114,115,118,127,131,133,135,137,138,144,149,150,151,154,159,164,166,167,168,169,170,176,238,247,250,251,252,265,267,272,276,287,295,306,308,316,317,319,326,327,328,329,330,338,340,342,344,345,357,364],input_arg:342,input_cleanup_bypass_permiss:344,input_cmdset:328,input_func_modul:[74,272],input_str:328,input_validation_cheat_sheet:357,inputcmdset:328,inputcommand:[74,83,88],inputcompon:137,inputdebug:[74,272],inputfunc:[40,45,104,139,141,142,146,262,295,306,308,364],inputfunc_nam:295,inputfunct:74,inputhandl:141,inputlin:[87,165,175,316,317],insecur:90,insensit:[51,166,245,317,349],insert:[13,14,25,38,50,51,58,64,71,87,96,109,114,138,153,251,322,328,330,344],insid:[0,5,10,11,13,15,19,20,21,23,25,27,28,31,33,38,42,46,47,51,57,59,63,64,67,68,69,71,72,73,80,82,83,85,86,88,89,91,92,93,95,96,100,102,105,106,108,109,110,111,114,117,121,123,125,127,132,133,134,135,136,139,141,146,169,175,241,246,247,250,267,284,305,312,322,323,344,364],inside_rec:241,insiderecurs:241,insight:[20,41,42,122,136],insist:[90,91],inspect:[12,23,51,85,144,159,169,265,267,328],inspectdb:86,inspir:[33,41,73,116,127,129,330,344],instac:[154,247,306],instal:[0,3,5,14,20,26,37,38,41,42,46,47,54,55,57,58,59,60,64,65,76,77,79,95,96,97,98,101,103,106,108,110,124,127,128,130,134,138,139,141,363,364],installed_app:[4,69,86,127,133,134],instanc:[0,2,3,8,11,16,17,22,25,27,28,29,39,41,42,46,50,51,56,57,58,59,60,61,62,64,69,76,84,85,91,95,96,97,102,103,105,107,109,116,119,121,126,127,131,136,137,144,148,150,151,152,153,154,163,166,168,169,175,177,239,246,247,251,252,255,256,260,261,264,267,276,277,278,279,280,281,282,283,285,289,290,294,298,299,307,308,312,316,318,319,321,324,325,328,330,334,335,340,342,344,345,357,364],instant:136,instanti:[33,86,127,144,153,170,258,261,284,305,308,316,327],instead:[0,3,6,9,10,11,12,14,16,19,20,21,22,23,25,26,27,29,30,31,33,34,37,38,39,41,46,48,49,51,57,58,60,62,63,64,67,79,80,83,84,85,86,89,90,91,93,95,96,100,102,103,104,105,106,109,110,111,112,114,116,117,118,119,121,123,125,126,127,128,131,132,133,134,135,136,138,139,144,146,153,154,156,157,159,161,164,168,169,171,175,176,241,242,245,247,252,261,267,295,296,306,310,316,318,319,324,328,329,334,337,339,340,341,344,357],instig:157,instil:140,instnac:260,instr:[276,344],instruct:[0,8,9,13,14,23,27,30,37,38,42,46,47,55,57,58,60,61,63,67,74,75,77,79,83,85,90,93,96,97,100,106,119,124,131,139,144,154,169,252,261,264,267,277,279,285,290,291,295,296,298,306,308,328,338,364],integ:[25,31,33,39,85,91,105,109,114,123,125,151,241,247,317,340,344,345],integerfield:[133,357],integr:[4,7,41,45,61,64,76,79,103,134,137,139,170,270,272,328,364],intellig:[73,83,91,103,134,153,298],intend:[13,17,20,22,27,31,33,34,37,42,55,61,90,103,108,109,111,112,114,122,126,131,136,137,144,238,239,247,252,285,317,319,324,325,327,330,341,342,344,345],intens:[79,93,114],intent:[51,76,96,103,344],inter:13,interact:[2,20,23,29,33,38,40,42,43,51,55,56,59,61,77,79,100,106,108,110,116,122,133,138,141,158,267,284,322,337,342,344,364],intercept:308,interchang:[116,328],interest:[0,1,4,11,14,20,21,22,26,33,37,40,42,46,49,55,57,60,61,70,79,86,90,91,93,96,103,109,114,119,120,121,123,136,153,168],interf:63,interfac:[9,21,22,23,25,36,40,42,63,64,69,70,79,80,90,96,97,101,104,119,133,135,137,138,139,156,159,175,245,247,259,278,307,312,316,319,321,344,364],interfaceclass:287,interfer:[23,97,251],interim:[29,115],interlink:[284,305],intermediari:[242,257,328],intern:[10,11,15,27,34,40,51,63,76,80,87,88,90,100,102,103,104,105,107,109,110,112,113,116,128,144,146,177,245,247,251,258,295,296,316,318,319,321,325,328,330,344,364],internal:328,internal_port:90,internation:[7,113,139,364],internet:[10,12,16,33,40,63,67,72,90,103,124,157,264,269,277,278,279,287,290,298,312],interpret:[33,42,56,59,60,91,93,96,102,103,104,109,134,154,158,159,251,252,295,321,340,364],interrupt:[63,150,154,170,287],interruptcommand:[33,91,141,150,154],intersect:[31,152],interv:[64,74,102,115,116,120,121,132,146,147,255,256,261,272,324,331,344],interval1:261,intim:[31,33],intimid:58,intoexit:159,intpropv:123,intricaci:62,intrigu:54,intro:[4,69,122,124,134],intro_menu:[141,142,178,229,364],introduc:[26,29,31,57,73,97,123,124,127,131,139],introduct:[3,13,14,15,18,19,20,45,60,61,63,124,127,131,139,363,364],introductori:[55,63],intrus:126,intuit:[22,51,61,86,91,131,139,152],intxt:27,inv:[31,43,82,165],invalid:[11,41,60,91,109,144,251,330,340,344,345],invalid_formchar:327,inventori:[20,21,25,27,31,43,80,85,91,97,119,138,165,241,247,318,364],invers:[80,114,126,293,343],invert:[114,126],invis:24,invit:[0,10,61,77],invitingli:20,invok:[11,13,14,102],involv:[40,56,61,68,75,80,89,105,107,116,123,318,319,321],ioerror:322,ipregex:157,ipstart:[63,100,110],iptabl:103,ipython:[26,58,59,96],irc2chan:[43,72,164],irc:[7,9,26,34,55,60,63,70,79,98,131,138,139,141,142,146,164,172,262,272,275,285,308,363,364],irc_botnam:146,irc_channel:146,irc_en:[72,164,241],irc_network:146,irc_port:146,irc_rpl_endofnam:279,irc_rpl_namrepli:279,irc_ssl:146,ircbot:[146,279],ircbotfactori:[146,279],ircclient:[279,308],ircclientfactori:285,irchannel:[72,164],ircnetwork:[72,164],ircstatu:[43,164],ironrealm:291,irrelev:[103,276],irur:52,is_account_object:56,is_act:256,is_aggress:117,is_anonym:[4,69],is_anyon:4,is_authent:133,is_ban:144,is_bot:148,is_build:4,is_channel:[33,41],is_connect:[148,247],is_craft:29,is_exit:[33,154],is_fight:29,is_full_moon:25,is_gm:58,is_in_chargen:123,is_inst:27,is_it:344,is_iter:344,is_next:[148,177,239,246,256,316,318],is_o:344,is_ouch:11,is_prototype_bas:251,is_sai:118,is_subprocess:344,is_superus:[2,4,144,147,148,242,247,324],is_thief:166,is_typeclass:[48,144,318],is_valid:[102,121,133,256,259],isalnum:321,isalpha:321,isb:342,isbinari:[278,295],isclos:137,isconnect:137,isdigit:[58,114,321],isfiremag:28,isinst:[39,344],isleaf:296,islow:321,isn:[0,4,17,22,41,42,46,50,56,62,63,69,91,119,138,269,321,338,349],isnul:340,iso:[15,113,171],isol:[13,37,38,61,63,64,91,95,100,127],isp:[90,103],isspac:321,issu:[7,8,10,11,13,14,21,22,23,29,31,33,37,38,42,43,45,48,54,58,60,63,70,79,85,89,90,93,103,108,123,125,126,127,131,138,140,164,171,251,267,298,299,330,363,364],istart:[42,110,141],istep:299,istitl:321,isub:116,isupp:321,ital:364,itch:[61,63],item:[20,38,47,51,59,63,68,69,82,85,86,116,117,138,165,286,316,344],itend:344,iter:[11,49,51,59,97,112,119,138,144,147,176,238,245,247,252,255,259,296,298,299,316,318,319,321,322,325,329,341,344],iter_cal:329,iter_to_str:344,itl:22,its:[0,2,3,5,9,11,12,14,15,16,20,21,22,23,25,27,29,31,33,37,38,39,40,41,42,44,49,50,51,52,55,56,57,58,60,61,62,63,64,65,68,69,70,72,73,75,80,81,82,83,84,85,86,88,89,90,91,93,95,96,98,100,101,102,103,104,105,109,111,114,115,117,118,119,121,122,123,124,125,126,127,128,129,130,131,133,134,135,136,137,138,139,144,146,148,150,151,152,153,154,157,159,167,169,175,176,245,246,247,252,260,261,267,271,272,276,280,291,293,294,295,296,299,307,308,312,313,316,317,318,319,322,327,328,330,334,337,338,339,340,341,342,344,347,357],itself:[0,4,9,11,15,17,20,21,22,23,25,27,29,33,36,37,38,40,41,44,45,46,47,49,51,55,60,63,64,68,75,77,78,80,82,85,86,89,96,104,105,106,111,114,115,116,118,119,122,123,125,127,131,133,134,135,136,144,146,166,175,236,239,241,245,247,249,250,252,260,267,291,296,308,312,316,319,321,324,326,328,339,341,344,357],iusernamepassword:287,iwar:85,iwebsocketclientchannelfactori:278,iwth:261,jack:87,jail:[12,13],jamochamud:24,jan:[12,62,364],januari:62,jarin:90,javascript:[55,83,88,103,135,136,137,138,295,296],jenkin:123,jetbrain:[79,106],jnwidufhjw4545_oifej:9,job:[33,41,67,69,80,144],john:58,johnni:364,johnsson:87,join:[9,22,34,49,58,61,63,65,72,96,112,116,119,123,133,144,164,175,321,344,364],joiner:175,jointli:[64,153],joke:59,joker_kei:22,jqueri:138,json:[83,88,137,138,278,291,295,296,325],jsondata:88,jsonencod:296,jsonifi:296,jtext:321,judgement:73,jumbotron:364,jump:[13,14,21,41,44,49,51,52,55,61,63,77,89,108,131,139,265],junk:276,just:[0,1,3,4,5,6,9,10,11,12,13,14,15,17,19,20,21,22,23,25,26,27,28,29,30,31,33,34,37,38,39,40,41,42,44,46,47,48,49,51,52,54,56,57,58,59,60,61,62,63,64,68,69,70,73,74,76,77,79,80,81,83,85,86,87,88,89,90,91,93,95,96,97,100,101,102,105,106,107,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,125,126,127,128,131,132,133,134,135,136,137,138,140,144,152,153,154,157,159,164,167,168,170,175,242,247,252,257,272,285,295,299,305,312,316,317,318,321,325,326,328,330,339,340,342,344,345,364],justif:[329,344],justifi:[96,109,321,329,344],justifii:329,justify_kwarg:329,kcachegrind:93,keen:37,keep:[0,1,4,7,9,11,13,14,15,16,20,25,26,29,30,33,34,42,45,48,51,56,57,58,60,61,62,63,64,68,69,73,75,76,77,78,81,82,85,91,92,95,96,97,100,105,109,116,118,121,122,126,128,131,132,133,134,138,146,153,251,252,269,310,328,330,344],keep_log:[34,175,176,324],keepal:[105,290,296],keeper:85,keepint:64,kei:[0,1,5,8,9,10,11,13,21,25,26,27,28,29,30,31,33,34,38,39,41,42,44,49,50,52,56,57,58,60,62,69,71,74,80,81,82,84,85,86,88,89,91,95,96,97,102,107,111,112,114,115,116,119,120,121,123,125,127,129,131,133,137,138,144,146,147,148,150,152,153,154,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,175,176,177,238,239,241,245,246,247,250,251,252,255,256,257,258,259,260,261,265,267,272,273,274,276,285,288,291,292,294,295,296,298,299,306,307,308,310,316,317,318,319,323,324,326,327,328,329,337,338,339,341,342,344,357,364],kept:[33,57,80,91,119,127,159,252,316],key2:[51,247],key_mergetyp:[31,152],keyboard:138,keydown:137,keyerror:[251,261,339,344],keyfil:[288,292],keynam:[175,176,238,250,252,324],keypair:287,keys_go_back:22,keystr:319,keystrok:287,keywod:330,keyword:[0,1,5,10,11,22,25,27,29,30,33,34,50,51,52,58,62,74,80,81,83,86,91,93,95,102,107,109,114,115,119,123,125,127,134,144,146,147,150,154,159,165,175,176,242,245,247,251,252,255,257,260,261,265,267,272,276,278,279,285,286,287,290,295,296,306,307,308,310,316,317,318,324,327,328,329,330,334,338,340,341,344,364],kick:[12,31,51,58,90,146,152,157,164,171,329],kildclient:24,kill:[20,27,51,61,75,93,100,102,105,116,257,261,267,305,312,364],killsign:267,kilogram:82,kind:[0,11,37,38,40,80,91,97,104,116,118,119,121,133,138,242,318,345],kinda:138,kindli:126,kitchen:[44,159],knew:95,knock:51,know:[0,2,5,6,8,10,11,13,14,15,16,20,21,22,23,26,29,31,33,37,38,39,40,41,42,44,48,49,51,54,56,57,58,60,61,64,67,69,70,72,73,74,79,80,81,82,83,84,85,86,89,90,91,93,95,96,97,98,100,102,104,105,110,111,113,114,116,117,118,119,121,125,126,127,128,131,132,133,134,136,138,139,154,158,159,167,170,246,247,272,306,308,316,322,323,328,344,363,364],knowledg:[13,15,33,55,77,289,308],known:[7,20,24,33,50,73,79,80,87,92,96,109,114,115,125,134,137,143,168,329,364],knuth:93,kobold:61,koster:79,kovash:51,kovitiku:364,kwar:318,kwarg:[1,10,25,29,33,40,41,51,58,59,74,80,81,83,84,88,96,107,109,114,115,118,121,125,132,134,137,144,146,147,148,150,153,154,156,157,158,159,164,165,166,167,168,169,170,171,175,176,177,238,239,241,242,245,246,247,249,250,251,252,255,256,257,259,260,261,264,265,272,273,274,276,277,278,279,284,285,286,287,288,290,291,292,295,296,298,300,306,307,308,309,310,312,316,317,318,319,321,324,326,327,328,329,330,331,333,334,337,338,339,340,341,342,344,345,357],kwargtyp:344,label:[48,64,70,86,112,133,140,357],label_suffix:357,laborum:52,lack:[13,38,56,61,70,129,247,316,344],ladder:58,lag:[49,63],lai:[1,48],lair:14,lambda:[10,39,51,69,109,252,344],lamp:111,land:[91,116],landscap:[103,111],languag:[7,15,38,40,47,55,56,57,58,64,79,91,95,103,108,113,114,118,124,125,127,129,130,137,139,364],language_cod:76,larg:[10,11,13,14,16,20,23,37,51,55,56,61,86,90,96,97,108,109,122,127,251,285,322,327,334],larger:[14,20,38,49,57,61,68,80,82,86,108,247,293,321,334,344,347],largesword:86,laser:77,last:[4,11,13,14,22,26,29,31,33,34,36,38,42,48,51,54,58,60,69,74,76,86,87,89,91,95,96,105,107,110,116,121,122,126,127,131,134,136,137,147,150,151,153,159,164,165,247,271,321,322,323,328,329,330,331,337,344,364],last_cmd:33,last_initial_setup_step:305,last_step:271,lastcast:28,lastli:[81,83,111,133,150],lastsit:25,late:[251,323],later:[0,2,9,11,12,13,22,23,33,34,40,46,55,58,60,61,63,64,69,73,74,76,81,83,84,86,90,95,97,109,111,114,115,117,120,121,123,125,131,133,138,139,140,152,156,157,159,167,175,251,252,261,287,319,344],latest:[20,21,27,31,36,38,58,63,64,75,83,98,131,159,164,169,247,252,286,310,328,337,363,364],latin:[15,113,171,247,344,364],latin_nam:247,latinifi:[247,344],latter:[6,27,29,34,64,77,80,89,91,95,115,126,256,258,319],launch:[14,21,54,63,75,85,90,93,102,106,110,122,127,138,153,266,267,277,279,298,326,344,364],launcher:[93,106,266,267,276,277,298],law:79,layer:[22,31,246,318],layout:[27,49,56,58,96,119,125,128,137,138,247,364],lazi:344,lazy_properti:344,lazyencod:296,lazyset:337,lc_messag:76,lcnorth:114,ldesc:56,ldflag:75,lead:[0,11,13,17,20,22,23,31,37,49,51,56,60,61,64,69,79,83,86,102,103,111,121,144,151,152,159,169,247,251,252,306,316,318,328,330,344],leak:135,leap:[62,118],learn:[0,15,16,17,20,22,29,31,33,42,46,49,56,57,60,63,68,69,79,80,81,95,96,106,108,118,122,124,126,127,131,134,136,139,364],least:[3,8,33,39,42,47,49,51,55,57,58,61,67,73,80,86,90,96,102,106,121,138,144,153,176,238,247,252,259,321,327,330,341,344],leather:85,leav:[0,2,20,21,22,25,58,60,73,74,77,85,93,95,102,103,116,123,137,138,156,158,159,175,247,260,291,295,296,328,334,364],leaver:175,left:[22,27,33,36,38,39,41,57,69,74,80,85,86,91,101,102,109,111,114,137,138,144,159,165,167,242,252,318,321,330,344,363],left_justifi:109,leg:304,legaci:[88,109,144],legal:[90,103],legend:[24,49,50],leisur:345,len:[25,49,58,71,85,109,114,116,119,120,121,151,168,344],lend:50,length:[22,23,25,49,62,66,68,71,83,86,90,91,95,122,151,269,310,316,321,330,344],lengthi:[1,25],lengthier:363,lenient:109,less:[22,34,44,51,56,61,64,73,86,90,91,106,108,116,119,132,133,139,316],let:[0,3,5,7,8,9,11,12,14,15,20,21,22,25,28,31,33,37,38,39,40,41,44,46,48,49,51,56,57,58,60,61,62,63,64,65,70,72,73,74,75,77,80,81,82,83,85,89,91,93,95,96,98,103,106,111,114,115,117,118,119,121,123,124,126,127,131,133,134,136,137,140,144,153,154,159,165,170,176,242,247,277,296,308,324,328,338,343,357,363,364],letsencrypt:[67,90],letter:[15,22,38,39,76,90,95,111,113,114,119,123,133,156,165,171,311,321,344],leve:251,level:[2,11,13,19,20,22,26,27,30,36,38,40,41,47,50,51,55,57,58,61,63,66,69,71,73,79,80,85,90,95,96,104,105,108,111,112,119,122,125,130,133,138,139,140,144,147,156,159,161,162,175,241,247,252,269,306,316,318,324,326,331,344],lever:[33,125],leverag:[3,38],levi:86,lhs:[25,58,167],lhslist:167,lib:[63,67,75,97],libapache2:8,libcrypt:75,libjpeg:75,librari:[6,13,26,45,53,56,57,63,64,75,76,78,79,91,95,100,103,108,109,125,127,128,133,136,137,138,178,251,252,280,316,318,330,344,364],licenc:321,licens:[37,45,79,106,139,321,364],lie:111,lies:[33,131],life:[11,37,62,87,95,126,364],lift:[20,73,80,96,123,242,364],lifter:80,light:[14,23,27,38,61,102,108,122,153,252,260,321],lighter:114,lightest:27,lightli:16,lightsail:90,like:[0,2,3,5,6,8,9,10,11,12,14,15,16,17,19,20,21,22,23,25,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,42,44,45,46,48,49,51,52,53,54,55,57,58,59,60,61,62,63,64,65,67,68,69,70,71,72,73,74,75,76,77,79,80,81,83,84,85,86,88,89,90,91,93,95,96,97,100,102,103,104,105,106,107,108,109,111,112,114,115,116,117,118,119,120,121,125,126,127,128,129,131,132,133,134,135,136,137,138,139,140,144,146,148,149,151,152,153,156,158,159,164,167,171,172,175,176,238,239,241,242,245,246,247,251,252,267,272,280,296,299,301,305,307,308,316,317,318,321,322,324,327,328,329,330,331,334,338,340,341,342,344,357,364],limbo:[0,9,13,14,20,22,27,59,63,66,104,111,121,122,134,159,271],limbo_exit:111,limit:[0,2,6,11,16,19,20,25,26,27,28,31,33,34,37,46,51,53,55,58,61,64,68,71,80,86,90,91,95,102,104,109,112,116,123,125,126,127,138,140,144,147,154,156,157,158,159,175,176,238,239,242,245,247,252,255,256,261,272,285,310,316,317,318,319,322,324,326,337,341,344,364],limit_valu:144,limitedsizeordereddict:344,line:[0,4,5,9,10,13,14,15,19,22,23,25,26,27,29,30,31,33,34,36,38,39,41,45,46,48,51,53,54,56,57,58,59,60,61,62,63,67,69,74,76,81,83,86,87,89,90,91,92,93,95,96,97,98,100,104,108,109,110,111,114,119,121,123,125,127,128,133,134,137,138,139,141,144,150,153,159,164,166,168,169,247,251,267,272,287,290,295,306,318,321,322,326,327,328,329,330,337,344,357,364],linear:49,linebreak:[69,321,343],lineeditor:326,lineend:343,lineno:38,linenum:326,liner:279,linereceiv:[287,290],linesend:296,lingo:[57,86,105,135],linguist:344,link:[2,3,4,9,14,17,18,20,22,25,29,31,33,37,39,40,43,46,48,49,51,54,55,57,63,64,69,70,72,85,89,90,96,98,105,111,119,121,123,124,128,131,133,134,139,144,148,159,164,242,247,256,265,267,278,282,287,290,318,343,344,364],linknam:[38,54],linktext:38,linod:90,linux:[4,8,9,23,25,38,64,67,72,75,87,90,93,97,100,106,131,344,364],liquid:318,list:[0,1,2,3,4,6,7,11,12,13,14,15,20,22,23,25,27,31,33,34,37,39,40,41,43,45,46,48,49,51,54,55,57,58,59,60,61,63,66,68,69,70,72,73,74,76,77,79,80,82,85,86,88,89,90,91,93,95,96,97,98,102,103,105,106,109,110,111,112,113,114,116,118,119,121,123,124,125,128,129,131,133,134,135,137,138,139,144,146,147,148,151,152,153,154,156,157,158,159,164,165,166,167,169,170,175,176,177,238,242,245,246,247,251,252,255,257,258,259,261,265,267,272,273,276,277,279,281,283,285,286,291,296,299,308,310,312,316,317,318,319,321,322,323,324,325,328,330,337,338,341,342,344,350,363,364],list_channel:164,list_nod:[328,364],list_of_all_rose_attribut:11,list_of_all_rose_ndb_attr:11,list_of_lycanthrop:119,list_of_myscript:102,list_prototyp:251,list_set:267,list_styl:156,list_to_str:344,listabl:159,listaccount:[43,169],listcmdset:159,listcmset:43,listen:[2,12,34,41,67,80,103,105,124,137,139,164,175,364],listing_contact:54,listnod:328,listobj:43,listobject:[43,159],listscript:43,liter:[13,20,57,66,109,165,321,340,344],literal_ev:[51,328,344],literatur:364,littl:[0,4,9,10,15,20,21,25,28,33,34,38,41,42,57,58,60,64,69,70,71,85,90,91,96,100,102,109,110,111,117,118,119,125,131,134,136,138,139,302,316,328,344,357],live:[8,23,38,60,63,67,70,79,90,100,106,364],ljust:321,load:[6,11,12,13,15,26,29,31,33,44,50,51,56,57,58,60,61,69,73,82,83,97,103,106,109,111,121,123,127,136,137,138,148,153,165,166,169,177,239,242,246,247,251,256,260,271,274,276,307,316,318,319,322,323,326,335,338,339,342,344,350,355],load_buff:326,load_data:323,load_game_set:350,load_kwarg:339,load_module_prototyp:251,load_sync_data:307,loader:[51,318,344],loadfunc:[50,326,339],loc:159,local0:67,local:[23,25,36,37,47,59,62,64,67,72,76,97,100,103,106,114,131,133,138,252,290,316,364],local_and_global_search:245,localecho:272,localhost:[3,4,9,23,24,63,67,69,75,90,95,133,134,135,137,296],localstorag:138,locat:[0,2,4,6,8,9,11,12,13,20,21,25,27,30,31,33,35,38,39,43,46,47,48,49,51,57,58,59,63,64,66,73,74,77,80,85,89,90,91,96,100,102,103,109,111,112,114,117,118,119,121,122,123,125,127,128,131,133,135,136,137,140,144,150,159,165,169,175,176,241,245,246,247,252,296,305,316,317,318,319,322,324,328,330,337,341,347],location_set:119,locations_set:[119,246],locattr:241,lock:[4,6,10,12,19,20,21,22,23,25,28,29,31,33,34,39,41,43,44,45,47,48,53,58,60,62,68,71,82,85,89,90,96,104,109,110,112,123,125,133,138,139,141,142,144,147,154,156,157,158,159,164,165,166,168,169,170,171,175,176,177,238,239,245,246,247,251,252,255,312,316,318,319,324,326,328,338,344,345,364],lock_definit:242,lock_func_modul:[80,242],lock_storag:[154,156,157,158,159,164,165,166,167,168,169,170,171,177,239,247,298,316,318,326,328,329],lock_typ:80,lockabl:58,lockablethreadpool:312,lockdown:[80,316,364],lockdown_mod:90,lockexcept:242,lockfunc1:80,lockfunc2:80,lockfunc:[25,33,53,80,104,121,141,142,159,164,240,319,364],lockhandl:[11,48,80,125,141,142,154,240,241,364],lockset:247,lockstr:[4,11,33,80,97,109,147,159,164,166,175,176,177,238,242,245,247,252,255,316,319,324],locktest:136,locktyp:[152,164,252,319],log:[2,4,5,6,8,10,11,12,20,21,23,24,25,33,34,35,36,39,44,45,47,51,53,55,57,58,59,60,63,64,65,66,67,71,72,73,74,75,76,83,86,89,90,93,100,101,102,105,106,107,110,111,114,121,122,123,128,130,131,133,134,135,137,138,144,147,153,157,171,175,176,247,256,260,267,272,276,277,281,284,285,287,290,298,299,300,306,308,310,312,318,324,337,344,364],log_dep:[27,337],log_depmsg:337,log_dir:[175,337],log_err:[27,337],log_errmsg:337,log_fil:[27,175,337],log_file_exist:337,log_info:[27,337],log_infomsg:337,log_msg:337,log_sec:337,log_secmsg:337,log_serv:337,log_trac:[27,102,118,120,337],log_tracemsg:337,log_typ:337,log_typemsg:337,log_warn:[27,337],log_warnmsg:337,logdir:36,logentry_set:148,logfil:[267,337,364],logged_in:105,loggedin:285,logger:[27,53,102,118,120,141,142,279,320,364],logic:[0,4,10,39,41,42,44,49,69,97,111,134,246,250,271,316,328,345],login:[2,4,7,9,25,33,35,51,55,69,70,80,90,97,101,105,107,131,133,139,144,156,171,242,271,272,287,290,295,296,299,308,344,349,351,360,364],login_func:299,logintest:360,logo:364,logout:[298,299,360],logout_func:299,logouttest:360,logprefix:[277,287,290,312],lone:[61,111,159,166],long_descript:54,long_running_funct:10,long_text:52,longer:[0,21,25,29,33,41,50,52,54,58,69,79,86,91,102,115,124,125,126,129,152,157,175,257,260,326,330,344,364],longest:27,longrun:33,loo:[154,170],look:[0,3,4,6,9,10,11,12,13,14,15,16,17,19,20,21,22,23,25,26,27,29,30,31,33,35,36,37,38,39,40,41,42,43,44,46,49,51,55,57,58,60,61,62,63,64,67,68,69,70,71,73,74,75,76,77,80,81,82,83,85,86,87,88,89,90,91,96,97,100,103,105,108,109,110,111,112,114,116,117,118,119,121,122,124,125,126,127,131,133,134,135,136,138,139,144,146,151,153,154,156,159,165,167,170,171,238,241,242,246,247,249,252,255,272,287,288,295,299,316,318,322,328,330,338,341,342,343,344,357,364],look_str:144,lookaccount:58,lookat:33,looker:[49,58,60,123,144,247,318],lookm:33,lookstr:247,lookup:[11,33,80,86,97,112,119,150,165,245,246,251,286,319,321,333,334,340,341,344,345,364],lookup_typ:340,lookup_usernam:51,lookuperror:321,loom:111,loop:[0,5,6,11,21,46,49,55,60,64,69,85,93,96,116,118,119,124,125,141,146,252,285],loopingcal:270,loos:[14,37,144,164,238,287,298,322],loot:61,lop:119,lore:[58,166],lose:[11,56,61,100,105,110,116,123,138,278,279,287,290],lost:[0,38,39,56,79,91,110,111,125,135,139,164,264,277,278,279,287,290,295,316,321],lot:[0,4,10,13,15,22,26,27,28,34,37,39,41,42,46,53,55,57,58,59,61,62,63,67,69,70,73,79,80,86,90,91,93,95,96,108,109,111,112,114,119,121,123,125,127,131,133,135,138,312],loud:21,love:137,low:[31,40,46,66,90,95,152],lower:[2,10,19,25,29,31,33,41,49,51,58,62,80,85,86,90,93,114,122,137,151,152,156,167,169,272,319,321,344],lower_channelkei:41,lowercas:[38,95,154,321],lowest:[66,90,241,321],lpmud:129,lpthw:77,lst:[49,238,324],lstart:50,lstrip:[91,119,321],ltthe:169,ltto:114,luc:327,luciano:79,luck:[8,51,91,96],luckili:[60,80,111,127,131],lue:[114,321],lug:55,luhttp:169,lunch:46,lunr:166,luxuri:[112,314],lycanthrop:119,lying:111,m2m:319,m2m_chang:107,m_len:344,mac:[9,23,24,38,64,93,100,106,131,344,364],machin:[13,25,100,106,131,364],macport:[63,131],macro:[4,116],macrosconfig:4,mad:131,made:[3,11,19,20,21,25,26,35,36,38,51,56,58,59,61,79,80,90,96,98,103,104,109,111,121,123,131,134,150,152,169,170,175,242,260,269,299,313,321,322,326,328,344],mag:[60,127,327],magazin:79,mage:51,mage_guild_block:51,mage_guild_welcom:51,magenta:126,magic:[30,60,61,80,112,121,122,140,269,364],magic_meadow:112,magicalforest:140,magnific:51,mai:[0,4,6,8,9,10,11,13,19,20,21,23,25,27,28,29,31,33,34,37,38,40,41,42,48,51,54,56,57,60,62,63,64,66,67,69,70,71,73,75,77,79,80,81,83,84,86,87,88,89,90,93,95,96,97,100,102,103,104,105,106,108,109,110,111,114,115,116,118,119,120,123,125,127,128,130,131,133,134,135,136,144,146,150,151,152,154,156,157,159,164,166,169,170,175,176,177,178,242,245,247,251,252,253,269,306,308,309,313,316,318,319,321,323,324,325,326,328,330,331,338,341,344,347],mail:[9,34,37,51,55,57,60,61,70,79,93,116,128,141,142,176,177,178,363,364],mailbox:34,main:[13,14,15,20,21,22,30,31,33,34,37,40,49,51,54,56,64,68,69,76,79,80,81,83,84,85,86,89,90,91,92,100,104,105,109,110,112,115,116,119,122,124,125,131,133,134,135,137,138,139,144,148,150,156,159,164,166,170,175,177,239,246,247,252,256,267,271,272,274,279,284,286,291,305,307,312,318,319,328,329,332,341,343,344,364],mainli:[10,12,33,34,51,57,79,83,89,93,96,105,156,236,316,322,344],maintain:[4,19,23,37,38,41,53,56,68,90,93,100,108,115,119,169,171,261,363],mainten:[90,103],major:[14,15,23,45,57,60,63,64,119,121,133],make:[0,1,2,4,5,6,7,8,9,10,11,12,13,14,15,16,19,22,23,24,25,26,28,29,30,31,33,36,37,38,39,40,41,42,43,44,46,47,48,49,50,51,54,55,56,59,61,62,63,64,68,70,71,72,73,74,75,77,78,79,80,81,83,85,86,87,89,90,91,93,95,96,97,100,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,122,124,125,126,128,130,132,133,134,136,137,138,139,140,144,146,148,151,152,153,154,156,157,159,164,167,170,176,238,241,242,245,247,251,252,255,258,261,267,271,279,284,298,299,305,306,308,309,311,312,316,317,318,319,321,322,323,324,325,326,328,330,331,334,341,342,343,344,360,363,364],make_it:344,make_shared_login:351,make_uniqu:152,makeconnect:276,makefactori:287,makefil:38,makeit:298,makemessag:76,makemigr:[36,86,133],malevol:14,malform:[342,345],malici:103,malign:242,man2x1:108,man:[87,90,108,129,165],mana:[28,30],manag:[2,7,9,11,31,39,40,53,56,57,59,80,83,85,86,89,93,96,100,102,105,110,115,119,125,127,128,131,133,138,141,142,143,144,148,159,164,169,170,172,175,177,236,239,243,246,247,251,253,256,261,262,267,274,314,316,318,319,320,323,324,332,335,337,341,344,360,364],manager_nam:316,manchest:344,mandat:357,mandatori:[0,22,107,109,129],mangl:293,manhol:287,manhole_ssh:287,mani:[0,1,2,4,5,9,10,11,12,14,15,17,20,26,27,30,31,33,34,38,40,44,49,51,55,56,57,58,61,62,63,64,66,68,70,72,73,76,77,85,86,88,89,90,91,93,95,96,98,102,103,104,105,107,108,109,110,111,113,114,115,116,118,119,120,121,122,123,124,125,126,127,128,129,131,133,134,135,140,147,148,152,154,159,164,170,177,239,242,245,246,252,256,261,267,281,289,291,310,316,318,319,321,328,329,334,335,337],manifest:97,manipul:[0,11,22,31,41,44,51,64,86,102,109,123,147,159,169,176,238,245,247,255,273,324,329],manner:[14,247,285,318],manpow:37,manual:[4,6,14,20,21,23,30,33,34,38,40,55,58,60,61,63,68,79,80,85,86,89,90,97,102,109,110,111,114,117,119,121,122,124,125,128,131,134,139,140,141,146,159,247,252,259,267,284,291,328,329,363,364],manual_paus:259,manytomanydescriptor:[148,177,239,246,256,316,318,319],manytomanyfield:[148,177,239,246,256,316,318,319],map:[0,15,25,39,46,51,57,58,61,64,67,87,88,97,100,124,135,138,139,156,164,175,247,251,252,291,316,318,321,327,328,342,344,364],map_modul:111,map_str:[49,111],mapbuild:[141,142,178,364],mapper:[334,364],march:[79,337],margin:17,mariadb:364,mark:[13,14,20,21,33,38,49,51,58,63,72,76,80,90,95,114,119,131,135,137,138,140,151,158,308,316,318,322,327,328,340],markdown:[1,4,38,48,54],marker:[13,20,33,51,64,87,114,138,164,165,247,279,287,290,295,296,316,319,321,327,328,329,347],market:90,markup:[81,114,136,139,141,142,159,320,343,344,364],mass:[61,124,139,364],massiv:[28,55],master:[7,9,37,38,57,61,63,73,95,98,100,104,116,118,134,313,364],match:[9,11,20,22,27,31,33,39,41,44,49,51,57,58,62,68,74,76,80,83,86,87,88,89,91,102,104,105,109,111,112,114,118,119,125,128,131,133,134,135,136,137,138,144,147,150,151,152,153,154,157,159,164,165,166,168,170,176,238,241,242,245,247,251,252,255,258,261,272,273,285,298,308,316,317,318,319,321,326,328,330,339,341,342,343,344,345,347,364],match_index:151,matcher:51,matches2:86,matchobject:[321,343],mate:64,math:39,mathemat:152,matplotlib:300,matrix:330,matt:102,matter:[0,4,9,11,25,31,36,41,51,57,61,62,63,69,73,76,84,91,95,103,105,107,108,116,117,127,136,152,246,272,316],matur:[108,128,129],maverick:64,max:[16,25,49,71,114,116,166,310,337,344],max_dbref:317,max_depth:344,max_dist:49,max_l:49,max_length:[49,86,133],max_lin:330,max_rmem:334,max_siz:337,max_valu:357,max_w:49,max_width:49,maxconn:67,maxdelai:[264,278,279,298],maxdepth:252,maxdiff:[170,352],maximum:[16,39,71,86,91,111,114,144,247,252,312,321,328,330,344],maxlengthvalid:144,maxnum:344,maxrotatedfil:337,maxsplit:321,maxthread:312,maxval:344,maxwidth:330,may_use_red_door:109,mayb:[6,9,11,13,14,21,22,25,27,31,33,38,44,48,49,54,61,63,68,69,70,73,82,85,86,90,109,116,119,122,138,140,153,285],mccp:[24,55,74,141,142,262,272,275,364],mccp_compress:280,meadow:[22,112,140],mean:[0,5,10,11,12,13,14,15,20,22,23,27,28,31,33,34,37,40,41,42,46,49,51,55,57,58,60,61,62,64,68,73,74,77,78,80,81,83,84,85,86,87,88,90,93,95,96,97,100,102,103,104,105,110,111,112,113,114,116,117,119,121,122,123,125,126,127,128,131,134,135,136,138,144,146,147,153,159,166,241,245,247,251,252,257,261,267,291,307,316,318,321,328,330,334,337,340,341],meaning:[154,170],meaningless:123,meant:[16,20,22,31,34,44,54,62,68,76,83,96,102,125,126,137,138,140,152,247,272,322,344],meantim:1,meanwhil:96,measur:[90,93,123,151,168,298,299,344],meat:133,mech:[124,139,364],mechan:[27,28,33,39,50,51,55,58,61,67,69,73,91,102,109,116,122,123,125,126,139,144,146,150,240,252,261,267,271,277,285,296,307,318,326,329,332,339,364],mechcmdset:21,mechcommand:21,mechcommandset:21,meck:21,media:[16,295,312,340,357],median:49,mediat:73,medium:16,mediumbox:276,meet:[25,36,61,122,311],mem:169,member:[9,11,70,86,164,165,167,247,344],membership:[4,9,119],memori:[6,12,23,28,31,33,56,75,86,90,93,113,125,135,144,169,175,247,260,261,300,310,316,320,329,334,339,344],memoryerror:63,memoryusag:300,memplot:[141,142,262,297,364],mental:126,mention:[6,9,10,11,13,14,15,21,29,33,40,41,49,56,57,61,63,70,74,80,90,102,108,113,115,126,127,153],menu:[11,25,31,38,45,46,47,53,54,55,63,65,69,105,106,109,110,123,128,138,139,141,142,159,248,252,265,267,320,338,364],menu_cmdset:328,menu_data:51,menu_login:[141,142,178,364],menu_modul:328,menu_module_path:328,menu_templ:328,menuchoic:[51,328],menudata:[249,328],menudebug:[51,328],menufil:328,menunode_inspect_and_bui:85,menunode_shopfront:85,menunodename1:51,menunodename2:51,menunodename3:51,menutre:[51,328],merchant:46,mercuri:108,mere:[117,169],merg:[3,5,22,33,37,38,44,51,57,62,64,97,131,139,150,151,152,153,252,256,291,328,364],merge_prior:328,merger:[5,31,37,111,152,153],mergetyp:[31,51,116,152,326,328,329],mess:[11,19,27,38,90,93,131,138],messag:[5,6,8,10,13,15,20,21,22,27,28,29,33,34,38,40,41,44,45,46,50,51,52,53,55,58,59,60,61,62,63,64,65,70,71,73,74,76,80,81,82,85,89,90,91,92,95,96,101,102,103,104,105,110,111,113,116,118,119,123,124,127,128,131,132,137,138,139,140,144,146,150,153,154,157,159,164,165,166,172,175,176,177,245,247,255,267,269,276,278,279,285,286,287,290,291,293,295,304,306,308,310,312,324,326,328,329,337,341,342,344,364],message_rout:137,message_search:176,message_transform:175,messagepath:[139,364],messagewindow:137,meta:[104,125,318,334,357],metaclass:[86,96,125,154,318],metadata:269,meteor:82,method:[1,2,5,6,9,10,11,22,25,27,28,29,30,31,34,38,39,40,42,46,48,49,51,55,58,59,60,62,64,68,69,73,77,80,83,86,88,89,91,95,96,102,104,105,107,109,111,112,114,115,116,117,118,119,120,121,123,125,127,131,132,133,134,137,139,144,147,148,150,152,153,154,156,159,160,164,166,167,169,170,175,176,177,238,239,241,242,245,247,255,260,261,264,269,272,273,274,276,277,278,279,280,285,287,290,293,295,296,298,299,303,305,306,307,308,310,316,318,321,322,324,326,328,329,330,331,334,335,337,338,339,341,342,343,344,364],methodnam:[170,261,293,303,335,342,352,360],metric:82,microsecond:11,microsoft:[63,111],mid:[29,108,121],middl:[29,33,49,90,321],middlewar:[141,142,346,348,364],midnight:[25,62],midst:122,midwai:114,mighht:91,might:[0,4,8,10,11,12,14,15,17,20,22,23,25,26,27,28,29,30,31,33,34,39,40,41,42,46,51,52,55,58,60,61,62,63,69,70,73,75,76,77,80,81,82,85,89,90,91,95,96,97,98,100,102,103,104,105,110,111,114,115,116,119,120,122,123,124,126,127,131,132,133,136,138,153,157,159,247,255,296,318,321,326,337,338,344,357,363],mighti:[29,111],migrat:[9,23,36,38,63,75,86,107,110,111,127,131,133,252,364],mike:159,mileston:139,million:[23,25,133],mime:[176,324],mimic:[23,34,50,55,73,93,177,306,326],mimick:[50,64,73,138,298,326,329],mimim:319,min:[49,62,102,114,331],min_dbref:317,min_height:330,min_shortcut:22,min_valu:357,min_width:330,mind:[10,12,13,14,37,41,45,51,54,55,56,57,60,61,122,126,134,138,269,344,364],mindex:151,mine:[46,103,138],mini:[55,111,124,364],miniatur:[61,122],minim:[61,103,105,116,138,252],minimalist:[33,58,108],minimap:364,minimum:[22,58,64,73,105,272,312,318,330,339,344],mininum:330,minlengthvalid:144,minor:[41,153,363],mint:[63,67,131],minthread:312,minu:[86,247,331],minut:[25,27,28,62,79,91,100,102,116,164,169,310,331,344],minval:344,mirc:279,mirror:[72,79,105],mis:57,misanthrop:119,misc:138,miscelan:320,miscellan:[47,364],mislead:41,mismatch:[74,344],miss:[49,57,60,63,70,90,95,97,251,272],missil:21,mission:[41,69],mistak:[38,60,363],misus:90,mit:[79,124,321],mitig:[57,103],mix:[11,30,33,34,51,53,114,126,133,144,166,177,247,251,252,311,319,322,330,344],mixin:[251,301,342],mixtur:81,mkdir:[9,36,63],mktime:62,mob0:56,mob:[14,55,56,61,80,105,122,141,142,153,159,178,229,252,322,364],mob_data:56,mob_db:56,mob_vnum_1:56,mobdb:56,mobil:[14,71,109,122,138,241],mock:[127,260,342],mock_repeat:170,mock_tim:303,mock_tutori:170,mockdeferlat:342,mockdelai:342,mocked_idmapp:303,mocked_o:303,mocked_open:303,mockup:138,mockval:342,mod:[8,251],mod_import:344,mod_import_from_path:344,mod_or_prototyp:251,mod_prototype_list:251,mod_proxi:364,mod_proxy_http:8,mod_proxy_wstunnel:8,mod_secur:103,mod_ssl:364,mod_sslj:8,mod_wsgi:364,mode:[2,8,31,41,42,43,50,51,67,69,74,79,93,100,103,106,116,117,123,133,135,138,141,158,166,169,171,247,267,272,277,284,295,296,305,322,326,328,337,344,364],mode_clos:296,mode_init:296,mode_input:296,mode_keepal:296,mode_rec:296,model:[9,11,34,38,41,45,59,64,69,73,80,87,96,104,112,115,119,125,132,135,136,139,141,142,143,144,147,172,175,176,236,243,247,253,257,261,262,273,314,316,317,319,320,325,332,333,335,340,341,344,357,364],model_inst:340,modelattributebackend:316,modelbackend:349,modelbas:334,modelclass:[11,112],modelform:357,modelnam:[154,175,239,318],moder:[4,39],modern:[10,11,15,30,79,103,108,126,138,280],modif:[0,8,25,33,37,46,83,91,100,123,131,138,313,357,364],modifi:[0,2,4,11,20,22,25,26,31,33,34,38,39,40,44,46,51,53,55,56,57,58,60,68,73,78,85,89,93,96,100,104,105,109,110,111,114,118,119,122,123,125,128,131,135,137,138,139,140,144,153,166,175,239,245,247,252,261,318,322,328,334,340,343,347,357,364],modified_text:114,modul:[3,5,6,11,13,15,20,21,26,27,29,31,33,35,37,38,40,45,47,50,51,55,56,57,58,59,60,62,65,68,74,75,80,81,82,83,85,89,93,96,97,98,102,103,104,105,107,108,110,111,114,117,119,121,122,123,124,125,127,135,138,139,150,151,153,154,159,161,162,163,166,168,170,241,242,246,247,250,251,252,257,259,260,261,264,266,267,271,272,276,284,286,287,290,291,294,296,298,299,300,305,307,308,309,316,318,319,320,321,322,323,324,325,326,327,328,329,331,342,344,364],modular:55,modulepath:276,mollit:52,moment:[21,31,46,57,76,85,91,96,115,135,139,144,256],monei:[9,61,70,86,90],monetari:37,monitor:[53,84,88,93,139,257,272,291,334,364],monitor_handl:[53,84,141,257],monitorhandl:[45,74,139,141,142,253,364],mono:25,monster:[29,57,61,64,89,109,159,252],month:[37,62,67,90,331,337,344],monthli:62,montorhandl:84,moo:[55,57,79,108,129],mood:[46,122],moon:[25,61,62,82],moor:122,moral:97,more:[0,1,2,3,4,5,9,10,11,12,13,14,15,17,19,20,21,22,23,25,26,27,28,31,33,34,35,36,37,39,40,41,42,44,46,49,50,51,52,55,56,58,59,60,61,62,63,64,66,67,68,69,70,71,72,73,74,75,76,77,79,83,85,86,87,88,89,90,91,93,95,96,97,100,102,103,104,105,108,109,110,111,112,113,114,115,116,118,119,121,122,123,124,125,126,127,131,132,133,134,136,137,138,141,143,144,147,148,151,152,153,158,159,164,165,166,169,170,171,175,176,178,238,245,247,251,252,255,277,279,282,291,298,299,308,313,316,317,318,321,322,324,325,326,327,328,329,330,334,341,342,344,345,357,364],more_command:329,morennanoth:170,morennthird:170,moreov:[90,102],most:[0,4,6,8,9,10,11,13,17,22,23,25,27,30,31,33,35,37,38,39,40,41,42,46,47,48,49,51,56,57,58,59,60,61,62,63,64,69,73,74,77,80,82,83,86,88,89,90,91,93,95,96,97,100,103,104,105,107,108,111,113,114,115,116,117,119,121,123,125,126,128,129,133,137,138,140,144,148,152,153,156,159,167,177,239,242,246,247,251,252,256,260,290,295,305,316,317,318,319,328,329,334,335,342,344,364],mostli:[40,51,57,69,73,90,91,95,114,123,125,137,138,152,171,287],motiv:[13,14,37,55,61,70,89,278,279,285,286,287,290,295,296,307,308],mount:100,mountain:[108,111],mous:[114,137,328],move:[0,4,9,14,15,21,22,23,29,33,34,41,44,46,49,50,51,52,54,58,61,63,69,77,79,82,85,89,91,95,96,111,116,117,122,126,133,134,138,153,159,165,238,241,247,299,318,322,329,364],move_callback:169,move_delai:169,move_hook:247,move_to:[0,85,89,121,247],movecommand:44,moved_obj:247,moved_object:247,movement:[58,109,121,169,247],mptt:4,mratio:[151,168],msdp:[55,83,272,291,364],msdp_list:272,msdp_report:272,msdp_send:272,msdp_unreport:272,msdp_var:291,msg:[0,2,5,10,11,13,22,25,27,28,29,30,33,38,40,41,42,44,46,50,51,52,53,56,58,59,60,62,71,73,80,82,84,85,86,88,89,91,95,96,105,111,112,114,116,118,119,121,123,127,129,137,138,141,144,146,147,154,156,159,160,164,175,176,177,242,247,278,279,306,322,324,326,328,329,337,342,344,364],msg_all:116,msg_all_sess:[33,154],msg_arriv:0,msg_channel:164,msg_content:[0,21,27,33,46,62,73,89,102,118,121,123,132,247],msg_help:166,msg_leav:0,msg_locat:247,msg_receiv:247,msg_self:247,msg_set:319,msglauncher2port:[267,276],msgmanag:[176,177],msgobj:[34,175],msgportal2serv:276,msgserver2port:276,msgstatu:[267,276],mssp:[55,104,141,142,262,275,364],mtt:294,much:[0,4,10,11,13,14,15,20,22,23,25,26,29,37,39,41,42,49,51,56,59,61,62,63,64,67,69,73,76,79,80,82,89,90,91,93,96,109,111,113,115,116,119,120,121,125,127,132,133,134,138,148,153,158,167,307,316,319,321,322,323,330,344,347],muck:57,mud:[8,15,21,22,23,24,30,40,49,55,56,60,61,63,64,72,73,74,80,87,88,90,91,92,95,97,98,100,101,104,105,108,110,111,114,115,116,117,122,124,126,128,132,135,137,138,140,148,153,156,264,280,281,282,287,290,291,294,322,331,364],mudbyt:79,mudconnector:[79,171],mudderi:79,muddev:63,mudform:327,mudinfo:[34,171],mudlab:79,mudlet:[24,96,101,282],mudmast:24,mudramm:24,mudstat:171,muhammad:343,mukluk:24,mult:109,multi:[10,22,31,38,51,55,61,95,96,100,104,105,119,122,123,151,169,247,308,328,344,364],multiaccount_mod:97,multidesc:[141,142,178,364],multilin:343,multimatch:[31,151,247,344],multimatch_str:[144,247,344],multimedia:137,multipl:[6,12,14,22,23,27,30,31,33,40,51,55,58,61,62,64,73,79,84,88,89,90,95,96,104,105,107,108,109,114,115,122,123,125,131,138,144,150,152,157,158,159,164,166,168,169,242,245,247,251,252,261,265,269,272,276,291,299,316,317,322,328,330,341,342,344,364],multiplay:[55,57,79],multipleobjectsreturn:[144,146,148,175,177,239,246,247,251,256,259,274,300,316,319,331,335],multisess:[41,69,328,364],multisession_mod:[2,24,33,64,69,105,123,133,144,156,160,247,308],multisession_modd:51,multitud:[57,111,114],multumatch:247,mundan:21,murri:344,muse:79,mush:[9,36,55,60,73,79,108,116,124,139,364],mushclient:[24,74,96,272,282],musher:79,mushman:108,mushpark:90,musoapbox:[57,79],must:[0,1,2,4,5,8,10,11,15,24,25,29,31,33,37,38,40,48,49,50,51,56,58,61,62,63,64,65,67,71,72,74,76,80,81,83,84,85,87,89,90,93,95,96,97,100,103,104,109,110,112,113,114,115,116,117,119,123,125,127,128,131,133,135,136,137,140,146,151,152,154,159,164,170,175,176,177,239,241,247,250,251,255,257,261,267,272,285,287,290,307,309,310,316,317,318,321,322,323,324,325,326,327,328,329,331,338,339,340,341,342,343,344,345],must_be_default:153,mutabl:[325,364],mute:[17,41,144,164,175],mute_channel:164,mutelist:[41,175],mutual:317,mux2:[129,171],mux:[20,21,33,34,41,45,55,58,103,108,139,149,167,364],muxaccountcommand:167,muxaccountlookcommand:156,muxcommand:[5,25,28,29,30,33,44,53,58,119,123,141,142,149,155,156,157,158,159,164,165,166,168,169,171,247,326,364],mvattr:[43,159],mxp:[24,55,74,114,141,142,166,262,272,275,287,290,321,328,343,344,364],mxp_pars:282,mxp_re:321,mxp_sub:321,mxp_url_r:321,mxp_url_sub:321,my_callback:309,my_datastor:86,my_funct:29,my_github_password:131,my_github_usernam:131,my_identsystem:87,my_number_handl:51,my_object:29,my_port:40,my_portal_plugin:40,my_script:102,my_server_plugin:40,my_servic:40,myaccount:112,myapp:86,myarx:9,myattr:[11,144],myawesomegam:67,mybot:164,mycallable1:51,mycar2:87,mychair:112,mychan:34,mychannel1:164,mychannel2:164,mychannel:[12,164],mycharact:81,mychargen:51,myclass:60,mycmd:[33,68,267],mycmdset:[5,31,33],mycommand1:31,mycommand2:31,mycommand3:31,mycommand:[30,31,33,83,342],mycommandtest:342,mycompon:137,myconf:36,mycontrib:127,mycss:137,mycssdiv:137,mycustom_protocol:40,mycustomcli:40,mycustomview:135,mydatastor:86,mydhaccount:100,mydhaccountt:100,mydhacct:100,myevennia:72,myevilcmdset:[31,152],myevmenu:51,myfix:131,myfunc:[10,115,127,344],myfunct:51,mygam:[2,3,5,6,9,13,14,21,23,25,26,27,30,31,35,38,40,42,44,47,49,51,53,54,56,57,58,60,62,63,65,67,69,71,73,74,75,76,80,81,82,85,86,89,90,93,95,96,100,102,104,106,109,110,111,114,116,118,119,120,121,123,125,127,128,131,133,134,135,136,137,292,342,344],mygamedir:38,mygamegam:81,myglobaleconomi:102,mygotocal:51,mygrapevin:164,myhandl:107,myhdaccount:100,myhousetypeclass:159,myinstanc:86,myircchan:164,mykwarg:51,mylayout:137,mylink:38,mylist2:11,mylist:[6,11,97,318],mylog:27,mymenu:51,mymethod:56,mymodul:115,mymud:[8,106],mymudgam:90,mynam:100,mynestedlist:325,mynod:51,mynoinputcommand:33,mynpc:123,myobj1:112,myobj2:112,myobj:[11,27,80,102,159,261],myobject:[5,11],myobjectcommand:25,myothercmdset:31,myownfactori:40,myownprototyp:109,mypath:127,myplugin:137,myproc:40,myproc_en:40,myprotfunc:109,myroom:[56,102,112,159],myros:89,myscript:[102,112,125],myscriptpath:102,myservic:40,mysess:105,mysql:[36,55,64,128,344,364],mysqlclient:23,myst:364,mysteri:[75,87],mytag1:137,mytag2:137,mythic:122,mytick:261,mytickerhandl:261,mytickerpool:261,mytop:20,mytup1:11,mytup:11,myvar:33,myview:135,naccount:308,naiv:[154,175,239,318],nake:33,name1:159,name2:159,name:[0,2,3,4,5,6,9,10,11,13,14,15,19,20,22,23,24,25,29,31,33,34,36,38,40,41,42,43,44,46,47,49,51,52,53,54,55,56,57,58,59,60,61,62,64,65,66,67,68,69,71,72,73,74,75,76,79,80,81,82,83,84,85,86,87,89,90,91,93,95,96,100,102,103,104,105,106,107,109,110,111,112,113,114,116,117,119,121,123,125,126,127,128,130,131,132,133,134,135,136,137,138,139,140,141,144,146,147,148,150,151,152,153,154,156,157,159,164,165,166,167,168,169,170,171,175,176,177,238,239,245,246,247,251,252,255,256,257,259,261,267,270,272,273,274,276,277,279,284,287,290,291,294,295,296,299,308,310,312,316,317,318,319,321,322,323,324,326,327,328,329,334,335,337,338,340,341,342,343,344,345,349,357,364],nameerror:[42,95],namesak:97,namespac:[69,125,137,252,310,322],napoleon:38,narg:114,narrow:91,nativ:[34,38,42,51,88,102,310,312],nattempt:51,nattribut:[11,51,116,125,159,245,252,306,316,318,324,328],nattributehandl:316,nattributeproperti:316,natur:[11,15,27,55,79,88,112,146,330],natural_height:330,natural_kei:316,natural_width:330,navig:[9,38,48,49,51,106,111,128,133,134],naw:[24,52,141,142,262,275,364],nbsp:343,nchar:120,nclient:298,ncolumn:330,ncurs:141,ndb:[6,13,22,25,29,33,51,102,105,116,125,144,148,169,246,256,306,318,328,364],ndb_:[109,159,252],ndb_del:306,ndb_get:306,ndb_set:306,ndk:75,nearbi:[119,152,153,154],nearli:321,neat:[0,3,138,357],neatli:[108,344],necess:[40,95],necessari:[0,4,22,36,39,40,51,57,58,59,61,77,91,108,110,114,118,121,125,131,138,153,154,177,251,252,296,322,328,330,338,340,344],necessarili:[38,41,57,88,90,109,344],necessit:309,neck:109,need:[1,2,3,4,5,6,8,9,10,11,13,14,15,19,20,21,22,23,25,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,42,44,45,46,48,49,50,51,54,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,79,80,81,82,83,84,85,86,87,88,89,90,91,93,95,96,97,98,100,102,103,104,105,106,109,110,111,112,113,114,115,116,117,118,119,121,122,123,124,125,126,127,128,130,131,133,134,135,136,137,138,140,144,146,147,148,152,154,156,159,164,165,167,175,242,246,247,251,252,255,267,269,272,276,284,291,296,298,306,307,308,312,316,318,319,321,322,324,328,329,330,331,338,339,341,342,344,364],need_gamedir:267,neg:[62,126,152,326,344],negat:[114,119,242],negoti:[55,281,283,285,294,308],negotiate_s:283,neighbor:39,neither:[11,54,61,73,97,110,166,251,291,316,319,328,345],nenter:51,nest:[11,14,33,51,114,144,159,241,247,252,291,325,364],nested_mut:11,nested_r:159,nestl:111,net:[9,57,63,72,79,90,146,164,171,280,281,291,294,308],netrc:131,network:[40,53,55,64,65,70,71,72,79,90,103,113,139,146,164,278,279,284,305,308],never:[12,14,26,27,31,33,51,54,56,60,61,62,64,80,86,88,91,95,96,104,114,115,118,119,121,125,127,131,133,144,169,242,247,306,316,325,344],nevertheless:[26,51,86,126,156],new_alias:[154,245],new_attrobj:316,new_channel:[58,164],new_datastor:86,new_destin:245,new_goto:328,new_hom:245,new_kei:[107,154,245,247,255],new_loc:[159,245],new_lock:[245,255],new_nam:[107,159],new_name2:159,new_obj:[80,247,252,255],new_obj_lockstr:159,new_object:[109,252],new_permiss:245,new_raw_str:151,new_room_lockstr:159,new_ros:89,new_script:102,new_typeclass:[144,318],new_typeclass_path:125,new_valu:[84,316],new_word:344,newbi:[25,48,55,124],newcom:[96,117],newer:9,newli:[46,58,60,66,131,133,147,159,175,176,238,245,247,252,259,324],newlin:[33,137,166,322,330],newnam:[33,159,318],newpassword:157,newstr:137,nexist:22,nexit:[120,127],next:[0,4,5,6,9,10,11,12,13,14,20,21,22,23,25,28,29,30,31,33,36,38,39,41,42,46,49,50,51,52,56,58,60,61,62,64,65,68,72,73,75,76,77,79,80,81,83,85,86,89,90,95,96,98,100,102,103,106,110,111,114,116,119,121,122,123,127,131,133,134,137,138,242,267,322,328,329,331,344,364],next_nod:51,nextnod:328,nextnodenam:328,nextrpi:79,nexu:45,nfkc:144,ng2:330,nginx:8,nice:[0,12,22,27,49,54,58,61,62,68,70,81,90,96,100,111,119,127,138,140,251,364],nicer:[20,60,96],niceti:159,nick:[2,11,43,45,57,74,79,89,129,139,144,146,159,164,165,175,246,247,279,316,317,364],nick_typ:87,nickhandl:[11,87,316],nicklist:[146,164,279],nicknam:[43,87,89,129,131,165,246,247,279,316,317],nickreplac:316,nicktemplateinvalid:316,nicktyp:247,nifti:8,night:[58,61,132,138],nine:66,nineti:345,nit:[60,62],nline:337,no_act:328,no_channel:[31,33,152,328],no_db:[251,252],no_default:[125,144,318],no_exit:[31,33,116,152,328],no_gmcp:291,no_log:153,no_mccp:280,no_msdp:291,no_mssp:281,no_mxp:282,no_naw:283,no_obj:[31,152,328],no_prefix:[144,154,156,157,158,159,164,165,166,167,168,169,170,171,175,247,298,326,328,329],no_superuser_bypass:[144,175,242,247,318],no_tel:80,noansi:342,nobj:120,nocaptcha:133,nocaptcha_recaptcha:133,nocolor:[81,272,287,290,295,296],nodaemon:106,node1:[51,328],node2:[51,328],node3:[51,328],node:[13,85,109,249,265,328,364],node_abort:51,node_apply_diff:249,node_attack:51,node_background:51,node_betrayal_background:51,node_border_char:328,node_destin:249,node_examine_ent:249,node_exit:51,node_formatt:[51,328],node_four:51,node_game_index_field:265,node_game_index_start:265,node_hom:249,node_index:[249,328],node_kei:249,node_loc:249,node_login:51,node_matching_the_choic:51,node_mssp_start:265,node_mylist:51,node_on:51,node_parse_input:51,node_password:51,node_prototype_desc:249,node_prototype_kei:249,node_prototype_sav:249,node_prototype_spawn:249,node_readus:51,node_select:51,node_set_nam:51,node_start:265,node_test:51,node_text:51,node_usernam:51,node_validate_prototyp:249,node_view_and_apply_set:265,node_view_sheet:51,node_violent_background:51,node_with_other_nam:328,nodefunc1:51,nodefunc2:51,nodefunc:328,nodekei:328,nodenam:[51,328],nodename_to_goto:51,nodestartfunc:51,nodetext:[51,249,328],nodetext_formatt:[51,249,328],noecho:169,noerror:247,nofound_str:[144,247,344],nogoahead:289,nohom:[245,324],nois:21,noisi:[90,264,269,277,287,290,298,312],noloc:159,nomarkup:[74,81],nomatch:[22,168,326,344],nomatch_exit:22,nomatch_single_exit:22,nomigr:127,non:[4,6,14,15,20,22,27,29,31,33,38,44,49,50,52,55,58,61,62,63,64,65,68,70,74,82,86,88,102,105,109,110,114,122,124,125,126,131,137,139,140,144,146,147,148,150,152,164,169,171,175,177,238,241,245,246,247,250,251,252,256,257,259,261,267,276,290,291,305,306,308,316,318,321,324,325,326,328,329,330,341,344,364],nonc:295,nondatabas:[11,306,318],none:[0,1,2,10,11,13,14,15,22,25,30,31,33,34,39,40,41,42,44,49,50,51,56,58,60,62,64,69,74,77,80,81,83,84,85,86,87,88,91,96,102,105,111,112,114,116,118,119,121,123,144,146,147,150,151,152,153,154,156,159,160,161,162,163,164,165,166,167,170,175,176,177,238,241,242,245,246,247,249,251,252,255,257,258,260,261,264,265,267,269,271,273,276,277,278,279,286,287,295,296,298,306,307,308,310,311,312,316,317,318,319,321,322,323,324,325,326,327,328,329,330,331,334,337,339,340,341,342,344,345,349,352,357],nonpc:123,noon:[20,60,73,76,80,96],nop:[290,364],nopkeepal:[24,290],nor:[11,13,29,31,42,54,106,108,116,126,247,251,291,316,319],norecapcha:133,norecaptcha_secret_kei:133,norecaptcha_site_kei:133,norecaptchafield:133,normal:[2,3,5,6,9,10,11,13,14,15,19,20,21,23,25,27,29,30,31,33,34,38,44,46,49,51,55,56,57,58,60,62,64,66,68,69,72,74,75,76,80,81,82,83,85,86,87,88,90,93,96,97,100,102,104,105,109,110,111,112,113,114,116,119,121,122,123,125,126,127,128,134,135,137,138,140,144,146,148,150,151,152,153,154,156,159,166,169,175,246,247,249,252,261,267,276,279,280,281,283,285,299,306,308,314,316,317,318,321,322,325,328,329,334,341,342,343,344,346],normal_turn_end:116,normalize_nam:247,normalize_usernam:144,north:[0,20,22,44,46,49,89,111,114,121,159,299],north_south:111,northeast:[20,159],northern:[22,111],northwest:159,nose:316,not_don:312,not_error:267,not_found:159,notabl:[6,9,10,40,63,97,131,154,159,170,271,318,321,325,344],notat:[119,159,321,344],notdatabas:125,note:[0,1,2,4,5,6,9,11,12,13,19,20,21,23,24,25,27,29,41,42,43,48,49,57,58,59,60,61,62,63,64,69,70,73,74,75,76,80,83,85,86,88,89,90,93,95,96,100,102,103,105,106,107,109,110,113,114,115,116,117,119,121,123,124,125,126,128,130,131,133,134,135,136,137,141,144,146,147,151,152,153,154,156,159,160,161,164,165,166,167,169,170,171,175,176,238,241,242,245,246,247,251,252,255,261,264,267,272,276,277,279,280,284,285,286,287,290,291,292,294,295,298,300,301,306,308,312,313,316,317,318,319,321,322,323,324,325,326,327,328,329,330,331,334,337,339,340,341,342,344,347,364],notepad:63,noteworthi:38,notfound:344,notgm:58,noth:[0,10,11,14,20,22,27,29,33,34,42,56,57,60,62,83,85,89,95,108,111,115,116,127,144,159,168,247,259,279,316,318,328],nother:120,notic:[0,10,12,13,20,22,23,29,33,36,37,39,41,42,46,62,69,70,91,96,117,121,126,127,131,280],notif:[4,75,131,137,138],notifi:[98,251],notificationsconfig:4,notimplementederror:290,notion:[62,115,116],now:[0,2,3,5,6,9,10,11,12,14,20,21,22,23,25,27,28,29,31,33,36,39,41,46,48,49,51,55,56,57,58,60,61,62,63,64,65,67,69,71,72,73,75,76,77,79,80,81,82,83,85,86,89,90,91,95,96,97,98,100,102,103,105,106,108,109,110,111,114,115,117,118,119,121,123,125,126,127,128,131,133,134,135,136,137,138,140,153,164,166,242,247,279,287,308,340,342,344],nowher:[95,111],noxterm256:290,npc:[9,33,46,51,61,64,73,111,119,124,139,241,364],npcname:118,npcshop:85,nprot:120,nr_start:258,nroom:[22,120],nroom_desc:127,nrow:330,ntf:63,nuanc:114,nudg:[78,312],nuisanc:103,nulla:52,num:[49,80,247],num_lines_to_append:337,num_object:119,num_objects__gt:119,num_tag:119,num_total_account:147,number:[0,6,10,11,12,13,20,21,23,25,26,27,31,33,34,36,38,41,49,50,51,57,58,60,61,62,64,71,73,77,81,85,87,90,93,95,96,97,98,100,102,104,105,107,111,112,114,115,116,119,120,122,123,125,127,131,134,135,140,141,144,146,147,151,152,153,157,159,164,165,166,176,177,245,247,251,252,255,258,265,267,272,278,279,281,285,298,299,308,310,312,316,317,319,321,322,324,326,328,329,330,331,334,337,341,344,357,364],number_of_dummi:267,number_tweet_output:120,numbertweetoutput:120,numer:[61,73,97,321],numpi:300,o_o:138,obj1:[11,80,97,109,159],obj2:[11,80,97,109,127,159,322],obj3:[11,109,159],obj4:11,obj5:11,obj:[2,6,10,11,22,25,27,31,33,41,42,48,56,58,59,60,80,82,84,86,87,89,91,96,102,109,112,115,117,119,121,125,127,139,144,152,153,154,157,159,165,167,169,170,176,177,241,242,245,246,247,252,255,256,257,258,296,298,299,306,316,317,318,319,322,324,325,329,339,340,341,342,344],obj_prototyp:252,obj_to_chang:125,objattr:241,objclass:[334,344],object1:33,object2:[33,247],object:[0,2,9,10,12,13,14,15,18,19,21,22,23,26,29,30,31,33,34,36,38,39,40,41,42,43,44,45,46,47,49,50,51,52,53,55,56,57,58,62,69,73,74,77,79,81,83,84,85,86,87,88,91,93,95,102,103,104,107,108,109,110,114,115,116,117,118,120,122,123,125,127,129,132,133,134,135,137,138,139,140,141,142,143,144,146,147,148,150,151,152,153,154,156,157,158,159,160,161,164,165,166,167,169,170,171,175,176,177,178,229,238,239,241,242,249,250,251,252,253,255,256,257,258,259,260,261,265,267,269,271,272,273,274,276,277,280,281,282,283,284,285,286,287,289,291,294,296,298,299,305,306,307,308,310,311,312,316,317,318,319,321,322,323,324,325,326,327,328,329,330,334,335,338,339,340,341,342,343,344,345,349,351,357,360,364],object_from_modul:344,object_id:134,object_search:[134,245],object_subscription_set:246,object_tot:[147,245,255,317],object_typ:159,object_typeclass:[342,360],objectcr:357,objectdb:[11,53,59,96,112,119,120,125,133,141,245,246,247,252,314,316,324,329,341],objectdb_set:[148,316,319],objectdbmanag:[245,246],objectdoesnotexist:[148,177,239,246,256,274,316,319,335],objectform:357,objectmanag:[245,247,317],objectnam:[6,58],objects_objectdb:86,objectsessionhandl:[2,247],objectupd:357,objid:80,objlist:109,objlocattr:241,objmanip:159,objmanipcommand:159,objnam:[27,125,159],objparam:252,objs2:112,objsparam:252,objtag:241,objtyp:176,obnoxi:269,obs:318,obscur:[48,72,82],observ:[13,14,20,81,88,159,165,291,322,344],obtain:[0,33,39,63,77,90,91,93,100,364],obviou:[0,59,61,103,121,128,138],obvious:[0,4,14,49,55,105,108,121,319],occaecat:52,occas:128,occasion:[90,119],occation:330,occur:[9,10,25,33,42,57,60,102,137,168,242,247,260,299,328,337],occurr:[46,91,123,321],ocean:[90,122],oct:364,octob:364,ocw:124,odd:[22,49,61,103,126],odor:58,off:[0,11,14,20,23,24,29,31,33,36,40,41,49,50,51,55,61,64,66,74,80,81,86,88,90,100,103,107,108,110,114,115,123,126,135,138,139,144,154,169,170,171,175,176,242,247,272,280,287,290,306,318,321,322,324,326,328,329,330,337,345,364],off_bal:29,offend:12,offer:[1,4,11,14,22,26,28,31,33,34,37,39,40,44,50,51,55,56,57,59,62,64,72,73,74,76,83,86,87,89,90,91,96,102,106,108,109,111,114,115,116,123,124,127,128,129,131,132,137,138,144,152,153,158,159,166,169,249,257,308,328],offici:[38,72,100,103,127,131,337,364],officia:52,offlin:[9,15,79,90,109,158,164,322],offscreen:9,offset:[326,337],often:[2,5,10,11,15,22,26,28,31,33,38,40,41,42,46,48,49,51,57,59,61,62,64,76,86,88,90,91,93,95,96,97,102,103,104,105,112,114,115,116,119,128,131,146,152,157,159,167,169,175,176,242,246,256,258,267,272,286,306,316,318,322,324,330,337,344],ohloh:37,okai:[41,42,48,49,51,58,75,77,111,123,128],olc:[43,47,159,249,252,364],olcmenu:249,old:[0,1,5,9,21,25,27,31,38,39,50,51,55,56,58,60,63,80,81,85,88,90,105,106,111,114,122,123,125,126,128,138,144,152,153,156,159,176,242,247,252,276,317,318,321,324,363],old_default_set:127,old_kei:[107,247],old_nam:107,older:[2,9,24,55,63,64,79,105,159],oldnam:318,oliv:114,omiss:60,omit:[91,100,109],on_bad_request:269,on_ent:22,on_leav:22,on_nomatch:22,onam:245,onbeforeunload:[83,137],onbuild:100,onc:[0,2,5,6,9,10,13,16,21,22,23,25,33,34,37,38,39,40,41,42,46,47,49,51,55,57,58,60,61,62,63,64,67,72,79,80,83,85,89,90,93,95,96,97,100,102,105,108,114,116,119,121,122,125,126,128,131,133,137,144,146,151,154,159,164,167,170,175,247,251,256,259,272,277,290,294,305,316,321,328,329,337,342,344],onclos:[40,278,295],onconnectionclos:[83,137],oncustomfunc:83,ond:319,ondefault:83,one:[0,1,2,3,4,5,9,10,11,12,13,14,15,16,19,20,21,22,23,25,26,27,28,29,31,33,34,35,36,37,41,42,44,46,47,48,49,50,51,52,54,55,56,57,58,59,60,61,62,63,64,65,67,68,69,70,72,73,74,76,77,79,80,81,82,83,85,86,87,88,89,90,91,92,93,95,96,97,98,100,102,103,104,105,106,108,109,111,112,113,114,115,116,118,119,121,122,123,125,126,127,128,131,132,133,134,135,136,137,138,140,143,144,148,151,152,153,154,156,157,159,164,165,168,169,170,175,176,177,238,239,241,242,245,246,247,249,250,251,252,255,256,261,267,269,271,272,277,278,279,287,290,291,299,306,307,308,312,314,316,317,318,319,321,322,324,325,327,328,329,330,331,334,335,337,339,340,341,342,344,345,357,360,364],ones:[4,9,14,20,22,27,31,33,43,57,58,65,72,74,80,81,83,90,95,100,103,109,114,116,126,127,135,152,153,154,177,251,252,271,276,308,321,330,338],onewai:159,ongo:[28,91,116],ongotopt:[83,137],onkeydown:[83,137],onli:[0,2,4,5,6,9,10,11,12,13,14,15,19,20,21,22,24,25,26,27,28,29,31,33,34,37,39,40,41,42,44,46,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,67,68,69,71,72,73,74,77,79,80,81,82,83,85,86,87,88,89,90,91,93,95,96,100,102,103,104,105,106,107,109,111,112,114,116,117,118,119,121,122,123,124,125,126,127,130,131,132,133,134,135,136,137,138,140,141,144,146,147,150,151,152,153,154,156,157,158,159,164,165,166,167,168,169,170,171,175,176,177,239,241,242,245,247,251,252,255,256,257,259,260,261,267,271,272,279,282,284,285,287,290,299,305,306,308,310,311,312,316,317,318,319,321,322,323,324,326,328,329,330,334,337,339,340,341,342,344,357,364],onlin:[7,12,15,21,37,41,55,57,58,60,61,64,65,68,69,70,71,73,77,79,89,96,98,101,104,108,116,123,128,129,139,141,156,164,175,177,281,322,364],onloggedin:[83,137],onlook:247,only_tim:[255,341],only_valid:252,onmessag:[40,278,295],onopen:[40,278,295],onoptionsui:137,onprompt:[83,137],onsend:[83,137],onset:[5,11],onsil:83,ontabcr:137,ontext:[83,137],onto:[25,31,33,44,55,60,61,72,90,95,121,137,153,164,246,279,325,328],onunknowncmd:137,onward:107,oob:[24,30,33,45,83,104,137,138,139,144,146,166,247,272,290,291,295,296,308,328,364],oobfunc:104,oobhandl:334,oobobject:102,ooc:[2,43,53,58,102,105,114,123,144,148,156,159,160,167,177,247],ooclook:105,opaqu:[15,103],open:[0,3,4,5,9,20,22,23,26,31,34,37,38,42,43,46,50,55,57,58,60,63,64,65,67,69,70,71,72,73,75,79,80,90,95,96,103,105,106,111,114,116,123,130,131,133,134,138,159,166,169,176,310,316,324,337,344,363,364],open_submenu:22,openhatch:79,opensoci:70,opensourc:321,oper:[9,11,12,14,22,27,33,41,42,46,51,57,59,60,61,63,64,67,72,74,80,82,88,89,90,95,96,97,102,109,110,112,115,119,124,126,131,137,139,144,147,150,152,154,156,159,164,169,175,242,247,252,261,264,267,276,277,281,283,287,289,290,296,298,299,306,307,316,317,318,321,324,328,329,330,334,342,344,364],opic:170,opinion:[1,48],opnli:316,oppon:[11,73],opportun:[0,4,22,91,133],oppos:[27,89,103,110,114,306,319],opposit:[41,58,111,121,159],opt:[58,137],optim:[23,27,33,34,39,56,64,86,93,115,119,154,175,251,252,302,305,316],option100:51,option10:51,option11:51,option12:51,option13:51,option14:51,option1:51,option2:51,option3:51,option4:51,option5:51,option6:51,option7:51,option8:51,option9:51,option:[2,4,7,8,10,11,17,20,23,24,25,27,29,31,33,34,36,38,41,42,43,47,50,54,55,57,62,63,64,74,76,79,80,81,83,85,86,96,100,102,104,106,108,109,111,112,113,114,116,117,123,127,129,133,134,135,137,138,139,141,144,146,147,150,151,152,153,154,156,157,159,164,166,167,170,171,175,176,177,238,241,242,245,246,247,249,251,252,255,256,257,258,259,260,261,264,265,267,269,272,273,276,277,279,280,281,282,283,284,285,286,287,289,290,291,294,295,296,298,299,306,308,310,316,317,318,319,321,322,323,324,326,327,328,329,330,331,334,337,338,339,340,341,342,343,344,345,349,350,364],option_class:[141,323],option_dict:328,option_gener:328,option_kei:345,option_typ:339,option_valu:339,optiona:[144,264,318],optionalposit:1,optionclass:[141,142,320,323,364],optioncontain:323,optionhandl:[141,142,320,338,364],optionlist:[51,249,328],options2:137,options_dict:339,options_formatt:[51,249,328],optionsl:251,optionstext:[51,328],oracl:[23,344],orang:[114,321],orc:[57,61,109,117],orc_shaman:109,orchestr:100,order:[0,2,5,6,9,10,11,13,14,22,27,31,33,36,37,39,44,49,50,51,58,60,61,62,63,64,68,69,70,71,80,84,87,89,93,100,102,104,109,111,113,114,116,119,121,122,123,126,127,128,131,133,134,136,137,138,144,150,153,154,160,165,166,169,170,241,242,245,247,252,278,290,295,299,306,316,318,321,322,328,329,330,337,341,342,344],order_bi:119,ordered_plugin:83,ordereddict:[11,344],ordin:321,org:[37,38,90,283,289,295,321,344,357],organ:[5,6,9,22,38,69,73,80,89,102,108,111,112,119,124,129,131,132,154,166,170],organiz:102,orient:[55,57,64,96,124],origin:[0,4,9,21,25,29,41,49,51,55,57,60,75,76,79,81,89,91,96,102,103,105,106,119,131,136,138,144,146,152,159,245,247,251,252,255,276,310,318,321,328,340,343,344,363],original_object:245,original_script:255,ormal:321,oscar:[154,175,239,318],osnam:344,oss:106,ostr:[144,147,176,238,245,255,341],osx:[63,131],other:[0,1,2,4,5,6,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,25,27,28,29,31,34,36,37,38,39,40,41,44,46,47,48,49,50,51,53,55,57,58,59,60,61,62,63,64,65,68,69,70,71,73,74,76,80,81,82,83,85,86,87,88,89,91,95,96,97,100,102,103,105,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,123,124,125,126,127,128,131,133,134,135,136,137,138,139,140,144,147,150,151,152,153,154,159,164,165,166,167,170,171,175,176,239,242,246,247,251,252,257,259,261,265,267,272,276,278,279,285,287,290,299,306,307,309,316,318,320,321,322,324,326,327,328,329,330,338,339,341,342,344,345,364],otherwis:[0,4,11,15,23,25,27,29,31,33,37,39,41,42,51,59,62,68,69,76,78,83,86,89,90,91,95,97,100,102,103,105,109,114,121,123,131,135,141,147,151,152,156,159,164,175,242,247,250,251,252,260,267,278,279,287,306,310,311,321,328,329,337,341,342,344],otypeclass_path:245,our:[2,3,4,8,9,11,14,16,20,21,23,25,26,30,31,33,36,37,38,39,40,41,42,43,44,46,49,55,57,58,59,60,61,62,63,64,67,70,72,73,75,77,78,79,80,81,82,83,85,88,90,91,98,100,101,103,111,115,116,117,119,123,124,127,128,129,131,132,134,135,136,137,138,140,148,153,167,177,242,257,312,337,363,364],ourself:123,ourselv:[0,20,58,80,87,118,132,138,144,280,281,283,294],out:[0,1,3,6,8,9,10,12,13,14,15,16,17,19,20,21,22,23,26,28,29,33,34,37,38,39,41,42,44,45,46,47,48,49,51,53,54,55,56,57,59,60,61,62,63,64,66,69,70,71,77,79,80,86,88,89,90,91,93,95,96,97,100,102,104,105,108,109,111,114,116,117,118,119,121,122,123,126,127,129,131,133,135,137,138,139,143,144,151,152,156,158,159,164,251,252,259,267,269,291,295,296,298,307,308,316,325,327,328,330,343,344,357,364],outcom:[38,73,86,152,242,247,251],outdat:8,outdata:[40,308],outdoor:[112,119,122,132],outer:330,outermost:[11,29,74],outfunc_nam:40,outgo:[67,88,90,96,105,146,247,279,291,307,344,364],outgoing_port:90,outlet:90,outlin:[36,43,111,133,278],outmessag:247,output:[4,14,20,22,26,27,34,40,51,52,58,74,79,88,91,95,96,100,105,106,108,110,111,113,114,116,120,121,123,126,128,129,135,137,138,141,142,154,164,166,169,171,178,207,208,247,267,272,287,291,299,306,321,328,329,337,340,342,344,364],outputcmd:291,outputcommand:[74,83,364],outputfunc:[40,59,83,247,272,278,364],outputfunc_nam:[40,272],outputfunct:83,outrank:317,outright:[12,90,363],outro:122,outsid:[0,13,15,20,21,38,39,57,64,67,73,88,96,100,104,108,109,110,112,121,134,166,241,291,306,307,316,319,330,364],outtempl:316,outtxt:27,outward:[49,90],over:[1,6,8,11,13,14,15,16,17,27,28,31,33,34,36,37,38,39,40,45,48,49,51,54,57,58,59,60,61,73,77,81,83,85,88,90,93,96,97,100,103,105,108,111,112,113,114,115,116,118,119,125,126,127,128,129,133,136,137,138,144,153,176,247,261,271,285,287,290,292,296,298,300,313,318,322,334,340,363],overal:[10,56,57,68,71,86,90,152,167,364],overcom:111,overhead:[23,27,34,113,132,316],overlap:[31,62,321,330],overload:[5,22,30,31,33,40,44,47,51,55,57,60,74,76,89,96,97,104,114,115,117,123,136,144,152,154,168,175,247,252,261,271,290,298,307,326,328,329,330,338,364],overrid:[1,3,4,9,20,21,22,25,31,36,51,53,54,68,69,80,83,91,96,102,105,107,109,117,118,121,135,137,144,154,159,164,166,170,175,176,242,247,251,252,259,290,308,312,316,321,328,329,334,337,338,341,364],overridden:[4,40,96,136,138,144,159,251,318,329],override_set:107,overriden:[144,166],overrod:16,overrul:[2,80,144,153,247,330],overseen:73,overshadow:61,overshoot:344,oversight:57,overview:[15,16,18,23,45,46,57,68,77,96,103,139,364],overwhelm:[46,61],overwrit:[5,76,136,138,159,166,285,317],overwritten:[33,134,319],owasp:357,own:[1,3,4,5,6,8,9,10,11,13,17,19,20,21,22,25,26,27,29,30,31,34,37,38,41,43,45,47,51,55,57,61,62,63,64,67,68,71,72,75,76,77,78,80,81,83,85,86,87,88,91,93,95,96,98,101,102,103,104,105,107,108,109,111,112,114,119,121,122,123,124,125,127,128,129,131,132,133,134,135,136,138,139,148,150,151,152,153,159,167,241,242,247,252,272,299,307,318,321,322,323,329,330,334,337,338,342,344,364],owner:[4,19,80,85,144,242,338],owner_object:80,ownership:[90,100],oxford:344,p_id:133,pace:122,pack:[83,276],packag:[8,9,23,38,41,47,63,64,72,75,78,88,90,93,96,97,100,108,127,128,135,141,143,149,155,172,178,236,240,243,253,262,267,276,291,295,314,320,346],package_nam:64,packagenam:64,packed_data:276,packeddict:[97,318],packedlist:[97,318],packet:[83,287],pad:[17,114,321,330,344],pad_bottom:330,pad_char:330,pad_left:330,pad_right:330,pad_top:330,pad_width:330,page:[7,8,9,12,13,14,16,17,20,21,23,25,26,28,31,33,36,37,38,40,43,45,48,51,52,55,57,58,59,60,61,64,67,70,72,73,75,76,77,79,80,81,88,89,90,94,96,99,100,101,103,104,106,108,110,124,125,126,127,129,130,131,133,134,137,138,139,154,159,164,165,175,239,251,296,318,328,329,344,346,347,355,361,363,364],page_back:329,page_ban:[12,164],page_end:329,page_formatt:[251,329],page_next:329,page_quit:329,page_top:329,pageno:[251,329],pager:[52,139,329],pages:[51,328],pagin:[251,329],paginag:329,paginated_db_queri:251,paginator_django:329,paginator_index:329,paginator_slic:329,pai:[56,85,90,103],paid:90,pain:[90,138],painstakingli:13,pair:[31,83,116,137,138,144,152,241,247,308,357],pal:87,palett:126,pallet:111,pane:[88,137,138,171],panel:[67,106],panic:109,paper:[61,79,116],paperback:73,par:23,paradigm:[9,61,118],paragraph:[14,27,322,330,344],parallel:[57,62,69,317],param:[67,159,247,261,269,279,312,343],paramat:[144,154,247,306],paramet:[0,22,24,31,36,39,42,46,49,62,91,100,106,119,127,141,144,146,147,150,151,152,153,154,164,166,175,176,177,238,239,242,245,246,247,249,251,252,255,257,258,259,260,261,264,265,266,267,269,271,272,273,274,276,277,278,279,280,281,282,283,284,285,286,287,289,290,291,292,294,295,296,298,304,305,306,307,308,310,311,312,316,317,318,319,321,322,323,324,325,326,327,328,329,330,331,334,337,338,339,341,342,343,344,345,349],paramount:127,paramt:345,paremt:252,parent1:109,parent2:109,parent:[2,6,22,25,27,31,33,38,40,43,44,60,64,81,89,96,109,114,118,121,123,125,140,148,156,159,167,169,246,247,251,252,256,316,317,318,326,335,337,342,344,364],parent_kei:22,parenthes:95,pari:[79,90],pariatur:52,paricular:33,parlanc:3,parri:116,parrot:118,pars:[3,15,31,33,38,40,50,51,63,81,83,88,97,104,108,109,114,123,124,129,134,139,149,150,151,154,159,165,166,167,169,170,242,247,250,251,252,272,279,282,291,295,296,298,308,316,321,322,326,327,328,342,343,344,364],parse_ansi:321,parse_ansi_to_irc:279,parse_fil:322,parse_html:343,parse_input:328,parse_irc_to_ansi:279,parse_menu_templ:[51,328],parse_nick_templ:316,parseabl:251,parsed_str:279,parser:[33,38,41,47,79,104,108,109,134,150,151,156,159,166,167,169,171,251,286,321,343],parsingerror:344,part:[1,4,5,9,11,13,14,15,16,20,22,23,26,29,33,36,37,38,39,40,41,42,44,45,46,48,49,51,57,58,60,61,68,69,70,73,76,80,85,86,88,90,91,92,95,102,105,106,111,114,116,117,119,122,123,124,125,127,131,135,136,137,138,139,140,151,152,154,164,167,168,170,175,238,241,242,250,251,259,267,271,296,298,307,310,312,316,317,321,322,326,328,342,344,364],parth:292,parti:[8,9,13,23,27,37,42,64,72,75,90,101,114,128,134,177,364],partial:[25,68,164,166,245,251,269,282,308,339,341,344,345],particip:[41,103],particular:[5,8,12,13,14,20,22,28,31,38,40,41,44,48,58,59,64,68,70,72,74,75,79,80,83,85,88,89,93,96,97,104,105,107,112,113,114,118,119,121,124,125,131,132,135,139,144,147,151,152,159,176,238,241,242,255,256,308,310,318,334,341],particularli:[0,4,12,38,39,51,55,127,154,167,170,252,271],partit:321,partli:[11,31,47,86,129,152],pass:[4,10,21,23,25,27,28,29,30,33,36,40,49,51,52,62,69,74,80,82,83,85,88,90,91,95,96,100,102,105,107,109,110,111,115,117,119,121,125,127,130,134,138,139,144,146,152,164,171,175,241,242,247,250,251,257,260,261,265,267,277,285,287,290,295,296,306,312,316,318,319,327,328,329,330,331,337,338,339,340,342,343,344],passag:[83,116,331],passant:126,passavataridterminalrealm:287,passiv:[29,116,133],passthrough:[1,31,259],password1:357,password2:357,password:[4,9,12,23,35,36,43,51,64,74,80,103,131,139,144,147,156,157,171,272,287,290,311,324,349,357],password_chang:360,passwordresettest:360,past:[0,13,20,26,37,46,50,58,62,69,96,104,108,111,116,123,133,137,147,313,322,331],pastebin:37,pat:245,patch:[125,342,364],patch_:37,path:[0,2,4,8,14,20,21,22,27,29,38,39,40,45,48,51,59,60,63,64,66,67,69,74,80,85,86,88,89,90,95,96,100,102,105,106,109,114,117,118,119,121,123,124,125,134,135,136,138,139,144,146,148,151,152,153,154,158,159,160,161,162,163,164,175,177,239,245,246,247,251,252,255,256,258,259,261,267,274,276,285,292,298,300,304,308,312,316,317,318,322,324,326,327,328,329,331,334,335,341,344,364],pathnam:342,patient:[20,70],patreon:70,patron:[37,70],pattern:[3,4,16,51,69,87,127,133,134,135,140,157,311,316,344],pattern_is_regex:316,paul:125,paus:[10,39,46,51,100,102,110,116,159,169,259,260,328,342,344,364],pausabl:344,pauseproduc:269,pax:364,paxboard:79,payload:[278,295],paypal:[37,70],paypalobject:70,pdb:[139,141,364],pdbref:[80,241],pdf:79,peac:117,peek:[20,26,51,91],peer:[278,295],peform:272,peg:103,pem:67,pemit:[108,157],penalti:86,pend:312,pennmush:[57,108,129,171],pentagon:103,peopl:[2,20,21,26,37,54,55,58,61,64,68,71,72,73,79,80,81,85,90,95,96,97,103,108,114,116,119,139,164,165,176,324],pep8:26,per:[2,4,11,19,33,38,41,47,51,58,60,62,64,69,83,86,89,93,100,105,109,112,116,119,123,138,144,164,245,247,251,280,281,283,291,294,310,328,329,330,334,337,338],perceiv:62,percent:[33,344],percentag:[116,317,344],percentil:344,perception_method_test:303,perfect:[50,55,61,75,100,131],perfectli:[4,69,96,112,129,138,321],perform:[11,13,14,22,23,25,39,41,42,51,52,55,59,71,74,75,80,89,91,93,97,102,103,114,116,117,123,133,134,144,150,152,156,159,164,166,245,247,251,256,257,271,276,290,298,299,316,317,318,325,328,329,338,341,344,345,357],perhap:[16,22,42,46,62,69,77,91,97,108,138],period:[90,95,96,100,103,127,128,130,344],perist:[34,125],perm1:319,perm2:319,perm:[4,11,12,19,22,25,33,58,68,71,80,85,109,112,123,133,148,157,158,159,164,165,166,169,239,241,242,246,247,256,316,318,319,344],perm_abov:[80,241],perm_us:157,perman:[4,5,12,21,24,25,31,51,85,90,96,122,123,138,156,159,164,165,169,260,318],permiss:[2,4,7,8,9,11,12,18,20,21,23,25,31,41,45,66,68,70,71,75,93,108,109,123,133,139,144,147,148,152,154,156,157,158,159,164,165,167,175,239,241,242,245,246,247,251,252,256,316,317,318,319,322,324,337,341,344,364],permission_account_default:[80,298],permission_func_modul:241,permission_guest_default:66,permission_hierarchi:[19,80,241,242,319],permissionerror:251,permissionhandl:[133,319],permit:[41,78,159,311],permstr:[80,144,245,318,324],perpetu:[93,364],persis:29,persist:[0,6,21,22,27,31,33,34,51,55,56,57,60,64,79,84,86,89,102,104,105,109,110,115,116,121,123,125,144,148,152,153,169,176,177,239,245,246,247,249,251,255,256,257,259,260,261,272,273,274,305,306,310,314,318,324,326,328,330,331,344,364],person:[12,21,61,63,70,73,90,102,105,118,129,139,144,159,164,165,175,364],persona:96,perspect:[73,76,77,105],pertain:[103,126,136],pertin:[68,133],perus:137,peski:85,pester:[57,61],phase:[49,61],philosophi:80,phone:[16,64,75,139],php:[108,357],phrase:46,physic:[2,49],pick:[6,9,13,15,20,21,31,33,35,37,39,51,55,62,68,72,73,80,85,90,95,96,100,102,104,106,111,119,132,151,156,159,165,167,247,251,299],pickl:[11,29,83,115,257,261,264,274,276,277,316,317,325,326,328,340,344],pickle_protocol:340,pickledfield:[245,340],pickledformfield:340,pickledobject:340,pickledobjectfield:340,pickledwidget:340,picklefield:[141,142,320,364],pickpocket:166,pickup:247,pictur:[21,40,57,106,138,364],pid:[36,80,100,110,131,133,241,247,267,277,344],piddir:36,pidfil:267,piec:[10,13,59,61,64,93,122,294,322,329],piggyback:144,pile:[153,322],pillow:75,ping:[146,164,267,279],pink:[119,321],pip:[9,23,26,38,42,47,59,63,65,71,75,93,96,97,98,100,127,128,130,133,141,364],pipe:[105,279,325],pitfal:[14,26,114,126],pixel:24,pizza:[148,177,239,246,256,316,318,319],pkg:75,pki:8,place:[0,2,3,4,5,8,9,11,14,15,20,21,25,26,30,37,41,46,49,51,55,62,63,64,69,71,73,75,76,80,83,89,90,91,95,96,100,102,103,104,105,109,111,121,123,124,126,128,129,131,132,133,135,136,138,144,157,159,165,175,247,255,259,276,285,290,306,307,308,316,322,323,325,328,344,364],placehold:[134,242,247,330],plai:[0,2,11,14,19,22,29,39,46,55,58,61,64,68,73,75,81,83,90,91,95,105,111,114,116,121,122,123,124,132,133,138,144,147,291,308,324,364],plain:[13,14,38,58,86,88,123,164,175,252,272,298,325],plan:[9,14,15,40,41,42,45,55,56,90,96,100,124,125,127,139,322,364],plane:121,planet:[62,79],plate:[82,125],platform:[9,16,56,63,90,102,106,131],playabl:[133,360],player1:247,player2:247,player:[9,10,11,12,19,20,21,22,25,29,31,34,40,41,51,53,54,55,58,60,61,64,65,68,71,73,77,80,81,83,85,90,91,93,95,97,98,105,108,110,111,112,113,116,117,118,119,120,121,122,123,124,133,138,139,153,156,159,169,176,238,256,281,290,307,322,327,328,344,357,364],playernam:71,playerornpc:9,pleas:[4,5,8,16,17,26,31,37,51,63,70,71,72,75,78,90,93,109,111,114,117,118,120,124,125,127,131,133,169,269,298,334,340,357,363],pleasur:16,plenti:[14,55,60,129],plot:300,plu:[22,27,64,73,106,169],pluck:33,plug:[96,103,107,136],plugin:[4,40,45,47,53,55,72,79,83,104,108,138,265,364],plugin_handl:[83,137],plugin_manag:137,plural:[19,58,80,247],png:[70,136],po1x1jbkiv_:37,pocoo:344,point:[0,2,4,5,8,13,14,15,20,21,22,25,27,29,31,33,34,36,37,38,39,42,49,51,55,56,60,61,62,63,67,69,73,75,81,83,85,86,88,89,90,91,93,95,97,100,102,104,105,106,112,113,115,116,121,123,125,127,130,131,133,134,135,136,138,139,144,150,154,159,164,167,247,249,251,261,267,271,285,287,295,306,308,316,318,322,328,344,347,364],pointer:[26,49,56,91],pointless:[6,10,89,115,166],poison:252,poke:119,polici:[43,45,90,103,139,239,311,316,364],polit:103,poll:[40,136,156,267,296],pong:279,pool:[23,31,115,261,312,325],poor:[48,58],poorli:103,pop:[10,23,25,38,48,58,85,106,138],popen:277,popul:[22,23,36,41,57,61,62,81,124,135,138,152,160,161,162,163,247,260,261,298,322,326,327,329],popular:[9,57,64,79,103,108],popup:[137,138],port:[0,8,9,23,36,54,55,63,67,72,100,101,110,146,164,276,279,287,299,308,312,364],portal:[40,45,47,53,79,88,89,90,93,103,104,106,110,121,128,137,139,141,142,146,169,262,264,267,305,306,307,308,331,337,344,364],portal_connect:308,portal_disconnect:308,portal_disconnect_al:308,portal_l:277,portal_pid:[277,344],portal_receive_adminserver2port:277,portal_receive_launcher2port:277,portal_receive_server2port:277,portal_receive_statu:277,portal_reset_serv:308,portal_restart_serv:308,portal_run:267,portal_service_plugin_modul:40,portal_services_plugin:[40,104],portal_services_plugin_modul:40,portal_sess:40,portal_session_sync:308,portal_sessions_sync:308,portal_shutdown:308,portal_st:267,portal_uptim:331,portallogobserv:337,portalsess:[40,105,285,364],portalsessiondata:308,portalsessionhandl:[40,141,142,262,275,286,308,364],portalsessionsdata:308,portion:77,pose:[29,43,58,116,144,165],pose_transform:175,posgresql:23,posit:[13,20,22,39,49,51,91,111,116,126,127,137,138,139,153,171,247,260,321,322,325,326,330,344,345,364],positive_integ:345,positiveinteg:338,posix:[337,344],possess:[7,77],possibl:[0,5,9,10,11,22,23,25,26,31,33,34,37,38,39,46,50,55,57,58,63,64,66,73,74,75,76,80,91,93,100,102,104,105,109,111,112,114,116,123,126,127,128,131,134,136,138,141,144,147,148,150,152,159,166,167,176,242,245,247,250,251,252,257,261,272,292,296,306,308,316,317,319,321,324,326,327,328,330,331,340,341,344,364],post:[5,31,34,37,55,57,58,61,63,69,70,71,80,98,107,111,120,133,136,259,296,364],post_delet:107,post_init:107,post_join_channel:175,post_leave_channel:175,post_migr:107,post_mov:247,post_sav:107,post_send_messag:175,postgr:[23,64],postgresql:[55,344,364],postgresql_psycopg2:23,postinit:[83,137],postupd:[71,120],pot:12,potato:24,potenti:[10,11,13,26,41,82,83,90,98,111,114,116,123,154,166,176,241,242,247,251,338,341,344],potion:[77,318],power:[15,19,20,29,30,31,33,42,46,50,51,55,56,58,61,64,80,89,96,109,111,116,122,123,137,138,152,153,158,159,322,328,344],powerfulli:0,pperm:[12,41,71,80,133,156,164,241,247],pperm_abov:241,pprofil:267,pprogram:267,practial:15,practic:[0,13,14,22,26,29,33,34,36,37,57,58,63,64,70,80,89,90,96,105,109,119,124,126,131,139,322,364],pre:[33,47,49,54,61,63,71,89,90,111,114,138,144,159,166,242,247,251,252,295,296,299,326,340],pre_delet:107,pre_init:107,pre_join_channel:175,pre_leave_channel:175,pre_migr:107,pre_sav:[107,340],pre_send_messag:175,preced:[19,31,41,96,109,114,119,152,154,247,252,317,330],precend:150,precis:[11,96,126,321],predefin:[121,311],predict:[125,133],prefac:119,prefer:[21,22,23,31,37,47,55,57,71,80,90,91,96,106,109,111,123,131,137,138,152,154,157,238,245,247],prefix:[20,22,23,42,76,86,97,103,125,144,151,166,168,175,245,272,279,310,321,337,341,344,357],prefix_str:25,prematur:[27,93],prepai:90,prepar:[3,49,57,87,109,127,136,144,164,256,325,340,363,364],prepars:38,prepend:[247,321,322,328,344],preprocess:159,prerequisit:[9,36,364],prescrib:[55,57],preselect:138,presenc:[9,17,23,55,56,90,122,124,126,136,144,247,312,346],present:[1,4,8,22,42,46,48,49,51,62,69,77,85,91,96,97,104,105,116,123,131,138,252,326,344],preserv:[126,167,318,321,322,337,344],press:[9,14,15,22,26,31,33,42,51,63,80,83,88,95,96,100,106,110,265,328],pressur:82,presto:20,presum:[62,73,153,337,338],pretend:75,pretti:[0,22,25,26,37,38,39,41,60,64,67,72,85,88,89,90,116,121,123,126,131,133,138,154,175,236,242,251,327,329,338,344],prettier:[0,357],prettifi:[57,344],prettili:62,pretty_corn:330,prettyt:[27,330],prev:[51,329],prev_entri:51,prevent:[11,20,33,38,46,62,95,310,364],preview:38,previou:[0,10,11,14,16,22,29,31,33,41,42,51,52,58,60,62,69,80,85,86,87,91,95,96,100,104,107,114,119,123,126,164,249,328,329,337],previous:[20,31,34,49,50,67,72,74,91,102,104,114,119,127,133,136,154,157,159,164,175,272,288,292,299,308,319,344],prgmr:90,price:90,primari:[17,100,125,133,245,247,316,341],primarili:[2,12,34,36,37,38,55,61,108,144,238,285,325,344],primary_kei:133,prime:150,primit:[61,159],princess:[111,122],principl:[2,9,19,26,30,33,37,38,40,51,55,57,60,80,85,89,90,96,98,119,123,132,138,153,156],print:[4,9,10,11,21,25,26,27,40,42,50,51,58,59,83,86,91,95,96,97,110,113,125,156,251,266,267,327,328,329,330,337,344],print_debug_info:328,printabl:293,printout:290,prio:[25,31,33,150,319],prior:[117,247],priorit:319,prioriti:[4,25,31,33,44,51,97,116,152,156,160,161,162,163,167,247,326,328,329],privat:[4,8,38,57,61,69,90,131,164,165,279,292],private_set:9,privatestaticroot:312,privileg:[21,23,60,63,65,72,98,123,165,247,318,364],privkei:67,privkeyfil:287,privmsg:279,prize:122,proactiv:115,probabl:[4,5,11,16,21,22,23,25,29,33,37,46,48,51,55,57,61,64,67,69,85,86,89,90,96,108,116,119,121,128,133,134,136,138,166,269,279,287,334,344,345],problem:[11,13,15,21,22,23,24,25,26,27,36,43,56,61,64,69,70,75,77,80,90,95,97,100,103,110,111,113,127,138,140,144,153,247,276,322,364],problemat:[25,344],proce:[14,15,100,121,126,164,294],procedud:51,procedur:[138,287,290],proceed:[131,344],process:[0,4,8,9,11,13,14,15,22,23,25,29,33,36,38,39,41,42,49,51,55,59,61,64,67,73,75,76,83,88,89,90,91,92,93,100,106,122,131,133,138,139,144,150,152,159,169,175,240,242,247,251,257,260,267,272,276,277,284,287,290,295,296,299,305,306,308,316,321,322,325,328,338,343,344,345,364],processed_result:344,processor:[18,43,93,110,111,124,139,141,142,158,169,170,320,364],procpool:344,produc:[33,51,96,114,123,131,156,159,247,251,252,266,298,316,318,327,328,344],producion:27,product:[23,26,36,90,93,103,106,128,131,135,298,301,328,364],production_set:9,prof:93,profession:[3,57,64,108],profil:[45,65,139,141,142,148,262,364],profit:138,profunc:109,progmat:56,program:[2,10,15,23,53,56,57,63,64,67,70,75,77,79,86,90,92,93,95,96,100,103,106,108,110,114,124,127,128,169,171,262,267,290,296,298,364],programm:[91,95],programmat:[114,138],progress:[70,73,79,85,131,326,364],proident:52,project:[4,15,25,37,49,64,70,72,77,79,91,99,108,111,124,127,131,135,136,338,364],promis:26,promisqu:126,prompt:[9,12,23,24,26,42,54,63,64,75,83,88,96,100,111,124,125,137,139,154,265,279,290,295,296,322,328,342,364],promptli:14,pron:247,prone:[1,128,153,318],pronoun:247,prop:61,propag:[8,152,271,340],proper:[15,21,23,27,36,39,44,56,57,61,64,85,91,96,100,103,116,123,127,131,133,135,137,138,159,247,327,342],properi:166,properli:[9,29,58,62,69,84,106,108,117,125,126,127,128,131,133,140,154,241,260,261,287,344],properti:[5,6,13,22,25,39,53,55,56,57,59,61,68,73,80,81,84,86,87,96,97,104,109,110,111,115,116,119,121,123,126,127,144,146,148,154,156,159,167,169,170,175,177,239,241,242,245,246,247,251,252,256,258,259,260,271,272,274,279,285,298,299,306,307,308,316,318,319,323,325,328,338,339,340,341,342,344,357,364],property_nam:245,property_valu:245,propnam:123,propos:[50,138],proprietari:23,propval:123,propvalu:123,prosimii:[133,134],prospect:61,prot:252,prot_func_modul:[109,250],protect:[6,31,90,159],protfunc:[141,142,248,251,252,364],protfunc_callable_protkei:250,protfunc_modul:251,protfunc_pars:251,protfunct:251,protkei:[109,250,251],proto:[276,287],protocol:[24,27,33,47,53,64,72,74,79,83,90,92,101,103,104,105,110,137,139,144,146,154,157,247,262,264,267,269,272,276,277,278,279,280,281,282,283,285,286,287,289,290,291,292,294,295,296,298,305,306,307,308,326,340,344,364],protocol_flag:[289,290,294,306],protocol_kei:307,protocol_path:[285,308],prototocol:169,protototyp:[249,251,252],protototype_tag:109,prototoyp:250,prototyp:[45,46,47,53,55,120,139,141,142,159,364],prototype1:252,prototype2:252,prototype_:109,prototype_desc:[109,252],prototype_dict:159,prototype_diff:252,prototype_diff_from_object:252,prototype_from_object:252,prototype_kei:[109,159,251,252],prototype_keykei:159,prototype_lock:[109,252],prototype_modul:[109,159,251,252],prototype_pagin:251,prototype_par:[109,159,252],prototype_tag:252,prototype_to_str:251,prototypeevmor:251,prototypefunc:252,protpar:[251,252],protpart:251,provid:[0,3,4,11,12,16,17,22,25,29,33,36,38,41,47,55,69,75,77,90,91,96,97,100,102,103,108,109,119,124,125,126,127,131,133,134,136,137,138,144,154,159,164,171,175,241,247,250,259,267,287,310,317,319,328,338,339,340,342,344,345,357],provok:[42,79],proxi:[47,60,67,70,103,125,312,364],proxypass:8,proxypassrevers:8,prudent:36,prune:31,pseudo:[40,49,91,108],psql:23,psycopg2:23,pty:9,pub:[41,164,175],pubkeyfil:287,publicli:[54,61,79,364],publish:[21,36,79,100],pudb:[141,364],puff:56,pull:[25,31,33,36,37,38,64,100,128,131,136,269],pullrequest:37,punch:31,puppet:[2,9,19,21,22,31,33,39,40,41,43,55,57,58,62,74,80,96,97,105,107,114,118,123,133,143,144,150,156,159,167,177,241,247,306,308,318,319,360,364],puppet_object:[2,144],purchas:[67,85],pure:[46,56,88,114,125,126,256,267,316,321],pure_ascii:344,purg:[11,110,125,169],purpos:[4,11,67,83,90,92,95,112,119,123,126,133,146,150,154,287,316,325,328,344],pursu:122,push:[22,38,76,100,103,126,364],pushd:63,put:[0,2,3,5,6,10,12,13,14,19,20,21,23,25,33,37,38,42,46,49,50,51,57,58,60,61,64,70,73,77,79,80,83,85,86,87,89,90,95,96,102,103,104,105,106,109,111,114,116,121,122,123,125,127,129,133,135,136,138,153,156,157,159,161,165,242,276,290,329,330,344,364],putti:90,puzzl:[79,122,141,142,178,364],pwd:100,py3:276,pyc:[47,95],pycharm:[38,45,139,364],pyflak:26,pylint:26,pyopenssl:65,pypath:344,pypath_prefix:344,pypath_to_realpath:344,pypi:[64,79,90,93,321],pypiwin32:[9,63],pyprof2calltre:93,python2:[9,63,97],python37:63,python3:[63,75],python:[0,2,3,4,9,10,11,12,14,15,19,20,21,22,23,27,29,31,33,37,38,39,42,45,46,47,49,50,51,53,56,58,60,62,63,64,65,66,69,72,73,75,76,80,82,83,85,86,89,90,91,93,97,98,100,102,103,104,106,108,109,110,111,113,114,116,118,119,123,124,125,127,128,130,133,134,135,139,151,153,158,159,163,169,170,242,245,246,250,252,255,258,261,267,269,276,280,285,295,306,308,312,314,317,318,321,322,324,325,326,327,328,330,331,334,337,340,342,344,347,363,364],python_execut:64,python_path:[153,344],pythonista:79,pythonpath:[153,267,277,322],pytz:345,qualiti:[61,151],quell:[2,6,20,43,121,156,241,364],quell_color:159,queri:[11,16,34,39,56,64,83,86,109,112,131,148,164,166,177,238,239,245,246,247,251,252,256,274,287,302,316,317,318,319,329,335,341,344,345,364],quersyet:119,query_al:316,query_categori:316,query_info:267,query_kei:316,query_statu:267,queryset:[64,102,112,119,147,176,238,245,251,255,273,317,329,341],queryset_maxs:329,quest:[55,57,61,63,117,122,139],question:[8,10,22,26,33,34,50,51,57,61,63,67,70,73,90,96,124,131,135,159,246,264,265,316,326,328,342,344],queu:267,queue:[36,116,312],qui:52,quick:[5,18,22,31,33,38,39,48,55,61,70,79,90,91,95,97,108,112,116,119,124,138,140,146,159,252,272,316,319,330,364],quicker:[0,37,86,87],quickli:[10,11,15,25,33,34,39,48,51,86,89,96,112,114,120,128,136,139,159,319,322],quickstart:[90,95,139,364],quiescentcallback:269,quiet:[25,85,144,157,159,164,247,329,344,364],quiethttp11clientfactori:269,quietli:[29,83,88,316],quirk:[24,45,139,153,364],quit:[0,2,4,10,17,21,22,23,30,33,38,39,40,42,43,46,50,51,54,55,57,60,67,75,85,93,96,105,119,127,128,133,156,171,287,326,328,329],quitfunc:[50,326],quitfunc_arg:326,quitsave_yesno:326,quo:115,quot:[23,27,35,50,51,80,95,96,109,114,118,159,171,326,328,340,344],ra4d24e8a3cab:35,race:[8,55,56,61,73,79,117,133,344],radiu:[39,49,111],rage:122,rail:[64,121],railroad:121,rain:[102,119,122,132],rais:[10,15,27,33,69,73,77,83,91,109,119,134,144,146,147,176,242,245,250,251,261,266,267,285,290,296,311,316,317,319,321,322,324,327,328,330,337,338,339,340,342,344,345],raise_error:[339,344],raise_except:[1,316],ram:[11,90],ramalho:79,ran:[13,36,42,127,259],rand:102,randint:[73,91,109,116,120,123,252],random:[9,20,35,46,60,73,90,91,102,104,109,114,116,120,123,132,252,298,299,344],random_string_from_modul:344,random_string_gener:[141,142,178,364],randomli:[86,93,102,120,132,267,299],rang:[24,31,39,42,49,50,56,59,63,88,91,93,103,109,111,116,118,120,122,127,159,317,326,357],rank:[19,241],raph:79,rapidli:153,raptur:291,rare:[10,22,33,34,38,63,86,104,106,115,128,164,242,245,324],rascal:112,rate:[33,37,64,90,164,261,267,286,344],rather:[2,3,11,13,20,22,25,26,29,33,37,38,39,41,47,55,57,60,61,64,71,86,89,91,93,95,97,102,104,110,111,112,115,116,127,128,129,131,134,135,138,144,148,152,156,159,160,166,167,169,175,236,247,249,251,252,316,318,321,330,339,340,343],raw:[3,12,20,33,38,41,51,56,64,74,83,86,95,109,114,119,144,151,154,159,167,168,170,247,272,287,290,295,296,306,316,321,326,328,338,344],raw_cmdnam:[151,168],raw_input:[85,328],raw_nick:87,raw_str:[33,51,85,144,146,150,151,154,247,249,306,316,328,342],raw_templ:87,rawstr:[154,170],rcannot:22,rdelet:159,re_bg:343,re_bgfg:343,re_blink:343,re_bold:343,re_color:343,re_dblspac:343,re_double_spac:343,re_fg:343,re_format:321,re_hilit:343,re_invers:343,re_mxplink:343,re_mxpurl:343,re_norm:343,re_str:343,re_ulin:343,re_underlin:343,re_unhilit:343,re_url:343,reach:[20,22,39,51,73,87,88,90,95,101,121,122,141,154,287,291,310,328,329,341],reachabl:[64,115],react:[51,115,117,118,247],reactiv:169,reactor:[278,305,312,342],read:[0,1,4,5,8,9,11,13,15,16,17,20,22,23,25,27,29,31,33,34,37,38,39,41,46,51,55,56,58,59,60,64,69,70,71,72,76,77,79,80,85,86,88,90,91,93,95,96,102,103,104,105,109,114,119,122,123,124,126,127,128,131,133,134,138,139,144,148,158,165,166,177,239,246,247,251,252,256,274,276,299,316,318,319,322,323,327,329,335,337,344,363,364],read_batchfil:322,read_default_fil:36,readabl:[1,27,38,49,51,93,96,108,114,115,125,166,321,328],reader:[38,48,58,74,79,81,98,133,164,272,286],readi:[2,10,12,15,20,25,29,36,37,40,42,54,63,75,77,80,83,89,93,106,121,131,136,138,144,154,247,296,329,338,344],readili:[23,111],readin:327,readlin:337,readm:[14,37,47,53,130,131,178],readthedoc:[79,83],real:[2,10,21,22,27,31,38,39,42,46,55,58,59,62,63,66,67,72,73,89,90,93,95,100,108,109,110,111,116,119,123,125,126,131,148,153,177,241,298,322,331,364],real_address:2,real_nam:2,real_seconds_until:331,realis:77,realist:[127,132],realiti:[21,55,56,61,77,79,126],realiz:[48,96,126,131],realli:[4,10,11,12,13,14,19,20,22,25,26,31,33,39,42,51,58,62,64,67,72,77,80,85,89,91,96,98,104,108,110,111,112,115,118,119,121,127,128,138,139,154,170,242,276,321,322,328,340,342],realm:287,realnam:89,realtim:58,reason:[8,9,11,12,13,22,25,29,34,37,38,39,40,41,44,49,51,56,57,58,60,61,63,64,69,73,80,82,83,86,87,89,93,97,102,103,104,106,109,114,115,116,119,122,126,129,131,138,144,157,159,164,169,245,247,251,257,264,269,276,277,278,279,285,286,287,290,295,296,298,306,307,308,318,326,337,344],reasourc:109,reassign:49,reattach:[106,278,279],rebas:131,reboot:[11,27,28,43,50,55,67,84,86,90,100,102,105,115,116,128,144,153,164,169,247,256,257,259,261,267,307,308,326,328,364],reboot_evennia:267,rebuild:[58,63,100,128,279],rebuilt:33,recal:[95,138],recapcha:364,recaptcha:133,receipt:[103,269],receiv:[31,33,34,37,41,42,51,52,58,77,83,87,91,105,113,114,127,133,137,138,144,152,153,171,175,176,177,247,269,272,276,278,279,285,295,296,298,305,306,324,329,341,342,344,364],receive_functioncal:276,receive_status_from_port:267,receiver1:342,receiver2:342,receiver_account_set:148,receiver_extern:177,receiver_object_set:246,receiver_script_set:256,recent:[4,17,25,60,67,123,147,310],recev:296,recip:[0,28,115],recipi:[34,58,144,175,176,247,276],reckon:9,reclaim:102,recog:87,recogn:[16,20,63,74,83,89,90,96,110,127,134,312],recognit:316,recommend:[9,12,23,24,25,26,36,37,38,51,55,58,59,60,61,63,69,73,79,86,88,89,90,93,95,108,109,122,124,125,127,131,135,169,242,245,247,269,322,328,341],reconfigur:90,reconnect:[144,146,164,175,264,267,276,278,279,305,308],reconnectingclientfactori:[264,278,279,298],record:[15,23,90,123,310,357],record_ip:310,recours:12,recov:[27,28,29,56,242,344],recoveri:116,recreat:[23,63,102,111,128,146,153,322,323],rectangl:327,rectangular:[58,327],recur:64,recurs:[11,241,251],red:[13,14,20,31,59,80,87,95,109,114,126,159,169,321,345],red_bal:59,red_button:[13,14,20,87,141,142,159,170,178,222,364],red_button_script:[141,142,178,222,364],red_kei:80,redbutton:[13,14,20,87,159],redd:103,reddit:103,redefin:[22,33,55,89,247,357],redhat:[63,67],redirect:[8,22,40,69,96,105,133,135,328,361],redistribut:34,redo:[50,61,326],redraw:287,reduc:[116,280,364],redund:321,reel:153,reen:[114,321],ref:[23,38,125,247,344,357],refactor:[45,57,139,247,363,364],refer:[0,8,9,13,19,20,22,31,33,34,37,40,46,48,49,51,56,57,62,64,69,73,79,80,86,87,88,89,90,95,96,100,104,105,106,109,110,111,116,118,119,124,125,126,127,129,130,131,133,134,144,153,159,164,168,175,241,247,257,258,260,261,269,279,299,307,317,328,334,340,341,344,364],referenc:[38,56,89,104,109,154,159,164,175,239,318,344],referenti:344,referr:90,refin:[49,119],reflect:96,reflow:16,reformat:[252,330,337],reformat_cel:330,reformat_column:[111,330],refresh:[26,134,287,310],refus:12,regain:29,regard:[48,126,127,138],regardless:[12,19,31,33,58,73,80,81,83,102,105,114,119,121,125,127,138,144,152,175,247,261,284,287,290,305,307,316,319,322,334,337,344],regex:[33,50,51,87,127,137,154,157,169,170,311,316,328,344,347],regex_nick:87,region:[58,90,140,157],regist:[65,71,83,103,104,116,120,131,133,135,137,138,144,147,164,169,257,267,278,279,285,308,310,312,321,360,364],register_error:321,registercompon:137,registertest:360,registr:65,registrar:67,registri:[310,312],regress:251,regul:242,regular:[3,17,33,38,51,69,79,90,96,105,115,127,132,134,135,146,152,242,261,316,319,334,344,347,363],regulararticl:335,regulararticle_set:335,regularcategori:335,regularli:[67,85,98,102,120,128,132,259,261,270,300,331],reilli:79,reinforc:79,reiniti:110,reinstal:63,reinvent:57,rel:[10,13,14,19,22,31,38,49,51,82,104,123,131,133,322,328],relai:[27,33,72,105,144,164,247,285,308,328,329,344],relat:[28,31,33,34,47,51,56,57,72,79,96,102,103,104,110,125,132,137,138,139,148,149,152,167,172,176,177,239,246,247,255,256,261,272,308,316,318,319,321,328,335,337,346,350,357,364],related_nam:[148,177,239,246,256,316,318,319,335],relationship:[34,49,119,125],relay:146,releas:[9,28,37,55,63,78,79,90,96,169,364],releg:1,relev:[3,9,11,14,22,30,33,37,38,47,58,62,79,80,89,96,107,112,114,116,119,123,124,125,133,135,140,144,150,152,242,258,281,299,306,307,308,321,326,328,338,364],reli:[9,34,41,51,62,70,81,85,86,88,91,114,115,119,126,127,135,267,318,328,364],reliabl:[13,23,25,29,125,334],reload:[0,2,3,5,6,7,12,13,14,19,21,22,26,27,28,29,31,33,35,36,39,40,41,42,43,44,48,50,51,55,57,58,60,62,63,65,66,68,69,71,73,74,81,92,95,96,98,102,104,105,106,115,116,117,118,121,123,125,128,133,134,135,136,139,144,146,153,158,159,169,175,242,245,247,255,257,259,261,267,276,277,279,281,305,308,312,316,322,324,326,327,328,331,344,364],reload_evennia:267,remain:[13,19,30,31,33,50,51,58,77,90,91,96,97,107,109,110,113,151,153,159,161,165,247,267,295,296,328,329,344],remaind:[21,33],remaining_repeat:102,remap:316,remark:364,remedi:60,rememb:[0,1,4,5,11,12,13,21,22,28,29,31,33,39,41,48,49,51,54,56,58,61,62,63,69,77,80,86,88,90,91,93,95,96,97,111,112,114,115,119,123,126,128,131,137,139,157,159,247,257,322,341],remind:[0,4,38,50,364],remit:157,remnisc:57,remot:[25,100,103,164,276,278,290,364],remov:[0,1,4,9,11,12,21,22,27,31,36,39,41,48,50,51,55,58,69,80,81,84,85,87,89,91,93,98,102,115,116,122,127,128,131,133,136,138,141,152,153,157,159,164,165,166,169,170,175,177,242,246,247,252,257,260,261,267,285,296,308,310,316,319,321,325,328,334,340,342,343,344,364],remove_alia:164,remove_backspac:343,remove_bel:343,remove_charact:116,remove_default:[31,153],remove_non_persist:255,remove_receiv:177,remove_send:177,remove_user_channel_alia:175,removeth:316,renam:[9,20,43,58,81,136,159,165,247,255,318],render:[3,22,38,69,81,102,107,133,134,136,166,312,338,340,347,355,357],render_post:296,renew:[29,58,67,310],reorgan:[45,47],repair:[21,61],repeat:[0,42,61,62,75,88,93,102,110,111,116,118,121,136,139,144,146,255,256,259,267,272,291,316,324,328,331,344,364],repeatedli:[14,42,62,74,102,139,256,259,261,267,272,298,350],repeatlist:74,repetit:[62,116],replac:[5,6,9,22,23,25,29,30,31,33,36,38,41,50,51,57,69,74,80,87,89,95,96,100,104,105,109,111,114,116,119,134,135,136,137,138,144,151,152,153,154,157,165,166,169,170,175,242,247,249,251,252,279,282,295,296,306,316,321,326,327,328,329,330,343,344,347],replace_data:330,replace_whitespac:330,replacement_str:165,replacement_templ:165,repli:[33,51,65,70,139,146,265,289,290,296,308,328],replic:[22,114,136,319],repo:[38,47,57,79,106,131,139,344,364],report:[22,24,26,33,37,43,61,63,70,73,75,84,91,93,97,102,103,104,115,116,127,131,136,138,147,159,164,247,267,272,279,282,283,290,291,295,298,306,308,321,324,328,344],report_to:[147,245,255,324],repositori:[8,9,23,25,36,38,63,76,78,96,100,130,252,364],repositri:76,repr:[91,344],reprehenderit:52,repres:[0,2,9,20,21,22,25,31,33,40,46,49,53,56,61,62,64,69,77,86,89,95,96,105,107,113,116,119,125,126,127,133,136,144,150,176,247,252,260,261,264,278,279,295,296,306,307,308,312,316,317,321,323,324,328,329,330,340,344],represent:[2,11,28,40,58,64,73,77,86,87,88,105,113,119,126,176,245,251,256,276,295,296,319,325,331],reprocess:103,reproduc:[10,96,247],reqhash:[317,344],request:[3,8,26,37,40,51,63,69,80,90,103,107,119,123,131,133,134,135,139,144,146,157,247,251,267,269,276,279,281,286,287,289,296,312,319,328,349,350,351,355],request_finish:107,request_start:107,requestavatarid:287,requestfactori:312,requestor:[144,310],requir:[1,4,8,9,10,11,14,15,22,23,33,36,37,38,46,47,49,50,51,54,58,60,61,67,68,69,70,71,75,77,78,79,80,84,85,86,89,90,93,102,109,110,111,114,115,116,118,119,125,126,127,129,132,133,134,136,137,147,158,159,164,176,177,238,241,245,247,251,260,267,278,279,292,300,311,317,322,327,328,329,330,334,339,340,341,344,357,364],require_al:319,require_singl:251,requr:109,requri:251,rerout:[138,156,160,279],rerun:[13,14,51,122],research:79,resembl:[25,55,129],resend:33,reserv:[1,10,33,95,96,111,251,311,317,344],reset:[0,7,12,15,17,23,27,29,31,33,43,44,50,60,66,73,81,102,104,105,111,114,116,121,123,125,126,139,144,146,153,159,169,242,267,271,277,287,305,316,319,322,330,331,342,344,364],reset_cach:[316,319],reset_callcount:102,reset_gametim:[27,331],reset_serv:271,reshuffl:364,resid:[47,96,108,242],residu:169,resist:[252,344],resiz:[58,138,327,330],resolut:[114,116],resolv:[26,29,38,42,60,70,90,95,104,116,131],resolve_combat:116,resort:[33,38,54,58,164,344],resourc:[9,23,26,28,38,41,47,48,53,56,90,95,96,103,108,115,124,135,136,139,144,257,265,296,312,323,342,364],respect:[0,6,23,33,48,58,80,104,105,123,125,157,159,166,242,247,306,307,318,319,322,324,330,341,344,357],respond:[0,46,51,61,83,84,107,110,117,118,126,294,298],respons:[7,10,16,17,37,49,51,60,63,64,70,85,88,90,91,118,120,121,144,146,153,154,164,175,239,247,265,267,269,276,298,299,308,318,338,340,344],resport:344,rest:[17,29,33,38,51,56,63,73,82,85,86,87,104,106,111,122,123,151,167,168,316,321,330],restart:[12,42,43,58,60,76,90,92,93,102,103,104,106,110,116,128,131,135,138,141,144,169,175,247,255,257,259,260,261,271,284,305,306,307,344,364],restartingwebsocketserverfactori:[146,278],restock:85,restor:[0,31,102,126,257,261],restrain:[159,241,327,344],restrict:[4,8,11,19,20,47,59,68,73,80,90,109,111,115,125,134,137,159,238,242,245,252,255,324,326,328,330,341],restructur:[38,56],result2:51,result:[10,11,23,27,30,31,33,38,44,48,51,58,59,73,80,88,90,91,95,96,97,104,105,109,114,115,116,118,119,123,124,126,127,131,134,135,136,144,147,151,152,154,159,166,175,177,238,242,245,247,251,252,255,267,276,298,316,318,321,326,327,328,330,334,337,338,341,342,344,345],resum:[29,33,102,260],resync:[146,276,306],ret:[33,342],ret_index:344,retain:[10,27,31,51,97,111,138,176,239,252,313,318,322,324,337,344],retain_inst:154,retext:38,retri:267,retriev:[0,33,69,74,86,96,97,108,112,119,123,139,140,144,148,150,153,159,164,169,170,176,238,241,246,251,265,272,273,279,285,294,316,319,325,334,339,341,344,364],retriv:[146,323],retroact:[58,125],retur:52,return_appear:[48,49,60,122,123,247],return_apper:247,return_cmdset:166,return_iter:251,return_key_and_categori:319,return_list:[1,316,319],return_map:111,return_minimap:111,return_obj:[1,11,87,316,319,339],return_par:252,return_prototyp:120,return_puppet:144,return_tagobj:319,return_tupl:[87,316],returnv:33,returnvalu:10,reus:[25,334],reusabl:122,rev342453534:344,revers:[29,31,33,39,111,114,121,126,134,148,164,177,239,246,256,312,316,318,319,321,335],reverseerror:[267,276],reversemanytoonedescriptor:[148,246,335],reverseproxyresourc:312,revert:[90,126,131,156,238],review:[0,31,37,41,64,70,128,135],revis:61,revisit:[36,328],reviu:51,revok:58,revolutionari:131,rework:[29,61],rewritemim:70,rfc1073:283,rfc858:289,rfc:[283,289],rfind:321,rgb:[114,321],rgbmatch:321,rhel:8,rhost:171,rhostmush:[57,108,129],rhs:[25,58,167,170],rhs_split:[159,165,167],rhslist:167,ricardo:344,riccardomurri:344,rich:[22,57,78,79,325],richard:79,rick:109,rid:[56,119,139],riddanc:12,ridden:[1,96],ride:121,right:[0,5,8,10,14,20,21,23,25,28,29,33,38,39,41,42,46,51,55,56,57,58,60,61,63,68,74,75,76,80,85,87,90,91,96,101,102,109,111,114,117,119,121,123,126,127,128,133,134,137,138,153,156,159,167,169,171,175,242,252,256,307,321,322,326,330,344,345],right_justifi:109,rigid:57,rindex:321,ripe:96,rise:[31,62],risen:62,risk:[38,57,63,90,123,138,158,169,344],rival:111,rjust:321,rm_attr:159,rnormal:114,rnote:169,road:[31,46,111,121,152],roadmap:[45,139,364],roam:[122,153],roar:111,robot:[77,133],robust:[85,91,103],rock:[6,60,86,116,124,153],rocki:122,rod:153,role:[17,23,55,57,61,73,91,364],roleplai:[9,11,57,61,68,73,79,116,123,139,364],roll1:73,roll2:73,roll:[11,58,61,63,73,91,114,116,123,310],roll_challeng:73,roll_dmg:73,roll_hit:73,roll_skil:73,roller:[73,116,364],rom:[79,364],roof:159,room1:127,room56:13,room:[9,12,13,14,15,20,21,22,27,31,33,42,44,45,46,53,55,56,57,59,62,63,64,73,77,80,85,91,96,102,104,108,109,111,112,116,117,118,119,120,121,122,123,124,125,127,129,132,133,140,141,142,150,151,152,153,157,159,165,170,178,229,241,247,256,271,299,322,342,360,364],room_count:119,room_flag:56,room_lava:56,room_typeclass:[342,360],roombuildingmenu:22,roomnam:[58,159],roomobj:119,roomref:121,root:[9,13,22,23,36,38,47,53,63,64,69,75,78,80,81,86,89,90,93,96,97,100,106,128,130,134,135,136,247,252,267,312,325],rose:[11,87,89,125],rostdev:90,roster:9,rosterentri:9,rot:127,rotat:337,rotate_log_fil:337,rotatelength:337,rough:38,roughli:[58,61,96,344],round:[17,298,330],rout:[5,20,49,56,121,137,144],router:90,routin:[245,302,341,344],row:[0,3,16,25,38,49,58,64,69,86,111,114,116,126,137,330,344],rpg:[58,60,73,124],rpi:79,rplanguag:[141,142,178,364],rpm:63,rpsystem:[38,141,142,178,364],rred:321,rsa:[287,288],rspli8t:91,rsplit:[123,321],rsrc:70,rss2chan:[43,98,164],rss:[7,55,79,128,139,141,142,146,164,172,262,272,275,285,364],rss_enabl:[98,164],rss_rate:146,rss_update_interv:164,rss_url:[98,146,164],rssbot:146,rssbotfactori:286,rsschan:164,rssfactori:286,rssreader:286,rst:364,rstop:159,rstrip:[91,321],rtest2:114,rtext:85,rthe:22,rthi:114,rtype:312,rubbish:156,rubi:64,ruin:122,rule:[12,13,14,21,33,47,55,58,61,68,77,79,80,96,114,124,126,127,131,139,239,322,364],rulebook:116,rumour:122,run:[0,2,3,5,6,8,9,10,11,13,14,15,20,21,23,24,26,27,28,29,31,35,36,38,40,45,46,47,51,53,54,56,57,59,60,61,62,63,64,67,68,69,72,73,76,79,80,81,83,85,86,90,91,92,93,95,96,97,101,102,103,104,109,110,111,115,119,121,122,123,124,125,126,128,130,131,132,133,134,136,137,138,139,141,144,146,150,151,153,154,158,159,165,166,169,170,175,241,242,247,251,252,255,256,259,260,261,267,271,273,277,284,285,292,296,298,301,305,306,310,312,318,321,322,326,328,329,331,337,341,342,344,363,364],run_async:[10,344],run_connect_wizard:267,run_custom_command:267,run_dummyrunn:267,run_exec:328,run_exec_then_goto:328,run_init_hook:305,run_initial_setup:305,run_menu:267,run_start_hook:[60,125,318],runexec:328,runexec_kwarg:328,runnabl:109,runner:[36,106,298,364],runsnak:93,runtest:[170,293,303,335,342,352,360],runtim:[12,27,33,62,154,331,344],runtimeerror:[73,144,146,251,285,316,328,344],runtimewarn:251,rusernam:51,rush:29,rusti:85,ruv:36,ryou:22,sad:[133,290,328],sadli:171,safe:[11,26,30,31,46,56,60,64,82,89,97,104,131,133,144,156,242,261,276,308,312,318,322,325,334,344],safe_convert_input:344,safe_convert_to_typ:344,safe_ev:344,safer:[12,13],safest:[0,90,105,318],safeti:[2,56,89,90,123,125,139,159,246,322,364],sage:364,sai:[0,5,6,10,12,14,17,20,22,25,26,27,29,31,33,39,40,41,43,44,46,51,56,57,58,60,61,62,63,64,69,73,77,78,80,89,90,91,93,96,109,114,116,117,118,119,123,125,126,127,128,129,131,137,138,139,140,153,165,175,247,328],said:[0,4,10,22,26,44,46,49,51,57,83,91,96,111,112,118,127,134,151,164,168,247,279,316,318,328],sake:[13,57,126,135,171],sale:85,same:[0,2,5,6,9,10,11,12,13,14,15,16,19,20,21,22,23,26,27,28,29,31,33,34,37,38,40,41,42,44,50,55,57,58,59,60,61,62,63,64,66,69,73,74,78,80,81,83,84,85,86,88,89,90,91,95,96,97,98,100,102,104,105,106,108,109,110,111,112,113,114,115,116,119,121,123,125,126,127,128,131,133,134,136,138,144,150,151,152,153,154,157,159,164,167,168,169,170,171,176,241,247,251,252,256,257,261,271,276,288,291,292,306,307,308,310,312,316,317,318,319,321,322,324,328,329,330,331,337,338,342,344,357,364],sampl:[8,36,56,100],sand:62,sandi:111,sane:[38,61,79,96],sanit:357,saniti:[9,49,111,127,139,338],sarah:[129,165],sat:[21,140],satisfi:[108,167,316],satur:103,save:[0,1,9,15,21,22,24,27,29,33,34,36,41,42,46,48,50,51,54,56,64,67,84,86,87,89,95,97,100,102,103,105,107,109,110,112,115,116,123,125,127,131,133,138,144,156,159,169,175,177,242,246,247,249,251,252,257,259,260,261,265,272,285,300,305,312,316,318,325,326,334,338,339,340,344,364],save_buff:326,save_data:338,save_for_next:[33,154],save_handl:338,save_kwarg:339,save_nam:261,save_prototyp:251,savefunc:[50,326,339],savehandl:339,saver:325,saverdict:325,saverlist:325,saverset:325,saveyesnocmdset:326,saw:[10,46,69],say_text:118,scale:[23,38,57,61,73,106,114],scalewai:90,scan:[8,150],scatter:322,scenario:58,scene:[11,21,55,59,61,73,74,97,109,112,114,116,122,126,256,261,334],schedul:[27,62,260,331],schema:[4,64,86,125,131,344,364],scheme:[28,33,63,86,114,159,169,321],scienc:[49,124],scientif:79,scissor:116,scm:9,scope:[29,55,64,74,124,134,138,255,324],score:[58,60,344,364],scratch:[40,46,57,58,61,63,123,124,128,136,139,271],scream:122,screen:[7,16,18,33,51,52,61,66,74,81,85,97,100,101,104,105,109,114,127,133,138,139,171,272,287,329,344,364],screenheight:[74,272],screenread:[43,74,171,272,295,296],screenshot:[55,133,139,364],screenwidth:[74,154,272],script:[6,11,13,14,20,27,36,43,45,47,53,55,56,57,59,61,62,63,71,80,84,85,86,89,90,93,103,104,105,106,107,108,109,110,112,115,116,117,119,120,122,125,130,132,133,137,138,139,141,142,144,146,158,159,169,176,177,178,191,246,247,251,252,267,300,305,322,323,324,331,339,341,342,344,360,364],script_copi:255,script_search:[59,255],script_typeclass:[342,360],scriptbas:259,scriptclass:258,scriptdb:[53,119,125,141,256,314],scriptdb_set:[148,246,316,319],scriptdbmanag:[255,256],scripthandl:[141,142,253,364],scriptmanag:255,scriptnam:[159,323],scroll:[20,45,52,63,77,95,96,97,123,138,329],scrub:308,scrypt:102,sdesc:56,sdk:63,sea:[111,122],seamlessli:[92,102],search:[0,2,9,13,21,22,30,33,41,42,43,48,50,55,58,59,60,64,68,70,73,76,87,89,96,102,104,109,116,123,124,125,127,131,134,136,139,140,141,142,144,147,150,152,154,159,164,166,175,176,238,239,241,245,247,251,252,255,258,273,316,317,318,319,320,321,324,326,344,347,363,364],search_:[27,59],search_account:[27,53,58,107,119,141,147,247,341],search_account_attribut:119,search_account_tag:[119,341],search_at_multimatch_input:247,search_at_result:247,search_attribute_object:119,search_channel:[27,41,53,119,141,164,176,341],search_channel_tag:[119,341],search_field:166,search_for_obj:159,search_help:[27,53,119,141,238],search_help_entri:341,search_helpentri:238,search_index_entri:[154,156,157,158,159,164,165,166,167,168,169,170,171,239,247,298,326,328,329],search_messag:[27,53,119,141,176,341],search_multimatch_regex:247,search_object:[11,13,27,53,111,119,121,125,141,144,245,341],search_object_attribut:119,search_object_by_tag:53,search_objects_with_prototyp:251,search_prototyp:251,search_script:[27,53,59,102,119,141,255,341],search_script_tag:[119,341],search_tag:[27,48,112,119,140,141,341],search_tag_account:112,search_tag_script:112,searchdata:[144,245,247,341],searchstr:68,season:61,sec:[10,29,62,74,279,331],secmsg:337,second:[0,10,11,14,16,21,22,25,27,29,31,33,38,39,41,51,62,63,69,80,85,86,88,90,91,95,100,102,103,104,109,110,114,115,116,119,120,121,123,126,127,128,132,134,144,146,151,159,164,166,170,241,247,252,255,260,261,267,272,281,286,299,310,321,324,328,331,337,344,345],secondari:[81,307],secondli:89,secreci:131,secret:[9,65,71,267,364],secret_kei:9,secret_set:[4,9,23,65,267],sect_insid:49,section:[1,4,9,11,15,18,21,22,23,25,26,29,31,33,35,36,38,39,40,48,51,58,60,62,63,68,69,75,77,80,86,89,90,93,95,96,100,111,113,119,124,125,127,133,137,138,139,166,247,252,321,322,328,345],sector:49,sector_typ:49,secur:[7,11,13,22,26,37,41,57,63,80,85,90,96,108,109,114,123,133,134,139,141,142,154,158,169,175,178,239,247,287,318,337,344,357,364],secure_attr:80,sed:36,see:[0,1,2,3,4,5,8,9,10,11,12,13,14,19,20,21,22,23,25,26,27,28,29,30,31,32,33,34,35,37,38,39,40,41,42,44,46,48,49,50,51,52,53,55,56,57,58,59,60,61,62,63,64,65,68,70,71,72,74,75,76,80,81,82,83,86,87,88,89,90,91,93,95,96,98,100,101,102,103,104,105,106,108,109,110,111,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,130,131,132,133,134,135,136,137,138,139,144,154,156,158,159,164,165,166,167,169,170,171,175,178,239,246,247,255,260,265,267,269,270,278,279,280,281,283,287,288,290,292,294,295,296,298,299,307,308,312,316,321,324,325,326,327,330,339,340,342,344,351,357,364],seek:[122,242,337],seem:[4,22,24,31,39,41,56,61,63,75,109,110,119,121,122,123,137,138,171,316,322],seen:[0,22,29,31,34,38,40,46,49,51,57,58,69,81,91,95,96,102,105,111,119,120,121,126,127,131,279,330],sefsefiwwj3:9,segment:[121,312],seldomli:[154,170],select:[2,20,22,27,31,51,54,63,69,77,80,85,86,104,105,106,111,119,120,123,131,133,137,138,140,151,152,157,318,326,328,364],selet:328,self:[0,1,2,5,6,9,10,11,13,20,21,22,25,27,28,29,30,31,33,38,39,40,41,42,44,49,50,51,56,57,58,59,60,62,63,71,72,73,76,77,80,81,82,85,86,87,89,95,96,102,109,115,116,117,118,119,120,121,123,125,127,129,132,134,144,146,148,150,152,153,154,156,159,160,164,167,169,170,171,175,177,241,247,260,265,267,269,270,274,278,279,285,287,288,290,292,294,295,296,298,306,307,308,316,318,319,321,326,328,329,334,338,339,340,342,344,351,364],self_pid:344,selfaccount:58,sell:[78,85],semi:[93,132,138],semicolon:[80,242,245,255,324],send:[2,12,22,25,27,29,33,34,41,51,52,58,59,61,64,67,70,71,73,74,76,80,81,83,89,91,93,95,96,102,103,105,107,110,113,114,115,116,118,120,123,126,133,137,138,139,140,144,146,153,154,157,159,164,175,176,177,247,260,261,264,267,269,270,272,276,277,278,279,280,282,285,286,287,289,290,291,293,295,296,298,299,306,307,308,309,321,324,325,328,330,342,344,364],send_:[40,83,285],send_adminportal2serv:277,send_adminserver2port:264,send_authent:278,send_channel:[278,279],send_default:[40,83,278,279,285,287,290,295,296],send_functioncal:276,send_game_detail:269,send_heartbeat:278,send_instruct:267,send_msgportal2serv:277,send_msgserver2port:264,send_p:279,send_privmsg:279,send_prompt:[83,287,290,295,296],send_reconnect:279,send_request_nicklist:279,send_status2launch:277,send_subscrib:278,send_text:[40,83,287,290,295,296],send_to_online_onli:175,send_unsubscrib:278,sender:[34,41,107,144,146,175,176,177,247,278,309,324,334,341],sender_account_set:148,sender_extern:177,sender_object:309,sender_object_set:246,sender_script_set:256,sender_str:175,senderobj:[176,324],sendlin:[287,290,295],sendmessag:40,sens:[1,10,22,31,37,56,58,80,86,89,96,102,121,138,152,245,324,325,328],sensibl:90,sensit:[11,51,58,80,147,176,238,317,319,331,341],sent:[25,34,51,58,69,74,83,88,91,105,107,113,114,119,137,138,144,146,150,164,175,176,177,247,264,267,269,272,276,277,278,279,287,291,295,306,308,316,328,341,342,364],sentenc:[46,91,344],sep:[321,344],sep_kei:22,separ:[8,11,13,14,20,23,29,31,33,37,38,40,46,48,51,57,58,61,62,64,71,72,75,77,80,84,85,86,87,89,91,92,93,95,96,98,101,102,103,105,106,112,114,115,119,121,123,126,129,131,133,136,137,138,140,151,153,154,159,165,166,167,169,238,242,245,246,247,251,255,257,261,286,291,296,308,318,321,322,324,327,341,342,344,364],separatli:29,sept:364,seq:87,sequenc:[10,13,14,15,33,38,64,80,81,87,89,113,126,154,158,175,242,265,271,321,322,328,330,342,343,344],seri:[51,61,79,114,131,136,138,330],serial:[11,83,138,250,260,261,285,325,338,340,344],serializ:296,seriou:[39,110],serious:63,serv:[45,49,55,64,83,101,103,104,111,135,152,176,296,312,322,324,355],server:[0,2,4,9,10,11,12,13,15,19,21,25,26,27,28,29,31,33,34,35,36,37,38,40,41,43,45,47,51,53,54,55,56,57,58,59,60,62,63,64,65,66,67,69,70,71,72,73,74,75,78,79,80,81,83,84,86,88,89,91,93,95,96,97,100,101,102,103,106,107,109,110,111,113,114,115,116,118,121,122,124,125,127,128,130,131,133,134,135,136,137,138,139,141,142,144,146,147,153,157,159,164,169,171,175,178,207,208,247,255,256,257,259,261,313,318,322,324,325,328,331,334,337,344,363,364],server_connect:285,server_disconnect:285,server_disconnect_al:285,server_epoch:[27,331],server_l:277,server_logged_in:285,server_nam:104,server_pid:[277,344],server_receive_adminportal2serv:264,server_receive_msgportal2serv:264,server_receive_statu:264,server_reload:[257,261],server_run:267,server_runn:305,server_servic:344,server_services_plugin:[40,104],server_services_plugin_modul:40,server_session_class:105,server_session_sync:285,server_st:267,server_twistd_cmd:277,server_twisted_cmd:277,serverconf:[157,261,364],serverconfig:[260,261,273,274],serverconfigmanag:[273,274],serverfactori:[277,287,290],serverload:[43,169],serverlogobserv:337,servermsg:337,servernam:[4,8,9,54,74,90,104],serverprocess:43,serversess:[40,105,114,141,142,242,262,285,308,316,364],serversessionhandl:[40,105,308,364],serverset:[80,164,241],servic:[12,23,40,43,45,67,71,90,100,103,104,110,131,133,141,142,169,262,264,267,268,276,277,284,305,312,344,364],sessdata:[307,308],sessid:[2,33,105,123,246,247,264,276,277,285,308],session:[2,12,15,24,31,33,40,43,45,47,51,53,57,74,81,84,88,89,91,96,100,107,114,123,127,138,139,141,142,144,146,147,148,150,151,152,154,156,157,160,162,167,171,246,247,249,250,251,257,262,264,272,276,277,278,279,285,286,287,290,295,296,305,306,308,310,326,328,329,344,345,364],session_data:308,session_from_account:308,session_from_sessid:308,session_handl:[53,105,141],session_portal_partial_sync:308,session_portal_sync:308,sessioncmdset:[31,43,162],sessionhandl:[40,83,141,142,144,247,262,272,278,279,285,286,306,307,364],sessionid:285,sessions_from_account:308,sessions_from_charact:308,sessions_from_csessid:[285,308],sessions_from_puppet:308,sesslen:247,set:[0,2,3,6,7,8,10,11,12,13,14,15,16,17,19,20,21,22,23,24,25,26,27,29,30,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,50,52,53,55,56,57,58,59,60,61,63,64,66,67,68,69,71,74,75,76,82,83,85,86,87,89,91,93,95,96,97,100,102,105,107,108,109,110,111,112,113,114,116,117,119,120,121,124,125,126,128,129,130,133,134,135,136,137,138,139,141,143,144,146,147,148,150,151,152,153,154,156,157,159,160,161,162,163,164,166,167,170,171,172,175,238,241,242,245,246,247,250,251,252,255,258,259,260,261,264,266,267,271,272,273,274,277,278,280,281,283,284,287,289,290,292,293,298,299,301,303,305,306,307,308,310,312,313,316,317,318,319,321,322,323,324,325,326,327,328,329,330,331,334,335,337,338,339,340,341,342,343,344,345,347,350,357,360,364],set_alias:154,set_attr:159,set_cach:316,set_class_from_typeclass:318,set_desc:164,set_descript:51,set_gamedir:267,set_kei:154,set_lock:164,set_log_filenam:175,set_nam:51,set_password:144,set_trac:[42,141],setcolor:81,setdesc:[43,57,165],sethelp:[20,43,68,166],sethom:[43,159],setnam:40,setobjalia:[43,159],setperm:157,setpow:364,sett:98,settabl:[74,86,290],setter:39,settestattr:50,settingnam:80,settings_chang:107,settings_default:[4,5,34,47,53,104,109,127,141,142,337,344,364],settings_ful:104,settings_mixin:[141,142,262,297,364],settl:[111,116],setup:[5,15,18,26,38,40,47,61,63,67,71,85,93,96,100,116,120,127,129,131,138,139,144,156,164,170,247,259,271,284,293,298,302,303,305,312,316,318,334,335,342,360,364],setup_sess:342,setup_str:302,setuptool:[63,75],sever:[0,11,14,19,22,29,31,33,36,38,41,42,48,50,52,55,56,57,59,62,69,79,80,102,104,109,113,116,119,125,137,158,159,167,169,176,247,293,294,319,324,344,364],shall:[126,134],shaman:[57,109],shape:[20,22,39,58,61,111,330],sharabl:109,share:[9,25,31,36,37,42,46,57,59,63,64,65,80,86,90,102,103,105,112,116,119,125,133,135,252,261,298,316,317,319,330,344,351,364],sharedloginmiddlewar:351,sharedmemorymanag:[317,333],sharedmemorymodel:[177,239,316,318,334,335,364],sharedmemorymodelbas:[148,177,239,246,256,316,318,334,335],sharedmemorystest:335,shaw:[77,79],she:[0,22,33,56,91,126],sheer:159,sheet:[23,38,51,133,134,137,327,364],sheet_lock:58,shell:[7,23,25,26,36,57,58,59,60,63,75,86,87,90,100,103,108,110,125,128,287,316,364],shield:[29,77,86],shift:[14,15,27,108,238,344],shine:21,shini:344,ship:[55,64,75,111],shire:62,shoot:[21,327],shop:[51,57,108,124,139,364],shop_exit:85,shopcmdset:85,shopnam:85,shopper:85,short_descript:54,shortcom:85,shortcut:[0,3,22,23,27,29,31,33,38,47,59,69,91,96,100,107,116,119,125,129,133,134,141,146,153,154,159,164,242,247,338,344,364],shorten:[42,46,125,252],shorter:[38,40,61,104,108,117,118,125,132,175,176,238,316,317,324,337],shortest:39,shorthand:[89,126,159],shortli:[0,22,77],should:[0,1,2,3,4,5,6,8,9,10,11,12,13,14,15,16,19,20,22,23,24,25,26,27,29,31,33,34,37,38,39,40,41,42,46,47,48,51,55,57,58,59,60,61,62,63,64,65,66,67,68,69,72,73,74,75,76,77,80,81,82,83,85,86,88,89,90,91,93,95,96,97,98,100,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,119,121,122,123,124,125,126,127,128,129,130,131,133,134,135,136,137,138,139,140,144,146,147,148,150,152,153,154,156,158,159,160,163,164,166,167,169,170,171,175,176,177,241,242,246,247,249,251,252,256,259,260,261,265,266,267,271,274,278,284,287,290,291,293,295,296,298,299,305,306,307,308,310,311,313,316,318,319,321,322,324,325,326,328,329,330,331,337,338,339,340,342,344,345,357,360],should_join:175,should_leav:175,should_list_top:166,should_show_help:166,shoulddrop:247,shoulder:58,shouldget:247,shouldgiv:247,shouldmov:247,shouldn:[0,13,21,22,29,41,48,58,93,126,247,298],shouldrot:337,shout:29,shove:21,show:[0,12,13,14,20,22,24,26,27,30,33,35,37,38,39,40,42,46,48,49,52,54,55,57,58,60,61,62,63,64,68,69,70,71,73,81,82,85,86,90,91,95,96,97,98,101,102,103,104,105,106,110,111,114,116,117,118,119,120,122,124,126,127,128,129,131,133,134,136,137,138,139,144,156,157,159,164,165,166,167,169,171,247,249,251,252,265,267,276,316,326,328,337,338,339,344,357,364],show_foot:329,show_map:49,show_non_edit:251,show_non_us:251,show_version_info:267,show_warn:267,showcas:[31,111],shown:[0,4,9,22,25,29,35,41,49,51,54,57,62,68,109,114,121,133,138,154,157,164,168,170,247,267,328,329,347],showtim:62,shrink:330,shrug:46,shrunk:101,shuffl:27,shun:[26,90,108],shut:[0,4,29,93,100,102,104,137,144,169,247,259,261,267,269,276,277,284,285,305,308,364],shutdown:[12,19,31,43,58,93,102,105,110,144,146,169,255,261,267,276,277,284,305,306,318,324,328],shy:[26,61,129],sibl:[10,57,96,102],sid:157,side:[0,1,11,24,36,38,48,49,58,73,74,83,91,105,112,119,126,127,133,137,138,144,146,148,159,165,167,177,239,246,256,264,272,276,277,285,288,291,292,295,306,307,308,316,318,319,321,330,335],sidebar:364,sidestep:19,sidewai:330,sigint:267,sign:[0,14,20,46,83,90,91,106,115,123,132,164,247,261,316,321,345],signal:[45,93,110,139,141,142,262,267,290,296,298,334,364],signal_acccount_post_first_login:107,signal_account_:107,signal_account_post_connect:107,signal_account_post_cr:107,signal_account_post_last_logout:107,signal_account_post_login:107,signal_account_post_login_fail:107,signal_account_post_logout:107,signal_account_post_renam:107,signal_channel_post_cr:107,signal_helpentry_post_cr:107,signal_object_:107,signal_object_post_cr:107,signal_object_post_puppet:107,signal_object_post_unpuppet:107,signal_script_post_cr:107,signal_typed_object_post_renam:107,signatur:[33,73,154,260,265,267,269,270,278,287,288,290,292,295,296,316,321,328,339,340,351],signed_integ:345,signedinteg:338,signedon:279,signifi:[14,241,316],signific:[97,342],significantli:50,signup:4,silenc:[164,269],silenced_system_check:127,silent:[10,62,118,157,164,271,279],silli:[60,89,96,109],silvren:[55,90],similar:[0,11,13,20,21,22,25,33,41,48,51,55,58,64,67,68,73,77,86,89,90,96,102,106,121,125,129,136,137,140,144,154,156,170,175,239,247,255,308,319,324,328,344],similarli:[58,62,90,112],simpl:[0,2,4,5,6,9,10,13,14,15,17,25,26,28,30,31,33,35,38,39,40,41,46,49,50,55,56,57,58,59,60,61,64,67,69,70,73,74,76,77,81,85,86,88,89,90,91,95,96,98,100,103,105,108,109,111,112,116,117,118,119,120,122,123,124,126,132,133,135,139,159,175,236,246,247,252,259,277,286,288,316,322,323,328,344,354,355,357,364],simpledoor:[141,142,178,364],simplemu:24,simpler:[10,15,51,56,158,159,325],simpleresponsereceiv:269,simplest:[6,29,58,73,90,116,153,322,345],simpli:[5,8,11,12,13,17,20,21,22,23,25,29,31,37,38,39,40,41,47,49,51,55,58,59,61,63,71,72,73,80,81,83,85,96,102,103,104,109,112,114,118,121,123,125,127,128,131,132,138,140,144,152,153,154,170,171,175,239,247,285,316,318,322,323,327,329,344],simplic:[22,39,55,126,171],simplif:[45,116],simplifi:[10,69,100,111,116,118],simplist:[116,123,132,137],simul:[33,73,93],simultan:[58,88,116,245,344],sinc:[0,1,3,4,5,6,9,10,11,13,14,19,21,22,23,25,26,27,28,29,31,33,34,35,38,39,40,41,42,44,47,48,49,50,51,54,55,56,57,58,59,60,61,62,64,69,74,76,80,83,84,85,86,88,89,90,91,94,96,97,100,102,104,110,111,114,115,116,118,119,121,122,123,125,126,127,131,133,134,135,138,144,146,148,152,153,154,159,167,168,169,176,241,245,247,251,252,257,260,261,267,269,272,284,289,291,305,306,308,310,316,317,318,322,323,324,326,328,331,334,337,340,341,342,344,357],singl:[0,5,10,14,16,22,23,31,33,37,38,44,48,51,55,57,58,59,61,64,67,73,77,83,87,88,90,95,96,105,108,111,112,114,119,122,125,127,128,129,139,144,157,164,165,169,177,247,251,252,260,261,299,306,308,316,317,319,321,322,327,328,330,344,357,364],singleton:[84,105,115,257,260,323,364],singular:[38,58,61,247],sink:26,sint:52,sir:46,sit:[11,14,29,33,47,55,63,80,83,90,95,96,119,121,123,125,167,175,177,242,255,258,261,280,319,324,339,342],sitabl:125,site:[8,16,17,23,37,69,71,79,80,90,97,98,100,101,103,111,133,134,312,364],site_nam:59,sitekei:364,situ:[11,318,325],situat:[0,6,11,22,33,37,42,46,62,76,83,86,102,105,119,125,131,153,154,159,334],six:[73,91],sixti:62,size:[16,24,42,49,58,97,101,108,111,137,138,141,269,283,321,327,329,330,334,337,344],size_limit:344,skeleton:123,sketch:[116,138],skill:[28,29,30,55,60,61,70,73,79,110,116,121,127,133,134,327],skill_combat:73,skillnam:73,skin:109,skip:[31,33,41,49,51,61,62,75,88,100,106,109,115,131,144,158,159,247,251,316,325,344],skipkei:296,skippabl:129,skull:109,sky:[102,132],slack:79,slash:[20,41,55,73,116,122],slate:111,sleep:[10,29,33,73],slew:[61,73,75,322],slice:[119,156,321,329],slice_bright_bg:156,slice_bright_fg:156,slice_dark_bg:156,slice_dark_fg:156,slight:[8,91],slightli:[42,62,63,79,116,123,177],slightly_smiling_fac:138,slip:343,slogan:9,sloppi:38,slot:[58,134,252,344],slow:[27,116,169,176,251,280,286,321,341,344],slow_exit:[141,142,169,178,364],slower:[62,77,90,93],slowli:79,slug:[154,175,239,318],small:[4,14,15,16,25,30,33,37,55,57,58,61,63,69,70,79,81,85,90,91,93,96,97,98,108,111,122,123,124,127,128,139,290,326,327,330,344],smaller:[13,14,16,38,101,330],smallest:[58,62,80,90,327,344],smallshield:86,smart:[41,77,91],smarter:109,smash:61,smell:61,smelli:109,smile:[33,165],smith:327,smithi:29,smoothli:134,smush:48,snake:136,snap:82,snapshot:131,snazzi:78,sneak:242,snippet:[10,13,21,31,55,64,80,109,114,139,169,276,343,344],snoop:103,snuff:26,social:[55,71],socializechat:299,soft:[4,64,139,364],softcod:[129,139,364],softli:78,softwar:[36,63,90,131],solar:62,soldier:85,sole:[57,69,146],solid:[49,55,114],solo:[20,63,124],solut:[0,9,14,25,27,29,39,56,69,73,85,90,91,103,111,115,118,121,122,125,127,138,168,242,364],solv:[21,27,44,49,61,63,77,97,111],some:[0,3,4,5,6,8,9,11,12,13,14,15,16,20,21,22,23,24,25,26,27,28,29,31,33,36,37,38,40,42,43,45,46,48,49,50,51,55,57,58,60,61,62,63,64,67,69,70,72,73,74,75,77,78,79,80,82,83,85,86,87,89,90,91,95,96,97,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,121,122,123,124,125,126,127,128,131,133,134,136,137,138,139,144,153,154,159,161,164,165,168,169,171,175,176,242,247,251,252,256,269,271,276,279,305,316,318,321,322,327,328,331,334,337,338,344,357,364],some_long_text_output:329,somebodi:[0,138],somehow:[33,40,73,80,87,90,113,140,326],someon:[0,1,29,33,46,48,49,58,60,80,85,90,96,103,107,115,117,118,119,138,144,165,247],somepassword:23,someth:[0,3,4,6,8,9,10,11,12,14,20,22,23,25,27,29,30,33,38,39,40,41,44,46,49,51,52,56,57,58,59,60,61,62,64,65,67,68,69,70,71,72,73,75,80,82,83,85,86,89,90,91,93,95,96,102,104,107,108,109,111,114,115,119,123,125,127,128,129,133,134,135,137,138,139,144,152,154,159,165,167,170,242,247,252,306,318,322,328,329,338,344],sometim:[6,22,27,33,40,42,50,51,60,62,64,80,86,91,93,95,96,102,109,110,119,136,138,166,245],somewhat:[4,22,41,57,127,138],somewher:[0,12,37,73,80,90,109,121,125,131,154,159,175,239,318,344,364],soon:[42,61,69,72,96,100,105,127,296,344],sophist:[10,27,55,108,116],sorl:4,sorri:[80,242],sort:[3,6,11,31,39,49,59,61,64,69,73,83,84,90,105,110,112,116,117,135,140,247,252,256,316,317,318,328,344,357],sort_kei:296,sought:[144,151,175,239,247,316,318],soul:111,sound:[22,29,37,58,61,80,82,83,102,104,111,115,131,138,291],sourc:[0,4,9,10,12,15,16,17,20,21,22,23,27,31,36,37,43,46,47,55,57,60,63,64,67,68,72,75,76,79,88,89,96,97,108,122,127,128,130,131,134,139,141,144,146,147,148,150,151,152,153,154,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,175,176,177,238,239,241,242,245,246,247,249,250,251,252,255,256,257,258,259,260,261,264,265,266,267,269,270,271,272,273,274,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,298,299,300,302,303,304,305,306,307,308,310,311,312,316,317,318,319,321,322,323,325,326,327,328,329,330,331,333,334,335,337,338,339,340,341,342,343,344,345,349,350,351,352,355,357,360,363,364],source_loc:[25,77,96,117,247],source_object:171,sourceforg:[280,281,291,294],sourceurl:279,south:[0,22,44,49,111,121,159,299],south_north:111,southeast:159,southern:111,southwest:[20,159],space:[9,20,21,22,25,33,35,38,41,46,48,49,51,57,68,80,87,91,95,102,109,111,114,116,118,126,129,137,138,151,154,159,164,165,166,167,170,171,247,311,318,321,322,327,328,330,343,344,347,364],spaceship:121,spacestart:343,spaghetti:[13,328],spam:[12,28,103,116,138,164,310],spammi:[12,116],span:[16,17,108],spanish:76,spatial:111,spawn:[43,47,53,55,93,120,122,137,138,141,157,159,249,250,251,252,364],spawner:[18,45,89,120,139,141,142,159,248,250,364],spd:134,speak:[0,15,19,41,46,60,96,113,117,118,126,133,165,247],speaker:46,spear:109,special:[2,10,11,13,14,15,19,20,25,26,27,30,31,33,35,37,38,41,42,51,58,60,61,64,69,76,77,80,81,83,85,86,88,89,95,102,103,104,107,111,112,113,114,116,119,122,123,125,127,131,134,137,146,148,150,153,165,168,242,247,271,272,295,299,316,318,322,328,343],specif:[0,2,4,9,11,12,22,23,24,25,26,27,31,33,36,37,38,39,40,41,42,46,47,50,51,53,55,56,59,61,62,64,67,69,77,78,79,80,82,87,88,89,90,91,95,96,100,105,107,110,111,112,115,116,119,121,122,123,124,125,126,127,131,132,133,134,135,137,138,144,147,150,157,159,166,169,171,177,178,238,241,245,247,255,257,267,271,272,279,295,296,306,316,318,321,322,326,328,329,330,344,364],specifi:[3,11,12,16,19,21,22,27,29,31,38,39,46,49,51,54,58,62,63,68,83,84,86,88,90,91,98,100,102,103,105,109,111,112,114,115,119,123,127,134,136,150,151,159,166,175,176,241,242,247,250,251,252,257,278,304,316,319,321,322,324,327,328,331,338,339,340,342,344,357],spectacular:42,speech:247,speed:[11,47,62,82,86,87,93,116,134,245,252,285,319,341],speedup:251,spell:[15,19,28,57,60,109,112,252],spend:[39,89,91,119],sphinx:38,spin:[62,90,342],spit:[3,60,116],split:[9,25,31,33,41,58,91,104,105,111,118,121,123,131,136,138,151,167,249,293,308,321,322,331],split_2:138,split_nested_attr:159,splithandl:138,spoken:[0,46,72,247],spool:63,sport:87,spot:[57,64,144],spread:[70,73,109,364],spring:[82,124],sprofil:267,spunki:77,spuriou:364,spyrit:24,sql:[7,36,56,57,64,86,125,139,302,364],sqlite3:[25,55,64,86,123,127,128,131,344,364],sqlite3_prep:305,sqlite:[23,86,128,305],sqllite:36,sqrt:39,squar:[38,39,129],squeez:[38,86],src:[10,17,20,59,75,80,89,100,102,133,137,139],srcobj:[154,167],srun:271,srv:36,ssessionhandl:83,ssh:[9,25,40,55,64,83,90,105,110,141,142,262,275,306,307,364],ssh_interfac:90,ssh_port:90,sshd_config:103,sshfactori:287,sshprotocol:287,sshserverfactori:287,sshuserauthserv:287,ssl:[7,8,55,64,67,83,88,141,142,146,164,262,275,279,292,307,364],ssl_context:[288,292],ssl_interfac:90,ssl_port:90,sslcertificatefil:8,sslcertificatekeyfil:8,sslciphersuit:8,sslengin:8,ssllab:8,sslprotocol:[8,288,292],ssltest:8,sslv3:67,sta:327,stab:[29,122],stabil:[61,170],stabl:[37,40,56,60,100],stabli:[97,261],stack:[13,31,61,121,137,152,153,247,251,308,328],stackexchang:127,stacktrac:251,staf:108,staff:[9,19,25,57,61,68,73,80,108,109,111,123,133,152,252,322],staffer:9,staffernam:9,stage:[2,36,56,61,77,111,123,131,133],stagger:279,stai:[1,31,49,51,63,90,91,121,125,126,138],stale:[100,125,260],stale_timeout:260,stamina:30,stamp:[27,96,105,125,137,144,148,157,169,246,256,299,304,318],stanc:[116,247],stand:[13,17,20,21,22,25,29,38,49,56,61,63,72,73,80,86,90,95,96,111,116,121,122,123,127,131,133,138,165,247,256,261,298,319,322,324,330],standalon:[67,103],standard:[0,1,6,8,9,15,21,27,30,41,50,57,58,59,63,64,79,83,88,91,95,103,113,114,116,120,126,131,136,139,141,144,156,247,287,289,294,311,316,321,330,331,342,345,364],stanza:277,star:159,stare:131,start:[0,1,2,3,4,5,7,12,13,14,15,16,18,20,21,23,25,26,27,29,31,33,34,38,39,40,41,42,44,45,47,48,49,50,51,54,55,57,59,60,61,62,64,65,66,67,69,70,72,73,74,75,76,77,79,80,83,84,86,87,90,91,93,95,96,97,98,101,102,103,104,105,106,107,108,109,111,114,116,119,120,121,123,124,125,127,128,130,131,132,133,136,137,138,139,144,146,151,152,158,159,164,165,166,167,168,169,170,175,247,249,251,255,256,257,258,259,260,261,264,267,269,271,272,277,278,279,280,284,285,286,291,292,298,299,304,305,308,312,317,321,322,323,324,326,328,329,330,331,337,344,347,363,364],start_all_dummy_cli:298,start_bot_sess:308,start_delai:[102,116,120,121,255,256,261,324],start_driv:121,start_evennia:267,start_index:164,start_lines1:267,start_lines2:267,start_loc_on_grid:49,start_olc:249,start_only_serv:267,start_ov:51,start_plugin_servic:40,start_portal_interact:267,start_serv:277,start_server_interact:267,start_sunrise_ev:62,startapp:[69,86,133,134],startclr:114,startedconnect:[264,278,279],starter:[9,136],starthour:25,startnod:[51,85,249,328],startnode_input:[51,249,328],startproduc:269,startservic:[270,312],startswith:[41,84,159,321,342],starttupl:287,startup:[11,35,40,60,62,90,102,104,136,247,256,259,296,305,337,344],stat:[17,43,60,61,71,85,116,123,133,134,136,139,364],state:[11,13,14,31,33,42,43,50,51,55,56,64,80,95,100,102,105,110,114,116,121,122,126,127,131,137,138,144,150,152,153,156,163,171,175,252,256,258,259,261,267,287,316,326,328],state_unlog:163,statefultelnetprotocol:[290,298],statement:[10,13,14,27,31,42,49,51,55,58,59,83,86,95,96,118,119,124,322,343],static_overrid:[135,136,137],static_root:136,statict:159,station:121,statist:[3,12,104,105,120,124,135,159,169,300,317,334],statu:[20,29,51,58,61,88,90,104,105,115,131,169,261,265,267,276,277,278,281,295,364],status:61,status_cod:269,stdin_open:100,stdout:[59,100,267,337],steadi:64,steal:[85,166],steer:121,step1:29,step2:29,step3:29,step:[0,4,7,8,13,14,21,23,29,31,33,36,38,39,41,45,46,50,51,58,63,69,73,77,82,85,86,91,97,100,102,106,108,121,122,123,126,127,128,134,138,139,158,164,261,271,283,294,298,299,308,318,322,325,326,328,329,363,364],stick:[15,33,38,51,63,113,157],still:[0,1,4,6,9,11,13,14,15,19,20,22,25,26,29,31,33,37,38,39,40,41,49,55,57,58,60,62,63,64,77,78,79,83,91,95,96,102,103,105,106,107,108,110,114,121,122,123,125,126,128,131,134,138,144,152,159,164,166,171,175,245,247,251,258,299,328,330,331,340,344],sting:111,stock:[34,55,85,101,357],stolen:[103,321],stone:[20,33,60],stoni:60,stop:[7,9,10,12,14,20,25,27,29,34,41,42,49,51,57,58,62,63,67,74,77,80,82,89,90,93,95,96,100,102,104,105,106,108,115,116,120,121,123,128,137,139,156,159,164,169,175,247,255,258,259,260,261,266,267,269,272,284,285,305,306,312,321,322,324,344,364],stop_driv:121,stop_evennia:267,stop_serv:277,stop_server_onli:267,stopproduc:269,stopservic:[270,312],storag:[11,13,23,28,29,33,47,56,64,73,85,86,96,102,125,133,138,148,169,177,242,246,247,251,252,256,259,261,274,310,314,316,318,323,338,339,364],storage_modul:323,storagecontain:102,storagescript:102,store:[0,2,9,13,15,21,23,27,28,29,31,33,34,37,39,40,41,44,46,47,49,50,55,56,57,58,60,61,64,69,73,75,80,82,85,86,87,89,91,95,97,100,102,104,105,112,113,115,116,119,121,123,125,127,128,131,133,134,135,136,137,138,139,144,146,148,153,156,157,159,160,162,166,167,177,238,241,242,246,250,251,252,253,257,258,259,260,261,267,271,272,273,274,277,279,280,281,283,291,294,299,305,306,307,308,310,312,316,317,318,319,321,323,324,325,326,327,328,329,331,334,338,339,340,344,357,364],store_kei:[261,344],store_result:48,stored_obj:25,storekei:[85,261],storenam:85,storeroom:85,storeroom_exit:85,storeroom_kei:85,storeroom_key_nam:85,stori:[3,9,97,133],storm:[28,119],storypag:3,storytel:123,stove:247,str:[0,10,11,22,25,27,39,40,50,51,58,59,60,73,74,84,91,96,113,114,119,125,127,133,134,141,144,146,147,150,151,152,153,154,159,164,166,175,176,177,238,239,242,245,246,247,250,251,252,255,257,258,259,261,264,265,267,271,272,273,274,276,277,278,279,280,282,285,286,287,290,291,292,295,296,298,304,305,306,307,308,310,311,312,316,317,318,319,321,322,323,324,326,327,328,329,330,337,338,339,340,341,342,343,344,345,349],straight:[49,68,126,319],straightforward:[25,41,85,91,121,123],strang:[6,8,14,29,41,56,131,153,171],strangl:90,strategi:42,strattr:[1,11,316],stream:[106,276,280,306],streamlin:36,strength:[11,57,58,60,61,73,80,116,134],stress:[93,298],stretch:[38,111],stribg:344,strict:[10,251,321],stricter:251,strictli:[19,51,59,77,133,330],strike:[51,82,116,165],string1:344,string2:344,string:[5,9,11,12,13,15,19,20,22,23,25,27,29,31,33,34,35,38,41,42,49,50,54,55,57,58,59,60,62,68,71,76,82,83,84,86,87,88,89,90,93,95,96,97,104,109,111,112,113,114,115,116,119,124,125,127,129,133,134,137,138,139,141,142,144,146,147,148,150,151,154,157,159,164,165,166,167,168,169,170,175,176,177,238,239,240,241,242,245,246,247,250,251,252,255,256,259,261,267,269,272,276,279,287,290,291,293,296,299,304,306,308,311,316,317,318,319,320,321,322,324,325,326,327,329,330,337,338,340,341,342,343,344,345,364],string_from_modul:344,string_partial_match:[245,344],string_similar:344,string_suggest:344,stringproduc:269,strip:[21,22,33,38,41,51,58,74,81,85,108,109,114,118,123,151,159,166,167,168,245,252,272,287,290,291,321,322,326,328,342,344,364],strip_ansi:[81,321,343],strip_cmd_prefix:166,strip_control_sequ:344,strip_mxp:321,strip_raw_ansi:321,strip_raw_cod:321,strip_unsafe_input:344,strip_unsafe_token:321,strippabl:328,strong:[80,114,123,343],strongest:80,strongli:[64,73,95,124],struct:56,structur:[9,11,33,37,41,45,47,48,49,51,55,56,59,63,64,68,69,80,83,88,95,96,109,119,133,134,136,138,159,164,175,247,251,252,291,296,319,325,328,354,364],strvalu:[11,316,317],stuck:[51,63],studi:[59,364],stuff:[3,9,11,21,29,31,37,38,47,49,51,57,61,67,73,80,85,96,102,105,107,109,119,138,153,170,261,305,350,364],stumbl:97,stupidli:34,sturdi:327,stutter:108,style:[3,16,20,21,27,33,37,38,40,41,43,45,51,55,57,58,61,79,87,95,106,111,114,116,122,124,129,138,148,154,156,167,251,326,330,344,364],styled_foot:154,styled_head:[33,154],styled_separ:154,styled_t:[33,154],sub:[9,11,36,37,38,57,65,69,88,90,108,109,116,119,137,138,143,149,164,166,172,178,236,238,240,243,252,253,262,314,320,321,343,346,361,364],sub_ansi:321,sub_app:133,sub_brightbg:321,sub_dblspac:343,sub_mxp_link:343,sub_mxp_url:343,sub_text:343,sub_to_channel:164,sub_xterm256:321,subbed_chan:164,subcategori:166,subclass:[27,64,105,109,118,119,125,159,246,251,256,277,290,296,318,335,340,344,364],subdir:127,subdirectori:[37,127],subdomain:[8,90,103],subfold:[47,86,95,96,134,135],subhead:38,subject:[36,39,81,86,90,124,364],submarin:121,submenu:[106,249],submiss:357,submit:[17,37,103,133,171,357],submodul:291,subnegoti:291,subnet:[12,157],subpackag:[88,127],subprocess:[25,344],subreddit:79,subscrib:[12,33,34,41,53,58,64,80,115,128,132,146,164,175,176,177,261,278,309],subscribernam:164,subscript:[33,58,79,115,132,164,176,177,261],subscriptionhandl:177,subsequ:[10,11,33,95,116,322,344],subsequent_ind:330,subset:[56,112,127],subsid:125,substitut:[51,71,87,106,247,321,343],substr:321,subsub:[166,170],subsubhead:38,subsubsubhead:38,subsubtop:[166,170],subsubtopicn:170,subsystem:[9,63,86,242],subtitl:17,subtop:[164,166,170],subtopic_separator_char:166,subtract:85,subturn:116,subword:344,succe:[61,116],succeed:164,success:[73,116,123,134,144,164,175,242,251,260,267,271,318,326,338,344],successfulli:[10,28,33,36,60,77,110,111,130,144,247,260,267,279,311,318],suddenli:[26,97,318],sudo:[63,67,100,103],suffic:[17,57,61],suffici:[86,90,119],suffix:[27,97,114,321,337,344],suggest:[1,23,25,37,38,48,51,52,55,61,68,70,90,95,97,125,138,140,151,166,247,344],suggestion_cutoff:166,suggestion_maxnum:166,suit:[29,34,55,64,117,139,170,344,364],suitabl:[21,25,33,37,55,63,64,80,83,87,88,90,112,131,147,152,164,242,301,308,324,328],sum:[37,82,91,139,153],summar:[0,79,139],summari:[0,7,46,79,96,110,123,364],sun:62,sunris:62,sunt:52,super_long_text:329,superflu:343,supersus:242,superus:[2,4,5,6,9,12,13,14,19,20,21,23,25,41,58,60,63,81,95,96,111,122,134,144,147,148,158,169,175,241,242,247,252,267,318,322,324,364],supplement:51,suppli:[10,11,27,34,37,51,58,59,63,68,72,74,84,88,93,102,105,109,112,114,115,116,123,127,148,153,154,157,159,164,169,170,176,245,246,247,251,256,261,278,308,318,326,331,341,344],supporst:294,support:[2,4,7,8,9,11,23,26,33,37,38,40,42,44,47,49,50,51,56,57,58,61,63,64,65,66,70,74,75,76,81,83,86,87,90,91,94,98,100,103,109,110,113,114,123,126,139,144,156,165,166,169,241,247,251,252,261,272,280,281,282,283,287,289,290,291,292,294,296,307,316,321,325,328,329,330,341,342,344,349,364],supports_set:[74,272],suppos:[0,33,51,61,76,83,109,119,138,144],supposedli:[67,291],suppress:[24,289],suppress_ga:[141,142,262,275,364],suppressga:289,supress:289,sur:79,sure:[0,2,4,5,8,9,11,12,13,14,15,19,20,21,23,25,28,29,30,31,33,36,37,38,41,42,44,49,51,57,58,60,61,62,63,67,71,72,73,75,78,80,81,86,87,89,90,91,93,95,96,97,100,102,105,106,109,110,111,112,113,115,116,118,123,125,126,127,128,131,133,134,136,137,138,140,144,146,152,153,154,156,159,167,176,238,241,242,247,251,252,258,267,271,277,279,284,305,311,312,313,317,318,321,323,325,328,334,340,341,343,344,360],surfac:[58,82,103],surpris:[22,39,69,80,91],surround:[31,33,111,116,119,129,157,340,344,364],surviv:[5,11,27,28,31,50,51,84,102,105,115,116,126,146,153,169,245,255,256,257,261,324,326,328,344],suscept:[27,56,242],suspect:133,suspend:[100,103,106],suspens:102,suspici:51,suspicion:133,svn:[36,108],swallow:[96,118,272,276,343],swap:[43,114,127,137,138,159,318,326,364],swap_autoind:326,swap_object:318,swap_typeclass:[60,125,144,318],swapcas:321,swapcont:138,swapper:318,swedish:76,sweep:102,swiftli:10,swing:[28,29,33,82],switch1:129,switch2:129,switch_map:159,switch_opt:[156,157,158,159,164,165,166,167,169],sword:[20,28,33,61,73,77,85,86,119,245,252,341,344],symbol:[14,15,33,49,75,106,108,119,171,329],symlink:[38,63],symmetr:330,sync:[64,83,105,131,255,285,290,305,306,307,308,316,325],sync_port:308,syncdata:[307,308],syncdb:127,synchron:[337,364],syntact:[242,344],syntax:[5,6,13,14,15,21,22,23,29,33,41,46,48,51,55,58,60,62,76,80,91,97,114,119,123,129,134,141,142,154,158,159,166,167,170,242,247,267,279,306,316,318,320,321,364],syntaxerror:60,sys_cmd:152,sys_game_tim:59,syscmdkei:[33,53,141],syscommand:[141,142,149,155,247,364],sysroot:75,system:[0,2,4,5,9,10,11,19,21,22,23,26,27,28,29,31,34,36,37,38,39,40,41,43,44,46,47,49,53,55,56,59,60,62,63,64,67,74,75,76,77,79,81,83,84,85,86,87,90,93,95,97,102,103,104,105,107,108,109,110,111,112,114,115,119,121,122,125,126,127,128,129,131,132,134,136,138,139,140,141,142,146,148,149,150,152,154,155,156,158,159,166,168,170,172,175,176,177,236,239,241,242,246,247,249,251,252,253,267,290,296,304,314,318,322,324,327,328,337,363,364],system_command:33,systemat:39,systemctl:8,systemd:67,systemmultimatch:168,systemnoinput:168,systemnomatch:168,tab:[9,14,26,30,36,59,69,95,96,106,114,137,138,321,330,343],tabl:[0,4,13,15,45,46,48,53,58,59,64,69,82,88,97,111,113,114,119,125,128,134,154,156,164,166,169,291,310,321,327,329,330,341,344,364],table_char:327,table_format:156,table_lin:330,table_str:58,tablea:327,tableb:327,tablechar:[58,327],tableclos:[88,291],tablecol:330,tableopen:[88,291],tablet:16,tabletop:[58,73,79,124],tabsiz:[321,330],tabstop:343,tack:[20,119,153],tackl:37,tactic:[73,116],taction:116,tag:[9,12,13,18,20,24,33,43,45,48,51,55,57,58,73,74,86,87,88,95,96,100,109,114,119,124,125,134,136,137,138,139,140,141,142,147,154,156,157,158,159,164,165,166,167,168,169,170,171,175,176,177,238,239,241,245,247,251,252,255,282,296,298,304,314,317,318,321,324,326,327,328,329,330,341,342,344,364],taghandl:[112,125,319],tagkei:[241,245,319,324],taglin:17,tagnam:252,tagstr:[252,319],tagtyp:[112,317,319,341],tail:[76,90,100,267,337],tail_log_fil:[267,337],tail_log_funct:337,tailor:[4,69,357],take:[0,3,4,9,10,11,13,14,15,16,17,19,20,21,22,25,26,27,28,29,31,33,37,38,40,42,46,49,51,52,55,56,57,58,62,64,69,70,74,75,76,77,79,80,83,85,90,91,95,96,103,104,105,106,108,109,111,114,116,119,121,122,123,124,125,126,127,133,134,136,138,139,144,146,151,152,156,168,175,177,242,252,287,295,298,307,308,317,318,321,326,327,328,329,338,342,344,345],taken:[31,56,64,103,116,120,121,123,165,238,247,287,311,321,324],takeov:309,taladan:48,tale:3,talk:[23,27,33,34,37,40,41,46,58,60,90,91,131,138,164,165,264],talker:[55,61],talki:64,talking_npc:[141,142,178,364],tall:[129,165],tallman:165,tandem:61,tantal:14,target:[21,25,28,29,30,33,34,40,58,73,88,103,114,116,119,123,127,136,138,144,154,159,164,165,169,175,177,245,247,257,317,321,324,328,344],target_loc:247,target_obj:242,task:[0,27,36,40,41,91,93,102,110,112,138,169,170,260,261,344],task_handl:[141,260,344],task_id:[169,260],taskhandl:[141,142,253,344,364],taskhandlertask:[260,344],tast:[22,34,133],tax:[75,93],taylor:79,tb_basic:[141,142,178,216,364],tb_equip:[141,142,178,216,364],tb_filenam:322,tb_item:[141,142,178,216,364],tb_iter:322,tb_magic:[141,142,178,216,364],tb_rang:[141,142,178,216,364],tbodi:134,tchar:116,tcp:[55,103],tcpserver:[40,312],teach:124,team:[33,36,61,64,70,108,131],teamciti:364,teardown:[127,170,293,342],teardown_account:342,teardown_sess:342,teaser:90,tech:[79,364],technic:[4,6,9,10,11,19,20,23,39,40,51,64,70,83,90,108,112,114,119,125,139,316,364],techniqu:[29,139,321],tediou:[1,106,111],teenag:[21,103],tehom:[9,119],tehomcd:9,tel:[0,12,43,58,63,91,121,159],teleport:[12,14,20,43,58,85,122,140,159,165,322],teleport_her:159,televis:31,tell:[0,3,5,8,10,12,13,19,21,22,23,26,29,31,33,41,42,43,46,49,51,58,59,60,61,69,73,74,75,76,77,80,83,86,87,90,91,93,95,96,100,102,103,109,110,116,117,121,127,128,130,131,132,134,135,139,146,156,164,165,177,247,267,285,296,308,326],telnet:[9,15,25,30,40,55,63,64,75,79,83,100,101,103,105,110,114,137,138,141,142,166,169,262,275,280,281,282,283,287,288,289,291,292,294,298,306,307,343,364],telnet_:90,telnet_hostnam:54,telnet_interfac:90,telnet_oob:[88,141,142,262,275,364],telnet_port:[9,36,54,90,299],telnet_ssl:[141,142,262,275,364],telnetoob:291,telnetprotocol:[288,290,292],telnetserverfactori:290,temp:177,templat:[2,3,4,5,27,31,47,64,81,87,104,107,109,123,125,131,134,135,136,137,138,141,142,164,165,167,175,247,267,296,306,307,316,320,327,347,350,355,364],template2menu:[51,328],template_overrid:[4,135,136,137],template_regex:316,template_rend:107,template_str:[51,87],templates_overrid:135,templatestr:327,templatetag:[141,142,346,356,364],tempmsg:[177,364],temporari:[6,11,110,122,127,131,153,177,261,328,364],temporarili:[20,26,31,51,60,90,97,102,127,164,169],tempt:[61,95,104,157],ten:[29,90,111],tend:[41,57,61,64,73,76,86,90,97,103,119,121,124,129,138,159],tent:[45,111,139],terabyt:25,term:[0,10,31,62,63,64,69,90,91,96,126,139,154,310],term_siz:[42,141],termin:[4,23,26,27,38,42,47,59,60,63,64,75,90,93,95,96,97,100,103,106,110,114,123,126,131,138,139,141,169,266,267,287,294,310],terminalrealm:287,terminals:287,terminalsessiontransport:287,terminalsessiontransport_getp:287,termux:364,terrain:49,terribl:280,ters:102,test1:[11,74,330],test2:[11,33,74,114],test3:[11,330],test4:[11,330],test5:11,test6:11,test7:11,test8:11,test:[0,5,10,11,13,14,15,17,19,20,21,22,23,24,25,29,31,33,36,37,38,41,42,45,46,50,51,56,58,60,61,62,63,65,67,68,69,72,73,74,79,80,81,85,89,90,91,95,96,98,106,107,109,111,115,116,120,124,130,131,132,133,137,138,139,141,142,147,149,151,155,156,158,166,169,178,191,207,208,222,251,262,269,272,275,296,297,298,302,318,320,321,322,324,328,332,342,344,346,348,356,364],test_:127,test_about:170,test_access:170,test_active_task:170,test_alternative_cal:127,test_amp_in:293,test_amp_out:293,test_attribute_command:170,test_ban:170,test_batch_command:170,test_bold:293,test_c_creates_button:303,test_c_creates_obj:303,test_c_dig:303,test_c_examin:303,test_c_help:303,test_c_login:303,test_c_login_no_dig:303,test_c_logout:303,test_c_look:303,test_c_mov:303,test_c_move_:303,test_c_move_n:303,test_c_soci:303,test_cal:170,test_cancel:170,test_cas:127,test_channel__al:170,test_channel__alias__unalia:170,test_channel__ban__unban:170,test_channel__boot:170,test_channel__cr:170,test_channel__desc:170,test_channel__destroi:170,test_channel__histori:170,test_channel__list:170,test_channel__lock:170,test_channel__msg:170,test_channel__mut:170,test_channel__noarg:170,test_channel__sub:170,test_channel__unlock:170,test_channel__unmut:170,test_channel__unsub:170,test_channel__who:170,test_char_cr:170,test_char_delet:170,test_color:293,test_color_test:170,test_copi:170,test_creat:170,test_data_in:293,test_data_out:293,test_desc:170,test_desc_default_to_room:170,test_destroi:170,test_destroy_sequ:170,test_dig:170,test_do_nested_lookup:170,test_do_task:170,test_echo:342,test_emit:170,test_empty_desc:170,test_examin:170,test_exit_command:170,test_find:170,test_forc:170,test_func_name_manipul:170,test_general_context:352,test_get:360,test_get_and_drop:170,test_get_authent:360,test_get_dis:360,test_giv:170,test_help:170,test_hom:170,test_ic:170,test_ic__nonaccess:170,test_ic__other_object:170,test_ident:293,test_idl:303,test_info_command:170,test_interrupt_command:170,test_invalid_access:360,test_inventori:170,test_ital:293,test_large_msg:293,test_list_cmdset:170,test_lock:170,test_lock_with_perm:360,test_locked_entri:360,test_look:170,test_memplot:303,test_messag:304,test_misformed_command:170,test_mudlet_ttyp:293,test_multimatch:170,test_mux_command:170,test_mycmd_char:127,test_mycmd_room:127,test_nam:170,test_nested_attribute_command:170,test_new_task_waiting_input:170,test_nick:170,test_no_input:170,test_no_task:170,test_object:170,test_object_cach:360,test_object_search:127,test_ooc:170,test_ooc_look:170,test_opt:170,test_pag:170,test_password:170,test_pause_unpaus:170,test_perm:170,test_persistent_task:170,test_pi:170,test_plain_ansi:293,test_pos:170,test_quel:170,test_queri:[141,142,262,297,364],test_quit:170,test_remov:170,test_resourc:[127,141,142,170,293,320,360,364],test_responce_of_y:170,test_return_valu:127,test_sai:170,test_script:170,test_script_multi_delet:170,test_server_load:170,test_sess:170,test_set_help:170,test_set_hom:170,test_set_obj_alia:170,test_simpl:127,test_simple_default:170,test_spawn:170,test_split_nested_attr:170,test_subtopic_fetch:170,test_subtopic_fetch_00_test:170,test_subtopic_fetch_01_test_creating_extra_stuff:170,test_subtopic_fetch_02_test_cr:170,test_subtopic_fetch_03_test_extra:170,test_subtopic_fetch_04_test_extra_subsubtop:170,test_subtopic_fetch_05_test_creating_extra_subsub:170,test_subtopic_fetch_06_test_something_els:170,test_subtopic_fetch_07_test_mor:170,test_subtopic_fetch_08_test_more_second_mor:170,test_subtopic_fetch_09_test_more_mor:170,test_subtopic_fetch_10_test_more_second_more_again:170,test_subtopic_fetch_11_test_more_second_third:170,test_tag:170,test_task_complete_waiting_input:170,test_teleport:170,test_tunnel:170,test_tunnel_exit_typeclass:170,test_typeclass:170,test_upp:127,test_valid_access:360,test_valid_access_multisession_0:360,test_valid_access_multisession_2:360,test_valid_char:360,test_view:360,test_wal:170,test_whisp:170,test_who:170,test_without_migr:127,test_wrong_func_nam:170,testabl:127,testaccount:170,testadmin:170,testampserv:293,testapp:133,testbatchprocess:170,testbuild:170,testcas:[127,293,303,335,342,352],testcmdtask:170,testcomm:170,testcommand:51,testcommschannel:170,testdummyrunnerset:303,testdynamic:127,tester:[90,119,285],testform:327,testgener:170,testgeneralcontext:352,testhelp:170,testid:33,testinterruptcommand:170,testirc:293,testmemplot:303,testmenu:328,testmixedrefer:335,testmod:308,testmymodel:127,testnnmain:170,testnod:51,testobj:127,testobject:127,testobjectdelet:335,testok:91,testregularrefer:335,testset:127,testsharedmemoryrefer:335,teststr:127,testsystem:170,testsystemcommand:170,testtelnet:293,testunconnectedcommand:170,testvalu:11,testwebsocket:293,text2html:[141,142,320,364],text:[0,1,2,5,7,9,10,13,14,15,17,18,21,22,24,26,30,33,34,35,37,40,43,45,46,48,50,52,53,55,56,57,58,59,60,63,68,72,73,76,77,78,79,80,81,83,85,86,87,88,90,91,95,96,97,98,100,108,109,110,111,112,118,121,123,124,126,127,131,133,137,138,139,144,146,151,154,156,157,158,159,164,165,166,167,168,169,170,171,176,177,239,242,247,249,252,256,264,265,272,278,279,282,285,286,287,290,291,295,296,298,306,307,308,311,312,316,317,319,321,322,324,326,327,328,329,330,338,341,342,343,344,345,357,364],text_:38,text_exit:22,text_single_exit:22,textarea:[340,357],textbook:40,textbox:357,textfield:[86,133],textn:170,textstr:74,texttag:[81,126,139,364],texttohtmlpars:343,textual:39,textwrap:330,textwrapp:330,than:[0,2,4,6,8,11,13,14,16,19,23,25,26,29,31,33,35,37,38,39,42,46,47,49,51,52,54,55,57,58,60,61,62,64,68,69,71,73,76,80,82,86,89,90,91,93,95,97,103,104,105,106,109,110,112,113,114,115,116,119,122,123,125,126,127,128,129,131,134,135,137,138,139,144,148,151,152,153,156,157,158,159,160,166,167,169,170,241,245,247,249,251,267,293,308,313,316,317,318,319,321,322,328,329,330,334,337,339,340,341,343,344,347],thank:[4,102,134,138,312],thankfulli:133,thead:134,thei:[0,1,2,4,5,6,8,9,10,11,12,13,14,15,16,17,19,20,21,22,23,25,27,29,30,31,33,34,37,38,39,40,41,42,44,46,48,51,55,56,57,58,61,63,64,66,68,69,73,75,77,78,80,81,83,85,86,88,89,90,91,92,93,95,96,97,102,103,105,106,107,108,109,110,111,112,113,114,116,118,119,121,122,123,124,125,126,127,131,132,134,136,137,138,139,140,144,152,153,156,158,159,164,165,167,168,169,175,241,242,246,247,251,252,253,256,258,259,261,267,287,288,290,291,292,296,299,305,306,307,308,310,316,321,322,323,325,328,330,344,345,357],theirs:116,them:[0,2,4,5,6,9,10,11,12,13,14,15,16,21,22,23,25,26,27,28,29,30,31,33,34,35,37,38,39,40,41,46,48,50,51,54,55,57,58,59,60,61,62,64,66,68,69,71,73,74,75,76,77,80,82,83,85,86,87,88,89,90,91,95,96,97,98,102,103,104,105,106,109,110,111,112,113,114,115,116,118,119,121,122,123,124,125,126,127,128,131,133,134,135,136,137,138,139,140,144,150,151,152,154,156,158,159,164,166,167,170,175,176,238,242,247,252,258,261,267,285,287,290,298,302,305,306,308,316,318,319,321,322,324,328,340,342,343],themat:61,theme:[61,134],themselv:[0,11,19,21,28,31,33,38,49,51,55,58,69,72,73,80,81,85,89,97,102,107,113,119,121,123,125,127,132,138,140,159,247,256,259,267,317,319,340],theoret:[31,108],theori:[31,42,57,79,123,139,144,152,364],thereaft:87,therefor:[0,49,62,68,91,102,122,127,158],therein:[15,33,156,167,169,171],thereof:247,thess:245,thi:[0,1,2,3,4,5,6,8,9,10,11,12,13,14,15,16,18,19,20,21,22,23,24,25,26,27,28,29,30,31,33,34,35,36,37,38,39,40,42,43,44,45,46,47,48,49,50,51,52,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,70,71,72,73,74,75,76,77,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,175,176,177,178,236,238,239,240,241,242,243,245,246,247,250,251,252,253,255,256,257,258,259,260,261,262,264,265,266,267,269,271,272,273,274,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,294,295,296,298,299,300,301,302,304,305,306,307,308,309,310,311,312,313,314,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,334,335,337,338,339,340,341,342,343,344,345,346,347,349,350,354,355,357,361,363,364],thie:51,thief:61,thieveri:166,thin:[10,22,29,111,337],thing:[0,1,3,4,5,6,8,9,10,11,12,13,15,19,20,21,22,25,26,27,28,29,30,31,33,34,37,39,40,41,46,47,48,49,50,51,55,58,59,60,61,63,64,67,69,70,71,73,74,75,76,79,80,82,83,85,86,89,90,91,93,95,96,97,100,102,103,104,105,107,108,109,110,111,114,115,116,118,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,144,152,153,159,242,246,247,276,280,312,316,318,321,322,330,340,364],think:[1,20,29,31,34,37,46,48,51,55,59,61,62,67,70,73,79,81,91,95,96,97,109,111,112,114,115,135,138,139,308],third:[0,8,9,23,27,37,38,39,42,51,64,69,72,75,90,96,101,114,121,127,128,134,159,170,321,328,364],thirdnod:51,this_sign:309,thoma:[12,87,157],thorn:[11,89],thorough:26,those:[2,3,4,6,9,11,13,14,15,19,20,21,23,28,30,31,33,35,36,44,47,48,51,55,56,57,58,60,61,62,64,68,71,73,77,78,79,80,81,85,86,88,89,90,95,96,103,105,109,110,111,112,114,118,119,121,123,124,125,127,128,130,131,135,136,138,153,154,156,159,164,165,166,170,176,242,251,252,255,260,290,295,298,317,318,328,329,330,338,339,342,344,357],though:[2,10,11,12,13,14,15,22,23,26,27,30,31,37,39,41,51,57,59,60,62,63,64,69,72,75,79,81,89,90,91,96,97,100,102,103,104,110,116,119,121,122,123,126,127,128,129,130,131,138,144,154,247,251,252,316,321,328,344],thought:[23,39,61,79,80,84,138],thousand:[39,90,111,133],thread:[23,27,55,79,110,286,312,337,344],threadpool:312,threat:103,three:[0,4,12,13,16,22,25,31,33,38,46,51,69,80,83,85,87,89,90,114,133,134,135,151,164,166,242,321,328],threshold:[310,322],thrill:85,throttl:[141,142,144,262,272,285,364],through:[0,1,2,5,9,13,14,17,23,25,27,30,31,33,34,38,39,40,41,44,46,48,51,52,55,56,57,58,59,60,61,62,64,68,69,70,71,76,77,80,83,85,87,88,89,90,91,93,96,97,98,99,103,104,105,106,107,108,109,110,114,116,117,119,121,122,124,136,138,139,140,141,144,153,159,164,166,240,242,246,247,257,258,261,267,269,274,283,287,290,296,299,304,306,307,317,318,322,324,327,328,329,342,343,344,357,364],throughout:[11,20,49,51,55,104],throughput:[175,176,324],thrown:116,thu:[14,19,31,33,39,44,51,54,57,58,73,80,83,86,96,108,111,114,121,122,123,125,134,135,136,147,156,160,242,247,261,299,313,316,317,324],thumb:[114,131],thumbnail:4,thunder:23,thunderstorm:122,thusli:75,tick:[23,33,38,51,64,115,131,132,139,261,299],ticker1:[115,261],ticker2:[115,261],ticker:[43,53,55,74,102,132,139,146,169,257,261,272,344,364],ticker_class:261,ticker_handl:[53,115,132,141,261,344],ticker_pool_class:261,ticker_storag:261,tickerhandl:[27,45,102,116,132,139,141,142,169,253,344,364],tickerpool:261,tickerpool_layout:261,tidbit:55,tidi:100,tie:[83,116,138,364],tied:[64,119,153,166,239,255],tier:90,ties:[49,135,161],tightli:[103,175],time:[0,1,2,4,5,6,8,9,10,11,12,13,14,17,20,21,22,23,25,26,28,29,30,31,34,36,37,39,40,41,42,43,45,49,51,52,53,54,55,56,58,59,60,61,63,64,65,66,67,69,70,72,73,75,80,83,86,88,89,90,91,93,95,96,100,104,105,106,109,110,113,114,115,116,117,119,121,122,123,124,125,127,128,129,131,132,133,135,138,139,144,146,148,150,151,153,154,157,164,169,175,176,177,239,246,247,250,252,253,255,256,259,260,261,267,269,271,273,274,279,285,290,292,298,299,300,304,305,306,308,310,316,318,319,321,322,323,324,329,331,334,335,337,340,344,363,364],time_factor:[27,62,331],time_format:[59,344,364],time_game_epoch:[27,62,331],time_unit:62,time_until_next_repeat:102,timedelai:[29,260,342,344],timedelta:[338,345],timefactor:62,timeformat:[337,344],timeit:93,timeout:[63,67,116,120,290,310,334],timer:[20,27,33,47,56,64,83,102,115,116,159,253,255,259,260,261,298,306,341,364],timerobject:102,timescript:331,timestamp:[25,27,298,299,310,331],timestep:299,timestr:337,timetrac:[141,142,262,297,364],timetupl:62,timezon:[23,337,338,345],tini:[23,39,81],tinker:97,tintin:[24,280,281,291,294],tinyfugu:24,tinymud:[57,108],tinymush:[57,108,129,171],tinymux:[57,108],tip:[12,37,70,79,103,112,364],tire:[20,153],titeuf87:364,titl:[17,22,34,38,48,69,98,137,164,166,176,238,321,324],title_lone_categori:166,titlebar:137,titleblock:69,tlen:71,tls:8,tlsv10:67,tlsv1:8,tmp:[36,63],to_byt:[344,364],to_dupl:152,to_execut:344,to_exit:0,to_non:247,to_obj:[144,154,247],to_object:176,to_pickl:325,to_str:[344,364],tobox:276,toc:363,todai:138,todo:58,toe:108,togeth:[0,3,8,9,14,22,29,31,33,38,48,49,57,58,61,64,68,71,73,83,89,90,92,116,119,122,123,124,125,126,127,131,138,150,159,161,166,245,246,252,276,295,308,321,322,341,364],toggl:[81,290],toggle_nop_keepal:290,togglecolor:81,toint:109,token:[71,287,290,322],told:[44,59,90,91,95,113,114,123,128,340],tolkien:62,tom:[58,87,123,129,159,165,327],tommi:[19,80,87],ton:[57,82],tone:114,tonon:159,too:[0,4,6,9,11,12,13,14,17,20,21,22,25,27,29,33,38,39,41,42,46,47,48,49,51,57,58,59,60,61,63,69,73,80,83,84,85,91,93,96,106,114,116,121,122,123,125,128,131,133,138,157,159,178,241,245,272,276,310,312,319,322,327,328,329,330,341,344],took:[127,344],tool:[4,6,7,8,23,29,53,57,62,63,64,86,90,96,100,108,109,111,112,114,119,136,139,364],toolbox:79,tooltip:137,top:[5,9,13,22,26,29,31,33,38,39,47,48,50,52,57,58,59,60,63,68,69,75,79,85,93,95,96,101,102,104,110,111,112,117,123,125,130,131,133,134,138,139,148,153,177,239,246,256,267,309,316,318,319,322,329,330,337],topcistr:238,topic:[4,10,20,31,33,40,42,55,68,69,86,93,105,119,126,166,238,341,357],topicstr:238,tostr:276,total:[27,62,80,82,91,93,102,104,105,114,118,139,147,169,304,329,330,331],total_num:334,touch:[8,38,54,60,96,97,103,104,114,310],tour:91,toward:[22,33,40,42,91,102,111],tower:111,trace:[83,96,304,328],traceback:[6,13,27,57,60,95,97,102,110,114,123,127,133,135,250,276,318,322,337,344,364],tracemessag:304,track:[11,27,30,49,57,61,64,73,77,82,86,95,98,99,100,102,105,116,121,128,132,133,138,144,153,175,257,278,279,284,287,290,305,310,325,326,338,364],tracker:[43,61,70,131],trade:46,trader:46,tradit:[10,15,36,73,74,83,90,103,114,116,138,290,306,329],tradition:[57,83],traffic:[8,103,280],train:[79,364],traindriv:121,traindrivingscript:121,training_dummi:73,trainobject:121,trainscript:121,trainstop:121,trainstoppedscript:121,trait:[27,73,252],transfer:[85,133,153,278,288,292,330],transform:36,transit:[89,124],translat:[14,40,45,79,87,88,113,114,126,252,269,321,364],transmit:113,transpar:[67,105,126,137,138,245,246,261],transport:[276,287,296],transportfactori:287,transpos:126,trap:[14,82,122],traumat:51,travel:[49,82,83,88,96],travers:[11,44,49,80,85,89,121,241,247],traverse_:33,traversing_object:247,travi:[45,139,364],treasur:9,treat:[10,14,33,64,95,96,105,111,112,119,125,138,144,150,153,245,247,252,299,308,328,330,341,364],tree:[3,11,33,38,47,51,61,63,64,77,80,96,131,140,247,252,267,296,312,328,344],tree_select:[141,142,178,364],treshold:334,tri:[11,12,14,24,29,33,51,58,61,80,83,87,90,91,105,107,113,116,119,133,138,151,169,271,310,344,345],trial:[106,293],tribal:111,trick:[8,22,51,79,138,318,357,364],tricki:[109,126,127,138],trickier:[9,69],trigger:[21,24,31,33,36,42,46,49,51,56,57,69,74,83,84,89,100,105,107,114,115,116,117,118,121,134,135,138,144,146,150,151,154,156,170,246,247,252,255,261,269,272,276,298,305,309,324,328],trim:321,trip:96,tripl:[27,38,96,114,344],trivial:[27,33,40,42,91,93,138],troll:12,troubl:[5,8,9,23,41,46,58,63,70,75,91,105,131,139,316,363],troubleshoot:[9,364],troublesom:[12,13,14],trove:9,truli:[0,12,39,41,105],trust:[19,51,57,169,322],truth:42,truthfulli:33,truthi:260,try_num_differenti:151,ttarget:116,tto:290,tty:[9,100],ttype:[55,141,142,262,275,287,290,364],ttype_step:294,tuck:111,tun:[43,159],tune:[67,126],tunnel:[0,20,22,43,44,49,58,121,159,292],tup:39,tupl:[11,39,41,42,51,59,60,80,86,87,88,90,109,116,119,134,141,144,151,157,159,164,166,167,176,238,241,242,245,247,251,252,255,261,264,267,276,277,287,288,292,299,306,308,316,319,321,323,324,326,328,331,337,339,344],tupled:337,turbo:75,turkish:144,turn:[0,10,12,27,31,33,38,41,50,51,57,58,64,66,77,79,80,81,83,88,90,96,102,105,107,110,111,114,117,118,121,122,126,127,131,133,135,138,139,144,154,169,170,175,176,247,252,267,272,280,287,290,298,308,314,318,322,324,328,329,330,342,344,347,364],turn_act:116,turnbattl:[141,142,178,364],tut:122,tutori:[3,4,10,16,17,20,22,25,26,28,29,31,32,33,35,37,38,39,41,42,45,48,49,51,55,57,58,60,61,63,64,70,71,77,79,81,82,90,91,95,102,111,112,114,115,126,133,135,139,170,363,364],tutorial_exampl:[13,14,20,102,141,142,178,364],tutorial_world:[20,22,63,122,141,142,178,364],tweak:[8,9,25,57,58,67,97,102,109,117,119,125,138,144,312,321,342,364],tweet:[124,139,364],tweet_output:120,tweet_stat:120,tweetstat:120,twenti:58,twice:[25,51,62,116,328],twist:[10,27,29,33,40,63,72,75,79,97,103,247,260,264,267,269,270,276,277,278,279,284,287,290,293,295,296,298,305,308,312,337,364],twistd:[63,106,110,284,305],twistedcli:40,twistedweb:103,twitch:[41,116],twitter:[7,55,120,139,364],twitter_api:71,two:[0,4,11,13,14,15,16,19,22,23,25,26,27,28,29,31,33,34,38,39,40,41,44,46,47,49,50,51,57,58,64,65,67,68,69,73,74,76,80,83,84,85,86,88,89,90,91,92,95,97,100,102,103,104,105,108,109,110,111,112,113,116,119,121,122,123,125,126,127,129,131,133,134,135,137,138,139,140,152,159,164,175,177,247,249,267,296,307,308,317,319,322,328,330,337,344,345,364],twowai:159,txt:[9,38,40,50,75,78,90,96,146,283,291,326,328,344],tyepclass:245,tying:[90,347],type:[0,8,12,14,16,17,19,20,21,22,24,25,26,27,28,29,31,33,34,35,37,41,42,43,44,46,47,49,50,51,55,56,57,58,59,61,62,64,73,75,77,79,80,81,82,83,86,87,88,90,91,95,96,97,102,103,105,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,125,126,128,133,137,138,139,144,146,154,159,164,166,169,170,171,175,176,177,239,241,242,246,247,251,252,255,260,261,265,267,269,270,276,278,279,285,287,288,290,291,292,294,295,296,298,306,308,312,316,317,318,319,321,322,324,325,328,329,330,339,340,341,343,344,351,357,364],typecalass:316,typeclass:[0,2,5,9,11,12,13,20,21,22,25,26,27,33,34,38,39,43,44,47,49,56,58,60,61,62,66,69,73,76,77,80,82,83,84,85,89,91,96,102,105,107,109,111,112,116,117,118,120,121,122,123,127,132,133,134,139,141,142,144,146,147,148,153,159,164,175,176,177,178,191,238,242,245,246,247,251,252,255,256,257,259,261,305,323,324,341,342,344,360,364],typeclass_path:[102,119,125,148,159,256,317,318],typeclass_search:[147,245,255,317],typeclassbas:96,typeclassmanag:[147,176,245,255],typedobject:[41,125,148,154,177,246,247,256,316,317,318,319,339,344],typedobjectmanag:[147,176,238,245,255,317],typeerror:[42,296],typenam:[22,144,146,148,175,177,239,246,247,251,256,259,274,300,316,318,331,334,335],typeobject:319,typic:[27,55,91,127],typo:[37,38,70,103,363],ubbfwiuvdezxc0m_2pm6ywo:37,ubuntu:[8,63,67,90,97,103,131],uemail:147,ufw:103,ugli:[56,109,137,338],uid:[100,147,148,279,286,307,308],uit:22,ulrik:58,ultima:79,umlaut:15,unabl:71,unaccept:33,unaffect:[51,116,260],unalia:164,unam:147,unassign:138,unauthenticated_respons:360,unavoid:115,unban:[12,157,164,170,175],unban_us:164,unbroken:327,uncal:260,uncas:321,uncategor:341,unchang:[87,97,127,252,344],unclear:[30,363],uncolor:[81,114],uncom:[67,90],uncommit:131,uncompress:280,unconnect:171,undefin:[36,86,112],under:[6,9,20,24,33,36,38,41,42,46,48,51,57,60,61,63,64,73,75,77,78,79,86,90,93,100,106,108,110,119,122,123,125,128,133,134,135,136,137,154,156,159,242,259,267,294,316,321,328,329,330,344,364],underli:[57,61,64,80,119,124,131],underlin:[330,343],underneath:[9,318],underscor:[0,38,51,74,88,95,97,114,119,152,344],underscror:152,understand:[4,10,15,24,25,26,29,30,31,33,37,38,39,41,42,44,48,49,55,60,61,63,79,81,83,91,95,96,103,104,105,109,111,113,114,123,124,127,131,133,134,136,139,151,152,164,312,321,344,364],understood:[83,91,111,127,295,296],undestand:25,undo:[50,103,326],undon:156,undoubtedli:57,unexpect:[91,126,127,328,344],unexpectedli:334,unfamiliar:[63,74,80,88,90,118,124],unformat:[51,328,331],unfortun:[4,41,61],ungm:364,unhandl:60,unhappi:9,unhilit:343,unicod:[15,83,113,144,321,344],unicodeencodeerror:321,unicorn:119,unifi:[133,307],uniform:105,uninform:8,uninstal:[63,364],uninstati:344,union:[31,51,152,328],uniqu:[2,12,13,20,31,33,35,36,38,40,46,51,55,57,60,61,64,71,80,83,84,90,95,96,102,105,109,112,119,123,125,127,137,138,144,147,150,152,154,159,164,171,175,176,238,247,251,252,255,261,264,276,277,285,298,299,307,308,316,317,318,319,324,326,338,341,344],unit:[27,31,34,36,37,45,47,55,62,64,79,82,107,124,130,139,176,269,324,331,344,364],unittest:[25,127,170,245,308,324,342],univers:[14,15,62],unix:[24,38,52,63,87,165,329,337,344],unixcommand:[141,142,178,364],unixtim:337,unknown:[41,56,69,137,251,344],unleash:28,unless:[4,5,11,12,21,22,23,27,29,33,38,51,72,78,80,84,88,89,90,96,102,110,115,123,138,140,144,152,153,157,159,164,166,167,175,241,242,247,252,265,280,296,308,316,318,341,342,344,345],unlik:[37,51,64,73,90,107,127,144,318],unlink:[43,159],unload:342,unload_modul:342,unlock:[58,77,80,164,316],unlocks_red_chest:80,unlog:[157,162,163,171,308],unloggedin:[105,141,142,149,155,308,364],unloggedincmdset:[35,43,105,163],unlucki:12,unmodifi:[151,168,328],unmonitor:[272,364],unmut:[164,175],unmute_channel:164,unnam:[112,152],unneccesari:113,unnecessari:[36,61],unpaced_data:276,unpack:[91,241],unpars:[74,87,151,295,296],unpaus:[100,102,159,169,260],unpickl:[83,276,316,325,340],unplay:[25,105],unpredict:344,unprivileg:252,unprogram:73,unpuppet:[43,96,107,123,156],unpuppet_al:144,unpuppet_object:[2,144],unquel:[20,43,80,122,156],unreal:79,unrecord_ip:310,unregist:135,unrel:[51,131],unrepat:344,unrepeat:[272,344,364],unreport:272,unsaf:[110,152,344],unsafe_token:321,unsatisfactori:111,unsav:326,unsel:85,unset:[33,49,58,89,116,157,242,247,251,252,255,261,316,324,328,329,330,337,342],unset_lock:164,unsign:345,unsigned_integ:[338,345],unsignedinteg:338,unstabl:100,unstrip:151,unsub:164,unsub_from_channel:164,unsubscrib:[58,115,261,278],unsuit:[19,251,319],unsur:[15,37,63,71,76,90,116,138],untag:137,untest:[24,61,63,127],until:[5,8,10,11,12,13,20,26,29,30,31,33,36,48,51,61,63,64,86,87,93,95,97,102,114,115,119,123,126,131,136,137,138,139,247,260,267,296,298,316,321,322,331,344],untouch:321,untrust:[13,344],unus:[33,81,144,150,154,164,175,247,259,290,306,311,317],unusu:[103,119],unwant:139,unwieldli:153,upcom:54,updat:[2,4,5,8,9,11,13,14,20,23,24,28,29,30,33,36,38,39,43,45,49,51,55,57,58,61,62,63,64,68,71,73,75,76,79,81,83,84,86,88,89,90,91,95,97,98,100,102,115,116,123,127,133,134,135,136,137,138,139,146,153,154,159,164,167,169,170,175,239,242,246,247,249,250,252,255,257,283,285,286,291,305,306,308,310,316,318,325,326,327,328,329,330,334,344,357,360,364],update_attribut:316,update_buff:326,update_cached_inst:334,update_charsheet:58,update_default:305,update_flag:306,update_po:49,update_scripts_after_server_start:255,update_session_count:306,update_undo:326,updatemethod:[137,138],upfir:106,upgrad:[63,64,75,364],upload:[4,63,64,90,100,364],upon:[14,29,61,80,86,90,96,100,103,113,117,123,258,269,278,310,329],upper:[29,39,86,101,114,127,138,156,321],uppercas:[114,321],upping:114,ups:7,upsel:90,upsid:41,upstart:40,upstream:[26,64,104,128,364],upt:153,uptim:[12,27,43,62,169,281,331],urfgar:109,uri:[154,175,239,318],url:[8,64,70,90,98,131,134,135,136,138,141,142,146,154,164,175,239,286,296,312,318,343,346,353,356,364],url_nam:360,url_or_ref:38,url_to_online_repo:131,urlencod:69,urlpattern:[3,4,69,133,134,135],usabl:[4,66,114,123,159,241,310,328],usag:[0,5,12,21,22,23,28,29,30,33,38,41,42,51,58,60,64,68,71,73,81,82,85,90,91,93,109,115,116,119,121,123,124,129,154,156,157,158,159,164,165,166,169,170,171,241,250,260,267,298,328,330,334,364],use:[0,2,3,4,5,6,8,9,10,11,12,13,14,15,16,17,19,20,21,22,23,24,25,26,27,28,29,31,33,34,35,36,37,38,39,40,41,42,46,47,48,49,50,51,52,54,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,76,79,80,81,82,83,84,85,86,87,88,89,90,91,93,95,96,98,100,102,103,104,105,106,107,108,109,111,112,113,114,116,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,144,146,147,148,150,151,152,153,154,156,159,160,164,165,166,167,169,170,171,175,176,177,241,242,245,246,247,251,252,260,261,265,272,276,289,291,292,295,298,299,306,307,308,316,317,318,319,321,322,323,324,326,327,328,329,330,334,337,338,340,342,344,345,364],use_dbref:[245,247,341],use_destin:247,use_i18n:76,use_nick:[144,247],use_required_attribut:357,use_xterm256:321,used:[0,2,3,7,9,10,11,13,15,16,17,19,20,22,23,24,27,29,30,31,34,35,38,40,41,46,47,48,50,51,52,54,55,56,57,58,59,60,62,63,64,67,68,69,72,73,74,79,80,82,83,84,85,86,87,88,89,90,91,93,95,96,100,102,103,104,105,107,108,109,110,111,112,113,114,115,116,118,119,120,121,122,123,124,125,126,127,128,129,131,133,134,135,136,137,139,141,144,146,150,152,153,154,156,159,164,166,167,168,169,170,171,175,176,238,239,240,241,242,245,247,251,252,257,259,260,261,262,264,265,269,272,273,276,277,278,279,280,281,282,283,284,285,287,289,290,291,294,295,296,299,306,308,309,316,317,318,319,320,321,322,324,325,326,328,329,330,337,338,339,340,341,342,344,345,357,363,364],used_kei:80,useful:[0,1,4,5,10,11,12,13,14,15,16,17,18,19,20,22,23,25,26,27,28,29,30,31,34,36,37,38,39,41,42,46,47,48,50,51,53,57,58,59,60,63,64,66,69,70,80,81,87,89,90,91,93,95,96,102,104,107,109,110,111,112,114,115,116,119,120,123,124,125,127,131,132,133,138,139,150,152,153,154,156,158,159,166,167,170,175,178,241,247,251,252,267,287,316,318,322,328,331,340,344,364],user:[2,4,7,8,10,11,12,13,14,20,22,23,25,28,29,30,31,35,36,37,40,41,42,49,50,51,52,55,60,63,64,65,66,67,68,70,71,72,74,75,76,77,79,80,81,85,87,88,90,91,93,95,97,98,100,101,104,105,107,109,113,114,119,121,122,123,125,126,127,133,134,135,136,137,138,139,144,146,148,151,154,157,159,164,166,169,175,176,177,239,242,247,252,259,262,265,271,279,286,287,290,295,296,306,308,311,316,318,321,326,328,329,330,338,342,344,345,347,349,357,364],user_input:51,user_permiss:148,userauth:287,usercreationform:357,usermanag:147,usernam:[2,4,12,35,51,74,100,107,119,131,134,144,148,287,311,349,357],username__contain:119,usernamefield:357,userpassword:[12,157],uses:[0,5,9,13,15,16,17,22,23,29,30,31,33,34,39,40,44,57,64,68,69,80,81,86,88,90,98,107,109,112,113,114,115,119,124,125,127,130,131,136,137,152,166,242,245,256,261,276,296,310,316,319,337,338,342,344,347],uses_databas:344,using:[2,4,5,6,8,9,10,11,12,13,14,15,19,20,21,22,23,24,25,26,27,28,29,30,31,33,34,36,37,38,39,41,43,45,46,47,49,50,51,53,55,56,57,58,59,60,61,62,63,64,67,68,70,71,72,73,74,77,78,79,80,81,83,85,86,87,88,89,90,91,93,95,96,97,100,101,102,103,105,107,108,109,110,111,112,114,115,116,117,118,120,121,122,123,124,125,126,128,129,131,132,133,134,137,138,139,140,144,148,150,153,154,156,158,159,164,166,167,168,169,175,242,245,247,250,251,252,256,260,261,278,279,280,285,286,290,296,299,308,309,310,312,316,318,319,321,322,326,328,329,331,337,338,339,340,341,342,344,346,357,363,364],usr:[63,64,75,100],usual:[0,2,4,5,6,8,9,11,19,20,21,22,23,25,26,27,29,30,31,33,34,37,38,40,41,46,47,50,51,52,57,59,60,62,63,64,67,72,74,80,81,87,89,90,91,93,95,96,97,100,102,105,106,109,110,112,114,115,119,124,125,126,127,131,133,136,144,146,147,151,152,153,154,156,159,164,165,169,170,177,242,245,246,247,251,252,267,269,274,299,306,316,318,321,323,324,328,329,337,339,341,342,344],utc:[23,345],utf8:[23,36],utf:[15,24,58,74,111,113,171,272,278,295,330,344],util:[8,10,11,13,14,16,34,41,45,47,48,49,50,51,52,57,58,59,62,63,81,82,85,86,89,96,97,102,103,111,114,117,124,127,133,134,137,139,141,142,158,169,170,175,177,178,191,239,245,247,249,251,259,260,274,293,298,316,317,318,346,357,360,364],utilis:328,v21:63,vagu:21,val:[11,88,144,156,291,344],valid:[1,11,13,26,30,31,33,42,44,51,58,60,67,69,88,89,90,91,95,96,97,102,103,109,110,114,119,123,133,134,141,142,144,147,151,153,159,167,175,176,242,247,249,251,252,255,257,259,260,261,262,265,267,291,295,306,316,317,319,322,324,328,338,339,340,341,342,343,344,345,357,364],valid_handl:338,validate_email_address:344,validate_nam:247,validate_onli:242,validate_password:[51,144],validate_prototyp:251,validate_sess:308,validate_usernam:144,validationerror:[144,251,311,338,340],validator_config:144,validator_kei:338,validatorfunc:[141,142,320,364],valign:330,valu:[0,2,4,6,10,11,12,17,20,22,25,27,28,31,33,38,39,41,42,49,50,58,59,60,61,62,64,67,69,73,74,77,80,81,82,84,85,86,87,88,90,97,102,111,114,115,116,123,125,126,127,128,133,134,137,138,139,144,147,148,150,152,154,156,157,159,175,177,239,241,242,245,246,247,250,251,252,255,256,260,261,265,272,273,274,276,285,290,291,306,307,308,313,316,317,318,319,321,323,324,325,326,327,328,334,335,338,339,340,341,342,344,345,357,364],valuabl:122,value1:[38,109],value2:[38,109],value3:38,value_from_datadict:340,value_to_obj:251,value_to_obj_or_ani:251,value_to_str:340,valueerror:[41,91,109,123,147,316,319,321,324,344,345],valuei:111,values_list:119,valuex:111,vanilla:[9,26,49,56,58,86,101,125],vaniti:51,vari:[30,40,60,64,82,108,114,125,131,306,316,318],variabl:[0,3,5,11,13,28,31,33,38,41,46,49,51,55,56,58,64,66,69,80,83,88,91,95,96,97,100,103,104,106,109,113,121,124,133,134,135,137,138,144,148,150,154,156,159,164,167,169,170,171,175,241,246,247,251,252,264,267,277,280,281,283,287,289,299,306,313,321,322,328,344,350,364],variable_from_modul:344,variablenam:344,variant:[11,55,112,153,278,321],variat:[62,73,116,152,344],varieti:[55,82,116,120],variou:[5,6,11,15,33,37,40,41,46,47,48,53,57,62,67,69,73,77,81,88,89,90,93,97,102,103,105,109,110,112,114,115,116,123,124,125,127,137,139,152,168,242,246,247,252,253,261,299,324,330,341,342,347],varnam:291,vast:[23,60,86,108,111,119],vastli:64,vcpython27:9,vector:344,vehicl:[21,124,139,364],velit:52,venu:[131,176],venv:[63,75],verb:[25,247,303],verbal:247,verbatim:364,verbatim_el:344,verbos:[26,116,127],verbose_nam:[133,318],veri:[0,2,4,5,6,8,9,10,11,13,14,17,20,21,22,23,26,27,28,29,31,33,35,37,38,39,40,41,42,46,49,50,51,52,55,56,57,58,60,61,64,67,68,70,72,73,74,77,78,79,80,85,86,88,90,91,93,95,96,97,104,107,108,109,110,111,112,114,115,116,119,121,122,123,125,127,128,129,131,132,134,137,138,139,140,144,146,152,154,170,175,176,177,238,246,251,271,317,319,324,326,328,344],verif:90,verifi:[36,51,63,90,131,159,292,342],verify_or_create_ssl_key_and_cert:292,verify_ssl_key_and_cert:288,versa:[40,61,88,105,116,164,276],version:[2,4,7,11,13,14,20,21,23,24,29,30,31,33,35,36,37,41,43,47,51,54,57,60,61,63,64,74,75,76,79,81,86,87,90,91,95,96,100,108,111,114,123,124,125,126,128,136,137,139,159,167,169,171,247,252,267,272,286,310,316,321,329,344,357,363,364],version_info:267,versionad:38,versionchang:38,versu:[55,364],vertic:[138,330,344],very_strong:242,very_weak:80,vest:103,vet:109,veteran:79,vfill_char:330,vhost:364,via:[10,11,27,37,40,51,52,55,56,57,63,70,73,74,83,85,86,90,92,93,101,103,108,109,114,119,123,125,126,131,137,172,176,177,246,256,316,319,321,335],vice:[40,61,88,105,116,164,276],vicin:[33,165],video:[79,95,114,137],vienv:9,view:[1,4,17,27,34,38,41,42,50,51,52,55,58,60,63,64,72,80,82,86,90,96,101,102,110,111,115,116,123,124,131,136,139,141,142,144,154,156,157,159,164,165,166,169,175,239,247,249,302,318,329,346,347,350,353,356,357,364],view_attr:159,viewabl:[53,55,166],viewer:[25,38,69,247,318],viewport:42,vim:[14,50,79,326],violent:51,virtual:[4,41,55,57,59,63,79,90,124,169,331],virtual_env:75,virtualenv:[9,23,26,36,38,63,75,76,90,93,95,96,97,100,106,110,128,364],virtualhost:8,viru:63,visibl:[13,25,31,36,38,48,54,61,63,67,69,81,90,96,105,114,123,125,131,139,165,166,247,279,312,328,344],vision:[11,58,61],visit:[22,49,90,111,133,134,328],visitor:[103,134,135],vista:63,visual:[25,57,63,93,114,137,144,166,321,363],vital:91,vniftg:63,vnum:56,vocabulari:[46,344],voic:[33,46,124,139,364],volatil:251,volum:[21,61,100],volund:119,voluntari:37,volupt:52,vowel:119,vpad_char:330,vulner:[29,103],w001:127,wai:[0,2,5,6,9,10,11,12,13,14,15,19,20,21,22,23,27,28,30,31,33,37,38,39,40,41,42,44,46,48,49,54,55,56,57,58,61,62,63,64,68,69,70,72,73,74,75,79,80,82,83,84,85,86,87,88,89,90,91,92,93,95,96,97,98,102,103,104,105,106,107,109,110,111,112,113,114,115,116,117,118,119,121,122,123,124,125,126,127,128,129,131,132,133,136,138,139,140,144,151,152,159,166,175,242,247,251,261,267,272,276,287,308,310,312,313,314,316,317,319,322,327,328,330,334,337,340,344,364],wail:49,wait:[0,10,20,25,27,28,29,33,42,51,102,121,138,146,170,255,267,277,296,298,310,324,328,344],wait_for_disconnect:277,wait_for_server_connect:277,wait_for_statu:267,wait_for_status_repli:267,waiter:267,waitinf:170,walias:159,walk:[0,14,21,31,39,46,49,60,62,85,139,322],walki:64,wall:[111,157,165],wanna:37,want:[0,2,3,4,5,6,8,9,10,11,12,13,14,15,19,20,21,22,23,24,25,26,27,28,29,30,31,33,34,35,37,38,39,40,41,42,44,46,48,49,50,51,54,57,58,60,61,62,63,64,66,67,68,69,70,71,72,73,74,75,76,77,78,80,81,82,83,84,85,86,87,88,89,90,91,93,95,96,97,98,102,103,104,105,106,107,108,109,110,111,113,114,115,118,119,121,122,123,125,126,127,128,131,132,133,134,135,136,137,138,140,144,152,153,154,156,159,165,166,170,171,241,242,247,252,257,259,261,283,285,291,298,308,313,316,318,326,328,329,334,340,342,344,357,363,364],wanted_id:80,warchannel:164,ware:85,warehous:322,wari:[114,247,318],warm:[102,110,271],warn:[8,23,27,31,59,60,63,64,90,91,93,104,105,111,128,134,138,140,152,175,266,267,292,337,364],warnmsg:337,warrior:[28,57,58,61,122,123,164],wasclean:[278,295],wasn:[0,42,134],wast:[6,14,115],watch:[14,84,106,139],water:153,wave:111,wcach:169,wdestin:159,weak:252,weakref:334,weaksharedmemorymodel:[274,334],weaksharedmemorymodelbas:[274,334],weakvalu:334,wealth:85,weapon:[29,51,61,64,73,77,82,85,86,109,116,122,252],wear:82,weather:[30,61,73,102,111,112,115,122,124,139,140,364],weather_script:102,weatherroom:132,web:[4,8,9,16,17,23,25,30,38,47,53,55,61,63,64,67,69,72,75,76,79,80,83,95,101,109,110,119,139,141,142,269,271,281,285,291,295,296,306,310,312,319,325,364],web_client_url:54,web_get_admin_url:[154,175,239,318],web_get_create_url:[175,239,318],web_get_delete_url:[175,239,318],web_get_detail_url:[154,175,239,318],web_get_puppet_url:318,web_get_update_url:[175,239,318],webclient:[24,30,40,45,53,54,64,67,69,83,88,95,103,105,110,114,135,139,141,142,166,169,262,272,275,291,296,307,328,346,351,360,364],webclient_ajax:[137,141,142,262,275,364],webclient_en:103,webclient_gui:[83,364],webclient_opt:272,webclientdata:296,webclienttest:360,webpag:[8,17,77,90,354],webport:36,webserv:[3,7,8,9,23,40,47,55,67,90,100,101,104,135,139,141,142,262,364],webserver_en:103,webserver_interfac:[67,90],webserver_port:[36,90],webservic:103,websit:[3,9,17,38,53,55,57,64,67,69,79,90,98,101,103,124,133,136,137,138,139,141,142,296,312,346,351,364],websocket:[40,55,64,90,100,137,278,284,295,307,364],websocket_client_interfac:[67,90],websocket_client_port:[67,90],websocket_client_url:[8,67,90],websocket_clos:295,websocketcli:295,websocketclientfactori:278,websocketclientprotocol:278,websocketserverfactori:284,websocketserverprotocol:295,weed:[26,119,152],week:[62,337,345],weeklylogfil:337,weigh:[82,298],weight:[23,38,61,108,124,139,317,364],weird:344,weirdli:96,welcom:[3,4,22,35,37,63,72,76,85],well:[2,4,6,9,11,12,16,17,19,21,22,23,25,26,33,37,38,39,40,41,43,44,45,46,49,50,51,52,55,57,58,61,62,64,66,68,69,71,74,75,81,85,88,89,91,96,98,103,104,105,106,108,109,113,116,118,119,120,123,124,125,127,128,131,133,134,135,136,138,148,152,153,154,159,172,175,247,256,260,262,267,276,278,279,285,302,310,316,317,321,325,328,331,340,344],went:[57,110,127,131,257,261],were:[1,10,11,13,24,31,33,37,42,44,51,58,59,64,69,77,82,85,86,91,100,102,104,108,109,119,123,125,126,127,137,144,151,152,153,164,175,247,251,314,318,322,341,344],weren:62,werewolf:25,werewolv:119,werkzeug:344,west:[20,25,44,49,111,159],west_east:111,western:111,wether:[147,324],wevennia:22,wflushmem:169,wguild:164,what:[0,1,2,4,8,9,10,12,13,14,19,20,21,22,23,25,26,27,29,31,33,38,39,40,42,44,45,46,48,49,51,56,57,58,60,61,62,63,64,67,68,69,70,72,73,74,77,78,79,80,81,83,85,86,88,89,90,93,95,96,97,98,102,103,104,105,108,109,110,111,113,114,115,116,117,118,119,121,122,123,124,125,126,127,128,129,131,132,133,134,136,138,139,140,144,150,152,153,154,156,159,170,175,239,242,247,250,251,252,267,269,272,279,291,296,311,313,316,318,319,321,322,328,338,339,342,344,345,347,349,357,364],whatev:[2,11,14,21,22,23,27,33,40,46,48,51,56,58,61,64,67,78,82,89,91,100,102,111,123,127,131,133,134,138,144,146,153,159,247,252,256,257,278,287,290,295,308,316,329,338],whatnot:138,wheel:[57,63,75,115],whelp:166,when:[0,2,3,4,5,6,8,9,10,11,12,13,14,15,17,19,20,21,22,23,24,26,27,29,30,31,33,34,35,36,37,38,39,40,41,42,44,46,47,49,50,51,52,56,57,58,59,60,61,62,63,64,65,66,67,68,69,73,74,75,76,77,78,79,80,82,83,84,85,86,87,88,89,90,91,93,95,96,97,98,100,102,103,104,105,106,107,108,109,110,111,112,113,114,116,117,118,119,120,121,122,123,124,125,126,127,128,129,131,132,133,136,137,138,139,141,144,146,148,150,152,153,154,156,158,159,164,165,166,167,168,169,171,175,176,177,238,239,241,242,245,246,247,249,251,252,255,256,257,259,260,261,264,267,269,273,274,276,277,278,279,280,281,282,283,285,287,288,289,290,291,292,295,296,298,299,305,306,307,308,309,310,316,318,319,321,322,324,325,326,327,328,329,330,334,335,337,339,344,347,357,364],when_stop:267,whenev:[6,10,11,22,25,33,46,64,66,74,76,80,84,87,90,95,98,100,102,106,107,109,111,113,117,119,128,144,153,175,245,247,257,259,269,286,306,307,308],where:[0,1,3,6,9,10,11,12,13,14,20,21,22,25,26,29,31,33,36,38,39,40,41,42,46,48,49,50,51,52,56,57,58,59,61,62,64,69,73,75,76,80,83,85,86,88,90,91,95,100,102,103,104,105,108,109,111,113,114,117,118,119,121,122,123,124,125,127,131,133,134,135,136,137,138,139,151,152,157,159,165,166,168,175,176,241,242,245,247,251,252,257,267,269,272,276,299,304,308,316,318,321,322,326,328,329,330,331,338,339,342,344,364],wherea:[11,12,13,19,21,26,31,33,34,40,42,55,56,61,80,81,85,86,93,97,103,105,109,113,114,116,125,128,147,245,255,261,296,316,334],whereabout:122,wherev:[11,63,64,67,100,111,127],whether:[0,12,39,46,51,55,62,69,77,121,144,146,153,159,164,166,175,247,261,278,295,310,316,317,321,338,340,344],whewiu:9,which:[0,1,3,4,5,6,9,10,11,12,13,14,15,19,20,22,24,25,26,27,28,29,30,31,33,34,36,37,38,39,40,41,42,43,44,46,49,51,52,56,57,58,59,60,61,62,63,64,65,66,67,69,71,72,73,74,76,77,80,81,82,83,85,86,87,88,89,90,91,93,95,96,97,100,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,125,126,127,131,132,133,134,135,136,137,138,139,140,144,146,150,152,153,154,156,157,159,165,166,167,170,171,175,176,177,239,242,245,246,247,251,252,255,256,257,259,261,264,266,267,271,272,279,285,287,295,296,298,299,306,307,308,310,313,316,317,318,319,321,322,324,325,328,329,330,331,334,337,338,340,341,342,344,347,349,350,357],whichev:[27,90,103],whilst:[77,111],whim:139,whisper:[43,46,165,247],white:[48,74,114,126,321,344],whitelist:74,whitepag:[1,48,138,364],whitespac:[14,27,33,58,81,119,123,167,321,322,330,344],who:[4,10,11,12,21,34,41,43,46,49,51,55,56,58,61,73,80,87,95,103,109,114,116,119,121,123,124,125,127,132,133,138,146,154,156,159,164,175,177,239,242,247,252,318,326,328,364],whoever:133,whole:[4,16,49,51,55,57,60,61,67,87,96,111,112,122,123,129,138,152,159,330],wholist:175,whome:159,whomev:[73,114,121],whose:[88,114,119,125,144,154,170,255,272,323,328,344],whould:328,why:[0,11,12,20,22,25,39,41,44,46,51,55,60,63,64,82,91,95,96,103,111,123,125,126,139,157,264,265,328],wick:316,wide:[16,25,27,39,58,61,73,86,91,138,157,327,330,344],widen:12,wider:[12,25,39,157,330],widest:344,widget:[340,357],width:[16,17,25,27,33,49,74,109,111,114,141,154,272,287,306,321,326,327,329,330,344],wield:[61,82,109],wifi:[90,103],wiki:[1,9,33,37,45,48,55,58,70,79,108,111,124,125,138,295,363,364],wiki_account_handl:4,wiki_account_signup_allow:4,wiki_can:4,wiki_can_admin:4,wiki_can_assign:4,wiki_can_assign_own:4,wiki_can_change_permiss:4,wiki_can_delet:4,wiki_can_moder:4,wiki_can_read:4,wiki_can_writ:4,wikiconfig:4,wikimedia:37,wikipedia:[15,37,55,113,127,131,295],wild:[108,126,131],wildcard:[12,57,87,157,159,344],wildcard_to_regexp:344,wilder:[141,142,178,364],will_suppress_ga:289,will_ttyp:294,willing:[58,61,79,364],win10:63,win7:63,win8:63,win:[9,24,91,116,122],wind:[122,132],window:[4,23,25,31,38,44,45,49,52,64,72,76,83,88,89,93,95,96,97,101,105,106,110,128,131,137,138,154,166,267,283,306,310,344,364],windowid:306,windows10:63,wingd:111,winpti:9,wintext:73,wip:38,wipe:[9,13,23,43,111,138,152,159,169],wire:[27,40,64,83,88,90,113,138,168,264,276,277,308,321],wis:58,wisdom:[60,93],wise:[6,11,13,14,15,26,58,60,80,96,118,131,135],wise_text:60,wiseobject:60,wiser:20,wiseword:60,wish:[33,36,39,75,120,131,136,321,343,357],with_metaclass:96,withdraw:116,within:[1,8,9,10,11,22,24,26,31,33,37,38,39,47,49,51,56,58,64,90,95,97,100,114,115,116,117,118,119,120,124,126,131,134,136,137,138,144,148,150,159,238,247,252,260,310,316,317,321,337,344,357],without:[0,8,11,12,13,14,16,20,21,22,23,25,27,29,30,31,33,35,37,38,40,42,44,46,49,50,51,55,57,58,59,60,61,63,64,66,67,76,80,86,88,90,91,92,93,96,97,100,101,104,107,108,109,114,115,118,119,121,123,125,126,127,128,129,131,133,136,138,139,144,146,151,154,156,157,159,164,165,166,167,168,169,170,175,176,177,242,245,247,250,251,252,259,260,276,287,290,291,298,308,309,316,318,321,322,324,325,326,328,329,337,340,341,342,344,350],withstand:80,wiz:58,wizard:[109,252,265,267,364],wkei:159,wlocat:159,wlock:159,wndb_:159,won:[0,2,4,10,11,12,13,15,21,22,23,29,31,38,41,42,46,57,61,63,69,73,78,81,83,85,86,91,95,96,100,111,114,119,123,125,127,134,137,138,153,312,321,340],wonder:[9,16,56,82,119,138],wont_suppress_ga:289,wont_ttyp:294,wooden:109,woosh:21,word:[14,27,33,46,49,50,62,69,70,72,76,88,89,91,93,95,96,97,111,119,122,126,131,136,151,166,167,171,245,279,326,341,344,364],work:[0,2,4,5,8,9,10,11,13,14,15,16,20,21,22,23,24,25,26,27,28,29,31,34,36,37,38,41,42,43,44,48,49,51,56,57,58,59,60,61,62,63,64,66,67,70,71,72,75,80,81,83,84,85,86,89,90,93,95,96,97,102,103,105,106,108,109,111,112,114,115,116,117,119,122,123,124,126,127,128,129,132,133,134,136,138,139,150,153,154,156,159,164,165,167,169,171,175,239,241,242,247,251,252,267,271,272,284,299,312,314,316,318,319,322,327,328,329,330,338,344,350,363,364],workaround:[63,100,131,364],workflow:61,world:[9,10,11,13,14,15,21,27,31,33,34,39,41,47,49,51,55,57,58,60,62,63,64,68,72,73,78,79,80,82,86,90,96,104,108,109,111,113,116,117,121,123,124,127,131,139,144,158,159,164,166,239,256,306,308,321,322,331,342,363,364],world_map:111,worm:49,worm_has_map:49,worri:[0,11,15,36,39,41,51,55,104,113,114,123,127,138],worst:61,worth:[0,8,21,29,51,61,70,79,91,93,124,125,133],worthi:61,worthless:90,would:[0,1,4,6,8,9,10,11,13,14,15,16,19,20,21,22,25,27,29,31,33,36,39,41,42,44,46,48,49,51,55,56,57,58,60,61,62,63,64,68,69,73,77,80,81,82,85,86,88,89,90,91,93,95,96,100,102,105,106,109,111,112,114,115,116,117,118,119,121,123,125,126,127,128,133,134,135,136,138,140,144,151,152,153,154,159,168,175,239,242,251,252,279,291,318,321,322,325,328,339,340,342,344],wouldn:[39,126,138],wow:[69,138],wpermiss:159,wprototype_desc:159,wprototype_kei:159,wprototype_lock:159,wprototype_par:159,wprototype_tag:159,wrap:[10,30,49,51,59,96,102,109,119,136,274,314,330,344],wrap_conflictual_object:340,wrapper:[10,27,29,51,74,86,93,105,119,125,144,148,176,177,239,246,247,256,260,272,274,306,316,318,319,321,330,334,335,337,344],wresid:169,write:[0,4,10,11,14,15,16,20,22,23,25,27,31,33,34,37,38,41,44,46,48,51,56,58,62,63,65,68,69,71,72,87,88,91,93,96,108,123,124,125,129,131,138,159,164,166,175,247,280,337,342,363,364],writeabl:75,written:[15,27,38,54,56,57,58,79,103,109,127,133,134,166,322],wrong:[26,41,42,60,63,81,85,95,110,127,152,159,169],wrote:342,wserver:169,wservic:164,wsgi:[8,312],wsgi_resourc:312,wsgiwebserv:312,wsl:[38,63],wss:[8,67,90],wtypeclass:159,wwhere:247,www:[8,9,22,38,55,70,90,108,128,133,141,169,282,283,289,291,343,357],wyou:82,x0c:159,x1b:[321,343],x2x:58,x4x:327,x5x:327,x6x:327,x7x:327,x8x:327,x9x:327,x_r:39,xcode:63,xenial:130,xforward:312,xgettext:76,xit:22,xmlcharrefreplac:321,xp_gain:73,xpo:330,xterm256:[55,74,81,83,137,156,272,287,290,321,364],xterm256_bg:321,xterm256_bg_sub:321,xterm256_fg:321,xterm256_fg_sub:321,xterm256_gbg:321,xterm256_gbg_sub:321,xterm256_gfg:321,xterm256_gfg_sub:321,xterm:[114,126],xterms256:114,xval:33,xxx:[25,42],xxxxx1xxxxx:327,xxxxx3xxxxx:327,xxxxxxx2xxxxxxx:327,xxxxxxxxxx3xxxxxxxxxxx:58,xxxxxxxxxx4xxxxxxxxxxx:58,xxxxxxxxxxx:327,xxxxxxxxxxxxxx1xxxxxxxxxxxxxxx:58,xxxxxxxxxxxxxxxxxxxxxx:58,xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:58,xyz:87,y_r:39,yan:[114,321],yank:50,yeah:138,year:[25,55,61,62,88,90,108,331,337,344,357],yearli:[62,90],yellow:[114,126,131],yep:138,yes:[10,33,38,39,46,51,126,138,159,169,265,326,328,344],yes_act:328,yes_no_question_cmdset:328,yesno:[38,51,326],yesnoquestioncmdset:328,yet:[0,2,4,12,14,22,25,28,35,36,41,42,46,49,51,54,60,63,64,67,76,79,86,90,96,105,109,111,119,121,128,130,131,133,134,138,144,164,171,242,246,260,285,308,312,321],yield:[10,23,33,80,108,159,330,342,344,364],yml:[100,130],you:[0,1,2,3,4,5,6,8,9,10,11,12,13,14,15,16,17,19,20,21,22,23,24,25,27,28,29,30,31,33,34,35,36,37,38,39,40,41,42,44,46,47,48,49,50,51,54,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,95,96,97,98,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,144,153,154,156,159,164,165,166,167,168,169,170,171,175,241,242,247,252,257,258,259,260,261,269,278,279,280,296,298,308,310,312,313,316,318,321,322,324,327,328,330,331,340,341,342,344,357,363,364],young:77,your:[0,1,3,5,6,7,8,9,10,11,12,13,14,15,16,17,21,22,23,25,27,29,30,31,34,35,36,37,38,41,42,44,45,46,47,48,49,50,51,54,55,56,57,58,59,61,62,63,64,65,66,67,68,69,70,71,72,73,75,76,77,78,79,80,81,82,83,85,87,88,91,93,95,96,98,101,102,104,105,106,107,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,129,130,132,134,135,136,138,139,140,144,148,151,153,154,156,157,159,164,165,166,169,170,171,241,242,246,298,318,321,326,328,330,340,341,342,344,345,357,364],your_email:131,yourhostnam:67,yournam:8,yourpassword:23,yourrepo:106,yourself:[0,2,5,6,14,16,19,22,23,26,31,37,38,42,51,55,58,63,69,70,73,78,80,86,89,90,91,96,102,108,111,119,123,125,130,131,135,159,165,328,364],yoursit:133,yourusernam:131,yourwebsit:133,yousuck:12,yousuckmor:12,youtub:131,ypo:330,ythi:114,yum:[8,67,131],yvonn:58,z_r:39,zed:[77,79],zero:[20,27,109,164,247,316,321],zip:103,zlib:[75,276,280],zmud:[24,282],zone:[18,46,55,56,70,79,112,119,122,124,139,319,337,364],zope:97,zopeinterfac:63,zuggsoft:282,zy1rozgc6mq:45},titles:["A voice operated elevator using events","API refactoring","Accounts","Add a simple new web page","Add a wiki on your website","Adding Command Tutorial","Adding Object Typeclass Tutorial","Administrative Docs","Apache Config","Arxcode installing help","Async Process","Attributes","Banning","Batch Code Processor","Batch Command Processor","Batch Processors","Bootstrap & Evennia","Bootstrap Components and Utilities","Builder Docs","Building Permissions","Building Quickstart","Building a mech tutorial","Building menus","Choosing An SQL Server","Client Support Grid","Coding FAQ","Coding Introduction","Coding Utils","Command Cooldown","Command Duration","Command Prompt","Command Sets","Command System","Commands","Communications","Connection Screen","Continuous Integration","Contributing","Contributing to Evennia Docs","Coordinates","Custom Protocols","Customize channels","Debugging","Default Commands","Default Exit Errors","Developer Central","Dialogues in events","Directory Overview","Docs refactoring","Dynamic In Game Map","EvEditor","EvMenu","EvMore","API Summary","Evennia Game Index","Evennia Introduction","Evennia for Diku Users","Evennia for MUSH Users","Evennia for roleplaying sessions","Execute Python Code","First Steps Coding","Game Planning","Gametime Tutorial","Getting Started","Glossary","Grapevine","Guest Logins","HAProxy Config (Optional)","Help System","Help System Tutorial","How To Get And Give Help","How to connect Evennia to Twitter","IRC","Implementing a game rule system","Inputfuncs","Installing on Android","Internationalization","Learn Python for Evennia The Hard Way","Licensing","Links","Locks","Manually Configuring Color","Mass and weight for objects","Messagepath","MonitorHandler","NPC shop Tutorial","New Models","Nicks","OOB","Objects","Online Setup","Parsing command arguments, theory and best practices","Portal And Server","Profiling","Python 3","Python basic introduction","Python basic tutorial part two","Quirks","RSS","Roadmap","Running Evennia in Docker","Screenshot","Scripts","Security","Server Conf","Sessions","Setting up PyCharm","Signals","Soft Code","Spawner and Prototypes","Start Stop Reload","Static In Game Map","Tags","Text Encodings","TextTags","TickerHandler","Turn based Combat System","Tutorial Aggressive NPCs","Tutorial NPCs listening","Tutorial Searching For Objects","Tutorial Tweeting Game Stats","Tutorial Vehicles","Tutorial World Introduction","Tutorial for basic MUSH like game","Tutorials","Typeclasses","Understanding Color Tags","Unit Testing","Updating Your Game","Using MUX as a Standard","Using Travis","Version Control","Weather Tutorial","Web Character Generation","Web Character View Tutorial","Web Features","Web Tutorial","Webclient","Webclient brainstorm","Wiki Index","Zones","evennia","evennia","evennia.accounts","evennia.accounts.accounts","evennia.accounts.admin","evennia.accounts.bots","evennia.accounts.manager","evennia.accounts.models","evennia.commands","evennia.commands.cmdhandler","evennia.commands.cmdparser","evennia.commands.cmdset","evennia.commands.cmdsethandler","evennia.commands.command","evennia.commands.default","evennia.commands.default.account","evennia.commands.default.admin","evennia.commands.default.batchprocess","evennia.commands.default.building","evennia.commands.default.cmdset_account","evennia.commands.default.cmdset_character","evennia.commands.default.cmdset_session","evennia.commands.default.cmdset_unloggedin","evennia.commands.default.comms","evennia.commands.default.general","evennia.commands.default.help","evennia.commands.default.muxcommand","evennia.commands.default.syscommands","evennia.commands.default.system","evennia.commands.default.tests","evennia.commands.default.unloggedin","evennia.comms","evennia.comms.admin","evennia.comms.channelhandler","evennia.comms.comms","evennia.comms.managers","evennia.comms.models","evennia.contrib","evennia.contrib.barter","evennia.contrib.building_menu","evennia.contrib.chargen","evennia.contrib.clothing","evennia.contrib.color_markups","evennia.contrib.custom_gametime","evennia.contrib.dice","evennia.contrib.email_login","evennia.contrib.extended_room","evennia.contrib.fieldfill","evennia.contrib.gendersub","evennia.contrib.health_bar","evennia.contrib.ingame_python","evennia.contrib.ingame_python.callbackhandler","evennia.contrib.ingame_python.commands","evennia.contrib.ingame_python.eventfuncs","evennia.contrib.ingame_python.scripts","evennia.contrib.ingame_python.tests","evennia.contrib.ingame_python.typeclasses","evennia.contrib.ingame_python.utils","evennia.contrib.mail","evennia.contrib.mapbuilder","evennia.contrib.menu_login","evennia.contrib.multidescer","evennia.contrib.puzzles","evennia.contrib.random_string_generator","evennia.contrib.rplanguage","evennia.contrib.rpsystem","evennia.contrib.security","evennia.contrib.security.auditing","evennia.contrib.security.auditing.outputs","evennia.contrib.security.auditing.server","evennia.contrib.security.auditing.tests","evennia.contrib.simpledoor","evennia.contrib.slow_exit","evennia.contrib.talking_npc","evennia.contrib.tree_select","evennia.contrib.turnbattle","evennia.contrib.turnbattle.tb_basic","evennia.contrib.turnbattle.tb_equip","evennia.contrib.turnbattle.tb_items","evennia.contrib.turnbattle.tb_magic","evennia.contrib.turnbattle.tb_range","evennia.contrib.tutorial_examples","evennia.contrib.tutorial_examples.bodyfunctions","evennia.contrib.tutorial_examples.cmdset_red_button","evennia.contrib.tutorial_examples.example_batch_code","evennia.contrib.tutorial_examples.red_button","evennia.contrib.tutorial_examples.red_button_scripts","evennia.contrib.tutorial_examples.tests","evennia.contrib.tutorial_world","evennia.contrib.tutorial_world.intro_menu","evennia.contrib.tutorial_world.mob","evennia.contrib.tutorial_world.objects","evennia.contrib.tutorial_world.rooms","evennia.contrib.unixcommand","evennia.contrib.wilderness","evennia.help","evennia.help.admin","evennia.help.manager","evennia.help.models","evennia.locks","evennia.locks.lockfuncs","evennia.locks.lockhandler","evennia.objects","evennia.objects.admin","evennia.objects.manager","evennia.objects.models","evennia.objects.objects","evennia.prototypes","evennia.prototypes.menus","evennia.prototypes.protfuncs","evennia.prototypes.prototypes","evennia.prototypes.spawner","evennia.scripts","evennia.scripts.admin","evennia.scripts.manager","evennia.scripts.models","evennia.scripts.monitorhandler","evennia.scripts.scripthandler","evennia.scripts.scripts","evennia.scripts.taskhandler","evennia.scripts.tickerhandler","evennia.server","evennia.server.admin","evennia.server.amp_client","evennia.server.connection_wizard","evennia.server.deprecations","evennia.server.evennia_launcher","evennia.server.game_index_client","evennia.server.game_index_client.client","evennia.server.game_index_client.service","evennia.server.initial_setup","evennia.server.inputfuncs","evennia.server.manager","evennia.server.models","evennia.server.portal","evennia.server.portal.amp","evennia.server.portal.amp_server","evennia.server.portal.grapevine","evennia.server.portal.irc","evennia.server.portal.mccp","evennia.server.portal.mssp","evennia.server.portal.mxp","evennia.server.portal.naws","evennia.server.portal.portal","evennia.server.portal.portalsessionhandler","evennia.server.portal.rss","evennia.server.portal.ssh","evennia.server.portal.ssl","evennia.server.portal.suppress_ga","evennia.server.portal.telnet","evennia.server.portal.telnet_oob","evennia.server.portal.telnet_ssl","evennia.server.portal.tests","evennia.server.portal.ttype","evennia.server.portal.webclient","evennia.server.portal.webclient_ajax","evennia.server.profiling","evennia.server.profiling.dummyrunner","evennia.server.profiling.dummyrunner_settings","evennia.server.profiling.memplot","evennia.server.profiling.settings_mixin","evennia.server.profiling.test_queries","evennia.server.profiling.tests","evennia.server.profiling.timetrace","evennia.server.server","evennia.server.serversession","evennia.server.session","evennia.server.sessionhandler","evennia.server.signals","evennia.server.throttle","evennia.server.validators","evennia.server.webserver","evennia.settings_default","evennia.typeclasses","evennia.typeclasses.admin","evennia.typeclasses.attributes","evennia.typeclasses.managers","evennia.typeclasses.models","evennia.typeclasses.tags","evennia.utils","evennia.utils.ansi","evennia.utils.batchprocessors","evennia.utils.containers","evennia.utils.create","evennia.utils.dbserialize","evennia.utils.eveditor","evennia.utils.evform","evennia.utils.evmenu","evennia.utils.evmore","evennia.utils.evtable","evennia.utils.gametime","evennia.utils.idmapper","evennia.utils.idmapper.manager","evennia.utils.idmapper.models","evennia.utils.idmapper.tests","evennia.utils.inlinefuncs","evennia.utils.logger","evennia.utils.optionclasses","evennia.utils.optionhandler","evennia.utils.picklefield","evennia.utils.search","evennia.utils.test_resources","evennia.utils.text2html","evennia.utils.utils","evennia.utils.validatorfuncs","evennia.web","evennia.web.urls","evennia.web.utils","evennia.web.utils.backends","evennia.web.utils.general_context","evennia.web.utils.middleware","evennia.web.utils.tests","evennia.web.webclient","evennia.web.webclient.urls","evennia.web.webclient.views","evennia.web.website","evennia.web.website.forms","evennia.web.website.templatetags","evennia.web.website.templatetags.addclass","evennia.web.website.tests","evennia.web.website.urls","evennia.web.website.views","Evennia Documentation","<no title>"],titleterms:{"2017":138,"2019":[1,48,138],"3rd":138,"9th":138,"case":0,"class":[22,27,33,41,51,96,125,127],"default":[5,6,25,30,43,44,55,60,74,80,137,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171],"final":[49,75],"function":[22,42,51,53,80,89,95,102,114],"goto":51,"import":[26,38,41,95],"new":[3,4,6,58,60,69,86,97,102,114,125,127,133],"public":54,"return":[51,59,105],"static":111,"super":19,"switch":41,"try":41,Adding:[0,4,5,6,9,20,25,31,39,40,41,44,74,86,112,121,133],And:[70,92],For:119,NOT:77,PMs:58,TLS:8,The:[3,10,11,13,14,16,18,19,22,26,29,41,46,47,49,50,51,58,69,77,83,85,93,96,109,116,123,135],USE:77,Use:[26,103],Using:[49,52,84,86,90,93,109,112,127,129,130,140],Will:25,Yes:51,abort:29,about:[29,115,125,128],abus:12,access_typ:80,account:[2,58,64,97,143,144,145,146,147,148,156],activ:[57,133],actual:[33,125],add:[3,4,23,25,60],add_choic:22,addclass:359,adding:127,addit:[9,39,41,44,100],address:25,admin:[64,97,135,145,157,173,237,244,254,263,315],administr:7,advanc:[18,29,53,87,110],aggress:117,alia:97,alias:112,all:[25,51,67,69],alpha:61,altern:[9,106],amp:276,amp_client:264,amp_serv:277,analyz:93,android:75,ani:[13,55],annot:119,anoth:[38,41,119],ansi:[27,114,126,321],apach:8,api:[1,38,45,53,137],app:[69,133],arbitrari:51,area:[111,123],arg:91,arg_regex:33,argument:[1,51,91],arm:21,arx:9,arxcod:9,ascii:27,ask:[33,51],assign:[19,33],assort:[10,14,31,33,40,51,112,118],async:10,asynchron:10,attach:[106,107],attack:[73,123],attribut:[11,64,97,316],attributehandl:11,audit:[208,209,210,211],aug:[1,48],auto:68,automat:25,avail:[35,59,107],backend:349,ban:12,barter:179,base:[25,109,116],basic:[4,13,14,18,55,71,95,96,123,127,136],batch:[13,14,15,322],batchcod:13,batchprocess:158,batchprocessor:322,befor:26,best:91,beta:61,between:[13,51,125],block:[13,29,38],blockquot:38,bodyfunct:223,bold:38,boot:12,bootstrap:[16,17],border:17,bot:146,brainstorm:[45,138],branch:[51,131],bridg:77,brief:[55,69],briefli:88,bug:97,build:[18,19,20,21,22,38,49,58,61,85,111,124,159],builder:18,building_menu:[22,180],busi:85,button:[17,20],calendar:62,call:33,callabl:51,callback:[0,46,137],callbackhandl:192,caller:51,can:[11,22,55],capcha:133,card:17,care:103,caveat:[13,14,75,114,125],central:45,certif:67,chainsol:138,chang:[0,5,6,25,38,58,60,76,97,103,108,128,131,136],channel:[25,34,41,58,64],channelhandl:174,charact:[6,24,25,46,58,60,61,64,73,82,89,96,123,133,134],chargen:[123,181],chat:138,cheat:42,check:[11,80],checker:26,checkpoint:133,choic:22,choos:23,clean:9,clickabl:114,client:[24,83,88,90,135,137,269],client_opt:74,clone:[9,131],cloth:182,cloud9:90,cmdhandler:150,cmdparser:151,cmdset:[5,152],cmdset_account:160,cmdset_charact:161,cmdset_red_button:224,cmdset_sess:162,cmdset_unloggedin:163,cmdsethandl:153,code:[8,13,22,25,26,27,38,41,42,50,59,60,61,73,85,87,108,124,128,131,322],collabor:57,color:[17,25,27,81,126],color_markup:183,colour:114,combat:[116,123],comfort:100,comm:[164,172,173,174,175,176,177],command:[5,14,22,25,28,29,30,31,32,33,35,41,42,43,44,45,53,58,60,62,68,71,73,81,85,88,91,97,100,116,121,123,127,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,193,322],comment:[44,49],commit:131,commun:[13,34],complet:80,complex:[22,119],compon:[17,45],comput:90,concept:[45,49,116],conclud:[39,123],conclus:[22,41,91,111],condit:[25,119],conf:104,config:[8,53,67,81],configur:[8,23,65,67,71,72,81,98,106,131,133],congratul:61,connect:[35,54,71,90,97],connection_wizard:265,contain:[100,323],content:[25,55],continu:36,contrib:[22,37,64,124,127,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235],contribut:[37,38,53],control:131,convert:91,cooldown:28,coordin:39,copi:8,core:[45,53,56,64],cprofil:93,creat:[0,2,3,5,6,12,20,21,27,33,36,51,53,69,86,89,97,100,111,121,123,125,133,324],createnpc:123,creatur:100,credit:79,crop:27,current:[42,62],custom:[4,5,7,10,22,40,41,51,57,62,80,81,105,113,124,127,135,137],custom_gametim:184,data:[6,11,40,51,105,106],databas:[9,53,68,86,97,109,128],dbref:25,dbserial:325,deal:102,debug:[13,42,103],debugg:106,decor:[10,51],dedent:27,dedic:133,defaultobject:97,defin:[31,33,34,51,80,86,102,131],definit:80,delai:[10,27,29],delimit:25,demo:61,depend:[9,128],deploi:100,deprec:[38,266],desc:51,descer:57,descript:100,design:85,detail:[69,133],develop:[45,57,79,100,103,110,124,127],dialogu:46,dice:[58,185],dictionari:51,differ:[56,125],diku:56,direct:[38,106],directori:[47,90,104],disabl:103,discuss:79,displai:[24,27,49,62],django:[64,80,110,119,133,135],doc:[7,18,26,38,48],docker:100,docstr:38,document:[37,38,129,363],don:[13,55,100],donat:37,down:[20,110,121],dummi:73,dummyrunn:[93,298],dummyrunner_set:299,durat:29,dure:110,dynam:[33,49,51,127],earli:7,echo:74,edit:[22,38,50,123],editnpc:123,editor:50,elev:0,email_login:186,emul:56,encod:[15,113],encrypt:90,end:41,engin:124,enjoi:8,enter:121,entir:0,entri:[20,68],error:[44,95,102,110],eval:38,eveditor:[50,326],evennia:[4,5,7,8,9,16,23,25,26,38,41,42,45,47,54,55,56,57,58,67,71,75,76,77,79,90,91,95,96,100,106,109,110,124,126,127,128,131,137,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363],evennia_launch:267,evenniatest:127,event:[0,46,62],eventfunc:194,everi:30,everyth:22,evform:[58,327],evmenu:[25,51,328],evmor:[52,329],evtabl:[25,58,330],examin:42,exampl:[39,42,46,50,51,73,80,83,90,102,108,116,127,137,322],example_batch_cod:225,execut:[42,59],exercis:77,exist:[6,125],exit:[0,6,25,33,44,89],expand:[116,121],explan:22,explor:[26,96],extended_room:187,extern:[38,103],familiar:[56,57],faq:25,faster:127,featur:[55,69,135],feel:56,field:64,fieldfil:188,file:[13,14,15,38,104,127,131,322],fill:27,find:[39,59],firewal:103,first:[0,22,46,57,60,95,124],fix:131,flexibl:38,folder:[9,26,131],foreground:110,forget:97,fork:[37,131],form:[17,133,357],format:51,forum:79,framework:79,from:[4,20,25,51,55,60,90,96,100,133,137,138,328],front:136,full:[22,41,69,83],func:41,further:[8,10,136],futur:[21,138],game:[7,26,27,39,45,47,49,54,55,57,58,59,61,62,73,90,100,111,120,123,124,127,128,131],game_index_cli:[268,269,270],gamedir:38,gameplai:122,gametim:[62,331],gap:77,gendersub:189,gener:[17,22,41,45,79,123,124,133,165,328],general_context:350,get:[20,51,63,67,70,119],get_client_opt:74,get_input:51,get_inputfunc:74,get_valu:74,git:[64,131],github:64,give:70,given:112,global:[53,91,102],glossari:64,gmcp:88,godhood:20,goldenlayout:137,googl:133,grant:58,grapevin:[65,278],griatch:[1,48,138],grid:[24,49],group:119,guest:66,gui:138,guid:9,handl:[12,69,103,110],handler:[53,107,116],haproxi:67,hard:77,have:123,head:38,health_bar:190,hello:95,help:[9,20,26,37,68,69,70,166,236,237,238,239],here:[26,55,60,96],hierarchi:58,hint:8,hook:125,host:90,hous:20,how:[2,33,58,70,71,89,100,113,121,125],html:[3,133],http:[8,67],idea:138,idmapp:[332,333,334,335],imag:[100,103],implement:73,improv:69,index:[54,69,133,139],info:[79,110],inform:[45,90],infrastructur:73,ingame_python:[191,192,193,194,195,196,197,198],ingo:83,inherit:140,inherits_from:27,initi:[6,23,25,116],initial_setup:271,inlin:114,inlinefunc:[114,336],input:[33,51,88],inputfunc:[74,83,88,272],insid:119,instal:[4,7,8,9,23,63,67,71,75,90,100,122,131,133],instanc:[33,86,125],instruct:88,integr:36,interact:[10,13,14,26],interfac:103,intern:38,internation:76,interpret:106,intro_menu:230,introduct:[9,26,49,51,55,93,95,111,122,133],inventori:82,irc:[72,279],issu:24,ital:38,jan:138,johnni:1,join:41,jumbotron:17,just:55,kei:[22,51,109],keyword:46,kill:110,know:[55,103],known:97,kovitiku:48,languag:[51,76],last:25,latest:[100,128],latin:25,launch:[50,51],layout:[16,41,47],learn:[26,55,77],leav:[41,121],let:[13,42,69,90],librari:[47,96],licens:78,life:7,lift:12,like:[13,56,123],limit:[13,14,119],line:[21,42,50],link:[38,79,114],linux:[36,63,110],list:[38,42],list_nod:51,listen:118,literatur:79,live:110,local:[38,90,91],lock:[11,80,121,240,241,242],lockdown:90,lockfunc:241,lockhandl:242,log:[9,27,69,95,103],logfil:106,logger:337,login:[66,74],logo:136,longer:46,look:[5,56,95,123],lookup:53,mac:[63,110],machin:90,magic:97,mail:[131,199],main:[38,53],make:[20,21,27,57,58,60,67,121,123,127,131],manag:[4,137,147,176,238,245,255,273,317,333],manual:[54,81],map:[49,111],mapbuild:200,mapper:49,mariadb:23,markup:321,mass:82,master:[58,131],match:97,mccp:280,mech:21,mechan:124,memplot:300,menu:[22,27,51,85,249,328],menu_login:201,merg:31,messag:[0,25,83,88],messagepath:83,method:[33,41,81,97],middlewar:351,migrat:[4,64,128],mind:131,mini:127,minimap:111,miscellan:124,mob:231,mod_proxi:8,mod_ssl:8,mod_wsgi:8,mode:[13,14,64,90,105,110],model:[53,86,127,133,148,177,239,246,256,274,318,334],modif:58,modifi:[8,30],modul:[71,73,95,109,116],monitor:74,monitorhandl:[84,257],more:[16,29,38,53,57,80,81,128,135],most:26,move:[25,121],msdp:88,msg:[34,81,83],mssp:281,mud:79,multi:57,multidesc:[57,202],multipl:[11,119],multisess:[64,105],mush:[57,123],mutabl:[11,97],mux:129,muxcommand:167,mxp:282,mysql:23,myst:38,name:[12,88,97],naw:283,ndb:11,need:[0,55],nest:22,next:[57,63,71],nice:67,nick:87,node:51,non:[11,25,28,54],nop:24,note:[8,10,14,15,31,33,38,40,51,87,112,118,122,127],npc:[85,117,118,123],number:91,object:[5,6,11,20,25,27,59,60,61,64,80,82,89,96,97,105,111,112,119,121,124,232,243,244,245,246,247],obtain:133,oct:138,octob:138,off:25,offici:79,olc:109,one:[38,39],onli:[38,110],onlin:[90,131],oob:88,open:85,oper:[0,10],option:[1,22,51,58,67,90,91,103,110],optionclass:338,optionhandl:339,other:[23,33,45,79,90,104],our:[0,22,69,95,96,108,121,133],out:[25,40,58],outgo:83,output:[59,127,209],outputcommand:88,outputfunc:88,outsid:[59,90],overal:73,overload:[81,125,135],overrid:97,overview:[36,47,86,116,136],own:[2,33,40,74,89,90,100,137],page:[3,4,69,135,136],parent:[57,86],pars:[25,41,91,95],part:96,parti:79,patch:37,path:[13,83],paus:[0,29,33],pax:9,pdb:42,permiss:[19,58,80,112,122],perpetu:61,persist:[11,28,29,50],person:20,picklefield:340,pictur:133,pip:[4,64],place:38,plai:67,plan:[26,61,111],player:57,plugin:137,point:26,polici:129,port:[90,103],portal:[83,92,105,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296],portalsess:83,portalsessionhandl:[83,285],posit:1,possibl:51,post:138,postgresql:23,practic:91,prepar:36,prerequisit:75,prevent:25,privileg:4,problem:108,process:[10,110],processor:[13,14,15,322],product:[21,100],profil:[93,297,298,299,300,301,302,303,304],program:[42,55],progress:77,project:[36,106],prompt:[30,51],properti:[2,11,31,33,34,51,64,89,102,105,112,125],protfunc:[109,250],protocol:[40,45,55,88],prototyp:[109,248,249,250,251,252],proxi:[8,90],publicli:131,pudb:42,puppet:64,push:[20,131],put:[67,69,131],puzzl:203,pycharm:106,python:[13,26,55,57,59,71,77,79,94,95,96],quell:[19,80,122],queri:[119,125],quick:[36,63],quickstart:20,quiet:91,quirk:97,random_string_gener:204,read:[10,26,135,136],real:13,reboot:110,recapcha:133,receiv:[40,88],red_button:226,red_button_script:227,reduc:1,refactor:[1,48],refer:[25,38],regist:90,relat:[45,62],releas:[38,61],relev:90,reli:13,reload:[8,25,97,110],remark:123,rememb:38,remind:69,remot:[90,131],remov:[25,112],repeat:[51,74],repo:9,repositori:[26,37,64,131],requir:63,reset:[110,128],reshuffl:20,resourc:79,restart:8,retriev:11,roadmap:99,role:58,roleplai:58,roller:58,rom:56,room:[0,6,25,39,49,58,61,82,89,233],rplanguag:205,rpsystem:206,rss:[98,286],rst:38,rule:[31,73,116],run:[4,7,25,33,42,55,75,100,106,127],runner:127,safeti:13,sage:48,same:[46,51],save:11,schema:128,score:123,screen:35,screenshot:101,script:[64,102,121,195,253,254,255,256,257,258,259,260,261],scripthandl:258,search:[27,31,39,53,86,91,112,119,341],secret:133,secur:[8,67,103,207,208,209,210,211],see:[69,97],select:25,self:91,send:[30,40,88],sent:30,separ:22,sept:[1,48],server:[7,8,23,76,90,92,104,105,123,210,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312],serverconf:104,serversess:[83,306],serversessionhandl:83,servic:270,session:[25,58,64,83,105,307],sessionhandl:[105,308],set:[4,5,9,31,49,51,54,62,65,72,80,81,90,98,103,104,106,123,127,131],setpow:123,settings_default:313,settings_mixin:301,setup:[8,9,23,36,90],sever:[39,46,91],share:131,sharedmemorymodel:86,sheet:[42,58],shell:96,shop:85,shortcut:[11,53],show:[51,123],shut:110,sidebar:38,signal:[107,309],simpl:[3,22,29,42,51,80,93,127],simpledoor:212,singl:11,singleton:53,site:[64,135],sitekei:133,slow_exit:213,soft:108,softcod:[57,108],solut:108,some:[39,41,56],somewher:55,sourc:[38,106],space:17,spawn:[57,109],spawner:[109,252],specif:5,spread:37,spuriou:24,sql:23,sqlite3:23,ssh:[88,103,287],ssl:[90,288],standard:[55,62,129],start:[9,58,63,85,100,110],stat:120,statu:110,step:[5,9,20,42,57,60,61,65,71,72,75,98,124,131,133],stop:110,storag:51,store:[6,11,25,51,109],string:[51,80,91,328],strip:91,structur:38,studi:0,stuff:[55,123],style:17,sub:22,subclass:89,subject:96,suit:127,summari:[12,53,55],superus:80,support:[24,55,88],suppress_ga:289,surround:42,swap:125,synchron:10,syntax:[26,38,57,110,322],syscommand:168,system:[16,32,33,45,61,68,69,73,80,116,123,124,169],tabl:[25,27,38,86],tag:[39,64,112,126,319],talking_npc:214,taskhandl:260,tb_basic:217,tb_equip:218,tb_item:219,tb_magic:220,tb_rang:221,teamciti:36,tech:61,technic:[38,55],telnet:[24,88,90,290],telnet_oob:291,telnet_ssl:292,templat:[36,51,69,133,328],templatetag:[358,359],tempmsg:34,temporari:51,termux:75,test:[55,59,93,123,127,170,196,211,228,293,303,335,352,360],test_queri:302,test_resourc:342,text2html:343,text:[27,38,51,74,113,114,136],texttag:114,theori:91,thi:[41,69],thing:[38,56,57,119],third:79,throttl:310,through:[37,42,100],ticker:[64,115],tickerhandl:[115,261],tie:58,time:[27,33,62,102,108],time_format:27,timer:93,timetrac:304,tip:131,titeuf87:138,to_byt:27,to_str:27,togeth:[67,69],tool:[12,27,79],traceback:26,track:131,train:[73,121],translat:76,travi:130,treat:13,tree_select:215,trick:131,troubleshoot:[60,63,75],ttype:294,turn:[25,97,116],turnbattl:[216,217,218,219,220,221],tutori:[0,5,6,18,21,46,62,69,85,96,116,117,118,119,120,121,122,123,124,127,132,134,136],tutorial_exampl:[222,223,224,225,226,227,228],tutorial_world:[229,230,231,232,233],tweak:[60,96],tweet:[71,120],twist:64,twitter:71,two:96,type:[2,5,6,11,60,89],typeclass:[6,45,53,57,64,81,97,119,124,125,140,197,314,315,316,317,318,319],under:131,understand:126,ungm:58,uninstal:122,unit:127,unixcommand:234,unloggedin:171,unmonitor:74,unrepeat:74,updat:[6,25,60,125,128,131],upgrad:128,upload:103,upstream:[97,131],url:[3,4,38,69,133,347,354,361],usag:[1,13,14,50],use:[55,97,115],used:[25,33],useful:[33,79],user:[19,33,56,57,69,103,124,131],using:[0,42,119,127],util:[17,27,29,33,53,79,106,119,198,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,348,349,350,351,352],valid:[80,311],validatorfunc:345,valu:[51,109,119],variabl:[42,59],vehicl:121,verbatim:38,version:[38,131],versu:10,vhost:8,view:[3,68,69,133,134,135,355,362],virtualenv:64,voic:0,wai:[29,51,77],want:[55,100],warn:38,weather:132,web:[3,45,88,90,97,103,124,133,134,135,136,137,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362],webclient:[137,138,295,353,354,355],webclient_ajax:296,webclient_gui:137,webserv:[103,312],websit:[4,135,356,357,358,359,360,361,362],websocket:[8,67],weight:82,what:[11,16,36,41,55,91,100],when:[25,115],where:[5,55,60,63,96],whitepag:45,who:33,wiki:[4,139],wilder:235,willing:55,window:[9,63],wizard:54,word:37,work:[7,33,55,69,77,91,100,121,125,131],workaround:24,world:[18,20,61,95,122],write:[40,127,137],xterm256:[114,126],yield:[29,51],you:[26,55],your:[2,4,19,20,26,33,39,40,60,74,86,89,90,97,100,103,108,128,131,133,137],yourself:[20,60,61],zone:140}}) \ No newline at end of file diff --git a/docs/0.9.5/toc.html b/docs/0.9.5/toc.html deleted file mode 100644 index afe0bbb9c2..0000000000 --- a/docs/0.9.5/toc.html +++ /dev/null @@ -1,2911 +0,0 @@ - - - - - - - - - <no title> — Evennia 0.9.5 documentation - - - - - - - - - - - - - - - -
-
-
-
- -
- -
-
-
- - -
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/1.0-dev/.buildinfo b/docs/1.0-dev/.buildinfo index f57f6ab2ad..c7fb00697b 100644 --- a/docs/1.0-dev/.buildinfo +++ b/docs/1.0-dev/.buildinfo @@ -1,4 +1,4 @@ # Sphinx build info version 1 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: 748e2610a5e1998440e59b6c2189f551 +config: 9fde846aa7129b95929c8fe0abbb9b30 tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/1.0-dev/Coding/Coding-Introduction.html b/docs/1.0-dev/Coding/Coding-Introduction.html index 83d202c1ca..59c6f00ea8 100644 --- a/docs/1.0-dev/Coding/Coding-Introduction.html +++ b/docs/1.0-dev/Coding/Coding-Introduction.html @@ -246,7 +246,6 @@ chat are also there for you.

Versions

diff --git a/docs/1.0-dev/Coding/Coding-Overview.html b/docs/1.0-dev/Coding/Coding-Overview.html index 4f58d28a64..96f4847135 100644 --- a/docs/1.0-dev/Coding/Coding-Overview.html +++ b/docs/1.0-dev/Coding/Coding-Overview.html @@ -147,7 +147,6 @@ to you, but some things may still be useful.

Versions

diff --git a/docs/1.0-dev/Coding/Continuous-Integration.html b/docs/1.0-dev/Coding/Continuous-Integration.html index a18761d699..2a8beb7670 100644 --- a/docs/1.0-dev/Coding/Continuous-Integration.html +++ b/docs/1.0-dev/Coding/Continuous-Integration.html @@ -351,7 +351,6 @@ build steps could be added or removed at this point, adding some features like U

Versions

diff --git a/docs/1.0-dev/Coding/Debugging.html b/docs/1.0-dev/Coding/Debugging.html index 4b3bf3245b..3a749efe2b 100644 --- a/docs/1.0-dev/Coding/Debugging.html +++ b/docs/1.0-dev/Coding/Debugging.html @@ -380,7 +380,6 @@ topic here.

Versions

diff --git a/docs/1.0-dev/Coding/Flat-API.html b/docs/1.0-dev/Coding/Flat-API.html index 2889723251..515b947758 100644 --- a/docs/1.0-dev/Coding/Flat-API.html +++ b/docs/1.0-dev/Coding/Flat-API.html @@ -121,7 +121,6 @@ package imports from.

Versions

diff --git a/docs/1.0-dev/Coding/Profiling.html b/docs/1.0-dev/Coding/Profiling.html index 93fa73a3fd..52bf6e3adc 100644 --- a/docs/1.0-dev/Coding/Profiling.html +++ b/docs/1.0-dev/Coding/Profiling.html @@ -340,7 +340,6 @@ For this, actual real-game testing is required.

Versions

diff --git a/docs/1.0-dev/Coding/Quirks.html b/docs/1.0-dev/Coding/Quirks.html index 8a8797c645..4a2e0f4929 100644 --- a/docs/1.0-dev/Coding/Quirks.html +++ b/docs/1.0-dev/Coding/Quirks.html @@ -204,7 +204,6 @@ instructions, use the following command to fix it:

Versions

diff --git a/docs/1.0-dev/Coding/Setting-up-PyCharm.html b/docs/1.0-dev/Coding/Setting-up-PyCharm.html index f955bfe439..74cad0f28e 100644 --- a/docs/1.0-dev/Coding/Setting-up-PyCharm.html +++ b/docs/1.0-dev/Coding/Setting-up-PyCharm.html @@ -212,7 +212,6 @@ still running in interactive mode.

Versions

diff --git a/docs/1.0-dev/Coding/Unit-Testing.html b/docs/1.0-dev/Coding/Unit-Testing.html index 29ffc3aef9..307a7f5c26 100644 --- a/docs/1.0-dev/Coding/Unit-Testing.html +++ b/docs/1.0-dev/Coding/Unit-Testing.html @@ -399,7 +399,6 @@ django-test-without-migrations package. To install it, simply:

Versions

diff --git a/docs/1.0-dev/Coding/Updating-Your-Game.html b/docs/1.0-dev/Coding/Updating-Your-Game.html index ab3db99a6e..7f73b7ec8f 100644 --- a/docs/1.0-dev/Coding/Updating-Your-Game.html +++ b/docs/1.0-dev/Coding/Updating-Your-Game.html @@ -222,7 +222,6 @@ you then just run e

Versions

diff --git a/docs/1.0-dev/Coding/Using-Travis.html b/docs/1.0-dev/Coding/Using-Travis.html index 208dcbf64b..2614ff2229 100644 --- a/docs/1.0-dev/Coding/Using-Travis.html +++ b/docs/1.0-dev/Coding/Using-Travis.html @@ -52,18 +52,18 @@ need to set up yourself is a Travis config file named
language: python
-python:
-  - "2.7"
-install:
-  - git clone https://github.com/evennia/evennia.git
-  - cd evennia
-  - pip install -e .
-  - cd $TRAVIS_BUILD_DIR
-script:
-  - evennia migrate
-  - evennia test evennia
-  - evennia test
+
language: python
+python:
+  - "2.7"
+install:
+  - git clone https://github.com/evennia/evennia.git
+  - cd evennia
+  - pip install -e .
+  - cd $TRAVIS_BUILD_DIR
+script:
+  - evennia migrate
+  - evennia test evennia
+  - evennia test
 

This will tell travis how to download Evennia, install it, set up a database and then run the test @@ -115,7 +115,6 @@ fitting your game.

Versions

diff --git a/docs/1.0-dev/Coding/Version-Control.html b/docs/1.0-dev/Coding/Version-Control.html index a8aebf85b4..76822bbf03 100644 --- a/docs/1.0-dev/Coding/Version-Control.html +++ b/docs/1.0-dev/Coding/Version-Control.html @@ -567,7 +567,6 @@ template.

Versions

diff --git a/docs/1.0-dev/Components/Accounts.html b/docs/1.0-dev/Components/Accounts.html index 8f61c4dd0b..dfc8aefb0d 100644 --- a/docs/1.0-dev/Components/Accounts.html +++ b/docs/1.0-dev/Components/Accounts.html @@ -188,7 +188,6 @@ any.

Versions

diff --git a/docs/1.0-dev/Components/Attributes.html b/docs/1.0-dev/Components/Attributes.html index af7ecf9fe1..54ae469862 100644 --- a/docs/1.0-dev/Components/Attributes.html +++ b/docs/1.0-dev/Components/Attributes.html @@ -712,7 +712,6 @@ grand vision!

Versions

diff --git a/docs/1.0-dev/Components/Batch-Code-Processor.html b/docs/1.0-dev/Components/Batch-Code-Processor.html index b5636dfd59..18ea007964 100644 --- a/docs/1.0-dev/Components/Batch-Code-Processor.html +++ b/docs/1.0-dev/Components/Batch-Code-Processor.html @@ -325,7 +325,6 @@ executed. When the code runs it has no knowledge of what file those strings wher

Versions

diff --git a/docs/1.0-dev/Components/Batch-Command-Processor.html b/docs/1.0-dev/Components/Batch-Command-Processor.html index f182a3ff27..c3f05e62c9 100644 --- a/docs/1.0-dev/Components/Batch-Command-Processor.html +++ b/docs/1.0-dev/Components/Batch-Command-Processor.html @@ -269,7 +269,6 @@ mode instead, see its readme for install instructions.

Versions

diff --git a/docs/1.0-dev/Components/Batch-Processors.html b/docs/1.0-dev/Components/Batch-Processors.html index 9a12ae9be9..8fe00de5b1 100644 --- a/docs/1.0-dev/Components/Batch-Processors.html +++ b/docs/1.0-dev/Components/Batch-Processors.html @@ -162,7 +162,6 @@ allowed.

Versions

diff --git a/docs/1.0-dev/Components/Bootstrap-Components-and-Utilities.html b/docs/1.0-dev/Components/Bootstrap-Components-and-Utilities.html index 26f34cdd80..31709d88c1 100644 --- a/docs/1.0-dev/Components/Bootstrap-Components-and-Utilities.html +++ b/docs/1.0-dev/Components/Bootstrap-Components-and-Utilities.html @@ -196,7 +196,6 @@ over Versions diff --git a/docs/1.0-dev/Components/Channels.html b/docs/1.0-dev/Components/Channels.html index 38ac17210b..cf7f7f5502 100644 --- a/docs/1.0-dev/Components/Channels.html +++ b/docs/1.0-dev/Components/Channels.html @@ -465,7 +465,6 @@ subscribers (and thus wipe all their aliases).

Versions

diff --git a/docs/1.0-dev/Components/Coding-Utils.html b/docs/1.0-dev/Components/Coding-Utils.html index 97a8bbe2b2..80561b5346 100644 --- a/docs/1.0-dev/Components/Coding-Utils.html +++ b/docs/1.0-dev/Components/Coding-Utils.html @@ -398,7 +398,6 @@ instructions.

Versions

diff --git a/docs/1.0-dev/Components/Command-Sets.html b/docs/1.0-dev/Components/Command-Sets.html index 59f39e0fff..e3006e3179 100644 --- a/docs/1.0-dev/Components/Command-Sets.html +++ b/docs/1.0-dev/Components/Command-Sets.html @@ -463,7 +463,6 @@ commands having any combination of the keys and/or aliases “kick”, “punch

Versions

diff --git a/docs/1.0-dev/Components/Command-System.html b/docs/1.0-dev/Components/Command-System.html index 13f6094db4..c6174e68fd 100644 --- a/docs/1.0-dev/Components/Command-System.html +++ b/docs/1.0-dev/Components/Command-System.html @@ -94,7 +94,6 @@

Versions

diff --git a/docs/1.0-dev/Components/Commands.html b/docs/1.0-dev/Components/Commands.html index 528323491e..09341b3024 100644 --- a/docs/1.0-dev/Components/Commands.html +++ b/docs/1.0-dev/Components/Commands.html @@ -775,7 +775,6 @@ on.

Versions

diff --git a/docs/1.0-dev/Components/Communications.html b/docs/1.0-dev/Components/Communications.html index 9e4b8c8764..07ac5aeeb1 100644 --- a/docs/1.0-dev/Components/Communications.html +++ b/docs/1.0-dev/Components/Communications.html @@ -91,7 +91,6 @@ and is a building block for implementing other game systems. It’s used by the

Versions

diff --git a/docs/1.0-dev/Components/Components-Overview.html b/docs/1.0-dev/Components/Components-Overview.html index 73a7985215..6e80b15d8b 100644 --- a/docs/1.0-dev/Components/Components-Overview.html +++ b/docs/1.0-dev/Components/Components-Overview.html @@ -190,7 +190,6 @@ than, the doc-strings of each component in the Versions diff --git a/docs/1.0-dev/Components/Connection-Screen.html b/docs/1.0-dev/Components/Connection-Screen.html index 51e12e8a41..3d4af099e1 100644 --- a/docs/1.0-dev/Components/Connection-Screen.html +++ b/docs/1.0-dev/Components/Connection-Screen.html @@ -124,7 +124,6 @@ tutorial section on how to add new commands to a default command set.

Versions

diff --git a/docs/1.0-dev/Components/Default-Commands.html b/docs/1.0-dev/Components/Default-Commands.html index 69c7129b90..8237773949 100644 --- a/docs/1.0-dev/Components/Default-Commands.html +++ b/docs/1.0-dev/Components/Default-Commands.html @@ -191,7 +191,6 @@ with 1.0-dev (develop branch) -
  • 0.9.5 (v0.9.5 branch)
  • diff --git a/docs/1.0-dev/Components/EvEditor.html b/docs/1.0-dev/Components/EvEditor.html index 47347cb49e..201ec0d57a 100644 --- a/docs/1.0-dev/Components/EvEditor.html +++ b/docs/1.0-dev/Components/EvEditor.html @@ -269,7 +269,6 @@ editor can be useful if you want to test the code you have typed but add new lin

    Versions

    diff --git a/docs/1.0-dev/Components/EvMenu.html b/docs/1.0-dev/Components/EvMenu.html index fa16277a72..c67d134f96 100644 --- a/docs/1.0-dev/Components/EvMenu.html +++ b/docs/1.0-dev/Components/EvMenu.html @@ -1335,7 +1335,6 @@ until the exit node.

    Versions

    diff --git a/docs/1.0-dev/Components/EvMore.html b/docs/1.0-dev/Components/EvMore.html index 3ea04dd007..a7937481c2 100644 --- a/docs/1.0-dev/Components/EvMore.html +++ b/docs/1.0-dev/Components/EvMore.html @@ -123,7 +123,6 @@ paging.

    Versions

    diff --git a/docs/1.0-dev/Components/FuncParser.html b/docs/1.0-dev/Components/FuncParser.html index 79fea629e9..f719d28e59 100644 --- a/docs/1.0-dev/Components/FuncParser.html +++ b/docs/1.0-dev/Components/FuncParser.html @@ -466,7 +466,6 @@ all the defaults (like 1.0-dev (develop branch) -
  • 0.9.5 (v0.9.5 branch)
  • diff --git a/docs/1.0-dev/Components/Help-System.html b/docs/1.0-dev/Components/Help-System.html index f32740b413..58338dbf47 100644 --- a/docs/1.0-dev/Components/Help-System.html +++ b/docs/1.0-dev/Components/Help-System.html @@ -485,7 +485,6 @@ at that point).

    Versions

    diff --git a/docs/1.0-dev/Components/Inputfuncs.html b/docs/1.0-dev/Components/Inputfuncs.html index 0d034a3f0d..695920e123 100644 --- a/docs/1.0-dev/Components/Inputfuncs.html +++ b/docs/1.0-dev/Components/Inputfuncs.html @@ -285,7 +285,6 @@ add more. By default the following fields/attributes can be monitored:

    Versions

    diff --git a/docs/1.0-dev/Components/Locks.html b/docs/1.0-dev/Components/Locks.html index 25e952f6f4..c5eca26603 100644 --- a/docs/1.0-dev/Components/Locks.html +++ b/docs/1.0-dev/Components/Locks.html @@ -467,7 +467,6 @@ interface. It’s stand-alone from the permissions described above.

    Versions

    diff --git a/docs/1.0-dev/Components/MonitorHandler.html b/docs/1.0-dev/Components/MonitorHandler.html index 370ba0384f..d966921e97 100644 --- a/docs/1.0-dev/Components/MonitorHandler.html +++ b/docs/1.0-dev/Components/MonitorHandler.html @@ -159,7 +159,6 @@ the monitor to remove:

    Versions

    diff --git a/docs/1.0-dev/Components/Msg.html b/docs/1.0-dev/Components/Msg.html index 4889ad75bd..e44c59dd51 100644 --- a/docs/1.0-dev/Components/Msg.html +++ b/docs/1.0-dev/Components/Msg.html @@ -180,7 +180,6 @@ it.

    Versions

    diff --git a/docs/1.0-dev/Components/Nicks.html b/docs/1.0-dev/Components/Nicks.html index 0768a78f9d..817b951394 100644 --- a/docs/1.0-dev/Components/Nicks.html +++ b/docs/1.0-dev/Components/Nicks.html @@ -203,7 +203,6 @@ basically the unchanged strings you enter to the 1.0-dev (develop branch) -
  • 0.9.5 (v0.9.5 branch)
  • diff --git a/docs/1.0-dev/Components/Objects.html b/docs/1.0-dev/Components/Objects.html index 04ee15431e..2bed940d89 100644 --- a/docs/1.0-dev/Components/Objects.html +++ b/docs/1.0-dev/Components/Objects.html @@ -276,7 +276,6 @@ and display this as an error message. If this is not found, the Exit will instea

    Versions

    diff --git a/docs/1.0-dev/Components/Outputfuncs.html b/docs/1.0-dev/Components/Outputfuncs.html index c593cfe10a..6657bf033e 100644 --- a/docs/1.0-dev/Components/Outputfuncs.html +++ b/docs/1.0-dev/Components/Outputfuncs.html @@ -85,7 +85,6 @@

    Versions

    diff --git a/docs/1.0-dev/Components/Permissions.html b/docs/1.0-dev/Components/Permissions.html index 50f8daffbf..70e48ce962 100644 --- a/docs/1.0-dev/Components/Permissions.html +++ b/docs/1.0-dev/Components/Permissions.html @@ -288,7 +288,6 @@ affectable by locks.

    Versions

    diff --git a/docs/1.0-dev/Components/Portal-And-Server.html b/docs/1.0-dev/Components/Portal-And-Server.html index 5fcf4ab0c6..67e82c6d88 100644 --- a/docs/1.0-dev/Components/Portal-And-Server.html +++ b/docs/1.0-dev/Components/Portal-And-Server.html @@ -93,7 +93,6 @@ This allows the two programs to communicate seamlessly.

    Versions

    diff --git a/docs/1.0-dev/Components/Prototypes.html b/docs/1.0-dev/Components/Prototypes.html index 0a9514dd41..36baa764ed 100644 --- a/docs/1.0-dev/Components/Prototypes.html +++ b/docs/1.0-dev/Components/Prototypes.html @@ -422,7 +422,6 @@ the api docs.

    Versions

    diff --git a/docs/1.0-dev/Components/Scripts.html b/docs/1.0-dev/Components/Scripts.html index d727dbeb0b..d2e96e57d0 100644 --- a/docs/1.0-dev/Components/Scripts.html +++ b/docs/1.0-dev/Components/Scripts.html @@ -503,7 +503,6 @@ traceback occurred in your script.

    Versions

    diff --git a/docs/1.0-dev/Components/Server.html b/docs/1.0-dev/Components/Server.html index 51a71a3a30..62c389ad74 100644 --- a/docs/1.0-dev/Components/Server.html +++ b/docs/1.0-dev/Components/Server.html @@ -85,7 +85,6 @@

    Versions

    diff --git a/docs/1.0-dev/Components/Sessions.html b/docs/1.0-dev/Components/Sessions.html index b8f89e3252..1479aaa42a 100644 --- a/docs/1.0-dev/Components/Sessions.html +++ b/docs/1.0-dev/Components/Sessions.html @@ -275,7 +275,6 @@ module for details on the capabilities of the 1.0-dev (develop branch) -
  • 0.9.5 (v0.9.5 branch)
  • diff --git a/docs/1.0-dev/Components/Signals.html b/docs/1.0-dev/Components/Signals.html index 94bdbc4512..c7556cf302 100644 --- a/docs/1.0-dev/Components/Signals.html +++ b/docs/1.0-dev/Components/Signals.html @@ -202,7 +202,6 @@ decorator (only relevant for unit testing)

    Versions

    diff --git a/docs/1.0-dev/Components/Tags.html b/docs/1.0-dev/Components/Tags.html index 51a4a510ed..f6969147b5 100644 --- a/docs/1.0-dev/Components/Tags.html +++ b/docs/1.0-dev/Components/Tags.html @@ -249,7 +249,6 @@ is found in the Versions diff --git a/docs/1.0-dev/Components/TickerHandler.html b/docs/1.0-dev/Components/TickerHandler.html index 2db79715d9..a2d350c4c8 100644 --- a/docs/1.0-dev/Components/TickerHandler.html +++ b/docs/1.0-dev/Components/TickerHandler.html @@ -205,7 +205,6 @@ same time without input from something else.

    Versions

    diff --git a/docs/1.0-dev/Components/Typeclasses.html b/docs/1.0-dev/Components/Typeclasses.html index 55873f4b4d..22f2d3919b 100644 --- a/docs/1.0-dev/Components/Typeclasses.html +++ b/docs/1.0-dev/Components/Typeclasses.html @@ -413,7 +413,6 @@ comments for examples and solutions.

    Versions

    diff --git a/docs/1.0-dev/Components/Web-API.html b/docs/1.0-dev/Components/Web-API.html index d91c148388..3d8142c231 100644 --- a/docs/1.0-dev/Components/Web-API.html +++ b/docs/1.0-dev/Components/Web-API.html @@ -204,7 +204,6 @@ copy over evennia/w

    Versions

    diff --git a/docs/1.0-dev/Components/Web-Admin.html b/docs/1.0-dev/Components/Web-Admin.html index 0e7998d89c..e64c9aa42e 100644 --- a/docs/1.0-dev/Components/Web-Admin.html +++ b/docs/1.0-dev/Components/Web-Admin.html @@ -251,7 +251,6 @@ following to your m

    Versions

    diff --git a/docs/1.0-dev/Components/Webclient.html b/docs/1.0-dev/Components/Webclient.html index 9438ec9b01..f157db0fda 100644 --- a/docs/1.0-dev/Components/Webclient.html +++ b/docs/1.0-dev/Components/Webclient.html @@ -350,7 +350,6 @@ window.plugin_handler.add("myplugin", myplugin);

    Versions

    diff --git a/docs/1.0-dev/Components/Webserver.html b/docs/1.0-dev/Components/Webserver.html index 26eb637b76..4862d3e56e 100644 --- a/docs/1.0-dev/Components/Webserver.html +++ b/docs/1.0-dev/Components/Webserver.html @@ -164,7 +164,6 @@ come back or you reload it manually in your browser.

    Versions

    diff --git a/docs/1.0-dev/Components/Website.html b/docs/1.0-dev/Components/Website.html index d1769bb87c..9e9727ee44 100644 --- a/docs/1.0-dev/Components/Website.html +++ b/docs/1.0-dev/Components/Website.html @@ -255,13 +255,13 @@ browser without cache (Ctrl-F5 in Firefox, for example).

    As an example, add/copy custom.css to mygame/web/static/website/css/ and add the following:

    -
    .navbar {
    -  background-color: #7a3d54;
    -}
    +
    .navbar {
    +  background-color: #7a3d54;
    +}
     
    -.footer {
    -  background-color: #7a3d54;
    -}
    +.footer {
    +  background-color: #7a3d54;
    +}
     

    Reload and your website now has a red theme!

    @@ -485,7 +485,6 @@ on the Django website - it covers all you need.

    Versions

    diff --git a/docs/1.0-dev/Concepts/Async-Process.html b/docs/1.0-dev/Concepts/Async-Process.html index 14e7c83481..43270e9909 100644 --- a/docs/1.0-dev/Concepts/Async-Process.html +++ b/docs/1.0-dev/Concepts/Async-Process.html @@ -301,7 +301,6 @@ your own liking.

    Versions

    diff --git a/docs/1.0-dev/Concepts/Banning.html b/docs/1.0-dev/Concepts/Banning.html index 846486a48a..badedda31a 100644 --- a/docs/1.0-dev/Concepts/Banning.html +++ b/docs/1.0-dev/Concepts/Banning.html @@ -240,7 +240,6 @@ objects on the fly. For advanced users.

    Versions

    diff --git a/docs/1.0-dev/Concepts/Bootstrap-&-Evennia.html b/docs/1.0-dev/Concepts/Bootstrap-&-Evennia.html index 527e1485f8..d4420997f4 100644 --- a/docs/1.0-dev/Concepts/Bootstrap-&-Evennia.html +++ b/docs/1.0-dev/Concepts/Bootstrap-&-Evennia.html @@ -192,7 +192,6 @@ started/introduction/) or read one of our other web tutorials.

    Versions

    diff --git a/docs/1.0-dev/Concepts/Building-Permissions.html b/docs/1.0-dev/Concepts/Building-Permissions.html index e3f0775207..90bbd42c91 100644 --- a/docs/1.0-dev/Concepts/Building-Permissions.html +++ b/docs/1.0-dev/Concepts/Building-Permissions.html @@ -162,7 +162,6 @@ levels. Note that you cannot escalate your permissions this way; If the Characte

    Versions

    diff --git a/docs/1.0-dev/Concepts/Change-Messages-Per-Receiver.html b/docs/1.0-dev/Concepts/Change-Messages-Per-Receiver.html index 1c04a694a4..fe33bbc375 100644 --- a/docs/1.0-dev/Concepts/Change-Messages-Per-Receiver.html +++ b/docs/1.0-dev/Concepts/Change-Messages-Per-Receiver.html @@ -444,7 +444,6 @@ worth checking out for inspiration.

    Versions

    diff --git a/docs/1.0-dev/Concepts/Clickable-Links.html b/docs/1.0-dev/Concepts/Clickable-Links.html index c40424f711..991420ce5c 100644 --- a/docs/1.0-dev/Concepts/Clickable-Links.html +++ b/docs/1.0-dev/Concepts/Clickable-Links.html @@ -101,7 +101,6 @@ will be shown.

    Versions

    diff --git a/docs/1.0-dev/Concepts/Colors.html b/docs/1.0-dev/Concepts/Colors.html index 17aa137708..3a7802cf02 100644 --- a/docs/1.0-dev/Concepts/Colors.html +++ b/docs/1.0-dev/Concepts/Colors.html @@ -269,7 +269,6 @@ use of ANSI color tags and the pitfalls of mixing ANSI and Xterms256 color tags

    Versions

    diff --git a/docs/1.0-dev/Concepts/Concepts-Overview.html b/docs/1.0-dev/Concepts/Concepts-Overview.html index 9104302be0..a9cc0ace86 100644 --- a/docs/1.0-dev/Concepts/Concepts-Overview.html +++ b/docs/1.0-dev/Concepts/Concepts-Overview.html @@ -150,7 +150,6 @@

    Versions

    diff --git a/docs/1.0-dev/Concepts/Custom-Protocols.html b/docs/1.0-dev/Concepts/Custom-Protocols.html index 308a398d86..8c7bfc066d 100644 --- a/docs/1.0-dev/Concepts/Custom-Protocols.html +++ b/docs/1.0-dev/Concepts/Custom-Protocols.html @@ -315,7 +315,6 @@ ways.

    Versions

    diff --git a/docs/1.0-dev/Concepts/Guest-Logins.html b/docs/1.0-dev/Concepts/Guest-Logins.html index 5dc0f02250..e4bb14bc8a 100644 --- a/docs/1.0-dev/Concepts/Guest-Logins.html +++ b/docs/1.0-dev/Concepts/Guest-Logins.html @@ -109,7 +109,6 @@ of nine names from

    Versions

    diff --git a/docs/1.0-dev/Concepts/Internationalization.html b/docs/1.0-dev/Concepts/Internationalization.html index c0e28e8b84..8652ad9193 100644 --- a/docs/1.0-dev/Concepts/Internationalization.html +++ b/docs/1.0-dev/Concepts/Internationalization.html @@ -275,7 +275,6 @@ Swedish: "Fel medan cmdset laddades: Ingen cmdset-klass med namn '{cla

    Versions

    diff --git a/docs/1.0-dev/Concepts/Messagepath.html b/docs/1.0-dev/Concepts/Messagepath.html index 5e7308a3e0..94c5ec26e7 100644 --- a/docs/1.0-dev/Concepts/Messagepath.html +++ b/docs/1.0-dev/Concepts/Messagepath.html @@ -304,7 +304,6 @@ may trigger changes in the GUI or play a sound etc.

    Versions

    diff --git a/docs/1.0-dev/Concepts/Multisession-modes.html b/docs/1.0-dev/Concepts/Multisession-modes.html index 7ce616eb90..cf01160a1b 100644 --- a/docs/1.0-dev/Concepts/Multisession-modes.html +++ b/docs/1.0-dev/Concepts/Multisession-modes.html @@ -85,7 +85,6 @@

    Versions

    diff --git a/docs/1.0-dev/Concepts/New-Models.html b/docs/1.0-dev/Concepts/New-Models.html index 35e98ee952..3df50dec29 100644 --- a/docs/1.0-dev/Concepts/New-Models.html +++ b/docs/1.0-dev/Concepts/New-Models.html @@ -335,7 +335,6 @@ lot more information about querying the database.

    Versions

    diff --git a/docs/1.0-dev/Concepts/OOB.html b/docs/1.0-dev/Concepts/OOB.html index 4ca32cb0f3..5367b16ca8 100644 --- a/docs/1.0-dev/Concepts/OOB.html +++ b/docs/1.0-dev/Concepts/OOB.html @@ -256,7 +256,6 @@ same example ("

    Versions

    diff --git a/docs/1.0-dev/Concepts/Soft-Code.html b/docs/1.0-dev/Concepts/Soft-Code.html index 2178551145..d0d1099ea1 100644 --- a/docs/1.0-dev/Concepts/Soft-Code.html +++ b/docs/1.0-dev/Concepts/Soft-Code.html @@ -176,7 +176,6 @@ pseudo-softcode plugin aimed at developers wanting to script their game from ins

    Versions

    diff --git a/docs/1.0-dev/Concepts/Text-Encodings.html b/docs/1.0-dev/Concepts/Text-Encodings.html index 9cc3d32498..43628fde7d 100644 --- a/docs/1.0-dev/Concepts/Text-Encodings.html +++ b/docs/1.0-dev/Concepts/Text-Encodings.html @@ -149,7 +149,6 @@ the Wikipedia article 1.0-dev (develop branch) -
  • 0.9.5 (v0.9.5 branch)
  • diff --git a/docs/1.0-dev/Concepts/TextTags.html b/docs/1.0-dev/Concepts/TextTags.html index 4e47e191d5..ddd2904832 100644 --- a/docs/1.0-dev/Concepts/TextTags.html +++ b/docs/1.0-dev/Concepts/TextTags.html @@ -95,7 +95,6 @@ circumstances. The parser is run on all outgoing messages if 1.0-dev (develop branch) -
  • 0.9.5 (v0.9.5 branch)
  • diff --git a/docs/1.0-dev/Concepts/Using-MUX-as-a-Standard.html b/docs/1.0-dev/Concepts/Using-MUX-as-a-Standard.html index 68930ce859..d845c12d80 100644 --- a/docs/1.0-dev/Concepts/Using-MUX-as-a-Standard.html +++ b/docs/1.0-dev/Concepts/Using-MUX-as-a-Standard.html @@ -168,7 +168,6 @@ something to the effect of

    Versions

    diff --git a/docs/1.0-dev/Concepts/Web-Features.html b/docs/1.0-dev/Concepts/Web-Features.html index d4afe20a46..19fd9568d0 100644 --- a/docs/1.0-dev/Concepts/Web-Features.html +++ b/docs/1.0-dev/Concepts/Web-Features.html @@ -216,7 +216,6 @@ implementation, the relevant django “applications” in default Evennia are Versions diff --git a/docs/1.0-dev/Concepts/Zones.html b/docs/1.0-dev/Concepts/Zones.html index 68d2f7d7bb..0a173a63e6 100644 --- a/docs/1.0-dev/Concepts/Zones.html +++ b/docs/1.0-dev/Concepts/Zones.html @@ -138,7 +138,6 @@ properly search the inheritance tree.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Arxcode-installing-help.html b/docs/1.0-dev/Contribs/Arxcode-installing-help.html index 341aa27581..38ed2a414c 100644 --- a/docs/1.0-dev/Contribs/Arxcode-installing-help.html +++ b/docs/1.0-dev/Contribs/Arxcode-installing-help.html @@ -338,7 +338,6 @@ on localhost at port 4000, and the webserver at Versions diff --git a/docs/1.0-dev/Contribs/Building-menus.html b/docs/1.0-dev/Contribs/Building-menus.html index 0a91548e77..fefabc6e8c 100644 --- a/docs/1.0-dev/Contribs/Building-menus.html +++ b/docs/1.0-dev/Contribs/Building-menus.html @@ -1292,7 +1292,6 @@ exhaustive but user-friendly.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-AWSStorage.html b/docs/1.0-dev/Contribs/Contrib-AWSStorage.html index 6d84b2ca3b..50c30df90a 100644 --- a/docs/1.0-dev/Contribs/Contrib-AWSStorage.html +++ b/docs/1.0-dev/Contribs/Contrib-AWSStorage.html @@ -314,7 +314,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Auditing.html b/docs/1.0-dev/Contribs/Contrib-Auditing.html index 7697922a9b..b81e234b55 100644 --- a/docs/1.0-dev/Contribs/Contrib-Auditing.html +++ b/docs/1.0-dev/Contribs/Contrib-Auditing.html @@ -161,7 +161,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Barter.html b/docs/1.0-dev/Contribs/Contrib-Barter.html index 569211026f..4bd818db67 100644 --- a/docs/1.0-dev/Contribs/Contrib-Barter.html +++ b/docs/1.0-dev/Contribs/Contrib-Barter.html @@ -200,7 +200,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Batchprocessor.html b/docs/1.0-dev/Contribs/Contrib-Batchprocessor.html index e83640c9e6..67525ac07e 100644 --- a/docs/1.0-dev/Contribs/Contrib-Batchprocessor.html +++ b/docs/1.0-dev/Contribs/Contrib-Batchprocessor.html @@ -126,7 +126,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Bodyfunctions.html b/docs/1.0-dev/Contribs/Contrib-Bodyfunctions.html index f328ffaae6..6777be84de 100644 --- a/docs/1.0-dev/Contribs/Contrib-Bodyfunctions.html +++ b/docs/1.0-dev/Contribs/Contrib-Bodyfunctions.html @@ -108,7 +108,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Building-Menu.html b/docs/1.0-dev/Contribs/Contrib-Building-Menu.html index 062f4c54e5..4cd30c4fb9 100644 --- a/docs/1.0-dev/Contribs/Contrib-Building-Menu.html +++ b/docs/1.0-dev/Contribs/Contrib-Building-Menu.html @@ -206,7 +206,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Clothing.html b/docs/1.0-dev/Contribs/Contrib-Clothing.html index 769f125c2f..2535da2a61 100644 --- a/docs/1.0-dev/Contribs/Contrib-Clothing.html +++ b/docs/1.0-dev/Contribs/Contrib-Clothing.html @@ -176,7 +176,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Color-Markups.html b/docs/1.0-dev/Contribs/Contrib-Color-Markups.html index e9afde09ef..e4abe96c5d 100644 --- a/docs/1.0-dev/Contribs/Contrib-Color-Markups.html +++ b/docs/1.0-dev/Contribs/Contrib-Color-Markups.html @@ -147,7 +147,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Cooldowns.html b/docs/1.0-dev/Contribs/Contrib-Cooldowns.html index 8c20a57dd3..c533134bc3 100644 --- a/docs/1.0-dev/Contribs/Contrib-Cooldowns.html +++ b/docs/1.0-dev/Contribs/Contrib-Cooldowns.html @@ -145,7 +145,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Crafting.html b/docs/1.0-dev/Contribs/Contrib-Crafting.html index 9310630f30..4b9948fd61 100644 --- a/docs/1.0-dev/Contribs/Contrib-Crafting.html +++ b/docs/1.0-dev/Contribs/Contrib-Crafting.html @@ -370,7 +370,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Custom-Gametime.html b/docs/1.0-dev/Contribs/Contrib-Custom-Gametime.html index 69e6b08678..146df47307 100644 --- a/docs/1.0-dev/Contribs/Contrib-Custom-Gametime.html +++ b/docs/1.0-dev/Contribs/Contrib-Custom-Gametime.html @@ -138,7 +138,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Dice.html b/docs/1.0-dev/Contribs/Contrib-Dice.html index 91ac705fbe..25c5568758 100644 --- a/docs/1.0-dev/Contribs/Contrib-Dice.html +++ b/docs/1.0-dev/Contribs/Contrib-Dice.html @@ -155,7 +155,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Email-Login.html b/docs/1.0-dev/Contribs/Contrib-Email-Login.html index 1d9eca7277..f557236b33 100644 --- a/docs/1.0-dev/Contribs/Contrib-Email-Login.html +++ b/docs/1.0-dev/Contribs/Contrib-Email-Login.html @@ -121,7 +121,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Evscaperoom.html b/docs/1.0-dev/Contribs/Contrib-Evscaperoom.html index 87c449c05e..ff4fc74c84 100644 --- a/docs/1.0-dev/Contribs/Contrib-Evscaperoom.html +++ b/docs/1.0-dev/Contribs/Contrib-Evscaperoom.html @@ -211,7 +211,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Extended-Room.html b/docs/1.0-dev/Contribs/Contrib-Extended-Room.html index c198adbd42..c775ab829a 100644 --- a/docs/1.0-dev/Contribs/Contrib-Extended-Room.html +++ b/docs/1.0-dev/Contribs/Contrib-Extended-Room.html @@ -172,7 +172,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Fieldfill.html b/docs/1.0-dev/Contribs/Contrib-Fieldfill.html index 456c91ec06..20b82106a6 100644 --- a/docs/1.0-dev/Contribs/Contrib-Fieldfill.html +++ b/docs/1.0-dev/Contribs/Contrib-Fieldfill.html @@ -242,7 +242,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Gendersub.html b/docs/1.0-dev/Contribs/Contrib-Gendersub.html index bc59bd229f..d6516897fa 100644 --- a/docs/1.0-dev/Contribs/Contrib-Gendersub.html +++ b/docs/1.0-dev/Contribs/Contrib-Gendersub.html @@ -135,7 +135,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Health-Bar.html b/docs/1.0-dev/Contribs/Contrib-Health-Bar.html index c72a5014fb..e0fac3aeea 100644 --- a/docs/1.0-dev/Contribs/Contrib-Health-Bar.html +++ b/docs/1.0-dev/Contribs/Contrib-Health-Bar.html @@ -124,7 +124,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Ingame-Python-Tutorial-Dialogue.html b/docs/1.0-dev/Contribs/Contrib-Ingame-Python-Tutorial-Dialogue.html index fcb06ead46..61482829a2 100644 --- a/docs/1.0-dev/Contribs/Contrib-Ingame-Python-Tutorial-Dialogue.html +++ b/docs/1.0-dev/Contribs/Contrib-Ingame-Python-Tutorial-Dialogue.html @@ -318,7 +318,6 @@ events).

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Ingame-Python-Tutorial-Elevator.html b/docs/1.0-dev/Contribs/Contrib-Ingame-Python-Tutorial-Elevator.html index 5f1952b58e..bea91e9d7e 100644 --- a/docs/1.0-dev/Contribs/Contrib-Ingame-Python-Tutorial-Elevator.html +++ b/docs/1.0-dev/Contribs/Contrib-Ingame-Python-Tutorial-Elevator.html @@ -506,7 +506,6 @@ shown in the next tutorial.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Ingame-Python.html b/docs/1.0-dev/Contribs/Contrib-Ingame-Python.html index 33664ea029..61765e4a4e 100644 --- a/docs/1.0-dev/Contribs/Contrib-Ingame-Python.html +++ b/docs/1.0-dev/Contribs/Contrib-Ingame-Python.html @@ -999,7 +999,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Mail.html b/docs/1.0-dev/Contribs/Contrib-Mail.html index 7b75819007..32c8144b11 100644 --- a/docs/1.0-dev/Contribs/Contrib-Mail.html +++ b/docs/1.0-dev/Contribs/Contrib-Mail.html @@ -143,7 +143,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Mapbuilder.html b/docs/1.0-dev/Contribs/Contrib-Mapbuilder.html index 456b20afc7..083591eabf 100644 --- a/docs/1.0-dev/Contribs/Contrib-Mapbuilder.html +++ b/docs/1.0-dev/Contribs/Contrib-Mapbuilder.html @@ -372,7 +372,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Menu-Login.html b/docs/1.0-dev/Contribs/Contrib-Menu-Login.html index 4f37e06ac1..a16195baf5 100644 --- a/docs/1.0-dev/Contribs/Contrib-Menu-Login.html +++ b/docs/1.0-dev/Contribs/Contrib-Menu-Login.html @@ -115,7 +115,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Mirror.html b/docs/1.0-dev/Contribs/Contrib-Mirror.html index 9c5685cc27..e0f37f32d6 100644 --- a/docs/1.0-dev/Contribs/Contrib-Mirror.html +++ b/docs/1.0-dev/Contribs/Contrib-Mirror.html @@ -110,7 +110,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Multidescer.html b/docs/1.0-dev/Contribs/Contrib-Multidescer.html index 26da170a02..ad6c0f42bd 100644 --- a/docs/1.0-dev/Contribs/Contrib-Multidescer.html +++ b/docs/1.0-dev/Contribs/Contrib-Multidescer.html @@ -114,7 +114,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Mux-Comms-Cmds.html b/docs/1.0-dev/Contribs/Contrib-Mux-Comms-Cmds.html index ca43835973..f93778b387 100644 --- a/docs/1.0-dev/Contribs/Contrib-Mux-Comms-Cmds.html +++ b/docs/1.0-dev/Contribs/Contrib-Mux-Comms-Cmds.html @@ -160,7 +160,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Overview.html b/docs/1.0-dev/Contribs/Contrib-Overview.html index f2efed3d1f..d0a83c5ab2 100644 --- a/docs/1.0-dev/Contribs/Contrib-Overview.html +++ b/docs/1.0-dev/Contribs/Contrib-Overview.html @@ -586,7 +586,6 @@ will be overwritten.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Puzzles.html b/docs/1.0-dev/Contribs/Contrib-Puzzles.html index b4e6ad64e9..3297e06e37 100644 --- a/docs/1.0-dev/Contribs/Contrib-Puzzles.html +++ b/docs/1.0-dev/Contribs/Contrib-Puzzles.html @@ -163,7 +163,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-RPSystem.html b/docs/1.0-dev/Contribs/Contrib-RPSystem.html index 239a5d10d1..4752a6dd50 100644 --- a/docs/1.0-dev/Contribs/Contrib-RPSystem.html +++ b/docs/1.0-dev/Contribs/Contrib-RPSystem.html @@ -350,7 +350,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Random-String-Generator.html b/docs/1.0-dev/Contribs/Contrib-Random-String-Generator.html index 8fd06487a3..dfc458c1fd 100644 --- a/docs/1.0-dev/Contribs/Contrib-Random-String-Generator.html +++ b/docs/1.0-dev/Contribs/Contrib-Random-String-Generator.html @@ -150,7 +150,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Red-Button.html b/docs/1.0-dev/Contribs/Contrib-Red-Button.html index 02fcfe3783..ba7e33edd7 100644 --- a/docs/1.0-dev/Contribs/Contrib-Red-Button.html +++ b/docs/1.0-dev/Contribs/Contrib-Red-Button.html @@ -123,7 +123,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Simpledoor.html b/docs/1.0-dev/Contribs/Contrib-Simpledoor.html index ffdd6e2c94..dd885c9ca5 100644 --- a/docs/1.0-dev/Contribs/Contrib-Simpledoor.html +++ b/docs/1.0-dev/Contribs/Contrib-Simpledoor.html @@ -137,7 +137,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Slow-Exit.html b/docs/1.0-dev/Contribs/Contrib-Slow-Exit.html index b2c963756a..268e4b3b7c 100644 --- a/docs/1.0-dev/Contribs/Contrib-Slow-Exit.html +++ b/docs/1.0-dev/Contribs/Contrib-Slow-Exit.html @@ -149,7 +149,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Talking-Npc.html b/docs/1.0-dev/Contribs/Contrib-Talking-Npc.html index 1dbb4ccd9b..a6208b28f5 100644 --- a/docs/1.0-dev/Contribs/Contrib-Talking-Npc.html +++ b/docs/1.0-dev/Contribs/Contrib-Talking-Npc.html @@ -111,7 +111,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Traits.html b/docs/1.0-dev/Contribs/Contrib-Traits.html index afe47c5df9..9bb59c0d5c 100644 --- a/docs/1.0-dev/Contribs/Contrib-Traits.html +++ b/docs/1.0-dev/Contribs/Contrib-Traits.html @@ -521,7 +521,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Tree-Select.html b/docs/1.0-dev/Contribs/Contrib-Tree-Select.html index 3ca69c04fe..d76e044cd4 100644 --- a/docs/1.0-dev/Contribs/Contrib-Tree-Select.html +++ b/docs/1.0-dev/Contribs/Contrib-Tree-Select.html @@ -239,7 +239,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Turnbattle.html b/docs/1.0-dev/Contribs/Contrib-Turnbattle.html index d8dd0ee641..3b045b454e 100644 --- a/docs/1.0-dev/Contribs/Contrib-Turnbattle.html +++ b/docs/1.0-dev/Contribs/Contrib-Turnbattle.html @@ -137,7 +137,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Tutorial-World.html b/docs/1.0-dev/Contribs/Contrib-Tutorial-World.html index ac82e4d6f2..3ec804c70d 100644 --- a/docs/1.0-dev/Contribs/Contrib-Tutorial-World.html +++ b/docs/1.0-dev/Contribs/Contrib-Tutorial-World.html @@ -189,7 +189,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Unixcommand.html b/docs/1.0-dev/Contribs/Contrib-Unixcommand.html index 0ecde4c4da..9b95ff7137 100644 --- a/docs/1.0-dev/Contribs/Contrib-Unixcommand.html +++ b/docs/1.0-dev/Contribs/Contrib-Unixcommand.html @@ -155,7 +155,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-Wilderness.html b/docs/1.0-dev/Contribs/Contrib-Wilderness.html index 54d22a0933..e71d32c585 100644 --- a/docs/1.0-dev/Contribs/Contrib-Wilderness.html +++ b/docs/1.0-dev/Contribs/Contrib-Wilderness.html @@ -205,7 +205,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contribs/Contrib-XYZGrid.html b/docs/1.0-dev/Contribs/Contrib-XYZGrid.html index 1a8ec26f03..3d1b361912 100644 --- a/docs/1.0-dev/Contribs/Contrib-XYZGrid.html +++ b/docs/1.0-dev/Contribs/Contrib-XYZGrid.html @@ -1308,7 +1308,7 @@ know how to call find the pathfinder though:

  • xymap.get_shortest_path(start_xy, end_xy)

  • xymap.get_visual_range(xy, dist=2, **kwargs)

  • -

    See the XYMap documentation for +

    See the XYMap documentation for details.

    @@ -1556,7 +1556,6 @@ file will be overwritten, so edit that file rather than this one.

    Versions

    diff --git a/docs/1.0-dev/Contributing-Docs.html b/docs/1.0-dev/Contributing-Docs.html index 72ed89ab21..4b34fdc95f 100644 --- a/docs/1.0-dev/Contributing-Docs.html +++ b/docs/1.0-dev/Contributing-Docs.html @@ -824,7 +824,6 @@ available at 1.0-dev (develop branch) -
  • 0.9.5 (v0.9.5 branch)
  • diff --git a/docs/1.0-dev/Contributing.html b/docs/1.0-dev/Contributing.html index 50c0fb9f74..667e1e0ab8 100644 --- a/docs/1.0-dev/Contributing.html +++ b/docs/1.0-dev/Contributing.html @@ -287,7 +287,6 @@ PayPal yourself to use it).

    Versions

    diff --git a/docs/1.0-dev/Evennia-API.html b/docs/1.0-dev/Evennia-API.html index df104d5a65..5c3b1a57d6 100644 --- a/docs/1.0-dev/Evennia-API.html +++ b/docs/1.0-dev/Evennia-API.html @@ -232,7 +232,6 @@ game-specific contributions and plugins (1.0-dev (develop branch) -
  • 0.9.5 (v0.9.5 branch)
  • diff --git a/docs/1.0-dev/Evennia-Introduction.html b/docs/1.0-dev/Evennia-Introduction.html index b19917f049..29ed1948ff 100644 --- a/docs/1.0-dev/Evennia-Introduction.html +++ b/docs/1.0-dev/Evennia-Introduction.html @@ -237,7 +237,6 @@ your own game, you will end up with a small (very small) game that you can build

    Versions

    diff --git a/docs/1.0-dev/Glossary.html b/docs/1.0-dev/Glossary.html index eecea1407d..ffde33fd66 100644 --- a/docs/1.0-dev/Glossary.html +++ b/docs/1.0-dev/Glossary.html @@ -486,7 +486,6 @@ activated whenever you want to use the 1.0-dev (develop branch) -
  • 0.9.5 (v0.9.5 branch)
  • diff --git a/docs/1.0-dev/Howto/Add-a-wiki-on-your-website.html b/docs/1.0-dev/Howto/Add-a-wiki-on-your-website.html index 75a9b9f02f..06bce32076 100644 --- a/docs/1.0-dev/Howto/Add-a-wiki-on-your-website.html +++ b/docs/1.0-dev/Howto/Add-a-wiki-on-your-website.html @@ -326,7 +326,6 @@ necessary. If you’re interested in supporting this little project, you are mo

    Versions

    diff --git a/docs/1.0-dev/Howto/Building-a-mech-tutorial.html b/docs/1.0-dev/Howto/Building-a-mech-tutorial.html index 9b3d115400..534da08824 100644 --- a/docs/1.0-dev/Howto/Building-a-mech-tutorial.html +++ b/docs/1.0-dev/Howto/Building-a-mech-tutorial.html @@ -323,7 +323,6 @@ shooting goodness would be made available to you only when you enter it.

    Versions

    diff --git a/docs/1.0-dev/Howto/Coding-FAQ.html b/docs/1.0-dev/Howto/Coding-FAQ.html index 6a39387b69..5826be7115 100644 --- a/docs/1.0-dev/Howto/Coding-FAQ.html +++ b/docs/1.0-dev/Howto/Coding-FAQ.html @@ -453,7 +453,6 @@ discussion where some suitable fonts are suggested.

    Versions

    diff --git a/docs/1.0-dev/Howto/Command-Cooldown.html b/docs/1.0-dev/Howto/Command-Cooldown.html index d5cb1189ed..12655d00c0 100644 --- a/docs/1.0-dev/Howto/Command-Cooldown.html +++ b/docs/1.0-dev/Howto/Command-Cooldown.html @@ -183,7 +183,6 @@ other types of attacks for a while before the warrior can recover.

    Versions

    diff --git a/docs/1.0-dev/Howto/Command-Duration.html b/docs/1.0-dev/Howto/Command-Duration.html index 67b1dff2af..5f17f80b63 100644 --- a/docs/1.0-dev/Howto/Command-Duration.html +++ b/docs/1.0-dev/Howto/Command-Duration.html @@ -484,7 +484,6 @@ callback when the server comes back up (it will resume the countdown and ignore

    Versions

    diff --git a/docs/1.0-dev/Howto/Command-Prompt.html b/docs/1.0-dev/Howto/Command-Prompt.html index 5964437e68..4c38495194 100644 --- a/docs/1.0-dev/Howto/Command-Prompt.html +++ b/docs/1.0-dev/Howto/Command-Prompt.html @@ -208,7 +208,6 @@ directly the easiest way is to just wrap those with a multiple inheritance to yo

    Versions

    diff --git a/docs/1.0-dev/Howto/Coordinates.html b/docs/1.0-dev/Howto/Coordinates.html index 3c77386cb8..1101cabef3 100644 --- a/docs/1.0-dev/Howto/Coordinates.html +++ b/docs/1.0-dev/Howto/Coordinates.html @@ -429,7 +429,6 @@ square (E, G, M and O) are not in this circle. So we remove them.

    Versions

    diff --git a/docs/1.0-dev/Howto/Default-Exit-Errors.html b/docs/1.0-dev/Howto/Default-Exit-Errors.html index 7243a39a1a..3c7071aed6 100644 --- a/docs/1.0-dev/Howto/Default-Exit-Errors.html +++ b/docs/1.0-dev/Howto/Default-Exit-Errors.html @@ -204,7 +204,6 @@ matching “north” exit-command.

    Versions

    diff --git a/docs/1.0-dev/Howto/Dynamic-In-Game-Map.html b/docs/1.0-dev/Howto/Dynamic-In-Game-Map.html index d85d90eabc..dce9e23819 100644 --- a/docs/1.0-dev/Howto/Dynamic-In-Game-Map.html +++ b/docs/1.0-dev/Howto/Dynamic-In-Game-Map.html @@ -555,7 +555,6 @@ also look into up/down directions and figure out how to display that in a good w

    Versions

    diff --git a/docs/1.0-dev/Howto/Evennia-for-Diku-Users.html b/docs/1.0-dev/Howto/Evennia-for-Diku-Users.html index 2498c26e41..b5ff10e064 100644 --- a/docs/1.0-dev/Howto/Evennia-for-Diku-Users.html +++ b/docs/1.0-dev/Howto/Evennia-for-Diku-Users.html @@ -78,7 +78,7 @@ handling, that you are accessing the right object. In Diku C, accessing characte done by:

    /* creating pointer of both character and room struct */
     
    -void(struct char ch*, struct room room*){
    +void(struct char ch*, struct room room*){
         int dam;
         if (ROOM_FLAGGED(room, ROOM_LAVA)){
             dam = 100;
    @@ -270,7 +270,6 @@ your mob.

    Versions

    diff --git a/docs/1.0-dev/Howto/Evennia-for-MUSH-Users.html b/docs/1.0-dev/Howto/Evennia-for-MUSH-Users.html index 582c7ed196..d4be0d2149 100644 --- a/docs/1.0-dev/Howto/Evennia-for-MUSH-Users.html +++ b/docs/1.0-dev/Howto/Evennia-for-MUSH-Users.html @@ -293,7 +293,6 @@ or post a question in our 1.0-dev (develop branch) -
  • 0.9.5 (v0.9.5 branch)
  • diff --git a/docs/1.0-dev/Howto/Evennia-for-roleplaying-sessions.html b/docs/1.0-dev/Howto/Evennia-for-roleplaying-sessions.html index 9804d16876..7be1533174 100644 --- a/docs/1.0-dev/Howto/Evennia-for-roleplaying-sessions.html +++ b/docs/1.0-dev/Howto/Evennia-for-roleplaying-sessions.html @@ -813,7 +813,6 @@ when the message was sent.

    Versions

    diff --git a/docs/1.0-dev/Howto/Gametime-Tutorial.html b/docs/1.0-dev/Howto/Gametime-Tutorial.html index 2c1d07a775..2a4c36e2a7 100644 --- a/docs/1.0-dev/Howto/Gametime-Tutorial.html +++ b/docs/1.0-dev/Howto/Gametime-Tutorial.html @@ -375,7 +375,6 @@ same way as described for the default one above.

    Versions

    diff --git a/docs/1.0-dev/Howto/Help-System-Tutorial.html b/docs/1.0-dev/Howto/Help-System-Tutorial.html index e50d35a59e..80ec62067f 100644 --- a/docs/1.0-dev/Howto/Help-System-Tutorial.html +++ b/docs/1.0-dev/Howto/Help-System-Tutorial.html @@ -568,7 +568,6 @@ themselves links to display their details.

    Versions

    diff --git a/docs/1.0-dev/Howto/Howto-Overview.html b/docs/1.0-dev/Howto/Howto-Overview.html index ab53ac7843..35d1a76db6 100644 --- a/docs/1.0-dev/Howto/Howto-Overview.html +++ b/docs/1.0-dev/Howto/Howto-Overview.html @@ -246,7 +246,6 @@ in mind for your own game, this will give you a good start.

    Versions

    diff --git a/docs/1.0-dev/Howto/Manually-Configuring-Color.html b/docs/1.0-dev/Howto/Manually-Configuring-Color.html index e31835e894..9beac39ffb 100644 --- a/docs/1.0-dev/Howto/Manually-Configuring-Color.html +++ b/docs/1.0-dev/Howto/Manually-Configuring-Color.html @@ -248,7 +248,6 @@ regardless of if Evennia thinks their client supports it or not.

    Versions

    diff --git a/docs/1.0-dev/Howto/Mass-and-weight-for-objects.html b/docs/1.0-dev/Howto/Mass-and-weight-for-objects.html index 5c38e71409..c36cedfd28 100644 --- a/docs/1.0-dev/Howto/Mass-and-weight-for-objects.html +++ b/docs/1.0-dev/Howto/Mass-and-weight-for-objects.html @@ -180,7 +180,6 @@ the following message in the elevator’s appearance: 1.0-dev (develop branch) -
  • 0.9.5 (v0.9.5 branch)
  • diff --git a/docs/1.0-dev/Howto/NPC-shop-Tutorial.html b/docs/1.0-dev/Howto/NPC-shop-Tutorial.html index 1a1efa9bcb..0264865d99 100644 --- a/docs/1.0-dev/Howto/NPC-shop-Tutorial.html +++ b/docs/1.0-dev/Howto/NPC-shop-Tutorial.html @@ -414,7 +414,6 @@ it well stocked.

    Versions

    diff --git a/docs/1.0-dev/Howto/Parsing-commands-tutorial.html b/docs/1.0-dev/Howto/Parsing-commands-tutorial.html index db4073c396..c1c4137626 100644 --- a/docs/1.0-dev/Howto/Parsing-commands-tutorial.html +++ b/docs/1.0-dev/Howto/Parsing-commands-tutorial.html @@ -803,7 +803,6 @@ code.

    Versions

    diff --git a/docs/1.0-dev/Howto/Starting/Part1/Adding-Commands.html b/docs/1.0-dev/Howto/Starting/Part1/Adding-Commands.html index b974e696b5..297dbac30d 100644 --- a/docs/1.0-dev/Howto/Starting/Part1/Adding-Commands.html +++ b/docs/1.0-dev/Howto/Starting/Part1/Adding-Commands.html @@ -484,7 +484,6 @@ get into how we replace and extend Evennia’s default Commands.

    Versions

    diff --git a/docs/1.0-dev/Howto/Starting/Part1/Building-Quickstart.html b/docs/1.0-dev/Howto/Starting/Part1/Building-Quickstart.html index ad93d8e665..ee3a0a9194 100644 --- a/docs/1.0-dev/Howto/Starting/Part1/Building-Quickstart.html +++ b/docs/1.0-dev/Howto/Starting/Part1/Building-Quickstart.html @@ -407,7 +407,6 @@ example. Evennia comes with a tutorial world for you to explore. We will try tha

    Versions

    diff --git a/docs/1.0-dev/Howto/Starting/Part1/Creating-Things.html b/docs/1.0-dev/Howto/Starting/Part1/Creating-Things.html index 7e40bb7ab8..0dbb723325 100644 --- a/docs/1.0-dev/Howto/Starting/Part1/Creating-Things.html +++ b/docs/1.0-dev/Howto/Starting/Part1/Creating-Things.html @@ -155,7 +155,6 @@ You can find the parent class for Accounts in 1.0-dev (develop branch) -
  • 0.9.5 (v0.9.5 branch)
  • diff --git a/docs/1.0-dev/Howto/Starting/Part1/Django-queries.html b/docs/1.0-dev/Howto/Starting/Part1/Django-queries.html index fd492bfb8e..da84221d37 100644 --- a/docs/1.0-dev/Howto/Starting/Part1/Django-queries.html +++ b/docs/1.0-dev/Howto/Starting/Part1/Django-queries.html @@ -487,7 +487,6 @@ to understand how to plan what our tutorial game will be about.

    Versions

    diff --git a/docs/1.0-dev/Howto/Starting/Part1/Evennia-Library-Overview.html b/docs/1.0-dev/Howto/Starting/Part1/Evennia-Library-Overview.html index 8a85998da7..72b60aeba2 100644 --- a/docs/1.0-dev/Howto/Starting/Part1/Evennia-Library-Overview.html +++ b/docs/1.0-dev/Howto/Starting/Part1/Evennia-Library-Overview.html @@ -237,7 +237,6 @@ to look it up in the docs:

    Versions

    diff --git a/docs/1.0-dev/Howto/Starting/Part1/Gamedir-Overview.html b/docs/1.0-dev/Howto/Starting/Part1/Gamedir-Overview.html index 96beb92376..ff55481ea8 100644 --- a/docs/1.0-dev/Howto/Starting/Part1/Gamedir-Overview.html +++ b/docs/1.0-dev/Howto/Starting/Part1/Gamedir-Overview.html @@ -335,7 +335,6 @@ equipment, stats and looks.

    Versions

    diff --git a/docs/1.0-dev/Howto/Starting/Part1/Learning-Typeclasses.html b/docs/1.0-dev/Howto/Starting/Part1/Learning-Typeclasses.html index 4138dafc04..850163a308 100644 --- a/docs/1.0-dev/Howto/Starting/Part1/Learning-Typeclasses.html +++ b/docs/1.0-dev/Howto/Starting/Part1/Learning-Typeclasses.html @@ -731,7 +731,6 @@ this tutorial. But that’s enough of them for now. It’s time to take some act

    Versions

    diff --git a/docs/1.0-dev/Howto/Starting/Part1/More-on-Commands.html b/docs/1.0-dev/Howto/Starting/Part1/More-on-Commands.html index a1737d95f1..647fd9cd9d 100644 --- a/docs/1.0-dev/Howto/Starting/Part1/More-on-Commands.html +++ b/docs/1.0-dev/Howto/Starting/Part1/More-on-Commands.html @@ -607,7 +607,6 @@ command on ourselves.

    Versions

    diff --git a/docs/1.0-dev/Howto/Starting/Part1/Python-basic-introduction.html b/docs/1.0-dev/Howto/Starting/Part1/Python-basic-introduction.html index 08db2998b0..3cba791f9f 100644 --- a/docs/1.0-dev/Howto/Starting/Part1/Python-basic-introduction.html +++ b/docs/1.0-dev/Howto/Starting/Part1/Python-basic-introduction.html @@ -737,7 +737,6 @@ Now let’s look at the rest of the stuff you’ve got going on inside that Versions diff --git a/docs/1.0-dev/Howto/Starting/Part1/Python-classes-and-objects.html b/docs/1.0-dev/Howto/Starting/Part1/Python-classes-and-objects.html index b44b83ae62..42e11b2a5d 100644 --- a/docs/1.0-dev/Howto/Starting/Part1/Python-classes-and-objects.html +++ b/docs/1.0-dev/Howto/Starting/Part1/Python-classes-and-objects.html @@ -503,7 +503,6 @@ provides. But first we need to learn just where to find everything.

    Versions

    diff --git a/docs/1.0-dev/Howto/Starting/Part1/Searching-Things.html b/docs/1.0-dev/Howto/Starting/Part1/Searching-Things.html index c668820504..5bd2c2ea88 100644 --- a/docs/1.0-dev/Howto/Starting/Part1/Searching-Things.html +++ b/docs/1.0-dev/Howto/Starting/Part1/Searching-Things.html @@ -377,7 +377,6 @@ Django queries and querysets in earnest.

    Versions

    diff --git a/docs/1.0-dev/Howto/Starting/Part1/Starting-Part1.html b/docs/1.0-dev/Howto/Starting/Part1/Starting-Part1.html index 7a6fa0a46c..e17bb8ea8f 100644 --- a/docs/1.0-dev/Howto/Starting/Part1/Starting-Part1.html +++ b/docs/1.0-dev/Howto/Starting/Part1/Starting-Part1.html @@ -236,7 +236,6 @@ the log again just run

    Versions

    diff --git a/docs/1.0-dev/Howto/Starting/Part1/Tutorial-World-Introduction.html b/docs/1.0-dev/Howto/Starting/Part1/Tutorial-World-Introduction.html index 5e201500a3..0e3d79c1a2 100644 --- a/docs/1.0-dev/Howto/Starting/Part1/Tutorial-World-Introduction.html +++ b/docs/1.0-dev/Howto/Starting/Part1/Tutorial-World-Introduction.html @@ -223,7 +223,6 @@ move on with how to access this power through code.

    Versions

    diff --git a/docs/1.0-dev/Howto/Starting/Part2/Game-Planning.html b/docs/1.0-dev/Howto/Starting/Part2/Game-Planning.html index b10cad2e44..e6068479f0 100644 --- a/docs/1.0-dev/Howto/Starting/Part2/Game-Planning.html +++ b/docs/1.0-dev/Howto/Starting/Part2/Game-Planning.html @@ -324,7 +324,6 @@ have made their dream game a reality!

    Versions

    diff --git a/docs/1.0-dev/Howto/Starting/Part2/Planning-Some-Useful-Contribs.html b/docs/1.0-dev/Howto/Starting/Part2/Planning-Some-Useful-Contribs.html index 15fef699d0..d63ed2d65d 100644 --- a/docs/1.0-dev/Howto/Starting/Part2/Planning-Some-Useful-Contribs.html +++ b/docs/1.0-dev/Howto/Starting/Part2/Planning-Some-Useful-Contribs.html @@ -333,7 +333,6 @@ back to your planning and adjust it as you learn what works and what does not.Versions diff --git a/docs/1.0-dev/Howto/Starting/Part2/Planning-The-Tutorial-Game.html b/docs/1.0-dev/Howto/Starting/Part2/Planning-The-Tutorial-Game.html index e2a097a8f3..938031104d 100644 --- a/docs/1.0-dev/Howto/Starting/Part2/Planning-The-Tutorial-Game.html +++ b/docs/1.0-dev/Howto/Starting/Part2/Planning-The-Tutorial-Game.html @@ -558,7 +558,6 @@ to code themselves. So in the next lesson we will check out what help we have fr

    Versions

    diff --git a/docs/1.0-dev/Howto/Starting/Part2/Planning-Where-Do-I-Begin.html b/docs/1.0-dev/Howto/Starting/Part2/Planning-Where-Do-I-Begin.html index 6b6760cab2..ad7298ff4d 100644 --- a/docs/1.0-dev/Howto/Starting/Part2/Planning-Where-Do-I-Begin.html +++ b/docs/1.0-dev/Howto/Starting/Part2/Planning-Where-Do-I-Begin.html @@ -248,7 +248,6 @@ then try to answer those questions for the sake of creating our little tutorial

    Versions

    diff --git a/docs/1.0-dev/Howto/Starting/Part2/Starting-Part2.html b/docs/1.0-dev/Howto/Starting/Part2/Starting-Part2.html index 131a6c5bce..fdbd40a6e1 100644 --- a/docs/1.0-dev/Howto/Starting/Part2/Starting-Part2.html +++ b/docs/1.0-dev/Howto/Starting/Part2/Starting-Part2.html @@ -138,7 +138,6 @@ and “what to think about” when creating a multiplayer online text game.

    Versions

    diff --git a/docs/1.0-dev/Howto/Starting/Part3/A-Sittable-Object.html b/docs/1.0-dev/Howto/Starting/Part3/A-Sittable-Object.html index 12f17882ba..15745d8f5a 100644 --- a/docs/1.0-dev/Howto/Starting/Part3/A-Sittable-Object.html +++ b/docs/1.0-dev/Howto/Starting/Part3/A-Sittable-Object.html @@ -844,7 +844,6 @@ mixing them, or even try a third solution that better fits what you have in mind

    Versions

    diff --git a/docs/1.0-dev/Howto/Starting/Part3/Implementing-a-game-rule-system.html b/docs/1.0-dev/Howto/Starting/Part3/Implementing-a-game-rule-system.html index 4fd6ad2f35..950d31cb70 100644 --- a/docs/1.0-dev/Howto/Starting/Part3/Implementing-a-game-rule-system.html +++ b/docs/1.0-dev/Howto/Starting/Part3/Implementing-a-game-rule-system.html @@ -355,7 +355,6 @@ your rulesVersions diff --git a/docs/1.0-dev/Howto/Starting/Part3/Starting-Part3.html b/docs/1.0-dev/Howto/Starting/Part3/Starting-Part3.html index c334115e5b..f5f630f973 100644 --- a/docs/1.0-dev/Howto/Starting/Part3/Starting-Part3.html +++ b/docs/1.0-dev/Howto/Starting/Part3/Starting-Part3.html @@ -138,7 +138,6 @@ with using Evennia. This be of much use when doing your own thing later.

    Versions

    diff --git a/docs/1.0-dev/Howto/Starting/Part3/Turn-based-Combat-System.html b/docs/1.0-dev/Howto/Starting/Part3/Turn-based-Combat-System.html index bfaf974557..9561c9b51f 100644 --- a/docs/1.0-dev/Howto/Starting/Part3/Turn-based-Combat-System.html +++ b/docs/1.0-dev/Howto/Starting/Part3/Turn-based-Combat-System.html @@ -598,7 +598,6 @@ show others what’s going on.

    Versions

    diff --git a/docs/1.0-dev/Howto/Starting/Part3/Tutorial-for-basic-MUSH-like-game.html b/docs/1.0-dev/Howto/Starting/Part3/Tutorial-for-basic-MUSH-like-game.html index 25aa673fca..5a7d67fa14 100644 --- a/docs/1.0-dev/Howto/Starting/Part3/Tutorial-for-basic-MUSH-like-game.html +++ b/docs/1.0-dev/Howto/Starting/Part3/Tutorial-for-basic-MUSH-like-game.html @@ -725,7 +725,6 @@ as the 1.0-dev (develop branch) -
  • 0.9.5 (v0.9.5 branch)
  • diff --git a/docs/1.0-dev/Howto/Starting/Part4/Starting-Part4.html b/docs/1.0-dev/Howto/Starting/Part4/Starting-Part4.html index 60c36fce4e..dfad1f7b83 100644 --- a/docs/1.0-dev/Howto/Starting/Part4/Starting-Part4.html +++ b/docs/1.0-dev/Howto/Starting/Part4/Starting-Part4.html @@ -105,7 +105,6 @@ and batchcode processors.

    Versions

    diff --git a/docs/1.0-dev/Howto/Starting/Part5/Add-a-simple-new-web-page.html b/docs/1.0-dev/Howto/Starting/Part5/Add-a-simple-new-web-page.html index 04f45e5dd3..15acc26f00 100644 --- a/docs/1.0-dev/Howto/Starting/Part5/Add-a-simple-new-web-page.html +++ b/docs/1.0-dev/Howto/Starting/Part5/Add-a-simple-new-web-page.html @@ -178,7 +178,6 @@ to.

    Versions

    diff --git a/docs/1.0-dev/Howto/Starting/Part5/Starting-Part5.html b/docs/1.0-dev/Howto/Starting/Part5/Starting-Part5.html index 2a12053162..7f762220c6 100644 --- a/docs/1.0-dev/Howto/Starting/Part5/Starting-Part5.html +++ b/docs/1.0-dev/Howto/Starting/Part5/Starting-Part5.html @@ -103,7 +103,6 @@ to bring your game online so you can invite your first players.

    Versions

    diff --git a/docs/1.0-dev/Howto/Starting/Part5/Web-Tutorial.html b/docs/1.0-dev/Howto/Starting/Part5/Web-Tutorial.html index 8423831df0..179479c663 100644 --- a/docs/1.0-dev/Howto/Starting/Part5/Web-Tutorial.html +++ b/docs/1.0-dev/Howto/Starting/Part5/Web-Tutorial.html @@ -200,7 +200,6 @@ works and what possibilities exist.

    Versions

    diff --git a/docs/1.0-dev/Howto/Static-In-Game-Map.html b/docs/1.0-dev/Howto/Static-In-Game-Map.html index c3b2262e4b..21a521fe69 100644 --- a/docs/1.0-dev/Howto/Static-In-Game-Map.html +++ b/docs/1.0-dev/Howto/Static-In-Game-Map.html @@ -483,7 +483,6 @@ Tutorial), Versions diff --git a/docs/1.0-dev/Howto/Tutorial-Aggressive-NPCs.html b/docs/1.0-dev/Howto/Tutorial-Aggressive-NPCs.html index 6fba951ca0..fd041932c6 100644 --- a/docs/1.0-dev/Howto/Tutorial-Aggressive-NPCs.html +++ b/docs/1.0-dev/Howto/Tutorial-Aggressive-NPCs.html @@ -192,7 +192,6 @@ AI code).

    Versions

    diff --git a/docs/1.0-dev/Howto/Tutorial-NPCs-listening.html b/docs/1.0-dev/Howto/Tutorial-NPCs-listening.html index f61a7abdc5..954d96dfaf 100644 --- a/docs/1.0-dev/Howto/Tutorial-NPCs-listening.html +++ b/docs/1.0-dev/Howto/Tutorial-NPCs-listening.html @@ -190,7 +190,6 @@ Which way to go depends on the design requirements of your particular game.

    Versions

    diff --git a/docs/1.0-dev/Howto/Tutorial-Tweeting-Game-Stats.html b/docs/1.0-dev/Howto/Tutorial-Tweeting-Game-Stats.html index f0258d8900..545e5d509a 100644 --- a/docs/1.0-dev/Howto/Tutorial-Tweeting-Game-Stats.html +++ b/docs/1.0-dev/Howto/Tutorial-Tweeting-Game-Stats.html @@ -174,7 +174,6 @@ as mygame/typeclass

    Versions

    diff --git a/docs/1.0-dev/Howto/Tutorial-Vehicles.html b/docs/1.0-dev/Howto/Tutorial-Vehicles.html index 6bc2501a60..ffa1629aaf 100644 --- a/docs/1.0-dev/Howto/Tutorial-Vehicles.html +++ b/docs/1.0-dev/Howto/Tutorial-Vehicles.html @@ -476,7 +476,6 @@ direction to which room it goes.

    Versions

    diff --git a/docs/1.0-dev/Howto/Understanding-Color-Tags.html b/docs/1.0-dev/Howto/Understanding-Color-Tags.html index 383abca184..1a2e522098 100644 --- a/docs/1.0-dev/Howto/Understanding-Color-Tags.html +++ b/docs/1.0-dev/Howto/Understanding-Color-Tags.html @@ -251,7 +251,6 @@ push it over the limit, so to speak.

    Versions

    diff --git a/docs/1.0-dev/Howto/Weather-Tutorial.html b/docs/1.0-dev/Howto/Weather-Tutorial.html index 31ea7990d1..e5090fb7e8 100644 --- a/docs/1.0-dev/Howto/Weather-Tutorial.html +++ b/docs/1.0-dev/Howto/Weather-Tutorial.html @@ -128,7 +128,6 @@ weather came before it. Expanding it to be more realistic is a useful exercise.<

    Versions

    diff --git a/docs/1.0-dev/Howto/Web-Character-Generation.html b/docs/1.0-dev/Howto/Web-Character-Generation.html index 2f79c2a0e2..5e394229eb 100644 --- a/docs/1.0-dev/Howto/Web-Character-Generation.html +++ b/docs/1.0-dev/Howto/Web-Character-Generation.html @@ -448,7 +448,7 @@ this demonstration, we will only list the applications that the account has subm easily adjust this to include saved applications, or other types of applications if you have different kinds.

    Please refer back to views.py to see where we define the variables these templates make use of.

    -
    <!-- file mygame/web/chargen/templates/chargen/index.html-->
    +
    <!-- file mygame/web/chargen/templates/chargen/index.html-->
     
     {% extends "base.html" %}
     {% block content %}
    @@ -476,7 +476,7 @@ different kinds.

    name and character background. You will likely want to extend this to show many more fields for your game. In a full-fledged character generation, you may want to extend the boolean attribute of submitted to allow accounts to save character applications and submit them later.

    -
    <!-- file mygame/web/chargen/templates/chargen/detail.html-->
    +
    <!-- file mygame/web/chargen/templates/chargen/detail.html-->
     
     {% extends "base.html" %}
     {% block content %}
    @@ -504,7 +504,7 @@ majority of the application process. There will be a form input for every field
     forms.py, which is handy. We have used POST as our method because we are sending information to the
     server that will update the database. As an alternative, GET would be much less secure. You can read
     up on documentation elsewhere on the web for GET vs. POST.

    -
    <!-- file mygame/web/chargen/templates/chargen/create.html-->
    +
    <!-- file mygame/web/chargen/templates/chargen/create.html-->
     
     {% extends "base.html" %}
     {% block content %}
    @@ -733,7 +733,6 @@ to see what happens.  And do the same while checking the checkbox!

    Versions

    diff --git a/docs/1.0-dev/Howto/Web-Character-View-Tutorial.html b/docs/1.0-dev/Howto/Web-Character-View-Tutorial.html index 16d383cea3..e5796826be 100644 --- a/docs/1.0-dev/Howto/Web-Character-View-Tutorial.html +++ b/docs/1.0-dev/Howto/Web-Character-View-Tutorial.html @@ -286,7 +286,6 @@ here.

    Versions

    diff --git a/docs/1.0-dev/Licensing.html b/docs/1.0-dev/Licensing.html index 0321e51ea2..220959ba33 100644 --- a/docs/1.0-dev/Licensing.html +++ b/docs/1.0-dev/Licensing.html @@ -104,7 +104,6 @@ as Evennia itself, unless the individual contributor has specifically defined ot

    Versions

    diff --git a/docs/1.0-dev/Links.html b/docs/1.0-dev/Links.html index edb9f0ce43..ee701393c3 100644 --- a/docs/1.0-dev/Links.html +++ b/docs/1.0-dev/Links.html @@ -310,7 +310,6 @@ free online programming curriculum for different skill levels

    Versions

    diff --git a/docs/1.0-dev/Setup/Apache-Config.html b/docs/1.0-dev/Setup/Apache-Config.html index b7bff228f4..286cf0847f 100644 --- a/docs/1.0-dev/Setup/Apache-Config.html +++ b/docs/1.0-dev/Setup/Apache-Config.html @@ -283,7 +283,6 @@ port but this should be applicable also to other types of proxies (like nginx).<

    Versions

    diff --git a/docs/1.0-dev/Setup/Choosing-An-SQL-Server.html b/docs/1.0-dev/Setup/Choosing-An-SQL-Server.html index 2233b40121..1197518a0b 100644 --- a/docs/1.0-dev/Setup/Choosing-An-SQL-Server.html +++ b/docs/1.0-dev/Setup/Choosing-An-SQL-Server.html @@ -123,16 +123,16 @@ have to since the resulting command, and your password, will be logged in the sh

    This will open a console to the postgres service using the psql client.

    On the psql command line:

    -
    CREATE USER evennia WITH PASSWORD 'somepassword';
    -CREATE DATABASE evennia;
    +
    CREATE USER evennia WITH PASSWORD 'somepassword';
    +CREATE DATABASE evennia;
     
     -- Postgres-specific optimizations
     -- https://docs.djangoproject.com/en/dev/ref/databases/#optimizing-postgresql-s-configuration
    -ALTER ROLE evennia SET client_encoding TO 'utf8';
    -ALTER ROLE evennia SET default_transaction_isolation TO 'read committed';
    -ALTER ROLE evennia SET timezone TO 'UTC';
    +ALTER ROLE evennia SET client_encoding TO 'utf8';
    +ALTER ROLE evennia SET default_transaction_isolation TO 'read committed';
    +ALTER ROLE evennia SET timezone TO 'UTC';
     
    -GRANT ALL PRIVILEGES ON DATABASE evennia TO evennia;
    +GRANT ALL PRIVILEGES ON DATABASE evennia TO evennia;
     -- Other useful commands:
     --  \l       (list all databases and permissions)
     --  \q       (exit)
    @@ -275,12 +275,12 @@ recommends the  mys
     

    You should get to enter your database root password (set this up when you installed the database server).

    Inside the database client interface:

    -
    CREATE USER 'evennia'@'localhost' IDENTIFIED BY 'somepassword';
    -CREATE DATABASE evennia;
    -ALTER DATABASE `evennia` CHARACTER SET utf8; -- note that it's `evennia` with back-ticks, not
    -quotes!
    -GRANT ALL PRIVILEGES ON evennia.* TO 'evennia'@'localhost';
    -FLUSH PRIVILEGES;
    +
    CREATE USER 'evennia'@'localhost' IDENTIFIED BY 'somepassword';
    +CREATE DATABASE evennia;
    +ALTER DATABASE `evennia` CHARACTER SET utf8; -- note that it's `evennia` with back-ticks, not
    +quotes!
    +GRANT ALL PRIVILEGES ON evennia.* TO 'evennia'@'localhost';
    +FLUSH PRIVILEGES;
     -- use 'exit' to quit client
     
    @@ -408,7 +408,6 @@ others. If you try other databases out, consider expanding this page with instru

    Versions

    diff --git a/docs/1.0-dev/Setup/Client-Support-Grid.html b/docs/1.0-dev/Setup/Client-Support-Grid.html index 729f020edd..86b21c7e3c 100644 --- a/docs/1.0-dev/Setup/Client-Support-Grid.html +++ b/docs/1.0-dev/Setup/Client-Support-Grid.html @@ -251,7 +251,6 @@ parameter to disable it for that Evennia account permanently.

    Versions

    diff --git a/docs/1.0-dev/Setup/Evennia-Game-Index.html b/docs/1.0-dev/Setup/Evennia-Game-Index.html index 3f8fa0502b..4c30d0bd09 100644 --- a/docs/1.0-dev/Setup/Evennia-Game-Index.html +++ b/docs/1.0-dev/Setup/Evennia-Game-Index.html @@ -161,7 +161,6 @@ if you are not ready for players yet.

    Versions

    diff --git a/docs/1.0-dev/Setup/Extended-Installation.html b/docs/1.0-dev/Setup/Extended-Installation.html index c888c710c6..779d24ef8e 100644 --- a/docs/1.0-dev/Setup/Extended-Installation.html +++ b/docs/1.0-dev/Setup/Extended-Installation.html @@ -605,7 +605,6 @@ virus software interfering. Try disabling or changing your anti-virus software s

    Versions

    diff --git a/docs/1.0-dev/Setup/Grapevine.html b/docs/1.0-dev/Setup/Grapevine.html index b27f91ef19..2973821b03 100644 --- a/docs/1.0-dev/Setup/Grapevine.html +++ b/docs/1.0-dev/Setup/Grapevine.html @@ -152,7 +152,6 @@ it to your channel in-game.

    Versions

    diff --git a/docs/1.0-dev/Setup/HAProxy-Config.html b/docs/1.0-dev/Setup/HAProxy-Config.html index 8c4b17170f..1c2846375b 100644 --- a/docs/1.0-dev/Setup/HAProxy-Config.html +++ b/docs/1.0-dev/Setup/HAProxy-Config.html @@ -318,7 +318,6 @@ uncommented in the config file, it will now start as a background process.

    Versions

    diff --git a/docs/1.0-dev/Setup/How-to-connect-Evennia-to-Twitter.html b/docs/1.0-dev/Setup/How-to-connect-Evennia-to-Twitter.html index 0bd97e0d31..fdfcf11fcc 100644 --- a/docs/1.0-dev/Setup/How-to-connect-Evennia-to-Twitter.html +++ b/docs/1.0-dev/Setup/How-to-connect-Evennia-to-Twitter.html @@ -192,7 +192,6 @@ help.

    Versions

    diff --git a/docs/1.0-dev/Setup/IRC.html b/docs/1.0-dev/Setup/IRC.html index 91303ec3f6..d2945d139f 100644 --- a/docs/1.0-dev/Setup/IRC.html +++ b/docs/1.0-dev/Setup/IRC.html @@ -171,7 +171,6 @@ name of the IRC channel you used (#evennia here).

    Versions

    diff --git a/docs/1.0-dev/Setup/Installing-on-Android.html b/docs/1.0-dev/Setup/Installing-on-Android.html index 8b97418f30..f429f5a655 100644 --- a/docs/1.0-dev/Setup/Installing-on-Android.html +++ b/docs/1.0-dev/Setup/Installing-on-Android.html @@ -222,7 +222,6 @@ killed if your phone is heavily taxed. Termux seems to keep a notification up to

    Versions

    diff --git a/docs/1.0-dev/Setup/Online-Setup.html b/docs/1.0-dev/Setup/Online-Setup.html index db966e83e8..a9839a4e39 100644 --- a/docs/1.0-dev/Setup/Online-Setup.html +++ b/docs/1.0-dev/Setup/Online-Setup.html @@ -574,7 +574,6 @@ sufficient resources to operate a Cloud9 development environment without charge.

    Versions

    diff --git a/docs/1.0-dev/Setup/RSS.html b/docs/1.0-dev/Setup/RSS.html index 5b042f9062..feef0d3a24 100644 --- a/docs/1.0-dev/Setup/RSS.html +++ b/docs/1.0-dev/Setup/RSS.html @@ -138,7 +138,6 @@ same channels as 1.0-dev (develop branch) -
  • 0.9.5 (v0.9.5 branch)
  • diff --git a/docs/1.0-dev/Setup/Running-Evennia-in-Docker.html b/docs/1.0-dev/Setup/Running-Evennia-in-Docker.html index d8c7bb632d..2a326a00dc 100644 --- a/docs/1.0-dev/Setup/Running-Evennia-in-Docker.html +++ b/docs/1.0-dev/Setup/Running-Evennia-in-Docker.html @@ -375,7 +375,6 @@ line.

    Versions

    diff --git a/docs/1.0-dev/Setup/Security.html b/docs/1.0-dev/Setup/Security.html index 6777122808..3e959700b2 100644 --- a/docs/1.0-dev/Setup/Security.html +++ b/docs/1.0-dev/Setup/Security.html @@ -250,7 +250,6 @@ ISP snooping.

    Versions

    diff --git a/docs/1.0-dev/Setup/Server-Conf.html b/docs/1.0-dev/Setup/Server-Conf.html index d7f6d44c5a..6af355b86d 100644 --- a/docs/1.0-dev/Setup/Server-Conf.html +++ b/docs/1.0-dev/Setup/Server-Conf.html @@ -191,7 +191,6 @@ know about if you are an Evennia developer.

    Versions

    diff --git a/docs/1.0-dev/Setup/Settings-File.html b/docs/1.0-dev/Setup/Settings-File.html index 192482a76a..e118f92efd 100644 --- a/docs/1.0-dev/Setup/Settings-File.html +++ b/docs/1.0-dev/Setup/Settings-File.html @@ -85,7 +85,6 @@

    Versions

    diff --git a/docs/1.0-dev/Setup/Setup-Overview.html b/docs/1.0-dev/Setup/Setup-Overview.html index f5f268b4f2..bfa12805dd 100644 --- a/docs/1.0-dev/Setup/Setup-Overview.html +++ b/docs/1.0-dev/Setup/Setup-Overview.html @@ -151,7 +151,6 @@

    Versions

    diff --git a/docs/1.0-dev/Setup/Setup-Quickstart.html b/docs/1.0-dev/Setup/Setup-Quickstart.html index b36b8b7876..b8d76e6923 100644 --- a/docs/1.0-dev/Setup/Setup-Quickstart.html +++ b/docs/1.0-dev/Setup/Setup-Quickstart.html @@ -198,7 +198,6 @@ a web browser at http

    Versions

    diff --git a/docs/1.0-dev/Setup/Start-Stop-Reload.html b/docs/1.0-dev/Setup/Start-Stop-Reload.html index a154498d9f..2caa201870 100644 --- a/docs/1.0-dev/Setup/Start-Stop-Reload.html +++ b/docs/1.0-dev/Setup/Start-Stop-Reload.html @@ -287,7 +287,6 @@ In-game you should now get the message that the Server has successfully restarte

    Versions

    diff --git a/docs/1.0-dev/Unimplemented.html b/docs/1.0-dev/Unimplemented.html index 4ef2efe9bc..152680dd2e 100644 --- a/docs/1.0-dev/Unimplemented.html +++ b/docs/1.0-dev/Unimplemented.html @@ -103,7 +103,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/django/conf.html b/docs/1.0-dev/_modules/django/conf.html index dfa1c0c871..bfdc529e61 100644 --- a/docs/1.0-dev/_modules/django/conf.html +++ b/docs/1.0-dev/_modules/django/conf.html @@ -348,7 +348,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/django/db/models/fields/related_descriptors.html b/docs/1.0-dev/_modules/django/db/models/fields/related_descriptors.html index 7b7ca4844b..381f373774 100644 --- a/docs/1.0-dev/_modules/django/db/models/fields/related_descriptors.html +++ b/docs/1.0-dev/_modules/django/db/models/fields/related_descriptors.html @@ -1280,7 +1280,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/django/db/models/manager.html b/docs/1.0-dev/_modules/django/db/models/manager.html index b92d564a8c..98b81c786d 100644 --- a/docs/1.0-dev/_modules/django/db/models/manager.html +++ b/docs/1.0-dev/_modules/django/db/models/manager.html @@ -278,7 +278,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/django/db/models/query.html b/docs/1.0-dev/_modules/django/db/models/query.html index 0e5dd162ff..e172293d6d 100644 --- a/docs/1.0-dev/_modules/django/db/models/query.html +++ b/docs/1.0-dev/_modules/django/db/models/query.html @@ -2089,7 +2089,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/django/db/models/query_utils.html b/docs/1.0-dev/_modules/django/db/models/query_utils.html index f4bd046a85..cd8d61964a 100644 --- a/docs/1.0-dev/_modules/django/db/models/query_utils.html +++ b/docs/1.0-dev/_modules/django/db/models/query_utils.html @@ -421,7 +421,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/django/utils/deconstruct.html b/docs/1.0-dev/_modules/django/utils/deconstruct.html new file mode 100644 index 0000000000..67f723fdf4 --- /dev/null +++ b/docs/1.0-dev/_modules/django/utils/deconstruct.html @@ -0,0 +1,159 @@ + + + + + + + + django.utils.deconstruct — Evennia 1.0-dev documentation + + + + + + + + + + + + + + + +
    +
    +
    +
    + +

    Source code for django.utils.deconstruct

    +from importlib import import_module
    +
    +from django.utils.version import get_docs_version
    +
    +
    +def deconstructible(*args, path=None):
    +    """
    +    Class decorator that allows the decorated class to be serialized
    +    by the migrations subsystem.
    +
    +    The `path` kwarg specifies the import path.
    +    """
    +    def decorator(klass):
    +        def __new__(cls, *args, **kwargs):
    +            # We capture the arguments to make returning them trivial
    +            obj = super(klass, cls).__new__(cls)
    +            obj._constructor_args = (args, kwargs)
    +            return obj
    +
    +        def deconstruct(obj):
    +            """
    +            Return a 3-tuple of class import path, positional arguments,
    +            and keyword arguments.
    +            """
    +            # Fallback version
    +            if path:
    +                module_name, _, name = path.rpartition('.')
    +            else:
    +                module_name = obj.__module__
    +                name = obj.__class__.__name__
    +            # Make sure it's actually there and not an inner class
    +            module = import_module(module_name)
    +            if not hasattr(module, name):
    +                raise ValueError(
    +                    "Could not find object %s in %s.\n"
    +                    "Please note that you cannot serialize things like inner "
    +                    "classes. Please move the object into the main module "
    +                    "body to use migrations.\n"
    +                    "For more information, see "
    +                    "https://docs.djangoproject.com/en/%s/topics/migrations/#serializing-values"
    +                    % (name, module_name, get_docs_version()))
    +            return (
    +                path or '%s.%s' % (obj.__class__.__module__, name),
    +                obj._constructor_args[0],
    +                obj._constructor_args[1],
    +            )
    +
    +        klass.__new__ = staticmethod(__new__)
    +        klass.deconstruct = deconstruct
    +
    +        return klass
    +
    +    if not args:
    +        return decorator
    +    return decorator(*args)
    +
    + +
    +
    +
    +
    + +
    +
    + + + + \ No newline at end of file diff --git a/docs/1.0-dev/_modules/django/utils/functional.html b/docs/1.0-dev/_modules/django/utils/functional.html index bc0060d9ed..0ed8b45c92 100644 --- a/docs/1.0-dev/_modules/django/utils/functional.html +++ b/docs/1.0-dev/_modules/django/utils/functional.html @@ -498,7 +498,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia.html b/docs/1.0-dev/_modules/evennia.html index 9dbf05aefd..014901ddc0 100644 --- a/docs/1.0-dev/_modules/evennia.html +++ b/docs/1.0-dev/_modules/evennia.html @@ -507,7 +507,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/accounts/accounts.html b/docs/1.0-dev/_modules/evennia/accounts/accounts.html index df7d012edc..96ad486e3f 100644 --- a/docs/1.0-dev/_modules/evennia/accounts/accounts.html +++ b/docs/1.0-dev/_modules/evennia/accounts/accounts.html @@ -1883,7 +1883,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/accounts/bots.html b/docs/1.0-dev/_modules/evennia/accounts/bots.html index 7e7436c5cd..fe4acafabe 100644 --- a/docs/1.0-dev/_modules/evennia/accounts/bots.html +++ b/docs/1.0-dev/_modules/evennia/accounts/bots.html @@ -656,7 +656,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/accounts/manager.html b/docs/1.0-dev/_modules/evennia/accounts/manager.html index 341ebabc93..0eb443e1c2 100644 --- a/docs/1.0-dev/_modules/evennia/accounts/manager.html +++ b/docs/1.0-dev/_modules/evennia/accounts/manager.html @@ -373,7 +373,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/accounts/models.html b/docs/1.0-dev/_modules/evennia/accounts/models.html index 2a65c21ef1..f833f484a8 100644 --- a/docs/1.0-dev/_modules/evennia/accounts/models.html +++ b/docs/1.0-dev/_modules/evennia/accounts/models.html @@ -258,7 +258,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/commands/cmdhandler.html b/docs/1.0-dev/_modules/evennia/commands/cmdhandler.html index b330efcd00..5aa2906ab5 100644 --- a/docs/1.0-dev/_modules/evennia/commands/cmdhandler.html +++ b/docs/1.0-dev/_modules/evennia/commands/cmdhandler.html @@ -856,7 +856,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/commands/cmdparser.html b/docs/1.0-dev/_modules/evennia/commands/cmdparser.html index 52d77fd4d7..f4d8d263c8 100644 --- a/docs/1.0-dev/_modules/evennia/commands/cmdparser.html +++ b/docs/1.0-dev/_modules/evennia/commands/cmdparser.html @@ -302,7 +302,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/commands/cmdset.html b/docs/1.0-dev/_modules/evennia/commands/cmdset.html index 13877046b5..72608b5f8b 100644 --- a/docs/1.0-dev/_modules/evennia/commands/cmdset.html +++ b/docs/1.0-dev/_modules/evennia/commands/cmdset.html @@ -752,7 +752,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/commands/cmdsethandler.html b/docs/1.0-dev/_modules/evennia/commands/cmdsethandler.html index 779cf0bad8..2f39e2cc91 100644 --- a/docs/1.0-dev/_modules/evennia/commands/cmdsethandler.html +++ b/docs/1.0-dev/_modules/evennia/commands/cmdsethandler.html @@ -742,7 +742,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/commands/command.html b/docs/1.0-dev/_modules/evennia/commands/command.html index 1ef964a160..b7b445d4a5 100644 --- a/docs/1.0-dev/_modules/evennia/commands/command.html +++ b/docs/1.0-dev/_modules/evennia/commands/command.html @@ -820,7 +820,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/commands/default/account.html b/docs/1.0-dev/_modules/evennia/commands/default/account.html index ab13e7bb7d..6e8504c192 100644 --- a/docs/1.0-dev/_modules/evennia/commands/default/account.html +++ b/docs/1.0-dev/_modules/evennia/commands/default/account.html @@ -1131,7 +1131,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/commands/default/admin.html b/docs/1.0-dev/_modules/evennia/commands/default/admin.html index 5cf22cbcba..e321a1c306 100644 --- a/docs/1.0-dev/_modules/evennia/commands/default/admin.html +++ b/docs/1.0-dev/_modules/evennia/commands/default/admin.html @@ -681,7 +681,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/commands/default/batchprocess.html b/docs/1.0-dev/_modules/evennia/commands/default/batchprocess.html index 1ea0d1e201..10c0e4e59c 100644 --- a/docs/1.0-dev/_modules/evennia/commands/default/batchprocess.html +++ b/docs/1.0-dev/_modules/evennia/commands/default/batchprocess.html @@ -897,7 +897,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/commands/default/building.html b/docs/1.0-dev/_modules/evennia/commands/default/building.html index 0bfac269db..862a5a55e8 100644 --- a/docs/1.0-dev/_modules/evennia/commands/default/building.html +++ b/docs/1.0-dev/_modules/evennia/commands/default/building.html @@ -4377,7 +4377,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/commands/default/cmdset_account.html b/docs/1.0-dev/_modules/evennia/commands/default/cmdset_account.html index 128291e30f..78ce5d350b 100644 --- a/docs/1.0-dev/_modules/evennia/commands/default/cmdset_account.html +++ b/docs/1.0-dev/_modules/evennia/commands/default/cmdset_account.html @@ -153,7 +153,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/commands/default/cmdset_character.html b/docs/1.0-dev/_modules/evennia/commands/default/cmdset_character.html index 217ca704f9..a25f2acb0c 100644 --- a/docs/1.0-dev/_modules/evennia/commands/default/cmdset_character.html +++ b/docs/1.0-dev/_modules/evennia/commands/default/cmdset_character.html @@ -168,7 +168,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/commands/default/cmdset_session.html b/docs/1.0-dev/_modules/evennia/commands/default/cmdset_session.html index b7190c7d01..0d8557f151 100644 --- a/docs/1.0-dev/_modules/evennia/commands/default/cmdset_session.html +++ b/docs/1.0-dev/_modules/evennia/commands/default/cmdset_session.html @@ -94,7 +94,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/commands/default/cmdset_unloggedin.html b/docs/1.0-dev/_modules/evennia/commands/default/cmdset_unloggedin.html index 4e6e3241a1..79d5bbcde7 100644 --- a/docs/1.0-dev/_modules/evennia/commands/default/cmdset_unloggedin.html +++ b/docs/1.0-dev/_modules/evennia/commands/default/cmdset_unloggedin.html @@ -103,7 +103,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/commands/default/comms.html b/docs/1.0-dev/_modules/evennia/commands/default/comms.html index a82691da0d..959d7222ab 100644 --- a/docs/1.0-dev/_modules/evennia/commands/default/comms.html +++ b/docs/1.0-dev/_modules/evennia/commands/default/comms.html @@ -1940,7 +1940,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/commands/default/general.html b/docs/1.0-dev/_modules/evennia/commands/default/general.html index f1551e1ef3..75ed098245 100644 --- a/docs/1.0-dev/_modules/evennia/commands/default/general.html +++ b/docs/1.0-dev/_modules/evennia/commands/default/general.html @@ -815,7 +815,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/commands/default/help.html b/docs/1.0-dev/_modules/evennia/commands/default/help.html index 5e02b2ca81..7e4b9f6890 100644 --- a/docs/1.0-dev/_modules/evennia/commands/default/help.html +++ b/docs/1.0-dev/_modules/evennia/commands/default/help.html @@ -1057,7 +1057,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/commands/default/muxcommand.html b/docs/1.0-dev/_modules/evennia/commands/default/muxcommand.html index e07ac7e125..489aa61e88 100644 --- a/docs/1.0-dev/_modules/evennia/commands/default/muxcommand.html +++ b/docs/1.0-dev/_modules/evennia/commands/default/muxcommand.html @@ -346,7 +346,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/commands/default/syscommands.html b/docs/1.0-dev/_modules/evennia/commands/default/syscommands.html index 12f66dad60..32a7fc2374 100644 --- a/docs/1.0-dev/_modules/evennia/commands/default/syscommands.html +++ b/docs/1.0-dev/_modules/evennia/commands/default/syscommands.html @@ -181,7 +181,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/commands/default/system.html b/docs/1.0-dev/_modules/evennia/commands/default/system.html index 6632e116d9..3f159193df 100644 --- a/docs/1.0-dev/_modules/evennia/commands/default/system.html +++ b/docs/1.0-dev/_modules/evennia/commands/default/system.html @@ -1231,7 +1231,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/commands/default/tests.html b/docs/1.0-dev/_modules/evennia/commands/default/tests.html index c88ffe57ef..9b6209af1f 100644 --- a/docs/1.0-dev/_modules/evennia/commands/default/tests.html +++ b/docs/1.0-dev/_modules/evennia/commands/default/tests.html @@ -2093,7 +2093,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/commands/default/unloggedin.html b/docs/1.0-dev/_modules/evennia/commands/default/unloggedin.html index c6f02505dd..a01d155f56 100644 --- a/docs/1.0-dev/_modules/evennia/commands/default/unloggedin.html +++ b/docs/1.0-dev/_modules/evennia/commands/default/unloggedin.html @@ -590,7 +590,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/comms/comms.html b/docs/1.0-dev/_modules/evennia/comms/comms.html index 19882d649b..35eef4a795 100644 --- a/docs/1.0-dev/_modules/evennia/comms/comms.html +++ b/docs/1.0-dev/_modules/evennia/comms/comms.html @@ -931,7 +931,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/comms/managers.html b/docs/1.0-dev/_modules/evennia/comms/managers.html index 97f455a405..489b26415d 100644 --- a/docs/1.0-dev/_modules/evennia/comms/managers.html +++ b/docs/1.0-dev/_modules/evennia/comms/managers.html @@ -580,7 +580,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/comms/models.html b/docs/1.0-dev/_modules/evennia/comms/models.html index 148da85094..cc6b463bb2 100644 --- a/docs/1.0-dev/_modules/evennia/comms/models.html +++ b/docs/1.0-dev/_modules/evennia/comms/models.html @@ -789,7 +789,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/base_systems/awsstorage/aws_s3_cdn.html b/docs/1.0-dev/_modules/evennia/contrib/base_systems/awsstorage/aws_s3_cdn.html new file mode 100644 index 0000000000..ee9c6e3d69 --- /dev/null +++ b/docs/1.0-dev/_modules/evennia/contrib/base_systems/awsstorage/aws_s3_cdn.html @@ -0,0 +1,969 @@ + + + + + + + + evennia.contrib.base_systems.awsstorage.aws_s3_cdn — Evennia 1.0-dev documentation + + + + + + + + + + + + + + + +
    +
    +
    +
    + +

    Source code for evennia.contrib.base_systems.awsstorage.aws_s3_cdn

    +"""
    +AWS Storage System
    +The Right Honourable Reverend (trhr) 2020
    +
    +ABOUT THIS PLUGIN:
    +
    +This plugin migrates the Web-based portion of Evennia, namely images,
    +javascript, and other items located inside staticfiles into Amazon AWS (S3) for hosting.
    +
    +Files hosted on S3 are "in the cloud," and while your personal
    +server may be sufficient for serving multimedia to a minimal number of users,
    +the perfect use case for this plugin would be:
    +
    +1) Servers supporting heavy web-based traffic (webclient, etc)
    +2) With a sizable number of users
    +3) Where the users are globally distributed
    +4) Where multimedia files are served to users as a part of gameplay
    +
    +Bottom line - if you're sending an image to a player every time they traverse a
    +map, the bandwidth reduction will be substantial. If not, probably skip
    +this one.
    +
    +Note that storing and serving files via S3 is not technically free outside of
    +Amazon's "free tier" offering, which you may or may not be eligible for;
    +evennia's base install currently requires 1.5MB of storage space on S3,
    +making the current total cost to install this plugin ~$0.0005 per year. If
    +you have substantial media assets and intend to serve them to many users,
    +caveat emptor on a total cost of ownership - check AWS's pricing structure.
    +
    +See the ./README.md file for details and install instructions.
    +
    +"""
    +
    +from django.core.exceptions import (
    +    ImproperlyConfigured,
    +    SuspiciousOperation,
    +    SuspiciousFileOperation,
    +)
    +
    +try:
    +    from django.conf import settings as ev_settings
    +
    +    if (
    +        not ev_settings.AWS_ACCESS_KEY_ID
    +        or not ev_settings.AWS_SECRET_ACCESS_KEY
    +        or not ev_settings.AWS_STORAGE_BUCKET_NAME
    +        or not ev_settings.AWS_S3_REGION_NAME
    +    ):
    +        raise ImproperlyConfigured(
    +            (
    +                "You must add AWS-specific settings"
    +                "to mygame/server/conf/secret_settings.py to use this plugin."
    +            )
    +        )
    +
    +    if "mygame-evennia" == ev_settings.AWS_STORAGE_BUCKET_NAME:
    +        raise ImproperlyConfigured(
    +            (
    +                "You must customize your AWS_STORAGE_BUCKET_NAME"
    +                "in mygame/server/conf/secret_settings.py;"
    +                "it must be unique among ALL other S3 users"
    +            )
    +        )
    +
    +except Exception as e:
    +    print(e)
    +
    +import io
    +import mimetypes
    +import os
    +import posixpath
    +import threading
    +from gzip import GzipFile
    +from tempfile import SpooledTemporaryFile
    +from django.core.files.base import File
    +from django.core.files.storage import Storage
    +from django.utils.deconstruct import deconstructible
    +from django.utils.encoding import filepath_to_uri, force_bytes, force_text, smart_text
    +from django.utils.timezone import is_naive, make_naive
    +
    +try:
    +    from django.utils.six.moves.urllib import parse as urlparse
    +except ImportError:
    +    from urllib import parse as urlparse
    +
    +try:
    +    import boto3.session
    +    from boto3 import __version__ as boto3_version
    +    from botocore.client import Config
    +    from botocore.exceptions import ClientError
    +except ImportError as e:
    +    raise ImproperlyConfigured("Couldn't load S3 bindings. %s Did you run 'pip install boto3?'" % e)
    +
    +boto3_version_info = tuple([int(i) for i in boto3_version.split(".")])
    +
    +
    +
    [docs]def setting(name, default=None): + """ + Helper function to get a Django setting by name. If setting doesn't exist + it will return a default. + + Args: + name (str): A Django setting name + + Returns: + The value of the setting variable by that name + + """ + return getattr(ev_settings, name, default)
    + + +
    [docs]def safe_join(base, *paths): + """ + Helper function, a version of django.utils._os.safe_join for S3 paths. + Joins one or more path components to the base path component + intelligently. Returns a normalized version of the final path. + The final path must be located inside of the base path component + (otherwise a ValueError is raised). Paths outside the base path + indicate a possible security sensitive operation. + + Args: + base (str): A path string to the base of the staticfiles + *paths (list): A list of paths as referenced from the base path + + Returns: + final_path (str): A joined path, base + filepath + + """ + base_path = force_text(base) + base_path = base_path.rstrip("/") + paths = [force_text(p) for p in paths] + + final_path = base_path + "/" + for path in paths: + _final_path = posixpath.normpath(posixpath.join(final_path, path)) + # posixpath.normpath() strips the trailing /. Add it back. + if path.endswith("/") or _final_path + "/" == final_path: + _final_path += "/" + final_path = _final_path + if final_path == base_path: + final_path += "/" + + # Ensure final_path starts with base_path and that the next character after + # the base path is /. + base_path_len = len(base_path) + if not final_path.startswith(base_path) or final_path[base_path_len] != "/": + raise ValueError("the joined path is located outside of the base path" " component") + + return final_path.lstrip("/")
    + + +
    [docs]def check_location(storage): + """ + Helper function to make sure that the storage location is configured correctly. + + Args: + storage (Storage): A Storage object (Django) + + Raises: + ImproperlyConfigured: If the storage location is not configured correctly, + this is raised. + + """ + if storage.location.startswith("/"): + correct = storage.location.lstrip("/") + raise ImproperlyConfigured( + "{}.location cannot begin with a leading slash. Found '{}'. Use '{}' instead.".format( + storage.__class__.__name__, storage.location, correct, + ) + )
    + + +
    [docs]def lookup_env(names): + """ + Helper function for looking up names in env vars. Returns the first element found. + + Args: + names (str): A list of environment variables + + Returns: + value (str): The value of the found environment variable. + + """ + for name in names: + value = os.environ.get(name) + if value: + return value
    + + +
    [docs]def get_available_overwrite_name(name, max_length): + """ + Helper function indicating files that will be overwritten during trunc. + + Args: + name (str): The name of the file + max_length (int): The maximum length of a filename + + Returns: + joined (path): A joined path including directory, file, and extension + """ + if max_length is None or len(name) <= max_length: + return name + + # Adapted from Django + dir_name, file_name = os.path.split(name) + file_root, file_ext = os.path.splitext(file_name) + truncation = len(name) - max_length + + file_root = file_root[:-truncation] + if not file_root: + raise SuspiciousFileOperation( + 'aws-s3-cdn tried to truncate away entire filename "%s". ' + "Please make sure that the corresponding file field " + 'allows sufficient "max_length".' % name + ) + return os.path.join(dir_name, "{}{}".format(file_root, file_ext))
    + + +
    [docs]@deconstructible +class S3Boto3StorageFile(File): + + """ + The default file object used by the S3Boto3Storage backend. + This file implements file streaming using boto's multipart + uploading functionality. The file can be opened in read or + write mode. + This class extends Django's File class. However, the contained + data is only the data contained in the current buffer. So you + should not access the contained file object directly. You should + access the data via this class. + Warning: This file *must* be closed using the close() method in + order to properly write the file to S3. Be sure to close the file + in your application. + """ + + buffer_size = setting("AWS_S3_FILE_BUFFER_SIZE", 5242880) + +
    [docs] def __init__(self, name, mode, storage, buffer_size=None): + """ + Initializes the File object. + + Args: + name (str): The name of the file + mode (str): The access mode ('r' or 'w') + storage (Storage): The Django Storage object + buffer_size (int): The buffer size, for multipart uploads + """ + if "r" in mode and "w" in mode: + raise ValueError("Can't combine 'r' and 'w' in mode.") + self._storage = storage + self.name = name[len(self._storage.location) :].lstrip("/") + self._mode = mode + self._force_mode = (lambda b: b) if "b" in mode else force_text + self.obj = storage.bucket.Object(storage._encode_name(name)) + if "w" not in mode: + # Force early RAII-style exception if object does not exist + self.obj.load() + self._is_dirty = False + self._raw_bytes_written = 0 + self._file = None + self._multipart = None + # 5 MB is the minimum part size (if there is more than one part). + # Amazon allows up to 10,000 parts. The default supports uploads + # up to roughly 50 GB. Increase the part size to accommodate + # for files larger than this. + if buffer_size is not None: + self.buffer_size = buffer_size + self._write_counter = 0
    + + @property + def size(self): + """ + Helper property to return filesize + """ + return self.obj.content_length + + def _get_file(self): + """ + Helper function to manage zipping and temporary files + """ + if self._file is None: + self._file = SpooledTemporaryFile( + max_size=self._storage.max_memory_size, + suffix=".S3Boto3StorageFile", + dir=setting("FILE_UPLOAD_TEMP_DIR"), + ) + if "r" in self._mode: + self._is_dirty = False + self.obj.download_fileobj(self._file) + self._file.seek(0) + if self._storage.gzip and self.obj.content_encoding == "gzip": + self._file = GzipFile(mode=self._mode, fileobj=self._file, mtime=0.0) + return self._file + + def _set_file(self, value): + self._file = value + + file = property(_get_file, _set_file) + +
    [docs] def read(self, *args, **kwargs): + """ + Checks if file is in read mode; then continues to boto3 operation + """ + if "r" not in self._mode: + raise AttributeError("File was not opened in read mode.") + return self._force_mode(super().read(*args, **kwargs))
    + +
    [docs] def readline(self, *args, **kwargs): + """ + Checks if file is in read mode; then continues to boto3 operation + """ + if "r" not in self._mode: + raise AttributeError("File was not opened in read mode.") + return self._force_mode(super().readline(*args, **kwargs))
    + +
    [docs] def write(self, content): + """ + Checks if file is in write mode or needs multipart handling, + then continues to boto3 operation. + """ + if "w" not in self._mode: + raise AttributeError("File was not opened in write mode.") + self._is_dirty = True + if self._multipart is None: + self._multipart = self.obj.initiate_multipart_upload( + **self._storage._get_write_parameters(self.obj.key) + ) + if self.buffer_size <= self._buffer_file_size: + self._flush_write_buffer() + bstr = force_bytes(content) + self._raw_bytes_written += len(bstr) + return super().write(bstr)
    + + @property + def _buffer_file_size(self): + pos = self.file.tell() + self.file.seek(0, os.SEEK_END) + length = self.file.tell() + self.file.seek(pos) + return length + + def _flush_write_buffer(self): + """ + Flushes the write buffer. + """ + if self._buffer_file_size: + self._write_counter += 1 + self.file.seek(0) + part = self._multipart.Part(self._write_counter) + part.upload(Body=self.file.read()) + self.file.seek(0) + self.file.truncate() + + def _create_empty_on_close(self): + """ + Attempt to create an empty file for this key when this File is closed if no bytes + have been written and no object already exists on S3 for this key. + This behavior is meant to mimic the behavior of Django's builtin FileSystemStorage, + where files are always created after they are opened in write mode: + f = storage.open("file.txt", mode="w") + f.close() + + Raises: + Exception: Raised if a 404 error occurs + """ + assert "w" in self._mode + assert self._raw_bytes_written == 0 + + try: + # Check if the object exists on the server; if so, don't do anything + self.obj.load() + except ClientError as err: + if err.response["ResponseMetadata"]["HTTPStatusCode"] == 404: + self.obj.put(Body=b"", **self._storage._get_write_parameters(self.obj.key)) + else: + raise + +
    [docs] def close(self): + """ + Manages file closing after multipart uploads + """ + if self._is_dirty: + self._flush_write_buffer() + parts = [ + {"ETag": part.e_tag, "PartNumber": part.part_number} + for part in self._multipart.parts.all() + ] + self._multipart.complete(MultipartUpload={"Parts": parts}) + else: + if self._multipart is not None: + self._multipart.abort() + if "w" in self._mode and self._raw_bytes_written == 0: + self._create_empty_on_close() + if self._file is not None: + self._file.close() + self._file = None
    + + +
    [docs]@deconstructible +class S3Boto3Storage(Storage): + """ + Amazon Simple Storage Service using Boto3 + This storage backend supports opening files in read or write + mode and supports streaming(buffering) data in chunks to S3 + when writing. + """ + + default_content_type = "application/octet-stream" + # If config provided in init, signature_version and addressing_style settings/args are ignored. + config = None + # used for looking up the access and secret key from env vars + access_key_names = ["AWS_S3_ACCESS_KEY_ID", "AWS_ACCESS_KEY_ID"] + secret_key_names = ["AWS_S3_SECRET_ACCESS_KEY", "AWS_SECRET_ACCESS_KEY"] + security_token_names = ["AWS_SESSION_TOKEN", "AWS_SECURITY_TOKEN"] + security_token = None + + access_key = setting("AWS_S3_ACCESS_KEY_ID", setting("AWS_ACCESS_KEY_ID", "")) + secret_key = setting("AWS_S3_SECRET_ACCESS_KEY", setting("AWS_SECRET_ACCESS_KEY", "")) + file_overwrite = setting("AWS_S3_FILE_OVERWRITE", True) + object_parameters = setting("AWS_S3_OBJECT_PARAMETERS", {}) + bucket_name = setting("AWS_STORAGE_BUCKET_NAME") + auto_create_bucket = setting("AWS_AUTO_CREATE_BUCKET", False) + default_acl = setting("AWS_DEFAULT_ACL", "public-read") + bucket_acl = setting("AWS_BUCKET_ACL", default_acl) + querystring_auth = setting("AWS_QUERYSTRING_AUTH", True) + querystring_expire = setting("AWS_QUERYSTRING_EXPIRE", 3600) + signature_version = setting("AWS_S3_SIGNATURE_VERSION") + reduced_redundancy = setting("AWS_REDUCED_REDUNDANCY", False) + location = setting("AWS_LOCATION", "") + encryption = setting("AWS_S3_ENCRYPTION", False) + custom_domain = setting("AWS_S3_CUSTOM_DOMAIN") + addressing_style = setting("AWS_S3_ADDRESSING_STYLE") + secure_urls = setting("AWS_S3_SECURE_URLS", True) + file_name_charset = setting("AWS_S3_FILE_NAME_CHARSET", "utf-8") + gzip = setting("AWS_IS_GZIPPED", False) + preload_metadata = setting("AWS_PRELOAD_METADATA", False) + gzip_content_types = setting( + "GZIP_CONTENT_TYPES", + ( + "text/css", + "text/javascript", + "application/javascript", + "application/x-javascript", + "image/svg+xml", + ), + ) + url_protocol = setting("AWS_S3_URL_PROTOCOL", "http:") + endpoint_url = setting("AWS_S3_ENDPOINT_URL") + proxies = setting("AWS_S3_PROXIES") + region_name = setting("AWS_S3_REGION_NAME") + use_ssl = setting("AWS_S3_USE_SSL", True) + verify = setting("AWS_S3_VERIFY", None) + max_memory_size = setting("AWS_S3_MAX_MEMORY_SIZE", 0) + +
    [docs] def __init__(self, acl=None, bucket=None, **settings): + """ + Check if some of the settings we've provided as class attributes + need to be overwritten with values passed in here. + """ + for name, value in settings.items(): + if hasattr(self, name): + setattr(self, name, value) + + check_location(self) + + # Backward-compatibility: given the anteriority of the SECURE_URL setting + # we fall back to https if specified in order to avoid the construction + # of unsecure urls. + if self.secure_urls: + self.url_protocol = "https:" + + self._entries = {} + self._bucket = None + self._connections = threading.local() + + self.access_key, self.secret_key = self._get_access_keys() + self.security_token = self._get_security_token() + + if not self.config: + kwargs = dict( + s3={"addressing_style": self.addressing_style}, + signature_version=self.signature_version, + ) + + if boto3_version_info >= (1, 4, 4): + kwargs["proxies"] = self.proxies + self.config = Config(**kwargs)
    + + def __getstate__(self): + state = self.__dict__.copy() + state.pop("_connections", None) + state.pop("_bucket", None) + return state + + def __setstate__(self, state): + state["_connections"] = threading.local() + state["_bucket"] = None + self.__dict__ = state + + @property + def connection(self): + """ + Creates the actual connection to S3 + """ + connection = getattr(self._connections, "connection", None) + if connection is None: + session = boto3.session.Session() + self._connections.connection = session.resource( + "s3", + aws_access_key_id=self.access_key, + aws_secret_access_key=self.secret_key, + aws_session_token=self.security_token, + region_name=self.region_name, + use_ssl=self.use_ssl, + endpoint_url=self.endpoint_url, + config=self.config, + verify=self.verify, + ) + return self._connections.connection + + @property + def bucket(self): + """ + Get the current bucket. If there is no current bucket object + create it. + """ + if self._bucket is None: + self._bucket = self._get_or_create_bucket(self.bucket_name) + return self._bucket + + @property + def entries(self): + """ + Get the locally cached files for the bucket. + """ + if self.preload_metadata and not self._entries: + self._entries = { + self._decode_name(entry.key): entry + for entry in self.bucket.objects.filter(Prefix=self.location) + } + return self._entries + + def _get_access_keys(self): + """ + Gets the access keys to use when accessing S3. If none is + provided in the settings then get them from the environment + variables. + """ + access_key = self.access_key or lookup_env(S3Boto3Storage.access_key_names) + secret_key = self.secret_key or lookup_env(S3Boto3Storage.secret_key_names) + return access_key, secret_key + + def _get_security_token(self): + """ + Gets the security token to use when accessing S3. Get it from + the environment variables. + """ + security_token = self.security_token or lookup_env(S3Boto3Storage.security_token_names) + return security_token + + def _get_or_create_bucket(self, name): + """ + Retrieves a bucket if it exists, otherwise creates it. + """ + bucket = self.connection.Bucket(name) + if self.auto_create_bucket: + try: + # Directly call head_bucket instead of bucket.load() because head_bucket() + # fails on wrong region, while bucket.load() does not. + bucket.meta.client.head_bucket(Bucket=name) + except ClientError as err: + if err.response["ResponseMetadata"]["HTTPStatusCode"] == 301: + raise ImproperlyConfigured( + "Bucket %s exists, but in a different " + "region than we are connecting to. Set " + "the region to connect to by setting " + "AWS_S3_REGION_NAME to the correct region." % name + ) + + elif err.response["ResponseMetadata"]["HTTPStatusCode"] == 404: + # Notes: When using the us-east-1 Standard endpoint, you can create + # buckets in other regions. The same is not true when hitting region specific + # endpoints. However, when you create the bucket not in the same region, the + # connection will fail all future requests to the Bucket after the creation + # (301 Moved Permanently). + # + # For simplicity, we enforce in S3Boto3Storage that any auto-created + # bucket must match the region that the connection is for. + # + # Also note that Amazon specifically disallows "us-east-1" when passing bucket + # region names; LocationConstraint *must* be blank to create in US Standard. + + if self.bucket_acl: + bucket_params = {"ACL": self.bucket_acl} + else: + bucket_params = {} + region_name = self.connection.meta.client.meta.region_name + if region_name != "us-east-1": + bucket_params["CreateBucketConfiguration"] = { + "LocationConstraint": region_name + } + bucket.create(**bucket_params) + else: + raise + return bucket + + def _clean_name(self, name): + """ + Cleans the name so that Windows style paths work + """ + # Normalize Windows style paths + clean_name = posixpath.normpath(name).replace("\\", "/") + + # os.path.normpath() can strip trailing slashes so we implement + # a workaround here. + if name.endswith("/") and not clean_name.endswith("/"): + # Add a trailing slash as it was stripped. + clean_name += "/" + return clean_name + + def _normalize_name(self, name): + """ + Normalizes the name so that paths like /path/to/ignored/../something.txt + work. We check to make sure that the path pointed to is not outside + the directory specified by the LOCATION setting. + """ + try: + return safe_join(self.location, name) + except ValueError: + raise SuspiciousOperation("Attempted access to '%s' denied." % name) + + def _encode_name(self, name): + return smart_text(name, encoding=self.file_name_charset) + + def _decode_name(self, name): + return force_text(name, encoding=self.file_name_charset) + + def _compress_content(self, content): + """Gzip a given string content.""" + content.seek(0) + zbuf = io.BytesIO() + # The GZIP header has a modification time attribute (see http://www.zlib.org/rfc-gzip.html) + # Each time a file is compressed it changes even if the other contents don't change + # For S3 this defeats detection of changes using MD5 sums on gzipped files + # Fixing the mtime at 0.0 at compression time avoids this problem + zfile = GzipFile(mode="wb", fileobj=zbuf, mtime=0.0) + try: + zfile.write(force_bytes(content.read())) + finally: + zfile.close() + zbuf.seek(0) + # Boto 2 returned the InMemoryUploadedFile with the file pointer replaced, + # but Boto 3 seems to have issues with that. No need for fp.name in Boto3 + # so just returning the BytesIO directly + return zbuf + + def _open(self, name, mode="rb"): + """ + Opens the file, if it exists. + """ + name = self._normalize_name(self._clean_name(name)) + try: + f = S3Boto3StorageFile(name, mode, self) + except ClientError as err: + if err.response["ResponseMetadata"]["HTTPStatusCode"] == 404: + raise IOError("File does not exist: %s" % name) + raise # Let it bubble up if it was some other error + return f + + def _save(self, name, content): + """ + Stitches and cleans multipart uploads; normalizes file paths. + """ + cleaned_name = self._clean_name(name) + name = self._normalize_name(cleaned_name) + params = self._get_write_parameters(name, content) + + if ( + self.gzip + and params["ContentType"] in self.gzip_content_types + and "ContentEncoding" not in params + ): + content = self._compress_content(content) + params["ContentEncoding"] = "gzip" + + encoded_name = self._encode_name(name) + obj = self.bucket.Object(encoded_name) + if self.preload_metadata: + self._entries[encoded_name] = obj + + content.seek(0, os.SEEK_SET) + obj.upload_fileobj(content, ExtraArgs=params) + return cleaned_name + +
    [docs] def delete(self, name): + """ + Deletes a file from S3. + """ + name = self._normalize_name(self._clean_name(name)) + self.bucket.Object(self._encode_name(name)).delete() + + if name in self._entries: + del self._entries[name]
    + +
    [docs] def exists(self, name): + """ + Checks if file exists. + """ + name = self._normalize_name(self._clean_name(name)) + if self.entries: + return name in self.entries + try: + self.connection.meta.client.head_object(Bucket=self.bucket_name, Key=name) + return True + except ClientError: + return False
    + +
    [docs] def listdir(self, name): + """ + Translational function to go from S3 file paths to the format + Django's listdir expects. + """ + path = self._normalize_name(self._clean_name(name)) + # The path needs to end with a slash, but if the root is empty, leave + # it. + if path and not path.endswith("/"): + path += "/" + + directories = [] + files = [] + paginator = self.connection.meta.client.get_paginator("list_objects") + pages = paginator.paginate(Bucket=self.bucket_name, Delimiter="/", Prefix=path) + for page in pages: + for entry in page.get("CommonPrefixes", ()): + directories.append(posixpath.relpath(entry["Prefix"], path)) + for entry in page.get("Contents", ()): + files.append(posixpath.relpath(entry["Key"], path)) + return directories, files
    + +
    [docs] def size(self, name): + """ + Gets the filesize of a remote file. + """ + name = self._normalize_name(self._clean_name(name)) + if self.entries: + entry = self.entries.get(name) + if entry: + return entry.size if hasattr(entry, "size") else entry.content_length + return 0 + return self.bucket.Object(self._encode_name(name)).content_length
    + + def _get_write_parameters(self, name, content=None): + params = {} + + if self.encryption: + params["ServerSideEncryption"] = "AES256" + if self.reduced_redundancy: + params["StorageClass"] = "REDUCED_REDUNDANCY" + if self.default_acl: + params["ACL"] = self.default_acl + + _type, encoding = mimetypes.guess_type(name) + content_type = getattr(content, "content_type", None) + content_type = content_type or _type or self.default_content_type + + params["ContentType"] = content_type + if encoding: + params["ContentEncoding"] = encoding + + params.update(self.get_object_parameters(name)) + return params + +
    [docs] def get_object_parameters(self, name): + """ + Returns a dictionary that is passed to file upload. Override this + method to adjust this on a per-object basis to set e.g ContentDisposition. + By default, returns the value of AWS_S3_OBJECT_PARAMETERS. + Setting ContentEncoding will prevent objects from being automatically gzipped. + """ + return self.object_parameters.copy()
    + +
    [docs] def get_modified_time(self, name): + """ + Returns an (aware) datetime object containing the last modified time if + USE_TZ is True, otherwise returns a naive datetime in the local timezone. + """ + name = self._normalize_name(self._clean_name(name)) + entry = self.entries.get(name) + # only call self.bucket.Object() if the key is not found + # in the preloaded metadata. + if entry is None: + entry = self.bucket.Object(self._encode_name(name)) + if setting("USE_TZ"): + # boto3 returns TZ aware timestamps + return entry.last_modified + else: + return make_naive(entry.last_modified)
    + +
    [docs] def modified_time(self, name): + """Returns a naive datetime object containing the last modified time. + If USE_TZ=False then get_modified_time will return a naive datetime + so we just return that, else we have to localize and strip the tz + """ + mtime = self.get_modified_time(name) + return mtime if is_naive(mtime) else make_naive(mtime)
    + + def _strip_signing_parameters(self, url): + """ + Boto3 does not currently support generating URLs that are unsigned. Instead we + take the signed URLs and strip any querystring params related to signing and expiration. + Note that this may end up with URLs that are still invalid, especially if params are + passed in that only work with signed URLs, e.g. response header params. + The code attempts to strip all query parameters that match names of known parameters + from v2 and v4 signatures, regardless of the actual signature version used. + """ + split_url = urlparse.urlsplit(url) + qs = urlparse.parse_qsl(split_url.query, keep_blank_values=True) + blacklist = { + "x-amz-algorithm", + "x-amz-credential", + "x-amz-date", + "x-amz-expires", + "x-amz-signedheaders", + "x-amz-signature", + "x-amz-security-token", + "awsaccesskeyid", + "expires", + "signature", + } + filtered_qs = ((key, val) for key, val in qs if key.lower() not in blacklist) + # Note: Parameters that did not have a value in the original query string will have + # an '=' sign appended to it, e.g ?foo&bar becomes ?foo=&bar= + joined_qs = ("=".join(keyval) for keyval in filtered_qs) + split_url = split_url._replace(query="&".join(joined_qs)) + return split_url.geturl() + +
    [docs] def url(self, name, parameters=None, expire=None): + """ + Returns the URL of a remotely-hosted file + """ + # Preserve the trailing slash after normalizing the path. + name = self._normalize_name(self._clean_name(name)) + if self.custom_domain: + return "{}//{}/{}".format(self.url_protocol, self.custom_domain, filepath_to_uri(name)) + if expire is None: + expire = self.querystring_expire + + params = parameters.copy() if parameters else {} + params["Bucket"] = self.bucket.name + params["Key"] = self._encode_name(name) + url = self.bucket.meta.client.generate_presigned_url( + "get_object", Params=params, ExpiresIn=expire + ) + if self.querystring_auth: + return url + return self._strip_signing_parameters(url)
    + +
    [docs] def get_available_name(self, name, max_length=None): + """Overwrite existing file with the same name.""" + name = self._clean_name(name) + if self.file_overwrite: + return get_available_overwrite_name(name, max_length) + return super().get_available_name(name, max_length)
    +
    + +
    +
    +
    +
    + +
    +
    + + + + \ No newline at end of file diff --git a/docs/1.0-dev/_modules/evennia/contrib/base_systems/awsstorage/tests.html b/docs/1.0-dev/_modules/evennia/contrib/base_systems/awsstorage/tests.html index b456785099..75c095e747 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/base_systems/awsstorage/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/base_systems/awsstorage/tests.html @@ -684,7 +684,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/base_systems/building_menu/building_menu.html b/docs/1.0-dev/_modules/evennia/contrib/base_systems/building_menu/building_menu.html index 934e1880cd..42c398c8d6 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/base_systems/building_menu/building_menu.html +++ b/docs/1.0-dev/_modules/evennia/contrib/base_systems/building_menu/building_menu.html @@ -1346,7 +1346,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/base_systems/building_menu/tests.html b/docs/1.0-dev/_modules/evennia/contrib/base_systems/building_menu/tests.html index 102c6db931..a3f96ff15b 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/base_systems/building_menu/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/base_systems/building_menu/tests.html @@ -253,7 +253,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/base_systems/color_markups/tests.html b/docs/1.0-dev/_modules/evennia/contrib/base_systems/color_markups/tests.html index 73a3e0c85a..5224cfa005 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/base_systems/color_markups/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/base_systems/color_markups/tests.html @@ -142,7 +142,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/base_systems/custom_gametime/custom_gametime.html b/docs/1.0-dev/_modules/evennia/contrib/base_systems/custom_gametime/custom_gametime.html index ecb659f0ce..a39bfc763f 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/base_systems/custom_gametime/custom_gametime.html +++ b/docs/1.0-dev/_modules/evennia/contrib/base_systems/custom_gametime/custom_gametime.html @@ -406,7 +406,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/base_systems/custom_gametime/tests.html b/docs/1.0-dev/_modules/evennia/contrib/base_systems/custom_gametime/tests.html index 3da5acd851..970e1ccbec 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/base_systems/custom_gametime/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/base_systems/custom_gametime/tests.html @@ -130,7 +130,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/base_systems/email_login/email_login.html b/docs/1.0-dev/_modules/evennia/contrib/base_systems/email_login/email_login.html index 8817659d80..84b0bc88c3 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/base_systems/email_login/email_login.html +++ b/docs/1.0-dev/_modules/evennia/contrib/base_systems/email_login/email_login.html @@ -441,7 +441,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/base_systems/email_login/tests.html b/docs/1.0-dev/_modules/evennia/contrib/base_systems/email_login/tests.html index 323ddfd2dd..91decfaa3f 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/base_systems/email_login/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/base_systems/email_login/tests.html @@ -112,7 +112,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/callbackhandler.html b/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/callbackhandler.html index 1364b874cd..918a40ae24 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/callbackhandler.html +++ b/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/callbackhandler.html @@ -301,7 +301,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/commands.html b/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/commands.html index 2a5a4b06d6..da3a346f51 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/commands.html +++ b/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/commands.html @@ -658,7 +658,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/eventfuncs.html b/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/eventfuncs.html index f5534e46fe..d00dd37534 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/eventfuncs.html +++ b/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/eventfuncs.html @@ -167,7 +167,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/scripts.html b/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/scripts.html index 944b2e8005..325f926a11 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/scripts.html +++ b/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/scripts.html @@ -745,7 +745,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/tests.html b/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/tests.html index 1efe3d51f0..4ffab2cbea 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/tests.html @@ -619,7 +619,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/utils.html b/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/utils.html index 9c69f97e19..b38693589f 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/utils.html +++ b/docs/1.0-dev/_modules/evennia/contrib/base_systems/ingame_python/utils.html @@ -336,7 +336,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/base_systems/mux_comms_cmds/mux_comms_cmds.html b/docs/1.0-dev/_modules/evennia/contrib/base_systems/mux_comms_cmds/mux_comms_cmds.html index b2bc5ee6d1..d9b56e8840 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/base_systems/mux_comms_cmds/mux_comms_cmds.html +++ b/docs/1.0-dev/_modules/evennia/contrib/base_systems/mux_comms_cmds/mux_comms_cmds.html @@ -621,7 +621,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/base_systems/mux_comms_cmds/tests.html b/docs/1.0-dev/_modules/evennia/contrib/base_systems/mux_comms_cmds/tests.html index 03d4892881..09b7d83849 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/base_systems/mux_comms_cmds/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/base_systems/mux_comms_cmds/tests.html @@ -162,7 +162,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/base_systems/unixcommand/tests.html b/docs/1.0-dev/_modules/evennia/contrib/base_systems/unixcommand/tests.html index 21ac5f33c5..470476c543 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/base_systems/unixcommand/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/base_systems/unixcommand/tests.html @@ -126,7 +126,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/base_systems/unixcommand/unixcommand.html b/docs/1.0-dev/_modules/evennia/contrib/base_systems/unixcommand/unixcommand.html index ddf3dd3dc6..e22a7bfaee 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/base_systems/unixcommand/unixcommand.html +++ b/docs/1.0-dev/_modules/evennia/contrib/base_systems/unixcommand/unixcommand.html @@ -374,7 +374,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/commands.html b/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/commands.html index 2e217256e4..fe39de3613 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/commands.html +++ b/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/commands.html @@ -857,7 +857,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/menu.html b/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/menu.html index 9069dcd96a..ff1c041da5 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/menu.html +++ b/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/menu.html @@ -430,7 +430,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/objects.html b/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/objects.html index db3440fc09..06f9e66efb 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/objects.html +++ b/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/objects.html @@ -1157,7 +1157,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/room.html b/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/room.html index 102dd2149b..039622a7f8 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/room.html +++ b/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/room.html @@ -316,7 +316,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/scripts.html b/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/scripts.html index 8e5d01e81c..835651d0c3 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/scripts.html +++ b/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/scripts.html @@ -107,7 +107,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/state.html b/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/state.html index 4a391f1f8c..cb19fdb810 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/state.html +++ b/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/state.html @@ -384,7 +384,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/tests.html b/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/tests.html index 0f42b558b8..861efb4098 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/tests.html @@ -381,7 +381,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/utils.html b/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/utils.html index 83a004aafc..d49a931d38 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/utils.html +++ b/docs/1.0-dev/_modules/evennia/contrib/full_systems/evscaperoom/utils.html @@ -271,7 +271,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/barter/barter.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/barter/barter.html index 168952b22d..9b15a325b1 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/barter/barter.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/barter/barter.html @@ -975,7 +975,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/barter/tests.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/barter/tests.html index b6f8b86b3c..bde6631e9f 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/barter/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/barter/tests.html @@ -223,7 +223,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/clothing/clothing.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/clothing/clothing.html index 2b0bcdb701..7929008a05 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/clothing/clothing.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/clothing/clothing.html @@ -820,7 +820,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/clothing/tests.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/clothing/tests.html index 901c7141e6..77c80c60a8 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/clothing/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/clothing/tests.html @@ -209,7 +209,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/cooldowns/cooldowns.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/cooldowns/cooldowns.html index c956fdf222..8cfb578865 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/cooldowns/cooldowns.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/cooldowns/cooldowns.html @@ -284,7 +284,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/cooldowns/tests.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/cooldowns/tests.html index 84ea20244b..ac202dcadd 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/cooldowns/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/cooldowns/tests.html @@ -223,7 +223,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/crafting/crafting.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/crafting/crafting.html index eaf177bdfc..961d09a3bd 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/crafting/crafting.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/crafting/crafting.html @@ -1145,7 +1145,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/crafting/example_recipes.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/crafting/example_recipes.html index e26a96c3a8..21b8cd428f 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/crafting/example_recipes.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/crafting/example_recipes.html @@ -607,7 +607,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/crafting/tests.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/crafting/tests.html index 7a3e3f4d41..2de90368d5 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/crafting/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/crafting/tests.html @@ -765,7 +765,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/gendersub/gendersub.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/gendersub/gendersub.html index fb04f38539..efcefb770f 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/gendersub/gendersub.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/gendersub/gendersub.html @@ -235,7 +235,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/gendersub/tests.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/gendersub/tests.html index 4b641a91fa..8bd7118472 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/gendersub/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/gendersub/tests.html @@ -104,7 +104,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/mail/mail.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/mail/mail.html index 42a8936221..cf6a9d296a 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/mail/mail.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/mail/mail.html @@ -436,7 +436,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/mail/tests.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/mail/tests.html index 08ec530920..79b144636d 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/mail/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/mail/tests.html @@ -123,7 +123,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/multidescer/multidescer.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/multidescer/multidescer.html index 2240a7373e..963be95988 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/multidescer/multidescer.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/multidescer/multidescer.html @@ -345,7 +345,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/multidescer/tests.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/multidescer/tests.html index 9fa3973a41..db6e0ce8dc 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/multidescer/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/multidescer/tests.html @@ -116,7 +116,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/puzzles/puzzles.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/puzzles/puzzles.html index 05fedd213a..45d1bb4594 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/puzzles/puzzles.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/puzzles/puzzles.html @@ -894,7 +894,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/puzzles/tests.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/puzzles/tests.html index 5f75ff40ae..63bab3715f 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/puzzles/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/puzzles/tests.html @@ -1051,7 +1051,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_basic.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_basic.html index 9249c8f499..85615c07c7 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_basic.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_basic.html @@ -858,7 +858,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_equip.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_equip.html index aff5d7d41d..32d567cf61 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_equip.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_equip.html @@ -1214,7 +1214,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_items.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_items.html index a63b3155f0..cd4bafa4f0 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_items.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_items.html @@ -1533,7 +1533,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_magic.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_magic.html index 131ecbd8b2..353c5d1fed 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_magic.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_magic.html @@ -1455,7 +1455,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_range.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_range.html index 2964fbe711..ebf5852ccd 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_range.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tb_range.html @@ -1511,7 +1511,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tests.html b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tests.html index 213e627325..40e4082d53 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/game_systems/turnbattle/tests.html @@ -679,7 +679,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/extended_room/extended_room.html b/docs/1.0-dev/_modules/evennia/contrib/grid/extended_room/extended_room.html index 1a6d7725ab..7f0762b8ec 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/grid/extended_room/extended_room.html +++ b/docs/1.0-dev/_modules/evennia/contrib/grid/extended_room/extended_room.html @@ -669,7 +669,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/extended_room/tests.html b/docs/1.0-dev/_modules/evennia/contrib/grid/extended_room/tests.html index 775f6ffb77..d2d42e8286 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/grid/extended_room/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/grid/extended_room/tests.html @@ -179,7 +179,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/simpledoor/simpledoor.html b/docs/1.0-dev/_modules/evennia/contrib/grid/simpledoor/simpledoor.html index 9dbb5a5cf3..1f8c85f9df 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/grid/simpledoor/simpledoor.html +++ b/docs/1.0-dev/_modules/evennia/contrib/grid/simpledoor/simpledoor.html @@ -270,7 +270,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/simpledoor/tests.html b/docs/1.0-dev/_modules/evennia/contrib/grid/simpledoor/tests.html index 708692d61e..15a2593b78 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/grid/simpledoor/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/grid/simpledoor/tests.html @@ -105,7 +105,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/slow_exit/slow_exit.html b/docs/1.0-dev/_modules/evennia/contrib/grid/slow_exit/slow_exit.html index 90d5e62a0c..fd3eac76ac 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/grid/slow_exit/slow_exit.html +++ b/docs/1.0-dev/_modules/evennia/contrib/grid/slow_exit/slow_exit.html @@ -250,7 +250,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/slow_exit/tests.html b/docs/1.0-dev/_modules/evennia/contrib/grid/slow_exit/tests.html index 57420e9c42..9f80d4aed6 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/grid/slow_exit/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/grid/slow_exit/tests.html @@ -103,7 +103,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/wilderness/tests.html b/docs/1.0-dev/_modules/evennia/contrib/grid/wilderness/tests.html index dd78d33059..6d1c62b8a0 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/grid/wilderness/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/grid/wilderness/tests.html @@ -213,7 +213,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/wilderness/wilderness.html b/docs/1.0-dev/_modules/evennia/contrib/grid/wilderness/wilderness.html index 7b66703dd2..4f8f4cabd4 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/grid/wilderness/wilderness.html +++ b/docs/1.0-dev/_modules/evennia/contrib/grid/wilderness/wilderness.html @@ -850,7 +850,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/commands.html b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/commands.html index d28abed562..5feed4371e 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/commands.html +++ b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/commands.html @@ -550,7 +550,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/example.html b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/example.html index c0b0e0aa17..b96521fbf3 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/example.html +++ b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/example.html @@ -367,7 +367,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/launchcmd.html b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/launchcmd.html index 6a97070dc6..74e945dda7 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/launchcmd.html +++ b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/launchcmd.html @@ -500,7 +500,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/tests.html b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/tests.html index 9e0e48d7fd..6f4a037755 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/tests.html @@ -1374,7 +1374,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/utils.html b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/utils.html index 6a55d55a13..02db2ed08d 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/utils.html +++ b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/utils.html @@ -131,7 +131,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xymap.html b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xymap.html index dd18e5907e..596806bb77 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xymap.html +++ b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xymap.html @@ -1021,7 +1021,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xymap_legend.html b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xymap_legend.html index cffe1ab4a7..8098b04e87 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xymap_legend.html +++ b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xymap_legend.html @@ -1371,7 +1371,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xyzgrid.html b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xyzgrid.html index 85e00b5d74..5f6d9edd35 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xyzgrid.html +++ b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xyzgrid.html @@ -384,7 +384,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xyzroom.html b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xyzroom.html index f9d82f1983..7c01c33810 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xyzroom.html +++ b/docs/1.0-dev/_modules/evennia/contrib/grid/xyzgrid/xyzroom.html @@ -657,7 +657,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/rpg/dice/dice.html b/docs/1.0-dev/_modules/evennia/contrib/rpg/dice/dice.html index bc8ba58732..4ebfca7d4a 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/rpg/dice/dice.html +++ b/docs/1.0-dev/_modules/evennia/contrib/rpg/dice/dice.html @@ -366,7 +366,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/rpg/dice/tests.html b/docs/1.0-dev/_modules/evennia/contrib/rpg/dice/tests.html index 77e0f94ea9..89ff39f5e0 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/rpg/dice/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/rpg/dice/tests.html @@ -99,7 +99,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/rpg/health_bar/health_bar.html b/docs/1.0-dev/_modules/evennia/contrib/rpg/health_bar/health_bar.html index a58b88e6c6..3cb114e142 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/rpg/health_bar/health_bar.html +++ b/docs/1.0-dev/_modules/evennia/contrib/rpg/health_bar/health_bar.html @@ -211,7 +211,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/rpg/health_bar/tests.html b/docs/1.0-dev/_modules/evennia/contrib/rpg/health_bar/tests.html index 53e4c25ad2..a55724c6c9 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/rpg/health_bar/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/rpg/health_bar/tests.html @@ -122,7 +122,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/rplanguage.html b/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/rplanguage.html index 029966a3ac..bc9f484612 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/rplanguage.html +++ b/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/rplanguage.html @@ -661,7 +661,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/rpsystem.html b/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/rpsystem.html index 1d18c0021a..cdc289a63e 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/rpsystem.html +++ b/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/rpsystem.html @@ -1838,7 +1838,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/tests.html b/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/tests.html index 0a165e3f65..710869d579 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/rpg/rpsystem/tests.html @@ -397,7 +397,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/rpg/traits/tests.html b/docs/1.0-dev/_modules/evennia/contrib/rpg/traits/tests.html index 15d78eb360..5f96c77e55 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/rpg/traits/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/rpg/traits/tests.html @@ -1024,7 +1024,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/rpg/traits/traits.html b/docs/1.0-dev/_modules/evennia/contrib/rpg/traits/traits.html index 73678079ef..49bef4400a 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/rpg/traits/traits.html +++ b/docs/1.0-dev/_modules/evennia/contrib/rpg/traits/traits.html @@ -1711,7 +1711,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/tutorials/bodyfunctions/bodyfunctions.html b/docs/1.0-dev/_modules/evennia/contrib/tutorials/bodyfunctions/bodyfunctions.html index ae6a945d56..1285f8167e 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/tutorials/bodyfunctions/bodyfunctions.html +++ b/docs/1.0-dev/_modules/evennia/contrib/tutorials/bodyfunctions/bodyfunctions.html @@ -147,7 +147,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/tutorials/bodyfunctions/tests.html b/docs/1.0-dev/_modules/evennia/contrib/tutorials/bodyfunctions/tests.html index 7da4435131..30e1f0206f 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/tutorials/bodyfunctions/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/tutorials/bodyfunctions/tests.html @@ -149,7 +149,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/tutorials/mirror/mirror.html b/docs/1.0-dev/_modules/evennia/contrib/tutorials/mirror/mirror.html index 43ae51d8a4..81a924e1ba 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/tutorials/mirror/mirror.html +++ b/docs/1.0-dev/_modules/evennia/contrib/tutorials/mirror/mirror.html @@ -138,7 +138,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/tutorials/red_button/red_button.html b/docs/1.0-dev/_modules/evennia/contrib/tutorials/red_button/red_button.html index 1189ef072d..9a4381b08f 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/tutorials/red_button/red_button.html +++ b/docs/1.0-dev/_modules/evennia/contrib/tutorials/red_button/red_button.html @@ -656,7 +656,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/tutorials/talking_npc/talking_npc.html b/docs/1.0-dev/_modules/evennia/contrib/tutorials/talking_npc/talking_npc.html index f2f9546f4e..b93d7bf192 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/tutorials/talking_npc/talking_npc.html +++ b/docs/1.0-dev/_modules/evennia/contrib/tutorials/talking_npc/talking_npc.html @@ -215,7 +215,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/tutorials/talking_npc/tests.html b/docs/1.0-dev/_modules/evennia/contrib/tutorials/talking_npc/tests.html index 1f66f43a03..9f20d7df18 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/tutorials/talking_npc/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/tutorials/talking_npc/tests.html @@ -90,7 +90,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/intro_menu.html b/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/intro_menu.html index e7e884c0ee..f160dff34a 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/intro_menu.html +++ b/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/intro_menu.html @@ -858,7 +858,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/mob.html b/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/mob.html index 5f75e94945..7fdb0be66d 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/mob.html +++ b/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/mob.html @@ -512,7 +512,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/objects.html b/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/objects.html index 2d8934d71b..fe4338db17 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/objects.html +++ b/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/objects.html @@ -1260,7 +1260,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/rooms.html b/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/rooms.html index 2de2f53b3f..48fb7637c0 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/rooms.html +++ b/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/rooms.html @@ -1244,7 +1244,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/tests.html b/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/tests.html index 319a752e76..bcbb18a8f6 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/tutorials/tutorial_world/tests.html @@ -267,7 +267,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/utils/auditing/outputs.html b/docs/1.0-dev/_modules/evennia/contrib/utils/auditing/outputs.html index 90eef76222..1a1a554779 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/utils/auditing/outputs.html +++ b/docs/1.0-dev/_modules/evennia/contrib/utils/auditing/outputs.html @@ -136,7 +136,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/utils/auditing/server.html b/docs/1.0-dev/_modules/evennia/contrib/utils/auditing/server.html index 0435787a9f..5e5f2cddd8 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/utils/auditing/server.html +++ b/docs/1.0-dev/_modules/evennia/contrib/utils/auditing/server.html @@ -325,7 +325,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/utils/auditing/tests.html b/docs/1.0-dev/_modules/evennia/contrib/utils/auditing/tests.html index d549f4ec37..2316da220b 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/utils/auditing/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/utils/auditing/tests.html @@ -208,7 +208,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/utils/fieldfill/fieldfill.html b/docs/1.0-dev/_modules/evennia/contrib/utils/fieldfill/fieldfill.html index 6f041922e1..637703259a 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/utils/fieldfill/fieldfill.html +++ b/docs/1.0-dev/_modules/evennia/contrib/utils/fieldfill/fieldfill.html @@ -792,7 +792,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/utils/random_string_generator/random_string_generator.html b/docs/1.0-dev/_modules/evennia/contrib/utils/random_string_generator/random_string_generator.html index 501ac1cbaa..7cf21ca101 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/utils/random_string_generator/random_string_generator.html +++ b/docs/1.0-dev/_modules/evennia/contrib/utils/random_string_generator/random_string_generator.html @@ -431,7 +431,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/utils/random_string_generator/tests.html b/docs/1.0-dev/_modules/evennia/contrib/utils/random_string_generator/tests.html index 240074e2e8..721b9fb327 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/utils/random_string_generator/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/utils/random_string_generator/tests.html @@ -101,7 +101,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/utils/tree_select/tests.html b/docs/1.0-dev/_modules/evennia/contrib/utils/tree_select/tests.html index f15b2bd68e..b11819adab 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/utils/tree_select/tests.html +++ b/docs/1.0-dev/_modules/evennia/contrib/utils/tree_select/tests.html @@ -138,7 +138,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/contrib/utils/tree_select/tree_select.html b/docs/1.0-dev/_modules/evennia/contrib/utils/tree_select/tree_select.html index ca1c8c4968..7f5a0915c2 100644 --- a/docs/1.0-dev/_modules/evennia/contrib/utils/tree_select/tree_select.html +++ b/docs/1.0-dev/_modules/evennia/contrib/utils/tree_select/tree_select.html @@ -654,7 +654,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/help/filehelp.html b/docs/1.0-dev/_modules/evennia/help/filehelp.html index 11110b28ee..780cb82b76 100644 --- a/docs/1.0-dev/_modules/evennia/help/filehelp.html +++ b/docs/1.0-dev/_modules/evennia/help/filehelp.html @@ -335,7 +335,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/help/manager.html b/docs/1.0-dev/_modules/evennia/help/manager.html index 1adf4584e6..d639c09e81 100644 --- a/docs/1.0-dev/_modules/evennia/help/manager.html +++ b/docs/1.0-dev/_modules/evennia/help/manager.html @@ -276,7 +276,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/help/models.html b/docs/1.0-dev/_modules/evennia/help/models.html index 6b0b09efa7..808d3e22a3 100644 --- a/docs/1.0-dev/_modules/evennia/help/models.html +++ b/docs/1.0-dev/_modules/evennia/help/models.html @@ -384,7 +384,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/help/utils.html b/docs/1.0-dev/_modules/evennia/help/utils.html index 08d618491b..72498d1c62 100644 --- a/docs/1.0-dev/_modules/evennia/help/utils.html +++ b/docs/1.0-dev/_modules/evennia/help/utils.html @@ -308,7 +308,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/locks/lockfuncs.html b/docs/1.0-dev/_modules/evennia/locks/lockfuncs.html index 932d91b4fa..6229679f7e 100644 --- a/docs/1.0-dev/_modules/evennia/locks/lockfuncs.html +++ b/docs/1.0-dev/_modules/evennia/locks/lockfuncs.html @@ -706,7 +706,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/locks/lockhandler.html b/docs/1.0-dev/_modules/evennia/locks/lockhandler.html index 63ae75995c..805185af17 100644 --- a/docs/1.0-dev/_modules/evennia/locks/lockhandler.html +++ b/docs/1.0-dev/_modules/evennia/locks/lockhandler.html @@ -857,7 +857,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/objects/manager.html b/docs/1.0-dev/_modules/evennia/objects/manager.html index 108f9fbe12..41ddd307bf 100644 --- a/docs/1.0-dev/_modules/evennia/objects/manager.html +++ b/docs/1.0-dev/_modules/evennia/objects/manager.html @@ -810,7 +810,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/objects/models.html b/docs/1.0-dev/_modules/evennia/objects/models.html index cb76d0ea39..33255ce7d3 100644 --- a/docs/1.0-dev/_modules/evennia/objects/models.html +++ b/docs/1.0-dev/_modules/evennia/objects/models.html @@ -468,7 +468,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/objects/objects.html b/docs/1.0-dev/_modules/evennia/objects/objects.html index 2eaa3f7622..27e3f70b12 100644 --- a/docs/1.0-dev/_modules/evennia/objects/objects.html +++ b/docs/1.0-dev/_modules/evennia/objects/objects.html @@ -2938,7 +2938,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/prototypes/menus.html b/docs/1.0-dev/_modules/evennia/prototypes/menus.html index 7f3eb9b465..c139335814 100644 --- a/docs/1.0-dev/_modules/evennia/prototypes/menus.html +++ b/docs/1.0-dev/_modules/evennia/prototypes/menus.html @@ -2834,7 +2834,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/prototypes/protfuncs.html b/docs/1.0-dev/_modules/evennia/prototypes/protfuncs.html index 3a85758cfb..b440bdbb55 100644 --- a/docs/1.0-dev/_modules/evennia/prototypes/protfuncs.html +++ b/docs/1.0-dev/_modules/evennia/prototypes/protfuncs.html @@ -150,7 +150,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/prototypes/prototypes.html b/docs/1.0-dev/_modules/evennia/prototypes/prototypes.html index 0f2c8ef974..b270f003a3 100644 --- a/docs/1.0-dev/_modules/evennia/prototypes/prototypes.html +++ b/docs/1.0-dev/_modules/evennia/prototypes/prototypes.html @@ -1212,7 +1212,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/prototypes/spawner.html b/docs/1.0-dev/_modules/evennia/prototypes/spawner.html index 72d08920f8..e691bac09e 100644 --- a/docs/1.0-dev/_modules/evennia/prototypes/spawner.html +++ b/docs/1.0-dev/_modules/evennia/prototypes/spawner.html @@ -1112,7 +1112,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/scripts/manager.html b/docs/1.0-dev/_modules/evennia/scripts/manager.html index 179bb19662..99d7223ac7 100644 --- a/docs/1.0-dev/_modules/evennia/scripts/manager.html +++ b/docs/1.0-dev/_modules/evennia/scripts/manager.html @@ -403,7 +403,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/scripts/models.html b/docs/1.0-dev/_modules/evennia/scripts/models.html index a56c16f42e..2df02d11ca 100644 --- a/docs/1.0-dev/_modules/evennia/scripts/models.html +++ b/docs/1.0-dev/_modules/evennia/scripts/models.html @@ -257,7 +257,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/scripts/monitorhandler.html b/docs/1.0-dev/_modules/evennia/scripts/monitorhandler.html index bed903070d..8055ad4561 100644 --- a/docs/1.0-dev/_modules/evennia/scripts/monitorhandler.html +++ b/docs/1.0-dev/_modules/evennia/scripts/monitorhandler.html @@ -301,7 +301,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/scripts/scripthandler.html b/docs/1.0-dev/_modules/evennia/scripts/scripthandler.html index 3bd5cd319f..89aa7ef658 100644 --- a/docs/1.0-dev/_modules/evennia/scripts/scripthandler.html +++ b/docs/1.0-dev/_modules/evennia/scripts/scripthandler.html @@ -231,7 +231,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/scripts/scripts.html b/docs/1.0-dev/_modules/evennia/scripts/scripts.html index 0034d09d00..4eb603b341 100644 --- a/docs/1.0-dev/_modules/evennia/scripts/scripts.html +++ b/docs/1.0-dev/_modules/evennia/scripts/scripts.html @@ -886,7 +886,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/scripts/taskhandler.html b/docs/1.0-dev/_modules/evennia/scripts/taskhandler.html index f61fbb68b0..ebc82ef9f0 100644 --- a/docs/1.0-dev/_modules/evennia/scripts/taskhandler.html +++ b/docs/1.0-dev/_modules/evennia/scripts/taskhandler.html @@ -686,7 +686,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/scripts/tickerhandler.html b/docs/1.0-dev/_modules/evennia/scripts/tickerhandler.html index f4eda6f134..90387eafc0 100644 --- a/docs/1.0-dev/_modules/evennia/scripts/tickerhandler.html +++ b/docs/1.0-dev/_modules/evennia/scripts/tickerhandler.html @@ -719,7 +719,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/amp_client.html b/docs/1.0-dev/_modules/evennia/server/amp_client.html index 5bed005ac3..04ec1984e1 100644 --- a/docs/1.0-dev/_modules/evennia/server/amp_client.html +++ b/docs/1.0-dev/_modules/evennia/server/amp_client.html @@ -328,7 +328,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/connection_wizard.html b/docs/1.0-dev/_modules/evennia/server/connection_wizard.html index 57bbbb0cb9..ee9e0f629d 100644 --- a/docs/1.0-dev/_modules/evennia/server/connection_wizard.html +++ b/docs/1.0-dev/_modules/evennia/server/connection_wizard.html @@ -597,7 +597,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/deprecations.html b/docs/1.0-dev/_modules/evennia/server/deprecations.html index cd2f41fecc..484730358b 100644 --- a/docs/1.0-dev/_modules/evennia/server/deprecations.html +++ b/docs/1.0-dev/_modules/evennia/server/deprecations.html @@ -239,7 +239,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/evennia_launcher.html b/docs/1.0-dev/_modules/evennia/server/evennia_launcher.html index d35d055a17..f0aad36a9d 100644 --- a/docs/1.0-dev/_modules/evennia/server/evennia_launcher.html +++ b/docs/1.0-dev/_modules/evennia/server/evennia_launcher.html @@ -2430,7 +2430,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/game_index_client/client.html b/docs/1.0-dev/_modules/evennia/server/game_index_client/client.html index 6c18e350c2..82d3217a74 100644 --- a/docs/1.0-dev/_modules/evennia/server/game_index_client/client.html +++ b/docs/1.0-dev/_modules/evennia/server/game_index_client/client.html @@ -255,7 +255,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/game_index_client/service.html b/docs/1.0-dev/_modules/evennia/server/game_index_client/service.html index 4a5bc2975e..72b2bfb65e 100644 --- a/docs/1.0-dev/_modules/evennia/server/game_index_client/service.html +++ b/docs/1.0-dev/_modules/evennia/server/game_index_client/service.html @@ -134,7 +134,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/initial_setup.html b/docs/1.0-dev/_modules/evennia/server/initial_setup.html index 99b4234e24..a6301bcc2a 100644 --- a/docs/1.0-dev/_modules/evennia/server/initial_setup.html +++ b/docs/1.0-dev/_modules/evennia/server/initial_setup.html @@ -299,7 +299,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/inputfuncs.html b/docs/1.0-dev/_modules/evennia/server/inputfuncs.html index 78cd507c5e..430d9a10ed 100644 --- a/docs/1.0-dev/_modules/evennia/server/inputfuncs.html +++ b/docs/1.0-dev/_modules/evennia/server/inputfuncs.html @@ -730,7 +730,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/manager.html b/docs/1.0-dev/_modules/evennia/server/manager.html index 0da405361a..3cd74fcba4 100644 --- a/docs/1.0-dev/_modules/evennia/server/manager.html +++ b/docs/1.0-dev/_modules/evennia/server/manager.html @@ -129,7 +129,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/models.html b/docs/1.0-dev/_modules/evennia/server/models.html index 391e8ef4f1..06732c7edd 100644 --- a/docs/1.0-dev/_modules/evennia/server/models.html +++ b/docs/1.0-dev/_modules/evennia/server/models.html @@ -209,7 +209,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/portal/amp.html b/docs/1.0-dev/_modules/evennia/server/portal/amp.html index 2e80ceb9f9..fcd11af2f1 100644 --- a/docs/1.0-dev/_modules/evennia/server/portal/amp.html +++ b/docs/1.0-dev/_modules/evennia/server/portal/amp.html @@ -624,7 +624,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/portal/amp_server.html b/docs/1.0-dev/_modules/evennia/server/portal/amp_server.html index 4c80b8caaf..3bb97698b0 100644 --- a/docs/1.0-dev/_modules/evennia/server/portal/amp_server.html +++ b/docs/1.0-dev/_modules/evennia/server/portal/amp_server.html @@ -561,7 +561,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/portal/grapevine.html b/docs/1.0-dev/_modules/evennia/server/portal/grapevine.html index c473c19df6..5f216972f9 100644 --- a/docs/1.0-dev/_modules/evennia/server/portal/grapevine.html +++ b/docs/1.0-dev/_modules/evennia/server/portal/grapevine.html @@ -435,7 +435,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/portal/irc.html b/docs/1.0-dev/_modules/evennia/server/portal/irc.html index 083a29e861..a56cdc7cad 100644 --- a/docs/1.0-dev/_modules/evennia/server/portal/irc.html +++ b/docs/1.0-dev/_modules/evennia/server/portal/irc.html @@ -554,7 +554,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/portal/mccp.html b/docs/1.0-dev/_modules/evennia/server/portal/mccp.html index 57e55e0a40..cad30bc41b 100644 --- a/docs/1.0-dev/_modules/evennia/server/portal/mccp.html +++ b/docs/1.0-dev/_modules/evennia/server/portal/mccp.html @@ -165,7 +165,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/portal/mssp.html b/docs/1.0-dev/_modules/evennia/server/portal/mssp.html index bded14f3a9..280594f4e4 100644 --- a/docs/1.0-dev/_modules/evennia/server/portal/mssp.html +++ b/docs/1.0-dev/_modules/evennia/server/portal/mssp.html @@ -210,7 +210,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/portal/mxp.html b/docs/1.0-dev/_modules/evennia/server/portal/mxp.html index 93802b541d..ab7b4aa1ec 100644 --- a/docs/1.0-dev/_modules/evennia/server/portal/mxp.html +++ b/docs/1.0-dev/_modules/evennia/server/portal/mxp.html @@ -167,7 +167,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/portal/naws.html b/docs/1.0-dev/_modules/evennia/server/portal/naws.html index f7cb382cd5..d7093d5f5c 100644 --- a/docs/1.0-dev/_modules/evennia/server/portal/naws.html +++ b/docs/1.0-dev/_modules/evennia/server/portal/naws.html @@ -160,7 +160,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/portal/portal.html b/docs/1.0-dev/_modules/evennia/server/portal/portal.html index b6c5a1e7ff..4f6a368187 100644 --- a/docs/1.0-dev/_modules/evennia/server/portal/portal.html +++ b/docs/1.0-dev/_modules/evennia/server/portal/portal.html @@ -521,7 +521,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/portal/portalsessionhandler.html b/docs/1.0-dev/_modules/evennia/server/portal/portalsessionhandler.html index 3921d35f80..cf4c98d769 100644 --- a/docs/1.0-dev/_modules/evennia/server/portal/portalsessionhandler.html +++ b/docs/1.0-dev/_modules/evennia/server/portal/portalsessionhandler.html @@ -563,7 +563,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/portal/rss.html b/docs/1.0-dev/_modules/evennia/server/portal/rss.html index 5c6ab46fc9..9eb3087705 100644 --- a/docs/1.0-dev/_modules/evennia/server/portal/rss.html +++ b/docs/1.0-dev/_modules/evennia/server/portal/rss.html @@ -240,7 +240,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/portal/ssh.html b/docs/1.0-dev/_modules/evennia/server/portal/ssh.html index f1800d1a69..cc3d220dc1 100644 --- a/docs/1.0-dev/_modules/evennia/server/portal/ssh.html +++ b/docs/1.0-dev/_modules/evennia/server/portal/ssh.html @@ -604,7 +604,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/portal/ssl.html b/docs/1.0-dev/_modules/evennia/server/portal/ssl.html index 8b46735b19..12ec2da824 100644 --- a/docs/1.0-dev/_modules/evennia/server/portal/ssl.html +++ b/docs/1.0-dev/_modules/evennia/server/portal/ssl.html @@ -196,7 +196,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/portal/suppress_ga.html b/docs/1.0-dev/_modules/evennia/server/portal/suppress_ga.html index 2ef3988296..43c65841e7 100644 --- a/docs/1.0-dev/_modules/evennia/server/portal/suppress_ga.html +++ b/docs/1.0-dev/_modules/evennia/server/portal/suppress_ga.html @@ -144,7 +144,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/portal/telnet.html b/docs/1.0-dev/_modules/evennia/server/portal/telnet.html index 8c5bb88104..d2dc7dee45 100644 --- a/docs/1.0-dev/_modules/evennia/server/portal/telnet.html +++ b/docs/1.0-dev/_modules/evennia/server/portal/telnet.html @@ -586,7 +586,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/portal/telnet_oob.html b/docs/1.0-dev/_modules/evennia/server/portal/telnet_oob.html index e0331b0f74..6104bf5ea8 100644 --- a/docs/1.0-dev/_modules/evennia/server/portal/telnet_oob.html +++ b/docs/1.0-dev/_modules/evennia/server/portal/telnet_oob.html @@ -523,7 +523,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/portal/telnet_ssl.html b/docs/1.0-dev/_modules/evennia/server/portal/telnet_ssl.html index af6ca5fd0a..92beb8ce5e 100644 --- a/docs/1.0-dev/_modules/evennia/server/portal/telnet_ssl.html +++ b/docs/1.0-dev/_modules/evennia/server/portal/telnet_ssl.html @@ -228,7 +228,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/portal/tests.html b/docs/1.0-dev/_modules/evennia/server/portal/tests.html index 3667f1f3a1..1052dc4cff 100644 --- a/docs/1.0-dev/_modules/evennia/server/portal/tests.html +++ b/docs/1.0-dev/_modules/evennia/server/portal/tests.html @@ -397,7 +397,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/portal/ttype.html b/docs/1.0-dev/_modules/evennia/server/portal/ttype.html index aa2d7a229f..5129e8d66e 100644 --- a/docs/1.0-dev/_modules/evennia/server/portal/ttype.html +++ b/docs/1.0-dev/_modules/evennia/server/portal/ttype.html @@ -263,7 +263,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/portal/webclient.html b/docs/1.0-dev/_modules/evennia/server/portal/webclient.html index fa56393ee3..cf4d8fc11a 100644 --- a/docs/1.0-dev/_modules/evennia/server/portal/webclient.html +++ b/docs/1.0-dev/_modules/evennia/server/portal/webclient.html @@ -392,7 +392,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/portal/webclient_ajax.html b/docs/1.0-dev/_modules/evennia/server/portal/webclient_ajax.html index 607e3b7969..27aa29432f 100644 --- a/docs/1.0-dev/_modules/evennia/server/portal/webclient_ajax.html +++ b/docs/1.0-dev/_modules/evennia/server/portal/webclient_ajax.html @@ -567,7 +567,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/profiling/dummyrunner.html b/docs/1.0-dev/_modules/evennia/server/profiling/dummyrunner.html index 8e5d5a4cde..cf5c5083c4 100644 --- a/docs/1.0-dev/_modules/evennia/server/profiling/dummyrunner.html +++ b/docs/1.0-dev/_modules/evennia/server/profiling/dummyrunner.html @@ -702,7 +702,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/profiling/dummyrunner_settings.html b/docs/1.0-dev/_modules/evennia/server/profiling/dummyrunner_settings.html index 2388d4c0e0..c370a3c701 100644 --- a/docs/1.0-dev/_modules/evennia/server/profiling/dummyrunner_settings.html +++ b/docs/1.0-dev/_modules/evennia/server/profiling/dummyrunner_settings.html @@ -413,7 +413,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/profiling/memplot.html b/docs/1.0-dev/_modules/evennia/server/profiling/memplot.html index 1c861b060e..8c3b0c6767 100644 --- a/docs/1.0-dev/_modules/evennia/server/profiling/memplot.html +++ b/docs/1.0-dev/_modules/evennia/server/profiling/memplot.html @@ -192,7 +192,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/profiling/test_queries.html b/docs/1.0-dev/_modules/evennia/server/profiling/test_queries.html index 566b1f3c88..81ea7cbe34 100644 --- a/docs/1.0-dev/_modules/evennia/server/profiling/test_queries.html +++ b/docs/1.0-dev/_modules/evennia/server/profiling/test_queries.html @@ -119,7 +119,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/profiling/tests.html b/docs/1.0-dev/_modules/evennia/server/profiling/tests.html index 5919a101f5..4ef5df60fd 100644 --- a/docs/1.0-dev/_modules/evennia/server/profiling/tests.html +++ b/docs/1.0-dev/_modules/evennia/server/profiling/tests.html @@ -235,7 +235,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/profiling/timetrace.html b/docs/1.0-dev/_modules/evennia/server/profiling/timetrace.html index 2302150ed8..af58c37864 100644 --- a/docs/1.0-dev/_modules/evennia/server/profiling/timetrace.html +++ b/docs/1.0-dev/_modules/evennia/server/profiling/timetrace.html @@ -116,7 +116,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/server.html b/docs/1.0-dev/_modules/evennia/server/server.html index 587ffb7e7d..18afd88c05 100644 --- a/docs/1.0-dev/_modules/evennia/server/server.html +++ b/docs/1.0-dev/_modules/evennia/server/server.html @@ -828,7 +828,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/serversession.html b/docs/1.0-dev/_modules/evennia/server/serversession.html index 1e5c390735..c0510a7db4 100644 --- a/docs/1.0-dev/_modules/evennia/server/serversession.html +++ b/docs/1.0-dev/_modules/evennia/server/serversession.html @@ -513,7 +513,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/session.html b/docs/1.0-dev/_modules/evennia/server/session.html index 0af25e407c..526142f687 100644 --- a/docs/1.0-dev/_modules/evennia/server/session.html +++ b/docs/1.0-dev/_modules/evennia/server/session.html @@ -251,7 +251,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/sessionhandler.html b/docs/1.0-dev/_modules/evennia/server/sessionhandler.html index ad816c1406..b16acfecee 100644 --- a/docs/1.0-dev/_modules/evennia/server/sessionhandler.html +++ b/docs/1.0-dev/_modules/evennia/server/sessionhandler.html @@ -944,7 +944,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/throttle.html b/docs/1.0-dev/_modules/evennia/server/throttle.html index 8a6b0dbea2..e4fb0744cf 100644 --- a/docs/1.0-dev/_modules/evennia/server/throttle.html +++ b/docs/1.0-dev/_modules/evennia/server/throttle.html @@ -299,7 +299,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/validators.html b/docs/1.0-dev/_modules/evennia/server/validators.html index e0717dd709..00d21bf4ef 100644 --- a/docs/1.0-dev/_modules/evennia/server/validators.html +++ b/docs/1.0-dev/_modules/evennia/server/validators.html @@ -166,7 +166,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/server/webserver.html b/docs/1.0-dev/_modules/evennia/server/webserver.html index 3df4b77b2c..212b0a6bbb 100644 --- a/docs/1.0-dev/_modules/evennia/server/webserver.html +++ b/docs/1.0-dev/_modules/evennia/server/webserver.html @@ -376,7 +376,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/typeclasses/attributes.html b/docs/1.0-dev/_modules/evennia/typeclasses/attributes.html index 874aeab5ec..acdcd56c9b 100644 --- a/docs/1.0-dev/_modules/evennia/typeclasses/attributes.html +++ b/docs/1.0-dev/_modules/evennia/typeclasses/attributes.html @@ -1517,7 +1517,7 @@ # for the shell pattern we make sure we have matching $N on both sides pattern_args = [match.group(1) for match in _RE_NICK_RAW_ARG.finditer(pattern)] replacement_args = [ - match.group(1) for match in _RE_NICK_RAW_ARG.finditer(replacement)] + match.group(1) for match in _RE_NICK_RAW_ARG.finditer(replacement)] if set(pattern_args) != set(replacement_args): # We don't have the same amount of argN/$N tags in input/output. raise NickTemplateInvalid("Nicks: Both in/out-templates must contain the same $N tags.") @@ -1759,7 +1759,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/typeclasses/managers.html b/docs/1.0-dev/_modules/evennia/typeclasses/managers.html index 774d30e813..c841f3ba5b 100644 --- a/docs/1.0-dev/_modules/evennia/typeclasses/managers.html +++ b/docs/1.0-dev/_modules/evennia/typeclasses/managers.html @@ -935,7 +935,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/typeclasses/models.html b/docs/1.0-dev/_modules/evennia/typeclasses/models.html index ae8b119747..9f2acbf03a 100644 --- a/docs/1.0-dev/_modules/evennia/typeclasses/models.html +++ b/docs/1.0-dev/_modules/evennia/typeclasses/models.html @@ -1141,7 +1141,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/typeclasses/tags.html b/docs/1.0-dev/_modules/evennia/typeclasses/tags.html index 15f0271980..60b783b31d 100644 --- a/docs/1.0-dev/_modules/evennia/typeclasses/tags.html +++ b/docs/1.0-dev/_modules/evennia/typeclasses/tags.html @@ -659,7 +659,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/ansi.html b/docs/1.0-dev/_modules/evennia/utils/ansi.html index 18985bfbe9..01436a3c26 100644 --- a/docs/1.0-dev/_modules/evennia/utils/ansi.html +++ b/docs/1.0-dev/_modules/evennia/utils/ansi.html @@ -1579,7 +1579,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/batchprocessors.html b/docs/1.0-dev/_modules/evennia/utils/batchprocessors.html index b420662581..0d0180c6f9 100644 --- a/docs/1.0-dev/_modules/evennia/utils/batchprocessors.html +++ b/docs/1.0-dev/_modules/evennia/utils/batchprocessors.html @@ -515,7 +515,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/containers.html b/docs/1.0-dev/_modules/evennia/utils/containers.html index 797418eb7f..ff5cb2a551 100644 --- a/docs/1.0-dev/_modules/evennia/utils/containers.html +++ b/docs/1.0-dev/_modules/evennia/utils/containers.html @@ -322,7 +322,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/dbserialize.html b/docs/1.0-dev/_modules/evennia/utils/dbserialize.html index a5af0733d3..c7dfa684f3 100644 --- a/docs/1.0-dev/_modules/evennia/utils/dbserialize.html +++ b/docs/1.0-dev/_modules/evennia/utils/dbserialize.html @@ -836,7 +836,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/eveditor.html b/docs/1.0-dev/_modules/evennia/utils/eveditor.html index e4b8b3426f..e8f8698c3b 100644 --- a/docs/1.0-dev/_modules/evennia/utils/eveditor.html +++ b/docs/1.0-dev/_modules/evennia/utils/eveditor.html @@ -1219,7 +1219,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/evform.html b/docs/1.0-dev/_modules/evennia/utils/evform.html index 635ea72a66..9155ad1c43 100644 --- a/docs/1.0-dev/_modules/evennia/utils/evform.html +++ b/docs/1.0-dev/_modules/evennia/utils/evform.html @@ -544,7 +544,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/evmenu.html b/docs/1.0-dev/_modules/evennia/utils/evmenu.html index 8cf9101c50..50ff32c1da 100644 --- a/docs/1.0-dev/_modules/evennia/utils/evmenu.html +++ b/docs/1.0-dev/_modules/evennia/utils/evmenu.html @@ -2201,7 +2201,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/evmore.html b/docs/1.0-dev/_modules/evennia/utils/evmore.html index 8bf596b3ff..753e3c0738 100644 --- a/docs/1.0-dev/_modules/evennia/utils/evmore.html +++ b/docs/1.0-dev/_modules/evennia/utils/evmore.html @@ -629,7 +629,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/evtable.html b/docs/1.0-dev/_modules/evennia/utils/evtable.html index 87755d61ee..56b2006100 100644 --- a/docs/1.0-dev/_modules/evennia/utils/evtable.html +++ b/docs/1.0-dev/_modules/evennia/utils/evtable.html @@ -1825,7 +1825,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/funcparser.html b/docs/1.0-dev/_modules/evennia/utils/funcparser.html index 82a32a82bc..7b0df23f6d 100644 --- a/docs/1.0-dev/_modules/evennia/utils/funcparser.html +++ b/docs/1.0-dev/_modules/evennia/utils/funcparser.html @@ -1404,7 +1404,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/gametime.html b/docs/1.0-dev/_modules/evennia/utils/gametime.html index 4014341dfb..ed32c53405 100644 --- a/docs/1.0-dev/_modules/evennia/utils/gametime.html +++ b/docs/1.0-dev/_modules/evennia/utils/gametime.html @@ -361,7 +361,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/idmapper/manager.html b/docs/1.0-dev/_modules/evennia/utils/idmapper/manager.html index a828712ad7..a50e0e1111 100644 --- a/docs/1.0-dev/_modules/evennia/utils/idmapper/manager.html +++ b/docs/1.0-dev/_modules/evennia/utils/idmapper/manager.html @@ -109,7 +109,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/idmapper/models.html b/docs/1.0-dev/_modules/evennia/utils/idmapper/models.html index 407dd60a6e..3f59623592 100644 --- a/docs/1.0-dev/_modules/evennia/utils/idmapper/models.html +++ b/docs/1.0-dev/_modules/evennia/utils/idmapper/models.html @@ -753,7 +753,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/idmapper/tests.html b/docs/1.0-dev/_modules/evennia/utils/idmapper/tests.html index 5b34a7b3b0..4bc30fa831 100644 --- a/docs/1.0-dev/_modules/evennia/utils/idmapper/tests.html +++ b/docs/1.0-dev/_modules/evennia/utils/idmapper/tests.html @@ -154,7 +154,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/logger.html b/docs/1.0-dev/_modules/evennia/utils/logger.html index 7830039086..3e49b72e2d 100644 --- a/docs/1.0-dev/_modules/evennia/utils/logger.html +++ b/docs/1.0-dev/_modules/evennia/utils/logger.html @@ -672,7 +672,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/optionclasses.html b/docs/1.0-dev/_modules/evennia/utils/optionclasses.html index eb7eef4399..bca2f103af 100644 --- a/docs/1.0-dev/_modules/evennia/utils/optionclasses.html +++ b/docs/1.0-dev/_modules/evennia/utils/optionclasses.html @@ -399,7 +399,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/optionhandler.html b/docs/1.0-dev/_modules/evennia/utils/optionhandler.html index 8ccc4bca0d..8379eb7f70 100644 --- a/docs/1.0-dev/_modules/evennia/utils/optionhandler.html +++ b/docs/1.0-dev/_modules/evennia/utils/optionhandler.html @@ -260,7 +260,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/picklefield.html b/docs/1.0-dev/_modules/evennia/utils/picklefield.html index 2b7e6c6963..c88aa323d7 100644 --- a/docs/1.0-dev/_modules/evennia/utils/picklefield.html +++ b/docs/1.0-dev/_modules/evennia/utils/picklefield.html @@ -378,7 +378,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/search.html b/docs/1.0-dev/_modules/evennia/utils/search.html index f9c5a2f982..15357a12e1 100644 --- a/docs/1.0-dev/_modules/evennia/utils/search.html +++ b/docs/1.0-dev/_modules/evennia/utils/search.html @@ -440,7 +440,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/test_resources.html b/docs/1.0-dev/_modules/evennia/utils/test_resources.html index cca0ce77de..c60865413b 100644 --- a/docs/1.0-dev/_modules/evennia/utils/test_resources.html +++ b/docs/1.0-dev/_modules/evennia/utils/test_resources.html @@ -664,7 +664,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/text2html.html b/docs/1.0-dev/_modules/evennia/utils/text2html.html index 7a5131de08..3c938e8b94 100644 --- a/docs/1.0-dev/_modules/evennia/utils/text2html.html +++ b/docs/1.0-dev/_modules/evennia/utils/text2html.html @@ -461,7 +461,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/utils.html b/docs/1.0-dev/_modules/evennia/utils/utils.html index 9259dffabe..bd47fb9a21 100644 --- a/docs/1.0-dev/_modules/evennia/utils/utils.html +++ b/docs/1.0-dev/_modules/evennia/utils/utils.html @@ -2756,7 +2756,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/validatorfuncs.html b/docs/1.0-dev/_modules/evennia/utils/validatorfuncs.html index 994c0996f1..2b879da6f6 100644 --- a/docs/1.0-dev/_modules/evennia/utils/validatorfuncs.html +++ b/docs/1.0-dev/_modules/evennia/utils/validatorfuncs.html @@ -334,7 +334,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/conjugate.html b/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/conjugate.html index c810f62ad4..5ed7ad511d 100644 --- a/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/conjugate.html +++ b/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/conjugate.html @@ -463,7 +463,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/pronouns.html b/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/pronouns.html index 8d9b0545ca..a4ce798791 100644 --- a/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/pronouns.html +++ b/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/pronouns.html @@ -636,7 +636,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/tests.html b/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/tests.html index 0f11ae8760..7347010b33 100644 --- a/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/tests.html +++ b/docs/1.0-dev/_modules/evennia/utils/verb_conjugation/tests.html @@ -363,7 +363,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/admin/accounts.html b/docs/1.0-dev/_modules/evennia/web/admin/accounts.html index 3b0dc112d2..35af952dae 100644 --- a/docs/1.0-dev/_modules/evennia/web/admin/accounts.html +++ b/docs/1.0-dev/_modules/evennia/web/admin/accounts.html @@ -489,7 +489,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/admin/attributes.html b/docs/1.0-dev/_modules/evennia/web/admin/attributes.html index 2ba696a825..bffd320d4c 100644 --- a/docs/1.0-dev/_modules/evennia/web/admin/attributes.html +++ b/docs/1.0-dev/_modules/evennia/web/admin/attributes.html @@ -283,7 +283,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/admin/comms.html b/docs/1.0-dev/_modules/evennia/web/admin/comms.html index 5d43006d30..242e8ee2fa 100644 --- a/docs/1.0-dev/_modules/evennia/web/admin/comms.html +++ b/docs/1.0-dev/_modules/evennia/web/admin/comms.html @@ -360,7 +360,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/admin/frontpage.html b/docs/1.0-dev/_modules/evennia/web/admin/frontpage.html index 0a67319f82..91c0f36ae6 100644 --- a/docs/1.0-dev/_modules/evennia/web/admin/frontpage.html +++ b/docs/1.0-dev/_modules/evennia/web/admin/frontpage.html @@ -103,7 +103,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/admin/help.html b/docs/1.0-dev/_modules/evennia/web/admin/help.html index 574adec407..b99f7e47e3 100644 --- a/docs/1.0-dev/_modules/evennia/web/admin/help.html +++ b/docs/1.0-dev/_modules/evennia/web/admin/help.html @@ -139,7 +139,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/admin/objects.html b/docs/1.0-dev/_modules/evennia/web/admin/objects.html index b1f266c64f..c255416d16 100644 --- a/docs/1.0-dev/_modules/evennia/web/admin/objects.html +++ b/docs/1.0-dev/_modules/evennia/web/admin/objects.html @@ -427,7 +427,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/admin/scripts.html b/docs/1.0-dev/_modules/evennia/web/admin/scripts.html index 0d3d7a0d31..374175e48b 100644 --- a/docs/1.0-dev/_modules/evennia/web/admin/scripts.html +++ b/docs/1.0-dev/_modules/evennia/web/admin/scripts.html @@ -233,7 +233,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/admin/server.html b/docs/1.0-dev/_modules/evennia/web/admin/server.html index 1a32f836da..e47c0b1d77 100644 --- a/docs/1.0-dev/_modules/evennia/web/admin/server.html +++ b/docs/1.0-dev/_modules/evennia/web/admin/server.html @@ -101,7 +101,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/admin/tags.html b/docs/1.0-dev/_modules/evennia/web/admin/tags.html index 77384b5024..0b1097bb76 100644 --- a/docs/1.0-dev/_modules/evennia/web/admin/tags.html +++ b/docs/1.0-dev/_modules/evennia/web/admin/tags.html @@ -310,7 +310,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/admin/utils.html b/docs/1.0-dev/_modules/evennia/web/admin/utils.html index d3d272e3f6..dd7d757e27 100644 --- a/docs/1.0-dev/_modules/evennia/web/admin/utils.html +++ b/docs/1.0-dev/_modules/evennia/web/admin/utils.html @@ -155,7 +155,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/api/filters.html b/docs/1.0-dev/_modules/evennia/web/api/filters.html index 57ef597a54..167766adea 100644 --- a/docs/1.0-dev/_modules/evennia/web/api/filters.html +++ b/docs/1.0-dev/_modules/evennia/web/api/filters.html @@ -223,7 +223,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/api/permissions.html b/docs/1.0-dev/_modules/evennia/web/api/permissions.html index a05e90bb32..85de05541f 100644 --- a/docs/1.0-dev/_modules/evennia/web/api/permissions.html +++ b/docs/1.0-dev/_modules/evennia/web/api/permissions.html @@ -169,7 +169,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/api/root.html b/docs/1.0-dev/_modules/evennia/web/api/root.html index ed45989d92..09088fb7ce 100644 --- a/docs/1.0-dev/_modules/evennia/web/api/root.html +++ b/docs/1.0-dev/_modules/evennia/web/api/root.html @@ -93,7 +93,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/api/serializers.html b/docs/1.0-dev/_modules/evennia/web/api/serializers.html index 6d0a372456..de553b7426 100644 --- a/docs/1.0-dev/_modules/evennia/web/api/serializers.html +++ b/docs/1.0-dev/_modules/evennia/web/api/serializers.html @@ -412,7 +412,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/api/tests.html b/docs/1.0-dev/_modules/evennia/web/api/tests.html index df16394496..01e5b6ae78 100644 --- a/docs/1.0-dev/_modules/evennia/web/api/tests.html +++ b/docs/1.0-dev/_modules/evennia/web/api/tests.html @@ -255,7 +255,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/api/views.html b/docs/1.0-dev/_modules/evennia/web/api/views.html index 0c42b6a42b..c0be8ae8a7 100644 --- a/docs/1.0-dev/_modules/evennia/web/api/views.html +++ b/docs/1.0-dev/_modules/evennia/web/api/views.html @@ -249,7 +249,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/templatetags/addclass.html b/docs/1.0-dev/_modules/evennia/web/templatetags/addclass.html index 71bacff198..259bf7e4a1 100644 --- a/docs/1.0-dev/_modules/evennia/web/templatetags/addclass.html +++ b/docs/1.0-dev/_modules/evennia/web/templatetags/addclass.html @@ -93,7 +93,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/utils/adminsite.html b/docs/1.0-dev/_modules/evennia/web/utils/adminsite.html index 61dd3394ea..266864ed14 100644 --- a/docs/1.0-dev/_modules/evennia/web/utils/adminsite.html +++ b/docs/1.0-dev/_modules/evennia/web/utils/adminsite.html @@ -113,7 +113,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/utils/backends.html b/docs/1.0-dev/_modules/evennia/web/utils/backends.html index 9a6be23304..ca9f158bf7 100644 --- a/docs/1.0-dev/_modules/evennia/web/utils/backends.html +++ b/docs/1.0-dev/_modules/evennia/web/utils/backends.html @@ -119,7 +119,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/utils/general_context.html b/docs/1.0-dev/_modules/evennia/web/utils/general_context.html index 325b551718..38ab5f21a3 100644 --- a/docs/1.0-dev/_modules/evennia/web/utils/general_context.html +++ b/docs/1.0-dev/_modules/evennia/web/utils/general_context.html @@ -207,7 +207,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/utils/middleware.html b/docs/1.0-dev/_modules/evennia/web/utils/middleware.html index 49539c1d3b..0a030c16ca 100644 --- a/docs/1.0-dev/_modules/evennia/web/utils/middleware.html +++ b/docs/1.0-dev/_modules/evennia/web/utils/middleware.html @@ -148,7 +148,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/utils/tests.html b/docs/1.0-dev/_modules/evennia/web/utils/tests.html index 9aee470306..12c102b810 100644 --- a/docs/1.0-dev/_modules/evennia/web/utils/tests.html +++ b/docs/1.0-dev/_modules/evennia/web/utils/tests.html @@ -126,7 +126,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/webclient/views.html b/docs/1.0-dev/_modules/evennia/web/webclient/views.html index b9a790ed3a..13cd4c95fe 100644 --- a/docs/1.0-dev/_modules/evennia/web/webclient/views.html +++ b/docs/1.0-dev/_modules/evennia/web/webclient/views.html @@ -106,7 +106,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/website/forms.html b/docs/1.0-dev/_modules/evennia/web/website/forms.html index 27bec760a7..765fab16e5 100644 --- a/docs/1.0-dev/_modules/evennia/web/website/forms.html +++ b/docs/1.0-dev/_modules/evennia/web/website/forms.html @@ -251,7 +251,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/website/tests.html b/docs/1.0-dev/_modules/evennia/web/website/tests.html index bf139dfe96..7f0210011d 100644 --- a/docs/1.0-dev/_modules/evennia/web/website/tests.html +++ b/docs/1.0-dev/_modules/evennia/web/website/tests.html @@ -443,7 +443,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/website/views/accounts.html b/docs/1.0-dev/_modules/evennia/web/website/views/accounts.html index 5e0e78416e..20ec4bea6f 100644 --- a/docs/1.0-dev/_modules/evennia/web/website/views/accounts.html +++ b/docs/1.0-dev/_modules/evennia/web/website/views/accounts.html @@ -152,7 +152,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/website/views/channels.html b/docs/1.0-dev/_modules/evennia/web/website/views/channels.html index 0b4eb11a25..e65a01dd87 100644 --- a/docs/1.0-dev/_modules/evennia/web/website/views/channels.html +++ b/docs/1.0-dev/_modules/evennia/web/website/views/channels.html @@ -255,7 +255,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/website/views/characters.html b/docs/1.0-dev/_modules/evennia/web/website/views/characters.html index a17497d6dc..fc8c8757fa 100644 --- a/docs/1.0-dev/_modules/evennia/web/website/views/characters.html +++ b/docs/1.0-dev/_modules/evennia/web/website/views/characters.html @@ -330,7 +330,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/website/views/errors.html b/docs/1.0-dev/_modules/evennia/web/website/views/errors.html index 55192b1db8..237f17c345 100644 --- a/docs/1.0-dev/_modules/evennia/web/website/views/errors.html +++ b/docs/1.0-dev/_modules/evennia/web/website/views/errors.html @@ -92,7 +92,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/website/views/help.html b/docs/1.0-dev/_modules/evennia/web/website/views/help.html index 405c0785f6..24abeed4c7 100644 --- a/docs/1.0-dev/_modules/evennia/web/website/views/help.html +++ b/docs/1.0-dev/_modules/evennia/web/website/views/help.html @@ -409,7 +409,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/website/views/index.html b/docs/1.0-dev/_modules/evennia/web/website/views/index.html index a5a8b4143a..7bdd9704be 100644 --- a/docs/1.0-dev/_modules/evennia/web/website/views/index.html +++ b/docs/1.0-dev/_modules/evennia/web/website/views/index.html @@ -190,7 +190,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/website/views/mixins.html b/docs/1.0-dev/_modules/evennia/web/website/views/mixins.html index 959345011a..b6b62b4aff 100644 --- a/docs/1.0-dev/_modules/evennia/web/website/views/mixins.html +++ b/docs/1.0-dev/_modules/evennia/web/website/views/mixins.html @@ -167,7 +167,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/evennia/web/website/views/objects.html b/docs/1.0-dev/_modules/evennia/web/website/views/objects.html index 32ff17c53f..07ebf4b405 100644 --- a/docs/1.0-dev/_modules/evennia/web/website/views/objects.html +++ b/docs/1.0-dev/_modules/evennia/web/website/views/objects.html @@ -344,7 +344,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/functools.html b/docs/1.0-dev/_modules/functools.html index 50e81b201e..ea022e90a0 100644 --- a/docs/1.0-dev/_modules/functools.html +++ b/docs/1.0-dev/_modules/functools.html @@ -54,9 +54,12 @@ __all__ = ['update_wrapper', 'wraps', 'WRAPPER_ASSIGNMENTS', 'WRAPPER_UPDATES', 'total_ordering', 'cmp_to_key', 'lru_cache', 'reduce', 'partial', - 'partialmethod', 'singledispatch', 'singledispatchmethod', - "cached_property"] + 'partialmethod', 'singledispatch'] +try: + from _functools import reduce +except ImportError: + pass from abc import get_cache_token from collections import namedtuple # import types, weakref # Deferred to single_dispatch() @@ -266,45 +269,6 @@ pass -################################################################################ -### reduce() sequence to a single item -################################################################################ - -_initial_missing = object() - -def reduce(function, sequence, initial=_initial_missing): - """ - reduce(function, sequence[, initial]) -> value - - Apply a function of two arguments cumulatively to the items of a sequence, - from left to right, so as to reduce the sequence to a single value. - For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates - ((((1+2)+3)+4)+5). If initial is present, it is placed before the items - of the sequence in the calculation, and serves as a default when the - sequence is empty. - """ - - it = iter(sequence) - - if initial is _initial_missing: - try: - value = next(it) - except StopIteration: - raise TypeError("reduce() of empty sequence with no initial value") from None - else: - value = initial - - for element in it: - value = function(value, element) - - return value - -try: - from _functools import reduce -except ImportError: - pass - - ################################################################################ ### partial() argument application ################################################################################ @@ -317,13 +281,22 @@ __slots__ = "func", "args", "keywords", "__dict__", "__weakref__" - def __new__(cls, func, /, *args, **keywords): + def __new__(*args, **keywords): + if not args: + raise TypeError("descriptor '__new__' of partial needs an argument") + if len(args) < 2: + raise TypeError("type 'partial' takes at least one argument") + cls, func, *args = args if not callable(func): raise TypeError("the first argument must be callable") + args = tuple(args) if hasattr(func, "func"): args = func.args + args - keywords = {**func.keywords, **keywords} + tmpkw = func.keywords.copy() + tmpkw.update(keywords) + keywords = tmpkw + del tmpkw func = func.func self = super(partial, cls).__new__(cls) @@ -333,9 +306,13 @@ self.keywords = keywords return self - def __call__(self, /, *args, **keywords): - keywords = {**self.keywords, **keywords} - return self.func(*self.args, *args, **keywords) + def __call__(*args, **keywords): + if not args: + raise TypeError("descriptor '__call__' of partial needs an argument") + self, *args = args + newkeywords = self.keywords.copy() + newkeywords.update(keywords) + return self.func(*self.args, *args, **newkeywords) @recursive_repr() def __repr__(self): @@ -398,9 +375,6 @@ elif 'func' in keywords: func = keywords.pop('func') self, *args = args - import warnings - warnings.warn("Passing 'func' as keyword argument is deprecated", - DeprecationWarning, stacklevel=2) else: raise TypeError("type 'partialmethod' takes at least one argument, " "got %d" % (len(args)-1)) @@ -418,12 +392,12 @@ # it's also more efficient since only one function will be called self.func = func.func self.args = func.args + args - self.keywords = {**func.keywords, **keywords} + self.keywords = func.keywords.copy() + self.keywords.update(keywords) else: self.func = func self.args = args self.keywords = keywords - __init__.__text_signature__ = '($self, func, /, *args, **keywords)' def __repr__(self): args = ", ".join(map(repr, self.args)) @@ -437,14 +411,17 @@ keywords=keywords) def _make_unbound_method(self): - def _method(cls_or_self, /, *args, **keywords): - keywords = {**self.keywords, **keywords} - return self.func(cls_or_self, *self.args, *args, **keywords) + def _method(*args, **keywords): + call_keywords = self.keywords.copy() + call_keywords.update(keywords) + cls_or_self, *rest = args + call_args = (cls_or_self,) + self.args + tuple(rest) + return self.func(*call_args, **call_keywords) _method.__isabstractmethod__ = self.__isabstractmethod__ _method._partialmethod = self return _method - def __get__(self, obj, cls=None): + def __get__(self, obj, cls): get = getattr(self.func, "__get__", None) result = None if get is not None: @@ -467,12 +444,6 @@ def __isabstractmethod__(self): return getattr(self.func, "__isabstractmethod__", False) -# Helper functions - -def _unwrap_partial(func): - while isinstance(func, partial): - func = func.func - return func ################################################################################ ### LRU Cache function decorator @@ -552,18 +523,14 @@ # The internals of the lru_cache are encapsulated for thread safety and # to allow the implementation to change (including a possible C version). + # Early detection of an erroneous call to @lru_cache without any arguments + # resulting in the inner function being passed to maxsize instead of an + # integer or None. Negative maxsize is treated as 0. if isinstance(maxsize, int): - # Negative maxsize is treated as 0 if maxsize < 0: maxsize = 0 - elif callable(maxsize) and isinstance(typed, bool): - # The user_function was passed in directly via the maxsize argument - user_function, maxsize = maxsize, 128 - wrapper = _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo) - return update_wrapper(wrapper, user_function) elif maxsize is not None: - raise TypeError( - 'Expected first argument to be an integer, a callable, or None') + raise TypeError('Expected maxsize to be an integer or None') def decorating_function(user_function): wrapper = _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo) @@ -899,11 +866,9 @@ # only import typing if annotation parsing is necessary from typing import get_type_hints argname, cls = next(iter(get_type_hints(func).items())) - if not isinstance(cls, type): - raise TypeError( - f"Invalid annotation for {argname!r}. " - f"{cls!r} is not a class." - ) + assert isinstance(cls, type), ( + f"Invalid annotation for {argname!r}. {cls!r} is not a class." + ) registry[cls] = func if cache_token is None and hasattr(cls, '__abstractmethods__'): cache_token = get_cache_token() @@ -925,98 +890,6 @@ wrapper._clear_cache = dispatch_cache.clear update_wrapper(wrapper, func) return wrapper - - -# Descriptor version -class singledispatchmethod: - """Single-dispatch generic method descriptor. - - Supports wrapping existing descriptors and handles non-descriptor - callables as instance methods. - """ - - def __init__(self, func): - if not callable(func) and not hasattr(func, "__get__"): - raise TypeError(f"{func!r} is not callable or a descriptor") - - self.dispatcher = singledispatch(func) - self.func = func - - def register(self, cls, method=None): - """generic_method.register(cls, func) -> func - - Registers a new implementation for the given *cls* on a *generic_method*. - """ - return self.dispatcher.register(cls, func=method) - - def __get__(self, obj, cls=None): - def _method(*args, **kwargs): - method = self.dispatcher.dispatch(args[0].__class__) - return method.__get__(obj, cls)(*args, **kwargs) - - _method.__isabstractmethod__ = self.__isabstractmethod__ - _method.register = self.register - update_wrapper(_method, self.func) - return _method - - @property - def __isabstractmethod__(self): - return getattr(self.func, '__isabstractmethod__', False) - - -################################################################################ -### cached_property() - computed once per instance, cached as attribute -################################################################################ - -_NOT_FOUND = object() - - -class cached_property: - def __init__(self, func): - self.func = func - self.attrname = None - self.__doc__ = func.__doc__ - self.lock = RLock() - - def __set_name__(self, owner, name): - if self.attrname is None: - self.attrname = name - elif name != self.attrname: - raise TypeError( - "Cannot assign the same cached_property to two different names " - f"({self.attrname!r} and {name!r})." - ) - - def __get__(self, instance, owner=None): - if instance is None: - return self - if self.attrname is None: - raise TypeError( - "Cannot use cached_property instance without calling __set_name__ on it.") - try: - cache = instance.__dict__ - except AttributeError: # not all objects have __dict__ (e.g. class defines slots) - msg = ( - f"No '__dict__' attribute on {type(instance).__name__!r} " - f"instance to cache {self.attrname!r} property." - ) - raise TypeError(msg) from None - val = cache.get(self.attrname, _NOT_FOUND) - if val is _NOT_FOUND: - with self.lock: - # check if another thread filled cache while we awaited lock - val = cache.get(self.attrname, _NOT_FOUND) - if val is _NOT_FOUND: - val = self.func(instance) - try: - cache[self.attrname] = val - except TypeError: - msg = ( - f"The '__dict__' attribute on {type(instance).__name__!r} instance " - f"does not support item assignment for caching {self.attrname!r} property." - ) - raise TypeError(msg) from None - return val
    @@ -1051,7 +924,6 @@

    Versions

    diff --git a/docs/1.0-dev/_modules/index.html b/docs/1.0-dev/_modules/index.html index bcfa38db07..7ace023d8e 100644 --- a/docs/1.0-dev/_modules/index.html +++ b/docs/1.0-dev/_modules/index.html @@ -45,6 +45,7 @@
  • django.db.models.manager
  • django.db.models.query
  • django.db.models.query_utils
  • +
  • django.utils.deconstruct
  • django.utils.functional
  • evennia
    • evennia.accounts.accounts
    • @@ -75,6 +76,7 @@
    • evennia.comms.comms
    • evennia.comms.managers
    • evennia.comms.models
    • +
    • evennia.contrib.base_systems.awsstorage.aws_s3_cdn
    • evennia.contrib.base_systems.awsstorage.tests
    • evennia.contrib.base_systems.building_menu.building_menu
    • evennia.contrib.base_systems.building_menu.tests
    • @@ -332,7 +334,6 @@

      Versions

      diff --git a/docs/1.0-dev/_modules/rest_framework/test.html b/docs/1.0-dev/_modules/rest_framework/test.html index 57e41e42f9..f238897386 100644 --- a/docs/1.0-dev/_modules/rest_framework/test.html +++ b/docs/1.0-dev/_modules/rest_framework/test.html @@ -471,7 +471,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia-api.html b/docs/1.0-dev/api/evennia-api.html index 95115fec09..d603de8217 100644 --- a/docs/1.0-dev/api/evennia-api.html +++ b/docs/1.0-dev/api/evennia-api.html @@ -633,7 +633,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.accounts.accounts.html b/docs/1.0-dev/api/evennia.accounts.accounts.html index ef3959edd4..73f3b153bf 100644 --- a/docs/1.0-dev/api/evennia.accounts.accounts.html +++ b/docs/1.0-dev/api/evennia.accounts.accounts.html @@ -1179,7 +1179,6 @@ overriding the call (unused by default).

      Versions

      diff --git a/docs/1.0-dev/api/evennia.accounts.bots.html b/docs/1.0-dev/api/evennia.accounts.bots.html index dd7292ce17..e220c27c53 100644 --- a/docs/1.0-dev/api/evennia.accounts.bots.html +++ b/docs/1.0-dev/api/evennia.accounts.bots.html @@ -494,7 +494,6 @@ triggered by the bot_data_in Inputfunc.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.accounts.html b/docs/1.0-dev/api/evennia.accounts.html index 74ca76e693..d6cafdd5b9 100644 --- a/docs/1.0-dev/api/evennia.accounts.html +++ b/docs/1.0-dev/api/evennia.accounts.html @@ -95,7 +95,6 @@ more Objects depending on settings. An Account has no in-game existence.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.accounts.manager.html b/docs/1.0-dev/api/evennia.accounts.manager.html index c301110e07..e9429b654c 100644 --- a/docs/1.0-dev/api/evennia.accounts.manager.html +++ b/docs/1.0-dev/api/evennia.accounts.manager.html @@ -304,7 +304,6 @@ accounts of this typeclass.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.accounts.models.html b/docs/1.0-dev/api/evennia.accounts.models.html index f03371ad5f..d45e806530 100644 --- a/docs/1.0-dev/api/evennia.accounts.models.html +++ b/docs/1.0-dev/api/evennia.accounts.models.html @@ -412,7 +412,6 @@ class built by **create_forward_many_to_many_manager()** define

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.cmdhandler.html b/docs/1.0-dev/api/evennia.commands.cmdhandler.html index 6079cda897..8c9e78e4ec 100644 --- a/docs/1.0-dev/api/evennia.commands.cmdhandler.html +++ b/docs/1.0-dev/api/evennia.commands.cmdhandler.html @@ -170,7 +170,6 @@ default Evennia.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.cmdparser.html b/docs/1.0-dev/api/evennia.commands.cmdparser.html index 0a19fd716c..e4cf79cd2a 100644 --- a/docs/1.0-dev/api/evennia.commands.cmdparser.html +++ b/docs/1.0-dev/api/evennia.commands.cmdparser.html @@ -206,7 +206,6 @@ the remaining arguments, and the matched cmdobject from the cmdset.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.cmdset.html b/docs/1.0-dev/api/evennia.commands.cmdset.html index 253138fa9c..53ceae0995 100644 --- a/docs/1.0-dev/api/evennia.commands.cmdset.html +++ b/docs/1.0-dev/api/evennia.commands.cmdset.html @@ -423,7 +423,6 @@ self.add().

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.cmdsethandler.html b/docs/1.0-dev/api/evennia.commands.cmdsethandler.html index f6be176707..2726ff0533 100644 --- a/docs/1.0-dev/api/evennia.commands.cmdsethandler.html +++ b/docs/1.0-dev/api/evennia.commands.cmdsethandler.html @@ -391,7 +391,6 @@ handled automatically by @reload).

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.command.html b/docs/1.0-dev/api/evennia.commands.command.html index a40c9cc40b..3933127d75 100644 --- a/docs/1.0-dev/api/evennia.commands.command.html +++ b/docs/1.0-dev/api/evennia.commands.command.html @@ -529,7 +529,6 @@ detailing the contents of the table.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.default.account.html b/docs/1.0-dev/api/evennia.commands.default.account.html index 9a07462030..baa22b04f4 100644 --- a/docs/1.0-dev/api/evennia.commands.default.account.html +++ b/docs/1.0-dev/api/evennia.commands.default.account.html @@ -73,7 +73,7 @@ method. Otherwise all text will be returned to all connected sessions.

      -aliases = ['ls', 'l']
      +aliases = ['l', 'ls']
      @@ -104,7 +104,7 @@ method. Otherwise all text will be returned to all connected sessions.

      -search_index_entry = {'aliases': 'ls l', 'category': 'general', 'key': 'look', 'no_prefix': ' ls l', 'tags': '', 'text': '\n look while out-of-character\n\n Usage:\n look\n\n Look in the ooc state.\n '}
      +search_index_entry = {'aliases': 'l ls', 'category': 'general', 'key': 'look', 'no_prefix': ' l ls', 'tags': '', 'text': '\n look while out-of-character\n\n Usage:\n look\n\n Look in the ooc state.\n '}
      @@ -859,7 +859,6 @@ to all the variables defined therein.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.default.admin.html b/docs/1.0-dev/api/evennia.commands.default.admin.html index 4537a0850e..fe99d81d00 100644 --- a/docs/1.0-dev/api/evennia.commands.default.admin.html +++ b/docs/1.0-dev/api/evennia.commands.default.admin.html @@ -544,7 +544,6 @@ including all currently unlogged in.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.default.batchprocess.html b/docs/1.0-dev/api/evennia.commands.default.batchprocess.html index 6b6a30d6b0..3669e93060 100644 --- a/docs/1.0-dev/api/evennia.commands.default.batchprocess.html +++ b/docs/1.0-dev/api/evennia.commands.default.batchprocess.html @@ -78,7 +78,7 @@ skipping, reloading etc.

      -aliases = ['batchcmd', 'batchcommand']
      +aliases = ['batchcommand', 'batchcmd']
      @@ -109,7 +109,7 @@ skipping, reloading etc.

      -search_index_entry = {'aliases': 'batchcmd batchcommand', 'category': 'building', 'key': 'batchcommands', 'no_prefix': ' batchcmd batchcommand', 'tags': '', 'text': '\n build from batch-command file\n\n Usage:\n batchcommands[/interactive] <python.path.to.file>\n\n Switch:\n interactive - this mode will offer more control when\n executing the batch file, like stepping,\n skipping, reloading etc.\n\n Runs batches of commands from a batch-cmd text file (*.ev).\n\n '}
      +search_index_entry = {'aliases': 'batchcommand batchcmd', 'category': 'building', 'key': 'batchcommands', 'no_prefix': ' batchcommand batchcmd', 'tags': '', 'text': '\n build from batch-command file\n\n Usage:\n batchcommands[/interactive] <python.path.to.file>\n\n Switch:\n interactive - this mode will offer more control when\n executing the batch file, like stepping,\n skipping, reloading etc.\n\n Runs batches of commands from a batch-cmd text file (*.ev).\n\n '}
      @@ -219,7 +219,6 @@ object copies behind when testing out the script.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.default.building.html b/docs/1.0-dev/api/evennia.commands.default.building.html index ec0ce2b012..25d4e50f10 100644 --- a/docs/1.0-dev/api/evennia.commands.default.building.html +++ b/docs/1.0-dev/api/evennia.commands.default.building.html @@ -1285,7 +1285,7 @@ server settings.

      -aliases = ['@swap', '@type', '@update', '@parent', '@typeclasses']
      +aliases = ['@type', '@update', '@parent', '@swap', '@typeclasses']
      @@ -1316,7 +1316,7 @@ server settings.

      -search_index_entry = {'aliases': '@swap @type @update @parent @typeclasses', 'category': 'building', 'key': '@typeclass', 'no_prefix': 'typeclass swap type update parent typeclasses', 'tags': '', 'text': "\n set or change an object's typeclass\n\n Usage:\n typeclass[/switch] <object> [= typeclass.path]\n typeclass/prototype <object> = prototype_key\n\n typeclasses or typeclass/list/show [typeclass.path]\n swap - this is a shorthand for using /force/reset flags.\n update - this is a shorthand for using the /force/reload flag.\n\n Switch:\n show, examine - display the current typeclass of object (default) or, if\n given a typeclass path, show the docstring of that typeclass.\n update - *only* re-run at_object_creation on this object\n meaning locks or other properties set later may remain.\n reset - clean out *all* the attributes and properties on the\n object - basically making this a new clean object. This will also\n reset cmdsets!\n force - change to the typeclass also if the object\n already has a typeclass of the same name.\n list - show available typeclasses. Only typeclasses in modules actually\n imported or used from somewhere in the code will show up here\n (those typeclasses are still available if you know the path)\n prototype - clean and overwrite the object with the specified\n prototype key - effectively making a whole new object.\n\n Example:\n type button = examples.red_button.RedButton\n type/prototype button=a red button\n\n If the typeclass_path is not given, the current object's typeclass is\n assumed.\n\n View or set an object's typeclass. If setting, the creation hooks of the\n new typeclass will be run on the object. If you have clashing properties on\n the old class, use /reset. By default you are protected from changing to a\n typeclass of the same name as the one you already have - use /force to\n override this protection.\n\n The given typeclass must be identified by its location using python\n dot-notation pointing to the correct module and class. If no typeclass is\n given (or a wrong typeclass is given). Errors in the path or new typeclass\n will lead to the old typeclass being kept. The location of the typeclass\n module is searched from the default typeclass directory, as defined in the\n server settings.\n\n "}
      +search_index_entry = {'aliases': '@type @update @parent @swap @typeclasses', 'category': 'building', 'key': '@typeclass', 'no_prefix': 'typeclass type update parent swap typeclasses', 'tags': '', 'text': "\n set or change an object's typeclass\n\n Usage:\n typeclass[/switch] <object> [= typeclass.path]\n typeclass/prototype <object> = prototype_key\n\n typeclasses or typeclass/list/show [typeclass.path]\n swap - this is a shorthand for using /force/reset flags.\n update - this is a shorthand for using the /force/reload flag.\n\n Switch:\n show, examine - display the current typeclass of object (default) or, if\n given a typeclass path, show the docstring of that typeclass.\n update - *only* re-run at_object_creation on this object\n meaning locks or other properties set later may remain.\n reset - clean out *all* the attributes and properties on the\n object - basically making this a new clean object. This will also\n reset cmdsets!\n force - change to the typeclass also if the object\n already has a typeclass of the same name.\n list - show available typeclasses. Only typeclasses in modules actually\n imported or used from somewhere in the code will show up here\n (those typeclasses are still available if you know the path)\n prototype - clean and overwrite the object with the specified\n prototype key - effectively making a whole new object.\n\n Example:\n type button = examples.red_button.RedButton\n type/prototype button=a red button\n\n If the typeclass_path is not given, the current object's typeclass is\n assumed.\n\n View or set an object's typeclass. If setting, the creation hooks of the\n new typeclass will be run on the object. If you have clashing properties on\n the old class, use /reset. By default you are protected from changing to a\n typeclass of the same name as the one you already have - use /force to\n override this protection.\n\n The given typeclass must be identified by its location using python\n dot-notation pointing to the correct module and class. If no typeclass is\n given (or a wrong typeclass is given). Errors in the path or new typeclass\n will lead to the old typeclass being kept. The location of the typeclass\n module is searched from the default typeclass directory, as defined in the\n server settings.\n\n "}
      @@ -1471,7 +1471,7 @@ If object is not specified, the current location is examined.

      -aliases = ['@ex', '@exam']
      +aliases = ['@exam', '@ex']
      @@ -1739,7 +1739,7 @@ the cases, see the module doc.

      -search_index_entry = {'aliases': '@ex @exam', 'category': 'building', 'key': '@examine', 'no_prefix': 'examine ex exam', 'tags': '', 'text': '\n get detailed information about an object\n\n Usage:\n examine [<object>[/attrname]]\n examine [*<account>[/attrname]]\n\n Switch:\n account - examine an Account (same as adding *)\n object - examine an Object (useful when OOC)\n script - examine a Script\n channel - examine a Channel\n\n The examine command shows detailed game info about an\n object and optionally a specific attribute on it.\n If object is not specified, the current location is examined.\n\n Append a * before the search string to examine an account.\n\n '}
      +search_index_entry = {'aliases': '@exam @ex', 'category': 'building', 'key': '@examine', 'no_prefix': 'examine exam ex', 'tags': '', 'text': '\n get detailed information about an object\n\n Usage:\n examine [<object>[/attrname]]\n examine [*<account>[/attrname]]\n\n Switch:\n account - examine an Account (same as adding *)\n object - examine an Object (useful when OOC)\n script - examine a Script\n channel - examine a Channel\n\n The examine command shows detailed game info about an\n object and optionally a specific attribute on it.\n If object is not specified, the current location is examined.\n\n Append a * before the search string to examine an account.\n\n '}
      @@ -2261,7 +2261,6 @@ displays a list of available prototypes.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.default.cmdset_account.html b/docs/1.0-dev/api/evennia.commands.default.cmdset_account.html index 442c86fada..53ff551c87 100644 --- a/docs/1.0-dev/api/evennia.commands.default.cmdset_account.html +++ b/docs/1.0-dev/api/evennia.commands.default.cmdset_account.html @@ -118,7 +118,6 @@ command method rather than caller.msg().

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.default.cmdset_character.html b/docs/1.0-dev/api/evennia.commands.default.cmdset_character.html index e2af49b1f3..06bf4c160e 100644 --- a/docs/1.0-dev/api/evennia.commands.default.cmdset_character.html +++ b/docs/1.0-dev/api/evennia.commands.default.cmdset_character.html @@ -116,7 +116,6 @@ Account cmdset. Account commands remain available also to Characters.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.default.cmdset_session.html b/docs/1.0-dev/api/evennia.commands.default.cmdset_session.html index e4e76025cb..e59179d459 100644 --- a/docs/1.0-dev/api/evennia.commands.default.cmdset_session.html +++ b/docs/1.0-dev/api/evennia.commands.default.cmdset_session.html @@ -113,7 +113,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.default.cmdset_unloggedin.html b/docs/1.0-dev/api/evennia.commands.default.cmdset_unloggedin.html index ce09ee2efa..d0379b45f0 100644 --- a/docs/1.0-dev/api/evennia.commands.default.cmdset_unloggedin.html +++ b/docs/1.0-dev/api/evennia.commands.default.cmdset_unloggedin.html @@ -115,7 +115,6 @@ of the state instance in this module.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.default.comms.html b/docs/1.0-dev/api/evennia.commands.default.comms.html index e1c8bfbb59..e59ebb3aa9 100644 --- a/docs/1.0-dev/api/evennia.commands.default.comms.html +++ b/docs/1.0-dev/api/evennia.commands.default.comms.html @@ -196,7 +196,7 @@ ban mychannel1,mychannel2= EvilUser : Was banned for spamming.

      -aliases = ['@chan', '@channels']
      +aliases = ['@channels', '@chan']
      @@ -722,7 +722,7 @@ don’t actually sub to yet.

      -search_index_entry = {'aliases': '@chan @channels', 'category': 'comms', 'key': '@channel', 'no_prefix': 'channel chan channels', 'tags': '', 'text': "\n Use and manage in-game channels.\n\n Usage:\n channel channelname <msg>\n channel channel name = <msg>\n channel (show all subscription)\n channel/all (show available channels)\n channel/alias channelname = alias[;alias...]\n channel/unalias alias\n channel/who channelname\n channel/history channelname [= index]\n channel/sub channelname [= alias[;alias...]]\n channel/unsub channelname[,channelname, ...]\n channel/mute channelname[,channelname,...]\n channel/unmute channelname[,channelname,...]\n\n channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n channel/desc channelname = description\n channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n channel/ban channelname (list bans)\n channel/ban[/quiet] channelname[, channelname, ...] = subscribername [: reason]\n channel/unban[/quiet] channelname[, channelname, ...] = subscribername\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n\n # subtopics\n\n ## sending\n\n Usage: channel channelname msg\n channel channel name = msg (with space in channel name)\n\n This sends a message to the channel. Note that you will rarely use this\n command like this; instead you can use the alias\n\n channelname <msg>\n channelalias <msg>\n\n For example\n\n public Hello World\n pub Hello World\n\n (this shortcut doesn't work for aliases containing spaces)\n\n See channel/alias for help on setting channel aliases.\n\n ## alias and unalias\n\n Usage: channel/alias channel = alias[;alias[;alias...]]\n channel/unalias alias\n channel - this will list your subs and aliases to each channel\n\n Set one or more personal aliases for referencing a channel. For example:\n\n channel/alias warrior's guild = warrior;wguild;warchannel;warrior guild\n\n You can now send to the channel using all of these:\n\n warrior's guild Hello\n warrior Hello\n wguild Hello\n warchannel Hello\n\n Note that this will not work if the alias has a space in it. So the\n 'warrior guild' alias must be used with the `channel` command:\n\n channel warrior guild = Hello\n\n Channel-aliases can be removed one at a time, using the '/unalias' switch.\n\n ## who\n\n Usage: channel/who channelname\n\n List the channel's subscribers. Shows who are currently offline or are\n muting the channel. Subscribers who are 'muting' will not see messages sent\n to the channel (use channel/mute to mute a channel).\n\n ## history\n\n Usage: channel/history channel [= index]\n\n This will display the last |c20|n lines of channel history. By supplying an\n index number, you will step that many lines back before viewing those 20 lines.\n\n For example:\n\n channel/history public = 35\n\n will go back 35 lines and show the previous 20 lines from that point (so\n lines -35 to -55).\n\n ## sub and unsub\n\n Usage: channel/sub channel [=alias[;alias;...]]\n channel/unsub channel\n\n This subscribes you to a channel and optionally assigns personal shortcuts\n for you to use to send to that channel (see aliases). When you unsub, all\n your personal aliases will also be removed.\n\n ## mute and unmute\n\n Usage: channel/mute channelname\n channel/unmute channelname\n\n Muting silences all output from the channel without actually\n un-subscribing. Other channel members will see that you are muted in the /who\n list. Sending a message to the channel will automatically unmute you.\n\n ## create and destroy\n\n Usage: channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n\n Creates a new channel (or destroys one you control). You will automatically\n join the channel you create and everyone will be kicked and loose all aliases\n to a destroyed channel.\n\n ## lock and unlock\n\n Usage: channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n\n Note: this is an admin command.\n\n A lockstring is on the form locktype:lockfunc(). Channels understand three\n locktypes:\n listen - who may listen or join the channel.\n send - who may send messages to the channel\n control - who controls the channel. This is usually the one creating\n the channel.\n\n Common lockfuncs are all() and perm(). To make a channel everyone can\n listen to but only builders can talk on, use this:\n\n listen:all()\n send: perm(Builders)\n\n ## boot and ban\n\n Usage:\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n channel/ban channelname[, channelname, ...] = subscribername [: reason]\n channel/unban channelname[, channelname, ...] = subscribername\n channel/unban channelname\n channel/ban channelname (list bans)\n\n Booting will kick a named subscriber from channel(s) temporarily. The\n 'reason' will be passed to the booted user. Unless the /quiet switch is\n used, the channel will also be informed of the action. A booted user is\n still able to re-connect, but they'll have to set up their aliases again.\n\n Banning will blacklist a user from (re)joining the provided channels. It\n will then proceed to boot them from those channels if they were connected.\n The 'reason' and `/quiet` works the same as for booting.\n\n Example:\n boot mychannel1 = EvilUser : Kicking you to cool down a bit.\n ban mychannel1,mychannel2= EvilUser : Was banned for spamming.\n\n "}
      +search_index_entry = {'aliases': '@channels @chan', 'category': 'comms', 'key': '@channel', 'no_prefix': 'channel channels chan', 'tags': '', 'text': "\n Use and manage in-game channels.\n\n Usage:\n channel channelname <msg>\n channel channel name = <msg>\n channel (show all subscription)\n channel/all (show available channels)\n channel/alias channelname = alias[;alias...]\n channel/unalias alias\n channel/who channelname\n channel/history channelname [= index]\n channel/sub channelname [= alias[;alias...]]\n channel/unsub channelname[,channelname, ...]\n channel/mute channelname[,channelname,...]\n channel/unmute channelname[,channelname,...]\n\n channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n channel/desc channelname = description\n channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n channel/ban channelname (list bans)\n channel/ban[/quiet] channelname[, channelname, ...] = subscribername [: reason]\n channel/unban[/quiet] channelname[, channelname, ...] = subscribername\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n\n # subtopics\n\n ## sending\n\n Usage: channel channelname msg\n channel channel name = msg (with space in channel name)\n\n This sends a message to the channel. Note that you will rarely use this\n command like this; instead you can use the alias\n\n channelname <msg>\n channelalias <msg>\n\n For example\n\n public Hello World\n pub Hello World\n\n (this shortcut doesn't work for aliases containing spaces)\n\n See channel/alias for help on setting channel aliases.\n\n ## alias and unalias\n\n Usage: channel/alias channel = alias[;alias[;alias...]]\n channel/unalias alias\n channel - this will list your subs and aliases to each channel\n\n Set one or more personal aliases for referencing a channel. For example:\n\n channel/alias warrior's guild = warrior;wguild;warchannel;warrior guild\n\n You can now send to the channel using all of these:\n\n warrior's guild Hello\n warrior Hello\n wguild Hello\n warchannel Hello\n\n Note that this will not work if the alias has a space in it. So the\n 'warrior guild' alias must be used with the `channel` command:\n\n channel warrior guild = Hello\n\n Channel-aliases can be removed one at a time, using the '/unalias' switch.\n\n ## who\n\n Usage: channel/who channelname\n\n List the channel's subscribers. Shows who are currently offline or are\n muting the channel. Subscribers who are 'muting' will not see messages sent\n to the channel (use channel/mute to mute a channel).\n\n ## history\n\n Usage: channel/history channel [= index]\n\n This will display the last |c20|n lines of channel history. By supplying an\n index number, you will step that many lines back before viewing those 20 lines.\n\n For example:\n\n channel/history public = 35\n\n will go back 35 lines and show the previous 20 lines from that point (so\n lines -35 to -55).\n\n ## sub and unsub\n\n Usage: channel/sub channel [=alias[;alias;...]]\n channel/unsub channel\n\n This subscribes you to a channel and optionally assigns personal shortcuts\n for you to use to send to that channel (see aliases). When you unsub, all\n your personal aliases will also be removed.\n\n ## mute and unmute\n\n Usage: channel/mute channelname\n channel/unmute channelname\n\n Muting silences all output from the channel without actually\n un-subscribing. Other channel members will see that you are muted in the /who\n list. Sending a message to the channel will automatically unmute you.\n\n ## create and destroy\n\n Usage: channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n\n Creates a new channel (or destroys one you control). You will automatically\n join the channel you create and everyone will be kicked and loose all aliases\n to a destroyed channel.\n\n ## lock and unlock\n\n Usage: channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n\n Note: this is an admin command.\n\n A lockstring is on the form locktype:lockfunc(). Channels understand three\n locktypes:\n listen - who may listen or join the channel.\n send - who may send messages to the channel\n control - who controls the channel. This is usually the one creating\n the channel.\n\n Common lockfuncs are all() and perm(). To make a channel everyone can\n listen to but only builders can talk on, use this:\n\n listen:all()\n send: perm(Builders)\n\n ## boot and ban\n\n Usage:\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n channel/ban channelname[, channelname, ...] = subscribername [: reason]\n channel/unban channelname[, channelname, ...] = subscribername\n channel/unban channelname\n channel/ban channelname (list bans)\n\n Booting will kick a named subscriber from channel(s) temporarily. The\n 'reason' will be passed to the booted user. Unless the /quiet switch is\n used, the channel will also be informed of the action. A booted user is\n still able to re-connect, but they'll have to set up their aliases again.\n\n Banning will blacklist a user from (re)joining the provided channels. It\n will then proceed to boot them from those channels if they were connected.\n The 'reason' and `/quiet` works the same as for booting.\n\n Example:\n boot mychannel1 = EvilUser : Kicking you to cool down a bit.\n ban mychannel1,mychannel2= EvilUser : Was banned for spamming.\n\n "}
      @@ -875,7 +875,7 @@ ban mychannel1,mychannel2= EvilUser : Was banned for spamming.

      -aliases = ['@chan', '@channels']
      +aliases = ['@channels', '@chan']
      @@ -895,7 +895,7 @@ ban mychannel1,mychannel2= EvilUser : Was banned for spamming.

      -search_index_entry = {'aliases': '@chan @channels', 'category': 'comms', 'key': '@channel', 'no_prefix': 'channel chan channels', 'tags': '', 'text': "\n Use and manage in-game channels.\n\n Usage:\n channel channelname <msg>\n channel channel name = <msg>\n channel (show all subscription)\n channel/all (show available channels)\n channel/alias channelname = alias[;alias...]\n channel/unalias alias\n channel/who channelname\n channel/history channelname [= index]\n channel/sub channelname [= alias[;alias...]]\n channel/unsub channelname[,channelname, ...]\n channel/mute channelname[,channelname,...]\n channel/unmute channelname[,channelname,...]\n\n channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n channel/desc channelname = description\n channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n channel/ban channelname (list bans)\n channel/ban[/quiet] channelname[, channelname, ...] = subscribername [: reason]\n channel/unban[/quiet] channelname[, channelname, ...] = subscribername\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n\n # subtopics\n\n ## sending\n\n Usage: channel channelname msg\n channel channel name = msg (with space in channel name)\n\n This sends a message to the channel. Note that you will rarely use this\n command like this; instead you can use the alias\n\n channelname <msg>\n channelalias <msg>\n\n For example\n\n public Hello World\n pub Hello World\n\n (this shortcut doesn't work for aliases containing spaces)\n\n See channel/alias for help on setting channel aliases.\n\n ## alias and unalias\n\n Usage: channel/alias channel = alias[;alias[;alias...]]\n channel/unalias alias\n channel - this will list your subs and aliases to each channel\n\n Set one or more personal aliases for referencing a channel. For example:\n\n channel/alias warrior's guild = warrior;wguild;warchannel;warrior guild\n\n You can now send to the channel using all of these:\n\n warrior's guild Hello\n warrior Hello\n wguild Hello\n warchannel Hello\n\n Note that this will not work if the alias has a space in it. So the\n 'warrior guild' alias must be used with the `channel` command:\n\n channel warrior guild = Hello\n\n Channel-aliases can be removed one at a time, using the '/unalias' switch.\n\n ## who\n\n Usage: channel/who channelname\n\n List the channel's subscribers. Shows who are currently offline or are\n muting the channel. Subscribers who are 'muting' will not see messages sent\n to the channel (use channel/mute to mute a channel).\n\n ## history\n\n Usage: channel/history channel [= index]\n\n This will display the last |c20|n lines of channel history. By supplying an\n index number, you will step that many lines back before viewing those 20 lines.\n\n For example:\n\n channel/history public = 35\n\n will go back 35 lines and show the previous 20 lines from that point (so\n lines -35 to -55).\n\n ## sub and unsub\n\n Usage: channel/sub channel [=alias[;alias;...]]\n channel/unsub channel\n\n This subscribes you to a channel and optionally assigns personal shortcuts\n for you to use to send to that channel (see aliases). When you unsub, all\n your personal aliases will also be removed.\n\n ## mute and unmute\n\n Usage: channel/mute channelname\n channel/unmute channelname\n\n Muting silences all output from the channel without actually\n un-subscribing. Other channel members will see that you are muted in the /who\n list. Sending a message to the channel will automatically unmute you.\n\n ## create and destroy\n\n Usage: channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n\n Creates a new channel (or destroys one you control). You will automatically\n join the channel you create and everyone will be kicked and loose all aliases\n to a destroyed channel.\n\n ## lock and unlock\n\n Usage: channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n\n Note: this is an admin command.\n\n A lockstring is on the form locktype:lockfunc(). Channels understand three\n locktypes:\n listen - who may listen or join the channel.\n send - who may send messages to the channel\n control - who controls the channel. This is usually the one creating\n the channel.\n\n Common lockfuncs are all() and perm(). To make a channel everyone can\n listen to but only builders can talk on, use this:\n\n listen:all()\n send: perm(Builders)\n\n ## boot and ban\n\n Usage:\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n channel/ban channelname[, channelname, ...] = subscribername [: reason]\n channel/unban channelname[, channelname, ...] = subscribername\n channel/unban channelname\n channel/ban channelname (list bans)\n\n Booting will kick a named subscriber from channel(s) temporarily. The\n 'reason' will be passed to the booted user. Unless the /quiet switch is\n used, the channel will also be informed of the action. A booted user is\n still able to re-connect, but they'll have to set up their aliases again.\n\n Banning will blacklist a user from (re)joining the provided channels. It\n will then proceed to boot them from those channels if they were connected.\n The 'reason' and `/quiet` works the same as for booting.\n\n Example:\n boot mychannel1 = EvilUser : Kicking you to cool down a bit.\n ban mychannel1,mychannel2= EvilUser : Was banned for spamming.\n\n "}
      +search_index_entry = {'aliases': '@channels @chan', 'category': 'comms', 'key': '@channel', 'no_prefix': 'channel channels chan', 'tags': '', 'text': "\n Use and manage in-game channels.\n\n Usage:\n channel channelname <msg>\n channel channel name = <msg>\n channel (show all subscription)\n channel/all (show available channels)\n channel/alias channelname = alias[;alias...]\n channel/unalias alias\n channel/who channelname\n channel/history channelname [= index]\n channel/sub channelname [= alias[;alias...]]\n channel/unsub channelname[,channelname, ...]\n channel/mute channelname[,channelname,...]\n channel/unmute channelname[,channelname,...]\n\n channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n channel/desc channelname = description\n channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n channel/ban channelname (list bans)\n channel/ban[/quiet] channelname[, channelname, ...] = subscribername [: reason]\n channel/unban[/quiet] channelname[, channelname, ...] = subscribername\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n\n # subtopics\n\n ## sending\n\n Usage: channel channelname msg\n channel channel name = msg (with space in channel name)\n\n This sends a message to the channel. Note that you will rarely use this\n command like this; instead you can use the alias\n\n channelname <msg>\n channelalias <msg>\n\n For example\n\n public Hello World\n pub Hello World\n\n (this shortcut doesn't work for aliases containing spaces)\n\n See channel/alias for help on setting channel aliases.\n\n ## alias and unalias\n\n Usage: channel/alias channel = alias[;alias[;alias...]]\n channel/unalias alias\n channel - this will list your subs and aliases to each channel\n\n Set one or more personal aliases for referencing a channel. For example:\n\n channel/alias warrior's guild = warrior;wguild;warchannel;warrior guild\n\n You can now send to the channel using all of these:\n\n warrior's guild Hello\n warrior Hello\n wguild Hello\n warchannel Hello\n\n Note that this will not work if the alias has a space in it. So the\n 'warrior guild' alias must be used with the `channel` command:\n\n channel warrior guild = Hello\n\n Channel-aliases can be removed one at a time, using the '/unalias' switch.\n\n ## who\n\n Usage: channel/who channelname\n\n List the channel's subscribers. Shows who are currently offline or are\n muting the channel. Subscribers who are 'muting' will not see messages sent\n to the channel (use channel/mute to mute a channel).\n\n ## history\n\n Usage: channel/history channel [= index]\n\n This will display the last |c20|n lines of channel history. By supplying an\n index number, you will step that many lines back before viewing those 20 lines.\n\n For example:\n\n channel/history public = 35\n\n will go back 35 lines and show the previous 20 lines from that point (so\n lines -35 to -55).\n\n ## sub and unsub\n\n Usage: channel/sub channel [=alias[;alias;...]]\n channel/unsub channel\n\n This subscribes you to a channel and optionally assigns personal shortcuts\n for you to use to send to that channel (see aliases). When you unsub, all\n your personal aliases will also be removed.\n\n ## mute and unmute\n\n Usage: channel/mute channelname\n channel/unmute channelname\n\n Muting silences all output from the channel without actually\n un-subscribing. Other channel members will see that you are muted in the /who\n list. Sending a message to the channel will automatically unmute you.\n\n ## create and destroy\n\n Usage: channel/create channelname[;alias;alias[:typeclass]] [= description]\n channel/destroy channelname [= reason]\n\n Creates a new channel (or destroys one you control). You will automatically\n join the channel you create and everyone will be kicked and loose all aliases\n to a destroyed channel.\n\n ## lock and unlock\n\n Usage: channel/lock channelname = lockstring\n channel/unlock channelname = lockstring\n\n Note: this is an admin command.\n\n A lockstring is on the form locktype:lockfunc(). Channels understand three\n locktypes:\n listen - who may listen or join the channel.\n send - who may send messages to the channel\n control - who controls the channel. This is usually the one creating\n the channel.\n\n Common lockfuncs are all() and perm(). To make a channel everyone can\n listen to but only builders can talk on, use this:\n\n listen:all()\n send: perm(Builders)\n\n ## boot and ban\n\n Usage:\n channel/boot[/quiet] channelname[,channelname,...] = subscribername [: reason]\n channel/ban channelname[, channelname, ...] = subscribername [: reason]\n channel/unban channelname[, channelname, ...] = subscribername\n channel/unban channelname\n channel/ban channelname (list bans)\n\n Booting will kick a named subscriber from channel(s) temporarily. The\n 'reason' will be passed to the booted user. Unless the /quiet switch is\n used, the channel will also be informed of the action. A booted user is\n still able to re-connect, but they'll have to set up their aliases again.\n\n Banning will blacklist a user from (re)joining the provided channels. It\n will then proceed to boot them from those channels if they were connected.\n The 'reason' and `/quiet` works the same as for booting.\n\n Example:\n boot mychannel1 = EvilUser : Kicking you to cool down a bit.\n ban mychannel1,mychannel2= EvilUser : Was banned for spamming.\n\n "}
      @@ -1301,7 +1301,6 @@ must be added to game settings.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.default.general.html b/docs/1.0-dev/api/evennia.commands.default.general.html index 780ac62d4c..1cde20d9da 100644 --- a/docs/1.0-dev/api/evennia.commands.default.general.html +++ b/docs/1.0-dev/api/evennia.commands.default.general.html @@ -115,7 +115,7 @@ look *<account&g
      -aliases = ['ls', 'l']
      +aliases = ['l', 'ls']
      @@ -146,7 +146,7 @@ look *<account&g
      -search_index_entry = {'aliases': 'ls l', 'category': 'general', 'key': 'look', 'no_prefix': ' ls l', 'tags': '', 'text': '\n look at location or object\n\n Usage:\n look\n look <obj>\n look *<account>\n\n Observes your location or objects in your vicinity.\n '}
      +search_index_entry = {'aliases': 'l ls', 'category': 'general', 'key': 'look', 'no_prefix': ' l ls', 'tags': '', 'text': '\n look at location or object\n\n Usage:\n look\n look <obj>\n look *<account>\n\n Observes your location or objects in your vicinity.\n '}
      @@ -208,7 +208,7 @@ for everyone to use, you need build privileges and the alias command.

      -aliases = ['nickname', 'nicks']
      +aliases = ['nicks', 'nickname']
      @@ -240,7 +240,7 @@ for everyone to use, you need build privileges and the alias command.

      -search_index_entry = {'aliases': 'nickname nicks', 'category': 'general', 'key': 'nick', 'no_prefix': ' nickname nicks', 'tags': '', 'text': '\n define a personal alias/nick by defining a string to\n match and replace it with another on the fly\n\n Usage:\n nick[/switches] <string> [= [replacement_string]]\n nick[/switches] <template> = <replacement_template>\n nick/delete <string> or number\n nicks\n\n Switches:\n inputline - replace on the inputline (default)\n object - replace on object-lookup\n account - replace on account-lookup\n list - show all defined aliases (also "nicks" works)\n delete - remove nick by index in /list\n clearall - clear all nicks\n\n Examples:\n nick hi = say Hello, I\'m Sarah!\n nick/object tom = the tall man\n nick build $1 $2 = create/drop $1;$2\n nick tell $1 $2=page $1=$2\n nick tm?$1=page tallman=$1\n nick tm\\=$1=page tallman=$1\n\n A \'nick\' is a personal string replacement. Use $1, $2, ... to catch arguments.\n Put the last $-marker without an ending space to catch all remaining text. You\n can also use unix-glob matching for the left-hand side <string>:\n\n * - matches everything\n ? - matches 0 or 1 single characters\n [abcd] - matches these chars in any order\n [!abcd] - matches everything not among these chars\n \\= - escape literal \'=\' you want in your <string>\n\n Note that no objects are actually renamed or changed by this command - your nicks\n are only available to you. If you want to permanently add keywords to an object\n for everyone to use, you need build privileges and the alias command.\n\n '}
      +search_index_entry = {'aliases': 'nicks nickname', 'category': 'general', 'key': 'nick', 'no_prefix': ' nicks nickname', 'tags': '', 'text': '\n define a personal alias/nick by defining a string to\n match and replace it with another on the fly\n\n Usage:\n nick[/switches] <string> [= [replacement_string]]\n nick[/switches] <template> = <replacement_template>\n nick/delete <string> or number\n nicks\n\n Switches:\n inputline - replace on the inputline (default)\n object - replace on object-lookup\n account - replace on account-lookup\n list - show all defined aliases (also "nicks" works)\n delete - remove nick by index in /list\n clearall - clear all nicks\n\n Examples:\n nick hi = say Hello, I\'m Sarah!\n nick/object tom = the tall man\n nick build $1 $2 = create/drop $1;$2\n nick tell $1 $2=page $1=$2\n nick tm?$1=page tallman=$1\n nick tm\\=$1=page tallman=$1\n\n A \'nick\' is a personal string replacement. Use $1, $2, ... to catch arguments.\n Put the last $-marker without an ending space to catch all remaining text. You\n can also use unix-glob matching for the left-hand side <string>:\n\n * - matches everything\n ? - matches 0 or 1 single characters\n [abcd] - matches these chars in any order\n [!abcd] - matches everything not among these chars\n \\= - escape literal \'=\' you want in your <string>\n\n Note that no objects are actually renamed or changed by this command - your nicks\n are only available to you. If you want to permanently add keywords to an object\n for everyone to use, you need build privileges and the alias command.\n\n '}
      @@ -791,7 +791,6 @@ which permission groups you are a member of.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.default.help.html b/docs/1.0-dev/api/evennia.commands.default.help.html index dd6ca6e489..d8e7a657dc 100644 --- a/docs/1.0-dev/api/evennia.commands.default.help.html +++ b/docs/1.0-dev/api/evennia.commands.default.help.html @@ -487,7 +487,6 @@ the user will be able to enter a partial match to access it.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.default.html b/docs/1.0-dev/api/evennia.commands.default.html index 4d35acea40..b1a3130db4 100644 --- a/docs/1.0-dev/api/evennia.commands.default.html +++ b/docs/1.0-dev/api/evennia.commands.default.html @@ -105,7 +105,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.default.muxcommand.html b/docs/1.0-dev/api/evennia.commands.default.muxcommand.html index 6ca2730607..482729d345 100644 --- a/docs/1.0-dev/api/evennia.commands.default.muxcommand.html +++ b/docs/1.0-dev/api/evennia.commands.default.muxcommand.html @@ -281,7 +281,6 @@ character is actually attached to this Account and Session.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.default.syscommands.html b/docs/1.0-dev/api/evennia.commands.default.syscommands.html index fdde5f653d..bda483e51d 100644 --- a/docs/1.0-dev/api/evennia.commands.default.syscommands.html +++ b/docs/1.0-dev/api/evennia.commands.default.syscommands.html @@ -237,7 +237,6 @@ the raw_cmdname is the cmdname unmodified by eventual prefix-st

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.default.system.html b/docs/1.0-dev/api/evennia.commands.default.system.html index 4234cd3b6a..783a5a01b9 100644 --- a/docs/1.0-dev/api/evennia.commands.default.system.html +++ b/docs/1.0-dev/api/evennia.commands.default.system.html @@ -768,7 +768,6 @@ to all the variables defined therein.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.default.tests.html b/docs/1.0-dev/api/evennia.commands.default.tests.html index add272ce90..419ba67830 100644 --- a/docs/1.0-dev/api/evennia.commands.default.tests.html +++ b/docs/1.0-dev/api/evennia.commands.default.tests.html @@ -736,7 +736,7 @@ main test suite started with

      Test the batch processor.

      -red_button = <module 'evennia.contrib.tutorials.red_button.red_button' from '/home/griatch/Devel/Home/evennia/evennia/evennia/contrib/tutorials/red_button/red_button.py'>
      +red_button = <module 'evennia.contrib.tutorials.red_button.red_button' from '/home/runner/work/evennia/evennia/evennia/contrib/tutorials/red_button/red_button.py'>
      @@ -928,7 +928,6 @@ set in self.parse())

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.default.unloggedin.html b/docs/1.0-dev/api/evennia.commands.default.unloggedin.html index cf05cc1f36..07d6f0dece 100644 --- a/docs/1.0-dev/api/evennia.commands.default.unloggedin.html +++ b/docs/1.0-dev/api/evennia.commands.default.unloggedin.html @@ -62,7 +62,7 @@ connect “account name” “pass word”

      -aliases = ['co', 'con', 'conn']
      +aliases = ['conn', 'co', 'con']
      @@ -97,7 +97,7 @@ there is no object yet before the account has logged in)

      -search_index_entry = {'aliases': 'co con conn', 'category': 'general', 'key': 'connect', 'no_prefix': ' co con conn', 'tags': '', 'text': '\n connect to the game\n\n Usage (at login screen):\n connect accountname password\n connect "account name" "pass word"\n\n Use the create command to first create an account before logging in.\n\n If you have spaces in your name, enclose it in double quotes.\n '}
      +search_index_entry = {'aliases': 'conn co con', 'category': 'general', 'key': 'connect', 'no_prefix': ' conn co con', 'tags': '', 'text': '\n connect to the game\n\n Usage (at login screen):\n connect accountname password\n connect "account name" "pass word"\n\n Use the create command to first create an account before logging in.\n\n If you have spaces in your name, enclose it in double quotes.\n '}
      @@ -121,7 +121,7 @@ create “account name” “pass word”

      -aliases = ['cre', 'cr']
      +aliases = ['cr', 'cre']
      @@ -152,7 +152,7 @@ create “account name” “pass word”

      -search_index_entry = {'aliases': 'cre cr', 'category': 'general', 'key': 'create', 'no_prefix': ' cre cr', 'tags': '', 'text': '\n create a new account account\n\n Usage (at login screen):\n create <accountname> <password>\n create "account name" "pass word"\n\n This creates a new account account.\n\n If you have spaces in your name, enclose it in double quotes.\n '}
      +search_index_entry = {'aliases': 'cr cre', 'category': 'general', 'key': 'create', 'no_prefix': ' cr cre', 'tags': '', 'text': '\n create a new account account\n\n Usage (at login screen):\n create <accountname> <password>\n create "account name" "pass word"\n\n This creates a new account account.\n\n If you have spaces in your name, enclose it in double quotes.\n '}
      @@ -176,7 +176,7 @@ version is a bit more complicated.

      -aliases = ['qu', 'q']
      +aliases = ['q', 'qu']
      @@ -202,7 +202,7 @@ version is a bit more complicated.

      -search_index_entry = {'aliases': 'qu q', 'category': 'general', 'key': 'quit', 'no_prefix': ' qu q', 'tags': '', 'text': '\n quit when in unlogged-in state\n\n Usage:\n quit\n\n We maintain a different version of the quit command\n here for unconnected accounts for the sake of simplicity. The logged in\n version is a bit more complicated.\n '}
      +search_index_entry = {'aliases': 'q qu', 'category': 'general', 'key': 'quit', 'no_prefix': ' q qu', 'tags': '', 'text': '\n quit when in unlogged-in state\n\n Usage:\n quit\n\n We maintain a different version of the quit command\n here for unconnected accounts for the sake of simplicity. The logged in\n version is a bit more complicated.\n '}
      @@ -226,7 +226,7 @@ All it does is display the connect screen.

      -aliases = ['l', 'look']
      +aliases = ['look', 'l']
      @@ -252,7 +252,7 @@ All it does is display the connect screen.

      -search_index_entry = {'aliases': 'l look', 'category': 'general', 'key': '__unloggedin_look_command', 'no_prefix': ' l look', 'tags': '', 'text': '\n look when in unlogged-in state\n\n Usage:\n look\n\n This is an unconnected version of the look command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}
      +search_index_entry = {'aliases': 'look l', 'category': 'general', 'key': '__unloggedin_look_command', 'no_prefix': ' look l', 'tags': '', 'text': '\n look when in unlogged-in state\n\n Usage:\n look\n\n This is an unconnected version of the look command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}
      @@ -498,7 +498,6 @@ logged in, use option screenreader on).

      Versions

      diff --git a/docs/1.0-dev/api/evennia.commands.html b/docs/1.0-dev/api/evennia.commands.html index 7f938f9a22..d91b892daf 100644 --- a/docs/1.0-dev/api/evennia.commands.html +++ b/docs/1.0-dev/api/evennia.commands.html @@ -121,7 +121,6 @@ Evennia.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.comms.comms.html b/docs/1.0-dev/api/evennia.comms.comms.html index a69153b4e5..f4c297e6d4 100644 --- a/docs/1.0-dev/api/evennia.comms.comms.html +++ b/docs/1.0-dev/api/evennia.comms.comms.html @@ -862,7 +862,6 @@ responsibility.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.comms.html b/docs/1.0-dev/api/evennia.comms.html index c25a4f45c8..04724d9c9b 100644 --- a/docs/1.0-dev/api/evennia.comms.html +++ b/docs/1.0-dev/api/evennia.comms.html @@ -94,7 +94,6 @@ as code related to external communication like IRC or RSS.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.comms.managers.html b/docs/1.0-dev/api/evennia.comms.managers.html index 7fdf04e19b..cdd1ea7a91 100644 --- a/docs/1.0-dev/api/evennia.comms.managers.html +++ b/docs/1.0-dev/api/evennia.comms.managers.html @@ -421,7 +421,6 @@ case sensitive) match.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.comms.models.html b/docs/1.0-dev/api/evennia.comms.models.html index e4f6886eed..221a10e93e 100644 --- a/docs/1.0-dev/api/evennia.comms.models.html +++ b/docs/1.0-dev/api/evennia.comms.models.html @@ -788,7 +788,6 @@ entities to un-subscribe from the channel.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.awsstorage.aws_s3_cdn.html b/docs/1.0-dev/api/evennia.contrib.base_systems.awsstorage.aws_s3_cdn.html index a3b51511da..0ec08ad1a0 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.awsstorage.aws_s3_cdn.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.awsstorage.aws_s3_cdn.html @@ -40,8 +40,471 @@
      -
      -

      evennia.contrib.base_systems.awsstorage.aws_s3_cdn

      +
      +

      evennia.contrib.base_systems.awsstorage.aws_s3_cdn

      +

      AWS Storage System +The Right Honourable Reverend (trhr) 2020

      +

      ABOUT THIS PLUGIN:

      +

      This plugin migrates the Web-based portion of Evennia, namely images, +javascript, and other items located inside staticfiles into Amazon AWS (S3) for hosting.

      +

      Files hosted on S3 are “in the cloud,” and while your personal +server may be sufficient for serving multimedia to a minimal number of users, +the perfect use case for this plugin would be:

      +
        +
      1. Servers supporting heavy web-based traffic (webclient, etc)

      2. +
      3. With a sizable number of users

      4. +
      5. Where the users are globally distributed

      6. +
      7. Where multimedia files are served to users as a part of gameplay

      8. +
      +

      Bottom line - if you’re sending an image to a player every time they traverse a +map, the bandwidth reduction will be substantial. If not, probably skip +this one.

      +

      Note that storing and serving files via S3 is not technically free outside of +Amazon’s “free tier” offering, which you may or may not be eligible for; +evennia’s base install currently requires 1.5MB of storage space on S3, +making the current total cost to install this plugin ~$0.0005 per year. If +you have substantial media assets and intend to serve them to many users, +caveat emptor on a total cost of ownership - check AWS’s pricing structure.

      +

      See the ./README.md file for details and install instructions.

      +
      +
      +evennia.contrib.base_systems.awsstorage.aws_s3_cdn.setting(name, default=None)[source]
      +

      Helper function to get a Django setting by name. If setting doesn’t exist +it will return a default.

      +
      +
      Parameters
      +

      name (str) – A Django setting name

      +
      +
      Returns
      +

      The value of the setting variable by that name

      +
      +
      +
      + +
      +
      +evennia.contrib.base_systems.awsstorage.aws_s3_cdn.safe_join(base, *paths)[source]
      +

      Helper function, a version of django.utils._os.safe_join for S3 paths. +Joins one or more path components to the base path component +intelligently. Returns a normalized version of the final path. +The final path must be located inside of the base path component +(otherwise a ValueError is raised). Paths outside the base path +indicate a possible security sensitive operation.

      +
      +
      Parameters
      +
        +
      • base (str) – A path string to the base of the staticfiles

      • +
      • *paths (list) – A list of paths as referenced from the base path

      • +
      +
      +
      Returns
      +

      final_path (str) – A joined path, base + filepath

      +
      +
      +
      + +
      +
      +evennia.contrib.base_systems.awsstorage.aws_s3_cdn.check_location(storage)[source]
      +

      Helper function to make sure that the storage location is configured correctly.

      +
      +
      Parameters
      +

      storage (Storage) – A Storage object (Django)

      +
      +
      Raises
      +

      ImproperlyConfigured – If the storage location is not configured correctly, +this is raised.

      +
      +
      +
      + +
      +
      +evennia.contrib.base_systems.awsstorage.aws_s3_cdn.lookup_env(names)[source]
      +

      Helper function for looking up names in env vars. Returns the first element found.

      +
      +
      Parameters
      +

      names (str) – A list of environment variables

      +
      +
      Returns
      +

      value (str) – The value of the found environment variable.

      +
      +
      +
      + +
      +
      +evennia.contrib.base_systems.awsstorage.aws_s3_cdn.get_available_overwrite_name(name, max_length)[source]
      +

      Helper function indicating files that will be overwritten during trunc.

      +
      +
      Parameters
      +
        +
      • name (str) – The name of the file

      • +
      • max_length (int) – The maximum length of a filename

      • +
      +
      +
      Returns
      +

      joined (path) – A joined path including directory, file, and extension

      +
      +
      +
      + +
      +
      +class evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3StorageFile(*args, **kwargs)[source]
      +

      Bases: django.core.files.base.File

      +

      The default file object used by the S3Boto3Storage backend. +This file implements file streaming using boto’s multipart +uploading functionality. The file can be opened in read or +write mode. +This class extends Django’s File class. However, the contained +data is only the data contained in the current buffer. So you +should not access the contained file object directly. You should +access the data via this class. +Warning: This file must be closed using the close() method in +order to properly write the file to S3. Be sure to close the file +in your application.

      +
      +
      +__init__(name, mode, storage, buffer_size=None)[source]
      +

      Initializes the File object.

      +
      +
      Parameters
      +
        +
      • name (str) – The name of the file

      • +
      • mode (str) – The access mode (‘r’ or ‘w’)

      • +
      • storage (Storage) – The Django Storage object

      • +
      • buffer_size (int) – The buffer size, for multipart uploads

      • +
      +
      +
      +
      + +
      +
      +buffer_size = 5242880
      +
      + +
      +
      +property size
      +

      Helper property to return filesize

      +
      + +
      +
      +property file
      +

      Helper function to manage zipping and temporary files

      +
      + +
      +
      +read(*args, **kwargs)[source]
      +

      Checks if file is in read mode; then continues to boto3 operation

      +
      + +
      +
      +readline(*args, **kwargs)[source]
      +

      Checks if file is in read mode; then continues to boto3 operation

      +
      + +
      +
      +write(content)[source]
      +

      Checks if file is in write mode or needs multipart handling, +then continues to boto3 operation.

      +
      + +
      +
      +close()[source]
      +

      Manages file closing after multipart uploads

      +
      + +
      +
      +deconstruct()
      +

      Return a 3-tuple of class import path, positional arguments, +and keyword arguments.

      +
      + +
      + +
      +
      +class evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage(*args, **kwargs)[source]
      +

      Bases: django.core.files.storage.Storage

      +

      Amazon Simple Storage Service using Boto3 +This storage backend supports opening files in read or write +mode and supports streaming(buffering) data in chunks to S3 +when writing.

      +
      +
      +default_content_type = 'application/octet-stream'
      +
      + +
      +
      +access_key_names = ['AWS_S3_ACCESS_KEY_ID', 'AWS_ACCESS_KEY_ID']
      +
      + +
      +
      +secret_key_names = ['AWS_S3_SECRET_ACCESS_KEY', 'AWS_SECRET_ACCESS_KEY']
      +
      + +
      +
      +security_token_names = ['AWS_SESSION_TOKEN', 'AWS_SECURITY_TOKEN']
      +
      + +
      +
      +file_overwrite = True
      +
      + +
      +
      +object_parameters = {}
      +
      + +
      +
      +bucket_name = None
      +
      + +
      +
      +auto_create_bucket = False
      +
      + +
      +
      +default_acl = 'public-read'
      +
      + +
      +
      +bucket_acl = 'public-read'
      +
      + +
      +
      +querystring_auth = True
      +
      + +
      +
      +querystring_expire = 3600
      +
      + +
      +
      +signature_version = None
      +
      + +
      +
      +reduced_redundancy = False
      +
      + +
      +
      +location = ''
      +
      + +
      +
      +encryption = False
      +
      + +
      +
      +custom_domain = None
      +
      + +
      +
      +addressing_style = None
      +
      + +
      +
      +secure_urls = True
      +
      + +
      +
      +file_name_charset = 'utf-8'
      +
      + +
      +
      +gzip = False
      +
      + +
      +
      +preload_metadata = False
      +
      + +
      +
      +gzip_content_types = ('text/css', 'text/javascript', 'application/javascript', 'application/x-javascript', 'image/svg+xml')
      +
      + +
      +
      +endpoint_url = None
      +
      + +
      +
      +proxies = None
      +
      + +
      +
      +region_name = None
      +
      + +
      +
      +use_ssl = True
      +
      + +
      +
      +verify = None
      +
      + +
      +
      +max_memory_size = 0
      +
      + +
      +
      +__init__(acl=None, bucket=None, **settings)[source]
      +

      Check if some of the settings we’ve provided as class attributes +need to be overwritten with values passed in here.

      +
      + +
      +
      +url_protocol = 'http:'
      +
      + +
      +
      +access_key = ''
      +
      + +
      +
      +secret_key = ''
      +
      + +
      +
      +security_token = None
      +
      + +
      +
      +config = None
      +
      + +
      +
      +property connection
      +

      Creates the actual connection to S3

      +
      + +
      +
      +property bucket
      +

      Get the current bucket. If there is no current bucket object +create it.

      +
      + +
      +
      +property entries
      +

      Get the locally cached files for the bucket.

      +
      + +
      +
      +delete(name)[source]
      +

      Deletes a file from S3.

      +
      + +
      +
      +exists(name)[source]
      +

      Checks if file exists.

      +
      + +
      +
      +listdir(name)[source]
      +

      Translational function to go from S3 file paths to the format +Django’s listdir expects.

      +
      + +
      +
      +size(name)[source]
      +

      Gets the filesize of a remote file.

      +
      + +
      +
      +deconstruct()
      +

      Return a 3-tuple of class import path, positional arguments, +and keyword arguments.

      +
      + +
      +
      +get_object_parameters(name)[source]
      +

      Returns a dictionary that is passed to file upload. Override this +method to adjust this on a per-object basis to set e.g ContentDisposition. +By default, returns the value of AWS_S3_OBJECT_PARAMETERS. +Setting ContentEncoding will prevent objects from being automatically gzipped.

      +
      + +
      +
      +get_modified_time(name)[source]
      +

      Returns an (aware) datetime object containing the last modified time if +USE_TZ is True, otherwise returns a naive datetime in the local timezone.

      +
      + +
      +
      +modified_time(name)[source]
      +

      Returns a naive datetime object containing the last modified time. +If USE_TZ=False then get_modified_time will return a naive datetime +so we just return that, else we have to localize and strip the tz

      +
      + +
      +
      +url(name, parameters=None, expire=None)[source]
      +

      Returns the URL of a remotely-hosted file

      +
      + +
      +
      +get_available_name(name, max_length=None)[source]
      +

      Overwrite existing file with the same name.

      +
      + +
      +
      @@ -84,7 +547,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.awsstorage.html b/docs/1.0-dev/api/evennia.contrib.base_systems.awsstorage.html index 5531a6b457..b22e18a2c0 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.awsstorage.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.awsstorage.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.awsstorage.tests.html b/docs/1.0-dev/api/evennia.contrib.base_systems.awsstorage.tests.html index 1ef696988f..0fa98c9633 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.awsstorage.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.awsstorage.tests.html @@ -301,7 +301,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.building_menu.building_menu.html b/docs/1.0-dev/api/evennia.contrib.base_systems.building_menu.building_menu.html index a89dc006d7..a31840aec8 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.building_menu.building_menu.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.building_menu.building_menu.html @@ -924,7 +924,6 @@ set in self.parse())

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.building_menu.html b/docs/1.0-dev/api/evennia.contrib.base_systems.building_menu.html index 25aa11ce9f..168727f9f8 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.building_menu.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.building_menu.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.building_menu.tests.html b/docs/1.0-dev/api/evennia.contrib.base_systems.building_menu.tests.html index 33144f9b5d..5fa57c2a1e 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.building_menu.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.building_menu.tests.html @@ -155,7 +155,6 @@ Use add_choice and its variants to create menu choices.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.color_markups.color_markups.html b/docs/1.0-dev/api/evennia.contrib.base_systems.color_markups.color_markups.html index fd2966889e..a646c84083 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.color_markups.color_markups.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.color_markups.color_markups.html @@ -126,7 +126,6 @@ COLOR_ANSI_BRIGHT_BGS_EXTRA_MAP = color_markups.CURLY_COLOR_ANSI_BRIGHT_BGS_EXTR

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.color_markups.html b/docs/1.0-dev/api/evennia.contrib.base_systems.color_markups.html index 5761000d51..b7649c95b9 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.color_markups.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.color_markups.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.color_markups.tests.html b/docs/1.0-dev/api/evennia.contrib.base_systems.color_markups.tests.html index b21218d0d0..c422a98757 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.color_markups.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.color_markups.tests.html @@ -106,7 +106,6 @@ settings to test it causes issues with unrelated tests.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.custom_gametime.custom_gametime.html b/docs/1.0-dev/api/evennia.contrib.base_systems.custom_gametime.custom_gametime.html index aee1473b39..fa18ca00e5 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.custom_gametime.custom_gametime.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.custom_gametime.custom_gametime.html @@ -323,7 +323,6 @@ The time is given in units as keyword arguments.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.custom_gametime.html b/docs/1.0-dev/api/evennia.contrib.base_systems.custom_gametime.html index babb4d5160..05730c6c0f 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.custom_gametime.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.custom_gametime.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.custom_gametime.tests.html b/docs/1.0-dev/api/evennia.contrib.base_systems.custom_gametime.tests.html index 009101e394..1821cf503b 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.custom_gametime.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.custom_gametime.tests.html @@ -127,7 +127,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.email_login.connection_screens.html b/docs/1.0-dev/api/evennia.contrib.base_systems.email_login.connection_screens.html index e7de846c06..f4ae96e0da 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.email_login.connection_screens.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.email_login.connection_screens.html @@ -99,7 +99,6 @@ of the screen is done by the unlogged-in “look” command.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.email_login.email_login.html b/docs/1.0-dev/api/evennia.contrib.base_systems.email_login.email_login.html index a687de1aca..08ae43583d 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.email_login.email_login.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.email_login.email_login.html @@ -78,7 +78,7 @@ the module given by settings.CONNECTION_SCREEN_MODULE.

      -aliases = ['co', 'con', 'conn']
      +aliases = ['conn', 'co', 'con']
      @@ -108,7 +108,7 @@ there is no object yet before the account has logged in)

      -search_index_entry = {'aliases': 'co con conn', 'category': 'general', 'key': 'connect', 'no_prefix': ' co con conn', 'tags': '', 'text': '\n Connect to the game.\n\n Usage (at login screen):\n connect <email> <password>\n\n Use the create command to first create an account before logging in.\n '}
      +search_index_entry = {'aliases': 'conn co con', 'category': 'general', 'key': 'connect', 'no_prefix': ' conn co con', 'tags': '', 'text': '\n Connect to the game.\n\n Usage (at login screen):\n connect <email> <password>\n\n Use the create command to first create an account before logging in.\n '}
      @@ -130,7 +130,7 @@ there is no object yet before the account has logged in)

      -aliases = ['cre', 'cr']
      +aliases = ['cr', 'cre']
      @@ -166,7 +166,7 @@ name enclosed in quotes:

      -search_index_entry = {'aliases': 'cre cr', 'category': 'general', 'key': 'create', 'no_prefix': ' cre cr', 'tags': '', 'text': '\n Create a new account.\n\n Usage (at login screen):\n create "accountname" <email> <password>\n\n This creates a new account account.\n\n '}
      +search_index_entry = {'aliases': 'cr cre', 'category': 'general', 'key': 'create', 'no_prefix': ' cr cre', 'tags': '', 'text': '\n Create a new account.\n\n Usage (at login screen):\n create "accountname" <email> <password>\n\n This creates a new account account.\n\n '}
      @@ -185,7 +185,7 @@ version is a bit more complicated.

      -aliases = ['qu', 'q']
      +aliases = ['q', 'qu']
      @@ -211,7 +211,7 @@ version is a bit more complicated.

      -search_index_entry = {'aliases': 'qu q', 'category': 'general', 'key': 'quit', 'no_prefix': ' qu q', 'tags': '', 'text': '\n We maintain a different version of the `quit` command\n here for unconnected accounts for the sake of simplicity. The logged in\n version is a bit more complicated.\n '}
      +search_index_entry = {'aliases': 'q qu', 'category': 'general', 'key': 'quit', 'no_prefix': ' q qu', 'tags': '', 'text': '\n We maintain a different version of the `quit` command\n here for unconnected accounts for the sake of simplicity. The logged in\n version is a bit more complicated.\n '}
      @@ -230,7 +230,7 @@ All it does is display the connect screen.

      -aliases = ['l', 'look']
      +aliases = ['look', 'l']
      @@ -256,7 +256,7 @@ All it does is display the connect screen.

      -search_index_entry = {'aliases': 'l look', 'category': 'general', 'key': '__unloggedin_look_command', 'no_prefix': ' l look', 'tags': '', 'text': '\n This is an unconnected version of the `look` command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}
      +search_index_entry = {'aliases': 'look l', 'category': 'general', 'key': '__unloggedin_look_command', 'no_prefix': ' look l', 'tags': '', 'text': '\n This is an unconnected version of the `look` command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}
      @@ -347,7 +347,6 @@ for simplicity. It shows a pane of info.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.email_login.html b/docs/1.0-dev/api/evennia.contrib.base_systems.email_login.html index 8f297cc447..4f9def5480 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.email_login.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.email_login.html @@ -92,7 +92,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.email_login.tests.html b/docs/1.0-dev/api/evennia.contrib.base_systems.email_login.tests.html index 12baffc657..f7277c157e 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.email_login.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.email_login.tests.html @@ -111,7 +111,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.html b/docs/1.0-dev/api/evennia.contrib.base_systems.html index 4ff487b29c..3784cc28a5 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.html @@ -140,7 +140,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.callbackhandler.html b/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.callbackhandler.html index 9e4355a1ee..dc6ad6b939 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.callbackhandler.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.callbackhandler.html @@ -215,63 +215,63 @@ the expected fields for a callback (code, author, valid…).

      class evennia.contrib.base_systems.ingame_python.callbackhandler.Callback(obj, name, number, code, author, valid, parameters, created_on, updated_by, updated_on)

      Bases: tuple

      -
      +
      -author
      +property author

      Alias for field number 4

      -
      +
      -code
      +property code

      Alias for field number 3

      -
      +
      -created_on
      +property created_on

      Alias for field number 7

      -
      +
      -name
      +property name

      Alias for field number 1

      -
      +
      -number
      +property number

      Alias for field number 2

      -
      +
      -obj
      +property obj

      Alias for field number 0

      -
      +
      -parameters
      +property parameters

      Alias for field number 6

      -
      +
      -updated_by
      +property updated_by

      Alias for field number 8

      -
      +
      -updated_on
      +property updated_on

      Alias for field number 9

      -
      +
      -valid
      +property valid

      Alias for field number 5

      @@ -319,7 +319,6 @@ the expected fields for a callback (code, author, valid…).

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.commands.html b/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.commands.html index dac4abe75b..354be75433 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.commands.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.commands.html @@ -55,7 +55,7 @@
      -aliases = ['@calls', '@callbacks', '@callback']
      +aliases = ['@callbacks', '@calls', '@callback']
      @@ -136,7 +136,7 @@ on user permission.

      -search_index_entry = {'aliases': '@calls @callbacks @callback', 'category': 'building', 'key': '@call', 'no_prefix': 'call calls callbacks callback', 'tags': '', 'text': '\n Command to edit callbacks.\n '}
      +search_index_entry = {'aliases': '@callbacks @calls @callback', 'category': 'building', 'key': '@call', 'no_prefix': 'call callbacks calls callback', 'tags': '', 'text': '\n Command to edit callbacks.\n '}
      @@ -183,7 +183,6 @@ on user permission.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.eventfuncs.html b/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.eventfuncs.html index 01080f2ef1..df441b9ca1 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.eventfuncs.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.eventfuncs.html @@ -151,7 +151,6 @@ to be called from inside another event.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.html b/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.html index 46d462d6db..1a767a1ee1 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.html @@ -95,7 +95,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.scripts.html b/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.scripts.html index f7d8d4f363..3242b23e69 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.scripts.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.scripts.html @@ -440,7 +440,6 @@ restart only twice.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.tests.html b/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.tests.html index 8cde7eb763..ef4e4eaf8a 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.tests.html @@ -226,7 +226,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.typeclasses.html b/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.typeclasses.html index 886d842841..5992a43edd 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.typeclasses.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.typeclasses.html @@ -84,7 +84,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.utils.html b/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.utils.html index 24d8f47312..6d0dd97a02 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.utils.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.ingame_python.utils.html @@ -204,7 +204,6 @@ either “yes” or “okay” (maybe ‘say I don’t like it, but okay’).

      Versions diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.menu_login.connection_screens.html b/docs/1.0-dev/api/evennia.contrib.base_systems.menu_login.connection_screens.html index 69d7ff7538..b608a4fa4e 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.menu_login.connection_screens.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.menu_login.connection_screens.html @@ -84,7 +84,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.menu_login.html b/docs/1.0-dev/api/evennia.contrib.base_systems.menu_login.html index 51edd02d6e..e77c02c9f3 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.menu_login.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.menu_login.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.menu_login.menu_login.html b/docs/1.0-dev/api/evennia.contrib.base_systems.menu_login.menu_login.html index 5fe6a0bab7..a7d3bbc635 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.menu_login.menu_login.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.menu_login.menu_login.html @@ -84,7 +84,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.menu_login.tests.html b/docs/1.0-dev/api/evennia.contrib.base_systems.menu_login.tests.html index 74d47601ad..7a25276a1c 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.menu_login.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.menu_login.tests.html @@ -84,7 +84,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.mux_comms_cmds.html b/docs/1.0-dev/api/evennia.contrib.base_systems.mux_comms_cmds.html index 34f09a8fca..5b1b90e4c7 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.mux_comms_cmds.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.mux_comms_cmds.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.html b/docs/1.0-dev/api/evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.html index 58c6104bbf..ad36fb4026 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.html @@ -156,7 +156,7 @@ for that channel.

      -aliases = ['delaliaschan', 'delchanalias']
      +aliases = ['delchanalias', 'delaliaschan']
      @@ -187,7 +187,7 @@ for that channel.

      -search_index_entry = {'aliases': 'delaliaschan delchanalias', 'category': 'comms', 'key': 'delcom', 'no_prefix': ' delaliaschan delchanalias', 'tags': '', 'text': "\n remove a channel alias and/or unsubscribe from channel\n\n Usage:\n delcom <alias or channel>\n delcom/all <channel>\n\n If the full channel name is given, unsubscribe from the\n channel. If an alias is given, remove the alias but don't\n unsubscribe. If the 'all' switch is used, remove all aliases\n for that channel.\n "}
      +search_index_entry = {'aliases': 'delchanalias delaliaschan', 'category': 'comms', 'key': 'delcom', 'no_prefix': ' delchanalias delaliaschan', 'tags': '', 'text': "\n remove a channel alias and/or unsubscribe from channel\n\n Usage:\n delcom <alias or channel>\n delcom/all <channel>\n\n If the full channel name is given, unsubscribe from the\n channel. If an alias is given, remove the alias but don't\n unsubscribe. If the 'all' switch is used, remove all aliases\n for that channel.\n "}
      @@ -633,7 +633,6 @@ channel lists.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.mux_comms_cmds.tests.html b/docs/1.0-dev/api/evennia.contrib.base_systems.mux_comms_cmds.tests.html index 698230f720..87b675518d 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.mux_comms_cmds.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.mux_comms_cmds.tests.html @@ -133,7 +133,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.unixcommand.html b/docs/1.0-dev/api/evennia.contrib.base_systems.unixcommand.html index 37ced182a8..8fd99589f8 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.unixcommand.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.unixcommand.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.unixcommand.tests.html b/docs/1.0-dev/api/evennia.contrib.base_systems.unixcommand.tests.html index a1f336edba..b22929a3f3 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.unixcommand.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.unixcommand.tests.html @@ -147,7 +147,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.base_systems.unixcommand.unixcommand.html b/docs/1.0-dev/api/evennia.contrib.base_systems.unixcommand.unixcommand.html index 02e628c7cb..4e357b06c1 100644 --- a/docs/1.0-dev/api/evennia.contrib.base_systems.unixcommand.unixcommand.html +++ b/docs/1.0-dev/api/evennia.contrib.base_systems.unixcommand.unixcommand.html @@ -373,7 +373,6 @@ use its add_argument method.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.commands.html b/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.commands.html index 6ae3edafca..006b19102f 100644 --- a/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.commands.html +++ b/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.commands.html @@ -150,7 +150,7 @@ the operation will be general or on the room.

      -aliases = ['q', 'abort', 'quit', 'chicken out']
      +aliases = ['abort', 'quit', 'q', 'chicken out']
      @@ -174,7 +174,7 @@ set in self.parse())

      -search_index_entry = {'aliases': 'q abort quit chicken out', 'category': 'evscaperoom', 'key': 'give up', 'no_prefix': ' q abort quit chicken out', 'tags': '', 'text': '\n Give up\n\n Usage:\n give up\n\n Abandons your attempts at escaping and of ever winning the pie-eating contest.\n\n '}
      +search_index_entry = {'aliases': 'abort quit q chicken out', 'category': 'evscaperoom', 'key': 'give up', 'no_prefix': ' abort quit q chicken out', 'tags': '', 'text': '\n Give up\n\n Usage:\n give up\n\n Abandons your attempts at escaping and of ever winning the pie-eating contest.\n\n '}
      @@ -195,7 +195,7 @@ set in self.parse())

      -aliases = ['ls', 'l']
      +aliases = ['l', 'ls']
      @@ -229,7 +229,7 @@ set in self.parse())

      -search_index_entry = {'aliases': 'ls l', 'category': 'evscaperoom', 'key': 'look', 'no_prefix': ' ls l', 'tags': '', 'text': '\n Look at the room, an object or the currently focused object\n\n Usage:\n look [obj]\n\n '}
      +search_index_entry = {'aliases': 'l ls', 'category': 'evscaperoom', 'key': 'look', 'no_prefix': ' l ls', 'tags': '', 'text': '\n Look at the room, an object or the currently focused object\n\n Usage:\n look [obj]\n\n '}
      @@ -310,7 +310,7 @@ shout

      -aliases = ['whisper', ';', 'shout']
      +aliases = ['whisper', 'shout', ';']
      @@ -339,7 +339,7 @@ set in self.parse())

      -search_index_entry = {'aliases': 'whisper ; shout', 'category': 'general', 'key': 'say', 'no_prefix': ' whisper ; shout', 'tags': '', 'text': '\n Perform an communication action.\n\n Usage:\n say <text>\n whisper\n shout\n\n '}
      +search_index_entry = {'aliases': 'whisper shout ;', 'category': 'general', 'key': 'say', 'no_prefix': ' whisper shout ;', 'tags': '', 'text': '\n Perform an communication action.\n\n Usage:\n say <text>\n whisper\n shout\n\n '}
      @@ -367,7 +367,7 @@ emote /me points to /box and /lever.

      -aliases = [':', 'pose']
      +aliases = ['pose', ':']
      @@ -406,7 +406,7 @@ set in self.parse())

      -search_index_entry = {'aliases': ': pose', 'category': 'general', 'key': 'emote', 'no_prefix': ' : pose', 'tags': '', 'text': '\n Perform a free-form emote. Use /me to\n include yourself in the emote and /name\n to include other objects or characters.\n Use "..." to enact speech.\n\n Usage:\n emote <emote>\n :<emote\n\n Example:\n emote /me smiles at /peter\n emote /me points to /box and /lever.\n\n '}
      +search_index_entry = {'aliases': 'pose :', 'category': 'general', 'key': 'emote', 'no_prefix': ' pose :', 'tags': '', 'text': '\n Perform a free-form emote. Use /me to\n include yourself in the emote and /name\n to include other objects or characters.\n Use "..." to enact speech.\n\n Usage:\n emote <emote>\n :<emote\n\n Example:\n emote /me smiles at /peter\n emote /me points to /box and /lever.\n\n '}
      @@ -429,7 +429,7 @@ looks and what actions is available.

      -aliases = ['ex', 'e', 'examine', 'unfocus']
      +aliases = ['e', 'examine', 'unfocus', 'ex']
      @@ -458,7 +458,7 @@ set in self.parse())

      -search_index_entry = {'aliases': 'ex e examine unfocus', 'category': 'evscaperoom', 'key': 'focus', 'no_prefix': ' ex e examine unfocus', 'tags': '', 'text': '\n Focus your attention on a target.\n\n Usage:\n focus <obj>\n\n Once focusing on an object, use look to get more information about how it\n looks and what actions is available.\n\n '}
      +search_index_entry = {'aliases': 'e examine unfocus ex', 'category': 'evscaperoom', 'key': 'focus', 'no_prefix': ' e examine unfocus ex', 'tags': '', 'text': '\n Focus your attention on a target.\n\n Usage:\n focus <obj>\n\n Once focusing on an object, use look to get more information about how it\n looks and what actions is available.\n\n '}
      @@ -520,7 +520,7 @@ set in self.parse())

      -aliases = ['i', 'inv', 'inventory', 'give']
      +aliases = ['inventory', 'i', 'give', 'inv']
      @@ -544,7 +544,7 @@ set in self.parse())

      -search_index_entry = {'aliases': 'i inv inventory give', 'category': 'evscaperoom', 'key': 'get', 'no_prefix': ' i inv inventory give', 'tags': '', 'text': '\n Use focus / examine instead.\n\n '}
      +search_index_entry = {'aliases': 'inventory i give inv', 'category': 'evscaperoom', 'key': 'get', 'no_prefix': ' inventory i give inv', 'tags': '', 'text': '\n Use focus / examine instead.\n\n '}
      @@ -1037,7 +1037,6 @@ self.add().

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.html b/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.html index beaff965c5..9b3c616df8 100644 --- a/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.html +++ b/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.html @@ -97,7 +97,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.menu.html b/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.menu.html index d40f2f6845..68822af970 100644 --- a/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.menu.html +++ b/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.menu.html @@ -194,7 +194,6 @@ option related to this node.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.objects.html b/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.objects.html index 5b6c9ea68c..1504b00a7e 100644 --- a/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.objects.html +++ b/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.objects.html @@ -1814,7 +1814,6 @@ inject the list of callsigns.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.room.html b/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.room.html index 79ed32d65d..f7a8d53f9f 100644 --- a/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.room.html +++ b/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.room.html @@ -273,7 +273,6 @@ contents of the object by default.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.scripts.html b/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.scripts.html index 0e3049ccd8..60b12944a3 100644 --- a/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.scripts.html +++ b/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.scripts.html @@ -134,7 +134,6 @@ overriding the call (unused by default).

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.state.html b/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.state.html index 02060ab3cb..45d5b61d40 100644 --- a/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.state.html +++ b/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.state.html @@ -270,7 +270,6 @@ happens just before room.character_cleanup()

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.tests.html b/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.tests.html index 6d55e2b786..2481ff938a 100644 --- a/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.tests.html @@ -210,7 +210,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.utils.html b/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.utils.html index 2721209dc9..8f92a8607b 100644 --- a/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.utils.html +++ b/docs/1.0-dev/api/evennia.contrib.full_systems.evscaperoom.utils.html @@ -202,7 +202,6 @@ surrounded by borders.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.full_systems.html b/docs/1.0-dev/api/evennia.contrib.full_systems.html index 65053a8abc..e338efd9b8 100644 --- a/docs/1.0-dev/api/evennia.contrib.full_systems.html +++ b/docs/1.0-dev/api/evennia.contrib.full_systems.html @@ -100,7 +100,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.barter.barter.html b/docs/1.0-dev/api/evennia.contrib.game_systems.barter.barter.html index 5ce84d7646..993058f8db 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.barter.barter.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.barter.barter.html @@ -885,7 +885,6 @@ info to your choice.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.barter.html b/docs/1.0-dev/api/evennia.contrib.game_systems.barter.html index b41259c4b9..bc2258b90e 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.barter.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.barter.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.barter.tests.html b/docs/1.0-dev/api/evennia.contrib.game_systems.barter.tests.html index 8716842c16..026dfa3ec7 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.barter.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.barter.tests.html @@ -122,7 +122,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.clothing.clothing.html b/docs/1.0-dev/api/evennia.contrib.game_systems.clothing.clothing.html index 39b2131185..1699b8634e 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.clothing.clothing.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.clothing.clothing.html @@ -735,7 +735,6 @@ items.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.clothing.html b/docs/1.0-dev/api/evennia.contrib.game_systems.clothing.html index e41875d271..53ee8bc961 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.clothing.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.clothing.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.clothing.tests.html b/docs/1.0-dev/api/evennia.contrib.game_systems.clothing.tests.html index 32095187db..9446584557 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.clothing.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.clothing.tests.html @@ -107,7 +107,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.cooldowns.cooldowns.html b/docs/1.0-dev/api/evennia.contrib.game_systems.cooldowns.cooldowns.html index aff48ec092..ba73f08951 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.cooldowns.cooldowns.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.cooldowns.cooldowns.html @@ -318,7 +318,6 @@ requirements small.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.cooldowns.html b/docs/1.0-dev/api/evennia.contrib.game_systems.cooldowns.html index fdfaa0168e..2cb2c21d68 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.cooldowns.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.cooldowns.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.cooldowns.tests.html b/docs/1.0-dev/api/evennia.contrib.game_systems.cooldowns.tests.html index a025483bff..f01a42ff96 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.cooldowns.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.cooldowns.tests.html @@ -177,7 +177,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.crafting.crafting.html b/docs/1.0-dev/api/evennia.contrib.game_systems.crafting.crafting.html index b2bfd030a8..3fce2249dd 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.crafting.crafting.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.crafting.crafting.html @@ -867,7 +867,6 @@ the crafting_tool_err_msg if available.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.crafting.example_recipes.html b/docs/1.0-dev/api/evennia.contrib.game_systems.crafting.example_recipes.html index 7b79fb4682..1af6e80a01 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.crafting.example_recipes.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.crafting.example_recipes.html @@ -577,7 +577,6 @@ set in self.parse())

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.crafting.html b/docs/1.0-dev/api/evennia.contrib.game_systems.crafting.html index d8405ba133..c0fda73671 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.crafting.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.crafting.html @@ -102,7 +102,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.crafting.tests.html b/docs/1.0-dev/api/evennia.contrib.game_systems.crafting.tests.html index fbee692699..c62e15b8a4 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.crafting.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.crafting.tests.html @@ -297,7 +297,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.gendersub.gendersub.html b/docs/1.0-dev/api/evennia.contrib.game_systems.gendersub.gendersub.html index 2c49cff2bf..2bda131fa4 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.gendersub.gendersub.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.gendersub.gendersub.html @@ -224,7 +224,6 @@ All extra kwargs will be passed on to the protocol.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.gendersub.html b/docs/1.0-dev/api/evennia.contrib.game_systems.gendersub.html index 1af4ada0e7..6a999253a2 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.gendersub.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.gendersub.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.gendersub.tests.html b/docs/1.0-dev/api/evennia.contrib.game_systems.gendersub.tests.html index 5bdcb7e88a..69fb942448 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.gendersub.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.gendersub.tests.html @@ -101,7 +101,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.html b/docs/1.0-dev/api/evennia.contrib.game_systems.html index 05d81407b8..491e5bcb75 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.html @@ -148,7 +148,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.mail.html b/docs/1.0-dev/api/evennia.contrib.game_systems.mail.html index dc9c7d5226..f07f1512ef 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.mail.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.mail.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.mail.mail.html b/docs/1.0-dev/api/evennia.contrib.game_systems.mail.mail.html index 524cccc0c0..467926b1ec 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.mail.mail.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.mail.mail.html @@ -343,7 +343,6 @@ reply - Replies to a received message, appending the original message to the b

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.mail.tests.html b/docs/1.0-dev/api/evennia.contrib.game_systems.mail.tests.html index 728b26bc5e..f6095905e3 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.mail.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.mail.tests.html @@ -96,7 +96,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.multidescer.html b/docs/1.0-dev/api/evennia.contrib.game_systems.multidescer.html index dcc9b8be78..b8fc0fe673 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.multidescer.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.multidescer.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.multidescer.multidescer.html b/docs/1.0-dev/api/evennia.contrib.game_systems.multidescer.multidescer.html index bcfabba762..09b880cd59 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.multidescer.multidescer.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.multidescer.multidescer.html @@ -168,7 +168,6 @@ description in use and db.multidesc to store all descriptions.<

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.multidescer.tests.html b/docs/1.0-dev/api/evennia.contrib.game_systems.multidescer.tests.html index 72dba6c5cb..df74c5f9a1 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.multidescer.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.multidescer.tests.html @@ -96,7 +96,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.puzzles.html b/docs/1.0-dev/api/evennia.contrib.game_systems.puzzles.html index 5b8de1f41a..3b25a1ea42 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.puzzles.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.puzzles.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.puzzles.puzzles.html b/docs/1.0-dev/api/evennia.contrib.game_systems.puzzles.puzzles.html index a5c9e083ec..3cf20de622 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.puzzles.puzzles.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.puzzles.puzzles.html @@ -550,7 +550,6 @@ self.add().

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.puzzles.tests.html b/docs/1.0-dev/api/evennia.contrib.game_systems.puzzles.tests.html index a051d4f8d3..0246c335c4 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.puzzles.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.puzzles.tests.html @@ -147,7 +147,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.html b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.html index e5f941beff..1e98dda8ae 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.html @@ -95,7 +95,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_basic.html b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_basic.html index deb755259e..6783062a07 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_basic.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_basic.html @@ -799,7 +799,6 @@ topics related to the game.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_equip.html b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_equip.html index e2550808cb..34f942c880 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_equip.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_equip.html @@ -1098,7 +1098,6 @@ You can’t use this command in combat.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_items.html b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_items.html index b6e4d3c373..f339e3056f 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_items.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_items.html @@ -1078,7 +1078,6 @@ items using the same function work differently.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_magic.html b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_magic.html index 13a03a9906..3a7f54d261 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_magic.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_magic.html @@ -1027,7 +1027,6 @@ instead of creating objects directly.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_range.html b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_range.html index be3daf60fc..a8f31574c5 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_range.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tb_range.html @@ -1293,7 +1293,6 @@ topics related to the game.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tests.html b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tests.html index 8617ea8a83..6baafa63db 100644 --- a/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.game_systems.turnbattle.tests.html @@ -267,7 +267,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.extended_room.extended_room.html b/docs/1.0-dev/api/evennia.contrib.grid.extended_room.extended_room.html index 7eb533864a..c8c8e3a0f7 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.extended_room.extended_room.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.extended_room.extended_room.html @@ -279,7 +279,7 @@ look *<account&g
      -aliases = ['ls', 'l']
      +aliases = ['l', 'ls']
      @@ -299,7 +299,7 @@ look *<account&g
      -search_index_entry = {'aliases': 'ls l', 'category': 'general', 'key': 'look', 'no_prefix': ' ls l', 'tags': '', 'text': '\n look\n\n Usage:\n look\n look <obj>\n look <room detail>\n look *<account>\n\n Observes your location, details at your location or objects in your vicinity.\n '}
      +search_index_entry = {'aliases': 'l ls', 'category': 'general', 'key': 'look', 'no_prefix': ' l ls', 'tags': '', 'text': '\n look\n\n Usage:\n look\n look <obj>\n look <room detail>\n look *<account>\n\n Observes your location, details at your location or objects in your vicinity.\n '}
      @@ -545,7 +545,6 @@ self.add().

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.extended_room.html b/docs/1.0-dev/api/evennia.contrib.grid.extended_room.html index b3e07e5536..0ecfa6399e 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.extended_room.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.extended_room.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.extended_room.tests.html b/docs/1.0-dev/api/evennia.contrib.grid.extended_room.tests.html index 2844566b1d..4ac6bb5282 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.extended_room.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.extended_room.tests.html @@ -156,7 +156,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.html b/docs/1.0-dev/api/evennia.contrib.grid.html index d5dd077f00..b39e5b76b7 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.html @@ -146,7 +146,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.mapbuilder.html b/docs/1.0-dev/api/evennia.contrib.grid.mapbuilder.html index 33ad0a655e..6c894e9d58 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.mapbuilder.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.mapbuilder.html @@ -90,7 +90,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.mapbuilder.mapbuilder.html b/docs/1.0-dev/api/evennia.contrib.grid.mapbuilder.mapbuilder.html index 24fd3591d7..6926312e8b 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.mapbuilder.mapbuilder.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.mapbuilder.mapbuilder.html @@ -84,7 +84,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.mapbuilder.tests.html b/docs/1.0-dev/api/evennia.contrib.grid.mapbuilder.tests.html index 0ac1415e54..ebae6a65db 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.mapbuilder.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.mapbuilder.tests.html @@ -84,7 +84,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.simpledoor.html b/docs/1.0-dev/api/evennia.contrib.grid.simpledoor.html index e2d440cfb9..717e7ef38e 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.simpledoor.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.simpledoor.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.simpledoor.simpledoor.html b/docs/1.0-dev/api/evennia.contrib.grid.simpledoor.simpledoor.html index 6311fc1647..71cdc328f9 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.simpledoor.simpledoor.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.simpledoor.simpledoor.html @@ -308,7 +308,6 @@ self.add().

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.simpledoor.tests.html b/docs/1.0-dev/api/evennia.contrib.grid.simpledoor.tests.html index 90f91edd7c..fddee8b898 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.simpledoor.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.simpledoor.tests.html @@ -96,7 +96,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.slow_exit.html b/docs/1.0-dev/api/evennia.contrib.grid.slow_exit.html index 2cadc32c5f..8a7a617f08 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.slow_exit.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.slow_exit.html @@ -98,7 +98,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.slow_exit.slow_exit.html b/docs/1.0-dev/api/evennia.contrib.grid.slow_exit.slow_exit.html index 871135a59b..2a889e6b5c 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.slow_exit.slow_exit.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.slow_exit.slow_exit.html @@ -282,7 +282,6 @@ self.add().

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.slow_exit.tests.html b/docs/1.0-dev/api/evennia.contrib.grid.slow_exit.tests.html index 24c18b46a2..408bb57b83 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.slow_exit.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.slow_exit.tests.html @@ -96,7 +96,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.wilderness.html b/docs/1.0-dev/api/evennia.contrib.grid.wilderness.html index 6b59922478..c2d321f10d 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.wilderness.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.wilderness.html @@ -97,7 +97,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.wilderness.tests.html b/docs/1.0-dev/api/evennia.contrib.grid.wilderness.tests.html index fe008aaa5d..39a0b27cc3 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.wilderness.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.wilderness.tests.html @@ -142,7 +142,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.wilderness.wilderness.html b/docs/1.0-dev/api/evennia.contrib.grid.wilderness.wilderness.html index 3f75b138e9..ac983a8e66 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.wilderness.wilderness.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.wilderness.wilderness.html @@ -718,7 +718,6 @@ coordinate.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.commands.html b/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.commands.html index 12fa45ad78..7847063b9c 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.commands.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.commands.html @@ -49,33 +49,33 @@ the commands with XYZ-aware equivalents.

      class evennia.contrib.grid.xyzgrid.commands.PathData(target, xymap, directions, step_sequence, task)

      Bases: tuple

      -
      +
      -directions
      +property directions

      Alias for field number 2

      -
      +
      -step_sequence
      +property step_sequence

      Alias for field number 3

      -
      +
      -target
      +property target

      Alias for field number 0

      -
      +
      -task
      +property task

      Alias for field number 4

      -
      +
      -xymap
      +property xymap

      Alias for field number 1

      @@ -384,7 +384,6 @@ self.add().

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.example.html b/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.example.html index 394e0c8450..dfa19a1028 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.example.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.example.html @@ -132,7 +132,6 @@ into a room by only acts as a target for finding the exit’s destination.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.html b/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.html index 6412d88020..7c09912794 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.html @@ -105,7 +105,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.launchcmd.html b/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.launchcmd.html index 99eb088dab..d0c108ba47 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.launchcmd.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.launchcmd.html @@ -102,7 +102,6 @@ once added to settings.EXTRA_LAUNCHER_COMMANDS.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.prototypes.html b/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.prototypes.html index 67a660eeea..aadf08494d 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.prototypes.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.prototypes.html @@ -97,7 +97,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.tests.html b/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.tests.html index a6497da6fb..880f73248d 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.tests.html @@ -1362,7 +1362,6 @@ different visibility distances.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.utils.html b/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.utils.html index 92aa67371a..61026a3b0a 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.utils.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.utils.html @@ -111,7 +111,6 @@ leads to another map.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.xymap.html b/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.xymap.html index 8950158c48..8ff70b229e 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.xymap.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.xymap.html @@ -523,7 +523,6 @@ weights and may also show nodes not actually reachable at the moment:

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.xymap_legend.html b/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.xymap_legend.html index f5a1116e9f..5ecfd45150 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.xymap_legend.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.xymap_legend.html @@ -1273,7 +1273,6 @@ one-way link out of the teleporter on one side.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.xyzgrid.html b/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.xyzgrid.html index 7479f232d1..13de2f9ecb 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.xyzgrid.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.xyzgrid.html @@ -316,7 +316,6 @@ previously exist.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.xyzroom.html b/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.xyzroom.html index a8519d571e..84696f1536 100644 --- a/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.xyzroom.html +++ b/docs/1.0-dev/api/evennia.contrib.grid.xyzgrid.xyzroom.html @@ -515,7 +515,6 @@ be any room (including non-XYRooms) and is not checked for XYZ coordinates.

      <

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.html b/docs/1.0-dev/api/evennia.contrib.html index 89d0fec8a1..75476b4ecc 100644 --- a/docs/1.0-dev/api/evennia.contrib.html +++ b/docs/1.0-dev/api/evennia.contrib.html @@ -392,7 +392,6 @@ useful but are deemed too game-specific to go into the core library.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.rpg.dice.dice.html b/docs/1.0-dev/api/evennia.contrib.rpg.dice.dice.html index d7751b4d96..fb84c39fe7 100644 --- a/docs/1.0-dev/api/evennia.contrib.rpg.dice.dice.html +++ b/docs/1.0-dev/api/evennia.contrib.rpg.dice.dice.html @@ -337,7 +337,6 @@ Add with @py self.cmdset.add(“contrib.dice.DiceCmdSet”)

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.rpg.dice.html b/docs/1.0-dev/api/evennia.contrib.rpg.dice.html index bd399e91e2..a2d6a3f539 100644 --- a/docs/1.0-dev/api/evennia.contrib.rpg.dice.html +++ b/docs/1.0-dev/api/evennia.contrib.rpg.dice.html @@ -96,7 +96,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.rpg.dice.tests.html b/docs/1.0-dev/api/evennia.contrib.rpg.dice.tests.html index cf2c39afd1..20c48b0352 100644 --- a/docs/1.0-dev/api/evennia.contrib.rpg.dice.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.rpg.dice.tests.html @@ -101,7 +101,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.rpg.health_bar.health_bar.html b/docs/1.0-dev/api/evennia.contrib.rpg.health_bar.health_bar.html index 0b765b2aab..244cd1c8df 100644 --- a/docs/1.0-dev/api/evennia.contrib.rpg.health_bar.health_bar.html +++ b/docs/1.0-dev/api/evennia.contrib.rpg.health_bar.health_bar.html @@ -149,7 +149,6 @@ readers will be unable to read the graphical aspect of the bar.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.rpg.health_bar.html b/docs/1.0-dev/api/evennia.contrib.rpg.health_bar.html index a22ac2585a..1055df0703 100644 --- a/docs/1.0-dev/api/evennia.contrib.rpg.health_bar.html +++ b/docs/1.0-dev/api/evennia.contrib.rpg.health_bar.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.rpg.health_bar.tests.html b/docs/1.0-dev/api/evennia.contrib.rpg.health_bar.tests.html index 17310ae681..ac072de188 100644 --- a/docs/1.0-dev/api/evennia.contrib.rpg.health_bar.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.rpg.health_bar.tests.html @@ -96,7 +96,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.rpg.html b/docs/1.0-dev/api/evennia.contrib.rpg.html index dbe504fe34..71fd1522d2 100644 --- a/docs/1.0-dev/api/evennia.contrib.rpg.html +++ b/docs/1.0-dev/api/evennia.contrib.rpg.html @@ -135,7 +135,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.rpg.rpsystem.html b/docs/1.0-dev/api/evennia.contrib.rpg.rpsystem.html index 4e6f15090f..0f05c65bad 100644 --- a/docs/1.0-dev/api/evennia.contrib.rpg.rpsystem.html +++ b/docs/1.0-dev/api/evennia.contrib.rpg.rpsystem.html @@ -92,7 +92,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.rpg.rpsystem.rplanguage.html b/docs/1.0-dev/api/evennia.contrib.rpg.rpsystem.rplanguage.html index b060f51799..8f9e318550 100644 --- a/docs/1.0-dev/api/evennia.contrib.rpg.rpsystem.rplanguage.html +++ b/docs/1.0-dev/api/evennia.contrib.rpg.rpsystem.rplanguage.html @@ -411,7 +411,6 @@ means fully obscured.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.rpg.rpsystem.rpsystem.html b/docs/1.0-dev/api/evennia.contrib.rpg.rpsystem.rpsystem.html index 7f90f6d21b..2ddc6bb432 100644 --- a/docs/1.0-dev/api/evennia.contrib.rpg.rpsystem.rpsystem.html +++ b/docs/1.0-dev/api/evennia.contrib.rpg.rpsystem.rpsystem.html @@ -1375,7 +1375,6 @@ the evennia.contrib.rpg.rplanguage module.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.rpg.rpsystem.tests.html b/docs/1.0-dev/api/evennia.contrib.rpg.rpsystem.tests.html index d19a757c9b..d1118a3e0b 100644 --- a/docs/1.0-dev/api/evennia.contrib.rpg.rpsystem.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.rpg.rpsystem.tests.html @@ -203,7 +203,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.rpg.traits.html b/docs/1.0-dev/api/evennia.contrib.rpg.traits.html index 28ef7c3cbb..8a5ad08ae3 100644 --- a/docs/1.0-dev/api/evennia.contrib.rpg.traits.html +++ b/docs/1.0-dev/api/evennia.contrib.rpg.traits.html @@ -112,7 +112,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.rpg.traits.tests.html b/docs/1.0-dev/api/evennia.contrib.rpg.traits.tests.html index 7c0de83a9f..63c7ade77f 100644 --- a/docs/1.0-dev/api/evennia.contrib.rpg.traits.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.rpg.traits.tests.html @@ -578,7 +578,6 @@ under the hood.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.rpg.traits.traits.html b/docs/1.0-dev/api/evennia.contrib.rpg.traits.traits.html index c26cb535fa..741c22a34a 100644 --- a/docs/1.0-dev/api/evennia.contrib.rpg.traits.traits.html +++ b/docs/1.0-dev/api/evennia.contrib.rpg.traits.traits.html @@ -1058,7 +1058,6 @@ returned.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.batchprocessor.example_batch_code.html b/docs/1.0-dev/api/evennia.contrib.tutorials.batchprocessor.example_batch_code.html index 1e8a05b3ae..86abe44939 100644 --- a/docs/1.0-dev/api/evennia.contrib.tutorials.batchprocessor.example_batch_code.html +++ b/docs/1.0-dev/api/evennia.contrib.tutorials.batchprocessor.example_batch_code.html @@ -84,7 +84,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.batchprocessor.html b/docs/1.0-dev/api/evennia.contrib.tutorials.batchprocessor.html index d4f8cd5d7e..089f86d3d2 100644 --- a/docs/1.0-dev/api/evennia.contrib.tutorials.batchprocessor.html +++ b/docs/1.0-dev/api/evennia.contrib.tutorials.batchprocessor.html @@ -90,7 +90,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.bodyfunctions.bodyfunctions.html b/docs/1.0-dev/api/evennia.contrib.tutorials.bodyfunctions.bodyfunctions.html index 2d0217635a..c499fc0d96 100644 --- a/docs/1.0-dev/api/evennia.contrib.tutorials.bodyfunctions.bodyfunctions.html +++ b/docs/1.0-dev/api/evennia.contrib.tutorials.bodyfunctions.bodyfunctions.html @@ -141,7 +141,6 @@ a random check here so as to only return 33% of the time.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.bodyfunctions.html b/docs/1.0-dev/api/evennia.contrib.tutorials.bodyfunctions.html index f6f4d93383..a3991ff1da 100644 --- a/docs/1.0-dev/api/evennia.contrib.tutorials.bodyfunctions.html +++ b/docs/1.0-dev/api/evennia.contrib.tutorials.bodyfunctions.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.bodyfunctions.tests.html b/docs/1.0-dev/api/evennia.contrib.tutorials.bodyfunctions.tests.html index 7fd106f7d6..ede8f66b94 100644 --- a/docs/1.0-dev/api/evennia.contrib.tutorials.bodyfunctions.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.tutorials.bodyfunctions.tests.html @@ -121,7 +121,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.html b/docs/1.0-dev/api/evennia.contrib.tutorials.html index 0855f3a366..51239365f9 100644 --- a/docs/1.0-dev/api/evennia.contrib.tutorials.html +++ b/docs/1.0-dev/api/evennia.contrib.tutorials.html @@ -122,7 +122,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.mirror.html b/docs/1.0-dev/api/evennia.contrib.tutorials.mirror.html index 414e2de456..fd1662f954 100644 --- a/docs/1.0-dev/api/evennia.contrib.tutorials.mirror.html +++ b/docs/1.0-dev/api/evennia.contrib.tutorials.mirror.html @@ -90,7 +90,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.mirror.mirror.html b/docs/1.0-dev/api/evennia.contrib.tutorials.mirror.mirror.html index 7a541d07b8..a6baacb6c8 100644 --- a/docs/1.0-dev/api/evennia.contrib.tutorials.mirror.mirror.html +++ b/docs/1.0-dev/api/evennia.contrib.tutorials.mirror.mirror.html @@ -155,7 +155,6 @@ on all entities in it.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.red_button.html b/docs/1.0-dev/api/evennia.contrib.tutorials.red_button.html index 51f7581c06..8e6c6c0daa 100644 --- a/docs/1.0-dev/api/evennia.contrib.tutorials.red_button.html +++ b/docs/1.0-dev/api/evennia.contrib.tutorials.red_button.html @@ -93,7 +93,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.red_button.red_button.html b/docs/1.0-dev/api/evennia.contrib.tutorials.red_button.red_button.html index 81611f83ac..615be066f8 100644 --- a/docs/1.0-dev/api/evennia.contrib.tutorials.red_button.red_button.html +++ b/docs/1.0-dev/api/evennia.contrib.tutorials.red_button.red_button.html @@ -183,7 +183,7 @@ check if the lid is open or closed.

      -aliases = ['smash', 'smash lid', 'break lid']
      +aliases = ['break lid', 'smash lid', 'smash']
      @@ -210,7 +210,7 @@ break.

      -search_index_entry = {'aliases': 'smash smash lid break lid', 'category': 'general', 'key': 'smash glass', 'no_prefix': ' smash smash lid break lid', 'tags': '', 'text': '\n Smash the protective glass.\n\n Usage:\n smash glass\n\n Try to smash the glass of the button.\n\n '}
      +search_index_entry = {'aliases': 'break lid smash lid smash', 'category': 'general', 'key': 'smash glass', 'no_prefix': ' break lid smash lid smash', 'tags': '', 'text': '\n Smash the protective glass.\n\n Usage:\n smash glass\n\n Try to smash the glass of the button.\n\n '}
      @@ -437,7 +437,7 @@ be mutually exclusive.

      -aliases = ['ex', 'l', 'feel', 'examine', 'get', 'listen']
      +aliases = ['feel', 'l', 'examine', 'listen', 'ex', 'get']
      @@ -463,7 +463,7 @@ be mutually exclusive.

      -search_index_entry = {'aliases': 'ex l feel examine get listen', 'category': 'general', 'key': 'look', 'no_prefix': ' ex l feel examine get listen', 'tags': '', 'text': "\n Looking around in darkness\n\n Usage:\n look <obj>\n\n ... not that there's much to see in the dark.\n\n "}
      +search_index_entry = {'aliases': 'feel l examine listen ex get', 'category': 'general', 'key': 'look', 'no_prefix': ' feel l examine listen ex get', 'tags': '', 'text': "\n Looking around in darkness\n\n Usage:\n look <obj>\n\n ... not that there's much to see in the dark.\n\n "}
      @@ -747,7 +747,6 @@ temporarily.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.talking_npc.html b/docs/1.0-dev/api/evennia.contrib.tutorials.talking_npc.html index 43b6854d6a..e9f19ee574 100644 --- a/docs/1.0-dev/api/evennia.contrib.tutorials.talking_npc.html +++ b/docs/1.0-dev/api/evennia.contrib.tutorials.talking_npc.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.talking_npc.talking_npc.html b/docs/1.0-dev/api/evennia.contrib.tutorials.talking_npc.talking_npc.html index 5471719588..7b55b0bed0 100644 --- a/docs/1.0-dev/api/evennia.contrib.tutorials.talking_npc.talking_npc.html +++ b/docs/1.0-dev/api/evennia.contrib.tutorials.talking_npc.talking_npc.html @@ -233,7 +233,6 @@ the conversation defined above.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.talking_npc.tests.html b/docs/1.0-dev/api/evennia.contrib.tutorials.talking_npc.tests.html index 6f47835157..3c4215c29c 100644 --- a/docs/1.0-dev/api/evennia.contrib.tutorials.talking_npc.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.tutorials.talking_npc.tests.html @@ -96,7 +96,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.html b/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.html index 61202b9ff4..8e605a4992 100644 --- a/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.html +++ b/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.html @@ -94,7 +94,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.intro_menu.html b/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.intro_menu.html index b58eeb2afc..c982921e0a 100644 --- a/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.intro_menu.html +++ b/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.intro_menu.html @@ -275,7 +275,6 @@ option related to this node.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.mob.html b/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.mob.html index 8b04a81b9a..e0633d38d8 100644 --- a/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.mob.html +++ b/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.mob.html @@ -324,7 +324,6 @@ right away, also when patrolling on a very slow ticker.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.objects.html b/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.objects.html index b49cb1f432..00371f0987 100644 --- a/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.objects.html +++ b/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.objects.html @@ -364,7 +364,7 @@ of the object. We overload it with our own version.

      -aliases = ['burn', 'light']
      +aliases = ['light', 'burn']
      @@ -391,7 +391,7 @@ to sit on a “lightable” object, we operate only on self.obj.

      -search_index_entry = {'aliases': 'burn light', 'category': 'tutorialworld', 'key': 'on', 'no_prefix': ' burn light', 'tags': '', 'text': '\n Creates light where there was none. Something to burn.\n '}
      +search_index_entry = {'aliases': 'light burn', 'category': 'tutorialworld', 'key': 'on', 'no_prefix': ' light burn', 'tags': '', 'text': '\n Creates light where there was none. Something to burn.\n '}
      @@ -495,7 +495,7 @@ shift green root up/down

      -aliases = ['shiftroot', 'push', 'move', 'pull']
      +aliases = ['pull', 'push', 'move', 'shiftroot']
      @@ -531,7 +531,7 @@ yellow/green - horizontal roots

      -search_index_entry = {'aliases': 'shiftroot push move pull', 'category': 'tutorialworld', 'key': 'shift', 'no_prefix': ' shiftroot push move pull', 'tags': '', 'text': '\n Shifts roots around.\n\n Usage:\n shift blue root left/right\n shift red root left/right\n shift yellow root up/down\n shift green root up/down\n\n '}
      +search_index_entry = {'aliases': 'pull push move shiftroot', 'category': 'tutorialworld', 'key': 'shift', 'no_prefix': ' pull push move shiftroot', 'tags': '', 'text': '\n Shifts roots around.\n\n Usage:\n shift blue root left/right\n shift red root left/right\n shift yellow root up/down\n shift green root up/down\n\n '}
      @@ -548,7 +548,7 @@ yellow/green - horizontal roots

      -aliases = ['press button', 'button', 'push button']
      +aliases = ['push button', 'button', 'press button']
      @@ -574,7 +574,7 @@ yellow/green - horizontal roots

      -search_index_entry = {'aliases': 'press button button push button', 'category': 'tutorialworld', 'key': 'press', 'no_prefix': ' press button button push button', 'tags': '', 'text': '\n Presses a button.\n '}
      +search_index_entry = {'aliases': 'push button button press button', 'category': 'tutorialworld', 'key': 'press', 'no_prefix': ' push button button press button', 'tags': '', 'text': '\n Presses a button.\n '}
      @@ -718,7 +718,7 @@ parry - forgoes your attack but will make you harder to hit on next

      -aliases = ['fight', 'stab', 'pierce', 'slash', 'chop', 'hit', 'defend', 'kill', 'thrust', 'bash', 'parry']
      +aliases = ['slash', 'chop', 'pierce', 'defend', 'bash', 'thrust', 'parry', 'stab', 'fight', 'kill', 'hit']
      @@ -744,7 +744,7 @@ parry - forgoes your attack but will make you harder to hit on next

      -search_index_entry = {'aliases': 'fight stab pierce slash chop hit defend kill thrust bash parry', 'category': 'tutorialworld', 'key': 'attack', 'no_prefix': ' fight stab pierce slash chop hit defend kill thrust bash parry', 'tags': '', 'text': '\n Attack the enemy. Commands:\n\n stab <enemy>\n slash <enemy>\n parry\n\n stab - (thrust) makes a lot of damage but is harder to hit with.\n slash - is easier to land, but does not make as much damage.\n parry - forgoes your attack but will make you harder to hit on next\n enemy attack.\n\n '}
      +search_index_entry = {'aliases': 'slash chop pierce defend bash thrust parry stab fight kill hit', 'category': 'tutorialworld', 'key': 'attack', 'no_prefix': ' slash chop pierce defend bash thrust parry stab fight kill hit', 'tags': '', 'text': '\n Attack the enemy. Commands:\n\n stab <enemy>\n slash <enemy>\n parry\n\n stab - (thrust) makes a lot of damage but is harder to hit with.\n slash - is easier to land, but does not make as much damage.\n parry - forgoes your attack but will make you harder to hit on next\n enemy attack.\n\n '}
      @@ -990,7 +990,6 @@ pulling weapons from it indefinitely.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.rooms.html b/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.rooms.html index fba05244ee..c42e1fb98f 100644 --- a/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.rooms.html +++ b/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.rooms.html @@ -187,7 +187,7 @@ code except for adding in the details.

      -aliases = ['ls', 'l']
      +aliases = ['l', 'ls']
      @@ -202,7 +202,7 @@ code except for adding in the details.

      -search_index_entry = {'aliases': 'ls l', 'category': 'tutorialworld', 'key': 'look', 'no_prefix': ' ls l', 'tags': '', 'text': '\n looks at the room and on details\n\n Usage:\n look <obj>\n look <room detail>\n look *<account>\n\n Observes your location, details at your location or objects\n in your vicinity.\n\n Tutorial: This is a child of the default Look command, that also\n allows us to look at "details" in the room. These details are\n things to examine and offers some extra description without\n actually having to be actual database objects. It uses the\n return_detail() hook on TutorialRooms for this.\n '}
      +search_index_entry = {'aliases': 'l ls', 'category': 'tutorialworld', 'key': 'look', 'no_prefix': ' l ls', 'tags': '', 'text': '\n looks at the room and on details\n\n Usage:\n look <obj>\n look <room detail>\n look *<account>\n\n Observes your location, details at your location or objects\n in your vicinity.\n\n Tutorial: This is a child of the default Look command, that also\n allows us to look at "details" in the room. These details are\n things to examine and offers some extra description without\n actually having to be actual database objects. It uses the\n return_detail() hook on TutorialRooms for this.\n '}
      @@ -868,7 +868,7 @@ to find something.

      -aliases = ['search', 'l', 'feel', 'feel around', 'fiddle']
      +aliases = ['feel around', 'fiddle', 'feel', 'l', 'search']
      @@ -896,7 +896,7 @@ random chance of eventually finding a light source.

      -search_index_entry = {'aliases': 'search l feel feel around fiddle', 'category': 'tutorialworld', 'key': 'look', 'no_prefix': ' search l feel feel around fiddle', 'tags': '', 'text': '\n Look around in darkness\n\n Usage:\n look\n\n Look around in the darkness, trying\n to find something.\n '}
      +search_index_entry = {'aliases': 'feel around fiddle feel l search', 'category': 'tutorialworld', 'key': 'look', 'no_prefix': ' feel around fiddle feel l search', 'tags': '', 'text': '\n Look around in darkness\n\n Usage:\n look\n\n Look around in the darkness, trying\n to find something.\n '}
      @@ -1257,7 +1257,6 @@ overriding the call (unused by default).

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.tests.html b/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.tests.html index 0ac34d8615..c78100e5df 100644 --- a/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.tutorials.tutorial_world.tests.html @@ -183,7 +183,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.utils.auditing.html b/docs/1.0-dev/api/evennia.contrib.utils.auditing.html index 41fa77d5e0..83209aff3b 100644 --- a/docs/1.0-dev/api/evennia.contrib.utils.auditing.html +++ b/docs/1.0-dev/api/evennia.contrib.utils.auditing.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.utils.auditing.outputs.html b/docs/1.0-dev/api/evennia.contrib.utils.auditing.outputs.html index c4f634c50f..9ec52fa95e 100644 --- a/docs/1.0-dev/api/evennia.contrib.utils.auditing.outputs.html +++ b/docs/1.0-dev/api/evennia.contrib.utils.auditing.outputs.html @@ -126,7 +126,6 @@ compromised or taken down, losing your logs along with it is no help!).

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.utils.auditing.server.html b/docs/1.0-dev/api/evennia.contrib.utils.auditing.server.html index a4657ee96b..afc7063efe 100644 --- a/docs/1.0-dev/api/evennia.contrib.utils.auditing.server.html +++ b/docs/1.0-dev/api/evennia.contrib.utils.auditing.server.html @@ -165,7 +165,6 @@ writing to log. Recording cleartext password attempts is bad policy.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.utils.auditing.tests.html b/docs/1.0-dev/api/evennia.contrib.utils.auditing.tests.html index 1b257294ac..d6d502832b 100644 --- a/docs/1.0-dev/api/evennia.contrib.utils.auditing.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.utils.auditing.tests.html @@ -111,7 +111,6 @@ parsed from the Session object.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.utils.fieldfill.fieldfill.html b/docs/1.0-dev/api/evennia.contrib.utils.fieldfill.fieldfill.html index 1297593a50..566e9e923b 100644 --- a/docs/1.0-dev/api/evennia.contrib.utils.fieldfill.fieldfill.html +++ b/docs/1.0-dev/api/evennia.contrib.utils.fieldfill.fieldfill.html @@ -444,7 +444,6 @@ send

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.utils.fieldfill.html b/docs/1.0-dev/api/evennia.contrib.utils.fieldfill.html index 668d35bec4..f7a98df857 100644 --- a/docs/1.0-dev/api/evennia.contrib.utils.fieldfill.html +++ b/docs/1.0-dev/api/evennia.contrib.utils.fieldfill.html @@ -90,7 +90,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.utils.html b/docs/1.0-dev/api/evennia.contrib.utils.html index 0a628262c4..a27aa1e4ff 100644 --- a/docs/1.0-dev/api/evennia.contrib.utils.html +++ b/docs/1.0-dev/api/evennia.contrib.utils.html @@ -108,7 +108,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.utils.random_string_generator.html b/docs/1.0-dev/api/evennia.contrib.utils.random_string_generator.html index ac798ab4f6..3b43387ac5 100644 --- a/docs/1.0-dev/api/evennia.contrib.utils.random_string_generator.html +++ b/docs/1.0-dev/api/evennia.contrib.utils.random_string_generator.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.utils.random_string_generator.random_string_generator.html b/docs/1.0-dev/api/evennia.contrib.utils.random_string_generator.random_string_generator.html index a281b1bbb1..9ec85aab93 100644 --- a/docs/1.0-dev/api/evennia.contrib.utils.random_string_generator.random_string_generator.html +++ b/docs/1.0-dev/api/evennia.contrib.utils.random_string_generator.random_string_generator.html @@ -299,7 +299,6 @@ calling the get method.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.utils.random_string_generator.tests.html b/docs/1.0-dev/api/evennia.contrib.utils.random_string_generator.tests.html index 20e129577b..b3430611da 100644 --- a/docs/1.0-dev/api/evennia.contrib.utils.random_string_generator.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.utils.random_string_generator.tests.html @@ -97,7 +97,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.utils.tree_select.html b/docs/1.0-dev/api/evennia.contrib.utils.tree_select.html index 8eaf9dbffc..cf414658df 100644 --- a/docs/1.0-dev/api/evennia.contrib.utils.tree_select.html +++ b/docs/1.0-dev/api/evennia.contrib.utils.tree_select.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.utils.tree_select.tests.html b/docs/1.0-dev/api/evennia.contrib.utils.tree_select.tests.html index cc85380fc7..1b6b022820 100644 --- a/docs/1.0-dev/api/evennia.contrib.utils.tree_select.tests.html +++ b/docs/1.0-dev/api/evennia.contrib.utils.tree_select.tests.html @@ -107,7 +107,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.contrib.utils.tree_select.tree_select.html b/docs/1.0-dev/api/evennia.contrib.utils.tree_select.tree_select.html index c15c680644..4002148217 100644 --- a/docs/1.0-dev/api/evennia.contrib.utils.tree_select.tree_select.html +++ b/docs/1.0-dev/api/evennia.contrib.utils.tree_select.tree_select.html @@ -439,7 +439,6 @@ to determine the color the player chose.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.help.filehelp.html b/docs/1.0-dev/api/evennia.help.filehelp.html index b24e7c86b9..fd505fecc9 100644 --- a/docs/1.0-dev/api/evennia.help.filehelp.html +++ b/docs/1.0-dev/api/evennia.help.filehelp.html @@ -282,7 +282,6 @@ return a list of **FileHelpEntry.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.help.html b/docs/1.0-dev/api/evennia.help.html index b26422a030..aaaf73694e 100644 --- a/docs/1.0-dev/api/evennia.help.html +++ b/docs/1.0-dev/api/evennia.help.html @@ -96,7 +96,6 @@ itself.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.help.manager.html b/docs/1.0-dev/api/evennia.help.manager.html index 4193b68ee8..9da1530f80 100644 --- a/docs/1.0-dev/api/evennia.help.manager.html +++ b/docs/1.0-dev/api/evennia.help.manager.html @@ -250,7 +250,6 @@ in-game setting information and so on.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.help.models.html b/docs/1.0-dev/api/evennia.help.models.html index 38878949fd..ea29ec64af 100644 --- a/docs/1.0-dev/api/evennia.help.models.html +++ b/docs/1.0-dev/api/evennia.help.models.html @@ -413,7 +413,6 @@ object the first time, the query is executed.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.help.utils.html b/docs/1.0-dev/api/evennia.help.utils.html index d253e9a15a..7c6aca3b79 100644 --- a/docs/1.0-dev/api/evennia.help.utils.html +++ b/docs/1.0-dev/api/evennia.help.utils.html @@ -186,7 +186,6 @@ followed by any sub-sub-categories down to a max-depth of 5.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.html b/docs/1.0-dev/api/evennia.html index f862d400e6..0bf185b055 100644 --- a/docs/1.0-dev/api/evennia.html +++ b/docs/1.0-dev/api/evennia.html @@ -739,7 +739,6 @@ with ‘q’, remove the break line and restart server when finished.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.locks.html b/docs/1.0-dev/api/evennia.locks.html index e98ebb6ffa..e400777f91 100644 --- a/docs/1.0-dev/api/evennia.locks.html +++ b/docs/1.0-dev/api/evennia.locks.html @@ -93,7 +93,6 @@ also contains the default lock functions used in lock definitions.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.locks.lockfuncs.html b/docs/1.0-dev/api/evennia.locks.lockfuncs.html index fd02df55e5..73de9e1cad 100644 --- a/docs/1.0-dev/api/evennia.locks.lockfuncs.html +++ b/docs/1.0-dev/api/evennia.locks.lockfuncs.html @@ -437,7 +437,6 @@ unpacked to their real value. We only support basic properties.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.locks.lockhandler.html b/docs/1.0-dev/api/evennia.locks.lockhandler.html index 0177bde535..9027206385 100644 --- a/docs/1.0-dev/api/evennia.locks.lockhandler.html +++ b/docs/1.0-dev/api/evennia.locks.lockhandler.html @@ -456,7 +456,6 @@ among the locks defined by lockstring.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.objects.html b/docs/1.0-dev/api/evennia.objects.html index b2fb0bd7cc..24879f8b72 100644 --- a/docs/1.0-dev/api/evennia.objects.html +++ b/docs/1.0-dev/api/evennia.objects.html @@ -93,7 +93,6 @@ objects inherit from classes in this package.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.objects.manager.html b/docs/1.0-dev/api/evennia.objects.manager.html index e473f5981d..f894acaeac 100644 --- a/docs/1.0-dev/api/evennia.objects.manager.html +++ b/docs/1.0-dev/api/evennia.objects.manager.html @@ -492,7 +492,6 @@ adding this rarely makes sense since this data will not survive a reload.

      Versions diff --git a/docs/1.0-dev/api/evennia.objects.models.html b/docs/1.0-dev/api/evennia.objects.models.html index ecc8d23fc2..44d3772cf2 100644 --- a/docs/1.0-dev/api/evennia.objects.models.html +++ b/docs/1.0-dev/api/evennia.objects.models.html @@ -564,7 +564,6 @@ class built by **create_forward_many_to_many_manager()** define

      Versions

      diff --git a/docs/1.0-dev/api/evennia.objects.objects.html b/docs/1.0-dev/api/evennia.objects.objects.html index a8231fd02c..7b7a279754 100644 --- a/docs/1.0-dev/api/evennia.objects.objects.html +++ b/docs/1.0-dev/api/evennia.objects.objects.html @@ -2243,7 +2243,6 @@ read for an error string instead.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.prototypes.html b/docs/1.0-dev/api/evennia.prototypes.html index 93259aee17..bf9d4797b1 100644 --- a/docs/1.0-dev/api/evennia.prototypes.html +++ b/docs/1.0-dev/api/evennia.prototypes.html @@ -92,7 +92,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.prototypes.menus.html b/docs/1.0-dev/api/evennia.prototypes.menus.html index 4d4ddd99b0..e45e7acd98 100644 --- a/docs/1.0-dev/api/evennia.prototypes.menus.html +++ b/docs/1.0-dev/api/evennia.prototypes.menus.html @@ -197,7 +197,6 @@ prototype rather than creating a new one.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.prototypes.protfuncs.html b/docs/1.0-dev/api/evennia.prototypes.protfuncs.html index 987f5a5e78..3adcb57df7 100644 --- a/docs/1.0-dev/api/evennia.prototypes.protfuncs.html +++ b/docs/1.0-dev/api/evennia.prototypes.protfuncs.html @@ -121,7 +121,6 @@ Returns the value of another key in this prototoype. Will raise an error if

      Versions

      diff --git a/docs/1.0-dev/api/evennia.prototypes.prototypes.html b/docs/1.0-dev/api/evennia.prototypes.prototypes.html index b32aaaa090..895f124cb7 100644 --- a/docs/1.0-dev/api/evennia.prototypes.prototypes.html +++ b/docs/1.0-dev/api/evennia.prototypes.prototypes.html @@ -518,7 +518,6 @@ validator (callable, optional): If given, this will be called with the value to<

      Versions

      diff --git a/docs/1.0-dev/api/evennia.prototypes.spawner.html b/docs/1.0-dev/api/evennia.prototypes.spawner.html index 1ec79e01e6..be8946c91f 100644 --- a/docs/1.0-dev/api/evennia.prototypes.spawner.html +++ b/docs/1.0-dev/api/evennia.prototypes.spawner.html @@ -522,7 +522,6 @@ custom prototype_parents are given to this function.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.scripts.html b/docs/1.0-dev/api/evennia.scripts.html index e1da70204d..2e5b47ccd3 100644 --- a/docs/1.0-dev/api/evennia.scripts.html +++ b/docs/1.0-dev/api/evennia.scripts.html @@ -99,7 +99,6 @@ timed effects.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.scripts.manager.html b/docs/1.0-dev/api/evennia.scripts.manager.html index bccc0b2a67..99df9f918f 100644 --- a/docs/1.0-dev/api/evennia.scripts.manager.html +++ b/docs/1.0-dev/api/evennia.scripts.manager.html @@ -281,7 +281,6 @@ scripts in the database.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.scripts.models.html b/docs/1.0-dev/api/evennia.scripts.models.html index c7309767fe..9dae2f70c0 100644 --- a/docs/1.0-dev/api/evennia.scripts.models.html +++ b/docs/1.0-dev/api/evennia.scripts.models.html @@ -378,7 +378,6 @@ class built by **create_forward_many_to_many_manager()** define

      Versions

      diff --git a/docs/1.0-dev/api/evennia.scripts.monitorhandler.html b/docs/1.0-dev/api/evennia.scripts.monitorhandler.html index fc597733a1..cdb6cd1796 100644 --- a/docs/1.0-dev/api/evennia.scripts.monitorhandler.html +++ b/docs/1.0-dev/api/evennia.scripts.monitorhandler.html @@ -203,7 +203,6 @@ all kwargs must be possible to pickle!

      Versions

      diff --git a/docs/1.0-dev/api/evennia.scripts.scripthandler.html b/docs/1.0-dev/api/evennia.scripts.scripthandler.html index def23f6382..5a5f2a77bf 100644 --- a/docs/1.0-dev/api/evennia.scripts.scripthandler.html +++ b/docs/1.0-dev/api/evennia.scripts.scripthandler.html @@ -185,7 +185,6 @@ If no key is given, delete all scripts on the object!

      Versions

      diff --git a/docs/1.0-dev/api/evennia.scripts.scripts.html b/docs/1.0-dev/api/evennia.scripts.scripts.html index a2e229d370..f96e4dfdff 100644 --- a/docs/1.0-dev/api/evennia.scripts.scripts.html +++ b/docs/1.0-dev/api/evennia.scripts.scripts.html @@ -305,7 +305,6 @@ could be used).

      Versions

      diff --git a/docs/1.0-dev/api/evennia.scripts.taskhandler.html b/docs/1.0-dev/api/evennia.scripts.taskhandler.html index d6c1c8548e..c764290a4a 100644 --- a/docs/1.0-dev/api/evennia.scripts.taskhandler.html +++ b/docs/1.0-dev/api/evennia.scripts.taskhandler.html @@ -563,7 +563,6 @@ This method should be automatically called when Evennia starts.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.scripts.tickerhandler.html b/docs/1.0-dev/api/evennia.scripts.tickerhandler.html index 26ffab0a37..5cd1770913 100644 --- a/docs/1.0-dev/api/evennia.scripts.tickerhandler.html +++ b/docs/1.0-dev/api/evennia.scripts.tickerhandler.html @@ -428,7 +428,6 @@ non-db objects.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.amp_client.html b/docs/1.0-dev/api/evennia.server.amp_client.html index 70a8f900ef..c2da2f2027 100644 --- a/docs/1.0-dev/api/evennia.server.amp_client.html +++ b/docs/1.0-dev/api/evennia.server.amp_client.html @@ -266,7 +266,6 @@ operation, as defined by the global variables in

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.connection_wizard.html b/docs/1.0-dev/api/evennia.server.connection_wizard.html index 2bb2cf7e87..4e4595d722 100644 --- a/docs/1.0-dev/api/evennia.server.connection_wizard.html +++ b/docs/1.0-dev/api/evennia.server.connection_wizard.html @@ -205,7 +205,6 @@ fails (and is expected to echo why if so).

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.deprecations.html b/docs/1.0-dev/api/evennia.server.deprecations.html index 804ca65925..52a3839aef 100644 --- a/docs/1.0-dev/api/evennia.server.deprecations.html +++ b/docs/1.0-dev/api/evennia.server.deprecations.html @@ -109,7 +109,6 @@ does not stop launch.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.evennia_launcher.html b/docs/1.0-dev/api/evennia.server.evennia_launcher.html index b5b57ed549..f7dfcbb766 100644 --- a/docs/1.0-dev/api/evennia.server.evennia_launcher.html +++ b/docs/1.0-dev/api/evennia.server.evennia_launcher.html @@ -612,7 +612,6 @@ in the terminal/console, for example:

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.game_index_client.client.html b/docs/1.0-dev/api/evennia.server.game_index_client.client.html index 412d5ff9d1..3342b10276 100644 --- a/docs/1.0-dev/api/evennia.server.game_index_client.client.html +++ b/docs/1.0-dev/api/evennia.server.game_index_client.client.html @@ -195,7 +195,6 @@ to this Protocol. The connection has been closed.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.game_index_client.html b/docs/1.0-dev/api/evennia.server.game_index_client.html index c7fe84f4b3..5c71cdf37a 100644 --- a/docs/1.0-dev/api/evennia.server.game_index_client.html +++ b/docs/1.0-dev/api/evennia.server.game_index_client.html @@ -90,7 +90,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.game_index_client.service.html b/docs/1.0-dev/api/evennia.server.game_index_client.service.html index 3cafcb129a..9198f6d60a 100644 --- a/docs/1.0-dev/api/evennia.server.game_index_client.service.html +++ b/docs/1.0-dev/api/evennia.server.game_index_client.service.html @@ -114,7 +114,6 @@ to the Evennia Game Index.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.html b/docs/1.0-dev/api/evennia.server.html index 05b6e06258..91db58c7ed 100644 --- a/docs/1.0-dev/api/evennia.server.html +++ b/docs/1.0-dev/api/evennia.server.html @@ -151,7 +151,6 @@ to connect to the game.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.initial_setup.html b/docs/1.0-dev/api/evennia.server.initial_setup.html index dd46b2a89c..05b4a50e26 100644 --- a/docs/1.0-dev/api/evennia.server.initial_setup.html +++ b/docs/1.0-dev/api/evennia.server.initial_setup.html @@ -132,7 +132,6 @@ the function will exit immediately.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.inputfuncs.html b/docs/1.0-dev/api/evennia.server.inputfuncs.html index 3b59e621b7..8f2ab85a98 100644 --- a/docs/1.0-dev/api/evennia.server.inputfuncs.html +++ b/docs/1.0-dev/api/evennia.server.inputfuncs.html @@ -393,7 +393,6 @@ common clients.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.manager.html b/docs/1.0-dev/api/evennia.server.manager.html index d24a9a8406..51282da189 100644 --- a/docs/1.0-dev/api/evennia.server.manager.html +++ b/docs/1.0-dev/api/evennia.server.manager.html @@ -122,7 +122,6 @@ value (str): If key was given, this is the stored value, or

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.models.html b/docs/1.0-dev/api/evennia.server.models.html index cd0cf7790c..cd7f9a99ce 100644 --- a/docs/1.0-dev/api/evennia.server.models.html +++ b/docs/1.0-dev/api/evennia.server.models.html @@ -176,7 +176,6 @@ object the first time, the query is executed.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.portal.amp.html b/docs/1.0-dev/api/evennia.server.portal.amp.html index 2c5346078a..9e7c34c064 100644 --- a/docs/1.0-dev/api/evennia.server.portal.amp.html +++ b/docs/1.0-dev/api/evennia.server.portal.amp.html @@ -559,7 +559,6 @@ function call

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.portal.amp_server.html b/docs/1.0-dev/api/evennia.server.portal.amp_server.html index 28dff9aa19..782671cfbd 100644 --- a/docs/1.0-dev/api/evennia.server.portal.amp_server.html +++ b/docs/1.0-dev/api/evennia.server.portal.amp_server.html @@ -307,7 +307,6 @@ global variables in evennia/server/amp.py.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.portal.grapevine.html b/docs/1.0-dev/api/evennia.server.portal.grapevine.html index 12036b52af..e64bb6cae4 100644 --- a/docs/1.0-dev/api/evennia.server.portal.grapevine.html +++ b/docs/1.0-dev/api/evennia.server.portal.grapevine.html @@ -304,7 +304,6 @@ disconnect this protocol.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.portal.html b/docs/1.0-dev/api/evennia.server.portal.html index 928f616e77..dc8e1a9dfd 100644 --- a/docs/1.0-dev/api/evennia.server.portal.html +++ b/docs/1.0-dev/api/evennia.server.portal.html @@ -109,7 +109,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.portal.irc.html b/docs/1.0-dev/api/evennia.server.portal.irc.html index f2b887a8c6..acf9201efb 100644 --- a/docs/1.0-dev/api/evennia.server.portal.irc.html +++ b/docs/1.0-dev/api/evennia.server.portal.irc.html @@ -420,7 +420,6 @@ sessions.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.portal.mccp.html b/docs/1.0-dev/api/evennia.server.portal.mccp.html index 2c2705eac2..d915bc2b11 100644 --- a/docs/1.0-dev/api/evennia.server.portal.mccp.html +++ b/docs/1.0-dev/api/evennia.server.portal.mccp.html @@ -154,7 +154,6 @@ creating a zlib compression stream.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.portal.mssp.html b/docs/1.0-dev/api/evennia.server.portal.mssp.html index 4e91adffe3..317fcf5aa8 100644 --- a/docs/1.0-dev/api/evennia.server.portal.mssp.html +++ b/docs/1.0-dev/api/evennia.server.portal.mssp.html @@ -155,7 +155,6 @@ operation.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.portal.mxp.html b/docs/1.0-dev/api/evennia.server.portal.mxp.html index 929d38ce12..9d53ad6311 100644 --- a/docs/1.0-dev/api/evennia.server.portal.mxp.html +++ b/docs/1.0-dev/api/evennia.server.portal.mxp.html @@ -147,7 +147,6 @@ that supports it (mudlet, zmud, mushclient are a few)

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.portal.naws.html b/docs/1.0-dev/api/evennia.server.portal.naws.html index 17993df03f..78b8b12045 100644 --- a/docs/1.0-dev/api/evennia.server.portal.naws.html +++ b/docs/1.0-dev/api/evennia.server.portal.naws.html @@ -143,7 +143,6 @@ operation.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.portal.portal.html b/docs/1.0-dev/api/evennia.server.portal.portal.html index 81d1fa745f..dd2d3071fe 100644 --- a/docs/1.0-dev/api/evennia.server.portal.portal.html +++ b/docs/1.0-dev/api/evennia.server.portal.portal.html @@ -142,7 +142,6 @@ case it always needs to be restarted manually.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.portal.portalsessionhandler.html b/docs/1.0-dev/api/evennia.server.portal.portalsessionhandler.html index a1eb7dec3e..2a052ea7da 100644 --- a/docs/1.0-dev/api/evennia.server.portal.portalsessionhandler.html +++ b/docs/1.0-dev/api/evennia.server.portal.portalsessionhandler.html @@ -343,7 +343,6 @@ method exixts, it sends the data to a method send_default.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.portal.rss.html b/docs/1.0-dev/api/evennia.server.portal.rss.html index c6d96c0d63..52d3d08eb8 100644 --- a/docs/1.0-dev/api/evennia.server.portal.rss.html +++ b/docs/1.0-dev/api/evennia.server.portal.rss.html @@ -184,7 +184,6 @@ on slow connections.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.portal.ssh.html b/docs/1.0-dev/api/evennia.server.portal.ssh.html index f51eb68403..23533233a9 100644 --- a/docs/1.0-dev/api/evennia.server.portal.ssh.html +++ b/docs/1.0-dev/api/evennia.server.portal.ssh.html @@ -405,7 +405,6 @@ do not exist, the keypair is created.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.portal.ssl.html b/docs/1.0-dev/api/evennia.server.portal.ssl.html index 2fcbb4f9cf..e529914b27 100644 --- a/docs/1.0-dev/api/evennia.server.portal.ssl.html +++ b/docs/1.0-dev/api/evennia.server.portal.ssl.html @@ -125,7 +125,6 @@ server-side.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.portal.suppress_ga.html b/docs/1.0-dev/api/evennia.server.portal.suppress_ga.html index 2261b6f4b4..e822b15092 100644 --- a/docs/1.0-dev/api/evennia.server.portal.suppress_ga.html +++ b/docs/1.0-dev/api/evennia.server.portal.suppress_ga.html @@ -133,7 +133,6 @@ protocol to set it up.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.portal.telnet.html b/docs/1.0-dev/api/evennia.server.portal.telnet.html index df922088a1..a27816553e 100644 --- a/docs/1.0-dev/api/evennia.server.portal.telnet.html +++ b/docs/1.0-dev/api/evennia.server.portal.telnet.html @@ -326,7 +326,6 @@ Note that it must be actively turned back on again!

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.portal.telnet_oob.html b/docs/1.0-dev/api/evennia.server.portal.telnet_oob.html index 79aeab6c44..64193fb0bb 100644 --- a/docs/1.0-dev/api/evennia.server.portal.telnet_oob.html +++ b/docs/1.0-dev/api/evennia.server.portal.telnet_oob.html @@ -299,7 +299,6 @@ We assume the structure is valid JSON.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.portal.telnet_ssl.html b/docs/1.0-dev/api/evennia.server.portal.telnet_ssl.html index 39c3d4d1cf..b3081e2cd9 100644 --- a/docs/1.0-dev/api/evennia.server.portal.telnet_ssl.html +++ b/docs/1.0-dev/api/evennia.server.portal.telnet_ssl.html @@ -136,7 +136,6 @@ server-side.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.portal.tests.html b/docs/1.0-dev/api/evennia.server.portal.tests.html index 85633838e7..40a651f959 100644 --- a/docs/1.0-dev/api/evennia.server.portal.tests.html +++ b/docs/1.0-dev/api/evennia.server.portal.tests.html @@ -192,7 +192,6 @@ its inverse gives the correct string.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.portal.ttype.html b/docs/1.0-dev/api/evennia.server.portal.ttype.html index ffae6d421a..07277ca8fc 100644 --- a/docs/1.0-dev/api/evennia.server.portal.ttype.html +++ b/docs/1.0-dev/api/evennia.server.portal.ttype.html @@ -142,7 +142,6 @@ stored on protocol.protocol_flags under the TTYPE key.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.portal.webclient.html b/docs/1.0-dev/api/evennia.server.portal.webclient.html index 16009ca089..2d6bad84ef 100644 --- a/docs/1.0-dev/api/evennia.server.portal.webclient.html +++ b/docs/1.0-dev/api/evennia.server.portal.webclient.html @@ -259,7 +259,6 @@ client instead.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.portal.webclient_ajax.html b/docs/1.0-dev/api/evennia.server.portal.webclient_ajax.html index cbab24baab..619861cc79 100644 --- a/docs/1.0-dev/api/evennia.server.portal.webclient_ajax.html +++ b/docs/1.0-dev/api/evennia.server.portal.webclient_ajax.html @@ -403,7 +403,6 @@ client instead.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.profiling.dummyrunner.html b/docs/1.0-dev/api/evennia.server.profiling.dummyrunner.html index c2fc8ca5fd..53416c7511 100644 --- a/docs/1.0-dev/api/evennia.server.profiling.dummyrunner.html +++ b/docs/1.0-dev/api/evennia.server.profiling.dummyrunner.html @@ -341,7 +341,6 @@ all “intelligence” of the dummy client.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.profiling.dummyrunner_settings.html b/docs/1.0-dev/api/evennia.server.profiling.dummyrunner_settings.html index 3dbc75fe9b..b309a88943 100644 --- a/docs/1.0-dev/api/evennia.server.profiling.dummyrunner_settings.html +++ b/docs/1.0-dev/api/evennia.server.profiling.dummyrunner_settings.html @@ -224,7 +224,6 @@ dummyrunner output about just how fast commands are being processed.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.profiling.html b/docs/1.0-dev/api/evennia.server.profiling.html index 375f50f9ec..0621f44a54 100644 --- a/docs/1.0-dev/api/evennia.server.profiling.html +++ b/docs/1.0-dev/api/evennia.server.profiling.html @@ -95,7 +95,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.profiling.memplot.html b/docs/1.0-dev/api/evennia.server.profiling.memplot.html index 858c33dd25..705591cd88 100644 --- a/docs/1.0-dev/api/evennia.server.profiling.memplot.html +++ b/docs/1.0-dev/api/evennia.server.profiling.memplot.html @@ -129,7 +129,6 @@ the script will append to this file if it already exists.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.profiling.settings_mixin.html b/docs/1.0-dev/api/evennia.server.profiling.settings_mixin.html index ef7b473112..cd287797d3 100644 --- a/docs/1.0-dev/api/evennia.server.profiling.settings_mixin.html +++ b/docs/1.0-dev/api/evennia.server.profiling.settings_mixin.html @@ -91,7 +91,6 @@ servers!

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.profiling.test_queries.html b/docs/1.0-dev/api/evennia.server.profiling.test_queries.html index 9f6dc35e82..0116a89396 100644 --- a/docs/1.0-dev/api/evennia.server.profiling.test_queries.html +++ b/docs/1.0-dev/api/evennia.server.profiling.test_queries.html @@ -93,7 +93,6 @@ to setup the environment to test.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.profiling.tests.html b/docs/1.0-dev/api/evennia.server.profiling.tests.html index d18d9a7f09..929a85eb85 100644 --- a/docs/1.0-dev/api/evennia.server.profiling.tests.html +++ b/docs/1.0-dev/api/evennia.server.profiling.tests.html @@ -187,7 +187,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.profiling.timetrace.html b/docs/1.0-dev/api/evennia.server.profiling.timetrace.html index ab5f9fab50..30db5ba60a 100644 --- a/docs/1.0-dev/api/evennia.server.profiling.timetrace.html +++ b/docs/1.0-dev/api/evennia.server.profiling.timetrace.html @@ -102,7 +102,6 @@ This message will get attached time stamp.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.server.html b/docs/1.0-dev/api/evennia.server.server.html index e6a1929980..51299e5586 100644 --- a/docs/1.0-dev/api/evennia.server.server.html +++ b/docs/1.0-dev/api/evennia.server.server.html @@ -227,7 +227,6 @@ shutdown or a reset.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.serversession.html b/docs/1.0-dev/api/evennia.server.serversession.html index 9b0be59454..dcb474b88f 100644 --- a/docs/1.0-dev/api/evennia.server.serversession.html +++ b/docs/1.0-dev/api/evennia.server.serversession.html @@ -392,7 +392,6 @@ property, e.g. obj.ndb.attr = value etc.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.session.html b/docs/1.0-dev/api/evennia.server.session.html index 392ea8fff1..66e13949d8 100644 --- a/docs/1.0-dev/api/evennia.server.session.html +++ b/docs/1.0-dev/api/evennia.server.session.html @@ -197,7 +197,6 @@ should overload this to format/handle the outgoing data as needed.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.sessionhandler.html b/docs/1.0-dev/api/evennia.server.sessionhandler.html index 8720cad1ad..59e9fbd024 100644 --- a/docs/1.0-dev/api/evennia.server.sessionhandler.html +++ b/docs/1.0-dev/api/evennia.server.sessionhandler.html @@ -604,7 +604,6 @@ on the form commandname=((args), {kwargs}).

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.signals.html b/docs/1.0-dev/api/evennia.server.signals.html index 38a75535f0..d8d50ae572 100644 --- a/docs/1.0-dev/api/evennia.server.signals.html +++ b/docs/1.0-dev/api/evennia.server.signals.html @@ -98,7 +98,6 @@ without necessitating a full takeover of hooks that may be in high demand.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.throttle.html b/docs/1.0-dev/api/evennia.server.throttle.html index 51f32a7431..0e7c0c8177 100644 --- a/docs/1.0-dev/api/evennia.server.throttle.html +++ b/docs/1.0-dev/api/evennia.server.throttle.html @@ -237,7 +237,6 @@ fails recently.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.validators.html b/docs/1.0-dev/api/evennia.server.validators.html index 4498a920d6..83a708c0aa 100644 --- a/docs/1.0-dev/api/evennia.server.validators.html +++ b/docs/1.0-dev/api/evennia.server.validators.html @@ -146,7 +146,6 @@ by this validator.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.server.webserver.html b/docs/1.0-dev/api/evennia.server.webserver.html index 845511d6d3..78a860f89a 100644 --- a/docs/1.0-dev/api/evennia.server.webserver.html +++ b/docs/1.0-dev/api/evennia.server.webserver.html @@ -304,7 +304,6 @@ directory this path represents.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.settings_default.html b/docs/1.0-dev/api/evennia.settings_default.html index f7bc82f257..f34a719d2c 100644 --- a/docs/1.0-dev/api/evennia.settings_default.html +++ b/docs/1.0-dev/api/evennia.settings_default.html @@ -92,7 +92,6 @@ always be sure of what you have changed and what is default behaviour.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.typeclasses.attributes.html b/docs/1.0-dev/api/evennia.typeclasses.attributes.html index c003d5e1ed..52061c0f02 100644 --- a/docs/1.0-dev/api/evennia.typeclasses.attributes.html +++ b/docs/1.0-dev/api/evennia.typeclasses.attributes.html @@ -1514,7 +1514,6 @@ with nicks stored on the Account level.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.typeclasses.html b/docs/1.0-dev/api/evennia.typeclasses.html index a2fd6a266b..ecb350f99e 100644 --- a/docs/1.0-dev/api/evennia.typeclasses.html +++ b/docs/1.0-dev/api/evennia.typeclasses.html @@ -98,7 +98,6 @@ Attribute and Tag models are defined along with their handlers.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.typeclasses.managers.html b/docs/1.0-dev/api/evennia.typeclasses.managers.html index 9ed3787bde..3498ecb006 100644 --- a/docs/1.0-dev/api/evennia.typeclasses.managers.html +++ b/docs/1.0-dev/api/evennia.typeclasses.managers.html @@ -491,7 +491,6 @@ Mutually exclusive to include_children.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.typeclasses.models.html b/docs/1.0-dev/api/evennia.typeclasses.models.html index c767a60ee1..7bd32ed34b 100644 --- a/docs/1.0-dev/api/evennia.typeclasses.models.html +++ b/docs/1.0-dev/api/evennia.typeclasses.models.html @@ -770,7 +770,6 @@ developer’s responsibility.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.typeclasses.tags.html b/docs/1.0-dev/api/evennia.typeclasses.tags.html index 3cbbef98f5..b96096ae1d 100644 --- a/docs/1.0-dev/api/evennia.typeclasses.tags.html +++ b/docs/1.0-dev/api/evennia.typeclasses.tags.html @@ -509,7 +509,6 @@ replicated with a lock check against the lockstring

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.ansi.html b/docs/1.0-dev/api/evennia.utils.ansi.html index ba908a142f..26eed0fc5f 100644 --- a/docs/1.0-dev/api/evennia.utils.ansi.html +++ b/docs/1.0-dev/api/evennia.utils.ansi.html @@ -974,7 +974,6 @@ with.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.batchprocessors.html b/docs/1.0-dev/api/evennia.utils.batchprocessors.html index 8c8ff2cd46..edcb329d9f 100644 --- a/docs/1.0-dev/api/evennia.utils.batchprocessors.html +++ b/docs/1.0-dev/api/evennia.utils.batchprocessors.html @@ -396,7 +396,6 @@ namespace.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.containers.html b/docs/1.0-dev/api/evennia.utils.containers.html index 9f4d80e6bb..611e24549a 100644 --- a/docs/1.0-dev/api/evennia.utils.containers.html +++ b/docs/1.0-dev/api/evennia.utils.containers.html @@ -231,7 +231,6 @@ scripts defined in settings.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.create.html b/docs/1.0-dev/api/evennia.utils.create.html index 633baab511..df14d9a8ec 100644 --- a/docs/1.0-dev/api/evennia.utils.create.html +++ b/docs/1.0-dev/api/evennia.utils.create.html @@ -300,7 +300,6 @@ operations and is thus not suitable for play-testing the game.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.dbserialize.html b/docs/1.0-dev/api/evennia.utils.dbserialize.html index cd78c71f8c..7a84a2cb9c 100644 --- a/docs/1.0-dev/api/evennia.utils.dbserialize.html +++ b/docs/1.0-dev/api/evennia.utils.dbserialize.html @@ -166,7 +166,6 @@ _SaverList, _SaverDict and _SaverSet counterparts.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.eveditor.html b/docs/1.0-dev/api/evennia.utils.eveditor.html index cc9f252f2f..0f1e0d4e8b 100644 --- a/docs/1.0-dev/api/evennia.utils.eveditor.html +++ b/docs/1.0-dev/api/evennia.utils.eveditor.html @@ -277,7 +277,7 @@ indentation.

      -aliases = [':i', ':>', ':h', ':', ':s', ':dd', ':x', ':DD', ':!', '::', ':q', ':w', ':I', ':echo', ':::', ':f', ':uu', ':p', ':fd', ':q!', ':j', ':S', ':y', ':fi', ':dw', ':wq', ':UU', ':=', ':A', ':u', ':<', ':r']
      +aliases = [':fi', ':S', ':s', ':!', ':j', ':f', ':dw', ':u', ':DD', ':q', ':q!', ':p', ':', ':fd', ':wq', ':::', ':uu', ':i', ':I', ':A', ':x', ':w', ':=', '::', ':dd', ':UU', ':>', ':r', ':<', ':echo', ':y', ':h']
      @@ -305,7 +305,7 @@ efficient presentation.

      -search_index_entry = {'aliases': ':i :> :h : :s :dd :x :DD :! :: :q :w :I :echo ::: :f :uu :p :fd :q! :j :S :y :fi :dw :wq :UU := :A :u :< :r', 'category': 'general', 'key': ':editor_command_group', 'no_prefix': ' :i :> :h : :s :dd :x :DD :! :: :q :w :I :echo ::: :f :uu :p :fd :q! :j :S :y :fi :dw :wq :UU := :A :u :< :r', 'tags': '', 'text': '\n Commands for the editor\n '}
      +search_index_entry = {'aliases': ':fi :S :s :! :j :f :dw :u :DD :q :q! :p : :fd :wq ::: :uu :i :I :A :x :w := :: :dd :UU :> :r :< :echo :y :h', 'category': 'general', 'key': ':editor_command_group', 'no_prefix': ' :fi :S :s :! :j :f :dw :u :DD :q :q! :p : :fd :wq ::: :uu :i :I :A :x :w := :: :dd :UU :> :r :< :echo :y :h', 'tags': '', 'text': '\n Commands for the editor\n '}
      @@ -533,7 +533,6 @@ formatting information.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.evform.html b/docs/1.0-dev/api/evennia.utils.evform.html index 2e45e33cc9..9f3d2d6973 100644 --- a/docs/1.0-dev/api/evennia.utils.evform.html +++ b/docs/1.0-dev/api/evennia.utils.evform.html @@ -262,7 +262,6 @@ If this is given, filename is not read.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.evmenu.html b/docs/1.0-dev/api/evennia.utils.evmenu.html index f506820c42..d8b578b23e 100644 --- a/docs/1.0-dev/api/evennia.utils.evmenu.html +++ b/docs/1.0-dev/api/evennia.utils.evmenu.html @@ -947,7 +947,7 @@ single question.

      -aliases = ['abort', 'y', 'no', 'a', 'n', '__nomatch_command', 'yes']
      +aliases = ['y', 'yes', 'no', 'abort', '__nomatch_command', 'a', 'n']
      @@ -973,7 +973,7 @@ single question.

      -search_index_entry = {'aliases': 'abort y no a n __nomatch_command yes', 'category': 'general', 'key': '__noinput_command', 'no_prefix': ' abort y no a n __nomatch_command yes', 'tags': '', 'text': '\n Handle a prompt for yes or no. Press [return] for the default choice.\n\n '}
      +search_index_entry = {'aliases': 'y yes no abort __nomatch_command a n', 'category': 'general', 'key': '__noinput_command', 'no_prefix': ' y yes no abort __nomatch_command a n', 'tags': '', 'text': '\n Handle a prompt for yes or no. Press [return] for the default choice.\n\n '}
      @@ -1172,7 +1172,6 @@ Must be on the form callable(caller, raw_string, **kwargs).

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.evmore.html b/docs/1.0-dev/api/evennia.utils.evmore.html index c1bc07ceae..c25da5c3a9 100644 --- a/docs/1.0-dev/api/evennia.utils.evmore.html +++ b/docs/1.0-dev/api/evennia.utils.evmore.html @@ -78,7 +78,7 @@ the caller.msg() construct every time the page is updated.

      -aliases = ['t', 'abort', 'top', 'e', 'p', 'end', 'q', 'next', 'a', 'n', 'quit', 'previous']
      +aliases = ['top', 'end', 'quit', 'q', 'e', 'abort', 'next', 'previous', 't', 'a', 'p', 'n']
      @@ -104,7 +104,7 @@ the caller.msg() construct every time the page is updated.

      -search_index_entry = {'aliases': 't abort top e p end q next a n quit previous', 'category': 'general', 'key': '__noinput_command', 'no_prefix': ' t abort top e p end q next a n quit previous', 'tags': '', 'text': '\n Manipulate the text paging. Catch no-input with aliases.\n '}
      +search_index_entry = {'aliases': 'top end quit q e abort next previous t a p n', 'category': 'general', 'key': '__noinput_command', 'no_prefix': ' top end quit q e abort next previous t a p n', 'tags': '', 'text': '\n Manipulate the text paging. Catch no-input with aliases.\n '}
      @@ -543,7 +543,6 @@ the evmore commands will be available when this is run).

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.evtable.html b/docs/1.0-dev/api/evennia.utils.evtable.html index 85669906fa..3ef6b91501 100644 --- a/docs/1.0-dev/api/evennia.utils.evtable.html +++ b/docs/1.0-dev/api/evennia.utils.evtable.html @@ -652,7 +652,6 @@ given from 0 to Ncolumns-1.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.funcparser.html b/docs/1.0-dev/api/evennia.utils.funcparser.html index 834d6b5e9e..0f77e0e5be 100644 --- a/docs/1.0-dev/api/evennia.utils.funcparser.html +++ b/docs/1.0-dev/api/evennia.utils.funcparser.html @@ -906,7 +906,6 @@ and the mapping can always be auto-detected.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.gametime.html b/docs/1.0-dev/api/evennia.utils.gametime.html index 3f46d732ed..8538311d00 100644 --- a/docs/1.0-dev/api/evennia.utils.gametime.html +++ b/docs/1.0-dev/api/evennia.utils.gametime.html @@ -281,7 +281,6 @@ the epoch set by settings.TIME_GAME_EPOCH will still apply.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.html b/docs/1.0-dev/api/evennia.utils.html index fbc15bd7b7..3fa53bca8b 100644 --- a/docs/1.0-dev/api/evennia.utils.html +++ b/docs/1.0-dev/api/evennia.utils.html @@ -144,7 +144,6 @@ functionality.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.idmapper.html b/docs/1.0-dev/api/evennia.utils.idmapper.html index 5a0459a35c..091b6c4e9a 100644 --- a/docs/1.0-dev/api/evennia.utils.idmapper.html +++ b/docs/1.0-dev/api/evennia.utils.idmapper.html @@ -92,7 +92,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.idmapper.manager.html b/docs/1.0-dev/api/evennia.utils.idmapper.manager.html index 0bc33b91c7..746caaa85f 100644 --- a/docs/1.0-dev/api/evennia.utils.idmapper.manager.html +++ b/docs/1.0-dev/api/evennia.utils.idmapper.manager.html @@ -97,7 +97,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.idmapper.models.html b/docs/1.0-dev/api/evennia.utils.idmapper.models.html index 9f9bc04582..b4a71e002b 100644 --- a/docs/1.0-dev/api/evennia.utils.idmapper.models.html +++ b/docs/1.0-dev/api/evennia.utils.idmapper.models.html @@ -309,7 +309,6 @@ catch in an easy way here. Ideas are appreciated. /Griatch

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.idmapper.tests.html b/docs/1.0-dev/api/evennia.utils.idmapper.tests.html index 7c692f528a..7479cabec0 100644 --- a/docs/1.0-dev/api/evennia.utils.idmapper.tests.html +++ b/docs/1.0-dev/api/evennia.utils.idmapper.tests.html @@ -406,7 +406,6 @@ object the first time, the query is executed.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.logger.html b/docs/1.0-dev/api/evennia.utils.logger.html index b07200e3e9..7453fce5a2 100644 --- a/docs/1.0-dev/api/evennia.utils.logger.html +++ b/docs/1.0-dev/api/evennia.utils.logger.html @@ -480,7 +480,6 @@ all if the file is shorter than nlines.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.optionclasses.html b/docs/1.0-dev/api/evennia.utils.optionclasses.html index cc9654d0ca..453b60ec53 100644 --- a/docs/1.0-dev/api/evennia.utils.optionclasses.html +++ b/docs/1.0-dev/api/evennia.utils.optionclasses.html @@ -899,7 +899,6 @@ entries are processed.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.optionhandler.html b/docs/1.0-dev/api/evennia.utils.optionhandler.html index cd1dcab068..f99ecfb474 100644 --- a/docs/1.0-dev/api/evennia.utils.optionhandler.html +++ b/docs/1.0-dev/api/evennia.utils.optionhandler.html @@ -207,7 +207,6 @@ than their values.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.picklefield.html b/docs/1.0-dev/api/evennia.utils.picklefield.html index 41cc932cec..10e0f557b3 100644 --- a/docs/1.0-dev/api/evennia.utils.picklefield.html +++ b/docs/1.0-dev/api/evennia.utils.picklefield.html @@ -251,7 +251,6 @@ This is used by the serialization framework.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.search.html b/docs/1.0-dev/api/evennia.utils.search.html index 3c9fd0f702..573408dee2 100644 --- a/docs/1.0-dev/api/evennia.utils.search.html +++ b/docs/1.0-dev/api/evennia.utils.search.html @@ -370,7 +370,6 @@ matches were found.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.test_resources.html b/docs/1.0-dev/api/evennia.utils.test_resources.html index 40b1493c70..fc6543eb5a 100644 --- a/docs/1.0-dev/api/evennia.utils.test_resources.html +++ b/docs/1.0-dev/api/evennia.utils.test_resources.html @@ -423,7 +423,6 @@ classes and settings in mygame.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.text2html.html b/docs/1.0-dev/api/evennia.utils.text2html.html index b1db39c729..00b64b4efb 100644 --- a/docs/1.0-dev/api/evennia.utils.text2html.html +++ b/docs/1.0-dev/api/evennia.utils.text2html.html @@ -460,7 +460,6 @@ into html statements.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.utils.html b/docs/1.0-dev/api/evennia.utils.utils.html index 7ccc1a64eb..eeb84f6ad8 100644 --- a/docs/1.0-dev/api/evennia.utils.utils.html +++ b/docs/1.0-dev/api/evennia.utils.utils.html @@ -1728,7 +1728,6 @@ is longer than base_word, the excess will retain its original c

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.validatorfuncs.html b/docs/1.0-dev/api/evennia.utils.validatorfuncs.html index 5f29e9b29a..935c70eaa6 100644 --- a/docs/1.0-dev/api/evennia.utils.validatorfuncs.html +++ b/docs/1.0-dev/api/evennia.utils.validatorfuncs.html @@ -207,7 +207,6 @@ ignored.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.verb_conjugation.conjugate.html b/docs/1.0-dev/api/evennia.utils.verb_conjugation.conjugate.html index e0b13e37c6..ea2255f200 100644 --- a/docs/1.0-dev/api/evennia.utils.verb_conjugation.conjugate.html +++ b/docs/1.0-dev/api/evennia.utils.verb_conjugation.conjugate.html @@ -338,7 +338,6 @@ need, dare, ought.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.verb_conjugation.html b/docs/1.0-dev/api/evennia.utils.verb_conjugation.html index 816ce37eeb..833571a5bf 100644 --- a/docs/1.0-dev/api/evennia.utils.verb_conjugation.html +++ b/docs/1.0-dev/api/evennia.utils.verb_conjugation.html @@ -91,7 +91,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.verb_conjugation.pronouns.html b/docs/1.0-dev/api/evennia.utils.verb_conjugation.pronouns.html index 2b81f29f5d..58b85e2934 100644 --- a/docs/1.0-dev/api/evennia.utils.verb_conjugation.pronouns.html +++ b/docs/1.0-dev/api/evennia.utils.verb_conjugation.pronouns.html @@ -226,7 +226,6 @@ string and others respectively. If pronoun is invalid, the word is returned verb

      Versions

      diff --git a/docs/1.0-dev/api/evennia.utils.verb_conjugation.tests.html b/docs/1.0-dev/api/evennia.utils.verb_conjugation.tests.html index f75bcd347c..3271c2e68e 100644 --- a/docs/1.0-dev/api/evennia.utils.verb_conjugation.tests.html +++ b/docs/1.0-dev/api/evennia.utils.verb_conjugation.tests.html @@ -937,7 +937,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.admin.accounts.html b/docs/1.0-dev/api/evennia.web.admin.accounts.html index ecf0cb1b9e..9619bf6747 100644 --- a/docs/1.0-dev/api/evennia.web.admin.accounts.html +++ b/docs/1.0-dev/api/evennia.web.admin.accounts.html @@ -468,7 +468,6 @@ has a slightly different workflow.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.admin.attributes.html b/docs/1.0-dev/api/evennia.web.admin.attributes.html index f8c9430a18..6091c1003c 100644 --- a/docs/1.0-dev/api/evennia.web.admin.attributes.html +++ b/docs/1.0-dev/api/evennia.web.admin.attributes.html @@ -227,7 +227,6 @@ people used the admin at the same time

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.admin.comms.html b/docs/1.0-dev/api/evennia.web.admin.comms.html index 44651f6ac5..414cf9ae68 100644 --- a/docs/1.0-dev/api/evennia.web.admin.comms.html +++ b/docs/1.0-dev/api/evennia.web.admin.comms.html @@ -468,7 +468,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.admin.frontpage.html b/docs/1.0-dev/api/evennia.web.admin.frontpage.html index b7058861db..348c591124 100644 --- a/docs/1.0-dev/api/evennia.web.admin.frontpage.html +++ b/docs/1.0-dev/api/evennia.web.admin.frontpage.html @@ -97,7 +97,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.admin.help.html b/docs/1.0-dev/api/evennia.web.admin.help.html index 01a007f44a..d3ddeb62a5 100644 --- a/docs/1.0-dev/api/evennia.web.admin.help.html +++ b/docs/1.0-dev/api/evennia.web.admin.help.html @@ -220,7 +220,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.admin.html b/docs/1.0-dev/api/evennia.web.admin.html index efbdb1fcb0..102fd535dd 100644 --- a/docs/1.0-dev/api/evennia.web.admin.html +++ b/docs/1.0-dev/api/evennia.web.admin.html @@ -100,7 +100,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.admin.objects.html b/docs/1.0-dev/api/evennia.web.admin.objects.html index 6cde81134a..994eb18e12 100644 --- a/docs/1.0-dev/api/evennia.web.admin.objects.html +++ b/docs/1.0-dev/api/evennia.web.admin.objects.html @@ -388,7 +388,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.admin.scripts.html b/docs/1.0-dev/api/evennia.web.admin.scripts.html index 2100249572..131a6fe0d1 100644 --- a/docs/1.0-dev/api/evennia.web.admin.scripts.html +++ b/docs/1.0-dev/api/evennia.web.admin.scripts.html @@ -258,7 +258,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.admin.server.html b/docs/1.0-dev/api/evennia.web.admin.server.html index 61fdf26c89..b6b6515e5e 100644 --- a/docs/1.0-dev/api/evennia.web.admin.server.html +++ b/docs/1.0-dev/api/evennia.web.admin.server.html @@ -133,7 +133,6 @@ in the web admin interface.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.admin.tags.html b/docs/1.0-dev/api/evennia.web.admin.tags.html index f5c9084629..83e5f88ddc 100644 --- a/docs/1.0-dev/api/evennia.web.admin.tags.html +++ b/docs/1.0-dev/api/evennia.web.admin.tags.html @@ -312,7 +312,6 @@ people used the admin at the same time

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.admin.urls.html b/docs/1.0-dev/api/evennia.web.admin.urls.html index ef3cc61d0d..23525cfab2 100644 --- a/docs/1.0-dev/api/evennia.web.admin.urls.html +++ b/docs/1.0-dev/api/evennia.web.admin.urls.html @@ -86,7 +86,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.admin.utils.html b/docs/1.0-dev/api/evennia.web.admin.utils.html index 09019ba7e0..601b8882dc 100644 --- a/docs/1.0-dev/api/evennia.web.admin.utils.html +++ b/docs/1.0-dev/api/evennia.web.admin.utils.html @@ -125,7 +125,6 @@ admin process. This is intended to be used with forms.ChoiceField.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.api.filters.html b/docs/1.0-dev/api/evennia.web.api.filters.html index 3833c7c479..8e8ea4809b 100644 --- a/docs/1.0-dev/api/evennia.web.api.filters.html +++ b/docs/1.0-dev/api/evennia.web.api.filters.html @@ -295,7 +295,6 @@ documentation specifically regarding DRF integration.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.api.html b/docs/1.0-dev/api/evennia.web.api.html index a5c4e5ac75..c53bd2b60e 100644 --- a/docs/1.0-dev/api/evennia.web.api.html +++ b/docs/1.0-dev/api/evennia.web.api.html @@ -95,7 +95,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.api.permissions.html b/docs/1.0-dev/api/evennia.web.api.permissions.html index c87c627bc9..d6a93924c3 100644 --- a/docs/1.0-dev/api/evennia.web.api.permissions.html +++ b/docs/1.0-dev/api/evennia.web.api.permissions.html @@ -180,7 +180,6 @@ complete the action.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.api.root.html b/docs/1.0-dev/api/evennia.web.api.root.html index 0de6680217..cec63543f8 100644 --- a/docs/1.0-dev/api/evennia.web.api.root.html +++ b/docs/1.0-dev/api/evennia.web.api.root.html @@ -104,7 +104,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.api.serializers.html b/docs/1.0-dev/api/evennia.web.api.serializers.html index 038a41f978..1dd571f0a3 100644 --- a/docs/1.0-dev/api/evennia.web.api.serializers.html +++ b/docs/1.0-dev/api/evennia.web.api.serializers.html @@ -534,7 +534,6 @@ explicitly to not have them render PK-related fields.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.api.tests.html b/docs/1.0-dev/api/evennia.web.api.tests.html index df403fbf0e..a8d2858b55 100644 --- a/docs/1.0-dev/api/evennia.web.api.tests.html +++ b/docs/1.0-dev/api/evennia.web.api.tests.html @@ -150,7 +150,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.api.urls.html b/docs/1.0-dev/api/evennia.web.api.urls.html index bcb4137d8f..ed00b0f1dc 100644 --- a/docs/1.0-dev/api/evennia.web.api.urls.html +++ b/docs/1.0-dev/api/evennia.web.api.urls.html @@ -98,7 +98,6 @@ set attribute: action: POST, url: /objects/<:pk>/set-attribute, view nam

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.api.views.html b/docs/1.0-dev/api/evennia.web.api.views.html index 6ef72fa4b9..8bf5b8794e 100644 --- a/docs/1.0-dev/api/evennia.web.api.views.html +++ b/docs/1.0-dev/api/evennia.web.api.views.html @@ -485,7 +485,6 @@ Note that command auto-help and file-based help entries are not accessible this

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.html b/docs/1.0-dev/api/evennia.web.html index 1f91e9960f..bcd59828da 100644 --- a/docs/1.0-dev/api/evennia.web.html +++ b/docs/1.0-dev/api/evennia.web.html @@ -153,7 +153,6 @@ relate the database contents to web pages.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.templatetags.addclass.html b/docs/1.0-dev/api/evennia.web.templatetags.addclass.html index 86ee513bd1..8db0515ac8 100644 --- a/docs/1.0-dev/api/evennia.web.templatetags.addclass.html +++ b/docs/1.0-dev/api/evennia.web.templatetags.addclass.html @@ -89,7 +89,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.templatetags.html b/docs/1.0-dev/api/evennia.web.templatetags.html index 928ba26c56..3480c434c1 100644 --- a/docs/1.0-dev/api/evennia.web.templatetags.html +++ b/docs/1.0-dev/api/evennia.web.templatetags.html @@ -89,7 +89,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.urls.html b/docs/1.0-dev/api/evennia.web.urls.html index 6c8ca095ef..dd87c9eddf 100644 --- a/docs/1.0-dev/api/evennia.web.urls.html +++ b/docs/1.0-dev/api/evennia.web.urls.html @@ -99,7 +99,6 @@ dynamic content as appropriate.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.utils.adminsite.html b/docs/1.0-dev/api/evennia.web.utils.adminsite.html index 6d95107977..189318bbf7 100644 --- a/docs/1.0-dev/api/evennia.web.utils.adminsite.html +++ b/docs/1.0-dev/api/evennia.web.utils.adminsite.html @@ -126,7 +126,6 @@ registered in this site.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.utils.backends.html b/docs/1.0-dev/api/evennia.web.utils.backends.html index 8b75835f8e..0638caf6b8 100644 --- a/docs/1.0-dev/api/evennia.web.utils.backends.html +++ b/docs/1.0-dev/api/evennia.web.utils.backends.html @@ -110,7 +110,6 @@ an already authenticated account and bypass authentication.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.utils.general_context.html b/docs/1.0-dev/api/evennia.web.utils.general_context.html index 90b0be2533..10cdef698c 100644 --- a/docs/1.0-dev/api/evennia.web.utils.general_context.html +++ b/docs/1.0-dev/api/evennia.web.utils.general_context.html @@ -101,7 +101,6 @@ to context of all views.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.utils.html b/docs/1.0-dev/api/evennia.web.utils.html index 6eac238e1e..b0fb655d51 100644 --- a/docs/1.0-dev/api/evennia.web.utils.html +++ b/docs/1.0-dev/api/evennia.web.utils.html @@ -93,7 +93,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.utils.middleware.html b/docs/1.0-dev/api/evennia.web.utils.middleware.html index c18f5c5553..5a3c0566e5 100644 --- a/docs/1.0-dev/api/evennia.web.utils.middleware.html +++ b/docs/1.0-dev/api/evennia.web.utils.middleware.html @@ -102,7 +102,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.utils.tests.html b/docs/1.0-dev/api/evennia.web.utils.tests.html index ca342d8063..ee27b3f101 100644 --- a/docs/1.0-dev/api/evennia.web.utils.tests.html +++ b/docs/1.0-dev/api/evennia.web.utils.tests.html @@ -100,7 +100,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.webclient.html b/docs/1.0-dev/api/evennia.web.webclient.html index f5e1205a90..758d97781d 100644 --- a/docs/1.0-dev/api/evennia.web.webclient.html +++ b/docs/1.0-dev/api/evennia.web.webclient.html @@ -90,7 +90,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.webclient.urls.html b/docs/1.0-dev/api/evennia.web.webclient.urls.html index c418bf927b..1e78f2900d 100644 --- a/docs/1.0-dev/api/evennia.web.webclient.urls.html +++ b/docs/1.0-dev/api/evennia.web.webclient.urls.html @@ -85,7 +85,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.webclient.views.html b/docs/1.0-dev/api/evennia.web.webclient.views.html index 3cbb3616d8..15541a88a7 100644 --- a/docs/1.0-dev/api/evennia.web.webclient.views.html +++ b/docs/1.0-dev/api/evennia.web.webclient.views.html @@ -92,7 +92,6 @@ page and serve it eventual static content.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.website.forms.html b/docs/1.0-dev/api/evennia.web.website.forms.html index d8c57ce42d..c5c2f70fca 100644 --- a/docs/1.0-dev/api/evennia.web.website.forms.html +++ b/docs/1.0-dev/api/evennia.web.website.forms.html @@ -322,7 +322,6 @@ wish to allow.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.website.html b/docs/1.0-dev/api/evennia.web.website.html index 4e0f9b6e3c..bfd04a2001 100644 --- a/docs/1.0-dev/api/evennia.web.website.html +++ b/docs/1.0-dev/api/evennia.web.website.html @@ -106,7 +106,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.website.tests.html b/docs/1.0-dev/api/evennia.web.website.tests.html index 1ef3cd06cb..39ae30df6a 100644 --- a/docs/1.0-dev/api/evennia.web.website.tests.html +++ b/docs/1.0-dev/api/evennia.web.website.tests.html @@ -530,7 +530,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.website.urls.html b/docs/1.0-dev/api/evennia.web.website.urls.html index b9f8597532..2c9b4ddd5f 100644 --- a/docs/1.0-dev/api/evennia.web.website.urls.html +++ b/docs/1.0-dev/api/evennia.web.website.urls.html @@ -85,7 +85,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.website.views.accounts.html b/docs/1.0-dev/api/evennia.web.website.views.accounts.html index 4032924325..c8b7c647ec 100644 --- a/docs/1.0-dev/api/evennia.web.website.views.accounts.html +++ b/docs/1.0-dev/api/evennia.web.website.views.accounts.html @@ -132,7 +132,6 @@ proceeds with creating the Account object.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.website.views.channels.html b/docs/1.0-dev/api/evennia.web.website.views.channels.html index 97e45c30d2..15f52b44f2 100644 --- a/docs/1.0-dev/api/evennia.web.website.views.channels.html +++ b/docs/1.0-dev/api/evennia.web.website.views.channels.html @@ -207,7 +207,6 @@ name.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.website.views.characters.html b/docs/1.0-dev/api/evennia.web.website.views.characters.html index 3a7c710e2f..ce665e709b 100644 --- a/docs/1.0-dev/api/evennia.web.website.views.characters.html +++ b/docs/1.0-dev/api/evennia.web.website.views.characters.html @@ -298,7 +298,6 @@ proceeds with creating the Character object.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.website.views.errors.html b/docs/1.0-dev/api/evennia.web.website.views.errors.html index c9b33c6a4e..34161e1e10 100644 --- a/docs/1.0-dev/api/evennia.web.website.views.errors.html +++ b/docs/1.0-dev/api/evennia.web.website.views.errors.html @@ -92,7 +92,6 @@ implemented yet.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.website.views.help.html b/docs/1.0-dev/api/evennia.web.website.views.help.html index 5fad6e15d3..b6927e18aa 100644 --- a/docs/1.0-dev/api/evennia.web.website.views.help.html +++ b/docs/1.0-dev/api/evennia.web.website.views.help.html @@ -268,7 +268,6 @@ instead of pk and slug.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.website.views.html b/docs/1.0-dev/api/evennia.web.website.views.html index 5a23089db3..1e90a43316 100644 --- a/docs/1.0-dev/api/evennia.web.website.views.html +++ b/docs/1.0-dev/api/evennia.web.website.views.html @@ -97,7 +97,6 @@

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.website.views.index.html b/docs/1.0-dev/api/evennia.web.website.views.index.html index f9408b055e..09fde79c62 100644 --- a/docs/1.0-dev/api/evennia.web.website.views.index.html +++ b/docs/1.0-dev/api/evennia.web.website.views.index.html @@ -133,7 +133,6 @@ of this method.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.website.views.mixins.html b/docs/1.0-dev/api/evennia.web.website.views.mixins.html index 818f03873c..0d552ba9b4 100644 --- a/docs/1.0-dev/api/evennia.web.website.views.mixins.html +++ b/docs/1.0-dev/api/evennia.web.website.views.mixins.html @@ -159,7 +159,6 @@ otherwise.

      Versions

      diff --git a/docs/1.0-dev/api/evennia.web.website.views.objects.html b/docs/1.0-dev/api/evennia.web.website.views.objects.html index 631462f30f..f3960126d6 100644 --- a/docs/1.0-dev/api/evennia.web.website.views.objects.html +++ b/docs/1.0-dev/api/evennia.web.website.views.objects.html @@ -257,7 +257,6 @@ validated and sanitized.

      Versions

      diff --git a/docs/1.0-dev/genindex.html b/docs/1.0-dev/genindex.html index 980068049f..c40a9b878b 100644 --- a/docs/1.0-dev/genindex.html +++ b/docs/1.0-dev/genindex.html @@ -87,6 +87,10 @@
    • (evennia.comms.models.SubscriptionHandler method)
    • (evennia.comms.models.TempMsg method) +
    • +
    • (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage method) +
    • +
    • (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3StorageFile method)
    • (evennia.contrib.base_systems.building_menu.building_menu.BuildingMenu method)
    • @@ -365,6 +369,10 @@
    • (evennia.typeclasses.models.TypedObject method)
    +
  • access_key (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute) +
  • +
  • access_key_names (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute) +
  • access_type (evennia.web.website.views.channels.ChannelMixin attribute)
  • authenticated_response (evennia.web.website.tests.EvenniaWebTest attribute)
  • -
  • author (evennia.contrib.base_systems.ingame_python.callbackhandler.Callback attribute) +
  • author() (evennia.contrib.base_systems.ingame_python.callbackhandler.Callback property)
  • auto_close_msg (evennia.contrib.tutorials.red_button.red_button.RedButton attribute) +
  • +
  • auto_create_bucket (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute)
  • auto_help (evennia.commands.command.Command attribute) @@ -2610,6 +2622,14 @@
  • brightbg_sub (evennia.utils.ansi.ANSIParser attribute)
  • broadcast() (evennia.server.portal.amp.AMPMultiConnectionProtocol method) +
  • +
  • bucket() (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage property) +
  • +
  • bucket_acl (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute) +
  • +
  • bucket_name (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute) +
  • +
  • buffer_size (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3StorageFile attribute)
  • build_links() (evennia.contrib.grid.xyzgrid.xymap_legend.MapNode method) @@ -2924,6 +2944,8 @@
  • check_has_attr() (evennia.commands.default.building.CmdCpAttr method)
  • check_light_state() (evennia.contrib.tutorials.tutorial_world.rooms.DarkRoom method) +
  • +
  • check_location() (in module evennia.contrib.base_systems.awsstorage.aws_s3_cdn)
  • check_locks() (evennia.web.api.permissions.EvenniaPermission static method)
  • @@ -3053,8 +3075,12 @@
  • Climbable.MultipleObjectsReturned
  • -
  • close() (evennia.contrib.base_systems.building_menu.building_menu.BuildingMenu method) +
  • close() (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3StorageFile method) + +
  • close_menu() (evennia.contrib.tutorials.tutorial_world.intro_menu.TutorialEvMenu method)
  • +
  • connection() (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage property) +
  • connection_time() (evennia.accounts.accounts.DefaultAccount property)
  • current_choice() (evennia.contrib.base_systems.building_menu.building_menu.BuildingMenu property) +
  • +
  • custom_domain (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute)
  • custom_gametime() (in module evennia.contrib.base_systems.custom_gametime.custom_gametime)
  • @@ -4437,6 +4467,12 @@
  • decode_msdp() (evennia.server.portal.telnet_oob.TelnetOOB method)
  • +
  • deconstruct() (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage method) + +
  • decrease_indent() (evennia.utils.eveditor.EvEditor method)
  • dedent() (in module evennia.utils.utils) @@ -4457,12 +4493,16 @@
  • (in module evennia.server.inputfuncs)
  • +
  • default_acl (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute) +
  • default_confirm (evennia.commands.default.building.CmdDestroy attribute)
  • +
  • default_content_type (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute) +
  • default_error_messages (evennia.utils.picklefield.PickledFormField attribute)
  • default_keys (evennia.contrib.rpg.traits.traits.CounterTrait attribute) @@ -4505,12 +4545,12 @@
  • DefaultExit.MultipleObjectsReturned
  • + + - + +
    • evennia.contrib.utils.tree_select.tests @@ -6259,8 +6316,6 @@
    • module
    - -
    • evennia.contrib.utils.tree_select.tree_select @@ -7489,9 +7544,11 @@
  • ExhaustedGenerator
  • -
  • exists() (evennia.scripts.taskhandler.TaskHandler method) +
  • exists() (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage method)
  • @@ -7663,6 +7720,12 @@
  • (evennia.web.admin.tags.TagAdmin attribute)
  • +
  • file() (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3StorageFile property) +
  • +
  • file_name_charset (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute) +
  • +
  • file_overwrite (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute) +
  • FileHelpEntry (class in evennia.help.filehelp)
  • FileHelpStorageHandler (class in evennia.help.filehelp) @@ -8630,6 +8693,10 @@
  • get_attribute() (evennia.typeclasses.managers.TypedObjectManager method)
  • get_attributes() (evennia.web.api.serializers.TypeclassSerializerMixin static method) +
  • +
  • get_available_name() (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage method) +
  • +
  • get_available_overwrite_name() (in module evennia.contrib.base_systems.awsstorage.aws_s3_cdn)
  • get_browserstr() (evennia.server.portal.webclient_ajax.AjaxWebClient method)
  • @@ -8918,6 +8985,8 @@
  • get_min_height() (evennia.utils.evtable.EvCell method)
  • get_min_width() (evennia.utils.evtable.EvCell method) +
  • +
  • get_modified_time() (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage method)
  • get_new() (evennia.server.portal.rss.RSSReader method)
  • @@ -8971,6 +9040,8 @@
  • (evennia.web.website.views.objects.ObjectDetailView method)
  • +
  • get_object_parameters() (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage method) +
  • get_object_with_account() (evennia.objects.manager.ObjectDBManager method)
  • get_objs_at_coordinates() (evennia.contrib.grid.wilderness.wilderness.WildernessScript method) @@ -9176,6 +9247,10 @@
  • grid() (evennia.contrib.grid.xyzgrid.xyzgrid.XYZGrid property)
  • groups (evennia.accounts.models.AccountDB attribute) +
  • +
  • gzip (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute) +
  • +
  • gzip_content_types (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute)
  • @@ -11094,6 +11169,8 @@
  • list_tasks() (evennia.contrib.base_systems.ingame_python.commands.CmdCallback method)
  • list_to_string() (in module evennia.utils.utils) +
  • +
  • listdir() (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage method)
  • Listenable (class in evennia.contrib.full_systems.evscaperoom.objects)
  • @@ -11130,6 +11207,8 @@
  • load_sync_data() (evennia.server.session.Session method)
  • loads() (in module evennia.server.portal.amp) +
  • +
  • location (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute)
  • location() (evennia.objects.models.ObjectDB property)
  • @@ -12143,6 +12222,8 @@
  • (evennia.server.webserver.Website method)
  • +
  • lookup_env() (in module evennia.contrib.base_systems.awsstorage.aws_s3_cdn) +
  • lower() (evennia.utils.ansi.ANSIString method)
  • lstrip() (evennia.utils.ansi.ANSIString method) @@ -12271,6 +12352,8 @@
  • (evennia.contrib.rpg.traits.traits.GaugeTrait property)
  • +
  • max_memory_size (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute) +
  • max_num_lines (evennia.web.website.views.channels.ChannelDetailView attribute)
  • max_pathfinding_length (evennia.contrib.grid.xyzgrid.xymap.XYMap attribute) @@ -12582,6 +12665,8 @@
  • ModelAttributeBackend (class in evennia.typeclasses.attributes)
  • models (evennia.web.admin.comms.MsgForm.Meta attribute) +
  • +
  • modified_time() (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage method)
  • module @@ -12656,6 +12741,8 @@
  • evennia.contrib.base_systems
  • evennia.contrib.base_systems.awsstorage +
  • +
  • evennia.contrib.base_systems.awsstorage.aws_s3_cdn
  • evennia.contrib.base_systems.awsstorage.tests
  • @@ -13402,11 +13489,9 @@

    N

    @@ -13734,16 +13821,18 @@
  • obfuscate_whisper() (in module evennia.contrib.rpg.rpsystem.rplanguage)
  • -
  • obj (evennia.contrib.base_systems.ingame_python.callbackhandler.Callback attribute) +
  • obj (evennia.contrib.game_systems.cooldowns.cooldowns.CooldownHandler attribute)
  • -
  • obj() (evennia.scripts.models.ScriptDB property) +
  • obj() (evennia.contrib.base_systems.ingame_python.callbackhandler.Callback property) + +
  • obj1_search (evennia.contrib.full_systems.evscaperoom.commands.CmdCreateObj attribute)
  • +
  • preload_metadata (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute) +
  • print_debug_info() (evennia.utils.evmenu.EvMenu method)
  • print_help() (evennia.contrib.base_systems.unixcommand.unixcommand.UnixCommandParser method) @@ -14815,6 +14908,8 @@
  • prototype_to_str() (in module evennia.prototypes.prototypes)
  • PrototypeEvMore (class in evennia.prototypes.prototypes) +
  • +
  • proxies (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute)
  • puppet() (evennia.accounts.accounts.DefaultAccount property)
  • @@ -14866,10 +14961,10 @@
  • (evennia.typeclasses.attributes.ModelAttributeBackend method)
  • - - +
    • queryset (evennia.web.api.views.AccountDBViewSet attribute)
        @@ -14887,6 +14982,10 @@
    • queryset_maxsize() (in module evennia.utils.evmore) +
    • +
    • querystring_auth (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute) +
    • +
    • querystring_expire (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute)
    • QuietHTTP11ClientFactory (class in evennia.server.game_index_client.client)
    • @@ -14971,6 +15070,8 @@
    • re_unhilite (evennia.utils.text2html.TextToHTMLparser attribute)
    • re_url (evennia.utils.text2html.TextToHTMLparser attribute) +
    • +
    • read() (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3StorageFile method)
    • read_batchfile() (in module evennia.utils.batchprocessors)
    • @@ -14999,6 +15100,8 @@
    • Readable.DoesNotExist
    • Readable.MultipleObjectsReturned +
    • +
    • readline() (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3StorageFile method)
    • readlines() (evennia.utils.logger.EvenniaLogFile method)
    • @@ -15067,6 +15170,8 @@
    • RedButton.DoesNotExist
    • RedButton.MultipleObjectsReturned +
    • +
    • reduced_redundancy (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute)
    • reformat() (evennia.utils.evtable.EvCell method) @@ -15081,6 +15186,8 @@
    • reformat_column() (evennia.utils.evtable.EvTable method)
    • regex_tuple_from_key_alias() (in module evennia.contrib.rpg.rpsystem.rpsystem) +
    • +
    • region_name (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute)
    • register_events() (in module evennia.contrib.base_systems.ingame_python.utils)
    • @@ -15490,11 +15597,17 @@

      S

      - +
      -
    • send_to_online_only (evennia.comms.comms.DefaultChannel attribute) -
    • +
    • signature_version (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute) +
    • signed_integer() (in module evennia.utils.validatorfuncs)
    • SignedInteger (class in evennia.utils.optionclasses) @@ -16738,6 +16865,12 @@
    • Sittable.MultipleObjectsReturned
    • +
    • size() (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage method) + +
    • skill_requirements (evennia.contrib.game_systems.crafting.example_recipes.FireballRecipe attribute)
    • -
    • task (evennia.contrib.grid.xyzgrid.commands.PathData attribute) +
    • task() (evennia.contrib.grid.xyzgrid.commands.PathData property)
    • TaskHandler (class in evennia.scripts.taskhandler)
    • @@ -19926,10 +20059,10 @@
    • (evennia.utils.utils.LimitedSizeOrderedDict method)
    • -
      -
    • updated_by (evennia.contrib.base_systems.ingame_python.callbackhandler.Callback attribute) +
    • updated_by() (evennia.contrib.base_systems.ingame_python.callbackhandler.Callback property)
    • -
    • updated_on (evennia.contrib.base_systems.ingame_python.callbackhandler.Callback attribute) +
    • updated_on() (evennia.contrib.base_systems.ingame_python.callbackhandler.Callback property)
    • UpMapLink (class in evennia.contrib.grid.xyzgrid.xymap_legend)
    • upper() (evennia.utils.ansi.ANSIString method)
    • uptime() (in module evennia.utils.gametime) +
    • +
    • url() (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage method)
    • url_name (evennia.web.website.tests.AdminTest attribute) @@ -20004,6 +20139,8 @@
    • (evennia.web.website.tests.WebclientTest attribute)
    • +
    • url_protocol (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute) +
    • Usable (class in evennia.contrib.full_systems.evscaperoom.objects)
    • Usable.DoesNotExist @@ -20011,6 +20148,8 @@
    • Usable.MultipleObjectsReturned
    • use_item() (in module evennia.contrib.game_systems.turnbattle.tb_items) +
    • +
    • use_ssl (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute)
    • user_change_password() (evennia.web.admin.accounts.AccountAdmin method)
    • @@ -20024,7 +20163,7 @@

      V

      - + @@ -20370,10 +20515,12 @@
    • XYMap (class in evennia.contrib.grid.xyzgrid.xymap)
    • -
    • xymap (evennia.contrib.grid.xyzgrid.commands.PathData attribute) -
    • -
    • xymap() (evennia.contrib.grid.xyzgrid.xyzroom.XYZRoom property) +
    • xymap() (evennia.contrib.grid.xyzgrid.commands.PathData property) + +
    • xyz() (evennia.contrib.grid.xyzgrid.xyzroom.XYZExit property)
        @@ -20473,7 +20620,6 @@

        Versions

        diff --git a/docs/1.0-dev/index.html b/docs/1.0-dev/index.html index 10549d08eb..1203ace30c 100644 --- a/docs/1.0-dev/index.html +++ b/docs/1.0-dev/index.html @@ -144,7 +144,6 @@ off using v0.9.5 of the docs, or the original wiki. You have been warned.

        Versions

        diff --git a/docs/1.0-dev/objects.inv b/docs/1.0-dev/objects.inv index 0f51f83b42..cbfb805ecf 100644 Binary files a/docs/1.0-dev/objects.inv and b/docs/1.0-dev/objects.inv differ diff --git a/docs/1.0-dev/py-modindex.html b/docs/1.0-dev/py-modindex.html index 2241f74573..1a3d726993 100644 --- a/docs/1.0-dev/py-modindex.html +++ b/docs/1.0-dev/py-modindex.html @@ -229,6 +229,11 @@
    • + + +
      +
    • verify (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage attribute) +
    • verify_online_player() (in module evennia.contrib.utils.fieldfill.fieldfill)
    • verify_or_create_SSL_key_and_cert() (in module evennia.server.portal.telnet_ssl) @@ -20270,10 +20411,10 @@
    • webclient() (in module evennia.web.webclient.views)
    • -
    • wrap_conflictual_object() (in module evennia.utils.picklefield)
    • -
    • write() (evennia.utils.logger.WeeklyLogFile method) +
    • write() (evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3StorageFile method) + +
    • WSGIWebServer (class in evennia.server.webserver)
    •     evennia.contrib.base_systems.awsstorage
          + evennia.contrib.base_systems.awsstorage.aws_s3_cdn +
          @@ -1739,7 +1744,6 @@

      Versions

      diff --git a/docs/1.0-dev/search.html b/docs/1.0-dev/search.html index 741b95a2d1..7606808cef 100644 --- a/docs/1.0-dev/search.html +++ b/docs/1.0-dev/search.html @@ -88,7 +88,6 @@

      Versions

      diff --git a/docs/1.0-dev/searchindex.js b/docs/1.0-dev/searchindex.js index a2693c6de1..27dc5249f1 100644 --- a/docs/1.0-dev/searchindex.js +++ b/docs/1.0-dev/searchindex.js @@ -1 +1 @@ -Search.setIndex({docnames:["Coding/Coding-Introduction","Coding/Coding-Overview","Coding/Continuous-Integration","Coding/Debugging","Coding/Flat-API","Coding/Profiling","Coding/Quirks","Coding/Setting-up-PyCharm","Coding/Unit-Testing","Coding/Updating-Your-Game","Coding/Using-Travis","Coding/Version-Control","Components/Accounts","Components/Attributes","Components/Batch-Code-Processor","Components/Batch-Command-Processor","Components/Batch-Processors","Components/Bootstrap-Components-and-Utilities","Components/Channels","Components/Coding-Utils","Components/Command-Sets","Components/Command-System","Components/Commands","Components/Communications","Components/Components-Overview","Components/Connection-Screen","Components/Default-Commands","Components/EvEditor","Components/EvMenu","Components/EvMore","Components/FuncParser","Components/Help-System","Components/Inputfuncs","Components/Locks","Components/MonitorHandler","Components/Msg","Components/Nicks","Components/Objects","Components/Outputfuncs","Components/Permissions","Components/Portal-And-Server","Components/Prototypes","Components/Scripts","Components/Server","Components/Sessions","Components/Signals","Components/Tags","Components/TickerHandler","Components/Typeclasses","Components/Web-API","Components/Web-Admin","Components/Webclient","Components/Webserver","Components/Website","Concepts/Async-Process","Concepts/Banning","Concepts/Bootstrap-&-Evennia","Concepts/Building-Permissions","Concepts/Change-Messages-Per-Receiver","Concepts/Clickable-Links","Concepts/Colors","Concepts/Concepts-Overview","Concepts/Custom-Protocols","Concepts/Guest-Logins","Concepts/Internationalization","Concepts/Messagepath","Concepts/Multisession-modes","Concepts/New-Models","Concepts/OOB","Concepts/Soft-Code","Concepts/Text-Encodings","Concepts/TextTags","Concepts/Using-MUX-as-a-Standard","Concepts/Web-Features","Concepts/Zones","Contribs/Arxcode-installing-help","Contribs/Building-menus","Contribs/Contrib-AWSStorage","Contribs/Contrib-Auditing","Contribs/Contrib-Barter","Contribs/Contrib-Batchprocessor","Contribs/Contrib-Bodyfunctions","Contribs/Contrib-Building-Menu","Contribs/Contrib-Clothing","Contribs/Contrib-Color-Markups","Contribs/Contrib-Cooldowns","Contribs/Contrib-Crafting","Contribs/Contrib-Custom-Gametime","Contribs/Contrib-Dice","Contribs/Contrib-Email-Login","Contribs/Contrib-Evscaperoom","Contribs/Contrib-Extended-Room","Contribs/Contrib-Fieldfill","Contribs/Contrib-Gendersub","Contribs/Contrib-Health-Bar","Contribs/Contrib-Ingame-Python","Contribs/Contrib-Ingame-Python-Tutorial-Dialogue","Contribs/Contrib-Ingame-Python-Tutorial-Elevator","Contribs/Contrib-Mail","Contribs/Contrib-Mapbuilder","Contribs/Contrib-Menu-Login","Contribs/Contrib-Mirror","Contribs/Contrib-Multidescer","Contribs/Contrib-Mux-Comms-Cmds","Contribs/Contrib-Overview","Contribs/Contrib-Puzzles","Contribs/Contrib-RPSystem","Contribs/Contrib-Random-String-Generator","Contribs/Contrib-Red-Button","Contribs/Contrib-Simpledoor","Contribs/Contrib-Slow-Exit","Contribs/Contrib-Talking-Npc","Contribs/Contrib-Traits","Contribs/Contrib-Tree-Select","Contribs/Contrib-Turnbattle","Contribs/Contrib-Tutorial-World","Contribs/Contrib-Unixcommand","Contribs/Contrib-Wilderness","Contribs/Contrib-XYZGrid","Contributing","Contributing-Docs","Evennia-API","Evennia-Introduction","Glossary","Howto/Add-a-wiki-on-your-website","Howto/Building-a-mech-tutorial","Howto/Coding-FAQ","Howto/Command-Cooldown","Howto/Command-Duration","Howto/Command-Prompt","Howto/Coordinates","Howto/Default-Exit-Errors","Howto/Dynamic-In-Game-Map","Howto/Evennia-for-Diku-Users","Howto/Evennia-for-MUSH-Users","Howto/Evennia-for-roleplaying-sessions","Howto/Gametime-Tutorial","Howto/Help-System-Tutorial","Howto/Howto-Overview","Howto/Manually-Configuring-Color","Howto/Mass-and-weight-for-objects","Howto/NPC-shop-Tutorial","Howto/Parsing-commands-tutorial","Howto/Starting/Part1/Adding-Commands","Howto/Starting/Part1/Building-Quickstart","Howto/Starting/Part1/Creating-Things","Howto/Starting/Part1/Django-queries","Howto/Starting/Part1/Evennia-Library-Overview","Howto/Starting/Part1/Gamedir-Overview","Howto/Starting/Part1/Learning-Typeclasses","Howto/Starting/Part1/More-on-Commands","Howto/Starting/Part1/Python-basic-introduction","Howto/Starting/Part1/Python-classes-and-objects","Howto/Starting/Part1/Searching-Things","Howto/Starting/Part1/Starting-Part1","Howto/Starting/Part1/Tutorial-World-Introduction","Howto/Starting/Part2/Game-Planning","Howto/Starting/Part2/Planning-Some-Useful-Contribs","Howto/Starting/Part2/Planning-The-Tutorial-Game","Howto/Starting/Part2/Planning-Where-Do-I-Begin","Howto/Starting/Part2/Starting-Part2","Howto/Starting/Part3/A-Sittable-Object","Howto/Starting/Part3/Implementing-a-game-rule-system","Howto/Starting/Part3/Starting-Part3","Howto/Starting/Part3/Turn-based-Combat-System","Howto/Starting/Part3/Tutorial-for-basic-MUSH-like-game","Howto/Starting/Part4/Starting-Part4","Howto/Starting/Part5/Add-a-simple-new-web-page","Howto/Starting/Part5/Starting-Part5","Howto/Starting/Part5/Web-Tutorial","Howto/Static-In-Game-Map","Howto/Tutorial-Aggressive-NPCs","Howto/Tutorial-NPCs-listening","Howto/Tutorial-Tweeting-Game-Stats","Howto/Tutorial-Vehicles","Howto/Understanding-Color-Tags","Howto/Weather-Tutorial","Howto/Web-Character-Generation","Howto/Web-Character-View-Tutorial","Licensing","Links","Setup/Apache-Config","Setup/Choosing-An-SQL-Server","Setup/Client-Support-Grid","Setup/Evennia-Game-Index","Setup/Extended-Installation","Setup/Grapevine","Setup/HAProxy-Config","Setup/How-to-connect-Evennia-to-Twitter","Setup/IRC","Setup/Installing-on-Android","Setup/Online-Setup","Setup/RSS","Setup/Running-Evennia-in-Docker","Setup/Security","Setup/Server-Conf","Setup/Settings-File","Setup/Setup-Overview","Setup/Setup-Quickstart","Setup/Start-Stop-Reload","Unimplemented","api/evennia","api/evennia-api","api/evennia.accounts","api/evennia.accounts.accounts","api/evennia.accounts.bots","api/evennia.accounts.manager","api/evennia.accounts.models","api/evennia.commands","api/evennia.commands.cmdhandler","api/evennia.commands.cmdparser","api/evennia.commands.cmdset","api/evennia.commands.cmdsethandler","api/evennia.commands.command","api/evennia.commands.default","api/evennia.commands.default.account","api/evennia.commands.default.admin","api/evennia.commands.default.batchprocess","api/evennia.commands.default.building","api/evennia.commands.default.cmdset_account","api/evennia.commands.default.cmdset_character","api/evennia.commands.default.cmdset_session","api/evennia.commands.default.cmdset_unloggedin","api/evennia.commands.default.comms","api/evennia.commands.default.general","api/evennia.commands.default.help","api/evennia.commands.default.muxcommand","api/evennia.commands.default.syscommands","api/evennia.commands.default.system","api/evennia.commands.default.tests","api/evennia.commands.default.unloggedin","api/evennia.comms","api/evennia.comms.comms","api/evennia.comms.managers","api/evennia.comms.models","api/evennia.contrib","api/evennia.contrib.base_systems","api/evennia.contrib.base_systems.awsstorage","api/evennia.contrib.base_systems.awsstorage.aws_s3_cdn","api/evennia.contrib.base_systems.awsstorage.tests","api/evennia.contrib.base_systems.building_menu","api/evennia.contrib.base_systems.building_menu.building_menu","api/evennia.contrib.base_systems.building_menu.tests","api/evennia.contrib.base_systems.color_markups","api/evennia.contrib.base_systems.color_markups.color_markups","api/evennia.contrib.base_systems.color_markups.tests","api/evennia.contrib.base_systems.custom_gametime","api/evennia.contrib.base_systems.custom_gametime.custom_gametime","api/evennia.contrib.base_systems.custom_gametime.tests","api/evennia.contrib.base_systems.email_login","api/evennia.contrib.base_systems.email_login.connection_screens","api/evennia.contrib.base_systems.email_login.email_login","api/evennia.contrib.base_systems.email_login.tests","api/evennia.contrib.base_systems.ingame_python","api/evennia.contrib.base_systems.ingame_python.callbackhandler","api/evennia.contrib.base_systems.ingame_python.commands","api/evennia.contrib.base_systems.ingame_python.eventfuncs","api/evennia.contrib.base_systems.ingame_python.scripts","api/evennia.contrib.base_systems.ingame_python.tests","api/evennia.contrib.base_systems.ingame_python.typeclasses","api/evennia.contrib.base_systems.ingame_python.utils","api/evennia.contrib.base_systems.menu_login","api/evennia.contrib.base_systems.menu_login.connection_screens","api/evennia.contrib.base_systems.menu_login.menu_login","api/evennia.contrib.base_systems.menu_login.tests","api/evennia.contrib.base_systems.mux_comms_cmds","api/evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds","api/evennia.contrib.base_systems.mux_comms_cmds.tests","api/evennia.contrib.base_systems.unixcommand","api/evennia.contrib.base_systems.unixcommand.tests","api/evennia.contrib.base_systems.unixcommand.unixcommand","api/evennia.contrib.full_systems","api/evennia.contrib.full_systems.evscaperoom","api/evennia.contrib.full_systems.evscaperoom.commands","api/evennia.contrib.full_systems.evscaperoom.menu","api/evennia.contrib.full_systems.evscaperoom.objects","api/evennia.contrib.full_systems.evscaperoom.room","api/evennia.contrib.full_systems.evscaperoom.scripts","api/evennia.contrib.full_systems.evscaperoom.state","api/evennia.contrib.full_systems.evscaperoom.tests","api/evennia.contrib.full_systems.evscaperoom.utils","api/evennia.contrib.game_systems","api/evennia.contrib.game_systems.barter","api/evennia.contrib.game_systems.barter.barter","api/evennia.contrib.game_systems.barter.tests","api/evennia.contrib.game_systems.clothing","api/evennia.contrib.game_systems.clothing.clothing","api/evennia.contrib.game_systems.clothing.tests","api/evennia.contrib.game_systems.cooldowns","api/evennia.contrib.game_systems.cooldowns.cooldowns","api/evennia.contrib.game_systems.cooldowns.tests","api/evennia.contrib.game_systems.crafting","api/evennia.contrib.game_systems.crafting.crafting","api/evennia.contrib.game_systems.crafting.example_recipes","api/evennia.contrib.game_systems.crafting.tests","api/evennia.contrib.game_systems.gendersub","api/evennia.contrib.game_systems.gendersub.gendersub","api/evennia.contrib.game_systems.gendersub.tests","api/evennia.contrib.game_systems.mail","api/evennia.contrib.game_systems.mail.mail","api/evennia.contrib.game_systems.mail.tests","api/evennia.contrib.game_systems.multidescer","api/evennia.contrib.game_systems.multidescer.multidescer","api/evennia.contrib.game_systems.multidescer.tests","api/evennia.contrib.game_systems.puzzles","api/evennia.contrib.game_systems.puzzles.puzzles","api/evennia.contrib.game_systems.puzzles.tests","api/evennia.contrib.game_systems.turnbattle","api/evennia.contrib.game_systems.turnbattle.tb_basic","api/evennia.contrib.game_systems.turnbattle.tb_equip","api/evennia.contrib.game_systems.turnbattle.tb_items","api/evennia.contrib.game_systems.turnbattle.tb_magic","api/evennia.contrib.game_systems.turnbattle.tb_range","api/evennia.contrib.game_systems.turnbattle.tests","api/evennia.contrib.grid","api/evennia.contrib.grid.extended_room","api/evennia.contrib.grid.extended_room.extended_room","api/evennia.contrib.grid.extended_room.tests","api/evennia.contrib.grid.mapbuilder","api/evennia.contrib.grid.mapbuilder.mapbuilder","api/evennia.contrib.grid.mapbuilder.tests","api/evennia.contrib.grid.simpledoor","api/evennia.contrib.grid.simpledoor.simpledoor","api/evennia.contrib.grid.simpledoor.tests","api/evennia.contrib.grid.slow_exit","api/evennia.contrib.grid.slow_exit.slow_exit","api/evennia.contrib.grid.slow_exit.tests","api/evennia.contrib.grid.wilderness","api/evennia.contrib.grid.wilderness.tests","api/evennia.contrib.grid.wilderness.wilderness","api/evennia.contrib.grid.xyzgrid","api/evennia.contrib.grid.xyzgrid.commands","api/evennia.contrib.grid.xyzgrid.example","api/evennia.contrib.grid.xyzgrid.launchcmd","api/evennia.contrib.grid.xyzgrid.prototypes","api/evennia.contrib.grid.xyzgrid.tests","api/evennia.contrib.grid.xyzgrid.utils","api/evennia.contrib.grid.xyzgrid.xymap","api/evennia.contrib.grid.xyzgrid.xymap_legend","api/evennia.contrib.grid.xyzgrid.xyzgrid","api/evennia.contrib.grid.xyzgrid.xyzroom","api/evennia.contrib.rpg","api/evennia.contrib.rpg.dice","api/evennia.contrib.rpg.dice.dice","api/evennia.contrib.rpg.dice.tests","api/evennia.contrib.rpg.health_bar","api/evennia.contrib.rpg.health_bar.health_bar","api/evennia.contrib.rpg.health_bar.tests","api/evennia.contrib.rpg.rpsystem","api/evennia.contrib.rpg.rpsystem.rplanguage","api/evennia.contrib.rpg.rpsystem.rpsystem","api/evennia.contrib.rpg.rpsystem.tests","api/evennia.contrib.rpg.traits","api/evennia.contrib.rpg.traits.tests","api/evennia.contrib.rpg.traits.traits","api/evennia.contrib.tutorials","api/evennia.contrib.tutorials.batchprocessor","api/evennia.contrib.tutorials.batchprocessor.example_batch_code","api/evennia.contrib.tutorials.bodyfunctions","api/evennia.contrib.tutorials.bodyfunctions.bodyfunctions","api/evennia.contrib.tutorials.bodyfunctions.tests","api/evennia.contrib.tutorials.mirror","api/evennia.contrib.tutorials.mirror.mirror","api/evennia.contrib.tutorials.red_button","api/evennia.contrib.tutorials.red_button.red_button","api/evennia.contrib.tutorials.talking_npc","api/evennia.contrib.tutorials.talking_npc.talking_npc","api/evennia.contrib.tutorials.talking_npc.tests","api/evennia.contrib.tutorials.tutorial_world","api/evennia.contrib.tutorials.tutorial_world.intro_menu","api/evennia.contrib.tutorials.tutorial_world.mob","api/evennia.contrib.tutorials.tutorial_world.objects","api/evennia.contrib.tutorials.tutorial_world.rooms","api/evennia.contrib.tutorials.tutorial_world.tests","api/evennia.contrib.utils","api/evennia.contrib.utils.auditing","api/evennia.contrib.utils.auditing.outputs","api/evennia.contrib.utils.auditing.server","api/evennia.contrib.utils.auditing.tests","api/evennia.contrib.utils.fieldfill","api/evennia.contrib.utils.fieldfill.fieldfill","api/evennia.contrib.utils.random_string_generator","api/evennia.contrib.utils.random_string_generator.random_string_generator","api/evennia.contrib.utils.random_string_generator.tests","api/evennia.contrib.utils.tree_select","api/evennia.contrib.utils.tree_select.tests","api/evennia.contrib.utils.tree_select.tree_select","api/evennia.help","api/evennia.help.filehelp","api/evennia.help.manager","api/evennia.help.models","api/evennia.help.utils","api/evennia.locks","api/evennia.locks.lockfuncs","api/evennia.locks.lockhandler","api/evennia.objects","api/evennia.objects.manager","api/evennia.objects.models","api/evennia.objects.objects","api/evennia.prototypes","api/evennia.prototypes.menus","api/evennia.prototypes.protfuncs","api/evennia.prototypes.prototypes","api/evennia.prototypes.spawner","api/evennia.scripts","api/evennia.scripts.manager","api/evennia.scripts.models","api/evennia.scripts.monitorhandler","api/evennia.scripts.scripthandler","api/evennia.scripts.scripts","api/evennia.scripts.taskhandler","api/evennia.scripts.tickerhandler","api/evennia.server","api/evennia.server.amp_client","api/evennia.server.connection_wizard","api/evennia.server.deprecations","api/evennia.server.evennia_launcher","api/evennia.server.game_index_client","api/evennia.server.game_index_client.client","api/evennia.server.game_index_client.service","api/evennia.server.initial_setup","api/evennia.server.inputfuncs","api/evennia.server.manager","api/evennia.server.models","api/evennia.server.portal","api/evennia.server.portal.amp","api/evennia.server.portal.amp_server","api/evennia.server.portal.grapevine","api/evennia.server.portal.irc","api/evennia.server.portal.mccp","api/evennia.server.portal.mssp","api/evennia.server.portal.mxp","api/evennia.server.portal.naws","api/evennia.server.portal.portal","api/evennia.server.portal.portalsessionhandler","api/evennia.server.portal.rss","api/evennia.server.portal.ssh","api/evennia.server.portal.ssl","api/evennia.server.portal.suppress_ga","api/evennia.server.portal.telnet","api/evennia.server.portal.telnet_oob","api/evennia.server.portal.telnet_ssl","api/evennia.server.portal.tests","api/evennia.server.portal.ttype","api/evennia.server.portal.webclient","api/evennia.server.portal.webclient_ajax","api/evennia.server.profiling","api/evennia.server.profiling.dummyrunner","api/evennia.server.profiling.dummyrunner_settings","api/evennia.server.profiling.memplot","api/evennia.server.profiling.settings_mixin","api/evennia.server.profiling.test_queries","api/evennia.server.profiling.tests","api/evennia.server.profiling.timetrace","api/evennia.server.server","api/evennia.server.serversession","api/evennia.server.session","api/evennia.server.sessionhandler","api/evennia.server.signals","api/evennia.server.throttle","api/evennia.server.validators","api/evennia.server.webserver","api/evennia.settings_default","api/evennia.typeclasses","api/evennia.typeclasses.attributes","api/evennia.typeclasses.managers","api/evennia.typeclasses.models","api/evennia.typeclasses.tags","api/evennia.utils","api/evennia.utils.ansi","api/evennia.utils.batchprocessors","api/evennia.utils.containers","api/evennia.utils.create","api/evennia.utils.dbserialize","api/evennia.utils.eveditor","api/evennia.utils.evform","api/evennia.utils.evmenu","api/evennia.utils.evmore","api/evennia.utils.evtable","api/evennia.utils.funcparser","api/evennia.utils.gametime","api/evennia.utils.idmapper","api/evennia.utils.idmapper.manager","api/evennia.utils.idmapper.models","api/evennia.utils.idmapper.tests","api/evennia.utils.logger","api/evennia.utils.optionclasses","api/evennia.utils.optionhandler","api/evennia.utils.picklefield","api/evennia.utils.search","api/evennia.utils.test_resources","api/evennia.utils.text2html","api/evennia.utils.utils","api/evennia.utils.validatorfuncs","api/evennia.utils.verb_conjugation","api/evennia.utils.verb_conjugation.conjugate","api/evennia.utils.verb_conjugation.pronouns","api/evennia.utils.verb_conjugation.tests","api/evennia.web","api/evennia.web.admin","api/evennia.web.admin.accounts","api/evennia.web.admin.attributes","api/evennia.web.admin.comms","api/evennia.web.admin.frontpage","api/evennia.web.admin.help","api/evennia.web.admin.objects","api/evennia.web.admin.scripts","api/evennia.web.admin.server","api/evennia.web.admin.tags","api/evennia.web.admin.urls","api/evennia.web.admin.utils","api/evennia.web.api","api/evennia.web.api.filters","api/evennia.web.api.permissions","api/evennia.web.api.root","api/evennia.web.api.serializers","api/evennia.web.api.tests","api/evennia.web.api.urls","api/evennia.web.api.views","api/evennia.web.templatetags","api/evennia.web.templatetags.addclass","api/evennia.web.urls","api/evennia.web.utils","api/evennia.web.utils.adminsite","api/evennia.web.utils.backends","api/evennia.web.utils.general_context","api/evennia.web.utils.middleware","api/evennia.web.utils.tests","api/evennia.web.webclient","api/evennia.web.webclient.urls","api/evennia.web.webclient.views","api/evennia.web.website","api/evennia.web.website.forms","api/evennia.web.website.tests","api/evennia.web.website.urls","api/evennia.web.website.views","api/evennia.web.website.views.accounts","api/evennia.web.website.views.channels","api/evennia.web.website.views.characters","api/evennia.web.website.views.errors","api/evennia.web.website.views.help","api/evennia.web.website.views.index","api/evennia.web.website.views.mixins","api/evennia.web.website.views.objects","index","toc"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":3,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":2,"sphinx.domains.rst":2,"sphinx.domains.std":1,"sphinx.ext.todo":2,"sphinx.ext.viewcode":1,sphinx:56},filenames:["Coding/Coding-Introduction.md","Coding/Coding-Overview.md","Coding/Continuous-Integration.md","Coding/Debugging.md","Coding/Flat-API.md","Coding/Profiling.md","Coding/Quirks.md","Coding/Setting-up-PyCharm.md","Coding/Unit-Testing.md","Coding/Updating-Your-Game.md","Coding/Using-Travis.md","Coding/Version-Control.md","Components/Accounts.md","Components/Attributes.md","Components/Batch-Code-Processor.md","Components/Batch-Command-Processor.md","Components/Batch-Processors.md","Components/Bootstrap-Components-and-Utilities.md","Components/Channels.md","Components/Coding-Utils.md","Components/Command-Sets.md","Components/Command-System.md","Components/Commands.md","Components/Communications.md","Components/Components-Overview.md","Components/Connection-Screen.md","Components/Default-Commands.md","Components/EvEditor.md","Components/EvMenu.md","Components/EvMore.md","Components/FuncParser.md","Components/Help-System.md","Components/Inputfuncs.md","Components/Locks.md","Components/MonitorHandler.md","Components/Msg.md","Components/Nicks.md","Components/Objects.md","Components/Outputfuncs.md","Components/Permissions.md","Components/Portal-And-Server.md","Components/Prototypes.md","Components/Scripts.md","Components/Server.md","Components/Sessions.md","Components/Signals.md","Components/Tags.md","Components/TickerHandler.md","Components/Typeclasses.md","Components/Web-API.md","Components/Web-Admin.md","Components/Webclient.md","Components/Webserver.md","Components/Website.md","Concepts/Async-Process.md","Concepts/Banning.md","Concepts/Bootstrap-&-Evennia.md","Concepts/Building-Permissions.md","Concepts/Change-Messages-Per-Receiver.md","Concepts/Clickable-Links.md","Concepts/Colors.md","Concepts/Concepts-Overview.md","Concepts/Custom-Protocols.md","Concepts/Guest-Logins.md","Concepts/Internationalization.md","Concepts/Messagepath.md","Concepts/Multisession-modes.md","Concepts/New-Models.md","Concepts/OOB.md","Concepts/Soft-Code.md","Concepts/Text-Encodings.md","Concepts/TextTags.md","Concepts/Using-MUX-as-a-Standard.md","Concepts/Web-Features.md","Concepts/Zones.md","Contribs/Arxcode-installing-help.md","Contribs/Building-menus.md","Contribs/Contrib-AWSStorage.md","Contribs/Contrib-Auditing.md","Contribs/Contrib-Barter.md","Contribs/Contrib-Batchprocessor.md","Contribs/Contrib-Bodyfunctions.md","Contribs/Contrib-Building-Menu.md","Contribs/Contrib-Clothing.md","Contribs/Contrib-Color-Markups.md","Contribs/Contrib-Cooldowns.md","Contribs/Contrib-Crafting.md","Contribs/Contrib-Custom-Gametime.md","Contribs/Contrib-Dice.md","Contribs/Contrib-Email-Login.md","Contribs/Contrib-Evscaperoom.md","Contribs/Contrib-Extended-Room.md","Contribs/Contrib-Fieldfill.md","Contribs/Contrib-Gendersub.md","Contribs/Contrib-Health-Bar.md","Contribs/Contrib-Ingame-Python.md","Contribs/Contrib-Ingame-Python-Tutorial-Dialogue.md","Contribs/Contrib-Ingame-Python-Tutorial-Elevator.md","Contribs/Contrib-Mail.md","Contribs/Contrib-Mapbuilder.md","Contribs/Contrib-Menu-Login.md","Contribs/Contrib-Mirror.md","Contribs/Contrib-Multidescer.md","Contribs/Contrib-Mux-Comms-Cmds.md","Contribs/Contrib-Overview.md","Contribs/Contrib-Puzzles.md","Contribs/Contrib-RPSystem.md","Contribs/Contrib-Random-String-Generator.md","Contribs/Contrib-Red-Button.md","Contribs/Contrib-Simpledoor.md","Contribs/Contrib-Slow-Exit.md","Contribs/Contrib-Talking-Npc.md","Contribs/Contrib-Traits.md","Contribs/Contrib-Tree-Select.md","Contribs/Contrib-Turnbattle.md","Contribs/Contrib-Tutorial-World.md","Contribs/Contrib-Unixcommand.md","Contribs/Contrib-Wilderness.md","Contribs/Contrib-XYZGrid.md","Contributing.md","Contributing-Docs.md","Evennia-API.md","Evennia-Introduction.md","Glossary.md","Howto/Add-a-wiki-on-your-website.md","Howto/Building-a-mech-tutorial.md","Howto/Coding-FAQ.md","Howto/Command-Cooldown.md","Howto/Command-Duration.md","Howto/Command-Prompt.md","Howto/Coordinates.md","Howto/Default-Exit-Errors.md","Howto/Dynamic-In-Game-Map.md","Howto/Evennia-for-Diku-Users.md","Howto/Evennia-for-MUSH-Users.md","Howto/Evennia-for-roleplaying-sessions.md","Howto/Gametime-Tutorial.md","Howto/Help-System-Tutorial.md","Howto/Howto-Overview.md","Howto/Manually-Configuring-Color.md","Howto/Mass-and-weight-for-objects.md","Howto/NPC-shop-Tutorial.md","Howto/Parsing-commands-tutorial.md","Howto/Starting/Part1/Adding-Commands.md","Howto/Starting/Part1/Building-Quickstart.md","Howto/Starting/Part1/Creating-Things.md","Howto/Starting/Part1/Django-queries.md","Howto/Starting/Part1/Evennia-Library-Overview.md","Howto/Starting/Part1/Gamedir-Overview.md","Howto/Starting/Part1/Learning-Typeclasses.md","Howto/Starting/Part1/More-on-Commands.md","Howto/Starting/Part1/Python-basic-introduction.md","Howto/Starting/Part1/Python-classes-and-objects.md","Howto/Starting/Part1/Searching-Things.md","Howto/Starting/Part1/Starting-Part1.md","Howto/Starting/Part1/Tutorial-World-Introduction.md","Howto/Starting/Part2/Game-Planning.md","Howto/Starting/Part2/Planning-Some-Useful-Contribs.md","Howto/Starting/Part2/Planning-The-Tutorial-Game.md","Howto/Starting/Part2/Planning-Where-Do-I-Begin.md","Howto/Starting/Part2/Starting-Part2.md","Howto/Starting/Part3/A-Sittable-Object.md","Howto/Starting/Part3/Implementing-a-game-rule-system.md","Howto/Starting/Part3/Starting-Part3.md","Howto/Starting/Part3/Turn-based-Combat-System.md","Howto/Starting/Part3/Tutorial-for-basic-MUSH-like-game.md","Howto/Starting/Part4/Starting-Part4.md","Howto/Starting/Part5/Add-a-simple-new-web-page.md","Howto/Starting/Part5/Starting-Part5.md","Howto/Starting/Part5/Web-Tutorial.md","Howto/Static-In-Game-Map.md","Howto/Tutorial-Aggressive-NPCs.md","Howto/Tutorial-NPCs-listening.md","Howto/Tutorial-Tweeting-Game-Stats.md","Howto/Tutorial-Vehicles.md","Howto/Understanding-Color-Tags.md","Howto/Weather-Tutorial.md","Howto/Web-Character-Generation.md","Howto/Web-Character-View-Tutorial.md","Licensing.md","Links.md","Setup/Apache-Config.md","Setup/Choosing-An-SQL-Server.md","Setup/Client-Support-Grid.md","Setup/Evennia-Game-Index.md","Setup/Extended-Installation.md","Setup/Grapevine.md","Setup/HAProxy-Config.md","Setup/How-to-connect-Evennia-to-Twitter.md","Setup/IRC.md","Setup/Installing-on-Android.md","Setup/Online-Setup.md","Setup/RSS.md","Setup/Running-Evennia-in-Docker.md","Setup/Security.md","Setup/Server-Conf.md","Setup/Settings-File.md","Setup/Setup-Overview.md","Setup/Setup-Quickstart.md","Setup/Start-Stop-Reload.md","Unimplemented.md","api/evennia.md","api/evennia-api.md","api/evennia.accounts.md","api/evennia.accounts.accounts.md","api/evennia.accounts.bots.md","api/evennia.accounts.manager.md","api/evennia.accounts.models.md","api/evennia.commands.md","api/evennia.commands.cmdhandler.md","api/evennia.commands.cmdparser.md","api/evennia.commands.cmdset.md","api/evennia.commands.cmdsethandler.md","api/evennia.commands.command.md","api/evennia.commands.default.md","api/evennia.commands.default.account.md","api/evennia.commands.default.admin.md","api/evennia.commands.default.batchprocess.md","api/evennia.commands.default.building.md","api/evennia.commands.default.cmdset_account.md","api/evennia.commands.default.cmdset_character.md","api/evennia.commands.default.cmdset_session.md","api/evennia.commands.default.cmdset_unloggedin.md","api/evennia.commands.default.comms.md","api/evennia.commands.default.general.md","api/evennia.commands.default.help.md","api/evennia.commands.default.muxcommand.md","api/evennia.commands.default.syscommands.md","api/evennia.commands.default.system.md","api/evennia.commands.default.tests.md","api/evennia.commands.default.unloggedin.md","api/evennia.comms.md","api/evennia.comms.comms.md","api/evennia.comms.managers.md","api/evennia.comms.models.md","api/evennia.contrib.md","api/evennia.contrib.base_systems.md","api/evennia.contrib.base_systems.awsstorage.md","api/evennia.contrib.base_systems.awsstorage.aws_s3_cdn.md","api/evennia.contrib.base_systems.awsstorage.tests.md","api/evennia.contrib.base_systems.building_menu.md","api/evennia.contrib.base_systems.building_menu.building_menu.md","api/evennia.contrib.base_systems.building_menu.tests.md","api/evennia.contrib.base_systems.color_markups.md","api/evennia.contrib.base_systems.color_markups.color_markups.md","api/evennia.contrib.base_systems.color_markups.tests.md","api/evennia.contrib.base_systems.custom_gametime.md","api/evennia.contrib.base_systems.custom_gametime.custom_gametime.md","api/evennia.contrib.base_systems.custom_gametime.tests.md","api/evennia.contrib.base_systems.email_login.md","api/evennia.contrib.base_systems.email_login.connection_screens.md","api/evennia.contrib.base_systems.email_login.email_login.md","api/evennia.contrib.base_systems.email_login.tests.md","api/evennia.contrib.base_systems.ingame_python.md","api/evennia.contrib.base_systems.ingame_python.callbackhandler.md","api/evennia.contrib.base_systems.ingame_python.commands.md","api/evennia.contrib.base_systems.ingame_python.eventfuncs.md","api/evennia.contrib.base_systems.ingame_python.scripts.md","api/evennia.contrib.base_systems.ingame_python.tests.md","api/evennia.contrib.base_systems.ingame_python.typeclasses.md","api/evennia.contrib.base_systems.ingame_python.utils.md","api/evennia.contrib.base_systems.menu_login.md","api/evennia.contrib.base_systems.menu_login.connection_screens.md","api/evennia.contrib.base_systems.menu_login.menu_login.md","api/evennia.contrib.base_systems.menu_login.tests.md","api/evennia.contrib.base_systems.mux_comms_cmds.md","api/evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.md","api/evennia.contrib.base_systems.mux_comms_cmds.tests.md","api/evennia.contrib.base_systems.unixcommand.md","api/evennia.contrib.base_systems.unixcommand.tests.md","api/evennia.contrib.base_systems.unixcommand.unixcommand.md","api/evennia.contrib.full_systems.md","api/evennia.contrib.full_systems.evscaperoom.md","api/evennia.contrib.full_systems.evscaperoom.commands.md","api/evennia.contrib.full_systems.evscaperoom.menu.md","api/evennia.contrib.full_systems.evscaperoom.objects.md","api/evennia.contrib.full_systems.evscaperoom.room.md","api/evennia.contrib.full_systems.evscaperoom.scripts.md","api/evennia.contrib.full_systems.evscaperoom.state.md","api/evennia.contrib.full_systems.evscaperoom.tests.md","api/evennia.contrib.full_systems.evscaperoom.utils.md","api/evennia.contrib.game_systems.md","api/evennia.contrib.game_systems.barter.md","api/evennia.contrib.game_systems.barter.barter.md","api/evennia.contrib.game_systems.barter.tests.md","api/evennia.contrib.game_systems.clothing.md","api/evennia.contrib.game_systems.clothing.clothing.md","api/evennia.contrib.game_systems.clothing.tests.md","api/evennia.contrib.game_systems.cooldowns.md","api/evennia.contrib.game_systems.cooldowns.cooldowns.md","api/evennia.contrib.game_systems.cooldowns.tests.md","api/evennia.contrib.game_systems.crafting.md","api/evennia.contrib.game_systems.crafting.crafting.md","api/evennia.contrib.game_systems.crafting.example_recipes.md","api/evennia.contrib.game_systems.crafting.tests.md","api/evennia.contrib.game_systems.gendersub.md","api/evennia.contrib.game_systems.gendersub.gendersub.md","api/evennia.contrib.game_systems.gendersub.tests.md","api/evennia.contrib.game_systems.mail.md","api/evennia.contrib.game_systems.mail.mail.md","api/evennia.contrib.game_systems.mail.tests.md","api/evennia.contrib.game_systems.multidescer.md","api/evennia.contrib.game_systems.multidescer.multidescer.md","api/evennia.contrib.game_systems.multidescer.tests.md","api/evennia.contrib.game_systems.puzzles.md","api/evennia.contrib.game_systems.puzzles.puzzles.md","api/evennia.contrib.game_systems.puzzles.tests.md","api/evennia.contrib.game_systems.turnbattle.md","api/evennia.contrib.game_systems.turnbattle.tb_basic.md","api/evennia.contrib.game_systems.turnbattle.tb_equip.md","api/evennia.contrib.game_systems.turnbattle.tb_items.md","api/evennia.contrib.game_systems.turnbattle.tb_magic.md","api/evennia.contrib.game_systems.turnbattle.tb_range.md","api/evennia.contrib.game_systems.turnbattle.tests.md","api/evennia.contrib.grid.md","api/evennia.contrib.grid.extended_room.md","api/evennia.contrib.grid.extended_room.extended_room.md","api/evennia.contrib.grid.extended_room.tests.md","api/evennia.contrib.grid.mapbuilder.md","api/evennia.contrib.grid.mapbuilder.mapbuilder.md","api/evennia.contrib.grid.mapbuilder.tests.md","api/evennia.contrib.grid.simpledoor.md","api/evennia.contrib.grid.simpledoor.simpledoor.md","api/evennia.contrib.grid.simpledoor.tests.md","api/evennia.contrib.grid.slow_exit.md","api/evennia.contrib.grid.slow_exit.slow_exit.md","api/evennia.contrib.grid.slow_exit.tests.md","api/evennia.contrib.grid.wilderness.md","api/evennia.contrib.grid.wilderness.tests.md","api/evennia.contrib.grid.wilderness.wilderness.md","api/evennia.contrib.grid.xyzgrid.md","api/evennia.contrib.grid.xyzgrid.commands.md","api/evennia.contrib.grid.xyzgrid.example.md","api/evennia.contrib.grid.xyzgrid.launchcmd.md","api/evennia.contrib.grid.xyzgrid.prototypes.md","api/evennia.contrib.grid.xyzgrid.tests.md","api/evennia.contrib.grid.xyzgrid.utils.md","api/evennia.contrib.grid.xyzgrid.xymap.md","api/evennia.contrib.grid.xyzgrid.xymap_legend.md","api/evennia.contrib.grid.xyzgrid.xyzgrid.md","api/evennia.contrib.grid.xyzgrid.xyzroom.md","api/evennia.contrib.rpg.md","api/evennia.contrib.rpg.dice.md","api/evennia.contrib.rpg.dice.dice.md","api/evennia.contrib.rpg.dice.tests.md","api/evennia.contrib.rpg.health_bar.md","api/evennia.contrib.rpg.health_bar.health_bar.md","api/evennia.contrib.rpg.health_bar.tests.md","api/evennia.contrib.rpg.rpsystem.md","api/evennia.contrib.rpg.rpsystem.rplanguage.md","api/evennia.contrib.rpg.rpsystem.rpsystem.md","api/evennia.contrib.rpg.rpsystem.tests.md","api/evennia.contrib.rpg.traits.md","api/evennia.contrib.rpg.traits.tests.md","api/evennia.contrib.rpg.traits.traits.md","api/evennia.contrib.tutorials.md","api/evennia.contrib.tutorials.batchprocessor.md","api/evennia.contrib.tutorials.batchprocessor.example_batch_code.md","api/evennia.contrib.tutorials.bodyfunctions.md","api/evennia.contrib.tutorials.bodyfunctions.bodyfunctions.md","api/evennia.contrib.tutorials.bodyfunctions.tests.md","api/evennia.contrib.tutorials.mirror.md","api/evennia.contrib.tutorials.mirror.mirror.md","api/evennia.contrib.tutorials.red_button.md","api/evennia.contrib.tutorials.red_button.red_button.md","api/evennia.contrib.tutorials.talking_npc.md","api/evennia.contrib.tutorials.talking_npc.talking_npc.md","api/evennia.contrib.tutorials.talking_npc.tests.md","api/evennia.contrib.tutorials.tutorial_world.md","api/evennia.contrib.tutorials.tutorial_world.intro_menu.md","api/evennia.contrib.tutorials.tutorial_world.mob.md","api/evennia.contrib.tutorials.tutorial_world.objects.md","api/evennia.contrib.tutorials.tutorial_world.rooms.md","api/evennia.contrib.tutorials.tutorial_world.tests.md","api/evennia.contrib.utils.md","api/evennia.contrib.utils.auditing.md","api/evennia.contrib.utils.auditing.outputs.md","api/evennia.contrib.utils.auditing.server.md","api/evennia.contrib.utils.auditing.tests.md","api/evennia.contrib.utils.fieldfill.md","api/evennia.contrib.utils.fieldfill.fieldfill.md","api/evennia.contrib.utils.random_string_generator.md","api/evennia.contrib.utils.random_string_generator.random_string_generator.md","api/evennia.contrib.utils.random_string_generator.tests.md","api/evennia.contrib.utils.tree_select.md","api/evennia.contrib.utils.tree_select.tests.md","api/evennia.contrib.utils.tree_select.tree_select.md","api/evennia.help.md","api/evennia.help.filehelp.md","api/evennia.help.manager.md","api/evennia.help.models.md","api/evennia.help.utils.md","api/evennia.locks.md","api/evennia.locks.lockfuncs.md","api/evennia.locks.lockhandler.md","api/evennia.objects.md","api/evennia.objects.manager.md","api/evennia.objects.models.md","api/evennia.objects.objects.md","api/evennia.prototypes.md","api/evennia.prototypes.menus.md","api/evennia.prototypes.protfuncs.md","api/evennia.prototypes.prototypes.md","api/evennia.prototypes.spawner.md","api/evennia.scripts.md","api/evennia.scripts.manager.md","api/evennia.scripts.models.md","api/evennia.scripts.monitorhandler.md","api/evennia.scripts.scripthandler.md","api/evennia.scripts.scripts.md","api/evennia.scripts.taskhandler.md","api/evennia.scripts.tickerhandler.md","api/evennia.server.md","api/evennia.server.amp_client.md","api/evennia.server.connection_wizard.md","api/evennia.server.deprecations.md","api/evennia.server.evennia_launcher.md","api/evennia.server.game_index_client.md","api/evennia.server.game_index_client.client.md","api/evennia.server.game_index_client.service.md","api/evennia.server.initial_setup.md","api/evennia.server.inputfuncs.md","api/evennia.server.manager.md","api/evennia.server.models.md","api/evennia.server.portal.md","api/evennia.server.portal.amp.md","api/evennia.server.portal.amp_server.md","api/evennia.server.portal.grapevine.md","api/evennia.server.portal.irc.md","api/evennia.server.portal.mccp.md","api/evennia.server.portal.mssp.md","api/evennia.server.portal.mxp.md","api/evennia.server.portal.naws.md","api/evennia.server.portal.portal.md","api/evennia.server.portal.portalsessionhandler.md","api/evennia.server.portal.rss.md","api/evennia.server.portal.ssh.md","api/evennia.server.portal.ssl.md","api/evennia.server.portal.suppress_ga.md","api/evennia.server.portal.telnet.md","api/evennia.server.portal.telnet_oob.md","api/evennia.server.portal.telnet_ssl.md","api/evennia.server.portal.tests.md","api/evennia.server.portal.ttype.md","api/evennia.server.portal.webclient.md","api/evennia.server.portal.webclient_ajax.md","api/evennia.server.profiling.md","api/evennia.server.profiling.dummyrunner.md","api/evennia.server.profiling.dummyrunner_settings.md","api/evennia.server.profiling.memplot.md","api/evennia.server.profiling.settings_mixin.md","api/evennia.server.profiling.test_queries.md","api/evennia.server.profiling.tests.md","api/evennia.server.profiling.timetrace.md","api/evennia.server.server.md","api/evennia.server.serversession.md","api/evennia.server.session.md","api/evennia.server.sessionhandler.md","api/evennia.server.signals.md","api/evennia.server.throttle.md","api/evennia.server.validators.md","api/evennia.server.webserver.md","api/evennia.settings_default.md","api/evennia.typeclasses.md","api/evennia.typeclasses.attributes.md","api/evennia.typeclasses.managers.md","api/evennia.typeclasses.models.md","api/evennia.typeclasses.tags.md","api/evennia.utils.md","api/evennia.utils.ansi.md","api/evennia.utils.batchprocessors.md","api/evennia.utils.containers.md","api/evennia.utils.create.md","api/evennia.utils.dbserialize.md","api/evennia.utils.eveditor.md","api/evennia.utils.evform.md","api/evennia.utils.evmenu.md","api/evennia.utils.evmore.md","api/evennia.utils.evtable.md","api/evennia.utils.funcparser.md","api/evennia.utils.gametime.md","api/evennia.utils.idmapper.md","api/evennia.utils.idmapper.manager.md","api/evennia.utils.idmapper.models.md","api/evennia.utils.idmapper.tests.md","api/evennia.utils.logger.md","api/evennia.utils.optionclasses.md","api/evennia.utils.optionhandler.md","api/evennia.utils.picklefield.md","api/evennia.utils.search.md","api/evennia.utils.test_resources.md","api/evennia.utils.text2html.md","api/evennia.utils.utils.md","api/evennia.utils.validatorfuncs.md","api/evennia.utils.verb_conjugation.md","api/evennia.utils.verb_conjugation.conjugate.md","api/evennia.utils.verb_conjugation.pronouns.md","api/evennia.utils.verb_conjugation.tests.md","api/evennia.web.md","api/evennia.web.admin.md","api/evennia.web.admin.accounts.md","api/evennia.web.admin.attributes.md","api/evennia.web.admin.comms.md","api/evennia.web.admin.frontpage.md","api/evennia.web.admin.help.md","api/evennia.web.admin.objects.md","api/evennia.web.admin.scripts.md","api/evennia.web.admin.server.md","api/evennia.web.admin.tags.md","api/evennia.web.admin.urls.md","api/evennia.web.admin.utils.md","api/evennia.web.api.md","api/evennia.web.api.filters.md","api/evennia.web.api.permissions.md","api/evennia.web.api.root.md","api/evennia.web.api.serializers.md","api/evennia.web.api.tests.md","api/evennia.web.api.urls.md","api/evennia.web.api.views.md","api/evennia.web.templatetags.md","api/evennia.web.templatetags.addclass.md","api/evennia.web.urls.md","api/evennia.web.utils.md","api/evennia.web.utils.adminsite.md","api/evennia.web.utils.backends.md","api/evennia.web.utils.general_context.md","api/evennia.web.utils.middleware.md","api/evennia.web.utils.tests.md","api/evennia.web.webclient.md","api/evennia.web.webclient.urls.md","api/evennia.web.webclient.views.md","api/evennia.web.website.md","api/evennia.web.website.forms.md","api/evennia.web.website.tests.md","api/evennia.web.website.urls.md","api/evennia.web.website.views.md","api/evennia.web.website.views.accounts.md","api/evennia.web.website.views.channels.md","api/evennia.web.website.views.characters.md","api/evennia.web.website.views.errors.md","api/evennia.web.website.views.help.md","api/evennia.web.website.views.index.md","api/evennia.web.website.views.mixins.md","api/evennia.web.website.views.objects.md","index.md","toc.md"],objects:{"":{evennia:[201,0,0,"-"]},"evennia.accounts":{accounts:[204,0,0,"-"],bots:[205,0,0,"-"],manager:[206,0,0,"-"],models:[207,0,0,"-"]},"evennia.accounts.accounts":{DefaultAccount:[204,1,1,""],DefaultGuest:[204,1,1,""]},"evennia.accounts.accounts.DefaultAccount":{"delete":[204,3,1,""],DoesNotExist:[204,2,1,""],MultipleObjectsReturned:[204,2,1,""],access:[204,3,1,""],at_access:[204,3,1,""],at_account_creation:[204,3,1,""],at_cmdset_get:[204,3,1,""],at_disconnect:[204,3,1,""],at_failed_login:[204,3,1,""],at_first_login:[204,3,1,""],at_first_save:[204,3,1,""],at_init:[204,3,1,""],at_look:[204,3,1,""],at_msg_receive:[204,3,1,""],at_msg_send:[204,3,1,""],at_password_change:[204,3,1,""],at_post_channel_msg:[204,3,1,""],at_post_disconnect:[204,3,1,""],at_post_login:[204,3,1,""],at_pre_channel_msg:[204,3,1,""],at_pre_login:[204,3,1,""],at_server_reload:[204,3,1,""],at_server_shutdown:[204,3,1,""],authenticate:[204,3,1,""],basetype_setup:[204,3,1,""],channel_msg:[204,3,1,""],character:[204,3,1,""],characters:[204,3,1,""],cmdset:[204,4,1,""],connection_time:[204,3,1,""],create:[204,3,1,""],create_character:[204,3,1,""],disconnect_session_from_account:[204,3,1,""],execute_cmd:[204,3,1,""],get_all_puppets:[204,3,1,""],get_display_name:[204,3,1,""],get_puppet:[204,3,1,""],get_username_validators:[204,3,1,""],idle_time:[204,3,1,""],is_banned:[204,3,1,""],msg:[204,3,1,""],nicks:[204,4,1,""],normalize_username:[204,3,1,""],objects:[204,4,1,""],options:[204,4,1,""],path:[204,4,1,""],puppet:[204,3,1,""],puppet_object:[204,3,1,""],scripts:[204,4,1,""],search:[204,3,1,""],sessions:[204,4,1,""],set_password:[204,3,1,""],typename:[204,4,1,""],unpuppet_all:[204,3,1,""],unpuppet_object:[204,3,1,""],validate_password:[204,3,1,""],validate_username:[204,3,1,""]},"evennia.accounts.accounts.DefaultGuest":{DoesNotExist:[204,2,1,""],MultipleObjectsReturned:[204,2,1,""],at_post_disconnect:[204,3,1,""],at_post_login:[204,3,1,""],at_server_shutdown:[204,3,1,""],authenticate:[204,3,1,""],create:[204,3,1,""],path:[204,4,1,""],typename:[204,4,1,""]},"evennia.accounts.bots":{Bot:[205,1,1,""],BotStarter:[205,1,1,""],GrapevineBot:[205,1,1,""],IRCBot:[205,1,1,""],RSSBot:[205,1,1,""]},"evennia.accounts.bots.Bot":{DoesNotExist:[205,2,1,""],MultipleObjectsReturned:[205,2,1,""],at_server_shutdown:[205,3,1,""],basetype_setup:[205,3,1,""],execute_cmd:[205,3,1,""],msg:[205,3,1,""],path:[205,4,1,""],start:[205,3,1,""],typename:[205,4,1,""]},"evennia.accounts.bots.BotStarter":{DoesNotExist:[205,2,1,""],MultipleObjectsReturned:[205,2,1,""],at_repeat:[205,3,1,""],at_script_creation:[205,3,1,""],at_server_reload:[205,3,1,""],at_server_shutdown:[205,3,1,""],at_start:[205,3,1,""],path:[205,4,1,""],typename:[205,4,1,""]},"evennia.accounts.bots.GrapevineBot":{DoesNotExist:[205,2,1,""],MultipleObjectsReturned:[205,2,1,""],at_msg_send:[205,3,1,""],execute_cmd:[205,3,1,""],factory_path:[205,4,1,""],msg:[205,3,1,""],path:[205,4,1,""],start:[205,3,1,""],typename:[205,4,1,""]},"evennia.accounts.bots.IRCBot":{DoesNotExist:[205,2,1,""],MultipleObjectsReturned:[205,2,1,""],at_msg_send:[205,3,1,""],execute_cmd:[205,3,1,""],factory_path:[205,4,1,""],get_nicklist:[205,3,1,""],msg:[205,3,1,""],path:[205,4,1,""],ping:[205,3,1,""],reconnect:[205,3,1,""],start:[205,3,1,""],typename:[205,4,1,""]},"evennia.accounts.bots.RSSBot":{DoesNotExist:[205,2,1,""],MultipleObjectsReturned:[205,2,1,""],execute_cmd:[205,3,1,""],path:[205,4,1,""],start:[205,3,1,""],typename:[205,4,1,""]},"evennia.accounts.manager":{AccountDBManager:[206,1,1,""],AccountManager:[206,1,1,""]},"evennia.accounts.manager.AccountDBManager":{account_search:[206,3,1,""],create_account:[206,3,1,""],get_account_from_email:[206,3,1,""],get_account_from_name:[206,3,1,""],get_account_from_uid:[206,3,1,""],get_connected_accounts:[206,3,1,""],get_recently_connected_accounts:[206,3,1,""],get_recently_created_accounts:[206,3,1,""],num_total_accounts:[206,3,1,""],search_account:[206,3,1,""]},"evennia.accounts.models":{AccountDB:[207,1,1,""]},"evennia.accounts.models.AccountDB":{DoesNotExist:[207,2,1,""],MultipleObjectsReturned:[207,2,1,""],account_subscription_set:[207,4,1,""],cmdset_storage:[207,3,1,""],db_attributes:[207,4,1,""],db_cmdset_storage:[207,4,1,""],db_is_bot:[207,4,1,""],db_is_connected:[207,4,1,""],db_tags:[207,4,1,""],get_next_by_date_joined:[207,3,1,""],get_next_by_db_date_created:[207,3,1,""],get_previous_by_date_joined:[207,3,1,""],get_previous_by_db_date_created:[207,3,1,""],groups:[207,4,1,""],hide_from_accounts_set:[207,4,1,""],id:[207,4,1,""],is_bot:[207,3,1,""],is_connected:[207,3,1,""],key:[207,3,1,""],logentry_set:[207,4,1,""],name:[207,3,1,""],objectdb_set:[207,4,1,""],objects:[207,4,1,""],path:[207,4,1,""],receiver_account_set:[207,4,1,""],scriptdb_set:[207,4,1,""],sender_account_set:[207,4,1,""],typename:[207,4,1,""],uid:[207,3,1,""],user_permissions:[207,4,1,""]},"evennia.commands":{"default":[214,0,0,"-"],cmdhandler:[209,0,0,"-"],cmdparser:[210,0,0,"-"],cmdset:[211,0,0,"-"],cmdsethandler:[212,0,0,"-"],command:[213,0,0,"-"]},"evennia.commands.cmdhandler":{InterruptCommand:[209,2,1,""],cmdhandler:[209,5,1,""]},"evennia.commands.cmdparser":{build_matches:[210,5,1,""],cmdparser:[210,5,1,""],create_match:[210,5,1,""],try_num_differentiators:[210,5,1,""]},"evennia.commands.cmdset":{CmdSet:[211,1,1,""]},"evennia.commands.cmdset.CmdSet":{__init__:[211,3,1,""],add:[211,3,1,""],at_cmdset_creation:[211,3,1,""],count:[211,3,1,""],duplicates:[211,4,1,""],errmessage:[211,4,1,""],get:[211,3,1,""],get_all_cmd_keys_and_aliases:[211,3,1,""],get_system_cmds:[211,3,1,""],key:[211,4,1,""],key_mergetypes:[211,4,1,""],make_unique:[211,3,1,""],mergetype:[211,4,1,""],no_channels:[211,4,1,""],no_exits:[211,4,1,""],no_objs:[211,4,1,""],path:[211,4,1,""],persistent:[211,4,1,""],priority:[211,4,1,""],remove:[211,3,1,""],to_duplicate:[211,4,1,""]},"evennia.commands.cmdsethandler":{CmdSetHandler:[212,1,1,""],import_cmdset:[212,5,1,""]},"evennia.commands.cmdsethandler.CmdSetHandler":{"delete":[212,3,1,""],__init__:[212,3,1,""],add:[212,3,1,""],add_default:[212,3,1,""],all:[212,3,1,""],clear:[212,3,1,""],delete_default:[212,3,1,""],get:[212,3,1,""],has:[212,3,1,""],has_cmdset:[212,3,1,""],remove:[212,3,1,""],remove_default:[212,3,1,""],reset:[212,3,1,""],update:[212,3,1,""]},"evennia.commands.command":{Command:[213,1,1,""],CommandMeta:[213,1,1,""],InterruptCommand:[213,2,1,""]},"evennia.commands.command.Command":{__init__:[213,3,1,""],access:[213,3,1,""],aliases:[213,4,1,""],arg_regex:[213,4,1,""],at_post_cmd:[213,3,1,""],at_pre_cmd:[213,3,1,""],auto_help:[213,4,1,""],client_width:[213,3,1,""],execute_cmd:[213,3,1,""],func:[213,3,1,""],get_command_info:[213,3,1,""],get_extra_info:[213,3,1,""],get_help:[213,3,1,""],help_category:[213,4,1,""],is_exit:[213,4,1,""],key:[213,4,1,""],lock_storage:[213,4,1,""],lockhandler:[213,4,1,""],locks:[213,4,1,""],match:[213,3,1,""],msg:[213,3,1,""],msg_all_sessions:[213,4,1,""],parse:[213,3,1,""],retain_instance:[213,4,1,""],save_for_next:[213,4,1,""],search_index_entry:[213,4,1,""],set_aliases:[213,3,1,""],set_key:[213,3,1,""],styled_footer:[213,3,1,""],styled_header:[213,3,1,""],styled_separator:[213,3,1,""],styled_table:[213,3,1,""],web_get_admin_url:[213,3,1,""],web_get_detail_url:[213,3,1,""]},"evennia.commands.command.CommandMeta":{__init__:[213,3,1,""]},"evennia.commands.default":{account:[215,0,0,"-"],admin:[216,0,0,"-"],batchprocess:[217,0,0,"-"],building:[218,0,0,"-"],cmdset_account:[219,0,0,"-"],cmdset_character:[220,0,0,"-"],cmdset_session:[221,0,0,"-"],cmdset_unloggedin:[222,0,0,"-"],comms:[223,0,0,"-"],general:[224,0,0,"-"],help:[225,0,0,"-"],muxcommand:[226,0,0,"-"],syscommands:[227,0,0,"-"],system:[228,0,0,"-"],unloggedin:[230,0,0,"-"]},"evennia.commands.default.account":{CmdCharCreate:[215,1,1,""],CmdCharDelete:[215,1,1,""],CmdColorTest:[215,1,1,""],CmdIC:[215,1,1,""],CmdOOC:[215,1,1,""],CmdOOCLook:[215,1,1,""],CmdOption:[215,1,1,""],CmdPassword:[215,1,1,""],CmdQuell:[215,1,1,""],CmdQuit:[215,1,1,""],CmdSessions:[215,1,1,""],CmdStyle:[215,1,1,""],CmdWho:[215,1,1,""]},"evennia.commands.default.account.CmdCharCreate":{account_caller:[215,4,1,""],aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""]},"evennia.commands.default.account.CmdCharDelete":{aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""]},"evennia.commands.default.account.CmdColorTest":{account_caller:[215,4,1,""],aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""],slice_bright_bg:[215,4,1,""],slice_bright_fg:[215,4,1,""],slice_dark_bg:[215,4,1,""],slice_dark_fg:[215,4,1,""],table_format:[215,3,1,""]},"evennia.commands.default.account.CmdIC":{account_caller:[215,4,1,""],aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""]},"evennia.commands.default.account.CmdOOC":{account_caller:[215,4,1,""],aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""]},"evennia.commands.default.account.CmdOOCLook":{account_caller:[215,4,1,""],aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""]},"evennia.commands.default.account.CmdOption":{account_caller:[215,4,1,""],aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""],switch_options:[215,4,1,""]},"evennia.commands.default.account.CmdPassword":{account_caller:[215,4,1,""],aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""]},"evennia.commands.default.account.CmdQuell":{account_caller:[215,4,1,""],aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""]},"evennia.commands.default.account.CmdQuit":{account_caller:[215,4,1,""],aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""],switch_options:[215,4,1,""]},"evennia.commands.default.account.CmdSessions":{account_caller:[215,4,1,""],aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""]},"evennia.commands.default.account.CmdStyle":{aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],list_styles:[215,3,1,""],lock_storage:[215,4,1,""],search_index_entry:[215,4,1,""],set:[215,3,1,""],switch_options:[215,4,1,""]},"evennia.commands.default.account.CmdWho":{account_caller:[215,4,1,""],aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""]},"evennia.commands.default.admin":{CmdBan:[216,1,1,""],CmdBoot:[216,1,1,""],CmdEmit:[216,1,1,""],CmdForce:[216,1,1,""],CmdNewPassword:[216,1,1,""],CmdPerm:[216,1,1,""],CmdUnban:[216,1,1,""],CmdWall:[216,1,1,""]},"evennia.commands.default.admin.CmdBan":{aliases:[216,4,1,""],func:[216,3,1,""],help_category:[216,4,1,""],key:[216,4,1,""],lock_storage:[216,4,1,""],locks:[216,4,1,""],search_index_entry:[216,4,1,""]},"evennia.commands.default.admin.CmdBoot":{aliases:[216,4,1,""],func:[216,3,1,""],help_category:[216,4,1,""],key:[216,4,1,""],lock_storage:[216,4,1,""],locks:[216,4,1,""],search_index_entry:[216,4,1,""],switch_options:[216,4,1,""]},"evennia.commands.default.admin.CmdEmit":{aliases:[216,4,1,""],func:[216,3,1,""],help_category:[216,4,1,""],key:[216,4,1,""],lock_storage:[216,4,1,""],locks:[216,4,1,""],search_index_entry:[216,4,1,""],switch_options:[216,4,1,""]},"evennia.commands.default.admin.CmdForce":{aliases:[216,4,1,""],func:[216,3,1,""],help_category:[216,4,1,""],key:[216,4,1,""],lock_storage:[216,4,1,""],locks:[216,4,1,""],perm_used:[216,4,1,""],search_index_entry:[216,4,1,""]},"evennia.commands.default.admin.CmdNewPassword":{aliases:[216,4,1,""],func:[216,3,1,""],help_category:[216,4,1,""],key:[216,4,1,""],lock_storage:[216,4,1,""],locks:[216,4,1,""],search_index_entry:[216,4,1,""]},"evennia.commands.default.admin.CmdPerm":{aliases:[216,4,1,""],func:[216,3,1,""],help_category:[216,4,1,""],key:[216,4,1,""],lock_storage:[216,4,1,""],locks:[216,4,1,""],search_index_entry:[216,4,1,""],switch_options:[216,4,1,""]},"evennia.commands.default.admin.CmdUnban":{aliases:[216,4,1,""],func:[216,3,1,""],help_category:[216,4,1,""],key:[216,4,1,""],lock_storage:[216,4,1,""],locks:[216,4,1,""],search_index_entry:[216,4,1,""]},"evennia.commands.default.admin.CmdWall":{aliases:[216,4,1,""],func:[216,3,1,""],help_category:[216,4,1,""],key:[216,4,1,""],lock_storage:[216,4,1,""],locks:[216,4,1,""],search_index_entry:[216,4,1,""]},"evennia.commands.default.batchprocess":{CmdBatchCode:[217,1,1,""],CmdBatchCommands:[217,1,1,""]},"evennia.commands.default.batchprocess.CmdBatchCode":{aliases:[217,4,1,""],func:[217,3,1,""],help_category:[217,4,1,""],key:[217,4,1,""],lock_storage:[217,4,1,""],locks:[217,4,1,""],search_index_entry:[217,4,1,""],switch_options:[217,4,1,""]},"evennia.commands.default.batchprocess.CmdBatchCommands":{aliases:[217,4,1,""],func:[217,3,1,""],help_category:[217,4,1,""],key:[217,4,1,""],lock_storage:[217,4,1,""],locks:[217,4,1,""],search_index_entry:[217,4,1,""],switch_options:[217,4,1,""]},"evennia.commands.default.building":{CmdCopy:[218,1,1,""],CmdCpAttr:[218,1,1,""],CmdCreate:[218,1,1,""],CmdDesc:[218,1,1,""],CmdDestroy:[218,1,1,""],CmdDig:[218,1,1,""],CmdExamine:[218,1,1,""],CmdFind:[218,1,1,""],CmdLink:[218,1,1,""],CmdListCmdSets:[218,1,1,""],CmdLock:[218,1,1,""],CmdMvAttr:[218,1,1,""],CmdName:[218,1,1,""],CmdObjects:[218,1,1,""],CmdOpen:[218,1,1,""],CmdScripts:[218,1,1,""],CmdSetAttribute:[218,1,1,""],CmdSetHome:[218,1,1,""],CmdSetObjAlias:[218,1,1,""],CmdSpawn:[218,1,1,""],CmdTag:[218,1,1,""],CmdTeleport:[218,1,1,""],CmdTunnel:[218,1,1,""],CmdTypeclass:[218,1,1,""],CmdUnLink:[218,1,1,""],CmdWipe:[218,1,1,""],ObjManipCommand:[218,1,1,""]},"evennia.commands.default.building.CmdCopy":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.building.CmdCpAttr":{aliases:[218,4,1,""],check_from_attr:[218,3,1,""],check_has_attr:[218,3,1,""],check_to_attr:[218,3,1,""],func:[218,3,1,""],get_attr:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdCreate":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],new_obj_lockstring:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdDesc":{aliases:[218,4,1,""],edit_handler:[218,3,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdDestroy":{aliases:[218,4,1,""],confirm:[218,4,1,""],default_confirm:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdDig":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],new_room_lockstring:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdExamine":{aliases:[218,4,1,""],arg_regex:[218,4,1,""],detail_color:[218,4,1,""],format_account_key:[218,3,1,""],format_account_permissions:[218,3,1,""],format_account_typeclass:[218,3,1,""],format_aliases:[218,3,1,""],format_attributes:[218,3,1,""],format_channel_account_subs:[218,3,1,""],format_channel_object_subs:[218,3,1,""],format_channel_sub_totals:[218,3,1,""],format_chars:[218,3,1,""],format_current_cmds:[218,3,1,""],format_destination:[218,3,1,""],format_email:[218,3,1,""],format_exits:[218,3,1,""],format_home:[218,3,1,""],format_key:[218,3,1,""],format_location:[218,3,1,""],format_locks:[218,3,1,""],format_merged_cmdsets:[218,3,1,""],format_nattributes:[218,3,1,""],format_output:[218,3,1,""],format_permissions:[218,3,1,""],format_script_desc:[218,3,1,""],format_script_is_persistent:[218,3,1,""],format_script_timer_data:[218,3,1,""],format_scripts:[218,3,1,""],format_sessions:[218,3,1,""],format_single_attribute:[218,3,1,""],format_single_attribute_detail:[218,3,1,""],format_single_cmdset:[218,3,1,""],format_single_cmdset_options:[218,3,1,""],format_single_tag:[218,3,1,""],format_stored_cmdsets:[218,3,1,""],format_tags:[218,3,1,""],format_things:[218,3,1,""],format_typeclass:[218,3,1,""],func:[218,3,1,""],get_formatted_obj_data:[218,3,1,""],header_color:[218,4,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],msg:[218,3,1,""],object_type:[218,4,1,""],parse:[218,3,1,""],quell_color:[218,4,1,""],search_index_entry:[218,4,1,""],separator:[218,4,1,""],switch_options:[218,4,1,""],text:[218,4,1,""]},"evennia.commands.default.building.CmdFind":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdLink":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.building.CmdListCmdSets":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.building.CmdLock":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.building.CmdMvAttr":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdName":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.building.CmdObjects":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.building.CmdOpen":{aliases:[218,4,1,""],create_exit:[218,3,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],new_obj_lockstring:[218,4,1,""],parse:[218,3,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.building.CmdScripts":{aliases:[218,4,1,""],excluded_typeclass_paths:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""],switch_mapping:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdSetAttribute":{aliases:[218,4,1,""],check_attr:[218,3,1,""],check_obj:[218,3,1,""],do_nested_lookup:[218,3,1,""],edit_handler:[218,3,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],nested_re:[218,4,1,""],not_found:[218,4,1,""],rm_attr:[218,3,1,""],search_for_obj:[218,3,1,""],search_index_entry:[218,4,1,""],set_attr:[218,3,1,""],split_nested_attr:[218,3,1,""],view_attr:[218,3,1,""]},"evennia.commands.default.building.CmdSetHome":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.building.CmdSetObjAlias":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdSpawn":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdTag":{aliases:[218,4,1,""],arg_regex:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],options:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.building.CmdTeleport":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],parse:[218,3,1,""],rhs_split:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdTunnel":{aliases:[218,4,1,""],directions:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdTypeclass":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdUnLink":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],help_key:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.building.CmdWipe":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.building.ObjManipCommand":{aliases:[218,4,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],parse:[218,3,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.cmdset_account":{AccountCmdSet:[219,1,1,""]},"evennia.commands.default.cmdset_account.AccountCmdSet":{at_cmdset_creation:[219,3,1,""],key:[219,4,1,""],path:[219,4,1,""],priority:[219,4,1,""]},"evennia.commands.default.cmdset_character":{CharacterCmdSet:[220,1,1,""]},"evennia.commands.default.cmdset_character.CharacterCmdSet":{at_cmdset_creation:[220,3,1,""],key:[220,4,1,""],path:[220,4,1,""],priority:[220,4,1,""]},"evennia.commands.default.cmdset_session":{SessionCmdSet:[221,1,1,""]},"evennia.commands.default.cmdset_session.SessionCmdSet":{at_cmdset_creation:[221,3,1,""],key:[221,4,1,""],path:[221,4,1,""],priority:[221,4,1,""]},"evennia.commands.default.cmdset_unloggedin":{UnloggedinCmdSet:[222,1,1,""]},"evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet":{at_cmdset_creation:[222,3,1,""],key:[222,4,1,""],path:[222,4,1,""],priority:[222,4,1,""]},"evennia.commands.default.comms":{CmdChannel:[223,1,1,""],CmdGrapevine2Chan:[223,1,1,""],CmdIRC2Chan:[223,1,1,""],CmdIRCStatus:[223,1,1,""],CmdObjectChannel:[223,1,1,""],CmdPage:[223,1,1,""],CmdRSS2Chan:[223,1,1,""]},"evennia.commands.default.comms.CmdChannel":{account_caller:[223,4,1,""],add_alias:[223,3,1,""],aliases:[223,4,1,""],ban_user:[223,3,1,""],boot_user:[223,3,1,""],channel_list_bans:[223,3,1,""],channel_list_who:[223,3,1,""],create_channel:[223,3,1,""],destroy_channel:[223,3,1,""],display_all_channels:[223,3,1,""],display_subbed_channels:[223,3,1,""],func:[223,3,1,""],get_channel_aliases:[223,3,1,""],get_channel_history:[223,3,1,""],help_category:[223,4,1,""],key:[223,4,1,""],list_channels:[223,3,1,""],lock_storage:[223,4,1,""],locks:[223,4,1,""],msg_channel:[223,3,1,""],mute_channel:[223,3,1,""],remove_alias:[223,3,1,""],search_channel:[223,3,1,""],search_index_entry:[223,4,1,""],set_desc:[223,3,1,""],set_lock:[223,3,1,""],sub_to_channel:[223,3,1,""],switch_options:[223,4,1,""],unban_user:[223,3,1,""],unmute_channel:[223,3,1,""],unset_lock:[223,3,1,""],unsub_from_channel:[223,3,1,""]},"evennia.commands.default.comms.CmdGrapevine2Chan":{aliases:[223,4,1,""],func:[223,3,1,""],help_category:[223,4,1,""],key:[223,4,1,""],lock_storage:[223,4,1,""],locks:[223,4,1,""],search_index_entry:[223,4,1,""],switch_options:[223,4,1,""]},"evennia.commands.default.comms.CmdIRC2Chan":{aliases:[223,4,1,""],func:[223,3,1,""],help_category:[223,4,1,""],key:[223,4,1,""],lock_storage:[223,4,1,""],locks:[223,4,1,""],search_index_entry:[223,4,1,""],switch_options:[223,4,1,""]},"evennia.commands.default.comms.CmdIRCStatus":{aliases:[223,4,1,""],func:[223,3,1,""],help_category:[223,4,1,""],key:[223,4,1,""],lock_storage:[223,4,1,""],locks:[223,4,1,""],search_index_entry:[223,4,1,""]},"evennia.commands.default.comms.CmdObjectChannel":{account_caller:[223,4,1,""],aliases:[223,4,1,""],help_category:[223,4,1,""],key:[223,4,1,""],lock_storage:[223,4,1,""],search_index_entry:[223,4,1,""]},"evennia.commands.default.comms.CmdPage":{account_caller:[223,4,1,""],aliases:[223,4,1,""],func:[223,3,1,""],help_category:[223,4,1,""],key:[223,4,1,""],lock_storage:[223,4,1,""],locks:[223,4,1,""],search_index_entry:[223,4,1,""],switch_options:[223,4,1,""]},"evennia.commands.default.comms.CmdRSS2Chan":{aliases:[223,4,1,""],func:[223,3,1,""],help_category:[223,4,1,""],key:[223,4,1,""],lock_storage:[223,4,1,""],locks:[223,4,1,""],search_index_entry:[223,4,1,""],switch_options:[223,4,1,""]},"evennia.commands.default.general":{CmdAccess:[224,1,1,""],CmdDrop:[224,1,1,""],CmdGet:[224,1,1,""],CmdGive:[224,1,1,""],CmdHome:[224,1,1,""],CmdInventory:[224,1,1,""],CmdLook:[224,1,1,""],CmdNick:[224,1,1,""],CmdPose:[224,1,1,""],CmdSay:[224,1,1,""],CmdSetDesc:[224,1,1,""],CmdWhisper:[224,1,1,""]},"evennia.commands.default.general.CmdAccess":{aliases:[224,4,1,""],arg_regex:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],search_index_entry:[224,4,1,""]},"evennia.commands.default.general.CmdDrop":{aliases:[224,4,1,""],arg_regex:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],search_index_entry:[224,4,1,""]},"evennia.commands.default.general.CmdGet":{aliases:[224,4,1,""],arg_regex:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],search_index_entry:[224,4,1,""]},"evennia.commands.default.general.CmdGive":{aliases:[224,4,1,""],arg_regex:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],rhs_split:[224,4,1,""],search_index_entry:[224,4,1,""]},"evennia.commands.default.general.CmdHome":{aliases:[224,4,1,""],arg_regex:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],search_index_entry:[224,4,1,""]},"evennia.commands.default.general.CmdInventory":{aliases:[224,4,1,""],arg_regex:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],search_index_entry:[224,4,1,""]},"evennia.commands.default.general.CmdLook":{aliases:[224,4,1,""],arg_regex:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],search_index_entry:[224,4,1,""]},"evennia.commands.default.general.CmdNick":{aliases:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],parse:[224,3,1,""],search_index_entry:[224,4,1,""],switch_options:[224,4,1,""]},"evennia.commands.default.general.CmdPose":{aliases:[224,4,1,""],arg_regex:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],parse:[224,3,1,""],search_index_entry:[224,4,1,""]},"evennia.commands.default.general.CmdSay":{aliases:[224,4,1,""],arg_regex:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],search_index_entry:[224,4,1,""]},"evennia.commands.default.general.CmdSetDesc":{aliases:[224,4,1,""],arg_regex:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],search_index_entry:[224,4,1,""]},"evennia.commands.default.general.CmdWhisper":{aliases:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],search_index_entry:[224,4,1,""]},"evennia.commands.default.help":{CmdHelp:[225,1,1,""],CmdSetHelp:[225,1,1,""]},"evennia.commands.default.help.CmdHelp":{aliases:[225,4,1,""],arg_regex:[225,4,1,""],can_list_topic:[225,3,1,""],can_read_topic:[225,3,1,""],clickable_topics:[225,4,1,""],collect_topics:[225,3,1,""],do_search:[225,3,1,""],format_help_entry:[225,3,1,""],format_help_index:[225,3,1,""],func:[225,3,1,""],help_category:[225,4,1,""],help_more:[225,4,1,""],index_category_clr:[225,4,1,""],index_topic_clr:[225,4,1,""],index_type_separator_clr:[225,4,1,""],key:[225,4,1,""],lock_storage:[225,4,1,""],locks:[225,4,1,""],msg_help:[225,3,1,""],parse:[225,3,1,""],return_cmdset:[225,4,1,""],search_index_entry:[225,4,1,""],strip_cmd_prefix:[225,3,1,""],subtopic_separator_char:[225,4,1,""],suggestion_cutoff:[225,4,1,""],suggestion_maxnum:[225,4,1,""]},"evennia.commands.default.help.CmdSetHelp":{aliases:[225,4,1,""],arg_regex:[225,4,1,""],func:[225,3,1,""],help_category:[225,4,1,""],key:[225,4,1,""],lock_storage:[225,4,1,""],locks:[225,4,1,""],parse:[225,3,1,""],search_index_entry:[225,4,1,""],switch_options:[225,4,1,""]},"evennia.commands.default.muxcommand":{MuxAccountCommand:[226,1,1,""],MuxCommand:[226,1,1,""]},"evennia.commands.default.muxcommand.MuxAccountCommand":{account_caller:[226,4,1,""],aliases:[226,4,1,""],help_category:[226,4,1,""],key:[226,4,1,""],lock_storage:[226,4,1,""],search_index_entry:[226,4,1,""]},"evennia.commands.default.muxcommand.MuxCommand":{aliases:[226,4,1,""],at_post_cmd:[226,3,1,""],at_pre_cmd:[226,3,1,""],func:[226,3,1,""],get_command_info:[226,3,1,""],has_perm:[226,3,1,""],help_category:[226,4,1,""],key:[226,4,1,""],lock_storage:[226,4,1,""],parse:[226,3,1,""],search_index_entry:[226,4,1,""]},"evennia.commands.default.syscommands":{SystemMultimatch:[227,1,1,""],SystemNoInput:[227,1,1,""],SystemNoMatch:[227,1,1,""]},"evennia.commands.default.syscommands.SystemMultimatch":{aliases:[227,4,1,""],func:[227,3,1,""],help_category:[227,4,1,""],key:[227,4,1,""],lock_storage:[227,4,1,""],locks:[227,4,1,""],search_index_entry:[227,4,1,""]},"evennia.commands.default.syscommands.SystemNoInput":{aliases:[227,4,1,""],func:[227,3,1,""],help_category:[227,4,1,""],key:[227,4,1,""],lock_storage:[227,4,1,""],locks:[227,4,1,""],search_index_entry:[227,4,1,""]},"evennia.commands.default.syscommands.SystemNoMatch":{aliases:[227,4,1,""],func:[227,3,1,""],help_category:[227,4,1,""],key:[227,4,1,""],lock_storage:[227,4,1,""],locks:[227,4,1,""],search_index_entry:[227,4,1,""]},"evennia.commands.default.system":{CmdAbout:[228,1,1,""],CmdAccounts:[228,1,1,""],CmdPy:[228,1,1,""],CmdReload:[228,1,1,""],CmdReset:[228,1,1,""],CmdServerLoad:[228,1,1,""],CmdService:[228,1,1,""],CmdShutdown:[228,1,1,""],CmdTasks:[228,1,1,""],CmdTickers:[228,1,1,""],CmdTime:[228,1,1,""]},"evennia.commands.default.system.CmdAbout":{aliases:[228,4,1,""],func:[228,3,1,""],help_category:[228,4,1,""],key:[228,4,1,""],lock_storage:[228,4,1,""],locks:[228,4,1,""],search_index_entry:[228,4,1,""]},"evennia.commands.default.system.CmdAccounts":{aliases:[228,4,1,""],func:[228,3,1,""],help_category:[228,4,1,""],key:[228,4,1,""],lock_storage:[228,4,1,""],locks:[228,4,1,""],search_index_entry:[228,4,1,""],switch_options:[228,4,1,""]},"evennia.commands.default.system.CmdPy":{aliases:[228,4,1,""],arg_regex:[228,4,1,""],func:[228,3,1,""],help_category:[228,4,1,""],key:[228,4,1,""],lock_storage:[228,4,1,""],locks:[228,4,1,""],search_index_entry:[228,4,1,""],switch_options:[228,4,1,""]},"evennia.commands.default.system.CmdReload":{aliases:[228,4,1,""],func:[228,3,1,""],help_category:[228,4,1,""],key:[228,4,1,""],lock_storage:[228,4,1,""],locks:[228,4,1,""],search_index_entry:[228,4,1,""]},"evennia.commands.default.system.CmdReset":{aliases:[228,4,1,""],func:[228,3,1,""],help_category:[228,4,1,""],key:[228,4,1,""],lock_storage:[228,4,1,""],locks:[228,4,1,""],search_index_entry:[228,4,1,""]},"evennia.commands.default.system.CmdServerLoad":{aliases:[228,4,1,""],func:[228,3,1,""],help_category:[228,4,1,""],key:[228,4,1,""],lock_storage:[228,4,1,""],locks:[228,4,1,""],search_index_entry:[228,4,1,""],switch_options:[228,4,1,""]},"evennia.commands.default.system.CmdService":{aliases:[228,4,1,""],func:[228,3,1,""],help_category:[228,4,1,""],key:[228,4,1,""],lock_storage:[228,4,1,""],locks:[228,4,1,""],search_index_entry:[228,4,1,""],switch_options:[228,4,1,""]},"evennia.commands.default.system.CmdShutdown":{aliases:[228,4,1,""],func:[228,3,1,""],help_category:[228,4,1,""],key:[228,4,1,""],lock_storage:[228,4,1,""],locks:[228,4,1,""],search_index_entry:[228,4,1,""]},"evennia.commands.default.system.CmdTasks":{aliases:[228,4,1,""],coll_date_func:[228,3,1,""],do_task_action:[228,3,1,""],func:[228,3,1,""],help_category:[228,4,1,""],key:[228,4,1,""],lock_storage:[228,4,1,""],locks:[228,4,1,""],search_index_entry:[228,4,1,""],switch_options:[228,4,1,""]},"evennia.commands.default.system.CmdTickers":{aliases:[228,4,1,""],func:[228,3,1,""],help_category:[228,4,1,""],key:[228,4,1,""],lock_storage:[228,4,1,""],locks:[228,4,1,""],search_index_entry:[228,4,1,""]},"evennia.commands.default.system.CmdTime":{aliases:[228,4,1,""],func:[228,3,1,""],help_category:[228,4,1,""],key:[228,4,1,""],lock_storage:[228,4,1,""],locks:[228,4,1,""],search_index_entry:[228,4,1,""]},"evennia.commands.default.tests":{CmdInterrupt:[229,1,1,""],TestAccount:[229,1,1,""],TestAdmin:[229,1,1,""],TestBatchProcess:[229,1,1,""],TestBuilding:[229,1,1,""],TestCmdTasks:[229,1,1,""],TestComms:[229,1,1,""],TestCommsChannel:[229,1,1,""],TestGeneral:[229,1,1,""],TestHelp:[229,1,1,""],TestInterruptCommand:[229,1,1,""],TestSystem:[229,1,1,""],TestSystemCommands:[229,1,1,""],TestUnconnectedCommand:[229,1,1,""],func_test_cmd_tasks:[229,5,1,""]},"evennia.commands.default.tests.CmdInterrupt":{aliases:[229,4,1,""],func:[229,3,1,""],help_category:[229,4,1,""],key:[229,4,1,""],lock_storage:[229,4,1,""],parse:[229,3,1,""],search_index_entry:[229,4,1,""]},"evennia.commands.default.tests.TestAccount":{test_char_create:[229,3,1,""],test_char_delete:[229,3,1,""],test_color_test:[229,3,1,""],test_ic:[229,3,1,""],test_ic__nonaccess:[229,3,1,""],test_ic__other_object:[229,3,1,""],test_ooc:[229,3,1,""],test_ooc_look:[229,3,1,""],test_option:[229,3,1,""],test_password:[229,3,1,""],test_quell:[229,3,1,""],test_quit:[229,3,1,""],test_sessions:[229,3,1,""],test_who:[229,3,1,""]},"evennia.commands.default.tests.TestAdmin":{test_ban:[229,3,1,""],test_emit:[229,3,1,""],test_force:[229,3,1,""],test_perm:[229,3,1,""],test_wall:[229,3,1,""]},"evennia.commands.default.tests.TestBatchProcess":{red_button:[229,4,1,""],test_batch_commands:[229,3,1,""]},"evennia.commands.default.tests.TestBuilding":{test_attribute_commands:[229,3,1,""],test_copy:[229,3,1,""],test_create:[229,3,1,""],test_desc:[229,3,1,""],test_desc_default_to_room:[229,3,1,""],test_destroy:[229,3,1,""],test_destroy_sequence:[229,3,1,""],test_dig:[229,3,1,""],test_do_nested_lookup:[229,3,1,""],test_empty_desc:[229,3,1,""],test_examine:[229,3,1,""],test_exit_commands:[229,3,1,""],test_find:[229,3,1,""],test_list_cmdsets:[229,3,1,""],test_lock:[229,3,1,""],test_name:[229,3,1,""],test_nested_attribute_commands:[229,3,1,""],test_script:[229,3,1,""],test_script_multi_delete:[229,3,1,""],test_set_home:[229,3,1,""],test_set_obj_alias:[229,3,1,""],test_spawn:[229,3,1,""],test_split_nested_attr:[229,3,1,""],test_tag:[229,3,1,""],test_teleport:[229,3,1,""],test_tunnel:[229,3,1,""],test_tunnel_exit_typeclass:[229,3,1,""],test_typeclass:[229,3,1,""]},"evennia.commands.default.tests.TestCmdTasks":{setUp:[229,3,1,""],tearDown:[229,3,1,""],test_active_task:[229,3,1,""],test_call:[229,3,1,""],test_cancel:[229,3,1,""],test_do_task:[229,3,1,""],test_func_name_manipulation:[229,3,1,""],test_misformed_command:[229,3,1,""],test_new_task_waiting_input:[229,3,1,""],test_no_input:[229,3,1,""],test_no_tasks:[229,3,1,""],test_pause_unpause:[229,3,1,""],test_persistent_task:[229,3,1,""],test_remove:[229,3,1,""],test_responce_of_yes:[229,3,1,""],test_task_complete_waiting_input:[229,3,1,""],test_wrong_func_name:[229,3,1,""]},"evennia.commands.default.tests.TestComms":{test_page:[229,3,1,""]},"evennia.commands.default.tests.TestCommsChannel":{setUp:[229,3,1,""],tearDown:[229,3,1,""],test_channel__alias__unalias:[229,3,1,""],test_channel__all:[229,3,1,""],test_channel__ban__unban:[229,3,1,""],test_channel__boot:[229,3,1,""],test_channel__create:[229,3,1,""],test_channel__desc:[229,3,1,""],test_channel__destroy:[229,3,1,""],test_channel__history:[229,3,1,""],test_channel__list:[229,3,1,""],test_channel__lock:[229,3,1,""],test_channel__msg:[229,3,1,""],test_channel__mute:[229,3,1,""],test_channel__noarg:[229,3,1,""],test_channel__sub:[229,3,1,""],test_channel__unlock:[229,3,1,""],test_channel__unmute:[229,3,1,""],test_channel__unsub:[229,3,1,""],test_channel__who:[229,3,1,""]},"evennia.commands.default.tests.TestGeneral":{test_access:[229,3,1,""],test_get_and_drop:[229,3,1,""],test_give:[229,3,1,""],test_home:[229,3,1,""],test_inventory:[229,3,1,""],test_look:[229,3,1,""],test_mux_command:[229,3,1,""],test_nick:[229,3,1,""],test_pose:[229,3,1,""],test_say:[229,3,1,""],test_whisper:[229,3,1,""]},"evennia.commands.default.tests.TestHelp":{maxDiff:[229,4,1,""],setUp:[229,3,1,""],tearDown:[229,3,1,""],test_help:[229,3,1,""],test_set_help:[229,3,1,""],test_subtopic_fetch:[229,4,1,""],test_subtopic_fetch_00_test:[229,3,1,""],test_subtopic_fetch_01_test_creating_extra_stuff:[229,3,1,""],test_subtopic_fetch_02_test_creating:[229,3,1,""],test_subtopic_fetch_03_test_extra:[229,3,1,""],test_subtopic_fetch_04_test_extra_subsubtopic:[229,3,1,""],test_subtopic_fetch_05_test_creating_extra_subsub:[229,3,1,""],test_subtopic_fetch_06_test_Something_else:[229,3,1,""],test_subtopic_fetch_07_test_More:[229,3,1,""],test_subtopic_fetch_08_test_More_Second_more:[229,3,1,""],test_subtopic_fetch_09_test_More_more:[229,3,1,""],test_subtopic_fetch_10_test_more_second_more_again:[229,3,1,""],test_subtopic_fetch_11_test_more_second_third:[229,3,1,""]},"evennia.commands.default.tests.TestInterruptCommand":{test_interrupt_command:[229,3,1,""]},"evennia.commands.default.tests.TestSystem":{test_about:[229,3,1,""],test_objects:[229,3,1,""],test_py:[229,3,1,""],test_scripts:[229,3,1,""],test_server_load:[229,3,1,""]},"evennia.commands.default.tests.TestSystemCommands":{test_multimatch:[229,3,1,""],test_simple_defaults:[229,3,1,""]},"evennia.commands.default.tests.TestUnconnectedCommand":{test_info_command:[229,3,1,""]},"evennia.commands.default.unloggedin":{CmdUnconnectedConnect:[230,1,1,""],CmdUnconnectedCreate:[230,1,1,""],CmdUnconnectedEncoding:[230,1,1,""],CmdUnconnectedHelp:[230,1,1,""],CmdUnconnectedInfo:[230,1,1,""],CmdUnconnectedLook:[230,1,1,""],CmdUnconnectedQuit:[230,1,1,""],CmdUnconnectedScreenreader:[230,1,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedConnect":{aliases:[230,4,1,""],arg_regex:[230,4,1,""],func:[230,3,1,""],help_category:[230,4,1,""],key:[230,4,1,""],lock_storage:[230,4,1,""],locks:[230,4,1,""],search_index_entry:[230,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedCreate":{aliases:[230,4,1,""],arg_regex:[230,4,1,""],func:[230,3,1,""],help_category:[230,4,1,""],key:[230,4,1,""],lock_storage:[230,4,1,""],locks:[230,4,1,""],search_index_entry:[230,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedEncoding":{aliases:[230,4,1,""],func:[230,3,1,""],help_category:[230,4,1,""],key:[230,4,1,""],lock_storage:[230,4,1,""],locks:[230,4,1,""],search_index_entry:[230,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedHelp":{aliases:[230,4,1,""],func:[230,3,1,""],help_category:[230,4,1,""],key:[230,4,1,""],lock_storage:[230,4,1,""],locks:[230,4,1,""],search_index_entry:[230,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedInfo":{aliases:[230,4,1,""],func:[230,3,1,""],help_category:[230,4,1,""],key:[230,4,1,""],lock_storage:[230,4,1,""],locks:[230,4,1,""],search_index_entry:[230,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedLook":{aliases:[230,4,1,""],func:[230,3,1,""],help_category:[230,4,1,""],key:[230,4,1,""],lock_storage:[230,4,1,""],locks:[230,4,1,""],search_index_entry:[230,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedQuit":{aliases:[230,4,1,""],func:[230,3,1,""],help_category:[230,4,1,""],key:[230,4,1,""],lock_storage:[230,4,1,""],locks:[230,4,1,""],search_index_entry:[230,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedScreenreader":{aliases:[230,4,1,""],func:[230,3,1,""],help_category:[230,4,1,""],key:[230,4,1,""],lock_storage:[230,4,1,""],search_index_entry:[230,4,1,""]},"evennia.comms":{comms:[232,0,0,"-"],managers:[233,0,0,"-"],models:[234,0,0,"-"]},"evennia.comms.comms":{DefaultChannel:[232,1,1,""]},"evennia.comms.comms.DefaultChannel":{"delete":[232,3,1,""],DoesNotExist:[232,2,1,""],MultipleObjectsReturned:[232,2,1,""],access:[232,3,1,""],add_user_channel_alias:[232,3,1,""],at_channel_creation:[232,3,1,""],at_first_save:[232,3,1,""],at_init:[232,3,1,""],at_post_msg:[232,3,1,""],at_pre_msg:[232,3,1,""],ban:[232,3,1,""],banlist:[232,3,1,""],basetype_setup:[232,3,1,""],channel_msg_nick_pattern:[232,4,1,""],channel_msg_nick_replacement:[232,4,1,""],channel_prefix:[232,3,1,""],channel_prefix_string:[232,4,1,""],connect:[232,3,1,""],create:[232,3,1,""],disconnect:[232,3,1,""],distribute_message:[232,3,1,""],format_external:[232,3,1,""],format_message:[232,3,1,""],format_senders:[232,3,1,""],get_absolute_url:[232,3,1,""],get_log_filename:[232,3,1,""],has_connection:[232,3,1,""],log_file:[232,4,1,""],message_transform:[232,3,1,""],msg:[232,3,1,""],mute:[232,3,1,""],mutelist:[232,3,1,""],objects:[232,4,1,""],path:[232,4,1,""],pose_transform:[232,3,1,""],post_join_channel:[232,3,1,""],post_leave_channel:[232,3,1,""],post_send_message:[232,3,1,""],pre_join_channel:[232,3,1,""],pre_leave_channel:[232,3,1,""],pre_send_message:[232,3,1,""],remove_user_channel_alias:[232,3,1,""],send_to_online_only:[232,4,1,""],set_log_filename:[232,3,1,""],typename:[232,4,1,""],unban:[232,3,1,""],unmute:[232,3,1,""],web_get_admin_url:[232,3,1,""],web_get_create_url:[232,3,1,""],web_get_delete_url:[232,3,1,""],web_get_detail_url:[232,3,1,""],web_get_update_url:[232,3,1,""],wholist:[232,3,1,""]},"evennia.comms.managers":{ChannelDBManager:[233,1,1,""],ChannelManager:[233,1,1,""],CommError:[233,2,1,""],MsgManager:[233,1,1,""],identify_object:[233,5,1,""],to_object:[233,5,1,""]},"evennia.comms.managers.ChannelDBManager":{channel_search:[233,3,1,""],create_channel:[233,3,1,""],get_all_channels:[233,3,1,""],get_channel:[233,3,1,""],get_subscriptions:[233,3,1,""],search_channel:[233,3,1,""]},"evennia.comms.managers.MsgManager":{create_message:[233,3,1,""],get_message_by_id:[233,3,1,""],get_messages_by_receiver:[233,3,1,""],get_messages_by_sender:[233,3,1,""],identify_object:[233,3,1,""],message_search:[233,3,1,""],search_message:[233,3,1,""]},"evennia.comms.models":{ChannelDB:[234,1,1,""],Msg:[234,1,1,""],SubscriptionHandler:[234,1,1,""],TempMsg:[234,1,1,""]},"evennia.comms.models.ChannelDB":{DoesNotExist:[234,2,1,""],MultipleObjectsReturned:[234,2,1,""],db_account_subscriptions:[234,4,1,""],db_attributes:[234,4,1,""],db_object_subscriptions:[234,4,1,""],db_tags:[234,4,1,""],get_next_by_db_date_created:[234,3,1,""],get_previous_by_db_date_created:[234,3,1,""],id:[234,4,1,""],objects:[234,4,1,""],path:[234,4,1,""],subscriptions:[234,4,1,""],typename:[234,4,1,""]},"evennia.comms.models.Msg":{DoesNotExist:[234,2,1,""],MultipleObjectsReturned:[234,2,1,""],access:[234,3,1,""],date_created:[234,3,1,""],db_date_created:[234,4,1,""],db_header:[234,4,1,""],db_hide_from_accounts:[234,4,1,""],db_hide_from_objects:[234,4,1,""],db_lock_storage:[234,4,1,""],db_message:[234,4,1,""],db_receiver_external:[234,4,1,""],db_receivers_accounts:[234,4,1,""],db_receivers_objects:[234,4,1,""],db_receivers_scripts:[234,4,1,""],db_sender_accounts:[234,4,1,""],db_sender_external:[234,4,1,""],db_sender_objects:[234,4,1,""],db_sender_scripts:[234,4,1,""],db_tags:[234,4,1,""],get_next_by_db_date_created:[234,3,1,""],get_previous_by_db_date_created:[234,3,1,""],header:[234,3,1,""],hide_from:[234,3,1,""],id:[234,4,1,""],lock_storage:[234,3,1,""],locks:[234,4,1,""],message:[234,3,1,""],objects:[234,4,1,""],path:[234,4,1,""],receiver_external:[234,3,1,""],receivers:[234,3,1,""],remove_receiver:[234,3,1,""],remove_sender:[234,3,1,""],sender_external:[234,3,1,""],senders:[234,3,1,""],tags:[234,4,1,""],typename:[234,4,1,""]},"evennia.comms.models.SubscriptionHandler":{__init__:[234,3,1,""],add:[234,3,1,""],all:[234,3,1,""],clear:[234,3,1,""],get:[234,3,1,""],has:[234,3,1,""],online:[234,3,1,""],remove:[234,3,1,""]},"evennia.comms.models.TempMsg":{__init__:[234,3,1,""],access:[234,3,1,""],locks:[234,4,1,""],remove_receiver:[234,3,1,""],remove_sender:[234,3,1,""]},"evennia.contrib":{base_systems:[236,0,0,"-"],full_systems:[271,0,0,"-"],game_systems:[281,0,0,"-"],grid:[314,0,0,"-"],rpg:[341,0,0,"-"],tutorials:[355,0,0,"-"],utils:[374,0,0,"-"]},"evennia.contrib.base_systems":{awsstorage:[237,0,0,"-"],building_menu:[240,0,0,"-"],color_markups:[243,0,0,"-"],custom_gametime:[246,0,0,"-"],email_login:[249,0,0,"-"],mux_comms_cmds:[265,0,0,"-"],unixcommand:[268,0,0,"-"]},"evennia.contrib.base_systems.awsstorage":{tests:[239,0,0,"-"]},"evennia.contrib.base_systems.awsstorage.tests":{S3Boto3StorageTests:[239,1,1,""],S3Boto3TestCase:[239,1,1,""]},"evennia.contrib.base_systems.awsstorage.tests.S3Boto3StorageTests":{test_auto_creating_bucket:[239,3,1,""],test_auto_creating_bucket_with_acl:[239,3,1,""],test_clean_name:[239,3,1,""],test_clean_name_normalize:[239,3,1,""],test_clean_name_trailing_slash:[239,3,1,""],test_clean_name_windows:[239,3,1,""],test_compress_content_len:[239,3,1,""],test_connection_threading:[239,3,1,""],test_content_type:[239,3,1,""],test_generated_url_is_encoded:[239,3,1,""],test_location_leading_slash:[239,3,1,""],test_override_class_variable:[239,3,1,""],test_override_init_argument:[239,3,1,""],test_pickle_with_bucket:[239,3,1,""],test_pickle_without_bucket:[239,3,1,""],test_special_characters:[239,3,1,""],test_storage_delete:[239,3,1,""],test_storage_exists:[239,3,1,""],test_storage_exists_doesnt_create_bucket:[239,3,1,""],test_storage_exists_false:[239,3,1,""],test_storage_listdir_base:[239,3,1,""],test_storage_listdir_subdir:[239,3,1,""],test_storage_mtime:[239,3,1,""],test_storage_open_no_overwrite_existing:[239,3,1,""],test_storage_open_no_write:[239,3,1,""],test_storage_open_write:[239,3,1,""],test_storage_save:[239,3,1,""],test_storage_save_gzip:[239,3,1,""],test_storage_save_gzip_twice:[239,3,1,""],test_storage_save_gzipped:[239,3,1,""],test_storage_save_with_acl:[239,3,1,""],test_storage_size:[239,3,1,""],test_storage_url:[239,3,1,""],test_storage_url_slashes:[239,3,1,""],test_storage_write_beyond_buffer_size:[239,3,1,""],test_strip_signing_parameters:[239,3,1,""]},"evennia.contrib.base_systems.awsstorage.tests.S3Boto3TestCase":{setUp:[239,3,1,""]},"evennia.contrib.base_systems.building_menu":{building_menu:[241,0,0,"-"],tests:[242,0,0,"-"]},"evennia.contrib.base_systems.building_menu.building_menu":{BuildingMenu:[241,1,1,""],BuildingMenuCmdSet:[241,1,1,""],Choice:[241,1,1,""],CmdNoInput:[241,1,1,""],CmdNoMatch:[241,1,1,""],GenericBuildingCmd:[241,1,1,""],GenericBuildingMenu:[241,1,1,""],menu_edit:[241,5,1,""],menu_quit:[241,5,1,""],menu_setattr:[241,5,1,""]},"evennia.contrib.base_systems.building_menu.building_menu.BuildingMenu":{__init__:[241,3,1,""],add_choice:[241,3,1,""],add_choice_edit:[241,3,1,""],add_choice_quit:[241,3,1,""],close:[241,3,1,""],current_choice:[241,3,1,""],display:[241,3,1,""],display_choice:[241,3,1,""],display_title:[241,3,1,""],init:[241,3,1,""],joker_key:[241,4,1,""],keys_go_back:[241,4,1,""],min_shortcut:[241,4,1,""],move:[241,3,1,""],open:[241,3,1,""],open_parent_menu:[241,3,1,""],open_submenu:[241,3,1,""],relevant_choices:[241,3,1,""],restore:[241,3,1,""],sep_keys:[241,4,1,""]},"evennia.contrib.base_systems.building_menu.building_menu.BuildingMenuCmdSet":{at_cmdset_creation:[241,3,1,""],key:[241,4,1,""],path:[241,4,1,""],priority:[241,4,1,""]},"evennia.contrib.base_systems.building_menu.building_menu.Choice":{__init__:[241,3,1,""],enter:[241,3,1,""],format_text:[241,3,1,""],keys:[241,3,1,""],leave:[241,3,1,""],nomatch:[241,3,1,""]},"evennia.contrib.base_systems.building_menu.building_menu.CmdNoInput":{__init__:[241,3,1,""],aliases:[241,4,1,""],func:[241,3,1,""],help_category:[241,4,1,""],key:[241,4,1,""],lock_storage:[241,4,1,""],locks:[241,4,1,""],search_index_entry:[241,4,1,""]},"evennia.contrib.base_systems.building_menu.building_menu.CmdNoMatch":{__init__:[241,3,1,""],aliases:[241,4,1,""],func:[241,3,1,""],help_category:[241,4,1,""],key:[241,4,1,""],lock_storage:[241,4,1,""],locks:[241,4,1,""],search_index_entry:[241,4,1,""]},"evennia.contrib.base_systems.building_menu.building_menu.GenericBuildingCmd":{aliases:[241,4,1,""],func:[241,3,1,""],help_category:[241,4,1,""],key:[241,4,1,""],lock_storage:[241,4,1,""],search_index_entry:[241,4,1,""]},"evennia.contrib.base_systems.building_menu.building_menu.GenericBuildingMenu":{init:[241,3,1,""]},"evennia.contrib.base_systems.building_menu.tests":{Submenu:[242,1,1,""],TestBuildingMenu:[242,1,1,""]},"evennia.contrib.base_systems.building_menu.tests.Submenu":{init:[242,3,1,""]},"evennia.contrib.base_systems.building_menu.tests.TestBuildingMenu":{setUp:[242,3,1,""],test_add_choice_without_key:[242,3,1,""],test_callbacks:[242,3,1,""],test_multi_level:[242,3,1,""],test_quit:[242,3,1,""],test_setattr:[242,3,1,""],test_submenu:[242,3,1,""]},"evennia.contrib.base_systems.color_markups":{color_markups:[244,0,0,"-"],tests:[245,0,0,"-"]},"evennia.contrib.base_systems.color_markups.tests":{TestColorMarkup:[245,1,1,""]},"evennia.contrib.base_systems.color_markups.tests.TestColorMarkup":{test_curly_markup:[245,3,1,""],test_mux_markup:[245,3,1,""]},"evennia.contrib.base_systems.custom_gametime":{custom_gametime:[247,0,0,"-"],tests:[248,0,0,"-"]},"evennia.contrib.base_systems.custom_gametime.custom_gametime":{GametimeScript:[247,1,1,""],custom_gametime:[247,5,1,""],gametime_to_realtime:[247,5,1,""],real_seconds_until:[247,5,1,""],realtime_to_gametime:[247,5,1,""],schedule:[247,5,1,""],time_to_tuple:[247,5,1,""]},"evennia.contrib.base_systems.custom_gametime.custom_gametime.GametimeScript":{DoesNotExist:[247,2,1,""],MultipleObjectsReturned:[247,2,1,""],at_repeat:[247,3,1,""],at_script_creation:[247,3,1,""],path:[247,4,1,""],typename:[247,4,1,""]},"evennia.contrib.base_systems.custom_gametime.tests":{TestCustomGameTime:[248,1,1,""]},"evennia.contrib.base_systems.custom_gametime.tests.TestCustomGameTime":{tearDown:[248,3,1,""],test_custom_gametime:[248,3,1,""],test_gametime_to_realtime:[248,3,1,""],test_real_seconds_until:[248,3,1,""],test_realtime_to_gametime:[248,3,1,""],test_schedule:[248,3,1,""],test_time_to_tuple:[248,3,1,""]},"evennia.contrib.base_systems.email_login":{connection_screens:[250,0,0,"-"],email_login:[251,0,0,"-"],tests:[252,0,0,"-"]},"evennia.contrib.base_systems.email_login.email_login":{CmdUnconnectedConnect:[251,1,1,""],CmdUnconnectedCreate:[251,1,1,""],CmdUnconnectedHelp:[251,1,1,""],CmdUnconnectedLook:[251,1,1,""],CmdUnconnectedQuit:[251,1,1,""]},"evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedConnect":{aliases:[251,4,1,""],func:[251,3,1,""],help_category:[251,4,1,""],key:[251,4,1,""],lock_storage:[251,4,1,""],locks:[251,4,1,""],search_index_entry:[251,4,1,""]},"evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedCreate":{aliases:[251,4,1,""],func:[251,3,1,""],help_category:[251,4,1,""],key:[251,4,1,""],lock_storage:[251,4,1,""],locks:[251,4,1,""],parse:[251,3,1,""],search_index_entry:[251,4,1,""]},"evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedHelp":{aliases:[251,4,1,""],func:[251,3,1,""],help_category:[251,4,1,""],key:[251,4,1,""],lock_storage:[251,4,1,""],locks:[251,4,1,""],search_index_entry:[251,4,1,""]},"evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedLook":{aliases:[251,4,1,""],func:[251,3,1,""],help_category:[251,4,1,""],key:[251,4,1,""],lock_storage:[251,4,1,""],locks:[251,4,1,""],search_index_entry:[251,4,1,""]},"evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedQuit":{aliases:[251,4,1,""],func:[251,3,1,""],help_category:[251,4,1,""],key:[251,4,1,""],lock_storage:[251,4,1,""],locks:[251,4,1,""],search_index_entry:[251,4,1,""]},"evennia.contrib.base_systems.email_login.tests":{TestEmailLogin:[252,1,1,""]},"evennia.contrib.base_systems.email_login.tests.TestEmailLogin":{test_connect:[252,3,1,""],test_quit:[252,3,1,""],test_unconnectedhelp:[252,3,1,""],test_unconnectedlook:[252,3,1,""]},"evennia.contrib.base_systems.ingame_python":{callbackhandler:[254,0,0,"-"],commands:[255,0,0,"-"],eventfuncs:[256,0,0,"-"],scripts:[257,0,0,"-"],tests:[258,0,0,"-"],utils:[260,0,0,"-"]},"evennia.contrib.base_systems.ingame_python.callbackhandler":{Callback:[254,1,1,""],CallbackHandler:[254,1,1,""]},"evennia.contrib.base_systems.ingame_python.callbackhandler.Callback":{author:[254,4,1,""],code:[254,4,1,""],created_on:[254,4,1,""],name:[254,4,1,""],number:[254,4,1,""],obj:[254,4,1,""],parameters:[254,4,1,""],updated_by:[254,4,1,""],updated_on:[254,4,1,""],valid:[254,4,1,""]},"evennia.contrib.base_systems.ingame_python.callbackhandler.CallbackHandler":{__init__:[254,3,1,""],add:[254,3,1,""],all:[254,3,1,""],call:[254,3,1,""],edit:[254,3,1,""],format_callback:[254,3,1,""],get:[254,3,1,""],get_variable:[254,3,1,""],remove:[254,3,1,""],script:[254,4,1,""]},"evennia.contrib.base_systems.ingame_python.commands":{CmdCallback:[255,1,1,""]},"evennia.contrib.base_systems.ingame_python.commands.CmdCallback":{accept_callback:[255,3,1,""],add_callback:[255,3,1,""],aliases:[255,4,1,""],del_callback:[255,3,1,""],edit_callback:[255,3,1,""],func:[255,3,1,""],get_help:[255,3,1,""],help_category:[255,4,1,""],key:[255,4,1,""],list_callbacks:[255,3,1,""],list_tasks:[255,3,1,""],lock_storage:[255,4,1,""],locks:[255,4,1,""],search_index_entry:[255,4,1,""]},"evennia.contrib.base_systems.ingame_python.eventfuncs":{call_event:[256,5,1,""],deny:[256,5,1,""],get:[256,5,1,""]},"evennia.contrib.base_systems.ingame_python.scripts":{EventHandler:[257,1,1,""],TimeEventScript:[257,1,1,""],complete_task:[257,5,1,""]},"evennia.contrib.base_systems.ingame_python.scripts.EventHandler":{DoesNotExist:[257,2,1,""],MultipleObjectsReturned:[257,2,1,""],accept_callback:[257,3,1,""],add_callback:[257,3,1,""],add_event:[257,3,1,""],at_script_creation:[257,3,1,""],at_server_start:[257,3,1,""],call:[257,3,1,""],del_callback:[257,3,1,""],edit_callback:[257,3,1,""],get_callbacks:[257,3,1,""],get_events:[257,3,1,""],get_variable:[257,3,1,""],handle_error:[257,3,1,""],path:[257,4,1,""],set_task:[257,3,1,""],typename:[257,4,1,""]},"evennia.contrib.base_systems.ingame_python.scripts.TimeEventScript":{DoesNotExist:[257,2,1,""],MultipleObjectsReturned:[257,2,1,""],at_repeat:[257,3,1,""],at_script_creation:[257,3,1,""],path:[257,4,1,""],typename:[257,4,1,""]},"evennia.contrib.base_systems.ingame_python.tests":{TestCmdCallback:[258,1,1,""],TestDefaultCallbacks:[258,1,1,""],TestEventHandler:[258,1,1,""]},"evennia.contrib.base_systems.ingame_python.tests.TestCmdCallback":{setUp:[258,3,1,""],tearDown:[258,3,1,""],test_accept:[258,3,1,""],test_add:[258,3,1,""],test_del:[258,3,1,""],test_list:[258,3,1,""],test_lock:[258,3,1,""]},"evennia.contrib.base_systems.ingame_python.tests.TestDefaultCallbacks":{setUp:[258,3,1,""],tearDown:[258,3,1,""],test_exit:[258,3,1,""]},"evennia.contrib.base_systems.ingame_python.tests.TestEventHandler":{setUp:[258,3,1,""],tearDown:[258,3,1,""],test_accept:[258,3,1,""],test_add_validation:[258,3,1,""],test_call:[258,3,1,""],test_del:[258,3,1,""],test_edit:[258,3,1,""],test_edit_validation:[258,3,1,""],test_handler:[258,3,1,""],test_start:[258,3,1,""]},"evennia.contrib.base_systems.ingame_python.utils":{InterruptEvent:[260,2,1,""],get_event_handler:[260,5,1,""],get_next_wait:[260,5,1,""],keyword_event:[260,5,1,""],phrase_event:[260,5,1,""],register_events:[260,5,1,""],time_event:[260,5,1,""]},"evennia.contrib.base_systems.mux_comms_cmds":{mux_comms_cmds:[266,0,0,"-"],tests:[267,0,0,"-"]},"evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds":{CmdAddCom:[266,1,1,""],CmdAllCom:[266,1,1,""],CmdCBoot:[266,1,1,""],CmdCWho:[266,1,1,""],CmdCdesc:[266,1,1,""],CmdCdestroy:[266,1,1,""],CmdChannelCreate:[266,1,1,""],CmdClock:[266,1,1,""],CmdDelCom:[266,1,1,""],CmdSetLegacyComms:[266,1,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdAddCom":{account_caller:[266,4,1,""],aliases:[266,4,1,""],func:[266,3,1,""],help_category:[266,4,1,""],key:[266,4,1,""],lock_storage:[266,4,1,""],locks:[266,4,1,""],search_index_entry:[266,4,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdAllCom":{account_caller:[266,4,1,""],aliases:[266,4,1,""],func:[266,3,1,""],help_category:[266,4,1,""],key:[266,4,1,""],lock_storage:[266,4,1,""],locks:[266,4,1,""],search_index_entry:[266,4,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdCBoot":{account_caller:[266,4,1,""],aliases:[266,4,1,""],func:[266,3,1,""],help_category:[266,4,1,""],key:[266,4,1,""],lock_storage:[266,4,1,""],locks:[266,4,1,""],search_index_entry:[266,4,1,""],switch_options:[266,4,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdCWho":{account_caller:[266,4,1,""],aliases:[266,4,1,""],func:[266,3,1,""],help_category:[266,4,1,""],key:[266,4,1,""],lock_storage:[266,4,1,""],locks:[266,4,1,""],search_index_entry:[266,4,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdCdesc":{account_caller:[266,4,1,""],aliases:[266,4,1,""],func:[266,3,1,""],help_category:[266,4,1,""],key:[266,4,1,""],lock_storage:[266,4,1,""],locks:[266,4,1,""],search_index_entry:[266,4,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdCdestroy":{account_caller:[266,4,1,""],aliases:[266,4,1,""],func:[266,3,1,""],help_category:[266,4,1,""],key:[266,4,1,""],lock_storage:[266,4,1,""],locks:[266,4,1,""],search_index_entry:[266,4,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdChannelCreate":{account_caller:[266,4,1,""],aliases:[266,4,1,""],func:[266,3,1,""],help_category:[266,4,1,""],key:[266,4,1,""],lock_storage:[266,4,1,""],locks:[266,4,1,""],search_index_entry:[266,4,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdClock":{account_caller:[266,4,1,""],aliases:[266,4,1,""],func:[266,3,1,""],help_category:[266,4,1,""],key:[266,4,1,""],lock_storage:[266,4,1,""],locks:[266,4,1,""],search_index_entry:[266,4,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdDelCom":{account_caller:[266,4,1,""],aliases:[266,4,1,""],func:[266,3,1,""],help_category:[266,4,1,""],key:[266,4,1,""],lock_storage:[266,4,1,""],locks:[266,4,1,""],search_index_entry:[266,4,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdSetLegacyComms":{at_cmdset_createion:[266,3,1,""],path:[266,4,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.tests":{TestLegacyMuxComms:[267,1,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.tests.TestLegacyMuxComms":{setUp:[267,3,1,""],test_all_com:[267,3,1,""],test_cboot:[267,3,1,""],test_cdesc:[267,3,1,""],test_cdestroy:[267,3,1,""],test_clock:[267,3,1,""],test_cwho:[267,3,1,""],test_toggle_com:[267,3,1,""]},"evennia.contrib.base_systems.unixcommand":{tests:[269,0,0,"-"],unixcommand:[270,0,0,"-"]},"evennia.contrib.base_systems.unixcommand.tests":{CmdDummy:[269,1,1,""],TestUnixCommand:[269,1,1,""]},"evennia.contrib.base_systems.unixcommand.tests.CmdDummy":{aliases:[269,4,1,""],func:[269,3,1,""],help_category:[269,4,1,""],init_parser:[269,3,1,""],key:[269,4,1,""],lock_storage:[269,4,1,""],search_index_entry:[269,4,1,""]},"evennia.contrib.base_systems.unixcommand.tests.TestUnixCommand":{test_failure:[269,3,1,""],test_success:[269,3,1,""]},"evennia.contrib.base_systems.unixcommand.unixcommand":{HelpAction:[270,1,1,""],ParseError:[270,2,1,""],UnixCommand:[270,1,1,""],UnixCommandParser:[270,1,1,""]},"evennia.contrib.base_systems.unixcommand.unixcommand.UnixCommand":{__init__:[270,3,1,""],aliases:[270,4,1,""],func:[270,3,1,""],get_help:[270,3,1,""],help_category:[270,4,1,""],init_parser:[270,3,1,""],key:[270,4,1,""],lock_storage:[270,4,1,""],parse:[270,3,1,""],search_index_entry:[270,4,1,""]},"evennia.contrib.base_systems.unixcommand.unixcommand.UnixCommandParser":{__init__:[270,3,1,""],format_help:[270,3,1,""],format_usage:[270,3,1,""],print_help:[270,3,1,""],print_usage:[270,3,1,""]},"evennia.contrib.full_systems":{evscaperoom:[272,0,0,"-"]},"evennia.contrib.full_systems.evscaperoom":{commands:[273,0,0,"-"],menu:[274,0,0,"-"],objects:[275,0,0,"-"],room:[276,0,0,"-"],scripts:[277,0,0,"-"],state:[278,0,0,"-"],tests:[279,0,0,"-"],utils:[280,0,0,"-"]},"evennia.contrib.full_systems.evscaperoom.commands":{CmdCreateObj:[273,1,1,""],CmdEmote:[273,1,1,""],CmdEvscapeRoom:[273,1,1,""],CmdEvscapeRoomStart:[273,1,1,""],CmdFocus:[273,1,1,""],CmdFocusInteraction:[273,1,1,""],CmdGet:[273,1,1,""],CmdGiveUp:[273,1,1,""],CmdHelp:[273,1,1,""],CmdJumpState:[273,1,1,""],CmdLook:[273,1,1,""],CmdOptions:[273,1,1,""],CmdRerouter:[273,1,1,""],CmdSetEvScapeRoom:[273,1,1,""],CmdSetFlag:[273,1,1,""],CmdSpeak:[273,1,1,""],CmdStand:[273,1,1,""],CmdWho:[273,1,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdCreateObj":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],locks:[273,4,1,""],obj1_search:[273,4,1,""],obj2_search:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdEmote":{aliases:[273,4,1,""],arg_regex:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],room_replace:[273,3,1,""],search_index_entry:[273,4,1,""],you_replace:[273,3,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdEvscapeRoom":{aliases:[273,4,1,""],arg_regex:[273,4,1,""],focus:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],obj1_search:[273,4,1,""],obj2_search:[273,4,1,""],parse:[273,3,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdEvscapeRoomStart":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdFocus":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],obj1_search:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdFocusInteraction":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],obj1_search:[273,4,1,""],obj2_search:[273,4,1,""],parse:[273,3,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdGet":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdGiveUp":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdHelp":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdJumpState":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],locks:[273,4,1,""],obj1_search:[273,4,1,""],obj2_search:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdLook":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],obj1_search:[273,4,1,""],obj2_search:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdOptions":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdRerouter":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdSetEvScapeRoom":{at_cmdset_creation:[273,3,1,""],path:[273,4,1,""],priority:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdSetFlag":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],locks:[273,4,1,""],obj1_search:[273,4,1,""],obj2_search:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdSpeak":{aliases:[273,4,1,""],arg_regex:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdStand":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdWho":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],obj1_search:[273,4,1,""],obj2_search:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.menu":{EvscaperoomMenu:[274,1,1,""],OptionsMenu:[274,1,1,""],node_create_room:[274,5,1,""],node_join_room:[274,5,1,""],node_options:[274,5,1,""],node_quit:[274,5,1,""],node_set_desc:[274,5,1,""],run_evscaperoom_menu:[274,5,1,""],run_option_menu:[274,5,1,""]},"evennia.contrib.full_systems.evscaperoom.menu.EvscaperoomMenu":{node_border_char:[274,4,1,""],nodetext_formatter:[274,3,1,""],options_formatter:[274,3,1,""]},"evennia.contrib.full_systems.evscaperoom.menu.OptionsMenu":{node_formatter:[274,3,1,""]},"evennia.contrib.full_systems.evscaperoom.objects":{BaseApplicable:[275,1,1,""],BaseConsumable:[275,1,1,""],BasePositionable:[275,1,1,""],Climbable:[275,1,1,""],CodeInput:[275,1,1,""],Combinable:[275,1,1,""],Drinkable:[275,1,1,""],Edible:[275,1,1,""],EvscaperoomObject:[275,1,1,""],Feelable:[275,1,1,""],HasButtons:[275,1,1,""],IndexReadable:[275,1,1,""],Insertable:[275,1,1,""],Kneelable:[275,1,1,""],Liable:[275,1,1,""],Listenable:[275,1,1,""],Mixable:[275,1,1,""],Movable:[275,1,1,""],Openable:[275,1,1,""],Positionable:[275,1,1,""],Readable:[275,1,1,""],Rotatable:[275,1,1,""],Sittable:[275,1,1,""],Smellable:[275,1,1,""],Usable:[275,1,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.BaseApplicable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_apply:[275,3,1,""],at_cannot_apply:[275,3,1,""],handle_apply:[275,3,1,""],path:[275,4,1,""],target_flag:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.BaseConsumable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_already_consumed:[275,3,1,""],at_consume:[275,3,1,""],consume_flag:[275,4,1,""],handle_consume:[275,3,1,""],has_consumed:[275,3,1,""],one_consume_only:[275,4,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.BasePositionable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_again_position:[275,3,1,""],at_cannot_position:[275,3,1,""],at_object_creation:[275,3,1,""],at_position:[275,3,1,""],handle_position:[275,3,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Climbable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_focus_climb:[275,3,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.CodeInput":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_code_correct:[275,3,1,""],at_code_incorrect:[275,3,1,""],at_focus_code:[275,3,1,""],at_no_code:[275,3,1,""],case_insensitive:[275,4,1,""],code:[275,4,1,""],code_hint:[275,4,1,""],get_cmd_signatures:[275,3,1,""],infinitely_locked:[275,4,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Combinable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_apply:[275,3,1,""],at_cannot_apply:[275,3,1,""],at_focus_combine:[275,3,1,""],destroy_components:[275,4,1,""],get_cmd_signatures:[275,3,1,""],new_create_dict:[275,4,1,""],path:[275,4,1,""],target_flag:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Drinkable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_already_consumed:[275,3,1,""],at_consume:[275,3,1,""],at_focus_drink:[275,3,1,""],at_focus_sip:[275,3,1,""],consume_flag:[275,4,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Edible":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_focus_eat:[275,3,1,""],consume_flag:[275,4,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.EvscaperoomObject":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],action_prepositions:[275,4,1,""],at_focus:[275,3,1,""],at_object_creation:[275,3,1,""],at_speech:[275,3,1,""],at_unfocus:[275,3,1,""],check_character_flag:[275,3,1,""],check_flag:[275,3,1,""],get_cmd_signatures:[275,3,1,""],get_help:[275,3,1,""],get_position:[275,3,1,""],get_short_desc:[275,3,1,""],msg_char:[275,3,1,""],msg_room:[275,3,1,""],msg_system:[275,3,1,""],next_state:[275,3,1,""],parse:[275,3,1,""],path:[275,4,1,""],position_prep_map:[275,4,1,""],return_appearance:[275,3,1,""],room:[275,3,1,""],roomstate:[275,3,1,""],set_character_flag:[275,3,1,""],set_flag:[275,3,1,""],set_position:[275,3,1,""],tagcategory:[275,3,1,""],typename:[275,4,1,""],unset_character_flag:[275,3,1,""],unset_flag:[275,3,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Feelable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_focus_feel:[275,3,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.HasButtons":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_focus_press:[275,3,1,""],at_focus_push:[275,3,1,""],at_green_button:[275,3,1,""],at_nomatch:[275,3,1,""],at_red_button:[275,3,1,""],buttons:[275,4,1,""],get_cmd_signatures:[275,3,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.IndexReadable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_cannot_read:[275,3,1,""],at_focus_read:[275,3,1,""],at_read:[275,3,1,""],get_cmd_signatures:[275,3,1,""],index:[275,4,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Insertable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_apply:[275,3,1,""],at_cannot_apply:[275,3,1,""],at_focus_insert:[275,3,1,""],get_cmd_signatures:[275,3,1,""],path:[275,4,1,""],target_flag:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Kneelable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_focus_kneel:[275,3,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Liable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_focus_lie:[275,3,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Listenable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_focus_listen:[275,3,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Mixable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_mix:[275,3,1,""],at_mix_failure:[275,3,1,""],at_mix_success:[275,3,1,""],at_object_creation:[275,3,1,""],check_mixture:[275,3,1,""],handle_mix:[275,3,1,""],ingredient_recipe:[275,4,1,""],mixer_flag:[275,4,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Movable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_already_moved:[275,3,1,""],at_cannot_move:[275,3,1,""],at_focus_move:[275,3,1,""],at_focus_push:[275,3,1,""],at_focus_shove:[275,3,1,""],at_left:[275,3,1,""],at_object_creation:[275,3,1,""],at_right:[275,3,1,""],get_cmd_signatures:[275,3,1,""],move_positions:[275,4,1,""],path:[275,4,1,""],start_position:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Openable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_already_closed:[275,3,1,""],at_already_open:[275,3,1,""],at_close:[275,3,1,""],at_focus_close:[275,3,1,""],at_focus_open:[275,3,1,""],at_locked:[275,3,1,""],at_object_creation:[275,3,1,""],at_open:[275,3,1,""],open_flag:[275,4,1,""],path:[275,4,1,""],start_open:[275,4,1,""],typename:[275,4,1,""],unlock_flag:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Positionable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],get_cmd_signatures:[275,3,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Readable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_cannot_read:[275,3,1,""],at_focus_read:[275,3,1,""],at_object_creation:[275,3,1,""],at_read:[275,3,1,""],path:[275,4,1,""],read_flag:[275,4,1,""],start_readable:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Rotatable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_cannot_rotate:[275,3,1,""],at_focus_rotate:[275,3,1,""],at_focus_turn:[275,3,1,""],at_object_creation:[275,3,1,""],at_rotate:[275,3,1,""],path:[275,4,1,""],rotate_flag:[275,4,1,""],start_rotatable:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Sittable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_focus_sit:[275,3,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Smellable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_focus_smell:[275,3,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Usable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_apply:[275,3,1,""],at_cannot_apply:[275,3,1,""],at_focus_use:[275,3,1,""],path:[275,4,1,""],target_flag:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.room":{EvscapeRoom:[276,1,1,""]},"evennia.contrib.full_systems.evscaperoom.room.EvscapeRoom":{"delete":[276,3,1,""],DoesNotExist:[276,2,1,""],MultipleObjectsReturned:[276,2,1,""],achievement:[276,3,1,""],at_object_creation:[276,3,1,""],at_object_leave:[276,3,1,""],at_object_receive:[276,3,1,""],character_cleanup:[276,3,1,""],character_exit:[276,3,1,""],check_flag:[276,3,1,""],check_perm:[276,3,1,""],get_all_characters:[276,3,1,""],log:[276,3,1,""],path:[276,4,1,""],progress:[276,3,1,""],return_appearance:[276,3,1,""],score:[276,3,1,""],set_flag:[276,3,1,""],state:[276,3,1,""],statehandler:[276,4,1,""],tag_all_characters:[276,3,1,""],tag_character:[276,3,1,""],typename:[276,4,1,""],unset_flag:[276,3,1,""]},"evennia.contrib.full_systems.evscaperoom.scripts":{CleanupScript:[277,1,1,""]},"evennia.contrib.full_systems.evscaperoom.scripts.CleanupScript":{DoesNotExist:[277,2,1,""],MultipleObjectsReturned:[277,2,1,""],at_repeat:[277,3,1,""],at_script_creation:[277,3,1,""],path:[277,4,1,""],typename:[277,4,1,""]},"evennia.contrib.full_systems.evscaperoom.state":{BaseState:[278,1,1,""],StateHandler:[278,1,1,""]},"evennia.contrib.full_systems.evscaperoom.state.BaseState":{__init__:[278,3,1,""],character_enters:[278,3,1,""],character_leaves:[278,3,1,""],cinematic:[278,3,1,""],clean:[278,3,1,""],create_object:[278,3,1,""],get_hint:[278,3,1,""],get_object:[278,3,1,""],hints:[278,4,1,""],init:[278,3,1,""],msg:[278,3,1,""],next:[278,3,1,""],next_state:[278,4,1,""]},"evennia.contrib.full_systems.evscaperoom.state.StateHandler":{__init__:[278,3,1,""],init_state:[278,3,1,""],load_state:[278,3,1,""],next_state:[278,3,1,""]},"evennia.contrib.full_systems.evscaperoom.tests":{TestEvScapeRoom:[279,1,1,""],TestEvscaperoomCommands:[279,1,1,""],TestStates:[279,1,1,""],TestUtils:[279,1,1,""]},"evennia.contrib.full_systems.evscaperoom.tests.TestEvScapeRoom":{setUp:[279,3,1,""],tearDown:[279,3,1,""],test_room_methods:[279,3,1,""]},"evennia.contrib.full_systems.evscaperoom.tests.TestEvscaperoomCommands":{setUp:[279,3,1,""],test_base_parse:[279,3,1,""],test_base_search:[279,3,1,""],test_emote:[279,3,1,""],test_focus:[279,3,1,""],test_focus_interaction:[279,3,1,""],test_look:[279,3,1,""],test_set_focus:[279,3,1,""],test_speech:[279,3,1,""]},"evennia.contrib.full_systems.evscaperoom.tests.TestStates":{setUp:[279,3,1,""],tearDown:[279,3,1,""],test_all_states:[279,3,1,""],test_base_state:[279,3,1,""]},"evennia.contrib.full_systems.evscaperoom.tests.TestUtils":{test_overwrite:[279,3,1,""],test_parse_for_perspectives:[279,3,1,""],test_parse_for_things:[279,3,1,""]},"evennia.contrib.full_systems.evscaperoom.utils":{add_msg_borders:[280,5,1,""],create_evscaperoom_object:[280,5,1,""],create_fantasy_word:[280,5,1,""],msg_cinematic:[280,5,1,""],parse_for_perspectives:[280,5,1,""],parse_for_things:[280,5,1,""]},"evennia.contrib.game_systems":{barter:[282,0,0,"-"],clothing:[285,0,0,"-"],cooldowns:[288,0,0,"-"],crafting:[291,0,0,"-"],gendersub:[295,0,0,"-"],mail:[298,0,0,"-"],multidescer:[301,0,0,"-"],puzzles:[304,0,0,"-"],turnbattle:[307,0,0,"-"]},"evennia.contrib.game_systems.barter":{barter:[283,0,0,"-"],tests:[284,0,0,"-"]},"evennia.contrib.game_systems.barter.barter":{CmdAccept:[283,1,1,""],CmdDecline:[283,1,1,""],CmdEvaluate:[283,1,1,""],CmdFinish:[283,1,1,""],CmdOffer:[283,1,1,""],CmdStatus:[283,1,1,""],CmdTrade:[283,1,1,""],CmdTradeBase:[283,1,1,""],CmdTradeHelp:[283,1,1,""],CmdsetTrade:[283,1,1,""],TradeHandler:[283,1,1,""],TradeTimeout:[283,1,1,""]},"evennia.contrib.game_systems.barter.barter.CmdAccept":{aliases:[283,4,1,""],func:[283,3,1,""],help_category:[283,4,1,""],key:[283,4,1,""],lock_storage:[283,4,1,""],locks:[283,4,1,""],search_index_entry:[283,4,1,""]},"evennia.contrib.game_systems.barter.barter.CmdDecline":{aliases:[283,4,1,""],func:[283,3,1,""],help_category:[283,4,1,""],key:[283,4,1,""],lock_storage:[283,4,1,""],locks:[283,4,1,""],search_index_entry:[283,4,1,""]},"evennia.contrib.game_systems.barter.barter.CmdEvaluate":{aliases:[283,4,1,""],func:[283,3,1,""],help_category:[283,4,1,""],key:[283,4,1,""],lock_storage:[283,4,1,""],locks:[283,4,1,""],search_index_entry:[283,4,1,""]},"evennia.contrib.game_systems.barter.barter.CmdFinish":{aliases:[283,4,1,""],func:[283,3,1,""],help_category:[283,4,1,""],key:[283,4,1,""],lock_storage:[283,4,1,""],locks:[283,4,1,""],search_index_entry:[283,4,1,""]},"evennia.contrib.game_systems.barter.barter.CmdOffer":{aliases:[283,4,1,""],func:[283,3,1,""],help_category:[283,4,1,""],key:[283,4,1,""],lock_storage:[283,4,1,""],locks:[283,4,1,""],search_index_entry:[283,4,1,""]},"evennia.contrib.game_systems.barter.barter.CmdStatus":{aliases:[283,4,1,""],func:[283,3,1,""],help_category:[283,4,1,""],key:[283,4,1,""],lock_storage:[283,4,1,""],locks:[283,4,1,""],search_index_entry:[283,4,1,""]},"evennia.contrib.game_systems.barter.barter.CmdTrade":{aliases:[283,4,1,""],func:[283,3,1,""],help_category:[283,4,1,""],key:[283,4,1,""],lock_storage:[283,4,1,""],locks:[283,4,1,""],search_index_entry:[283,4,1,""]},"evennia.contrib.game_systems.barter.barter.CmdTradeBase":{aliases:[283,4,1,""],help_category:[283,4,1,""],key:[283,4,1,""],lock_storage:[283,4,1,""],parse:[283,3,1,""],search_index_entry:[283,4,1,""]},"evennia.contrib.game_systems.barter.barter.CmdTradeHelp":{aliases:[283,4,1,""],func:[283,3,1,""],help_category:[283,4,1,""],key:[283,4,1,""],lock_storage:[283,4,1,""],locks:[283,4,1,""],search_index_entry:[283,4,1,""]},"evennia.contrib.game_systems.barter.barter.CmdsetTrade":{at_cmdset_creation:[283,3,1,""],key:[283,4,1,""],path:[283,4,1,""]},"evennia.contrib.game_systems.barter.barter.TradeHandler":{__init__:[283,3,1,""],accept:[283,3,1,""],decline:[283,3,1,""],finish:[283,3,1,""],get_other:[283,3,1,""],join:[283,3,1,""],list:[283,3,1,""],msg_other:[283,3,1,""],offer:[283,3,1,""],search:[283,3,1,""],unjoin:[283,3,1,""]},"evennia.contrib.game_systems.barter.barter.TradeTimeout":{DoesNotExist:[283,2,1,""],MultipleObjectsReturned:[283,2,1,""],at_repeat:[283,3,1,""],at_script_creation:[283,3,1,""],is_valid:[283,3,1,""],path:[283,4,1,""],typename:[283,4,1,""]},"evennia.contrib.game_systems.barter.tests":{TestBarter:[284,1,1,""]},"evennia.contrib.game_systems.barter.tests.TestBarter":{setUp:[284,3,1,""],test_cmdtrade:[284,3,1,""],test_cmdtradehelp:[284,3,1,""],test_tradehandler_base:[284,3,1,""],test_tradehandler_joins:[284,3,1,""],test_tradehandler_offers:[284,3,1,""]},"evennia.contrib.game_systems.clothing":{clothing:[286,0,0,"-"],tests:[287,0,0,"-"]},"evennia.contrib.game_systems.clothing.clothing":{ClothedCharacter:[286,1,1,""],ClothedCharacterCmdSet:[286,1,1,""],CmdCover:[286,1,1,""],CmdDrop:[286,1,1,""],CmdGive:[286,1,1,""],CmdInventory:[286,1,1,""],CmdRemove:[286,1,1,""],CmdUncover:[286,1,1,""],CmdWear:[286,1,1,""],ContribClothing:[286,1,1,""],clothing_type_count:[286,5,1,""],get_worn_clothes:[286,5,1,""],order_clothes_list:[286,5,1,""],single_type_count:[286,5,1,""]},"evennia.contrib.game_systems.clothing.clothing.ClothedCharacter":{DoesNotExist:[286,2,1,""],MultipleObjectsReturned:[286,2,1,""],path:[286,4,1,""],return_appearance:[286,3,1,""],typename:[286,4,1,""]},"evennia.contrib.game_systems.clothing.clothing.ClothedCharacterCmdSet":{at_cmdset_creation:[286,3,1,""],key:[286,4,1,""],path:[286,4,1,""]},"evennia.contrib.game_systems.clothing.clothing.CmdCover":{aliases:[286,4,1,""],func:[286,3,1,""],help_category:[286,4,1,""],key:[286,4,1,""],lock_storage:[286,4,1,""],search_index_entry:[286,4,1,""]},"evennia.contrib.game_systems.clothing.clothing.CmdDrop":{aliases:[286,4,1,""],arg_regex:[286,4,1,""],func:[286,3,1,""],help_category:[286,4,1,""],key:[286,4,1,""],lock_storage:[286,4,1,""],locks:[286,4,1,""],search_index_entry:[286,4,1,""]},"evennia.contrib.game_systems.clothing.clothing.CmdGive":{aliases:[286,4,1,""],arg_regex:[286,4,1,""],func:[286,3,1,""],help_category:[286,4,1,""],key:[286,4,1,""],lock_storage:[286,4,1,""],locks:[286,4,1,""],search_index_entry:[286,4,1,""]},"evennia.contrib.game_systems.clothing.clothing.CmdInventory":{aliases:[286,4,1,""],arg_regex:[286,4,1,""],func:[286,3,1,""],help_category:[286,4,1,""],key:[286,4,1,""],lock_storage:[286,4,1,""],locks:[286,4,1,""],search_index_entry:[286,4,1,""]},"evennia.contrib.game_systems.clothing.clothing.CmdRemove":{aliases:[286,4,1,""],func:[286,3,1,""],help_category:[286,4,1,""],key:[286,4,1,""],lock_storage:[286,4,1,""],search_index_entry:[286,4,1,""]},"evennia.contrib.game_systems.clothing.clothing.CmdUncover":{aliases:[286,4,1,""],func:[286,3,1,""],help_category:[286,4,1,""],key:[286,4,1,""],lock_storage:[286,4,1,""],search_index_entry:[286,4,1,""]},"evennia.contrib.game_systems.clothing.clothing.CmdWear":{aliases:[286,4,1,""],func:[286,3,1,""],help_category:[286,4,1,""],key:[286,4,1,""],lock_storage:[286,4,1,""],search_index_entry:[286,4,1,""]},"evennia.contrib.game_systems.clothing.clothing.ContribClothing":{DoesNotExist:[286,2,1,""],MultipleObjectsReturned:[286,2,1,""],at_get:[286,3,1,""],path:[286,4,1,""],remove:[286,3,1,""],typename:[286,4,1,""],wear:[286,3,1,""]},"evennia.contrib.game_systems.clothing.tests":{TestClothingCmd:[287,1,1,""],TestClothingFunc:[287,1,1,""]},"evennia.contrib.game_systems.clothing.tests.TestClothingCmd":{test_clothingcommands:[287,3,1,""]},"evennia.contrib.game_systems.clothing.tests.TestClothingFunc":{test_clothingfunctions:[287,3,1,""]},"evennia.contrib.game_systems.cooldowns":{cooldowns:[289,0,0,"-"],tests:[290,0,0,"-"]},"evennia.contrib.game_systems.cooldowns.cooldowns":{CooldownHandler:[289,1,1,""]},"evennia.contrib.game_systems.cooldowns.cooldowns.CooldownHandler":{__init__:[289,3,1,""],add:[289,3,1,""],all:[289,3,1,""],cleanup:[289,3,1,""],clear:[289,3,1,""],data:[289,4,1,""],db_attribute:[289,4,1,""],extend:[289,3,1,""],obj:[289,4,1,""],ready:[289,3,1,""],reset:[289,3,1,""],set:[289,3,1,""],time_left:[289,3,1,""]},"evennia.contrib.game_systems.cooldowns.tests":{TestCooldowns:[290,1,1,""]},"evennia.contrib.game_systems.cooldowns.tests.TestCooldowns":{setUp:[290,3,1,""],test_add:[290,3,1,""],test_add_float:[290,3,1,""],test_add_multi:[290,3,1,""],test_add_negative:[290,3,1,""],test_add_none:[290,3,1,""],test_add_overwrite:[290,3,1,""],test_cleanup:[290,3,1,""],test_cleanup_doesnt_delete_anything:[290,3,1,""],test_clear:[290,3,1,""],test_empty:[290,3,1,""],test_extend:[290,3,1,""],test_extend_float:[290,3,1,""],test_extend_negative:[290,3,1,""],test_extend_none:[290,3,1,""],test_reset:[290,3,1,""],test_reset_non_existent:[290,3,1,""]},"evennia.contrib.game_systems.crafting":{crafting:[292,0,0,"-"],example_recipes:[293,0,0,"-"],tests:[294,0,0,"-"]},"evennia.contrib.game_systems.crafting.crafting":{CmdCraft:[292,1,1,""],CraftingCmdSet:[292,1,1,""],CraftingError:[292,2,1,""],CraftingRecipe:[292,1,1,""],CraftingRecipeBase:[292,1,1,""],CraftingValidationError:[292,2,1,""],craft:[292,5,1,""]},"evennia.contrib.game_systems.crafting.crafting.CmdCraft":{aliases:[292,4,1,""],arg_regex:[292,4,1,""],func:[292,3,1,""],help_category:[292,4,1,""],key:[292,4,1,""],lock_storage:[292,4,1,""],locks:[292,4,1,""],parse:[292,3,1,""],search_index_entry:[292,4,1,""]},"evennia.contrib.game_systems.crafting.crafting.CraftingCmdSet":{at_cmdset_creation:[292,3,1,""],key:[292,4,1,""],path:[292,4,1,""]},"evennia.contrib.game_systems.crafting.crafting.CraftingRecipe":{__init__:[292,3,1,""],consumable_names:[292,4,1,""],consumable_tag_category:[292,4,1,""],consumable_tags:[292,4,1,""],consume_on_fail:[292,4,1,""],do_craft:[292,3,1,""],error_consumable_excess_message:[292,4,1,""],error_consumable_missing_message:[292,4,1,""],error_consumable_order_message:[292,4,1,""],error_tool_excess_message:[292,4,1,""],error_tool_missing_message:[292,4,1,""],error_tool_order_message:[292,4,1,""],exact_consumable_order:[292,4,1,""],exact_consumables:[292,4,1,""],exact_tool_order:[292,4,1,""],exact_tools:[292,4,1,""],failure_message:[292,4,1,""],name:[292,4,1,""],output_names:[292,4,1,""],output_prototypes:[292,4,1,""],post_craft:[292,3,1,""],pre_craft:[292,3,1,""],seed:[292,3,1,""],success_message:[292,4,1,""],tool_names:[292,4,1,""],tool_tag_category:[292,4,1,""],tool_tags:[292,4,1,""]},"evennia.contrib.game_systems.crafting.crafting.CraftingRecipeBase":{__init__:[292,3,1,""],allow_reuse:[292,4,1,""],craft:[292,3,1,""],do_craft:[292,3,1,""],msg:[292,3,1,""],name:[292,4,1,""],post_craft:[292,3,1,""],pre_craft:[292,3,1,""]},"evennia.contrib.game_systems.crafting.example_recipes":{CmdCast:[293,1,1,""],CrucibleSteelRecipe:[293,1,1,""],FireballRecipe:[293,1,1,""],HealingRecipe:[293,1,1,""],LeatherRecipe:[293,1,1,""],OakBarkRecipe:[293,1,1,""],PigIronRecipe:[293,1,1,""],RawhideRecipe:[293,1,1,""],SwordBladeRecipe:[293,1,1,""],SwordGuardRecipe:[293,1,1,""],SwordHandleRecipe:[293,1,1,""],SwordPommelRecipe:[293,1,1,""],SwordRecipe:[293,1,1,""],random:[293,5,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.CmdCast":{aliases:[293,4,1,""],func:[293,3,1,""],help_category:[293,4,1,""],key:[293,4,1,""],lock_storage:[293,4,1,""],parse:[293,3,1,""],search_index_entry:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.CrucibleSteelRecipe":{consumable_tags:[293,4,1,""],name:[293,4,1,""],output_prototypes:[293,4,1,""],tool_tags:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.FireballRecipe":{desired_effects:[293,4,1,""],failure_effects:[293,4,1,""],name:[293,4,1,""],skill_requirements:[293,4,1,""],skill_roll:[293,4,1,""],success_message:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.HealingRecipe":{desired_effects:[293,4,1,""],failure_effects:[293,4,1,""],name:[293,4,1,""],skill_requirements:[293,4,1,""],skill_roll:[293,4,1,""],success_message:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.LeatherRecipe":{consumable_tags:[293,4,1,""],name:[293,4,1,""],output_prototypes:[293,4,1,""],tool_tags:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.OakBarkRecipe":{consumable_tags:[293,4,1,""],name:[293,4,1,""],output_prototypes:[293,4,1,""],tool_tags:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.PigIronRecipe":{consumable_tags:[293,4,1,""],name:[293,4,1,""],output_prototypes:[293,4,1,""],tool_tags:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.RawhideRecipe":{consumable_tags:[293,4,1,""],name:[293,4,1,""],output_prototypes:[293,4,1,""],tool_tags:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.SwordBladeRecipe":{consumable_tags:[293,4,1,""],name:[293,4,1,""],output_prototypes:[293,4,1,""],tool_tags:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.SwordGuardRecipe":{consumable_tags:[293,4,1,""],name:[293,4,1,""],output_prototypes:[293,4,1,""],tool_tags:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.SwordHandleRecipe":{consumable_tags:[293,4,1,""],name:[293,4,1,""],output_prototypes:[293,4,1,""],tool_tags:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.SwordPommelRecipe":{consumable_tags:[293,4,1,""],name:[293,4,1,""],output_prototypes:[293,4,1,""],tool_tags:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.SwordRecipe":{consumable_tags:[293,4,1,""],exact_consumable_order:[293,4,1,""],name:[293,4,1,""],output_prototypes:[293,4,1,""],tool_tags:[293,4,1,""]},"evennia.contrib.game_systems.crafting.tests":{TestCraftCommand:[294,1,1,""],TestCraftSword:[294,1,1,""],TestCraftUtils:[294,1,1,""],TestCraftingRecipe:[294,1,1,""],TestCraftingRecipeBase:[294,1,1,""]},"evennia.contrib.game_systems.crafting.tests.TestCraftCommand":{setUp:[294,3,1,""],test_craft__nocons__failure:[294,3,1,""],test_craft__notools__failure:[294,3,1,""],test_craft__success:[294,3,1,""]},"evennia.contrib.game_systems.crafting.tests.TestCraftSword":{setUp:[294,3,1,""],test_craft_sword:[294,3,1,""]},"evennia.contrib.game_systems.crafting.tests.TestCraftUtils":{maxDiff:[294,4,1,""],test_load_recipes:[294,3,1,""]},"evennia.contrib.game_systems.crafting.tests.TestCraftingRecipe":{maxDiff:[294,4,1,""],setUp:[294,3,1,""],tearDown:[294,3,1,""],test_craft__success:[294,3,1,""],test_craft_cons_excess__fail:[294,3,1,""],test_craft_cons_excess__sucess:[294,3,1,""],test_craft_cons_order__fail:[294,3,1,""],test_craft_missing_cons__always_consume__fail:[294,3,1,""],test_craft_missing_cons__fail:[294,3,1,""],test_craft_missing_tool__fail:[294,3,1,""],test_craft_tool_excess__fail:[294,3,1,""],test_craft_tool_excess__sucess:[294,3,1,""],test_craft_tool_order__fail:[294,3,1,""],test_craft_wrong_tool__fail:[294,3,1,""],test_error_format:[294,3,1,""],test_seed__success:[294,3,1,""]},"evennia.contrib.game_systems.crafting.tests.TestCraftingRecipeBase":{setUp:[294,3,1,""],test_craft_hook__fail:[294,3,1,""],test_craft_hook__succeed:[294,3,1,""],test_msg:[294,3,1,""],test_pre_craft:[294,3,1,""],test_pre_craft_fail:[294,3,1,""]},"evennia.contrib.game_systems.gendersub":{gendersub:[296,0,0,"-"],tests:[297,0,0,"-"]},"evennia.contrib.game_systems.gendersub.gendersub":{GenderCharacter:[296,1,1,""],SetGender:[296,1,1,""]},"evennia.contrib.game_systems.gendersub.gendersub.GenderCharacter":{DoesNotExist:[296,2,1,""],MultipleObjectsReturned:[296,2,1,""],at_object_creation:[296,3,1,""],msg:[296,3,1,""],path:[296,4,1,""],typename:[296,4,1,""]},"evennia.contrib.game_systems.gendersub.gendersub.SetGender":{aliases:[296,4,1,""],func:[296,3,1,""],help_category:[296,4,1,""],key:[296,4,1,""],lock_storage:[296,4,1,""],locks:[296,4,1,""],search_index_entry:[296,4,1,""]},"evennia.contrib.game_systems.gendersub.tests":{TestGenderSub:[297,1,1,""]},"evennia.contrib.game_systems.gendersub.tests.TestGenderSub":{test_gendercharacter:[297,3,1,""],test_setgender:[297,3,1,""]},"evennia.contrib.game_systems.mail":{mail:[299,0,0,"-"],tests:[300,0,0,"-"]},"evennia.contrib.game_systems.mail.mail":{CmdMail:[299,1,1,""],CmdMailCharacter:[299,1,1,""]},"evennia.contrib.game_systems.mail.mail.CmdMail":{aliases:[299,4,1,""],func:[299,3,1,""],get_all_mail:[299,3,1,""],help_category:[299,4,1,""],key:[299,4,1,""],lock:[299,4,1,""],lock_storage:[299,4,1,""],parse:[299,3,1,""],search_index_entry:[299,4,1,""],search_targets:[299,3,1,""],send_mail:[299,3,1,""]},"evennia.contrib.game_systems.mail.mail.CmdMailCharacter":{account_caller:[299,4,1,""],aliases:[299,4,1,""],help_category:[299,4,1,""],key:[299,4,1,""],lock_storage:[299,4,1,""],search_index_entry:[299,4,1,""]},"evennia.contrib.game_systems.mail.tests":{TestMail:[300,1,1,""]},"evennia.contrib.game_systems.mail.tests.TestMail":{test_mail:[300,3,1,""]},"evennia.contrib.game_systems.multidescer":{multidescer:[302,0,0,"-"],tests:[303,0,0,"-"]},"evennia.contrib.game_systems.multidescer.multidescer":{CmdMultiDesc:[302,1,1,""],DescValidateError:[302,2,1,""]},"evennia.contrib.game_systems.multidescer.multidescer.CmdMultiDesc":{aliases:[302,4,1,""],func:[302,3,1,""],help_category:[302,4,1,""],key:[302,4,1,""],lock_storage:[302,4,1,""],locks:[302,4,1,""],search_index_entry:[302,4,1,""]},"evennia.contrib.game_systems.multidescer.tests":{TestMultidescer:[303,1,1,""]},"evennia.contrib.game_systems.multidescer.tests.TestMultidescer":{test_cmdmultidesc:[303,3,1,""]},"evennia.contrib.game_systems.puzzles":{puzzles:[305,0,0,"-"],tests:[306,0,0,"-"]},"evennia.contrib.game_systems.puzzles.puzzles":{CmdArmPuzzle:[305,1,1,""],CmdCreatePuzzleRecipe:[305,1,1,""],CmdEditPuzzle:[305,1,1,""],CmdListArmedPuzzles:[305,1,1,""],CmdListPuzzleRecipes:[305,1,1,""],CmdUsePuzzleParts:[305,1,1,""],PuzzleRecipe:[305,1,1,""],PuzzleSystemCmdSet:[305,1,1,""],maskout_protodef:[305,5,1,""],proto_def:[305,5,1,""]},"evennia.contrib.game_systems.puzzles.puzzles.CmdArmPuzzle":{aliases:[305,4,1,""],func:[305,3,1,""],help_category:[305,4,1,""],key:[305,4,1,""],lock_storage:[305,4,1,""],locks:[305,4,1,""],search_index_entry:[305,4,1,""]},"evennia.contrib.game_systems.puzzles.puzzles.CmdCreatePuzzleRecipe":{aliases:[305,4,1,""],confirm:[305,4,1,""],default_confirm:[305,4,1,""],func:[305,3,1,""],help_category:[305,4,1,""],key:[305,4,1,""],lock_storage:[305,4,1,""],locks:[305,4,1,""],search_index_entry:[305,4,1,""]},"evennia.contrib.game_systems.puzzles.puzzles.CmdEditPuzzle":{aliases:[305,4,1,""],func:[305,3,1,""],help_category:[305,4,1,""],key:[305,4,1,""],lock_storage:[305,4,1,""],locks:[305,4,1,""],search_index_entry:[305,4,1,""]},"evennia.contrib.game_systems.puzzles.puzzles.CmdListArmedPuzzles":{aliases:[305,4,1,""],func:[305,3,1,""],help_category:[305,4,1,""],key:[305,4,1,""],lock_storage:[305,4,1,""],locks:[305,4,1,""],search_index_entry:[305,4,1,""]},"evennia.contrib.game_systems.puzzles.puzzles.CmdListPuzzleRecipes":{aliases:[305,4,1,""],func:[305,3,1,""],help_category:[305,4,1,""],key:[305,4,1,""],lock_storage:[305,4,1,""],locks:[305,4,1,""],search_index_entry:[305,4,1,""]},"evennia.contrib.game_systems.puzzles.puzzles.CmdUsePuzzleParts":{aliases:[305,4,1,""],func:[305,3,1,""],help_category:[305,4,1,""],key:[305,4,1,""],lock_storage:[305,4,1,""],locks:[305,4,1,""],search_index_entry:[305,4,1,""]},"evennia.contrib.game_systems.puzzles.puzzles.PuzzleRecipe":{DoesNotExist:[305,2,1,""],MultipleObjectsReturned:[305,2,1,""],path:[305,4,1,""],save_recipe:[305,3,1,""],typename:[305,4,1,""]},"evennia.contrib.game_systems.puzzles.puzzles.PuzzleSystemCmdSet":{at_cmdset_creation:[305,3,1,""],path:[305,4,1,""]},"evennia.contrib.game_systems.puzzles.tests":{TestPuzzles:[306,1,1,""]},"evennia.contrib.game_systems.puzzles.tests.TestPuzzles":{setUp:[306,3,1,""],test_cmd_armpuzzle:[306,3,1,""],test_cmd_puzzle:[306,3,1,""],test_cmd_use:[306,3,1,""],test_cmdset_puzzle:[306,3,1,""],test_e2e:[306,3,1,""],test_e2e_accumulative:[306,3,1,""],test_e2e_interchangeable_parts_and_results:[306,3,1,""],test_lspuzzlerecipes_lsarmedpuzzles:[306,3,1,""],test_puzzleedit:[306,3,1,""],test_puzzleedit_add_remove_parts_results:[306,3,1,""]},"evennia.contrib.game_systems.turnbattle":{tb_basic:[308,0,0,"-"],tb_equip:[309,0,0,"-"],tb_items:[310,0,0,"-"],tb_magic:[311,0,0,"-"],tb_range:[312,0,0,"-"],tests:[313,0,0,"-"]},"evennia.contrib.game_systems.turnbattle.tb_basic":{ACTIONS_PER_TURN:[308,6,1,""],BattleCmdSet:[308,1,1,""],CmdAttack:[308,1,1,""],CmdCombatHelp:[308,1,1,""],CmdDisengage:[308,1,1,""],CmdFight:[308,1,1,""],CmdPass:[308,1,1,""],CmdRest:[308,1,1,""],TBBasicCharacter:[308,1,1,""],TBBasicTurnHandler:[308,1,1,""],apply_damage:[308,5,1,""],at_defeat:[308,5,1,""],combat_cleanup:[308,5,1,""],get_attack:[308,5,1,""],get_damage:[308,5,1,""],get_defense:[308,5,1,""],is_in_combat:[308,5,1,""],is_turn:[308,5,1,""],resolve_attack:[308,5,1,""],roll_init:[308,5,1,""],spend_action:[308,5,1,""]},"evennia.contrib.game_systems.turnbattle.tb_basic.BattleCmdSet":{at_cmdset_creation:[308,3,1,""],key:[308,4,1,""],path:[308,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_basic.CmdAttack":{aliases:[308,4,1,""],func:[308,3,1,""],help_category:[308,4,1,""],key:[308,4,1,""],lock_storage:[308,4,1,""],search_index_entry:[308,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_basic.CmdCombatHelp":{aliases:[308,4,1,""],func:[308,3,1,""],help_category:[308,4,1,""],key:[308,4,1,""],lock_storage:[308,4,1,""],search_index_entry:[308,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_basic.CmdDisengage":{aliases:[308,4,1,""],func:[308,3,1,""],help_category:[308,4,1,""],key:[308,4,1,""],lock_storage:[308,4,1,""],search_index_entry:[308,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_basic.CmdFight":{aliases:[308,4,1,""],func:[308,3,1,""],help_category:[308,4,1,""],key:[308,4,1,""],lock_storage:[308,4,1,""],search_index_entry:[308,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_basic.CmdPass":{aliases:[308,4,1,""],func:[308,3,1,""],help_category:[308,4,1,""],key:[308,4,1,""],lock_storage:[308,4,1,""],search_index_entry:[308,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_basic.CmdRest":{aliases:[308,4,1,""],func:[308,3,1,""],help_category:[308,4,1,""],key:[308,4,1,""],lock_storage:[308,4,1,""],search_index_entry:[308,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_basic.TBBasicCharacter":{DoesNotExist:[308,2,1,""],MultipleObjectsReturned:[308,2,1,""],at_object_creation:[308,3,1,""],at_pre_move:[308,3,1,""],path:[308,4,1,""],typename:[308,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_basic.TBBasicTurnHandler":{DoesNotExist:[308,2,1,""],MultipleObjectsReturned:[308,2,1,""],at_repeat:[308,3,1,""],at_script_creation:[308,3,1,""],at_stop:[308,3,1,""],initialize_for_combat:[308,3,1,""],join_fight:[308,3,1,""],next_turn:[308,3,1,""],path:[308,4,1,""],start_turn:[308,3,1,""],turn_end_check:[308,3,1,""],typename:[308,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip":{ACTIONS_PER_TURN:[309,6,1,""],BattleCmdSet:[309,1,1,""],CmdAttack:[309,1,1,""],CmdCombatHelp:[309,1,1,""],CmdDisengage:[309,1,1,""],CmdDoff:[309,1,1,""],CmdDon:[309,1,1,""],CmdFight:[309,1,1,""],CmdPass:[309,1,1,""],CmdRest:[309,1,1,""],CmdUnwield:[309,1,1,""],CmdWield:[309,1,1,""],TBEArmor:[309,1,1,""],TBEWeapon:[309,1,1,""],TBEquipCharacter:[309,1,1,""],TBEquipTurnHandler:[309,1,1,""],apply_damage:[309,5,1,""],at_defeat:[309,5,1,""],combat_cleanup:[309,5,1,""],get_attack:[309,5,1,""],get_damage:[309,5,1,""],get_defense:[309,5,1,""],is_in_combat:[309,5,1,""],is_turn:[309,5,1,""],resolve_attack:[309,5,1,""],roll_init:[309,5,1,""],spend_action:[309,5,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.BattleCmdSet":{at_cmdset_creation:[309,3,1,""],key:[309,4,1,""],path:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.CmdAttack":{aliases:[309,4,1,""],func:[309,3,1,""],help_category:[309,4,1,""],key:[309,4,1,""],lock_storage:[309,4,1,""],search_index_entry:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.CmdCombatHelp":{aliases:[309,4,1,""],func:[309,3,1,""],help_category:[309,4,1,""],key:[309,4,1,""],lock_storage:[309,4,1,""],search_index_entry:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.CmdDisengage":{aliases:[309,4,1,""],func:[309,3,1,""],help_category:[309,4,1,""],key:[309,4,1,""],lock_storage:[309,4,1,""],search_index_entry:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.CmdDoff":{aliases:[309,4,1,""],func:[309,3,1,""],help_category:[309,4,1,""],key:[309,4,1,""],lock_storage:[309,4,1,""],search_index_entry:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.CmdDon":{aliases:[309,4,1,""],func:[309,3,1,""],help_category:[309,4,1,""],key:[309,4,1,""],lock_storage:[309,4,1,""],search_index_entry:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.CmdFight":{aliases:[309,4,1,""],func:[309,3,1,""],help_category:[309,4,1,""],key:[309,4,1,""],lock_storage:[309,4,1,""],search_index_entry:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.CmdPass":{aliases:[309,4,1,""],func:[309,3,1,""],help_category:[309,4,1,""],key:[309,4,1,""],lock_storage:[309,4,1,""],search_index_entry:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.CmdRest":{aliases:[309,4,1,""],func:[309,3,1,""],help_category:[309,4,1,""],key:[309,4,1,""],lock_storage:[309,4,1,""],search_index_entry:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.CmdUnwield":{aliases:[309,4,1,""],func:[309,3,1,""],help_category:[309,4,1,""],key:[309,4,1,""],lock_storage:[309,4,1,""],search_index_entry:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.CmdWield":{aliases:[309,4,1,""],func:[309,3,1,""],help_category:[309,4,1,""],key:[309,4,1,""],lock_storage:[309,4,1,""],search_index_entry:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.TBEArmor":{DoesNotExist:[309,2,1,""],MultipleObjectsReturned:[309,2,1,""],at_drop:[309,3,1,""],at_give:[309,3,1,""],at_object_creation:[309,3,1,""],at_pre_drop:[309,3,1,""],at_pre_give:[309,3,1,""],path:[309,4,1,""],typename:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.TBEWeapon":{DoesNotExist:[309,2,1,""],MultipleObjectsReturned:[309,2,1,""],at_drop:[309,3,1,""],at_give:[309,3,1,""],at_object_creation:[309,3,1,""],path:[309,4,1,""],typename:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.TBEquipCharacter":{DoesNotExist:[309,2,1,""],MultipleObjectsReturned:[309,2,1,""],at_object_creation:[309,3,1,""],at_pre_move:[309,3,1,""],path:[309,4,1,""],typename:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.TBEquipTurnHandler":{DoesNotExist:[309,2,1,""],MultipleObjectsReturned:[309,2,1,""],at_repeat:[309,3,1,""],at_script_creation:[309,3,1,""],at_stop:[309,3,1,""],initialize_for_combat:[309,3,1,""],join_fight:[309,3,1,""],next_turn:[309,3,1,""],path:[309,4,1,""],start_turn:[309,3,1,""],turn_end_check:[309,3,1,""],typename:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items":{BattleCmdSet:[310,1,1,""],CmdAttack:[310,1,1,""],CmdCombatHelp:[310,1,1,""],CmdDisengage:[310,1,1,""],CmdFight:[310,1,1,""],CmdPass:[310,1,1,""],CmdRest:[310,1,1,""],CmdUse:[310,1,1,""],DEF_DOWN_MOD:[310,6,1,""],ITEMFUNCS:[310,6,1,""],TBItemsCharacter:[310,1,1,""],TBItemsCharacterTest:[310,1,1,""],TBItemsTurnHandler:[310,1,1,""],add_condition:[310,5,1,""],apply_damage:[310,5,1,""],at_defeat:[310,5,1,""],combat_cleanup:[310,5,1,""],condition_tickdown:[310,5,1,""],get_attack:[310,5,1,""],get_damage:[310,5,1,""],get_defense:[310,5,1,""],is_in_combat:[310,5,1,""],is_turn:[310,5,1,""],itemfunc_add_condition:[310,5,1,""],itemfunc_attack:[310,5,1,""],itemfunc_cure_condition:[310,5,1,""],itemfunc_heal:[310,5,1,""],resolve_attack:[310,5,1,""],roll_init:[310,5,1,""],spend_action:[310,5,1,""],spend_item_use:[310,5,1,""],use_item:[310,5,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items.BattleCmdSet":{at_cmdset_creation:[310,3,1,""],key:[310,4,1,""],path:[310,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items.CmdAttack":{aliases:[310,4,1,""],func:[310,3,1,""],help_category:[310,4,1,""],key:[310,4,1,""],lock_storage:[310,4,1,""],search_index_entry:[310,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items.CmdCombatHelp":{aliases:[310,4,1,""],func:[310,3,1,""],help_category:[310,4,1,""],key:[310,4,1,""],lock_storage:[310,4,1,""],search_index_entry:[310,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items.CmdDisengage":{aliases:[310,4,1,""],func:[310,3,1,""],help_category:[310,4,1,""],key:[310,4,1,""],lock_storage:[310,4,1,""],search_index_entry:[310,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items.CmdFight":{aliases:[310,4,1,""],func:[310,3,1,""],help_category:[310,4,1,""],key:[310,4,1,""],lock_storage:[310,4,1,""],search_index_entry:[310,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items.CmdPass":{aliases:[310,4,1,""],func:[310,3,1,""],help_category:[310,4,1,""],key:[310,4,1,""],lock_storage:[310,4,1,""],search_index_entry:[310,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items.CmdRest":{aliases:[310,4,1,""],func:[310,3,1,""],help_category:[310,4,1,""],key:[310,4,1,""],lock_storage:[310,4,1,""],search_index_entry:[310,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items.CmdUse":{aliases:[310,4,1,""],func:[310,3,1,""],help_category:[310,4,1,""],key:[310,4,1,""],lock_storage:[310,4,1,""],search_index_entry:[310,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items.TBItemsCharacter":{DoesNotExist:[310,2,1,""],MultipleObjectsReturned:[310,2,1,""],apply_turn_conditions:[310,3,1,""],at_object_creation:[310,3,1,""],at_pre_move:[310,3,1,""],at_turn_start:[310,3,1,""],at_update:[310,3,1,""],path:[310,4,1,""],typename:[310,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items.TBItemsCharacterTest":{DoesNotExist:[310,2,1,""],MultipleObjectsReturned:[310,2,1,""],at_object_creation:[310,3,1,""],path:[310,4,1,""],typename:[310,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items.TBItemsTurnHandler":{DoesNotExist:[310,2,1,""],MultipleObjectsReturned:[310,2,1,""],at_repeat:[310,3,1,""],at_script_creation:[310,3,1,""],at_stop:[310,3,1,""],initialize_for_combat:[310,3,1,""],join_fight:[310,3,1,""],next_turn:[310,3,1,""],path:[310,4,1,""],start_turn:[310,3,1,""],turn_end_check:[310,3,1,""],typename:[310,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic":{ACTIONS_PER_TURN:[311,6,1,""],BattleCmdSet:[311,1,1,""],CmdAttack:[311,1,1,""],CmdCast:[311,1,1,""],CmdCombatHelp:[311,1,1,""],CmdDisengage:[311,1,1,""],CmdFight:[311,1,1,""],CmdLearnSpell:[311,1,1,""],CmdPass:[311,1,1,""],CmdRest:[311,1,1,""],CmdStatus:[311,1,1,""],TBMagicCharacter:[311,1,1,""],TBMagicTurnHandler:[311,1,1,""],apply_damage:[311,5,1,""],at_defeat:[311,5,1,""],combat_cleanup:[311,5,1,""],get_attack:[311,5,1,""],get_damage:[311,5,1,""],get_defense:[311,5,1,""],is_in_combat:[311,5,1,""],is_turn:[311,5,1,""],resolve_attack:[311,5,1,""],roll_init:[311,5,1,""],spell_attack:[311,5,1,""],spell_conjure:[311,5,1,""],spell_healing:[311,5,1,""],spend_action:[311,5,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.BattleCmdSet":{at_cmdset_creation:[311,3,1,""],key:[311,4,1,""],path:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.CmdAttack":{aliases:[311,4,1,""],func:[311,3,1,""],help_category:[311,4,1,""],key:[311,4,1,""],lock_storage:[311,4,1,""],search_index_entry:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.CmdCast":{aliases:[311,4,1,""],func:[311,3,1,""],help_category:[311,4,1,""],key:[311,4,1,""],lock_storage:[311,4,1,""],search_index_entry:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.CmdCombatHelp":{aliases:[311,4,1,""],func:[311,3,1,""],help_category:[311,4,1,""],key:[311,4,1,""],lock_storage:[311,4,1,""],search_index_entry:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.CmdDisengage":{aliases:[311,4,1,""],func:[311,3,1,""],help_category:[311,4,1,""],key:[311,4,1,""],lock_storage:[311,4,1,""],search_index_entry:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.CmdFight":{aliases:[311,4,1,""],func:[311,3,1,""],help_category:[311,4,1,""],key:[311,4,1,""],lock_storage:[311,4,1,""],search_index_entry:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.CmdLearnSpell":{aliases:[311,4,1,""],func:[311,3,1,""],help_category:[311,4,1,""],key:[311,4,1,""],lock_storage:[311,4,1,""],search_index_entry:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.CmdPass":{aliases:[311,4,1,""],func:[311,3,1,""],help_category:[311,4,1,""],key:[311,4,1,""],lock_storage:[311,4,1,""],search_index_entry:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.CmdRest":{aliases:[311,4,1,""],func:[311,3,1,""],help_category:[311,4,1,""],key:[311,4,1,""],lock_storage:[311,4,1,""],search_index_entry:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.CmdStatus":{aliases:[311,4,1,""],func:[311,3,1,""],help_category:[311,4,1,""],key:[311,4,1,""],lock_storage:[311,4,1,""],search_index_entry:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.TBMagicCharacter":{DoesNotExist:[311,2,1,""],MultipleObjectsReturned:[311,2,1,""],at_object_creation:[311,3,1,""],at_pre_move:[311,3,1,""],path:[311,4,1,""],typename:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.TBMagicTurnHandler":{DoesNotExist:[311,2,1,""],MultipleObjectsReturned:[311,2,1,""],at_repeat:[311,3,1,""],at_script_creation:[311,3,1,""],at_stop:[311,3,1,""],initialize_for_combat:[311,3,1,""],join_fight:[311,3,1,""],next_turn:[311,3,1,""],path:[311,4,1,""],start_turn:[311,3,1,""],turn_end_check:[311,3,1,""],typename:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range":{ACTIONS_PER_TURN:[312,6,1,""],BattleCmdSet:[312,1,1,""],CmdApproach:[312,1,1,""],CmdAttack:[312,1,1,""],CmdCombatHelp:[312,1,1,""],CmdDisengage:[312,1,1,""],CmdFight:[312,1,1,""],CmdPass:[312,1,1,""],CmdRest:[312,1,1,""],CmdShoot:[312,1,1,""],CmdStatus:[312,1,1,""],CmdWithdraw:[312,1,1,""],TBRangeCharacter:[312,1,1,""],TBRangeObject:[312,1,1,""],TBRangeTurnHandler:[312,1,1,""],apply_damage:[312,5,1,""],approach:[312,5,1,""],at_defeat:[312,5,1,""],combat_cleanup:[312,5,1,""],combat_status_message:[312,5,1,""],distance_inc:[312,5,1,""],get_attack:[312,5,1,""],get_damage:[312,5,1,""],get_defense:[312,5,1,""],get_range:[312,5,1,""],is_in_combat:[312,5,1,""],is_turn:[312,5,1,""],resolve_attack:[312,5,1,""],roll_init:[312,5,1,""],spend_action:[312,5,1,""],withdraw:[312,5,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.BattleCmdSet":{at_cmdset_creation:[312,3,1,""],key:[312,4,1,""],path:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.CmdApproach":{aliases:[312,4,1,""],func:[312,3,1,""],help_category:[312,4,1,""],key:[312,4,1,""],lock_storage:[312,4,1,""],search_index_entry:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.CmdAttack":{aliases:[312,4,1,""],func:[312,3,1,""],help_category:[312,4,1,""],key:[312,4,1,""],lock_storage:[312,4,1,""],search_index_entry:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.CmdCombatHelp":{aliases:[312,4,1,""],func:[312,3,1,""],help_category:[312,4,1,""],key:[312,4,1,""],lock_storage:[312,4,1,""],search_index_entry:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.CmdDisengage":{aliases:[312,4,1,""],func:[312,3,1,""],help_category:[312,4,1,""],key:[312,4,1,""],lock_storage:[312,4,1,""],search_index_entry:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.CmdFight":{aliases:[312,4,1,""],func:[312,3,1,""],help_category:[312,4,1,""],key:[312,4,1,""],lock_storage:[312,4,1,""],search_index_entry:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.CmdPass":{aliases:[312,4,1,""],func:[312,3,1,""],help_category:[312,4,1,""],key:[312,4,1,""],lock_storage:[312,4,1,""],search_index_entry:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.CmdRest":{aliases:[312,4,1,""],func:[312,3,1,""],help_category:[312,4,1,""],key:[312,4,1,""],lock_storage:[312,4,1,""],search_index_entry:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.CmdShoot":{aliases:[312,4,1,""],func:[312,3,1,""],help_category:[312,4,1,""],key:[312,4,1,""],lock_storage:[312,4,1,""],search_index_entry:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.CmdStatus":{aliases:[312,4,1,""],func:[312,3,1,""],help_category:[312,4,1,""],key:[312,4,1,""],lock_storage:[312,4,1,""],search_index_entry:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.CmdWithdraw":{aliases:[312,4,1,""],func:[312,3,1,""],help_category:[312,4,1,""],key:[312,4,1,""],lock_storage:[312,4,1,""],search_index_entry:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.TBRangeCharacter":{DoesNotExist:[312,2,1,""],MultipleObjectsReturned:[312,2,1,""],at_object_creation:[312,3,1,""],at_pre_move:[312,3,1,""],path:[312,4,1,""],typename:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.TBRangeObject":{DoesNotExist:[312,2,1,""],MultipleObjectsReturned:[312,2,1,""],at_drop:[312,3,1,""],at_get:[312,3,1,""],at_give:[312,3,1,""],at_pre_drop:[312,3,1,""],at_pre_get:[312,3,1,""],at_pre_give:[312,3,1,""],path:[312,4,1,""],typename:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.TBRangeTurnHandler":{DoesNotExist:[312,2,1,""],MultipleObjectsReturned:[312,2,1,""],at_repeat:[312,3,1,""],at_script_creation:[312,3,1,""],at_stop:[312,3,1,""],init_range:[312,3,1,""],initialize_for_combat:[312,3,1,""],join_fight:[312,3,1,""],join_rangefield:[312,3,1,""],next_turn:[312,3,1,""],path:[312,4,1,""],start_turn:[312,3,1,""],turn_end_check:[312,3,1,""],typename:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tests":{TestTurnBattleBasicCmd:[313,1,1,""],TestTurnBattleBasicFunc:[313,1,1,""],TestTurnBattleEquipCmd:[313,1,1,""],TestTurnBattleEquipFunc:[313,1,1,""],TestTurnBattleItemsCmd:[313,1,1,""],TestTurnBattleItemsFunc:[313,1,1,""],TestTurnBattleMagicCmd:[313,1,1,""],TestTurnBattleMagicFunc:[313,1,1,""],TestTurnBattleRangeCmd:[313,1,1,""],TestTurnBattleRangeFunc:[313,1,1,""]},"evennia.contrib.game_systems.turnbattle.tests.TestTurnBattleBasicCmd":{test_turnbattlecmd:[313,3,1,""]},"evennia.contrib.game_systems.turnbattle.tests.TestTurnBattleBasicFunc":{setUp:[313,3,1,""],tearDown:[313,3,1,""],test_tbbasicfunc:[313,3,1,""]},"evennia.contrib.game_systems.turnbattle.tests.TestTurnBattleEquipCmd":{setUp:[313,3,1,""],test_turnbattleequipcmd:[313,3,1,""]},"evennia.contrib.game_systems.turnbattle.tests.TestTurnBattleEquipFunc":{setUp:[313,3,1,""],tearDown:[313,3,1,""],test_tbequipfunc:[313,3,1,""]},"evennia.contrib.game_systems.turnbattle.tests.TestTurnBattleItemsCmd":{setUp:[313,3,1,""],test_turnbattleitemcmd:[313,3,1,""]},"evennia.contrib.game_systems.turnbattle.tests.TestTurnBattleItemsFunc":{setUp:[313,3,1,""],tearDown:[313,3,1,""],test_tbitemsfunc:[313,3,1,""]},"evennia.contrib.game_systems.turnbattle.tests.TestTurnBattleMagicCmd":{test_turnbattlemagiccmd:[313,3,1,""]},"evennia.contrib.game_systems.turnbattle.tests.TestTurnBattleMagicFunc":{setUp:[313,3,1,""],tearDown:[313,3,1,""],test_tbbasicfunc:[313,3,1,""]},"evennia.contrib.game_systems.turnbattle.tests.TestTurnBattleRangeCmd":{test_turnbattlerangecmd:[313,3,1,""]},"evennia.contrib.game_systems.turnbattle.tests.TestTurnBattleRangeFunc":{setUp:[313,3,1,""],tearDown:[313,3,1,""],test_tbrangefunc:[313,3,1,""]},"evennia.contrib.grid":{extended_room:[315,0,0,"-"],simpledoor:[321,0,0,"-"],slow_exit:[324,0,0,"-"],wilderness:[327,0,0,"-"],xyzgrid:[330,0,0,"-"]},"evennia.contrib.grid.extended_room":{extended_room:[316,0,0,"-"],tests:[317,0,0,"-"]},"evennia.contrib.grid.extended_room.extended_room":{CmdExtendedRoomDesc:[316,1,1,""],CmdExtendedRoomDetail:[316,1,1,""],CmdExtendedRoomGameTime:[316,1,1,""],CmdExtendedRoomLook:[316,1,1,""],ExtendedRoom:[316,1,1,""],ExtendedRoomCmdSet:[316,1,1,""]},"evennia.contrib.grid.extended_room.extended_room.CmdExtendedRoomDesc":{aliases:[316,4,1,""],func:[316,3,1,""],help_category:[316,4,1,""],key:[316,4,1,""],lock_storage:[316,4,1,""],reset_times:[316,3,1,""],search_index_entry:[316,4,1,""],switch_options:[316,4,1,""]},"evennia.contrib.grid.extended_room.extended_room.CmdExtendedRoomDetail":{aliases:[316,4,1,""],func:[316,3,1,""],help_category:[316,4,1,""],key:[316,4,1,""],lock_storage:[316,4,1,""],locks:[316,4,1,""],search_index_entry:[316,4,1,""]},"evennia.contrib.grid.extended_room.extended_room.CmdExtendedRoomGameTime":{aliases:[316,4,1,""],func:[316,3,1,""],help_category:[316,4,1,""],key:[316,4,1,""],lock_storage:[316,4,1,""],locks:[316,4,1,""],search_index_entry:[316,4,1,""]},"evennia.contrib.grid.extended_room.extended_room.CmdExtendedRoomLook":{aliases:[316,4,1,""],func:[316,3,1,""],help_category:[316,4,1,""],key:[316,4,1,""],lock_storage:[316,4,1,""],search_index_entry:[316,4,1,""]},"evennia.contrib.grid.extended_room.extended_room.ExtendedRoom":{DoesNotExist:[316,2,1,""],MultipleObjectsReturned:[316,2,1,""],at_object_creation:[316,3,1,""],del_detail:[316,3,1,""],get_time_and_season:[316,3,1,""],path:[316,4,1,""],replace_timeslots:[316,3,1,""],return_appearance:[316,3,1,""],return_detail:[316,3,1,""],set_detail:[316,3,1,""],typename:[316,4,1,""],update_current_description:[316,3,1,""]},"evennia.contrib.grid.extended_room.extended_room.ExtendedRoomCmdSet":{at_cmdset_creation:[316,3,1,""],path:[316,4,1,""]},"evennia.contrib.grid.extended_room.tests":{ForceUTCDatetime:[317,1,1,""],TestExtendedRoom:[317,1,1,""]},"evennia.contrib.grid.extended_room.tests.ForceUTCDatetime":{fromtimestamp:[317,3,1,""]},"evennia.contrib.grid.extended_room.tests.TestExtendedRoom":{DETAIL_DESC:[317,4,1,""],OLD_DESC:[317,4,1,""],SPRING_DESC:[317,4,1,""],room_typeclass:[317,4,1,""],setUp:[317,3,1,""],test_cmdextendedlook:[317,3,1,""],test_cmdgametime:[317,3,1,""],test_cmdsetdetail:[317,3,1,""],test_return_appearance:[317,3,1,""],test_return_detail:[317,3,1,""]},"evennia.contrib.grid.simpledoor":{simpledoor:[322,0,0,"-"],tests:[323,0,0,"-"]},"evennia.contrib.grid.simpledoor.simpledoor":{CmdOpen:[322,1,1,""],CmdOpenCloseDoor:[322,1,1,""],SimpleDoor:[322,1,1,""],SimpleDoorCmdSet:[322,1,1,""]},"evennia.contrib.grid.simpledoor.simpledoor.CmdOpen":{aliases:[322,4,1,""],create_exit:[322,3,1,""],help_category:[322,4,1,""],key:[322,4,1,""],lock_storage:[322,4,1,""],search_index_entry:[322,4,1,""]},"evennia.contrib.grid.simpledoor.simpledoor.CmdOpenCloseDoor":{aliases:[322,4,1,""],func:[322,3,1,""],help_category:[322,4,1,""],key:[322,4,1,""],lock_storage:[322,4,1,""],locks:[322,4,1,""],search_index_entry:[322,4,1,""]},"evennia.contrib.grid.simpledoor.simpledoor.SimpleDoor":{"delete":[322,3,1,""],DoesNotExist:[322,2,1,""],MultipleObjectsReturned:[322,2,1,""],at_failed_traverse:[322,3,1,""],at_object_creation:[322,3,1,""],path:[322,4,1,""],setdesc:[322,3,1,""],setlock:[322,3,1,""],typename:[322,4,1,""]},"evennia.contrib.grid.simpledoor.simpledoor.SimpleDoorCmdSet":{at_cmdset_creation:[322,3,1,""],path:[322,4,1,""]},"evennia.contrib.grid.simpledoor.tests":{TestSimpleDoor:[323,1,1,""]},"evennia.contrib.grid.simpledoor.tests.TestSimpleDoor":{test_cmdopen:[323,3,1,""]},"evennia.contrib.grid.slow_exit":{slow_exit:[325,0,0,"-"],tests:[326,0,0,"-"]},"evennia.contrib.grid.slow_exit.slow_exit":{CmdSetSpeed:[325,1,1,""],CmdStop:[325,1,1,""],SlowExit:[325,1,1,""],SlowExitCmdSet:[325,1,1,""]},"evennia.contrib.grid.slow_exit.slow_exit.CmdSetSpeed":{aliases:[325,4,1,""],func:[325,3,1,""],help_category:[325,4,1,""],key:[325,4,1,""],lock_storage:[325,4,1,""],search_index_entry:[325,4,1,""]},"evennia.contrib.grid.slow_exit.slow_exit.CmdStop":{aliases:[325,4,1,""],func:[325,3,1,""],help_category:[325,4,1,""],key:[325,4,1,""],lock_storage:[325,4,1,""],search_index_entry:[325,4,1,""]},"evennia.contrib.grid.slow_exit.slow_exit.SlowExit":{DoesNotExist:[325,2,1,""],MultipleObjectsReturned:[325,2,1,""],at_traverse:[325,3,1,""],path:[325,4,1,""],typename:[325,4,1,""]},"evennia.contrib.grid.slow_exit.slow_exit.SlowExitCmdSet":{at_cmdset_creation:[325,3,1,""],path:[325,4,1,""]},"evennia.contrib.grid.slow_exit.tests":{TestSlowExit:[326,1,1,""]},"evennia.contrib.grid.slow_exit.tests.TestSlowExit":{test_exit:[326,3,1,""]},"evennia.contrib.grid.wilderness":{tests:[328,0,0,"-"],wilderness:[329,0,0,"-"]},"evennia.contrib.grid.wilderness.tests":{TestWilderness:[328,1,1,""]},"evennia.contrib.grid.wilderness.tests.TestWilderness":{get_wilderness_script:[328,3,1,""],setUp:[328,3,1,""],test_create_wilderness_custom_name:[328,3,1,""],test_create_wilderness_default_name:[328,3,1,""],test_enter_wilderness:[328,3,1,""],test_enter_wilderness_custom_coordinates:[328,3,1,""],test_enter_wilderness_custom_name:[328,3,1,""],test_get_new_coordinates:[328,3,1,""],test_room_creation:[328,3,1,""],test_wilderness_correct_exits:[328,3,1,""]},"evennia.contrib.grid.wilderness.wilderness":{WildernessExit:[329,1,1,""],WildernessMapProvider:[329,1,1,""],WildernessRoom:[329,1,1,""],WildernessScript:[329,1,1,""],create_wilderness:[329,5,1,""],enter_wilderness:[329,5,1,""],get_new_coordinates:[329,5,1,""]},"evennia.contrib.grid.wilderness.wilderness.WildernessExit":{DoesNotExist:[329,2,1,""],MultipleObjectsReturned:[329,2,1,""],at_traverse:[329,3,1,""],at_traverse_coordinates:[329,3,1,""],mapprovider:[329,3,1,""],path:[329,4,1,""],typename:[329,4,1,""],wilderness:[329,3,1,""]},"evennia.contrib.grid.wilderness.wilderness.WildernessMapProvider":{at_prepare_room:[329,3,1,""],exit_typeclass:[329,4,1,""],get_location_name:[329,3,1,""],is_valid_coordinates:[329,3,1,""],room_typeclass:[329,4,1,""]},"evennia.contrib.grid.wilderness.wilderness.WildernessRoom":{DoesNotExist:[329,2,1,""],MultipleObjectsReturned:[329,2,1,""],at_object_leave:[329,3,1,""],at_object_receive:[329,3,1,""],coordinates:[329,3,1,""],get_display_name:[329,3,1,""],location_name:[329,3,1,""],path:[329,4,1,""],set_active_coordinates:[329,3,1,""],typename:[329,4,1,""],wilderness:[329,3,1,""]},"evennia.contrib.grid.wilderness.wilderness.WildernessScript":{DoesNotExist:[329,2,1,""],MultipleObjectsReturned:[329,2,1,""],at_post_object_leave:[329,3,1,""],at_script_creation:[329,3,1,""],at_start:[329,3,1,""],get_obj_coordinates:[329,3,1,""],get_objs_at_coordinates:[329,3,1,""],is_valid_coordinates:[329,3,1,""],itemcoordinates:[329,3,1,""],mapprovider:[329,3,1,""],move_obj:[329,3,1,""],path:[329,4,1,""],typename:[329,4,1,""]},"evennia.contrib.grid.xyzgrid":{commands:[331,0,0,"-"],example:[332,0,0,"-"],launchcmd:[333,0,0,"-"],prototypes:[334,0,0,"-"],tests:[335,0,0,"-"],utils:[336,0,0,"-"],xymap:[337,0,0,"-"],xymap_legend:[338,0,0,"-"],xyzgrid:[339,0,0,"-"],xyzroom:[340,0,0,"-"]},"evennia.contrib.grid.xyzgrid.commands":{CmdGoto:[331,1,1,""],CmdMap:[331,1,1,""],CmdXYZOpen:[331,1,1,""],CmdXYZTeleport:[331,1,1,""],PathData:[331,1,1,""],XYZGridCmdSet:[331,1,1,""]},"evennia.contrib.grid.xyzgrid.commands.CmdGoto":{aliases:[331,4,1,""],auto_step_delay:[331,4,1,""],default_xyz_path_interrupt_msg:[331,4,1,""],func:[331,3,1,""],help_category:[331,4,1,""],key:[331,4,1,""],lock_storage:[331,4,1,""],locks:[331,4,1,""],search_index_entry:[331,4,1,""]},"evennia.contrib.grid.xyzgrid.commands.CmdMap":{aliases:[331,4,1,""],func:[331,3,1,""],help_category:[331,4,1,""],key:[331,4,1,""],lock_storage:[331,4,1,""],locks:[331,4,1,""],search_index_entry:[331,4,1,""]},"evennia.contrib.grid.xyzgrid.commands.CmdXYZOpen":{aliases:[331,4,1,""],help_category:[331,4,1,""],key:[331,4,1,""],lock_storage:[331,4,1,""],parse:[331,3,1,""],search_index_entry:[331,4,1,""]},"evennia.contrib.grid.xyzgrid.commands.CmdXYZTeleport":{aliases:[331,4,1,""],help_category:[331,4,1,""],key:[331,4,1,""],lock_storage:[331,4,1,""],parse:[331,3,1,""],search_index_entry:[331,4,1,""]},"evennia.contrib.grid.xyzgrid.commands.PathData":{directions:[331,4,1,""],step_sequence:[331,4,1,""],target:[331,4,1,""],task:[331,4,1,""],xymap:[331,4,1,""]},"evennia.contrib.grid.xyzgrid.commands.XYZGridCmdSet":{at_cmdset_creation:[331,3,1,""],key:[331,4,1,""],path:[331,4,1,""]},"evennia.contrib.grid.xyzgrid.example":{TransitionToCave:[332,1,1,""],TransitionToLargeTree:[332,1,1,""]},"evennia.contrib.grid.xyzgrid.example.TransitionToCave":{symbol:[332,4,1,""],target_map_xyz:[332,4,1,""]},"evennia.contrib.grid.xyzgrid.example.TransitionToLargeTree":{symbol:[332,4,1,""],target_map_xyz:[332,4,1,""]},"evennia.contrib.grid.xyzgrid.launchcmd":{xyzcommand:[333,5,1,""]},"evennia.contrib.grid.xyzgrid.tests":{Map12aTransition:[335,1,1,""],Map12bTransition:[335,1,1,""],TestBuildExampleGrid:[335,1,1,""],TestMap10:[335,1,1,""],TestMap11:[335,1,1,""],TestMap1:[335,1,1,""],TestMap2:[335,1,1,""],TestMap3:[335,1,1,""],TestMap4:[335,1,1,""],TestMap5:[335,1,1,""],TestMap6:[335,1,1,""],TestMap7:[335,1,1,""],TestMap8:[335,1,1,""],TestMap9:[335,1,1,""],TestMapStressTest:[335,1,1,""],TestXYZGrid:[335,1,1,""],TestXYZGridTransition:[335,1,1,""]},"evennia.contrib.grid.xyzgrid.tests.Map12aTransition":{symbol:[335,4,1,""],target_map_xyz:[335,4,1,""]},"evennia.contrib.grid.xyzgrid.tests.Map12bTransition":{symbol:[335,4,1,""],target_map_xyz:[335,4,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestBuildExampleGrid":{setUp:[335,3,1,""],tearDown:[335,3,1,""],test_build:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMap1":{test_get_shortest_path:[335,3,1,""],test_get_visual_range__nodes__character:[335,4,1,""],test_get_visual_range__nodes__character_0:[335,3,1,""],test_get_visual_range__nodes__character_1:[335,3,1,""],test_get_visual_range__nodes__character_2:[335,3,1,""],test_get_visual_range__nodes__character_3:[335,3,1,""],test_get_visual_range__nodes__character_4:[335,3,1,""],test_get_visual_range__scan:[335,4,1,""],test_get_visual_range__scan_0:[335,3,1,""],test_get_visual_range__scan_1:[335,3,1,""],test_get_visual_range__scan_2:[335,3,1,""],test_get_visual_range__scan_3:[335,3,1,""],test_get_visual_range__scan__character:[335,4,1,""],test_get_visual_range__scan__character_0:[335,3,1,""],test_get_visual_range__scan__character_1:[335,3,1,""],test_get_visual_range__scan__character_2:[335,3,1,""],test_get_visual_range__scan__character_3:[335,3,1,""],test_node_from_coord:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMap10":{map_data:[335,4,1,""],map_display:[335,4,1,""],test_paths:[335,4,1,""],test_paths_0:[335,3,1,""],test_paths_1:[335,3,1,""],test_shortest_path:[335,4,1,""],test_shortest_path_0:[335,3,1,""],test_shortest_path_1:[335,3,1,""],test_shortest_path_2:[335,3,1,""],test_shortest_path_3:[335,3,1,""],test_shortest_path_4:[335,3,1,""],test_shortest_path_5:[335,3,1,""],test_shortest_path_6:[335,3,1,""],test_shortest_path_7:[335,3,1,""],test_shortest_path_8:[335,3,1,""],test_shortest_path_9:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMap11":{map_data:[335,4,1,""],map_display:[335,4,1,""],test_get_visual_range_with_path:[335,4,1,""],test_get_visual_range_with_path_0:[335,3,1,""],test_get_visual_range_with_path_1:[335,3,1,""],test_paths:[335,4,1,""],test_paths_0:[335,3,1,""],test_paths_1:[335,3,1,""],test_shortest_path:[335,4,1,""],test_shortest_path_0:[335,3,1,""],test_shortest_path_1:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMap2":{map_data:[335,4,1,""],map_display:[335,4,1,""],test_extended_path_tracking__horizontal:[335,3,1,""],test_extended_path_tracking__vertical:[335,3,1,""],test_get_visual_range__nodes__character:[335,4,1,""],test_get_visual_range__nodes__character_0:[335,3,1,""],test_get_visual_range__nodes__character_1:[335,3,1,""],test_get_visual_range__nodes__character_2:[335,3,1,""],test_get_visual_range__nodes__character_3:[335,3,1,""],test_get_visual_range__nodes__character_4:[335,3,1,""],test_get_visual_range__nodes__character_5:[335,3,1,""],test_get_visual_range__nodes__character_6:[335,3,1,""],test_get_visual_range__nodes__character_7:[335,3,1,""],test_get_visual_range__nodes__character_8:[335,3,1,""],test_get_visual_range__nodes__character_9:[335,3,1,""],test_get_visual_range__scan__character:[335,4,1,""],test_get_visual_range__scan__character_0:[335,3,1,""],test_get_visual_range__scan__character_1:[335,3,1,""],test_get_visual_range__scan__character_2:[335,3,1,""],test_get_visual_range__scan__character_3:[335,3,1,""],test_node_from_coord:[335,3,1,""],test_shortest_path:[335,4,1,""],test_shortest_path_0:[335,3,1,""],test_shortest_path_1:[335,3,1,""],test_shortest_path_2:[335,3,1,""],test_shortest_path_3:[335,3,1,""],test_shortest_path_4:[335,3,1,""],test_shortest_path_5:[335,3,1,""],test_shortest_path_6:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMap3":{map_data:[335,4,1,""],map_display:[335,4,1,""],test_get_visual_range__nodes__character:[335,4,1,""],test_get_visual_range__nodes__character_0:[335,3,1,""],test_get_visual_range__nodes__character_1:[335,3,1,""],test_shortest_path:[335,4,1,""],test_shortest_path_00:[335,3,1,""],test_shortest_path_01:[335,3,1,""],test_shortest_path_02:[335,3,1,""],test_shortest_path_03:[335,3,1,""],test_shortest_path_04:[335,3,1,""],test_shortest_path_05:[335,3,1,""],test_shortest_path_06:[335,3,1,""],test_shortest_path_07:[335,3,1,""],test_shortest_path_08:[335,3,1,""],test_shortest_path_09:[335,3,1,""],test_shortest_path_10:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMap4":{map_data:[335,4,1,""],map_display:[335,4,1,""],test_shortest_path:[335,4,1,""],test_shortest_path_0:[335,3,1,""],test_shortest_path_1:[335,3,1,""],test_shortest_path_2:[335,3,1,""],test_shortest_path_3:[335,3,1,""],test_shortest_path_4:[335,3,1,""],test_shortest_path_5:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMap5":{map_data:[335,4,1,""],map_display:[335,4,1,""],test_shortest_path:[335,4,1,""],test_shortest_path_0:[335,3,1,""],test_shortest_path_1:[335,3,1,""],test_shortest_path_2:[335,3,1,""],test_shortest_path_3:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMap6":{map_data:[335,4,1,""],map_display:[335,4,1,""],test_shortest_path:[335,4,1,""],test_shortest_path_0:[335,3,1,""],test_shortest_path_1:[335,3,1,""],test_shortest_path_2:[335,3,1,""],test_shortest_path_3:[335,3,1,""],test_shortest_path_4:[335,3,1,""],test_shortest_path_5:[335,3,1,""],test_shortest_path_6:[335,3,1,""],test_shortest_path_7:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMap7":{map_data:[335,4,1,""],map_display:[335,4,1,""],test_shortest_path:[335,4,1,""],test_shortest_path_0:[335,3,1,""],test_shortest_path_1:[335,3,1,""],test_shortest_path_2:[335,3,1,""],test_shortest_path_3:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMap8":{map_data:[335,4,1,""],map_display:[335,4,1,""],test_get_visual_range__nodes__character:[335,4,1,""],test_get_visual_range__nodes__character_0:[335,3,1,""],test_get_visual_range_with_path:[335,4,1,""],test_get_visual_range_with_path_0:[335,3,1,""],test_get_visual_range_with_path_1:[335,3,1,""],test_get_visual_range_with_path_2:[335,3,1,""],test_get_visual_range_with_path_3:[335,3,1,""],test_get_visual_range_with_path_4:[335,3,1,""],test_shortest_path:[335,4,1,""],test_shortest_path_0:[335,3,1,""],test_shortest_path_1:[335,3,1,""],test_shortest_path_2:[335,3,1,""],test_shortest_path_3:[335,3,1,""],test_shortest_path_4:[335,3,1,""],test_shortest_path_5:[335,3,1,""],test_shortest_path_6:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMap9":{map_data:[335,4,1,""],map_display:[335,4,1,""],test_shortest_path:[335,4,1,""],test_shortest_path_0:[335,3,1,""],test_shortest_path_1:[335,3,1,""],test_shortest_path_2:[335,3,1,""],test_shortest_path_3:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMapStressTest":{test_grid_creation:[335,4,1,""],test_grid_creation_0:[335,3,1,""],test_grid_creation_1:[335,3,1,""],test_grid_pathfind:[335,4,1,""],test_grid_pathfind_0:[335,3,1,""],test_grid_pathfind_1:[335,3,1,""],test_grid_visibility:[335,4,1,""],test_grid_visibility_0:[335,3,1,""],test_grid_visibility_1:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestXYZGrid":{setUp:[335,3,1,""],tearDown:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""],zcoord:[335,4,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestXYZGridTransition":{setUp:[335,3,1,""],tearDown:[335,3,1,""],test_shortest_path:[335,4,1,""],test_shortest_path_0:[335,3,1,""],test_shortest_path_1:[335,3,1,""],test_spawn:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.utils":{MapError:[336,2,1,""],MapParserError:[336,2,1,""],MapTransition:[336,2,1,""]},"evennia.contrib.grid.xyzgrid.utils.MapError":{__init__:[336,3,1,""]},"evennia.contrib.grid.xyzgrid.xymap":{XYMap:[337,1,1,""]},"evennia.contrib.grid.xyzgrid.xymap.XYMap":{__init__:[337,3,1,""],calculate_path_matrix:[337,3,1,""],empty_symbol:[337,4,1,""],get_components_with_symbol:[337,3,1,""],get_node_from_coord:[337,3,1,""],get_shortest_path:[337,3,1,""],get_visual_range:[337,3,1,""],legend_key_exceptions:[337,4,1,""],log:[337,3,1,""],mapcorner_symbol:[337,4,1,""],max_pathfinding_length:[337,4,1,""],parse:[337,3,1,""],reload:[337,3,1,""],spawn_links:[337,3,1,""],spawn_nodes:[337,3,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend":{BasicMapNode:[338,1,1,""],BlockedMapLink:[338,1,1,""],CrossMapLink:[338,1,1,""],DownMapLink:[338,1,1,""],EWMapLink:[338,1,1,""],EWOneWayMapLink:[338,1,1,""],InterruptMapLink:[338,1,1,""],InterruptMapNode:[338,1,1,""],InvisibleSmartMapLink:[338,1,1,""],MapLink:[338,1,1,""],MapNode:[338,1,1,""],MapTransitionNode:[338,1,1,""],NESWMapLink:[338,1,1,""],NSMapLink:[338,1,1,""],NSOneWayMapLink:[338,1,1,""],PlusMapLink:[338,1,1,""],RouterMapLink:[338,1,1,""],SENWMapLink:[338,1,1,""],SNOneWayMapLink:[338,1,1,""],SmartMapLink:[338,1,1,""],SmartRerouterMapLink:[338,1,1,""],SmartTeleporterMapLink:[338,1,1,""],TeleporterMapLink:[338,1,1,""],TransitionMapNode:[338,1,1,""],UpMapLink:[338,1,1,""],WEOneWayMapLink:[338,1,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.BasicMapNode":{prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.BlockedMapLink":{prototype:[338,4,1,""],symbol:[338,4,1,""],weights:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.CrossMapLink":{directions:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.DownMapLink":{direction_aliases:[338,4,1,""],prototype:[338,4,1,""],spawn_aliases:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.EWMapLink":{directions:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.EWOneWayMapLink":{directions:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.InterruptMapLink":{interrupt_path:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.InterruptMapNode":{display_symbol:[338,4,1,""],interrupt_path:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.InvisibleSmartMapLink":{direction_aliases:[338,4,1,""],display_symbol_aliases:[338,4,1,""],get_display_symbol:[338,3,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.MapLink":{__init__:[338,3,1,""],at_empty_target:[338,3,1,""],average_long_link_weights:[338,4,1,""],default_weight:[338,4,1,""],direction_aliases:[338,4,1,""],directions:[338,4,1,""],display_symbol:[338,4,1,""],generate_prototype_key:[338,3,1,""],get_direction:[338,3,1,""],get_display_symbol:[338,3,1,""],get_linked_neighbors:[338,3,1,""],get_weight:[338,3,1,""],interrupt_path:[338,4,1,""],multilink:[338,4,1,""],prototype:[338,4,1,""],spawn_aliases:[338,4,1,""],symbol:[338,4,1,""],traverse:[338,3,1,""],weights:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.MapNode":{__init__:[338,3,1,""],build_links:[338,3,1,""],direction_spawn_defaults:[338,4,1,""],display_symbol:[338,4,1,""],generate_prototype_key:[338,3,1,""],get_display_symbol:[338,3,1,""],get_exit_spawn_name:[338,3,1,""],get_spawn_xyz:[338,3,1,""],interrupt_path:[338,4,1,""],linkweights:[338,3,1,""],log:[338,3,1,""],multilink:[338,4,1,""],node_index:[338,4,1,""],prototype:[338,4,1,""],spawn:[338,3,1,""],spawn_links:[338,3,1,""],symbol:[338,4,1,""],unspawn:[338,3,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.MapTransitionNode":{display_symbol:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""],target_map_xyz:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.NESWMapLink":{directions:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.NSMapLink":{directions:[338,4,1,""],display_symbol:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.NSOneWayMapLink":{directions:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.PlusMapLink":{directions:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.RouterMapLink":{symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.SENWMapLink":{directions:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.SNOneWayMapLink":{directions:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.SmartMapLink":{get_direction:[338,3,1,""],multilink:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.SmartRerouterMapLink":{get_direction:[338,3,1,""],multilink:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.SmartTeleporterMapLink":{__init__:[338,3,1,""],at_empty_target:[338,3,1,""],direction_name:[338,4,1,""],display_symbol:[338,4,1,""],get_direction:[338,3,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.TeleporterMapLink":{symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.TransitionMapNode":{build_links:[338,3,1,""],display_symbol:[338,4,1,""],get_spawn_xyz:[338,3,1,""],symbol:[338,4,1,""],taget_map_xyz:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.UpMapLink":{direction_aliases:[338,4,1,""],prototype:[338,4,1,""],spawn_aliases:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.WEOneWayMapLink":{directions:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xyzgrid":{XYZGrid:[339,1,1,""],get_xyzgrid:[339,5,1,""]},"evennia.contrib.grid.xyzgrid.xyzgrid.XYZGrid":{"delete":[339,3,1,""],DoesNotExist:[339,2,1,""],MultipleObjectsReturned:[339,2,1,""],add_maps:[339,3,1,""],all_maps:[339,3,1,""],at_script_creation:[339,3,1,""],get_exit:[339,3,1,""],get_map:[339,3,1,""],get_room:[339,3,1,""],grid:[339,3,1,""],log:[339,3,1,""],maps_from_module:[339,3,1,""],path:[339,4,1,""],reload:[339,3,1,""],remove_map:[339,3,1,""],spawn:[339,3,1,""],typename:[339,4,1,""]},"evennia.contrib.grid.xyzgrid.xyzroom":{XYZExit:[340,1,1,""],XYZExitManager:[340,1,1,""],XYZManager:[340,1,1,""],XYZRoom:[340,1,1,""]},"evennia.contrib.grid.xyzgrid.xyzroom.XYZExit":{DoesNotExist:[340,2,1,""],MultipleObjectsReturned:[340,2,1,""],create:[340,3,1,""],objects:[340,4,1,""],path:[340,4,1,""],typename:[340,4,1,""],xyz:[340,3,1,""],xyz_destination:[340,3,1,""],xyzgrid:[340,3,1,""]},"evennia.contrib.grid.xyzgrid.xyzroom.XYZExitManager":{filter_xyz_exit:[340,3,1,""],get_xyz_exit:[340,3,1,""]},"evennia.contrib.grid.xyzgrid.xyzroom.XYZManager":{filter_xyz:[340,3,1,""],get_xyz:[340,3,1,""]},"evennia.contrib.grid.xyzgrid.xyzroom.XYZRoom":{DoesNotExist:[340,2,1,""],MultipleObjectsReturned:[340,2,1,""],create:[340,3,1,""],get_display_name:[340,3,1,""],map_align:[340,4,1,""],map_character_symbol:[340,4,1,""],map_display:[340,4,1,""],map_fill_all:[340,4,1,""],map_mode:[340,4,1,""],map_separator_char:[340,4,1,""],map_target_path_style:[340,4,1,""],map_visual_range:[340,4,1,""],objects:[340,4,1,""],path:[340,4,1,""],return_appearance:[340,3,1,""],typename:[340,4,1,""],xymap:[340,3,1,""],xyz:[340,3,1,""],xyzgrid:[340,3,1,""]},"evennia.contrib.rpg":{dice:[342,0,0,"-"],health_bar:[345,0,0,"-"],rpsystem:[348,0,0,"-"],traits:[352,0,0,"-"]},"evennia.contrib.rpg.dice":{dice:[343,0,0,"-"],tests:[344,0,0,"-"]},"evennia.contrib.rpg.dice.dice":{CmdDice:[343,1,1,""],DiceCmdSet:[343,1,1,""],roll:[343,5,1,""],roll_dice:[343,5,1,""]},"evennia.contrib.rpg.dice.dice.CmdDice":{aliases:[343,4,1,""],func:[343,3,1,""],help_category:[343,4,1,""],key:[343,4,1,""],lock_storage:[343,4,1,""],locks:[343,4,1,""],search_index_entry:[343,4,1,""]},"evennia.contrib.rpg.dice.dice.DiceCmdSet":{at_cmdset_creation:[343,3,1,""],path:[343,4,1,""]},"evennia.contrib.rpg.dice.tests":{TestDice:[344,1,1,""]},"evennia.contrib.rpg.dice.tests.TestDice":{test_cmddice:[344,3,1,""],test_roll_dice:[344,3,1,""]},"evennia.contrib.rpg.health_bar":{health_bar:[346,0,0,"-"],tests:[347,0,0,"-"]},"evennia.contrib.rpg.health_bar.health_bar":{display_meter:[346,5,1,""]},"evennia.contrib.rpg.health_bar.tests":{TestHealthBar:[347,1,1,""]},"evennia.contrib.rpg.health_bar.tests.TestHealthBar":{test_healthbar:[347,3,1,""]},"evennia.contrib.rpg.rpsystem":{rplanguage:[349,0,0,"-"],rpsystem:[350,0,0,"-"],tests:[351,0,0,"-"]},"evennia.contrib.rpg.rpsystem.rplanguage":{LanguageError:[349,2,1,""],LanguageExistsError:[349,2,1,""],LanguageHandler:[349,1,1,""],add_language:[349,5,1,""],available_languages:[349,5,1,""],obfuscate_language:[349,5,1,""],obfuscate_whisper:[349,5,1,""]},"evennia.contrib.rpg.rpsystem.rplanguage.LanguageHandler":{DoesNotExist:[349,2,1,""],MultipleObjectsReturned:[349,2,1,""],add:[349,3,1,""],at_script_creation:[349,3,1,""],path:[349,4,1,""],translate:[349,3,1,""],typename:[349,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem":{CmdEmote:[350,1,1,""],CmdMask:[350,1,1,""],CmdPose:[350,1,1,""],CmdRecog:[350,1,1,""],CmdSay:[350,1,1,""],CmdSdesc:[350,1,1,""],ContribRPCharacter:[350,1,1,""],ContribRPObject:[350,1,1,""],ContribRPRoom:[350,1,1,""],EmoteError:[350,2,1,""],LanguageError:[350,2,1,""],RPCommand:[350,1,1,""],RPSystemCmdSet:[350,1,1,""],RecogError:[350,2,1,""],RecogHandler:[350,1,1,""],SdescError:[350,2,1,""],SdescHandler:[350,1,1,""],ordered_permutation_regex:[350,5,1,""],parse_language:[350,5,1,""],parse_sdescs_and_recogs:[350,5,1,""],regex_tuple_from_key_alias:[350,5,1,""],send_emote:[350,5,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.CmdEmote":{aliases:[350,4,1,""],arg_regex:[350,4,1,""],func:[350,3,1,""],help_category:[350,4,1,""],key:[350,4,1,""],lock_storage:[350,4,1,""],locks:[350,4,1,""],search_index_entry:[350,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.CmdMask":{aliases:[350,4,1,""],func:[350,3,1,""],help_category:[350,4,1,""],key:[350,4,1,""],lock_storage:[350,4,1,""],search_index_entry:[350,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.CmdPose":{aliases:[350,4,1,""],func:[350,3,1,""],help_category:[350,4,1,""],key:[350,4,1,""],lock_storage:[350,4,1,""],parse:[350,3,1,""],search_index_entry:[350,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.CmdRecog":{aliases:[350,4,1,""],func:[350,3,1,""],help_category:[350,4,1,""],key:[350,4,1,""],lock_storage:[350,4,1,""],parse:[350,3,1,""],search_index_entry:[350,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.CmdSay":{aliases:[350,4,1,""],arg_regex:[350,4,1,""],func:[350,3,1,""],help_category:[350,4,1,""],key:[350,4,1,""],lock_storage:[350,4,1,""],locks:[350,4,1,""],search_index_entry:[350,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.CmdSdesc":{aliases:[350,4,1,""],func:[350,3,1,""],help_category:[350,4,1,""],key:[350,4,1,""],lock_storage:[350,4,1,""],locks:[350,4,1,""],search_index_entry:[350,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.ContribRPCharacter":{DoesNotExist:[350,2,1,""],MultipleObjectsReturned:[350,2,1,""],at_object_creation:[350,3,1,""],at_pre_say:[350,3,1,""],get_display_name:[350,3,1,""],path:[350,4,1,""],process_language:[350,3,1,""],process_recog:[350,3,1,""],process_sdesc:[350,3,1,""],recog:[350,4,1,""],sdesc:[350,4,1,""],typename:[350,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.ContribRPObject":{DoesNotExist:[350,2,1,""],MultipleObjectsReturned:[350,2,1,""],at_object_creation:[350,3,1,""],get_display_name:[350,3,1,""],path:[350,4,1,""],return_appearance:[350,3,1,""],search:[350,3,1,""],typename:[350,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.ContribRPRoom":{DoesNotExist:[350,2,1,""],MultipleObjectsReturned:[350,2,1,""],path:[350,4,1,""],typename:[350,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.RPCommand":{aliases:[350,4,1,""],help_category:[350,4,1,""],key:[350,4,1,""],lock_storage:[350,4,1,""],parse:[350,3,1,""],search_index_entry:[350,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.RPSystemCmdSet":{at_cmdset_creation:[350,3,1,""],path:[350,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.RecogHandler":{__init__:[350,3,1,""],add:[350,3,1,""],all:[350,3,1,""],get:[350,3,1,""],get_regex_tuple:[350,3,1,""],remove:[350,3,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.SdescHandler":{__init__:[350,3,1,""],add:[350,3,1,""],get:[350,3,1,""],get_regex_tuple:[350,3,1,""]},"evennia.contrib.rpg.rpsystem.tests":{TestLanguage:[351,1,1,""],TestRPSystem:[351,1,1,""],TestRPSystemCommands:[351,1,1,""]},"evennia.contrib.rpg.rpsystem.tests.TestLanguage":{setUp:[351,3,1,""],tearDown:[351,3,1,""],test_available_languages:[351,3,1,""],test_faulty_language:[351,3,1,""],test_obfuscate_language:[351,3,1,""],test_obfuscate_whisper:[351,3,1,""]},"evennia.contrib.rpg.rpsystem.tests.TestRPSystem":{maxDiff:[351,4,1,""],parse_sdescs_and_recogs:[351,3,1,""],setUp:[351,3,1,""],test_ordered_permutation_regex:[351,3,1,""],test_parse_language:[351,3,1,""],test_recog_handler:[351,3,1,""],test_regex_tuple_from_key_alias:[351,3,1,""],test_rpsearch:[351,3,1,""],test_sdesc_handler:[351,3,1,""],test_send_case_sensitive_emote:[351,3,1,""],test_send_emote:[351,3,1,""]},"evennia.contrib.rpg.rpsystem.tests.TestRPSystemCommands":{setUp:[351,3,1,""],test_commands:[351,3,1,""]},"evennia.contrib.rpg.traits":{tests:[353,0,0,"-"],traits:[354,0,0,"-"]},"evennia.contrib.rpg.traits.tests":{DummyCharacter:[353,1,1,""],TestNumericTraitOperators:[353,1,1,""],TestTrait:[353,1,1,""],TestTraitCounter:[353,1,1,""],TestTraitCounterTimed:[353,1,1,""],TestTraitFields:[353,1,1,""],TestTraitGauge:[353,1,1,""],TestTraitGaugeTimed:[353,1,1,""],TestTraitStatic:[353,1,1,""],TraitHandlerTest:[353,1,1,""]},"evennia.contrib.rpg.traits.tests.DummyCharacter":{health:[353,4,1,""],hunting:[353,4,1,""],strength:[353,4,1,""]},"evennia.contrib.rpg.traits.tests.TestNumericTraitOperators":{setUp:[353,3,1,""],tearDown:[353,3,1,""],test_add_traits:[353,3,1,""],test_comparisons_numeric:[353,3,1,""],test_comparisons_traits:[353,3,1,""],test_floordiv:[353,3,1,""],test_mul_traits:[353,3,1,""],test_pos_shortcut:[353,3,1,""],test_sub_traits:[353,3,1,""]},"evennia.contrib.rpg.traits.tests.TestTrait":{setUp:[353,3,1,""],test_init:[353,3,1,""],test_repr:[353,3,1,""],test_trait_getset:[353,3,1,""],test_validate_input__fail:[353,3,1,""],test_validate_input__valid:[353,3,1,""]},"evennia.contrib.rpg.traits.tests.TestTraitCounter":{setUp:[353,3,1,""],test_boundaries__bigmod:[353,3,1,""],test_boundaries__change_boundaries:[353,3,1,""],test_boundaries__disable:[353,3,1,""],test_boundaries__inverse:[353,3,1,""],test_boundaries__minmax:[353,3,1,""],test_current:[353,3,1,""],test_delete:[353,3,1,""],test_descs:[353,3,1,""],test_init:[353,3,1,""],test_percentage:[353,3,1,""],test_value:[353,3,1,""]},"evennia.contrib.rpg.traits.tests.TestTraitCounterTimed":{setUp:[353,3,1,""],test_timer_rate:[353,3,1,""],test_timer_ratetarget:[353,3,1,""]},"evennia.contrib.rpg.traits.tests.TestTraitFields":{test_traitfields:[353,3,1,""]},"evennia.contrib.rpg.traits.tests.TestTraitGauge":{setUp:[353,3,1,""],test_boundaries__bigmod:[353,3,1,""],test_boundaries__change_boundaries:[353,3,1,""],test_boundaries__disable:[353,3,1,""],test_boundaries__inverse:[353,3,1,""],test_boundaries__minmax:[353,3,1,""],test_current:[353,3,1,""],test_delete:[353,3,1,""],test_descs:[353,3,1,""],test_init:[353,3,1,""],test_percentage:[353,3,1,""],test_value:[353,3,1,""]},"evennia.contrib.rpg.traits.tests.TestTraitGaugeTimed":{setUp:[353,3,1,""],test_timer_rate:[353,3,1,""],test_timer_ratetarget:[353,3,1,""]},"evennia.contrib.rpg.traits.tests.TestTraitStatic":{setUp:[353,3,1,""],test_delete:[353,3,1,""],test_init:[353,3,1,""],test_value:[353,3,1,""]},"evennia.contrib.rpg.traits.tests.TraitHandlerTest":{setUp:[353,3,1,""],test_add_trait:[353,3,1,""],test_all:[353,3,1,""],test_cache:[353,3,1,""],test_clear:[353,3,1,""],test_getting:[353,3,1,""],test_remove:[353,3,1,""],test_setting:[353,3,1,""],test_trait_db_connection:[353,3,1,""]},"evennia.contrib.rpg.traits.traits":{CounterTrait:[354,1,1,""],GaugeTrait:[354,1,1,""],MandatoryTraitKey:[354,1,1,""],StaticTrait:[354,1,1,""],Trait:[354,1,1,""],TraitException:[354,2,1,""],TraitHandler:[354,1,1,""],TraitProperty:[354,1,1,""]},"evennia.contrib.rpg.traits.traits.CounterTrait":{base:[354,3,1,""],current:[354,3,1,""],default_keys:[354,4,1,""],desc:[354,3,1,""],max:[354,3,1,""],min:[354,3,1,""],mod:[354,3,1,""],percent:[354,3,1,""],ratetarget:[354,3,1,""],reset:[354,3,1,""],trait_type:[354,4,1,""],validate_input:[354,3,1,""],value:[354,3,1,""]},"evennia.contrib.rpg.traits.traits.GaugeTrait":{base:[354,3,1,""],current:[354,3,1,""],default_keys:[354,4,1,""],max:[354,3,1,""],min:[354,3,1,""],mod:[354,3,1,""],percent:[354,3,1,""],reset:[354,3,1,""],trait_type:[354,4,1,""],value:[354,3,1,""]},"evennia.contrib.rpg.traits.traits.StaticTrait":{base:[354,3,1,""],default_keys:[354,4,1,""],mod:[354,3,1,""],trait_type:[354,4,1,""],value:[354,3,1,""]},"evennia.contrib.rpg.traits.traits.Trait":{__init__:[354,3,1,""],allow_extra_properties:[354,4,1,""],default_keys:[354,4,1,""],key:[354,3,1,""],name:[354,3,1,""],trait_type:[354,4,1,""],validate_input:[354,3,1,""],value:[354,3,1,""]},"evennia.contrib.rpg.traits.traits.TraitException":{__init__:[354,3,1,""]},"evennia.contrib.rpg.traits.traits.TraitHandler":{__init__:[354,3,1,""],add:[354,3,1,""],all:[354,3,1,""],clear:[354,3,1,""],get:[354,3,1,""],remove:[354,3,1,""]},"evennia.contrib.rpg.traits.traits.TraitProperty":{__init__:[354,3,1,""]},"evennia.contrib.tutorials":{batchprocessor:[356,0,0,"-"],bodyfunctions:[358,0,0,"-"],mirror:[361,0,0,"-"],red_button:[363,0,0,"-"],talking_npc:[365,0,0,"-"],tutorial_world:[368,0,0,"-"]},"evennia.contrib.tutorials.bodyfunctions":{bodyfunctions:[359,0,0,"-"],tests:[360,0,0,"-"]},"evennia.contrib.tutorials.bodyfunctions.bodyfunctions":{BodyFunctions:[359,1,1,""]},"evennia.contrib.tutorials.bodyfunctions.bodyfunctions.BodyFunctions":{DoesNotExist:[359,2,1,""],MultipleObjectsReturned:[359,2,1,""],at_repeat:[359,3,1,""],at_script_creation:[359,3,1,""],path:[359,4,1,""],send_random_message:[359,3,1,""],typename:[359,4,1,""]},"evennia.contrib.tutorials.bodyfunctions.tests":{TestBodyFunctions:[360,1,1,""]},"evennia.contrib.tutorials.bodyfunctions.tests.TestBodyFunctions":{script_typeclass:[360,4,1,""],setUp:[360,3,1,""],tearDown:[360,3,1,""],test_at_repeat:[360,3,1,""],test_send_random_message:[360,3,1,""]},"evennia.contrib.tutorials.mirror":{mirror:[362,0,0,"-"]},"evennia.contrib.tutorials.mirror.mirror":{TutorialMirror:[362,1,1,""]},"evennia.contrib.tutorials.mirror.mirror.TutorialMirror":{DoesNotExist:[362,2,1,""],MultipleObjectsReturned:[362,2,1,""],msg:[362,3,1,""],path:[362,4,1,""],return_appearance:[362,3,1,""],typename:[362,4,1,""]},"evennia.contrib.tutorials.red_button":{red_button:[364,0,0,"-"]},"evennia.contrib.tutorials.red_button.red_button":{BlindCmdSet:[364,1,1,""],CmdBlindHelp:[364,1,1,""],CmdBlindLook:[364,1,1,""],CmdCloseLid:[364,1,1,""],CmdNudge:[364,1,1,""],CmdOpenLid:[364,1,1,""],CmdPushLidClosed:[364,1,1,""],CmdPushLidOpen:[364,1,1,""],CmdSmashGlass:[364,1,1,""],LidClosedCmdSet:[364,1,1,""],LidOpenCmdSet:[364,1,1,""],RedButton:[364,1,1,""]},"evennia.contrib.tutorials.red_button.red_button.BlindCmdSet":{at_cmdset_creation:[364,3,1,""],key:[364,4,1,""],mergetype:[364,4,1,""],no_exits:[364,4,1,""],no_objs:[364,4,1,""],path:[364,4,1,""]},"evennia.contrib.tutorials.red_button.red_button.CmdBlindHelp":{aliases:[364,4,1,""],func:[364,3,1,""],help_category:[364,4,1,""],key:[364,4,1,""],lock_storage:[364,4,1,""],locks:[364,4,1,""],search_index_entry:[364,4,1,""]},"evennia.contrib.tutorials.red_button.red_button.CmdBlindLook":{aliases:[364,4,1,""],func:[364,3,1,""],help_category:[364,4,1,""],key:[364,4,1,""],lock_storage:[364,4,1,""],locks:[364,4,1,""],search_index_entry:[364,4,1,""]},"evennia.contrib.tutorials.red_button.red_button.CmdCloseLid":{aliases:[364,4,1,""],func:[364,3,1,""],help_category:[364,4,1,""],key:[364,4,1,""],lock_storage:[364,4,1,""],locks:[364,4,1,""],search_index_entry:[364,4,1,""]},"evennia.contrib.tutorials.red_button.red_button.CmdNudge":{aliases:[364,4,1,""],func:[364,3,1,""],help_category:[364,4,1,""],key:[364,4,1,""],lock_storage:[364,4,1,""],locks:[364,4,1,""],search_index_entry:[364,4,1,""]},"evennia.contrib.tutorials.red_button.red_button.CmdOpenLid":{aliases:[364,4,1,""],func:[364,3,1,""],help_category:[364,4,1,""],key:[364,4,1,""],lock_storage:[364,4,1,""],locks:[364,4,1,""],search_index_entry:[364,4,1,""]},"evennia.contrib.tutorials.red_button.red_button.CmdPushLidClosed":{aliases:[364,4,1,""],func:[364,3,1,""],help_category:[364,4,1,""],key:[364,4,1,""],lock_storage:[364,4,1,""],locks:[364,4,1,""],search_index_entry:[364,4,1,""]},"evennia.contrib.tutorials.red_button.red_button.CmdPushLidOpen":{aliases:[364,4,1,""],func:[364,3,1,""],help_category:[364,4,1,""],key:[364,4,1,""],lock_storage:[364,4,1,""],locks:[364,4,1,""],search_index_entry:[364,4,1,""]},"evennia.contrib.tutorials.red_button.red_button.CmdSmashGlass":{aliases:[364,4,1,""],func:[364,3,1,""],help_category:[364,4,1,""],key:[364,4,1,""],lock_storage:[364,4,1,""],locks:[364,4,1,""],search_index_entry:[364,4,1,""]},"evennia.contrib.tutorials.red_button.red_button.LidClosedCmdSet":{at_cmdset_creation:[364,3,1,""],key:[364,4,1,""],path:[364,4,1,""]},"evennia.contrib.tutorials.red_button.red_button.LidOpenCmdSet":{at_cmdset_creation:[364,3,1,""],key:[364,4,1,""],path:[364,4,1,""]},"evennia.contrib.tutorials.red_button.red_button.RedButton":{DoesNotExist:[364,2,1,""],MultipleObjectsReturned:[364,2,1,""],at_object_creation:[364,3,1,""],auto_close_msg:[364,4,1,""],blind_target:[364,3,1,""],blink_msgs:[364,4,1,""],break_lamp:[364,3,1,""],desc_add_lamp_broken:[364,4,1,""],desc_closed_lid:[364,4,1,""],desc_open_lid:[364,4,1,""],lamp_breaks_msg:[364,4,1,""],path:[364,4,1,""],to_closed_state:[364,3,1,""],to_open_state:[364,3,1,""],typename:[364,4,1,""]},"evennia.contrib.tutorials.talking_npc":{talking_npc:[366,0,0,"-"],tests:[367,0,0,"-"]},"evennia.contrib.tutorials.talking_npc.talking_npc":{CmdTalk:[366,1,1,""],END:[366,5,1,""],TalkingCmdSet:[366,1,1,""],TalkingNPC:[366,1,1,""],info1:[366,5,1,""],info2:[366,5,1,""],info3:[366,5,1,""],menu_start_node:[366,5,1,""]},"evennia.contrib.tutorials.talking_npc.talking_npc.CmdTalk":{aliases:[366,4,1,""],func:[366,3,1,""],help_category:[366,4,1,""],key:[366,4,1,""],lock_storage:[366,4,1,""],locks:[366,4,1,""],search_index_entry:[366,4,1,""]},"evennia.contrib.tutorials.talking_npc.talking_npc.TalkingCmdSet":{at_cmdset_creation:[366,3,1,""],key:[366,4,1,""],path:[366,4,1,""]},"evennia.contrib.tutorials.talking_npc.talking_npc.TalkingNPC":{DoesNotExist:[366,2,1,""],MultipleObjectsReturned:[366,2,1,""],at_object_creation:[366,3,1,""],path:[366,4,1,""],typename:[366,4,1,""]},"evennia.contrib.tutorials.talking_npc.tests":{TestTalkingNPC:[367,1,1,""]},"evennia.contrib.tutorials.talking_npc.tests.TestTalkingNPC":{test_talkingnpc:[367,3,1,""]},"evennia.contrib.tutorials.tutorial_world":{intro_menu:[369,0,0,"-"],mob:[370,0,0,"-"],objects:[371,0,0,"-"],rooms:[372,0,0,"-"],tests:[373,0,0,"-"]},"evennia.contrib.tutorials.tutorial_world.intro_menu":{DemoCommandSetComms:[369,1,1,""],DemoCommandSetHelp:[369,1,1,""],DemoCommandSetRoom:[369,1,1,""],TutorialEvMenu:[369,1,1,""],do_nothing:[369,5,1,""],goto_cleanup_cmdsets:[369,5,1,""],goto_command_demo_comms:[369,5,1,""],goto_command_demo_help:[369,5,1,""],goto_command_demo_room:[369,5,1,""],init_menu:[369,5,1,""],send_testing_tagged:[369,5,1,""]},"evennia.contrib.tutorials.tutorial_world.intro_menu.DemoCommandSetComms":{at_cmdset_creation:[369,3,1,""],key:[369,4,1,""],no_exits:[369,4,1,""],no_objs:[369,4,1,""],path:[369,4,1,""],priority:[369,4,1,""]},"evennia.contrib.tutorials.tutorial_world.intro_menu.DemoCommandSetHelp":{at_cmdset_creation:[369,3,1,""],key:[369,4,1,""],path:[369,4,1,""],priority:[369,4,1,""]},"evennia.contrib.tutorials.tutorial_world.intro_menu.DemoCommandSetRoom":{at_cmdset_creation:[369,3,1,""],key:[369,4,1,""],no_exits:[369,4,1,""],no_objs:[369,4,1,""],path:[369,4,1,""],priority:[369,4,1,""]},"evennia.contrib.tutorials.tutorial_world.intro_menu.TutorialEvMenu":{close_menu:[369,3,1,""],options_formatter:[369,3,1,""]},"evennia.contrib.tutorials.tutorial_world.mob":{CmdMobOnOff:[370,1,1,""],Mob:[370,1,1,""],MobCmdSet:[370,1,1,""]},"evennia.contrib.tutorials.tutorial_world.mob.CmdMobOnOff":{aliases:[370,4,1,""],func:[370,3,1,""],help_category:[370,4,1,""],key:[370,4,1,""],lock_storage:[370,4,1,""],locks:[370,4,1,""],search_index_entry:[370,4,1,""]},"evennia.contrib.tutorials.tutorial_world.mob.Mob":{DoesNotExist:[370,2,1,""],MultipleObjectsReturned:[370,2,1,""],at_hit:[370,3,1,""],at_init:[370,3,1,""],at_new_arrival:[370,3,1,""],at_object_creation:[370,3,1,""],do_attack:[370,3,1,""],do_hunting:[370,3,1,""],do_patrol:[370,3,1,""],path:[370,4,1,""],set_alive:[370,3,1,""],set_dead:[370,3,1,""],start_attacking:[370,3,1,""],start_hunting:[370,3,1,""],start_idle:[370,3,1,""],start_patrolling:[370,3,1,""],typename:[370,4,1,""]},"evennia.contrib.tutorials.tutorial_world.mob.MobCmdSet":{at_cmdset_creation:[370,3,1,""],path:[370,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects":{CmdAttack:[371,1,1,""],CmdClimb:[371,1,1,""],CmdGetWeapon:[371,1,1,""],CmdLight:[371,1,1,""],CmdPressButton:[371,1,1,""],CmdRead:[371,1,1,""],CmdSetClimbable:[371,1,1,""],CmdSetCrumblingWall:[371,1,1,""],CmdSetLight:[371,1,1,""],CmdSetReadable:[371,1,1,""],CmdSetWeapon:[371,1,1,""],CmdSetWeaponRack:[371,1,1,""],CmdShiftRoot:[371,1,1,""],CrumblingWall:[371,1,1,""],LightSource:[371,1,1,""],Obelisk:[371,1,1,""],TutorialClimbable:[371,1,1,""],TutorialObject:[371,1,1,""],TutorialReadable:[371,1,1,""],TutorialWeapon:[371,1,1,""],TutorialWeaponRack:[371,1,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdAttack":{aliases:[371,4,1,""],func:[371,3,1,""],help_category:[371,4,1,""],key:[371,4,1,""],lock_storage:[371,4,1,""],locks:[371,4,1,""],search_index_entry:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdClimb":{aliases:[371,4,1,""],func:[371,3,1,""],help_category:[371,4,1,""],key:[371,4,1,""],lock_storage:[371,4,1,""],locks:[371,4,1,""],search_index_entry:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdGetWeapon":{aliases:[371,4,1,""],func:[371,3,1,""],help_category:[371,4,1,""],key:[371,4,1,""],lock_storage:[371,4,1,""],locks:[371,4,1,""],search_index_entry:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdLight":{aliases:[371,4,1,""],func:[371,3,1,""],help_category:[371,4,1,""],key:[371,4,1,""],lock_storage:[371,4,1,""],locks:[371,4,1,""],search_index_entry:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdPressButton":{aliases:[371,4,1,""],func:[371,3,1,""],help_category:[371,4,1,""],key:[371,4,1,""],lock_storage:[371,4,1,""],locks:[371,4,1,""],search_index_entry:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdRead":{aliases:[371,4,1,""],func:[371,3,1,""],help_category:[371,4,1,""],key:[371,4,1,""],lock_storage:[371,4,1,""],locks:[371,4,1,""],search_index_entry:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdSetClimbable":{at_cmdset_creation:[371,3,1,""],path:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdSetCrumblingWall":{at_cmdset_creation:[371,3,1,""],key:[371,4,1,""],path:[371,4,1,""],priority:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdSetLight":{at_cmdset_creation:[371,3,1,""],key:[371,4,1,""],path:[371,4,1,""],priority:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdSetReadable":{at_cmdset_creation:[371,3,1,""],path:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdSetWeapon":{at_cmdset_creation:[371,3,1,""],path:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdSetWeaponRack":{at_cmdset_creation:[371,3,1,""],key:[371,4,1,""],path:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdShiftRoot":{aliases:[371,4,1,""],func:[371,3,1,""],help_category:[371,4,1,""],key:[371,4,1,""],lock_storage:[371,4,1,""],locks:[371,4,1,""],parse:[371,3,1,""],search_index_entry:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CrumblingWall":{DoesNotExist:[371,2,1,""],MultipleObjectsReturned:[371,2,1,""],at_failed_traverse:[371,3,1,""],at_init:[371,3,1,""],at_object_creation:[371,3,1,""],at_post_traverse:[371,3,1,""],open_wall:[371,3,1,""],path:[371,4,1,""],reset:[371,3,1,""],return_appearance:[371,3,1,""],typename:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.LightSource":{DoesNotExist:[371,2,1,""],MultipleObjectsReturned:[371,2,1,""],at_init:[371,3,1,""],at_object_creation:[371,3,1,""],light:[371,3,1,""],path:[371,4,1,""],typename:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.Obelisk":{DoesNotExist:[371,2,1,""],MultipleObjectsReturned:[371,2,1,""],at_object_creation:[371,3,1,""],path:[371,4,1,""],return_appearance:[371,3,1,""],typename:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.TutorialClimbable":{DoesNotExist:[371,2,1,""],MultipleObjectsReturned:[371,2,1,""],at_object_creation:[371,3,1,""],path:[371,4,1,""],typename:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.TutorialObject":{DoesNotExist:[371,2,1,""],MultipleObjectsReturned:[371,2,1,""],at_object_creation:[371,3,1,""],path:[371,4,1,""],reset:[371,3,1,""],typename:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.TutorialReadable":{DoesNotExist:[371,2,1,""],MultipleObjectsReturned:[371,2,1,""],at_object_creation:[371,3,1,""],path:[371,4,1,""],typename:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.TutorialWeapon":{DoesNotExist:[371,2,1,""],MultipleObjectsReturned:[371,2,1,""],at_object_creation:[371,3,1,""],path:[371,4,1,""],reset:[371,3,1,""],typename:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.TutorialWeaponRack":{DoesNotExist:[371,2,1,""],MultipleObjectsReturned:[371,2,1,""],at_object_creation:[371,3,1,""],path:[371,4,1,""],produce_weapon:[371,3,1,""],typename:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms":{BridgeCmdSet:[372,1,1,""],BridgeRoom:[372,1,1,""],CmdBridgeHelp:[372,1,1,""],CmdDarkHelp:[372,1,1,""],CmdDarkNoMatch:[372,1,1,""],CmdEast:[372,1,1,""],CmdEvenniaIntro:[372,1,1,""],CmdLookBridge:[372,1,1,""],CmdLookDark:[372,1,1,""],CmdSetEvenniaIntro:[372,1,1,""],CmdTutorial:[372,1,1,""],CmdTutorialGiveUp:[372,1,1,""],CmdTutorialLook:[372,1,1,""],CmdTutorialSetDetail:[372,1,1,""],CmdWest:[372,1,1,""],DarkCmdSet:[372,1,1,""],DarkRoom:[372,1,1,""],IntroRoom:[372,1,1,""],OutroRoom:[372,1,1,""],TeleportRoom:[372,1,1,""],TutorialRoom:[372,1,1,""],TutorialRoomCmdSet:[372,1,1,""],WeatherRoom:[372,1,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.BridgeCmdSet":{at_cmdset_creation:[372,3,1,""],key:[372,4,1,""],path:[372,4,1,""],priority:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.BridgeRoom":{DoesNotExist:[372,2,1,""],MultipleObjectsReturned:[372,2,1,""],at_object_creation:[372,3,1,""],at_object_leave:[372,3,1,""],at_object_receive:[372,3,1,""],path:[372,4,1,""],typename:[372,4,1,""],update_weather:[372,3,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdBridgeHelp":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],locks:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdDarkHelp":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],locks:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdDarkNoMatch":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],locks:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdEast":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],locks:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdEvenniaIntro":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdLookBridge":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],locks:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdLookDark":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],locks:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdSetEvenniaIntro":{at_cmdset_creation:[372,3,1,""],key:[372,4,1,""],path:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdTutorial":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],locks:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdTutorialGiveUp":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdTutorialLook":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdTutorialSetDetail":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],locks:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdWest":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],locks:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.DarkCmdSet":{at_cmdset_creation:[372,3,1,""],key:[372,4,1,""],mergetype:[372,4,1,""],path:[372,4,1,""],priority:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.DarkRoom":{DoesNotExist:[372,2,1,""],MultipleObjectsReturned:[372,2,1,""],at_init:[372,3,1,""],at_object_creation:[372,3,1,""],at_object_leave:[372,3,1,""],at_object_receive:[372,3,1,""],check_light_state:[372,3,1,""],path:[372,4,1,""],typename:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.IntroRoom":{DoesNotExist:[372,2,1,""],MultipleObjectsReturned:[372,2,1,""],at_object_creation:[372,3,1,""],at_object_receive:[372,3,1,""],path:[372,4,1,""],typename:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.OutroRoom":{DoesNotExist:[372,2,1,""],MultipleObjectsReturned:[372,2,1,""],at_object_creation:[372,3,1,""],at_object_leave:[372,3,1,""],at_object_receive:[372,3,1,""],path:[372,4,1,""],typename:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.TeleportRoom":{DoesNotExist:[372,2,1,""],MultipleObjectsReturned:[372,2,1,""],at_object_creation:[372,3,1,""],at_object_receive:[372,3,1,""],path:[372,4,1,""],typename:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.TutorialRoom":{DoesNotExist:[372,2,1,""],MultipleObjectsReturned:[372,2,1,""],at_object_creation:[372,3,1,""],at_object_receive:[372,3,1,""],path:[372,4,1,""],return_detail:[372,3,1,""],set_detail:[372,3,1,""],typename:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.TutorialRoomCmdSet":{at_cmdset_creation:[372,3,1,""],key:[372,4,1,""],path:[372,4,1,""],priority:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.WeatherRoom":{DoesNotExist:[372,2,1,""],MultipleObjectsReturned:[372,2,1,""],at_object_creation:[372,3,1,""],path:[372,4,1,""],typename:[372,4,1,""],update_weather:[372,3,1,""]},"evennia.contrib.tutorials.tutorial_world.tests":{TestTutorialWorldMob:[373,1,1,""],TestTutorialWorldObjects:[373,1,1,""],TestTutorialWorldRooms:[373,1,1,""]},"evennia.contrib.tutorials.tutorial_world.tests.TestTutorialWorldMob":{test_mob:[373,3,1,""]},"evennia.contrib.tutorials.tutorial_world.tests.TestTutorialWorldObjects":{test_climbable:[373,3,1,""],test_crumblingwall:[373,3,1,""],test_lightsource:[373,3,1,""],test_obelisk:[373,3,1,""],test_readable:[373,3,1,""],test_tutorialobj:[373,3,1,""],test_weapon:[373,3,1,""],test_weaponrack:[373,3,1,""]},"evennia.contrib.tutorials.tutorial_world.tests.TestTutorialWorldRooms":{test_bridgeroom:[373,3,1,""],test_cmdtutorial:[373,3,1,""],test_darkroom:[373,3,1,""],test_introroom:[373,3,1,""],test_outroroom:[373,3,1,""],test_teleportroom:[373,3,1,""],test_weatherroom:[373,3,1,""]},"evennia.contrib.utils":{auditing:[375,0,0,"-"],fieldfill:[379,0,0,"-"],random_string_generator:[381,0,0,"-"],tree_select:[384,0,0,"-"]},"evennia.contrib.utils.auditing":{outputs:[376,0,0,"-"],server:[377,0,0,"-"],tests:[378,0,0,"-"]},"evennia.contrib.utils.auditing.outputs":{to_file:[376,5,1,""],to_syslog:[376,5,1,""]},"evennia.contrib.utils.auditing.server":{AuditedServerSession:[377,1,1,""]},"evennia.contrib.utils.auditing.server.AuditedServerSession":{audit:[377,3,1,""],data_in:[377,3,1,""],data_out:[377,3,1,""],mask:[377,3,1,""]},"evennia.contrib.utils.auditing.tests":{AuditingTest:[378,1,1,""]},"evennia.contrib.utils.auditing.tests.AuditingTest":{setup_session:[378,3,1,""],test_audit:[378,3,1,""],test_mask:[378,3,1,""]},"evennia.contrib.utils.fieldfill":{fieldfill:[380,0,0,"-"]},"evennia.contrib.utils.fieldfill.fieldfill":{CmdTestMenu:[380,1,1,""],FieldEvMenu:[380,1,1,""],display_formdata:[380,5,1,""],form_template_to_dict:[380,5,1,""],init_delayed_message:[380,5,1,""],init_fill_field:[380,5,1,""],menunode_fieldfill:[380,5,1,""],sendmessage:[380,5,1,""],verify_online_player:[380,5,1,""]},"evennia.contrib.utils.fieldfill.fieldfill.CmdTestMenu":{aliases:[380,4,1,""],func:[380,3,1,""],help_category:[380,4,1,""],key:[380,4,1,""],lock_storage:[380,4,1,""],search_index_entry:[380,4,1,""]},"evennia.contrib.utils.fieldfill.fieldfill.FieldEvMenu":{node_formatter:[380,3,1,""]},"evennia.contrib.utils.random_string_generator":{random_string_generator:[382,0,0,"-"],tests:[383,0,0,"-"]},"evennia.contrib.utils.random_string_generator.random_string_generator":{ExhaustedGenerator:[382,2,1,""],RandomStringGenerator:[382,1,1,""],RandomStringGeneratorScript:[382,1,1,""],RejectedRegex:[382,2,1,""]},"evennia.contrib.utils.random_string_generator.random_string_generator.RandomStringGenerator":{__init__:[382,3,1,""],all:[382,3,1,""],clear:[382,3,1,""],get:[382,3,1,""],remove:[382,3,1,""],script:[382,4,1,""]},"evennia.contrib.utils.random_string_generator.random_string_generator.RandomStringGeneratorScript":{DoesNotExist:[382,2,1,""],MultipleObjectsReturned:[382,2,1,""],at_script_creation:[382,3,1,""],path:[382,4,1,""],typename:[382,4,1,""]},"evennia.contrib.utils.random_string_generator.tests":{TestRandomStringGenerator:[383,1,1,""]},"evennia.contrib.utils.random_string_generator.tests.TestRandomStringGenerator":{test_generate:[383,3,1,""]},"evennia.contrib.utils.tree_select":{tests:[385,0,0,"-"],tree_select:[386,0,0,"-"]},"evennia.contrib.utils.tree_select.tests":{TestFieldFillFunc:[385,1,1,""],TestTreeSelectFunc:[385,1,1,""]},"evennia.contrib.utils.tree_select.tests.TestFieldFillFunc":{test_field_functions:[385,3,1,""]},"evennia.contrib.utils.tree_select.tests.TestTreeSelectFunc":{test_tree_functions:[385,3,1,""]},"evennia.contrib.utils.tree_select.tree_select":{CmdNameColor:[386,1,1,""],change_name_color:[386,5,1,""],dashcount:[386,5,1,""],go_up_one_category:[386,5,1,""],index_to_selection:[386,5,1,""],init_tree_selection:[386,5,1,""],is_category:[386,5,1,""],menunode_treeselect:[386,5,1,""],optlist_to_menuoptions:[386,5,1,""],parse_opts:[386,5,1,""]},"evennia.contrib.utils.tree_select.tree_select.CmdNameColor":{aliases:[386,4,1,""],func:[386,3,1,""],help_category:[386,4,1,""],key:[386,4,1,""],lock_storage:[386,4,1,""],search_index_entry:[386,4,1,""]},"evennia.help":{filehelp:[388,0,0,"-"],manager:[389,0,0,"-"],models:[390,0,0,"-"],utils:[391,0,0,"-"]},"evennia.help.filehelp":{FileHelpEntry:[388,1,1,""],FileHelpStorageHandler:[388,1,1,""]},"evennia.help.filehelp.FileHelpEntry":{__init__:[388,3,1,""],access:[388,3,1,""],aliases:[388,4,1,""],entrytext:[388,4,1,""],help_category:[388,4,1,""],key:[388,4,1,""],lock_storage:[388,4,1,""],locks:[388,4,1,""],search_index_entry:[388,3,1,""],web_get_admin_url:[388,3,1,""],web_get_detail_url:[388,3,1,""]},"evennia.help.filehelp.FileHelpStorageHandler":{__init__:[388,3,1,""],all:[388,3,1,""],load:[388,3,1,""]},"evennia.help.manager":{HelpEntryManager:[389,1,1,""]},"evennia.help.manager.HelpEntryManager":{all_to_category:[389,3,1,""],create_help:[389,3,1,""],find_apropos:[389,3,1,""],find_topicmatch:[389,3,1,""],find_topics_with_category:[389,3,1,""],find_topicsuggestions:[389,3,1,""],get_all_categories:[389,3,1,""],get_all_topics:[389,3,1,""],search_help:[389,3,1,""]},"evennia.help.models":{HelpEntry:[390,1,1,""]},"evennia.help.models.HelpEntry":{DoesNotExist:[390,2,1,""],MultipleObjectsReturned:[390,2,1,""],access:[390,3,1,""],aliases:[390,4,1,""],date_created:[390,3,1,""],db_date_created:[390,4,1,""],db_entrytext:[390,4,1,""],db_help_category:[390,4,1,""],db_key:[390,4,1,""],db_lock_storage:[390,4,1,""],db_tags:[390,4,1,""],entrytext:[390,3,1,""],get_absolute_url:[390,3,1,""],get_next_by_db_date_created:[390,3,1,""],get_previous_by_db_date_created:[390,3,1,""],help_category:[390,3,1,""],id:[390,4,1,""],key:[390,3,1,""],lock_storage:[390,3,1,""],locks:[390,4,1,""],objects:[390,4,1,""],path:[390,4,1,""],search_index_entry:[390,3,1,""],tags:[390,4,1,""],typename:[390,4,1,""],web_get_admin_url:[390,3,1,""],web_get_create_url:[390,3,1,""],web_get_delete_url:[390,3,1,""],web_get_detail_url:[390,3,1,""],web_get_update_url:[390,3,1,""]},"evennia.help.utils":{help_search_with_index:[391,5,1,""],parse_entry_for_subcategories:[391,5,1,""]},"evennia.locks":{lockfuncs:[393,0,0,"-"],lockhandler:[394,0,0,"-"]},"evennia.locks.lockfuncs":{"false":[393,5,1,""],"true":[393,5,1,""],all:[393,5,1,""],attr:[393,5,1,""],attr_eq:[393,5,1,""],attr_ge:[393,5,1,""],attr_gt:[393,5,1,""],attr_le:[393,5,1,""],attr_lt:[393,5,1,""],attr_ne:[393,5,1,""],dbref:[393,5,1,""],has_account:[393,5,1,""],holds:[393,5,1,""],id:[393,5,1,""],inside:[393,5,1,""],inside_rec:[393,5,1,""],locattr:[393,5,1,""],none:[393,5,1,""],objattr:[393,5,1,""],objlocattr:[393,5,1,""],objtag:[393,5,1,""],pdbref:[393,5,1,""],perm:[393,5,1,""],perm_above:[393,5,1,""],pid:[393,5,1,""],pperm:[393,5,1,""],pperm_above:[393,5,1,""],self:[393,5,1,""],serversetting:[393,5,1,""],superuser:[393,5,1,""],tag:[393,5,1,""]},"evennia.locks.lockhandler":{LockException:[394,2,1,""],LockHandler:[394,1,1,""]},"evennia.locks.lockhandler.LockHandler":{"delete":[394,3,1,""],__init__:[394,3,1,""],add:[394,3,1,""],all:[394,3,1,""],append:[394,3,1,""],cache_lock_bypass:[394,3,1,""],check:[394,3,1,""],check_lockstring:[394,3,1,""],clear:[394,3,1,""],get:[394,3,1,""],remove:[394,3,1,""],replace:[394,3,1,""],reset:[394,3,1,""],validate:[394,3,1,""]},"evennia.objects":{manager:[396,0,0,"-"],models:[397,0,0,"-"],objects:[398,0,0,"-"]},"evennia.objects.manager":{ObjectDBManager:[396,1,1,""],ObjectManager:[396,1,1,""]},"evennia.objects.manager.ObjectDBManager":{clear_all_sessids:[396,3,1,""],copy_object:[396,3,1,""],create_object:[396,3,1,""],get_contents:[396,3,1,""],get_object_with_account:[396,3,1,""],get_objs_with_attr:[396,3,1,""],get_objs_with_attr_value:[396,3,1,""],get_objs_with_db_property:[396,3,1,""],get_objs_with_db_property_value:[396,3,1,""],get_objs_with_key_and_typeclass:[396,3,1,""],get_objs_with_key_or_alias:[396,3,1,""],object_search:[396,3,1,""],search:[396,3,1,""],search_object:[396,3,1,""]},"evennia.objects.models":{ContentsHandler:[397,1,1,""],ObjectDB:[397,1,1,""]},"evennia.objects.models.ContentsHandler":{__init__:[397,3,1,""],add:[397,3,1,""],clear:[397,3,1,""],get:[397,3,1,""],init:[397,3,1,""],load:[397,3,1,""],remove:[397,3,1,""]},"evennia.objects.models.ObjectDB":{DoesNotExist:[397,2,1,""],MultipleObjectsReturned:[397,2,1,""],account:[397,3,1,""],at_db_location_postsave:[397,3,1,""],cmdset_storage:[397,3,1,""],contents_cache:[397,4,1,""],db_account:[397,4,1,""],db_account_id:[397,4,1,""],db_attributes:[397,4,1,""],db_cmdset_storage:[397,4,1,""],db_destination:[397,4,1,""],db_destination_id:[397,4,1,""],db_home:[397,4,1,""],db_home_id:[397,4,1,""],db_location:[397,4,1,""],db_location_id:[397,4,1,""],db_sessid:[397,4,1,""],db_tags:[397,4,1,""],destination:[397,3,1,""],destinations_set:[397,4,1,""],get_next_by_db_date_created:[397,3,1,""],get_previous_by_db_date_created:[397,3,1,""],hide_from_objects_set:[397,4,1,""],home:[397,3,1,""],homes_set:[397,4,1,""],id:[397,4,1,""],location:[397,3,1,""],locations_set:[397,4,1,""],object_subscription_set:[397,4,1,""],objects:[397,4,1,""],path:[397,4,1,""],receiver_object_set:[397,4,1,""],scriptdb_set:[397,4,1,""],sender_object_set:[397,4,1,""],sessid:[397,3,1,""],typename:[397,4,1,""]},"evennia.objects.objects":{DefaultCharacter:[398,1,1,""],DefaultExit:[398,1,1,""],DefaultObject:[398,1,1,""],DefaultRoom:[398,1,1,""],ExitCommand:[398,1,1,""],ObjectSessionHandler:[398,1,1,""]},"evennia.objects.objects.DefaultCharacter":{DoesNotExist:[398,2,1,""],MultipleObjectsReturned:[398,2,1,""],at_after_move:[398,3,1,""],at_post_move:[398,3,1,""],at_post_puppet:[398,3,1,""],at_post_unpuppet:[398,3,1,""],at_pre_puppet:[398,3,1,""],basetype_setup:[398,3,1,""],connection_time:[398,3,1,""],create:[398,3,1,""],idle_time:[398,3,1,""],lockstring:[398,4,1,""],normalize_name:[398,3,1,""],path:[398,4,1,""],typename:[398,4,1,""],validate_name:[398,3,1,""]},"evennia.objects.objects.DefaultExit":{DoesNotExist:[398,2,1,""],MultipleObjectsReturned:[398,2,1,""],at_cmdset_get:[398,3,1,""],at_failed_traverse:[398,3,1,""],at_init:[398,3,1,""],at_traverse:[398,3,1,""],basetype_setup:[398,3,1,""],create:[398,3,1,""],create_exit_cmdset:[398,3,1,""],exit_command:[398,4,1,""],lockstring:[398,4,1,""],path:[398,4,1,""],priority:[398,4,1,""],typename:[398,4,1,""]},"evennia.objects.objects.DefaultObject":{"delete":[398,3,1,""],DoesNotExist:[398,2,1,""],MultipleObjectsReturned:[398,2,1,""],access:[398,3,1,""],announce_move_from:[398,3,1,""],announce_move_to:[398,3,1,""],appearance_template:[398,4,1,""],at_access:[398,3,1,""],at_after_move:[398,3,1,""],at_after_traverse:[398,3,1,""],at_before_drop:[398,3,1,""],at_before_get:[398,3,1,""],at_before_give:[398,3,1,""],at_before_move:[398,3,1,""],at_before_say:[398,3,1,""],at_cmdset_get:[398,3,1,""],at_desc:[398,3,1,""],at_drop:[398,3,1,""],at_failed_traverse:[398,3,1,""],at_first_save:[398,3,1,""],at_get:[398,3,1,""],at_give:[398,3,1,""],at_init:[398,3,1,""],at_look:[398,3,1,""],at_msg_receive:[398,3,1,""],at_msg_send:[398,3,1,""],at_object_creation:[398,3,1,""],at_object_delete:[398,3,1,""],at_object_leave:[398,3,1,""],at_object_post_copy:[398,3,1,""],at_object_receive:[398,3,1,""],at_post_move:[398,3,1,""],at_post_puppet:[398,3,1,""],at_post_traverse:[398,3,1,""],at_post_unpuppet:[398,3,1,""],at_pre_drop:[398,3,1,""],at_pre_get:[398,3,1,""],at_pre_give:[398,3,1,""],at_pre_move:[398,3,1,""],at_pre_puppet:[398,3,1,""],at_pre_say:[398,3,1,""],at_pre_unpuppet:[398,3,1,""],at_say:[398,3,1,""],at_server_reload:[398,3,1,""],at_server_shutdown:[398,3,1,""],at_traverse:[398,3,1,""],basetype_posthook_setup:[398,3,1,""],basetype_setup:[398,3,1,""],clear_contents:[398,3,1,""],clear_exits:[398,3,1,""],cmdset:[398,4,1,""],contents:[398,3,1,""],contents_get:[398,3,1,""],contents_set:[398,3,1,""],copy:[398,3,1,""],create:[398,3,1,""],execute_cmd:[398,3,1,""],exits:[398,3,1,""],for_contents:[398,3,1,""],get_content_names:[398,3,1,""],get_display_name:[398,3,1,""],get_numbered_name:[398,3,1,""],get_visible_contents:[398,3,1,""],has_account:[398,3,1,""],is_connected:[398,3,1,""],is_superuser:[398,3,1,""],lockstring:[398,4,1,""],move_to:[398,3,1,""],msg:[398,3,1,""],msg_contents:[398,3,1,""],nicks:[398,4,1,""],objects:[398,4,1,""],path:[398,4,1,""],return_appearance:[398,3,1,""],scripts:[398,4,1,""],search:[398,3,1,""],search_account:[398,3,1,""],sessions:[398,4,1,""],typename:[398,4,1,""]},"evennia.objects.objects.DefaultRoom":{DoesNotExist:[398,2,1,""],MultipleObjectsReturned:[398,2,1,""],basetype_setup:[398,3,1,""],create:[398,3,1,""],lockstring:[398,4,1,""],path:[398,4,1,""],typename:[398,4,1,""]},"evennia.objects.objects.ExitCommand":{aliases:[398,4,1,""],func:[398,3,1,""],get_extra_info:[398,3,1,""],help_category:[398,4,1,""],key:[398,4,1,""],lock_storage:[398,4,1,""],obj:[398,4,1,""],search_index_entry:[398,4,1,""]},"evennia.objects.objects.ObjectSessionHandler":{__init__:[398,3,1,""],add:[398,3,1,""],all:[398,3,1,""],clear:[398,3,1,""],count:[398,3,1,""],get:[398,3,1,""],remove:[398,3,1,""]},"evennia.prototypes":{menus:[400,0,0,"-"],protfuncs:[401,0,0,"-"],prototypes:[402,0,0,"-"],spawner:[403,0,0,"-"]},"evennia.prototypes.menus":{OLCMenu:[400,1,1,""],node_apply_diff:[400,5,1,""],node_destination:[400,5,1,""],node_examine_entity:[400,5,1,""],node_home:[400,5,1,""],node_index:[400,5,1,""],node_key:[400,5,1,""],node_location:[400,5,1,""],node_prototype_desc:[400,5,1,""],node_prototype_key:[400,5,1,""],node_prototype_save:[400,5,1,""],node_prototype_spawn:[400,5,1,""],node_validate_prototype:[400,5,1,""],start_olc:[400,5,1,""]},"evennia.prototypes.menus.OLCMenu":{display_helptext:[400,3,1,""],helptext_formatter:[400,3,1,""],nodetext_formatter:[400,3,1,""],options_formatter:[400,3,1,""]},"evennia.prototypes.protfuncs":{protfunc_callable_protkey:[401,5,1,""]},"evennia.prototypes.prototypes":{DbPrototype:[402,1,1,""],PermissionError:[402,2,1,""],PrototypeEvMore:[402,1,1,""],ValidationError:[402,2,1,""],check_permission:[402,5,1,""],create_prototype:[402,5,1,""],delete_prototype:[402,5,1,""],format_available_protfuncs:[402,5,1,""],homogenize_prototype:[402,5,1,""],init_spawn_value:[402,5,1,""],list_prototypes:[402,5,1,""],load_module_prototypes:[402,5,1,""],protfunc_parser:[402,5,1,""],prototype_to_str:[402,5,1,""],save_prototype:[402,5,1,""],search_objects_with_prototype:[402,5,1,""],search_prototype:[402,5,1,""],validate_prototype:[402,5,1,""],value_to_obj:[402,5,1,""],value_to_obj_or_any:[402,5,1,""]},"evennia.prototypes.prototypes.DbPrototype":{DoesNotExist:[402,2,1,""],MultipleObjectsReturned:[402,2,1,""],at_script_creation:[402,3,1,""],path:[402,4,1,""],prototype:[402,3,1,""],typename:[402,4,1,""]},"evennia.prototypes.prototypes.PrototypeEvMore":{__init__:[402,3,1,""],init_pages:[402,3,1,""],page_formatter:[402,3,1,""],prototype_paginator:[402,3,1,""]},"evennia.prototypes.spawner":{Unset:[403,1,1,""],batch_create_object:[403,5,1,""],batch_update_objects_with_prototype:[403,5,1,""],flatten_diff:[403,5,1,""],flatten_prototype:[403,5,1,""],format_diff:[403,5,1,""],prototype_diff:[403,5,1,""],prototype_diff_from_object:[403,5,1,""],prototype_from_object:[403,5,1,""],spawn:[403,5,1,""]},"evennia.scripts":{manager:[405,0,0,"-"],models:[406,0,0,"-"],monitorhandler:[407,0,0,"-"],scripthandler:[408,0,0,"-"],scripts:[409,0,0,"-"],taskhandler:[410,0,0,"-"],tickerhandler:[411,0,0,"-"]},"evennia.scripts.manager":{ScriptDBManager:[405,1,1,""],ScriptManager:[405,1,1,""]},"evennia.scripts.manager.ScriptDBManager":{copy_script:[405,3,1,""],create_script:[405,3,1,""],delete_script:[405,3,1,""],get_all_scripts:[405,3,1,""],get_all_scripts_on_obj:[405,3,1,""],script_search:[405,3,1,""],search_script:[405,3,1,""],update_scripts_after_server_start:[405,3,1,""]},"evennia.scripts.models":{ScriptDB:[406,1,1,""]},"evennia.scripts.models.ScriptDB":{DoesNotExist:[406,2,1,""],MultipleObjectsReturned:[406,2,1,""],account:[406,3,1,""],db_account:[406,4,1,""],db_account_id:[406,4,1,""],db_attributes:[406,4,1,""],db_desc:[406,4,1,""],db_interval:[406,4,1,""],db_is_active:[406,4,1,""],db_obj:[406,4,1,""],db_obj_id:[406,4,1,""],db_persistent:[406,4,1,""],db_repeats:[406,4,1,""],db_start_delay:[406,4,1,""],db_tags:[406,4,1,""],desc:[406,3,1,""],get_next_by_db_date_created:[406,3,1,""],get_previous_by_db_date_created:[406,3,1,""],id:[406,4,1,""],interval:[406,3,1,""],is_active:[406,3,1,""],obj:[406,3,1,""],object:[406,3,1,""],objects:[406,4,1,""],path:[406,4,1,""],persistent:[406,3,1,""],receiver_script_set:[406,4,1,""],repeats:[406,3,1,""],sender_script_set:[406,4,1,""],start_delay:[406,3,1,""],typename:[406,4,1,""]},"evennia.scripts.monitorhandler":{MonitorHandler:[407,1,1,""]},"evennia.scripts.monitorhandler.MonitorHandler":{__init__:[407,3,1,""],add:[407,3,1,""],all:[407,3,1,""],at_update:[407,3,1,""],clear:[407,3,1,""],remove:[407,3,1,""],restore:[407,3,1,""],save:[407,3,1,""]},"evennia.scripts.scripthandler":{ScriptHandler:[408,1,1,""]},"evennia.scripts.scripthandler.ScriptHandler":{"delete":[408,3,1,""],__init__:[408,3,1,""],add:[408,3,1,""],all:[408,3,1,""],get:[408,3,1,""],start:[408,3,1,""],stop:[408,3,1,""]},"evennia.scripts.scripts":{DefaultScript:[409,1,1,""],DoNothing:[409,1,1,""],Store:[409,1,1,""]},"evennia.scripts.scripts.DefaultScript":{DoesNotExist:[409,2,1,""],MultipleObjectsReturned:[409,2,1,""],at_pause:[409,3,1,""],at_repeat:[409,3,1,""],at_script_creation:[409,3,1,""],at_script_delete:[409,3,1,""],at_server_reload:[409,3,1,""],at_server_shutdown:[409,3,1,""],at_server_start:[409,3,1,""],at_start:[409,3,1,""],at_stop:[409,3,1,""],create:[409,3,1,""],is_valid:[409,3,1,""],path:[409,4,1,""],typename:[409,4,1,""]},"evennia.scripts.scripts.DoNothing":{DoesNotExist:[409,2,1,""],MultipleObjectsReturned:[409,2,1,""],at_script_creation:[409,3,1,""],path:[409,4,1,""],typename:[409,4,1,""]},"evennia.scripts.scripts.Store":{DoesNotExist:[409,2,1,""],MultipleObjectsReturned:[409,2,1,""],at_script_creation:[409,3,1,""],path:[409,4,1,""],typename:[409,4,1,""]},"evennia.scripts.taskhandler":{TaskHandler:[410,1,1,""],TaskHandlerTask:[410,1,1,""],handle_error:[410,5,1,""]},"evennia.scripts.taskhandler.TaskHandler":{__init__:[410,3,1,""],active:[410,3,1,""],add:[410,3,1,""],call_task:[410,3,1,""],cancel:[410,3,1,""],clean_stale_tasks:[410,3,1,""],clear:[410,3,1,""],create_delays:[410,3,1,""],do_task:[410,3,1,""],exists:[410,3,1,""],get_deferred:[410,3,1,""],load:[410,3,1,""],remove:[410,3,1,""],save:[410,3,1,""]},"evennia.scripts.taskhandler.TaskHandlerTask":{__init__:[410,3,1,""],active:[410,3,1,"id6"],call:[410,3,1,"id3"],called:[410,3,1,""],cancel:[410,3,1,"id5"],do_task:[410,3,1,"id2"],exists:[410,3,1,"id7"],get_deferred:[410,3,1,""],get_id:[410,3,1,"id8"],pause:[410,3,1,"id0"],paused:[410,3,1,""],remove:[410,3,1,"id4"],unpause:[410,3,1,"id1"]},"evennia.scripts.tickerhandler":{Ticker:[411,1,1,""],TickerHandler:[411,1,1,""],TickerPool:[411,1,1,""]},"evennia.scripts.tickerhandler.Ticker":{__init__:[411,3,1,""],add:[411,3,1,""],remove:[411,3,1,""],stop:[411,3,1,""],validate:[411,3,1,""]},"evennia.scripts.tickerhandler.TickerHandler":{__init__:[411,3,1,""],add:[411,3,1,""],all:[411,3,1,""],all_display:[411,3,1,""],clear:[411,3,1,""],remove:[411,3,1,""],restore:[411,3,1,""],save:[411,3,1,""],ticker_pool_class:[411,4,1,""]},"evennia.scripts.tickerhandler.TickerPool":{__init__:[411,3,1,""],add:[411,3,1,""],remove:[411,3,1,""],stop:[411,3,1,""],ticker_class:[411,4,1,""]},"evennia.server":{amp_client:[413,0,0,"-"],connection_wizard:[414,0,0,"-"],deprecations:[415,0,0,"-"],evennia_launcher:[416,0,0,"-"],game_index_client:[417,0,0,"-"],initial_setup:[420,0,0,"-"],inputfuncs:[421,0,0,"-"],manager:[422,0,0,"-"],models:[423,0,0,"-"],portal:[424,0,0,"-"],profiling:[446,0,0,"-"],server:[454,0,0,"-"],serversession:[455,0,0,"-"],session:[456,0,0,"-"],sessionhandler:[457,0,0,"-"],signals:[458,0,0,"-"],throttle:[459,0,0,"-"],validators:[460,0,0,"-"],webserver:[461,0,0,"-"]},"evennia.server.amp_client":{AMPClientFactory:[413,1,1,""],AMPServerClientProtocol:[413,1,1,""]},"evennia.server.amp_client.AMPClientFactory":{__init__:[413,3,1,""],buildProtocol:[413,3,1,""],clientConnectionFailed:[413,3,1,""],clientConnectionLost:[413,3,1,""],factor:[413,4,1,""],initialDelay:[413,4,1,""],maxDelay:[413,4,1,""],noisy:[413,4,1,""],startedConnecting:[413,3,1,""]},"evennia.server.amp_client.AMPServerClientProtocol":{connectionMade:[413,3,1,""],data_to_portal:[413,3,1,""],send_AdminServer2Portal:[413,3,1,""],send_MsgServer2Portal:[413,3,1,""],server_receive_adminportal2server:[413,3,1,""],server_receive_msgportal2server:[413,3,1,""],server_receive_status:[413,3,1,""]},"evennia.server.connection_wizard":{ConnectionWizard:[414,1,1,""],node_game_index_fields:[414,5,1,""],node_game_index_start:[414,5,1,""],node_mssp_start:[414,5,1,""],node_start:[414,5,1,""],node_view_and_apply_settings:[414,5,1,""]},"evennia.server.connection_wizard.ConnectionWizard":{__init__:[414,3,1,""],ask_choice:[414,3,1,""],ask_continue:[414,3,1,""],ask_input:[414,3,1,""],ask_node:[414,3,1,""],ask_yesno:[414,3,1,""],display:[414,3,1,""]},"evennia.server.deprecations":{check_errors:[415,5,1,""],check_warnings:[415,5,1,""]},"evennia.server.evennia_launcher":{AMPLauncherProtocol:[416,1,1,""],MsgLauncher2Portal:[416,1,1,""],MsgStatus:[416,1,1,""],check_database:[416,5,1,""],check_main_evennia_dependencies:[416,5,1,""],collectstatic:[416,5,1,""],create_game_directory:[416,5,1,""],create_secret_key:[416,5,1,""],create_settings_file:[416,5,1,""],create_superuser:[416,5,1,""],del_pid:[416,5,1,""],error_check_python_modules:[416,5,1,""],evennia_version:[416,5,1,""],get_pid:[416,5,1,""],getenv:[416,5,1,""],init_game_directory:[416,5,1,""],kill:[416,5,1,""],list_settings:[416,5,1,""],main:[416,5,1,""],query_info:[416,5,1,""],query_status:[416,5,1,""],reboot_evennia:[416,5,1,""],reload_evennia:[416,5,1,""],run_connect_wizard:[416,5,1,""],run_custom_commands:[416,5,1,""],run_dummyrunner:[416,5,1,""],run_menu:[416,5,1,""],send_instruction:[416,5,1,""],set_gamedir:[416,5,1,""],show_version_info:[416,5,1,""],start_evennia:[416,5,1,""],start_only_server:[416,5,1,""],start_portal_interactive:[416,5,1,""],start_server_interactive:[416,5,1,""],stop_evennia:[416,5,1,""],stop_server_only:[416,5,1,""],tail_log_files:[416,5,1,""],wait_for_status:[416,5,1,""],wait_for_status_reply:[416,5,1,""]},"evennia.server.evennia_launcher.AMPLauncherProtocol":{__init__:[416,3,1,""],receive_status_from_portal:[416,3,1,""],wait_for_status:[416,3,1,""]},"evennia.server.evennia_launcher.MsgLauncher2Portal":{allErrors:[416,4,1,""],arguments:[416,4,1,""],commandName:[416,4,1,""],errors:[416,4,1,""],key:[416,4,1,""],response:[416,4,1,""],reverseErrors:[416,4,1,""]},"evennia.server.evennia_launcher.MsgStatus":{allErrors:[416,4,1,""],arguments:[416,4,1,""],commandName:[416,4,1,""],errors:[416,4,1,""],key:[416,4,1,""],response:[416,4,1,""],reverseErrors:[416,4,1,""]},"evennia.server.game_index_client":{client:[418,0,0,"-"],service:[419,0,0,"-"]},"evennia.server.game_index_client.client":{EvenniaGameIndexClient:[418,1,1,""],QuietHTTP11ClientFactory:[418,1,1,""],SimpleResponseReceiver:[418,1,1,""],StringProducer:[418,1,1,""]},"evennia.server.game_index_client.client.EvenniaGameIndexClient":{__init__:[418,3,1,""],handle_egd_response:[418,3,1,""],send_game_details:[418,3,1,""]},"evennia.server.game_index_client.client.QuietHTTP11ClientFactory":{noisy:[418,4,1,""]},"evennia.server.game_index_client.client.SimpleResponseReceiver":{__init__:[418,3,1,""],connectionLost:[418,3,1,""],dataReceived:[418,3,1,""]},"evennia.server.game_index_client.client.StringProducer":{__init__:[418,3,1,""],pauseProducing:[418,3,1,""],startProducing:[418,3,1,""],stopProducing:[418,3,1,""]},"evennia.server.game_index_client.service":{EvenniaGameIndexService:[419,1,1,""]},"evennia.server.game_index_client.service.EvenniaGameIndexService":{__init__:[419,3,1,""],name:[419,4,1,""],startService:[419,3,1,""],stopService:[419,3,1,""]},"evennia.server.initial_setup":{at_initial_setup:[420,5,1,""],collectstatic:[420,5,1,""],create_objects:[420,5,1,""],handle_setup:[420,5,1,""],reset_server:[420,5,1,""]},"evennia.server.inputfuncs":{"default":[421,5,1,""],bot_data_in:[421,5,1,""],client_gui:[421,5,1,""],client_options:[421,5,1,""],echo:[421,5,1,""],external_discord_hello:[421,5,1,""],get_client_options:[421,5,1,""],get_inputfuncs:[421,5,1,""],get_value:[421,5,1,""],hello:[421,5,1,""],login:[421,5,1,""],monitor:[421,5,1,""],monitored:[421,5,1,""],msdp_list:[421,5,1,""],msdp_report:[421,5,1,""],msdp_send:[421,5,1,""],msdp_unreport:[421,5,1,""],repeat:[421,5,1,""],supports_set:[421,5,1,""],text:[421,5,1,""],unmonitor:[421,5,1,""],unrepeat:[421,5,1,""],webclient_options:[421,5,1,""]},"evennia.server.manager":{ServerConfigManager:[422,1,1,""]},"evennia.server.manager.ServerConfigManager":{conf:[422,3,1,""]},"evennia.server.models":{ServerConfig:[423,1,1,""]},"evennia.server.models.ServerConfig":{DoesNotExist:[423,2,1,""],MultipleObjectsReturned:[423,2,1,""],db_key:[423,4,1,""],db_value:[423,4,1,""],id:[423,4,1,""],key:[423,3,1,""],objects:[423,4,1,""],path:[423,4,1,""],store:[423,3,1,""],typename:[423,4,1,""],value:[423,3,1,""]},"evennia.server.portal":{amp:[425,0,0,"-"],amp_server:[426,0,0,"-"],grapevine:[427,0,0,"-"],irc:[428,0,0,"-"],mccp:[429,0,0,"-"],mssp:[430,0,0,"-"],mxp:[431,0,0,"-"],naws:[432,0,0,"-"],portal:[433,0,0,"-"],portalsessionhandler:[434,0,0,"-"],rss:[435,0,0,"-"],ssh:[436,0,0,"-"],ssl:[437,0,0,"-"],suppress_ga:[438,0,0,"-"],telnet:[439,0,0,"-"],telnet_oob:[440,0,0,"-"],telnet_ssl:[441,0,0,"-"],tests:[442,0,0,"-"],ttype:[443,0,0,"-"],webclient:[444,0,0,"-"],webclient_ajax:[445,0,0,"-"]},"evennia.server.portal.amp":{AMPMultiConnectionProtocol:[425,1,1,""],AdminPortal2Server:[425,1,1,""],AdminServer2Portal:[425,1,1,""],Compressed:[425,1,1,""],FunctionCall:[425,1,1,""],MsgLauncher2Portal:[425,1,1,""],MsgPortal2Server:[425,1,1,""],MsgServer2Portal:[425,1,1,""],MsgStatus:[425,1,1,""],dumps:[425,5,1,""],loads:[425,5,1,""]},"evennia.server.portal.amp.AMPMultiConnectionProtocol":{__init__:[425,3,1,""],broadcast:[425,3,1,""],connectionLost:[425,3,1,""],connectionMade:[425,3,1,""],dataReceived:[425,3,1,""],data_in:[425,3,1,""],errback:[425,3,1,""],makeConnection:[425,3,1,""],receive_functioncall:[425,3,1,""],send_FunctionCall:[425,3,1,""]},"evennia.server.portal.amp.AdminPortal2Server":{allErrors:[425,4,1,""],arguments:[425,4,1,""],commandName:[425,4,1,""],errors:[425,4,1,""],key:[425,4,1,""],response:[425,4,1,""],reverseErrors:[425,4,1,""]},"evennia.server.portal.amp.AdminServer2Portal":{allErrors:[425,4,1,""],arguments:[425,4,1,""],commandName:[425,4,1,""],errors:[425,4,1,""],key:[425,4,1,""],response:[425,4,1,""],reverseErrors:[425,4,1,""]},"evennia.server.portal.amp.Compressed":{fromBox:[425,3,1,""],fromString:[425,3,1,""],toBox:[425,3,1,""],toString:[425,3,1,""]},"evennia.server.portal.amp.FunctionCall":{allErrors:[425,4,1,""],arguments:[425,4,1,""],commandName:[425,4,1,""],errors:[425,4,1,""],key:[425,4,1,""],response:[425,4,1,""],reverseErrors:[425,4,1,""]},"evennia.server.portal.amp.MsgLauncher2Portal":{allErrors:[425,4,1,""],arguments:[425,4,1,""],commandName:[425,4,1,""],errors:[425,4,1,""],key:[425,4,1,""],response:[425,4,1,""],reverseErrors:[425,4,1,""]},"evennia.server.portal.amp.MsgPortal2Server":{allErrors:[425,4,1,""],arguments:[425,4,1,""],commandName:[425,4,1,""],errors:[425,4,1,""],key:[425,4,1,""],response:[425,4,1,""],reverseErrors:[425,4,1,""]},"evennia.server.portal.amp.MsgServer2Portal":{allErrors:[425,4,1,""],arguments:[425,4,1,""],commandName:[425,4,1,""],errors:[425,4,1,""],key:[425,4,1,""],response:[425,4,1,""],reverseErrors:[425,4,1,""]},"evennia.server.portal.amp.MsgStatus":{allErrors:[425,4,1,""],arguments:[425,4,1,""],commandName:[425,4,1,""],errors:[425,4,1,""],key:[425,4,1,""],response:[425,4,1,""],reverseErrors:[425,4,1,""]},"evennia.server.portal.amp_server":{AMPServerFactory:[426,1,1,""],AMPServerProtocol:[426,1,1,""],getenv:[426,5,1,""]},"evennia.server.portal.amp_server.AMPServerFactory":{__init__:[426,3,1,""],buildProtocol:[426,3,1,""],logPrefix:[426,3,1,""],noisy:[426,4,1,""]},"evennia.server.portal.amp_server.AMPServerProtocol":{connectionLost:[426,3,1,""],data_to_server:[426,3,1,""],get_status:[426,3,1,""],portal_receive_adminserver2portal:[426,3,1,""],portal_receive_launcher2portal:[426,3,1,""],portal_receive_server2portal:[426,3,1,""],portal_receive_status:[426,3,1,""],send_AdminPortal2Server:[426,3,1,""],send_MsgPortal2Server:[426,3,1,""],send_Status2Launcher:[426,3,1,""],start_server:[426,3,1,""],stop_server:[426,3,1,""],wait_for_disconnect:[426,3,1,""],wait_for_server_connect:[426,3,1,""]},"evennia.server.portal.grapevine":{GrapevineClient:[427,1,1,""],RestartingWebsocketServerFactory:[427,1,1,""]},"evennia.server.portal.grapevine.GrapevineClient":{__init__:[427,3,1,""],at_login:[427,3,1,""],data_in:[427,3,1,""],disconnect:[427,3,1,""],onClose:[427,3,1,""],onMessage:[427,3,1,""],onOpen:[427,3,1,""],send_authenticate:[427,3,1,""],send_channel:[427,3,1,""],send_default:[427,3,1,""],send_heartbeat:[427,3,1,""],send_subscribe:[427,3,1,""],send_unsubscribe:[427,3,1,""]},"evennia.server.portal.grapevine.RestartingWebsocketServerFactory":{__init__:[427,3,1,""],buildProtocol:[427,3,1,""],clientConnectionFailed:[427,3,1,""],clientConnectionLost:[427,3,1,""],factor:[427,4,1,""],initialDelay:[427,4,1,""],maxDelay:[427,4,1,""],reconnect:[427,3,1,""],start:[427,3,1,""],startedConnecting:[427,3,1,""]},"evennia.server.portal.irc":{IRCBot:[428,1,1,""],IRCBotFactory:[428,1,1,""],parse_ansi_to_irc:[428,5,1,""],parse_irc_to_ansi:[428,5,1,""]},"evennia.server.portal.irc.IRCBot":{action:[428,3,1,""],at_login:[428,3,1,""],channel:[428,4,1,""],data_in:[428,3,1,""],disconnect:[428,3,1,""],factory:[428,4,1,""],get_nicklist:[428,3,1,""],irc_RPL_ENDOFNAMES:[428,3,1,""],irc_RPL_NAMREPLY:[428,3,1,""],lineRate:[428,4,1,""],logger:[428,4,1,""],nickname:[428,4,1,""],pong:[428,3,1,""],privmsg:[428,3,1,""],send_channel:[428,3,1,""],send_default:[428,3,1,""],send_ping:[428,3,1,""],send_privmsg:[428,3,1,""],send_reconnect:[428,3,1,""],send_request_nicklist:[428,3,1,""],signedOn:[428,3,1,""],sourceURL:[428,4,1,""]},"evennia.server.portal.irc.IRCBotFactory":{__init__:[428,3,1,""],buildProtocol:[428,3,1,""],clientConnectionFailed:[428,3,1,""],clientConnectionLost:[428,3,1,""],factor:[428,4,1,""],initialDelay:[428,4,1,""],maxDelay:[428,4,1,""],reconnect:[428,3,1,""],start:[428,3,1,""],startedConnecting:[428,3,1,""]},"evennia.server.portal.mccp":{Mccp:[429,1,1,""],mccp_compress:[429,5,1,""]},"evennia.server.portal.mccp.Mccp":{__init__:[429,3,1,""],do_mccp:[429,3,1,""],no_mccp:[429,3,1,""]},"evennia.server.portal.mssp":{Mssp:[430,1,1,""]},"evennia.server.portal.mssp.Mssp":{__init__:[430,3,1,""],do_mssp:[430,3,1,""],get_player_count:[430,3,1,""],get_uptime:[430,3,1,""],no_mssp:[430,3,1,""]},"evennia.server.portal.mxp":{Mxp:[431,1,1,""],mxp_parse:[431,5,1,""]},"evennia.server.portal.mxp.Mxp":{__init__:[431,3,1,""],do_mxp:[431,3,1,""],no_mxp:[431,3,1,""]},"evennia.server.portal.naws":{Naws:[432,1,1,""]},"evennia.server.portal.naws.Naws":{__init__:[432,3,1,""],do_naws:[432,3,1,""],negotiate_sizes:[432,3,1,""],no_naws:[432,3,1,""]},"evennia.server.portal.portal":{Portal:[433,1,1,""],Websocket:[433,1,1,""]},"evennia.server.portal.portal.Portal":{__init__:[433,3,1,""],get_info_dict:[433,3,1,""],shutdown:[433,3,1,""]},"evennia.server.portal.portalsessionhandler":{PortalSessionHandler:[434,1,1,""]},"evennia.server.portal.portalsessionhandler.PortalSessionHandler":{__init__:[434,3,1,""],announce_all:[434,3,1,""],at_server_connection:[434,3,1,""],connect:[434,3,1,""],count_loggedin:[434,3,1,""],data_in:[434,3,1,""],data_out:[434,3,1,""],disconnect:[434,3,1,""],disconnect_all:[434,3,1,""],generate_sessid:[434,3,1,""],server_connect:[434,3,1,""],server_disconnect:[434,3,1,""],server_disconnect_all:[434,3,1,""],server_logged_in:[434,3,1,""],server_session_sync:[434,3,1,""],sessions_from_csessid:[434,3,1,""],sync:[434,3,1,""]},"evennia.server.portal.rss":{RSSBotFactory:[435,1,1,""],RSSReader:[435,1,1,""]},"evennia.server.portal.rss.RSSBotFactory":{__init__:[435,3,1,""],start:[435,3,1,""]},"evennia.server.portal.rss.RSSReader":{__init__:[435,3,1,""],data_in:[435,3,1,""],disconnect:[435,3,1,""],get_new:[435,3,1,""],update:[435,3,1,""]},"evennia.server.portal.ssh":{AccountDBPasswordChecker:[436,1,1,""],ExtraInfoAuthServer:[436,1,1,""],PassAvatarIdTerminalRealm:[436,1,1,""],SSHServerFactory:[436,1,1,""],SshProtocol:[436,1,1,""],TerminalSessionTransport_getPeer:[436,1,1,""],getKeyPair:[436,5,1,""],makeFactory:[436,5,1,""]},"evennia.server.portal.ssh.AccountDBPasswordChecker":{__init__:[436,3,1,""],credentialInterfaces:[436,4,1,""],noisy:[436,4,1,""],requestAvatarId:[436,3,1,""]},"evennia.server.portal.ssh.ExtraInfoAuthServer":{auth_password:[436,3,1,""],noisy:[436,4,1,""]},"evennia.server.portal.ssh.PassAvatarIdTerminalRealm":{noisy:[436,4,1,""]},"evennia.server.portal.ssh.SSHServerFactory":{logPrefix:[436,3,1,""],noisy:[436,4,1,""]},"evennia.server.portal.ssh.SshProtocol":{__init__:[436,3,1,""],at_login:[436,3,1,""],connectionLost:[436,3,1,""],connectionMade:[436,3,1,""],data_out:[436,3,1,""],disconnect:[436,3,1,""],getClientAddress:[436,3,1,""],handle_EOF:[436,3,1,""],handle_FF:[436,3,1,""],handle_INT:[436,3,1,""],handle_QUIT:[436,3,1,""],lineReceived:[436,3,1,""],noisy:[436,4,1,""],sendLine:[436,3,1,""],send_default:[436,3,1,""],send_prompt:[436,3,1,""],send_text:[436,3,1,""],terminalSize:[436,3,1,""]},"evennia.server.portal.ssh.TerminalSessionTransport_getPeer":{__init__:[436,3,1,""],noisy:[436,4,1,""]},"evennia.server.portal.ssl":{SSLProtocol:[437,1,1,""],getSSLContext:[437,5,1,""],verify_SSL_key_and_cert:[437,5,1,""]},"evennia.server.portal.ssl.SSLProtocol":{__init__:[437,3,1,""]},"evennia.server.portal.suppress_ga":{SuppressGA:[438,1,1,""]},"evennia.server.portal.suppress_ga.SuppressGA":{__init__:[438,3,1,""],will_suppress_ga:[438,3,1,""],wont_suppress_ga:[438,3,1,""]},"evennia.server.portal.telnet":{TelnetProtocol:[439,1,1,""],TelnetServerFactory:[439,1,1,""]},"evennia.server.portal.telnet.TelnetProtocol":{__init__:[439,3,1,""],applicationDataReceived:[439,3,1,""],at_login:[439,3,1,""],connectionLost:[439,3,1,""],connectionMade:[439,3,1,""],dataReceived:[439,3,1,""],data_in:[439,3,1,""],data_out:[439,3,1,""],disableLocal:[439,3,1,""],disableRemote:[439,3,1,""],disconnect:[439,3,1,""],enableLocal:[439,3,1,""],enableRemote:[439,3,1,""],handshake_done:[439,3,1,""],sendLine:[439,3,1,""],send_default:[439,3,1,""],send_prompt:[439,3,1,""],send_text:[439,3,1,""],toggle_nop_keepalive:[439,3,1,""]},"evennia.server.portal.telnet.TelnetServerFactory":{logPrefix:[439,3,1,""],noisy:[439,4,1,""]},"evennia.server.portal.telnet_oob":{TelnetOOB:[440,1,1,""]},"evennia.server.portal.telnet_oob.TelnetOOB":{__init__:[440,3,1,""],data_out:[440,3,1,""],decode_gmcp:[440,3,1,""],decode_msdp:[440,3,1,""],do_gmcp:[440,3,1,""],do_msdp:[440,3,1,""],encode_gmcp:[440,3,1,""],encode_msdp:[440,3,1,""],no_gmcp:[440,3,1,""],no_msdp:[440,3,1,""]},"evennia.server.portal.telnet_ssl":{SSLProtocol:[441,1,1,""],getSSLContext:[441,5,1,""],verify_or_create_SSL_key_and_cert:[441,5,1,""]},"evennia.server.portal.telnet_ssl.SSLProtocol":{__init__:[441,3,1,""]},"evennia.server.portal.tests":{TestAMPServer:[442,1,1,""],TestIRC:[442,1,1,""],TestTelnet:[442,1,1,""],TestWebSocket:[442,1,1,""]},"evennia.server.portal.tests.TestAMPServer":{setUp:[442,3,1,""],test_amp_in:[442,3,1,""],test_amp_out:[442,3,1,""],test_large_msg:[442,3,1,""]},"evennia.server.portal.tests.TestIRC":{test_bold:[442,3,1,""],test_colors:[442,3,1,""],test_identity:[442,3,1,""],test_italic:[442,3,1,""],test_plain_ansi:[442,3,1,""]},"evennia.server.portal.tests.TestTelnet":{setUp:[442,3,1,""],test_mudlet_ttype:[442,3,1,""]},"evennia.server.portal.tests.TestWebSocket":{setUp:[442,3,1,""],tearDown:[442,3,1,""],test_data_in:[442,3,1,""],test_data_out:[442,3,1,""]},"evennia.server.portal.ttype":{Ttype:[443,1,1,""]},"evennia.server.portal.ttype.Ttype":{__init__:[443,3,1,""],will_ttype:[443,3,1,""],wont_ttype:[443,3,1,""]},"evennia.server.portal.webclient":{WebSocketClient:[444,1,1,""]},"evennia.server.portal.webclient.WebSocketClient":{__init__:[444,3,1,""],at_login:[444,3,1,""],data_in:[444,3,1,""],disconnect:[444,3,1,""],get_client_session:[444,3,1,""],nonce:[444,4,1,""],onClose:[444,3,1,""],onMessage:[444,3,1,""],onOpen:[444,3,1,""],sendLine:[444,3,1,""],send_default:[444,3,1,""],send_prompt:[444,3,1,""],send_text:[444,3,1,""]},"evennia.server.portal.webclient_ajax":{AjaxWebClient:[445,1,1,""],AjaxWebClientSession:[445,1,1,""],LazyEncoder:[445,1,1,""],jsonify:[445,5,1,""]},"evennia.server.portal.webclient_ajax.AjaxWebClient":{__init__:[445,3,1,""],allowedMethods:[445,4,1,""],at_login:[445,3,1,""],client_disconnect:[445,3,1,""],get_browserstr:[445,3,1,""],get_client_sessid:[445,3,1,""],isLeaf:[445,4,1,""],lineSend:[445,3,1,""],mode_close:[445,3,1,""],mode_init:[445,3,1,""],mode_input:[445,3,1,""],mode_keepalive:[445,3,1,""],mode_receive:[445,3,1,""],render_POST:[445,3,1,""]},"evennia.server.portal.webclient_ajax.AjaxWebClientSession":{__init__:[445,3,1,""],at_login:[445,3,1,""],data_in:[445,3,1,""],data_out:[445,3,1,""],disconnect:[445,3,1,""],get_client_session:[445,3,1,""],send_default:[445,3,1,""],send_prompt:[445,3,1,""],send_text:[445,3,1,""]},"evennia.server.portal.webclient_ajax.LazyEncoder":{"default":[445,3,1,""]},"evennia.server.profiling":{dummyrunner:[447,0,0,"-"],dummyrunner_settings:[448,0,0,"-"],memplot:[449,0,0,"-"],settings_mixin:[450,0,0,"-"],test_queries:[451,0,0,"-"],tests:[452,0,0,"-"],timetrace:[453,0,0,"-"]},"evennia.server.profiling.dummyrunner":{CmdDummyRunnerEchoResponse:[447,1,1,""],DummyClient:[447,1,1,""],DummyFactory:[447,1,1,""],DummyRunnerCmdSet:[447,1,1,""],gidcounter:[447,5,1,""],idcounter:[447,5,1,""],makeiter:[447,5,1,""],start_all_dummy_clients:[447,5,1,""]},"evennia.server.profiling.dummyrunner.CmdDummyRunnerEchoResponse":{aliases:[447,4,1,""],func:[447,3,1,""],help_category:[447,4,1,""],key:[447,4,1,""],lock_storage:[447,4,1,""],search_index_entry:[447,4,1,""]},"evennia.server.profiling.dummyrunner.DummyClient":{connectionLost:[447,3,1,""],connectionMade:[447,3,1,""],counter:[447,3,1,""],dataReceived:[447,3,1,""],error:[447,3,1,""],logout:[447,3,1,""],report:[447,3,1,""],step:[447,3,1,""]},"evennia.server.profiling.dummyrunner.DummyFactory":{__init__:[447,3,1,""],initialDelay:[447,4,1,""],maxDelay:[447,4,1,""],noisy:[447,4,1,""],protocol:[447,4,1,""]},"evennia.server.profiling.dummyrunner.DummyRunnerCmdSet":{at_cmdset_creation:[447,3,1,""],path:[447,4,1,""]},"evennia.server.profiling.dummyrunner_settings":{c_creates_button:[448,5,1,""],c_creates_obj:[448,5,1,""],c_digs:[448,5,1,""],c_examines:[448,5,1,""],c_help:[448,5,1,""],c_idles:[448,5,1,""],c_login:[448,5,1,""],c_login_nodig:[448,5,1,""],c_logout:[448,5,1,""],c_looks:[448,5,1,""],c_measure_lag:[448,5,1,""],c_moves:[448,5,1,""],c_moves_n:[448,5,1,""],c_moves_s:[448,5,1,""],c_socialize:[448,5,1,""]},"evennia.server.profiling.memplot":{Memplot:[449,1,1,""]},"evennia.server.profiling.memplot.Memplot":{DoesNotExist:[449,2,1,""],MultipleObjectsReturned:[449,2,1,""],at_repeat:[449,3,1,""],at_script_creation:[449,3,1,""],path:[449,4,1,""],typename:[449,4,1,""]},"evennia.server.profiling.test_queries":{count_queries:[451,5,1,""]},"evennia.server.profiling.tests":{TestDummyrunnerSettings:[452,1,1,""],TestMemPlot:[452,1,1,""]},"evennia.server.profiling.tests.TestDummyrunnerSettings":{clear_client_lists:[452,3,1,""],perception_method_tests:[452,3,1,""],setUp:[452,3,1,""],test_c_creates_button:[452,3,1,""],test_c_creates_obj:[452,3,1,""],test_c_digs:[452,3,1,""],test_c_examines:[452,3,1,""],test_c_help:[452,3,1,""],test_c_login:[452,3,1,""],test_c_login_no_dig:[452,3,1,""],test_c_logout:[452,3,1,""],test_c_looks:[452,3,1,""],test_c_move_n:[452,3,1,""],test_c_move_s:[452,3,1,""],test_c_moves:[452,3,1,""],test_c_socialize:[452,3,1,""],test_idles:[452,3,1,""]},"evennia.server.profiling.tests.TestMemPlot":{test_memplot:[452,3,1,""]},"evennia.server.profiling.timetrace":{timetrace:[453,5,1,""]},"evennia.server.server":{Evennia:[454,1,1,""]},"evennia.server.server.Evennia":{__init__:[454,3,1,""],at_post_portal_sync:[454,3,1,""],at_server_cold_start:[454,3,1,""],at_server_cold_stop:[454,3,1,""],at_server_reload_start:[454,3,1,""],at_server_reload_stop:[454,3,1,""],at_server_start:[454,3,1,""],at_server_stop:[454,3,1,""],create_default_channels:[454,3,1,""],get_info_dict:[454,3,1,""],run_init_hooks:[454,3,1,""],run_initial_setup:[454,3,1,""],shutdown:[454,3,1,""],sqlite3_prep:[454,3,1,""],update_defaults:[454,3,1,""]},"evennia.server.serversession":{ServerSession:[455,1,1,""]},"evennia.server.serversession.ServerSession":{__init__:[455,3,1,""],access:[455,3,1,""],at_cmdset_get:[455,3,1,""],at_disconnect:[455,3,1,""],at_login:[455,3,1,""],at_sync:[455,3,1,""],attributes:[455,4,1,""],cmdset_storage:[455,3,1,""],data_in:[455,3,1,""],data_out:[455,3,1,""],db:[455,3,1,""],execute_cmd:[455,3,1,""],get_account:[455,3,1,""],get_character:[455,3,1,""],get_client_size:[455,3,1,""],get_puppet:[455,3,1,""],get_puppet_or_account:[455,3,1,""],id:[455,3,1,""],log:[455,3,1,""],msg:[455,3,1,""],nattributes:[455,4,1,""],ndb:[455,3,1,""],ndb_del:[455,3,1,""],ndb_get:[455,3,1,""],ndb_set:[455,3,1,""],update_flags:[455,3,1,""],update_session_counters:[455,3,1,""]},"evennia.server.session":{Session:[456,1,1,""]},"evennia.server.session.Session":{at_sync:[456,3,1,""],data_in:[456,3,1,""],data_out:[456,3,1,""],disconnect:[456,3,1,""],get_sync_data:[456,3,1,""],init_session:[456,3,1,""],load_sync_data:[456,3,1,""]},"evennia.server.sessionhandler":{DummySession:[457,1,1,""],ServerSessionHandler:[457,1,1,""],SessionHandler:[457,1,1,""],delayed_import:[457,5,1,""]},"evennia.server.sessionhandler.DummySession":{sessid:[457,4,1,""]},"evennia.server.sessionhandler.ServerSessionHandler":{__init__:[457,3,1,""],account_count:[457,3,1,""],all_connected_accounts:[457,3,1,""],all_sessions_portal_sync:[457,3,1,""],announce_all:[457,3,1,""],call_inputfuncs:[457,3,1,""],data_in:[457,3,1,""],data_out:[457,3,1,""],disconnect:[457,3,1,""],disconnect_all_sessions:[457,3,1,""],disconnect_duplicate_sessions:[457,3,1,""],get_inputfuncs:[457,3,1,""],login:[457,3,1,""],portal_connect:[457,3,1,""],portal_disconnect:[457,3,1,""],portal_disconnect_all:[457,3,1,""],portal_reset_server:[457,3,1,""],portal_restart_server:[457,3,1,""],portal_session_sync:[457,3,1,""],portal_sessions_sync:[457,3,1,""],portal_shutdown:[457,3,1,""],session_from_account:[457,3,1,""],session_from_sessid:[457,3,1,""],session_portal_partial_sync:[457,3,1,""],session_portal_sync:[457,3,1,""],sessions_from_account:[457,3,1,""],sessions_from_character:[457,3,1,""],sessions_from_csessid:[457,3,1,""],sessions_from_puppet:[457,3,1,""],start_bot_session:[457,3,1,""],validate_sessions:[457,3,1,""]},"evennia.server.sessionhandler.SessionHandler":{clean_senddata:[457,3,1,""],get:[457,3,1,""],get_all_sync_data:[457,3,1,""],get_sessions:[457,3,1,""]},"evennia.server.throttle":{Throttle:[459,1,1,""]},"evennia.server.throttle.Throttle":{__init__:[459,3,1,""],check:[459,3,1,""],error_msg:[459,4,1,""],get:[459,3,1,""],get_cache_key:[459,3,1,""],record_ip:[459,3,1,""],remove:[459,3,1,""],touch:[459,3,1,""],unrecord_ip:[459,3,1,""],update:[459,3,1,""]},"evennia.server.validators":{EvenniaPasswordValidator:[460,1,1,""],EvenniaUsernameAvailabilityValidator:[460,1,1,""]},"evennia.server.validators.EvenniaPasswordValidator":{__init__:[460,3,1,""],get_help_text:[460,3,1,""],validate:[460,3,1,""]},"evennia.server.webserver":{DjangoWebRoot:[461,1,1,""],EvenniaReverseProxyResource:[461,1,1,""],HTTPChannelWithXForwardedFor:[461,1,1,""],LockableThreadPool:[461,1,1,""],PrivateStaticRoot:[461,1,1,""],WSGIWebServer:[461,1,1,""],Website:[461,1,1,""]},"evennia.server.webserver.DjangoWebRoot":{__init__:[461,3,1,""],empty_threadpool:[461,3,1,""],getChild:[461,3,1,""]},"evennia.server.webserver.EvenniaReverseProxyResource":{getChild:[461,3,1,""],render:[461,3,1,""]},"evennia.server.webserver.HTTPChannelWithXForwardedFor":{allHeadersReceived:[461,3,1,""]},"evennia.server.webserver.LockableThreadPool":{__init__:[461,3,1,""],callInThread:[461,3,1,""],lock:[461,3,1,""]},"evennia.server.webserver.PrivateStaticRoot":{directoryListing:[461,3,1,""]},"evennia.server.webserver.WSGIWebServer":{__init__:[461,3,1,""],startService:[461,3,1,""],stopService:[461,3,1,""]},"evennia.server.webserver.Website":{log:[461,3,1,""],logPrefix:[461,3,1,""],noisy:[461,4,1,""]},"evennia.typeclasses":{attributes:[464,0,0,"-"],managers:[465,0,0,"-"],models:[466,0,0,"-"],tags:[467,0,0,"-"]},"evennia.typeclasses.attributes":{Attribute:[464,1,1,""],AttributeHandler:[464,1,1,""],AttributeProperty:[464,1,1,""],DbHolder:[464,1,1,""],IAttribute:[464,1,1,""],IAttributeBackend:[464,1,1,""],InMemoryAttribute:[464,1,1,""],InMemoryAttributeBackend:[464,1,1,""],ModelAttributeBackend:[464,1,1,""],NAttributeProperty:[464,1,1,""],NickHandler:[464,1,1,""],NickTemplateInvalid:[464,2,1,""],initialize_nick_templates:[464,5,1,""],parse_nick_template:[464,5,1,""]},"evennia.typeclasses.attributes.Attribute":{DoesNotExist:[464,2,1,""],MultipleObjectsReturned:[464,2,1,""],accountdb_set:[464,4,1,""],attrtype:[464,3,1,""],category:[464,3,1,""],channeldb_set:[464,4,1,""],date_created:[464,3,1,""],db_attrtype:[464,4,1,""],db_category:[464,4,1,""],db_date_created:[464,4,1,""],db_key:[464,4,1,""],db_lock_storage:[464,4,1,""],db_model:[464,4,1,""],db_strvalue:[464,4,1,""],db_value:[464,4,1,""],get_next_by_db_date_created:[464,3,1,""],get_previous_by_db_date_created:[464,3,1,""],id:[464,4,1,""],key:[464,3,1,""],lock_storage:[464,3,1,""],model:[464,3,1,""],objectdb_set:[464,4,1,""],path:[464,4,1,""],scriptdb_set:[464,4,1,""],strvalue:[464,3,1,""],typename:[464,4,1,""],value:[464,3,1,""]},"evennia.typeclasses.attributes.AttributeHandler":{__init__:[464,3,1,""],add:[464,3,1,""],all:[464,3,1,""],batch_add:[464,3,1,""],clear:[464,3,1,""],get:[464,3,1,""],has:[464,3,1,""],remove:[464,3,1,""],reset_cache:[464,3,1,""]},"evennia.typeclasses.attributes.AttributeProperty":{__init__:[464,3,1,""],attrhandler_name:[464,4,1,""]},"evennia.typeclasses.attributes.DbHolder":{__init__:[464,3,1,""],all:[464,3,1,""],get_all:[464,3,1,""]},"evennia.typeclasses.attributes.IAttribute":{access:[464,3,1,""],attrtype:[464,3,1,""],category:[464,3,1,""],date_created:[464,3,1,""],key:[464,3,1,""],lock_storage:[464,3,1,""],locks:[464,4,1,""],model:[464,3,1,""],strvalue:[464,3,1,""]},"evennia.typeclasses.attributes.IAttributeBackend":{__init__:[464,3,1,""],batch_add:[464,3,1,""],clear_attributes:[464,3,1,""],create_attribute:[464,3,1,""],delete_attribute:[464,3,1,""],do_batch_delete:[464,3,1,""],do_batch_finish:[464,3,1,""],do_batch_update_attribute:[464,3,1,""],do_create_attribute:[464,3,1,""],do_delete_attribute:[464,3,1,""],do_update_attribute:[464,3,1,""],get:[464,3,1,""],get_all_attributes:[464,3,1,""],query_all:[464,3,1,""],query_category:[464,3,1,""],query_key:[464,3,1,""],reset_cache:[464,3,1,""],update_attribute:[464,3,1,""]},"evennia.typeclasses.attributes.InMemoryAttribute":{__init__:[464,3,1,""],value:[464,3,1,""]},"evennia.typeclasses.attributes.InMemoryAttributeBackend":{__init__:[464,3,1,""],do_batch_finish:[464,3,1,""],do_batch_update_attribute:[464,3,1,""],do_create_attribute:[464,3,1,""],do_delete_attribute:[464,3,1,""],do_update_attribute:[464,3,1,""],query_all:[464,3,1,""],query_category:[464,3,1,""],query_key:[464,3,1,""]},"evennia.typeclasses.attributes.ModelAttributeBackend":{__init__:[464,3,1,""],do_batch_finish:[464,3,1,""],do_batch_update_attribute:[464,3,1,""],do_create_attribute:[464,3,1,""],do_delete_attribute:[464,3,1,""],do_update_attribute:[464,3,1,""],query_all:[464,3,1,""],query_category:[464,3,1,""],query_key:[464,3,1,""]},"evennia.typeclasses.attributes.NAttributeProperty":{attrhandler_name:[464,4,1,""]},"evennia.typeclasses.attributes.NickHandler":{__init__:[464,3,1,""],add:[464,3,1,""],get:[464,3,1,""],has:[464,3,1,""],nickreplace:[464,3,1,""],remove:[464,3,1,""]},"evennia.typeclasses.managers":{TypedObjectManager:[465,1,1,""]},"evennia.typeclasses.managers.TypedObjectManager":{create_tag:[465,3,1,""],dbref:[465,3,1,""],dbref_search:[465,3,1,""],get_alias:[465,3,1,""],get_attribute:[465,3,1,""],get_by_alias:[465,3,1,""],get_by_attribute:[465,3,1,""],get_by_nick:[465,3,1,""],get_by_permission:[465,3,1,""],get_by_tag:[465,3,1,""],get_dbref_range:[465,3,1,""],get_id:[465,3,1,""],get_nick:[465,3,1,""],get_permission:[465,3,1,""],get_tag:[465,3,1,""],get_typeclass_totals:[465,3,1,""],object_totals:[465,3,1,""],typeclass_search:[465,3,1,""]},"evennia.typeclasses.models":{TypedObject:[466,1,1,""]},"evennia.typeclasses.models.TypedObject":{"delete":[466,3,1,""],Meta:[466,1,1,""],__init__:[466,3,1,""],access:[466,3,1,""],aliases:[466,4,1,""],at_idmapper_flush:[466,3,1,""],at_rename:[466,3,1,""],attributes:[466,4,1,""],check_permstring:[466,3,1,""],date_created:[466,3,1,""],db:[466,3,1,""],db_attributes:[466,4,1,""],db_date_created:[466,4,1,""],db_key:[466,4,1,""],db_lock_storage:[466,4,1,""],db_tags:[466,4,1,""],db_typeclass_path:[466,4,1,""],dbid:[466,3,1,""],dbref:[466,3,1,""],get_absolute_url:[466,3,1,""],get_display_name:[466,3,1,""],get_extra_info:[466,3,1,""],get_next_by_db_date_created:[466,3,1,""],get_previous_by_db_date_created:[466,3,1,""],is_typeclass:[466,3,1,""],key:[466,3,1,""],lock_storage:[466,3,1,""],locks:[466,4,1,""],name:[466,3,1,""],nattributes:[466,4,1,""],ndb:[466,3,1,""],objects:[466,4,1,""],path:[466,4,1,""],permissions:[466,4,1,""],search:[466,3,1,""],set_class_from_typeclass:[466,3,1,""],swap_typeclass:[466,3,1,""],tags:[466,4,1,""],typeclass_path:[466,3,1,""],typename:[466,4,1,""],web_get_admin_url:[466,3,1,""],web_get_create_url:[466,3,1,""],web_get_delete_url:[466,3,1,""],web_get_detail_url:[466,3,1,""],web_get_puppet_url:[466,3,1,""],web_get_update_url:[466,3,1,""]},"evennia.typeclasses.models.TypedObject.Meta":{"abstract":[466,4,1,""],ordering:[466,4,1,""],verbose_name:[466,4,1,""]},"evennia.typeclasses.tags":{AliasHandler:[467,1,1,""],PermissionHandler:[467,1,1,""],Tag:[467,1,1,""],TagHandler:[467,1,1,""]},"evennia.typeclasses.tags.PermissionHandler":{check:[467,3,1,""]},"evennia.typeclasses.tags.Tag":{DoesNotExist:[467,2,1,""],MultipleObjectsReturned:[467,2,1,""],accountdb_set:[467,4,1,""],channeldb_set:[467,4,1,""],db_category:[467,4,1,""],db_data:[467,4,1,""],db_key:[467,4,1,""],db_model:[467,4,1,""],db_tagtype:[467,4,1,""],helpentry_set:[467,4,1,""],id:[467,4,1,""],msg_set:[467,4,1,""],objectdb_set:[467,4,1,""],objects:[467,4,1,""],scriptdb_set:[467,4,1,""]},"evennia.typeclasses.tags.TagHandler":{__init__:[467,3,1,""],add:[467,3,1,""],all:[467,3,1,""],batch_add:[467,3,1,""],clear:[467,3,1,""],get:[467,3,1,""],has:[467,3,1,""],remove:[467,3,1,""],reset_cache:[467,3,1,""]},"evennia.utils":{ansi:[469,0,0,"-"],batchprocessors:[470,0,0,"-"],containers:[471,0,0,"-"],create:[472,0,0,"-"],dbserialize:[473,0,0,"-"],eveditor:[474,0,0,"-"],evform:[475,0,0,"-"],evmenu:[476,0,0,"-"],evmore:[477,0,0,"-"],evtable:[478,0,0,"-"],funcparser:[479,0,0,"-"],gametime:[480,0,0,"-"],idmapper:[481,0,0,"-"],logger:[485,0,0,"-"],optionclasses:[486,0,0,"-"],optionhandler:[487,0,0,"-"],picklefield:[488,0,0,"-"],search:[489,0,0,"-"],test_resources:[490,0,0,"-"],text2html:[491,0,0,"-"],utils:[492,0,0,"-"],validatorfuncs:[493,0,0,"-"],verb_conjugation:[494,0,0,"-"]},"evennia.utils.ansi":{ANSIMeta:[469,1,1,""],ANSIParser:[469,1,1,""],ANSIString:[469,1,1,""],parse_ansi:[469,5,1,""],raw:[469,5,1,""],strip_ansi:[469,5,1,""],strip_mxp:[469,5,1,""],strip_raw_ansi:[469,5,1,""],strip_unsafe_tokens:[469,5,1,""]},"evennia.utils.ansi.ANSIMeta":{__init__:[469,3,1,""]},"evennia.utils.ansi.ANSIParser":{ansi_escapes:[469,4,1,""],ansi_map:[469,4,1,""],ansi_map_dict:[469,4,1,""],ansi_re:[469,4,1,""],ansi_regex:[469,4,1,""],ansi_sub:[469,4,1,""],ansi_xterm256_bright_bg_map:[469,4,1,""],ansi_xterm256_bright_bg_map_dict:[469,4,1,""],brightbg_sub:[469,4,1,""],mxp_re:[469,4,1,""],mxp_sub:[469,4,1,""],mxp_url_re:[469,4,1,""],mxp_url_sub:[469,4,1,""],parse_ansi:[469,3,1,""],strip_mxp:[469,3,1,""],strip_raw_codes:[469,3,1,""],strip_unsafe_tokens:[469,3,1,""],sub_ansi:[469,3,1,""],sub_brightbg:[469,3,1,""],sub_xterm256:[469,3,1,""],unsafe_tokens:[469,4,1,""],xterm256_bg:[469,4,1,""],xterm256_bg_sub:[469,4,1,""],xterm256_fg:[469,4,1,""],xterm256_fg_sub:[469,4,1,""],xterm256_gbg:[469,4,1,""],xterm256_gbg_sub:[469,4,1,""],xterm256_gfg:[469,4,1,""],xterm256_gfg_sub:[469,4,1,""]},"evennia.utils.ansi.ANSIString":{__init__:[469,3,1,""],capitalize:[469,3,1,""],center:[469,3,1,""],clean:[469,3,1,""],count:[469,3,1,""],decode:[469,3,1,""],encode:[469,3,1,""],endswith:[469,3,1,""],expandtabs:[469,3,1,""],find:[469,3,1,""],format:[469,3,1,""],index:[469,3,1,""],isalnum:[469,3,1,""],isalpha:[469,3,1,""],isdigit:[469,3,1,""],islower:[469,3,1,""],isspace:[469,3,1,""],istitle:[469,3,1,""],isupper:[469,3,1,""],join:[469,3,1,""],ljust:[469,3,1,""],lower:[469,3,1,""],lstrip:[469,3,1,""],partition:[469,3,1,""],raw:[469,3,1,""],re_format:[469,4,1,""],replace:[469,3,1,""],rfind:[469,3,1,""],rindex:[469,3,1,""],rjust:[469,3,1,""],rsplit:[469,3,1,""],rstrip:[469,3,1,""],split:[469,3,1,""],startswith:[469,3,1,""],strip:[469,3,1,""],swapcase:[469,3,1,""],translate:[469,3,1,""],upper:[469,3,1,""]},"evennia.utils.batchprocessors":{BatchCodeProcessor:[470,1,1,""],BatchCommandProcessor:[470,1,1,""],read_batchfile:[470,5,1,""],tb_filename:[470,5,1,""],tb_iter:[470,5,1,""]},"evennia.utils.batchprocessors.BatchCodeProcessor":{code_exec:[470,3,1,""],parse_file:[470,3,1,""]},"evennia.utils.batchprocessors.BatchCommandProcessor":{parse_file:[470,3,1,""]},"evennia.utils.containers":{Container:[471,1,1,""],GlobalScriptContainer:[471,1,1,""],OptionContainer:[471,1,1,""]},"evennia.utils.containers.Container":{__init__:[471,3,1,""],all:[471,3,1,""],get:[471,3,1,""],load_data:[471,3,1,""],storage_modules:[471,4,1,""]},"evennia.utils.containers.GlobalScriptContainer":{__init__:[471,3,1,""],all:[471,3,1,""],get:[471,3,1,""],load_data:[471,3,1,""],start:[471,3,1,""]},"evennia.utils.containers.OptionContainer":{storage_modules:[471,4,1,""]},"evennia.utils.create":{create_account:[472,5,1,""],create_channel:[472,5,1,""],create_help_entry:[472,5,1,""],create_message:[472,5,1,""],create_object:[472,5,1,""],create_script:[472,5,1,""]},"evennia.utils.dbserialize":{dbserialize:[473,5,1,""],dbunserialize:[473,5,1,""],do_pickle:[473,5,1,""],do_unpickle:[473,5,1,""],from_pickle:[473,5,1,""],to_pickle:[473,5,1,""]},"evennia.utils.eveditor":{CmdEditorBase:[474,1,1,""],CmdEditorGroup:[474,1,1,""],CmdLineInput:[474,1,1,""],CmdSaveYesNo:[474,1,1,""],EvEditor:[474,1,1,""],EvEditorCmdSet:[474,1,1,""],SaveYesNoCmdSet:[474,1,1,""]},"evennia.utils.eveditor.CmdEditorBase":{aliases:[474,4,1,""],editor:[474,4,1,""],help_category:[474,4,1,""],help_entry:[474,4,1,""],key:[474,4,1,""],lock_storage:[474,4,1,""],locks:[474,4,1,""],parse:[474,3,1,""],search_index_entry:[474,4,1,""]},"evennia.utils.eveditor.CmdEditorGroup":{aliases:[474,4,1,""],arg_regex:[474,4,1,""],func:[474,3,1,""],help_category:[474,4,1,""],key:[474,4,1,""],lock_storage:[474,4,1,""],search_index_entry:[474,4,1,""]},"evennia.utils.eveditor.CmdLineInput":{aliases:[474,4,1,""],func:[474,3,1,""],help_category:[474,4,1,""],key:[474,4,1,""],lock_storage:[474,4,1,""],search_index_entry:[474,4,1,""]},"evennia.utils.eveditor.CmdSaveYesNo":{aliases:[474,4,1,""],func:[474,3,1,""],help_category:[474,4,1,""],help_cateogory:[474,4,1,""],key:[474,4,1,""],lock_storage:[474,4,1,""],locks:[474,4,1,""],search_index_entry:[474,4,1,""]},"evennia.utils.eveditor.EvEditor":{__init__:[474,3,1,""],decrease_indent:[474,3,1,""],deduce_indent:[474,3,1,""],display_buffer:[474,3,1,""],display_help:[474,3,1,""],get_buffer:[474,3,1,""],increase_indent:[474,3,1,""],load_buffer:[474,3,1,""],quit:[474,3,1,""],save_buffer:[474,3,1,""],swap_autoindent:[474,3,1,""],update_buffer:[474,3,1,""],update_undo:[474,3,1,""]},"evennia.utils.eveditor.EvEditorCmdSet":{at_cmdset_creation:[474,3,1,""],key:[474,4,1,""],mergetype:[474,4,1,""],path:[474,4,1,""]},"evennia.utils.eveditor.SaveYesNoCmdSet":{at_cmdset_creation:[474,3,1,""],key:[474,4,1,""],mergetype:[474,4,1,""],path:[474,4,1,""],priority:[474,4,1,""]},"evennia.utils.evform":{EvForm:[475,1,1,""]},"evennia.utils.evform.EvForm":{__init__:[475,3,1,""],map:[475,3,1,""],reload:[475,3,1,""]},"evennia.utils.evmenu":{CmdEvMenuNode:[476,1,1,""],CmdGetInput:[476,1,1,""],CmdYesNoQuestion:[476,1,1,""],EvMenu:[476,1,1,""],EvMenuCmdSet:[476,1,1,""],EvMenuError:[476,2,1,""],EvMenuGotoAbortMessage:[476,2,1,""],InputCmdSet:[476,1,1,""],YesNoQuestionCmdSet:[476,1,1,""],ask_yes_no:[476,5,1,""],get_input:[476,5,1,""],list_node:[476,5,1,""],parse_menu_template:[476,5,1,""],template2menu:[476,5,1,""]},"evennia.utils.evmenu.CmdEvMenuNode":{aliases:[476,4,1,""],auto_help_display_key:[476,4,1,""],func:[476,3,1,""],get_help:[476,3,1,""],help_category:[476,4,1,""],key:[476,4,1,""],lock_storage:[476,4,1,""],locks:[476,4,1,""],search_index_entry:[476,4,1,""]},"evennia.utils.evmenu.CmdGetInput":{aliases:[476,4,1,""],func:[476,3,1,""],help_category:[476,4,1,""],key:[476,4,1,""],lock_storage:[476,4,1,""],search_index_entry:[476,4,1,""]},"evennia.utils.evmenu.CmdYesNoQuestion":{aliases:[476,4,1,""],arg_regex:[476,4,1,""],func:[476,3,1,""],help_category:[476,4,1,""],key:[476,4,1,""],lock_storage:[476,4,1,""],search_index_entry:[476,4,1,""]},"evennia.utils.evmenu.EvMenu":{"goto":[476,3,1,""],__init__:[476,3,1,""],close_menu:[476,3,1,""],display_helptext:[476,3,1,""],display_nodetext:[476,3,1,""],extract_goto_exec:[476,3,1,""],helptext_formatter:[476,3,1,""],msg:[476,3,1,""],node_border_char:[476,4,1,""],node_formatter:[476,3,1,""],nodetext_formatter:[476,3,1,""],options_formatter:[476,3,1,""],parse_input:[476,3,1,""],print_debug_info:[476,3,1,""],run_exec:[476,3,1,""],run_exec_then_goto:[476,3,1,""]},"evennia.utils.evmenu.EvMenuCmdSet":{at_cmdset_creation:[476,3,1,""],key:[476,4,1,""],mergetype:[476,4,1,""],no_channels:[476,4,1,""],no_exits:[476,4,1,""],no_objs:[476,4,1,""],path:[476,4,1,""],priority:[476,4,1,""]},"evennia.utils.evmenu.InputCmdSet":{at_cmdset_creation:[476,3,1,""],key:[476,4,1,""],mergetype:[476,4,1,""],no_channels:[476,4,1,""],no_exits:[476,4,1,""],no_objs:[476,4,1,""],path:[476,4,1,""],priority:[476,4,1,""]},"evennia.utils.evmenu.YesNoQuestionCmdSet":{at_cmdset_creation:[476,3,1,""],key:[476,4,1,""],mergetype:[476,4,1,""],no_channels:[476,4,1,""],no_exits:[476,4,1,""],no_objs:[476,4,1,""],path:[476,4,1,""],priority:[476,4,1,""]},"evennia.utils.evmore":{CmdMore:[477,1,1,""],CmdMoreExit:[477,1,1,""],CmdSetMore:[477,1,1,""],EvMore:[477,1,1,""],msg:[477,5,1,""],queryset_maxsize:[477,5,1,""]},"evennia.utils.evmore.CmdMore":{aliases:[477,4,1,""],auto_help:[477,4,1,""],func:[477,3,1,""],help_category:[477,4,1,""],key:[477,4,1,""],lock_storage:[477,4,1,""],search_index_entry:[477,4,1,""]},"evennia.utils.evmore.CmdMoreExit":{aliases:[477,4,1,""],func:[477,3,1,""],help_category:[477,4,1,""],key:[477,4,1,""],lock_storage:[477,4,1,""],search_index_entry:[477,4,1,""]},"evennia.utils.evmore.CmdSetMore":{at_cmdset_creation:[477,3,1,""],key:[477,4,1,""],mergetype:[477,4,1,""],path:[477,4,1,""],priority:[477,4,1,""]},"evennia.utils.evmore.EvMore":{__init__:[477,3,1,""],display:[477,3,1,""],init_django_paginator:[477,3,1,""],init_evtable:[477,3,1,""],init_f_str:[477,3,1,""],init_iterable:[477,3,1,""],init_pages:[477,3,1,""],init_queryset:[477,3,1,""],init_str:[477,3,1,""],page_back:[477,3,1,""],page_end:[477,3,1,""],page_formatter:[477,3,1,""],page_next:[477,3,1,""],page_quit:[477,3,1,""],page_top:[477,3,1,""],paginator:[477,3,1,""],paginator_django:[477,3,1,""],paginator_index:[477,3,1,""],paginator_slice:[477,3,1,""],start:[477,3,1,""]},"evennia.utils.evtable":{ANSITextWrapper:[478,1,1,""],EvCell:[478,1,1,""],EvColumn:[478,1,1,""],EvTable:[478,1,1,""],fill:[478,5,1,""],wrap:[478,5,1,""]},"evennia.utils.evtable.EvCell":{__init__:[478,3,1,""],get:[478,3,1,""],get_height:[478,3,1,""],get_min_height:[478,3,1,""],get_min_width:[478,3,1,""],get_width:[478,3,1,""],reformat:[478,3,1,""],replace_data:[478,3,1,""]},"evennia.utils.evtable.EvColumn":{__init__:[478,3,1,""],add_rows:[478,3,1,""],reformat:[478,3,1,""],reformat_cell:[478,3,1,""]},"evennia.utils.evtable.EvTable":{__init__:[478,3,1,""],add_column:[478,3,1,""],add_header:[478,3,1,""],add_row:[478,3,1,""],get:[478,3,1,""],reformat:[478,3,1,""],reformat_column:[478,3,1,""]},"evennia.utils.funcparser":{FuncParser:[479,1,1,""],ParsingError:[479,2,1,""],funcparser_callable_add:[479,5,1,""],funcparser_callable_center_justify:[479,5,1,""],funcparser_callable_choice:[479,5,1,""],funcparser_callable_clr:[479,5,1,""],funcparser_callable_conjugate:[479,5,1,""],funcparser_callable_crop:[479,5,1,""],funcparser_callable_div:[479,5,1,""],funcparser_callable_eval:[479,5,1,""],funcparser_callable_justify:[479,5,1,""],funcparser_callable_left_justify:[479,5,1,""],funcparser_callable_mult:[479,5,1,""],funcparser_callable_pad:[479,5,1,""],funcparser_callable_pronoun:[479,5,1,""],funcparser_callable_pronoun_capitalize:[479,5,1,""],funcparser_callable_randint:[479,5,1,""],funcparser_callable_random:[479,5,1,""],funcparser_callable_right_justify:[479,5,1,""],funcparser_callable_round:[479,5,1,""],funcparser_callable_search:[479,5,1,""],funcparser_callable_search_list:[479,5,1,""],funcparser_callable_space:[479,5,1,""],funcparser_callable_sub:[479,5,1,""],funcparser_callable_toint:[479,5,1,""],funcparser_callable_you:[479,5,1,""],funcparser_callable_you_capitalize:[479,5,1,""]},"evennia.utils.funcparser.FuncParser":{__init__:[479,3,1,""],execute:[479,3,1,""],parse:[479,3,1,""],parse_to_any:[479,3,1,""],validate_callables:[479,3,1,""]},"evennia.utils.gametime":{TimeScript:[480,1,1,""],game_epoch:[480,5,1,""],gametime:[480,5,1,""],portal_uptime:[480,5,1,""],real_seconds_until:[480,5,1,""],reset_gametime:[480,5,1,""],runtime:[480,5,1,""],schedule:[480,5,1,""],server_epoch:[480,5,1,""],uptime:[480,5,1,""]},"evennia.utils.gametime.TimeScript":{DoesNotExist:[480,2,1,""],MultipleObjectsReturned:[480,2,1,""],at_repeat:[480,3,1,""],at_script_creation:[480,3,1,""],path:[480,4,1,""],typename:[480,4,1,""]},"evennia.utils.idmapper":{manager:[482,0,0,"-"],models:[483,0,0,"-"],tests:[484,0,0,"-"]},"evennia.utils.idmapper.manager":{SharedMemoryManager:[482,1,1,""]},"evennia.utils.idmapper.manager.SharedMemoryManager":{get:[482,3,1,""]},"evennia.utils.idmapper.models":{SharedMemoryModel:[483,1,1,""],SharedMemoryModelBase:[483,1,1,""],WeakSharedMemoryModel:[483,1,1,""],WeakSharedMemoryModelBase:[483,1,1,""],cache_size:[483,5,1,""],conditional_flush:[483,5,1,""],flush_cache:[483,5,1,""],flush_cached_instance:[483,5,1,""],update_cached_instance:[483,5,1,""]},"evennia.utils.idmapper.models.SharedMemoryModel":{"delete":[483,3,1,""],Meta:[483,1,1,""],at_idmapper_flush:[483,3,1,""],cache_instance:[483,3,1,""],flush_cached_instance:[483,3,1,""],flush_from_cache:[483,3,1,""],flush_instance_cache:[483,3,1,""],get_all_cached_instances:[483,3,1,""],get_cached_instance:[483,3,1,""],objects:[483,4,1,""],path:[483,4,1,""],save:[483,3,1,""],typename:[483,4,1,""]},"evennia.utils.idmapper.models.SharedMemoryModel.Meta":{"abstract":[483,4,1,""]},"evennia.utils.idmapper.models.WeakSharedMemoryModel":{Meta:[483,1,1,""],path:[483,4,1,""],typename:[483,4,1,""]},"evennia.utils.idmapper.models.WeakSharedMemoryModel.Meta":{"abstract":[483,4,1,""]},"evennia.utils.idmapper.tests":{Article:[484,1,1,""],Category:[484,1,1,""],RegularArticle:[484,1,1,""],RegularCategory:[484,1,1,""],SharedMemorysTest:[484,1,1,""]},"evennia.utils.idmapper.tests.Article":{DoesNotExist:[484,2,1,""],MultipleObjectsReturned:[484,2,1,""],category2:[484,4,1,""],category2_id:[484,4,1,""],category:[484,4,1,""],category_id:[484,4,1,""],id:[484,4,1,""],name:[484,4,1,""],path:[484,4,1,""],typename:[484,4,1,""]},"evennia.utils.idmapper.tests.Category":{DoesNotExist:[484,2,1,""],MultipleObjectsReturned:[484,2,1,""],article_set:[484,4,1,""],id:[484,4,1,""],name:[484,4,1,""],path:[484,4,1,""],regulararticle_set:[484,4,1,""],typename:[484,4,1,""]},"evennia.utils.idmapper.tests.RegularArticle":{DoesNotExist:[484,2,1,""],MultipleObjectsReturned:[484,2,1,""],category2:[484,4,1,""],category2_id:[484,4,1,""],category:[484,4,1,""],category_id:[484,4,1,""],id:[484,4,1,""],name:[484,4,1,""],objects:[484,4,1,""]},"evennia.utils.idmapper.tests.RegularCategory":{DoesNotExist:[484,2,1,""],MultipleObjectsReturned:[484,2,1,""],article_set:[484,4,1,""],id:[484,4,1,""],name:[484,4,1,""],objects:[484,4,1,""],regulararticle_set:[484,4,1,""]},"evennia.utils.idmapper.tests.SharedMemorysTest":{setUp:[484,3,1,""],testMixedReferences:[484,3,1,""],testObjectDeletion:[484,3,1,""],testRegularReferences:[484,3,1,""],testSharedMemoryReferences:[484,3,1,""]},"evennia.utils.logger":{EvenniaLogFile:[485,1,1,""],PortalLogObserver:[485,1,1,""],ServerLogObserver:[485,1,1,""],WeeklyLogFile:[485,1,1,""],log_dep:[485,5,1,""],log_depmsg:[485,5,1,""],log_err:[485,5,1,""],log_errmsg:[485,5,1,""],log_file:[485,5,1,""],log_file_exists:[485,5,1,""],log_info:[485,5,1,""],log_infomsg:[485,5,1,""],log_msg:[485,5,1,""],log_sec:[485,5,1,""],log_secmsg:[485,5,1,""],log_server:[485,5,1,""],log_trace:[485,5,1,""],log_tracemsg:[485,5,1,""],log_warn:[485,5,1,""],log_warnmsg:[485,5,1,""],rotate_log_file:[485,5,1,""],tail_log_file:[485,5,1,""],timeformat:[485,5,1,""]},"evennia.utils.logger.EvenniaLogFile":{num_lines_to_append:[485,4,1,""],readlines:[485,3,1,""],rotate:[485,3,1,""],seek:[485,3,1,""],settings:[485,4,1,""]},"evennia.utils.logger.PortalLogObserver":{emit:[485,3,1,""],prefix:[485,4,1,""],timeFormat:[485,4,1,""]},"evennia.utils.logger.ServerLogObserver":{prefix:[485,4,1,""]},"evennia.utils.logger.WeeklyLogFile":{__init__:[485,3,1,""],shouldRotate:[485,3,1,""],suffix:[485,3,1,""],write:[485,3,1,""]},"evennia.utils.optionclasses":{BaseOption:[486,1,1,""],Boolean:[486,1,1,""],Color:[486,1,1,""],Datetime:[486,1,1,""],Duration:[486,1,1,""],Email:[486,1,1,""],Future:[486,1,1,""],Lock:[486,1,1,""],PositiveInteger:[486,1,1,""],SignedInteger:[486,1,1,""],Text:[486,1,1,""],Timezone:[486,1,1,""],UnsignedInteger:[486,1,1,""]},"evennia.utils.optionclasses.BaseOption":{"default":[486,3,1,""],__init__:[486,3,1,""],changed:[486,3,1,""],deserialize:[486,3,1,""],display:[486,3,1,""],load:[486,3,1,""],save:[486,3,1,""],serialize:[486,3,1,""],set:[486,3,1,""],validate:[486,3,1,""],value:[486,3,1,""]},"evennia.utils.optionclasses.Boolean":{deserialize:[486,3,1,""],display:[486,3,1,""],serialize:[486,3,1,""],validate:[486,3,1,""]},"evennia.utils.optionclasses.Color":{deserialize:[486,3,1,""],display:[486,3,1,""],validate:[486,3,1,""]},"evennia.utils.optionclasses.Datetime":{deserialize:[486,3,1,""],serialize:[486,3,1,""],validate:[486,3,1,""]},"evennia.utils.optionclasses.Duration":{deserialize:[486,3,1,""],serialize:[486,3,1,""],validate:[486,3,1,""]},"evennia.utils.optionclasses.Email":{deserialize:[486,3,1,""],validate:[486,3,1,""]},"evennia.utils.optionclasses.Future":{validate:[486,3,1,""]},"evennia.utils.optionclasses.Lock":{validate:[486,3,1,""]},"evennia.utils.optionclasses.PositiveInteger":{deserialize:[486,3,1,""],validate:[486,3,1,""]},"evennia.utils.optionclasses.SignedInteger":{deserialize:[486,3,1,""],validate:[486,3,1,""]},"evennia.utils.optionclasses.Text":{deserialize:[486,3,1,""]},"evennia.utils.optionclasses.Timezone":{"default":[486,3,1,""],deserialize:[486,3,1,""],serialize:[486,3,1,""],validate:[486,3,1,""]},"evennia.utils.optionclasses.UnsignedInteger":{deserialize:[486,3,1,""],validate:[486,3,1,""],validator_key:[486,4,1,""]},"evennia.utils.optionhandler":{InMemorySaveHandler:[487,1,1,""],OptionHandler:[487,1,1,""]},"evennia.utils.optionhandler.InMemorySaveHandler":{__init__:[487,3,1,""],add:[487,3,1,""],get:[487,3,1,""]},"evennia.utils.optionhandler.OptionHandler":{__init__:[487,3,1,""],all:[487,3,1,""],get:[487,3,1,""],set:[487,3,1,""]},"evennia.utils.picklefield":{PickledFormField:[488,1,1,""],PickledObject:[488,1,1,""],PickledObjectField:[488,1,1,""],PickledWidget:[488,1,1,""],dbsafe_decode:[488,5,1,""],dbsafe_encode:[488,5,1,""],wrap_conflictual_object:[488,5,1,""]},"evennia.utils.picklefield.PickledFormField":{__init__:[488,3,1,""],clean:[488,3,1,""],default_error_messages:[488,4,1,""],widget:[488,4,1,""]},"evennia.utils.picklefield.PickledObjectField":{__init__:[488,3,1,""],formfield:[488,3,1,""],from_db_value:[488,3,1,""],get_db_prep_lookup:[488,3,1,""],get_db_prep_value:[488,3,1,""],get_default:[488,3,1,""],get_internal_type:[488,3,1,""],pre_save:[488,3,1,""],value_to_string:[488,3,1,""]},"evennia.utils.picklefield.PickledWidget":{media:[488,3,1,""],render:[488,3,1,""],value_from_datadict:[488,3,1,""]},"evennia.utils.search":{search_account:[489,5,1,""],search_account_tag:[489,5,1,""],search_channel:[489,5,1,""],search_channel_tag:[489,5,1,""],search_help_entry:[489,5,1,""],search_message:[489,5,1,""],search_object:[489,5,1,""],search_script:[489,5,1,""],search_script_tag:[489,5,1,""],search_tag:[489,5,1,""]},"evennia.utils.test_resources":{BaseEvenniaCommandTest:[490,1,1,""],BaseEvenniaTest:[490,1,1,""],BaseEvenniaTestCase:[490,1,1,""],EvenniaCommandTest:[490,1,1,""],EvenniaCommandTestMixin:[490,1,1,""],EvenniaTest:[490,1,1,""],EvenniaTestCase:[490,1,1,""],EvenniaTestMixin:[490,1,1,""],mockdeferLater:[490,5,1,""],mockdelay:[490,5,1,""],unload_module:[490,5,1,""]},"evennia.utils.test_resources.EvenniaCommandTestMixin":{call:[490,3,1,""]},"evennia.utils.test_resources.EvenniaTest":{account_typeclass:[490,4,1,""],character_typeclass:[490,4,1,""],exit_typeclass:[490,4,1,""],object_typeclass:[490,4,1,""],room_typeclass:[490,4,1,""],script_typeclass:[490,4,1,""]},"evennia.utils.test_resources.EvenniaTestMixin":{account_typeclass:[490,4,1,""],character_typeclass:[490,4,1,""],create_accounts:[490,3,1,""],create_chars:[490,3,1,""],create_objs:[490,3,1,""],create_rooms:[490,3,1,""],create_script:[490,3,1,""],exit_typeclass:[490,4,1,""],object_typeclass:[490,4,1,""],room_typeclass:[490,4,1,""],script_typeclass:[490,4,1,""],setUp:[490,3,1,""],setup_session:[490,3,1,""],tearDown:[490,3,1,""],teardown_accounts:[490,3,1,""],teardown_session:[490,3,1,""]},"evennia.utils.text2html":{TextToHTMLparser:[491,1,1,""],parse_html:[491,5,1,""]},"evennia.utils.text2html.TextToHTMLparser":{bg_colormap:[491,4,1,""],bgfgstart:[491,4,1,""],bgfgstop:[491,4,1,""],bgstart:[491,4,1,""],bgstop:[491,4,1,""],blink:[491,4,1,""],colorback:[491,4,1,""],colorcodes:[491,4,1,""],convert_linebreaks:[491,3,1,""],convert_urls:[491,3,1,""],fg_colormap:[491,4,1,""],fgstart:[491,4,1,""],fgstop:[491,4,1,""],hilite:[491,4,1,""],inverse:[491,4,1,""],normal:[491,4,1,""],parse:[491,3,1,""],re_bgfg:[491,4,1,""],re_bgs:[491,4,1,""],re_blink:[491,4,1,""],re_blinking:[491,3,1,""],re_bold:[491,3,1,""],re_color:[491,3,1,""],re_dblspace:[491,4,1,""],re_double_space:[491,3,1,""],re_fgs:[491,4,1,""],re_hilite:[491,4,1,""],re_inverse:[491,4,1,""],re_inversing:[491,3,1,""],re_mxplink:[491,4,1,""],re_mxpurl:[491,4,1,""],re_normal:[491,4,1,""],re_string:[491,4,1,""],re_uline:[491,4,1,""],re_underline:[491,3,1,""],re_unhilite:[491,4,1,""],re_url:[491,4,1,""],remove_backspaces:[491,3,1,""],remove_bells:[491,3,1,""],sub_dblspace:[491,3,1,""],sub_mxp_links:[491,3,1,""],sub_mxp_urls:[491,3,1,""],sub_text:[491,3,1,""],tabstop:[491,4,1,""],underline:[491,4,1,""],unhilite:[491,4,1,""]},"evennia.utils.utils":{LimitedSizeOrderedDict:[492,1,1,""],all_from_module:[492,5,1,""],at_search_result:[492,5,1,""],callables_from_module:[492,5,1,""],calledby:[492,5,1,""],check_evennia_dependencies:[492,5,1,""],class_from_module:[492,5,1,""],columnize:[492,5,1,""],copy_word_case:[492,5,1,""],crop:[492,5,1,""],datetime_format:[492,5,1,""],dbid_to_obj:[492,5,1,""],dbref:[492,5,1,""],dbref_to_obj:[492,5,1,""],dedent:[492,5,1,""],deepsize:[492,5,1,""],delay:[492,5,1,""],display_len:[492,5,1,""],fill:[492,5,1,""],format_grid:[492,5,1,""],format_table:[492,5,1,""],fuzzy_import_from_module:[492,5,1,""],get_all_cmdsets:[492,5,1,""],get_all_typeclasses:[492,5,1,""],get_evennia_pids:[492,5,1,""],get_evennia_version:[492,5,1,""],get_game_dir_path:[492,5,1,""],has_parent:[492,5,1,""],host_os_is:[492,5,1,""],inherits_from:[492,5,1,""],init_new_account:[492,5,1,""],interactive:[492,5,1,""],is_iter:[492,5,1,""],iter_to_str:[492,5,1,""],iter_to_string:[492,5,1,""],justify:[492,5,1,""],latinify:[492,5,1,""],lazy_property:[492,1,1,""],list_to_string:[492,5,1,""],m_len:[492,5,1,""],make_iter:[492,5,1,""],mod_import:[492,5,1,""],mod_import_from_path:[492,5,1,""],object_from_module:[492,5,1,""],pad:[492,5,1,""],percent:[492,5,1,""],percentile:[492,5,1,""],pypath_to_realpath:[492,5,1,""],random_string_from_module:[492,5,1,""],repeat:[492,5,1,""],run_async:[492,5,1,""],safe_convert_to_types:[492,5,1,""],server_services:[492,5,1,""],string_from_module:[492,5,1,""],string_partial_matching:[492,5,1,""],string_similarity:[492,5,1,""],string_suggestions:[492,5,1,""],strip_control_sequences:[492,5,1,""],strip_unsafe_input:[492,5,1,""],time_format:[492,5,1,""],to_bytes:[492,5,1,""],to_str:[492,5,1,""],unrepeat:[492,5,1,""],uses_database:[492,5,1,""],validate_email_address:[492,5,1,""],variable_from_module:[492,5,1,""],wildcard_to_regexp:[492,5,1,""],wrap:[492,5,1,""]},"evennia.utils.utils.LimitedSizeOrderedDict":{__init__:[492,3,1,""],update:[492,3,1,""]},"evennia.utils.utils.lazy_property":{__init__:[492,3,1,""]},"evennia.utils.validatorfuncs":{"boolean":[493,5,1,""],color:[493,5,1,""],datetime:[493,5,1,""],duration:[493,5,1,""],email:[493,5,1,""],future:[493,5,1,""],lock:[493,5,1,""],positive_integer:[493,5,1,""],signed_integer:[493,5,1,""],text:[493,5,1,""],timezone:[493,5,1,""],unsigned_integer:[493,5,1,""]},"evennia.utils.verb_conjugation":{conjugate:[495,0,0,"-"],pronouns:[496,0,0,"-"],tests:[497,0,0,"-"]},"evennia.utils.verb_conjugation.conjugate":{verb_actor_stance_components:[495,5,1,""],verb_all_tenses:[495,5,1,""],verb_conjugate:[495,5,1,""],verb_infinitive:[495,5,1,""],verb_is_past:[495,5,1,""],verb_is_past_participle:[495,5,1,""],verb_is_present:[495,5,1,""],verb_is_present_participle:[495,5,1,""],verb_is_tense:[495,5,1,""],verb_past:[495,5,1,""],verb_past_participle:[495,5,1,""],verb_present:[495,5,1,""],verb_present_participle:[495,5,1,""],verb_tense:[495,5,1,""]},"evennia.utils.verb_conjugation.pronouns":{pronoun_to_viewpoints:[496,5,1,""]},"evennia.utils.verb_conjugation.tests":{TestPronounMapping:[497,1,1,""],TestVerbConjugate:[497,1,1,""]},"evennia.utils.verb_conjugation.tests.TestPronounMapping":{test_mapping_with_options:[497,4,1,""],test_mapping_with_options_00_you:[497,3,1,""],test_mapping_with_options_01_you:[497,3,1,""],test_mapping_with_options_02_I:[497,3,1,""],test_mapping_with_options_03_I:[497,3,1,""],test_mapping_with_options_04_I:[497,3,1,""],test_mapping_with_options_05_Me:[497,3,1,""],test_mapping_with_options_06_your:[497,3,1,""],test_mapping_with_options_07_ours:[497,3,1,""],test_mapping_with_options_08_yourself:[497,3,1,""],test_mapping_with_options_09_yourself:[497,3,1,""],test_mapping_with_options_10_yourself:[497,3,1,""],test_mapping_with_options_11_yourself:[497,3,1,""],test_mapping_with_options_12_yourselves:[497,3,1,""],test_mapping_with_options_13_he:[497,3,1,""],test_mapping_with_options_14_he:[497,3,1,""],test_mapping_with_options_15_he:[497,3,1,""],test_mapping_with_options_16_her:[497,3,1,""],test_mapping_with_options_17_her:[497,3,1,""],test_mapping_with_options_18_their:[497,3,1,""],test_mapping_with_options_19_their:[497,3,1,""],test_mapping_with_options_20_itself:[497,3,1,""],test_mapping_with_options_21_themselves:[497,3,1,""],test_mapping_with_options_22_herself:[497,3,1,""]},"evennia.utils.verb_conjugation.tests.TestVerbConjugate":{test_verb_actor_stance_components:[497,4,1,""],test_verb_actor_stance_components_00_have:[497,3,1,""],test_verb_actor_stance_components_01_swimming:[497,3,1,""],test_verb_actor_stance_components_02_give:[497,3,1,""],test_verb_actor_stance_components_03_given:[497,3,1,""],test_verb_actor_stance_components_04_am:[497,3,1,""],test_verb_actor_stance_components_05_doing:[497,3,1,""],test_verb_actor_stance_components_06_are:[497,3,1,""],test_verb_actor_stance_components_07_had:[497,3,1,""],test_verb_actor_stance_components_08_grin:[497,3,1,""],test_verb_actor_stance_components_09_smile:[497,3,1,""],test_verb_actor_stance_components_10_vex:[497,3,1,""],test_verb_actor_stance_components_11_thrust:[497,3,1,""],test_verb_conjugate:[497,4,1,""],test_verb_conjugate_0_inf:[497,3,1,""],test_verb_conjugate_1_inf:[497,3,1,""],test_verb_conjugate_2_inf:[497,3,1,""],test_verb_conjugate_3_inf:[497,3,1,""],test_verb_conjugate_4_inf:[497,3,1,""],test_verb_conjugate_5_inf:[497,3,1,""],test_verb_conjugate_6_inf:[497,3,1,""],test_verb_conjugate_7_2sgpres:[497,3,1,""],test_verb_conjugate_8_3sgpres:[497,3,1,""],test_verb_get_all_tenses:[497,3,1,""],test_verb_infinitive:[497,4,1,""],test_verb_infinitive_0_have:[497,3,1,""],test_verb_infinitive_1_swim:[497,3,1,""],test_verb_infinitive_2_give:[497,3,1,""],test_verb_infinitive_3_given:[497,3,1,""],test_verb_infinitive_4_am:[497,3,1,""],test_verb_infinitive_5_doing:[497,3,1,""],test_verb_infinitive_6_are:[497,3,1,""],test_verb_is_past:[497,4,1,""],test_verb_is_past_0_1st:[497,3,1,""],test_verb_is_past_1_1st:[497,3,1,""],test_verb_is_past_2_1st:[497,3,1,""],test_verb_is_past_3_1st:[497,3,1,""],test_verb_is_past_4_1st:[497,3,1,""],test_verb_is_past_5_1st:[497,3,1,""],test_verb_is_past_6_1st:[497,3,1,""],test_verb_is_past_7_2nd:[497,3,1,""],test_verb_is_past_participle:[497,4,1,""],test_verb_is_past_participle_0_have:[497,3,1,""],test_verb_is_past_participle_1_swimming:[497,3,1,""],test_verb_is_past_participle_2_give:[497,3,1,""],test_verb_is_past_participle_3_given:[497,3,1,""],test_verb_is_past_participle_4_am:[497,3,1,""],test_verb_is_past_participle_5_doing:[497,3,1,""],test_verb_is_past_participle_6_are:[497,3,1,""],test_verb_is_past_participle_7_had:[497,3,1,""],test_verb_is_present:[497,4,1,""],test_verb_is_present_0_1st:[497,3,1,""],test_verb_is_present_1_1st:[497,3,1,""],test_verb_is_present_2_1st:[497,3,1,""],test_verb_is_present_3_1st:[497,3,1,""],test_verb_is_present_4_1st:[497,3,1,""],test_verb_is_present_5_1st:[497,3,1,""],test_verb_is_present_6_1st:[497,3,1,""],test_verb_is_present_7_1st:[497,3,1,""],test_verb_is_present_participle:[497,4,1,""],test_verb_is_present_participle_0_have:[497,3,1,""],test_verb_is_present_participle_1_swim:[497,3,1,""],test_verb_is_present_participle_2_give:[497,3,1,""],test_verb_is_present_participle_3_given:[497,3,1,""],test_verb_is_present_participle_4_am:[497,3,1,""],test_verb_is_present_participle_5_doing:[497,3,1,""],test_verb_is_present_participle_6_are:[497,3,1,""],test_verb_is_tense:[497,4,1,""],test_verb_is_tense_0_inf:[497,3,1,""],test_verb_is_tense_1_inf:[497,3,1,""],test_verb_is_tense_2_inf:[497,3,1,""],test_verb_is_tense_3_inf:[497,3,1,""],test_verb_is_tense_4_inf:[497,3,1,""],test_verb_is_tense_5_inf:[497,3,1,""],test_verb_is_tense_6_inf:[497,3,1,""],test_verb_past:[497,4,1,""],test_verb_past_0_1st:[497,3,1,""],test_verb_past_1_1st:[497,3,1,""],test_verb_past_2_1st:[497,3,1,""],test_verb_past_3_1st:[497,3,1,""],test_verb_past_4_1st:[497,3,1,""],test_verb_past_5_1st:[497,3,1,""],test_verb_past_6_1st:[497,3,1,""],test_verb_past_7_2nd:[497,3,1,""],test_verb_past_participle:[497,4,1,""],test_verb_past_participle_0_have:[497,3,1,""],test_verb_past_participle_1_swim:[497,3,1,""],test_verb_past_participle_2_give:[497,3,1,""],test_verb_past_participle_3_given:[497,3,1,""],test_verb_past_participle_4_am:[497,3,1,""],test_verb_past_participle_5_doing:[497,3,1,""],test_verb_past_participle_6_are:[497,3,1,""],test_verb_present:[497,4,1,""],test_verb_present_0_1st:[497,3,1,""],test_verb_present_1_1st:[497,3,1,""],test_verb_present_2_1st:[497,3,1,""],test_verb_present_3_1st:[497,3,1,""],test_verb_present_4_1st:[497,3,1,""],test_verb_present_5_1st:[497,3,1,""],test_verb_present_6_1st:[497,3,1,""],test_verb_present_7_2nd:[497,3,1,""],test_verb_present_8_3rd:[497,3,1,""],test_verb_present_participle:[497,4,1,""],test_verb_present_participle_0_have:[497,3,1,""],test_verb_present_participle_1_swim:[497,3,1,""],test_verb_present_participle_2_give:[497,3,1,""],test_verb_present_participle_3_given:[497,3,1,""],test_verb_present_participle_4_am:[497,3,1,""],test_verb_present_participle_5_doing:[497,3,1,""],test_verb_present_participle_6_are:[497,3,1,""],test_verb_tense:[497,4,1,""],test_verb_tense_0_have:[497,3,1,""],test_verb_tense_1_swim:[497,3,1,""],test_verb_tense_2_give:[497,3,1,""],test_verb_tense_3_given:[497,3,1,""],test_verb_tense_4_am:[497,3,1,""],test_verb_tense_5_doing:[497,3,1,""],test_verb_tense_6_are:[497,3,1,""]},"evennia.web":{admin:[499,0,0,"-"],api:[511,0,0,"-"],templatetags:[519,0,0,"-"],urls:[521,0,0,"-"],utils:[522,0,0,"-"],webclient:[528,0,0,"-"],website:[531,0,0,"-"]},"evennia.web.admin":{accounts:[500,0,0,"-"],attributes:[501,0,0,"-"],comms:[502,0,0,"-"],frontpage:[503,0,0,"-"],help:[504,0,0,"-"],objects:[505,0,0,"-"],scripts:[506,0,0,"-"],server:[507,0,0,"-"],tags:[508,0,0,"-"],urls:[509,0,0,"-"],utils:[510,0,0,"-"]},"evennia.web.admin.accounts":{AccountAdmin:[500,1,1,""],AccountAttributeInline:[500,1,1,""],AccountChangeForm:[500,1,1,""],AccountCreationForm:[500,1,1,""],AccountTagInline:[500,1,1,""],ObjectPuppetInline:[500,1,1,""]},"evennia.web.admin.accounts.AccountAdmin":{add_fieldsets:[500,4,1,""],add_form:[500,4,1,""],fieldsets:[500,4,1,""],form:[500,4,1,""],get_form:[500,3,1,""],inlines:[500,4,1,""],list_display:[500,4,1,""],list_display_links:[500,4,1,""],list_filter:[500,4,1,""],media:[500,3,1,""],ordering:[500,4,1,""],puppeted_objects:[500,3,1,""],readonly_fields:[500,4,1,""],response_add:[500,3,1,""],save_model:[500,3,1,""],search_fields:[500,4,1,""],serialized_string:[500,3,1,""],user_change_password:[500,3,1,""],view_on_site:[500,4,1,""]},"evennia.web.admin.accounts.AccountAttributeInline":{media:[500,3,1,""],model:[500,4,1,""],related_field:[500,4,1,""]},"evennia.web.admin.accounts.AccountChangeForm":{Meta:[500,1,1,""],__init__:[500,3,1,""],base_fields:[500,4,1,""],clean_username:[500,3,1,""],declared_fields:[500,4,1,""],media:[500,3,1,""]},"evennia.web.admin.accounts.AccountChangeForm.Meta":{fields:[500,4,1,""],model:[500,4,1,""]},"evennia.web.admin.accounts.AccountCreationForm":{Meta:[500,1,1,""],base_fields:[500,4,1,""],clean_username:[500,3,1,""],declared_fields:[500,4,1,""],media:[500,3,1,""]},"evennia.web.admin.accounts.AccountCreationForm.Meta":{fields:[500,4,1,""],model:[500,4,1,""]},"evennia.web.admin.accounts.AccountTagInline":{media:[500,3,1,""],model:[500,4,1,""],related_field:[500,4,1,""]},"evennia.web.admin.accounts.ObjectPuppetInline":{ObjectCreateForm:[500,1,1,""],extra:[500,4,1,""],fieldsets:[500,4,1,""],form:[500,4,1,""],has_add_permission:[500,3,1,""],has_delete_permission:[500,3,1,""],media:[500,3,1,""],model:[500,4,1,""],readonly_fields:[500,4,1,""],show_change_link:[500,4,1,""],verbose_name:[500,4,1,""],view_on_site:[500,4,1,""]},"evennia.web.admin.accounts.ObjectPuppetInline.ObjectCreateForm":{Meta:[500,1,1,""],__init__:[500,3,1,""],base_fields:[500,4,1,""],declared_fields:[500,4,1,""],media:[500,3,1,""]},"evennia.web.admin.accounts.ObjectPuppetInline.ObjectCreateForm.Meta":{fields:[500,4,1,""],model:[500,4,1,""]},"evennia.web.admin.attributes":{AttributeForm:[501,1,1,""],AttributeFormSet:[501,1,1,""],AttributeInline:[501,1,1,""]},"evennia.web.admin.attributes.AttributeForm":{Meta:[501,1,1,""],__init__:[501,3,1,""],base_fields:[501,4,1,""],clean_attr_value:[501,3,1,""],declared_fields:[501,4,1,""],media:[501,3,1,""],save:[501,3,1,""]},"evennia.web.admin.attributes.AttributeForm.Meta":{fields:[501,4,1,""]},"evennia.web.admin.attributes.AttributeFormSet":{save:[501,3,1,""]},"evennia.web.admin.attributes.AttributeInline":{extra:[501,4,1,""],form:[501,4,1,""],formset:[501,4,1,""],get_formset:[501,3,1,""],media:[501,3,1,""],model:[501,4,1,""],related_field:[501,4,1,""],verbose_name:[501,4,1,""],verbose_name_plural:[501,4,1,""]},"evennia.web.admin.comms":{ChannelAdmin:[502,1,1,""],ChannelAttributeInline:[502,1,1,""],ChannelForm:[502,1,1,""],ChannelTagInline:[502,1,1,""],MsgAdmin:[502,1,1,""],MsgForm:[502,1,1,""],MsgTagInline:[502,1,1,""]},"evennia.web.admin.comms.ChannelAdmin":{fieldsets:[502,4,1,""],form:[502,4,1,""],get_form:[502,3,1,""],inlines:[502,4,1,""],list_display:[502,4,1,""],list_display_links:[502,4,1,""],list_select_related:[502,4,1,""],media:[502,3,1,""],no_of_subscribers:[502,3,1,""],ordering:[502,4,1,""],raw_id_fields:[502,4,1,""],readonly_fields:[502,4,1,""],response_add:[502,3,1,""],save_as:[502,4,1,""],save_model:[502,3,1,""],save_on_top:[502,4,1,""],search_fields:[502,4,1,""],serialized_string:[502,3,1,""],subscriptions:[502,3,1,""]},"evennia.web.admin.comms.ChannelAttributeInline":{media:[502,3,1,""],model:[502,4,1,""],related_field:[502,4,1,""]},"evennia.web.admin.comms.ChannelForm":{Meta:[502,1,1,""],base_fields:[502,4,1,""],declared_fields:[502,4,1,""],media:[502,3,1,""]},"evennia.web.admin.comms.ChannelForm.Meta":{fields:[502,4,1,""],model:[502,4,1,""]},"evennia.web.admin.comms.ChannelTagInline":{media:[502,3,1,""],model:[502,4,1,""],related_field:[502,4,1,""]},"evennia.web.admin.comms.MsgAdmin":{fieldsets:[502,4,1,""],form:[502,4,1,""],get_form:[502,3,1,""],inlines:[502,4,1,""],list_display:[502,4,1,""],list_display_links:[502,4,1,""],list_select_related:[502,4,1,""],media:[502,3,1,""],ordering:[502,4,1,""],raw_id_fields:[502,4,1,""],readonly_fields:[502,4,1,""],receiver:[502,3,1,""],save_as:[502,4,1,""],save_on_top:[502,4,1,""],search_fields:[502,4,1,""],sender:[502,3,1,""],serialized_string:[502,3,1,""],start_of_message:[502,3,1,""],view_on_site:[502,4,1,""]},"evennia.web.admin.comms.MsgForm":{Meta:[502,1,1,""],base_fields:[502,4,1,""],declared_fields:[502,4,1,""],media:[502,3,1,""]},"evennia.web.admin.comms.MsgForm.Meta":{fields:[502,4,1,""],models:[502,4,1,""]},"evennia.web.admin.comms.MsgTagInline":{media:[502,3,1,""],model:[502,4,1,""],related_field:[502,4,1,""]},"evennia.web.admin.frontpage":{admin_wrapper:[503,5,1,""],evennia_admin:[503,5,1,""]},"evennia.web.admin.help":{HelpEntryAdmin:[504,1,1,""],HelpEntryForm:[504,1,1,""],HelpTagInline:[504,1,1,""]},"evennia.web.admin.help.HelpEntryAdmin":{fieldsets:[504,4,1,""],form:[504,4,1,""],inlines:[504,4,1,""],list_display:[504,4,1,""],list_display_links:[504,4,1,""],list_filter:[504,4,1,""],list_select_related:[504,4,1,""],media:[504,3,1,""],ordering:[504,4,1,""],save_as:[504,4,1,""],save_on_top:[504,4,1,""],search_fields:[504,4,1,""],view_on_site:[504,4,1,""]},"evennia.web.admin.help.HelpEntryForm":{Meta:[504,1,1,""],base_fields:[504,4,1,""],declared_fields:[504,4,1,""],media:[504,3,1,""]},"evennia.web.admin.help.HelpEntryForm.Meta":{fields:[504,4,1,""],model:[504,4,1,""]},"evennia.web.admin.help.HelpTagInline":{media:[504,3,1,""],model:[504,4,1,""],related_field:[504,4,1,""]},"evennia.web.admin.objects":{ObjectAdmin:[505,1,1,""],ObjectAttributeInline:[505,1,1,""],ObjectCreateForm:[505,1,1,""],ObjectEditForm:[505,1,1,""],ObjectTagInline:[505,1,1,""]},"evennia.web.admin.objects.ObjectAdmin":{add_fieldsets:[505,4,1,""],add_form:[505,4,1,""],fieldsets:[505,4,1,""],form:[505,4,1,""],get_fieldsets:[505,3,1,""],get_form:[505,3,1,""],get_urls:[505,3,1,""],inlines:[505,4,1,""],link_button:[505,3,1,""],link_object_to_account:[505,3,1,""],list_display:[505,4,1,""],list_display_links:[505,4,1,""],list_filter:[505,4,1,""],list_select_related:[505,4,1,""],media:[505,3,1,""],ordering:[505,4,1,""],raw_id_fields:[505,4,1,""],readonly_fields:[505,4,1,""],response_add:[505,3,1,""],save_as:[505,4,1,""],save_model:[505,3,1,""],save_on_top:[505,4,1,""],search_fields:[505,4,1,""],serialized_string:[505,3,1,""],view_on_site:[505,4,1,""]},"evennia.web.admin.objects.ObjectAttributeInline":{media:[505,3,1,""],model:[505,4,1,""],related_field:[505,4,1,""]},"evennia.web.admin.objects.ObjectCreateForm":{Meta:[505,1,1,""],__init__:[505,3,1,""],base_fields:[505,4,1,""],declared_fields:[505,4,1,""],media:[505,3,1,""]},"evennia.web.admin.objects.ObjectCreateForm.Meta":{fields:[505,4,1,""],model:[505,4,1,""]},"evennia.web.admin.objects.ObjectEditForm":{Meta:[505,1,1,""],base_fields:[505,4,1,""],declared_fields:[505,4,1,""],media:[505,3,1,""]},"evennia.web.admin.objects.ObjectEditForm.Meta":{fields:[505,4,1,""],model:[505,4,1,""]},"evennia.web.admin.objects.ObjectTagInline":{media:[505,3,1,""],model:[505,4,1,""],related_field:[505,4,1,""]},"evennia.web.admin.scripts":{ScriptAdmin:[506,1,1,""],ScriptAttributeInline:[506,1,1,""],ScriptForm:[506,1,1,""],ScriptTagInline:[506,1,1,""]},"evennia.web.admin.scripts.ScriptAdmin":{fieldsets:[506,4,1,""],form:[506,4,1,""],get_form:[506,3,1,""],inlines:[506,4,1,""],list_display:[506,4,1,""],list_display_links:[506,4,1,""],list_select_related:[506,4,1,""],media:[506,3,1,""],ordering:[506,4,1,""],raw_id_fields:[506,4,1,""],readonly_fields:[506,4,1,""],save_as:[506,4,1,""],save_model:[506,3,1,""],save_on_top:[506,4,1,""],search_fields:[506,4,1,""],serialized_string:[506,3,1,""],view_on_site:[506,4,1,""]},"evennia.web.admin.scripts.ScriptAttributeInline":{media:[506,3,1,""],model:[506,4,1,""],related_field:[506,4,1,""]},"evennia.web.admin.scripts.ScriptForm":{base_fields:[506,4,1,""],declared_fields:[506,4,1,""],media:[506,3,1,""]},"evennia.web.admin.scripts.ScriptTagInline":{media:[506,3,1,""],model:[506,4,1,""],related_field:[506,4,1,""]},"evennia.web.admin.server":{ServerConfigAdmin:[507,1,1,""]},"evennia.web.admin.server.ServerConfigAdmin":{list_display:[507,4,1,""],list_display_links:[507,4,1,""],list_select_related:[507,4,1,""],media:[507,3,1,""],ordering:[507,4,1,""],save_as:[507,4,1,""],save_on_top:[507,4,1,""],search_fields:[507,4,1,""]},"evennia.web.admin.tags":{InlineTagForm:[508,1,1,""],TagAdmin:[508,1,1,""],TagForm:[508,1,1,""],TagFormSet:[508,1,1,""],TagInline:[508,1,1,""]},"evennia.web.admin.tags.InlineTagForm":{Meta:[508,1,1,""],__init__:[508,3,1,""],base_fields:[508,4,1,""],declared_fields:[508,4,1,""],media:[508,3,1,""],save:[508,3,1,""]},"evennia.web.admin.tags.InlineTagForm.Meta":{fields:[508,4,1,""]},"evennia.web.admin.tags.TagAdmin":{fieldsets:[508,4,1,""],form:[508,4,1,""],list_display:[508,4,1,""],list_filter:[508,4,1,""],media:[508,3,1,""],search_fields:[508,4,1,""],view_on_site:[508,4,1,""]},"evennia.web.admin.tags.TagForm":{Meta:[508,1,1,""],base_fields:[508,4,1,""],declared_fields:[508,4,1,""],media:[508,3,1,""]},"evennia.web.admin.tags.TagForm.Meta":{fields:[508,4,1,""]},"evennia.web.admin.tags.TagFormSet":{save:[508,3,1,""],verbose_name:[508,4,1,""],verbose_name_plural:[508,4,1,""]},"evennia.web.admin.tags.TagInline":{extra:[508,4,1,""],form:[508,4,1,""],formset:[508,4,1,""],get_formset:[508,3,1,""],media:[508,3,1,""],model:[508,4,1,""],related_field:[508,4,1,""],verbose_name:[508,4,1,""],verbose_name_plural:[508,4,1,""]},"evennia.web.admin.utils":{get_and_load_cmdsets:[510,5,1,""],get_and_load_typeclasses:[510,5,1,""]},"evennia.web.api":{filters:[512,0,0,"-"],permissions:[513,0,0,"-"],root:[514,0,0,"-"],serializers:[515,0,0,"-"],tests:[516,0,0,"-"],urls:[517,0,0,"-"],views:[518,0,0,"-"]},"evennia.web.api.filters":{AccountDBFilterSet:[512,1,1,""],AliasFilter:[512,1,1,""],BaseTypeclassFilterSet:[512,1,1,""],HelpFilterSet:[512,1,1,""],ObjectDBFilterSet:[512,1,1,""],PermissionFilter:[512,1,1,""],ScriptDBFilterSet:[512,1,1,""],TagTypeFilter:[512,1,1,""],get_tag_query:[512,5,1,""]},"evennia.web.api.filters.AccountDBFilterSet":{Meta:[512,1,1,""],base_filters:[512,4,1,""],declared_filters:[512,4,1,""]},"evennia.web.api.filters.AccountDBFilterSet.Meta":{fields:[512,4,1,""],model:[512,4,1,""]},"evennia.web.api.filters.AliasFilter":{tag_type:[512,4,1,""]},"evennia.web.api.filters.BaseTypeclassFilterSet":{base_filters:[512,4,1,""],declared_filters:[512,4,1,""],filter_name:[512,3,1,""]},"evennia.web.api.filters.HelpFilterSet":{base_filters:[512,4,1,""],declared_filters:[512,4,1,""]},"evennia.web.api.filters.ObjectDBFilterSet":{Meta:[512,1,1,""],base_filters:[512,4,1,""],declared_filters:[512,4,1,""]},"evennia.web.api.filters.ObjectDBFilterSet.Meta":{fields:[512,4,1,""],model:[512,4,1,""]},"evennia.web.api.filters.PermissionFilter":{tag_type:[512,4,1,""]},"evennia.web.api.filters.ScriptDBFilterSet":{Meta:[512,1,1,""],base_filters:[512,4,1,""],declared_filters:[512,4,1,""]},"evennia.web.api.filters.ScriptDBFilterSet.Meta":{fields:[512,4,1,""],model:[512,4,1,""]},"evennia.web.api.filters.TagTypeFilter":{filter:[512,3,1,""],tag_type:[512,4,1,""]},"evennia.web.api.permissions":{EvenniaPermission:[513,1,1,""]},"evennia.web.api.permissions.EvenniaPermission":{MINIMUM_CREATE_PERMISSION:[513,4,1,""],MINIMUM_LIST_PERMISSION:[513,4,1,""],check_locks:[513,3,1,""],destroy_locks:[513,4,1,""],has_object_permission:[513,3,1,""],has_permission:[513,3,1,""],update_locks:[513,4,1,""],view_locks:[513,4,1,""]},"evennia.web.api.root":{APIRootRouter:[514,1,1,""],EvenniaAPIRoot:[514,1,1,""]},"evennia.web.api.root.APIRootRouter":{APIRootView:[514,4,1,""]},"evennia.web.api.serializers":{AccountListSerializer:[515,1,1,""],AccountSerializer:[515,1,1,""],AttributeSerializer:[515,1,1,""],HelpListSerializer:[515,1,1,""],HelpSerializer:[515,1,1,""],ObjectDBSerializer:[515,1,1,""],ObjectListSerializer:[515,1,1,""],ScriptDBSerializer:[515,1,1,""],ScriptListSerializer:[515,1,1,""],SimpleObjectDBSerializer:[515,1,1,""],TagSerializer:[515,1,1,""],TypeclassListSerializerMixin:[515,1,1,""],TypeclassSerializerMixin:[515,1,1,""]},"evennia.web.api.serializers.AccountListSerializer":{Meta:[515,1,1,""]},"evennia.web.api.serializers.AccountListSerializer.Meta":{fields:[515,4,1,""],model:[515,4,1,""],read_only_fields:[515,4,1,""]},"evennia.web.api.serializers.AccountSerializer":{Meta:[515,1,1,""],get_session_ids:[515,3,1,""]},"evennia.web.api.serializers.AccountSerializer.Meta":{fields:[515,4,1,""],model:[515,4,1,""],read_only_fields:[515,4,1,""]},"evennia.web.api.serializers.AttributeSerializer":{Meta:[515,1,1,""],get_value_display:[515,3,1,""]},"evennia.web.api.serializers.AttributeSerializer.Meta":{fields:[515,4,1,""],model:[515,4,1,""]},"evennia.web.api.serializers.HelpListSerializer":{Meta:[515,1,1,""]},"evennia.web.api.serializers.HelpListSerializer.Meta":{fields:[515,4,1,""],model:[515,4,1,""],read_only_fields:[515,4,1,""]},"evennia.web.api.serializers.HelpSerializer":{Meta:[515,1,1,""]},"evennia.web.api.serializers.HelpSerializer.Meta":{fields:[515,4,1,""],model:[515,4,1,""],read_only_fields:[515,4,1,""]},"evennia.web.api.serializers.ObjectDBSerializer":{Meta:[515,1,1,""],get_contents:[515,3,1,""],get_exits:[515,3,1,""]},"evennia.web.api.serializers.ObjectDBSerializer.Meta":{fields:[515,4,1,""],model:[515,4,1,""],read_only_fields:[515,4,1,""]},"evennia.web.api.serializers.ObjectListSerializer":{Meta:[515,1,1,""]},"evennia.web.api.serializers.ObjectListSerializer.Meta":{fields:[515,4,1,""],model:[515,4,1,""],read_only_fields:[515,4,1,""]},"evennia.web.api.serializers.ScriptDBSerializer":{Meta:[515,1,1,""]},"evennia.web.api.serializers.ScriptDBSerializer.Meta":{fields:[515,4,1,""],model:[515,4,1,""],read_only_fields:[515,4,1,""]},"evennia.web.api.serializers.ScriptListSerializer":{Meta:[515,1,1,""]},"evennia.web.api.serializers.ScriptListSerializer.Meta":{fields:[515,4,1,""],model:[515,4,1,""],read_only_fields:[515,4,1,""]},"evennia.web.api.serializers.SimpleObjectDBSerializer":{Meta:[515,1,1,""]},"evennia.web.api.serializers.SimpleObjectDBSerializer.Meta":{fields:[515,4,1,""],model:[515,4,1,""]},"evennia.web.api.serializers.TagSerializer":{Meta:[515,1,1,""]},"evennia.web.api.serializers.TagSerializer.Meta":{fields:[515,4,1,""],model:[515,4,1,""]},"evennia.web.api.serializers.TypeclassListSerializerMixin":{shared_fields:[515,4,1,""]},"evennia.web.api.serializers.TypeclassSerializerMixin":{get_aliases:[515,3,1,""],get_attributes:[515,3,1,""],get_nicks:[515,3,1,""],get_permissions:[515,3,1,""],get_tags:[515,3,1,""],shared_fields:[515,4,1,""]},"evennia.web.api.tests":{TestEvenniaRESTApi:[516,1,1,""]},"evennia.web.api.tests.TestEvenniaRESTApi":{client_class:[516,4,1,""],get_view_details:[516,3,1,""],maxDiff:[516,4,1,""],setUp:[516,3,1,""],tearDown:[516,3,1,""],test_create:[516,3,1,""],test_delete:[516,3,1,""],test_list:[516,3,1,""],test_retrieve:[516,3,1,""],test_set_attribute:[516,3,1,""],test_update:[516,3,1,""]},"evennia.web.api.views":{AccountDBViewSet:[518,1,1,""],CharacterViewSet:[518,1,1,""],ExitViewSet:[518,1,1,""],GeneralViewSetMixin:[518,1,1,""],HelpViewSet:[518,1,1,""],ObjectDBViewSet:[518,1,1,""],RoomViewSet:[518,1,1,""],ScriptDBViewSet:[518,1,1,""],TypeclassViewSetMixin:[518,1,1,""]},"evennia.web.api.views.AccountDBViewSet":{basename:[518,4,1,""],description:[518,4,1,""],detail:[518,4,1,""],filterset_class:[518,4,1,""],list_serializer_class:[518,4,1,""],name:[518,4,1,""],queryset:[518,4,1,""],serializer_class:[518,4,1,""],suffix:[518,4,1,""]},"evennia.web.api.views.CharacterViewSet":{basename:[518,4,1,""],description:[518,4,1,""],detail:[518,4,1,""],list_serializer_class:[518,4,1,""],name:[518,4,1,""],queryset:[518,4,1,""],suffix:[518,4,1,""]},"evennia.web.api.views.ExitViewSet":{basename:[518,4,1,""],description:[518,4,1,""],detail:[518,4,1,""],list_serializer_class:[518,4,1,""],name:[518,4,1,""],queryset:[518,4,1,""],suffix:[518,4,1,""]},"evennia.web.api.views.GeneralViewSetMixin":{get_serializer_class:[518,3,1,""]},"evennia.web.api.views.HelpViewSet":{basename:[518,4,1,""],description:[518,4,1,""],detail:[518,4,1,""],filterset_class:[518,4,1,""],list_serializer_class:[518,4,1,""],name:[518,4,1,""],queryset:[518,4,1,""],serializer_class:[518,4,1,""],suffix:[518,4,1,""]},"evennia.web.api.views.ObjectDBViewSet":{basename:[518,4,1,""],description:[518,4,1,""],detail:[518,4,1,""],filterset_class:[518,4,1,""],list_serializer_class:[518,4,1,""],name:[518,4,1,""],queryset:[518,4,1,""],serializer_class:[518,4,1,""],suffix:[518,4,1,""]},"evennia.web.api.views.RoomViewSet":{basename:[518,4,1,""],description:[518,4,1,""],detail:[518,4,1,""],list_serializer_class:[518,4,1,""],name:[518,4,1,""],queryset:[518,4,1,""],suffix:[518,4,1,""]},"evennia.web.api.views.ScriptDBViewSet":{basename:[518,4,1,""],description:[518,4,1,""],detail:[518,4,1,""],filterset_class:[518,4,1,""],list_serializer_class:[518,4,1,""],name:[518,4,1,""],queryset:[518,4,1,""],serializer_class:[518,4,1,""],suffix:[518,4,1,""]},"evennia.web.api.views.TypeclassViewSetMixin":{filter_backends:[518,4,1,""],permission_classes:[518,4,1,""],set_attribute:[518,3,1,""]},"evennia.web.templatetags":{addclass:[520,0,0,"-"]},"evennia.web.templatetags.addclass":{addclass:[520,5,1,""]},"evennia.web.utils":{adminsite:[523,0,0,"-"],backends:[524,0,0,"-"],general_context:[525,0,0,"-"],middleware:[526,0,0,"-"],tests:[527,0,0,"-"]},"evennia.web.utils.adminsite":{EvenniaAdminApp:[523,1,1,""],EvenniaAdminSite:[523,1,1,""]},"evennia.web.utils.adminsite.EvenniaAdminApp":{default_site:[523,4,1,""]},"evennia.web.utils.adminsite.EvenniaAdminSite":{app_order:[523,4,1,""],get_app_list:[523,3,1,""],site_header:[523,4,1,""]},"evennia.web.utils.backends":{CaseInsensitiveModelBackend:[524,1,1,""]},"evennia.web.utils.backends.CaseInsensitiveModelBackend":{authenticate:[524,3,1,""]},"evennia.web.utils.general_context":{general_context:[525,5,1,""],load_game_settings:[525,5,1,""]},"evennia.web.utils.middleware":{SharedLoginMiddleware:[526,1,1,""]},"evennia.web.utils.middleware.SharedLoginMiddleware":{__init__:[526,3,1,""],make_shared_login:[526,3,1,""]},"evennia.web.utils.tests":{TestGeneralContext:[527,1,1,""]},"evennia.web.utils.tests.TestGeneralContext":{maxDiff:[527,4,1,""],test_general_context:[527,3,1,""]},"evennia.web.webclient":{urls:[529,0,0,"-"],views:[530,0,0,"-"]},"evennia.web.webclient.views":{webclient:[530,5,1,""]},"evennia.web.website":{forms:[532,0,0,"-"],tests:[533,0,0,"-"],urls:[534,0,0,"-"],views:[535,0,0,"-"]},"evennia.web.website.forms":{AccountForm:[532,1,1,""],CharacterForm:[532,1,1,""],CharacterUpdateForm:[532,1,1,""],EvenniaForm:[532,1,1,""],ObjectForm:[532,1,1,""]},"evennia.web.website.forms.AccountForm":{Meta:[532,1,1,""],base_fields:[532,4,1,""],declared_fields:[532,4,1,""],media:[532,3,1,""]},"evennia.web.website.forms.AccountForm.Meta":{field_classes:[532,4,1,""],fields:[532,4,1,""],model:[532,4,1,""]},"evennia.web.website.forms.CharacterForm":{Meta:[532,1,1,""],base_fields:[532,4,1,""],declared_fields:[532,4,1,""],media:[532,3,1,""]},"evennia.web.website.forms.CharacterForm.Meta":{fields:[532,4,1,""],labels:[532,4,1,""],model:[532,4,1,""]},"evennia.web.website.forms.CharacterUpdateForm":{base_fields:[532,4,1,""],declared_fields:[532,4,1,""],media:[532,3,1,""]},"evennia.web.website.forms.EvenniaForm":{base_fields:[532,4,1,""],clean:[532,3,1,""],declared_fields:[532,4,1,""],media:[532,3,1,""]},"evennia.web.website.forms.ObjectForm":{Meta:[532,1,1,""],base_fields:[532,4,1,""],declared_fields:[532,4,1,""],media:[532,3,1,""]},"evennia.web.website.forms.ObjectForm.Meta":{fields:[532,4,1,""],labels:[532,4,1,""],model:[532,4,1,""]},"evennia.web.website.tests":{AdminTest:[533,1,1,""],ChannelDetailTest:[533,1,1,""],ChannelListTest:[533,1,1,""],CharacterCreateView:[533,1,1,""],CharacterDeleteView:[533,1,1,""],CharacterListView:[533,1,1,""],CharacterManageView:[533,1,1,""],CharacterPuppetView:[533,1,1,""],CharacterUpdateView:[533,1,1,""],EvenniaWebTest:[533,1,1,""],HelpDetailTest:[533,1,1,""],HelpListTest:[533,1,1,""],HelpLockedDetailTest:[533,1,1,""],IndexTest:[533,1,1,""],LoginTest:[533,1,1,""],LogoutTest:[533,1,1,""],PasswordResetTest:[533,1,1,""],RegisterTest:[533,1,1,""],WebclientTest:[533,1,1,""]},"evennia.web.website.tests.AdminTest":{unauthenticated_response:[533,4,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.ChannelDetailTest":{get_kwargs:[533,3,1,""],setUp:[533,3,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.ChannelListTest":{url_name:[533,4,1,""]},"evennia.web.website.tests.CharacterCreateView":{test_valid_access_multisession_0:[533,3,1,""],test_valid_access_multisession_2:[533,3,1,""],unauthenticated_response:[533,4,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.CharacterDeleteView":{get_kwargs:[533,3,1,""],test_invalid_access:[533,3,1,""],test_valid_access:[533,3,1,""],unauthenticated_response:[533,4,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.CharacterListView":{unauthenticated_response:[533,4,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.CharacterManageView":{unauthenticated_response:[533,4,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.CharacterPuppetView":{get_kwargs:[533,3,1,""],test_invalid_access:[533,3,1,""],unauthenticated_response:[533,4,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.CharacterUpdateView":{get_kwargs:[533,3,1,""],test_invalid_access:[533,3,1,""],test_valid_access:[533,3,1,""],unauthenticated_response:[533,4,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.EvenniaWebTest":{account_typeclass:[533,4,1,""],authenticated_response:[533,4,1,""],channel_typeclass:[533,4,1,""],character_typeclass:[533,4,1,""],exit_typeclass:[533,4,1,""],get_kwargs:[533,3,1,""],login:[533,3,1,""],object_typeclass:[533,4,1,""],room_typeclass:[533,4,1,""],script_typeclass:[533,4,1,""],setUp:[533,3,1,""],test_get:[533,3,1,""],test_get_authenticated:[533,3,1,""],test_valid_chars:[533,3,1,""],unauthenticated_response:[533,4,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.HelpDetailTest":{get_kwargs:[533,3,1,""],setUp:[533,3,1,""],test_object_cache:[533,3,1,""],test_view:[533,3,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.HelpListTest":{url_name:[533,4,1,""]},"evennia.web.website.tests.HelpLockedDetailTest":{get_kwargs:[533,3,1,""],setUp:[533,3,1,""],test_lock_with_perm:[533,3,1,""],test_locked_entry:[533,3,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.IndexTest":{url_name:[533,4,1,""]},"evennia.web.website.tests.LoginTest":{url_name:[533,4,1,""]},"evennia.web.website.tests.LogoutTest":{url_name:[533,4,1,""]},"evennia.web.website.tests.PasswordResetTest":{unauthenticated_response:[533,4,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.RegisterTest":{url_name:[533,4,1,""]},"evennia.web.website.tests.WebclientTest":{test_get:[533,3,1,""],test_get_disabled:[533,3,1,""],url_name:[533,4,1,""]},"evennia.web.website.views":{accounts:[536,0,0,"-"],channels:[537,0,0,"-"],characters:[538,0,0,"-"],errors:[539,0,0,"-"],help:[540,0,0,"-"],index:[541,0,0,"-"],mixins:[542,0,0,"-"],objects:[543,0,0,"-"]},"evennia.web.website.views.accounts":{AccountCreateView:[536,1,1,""],AccountMixin:[536,1,1,""]},"evennia.web.website.views.accounts.AccountCreateView":{form_valid:[536,3,1,""],success_url:[536,4,1,""],template_name:[536,4,1,""]},"evennia.web.website.views.accounts.AccountMixin":{form_class:[536,4,1,""],model:[536,4,1,""]},"evennia.web.website.views.channels":{ChannelDetailView:[537,1,1,""],ChannelListView:[537,1,1,""],ChannelMixin:[537,1,1,""]},"evennia.web.website.views.channels.ChannelDetailView":{attributes:[537,4,1,""],get_context_data:[537,3,1,""],get_object:[537,3,1,""],max_num_lines:[537,4,1,""],template_name:[537,4,1,""]},"evennia.web.website.views.channels.ChannelListView":{get_context_data:[537,3,1,""],max_popular:[537,4,1,""],page_title:[537,4,1,""],paginate_by:[537,4,1,""],template_name:[537,4,1,""]},"evennia.web.website.views.channels.ChannelMixin":{access_type:[537,4,1,""],get_queryset:[537,3,1,""],model:[537,4,1,""],page_title:[537,4,1,""]},"evennia.web.website.views.characters":{CharacterCreateView:[538,1,1,""],CharacterDeleteView:[538,1,1,""],CharacterDetailView:[538,1,1,""],CharacterListView:[538,1,1,""],CharacterManageView:[538,1,1,""],CharacterMixin:[538,1,1,""],CharacterPuppetView:[538,1,1,""],CharacterUpdateView:[538,1,1,""]},"evennia.web.website.views.characters.CharacterCreateView":{form_valid:[538,3,1,""],template_name:[538,4,1,""]},"evennia.web.website.views.characters.CharacterDetailView":{access_type:[538,4,1,""],attributes:[538,4,1,""],get_queryset:[538,3,1,""],template_name:[538,4,1,""]},"evennia.web.website.views.characters.CharacterListView":{access_type:[538,4,1,""],get_queryset:[538,3,1,""],page_title:[538,4,1,""],paginate_by:[538,4,1,""],template_name:[538,4,1,""]},"evennia.web.website.views.characters.CharacterManageView":{page_title:[538,4,1,""],paginate_by:[538,4,1,""],template_name:[538,4,1,""]},"evennia.web.website.views.characters.CharacterMixin":{form_class:[538,4,1,""],get_queryset:[538,3,1,""],model:[538,4,1,""],success_url:[538,4,1,""]},"evennia.web.website.views.characters.CharacterPuppetView":{get_redirect_url:[538,3,1,""]},"evennia.web.website.views.characters.CharacterUpdateView":{form_class:[538,4,1,""],template_name:[538,4,1,""]},"evennia.web.website.views.errors":{to_be_implemented:[539,5,1,""]},"evennia.web.website.views.help":{HelpDetailView:[540,1,1,""],HelpListView:[540,1,1,""],HelpMixin:[540,1,1,""],can_read_topic:[540,5,1,""],collect_topics:[540,5,1,""],get_help_category:[540,5,1,""],get_help_topic:[540,5,1,""]},"evennia.web.website.views.help.HelpDetailView":{get_context_data:[540,3,1,""],get_object:[540,3,1,""],page_title:[540,3,1,""],template_name:[540,4,1,""]},"evennia.web.website.views.help.HelpListView":{page_title:[540,4,1,""],paginate_by:[540,4,1,""],template_name:[540,4,1,""]},"evennia.web.website.views.help.HelpMixin":{get_queryset:[540,3,1,""],page_title:[540,4,1,""]},"evennia.web.website.views.index":{EvenniaIndexView:[541,1,1,""]},"evennia.web.website.views.index.EvenniaIndexView":{get_context_data:[541,3,1,""],template_name:[541,4,1,""]},"evennia.web.website.views.mixins":{EvenniaCreateView:[542,1,1,""],EvenniaDeleteView:[542,1,1,""],EvenniaDetailView:[542,1,1,""],EvenniaUpdateView:[542,1,1,""],TypeclassMixin:[542,1,1,""]},"evennia.web.website.views.mixins.EvenniaCreateView":{page_title:[542,3,1,""]},"evennia.web.website.views.mixins.EvenniaDeleteView":{page_title:[542,3,1,""]},"evennia.web.website.views.mixins.EvenniaDetailView":{page_title:[542,3,1,""]},"evennia.web.website.views.mixins.EvenniaUpdateView":{page_title:[542,3,1,""]},"evennia.web.website.views.mixins.TypeclassMixin":{typeclass:[542,3,1,""]},"evennia.web.website.views.objects":{ObjectCreateView:[543,1,1,""],ObjectDeleteView:[543,1,1,""],ObjectDetailView:[543,1,1,""],ObjectUpdateView:[543,1,1,""]},"evennia.web.website.views.objects.ObjectCreateView":{model:[543,4,1,""]},"evennia.web.website.views.objects.ObjectDeleteView":{"delete":[543,3,1,""],access_type:[543,4,1,""],model:[543,4,1,""],template_name:[543,4,1,""]},"evennia.web.website.views.objects.ObjectDetailView":{access_type:[543,4,1,""],attributes:[543,4,1,""],get_context_data:[543,3,1,""],get_object:[543,3,1,""],model:[543,4,1,""],template_name:[543,4,1,""]},"evennia.web.website.views.objects.ObjectUpdateView":{access_type:[543,4,1,""],form_valid:[543,3,1,""],get_initial:[543,3,1,""],get_success_url:[543,3,1,""],model:[543,4,1,""]},evennia:{accounts:[203,0,0,"-"],commands:[208,0,0,"-"],comms:[231,0,0,"-"],contrib:[235,0,0,"-"],help:[387,0,0,"-"],locks:[392,0,0,"-"],objects:[395,0,0,"-"],prototypes:[399,0,0,"-"],scripts:[404,0,0,"-"],server:[412,0,0,"-"],set_trace:[201,5,1,""],settings_default:[462,0,0,"-"],typeclasses:[463,0,0,"-"],utils:[468,0,0,"-"],web:[498,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","exception","Python exception"],"3":["py","method","Python method"],"4":["py","attribute","Python attribute"],"5":["py","function","Python function"],"6":["py","data","Python data"]},objtypes:{"0":"py:module","1":"py:class","2":"py:exception","3":"py:method","4":"py:attribute","5":"py:function","6":"py:data"},terms:{"000":[60,96,97,118,140,491],"0000":[96,97],"0004":76,"0005":77,"001":[76,335,491],"002":491,"003":[151,491],"004":491,"005":[60,469,491],"006":491,"007":491,"008":491,"009":491,"010":[126,491],"011":491,"012":491,"013":491,"014":491,"015":491,"015public":126,"016":491,"017":491,"018":491,"019":491,"020":491,"020t":126,"021":491,"022":491,"023":491,"024":491,"0247":76,"025":491,"026":491,"027":491,"028":491,"029":491,"030":491,"030a":126,"031":491,"032":491,"033":[469,491],"034":[76,491],"035":491,"036":491,"037":491,"038":491,"039":491,"040":491,"040f":126,"041":491,"042":491,"043":491,"043thi":151,"044":491,"045":491,"046":491,"047":491,"048":491,"049":491,"050":[469,491],"050f":126,"051":491,"052":491,"053":491,"054":[60,491],"055":[469,491],"056":491,"057":491,"058":491,"059":491,"060":491,"061":491,"062":491,"063":491,"064":491,"065":491,"066":491,"067":491,"068":491,"069":491,"070":491,"071":491,"072":491,"073":491,"074":491,"075":491,"076":491,"077":491,"078":491,"079":491,"080":491,"081":491,"082":491,"083":491,"084":491,"085":491,"086":491,"087":491,"088":491,"089":491,"090":491,"091":491,"092":491,"093":491,"094":491,"095":491,"096":491,"097":491,"098":491,"099":491,"0b16":183,"0d0":133,"0th":13,"0x045a0990":3,"100":[5,20,48,86,92,94,112,133,141,157,162,170,228,276,308,311,312,335,343,346,353,354,380,491,492,537,538],"1000":[5,42,133,164,193,308,309,310,311,312,402],"10000":537,"1000000":[5,140,485],"100m":491,"100mb":191,"101":[20,398,491],"101m":491,"102":[112,354,491],"102m":491,"103":491,"103m":491,"104":491,"104m":491,"105":491,"105m":491,"106":491,"106m":491,"107":491,"107m":491,"108":491,"108m":491,"109":491,"1098":48,"109m":491,"10gold":157,"10m":187,"110":[112,354,469,477,491],"110m":491,"111":[55,60,216,491],"111m":491,"112":491,"112m":491,"113":[191,491],"113m":491,"114":491,"114m":491,"115":491,"115600":133,"115m":491,"116":491,"116m":491,"117":491,"117m":491,"118":[47,491],"1184":182,"118m":491,"119":491,"119m":491,"120":[20,491],"1200":475,"120m":491,"121":491,"121m":491,"122":491,"122m":491,"123":[11,84,104,178,398,479,491],"1234":[13,41,105,184,305],"123dark":139,"123m":491,"124":491,"12400":140,"124m":491,"125":[49,491],"125m":491,"126":491,"126m":491,"127":[53,75,154,181,182,183,185,187,191,198,436,491],"127m":491,"128":491,"128m":491,"129":491,"129m":491,"12s":19,"130":491,"130m":491,"131":491,"131m":491,"132":491,"132m":491,"133":491,"133m":491,"134":[55,216,491],"134m":491,"135":491,"135m":491,"136":491,"136m":491,"137":491,"137m":491,"138":491,"138m":491,"139":491,"139m":491,"140":[3,201,491],"1400":475,"140313967648552":22,"140m":491,"141":491,"141m":491,"142":[76,241,491],"142m":491,"143":491,"143m":491,"144":491,"144m":491,"145":491,"145m":491,"146":491,"146m":491,"147":491,"147m":491,"148":491,"148m":491,"149":491,"149m":491,"150":[474,491],"150m":491,"151":491,"151m":491,"152":491,"152m":491,"153":491,"153m":491,"154":491,"154m":491,"155":491,"155m":491,"156":491,"156m":491,"157":491,"1577865600":136,"157m":491,"158":491,"158m":491,"159":[147,491],"159m":491,"15th":95,"160":491,"160m":491,"161":491,"161m":491,"162":491,"162m":491,"163":491,"163m":491,"164":491,"164m":491,"165":491,"165m":491,"166":491,"166m":491,"167":491,"167m":491,"168":491,"168m":491,"169":491,"169m":491,"16m":491,"170":491,"170m":491,"171":491,"171m":491,"172":491,"172m":491,"173":491,"1730":180,"173m":491,"174":491,"174m":491,"175":491,"175m":491,"176":491,"1763":146,"1764":146,"176m":491,"177":491,"177m":491,"178":491,"178m":491,"179":491,"179m":491,"17m":491,"180":491,"180m":491,"181":491,"181m":491,"182":491,"182m":491,"183":491,"183m":491,"184":491,"184m":491,"185":491,"185m":491,"186":491,"186m":491,"187":491,"187m":491,"188":491,"188m":491,"189":491,"189m":491,"18m":491,"190":491,"1903":146,"190m":491,"191":491,"191m":491,"192":491,"192m":491,"193":491,"193m":491,"194":491,"194m":491,"195":491,"195m":491,"196":491,"196m":491,"197":491,"1970":136,"197m":491,"198":491,"198m":491,"199":491,"1996":180,"1998":180,"199m":491,"19m":491,"1_7":8,"1d100":[88,157,162,343],"1d2":133,"1d20":[88,157,343],"1d6":162,"1gb":191,"1st":[30,58,95,136,479,495,496,497],"200":[112,354,491,533],"2001":180,"2003":180,"2004":180,"2008":492,"200m":491,"201":491,"2010":491,"2011":[104,108,111,115,363,364,365,366,368,371],"2012":[77,79,80,81,88,89,91,104,249,251,282,283,315,316,342,343,356,358,359],"2014":[104,110,112,125,324,325,352,354],"2015":[64,93,104,106,115,183,295,296,348,349,350,361,368],"2016":[98,99,100,102,104,109,111,298,299,301,302,321,322,365,366],"2017":[6,78,83,84,87,94,95,101,104,107,113,114,116,117,136,191,243,244,246,247,268,270,285,286,307,308,309,310,311,312,327,329,345,346,376,377,381,382,384,386],"2018":[64,75,82,92,104,105,151,152,240,241,260,304,305,379,380],"2019":[64,90,91,100,104,180,272,315,316],"201m":491,"202":491,"2020":[55,64,77,86,104,112,136,237,291,292,352,354,369],"2020_01_29":485,"2020_01_29__1":485,"2020_01_29__2":485,"2021":[50,64,85,103,104,118,265,266,288,289,330,495,496,540],"2025":95,"202m":491,"203":[191,491],"203m":491,"204":491,"2048":187,"204m":491,"205":[475,491],"205m":491,"206":491,"206m":491,"207":491,"2076":146,"207m":491,"208":[142,491],"208m":491,"209":491,"2099":77,"209m":491,"20m":491,"210":491,"210m":491,"211":491,"211m":491,"212":[55,491],"2128":133,"212m":491,"213":[49,491],"213m":491,"214":[49,491],"214m":491,"215":491,"215m":491,"216":491,"216m":491,"217":491,"217m":491,"218":491,"218m":491,"219":[75,491],"219m":491,"21m":491,"220":491,"2207":[107,382],"220m":491,"221":[470,491],"221m":491,"222":[60,469,491],"222m":491,"223":[55,491],"223m":491,"224":491,"224m":491,"225":[55,491],"225m":491,"226":491,"226m":491,"227":491,"227m":491,"228":491,"228m":491,"229":491,"229m":491,"22m":[469,491],"22nd":492,"230":[60,491],"230m":491,"231":491,"231m":491,"232":491,"232m":491,"233":[55,216,479,491],"233m":491,"234":[84,104,244,491],"234m":491,"235":491,"235m":491,"236":491,"236m":491,"237":[55,491],"237m":491,"238":491,"238m":491,"239":491,"239m":491,"23fwsf23sdfw23wef23":5,"23m":491,"240":491,"240m":491,"241":491,"241m":491,"242":491,"2429":540,"242m":491,"243":491,"243m":491,"244":[42,491],"244m":491,"245":491,"245m":491,"246":491,"246m":491,"247":491,"247m":491,"248":491,"248m":491,"249":491,"249m":491,"24m":491,"250":491,"250m":491,"251":491,"251m":491,"252":491,"252m":491,"253":491,"253m":491,"254":491,"254m":491,"255":[183,469,491],"255m":491,"256":[55,60,215,469],"25m":491,"26m":491,"27m":491,"280":188,"28gmcp":440,"28m":491,"29m":491,"2d10":[88,104],"2d6":[88,135,157,343],"2gb":191,"2nd":[30,58,280,479,495,496,497],"2nd_person_pronoun":496,"2sgpre":497,"2xcoal":293,"300":[60,175,247,480],"3000000":140,"302":533,"30m":[469,491],"30s":[157,335],"31m":[469,491],"31st":136,"32bit":[183,185],"32m":[469,491],"32nd":135,"333":[55,60],"33m":[469,491],"340":133,"343":30,"34m":[469,491],"358":50,"358283996582031":5,"35m":[469,491],"360":136,"3600":136,"36m":[469,491],"37m":[469,491],"3872":146,"38m":491,"39m":491,"3c3ccec30f037be174d3":492,"3d10":[88,343],"3d6":343,"3rd":[30,58,136,280,479,495,496,497],"3rd_person_pronoun":496,"3sgpast":495,"3sgpre":[495,497],"4000":[2,75,122,154,185,187,190,191,193,194,198],"4001":[2,49,50,51,52,53,73,75,124,137,154,167,177,178,181,185,187,190,191,193,194,198,445],"4002":[2,181,187,191,193],"4003":191,"4004":191,"4005":191,"4006":191,"403":11,"404":[53,137],"40m":[469,491],"41917":436,"41m":[469,491],"4201":191,"425":469,"42m":[469,491],"430000":136,"431":469,"43m":[469,491],"443":[181,187,194],"444":60,"44m":[469,491],"45m":[19,469,491],"46m":[469,491],"474a3b9f":40,"47m":[469,491],"48m":491,"49m":491,"4er43233fwefwfw":75,"4th":[118,120,180],"500":[53,60,118,175,337,469,540],"50000":140,"500red":469,"502916":8,"503435":8,"505":469,"50m":491,"50mb":191,"516106":133,"51m":491,"520":60,"52m":491,"530":151,"53m":491,"543":[30,479],"5432":182,"54343":30,"5434343":479,"54m":491,"550":[469,475],"550n":126,"551e":126,"552w":126,"553b":126,"554i":126,"555":[60,107,382,469],"555e":126,"55m":491,"565000":136,"566":42,"56m":491,"577349":491,"57m":491,"58m":491,"593":492,"59m":491,"5d5":133,"5mb":77,"5x5":170,"600":492,"60m":491,"61m":491,"624660":50,"62cb3a1a":40,"62m":491,"63m":491,"64m":491,"64x64":53,"65m":491,"6666":62,"6667":[180,189,205,223,457],"66m":491,"67m":491,"686":58,"68m":491,"69m":491,"6d6":133,"70982813835144":5,"70m":491,"71m":491,"72m":491,"73m":491,"74m":491,"75m":491,"760000":136,"76m":491,"775":2,"77m":491,"78m":491,"79m":491,"7a3d54":53,"8080":191,"80m":491,"8111":2,"81m":491,"82m":491,"83m":491,"84m":491,"85000":140,"85m":491,"86400":173,"86m":491,"87m":491,"8859":[16,70,230],"88m":491,"89m":491,"8f64fec2670c":191,"900":[92,380,475],"9000":532,"90m":491,"90s":493,"91m":491,"92m":491,"93m":491,"94608000":77,"94m":491,"95m":491,"96m":491,"97m":491,"981":[107,382],"98m":491,"990":475,"99999":156,"999999999999":338,"99m":491,"\u6d4b\u8bd5":126,"abstract":[67,114,118,123,147,157,275,312,464,465,466,483,486,492],"ansl\u00f6t":64,"boolean":[13,14,18,22,30,51,92,143,177,213,343,380,394,398,409,436,464,467,469,470,486,493],"break":[3,8,15,31,48,51,54,55,60,64,69,103,104,129,134,135,142,150,151,152,156,158,161,170,184,194,201,218,225,226,266,302,331,340,364,425,469,476,477,492],"byte":[16,19,30,70,416,418,425,427,436,444,492],"case":[3,8,9,11,13,14,15,16,18,19,20,22,28,31,32,33,37,39,41,44,45,48,49,50,51,52,53,54,55,60,62,64,65,67,68,69,70,76,77,85,90,95,96,106,118,119,120,123,125,126,127,128,131,132,135,136,137,139,140,142,143,144,145,146,147,148,149,150,151,152,153,155,156,159,161,164,165,170,173,174,177,180,181,182,193,194,198,199,204,205,206,210,212,213,215,218,224,225,226,232,233,239,241,258,283,286,289,292,293,316,331,338,340,343,350,351,353,364,372,378,380,382,388,389,390,393,394,396,398,402,406,408,421,425,429,433,447,454,457,464,465,466,467,469,471,479,483,489,490,492,496,500,524,545],"catch":[0,6,16,19,28,36,42,47,129,135,142,161,172,205,224,273,372,407,416,421,428,454,455,464,474,476,477,483,485,488,541],"char":[8,13,44,68,93,95,118,133,135,141,146,149,162,164,170,173,177,188,204,218,224,275,276,296,337,340,372,398,413,426,439,440,461,469,475,478],"class":[0,3,6,12,13,17,18,20,27,28,29,30,31,37,39,41,42,44,49,50,52,53,54,55,56,62,64,67,73,79,82,83,85,86,88,90,91,93,98,102,103,104,106,107,109,110,112,116,117,118,120,121,122,123,125,126,127,128,129,130,131,132,133,134,135,136,138,139,140,141,142,143,144,145,146,147,150,153,154,156,157,161,162,164,165,167,171,172,173,174,176,177,178,188,204,205,206,207,208,211,212,213,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,232,233,234,239,241,242,245,247,248,251,252,254,255,257,258,260,266,267,269,270,273,274,275,276,277,278,279,280,283,284,286,287,289,290,292,293,294,296,297,299,300,302,303,305,306,308,309,310,311,312,313,316,317,322,323,325,326,328,329,331,332,335,337,338,339,340,343,344,347,349,350,351,353,354,359,360,362,364,366,367,369,370,371,372,373,377,378,380,382,383,385,386,388,389,390,394,395,396,397,398,400,402,403,405,406,407,408,409,410,411,413,414,416,418,419,422,423,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,447,449,452,454,455,456,457,459,460,461,463,464,465,466,467,469,470,471,472,473,474,475,476,477,478,479,480,482,483,484,485,486,487,488,489,490,491,492,497,500,501,502,504,505,506,507,508,510,512,513,514,515,516,518,521,523,524,526,527,532,533,536,537,538,540,541,542,543,545],"const":270,"default":[2,3,5,6,7,8,9,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,27,28,31,35,36,37,39,41,42,44,45,46,48,49,50,52,54,55,56,57,60,61,62,63,64,65,67,68,70,71,72,73,74,75,76,77,78,79,82,83,84,85,86,87,89,90,91,92,93,94,95,96,97,99,100,102,103,104,106,110,112,113,114,116,117,120,121,122,123,124,125,128,130,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,151,152,153,154,157,158,159,161,164,165,167,169,170,171,172,174,175,177,178,181,182,185,186,187,188,189,190,191,193,194,195,198,201,202,204,205,207,208,209,210,211,212,213,232,233,234,241,244,247,251,255,257,258,266,270,273,275,276,277,278,280,283,286,289,292,296,299,302,305,308,309,310,311,312,316,322,325,328,329,331,334,337,338,339,340,343,346,349,350,353,354,362,364,366,370,372,376,377,378,380,386,387,388,389,390,391,392,394,396,398,402,403,406,407,409,410,411,414,416,418,420,421,422,426,438,439,440,445,447,448,454,455,456,457,461,462,464,465,466,467,469,471,472,474,476,477,478,479,482,483,485,486,487,488,489,490,492,493,500,512,518,523,524,532,538,540,541,542,543,544,545],"elsd\u00f6rfer":77,"export":[77,190],"final":[0,2,19,22,41,44,48,53,54,60,64,65,67,95,120,128,130,135,137,141,143,145,146,147,149,150,155,158,162,164,165,169,175,177,178,182,185,187,194,209,210,211,218,223,227,292,337,343,386,394,403,453,457,469,471,476,477,545],"float":[30,112,120,132,150,205,247,256,257,260,289,354,410,416,428,465,479,480,488,492],"function":[0,5,7,8,9,13,14,15,19,22,27,28,29,31,32,39,41,42,45,47,48,49,51,52,54,57,58,60,62,65,67,68,69,71,73,74,75,77,78,79,82,86,87,88,92,94,95,96,99,103,104,106,108,112,113,114,117,118,120,122,123,124,125,126,128,131,134,135,136,137,139,140,141,142,143,144,146,148,149,150,152,155,156,157,158,159,161,162,165,167,170,172,174,177,178,182,185,190,195,199,201,204,207,210,212,213,215,216,217,218,219,223,224,225,226,228,229,230,232,233,241,247,250,256,257,260,266,270,273,275,280,283,289,292,294,299,305,308,309,310,311,312,316,322,329,337,338,339,343,346,349,350,354,364,369,371,372,378,380,386,390,392,393,394,398,401,402,403,407,409,410,411,416,420,421,425,436,437,442,445,448,455,457,459,466,467,468,469,470,472,473,474,476,477,479,480,485,486,487,490,491,492,493,496,516,518,521,541,542,543,545],"g\u00e9n\u00e9ral":180,"goto":[118,141,331,369,476,545],"import":[1,3,5,6,7,8,10,12,13,14,15,16,18,19,20,22,27,28,29,30,31,32,33,34,35,37,39,42,44,45,46,47,48,49,50,51,53,54,56,57,58,62,64,65,67,70,73,74,75,76,79,82,83,84,85,86,87,88,90,91,92,93,94,95,96,97,98,99,102,103,104,106,109,110,112,113,116,117,119,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,139,141,142,143,145,146,148,149,150,153,156,158,159,161,162,164,165,167,169,170,171,172,173,174,175,176,177,178,184,185,188,189,191,194,195,199,201,212,218,228,241,244,245,247,260,266,270,280,283,286,289,292,299,302,308,309,310,311,312,316,322,325,329,343,346,349,350,353,354,364,371,372,380,382,386,389,394,402,403,411,416,420,428,429,450,454,457,458,464,466,470,471,474,475,476,477,478,479,489,490,492,523,543,545],"int":[13,20,28,30,32,42,48,92,112,116,118,126,130,132,133,135,141,142,149,151,165,178,204,205,206,210,211,213,233,247,254,256,257,260,270,280,283,286,289,308,309,310,311,312,337,338,340,343,346,350,354,380,386,391,396,398,403,405,408,410,411,413,414,416,421,425,426,427,428,430,434,435,436,444,445,447,457,459,461,464,465,469,472,474,475,476,477,478,479,480,483,485,489,492,495],"long":[0,8,11,13,16,18,19,22,28,29,31,33,36,44,47,48,54,62,67,69,70,72,73,75,76,95,96,104,106,115,117,118,120,123,126,128,131,132,135,136,139,141,143,144,146,149,151,152,158,159,161,162,170,172,174,175,177,179,180,182,188,189,191,215,225,251,257,270,283,293,305,311,325,338,425,430,445,469,470,477,478,479,492,495],"n\u00fa\u00f1ez":77,"new":[0,2,5,7,9,11,12,13,14,15,18,19,20,22,25,26,27,28,31,33,34,35,37,39,40,41,44,45,46,49,50,51,55,56,57,61,62,64,65,68,69,72,73,75,76,80,82,85,90,91,92,97,104,105,106,109,110,113,115,117,118,119,120,122,123,125,126,128,130,131,132,134,136,139,140,141,142,143,144,146,150,151,152,153,154,155,156,157,159,160,161,162,163,164,165,166,168,169,170,171,172,174,176,178,179,180,182,183,184,185,186,187,188,189,190,191,192,193,195,204,205,206,211,212,213,215,216,218,223,225,226,229,230,232,233,241,251,254,257,266,273,274,275,278,280,286,289,292,299,302,305,308,309,310,311,312,316,322,325,329,331,337,338,339,340,349,350,351,354,370,371,372,380,382,386,388,390,394,396,397,398,400,402,403,405,406,409,410,411,413,416,425,426,427,428,434,435,436,441,448,456,457,461,464,465,466,467,469,470,472,475,476,477,478,483,485,486,492,500,502,505,506,533,538,540,542,544,545],"null":[49,67,78,143,181,501,508],"public":[11,18,53,77,78,90,126,135,143,148,158,178,186,187,189,191,193,194,223,398,461,478,545],"return":[2,3,5,6,8,13,16,18,19,22,27,29,30,31,32,33,37,39,41,42,45,46,48,49,51,52,53,54,58,60,62,64,69,72,76,85,86,92,95,99,107,112,113,117,118,120,123,124,125,126,127,128,129,130,131,132,135,136,137,139,140,141,142,143,144,149,150,153,155,161,162,164,165,167,170,171,172,174,177,178,188,193,194,199,200,204,205,206,207,209,210,211,212,213,215,218,223,225,228,229,232,233,234,239,241,247,250,254,255,256,257,260,270,273,274,275,276,278,280,283,286,289,292,299,305,308,309,310,311,312,316,322,329,331,337,338,339,340,343,346,349,350,353,354,359,364,369,370,371,372,377,378,380,382,386,388,389,390,391,393,394,396,397,398,400,401,402,403,405,407,408,409,410,411,413,414,416,421,422,425,426,428,429,430,431,433,434,435,436,437,439,440,441,443,444,445,447,448,454,455,457,459,460,461,464,465,466,467,469,470,471,472,473,474,476,477,478,479,480,483,485,486,487,488,489,490,491,492,493,495,496,500,501,502,504,505,506,508,510,512,513,515,521,523,525,532,537,538,540,541,543,545],"short":[3,13,28,36,37,46,51,58,60,65,72,74,76,82,95,96,104,106,116,118,128,130,134,135,136,144,147,149,151,157,165,184,188,194,199,223,241,257,270,275,286,302,338,349,350,403,470,492,495],"static":[31,49,51,52,53,73,77,80,104,106,111,120,132,135,148,157,158,169,201,202,228,235,241,254,341,350,352,353,366,389,402,403,461,472,512,513,515,521,530,541,545],"super":[8,20,37,48,62,76,82,83,86,95,126,132,134,135,136,139,149,152,165,172,174,241,286,350,545],"switch":[11,12,14,15,18,20,22,27,31,39,48,54,56,57,60,68,72,75,80,95,96,97,98,99,102,104,126,135,139,140,144,164,165,174,175,182,186,189,191,192,198,215,216,217,218,223,224,225,226,228,230,233,266,275,278,299,302,305,309,316,331,343,364,406,466,472,477,493],"th\u00ed":144,"throw":[11,13,41,63,76,177,190,212,410,492],"true":[0,8,12,13,14,18,19,20,22,27,28,30,31,32,33,34,36,39,42,44,47,48,49,50,51,52,53,54,60,62,63,64,67,71,73,76,77,84,87,92,95,118,124,125,126,128,132,133,135,136,137,139,141,142,143,144,148,149,150,153,155,158,161,164,165,171,173,174,175,177,184,186,189,191,192,193,204,206,207,209,211,212,213,215,218,223,225,226,229,232,233,234,241,244,247,254,257,266,273,274,275,278,280,283,286,289,292,293,305,308,309,310,311,312,322,329,337,338,339,340,343,346,349,350,354,364,369,370,380,382,386,388,390,393,394,396,397,398,400,402,403,405,406,407,408,409,410,411,414,416,421,422,425,427,434,439,444,445,455,457,459,461,464,465,466,469,472,474,476,477,478,479,480,483,487,488,489,490,492,493,497,500,501,502,504,505,506,507,508,513,540],"try":[0,3,5,6,13,14,16,18,19,27,28,30,31,32,33,39,42,50,51,54,55,56,58,63,64,67,69,70,73,74,75,76,86,90,95,96,97,108,109,110,112,117,118,119,120,122,123,124,125,126,128,129,130,131,132,133,134,135,137,139,142,143,144,145,146,147,149,150,151,152,154,156,157,159,160,161,162,163,165,166,168,169,170,172,173,174,175,177,178,181,182,184,185,186,187,190,191,194,199,204,207,211,213,218,232,234,241,242,245,247,251,258,283,292,308,309,310,311,312,322,325,329,337,340,349,350,353,354,364,370,371,372,382,388,390,396,398,402,413,416,425,440,441,445,459,464,466,469,471,472,474,475,479,488,492,501,508],"var":[51,68,99,182,187,376,440,470],"void":133,"while":[5,11,13,14,15,18,20,22,25,27,28,30,35,39,42,49,51,54,58,60,64,65,67,69,72,75,76,77,92,95,97,105,106,115,117,118,119,120,122,126,127,128,132,133,134,135,136,142,144,145,147,148,149,151,152,155,156,157,158,161,164,169,170,172,174,177,178,182,185,187,190,191,194,199,204,215,218,225,226,229,258,283,292,305,309,312,329,337,340,350,364,370,372,380,382,398,402,403,409,440,463,464,466,476,478,479,490,492,493,501,508,541],AIs:180,AND:[13,33,39,92,146,162,218,380,394,464,467],ARE:28,AWS:[104,191,193,237,545],Adding:[1,11,21,22,39,41,69,91,134,138,140,141,148,151,157,158,161,164,188,225,316,337,476,545],Age:[92,380,532],And:[0,2,3,18,22,28,44,54,67,75,76,83,95,96,97,113,124,125,126,128,134,136,137,142,149,151,152,157,159,162,170,175,177,212,286,308,309,310,311,312,340,386,545],Are:[22,140,144,156,180,476,545],Aye:96,BGs:175,Being:[95,119,135,139,151,155,165],But:[0,3,8,13,14,16,18,19,20,22,28,31,39,41,42,45,48,54,58,60,65,67,76,79,90,95,97,112,118,119,120,122,123,125,126,127,128,130,131,134,136,137,140,141,142,143,144,146,148,149,150,151,152,153,156,158,159,161,162,166,170,175,177,178,184,187,189,193,195,211,212,283,340,354,402,467,542],DNS:[187,191],DOING:[92,380],DoS:[5,434],Doing:[11,22,42,122,128,133,143,162,178,212,215],For:[2,3,4,5,10,11,12,13,14,15,17,18,19,20,22,28,30,31,33,35,38,41,42,44,49,50,52,53,55,56,57,58,59,60,64,65,67,68,70,72,73,74,75,76,77,78,82,83,86,88,90,92,93,95,96,97,99,111,113,118,119,120,122,123,125,126,128,130,132,133,134,135,136,137,139,141,142,144,146,148,149,150,151,152,153,157,158,161,162,164,165,169,170,174,175,176,177,178,180,181,182,185,187,189,191,192,193,194,199,204,211,212,213,218,223,225,228,232,233,234,241,260,275,286,294,296,309,316,322,338,340,343,350,354,366,370,380,386,388,390,393,394,398,403,410,436,440,445,464,466,469,473,476,479,486,488,490,492,517,525,532,542],GMs:[135,157,158],Going:[116,158,159,270,545],Has:[183,308,309,310,311,312],His:[93,134,296],IDE:[7,120],IDEs:134,IDs:[97,177,178,193,256,464,492,515],INTO:[92,218,331,380],IOS:183,IPs:[55,182,194,376,459],IRE:[68,440],Its:[4,22,33,37,42,44,58,65,67,93,136,137,223,296,364,403,474,476,492],LTS:6,NOT:[13,22,33,51,115,126,146,191,194,218,338,394,403,459,479],Near:147,Not:[18,32,46,47,51,58,69,95,129,134,143,146,151,152,156,159,176,177,181,183,184,191,205,212,226,398,413,426,427,428,430,431,432,438,440,443,464,465,486,496],OBS:57,ONE:194,One:[2,9,10,28,30,33,36,42,44,47,55,58,76,79,88,90,95,96,97,104,112,113,120,123,126,128,132,134,135,137,142,143,144,146,149,151,152,153,158,161,165,171,174,175,176,180,181,182,185,199,201,207,209,225,275,283,289,292,337,338,340,343,349,354,370,371,386,396,402,403,426,454,464,465,469,470,476,477,479,492,501,508,540,545],PMs:545,Such:[8,14,22,28,50,95,123,127,134,156,158,162,218,403,469,476],THAT:142,THE:[92,380],THEN:[92,212,380],THERE:[92,380],TLS:[194,545],That:[0,3,4,5,11,16,20,22,30,32,39,41,42,44,46,47,48,54,74,75,76,79,82,85,89,95,96,97,112,113,118,122,123,124,125,126,130,132,134,136,137,142,143,144,146,147,149,150,151,155,157,158,161,162,167,169,170,178,192,241,251,266,283,289,338,354,386,394,403,457,476,517],The:[2,3,4,6,7,8,9,10,11,12,13,16,17,18,19,20,22,24,26,29,32,33,34,35,36,37,40,44,45,46,47,48,49,51,52,53,55,58,60,62,63,64,67,68,69,70,71,72,74,75,77,78,79,80,82,83,85,86,87,88,89,90,91,92,93,94,97,98,99,104,105,106,107,108,109,110,112,113,114,115,116,117,119,120,121,122,123,124,125,126,127,129,130,131,133,134,136,139,140,142,143,144,145,146,147,148,149,150,151,152,153,154,157,158,161,162,169,170,172,173,174,175,176,177,178,179,180,181,182,183,184,185,187,189,190,191,192,193,194,195,197,199,204,205,206,207,209,210,211,212,213,215,218,222,223,224,225,226,227,228,229,230,232,233,234,241,247,250,251,254,255,256,257,260,270,273,274,275,276,278,280,283,286,289,292,293,296,299,305,308,309,310,311,312,316,322,325,329,331,334,337,338,339,340,343,346,349,350,354,359,362,364,369,370,371,372,380,382,386,387,388,389,390,391,393,394,396,397,398,400,401,402,403,405,406,407,408,409,410,411,413,414,415,416,418,420,421,423,425,426,427,428,429,430,431,432,433,434,435,436,438,439,440,441,443,444,445,447,448,453,454,455,456,457,461,464,465,466,467,469,470,471,472,473,474,475,476,477,478,479,480,481,483,485,486,487,488,489,490,492,493,495,496,501,502,508,512,513,515,517,518,521,523,532,540,541,544,545],Their:[28,41,53,93,162,194,296],Theirs:[93,296],Then:[3,5,8,11,16,45,51,53,64,75,76,91,95,96,97,101,118,120,130,133,137,142,149,185,193,316,332],There:[0,5,6,8,9,13,14,15,16,18,19,20,22,28,30,31,37,39,42,44,45,46,48,49,50,53,54,57,58,60,67,68,69,70,76,77,80,90,91,92,95,96,97,112,113,117,118,120,123,125,126,132,134,135,136,137,139,141,142,143,144,145,146,148,150,151,153,156,157,158,159,161,162,164,165,169,170,171,172,174,177,180,181,182,187,189,191,192,194,195,226,292,308,309,310,311,312,316,329,337,354,380,386,403,411,421,440,457,469,470,476,479,544],These:[5,8,11,13,14,17,22,24,25,28,30,31,32,35,41,42,44,45,46,48,50,51,52,53,58,60,62,65,67,68,71,75,76,82,83,86,90,95,97,104,105,106,108,118,120,124,126,130,132,137,142,143,144,145,146,148,149,151,152,153,157,158,161,162,170,174,177,186,187,191,193,194,199,203,204,209,211,213,215,217,219,223,227,233,241,247,260,292,299,305,335,337,338,340,349,350,354,364,372,377,388,389,394,398,402,403,411,415,422,441,444,445,447,456,457,458,464,466,469,473,476,477,478,479,480,485,486,487,492,496,500,509,542],USING:292,Use:[5,8,11,12,14,15,20,28,30,31,35,37,41,44,48,51,55,58,60,75,76,79,81,89,98,99,100,107,108,111,118,120,124,126,135,137,144,150,151,152,155,164,165,181,182,183,184,185,186,187,191,193,198,204,210,215,216,218,223,224,225,228,230,232,241,242,247,251,270,273,283,292,299,302,305,309,310,311,312,333,350,366,382,388,396,397,398,416,418,422,427,444,445,447,451,464,466,469,475,476,478,479,483,489,492,505,545],Used:[22,174,209,212,218,230,302,329,336,337,340,380,386,396,397,409,418,436,464,466,477,478,490,492,500],Useful:[28,118,191],Uses:[218,230,251,370,376,416,464,478,483,545],Using:[1,4,19,28,33,35,39,47,58,61,71,76,86,96,104,108,122,135,136,142,146,149,150,151,152,154,158,160,163,165,166,168,174,197,201,202,235,270,309,341,350,352,364,398,436,463,476,545],VCS:2,VHS:[92,380],VPS:191,WILL:[142,183],WIS:135,WITH:[28,92,182,380],Was:223,Will:[20,32,107,118,144,156,199,204,223,247,278,280,292,340,350,382,398,401,403,414,416,425,426,466,476,478,479,480,487,492,545],With:[13,16,18,28,36,53,57,77,95,118,122,134,143,146,153,155,156,157,158,161,165,170,181,182,193,201,204,241,292,338,350,403,464,469,479],Yes:[22,92,95,380,474,476,545],__1:485,__2:485,_________________:48,_________________________:28,___________________________:113,______________________________:28,_______________________________:113,________________________________:28,_________________________________:48,______________________________________:476,_________________________________________:28,______________________________________________:28,_______________________________________________:28,____________________________________________________:28,_________________________________________________________:141,__________________________________________________________:141,_______________________________________________________________:113,________________________________________________________________:113,__all__:[500,502,504,505],__defaultclasspath__:466,__dict__:416,__doc__:[22,31,213,226,228,229,389,390,472,476],__example__:6,__ge:146,__ge__:6,__getitem__:469,__gt:146,__iendswith:146,__in:146,__init_:478,__init__:[4,6,13,45,48,62,82,119,121,132,147,148,149,152,167,211,212,213,234,241,254,270,278,283,289,292,336,337,338,350,354,382,388,394,397,398,402,407,408,410,411,413,414,416,418,419,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,443,444,445,447,454,455,457,459,460,461,464,466,467,469,471,474,475,476,477,478,479,485,486,487,488,492,500,501,505,508,523,526],__istartswith:146,__iter__:13,__le:146,__lt:146,__multimatch_command:227,__noinput_command:[211,227,241,474,476,477],__nomatch_command:[227,241,273,372,474,476,477],__packed_dbobj__:50,__pycache__:148,__settingsclasspath__:466,__str__:540,__unloggedin_look_command:[26,230,251],_action_thre:28,_action_two:28,_actual_myfunc_cal:28,_all_:211,_always_:[292,479],_and_:[479,492],_ask_again:28,_asynctest:[373,442],_attrs_to_sync:456,_attrtyp:464,_by_tag:19,_cach:466,_cached_cmdset:212,_call_or_get:241,_callable_no:476,_callable_y:476,_callback:[19,411],_char_index:469,_check_password:28,_check_usernam:28,_clean_nam:239,_clean_str:469,_cleanup_charact:164,_code_index:469,_compress_cont:239,_copi:[218,398],_create_charact:177,_creation:48,_dashlin:30,_data:477,_default:[28,476],_defend:28,_differ:469,_errorcmdset:212,_event:[95,260],_every_:292,_evmenu:476,_file:485,_flag:402,_footer:22,_format_diff_text_and_opt:403,_funcnam:492,_gambl:28,_get_a_random_goblin_nam:41,_get_db_hold:[455,466],_get_top:137,_getinput:476,_gettabl:421,_guaranteed_:479,_handle_answ:28,_helper:479,_http11clientfactori:418,_init:0,_init_charact:164,_is_fight:128,_is_in_mage_guild:28,_ital:120,_italic_:184,_last_puppet:[50,505],_linklen:338,_loadfunc:474,_magicrecip:293,_maptest:335,_menutre:[28,126,476],_mockobj:353,_monitor:421,_monitor_callback:34,_nicklist_cal:205,_npage:477,_oob_at_:483,_option:28,_overrid:[51,73],_page_formatt:477,_pagin:477,_parsedfunc:479,_pending_request:461,_permission_hierarchi:393,_ping_cal:205,_playabel_charact:50,_playable_charact:[137,177,505],_postsav:483,_power_cal:30,_prefix:350,_process_cal:30,_quell:393,_quitfunc:474,_raw_str:469,_reactor_stop:[433,454],_read:354,_recog_obj2recog:350,_recog_obj2regex:350,_recog_ref2recog:350,_regex:350,_repeat:421,_safe_contents_upd:397,_savefunc:474,_saver:[13,473],_saverdict:[13,354,473],_saverlist:[13,473],_saverset:473,_sdesc:350,_select:28,_sensitive_:524,_session:476,_set:146,_set_attribut:28,_set_nam:28,_should:545,_skill_check:28,_some_other_monitor_callback:34,_start_delai:411,_static:120,_step:338,_stop_:492,_stop_serv:433,_swordsmithingbaserecip:293,_templat:120,_test:[30,209],_to_evt:477,_traithandlerbas:353,_transit_:340,_try_again:28,_typeclass:53,_uptim:30,_validate_fieldnam:135,_weight:338,_yes_no_quest:476,a2enmod:181,a8oc3d5b:193,a_off:283,aaaaaargh:151,aardwolf:68,abandon:273,abat:159,abbrevi:[60,64,218,293,302,479],abcd:224,abid:175,abil:[13,20,22,29,33,41,51,54,69,95,104,106,110,118,133,134,135,144,148,151,155,157,158,162,165,178,191,193,308,309,310,311,312,325,349,350,398,409,416,464,536],abl:[0,2,3,5,7,10,11,13,14,15,18,19,20,22,28,29,30,36,37,41,42,46,50,52,53,57,67,74,76,86,90,94,95,97,103,109,112,118,120,122,123,124,125,127,128,132,134,135,137,139,141,142,144,150,151,155,156,159,161,162,164,165,167,170,174,177,178,181,182,185,187,188,190,191,193,194,195,212,215,216,218,219,223,225,232,234,241,247,275,299,308,309,310,311,312,322,333,337,338,346,350,354,464,466,473,488,492,533,545],abort:[19,22,28,29,37,104,110,118,126,153,161,204,213,218,232,273,292,325,331,338,372,398,401,409,476,477,479,492,545],about:[0,2,3,5,6,11,13,14,15,16,17,20,22,26,28,30,31,35,38,41,46,49,50,53,54,55,56,60,65,67,69,70,73,75,76,78,82,85,95,96,97,104,119,120,122,123,125,126,129,130,131,134,137,138,139,141,142,143,144,145,146,147,148,149,151,154,155,156,159,160,161,162,163,164,165,166,167,168,169,172,173,175,178,179,180,182,183,184,185,188,190,191,193,194,195,197,199,204,218,225,228,241,273,275,276,283,286,289,292,310,311,312,335,337,343,366,371,372,390,398,416,418,421,430,432,434,443,445,447,448,455,457,465,467,469,477,483,492,501,508,515,545],abov:[0,2,7,8,11,12,13,14,15,19,20,22,27,28,30,31,32,33,34,41,42,44,46,48,49,51,52,53,54,55,58,62,64,67,73,74,75,77,82,86,90,94,95,96,98,99,106,107,112,118,119,120,123,124,125,127,128,129,131,132,133,134,135,136,137,139,141,142,144,146,148,149,150,151,152,153,154,157,161,164,165,170,172,174,176,177,181,182,183,185,187,191,193,199,211,212,218,241,280,292,299,308,310,311,312,325,331,337,343,346,350,354,366,380,382,386,394,396,398,421,476,479,487,501],above_str:30,abruptli:[112,354],absolut:[19,53,93,120,133,136,138,142,180,247,286,296,343,475,480,492],absorb:32,abspath:492,abstractus:207,abus:[78,194,545],academi:180,acccount:24,accecss:479,accept:[13,15,18,19,20,28,30,32,33,47,48,68,76,79,92,95,106,110,118,119,135,150,151,157,158,177,178,182,184,191,204,209,210,228,255,258,283,325,337,338,340,343,349,350,370,372,380,382,398,416,421,434,460,461,465,470,476,479,488,492],accept_callback:[255,257],access:[0,8,9,11,13,14,15,18,19,20,22,26,28,29,30,31,32,33,34,35,36,39,41,42,44,45,46,48,49,51,52,53,55,57,62,63,65,67,69,73,76,77,82,86,94,95,97,104,112,118,119,120,121,123,124,125,126,128,130,132,133,134,135,137,138,141,142,143,145,146,147,148,149,150,151,154,155,157,158,161,162,164,165,170,174,175,177,178,181,182,185,187,188,191,193,194,195,198,204,206,207,211,212,213,215,216,218,223,224,225,226,228,230,232,233,234,241,254,256,266,270,273,292,294,305,308,309,310,311,312,316,340,346,349,350,353,354,372,388,389,390,391,392,393,394,397,398,401,402,403,406,408,410,411,413,416,425,426,455,457,463,464,466,467,470,471,472,479,485,491,492,496,501,502,508,513,515,518,532,538,540,543,545],access_obj:[393,464],access_object:33,access_opt:493,access_token_kei:[173,188],access_token_secret:[173,188],access_typ:[37,204,213,218,232,234,388,390,393,394,398,464,466,537,538,543,545],accessed_obj:[33,126,161,174,393,394],accessing_obj:[13,33,126,161,174,204,232,234,388,390,393,394,398,464,466],accessing_object:[13,33,393],accessor:[207,234,390,397,406,464,466,467,484],accessori:185,accident:[16,20,58,118,120,158,165,216,218,293,455],accommod:124,accomod:478,accompani:165,accomplish:[55,115,122,126,132,156,158,161,479],accord:[20,22,106,146,158,164,170,175,241,280,286,309,337,349,382,410,469,470,479],accordingli:[7,132,135,191,270],account1:[8,533],account2:[8,533],account:[5,8,11,13,15,17,18,20,22,25,26,27,28,29,30,32,33,35,36,37,39,40,41,42,44,45,46,48,49,53,55,57,60,63,65,69,72,73,75,76,87,94,97,98,99,100,104,109,120,121,124,125,126,132,133,134,136,137,139,142,143,144,147,148,149,150,153,156,165,170,173,175,177,178,183,186,188,191,193,195,199,201,202,208,209,210,211,212,213,214,216,218,219,220,223,224,225,226,228,230,232,233,234,241,247,251,254,255,257,266,273,274,286,289,299,308,310,311,312,316,322,329,340,346,350,364,369,370,371,372,376,380,388,390,393,394,396,397,398,400,402,403,404,405,406,416,420,421,436,447,448,455,456,457,464,466,467,469,472,476,477,479,486,487,489,490,492,493,498,499,505,512,513,515,518,523,524,531,532,533,535,538,540,542,545],account_cal:[215,223,226,266,299],account_count:457,account_id:[177,398],account_nam:133,account_search:[206,350,398],account_subscription_set:207,account_typeclass:[490,533],accountadmin:[50,500],accountattributeinlin:500,accountchangeform:500,accountcmdset:[12,20,26,76,134,135,136,150,215,219,299,545],accountcreateview:536,accountcreationform:500,accountdb:[48,121,177,201,204,207,213,232,388,390,463,466,486,493,500,501,508,512],accountdb_db_attribut:500,accountdb_db_tag:500,accountdb_set:[464,467],accountdbfilterset:[512,518],accountdbmanag:[206,207],accountdbpasswordcheck:436,accountdbviewset:518,accountform:[532,536],accountid:177,accountlist:135,accountlistseri:[515,518],accountmanag:[204,206],accountmixin:536,accountnam:[135,218,230,233,251],accountseri:[515,518],accounttaginlin:500,accross:118,accru:204,acct:153,accur:[76,213,254,278,289,309,312,336,354,388,403,410,414,416,418,419,427,436,437,439,441,444,445,464,469,487,488,526],accuraci:[96,114,142,157,309,310,311],accus:162,accustom:36,acept:[92,380],achiev:[19,22,60,76,97,120,134,146,155,159,175,276,311,416],ack:29,acl:[77,239],acquaint:[134,159],acquir:471,across:[28,30,41,42,44,48,56,62,67,69,83,106,118,133,142,151,156,158,187,204,211,212,286,338,340,349,372,380,389,398,409,411,413,425,426,440,457,477,478,479],act:[5,12,14,18,20,28,42,44,52,61,92,95,112,113,118,128,132,133,135,146,151,156,158,165,170,181,182,199,201,204,218,223,234,250,275,276,332,337,338,339,340,354,355,380,386,413,425,426,445,464,467,471,476],action1:164,action2:164,action:[3,5,28,42,49,50,58,60,68,76,77,80,85,90,92,95,96,97,104,114,116,118,122,123,128,130,134,136,142,148,149,151,156,161,162,164,165,171,172,177,191,204,205,213,223,224,228,232,270,273,275,278,280,283,289,308,309,310,311,312,338,350,364,369,380,388,389,390,402,406,407,428,447,448,449,459,466,476,477,483,500,513,516,517,518,545],action_count:164,action_nam:[308,309,310,311,312],action_preposit:275,actiondict:164,actions_per_turn:[308,309,311,312],activ:[0,2,9,14,19,20,22,37,39,42,44,49,55,60,63,64,65,73,75,77,95,119,120,123,124,127,136,139,143,156,169,180,185,186,189,190,191,192,198,199,204,209,212,216,218,228,230,232,255,329,364,370,377,397,398,401,410,421,428,429,430,431,432,436,438,439,440,447,457,459,464,465,476,477,478,479,492,545],activest:491,actor:[30,312,398,479,495,545],actor_stance_cal:545,actual:[0,2,3,5,6,7,8,9,11,12,13,14,15,18,19,28,30,31,33,35,36,37,39,41,44,46,47,50,51,52,53,54,57,58,60,62,65,67,68,70,76,77,90,96,103,104,117,118,120,123,125,128,131,132,135,137,139,141,142,143,144,145,146,147,148,150,151,152,153,155,156,157,158,159,161,162,164,165,166,169,170,174,175,177,178,180,181,185,188,191,193,195,204,209,213,215,218,223,224,226,228,229,230,232,234,241,260,273,278,283,286,292,293,302,305,308,309,310,311,312,316,325,329,334,335,337,338,339,349,350,353,364,366,371,372,380,386,388,390,393,394,397,398,403,436,439,445,447,453,455,456,457,461,462,464,466,469,471,474,476,483,486,487,488,490,492,510,543,545],actual_return:8,ada:31,adam:77,adapt:[62,97,124,125,137,157,162,177,292],add:[0,2,3,5,7,8,9,10,11,12,13,14,15,16,17,18,20,22,25,26,27,28,30,31,32,33,34,35,36,37,39,41,42,44,46,47,48,49,50,51,54,56,57,60,62,63,64,67,68,70,73,74,75,76,79,81,82,83,84,85,86,88,89,90,91,93,95,96,97,98,99,100,102,103,104,105,106,109,110,112,113,114,116,118,119,120,122,123,125,128,129,130,131,132,134,135,136,137,138,139,140,141,142,143,144,146,148,149,150,151,152,153,154,156,157,158,159,161,162,164,165,170,171,172,173,174,176,177,178,179,180,181,183,184,186,187,188,191,192,193,195,201,204,207,211,212,218,223,224,225,227,229,232,234,241,242,244,247,251,254,255,257,258,260,266,270,273,275,280,283,286,289,292,299,302,305,308,309,310,311,312,316,322,325,331,332,333,334,337,338,339,343,349,350,353,354,359,364,369,370,371,372,376,386,393,394,397,398,402,403,406,407,408,409,410,411,416,421,422,426,429,430,432,434,438,445,447,448,450,458,464,467,470,474,475,476,477,478,479,483,485,487,488,490,500,505,512,518,540,543,545],add_:478,add_act:164,add_alia:223,add_argu:[116,270],add_callback:[255,257],add_charact:164,add_choic:[82,241,242,545],add_choice_:241,add_choice_edit:[76,82,241],add_choice_quit:[76,241],add_collumn:213,add_column:[135,478],add_condit:310,add_default:[20,125,141,161,174,212],add_dist:312,add_ev:257,add_fieldset:[500,505],add_form:[500,505],add_head:478,add_languag:[106,349],add_map:339,add_msg_bord:280,add_row:[135,140,213,478],add_user_channel_alia:[18,232],add_view:[500,502,505],add_xp:162,addcallback:[22,398],addclass:[51,201,202,498,519,545],addcom:[103,135,143,266],added:[2,3,7,9,11,17,19,20,22,31,33,41,42,46,49,62,67,68,69,76,77,83,84,93,95,97,106,108,112,114,117,118,119,120,124,125,126,134,135,137,142,143,146,148,149,150,151,152,157,161,162,164,165,170,171,174,176,177,179,183,186,190,193,199,204,209,211,212,213,223,227,228,230,241,244,254,257,260,283,286,289,292,293,296,308,309,310,311,312,329,333,337,338,343,349,350,354,364,388,394,398,401,403,408,410,421,455,459,464,467,470,476,477,478,485,492,518,525,536,540,544],addendum:119,adding:[2,5,6,7,8,9,13,15,17,19,20,25,26,28,33,41,46,47,48,51,53,60,62,64,67,69,75,76,86,87,90,92,95,96,97,98,112,113,114,118,120,125,128,134,135,136,137,138,139,141,142,146,150,151,152,158,164,165,167,174,175,177,195,211,212,216,218,225,241,247,254,257,270,292,299,308,309,310,311,331,346,349,350,354,372,380,386,396,398,402,403,408,416,447,464,472,478,492,501,508],addingservermxp:431,addit:[2,20,27,30,42,50,53,60,68,76,84,95,96,99,104,113,118,119,120,124,126,132,135,136,137,140,142,178,181,191,194,195,204,205,212,213,225,232,241,244,254,255,257,270,312,338,340,349,353,376,386,394,398,401,410,427,455,464,466,476,532,545],addition:[126,170,312],additionalcmdset:20,addpart:305,addquot:492,addr:[206,413,426,427,428,472],address:[11,22,36,44,55,58,62,73,75,89,93,104,132,142,167,182,187,191,194,204,206,216,232,251,296,398,413,426,428,436,456,459,492,493,545],address_and_port:436,addresult:305,addscript:42,addservic:62,adjac:[99,118,312,370],adject:[6,58,161,479,496],adjoin:350,adjust:[22,97,119,157,175,177,185,346,410,476,478,479],admin:[0,12,13,16,18,22,33,39,52,53,55,57,67,75,78,125,132,135,137,141,148,149,156,158,165,174,177,178,189,192,199,201,202,206,207,208,213,214,218,223,228,230,232,251,266,273,280,370,388,390,394,397,398,425,426,466,472,488,498,523,545],admin_sit:[500,501,502,504,505,506,507,508],admin_wrapp:503,adminconfig:523,administr:[2,22,33,39,54,72,95,120,122,123,135,182,185,194,413,425,426,545],adminportal2serv:425,adminserver2port:425,adminsit:[50,201,202,498,522,545],adminstr:413,admintest:533,admit:130,admittedli:[118,155],adopt:[0,76,104,123,125,134,158,234,440,495],advanc:[5,14,20,22,28,30,41,44,48,53,54,55,62,67,69,76,77,99,104,106,108,112,115,122,123,127,130,131,135,138,146,151,154,158,165,170,180,195,218,226,308,309,310,311,312,316,350,354,364,382,431,470,474,475,476,478,545],advantag:[2,15,16,28,31,41,58,96,106,118,122,127,130,133,135,136,137,158,161,162,164,165,167,172,177,191,194,195,241,283,308,309,310,311,312,376,386,467,470],adventur:[86,104,105,115,148,155,158,170],advic:180,advis:[76,97,126],aesthet:27,affair:471,affect:[5,9,13,14,15,20,22,39,42,44,46,50,57,60,84,108,114,118,126,136,139,151,156,158,161,162,164,175,198,204,211,228,244,260,278,292,310,322,337,349,364,398,402,466,470,478,486],affili:410,affliat:410,afford:[44,141],afraid:191,after:[0,2,8,9,10,11,13,15,16,19,20,22,27,28,33,42,45,52,53,54,60,64,65,67,75,76,77,79,83,86,92,95,96,97,108,112,114,115,118,120,122,125,126,127,128,129,130,131,132,135,141,142,143,144,148,149,150,151,152,155,156,158,159,164,165,169,171,174,175,177,180,181,185,187,191,193,194,204,211,212,213,214,215,218,225,226,228,229,230,232,241,247,248,251,257,270,273,278,279,283,286,292,293,294,305,308,309,310,311,312,313,316,329,335,338,346,349,350,351,353,354,360,364,370,371,372,380,386,388,397,398,403,405,407,409,410,416,438,439,442,447,454,455,456,457,459,461,464,469,470,471,474,476,477,483,487,491,492,513,516,536,538,543],afterlif:158,afternoon:[91,316],afterward:[11,67,80,118,128,137,142,149,153,155,241],again:[3,7,9,13,14,15,18,22,28,35,42,44,52,55,60,67,76,85,90,95,97,104,107,108,115,117,118,123,125,127,128,130,132,133,134,135,136,137,139,141,142,143,144,147,149,150,151,152,154,156,158,161,162,164,165,170,174,175,177,182,184,185,187,191,192,193,198,199,205,212,223,229,247,257,289,308,311,312,329,364,382,409,416,433,436,439,459,469,470,473,488,490],againnneven:229,against:[11,13,20,22,48,64,65,95,114,119,125,134,135,146,155,157,164,191,194,204,210,211,293,308,309,310,311,312,350,394,396,398,402,403,434,459,464,466,467,489,492],age:[77,92,116,270,380,532],agenc:194,agent:2,agenta:[60,469],ages:[92,380],aggreg:180,aggress:[13,15,115,155,190,370,466,545],aggressive_pac:370,agi:[13,104,112,354],agil:13,agnost:[119,123],ago:[95,126,149,193,492],agre:[70,79,104,158,159,162,278,283],agree:283,ahead:[2,15,69,76,132,150,174,183,191,438],aid:[70,79,104,118,154,225,226,283,461],aim:[1,67,69,122,135,138,141,151,156,157,159,162,175,191,402],ain:96,ainnev:[104,112,146,162,354],air:[125,144,152,170],airport:153,ajax:[51,62,191,445,456],ajaxwebcli:445,ajaxwebclientsess:445,aka:[5,13,75,105,158,305,492],akin:149,alarm:[140,144],alchin:77,ale:99,alert:[18,232,398],alex:77,alexandrian:180,algebra:132,algorith:349,algorithm:[31,118,158,337,338,396,492],alia:[11,12,18,20,22,26,30,36,37,42,44,46,48,50,72,75,76,103,106,118,125,131,134,135,143,144,151,153,170,185,191,207,210,213,215,218,223,224,225,226,229,232,254,266,289,316,317,322,329,331,338,350,354,360,370,372,393,397,398,403,406,411,421,447,465,466,467,472,479,488,489,490,496,500,501,502,504,505,506,508,512,514,515,516,518,532,536,537,538,543,545],alias1:[218,316],alias2:[218,316],alias3:316,alias:[11,12,14,18,19,20,22,28,30,31,32,36,37,41,50,58,72,74,76,86,95,99,125,126,128,131,135,139,140,141,143,144,161,164,165,170,204,211,213,215,216,217,218,223,224,225,226,227,228,229,230,232,233,241,251,255,266,269,270,273,275,283,286,292,293,296,299,302,305,308,309,310,311,312,316,322,325,329,331,338,343,350,364,366,370,371,372,380,386,388,389,390,391,396,397,398,403,447,465,466,467,472,474,476,477,485,489,490,496,512,515,545],aliaschan:266,aliasdb:204,aliasfilt:512,aliashandl:[467,508,515],aliasnam:403,aliasstr:[396,472],align:[30,41,135,346,469,478,479,492],alist:6,aliv:[122,370],alkarouri:491,all:[0,2,5,6,7,8,9,11,12,13,14,15,16,17,18,19,20,22,25,27,28,30,31,32,33,35,36,37,39,41,42,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,62,64,65,67,68,69,70,71,72,73,74,75,76,77,78,80,82,86,88,90,91,92,96,97,103,104,105,106,107,109,112,113,115,117,118,119,120,121,122,123,125,127,128,129,130,131,132,133,134,135,136,139,140,141,142,143,144,145,146,147,148,150,151,152,153,154,155,156,157,159,161,162,163,164,165,166,167,169,170,171,172,174,175,176,177,178,179,180,181,182,184,185,189,190,191,192,193,194,195,198,199,204,205,206,208,209,210,211,212,213,214,215,216,217,218,219,220,223,224,225,226,227,228,229,230,232,233,234,241,251,254,257,266,269,270,273,275,276,278,279,283,286,289,292,293,296,299,302,305,308,309,310,311,312,316,322,325,329,331,337,338,339,340,343,349,350,353,354,362,364,366,369,370,371,372,377,380,382,386,388,389,390,391,392,393,394,395,396,397,398,401,402,403,405,407,408,409,410,411,412,415,416,420,421,422,425,427,428,430,432,433,434,435,436,439,440,443,444,445,447,448,454,455,456,457,459,461,462,463,464,465,466,467,469,470,471,472,473,474,475,476,477,478,479,483,485,487,489,490,491,492,493,495,497,500,501,502,504,505,506,508,509,510,518,521,523,525,532,538,540,541,543,544,545],all_alias:46,all_attr:466,all_book:153,all_cannon:146,all_cloth:13,all_cmd:225,all_connected_account:457,all_displai:411,all_famili:146,all_fantasy_book:153,all_flow:153,all_from_modul:492,all_kei:225,all_map:[118,339],all_opt:487,all_receiv:398,all_room:[14,146],all_ros:153,all_script:42,all_scripts_on_obj:42,all_sessions_portal_sync:457,all_to_categori:389,all_weapon:146,allcom:[103,143,266],allerror:[416,425],allevi:[8,13,69,461],allheadersreceiv:461,alli:312,alloc:191,allow:[0,2,3,6,7,8,11,12,13,14,15,16,19,20,22,28,30,31,32,33,35,36,37,39,40,41,46,48,49,50,51,52,53,54,55,56,57,58,64,67,69,70,71,72,73,75,76,77,78,79,82,86,87,90,91,92,93,95,96,97,99,102,104,106,112,113,114,117,118,120,121,122,123,124,125,128,129,130,131,132,134,135,138,139,141,142,144,146,148,149,150,151,152,153,156,157,161,162,164,165,167,170,174,175,177,178,179,181,182,184,185,186,187,188,189,190,191,192,193,194,195,204,205,207,209,211,212,213,215,216,217,218,223,225,226,228,229,232,233,234,241,247,257,266,270,273,275,278,280,283,286,292,294,296,302,308,309,310,311,312,316,329,337,338,340,343,349,350,353,354,364,370,371,372,380,382,386,388,390,391,393,394,396,398,402,403,407,410,411,416,420,421,423,427,429,430,431,432,439,440,441,443,448,454,455,457,459,460,464,466,467,469,470,472,474,476,477,478,479,480,483,486,487,488,490,492,503,505,512,513,518,532,537,540,545],allow_abort:476,allow_dupl:211,allow_extra_properti:354,allow_nan:445,allow_quit:476,allow_reus:292,allowed_attr:135,allowed_fieldnam:135,allowed_host:[191,194],allowed_propnam:165,allowedmethod:445,allowext:461,almost:[13,22,31,47,48,50,57,82,83,151,152,241,286,418,425,463],alon:[8,11,14,28,33,36,67,90,104,115,128,132,133,135,151,159,162,164,211,225,340,411,421,447,470,472,478,479,508],alone_suffix:452,along:[5,22,28,32,42,45,55,60,68,78,79,80,95,99,106,112,113,115,118,123,142,146,147,151,155,156,159,161,163,174,179,195,204,215,283,311,338,343,349,354,376,386,394,398,445,463,518],alongsid:[92,187,339,380],alonw:406,alpha:[184,191,469,545],alphabet:[16,70,170,469,544],alreadi:[0,7,8,9,11,12,13,14,16,19,20,22,27,28,30,31,33,37,42,44,46,48,51,53,62,68,73,75,76,78,90,95,96,97,115,118,119,120,123,125,126,128,132,133,134,135,137,139,140,141,142,143,144,145,148,149,150,151,152,153,154,156,159,161,162,164,165,169,171,172,173,174,177,178,184,185,189,193,194,199,204,206,211,212,215,218,226,228,232,233,266,275,280,283,286,289,292,293,308,309,310,311,312,329,337,338,340,349,350,354,370,371,382,394,398,402,403,416,425,433,434,436,441,444,449,454,455,457,464,467,469,472,477,485,490,492,513,524],alredi:62,alright:[79,283],also:[0,1,2,3,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,25,27,28,30,31,32,33,34,36,37,39,41,42,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,60,62,63,64,65,67,68,69,70,72,73,74,75,76,77,79,83,85,86,88,89,90,91,92,94,95,96,97,100,102,104,106,107,110,112,113,115,117,118,119,120,121,122,123,125,126,127,128,129,130,131,132,133,134,135,136,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,159,161,162,163,164,165,166,167,168,169,170,171,172,174,175,176,177,178,180,181,182,183,184,185,186,187,189,190,191,192,193,194,195,198,199,204,206,207,210,211,212,213,215,216,217,218,220,223,224,225,226,228,229,232,233,234,241,257,275,276,280,283,286,289,292,293,299,302,310,311,312,316,325,329,331,337,338,340,343,346,349,350,354,364,370,371,372,380,382,386,388,392,393,394,396,397,398,402,403,404,406,409,411,412,416,420,421,425,427,434,436,439,440,443,444,447,448,457,461,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,483,489,490,492,512,538,540,541,543,545],alt:469,alter:[51,95,97,123,124,170,182,464],altern:[13,18,22,28,31,36,42,46,50,60,64,74,86,104,105,112,116,120,123,128,134,139,143,154,161,170,172,177,182,185,189,191,197,223,226,232,233,250,305,312,350,354,364,389,393,394,396,434,469,472,492,545],although:[3,76,95,128,130,152,185,215,241,343,461,488,492],althougn:96,altogeth:[27,60,118,194],alwai:[4,8,9,12,13,14,15,18,19,20,22,28,30,31,32,33,35,37,39,41,42,44,45,46,47,48,51,55,58,60,67,68,73,86,95,97,98,106,109,112,118,119,120,123,124,125,126,129,130,132,134,135,136,137,141,142,143,144,149,150,151,152,153,154,156,158,161,162,165,174,175,178,181,182,185,189,191,204,211,212,213,215,217,218,223,225,226,229,232,233,234,273,278,292,294,299,322,337,338,340,349,350,354,364,391,393,394,396,397,398,402,403,411,416,418,421,425,433,436,439,440,444,445,448,455,457,462,464,465,466,467,469,472,479,483,488,489,492,493,513,525,541],always_pag:477,always_return:416,amaz:190,amazon:[77,104,180,191],amazonaw:77,amazons3:77,ambianc:69,ambigu:[93,118,213,296,338,398,466],ambiti:[69,72],amend:11,amfl:15,ammo:125,among:[2,12,25,37,123,136,153,159,165,170,180,195,224,286,371,394,396,478,489],amongst:99,amor:258,amount:[18,42,56,60,156,157,162,165,194,228,289,293,308,309,310,311,312,398,457,474,545],amp:[40,44,62,65,201,202,412,413,416,424,426,434,442,454,457,545],amp_client:[201,202,412,545],amp_maxlen:442,amp_port:191,amp_serv:[201,202,412,424,545],ampclientfactori:413,ampersand:69,amphack:425,ampl:151,amplauncherprotocol:416,ampmulticonnectionprotocol:[413,425,426],ampprotocol:413,ampserverclientprotocol:413,ampserverfactori:426,ampserverprotocol:426,amsterdam:191,amus:143,anaconda:75,analog:[65,132],analys:28,analysi:377,analyz:[16,22,28,33,86,115,158,172,209,225,292,350,398,402,403,407,416,477,492,495,545],anchor:[213,232,312,388,390,466],anchor_obj:312,ancient:[60,99],andr:183,andrei:77,andrew:77,android:[197,545],anew:[150,151,170,185,232,416],angelica:157,angl:[72,118,275],angri:31,angular:228,ani:[2,3,6,8,9,11,12,13,15,16,18,19,20,22,27,28,30,31,32,33,34,35,36,37,39,41,42,44,45,46,47,48,49,51,54,55,56,57,60,62,64,65,67,68,72,73,74,76,77,78,82,83,85,86,88,89,90,92,94,95,97,102,104,106,112,114,115,116,117,118,119,120,123,125,126,129,130,131,132,133,134,135,139,140,141,142,143,144,145,146,148,149,150,151,152,153,155,157,158,159,160,161,162,164,165,169,171,172,174,175,177,178,180,181,182,183,184,185,186,189,191,192,193,194,195,198,204,207,209,210,211,212,213,215,216,218,224,225,228,229,232,233,234,241,251,256,270,273,275,278,280,283,286,289,292,296,299,302,308,309,310,311,312,316,325,329,337,338,340,346,349,350,354,359,362,364,370,372,376,377,380,382,388,391,393,394,396,398,401,402,403,406,407,409,410,411,413,414,416,418,420,421,425,426,428,434,435,436,439,440,444,445,447,455,456,457,461,464,465,466,467,469,470,471,473,474,475,476,477,478,479,485,486,487,488,489,491,492,500,510,517,518,523,536,537,538,540,541,542,543,545],anim:[19,29,52,293],anna:[58,135,165,171,172,185,189,218],anna_object:58,annoi:[55,90,141,142,143,152,158],annot:[180,545],announc:[9,126,164,165,180,216,223,228,232,308,309,310,311,312,398],announce_al:[434,457],announce_move_from:[37,126,398],announce_move_to:[37,126,398],annoy:204,annoyinguser123:18,anonym:[63,124,137,350],anonymous_add:350,anoth:[2,3,5,6,7,8,13,14,15,20,22,28,31,33,37,41,44,46,49,51,54,56,58,60,69,70,74,76,86,90,92,95,96,97,107,113,117,118,119,123,125,128,130,132,133,134,135,136,137,142,143,144,146,148,151,152,154,157,158,161,164,165,169,170,174,176,179,181,185,187,191,192,204,211,212,215,218,223,224,232,241,256,275,278,283,286,292,299,308,309,310,311,312,329,331,336,338,350,371,380,382,386,388,390,391,398,401,457,464,466,470,474,476,477,479,490,492,518,545],another_batch_fil:470,another_nod:476,another_script:42,anotherusernam:49,ansi:[32,51,71,84,121,139,151,183,201,202,215,244,245,302,346,421,428,436,439,444,445,468,478,479,491,492,545],ansi_escap:469,ansi_map:469,ansi_map_dict:469,ansi_pars:469,ansi_r:469,ansi_regex:469,ansi_sub:469,ansi_xterm256_bright_bg_map:469,ansi_xterm256_bright_bg_map_dict:469,ansimatch:469,ansimeta:469,ansipars:469,ansistr:[201,469,478],ansitextwrapp:478,answer:[0,8,13,22,28,96,97,125,126,137,151,156,158,159,161,162,185,187,194,414,476],ant:95,antechamb:115,anthoni:77,anti:185,anticip:118,anul:181,anvil:[292,293],anwer:131,any_options_her:120,anybodi:194,anymor:[107,124,161,257,305,329,382,476,488],anyon:[3,33,55,64,90,124,125,126,128,135,141,158,164,165,172,184,191],anyth:[0,3,7,9,11,13,14,18,20,22,28,33,36,37,42,48,50,51,53,56,57,62,65,73,76,77,82,90,96,97,99,113,118,119,123,128,132,133,137,140,141,142,143,144,148,149,151,152,153,156,158,159,161,164,165,169,170,172,174,177,182,185,191,193,195,198,211,213,227,241,308,309,310,311,312,337,350,354,386,394,428,462,464,470,476,479],anytim:158,anywai:[15,18,28,60,69,74,89,97,118,122,124,142,144,161,190,251,283,337],anywher:[22,28,42,48,118,123,149,151,154,161,178,337,474],apach:[77,182,191,194,197,461,545],apache2:181,apache_wsgi:181,apart:[12,13,19,33,48,104,115,122,139,175,178,185,193,195,312,331],api:[0,3,8,13,14,16,18,19,24,29,31,35,37,41,42,44,48,52,58,80,86,149,153,155,162,170,173,177,188,201,202,204,217,228,230,234,251,292,388,455,464,466,470,471,477,498,544,545],api_kei:188,api_secret:188,apicli:516,apirootrout:514,apirootview:514,apocalyps:158,apostroph:16,app:[33,53,62,64,67,73,77,124,169,178,188,191,523,545],app_id:177,app_modul:523,app_nam:523,app_ord:523,appar:[95,135,175],apparit:372,appeal:[28,60],appear:[0,7,11,18,19,28,31,33,41,42,50,51,53,54,59,60,63,75,76,83,99,109,118,120,125,126,129,140,143,146,151,155,156,165,170,175,185,186,189,191,193,195,201,215,225,245,257,286,293,322,329,338,350,398,440,441,466,478,485,508,545],appearance_templ:398,append:[5,6,19,20,27,33,37,62,68,76,78,83,104,126,130,132,137,141,142,146,164,165,177,187,191,213,218,225,286,299,350,394,396,449,470,485,492],appendto:51,appform:177,appl:[79,275,283,398],appli:[2,7,9,14,20,22,30,31,33,41,47,48,53,56,65,75,76,80,84,95,97,104,112,118,119,139,150,158,159,163,170,174,175,177,181,182,204,209,211,226,244,273,275,308,309,310,311,312,329,337,338,353,354,394,398,402,403,406,411,457,464,465,466,469,470,475,478,480,489,492],applic:[9,33,46,49,62,67,73,91,147,169,177,178,180,181,185,193,194,204,275,292,312,316,380,416,419,429,433,454,455,461,529],applicationdatareceiv:439,applied_d:177,apply_damag:[308,309,310,311,312],apply_turn_condit:310,appnam:[13,33],appreci:[8,11,42,76,119,179,483],approach:[7,28,47,76,82,104,126,130,133,142,158,177,241,312,338],appropri:[2,7,20,22,58,72,75,94,95,104,142,174,177,181,182,188,204,216,275,346,416,455,486,488,492,521],approrpri:62,approv:[11,95,177,178],approxim:[228,492],apr:64,april:[90,104,136],apt:[11,181,185,187,190,191,194],arbitrari:[6,13,14,19,30,33,48,51,57,74,95,96,112,113,118,123,149,170,193,204,232,273,277,289,312,316,354,362,372,386,398,403,409,414,425,445,459,464,473,485,488,492,545],arcan:72,arcanist:158,arch:61,archer:403,archetyp:158,architectur:[33,159,403],archiv:[148,180,194],archwizard:403,area:[12,76,104,115,117,118,132,135,155,156,159,171,180,183,329,331,337,340,370,393,475,476,478,492,545],aren:[11,92,97,124,128,130,137,169,177,194,204,257,286,305,310,380,485,488,495],arg1:[33,213,226,229,232,273,464],arg2:[213,226,229,273,464],arg:[3,22,28,30,31,32,33,35,41,47,51,54,62,65,68,71,72,76,95,112,120,125,126,128,129,130,135,139,141,143,148,150,161,162,164,165,174,176,188,204,205,206,207,210,213,218,226,227,228,229,232,233,234,247,254,257,270,273,275,276,283,286,289,296,305,308,309,310,311,312,316,322,325,329,333,338,339,340,349,350,354,359,362,364,366,370,371,372,382,386,389,390,391,393,394,396,397,398,401,402,403,405,406,409,410,411,413,416,421,422,423,425,426,427,428,433,434,436,437,439,440,441,444,445,449,455,457,459,461,464,465,466,467,469,476,478,479,480,482,483,485,488,490,492,493,500,501,505,508,514,515,532,538,543,545],arg_regex:[131,213,218,224,225,228,229,230,273,286,292,350,474,476,545],arglist:226,argn:464,argpars:[116,270],argtyp:492,argu:13,arguabl:[118,151,157],argument:[0,3,5,8,13,15,18,19,20,22,27,29,30,32,33,36,37,41,42,47,48,54,55,58,62,65,68,72,76,78,82,90,92,95,96,99,104,107,116,124,125,126,128,134,135,136,137,139,141,143,144,145,146,152,161,165,167,170,178,182,204,205,206,209,210,212,213,215,216,218,223,224,225,226,228,229,232,233,241,247,250,254,256,257,266,270,273,275,277,278,280,286,292,296,308,309,310,311,312,316,322,331,339,340,346,349,350,362,372,377,380,382,394,396,398,402,403,405,407,409,410,411,414,416,421,425,427,428,434,435,436,439,440,444,445,447,448,455,456,457,459,460,464,465,466,467,469,470,472,474,475,476,477,478,479,483,486,488,489,492,518,541,545],argumentpars:[104,116,270],argumnet:478,aribtrarili:492,ariel:77,aris:194,arithmet:[13,30,112,354],arm:[0,22,105,305,545],armchair:161,armi:141,armor:[13,83,114,128,140,157,163,286,309],armour:128,armpuzzl:[105,305],armscii:[16,70],arn:77,arnold:36,around:[3,14,15,16,20,30,33,37,41,52,53,54,60,70,72,83,90,95,97,118,120,122,123,124,125,128,130,132,135,137,141,142,143,146,148,149,150,151,152,153,156,157,158,161,162,164,165,169,170,171,174,180,182,185,188,191,218,226,247,256,286,293,305,312,329,335,338,350,364,370,371,372,398,469,470,478,485,545],arrai:[49,68,142,338,440,492],arrang:76,arrayclos:[68,440],arrayopen:[68,440],arrest:118,arriv:[44,65,95,97,126,128,162,218,276,331,428],arrow:[3,51,118,151],art:[60,475],articl:[8,11,16,70,124,125,130,134,180,484],article_set:484,artifact:478,artifici:[158,162],artsi:159,arx:[180,197,545],arxcod:[180,197,545],as_view:[53,213,232,388,390,466],ascii:[16,70,75,99,104,118,170,204,230,337,475,478,492,545],asciiusernamevalid:204,asdf:218,ash:293,ashlei:[83,92,94,104,113,114,285,286,307,308,309,310,311,312,345,346,379,380,384,386],asian:492,asid:75,ask:[0,3,5,6,11,27,31,34,54,58,89,95,96,100,104,118,119,125,135,137,142,144,149,150,156,158,159,161,162,177,182,184,185,191,211,213,218,247,255,270,283,382,414,416,443,476,480,492,545],ask_again:28,ask_choic:414,ask_continu:414,ask_input:414,ask_nod:414,ask_yes_no:476,ask_yesno:414,askew:157,asn:376,aspect:[28,41,53,67,123,134,148,151,162,292,346],assert:[8,164,479],assertequ:8,assertionerror:[479,490],asset:[77,169,194,420,521,545],assetown:75,assign:[2,6,12,13,14,18,28,33,36,37,39,41,42,46,47,51,55,84,92,104,106,115,118,133,135,144,148,149,150,151,153,161,164,165,174,204,209,210,212,218,223,225,226,244,273,308,309,310,311,312,316,350,354,372,380,394,397,398,402,403,421,428,434,436,439,455,473,490,545],assist:191,associ:[13,28,44,65,73,124,128,143,149,153,180,191,204,208,218,232,254,257,350,398,455,457,465,538],assort:545,assum:[6,7,8,9,11,13,14,15,16,18,19,20,22,28,31,32,33,34,37,41,42,44,47,55,57,58,62,69,70,75,76,85,86,90,95,96,97,106,110,112,118,119,120,122,125,126,127,128,130,131,132,133,135,136,139,140,141,144,146,148,153,159,162,164,165,167,170,171,172,173,174,176,177,178,187,190,191,193,194,199,209,211,212,213,215,218,223,225,229,232,234,241,273,275,289,293,325,339,340,350,354,371,372,388,393,398,403,407,440,457,469,470,476,479,492,496,513,524,540,543],assumpt:[161,210],assur:[48,78,104,132],ast:[30,479],asterisk:[12,55,120,150,216],astronom:136,async:[177,492,545],asynccommand:54,asynchron:[5,19,22,40,61,85,104,123,127,128,205,289,398,425,426,440,485,492,545],at_:[48,483],at_access:[204,398],at_account_cr:[12,204],at_after_mov:398,at_after_travers:398,at_again_posit:275,at_already_clos:275,at_already_consum:275,at_already_mov:275,at_already_open:275,at_appli:275,at_before_drop:398,at_before_g:398,at_before_get:398,at_before_mov:398,at_before_sai:398,at_cannot_appli:275,at_cannot_mov:275,at_cannot_posit:275,at_cannot_read:275,at_cannot_rot:275,at_channel_cr:232,at_channel_msg:232,at_char_ent:171,at_clos:275,at_cmdset_cr:[20,22,76,82,83,91,95,102,103,106,109,110,125,126,129,131,134,135,136,139,141,143,150,161,164,165,174,211,219,220,221,222,241,266,273,283,286,292,299,302,305,308,309,310,311,312,316,322,325,331,343,350,364,366,369,370,371,372,447,474,476,477,545],at_cmdset_createion:266,at_cmdset_get:[204,398,455],at_code_correct:275,at_code_incorrect:275,at_consum:275,at_db_location_postsav:397,at_defeat:[308,309,310,311,312],at_desc:398,at_disconnect:[204,455],at_drink:275,at_drop:[309,312,398],at_empty_target:338,at_end:406,at_err:[54,492],at_err_funct:54,at_err_kwarg:[54,492],at_failed_login:204,at_failed_travers:[37,322,371,398],at_first_login:204,at_first_sav:[204,232,398],at_first_start:466,at_focu:275,at_focus_:[273,275],at_focus_climb:275,at_focus_clos:275,at_focus_cod:275,at_focus_combin:275,at_focus_drink:275,at_focus_eat:275,at_focus_feel:275,at_focus_insert:275,at_focus_kneel:275,at_focus_li:275,at_focus_listen:275,at_focus_mov:275,at_focus_open:275,at_focus_press:275,at_focus_push:275,at_focus_read:275,at_focus_rot:275,at_focus_shov:275,at_focus_sip:275,at_focus_sit:275,at_focus_smel:275,at_focus_turn:275,at_focus_us:275,at_get:[95,286,312,398],at_giv:[309,312,398],at_green_button:275,at_heard_sai:172,at_hit:370,at_idmapper_flush:[466,483],at_init:[45,48,204,232,370,371,372,398],at_initial_setup:[148,195,420],at_initial_setup_hook_modul:420,at_left:275,at_lock:275,at_login:[48,62,427,428,436,439,444,445,455],at_look:[204,398],at_message_rec:204,at_message_send:204,at_mix:275,at_mix_failur:275,at_mix_success:275,at_msg_rec:[204,296,398],at_msg_send:[204,205,296,362,398],at_new_arriv:370,at_no_cod:275,at_nomatch:275,at_now_add:67,at_object_cr:[13,20,33,37,48,88,112,125,126,130,132,135,139,141,161,162,165,174,176,218,275,276,296,308,309,310,311,312,316,322,343,350,354,364,366,370,371,372,398,466],at_object_delet:398,at_object_leav:[276,329,372,398],at_object_post_copi:398,at_object_rec:[37,171,276,329,372,398],at_open:275,at_password_chang:204,at_paus:[42,409],at_posit:275,at_post_all_msg:232,at_post_channel_msg:[18,204,232],at_post_cmd:[22,129,209,213,226,490],at_post_command:22,at_post_disconnect:204,at_post_func:161,at_post_login:[126,204],at_post_mov:[37,171,398],at_post_msg:232,at_post_object_leav:329,at_post_portal_sync:454,at_post_puppet:398,at_post_travers:[37,371,398],at_post_unpuppet:398,at_pr:398,at_pre_channel_msg:[18,204,232],at_pre_cmd:[22,209,213,226,490],at_pre_command:[22,161],at_pre_drop:[309,312,398],at_pre_g:[309,312,398],at_pre_get:[312,398],at_pre_leav:37,at_pre_login:204,at_pre_mov:[37,126,161,308,309,310,311,312,398],at_pre_msg:[18,232],at_pre_puppet:398,at_pre_sai:[350,398],at_pre_unpuppet:398,at_prepare_room:[117,329],at_read:275,at_red_button:275,at_reload:[228,454],at_renam:466,at_repeat:[42,48,164,173,174,205,247,257,277,283,308,309,310,311,312,359,409,449,480],at_return:[54,492],at_return_funct:54,at_return_kwarg:[54,492],at_right:275,at_rot:275,at_sai:[172,275,398],at_script_cr:[42,164,173,174,205,247,257,277,283,308,309,310,311,312,329,339,349,359,382,402,409,449,480],at_script_delet:409,at_search:[148,195],at_search_result:[227,492],at_server_cold_start:454,at_server_cold_stop:454,at_server_connect:434,at_server_reload:[42,199,204,205,398,409],at_server_reload_start:454,at_server_reload_stop:[126,454],at_server_shutdown:[42,199,204,205,398,409],at_server_start:[42,257,409,454],at_server_startstop:[126,148,195],at_server_stop:454,at_shutdown:454,at_smel:275,at_speech:275,at_start:[42,164,205,329,406,409],at_startstop_modul:411,at_stop:[42,164,174,308,309,310,311,312,409],at_sunris:136,at_sync:[455,456],at_tick:[47,411],at_travers:[37,325,329,398],at_traverse_coordin:329,at_turn_start:310,at_unfocu:275,at_upd:[310,407],at_weather_upd:176,ating:229,atlanti:183,atleast:[106,349],atom:[154,192],atop:[117,329],atribut:473,att:[28,64],attach:[13,37,44,46,64,74,85,104,113,123,124,125,133,135,143,150,151,153,199,213,218,226,239,289,296,299,329,386,394,398,408,453,467,501,508,545],attachmentsconfig:124,attack:[15,28,85,96,113,114,127,128,129,138,150,155,156,157,162,164,178,191,194,212,289,308,309,310,311,312,350,370,371,386,398,403,434,545],attack_count:311,attack_nam:311,attack_skil:403,attack_typ:312,attack_valu:[308,309,310,311,312],attempt:[7,12,20,28,36,73,76,97,118,128,142,173,183,194,215,218,273,308,309,310,311,312,316,322,377,413,416,421,454,459,466,479,492,538],attemt:30,attent:[37,120,133,135,170,194,273],attitud:134,attr1:[218,305],attr2:[218,305],attr3:218,attr:[13,28,33,41,51,76,82,132,135,146,218,225,234,241,276,372,393,402,403,455,464,466,483,488],attr_categori:501,attr_eq:393,attr_g:[33,393],attr_gt:[33,393],attr_kei:501,attr_l:[33,393],attr_lockstr:501,attr_lt:[33,393],attr_n:[33,393],attr_nam:218,attr_obj:[464,466],attr_object:466,attr_typ:501,attr_valu:501,attrcreat:[33,464],attread:13,attredit:[13,33,464],attrhandler_nam:464,attrib:394,attribiut:464,attribut:[3,12,18,19,24,27,28,32,33,34,35,36,37,41,42,44,46,47,48,55,67,69,76,82,85,96,97,102,104,106,112,114,126,127,129,130,132,133,134,135,137,139,140,141,142,144,146,151,157,161,162,164,165,177,178,201,202,204,206,207,212,218,227,228,232,241,256,257,275,289,292,293,302,305,308,309,310,311,312,316,325,338,350,354,364,370,371,372,393,396,397,398,401,402,403,405,406,407,410,421,455,463,465,466,467,472,473,474,480,485,486,489,492,498,499,500,502,505,506,508,515,517,518,532,537,538,540,543,545],attribute1:165,attribute2:165,attribute_list:464,attribute_nam:[161,204,350,396,398,489],attribute_valu:396,attributeerror:[3,13,67,149,161,455,464],attributeform:501,attributeformset:501,attributehandl:[13,48,464,487,492,515],attributeinlin:[500,501,502,505,506],attributemanag:13,attributeproperti:[464,545],attributeseri:515,attrkei:403,attrlist:464,attrnam:[13,28,33,41,48,112,218,354,393,396,466],attrread:[13,33,464],attrtyp:[13,464,465],attrvalu:28,attryp:465,atttribut:132,atyp:394,audibl:[106,349],audio:51,audit:[201,202,232,235,374,398,545],audit_allow_spars:78,audit_callback:[78,376],audit_in:78,audit_mask:78,audit_out:78,auditedserversess:[78,376,377],auditingtest:378,aug:[64,75],august:[75,492],aura:293,aut:29,auth:[49,78,204,206,207,223,436,500,523,524,532,538,543],auth_password:436,auth_profile_modul:207,authent:[44,45,53,62,78,177,194,204,427,434,436,439,445,455,457,524,537,538,540,543],authenticated_respons:533,author:[77,95,175,191,204,254,257,495],auto:[3,4,11,13,15,18,20,21,22,26,28,35,37,41,42,44,52,55,97,104,112,118,120,125,147,155,158,177,185,187,188,201,204,207,213,217,218,225,228,229,331,337,338,349,350,354,364,387,390,394,398,403,406,411,413,416,427,437,444,445,454,457,464,466,471,476,477,478,479,518,524,545],auto_close_msg:364,auto_help:[22,28,31,131,137,213,225,229,274,369,380,400,476,477],auto_help_display_kei:[213,229,476],auto_id:[502,504,506,508,532],auto_look:[28,274,369,380,400,476],auto_now_add:67,auto_quit:[28,274,369,380,400,476],auto_step_delai:331,auto_transl:[106,349],autobahn:[427,433,444],autocr:[13,464],autodoc:[49,120],autofield:177,autologin:524,autom:[2,15,30,49,50,67,134,135,180,185,187,193,194,199,538],automat:[6,9,15,18,19,20,27,28,30,31,33,34,41,42,44,48,50,53,54,57,63,67,73,74,76,79,83,95,96,97,99,104,105,111,115,118,119,122,123,129,135,136,139,141,143,146,148,149,150,151,152,153,157,161,164,165,169,170,171,172,174,175,182,186,187,188,189,191,193,195,204,211,212,213,218,223,224,226,228,241,256,257,258,270,275,283,286,292,294,305,312,331,339,349,350,366,382,394,397,398,408,410,411,421,430,433,436,441,454,457,459,470,474,476,477,478,479,490,492,517,518,525,545],automatical:411,autostart:[42,405,408,472],autumn:[6,91,316],avail:[0,2,3,5,7,8,9,11,13,14,18,20,22,24,28,30,31,32,33,35,37,41,42,44,48,49,51,53,54,56,58,60,62,64,68,69,70,71,76,77,79,82,86,90,91,93,95,96,97,98,102,106,107,112,118,120,121,123,125,126,130,131,132,134,135,136,139,140,141,142,143,144,145,148,149,150,151,152,153,155,156,158,159,161,164,165,170,174,177,178,179,180,181,182,185,186,189,190,191,192,193,195,198,199,201,204,209,210,211,212,213,215,218,220,223,224,225,226,228,229,230,241,250,257,273,275,280,283,292,293,296,299,302,308,309,310,311,312,316,333,349,350,354,364,366,371,372,382,386,394,398,401,402,403,406,421,445,447,448,459,470,471,476,477,478,479,490,492,510,525,537,540,545],available_chan:223,available_choic:[28,476],available_funct:402,available_languag:349,available_weapon:371,avatar:[68,123,148,149,151,398,436,518],avatarid:436,avenu:[83,286],averag:[5,14,104,106,116,118,191,228,257,270,349],average_long_link_weight:[118,338],avoid:[0,3,6,8,11,13,19,20,22,28,39,41,48,53,60,62,72,90,117,118,119,139,141,149,151,152,156,158,161,170,175,181,182,193,211,218,270,329,338,349,364,382,393,397,425,435,445,455,464,466,467,469,470,471,474,477,479,483,515],awai:[0,3,11,13,15,16,28,31,33,41,42,44,54,63,67,75,86,95,96,97,104,113,117,118,122,125,128,132,137,149,152,155,157,161,162,165,170,174,191,224,234,278,286,309,312,329,337,340,364,370,372,386,398,406,456,469,492,500,545],await:54,awak:158,awar:[0,11,13,15,20,22,28,48,68,93,104,118,131,154,157,175,176,177,199,270,275,296,329,331,338,340,350,370,382,398,466,469],award:158,awesom:[53,73,151,185],awesome_func:152,awesomegam:187,awhil:95,awkward:64,aws:[77,191],aws_access_key_id:77,aws_auto_create_bucket:77,aws_bucket_nam:77,aws_default_acl:77,aws_s3_cdn:[201,202,235,236,237,545],aws_s3_custom_domain:77,aws_s3_object_paramet:77,aws_s3_region_nam:77,aws_secret_access_kei:77,aws_storage_bucket_nam:77,awsstorag:[201,202,235,236,545],axe:158,axel:77,axes:[118,337],axi:[99,337],axio:49,azur:[77,191,193],b64decod:488,b64encod:488,b_offer:283,baaad:8,back:[0,2,6,7,11,13,14,15,18,19,20,22,27,28,30,32,36,42,44,48,49,51,52,53,54,55,64,65,67,70,73,76,82,95,96,97,101,104,112,113,115,117,118,120,123,125,128,132,133,135,137,139,141,142,144,146,148,149,150,151,152,153,154,155,156,157,158,159,160,162,164,165,167,170,172,174,175,177,182,185,187,191,193,199,200,201,204,212,215,218,223,227,241,275,278,283,289,292,311,322,331,350,354,362,364,386,400,416,421,425,428,434,436,439,454,466,473,476,477,485,492,496],back_exit:[95,97],backbon:[177,470],backend:[2,8,41,42,49,50,53,73,77,182,201,202,464,492,498,512,518,522,545],backend_class:464,background:[0,17,28,53,54,60,84,128,151,175,177,187,191,194,199,244,346,469,479,541],backpack:20,backtick:[120,479],backtrack:11,backup:[11,37,44,54,148,191,227,470],backward:[18,27,28,135,174,206,485],bad:[8,42,64,76,97,118,119,123,135,141,151,153,158,159,183,377,418],bad_back:394,baddi:155,badg:10,badli:354,bag:[31,143,292,492],bake:[86,104,337],baker:158,balanc:[128,133,156,158,164,180,478],ball:[20,195,210,211,293,403],ballon:305,balloon:305,ban:[18,33,61,103,126,143,158,204,216,223,229,232,266,394,545],ban_us:223,band:[51,68,436,439,440],bandit:96,bandwidth:[77,429],banid:216,bank:[156,545],banlist:[18,232],bar:[11,13,18,28,30,34,42,46,51,65,68,73,104,106,113,118,140,143,148,153,157,218,345,346,347,350,386,391,416,440,464,476,479,492,545],bardisk:99,bare:[22,94,122,135,150,157,162,195,309,346],barehandattack:133,bargain:67,bark:293,barkeep:[3,99,350],barrel:[99,155],barriento:77,barstool:161,barter:[42,156,171,185,201,202,235,281,545],bartl:180,base:[2,3,8,11,14,17,18,22,28,30,31,33,35,37,42,44,47,48,51,52,53,56,65,67,69,70,72,75,76,77,85,86,87,90,93,95,104,109,112,120,121,122,123,124,125,129,130,132,133,134,135,137,138,141,144,146,148,149,152,153,154,155,156,157,159,162,163,165,167,169,170,173,175,177,178,180,182,185,187,189,190,191,193,194,197,201,204,205,206,207,209,211,212,213,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,232,233,234,239,241,242,245,247,248,251,252,254,255,257,258,260,266,267,269,270,273,274,275,276,277,278,279,283,284,286,287,289,290,292,293,294,296,297,299,300,302,303,305,306,308,309,310,311,312,313,316,317,322,323,325,326,328,329,331,332,335,336,337,338,339,340,343,344,347,349,350,351,353,354,359,360,362,364,366,367,369,370,371,372,373,377,378,380,382,383,385,386,388,389,390,394,396,397,398,400,402,403,405,406,407,408,409,410,411,413,414,416,418,419,422,423,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,447,448,449,452,454,455,456,457,459,460,461,464,465,466,467,469,470,471,474,475,476,477,478,479,480,482,483,484,485,486,487,488,489,490,491,492,497,500,501,502,503,504,505,506,507,508,510,512,513,514,515,516,517,518,523,524,526,527,532,533,536,537,538,540,541,542,543,544,545],base_account_typeclass:12,base_channel_typeclass:18,base_char_typeclass:173,base_character_typeclass:[139,173,177,178,204,218],base_exit_typeclass:118,base_field:[500,501,502,504,505,506,508,532],base_filt:512,base_guest_typeclass:63,base_object_typeclass:[41,145,149,403,466],base_room_typeclass:118,base_script_path:393,base_script_typeclass:42,base_set:75,base_system:[77,82,84,87,89,95,100,103,116,201,202,235,545],base_systesm:95,base_word:492,baseapplic:275,baseclass:371,basecommand:143,baseconsum:275,basecontain:471,baseevenniacommandtest:[8,229,242,252,258,267,269,279,284,287,294,297,300,303,306,313,317,323,326,344,351,367,373,490],baseevenniatest:[8,245,248,258,279,287,290,313,328,335,347,351,360,373,378,383,385,442,490,516,533],baseevenniatestcas:[8,294,353,490],baseinlineformset:[501,508],baseline_index:492,basenam:518,baseobject:48,baseopt:486,basepath:492,basepermiss:513,baseposition:275,basest:278,basetyp:[398,470],basetype_posthook_setup:398,basetype_setup:[33,130,204,205,232,398],basetypeclassfilterset:512,bash:[2,120,185,371],basi:[22,95,118,119,124,136,148,169,191,226,234,338,350,445,466,475],basic:[0,2,9,12,16,17,20,22,33,36,51,53,56,57,58,62,65,67,70,73,75,76,90,92,96,97,99,114,118,128,130,133,134,135,136,137,138,139,143,144,148,149,150,151,152,154,155,156,157,158,161,162,164,167,170,171,172,174,175,177,178,180,199,204,205,218,223,225,232,234,256,292,305,309,311,371,380,393,395,398,447,532,541,545],basicmapnod:[118,338],bat:[75,185],batch:[24,26,104,148,170,180,185,201,202,217,229,356,403,425,464,467,468,545],batch_add:[403,464,467],batch_cmd:[15,148],batch_cod:[14,470],batch_code_insert:14,batch_create_object:403,batch_exampl:470,batch_import_path:[14,15],batch_insert_fil:15,batch_update_objects_with_prototyp:403,batchcmd:[26,156,158,217],batchcmdfil:[15,470],batchcod:[15,26,80,143,158,166,170,180,217,545],batchcode_map:170,batchcode_world:170,batchcodefil:14,batchcodeprocessor:470,batchcommand:[15,26,76,80,115,143,155,166,185,217,470],batchcommandprocessor:470,batchfil:[15,16,170,470],batchprocess:[201,202,208,214,545],batchprocessor:[14,80,201,202,217,235,355,468,545],batchscript:[14,470],batteri:204,battl:[155,164,180,194,308,309,310,311,312,545],battlecmdset:[308,309,310,311,312],bayonet:86,baz:[113,386],bazaar:69,beach:170,bear:[370,382],beat:[156,158,164],beaten:[164,372],beauti:[76,95,132,177],beazlei:180,becam:[128,175],becasu:4,becaus:[2,3,12,13,14,16,20,28,30,31,33,37,41,45,47,48,49,50,53,54,55,56,58,62,64,69,75,76,90,96,97,117,118,120,123,125,126,128,131,133,142,143,146,149,150,151,152,157,159,161,162,164,169,170,171,175,177,178,181,184,187,212,225,230,232,251,256,278,311,329,335,337,349,398,409,428,434,447,457,469,479,486,488,492,500,501,508,518,523],becom:[3,9,28,33,36,41,54,67,68,71,76,93,97,105,106,112,113,120,123,132,133,139,143,147,148,149,150,151,156,158,161,162,170,179,195,215,289,293,296,305,309,349,350,354,386,398,403,455,470,476,479,490],been:[2,3,5,9,13,14,15,28,30,31,42,44,57,64,73,76,78,82,95,96,97,99,104,105,106,112,118,120,124,125,132,135,137,141,142,146,151,153,164,165,171,175,177,178,180,182,194,200,204,211,212,213,217,218,223,226,232,234,241,257,292,305,308,309,310,311,312,329,338,350,354,372,382,388,390,394,397,398,402,403,410,411,418,430,434,436,444,454,455,456,457,459,464,466,470,474,475,492,495,497,508,523,539,544],befit:48,befor:[1,3,5,6,7,8,10,11,13,14,15,16,18,19,20,22,28,31,33,34,39,41,42,45,46,47,48,50,51,53,54,55,64,66,67,69,70,73,76,77,78,86,89,93,95,96,99,104,108,113,117,118,119,124,125,126,127,128,132,133,134,135,137,139,141,142,143,144,146,149,150,151,152,154,156,158,161,164,165,170,171,172,174,175,176,177,178,180,182,187,188,190,191,193,194,195,204,209,210,213,218,223,225,226,230,232,234,239,247,250,251,256,260,278,289,292,294,296,308,309,310,311,312,316,329,337,338,346,349,350,353,354,364,369,371,372,376,377,380,386,393,394,397,398,401,402,403,405,409,410,411,416,425,434,436,442,448,450,452,454,455,459,461,464,469,470,471,472,476,477,478,480,484,485,488,492,523,537,543,545],beforehand:[13,471],beg:15,beggar:97,begin:[0,3,5,7,8,14,15,22,27,31,33,45,54,76,95,96,97,106,120,122,124,126,135,137,142,144,146,151,156,160,164,170,171,176,178,189,224,225,256,308,309,310,311,312,337,349,350,386,396,398,469,470,476,479,489,545],beginn:[122,138,142,149,154,156,180],behav:[13,14,45,76,95,104,128,136,137,142,144,150,151,152,199,492],behavior:[5,20,22,27,31,41,51,60,73,83,92,95,97,106,118,137,148,175,204,213,229,270,286,292,310,312,338,350,372,380,416,464,476,501,508,545],behaviour:[20,22,33,99,175,405,462,472,478,492],behind:[6,11,13,22,32,41,46,55,60,95,107,118,122,125,132,152,155,175,185,217,354,372,382,406,411,483],behvaior:477,being:[2,3,5,11,13,14,20,22,28,30,31,35,39,41,42,45,47,48,52,54,58,65,68,72,76,77,80,86,88,93,95,97,101,104,106,112,114,118,123,125,126,127,133,137,142,145,147,148,149,151,155,157,158,159,170,172,175,177,184,185,187,191,194,204,210,218,224,228,229,232,247,296,299,308,309,310,311,312,338,343,349,350,354,362,364,372,390,398,405,418,421,428,448,457,459,464,466,469,470,472,476,477,478,479,492,495,497,501,508,512,515,523,544],beipmu:183,belong:[15,46,65,74,118,123,124,146,151,177,194,212,329,350,386,390,401],belov:158,below:[2,3,5,7,8,11,14,15,16,18,19,20,22,27,28,31,32,33,36,39,41,42,44,48,54,55,57,60,64,68,74,75,76,77,78,79,82,84,86,87,88,94,95,97,99,103,106,112,113,115,118,120,123,126,128,130,132,134,135,136,137,139,150,151,152,156,161,162,165,169,170,171,172,177,178,181,182,185,187,191,193,199,207,218,226,234,241,270,280,286,292,293,308,309,310,311,312,337,338,343,346,349,350,354,360,386,390,397,398,406,428,448,464,466,467,476,478,479,484,517],beneath:19,benefici:[132,310],benefit:[64,69,157,159,179,187,191,193,194,212,464,470,476],berserk:[112,354],besid:[7,15,20,39,64,94,97,104,150,170,346],best:[0,27,42,53,64,69,73,75,76,82,95,104,113,116,119,134,135,145,148,156,159,177,183,187,189,194,195,225,241,270,349,386,403,416,436,478,486,544,545],bet:[20,44,50,466],beta:[25,184,191,545],betray:28,better:[3,5,16,28,30,31,41,42,46,58,60,67,69,75,86,97,110,114,118,119,120,122,123,126,131,135,139,141,142,148,149,156,159,161,162,177,178,182,293,309,325,338,372,398,403,433,436,439,447,464,470,523],bettween:162,between:[2,5,11,12,13,15,18,20,22,30,31,36,41,42,44,46,51,54,58,60,62,64,68,70,74,76,78,79,84,90,95,96,97,98,99,102,104,107,112,113,114,118,120,123,126,127,130,132,133,134,135,137,141,142,143,148,149,151,152,155,157,158,162,164,165,173,174,175,187,191,193,210,213,218,223,225,228,229,233,234,244,256,257,260,283,286,292,293,299,302,308,309,310,311,312,335,337,338,339,340,349,350,353,354,382,386,398,403,411,416,425,428,435,436,439,440,447,448,455,467,469,470,472,476,478,479,480,492,496,526,545],bew:[91,316],bewar:130,beyond:[12,22,29,37,50,68,75,76,95,119,123,126,134,158,178,191,213,218,229,234,241,273,293,350,364,372,386,398,402,447,464,466,476,478],bg_colormap:491,bgcolor:491,bgfgstart:491,bgfgstop:491,bgstart:491,bgstop:491,bias:218,bidirect:425,big:[14,15,18,22,33,50,53,74,75,86,115,119,127,128,134,143,144,152,155,158,159,162,210,225,227,353,354,364,396,470,477,489,492],bigger:[62,106,112,125,137,146,165,335,337,349,354],biggest:[189,354,492],biggui:22,bigmech:125,bigsw:128,bikesh:146,bill:[191,194],bin:[2,75,123,124,147,185,190,193],binari:[5,118,182,185,427,429,444],bind:187,birth:532,bit:[0,3,7,11,13,17,25,41,42,51,53,55,58,64,75,76,95,96,97,115,124,128,130,136,137,139,143,146,147,148,151,152,154,156,158,159,161,174,178,185,190,223,230,251,293,394,398,470],bitbucket:134,bite:[156,170],bitten:146,black:[60,152,162,175,469],blackbird:180,blackbox:292,blackhaven:118,blacklist:[18,194,223],blacksmith:[39,467],blade:[158,293,371],blank:[28,67,78,92,171,178,204,380,469],blankmsg:[92,380],blargh:41,blast:[292,293],blatant:55,blaufeuer:146,bleed:[11,60,148,354,478],blend:[105,305],blender:[104,105,305],blind:[60,108,172,364],blind_target:364,blindcmdset:364,blindli:394,blink:[144,364,491],blink_msg:364,blist:6,blob:[96,120,155],block:[5,6,23,24,27,28,30,33,42,53,55,60,72,90,91,109,122,123,126,127,135,137,142,143,151,154,165,167,177,178,191,194,199,216,217,218,274,275,280,312,316,329,335,338,369,370,371,391,400,435,470,476,479,492,541,544,545],blockedmaplink:[118,338],blocker:118,blocking_cmdset:126,blockingcmdset:126,blockingroom:126,blocknam:53,blockquot:545,blocktitl:137,blog:[119,122,154,180,191,192],blond:157,blowtorch:183,blue:[14,60,134,139,150,151,158,175,371,469],blueprint:[51,134,170],blurb:[90,184,545],board:[33,35,132,156,174,180,545],boat:[20,174,212],bob:[13,22,49,139,216,280],bodi:[0,17,19,22,28,41,53,72,76,96,135,151,157,167,177,255,299,389,391,418,472],bodyfunct:[42,81,144,201,202,235,355,545],bodymag:293,bog:[125,156],boi:46,boiler:[28,48,53],bold:[184,545],bolt:403,bone:[28,122,157,162],bonu:[115,158,162,191,309,310,406],bonus:[128,158,309],book:[41,53,73,132,136,142,153,158,162,167,180,275],bool:[12,20,22,28,32,34,42,92,118,204,205,206,207,209,210,211,212,213,223,225,232,233,234,241,247,254,257,275,278,280,283,286,289,292,308,309,310,311,312,329,337,338,339,340,343,346,349,350,354,380,382,386,388,389,390,394,396,397,398,402,403,405,406,407,408,409,410,411,416,421,422,427,428,433,434,435,439,444,445,453,455,457,459,464,465,466,467,469,470,472,474,476,477,478,479,480,483,485,487,489,491,492,495,500,502,505,506,513,540],booleanfield:[177,500,506],booleanfilt:512,boom:[125,149],boost:391,boot:[18,33,103,143,149,193,199,216,223,232,266,411,545],boot_us:223,bootstrap:[24,53,61,124,545],border:[135,140,170,215,275,278,280,380,475,478,490,545],border_bottom:478,border_bottom_char:478,border_char:478,border_left:478,border_left_char:478,border_right:478,border_right_char:478,border_top:478,border_top_char:478,border_width:478,borderless:135,borderstyl:380,bore:[55,122,156,157,194],borrow:[20,185,211,425],bort:[28,29,476],boss:135,bot:[5,147,177,186,189,194,201,202,203,207,223,421,427,428,435,457,538,545],bot_data_in:[205,421],both:[0,2,6,7,8,9,13,16,18,19,20,22,28,30,31,32,34,36,39,44,48,49,53,57,58,62,67,68,76,79,80,84,95,97,98,99,100,104,109,112,113,118,119,120,126,131,132,133,134,135,136,137,141,142,146,148,150,151,152,157,158,159,161,164,169,170,174,177,178,180,182,186,187,188,191,194,195,199,209,211,218,223,228,233,234,244,275,280,283,292,299,305,311,312,322,331,337,338,340,346,354,372,386,394,396,398,402,403,404,406,409,411,425,434,444,445,447,454,456,459,464,465,469,472,476,478,479,487,492,515,518],bother:[9,128,194,464],botnam:[189,223,428,457],botnet:194,boto3:77,boto:77,botstart:205,bottl:99,bottom:[5,7,29,48,50,51,53,77,117,118,124,130,134,135,137,141,143,151,161,170,177,184,187,212,299,311,329,337,403,470,477,478],bottommost:118,bought:141,bouncer:[19,194,475],bound:[19,69,112,120,134,148,149,254,337,354,388,492],boundari:[112,118,353,354,492],bow:[158,403],bowl:[86,292],box:[3,7,30,33,35,36,41,49,63,73,86,96,97,122,135,137,144,146,149,150,151,152,154,157,162,165,167,170,181,185,188,191,195,218,273,331,337,350,393,425,470,532,544],brace:[76,95,97,126,142,398,469],bracket:[72,84,120,228,244,479],branch:[2,11,75,104,107,113,118,119,120,143,185,193,278,382,386,544,545],branchnam:11,brandymail:[98,104,299],braymer:77,bread:[56,86,104,292],breadrecip:292,breadth:312,break_lamp:364,break_long_word:478,break_on_hyphen:478,breakag:158,breakdown:228,breakpoint:[7,56,201],breath:[149,152],breez:[42,176],breviti:[135,151],bribe:28,brick:140,bridg:[44,65,76,115,121,155,180,182,372],bridgecmdset:372,bridgeroom:372,brief:[11,50,56,57,67,92,96,125,126,135,141,144,147,154,167,199,270,380,398,460,545],briefer:[37,199],briefli:[56,149,158,191,199,364,545],bright:[60,84,108,118,139,151,175,244,364,469],brightbg_sub:469,brighten:60,brighter:60,bring:[113,118,132,157,159,165,168,169,174,177,182,193,194,312,338,370,386,458],broad:130,broadcast:[78,204,232,425],broader:[130,350,398],brodowski:77,broken:[31,60,69,120,156,349,364,545],brown:469,brows:[7,51,75,104,122,126,130,135,136,137,141,142,147,165,167,169,191,194,538],browser:[0,49,51,52,53,56,59,73,75,120,123,137,147,148,154,167,169,177,178,181,185,187,190,191,194,198,277,444,445,540,541],brunt:158,brutal:270,bsd:[77,179,496],bsubtopicnna:229,btest:60,btn:17,bucket:[77,239,376],buf:[157,474],buff:157,buffer:[22,27,51,76,227,239,418,445,474,540],bug:[0,3,8,11,14,54,77,90,115,119,134,151,156,158,159,165,179,184,199,398,466,545],bugfix:77,buggi:[13,476],bui:[79,141,158,283],build:[2,5,7,10,13,14,15,16,18,19,20,22,23,24,26,28,31,35,36,37,41,44,46,48,51,53,54,58,67,69,70,72,74,75,80,86,92,99,104,106,115,118,122,123,134,137,138,139,143,145,146,148,149,150,151,154,155,157,159,160,161,163,165,168,169,173,180,185,190,193,201,202,208,210,214,216,217,224,225,240,241,242,255,270,278,280,316,322,331,332,334,335,337,338,339,349,350,370,394,398,402,403,416,427,428,470,478,532,544,545],build_forest:99,build_link:338,build_match:210,build_mountain:99,build_templ:99,buildchannel:18,builder:[12,13,15,18,30,31,33,39,41,46,49,50,57,69,76,82,83,92,95,104,105,116,118,124,126,133,135,141,145,149,156,159,161,165,216,218,223,224,228,241,270,286,305,316,322,329,331,350,364,372,380,394,398,447,466,467,470,513,545],buildier:403,building_menu:[82,201,202,235,236,545],buildingmenu:[76,82,241,242],buildingmenucmdset:241,buildprotocol:[413,426,427,428],buildshop:141,built:[5,14,19,24,28,30,56,62,73,104,105,120,123,134,135,148,151,156,157,159,162,165,174,184,185,190,193,194,207,234,305,337,338,339,349,390,397,406,411,464,466,467,470,474,476,484,545],builtin:429,bulk:[31,194],bullet:[120,156],bulletin:[33,35,156,180,545],bulletpoint:120,bunch:[16,19,69,70,135,146,150,152,157,161],burden:140,buri:[69,155],burn:[155,156,159,162,191,371],busi:[78,79,99,123,157,191,283,545],butter:[56,292],button:[7,11,14,15,20,22,33,36,49,50,51,52,53,65,68,73,75,80,95,104,148,150,151,177,178,218,275,293,363,364,371,448,477,505,545],button_expos:371,buy_ware_result:141,byngyri:[106,349],bypass:[4,33,39,54,57,109,124,135,144,149,155,161,164,175,204,206,218,232,322,394,396,466,472,489,492,524],bypass_mut:[18,232],bypass_perm:492,bypass_superus:33,byt:398,bytecod:469,bytes_or_buff:540,bytestr:[425,492],bytestream:492,c123:[84,104],c20:223,c_creates_button:448,c_creates_obj:448,c_dig:448,c_examin:448,c_help:448,c_idl:448,c_login:[5,448],c_login_nodig:448,c_logout:[5,448],c_look:[5,448],c_measure_lag:448,c_move:448,c_moves_:448,c_moves_n:448,c_score:165,c_social:448,cabinet:40,cabl:140,cach:[8,13,22,42,48,51,52,53,55,67,118,127,130,149,181,204,213,228,232,234,316,337,353,370,371,394,397,398,420,459,464,466,467,468,481,483,492,501,508,525],cache_inst:483,cache_lock_bypass:394,cache_s:[459,483],cachecontrol:77,cached_properti:492,cactu:311,cake:20,calcul:[19,42,54,91,112,118,126,130,146,162,164,165,212,247,260,308,309,311,312,316,335,338,349,353,354,403,480,483,492,537,543],calculate_path_matrix:337,calculated_node_to_go_to:28,calculu:133,calendar:[87,95,104,247,260,480,545],call:[0,2,3,5,8,9,11,12,13,14,15,18,19,20,27,28,30,32,33,34,37,41,42,44,45,47,48,49,51,52,54,56,58,62,65,67,68,69,71,73,76,80,82,86,96,97,99,103,104,107,108,111,112,113,116,117,118,120,123,124,125,126,127,128,129,130,132,133,134,135,136,137,139,141,142,143,144,145,146,147,148,150,151,152,153,156,159,161,162,164,165,167,170,171,172,173,174,175,176,177,178,182,185,186,188,189,190,191,193,195,198,199,204,205,209,210,211,212,213,215,218,223,226,227,228,229,230,232,234,241,247,250,251,254,255,256,257,258,260,266,270,273,275,276,277,278,280,283,286,289,292,293,294,296,305,308,309,310,311,312,316,322,329,338,340,343,349,350,354,359,362,364,366,369,370,371,372,380,382,386,393,394,397,398,401,402,403,405,407,409,410,411,413,416,418,420,421,425,426,427,428,429,430,431,432,434,435,436,437,438,439,440,441,443,444,445,447,448,449,454,455,456,457,458,461,464,466,467,469,470,471,472,474,476,477,478,479,480,483,485,487,488,489,490,492,501,508,513,518,532,536,538,541,542,543,545],call_async:54,call_command:8,call_ev:[97,256,545],call_inputfunc:[65,455,457],call_task:410,callabl:[27,28,34,41,47,52,53,58,71,92,104,113,132,165,241,257,278,310,337,380,386,398,401,402,403,407,411,414,416,418,426,457,471,474,476,477,479,480,485,487,488,492,545],callables_from_modul:492,callbac:76,callback1:476,callback:[19,22,27,28,32,34,47,54,76,78,82,85,87,92,104,113,124,128,136,205,228,241,242,247,254,255,256,257,258,260,289,369,377,380,386,398,407,410,411,414,416,418,421,425,426,427,429,443,444,447,458,476,480,485,490,492,545],callback_nam:[254,257],callbackhandl:[201,202,235,236,253,545],called_bi:209,calledbi:492,caller:[3,13,14,18,19,22,27,30,31,33,36,37,47,48,54,58,65,67,68,72,76,80,82,85,86,92,94,95,99,113,117,118,120,125,126,127,128,129,131,132,133,135,139,140,141,142,143,149,150,153,161,162,164,165,170,174,188,205,209,210,211,213,215,218,219,223,224,225,226,228,229,241,242,255,270,273,274,275,276,289,292,299,305,329,346,350,364,366,369,371,372,380,386,394,398,400,402,403,470,474,476,477,479,486,490,492,545],callerdepth:492,callertyp:209,callinthread:461,calllback:256,callsign:[28,275,421],calm:170,came:[75,95,122,125,126,143,151,170,176,180,329,370,398],camp:170,campfir:170,campsit:170,can:[0,2,3,4,5,6,7,8,9,10,11,12,14,15,16,17,18,19,20,22,25,27,28,30,31,32,33,34,35,36,37,39,40,41,42,44,45,46,47,48,49,50,51,52,53,54,55,57,58,59,60,62,63,64,65,67,68,69,70,71,73,74,75,77,78,79,80,82,83,84,85,86,87,88,90,91,92,93,94,95,96,97,98,99,104,105,106,107,108,109,112,113,114,115,116,117,118,119,120,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,139,140,141,142,143,144,145,146,147,148,149,150,151,154,155,156,157,159,161,162,164,165,167,168,169,170,171,172,173,174,175,177,178,179,180,182,183,184,185,186,187,188,189,190,191,192,193,194,195,198,199,203,204,205,206,207,210,211,212,213,215,216,218,223,224,225,226,227,228,229,230,232,233,234,239,241,244,247,250,256,257,260,266,270,274,275,276,277,278,280,283,286,289,292,293,296,299,305,308,309,310,311,312,316,322,329,331,333,334,337,338,340,343,346,349,350,354,362,364,370,371,372,376,380,382,386,388,390,393,394,396,397,398,401,402,403,404,405,406,407,409,411,416,427,431,434,436,439,440,444,445,447,448,454,455,456,457,458,461,462,463,464,465,466,467,469,470,471,472,474,475,476,477,478,479,486,487,488,489,490,492,493,495,496,500,513,515,518,532,537,538,540,541,543,545],can_:[95,256],can_delet:95,can_eat:95,can_ent:467,can_list_top:[225,540],can_mov:95,can_part:95,can_read_top:[225,540],can_sai:95,can_travers:95,cancel:[19,32,95,128,161,228,256,308,309,310,311,312,398,410],candid:[22,76,153,161,177,210,305,350,391,396,398,489],candidate_entri:391,candl:212,cannon:146,cannot:[4,8,9,13,14,15,19,20,22,27,28,35,39,41,46,50,54,57,60,64,75,76,90,91,92,96,109,115,118,119,125,126,127,128,130,131,133,137,141,148,149,150,153,155,156,159,162,165,177,185,191,195,204,205,212,215,218,225,241,254,257,278,292,312,316,322,331,370,371,380,386,389,394,396,398,402,411,464,471,473,475,478,483,492,545],cantanker:486,cantclear:[92,380],cantillon:180,cantmov:126,canva:132,capabl:[2,33,44,65,68,104,111,123,132,135,156,215,366,421,443,532,545],capcha:545,cape:134,capfirst:137,capit:[30,55,58,68,75,93,106,107,123,126,128,151,152,158,165,218,280,296,349,354,382,440,469,479,492,496],captcha:177,caption:120,captur:[78,126,142,485,543],car:[36,86,174],carbon:[292,293],card:[118,194,339,340,545],cardin:[118,131,132,135,218,337,338,339],care:[22,28,54,55,67,78,95,97,112,118,120,123,124,131,132,133,134,136,142,149,151,158,159,164,174,175,176,179,182,199,204,211,232,273,292,305,316,322,325,331,337,350,354,369,370,372,393,398,447,466,470,474,476,477,478,492,545],career:159,carefulli:[5,44,50,95,104,122,170,177],carri:[20,33,140,141,144,148,156,161,164,171,234,286,293,309,370,393,455,465,545],carv:86,cascad:483,case_insensit:275,case_sensit:[106,350],caseinsensitivemodelbackend:524,cast:[41,46,113,114,127,152,201,202,235,281,291,311,386,545],caster:[127,293,311],castl:[14,115,118,145,155,170,316,372],cat:[187,190],catchi:124,categor:[46,123,398],categori:[2,13,22,26,28,31,41,46,67,74,86,104,113,118,119,120,130,137,143,146,153,206,213,214,215,216,217,218,223,224,225,226,227,228,229,230,233,241,251,255,266,269,270,273,276,283,286,292,293,296,299,302,305,308,309,310,311,312,316,322,325,331,343,350,354,364,366,370,371,372,380,386,388,389,390,391,393,396,398,402,403,405,407,447,464,465,467,472,474,476,477,484,486,489,492,512,540],categoris:133,category2:484,category2_id:484,category_id:484,category_index:386,cater:[128,159],caught:[3,6,28,161,233],cauldron:293,caus:[3,8,13,20,33,51,55,74,89,123,128,129,143,149,164,165,171,182,191,212,232,245,251,289,293,329,338,364,398,447,476,478,492],caution:[51,95,136,476],cave:[96,118,331,332],caveat:[54,77,161,545],caveman:133,cblue:11,cboot:[55,103,143,266],cc1:185,cccacccc:475,ccccc2ccccc:135,cccccccc:475,ccccccccccc:135,cccccccccccccccccbccccccccccccccccc:475,ccccccccccccccccccccccccccccccccccc:475,ccreat:[103,135,143,186,189,192,266],cdesc:[103,143,266],cdestroi:[103,143,266],cdmset:20,cdn:[77,194],ceas:218,cel:475,celebr:156,cell:[0,115,135,137,155,170,380,475,478],celltext:475,cemit:143,censu:465,center:[30,41,53,56,118,124,130,132,170,278,280,331,337,346,469,478,492],center_justifi:41,centos7:187,centr:[31,170],central:[8,18,32,86,118,123,170,176,193,204,212,218,229,232,233,234,276,292,335,398,403,425,472,476,483,521],centre_east:170,centre_north:170,centre_south:170,centre_west:170,centric:[33,44,75,106,165,350],cert:[181,437,441],certain:[6,13,14,15,20,22,33,42,44,45,47,56,57,59,68,69,79,85,86,104,108,112,120,123,126,128,148,157,158,174,182,190,191,218,233,283,289,293,329,337,349,354,364,371,376,393,396,402,409,416,422,439,440,443,458,464,465,474,478,479,489,492,501,518,532,545],certainli:[16,131],certbot:[187,191,194],certfil:[437,441],certif:[181,191,437,441,545],certonli:187,cet:485,cfg:187,cflag:190,cgi:191,cha:[28,135],chain:[28,41,54,96,97,118,128,146,256,257,338,416,448,476,545],chain_1:[95,97],chain_2:[95,97],chain_3:95,chain_:[95,97],chain_flood_room:95,chain_open_door:97,chain_x:[95,97],chainedprotocol:436,chainsol:146,chair:[14,37,46,48,80,142,156,545],challeng:[90,104,115,138,152,155,162,180,276],chamber:115,chan:[18,26,223],chanalia:266,chanc:[5,11,20,30,47,63,76,86,125,127,149,155,156,162,164,184,211,293,308,309,310,311,312,364,371,372,448],chance_of_act:[5,448],chance_of_login:[5,448],chandler:164,chang:[0,2,3,5,8,10,12,13,14,15,16,18,20,22,25,27,28,30,31,32,33,34,35,36,37,41,42,44,45,46,47,48,51,55,56,57,58,60,61,63,65,67,73,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,92,93,94,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,121,123,124,125,128,129,130,132,134,136,139,141,142,143,144,146,148,150,151,152,154,156,157,161,162,163,164,165,167,170,172,174,175,176,177,178,179,181,182,184,185,187,188,190,191,193,195,197,199,204,212,213,215,216,218,224,229,232,241,250,251,254,257,266,270,275,278,283,286,292,296,302,308,309,310,311,312,316,322,325,329,338,339,340,346,349,350,353,354,370,371,372,386,388,390,396,398,402,403,406,407,409,410,411,416,421,432,447,454,455,462,464,466,470,473,474,477,478,479,485,486,487,488,500,501,502,505,506,508,541,543,545],change_name_color:386,changelock:[18,223],changelog:147,changepag:178,channel:[12,13,20,22,23,24,26,33,35,36,45,46,48,52,53,55,57,67,103,104,119,121,122,140,143,148,149,153,156,165,180,186,188,189,191,192,197,201,202,204,205,211,212,218,223,229,231,232,233,234,257,266,364,427,428,435,448,454,455,457,464,472,485,489,498,502,531,533,535,545],channel_:[18,232],channel_ban:[18,223,266],channel_color:126,channel_connectinfo:455,channel_detail:537,channel_list:537,channel_list_ban:223,channel_list_who:223,channel_msg:[18,204],channel_msg_nick_pattern:[18,232],channel_msg_nick_replac:[18,223,232],channel_msg_pattern:223,channel_prefix:[18,126,232],channel_prefix_str:[18,232],channel_search:233,channel_typeclass:533,channeladmin:502,channelalia:[18,223,232],channelattributeinlin:502,channelcl:223,channelcmdset:[20,143],channelconnect:234,channelcr:266,channelcreateview:232,channeldb:[48,121,201,232,234,463,502],channeldb_db_attribut:502,channeldb_db_tag:502,channeldb_set:[464,467],channeldbmanag:[233,234],channeldeleteview:232,channeldetailtest:533,channeldetailview:[232,537],channelform:502,channelhandl:18,channelkei:233,channellisttest:533,channellistview:537,channelmanag:[232,233],channelmixin:537,channelnam:[18,189,204,205,223,232,427],channeltaginlin:502,channelupdateview:232,char1:[8,162,224,490,533],char2:[8,162,224,533],char_health:372,char_nam:177,charac:34,charact:[2,3,5,6,8,12,13,15,16,17,19,20,22,27,28,30,31,32,33,36,39,42,44,48,49,53,57,60,62,64,67,68,70,72,73,75,76,81,83,85,86,88,90,91,92,93,95,97,98,99,102,104,105,106,107,108,112,113,114,115,117,118,121,122,125,127,128,129,130,132,133,134,136,137,138,139,141,142,143,144,145,146,147,148,150,151,152,153,154,157,163,164,169,170,171,172,173,174,182,188,201,202,203,204,206,210,211,213,215,218,219,220,224,225,226,228,230,232,241,254,256,257,273,275,276,278,286,289,296,299,302,305,308,309,310,311,312,316,329,331,335,337,338,340,343,346,349,350,353,354,359,364,366,370,371,372,376,380,382,386,388,390,394,398,409,421,442,455,460,464,466,467,469,470,475,476,478,479,490,492,493,498,512,518,531,532,533,535,540,542,543,545],character1:162,character2:162,character_cleanup:[276,278],character_cmdset:[91,316],character_ent:278,character_exit:276,character_form:538,character_id:398,character_leav:278,character_list:538,character_manage_list:538,character_sai:95,character_typeclass:[204,490,533],charactercmdset:[18,20,26,50,76,79,82,83,88,90,91,95,102,103,106,109,110,118,125,126,129,131,134,135,136,139,149,150,161,165,220,241,266,286,293,299,302,308,309,310,311,312,316,322,325,343,350,372,545],charactercreateview:[533,538],characterdeleteview:[533,538],characterdetailview:538,characterform:[532,538],characterlistview:[533,538],charactermanageview:[533,538],charactermixin:538,characterpuppetview:[533,538],charactersheet:28,characterupdateform:[532,538],characterupdateview:[533,538],characterviewset:518,charapp:177,charat:[92,380],charcreat:[26,96,97,137,143,215],charcter:18,chardata:135,chardelet:[26,143,215],chardeleteview:[390,466],chardetailview:[213,388,390,466],charfield:[67,177,488,500,501,502,504,505,506,508,532],charfilt:512,charg:191,chargen:[177,232,390,466,545],chargencmdset:165,chargenroom:165,chargenview:[390,466],charnam:[135,215,479],charpuppetview:466,charset:492,charsheet:135,charsheetform:135,charupdateview:[390,466],chase:155,chat:[0,12,23,39,53,75,99,119,122,135,156,158,159,165,180,185,186,189,192,197,445,485,545],chatroom:134,chatzilla:189,cheap:159,cheaper:47,cheapest:[118,191],cheapli:372,cheat:[120,162,182,545],chec:490,check:[0,2,3,5,6,7,8,9,10,11,14,15,18,19,20,22,28,30,35,36,37,41,42,46,47,48,49,55,57,58,62,64,67,76,78,86,92,95,96,97,104,119,120,124,126,127,128,130,131,132,133,135,137,139,140,141,142,148,149,150,154,158,159,161,162,164,165,169,170,171,172,174,177,184,185,186,187,188,191,192,193,194,198,199,204,206,209,210,211,212,213,215,217,218,223,224,225,226,228,229,230,232,234,251,257,270,275,276,278,283,286,289,292,299,308,309,310,311,312,316,329,335,338,340,354,359,364,370,372,380,393,394,397,398,402,403,406,408,409,410,415,416,420,425,431,436,454,455,457,459,460,461,464,466,467,469,470,472,479,486,487,490,492,493,495,500,501,508,513,540,543,545],check_attr:218,check_character_flag:275,check_circular:445,check_databas:416,check_db:416,check_defeat:162,check_end_turn:164,check_error:415,check_evennia_depend:492,check_flag:[275,276],check_from_attr:218,check_grid:132,check_has_attr:218,check_light_st:372,check_lock:513,check_lockstr:[33,124,394],check_main_evennia_depend:416,check_mixtur:275,check_obj:218,check_perm:276,check_permiss:402,check_permstr:[204,466],check_to_attr:218,check_warn:415,checkbox:177,checker:[16,132,393,436,493,497,545],checklockstr:143,checkout:[11,75,193],checkoutdir:2,checkpoint:545,cheer:99,chemic:293,cheng:77,chest:[39,90,142,152,153],chicken:273,child:[18,22,28,33,41,118,123,143,149,150,152,161,164,205,207,213,218,229,273,275,278,292,372,397,403,406,461,484,515],childhood:28,children:[22,46,48,123,125,146,171,207,340,397,398,406,416,465,466,484,510,538,545],chillout:218,chime:19,chines:[64,70,126,180],chip:135,chmod:2,choci:241,choic:[16,22,28,30,41,42,44,45,70,72,82,92,99,104,113,122,124,142,150,151,152,154,161,164,176,179,182,191,204,215,218,241,242,270,283,308,380,414,474,476,479,545],choice1:72,choice2:72,choice3:72,choicefield:[500,501,505,506,508,510],choos:[7,14,28,30,53,54,73,74,75,78,104,111,113,118,120,123,132,134,136,141,146,157,158,162,164,165,173,175,177,189,308,309,310,311,312,364,366,370,386,429,476,479,490,491,545],chop:[22,371],chore:156,chose:[28,67,135,151,177,184,194,198,386,476],chosen:[7,28,68,76,95,164,176,346,380,476,479],chown:193,chractercmdset:372,chraract:337,chri:77,christa:77,christian:77,chrome:183,chronicl:[92,380],chroot:187,chug:22,chunk:[14,80,137,170,418,470],church:[19,157],church_clock:19,churn:161,cid:448,cillum:29,cinemat:[278,280],circl:130,circuit:51,circular:[418,471],circumst:[28,71,96,134,141,148,150,151,161,211,311,532],circumv:216,cis:495,citi:[31,118,158,337],citymap:118,cjust:[30,479],clang:190,clank:[95,97],clarifi:126,clariti:[64,67,142,152,165,190,293],clash:[20,31,154,182,191,218,466,476],class_from_modul:492,classic:[14,44,46,47,149,158,164,167,180],classmethod:[130,204,232,292,294,317,340,390,398,409,466,483,526],classnam:[13,64,152],classobj:466,clatter:28,claus:[77,172,179],clean:[11,13,17,18,28,115,124,126,127,149,150,155,161,164,170,199,211,213,218,228,276,278,283,293,308,309,310,311,312,329,350,371,372,398,406,416,420,434,444,457,466,469,474,476,483,488,491,492,500,501,508,532,545],clean_attr_valu:501,clean_attribut:[48,204,466],clean_cmdset:[48,466],clean_senddata:457,clean_stale_task:410,clean_str:469,clean_usernam:500,cleaned_data:177,cleaner:[142,152,165],cleanli:[44,92,123,199,209,213,266,380,418,427,433,444,457,474],cleanup:[13,22,27,28,62,76,277,278,283,289,292,369,372,476,500],cleanupscript:277,clear:[9,13,16,18,22,27,46,47,48,51,55,58,62,70,72,76,92,118,119,120,123,124,128,137,139,156,159,161,162,170,176,195,199,212,215,216,218,224,230,234,289,331,339,350,353,354,372,380,382,394,396,397,398,407,410,411,418,455,459,464,466,467,476,483],clear_all_sessid:396,clear_attribut:464,clear_client_list:452,clear_cont:[37,398],clear_exit:[37,398],clearal:[72,224],clearli:[9,55,95,119,149,483],cleartext:[78,206,377,472],clemesha:461,clever:[18,20,28,54,394],cleverli:44,click:[2,7,9,11,49,50,51,52,53,59,71,73,120,137,147,177,191,476],click_top:225,clickabl:[71,120,225,545],clickable_top:225,client:[2,5,9,22,27,29,30,32,34,44,45,49,52,55,59,60,62,69,70,75,76,78,104,118,120,122,123,126,129,139,142,144,148,149,150,151,158,164,167,169,170,171,175,180,181,182,184,185,186,187,189,190,193,194,195,197,198,201,202,204,205,213,215,218,223,225,228,230,338,340,377,412,413,417,419,421,425,426,427,428,429,430,431,432,434,436,438,439,440,441,443,444,445,447,448,454,455,456,457,473,474,476,491,492,512,515,541,545],client_address:62,client_class:516,client_default_height:29,client_disconnect:445,client_encod:182,client_gui:421,client_opt:[68,421,440,545],client_secret:186,client_typ:275,client_width:[22,213],clientconnectionfail:[413,427,428],clientconnectionlost:[413,427,428],clienthelp:51,clientkei:447,clientraw:228,clientsess:[444,445],clientwidth:143,cliff:[99,115,144,218],climat:46,climb:[5,22,122,218,275,371],climbabl:[275,371],clipboard:50,clock:[19,22,55,103,143,162,266],clone:[9,10,64,120,123,147,185,545],close:[7,11,15,27,28,44,48,51,52,62,76,82,90,95,96,97,104,108,109,114,120,123,126,130,137,149,151,152,177,187,191,193,194,199,228,230,239,241,251,275,277,283,312,322,346,364,369,418,426,427,434,436,444,445,457,464,470,476,479],close_menu:[369,476],closer:[312,349],closest:[60,112,130,354,492],cloth:[13,102,201,202,235,281,470,545],clothedcharact:[83,286],clothedcharactercmdset:[83,286],clothes_list:286,clothing_typ:[83,286],clothing_type_count:286,clothing_type_ord:286,cloud9:545,cloud:[42,77,104,176,191,193,194],cloud_keep:[99,104],cloudi:42,clr:[30,280,402,479],cls:[130,204,354],club:292,clue:371,clump:152,clunki:[11,312],cluster:182,clutter:[120,212],cma:11,cmd:[5,15,18,20,22,31,33,55,68,76,80,126,127,128,131,135,136,140,141,143,151,154,161,165,174,188,198,211,213,215,216,217,218,223,224,225,226,227,228,229,230,241,251,255,266,269,270,273,283,286,292,293,296,299,302,305,308,309,310,311,312,316,322,325,331,343,350,364,366,370,371,372,380,386,387,398,440,444,445,447,470,474,476,477,540],cmd_arg:142,cmd_channel:22,cmd_help_dict:225,cmd_help_top:540,cmd_ignore_prefix:[22,210],cmd_kei:142,cmd_last:44,cmd_last_vis:44,cmd_loginstart:22,cmd_multimatch:[22,209],cmd_na_m:68,cmd_name:[68,440],cmd_noinput:[22,209,476],cmd_nomatch:[22,209,372,476],cmd_noperm:22,cmd_on_exit:[28,274,369,380,386,400,476],cmd_or_top:[225,540],cmd_total:44,cmdabout:228,cmdaccept:283,cmdaccess:224,cmdaccount:228,cmdaddcom:266,cmdallcom:266,cmdapproach:312,cmdarmpuzzl:305,cmdasync:54,cmdattack:[128,162,164,165,308,309,310,311,312,371],cmdban:216,cmdbare:143,cmdbatchcod:217,cmdbatchcommand:217,cmdbigsw:128,cmdblindhelp:364,cmdblindlook:364,cmdblock:126,cmdboot:216,cmdbridgehelp:372,cmdbui:141,cmdbuildshop:141,cmdcallback:[95,255],cmdcast:[293,311],cmdcboot:266,cmdcdesc:266,cmdcdestroi:266,cmdchannel:[18,223,266],cmdchannelcr:266,cmdcharcreat:215,cmdchardelet:215,cmdclimb:371,cmdclock:266,cmdcloselid:364,cmdcolortest:215,cmdcombathelp:[308,309,310,311,312],cmdconfigcolor:139,cmdconfirm:22,cmdcopi:218,cmdcover:286,cmdcpattr:218,cmdcraft:[86,292],cmdcraftarmour:128,cmdcreat:218,cmdcreatenpc:165,cmdcreateobj:273,cmdcreatepuzzlerecip:305,cmdcwho:266,cmddarkhelp:372,cmddarknomatch:372,cmddeclin:283,cmddefend:164,cmddelcom:266,cmddesc:[218,316],cmddestroi:218,cmddiagnos:129,cmddice:[88,135,343],cmddig:218,cmddisengag:[164,308,309,310,311,312],cmddoff:309,cmddon:309,cmddrop:[224,286],cmddummi:269,cmddummyrunnerechorespons:447,cmdeast:372,cmdecho:[22,120,128,143,150,490],cmdedit:[82,241],cmdeditnpc:165,cmdeditorbas:474,cmdeditorgroup:474,cmdeditpuzzl:305,cmdemit:216,cmdemot:[273,350],cmdentertrain:174,cmdevalu:283,cmdevenniaintro:372,cmdevmenunod:476,cmdevscaperoom:273,cmdevscaperoomstart:[90,273],cmdexamin:218,cmdexiterror:131,cmdexiterroreast:131,cmdexiterrornorth:131,cmdexiterrorsouth:131,cmdexiterrorwest:131,cmdextendedroomdesc:[91,316],cmdextendedroomdetail:[91,316],cmdextendedroomgametim:[91,316],cmdextendedroomlook:[91,316],cmdfeint:164,cmdfight:[308,309,310,311,312],cmdfind:218,cmdfinish:283,cmdfocu:273,cmdfocusinteract:273,cmdforc:216,cmdget:[126,150,224,273],cmdgetinput:476,cmdgetweapon:371,cmdgive:[224,286],cmdgiveup:273,cmdgmsheet:135,cmdgoto:331,cmdgrapevine2chan:223,cmdhandler:[20,22,37,65,148,201,202,204,208,210,211,212,213,215,226,227,228,229,230,273,305,316,372,397,398,406,490,492,545],cmdhelp:[31,164,225,273,308,309,310,311,312],cmdhit:[143,150,164],cmdhome:224,cmdic:215,cmdid:421,cmdinsid:174,cmdinterrupt:229,cmdinventori:[140,224,286],cmdirc2chan:223,cmdircstatu:223,cmdjumpstat:273,cmdlaunch:125,cmdlearnspel:311,cmdleavetrain:174,cmdlen:[210,227],cmdlight:371,cmdline:416,cmdlineinput:474,cmdlink:218,cmdlistarmedpuzzl:305,cmdlistcmdset:218,cmdlistpuzzlerecip:305,cmdlock:218,cmdlook:[4,129,224,273,316,372],cmdlookbridg:372,cmdlookdark:372,cmdmail:[98,299],cmdmailcharact:[98,299],cmdmakegm:135,cmdmap:331,cmdmapbuild:99,cmdmask:350,cmdmobonoff:370,cmdmore:477,cmdmoreexit:477,cmdmultidesc:[102,134,302],cmdmvattr:218,cmdmycmd:[31,133],cmdmylook:8,cmdname2:210,cmdname3:210,cmdname:[32,51,62,65,68,143,161,165,209,210,213,218,226,227,229,421,439,440,444,445,457,490],cmdnamecolor:[113,386],cmdnewpassword:216,cmdnick:224,cmdnoinput:241,cmdnomatch:241,cmdnositstand:161,cmdnpc:165,cmdnudg:364,cmdobj:[209,210,227,490],cmdobj_kei:209,cmdobject:[209,210,218],cmdobjectchannel:[18,223],cmdoffer:283,cmdooc:215,cmdooclook:215,cmdopen:[218,322,331],cmdopenclosedoor:322,cmdopenlid:364,cmdoption:[215,273],cmdpage:223,cmdparri:164,cmdparser:[195,201,202,208,545],cmdpass:[308,309,310,311,312],cmdpassword:215,cmdperm:216,cmdplant:[116,270],cmdpose:[164,224,350],cmdpressbutton:371,cmdpush:95,cmdpushlidclos:364,cmdpushlidopen:364,cmdpy:228,cmdquell:215,cmdquit:215,cmdread:371,cmdrecog:350,cmdreload:228,cmdremov:286,cmdrerout:273,cmdreset:228,cmdrest:[308,309,310,311,312],cmdroll:142,cmdrss2chan:223,cmdsai:[164,224,350],cmdsaveyesno:474,cmdscript:218,cmdsdesc:350,cmdser:476,cmdserverload:228,cmdservic:228,cmdsession:215,cmdset:[3,6,12,15,18,20,22,26,28,31,37,42,44,62,64,76,79,86,88,90,91,93,95,98,103,105,108,110,118,121,125,126,131,134,136,137,139,141,147,148,149,161,164,165,174,201,202,204,208,209,210,212,213,218,219,220,221,222,226,227,228,229,241,255,266,270,273,283,286,292,296,299,305,308,309,310,311,312,316,322,325,331,343,350,364,366,369,370,371,372,397,398,406,447,454,455,466,474,476,477,490,492,510,545],cmdset_account:[12,201,202,208,214,545],cmdset_charact:[201,202,208,214,286,308,309,310,311,312,545],cmdset_creat:79,cmdset_mergetyp:[28,274,369,380,400,476],cmdset_prior:[28,274,369,380,400,476],cmdset_sess:[44,201,202,208,214,545],cmdset_stack:212,cmdset_storag:[207,397,455],cmdset_trad:283,cmdset_unloggedin:[22,89,100,201,202,208,214,251,545],cmdsetattribut:218,cmdsetclimb:371,cmdsetcrumblingwal:371,cmdsetdesc:224,cmdsetevenniaintro:372,cmdsetevscaperoom:273,cmdsetflag:273,cmdsethandl:[44,201,202,208,545],cmdsethelp:225,cmdsethom:218,cmdsetkei:20,cmdsetkeystr:211,cmdsetlegacycomm:[103,266],cmdsetlight:371,cmdsetmor:477,cmdsetobj:[211,212,219,220,221,222,241,266,273,283,286,292,305,308,309,310,311,312,316,322,325,331,343,350,364,366,369,370,371,372,447,474,476,477],cmdsetobjalia:218,cmdsetpow:165,cmdsetread:371,cmdsetsit:161,cmdsetspe:[110,325],cmdsettestattr:27,cmdsettrad:[79,283],cmdsettrain:174,cmdsetweapon:371,cmdsetweaponrack:371,cmdsheet:135,cmdshiftroot:371,cmdshoot:[125,312],cmdshutdown:228,cmdsit2:161,cmdsit:161,cmdsmashglass:364,cmdsmile:22,cmdspawn:218,cmdspeak:273,cmdspellfirestorm:127,cmdstand2:161,cmdstand:[161,273],cmdstatu:[283,311,312],cmdstop:[110,325],cmdstring:[22,135,143,209,213,226,229,490],cmdstyle:215,cmdtag:218,cmdtalk:366,cmdtask:228,cmdteleport:[218,331],cmdtest:[3,128,142],cmdtestid:22,cmdtestinput:28,cmdtestmenu:[28,92,380,476],cmdticker:228,cmdtime:[136,228],cmdtrade:283,cmdtradebas:283,cmdtradehelp:283,cmdtunnel:218,cmdtutori:372,cmdtutorialgiveup:372,cmdtutoriallook:372,cmdtutorialsetdetail:372,cmdtweet:188,cmdtypeclass:218,cmdunban:216,cmdunconnectedconnect:[230,251],cmdunconnectedcr:[230,251],cmdunconnectedencod:230,cmdunconnectedhelp:[230,251],cmdunconnectedinfo:230,cmdunconnectedlook:[230,251],cmdunconnectedquit:[230,251],cmdunconnectedscreenread:230,cmduncov:286,cmdunlink:218,cmdunwield:309,cmduse:310,cmdusepuzzlepart:305,cmdwait:22,cmdwall:216,cmdwear:286,cmdwerewolf:126,cmdwest:372,cmdwhisper:224,cmdwho:[215,273],cmdwield:309,cmdwipe:218,cmdwithdraw:312,cmdxyzopen:331,cmdxyzteleport:331,cmdyesnoquest:476,cmset:[212,510],cmud:183,cnf:[2,182],coal:[292,293],coast:[155,170],coastal:170,cobj:273,cockpit:125,code:[2,5,6,7,8,12,15,16,20,22,24,28,30,31,33,34,37,39,41,44,46,47,48,49,50,52,53,54,55,56,57,60,61,62,64,67,68,72,73,75,77,79,80,82,85,86,90,96,97,99,104,107,112,115,118,121,122,123,124,128,130,132,133,134,135,136,137,138,142,144,146,147,148,149,150,152,153,154,155,157,159,160,161,163,164,165,166,168,169,170,171,172,174,175,176,178,180,182,185,192,193,194,195,197,199,201,202,204,208,209,212,215,217,218,223,225,228,231,235,241,247,254,257,270,275,278,281,283,289,291,310,337,343,346,372,382,394,403,406,427,428,444,455,458,466,468,469,474,476,478,489,490,491,492,499,541,544,545],code_exec:470,code_hint:275,code_tri:275,codebas:[11,72,74,120,122,133,153,229],codeblock:120,codec:469,codefunc:474,codeinput:275,coder:[0,1,76,90,104,133,156,158,159,180,209,398],coding_styl:120,coerc:487,coexist:175,coher:166,coin:[79,104,119,152,153,156,157,283,545],col:[56,167,478],cold:[55,199,228,403,407,411,454],cole:492,coll_date_func:228,collabor:[11,90,123,124,156,159,191,225,545],collat:[31,65,402],collect:[0,13,20,30,31,49,105,118,152,169,209,211,225,228,305,354,464,492,518,540],collect_top:[225,540],collector:169,collectstat:[51,53,169,416,420],collid:[20,41,112,184,191,275,354,476,479],collis:[20,22,459],collist:152,colon:[19,33,95,144,151,394],color:[18,22,26,28,30,32,41,51,56,71,72,94,104,113,118,120,121,132,135,137,138,143,144,151,170,180,185,213,215,243,244,245,270,280,293,337,338,340,346,350,369,386,398,402,421,428,436,439,444,445,469,478,479,486,490,491,493,545],color_ansi_bright_bg_extra_map:[84,244],color_ansi_bright_bgs_extra_map:[84,244],color_ansi_extra_map:[84,244],color_markup:[84,201,202,235,236,545],color_no_default:[84,244],color_typ:469,color_xterm256_extra_bg:[84,244],color_xterm256_extra_fg:[84,244],color_xterm256_extra_gbg:[84,244],color_xterm256_extra_gfg:[84,244],colorablecharact:139,colorback:491,colorcod:491,colour:[19,218,443,469,478,545],column:[51,56,58,67,95,96,117,118,120,123,132,135,137,170,213,215,329,340,478,492],com:[0,8,9,10,11,40,49,53,54,56,64,69,73,75,76,77,85,90,96,120,122,130,149,153,155,156,170,177,180,181,182,184,185,187,190,191,192,193,194,201,223,228,241,251,289,391,428,431,440,444,461,478,491,492,532,544],coman:77,combat:[11,15,20,28,41,48,69,96,104,114,115,122,123,126,127,138,143,148,149,155,157,158,162,163,170,171,180,185,212,308,309,310,311,312,370,406,545],combat_:[308,309,310,311,312],combat_cleanup:[308,309,310,311,312],combat_cmdset:164,combat_handl:164,combat_handler_:164,combat_movesleft:[308,309,310,311],combat_scor:165,combat_status_messag:312,combatcmdset:164,combathandl:164,combatscor:165,combin:[8,13,19,20,22,34,35,41,46,47,55,60,86,104,105,112,118,122,127,129,134,135,144,146,150,151,158,172,174,181,187,191,209,210,211,218,275,292,293,302,305,338,340,349,354,364,394,402,405,411,416,465,467,472,479,486,490,492],combo:44,come:[5,11,12,13,16,19,22,28,29,31,33,42,44,51,52,53,54,56,60,62,65,68,72,73,90,91,95,96,104,115,118,122,123,124,125,126,128,132,134,135,136,137,141,142,144,148,149,151,152,156,158,159,161,162,164,165,167,170,172,174,175,177,178,182,187,193,198,204,211,308,309,310,311,312,316,350,382,402,403,434,439,444,445,447,453,469,477,515,541],comet:[51,62,445],comfi:161,comfort:[11,16,122,137,142,159,545],comg:49,comlist:266,comm:[18,22,26,35,121,123,147,188,201,202,208,214,265,266,267,472,498,499,523,537,545],comma:[18,50,58,67,95,96,144,151,152,178,182,218,226,260,292,299,394,398,479,492],comman:144,command:[0,2,5,7,8,9,11,12,13,14,16,18,19,23,27,28,29,32,33,35,36,37,39,40,41,44,46,48,50,51,52,54,55,57,58,59,60,61,62,63,64,65,67,68,69,70,71,72,74,75,78,79,80,82,83,85,86,88,90,92,93,96,97,99,102,104,105,106,108,109,110,111,113,114,115,117,118,120,122,123,124,125,132,133,134,137,138,144,145,147,153,155,156,158,159,162,169,170,171,172,173,175,180,181,182,183,185,186,187,189,190,191,192,194,195,198,199,201,202,204,205,232,233,235,236,241,250,251,253,256,258,265,266,268,269,270,271,272,274,275,280,283,286,289,292,293,294,296,299,302,305,308,309,310,311,312,314,316,322,325,329,330,332,333,343,350,362,364,366,369,370,371,372,377,380,386,387,388,389,390,391,393,394,398,402,403,406,413,416,421,425,426,434,436,439,440,444,445,447,448,454,455,466,468,469,472,474,476,477,486,489,490,492,518,540,541,544,545],command_default_arg_regex:22,command_default_class:126,command_default_help_categori:31,command_pars:210,commandhandl:[32,212,227],commandmeta:213,commandnam:[22,32,65,144,270,416,425,455,457],commandset:[33,37,143,212],commandtestmixin:490,comment:[14,15,28,48,75,80,126,143,161,172,181,183,191,337,470,476,545],commerc:180,commerci:[7,159,191],commerror:233,commit:[2,9,10,16,63,69,119,120,123,126,182,192,193,376,501,508,545],commmand:[109,308,309,310,311,312,322],commom:545,common:[0,6,8,11,16,18,19,22,28,32,33,41,42,44,45,46,47,48,54,55,56,58,62,65,68,70,79,86,104,106,110,120,121,123,129,136,137,142,144,145,148,149,151,152,153,156,158,159,160,162,164,165,177,185,187,191,211,218,223,230,283,292,325,349,350,394,396,406,421,444,448,465,466,475,477,487,489,492,518,525,541],commonli:[9,30,31,36,42,44,45,47,53,58,65,67,95,112,118,123,146,150,158,182,185,195,338,354,398,490,518],commonmark:120,commun:[7,18,22,35,40,51,52,62,65,68,70,76,77,78,104,121,122,123,134,142,143,147,148,149,158,159,180,181,182,189,191,194,204,220,223,230,231,232,233,234,273,299,339,369,397,405,413,425,426,436,437,439,440,441,442,455,457,472,473,488,544,545],compact:[141,146,178,364],compani:[68,123],compar:[6,8,11,14,16,19,20,65,75,95,99,106,112,118,124,127,128,131,135,141,142,146,159,162,164,165,305,308,309,310,311,312,349,354,393,394,403,447,469,490,492],comparison:[5,14,30,146,147,353,393,403,476,490],compartment:135,compass:144,compat:[15,28,77,112,113,125,218,354,478,485,492],compet:[16,68,158],compil:[5,22,64,69,75,120,133,148,185,190,191,213,218,224,225,228,230,273,286,292,350,469,474,476,491],compilemessag:64,complain:[3,9,67,142,161,199],complement:[0,45,159,354],complementari:[24,30,41,42,70],complet:[2,5,9,11,12,13,14,15,16,19,20,22,27,37,39,41,44,45,50,52,54,68,76,78,84,85,94,95,99,104,115,119,123,126,131,132,135,136,139,141,146,150,151,155,156,157,158,159,165,170,182,187,191,195,198,199,204,211,212,213,226,228,229,244,257,271,289,309,316,338,346,364,372,380,398,410,416,418,426,427,444,464,470,475,476,477,489,492,513,532,545],complete_task:257,complex:[5,15,16,20,22,30,47,58,67,69,90,95,104,107,111,118,120,123,136,144,148,150,151,152,153,156,157,158,161,162,164,165,170,193,195,212,232,258,275,364,366,382,403,448,464,545],complianc:[183,316],compliant:[130,440],complic:[54,76,92,97,113,128,132,137,142,146,170,177,178,191,230,251,380,386,464],compon:[0,5,8,22,35,42,49,50,51,53,60,61,62,73,118,120,128,132,135,138,147,156,159,164,165,166,168,191,199,201,202,218,228,233,234,235,247,292,305,314,330,337,339,349,353,396,403,404,405,406,409,416,445,472,475,479,489,492,495,521,544,545],componenta:4,componentid:51,componentnam:51,componentst:51,compos:[92,193,380],composit:[442,465],comprehens:[5,8,33,35,48,122,157,161,185,194],compress:[32,421,425,429,488],compress_object:488,compris:204,compromis:[194,376],comput:[11,47,54,55,70,123,132,133,146,147,158,162,176,185,189,193,198,216,228,350,492,493,545],computation:47,comsystem:234,con:[26,135,180,230,251],concaten:[148,469],concept:[11,40,47,62,64,85,96,102,104,119,120,130,134,137,138,139,151,152,154,156,157,161,289,302,354,544,545],conceptu:[28,132],concern:[64,68,95,104,118,131,151,185,211,382,390],conch:[436,439,447],concis:159,conclud:[146,283,476,545],conclus:545,concret:95,concurr:182,conda:75,conder:470,condit:[5,30,58,88,95,96,104,114,122,132,141,142,143,146,150,156,157,162,165,181,209,225,310,343,350,394,398,409,415,416,461,467,492,545],condition:126,condition_result:343,condition_tickdown:310,conditional_flush:483,conduct:169,conductor:174,conect:457,conf:[2,5,8,11,24,25,32,33,41,42,50,53,62,64,67,73,75,78,84,86,90,95,99,100,118,120,124,126,136,137,139,149,161,173,174,177,178,181,182,184,186,187,191,194,204,244,292,332,334,416,422,423,462,470,545],confer:[180,492],confid:[3,119,130],config:[2,7,10,11,12,30,62,75,124,185,187,191,192,354,416,418,422,423,434,507,545],config_1:12,config_2:12,config_3:12,config_color:139,configcmd:139,configdict:[436,457],configur:[2,8,12,50,95,97,120,123,126,136,137,138,148,169,173,184,185,191,193,194,204,207,210,215,270,354,376,377,418,423,434,457,459,461,462,465,532,545],configut:7,confirm:[22,51,77,89,118,144,181,185,194,218,251,305,440,443,543],conflict:[3,158,175],confus:[0,5,6,11,20,22,36,39,42,51,54,60,64,74,76,89,95,118,120,123,131,135,142,146,149,152,169,175,191,223,251,338,542],congratul:545,conid:435,conj:[30,58,398,479],conjug:[30,58,201,202,398,468,479,494,497,545],conjunct:95,conjur:[114,311],conn:[26,230,251],conn_tim:44,connect:[5,8,12,13,14,17,18,20,22,24,26,32,37,39,40,42,44,45,48,50,51,52,53,55,60,62,63,64,65,68,71,75,78,89,90,94,95,96,97,99,100,104,110,115,118,122,123,124,126,132,134,137,141,142,144,146,147,148,149,150,158,165,169,170,173,175,181,182,183,185,186,187,189,192,193,194,195,198,199,204,205,206,207,215,216,218,223,230,232,233,234,250,251,254,255,257,266,325,335,337,338,340,346,377,397,398,404,412,413,416,418,425,426,427,428,429,434,435,436,439,444,445,447,448,454,455,456,457,458,461,464,466,472,488,515,518,545],connection_cr:45,connection_screen:[25,89,100,148,195,201,202,235,236,249,251,261,545],connection_screen_modul:[89,100,251],connection_set:184,connection_tim:[204,398],connection_wizard:[201,202,412,545],connectiondon:418,connectionlost:[418,425,426,436,439,447],connectionmad:[413,425,436,439,447],connectionwizard:414,connector:[413,427,428,434,457],conquer:155,cons3:294,consecut:28,consequ:[191,212],consid:[0,5,6,13,14,15,18,19,20,22,28,30,32,33,39,41,42,44,46,47,48,50,52,54,55,58,60,62,67,70,73,86,92,96,97,105,106,112,118,119,122,123,124,130,131,134,140,141,146,148,151,153,156,157,159,161,174,177,178,179,182,185,191,194,204,211,212,270,289,305,312,335,337,338,349,350,354,380,398,402,403,406,421,436,439,465,467,470,471,476,477,479],consider:[67,78,149,158,170,172,195,403,478],consist:[12,13,17,22,28,31,33,40,41,51,58,60,67,73,96,99,106,118,120,131,136,151,154,155,157,164,165,199,204,210,225,226,232,233,247,283,293,305,339,349,387,394,403,440,445,455,464,466,472,478,490,492,501,508,543],consitut:149,consol:[0,3,6,7,51,57,60,64,75,77,120,123,149,151,152,154,165,182,185,190,191,193,198,225,228,339,350,416],conson:[106,349],constant:[68,97,425,490],constantli:[171,372],constitu:[212,226],constitut:13,constraint:[97,182],construct:[2,123,128,161,177,403,460,464,469,477,532],constructor:[22,76,86,112,241,292,354,427],consum:[54,86,104,275,292,293,294,418,492],consumable_kwarg:292,consumable_nam:292,consumable_tag:[86,292,293],consumable_tag_categori:[86,292],consume_flag:275,consume_on_fail:292,consumer_kei:[173,188],consumer_secret:[173,188],consumpt:[5,182,459],contact:[18,37,191,193],contain:[0,6,9,13,14,15,17,20,22,26,28,30,31,33,35,37,41,44,51,52,53,54,56,60,62,67,72,75,76,78,90,92,93,95,96,97,99,104,106,107,110,113,114,116,118,119,120,121,122,123,125,126,130,133,134,136,137,142,143,144,146,147,148,149,150,151,157,161,165,169,172,175,177,178,180,185,190,195,198,201,202,204,205,206,208,209,210,211,212,214,217,218,223,225,231,241,254,255,256,257,258,260,270,273,292,296,305,310,325,329,337,338,339,340,349,350,354,364,371,377,378,380,382,386,388,389,392,398,400,402,403,410,412,415,419,421,447,459,460,461,464,465,466,467,468,469,470,473,475,476,477,478,479,489,490,491,492,493,515,521,530,540,541,543,545],container:193,contempl:133,content:[5,11,14,17,19,30,35,37,48,50,51,52,53,56,80,90,95,104,120,124,125,130,132,133,135,137,140,141,142,146,148,150,151,153,154,158,159,160,161,163,165,166,167,168,171,174,177,178,180,187,191,213,216,218,239,275,276,331,350,388,396,397,398,467,469,470,471,474,476,478,489,490,498,508,515,521,530,544,545],content_typ:[397,398],contentof:478,contents_cach:397,contents_get:[153,398],contents_set:398,contentshandl:397,contest:[90,273],context:[53,60,95,96,122,137,142,154,175,177,241,257,437,441,525,537,538,540,541,543],context_processor:525,contextu:46,contibut:[80,104],continu:[1,3,13,19,22,28,46,47,53,54,59,67,77,95,96,99,104,118,119,122,125,128,132,135,137,141,143,150,151,164,165,169,188,190,191,338,398,414,425,461,464,476,485,492,545],contrari:[49,95,97,112,136,148,158,228,354,467],contrast:[39,42,70,133,191,440],contrib:[14,15,50,58,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,98,99,100,101,102,103,105,106,107,108,109,110,111,112,113,114,115,116,117,118,120,121,122,124,134,135,136,138,144,147,148,151,155,158,160,162,163,164,179,185,201,202,204,206,207,228,229,458,469,470,500,501,502,504,505,506,507,508,523,524,532,538,543,545],contribcloth:286,contribrpcharact:[106,350],contribrpobject:[106,350],contribrproom:[106,350],contribu:11,contribut:[0,8,11,64,76,77,78,79,81,83,85,86,88,90,91,92,93,94,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,123,124,140,147,157,169,179,197,198,235,244,270,283,286,299,305,316,322,325,343,350,366,376,377,382,544,545],contributor:[77,179,241,354],control:[1,2,3,4,9,12,14,15,18,20,22,27,28,29,30,31,32,33,37,40,41,42,44,49,50,55,57,58,60,65,67,69,73,75,77,79,80,86,104,108,118,119,120,121,123,125,134,135,139,144,146,147,148,149,150,154,156,158,159,162,165,172,174,185,187,191,194,197,199,204,205,215,217,218,223,256,266,275,283,329,340,350,364,370,372,393,398,406,416,455,457,466,476,479,490,513,532,545],contrub:86,convei:[350,398],convenei:45,conveni:[2,7,18,28,31,32,33,37,39,41,42,48,53,54,62,67,69,74,75,82,99,118,120,122,125,134,137,149,150,151,153,154,177,181,192,199,204,218,228,241,278,280,292,299,398,448,459,470,471,476,477,479,485,488,489],convent:[20,45,67,97,146,175],convention:[213,398,466],convers:[18,28,30,36,86,104,111,174,349,366,444,445,469,492,544],convert:[9,13,18,19,36,41,60,62,65,68,70,87,92,118,119,123,130,132,136,139,141,146,149,154,161,175,180,194,206,216,247,337,343,380,386,393,396,402,403,405,407,425,427,436,439,440,457,461,469,473,476,477,478,479,480,488,491,492,495,515,545],convert_linebreak:491,convert_url:491,convinc:[28,191],cool:[0,75,76,95,125,156,167,180,218,223],cool_gui:39,cooldown:[128,164,201,202,235,281,545],cooldownhandl:[85,289],coord:[130,335,337,338,340],coordi:130,coordin:[51,99,104,117,118,132,312,329,331,337,338,339,340,545],coordx:130,coordz:130,cope:311,copi:[0,2,5,9,11,14,15,22,26,27,28,41,44,49,50,51,53,73,77,90,97,104,123,124,126,136,139,143,144,147,148,165,169,170,177,187,191,193,195,217,218,257,286,308,309,310,311,312,372,396,398,405,416,425,462,469,485,540,541,545],copy_object:[396,398],copy_script:405,copy_word_cas:492,copyright:[179,191],core:[7,11,37,48,57,64,68,87,98,104,119,132,147,152,157,179,195,204,207,228,234,235,293,299,390,397,398,406,412,423,433,440,454,464,466,467,470,477,484,490,532,543,544,545],corner:[17,115,117,118,130,134,180,329,337,478],corner_bottom_left_char:478,corner_bottom_right_char:478,corner_char:478,corner_top_left_char:478,corner_top_right_char:478,corpu:[106,349],correct:[15,19,20,22,27,30,53,54,60,70,115,119,120,125,129,142,149,152,159,165,174,175,182,209,215,218,233,275,305,316,337,350,360,394,431,434,436,442,456,469,490,492],correctli:[2,3,6,19,22,27,28,46,47,75,118,120,124,128,131,132,136,141,142,148,165,174,175,181,189,191,199,204,207,212,215,292,407,416,425,461,488,515],correl:403,correspond:[22,33,44,53,73,99,105,118,141,144,247,305,386,464,501,508,513,532],correspondingli:9,corrupt:133,cosi:170,cosin:492,cosmet:329,cost:[117,118,127,141,191,311,329,350,545],cottag:[59,170],couchdb:77,could:[2,3,5,7,8,9,12,13,14,15,16,18,20,22,28,30,31,33,34,35,36,37,39,41,42,46,47,48,53,54,55,57,58,60,62,65,67,68,69,70,72,73,74,75,76,79,82,86,90,95,96,97,104,107,110,112,113,118,120,122,123,124,125,126,127,128,129,130,131,132,134,135,136,137,139,140,141,142,143,144,146,148,149,150,151,152,154,156,157,158,159,161,162,164,165,167,169,170,171,172,173,174,175,176,177,180,185,186,187,188,189,191,192,204,212,218,225,233,234,241,260,275,276,283,292,325,329,338,340,343,346,350,353,354,364,372,382,386,394,398,409,421,440,445,461,466,467,469,470,474,478,479,480,483,487,492,496],couldn:[57,74,123,130,131,142,143,151,175,178,382],count:[18,49,52,114,123,146,149,151,164,173,195,206,211,286,289,310,386,398,430,434,447,451,457,459,465,469,476,479,485,496],count_loggedin:434,count_queri:451,countdown:[42,128,144],counter:[9,42,44,76,128,137,141,157,164,201,205,235,341,352,353,372,434,447,448,455,476,545],counterpart:[14,60,157,421,457,473],countertrait:354,countri:216,coupl:[11,39,76,110,137,171,193,232,325],cours:[0,5,7,10,16,22,47,53,55,69,74,75,76,78,86,95,96,97,104,115,118,120,123,124,125,134,142,149,150,151,152,155,156,165,176,179,198,309,312,369],court:115,courtesi:55,cousin:[72,95,104,142],cover:[0,11,14,15,31,53,61,62,66,67,75,83,95,108,118,119,128,134,146,147,148,150,151,157,158,159,173,180,181,182,185,191,197,275,286,293,316,338,364,372,398,492],coverag:8,coveral:8,cpanel:191,cpattr:[26,143,218],cprofil:545,cpu:[5,55,191,194,228],cpython:5,crack:67,craft:[33,58,92,105,128,156,170,201,202,235,281,380,545],craft_recipe_modul:[86,292],craft_recipes_modul:292,craft_result:292,crafted_result:292,crafter:[292,293,294,545],crafting_consumable_err_msg:292,crafting_materi:[86,292,293],crafting_recipe_modul:86,crafting_result:292,crafting_skil:86,crafting_tool:[86,292],crafting_tool_err_msg:292,craftingcmdset:292,craftingerror:292,craftingrecip:[86,292,293,294],craftingrecipebas:[86,292],craftingvalidationerror:[86,292],craftrecip:292,cram:155,crank:47,crash:[0,151,156,170,180,194,420,464],crate:[36,144],crave:197,crawl:194,crawler:[230,430],cre:[26,230,251],creat:[0,3,5,7,8,10,11,13,14,15,16,18,20,25,26,27,28,30,31,33,35,36,39,41,42,44,45,46,49,50,51,53,56,57,61,62,63,69,72,73,74,75,76,77,79,80,82,83,86,90,91,92,96,99,101,102,103,104,105,106,107,108,111,112,113,115,117,118,119,120,122,123,124,126,128,130,131,132,133,134,135,136,139,141,142,146,148,150,152,153,154,155,156,157,159,160,161,162,163,164,166,168,169,171,172,173,176,178,179,180,182,184,185,186,188,189,190,191,194,195,198,201,202,204,205,206,207,210,211,212,213,215,218,223,224,225,226,227,228,229,230,232,233,234,239,241,242,245,247,251,256,257,258,260,266,270,273,274,275,276,277,278,280,283,286,292,293,294,296,299,302,305,308,309,310,311,312,316,322,329,337,338,339,340,343,349,350,354,359,364,366,369,370,371,372,377,380,382,386,388,389,390,394,396,397,398,400,401,402,403,405,406,409,410,411,413,416,420,421,426,428,429,434,436,437,441,448,454,456,457,459,461,464,465,466,467,468,469,470,471,474,475,476,478,479,480,485,490,492,500,505,512,517,518,533,536,538,540,541,542,543,545],creataion:335,create_:[37,48],create_account:[19,45,48,121,201,206,472,490],create_attribut:464,create_cal:204,create_channel:[18,19,121,201,223,232,233,472],create_char:490,create_charact:[204,398],create_default_channel:454,create_delai:410,create_evscaperoom_object:280,create_exit:[218,322],create_exit_cmdset:398,create_fantasy_word:280,create_forward_many_to_many_manag:[207,234,390,397,406,464,466,467,484],create_game_directori:416,create_grid:132,create_help:389,create_help_entri:[19,31,121,201,472],create_kwarg:403,create_match:210,create_messag:[19,35,121,201,233,472],create_obj:490,create_object:[8,13,14,19,33,37,48,80,86,99,121,141,145,165,170,177,201,278,280,292,364,396,398,403,420,470,472,545],create_prototyp:[402,403],create_room:490,create_script:[19,42,48,95,121,133,164,201,405,409,470,472,490],create_secret_kei:416,create_settings_fil:416,create_superus:416,create_tag:465,create_wild:[117,329],createbucket:77,created_on:254,createnpc:545,createobj:273,creater:121,createview:542,creation:[6,11,13,15,28,33,37,44,48,67,74,78,99,118,120,125,135,139,144,145,147,149,156,158,163,165,170,177,180,201,204,207,218,223,225,232,277,292,305,308,309,310,311,312,322,331,337,340,350,354,371,372,377,390,396,397,398,403,406,411,449,466,472,474,475,476,478,500,501,505,508,532,536,538,543,544,545],creation_:472,creativ:[69,158],creator:[28,33,74,121,159,165,170,180,225,232,308,309,310,311,312,398,478],creatur:545,cred:[11,436],credenti:[11,52,53,77,191,194,204,436],credentialinterfac:436,credit:[11,119,151,191,194,491,492,545],creset:11,crew:146,criteria:[28,104,107,146,233,256,382,402,465,489],criterion:[11,146,149,150,155,204,283,350,389,396,398,405,408,489,492],critic:[0,6,9,20,42,44,57,60,90,185,187,394,415,416,485],critici:466,cron:187,crontab:187,crop:[30,60,135,337,475,478,479,492,545],crop_str:478,cross:[115,118,170,293,335,338,372,478],crossbario:444,crossbow:128,crossmaplink:[118,338],crossroad:170,crowd:[156,194],crt:[181,187],crucial:[47,142],crucibl:293,crucible_steel:293,cruciblesteelrecip:293,crud:[517,518],crude:[97,292,293],crumblingwal:371,crumblingwall_cmdset:371,crush:125,crypt:155,cryptocurr:194,cscore:165,csessid:[434,444,445,457],csession:[444,445],csrf_token:177,css:[17,50,51,53,71,73,122,148,169,491,521],cssclass:51,ctrl:[5,53,151,154,185,187,191,193,198,199,447],cuddli:[149,152],culpa:29,cumbersom:[9,28,174,386],cumul:448,cup:119,cupidatat:29,cur_valu:346,cure:[114,310,311],cure_condit:310,curi:132,curiou:69,curli:[84,244],curly_color_ansi_bright_bg_extra_map:[84,244],curly_color_ansi_bright_bgs_extra_map:[84,244],curly_color_ansi_extra_map:[84,244],curly_color_xterm256_extra_bg:[84,244],curly_color_xterm256_extra_fg:[84,244],curly_color_xterm256_extra_gbg:[84,244],curly_color_xterm256_extra_gfg:[84,244],curr_sess:457,curr_tim:316,currenc:[141,173],current:[5,6,7,8,9,11,12,14,15,18,19,20,22,26,27,28,30,32,37,39,42,43,44,46,47,51,52,53,55,57,58,60,67,75,76,77,79,82,91,92,94,95,96,97,99,104,107,112,114,118,123,125,126,127,128,132,135,141,143,144,146,147,148,149,150,152,157,161,164,165,173,174,177,180,187,193,195,198,204,206,207,209,210,212,213,215,216,218,223,224,225,227,228,230,241,257,260,266,273,275,278,283,286,292,302,308,309,310,311,312,316,322,325,329,331,338,340,346,350,353,354,362,369,371,372,380,382,386,389,396,397,398,403,406,410,411,416,421,426,432,433,436,437,440,448,455,457,459,465,466,474,476,478,479,480,485,486,489,492,500,515,537,538,540,541,545],current_choic:241,current_cmdset:218,current_coordin:329,current_kei:[401,402],current_tim:447,current_us:177,current_weath:42,current_weight:338,currentroom:174,curriculum:180,curs:[3,157],curtain:31,curv:[122,133],curx:132,cushion:161,custom:[0,6,12,13,15,16,17,19,20,22,25,26,32,36,37,41,46,48,52,55,56,58,61,63,65,67,74,77,78,83,85,92,93,95,97,99,104,106,112,114,115,117,118,121,122,123,125,126,129,132,133,135,137,138,141,144,146,148,150,155,156,157,158,161,162,164,165,169,171,172,174,175,176,177,179,180,186,188,191,193,195,199,204,205,206,207,209,211,212,213,218,223,224,225,230,232,246,247,248,257,260,273,274,275,276,278,283,286,289,292,296,305,316,329,333,337,338,349,350,354,364,369,371,372,376,377,380,388,389,396,398,400,401,402,403,405,411,416,420,422,425,447,456,466,471,474,476,477,478,483,486,487,490,491,492,499,500,502,507,517,518,523,524,541,545],custom_add:257,custom_cal:[257,260],custom_evennia_launcher_command:416,custom_gametim:[87,95,136,201,202,235,236,545],custom_helpstr:275,custom_kei:402,custom_pattern:[124,167,177,178],customis:[201,202,235,314,327,545],customiz:[17,82,94,104,106,161,241,346,350,364,380],customlog:181,customt:490,cut:[18,27,62,86,122,132,142,144,158,165,170,337,403],cute:169,cutoff:492,cvcc:349,cvccv:349,cvccvcv:349,cvcvcc:349,cvcvccc:349,cvcvccvv:349,cvcvcvcvv:349,cvcvvcvvcc:[106,349],cvv:349,cvvc:[106,349],cwho:[103,143,266],cyan:[60,175],cyberpunk:[18,153],cyberspac:180,cycl:[14,15,126,133,136,156,176,308,309,310,311,312],cyril:16,daemon:[5,78,181,187,193,194,199,433,461],daffodil:153,dai:[2,19,69,87,91,95,104,133,136,156,157,173,175,176,187,193,194,206,247,293,316,480,485,492,493,545],daili:36,dailylogfil:485,dali:[106,349],dalnet:223,dalton:146,dam:133,damag:[15,114,125,127,141,155,157,158,162,164,194,293,308,309,310,311,312,370,371],damage_rang:311,damage_taken:133,damage_valu:[308,309,310,311,312],damascu:293,danc:118,dandi:74,danger:[6,14,20,44,95,120,140,211],dare:[22,143,495],dark:[14,15,17,20,31,60,112,118,151,155,157,159,162,170,175,180,212,316,354,364,372,406,469,470],darkcmdset:372,darker:[60,175],darkgrai:175,darkroom:372,darkroom_cmdset:372,darkstat:372,dash:[95,107,120,382,386],dashcount:386,dashlin:30,data:[5,6,9,12,14,16,18,19,30,31,36,41,42,46,48,49,50,51,53,54,65,67,68,70,73,76,78,85,86,92,94,104,112,118,123,126,133,134,135,148,149,152,156,159,177,178,182,187,190,191,193,195,204,205,206,213,218,225,228,256,257,289,292,337,338,339,346,350,353,354,376,377,380,396,397,398,400,402,404,409,411,413,414,418,422,423,425,426,427,428,429,434,435,436,437,439,440,441,443,444,445,447,449,454,455,456,457,459,463,464,465,466,467,469,470,471,472,473,475,476,477,478,479,482,485,486,487,488,492,501,502,504,506,508,512,515,518,523,532,536,538,540,541,543,545],data_default_valu:354,data_in:[62,65,377,425,427,428,434,435,439,444,445,455,456,457],data_out:[62,377,434,436,439,440,445,455,456,457],data_to_port:413,data_to_serv:426,databa:416,databas:[2,5,8,10,11,13,14,16,17,18,19,20,23,32,33,34,35,36,37,42,44,45,46,47,48,49,50,52,53,55,57,73,74,77,78,91,95,97,104,117,118,120,122,123,124,125,127,128,130,133,134,135,142,143,145,147,148,150,151,153,156,157,158,161,164,165,169,170,177,178,182,185,193,195,197,198,199,204,206,207,211,212,218,225,228,232,233,234,256,257,311,316,339,340,350,372,387,388,389,390,393,396,397,398,402,404,405,406,407,410,411,416,420,422,433,447,454,463,464,465,466,467,470,472,473,481,483,488,489,492,498,502,505,506,508,518,545],dataclass:479,datareceiv:[418,425,439,447],dataset:402,datastor:67,date:[9,11,13,31,55,64,67,77,132,136,175,177,182,187,190,212,216,228,376,480,485,493],date_appli:177,date_cr:[48,204,207,234,390,406,464,466],date_join:[207,500],date_s:35,datetim:[48,136,177,247,317,464,480,485,486,492,493],datetime_format:492,datetimefield:[67,177,207,234,390,397,406,464,466,492,500],davewiththenicehat:540,david:[77,180],dawn:144,day_rot:485,daylight:157,db3:[5,9,11,148,170,182,198],db3_backup:5,db_:[34,48,67,146,350,396,398,407,421,489],db_account:[277,286,396,397,406,500,505],db_account__db_kei:505,db_account__id:512,db_account__usernam:512,db_account_id:[397,406],db_account_subscript:[234,502],db_attribut:[45,85,207,234,289,397,406,466,500,502,505],db_attribute_categori:354,db_attribute_kei:354,db_attributes__db_kei:146,db_attributes__db_value__gt:146,db_attrtyp:[464,515],db_attryp:36,db_categori:[67,146,464,467,508,515],db_category__iequ:67,db_cmdset_storag:[207,286,397,500,505],db_data:[467,508,515],db_date_cr:[67,207,234,277,286,390,397,406,464,466,500,502,504,505,506,515],db_desc:[277,406,512],db_destin:[286,397,500,505],db_destination__isnul:173,db_destination_id:397,db_entrytext:[390,504,515],db_header:[234,502],db_help_categori:[390,504,515],db_help_dict:225,db_help_top:540,db_hide_from_account:[234,502],db_hide_from_object:[234,502],db_hide_from_receiv:234,db_hide_from_send:234,db_home:[286,397,500,505,515],db_home__db_kei:512,db_home__id:512,db_home_id:397,db_index:67,db_interv:[277,406,506,512,515],db_is_act:[277,406,512,515],db_is_bot:[207,500,512],db_is_connect:[207,500,512],db_kei:[34,48,49,67,118,137,145,146,149,256,277,286,390,407,423,464,466,467,500,502,504,505,506,507,508,512,515,532],db_key__contain:48,db_key__exact:146,db_key__icontain:[67,146],db_key__iexact:146,db_key__in:146,db_key__startswith:48,db_locat:[34,49,146,149,286,397,500,505,515],db_location__db_kei:[505,512],db_location__db_tags__db_key__iexact:146,db_location__id:512,db_location__isnul:173,db_location_id:397,db_lock_storag:[234,277,286,390,464,466,500,502,504,505,506],db_messag:[234,502],db_model:[464,467,508],db_obj:[277,406,473,506],db_obj__db_kei:512,db_obj__id:512,db_obj_id:406,db_object_subscript:[234,502],db_permiss:67,db_persist:[277,406,506,512,515],db_properti:421,db_protototyp:402,db_receiver_extern:[234,502],db_receivers_account:[234,502],db_receivers_accounts__db_kei:502,db_receivers_object:[234,502],db_receivers_objects__db_kei:502,db_receivers_script:[234,502],db_receivers_scripts__db_kei:502,db_repeat:[277,406,506,515],db_sender_account:[234,502],db_sender_accounts__db_kei:502,db_sender_extern:[234,502],db_sender_object:[234,502],db_sender_objects__db_kei:502,db_sender_script:[234,502],db_sender_scripts__db_kei:502,db_sessid:[286,396,397,500,505],db_start_delai:[277,406,506,515],db_strvalu:464,db_tag:[146,207,234,390,397,406,466,467,500,502,504,505],db_tags__db_categori:[130,146,512],db_tags__db_kei:[130,146,502,512],db_tags__db_key__iexact:146,db_tags__db_key__in:130,db_tagtyp:[467,508,512,515],db_text:67,db_typeclass_path:[67,173,277,286,397,466,492,500,502,505,506,512,515],db_valu:[34,36,146,423,464,507,515,518],dbef:[218,405,489],dbentri:225,dbhandler:532,dbholder:464,dbid:[48,205,223,466],dbid_to_obj:492,dbmodel:465,dbobj:[13,464],dbobject:[13,465,466],dbprototyp:[218,402],dbref:[9,14,30,33,35,41,48,55,63,92,95,99,118,135,144,149,155,164,170,174,204,206,207,216,218,223,233,234,305,322,329,331,340,350,372,380,393,396,397,398,403,405,406,408,465,466,472,479,489,492,545],dbref_search:[206,396,405,465],dbref_to_obj:492,dbrefmax:218,dbrefmin:218,dbsafe_decod:488,dbsafe_encod:488,dbserial:[6,13,201,202,407,468,545],dbshell:[9,67,182,199],dbstore:353,dbunseri:473,ddesc:133,deactiv:[91,123,139,171,185,223,316,370,476],dead:[46,158,354,370,371,454,457,483],deadli:155,deal:[16,18,28,31,44,46,53,54,55,70,78,79,82,92,123,137,142,157,162,164,175,178,194,204,241,247,283,308,309,310,311,312,337,338,380,397,398,455,466,469,486,543,545],dealt:[226,310,311],dealth:310,death:[28,156,162,173,545],death_msg:370,death_pac:370,debat:142,debian:[11,181,182,185,187],debuff:[112,354],debug:[1,7,15,19,28,32,42,53,73,78,80,95,104,142,150,151,189,209,213,217,228,273,274,369,380,400,416,421,427,428,439,461,470,476,485,492,545],debugg:[3,16,199,201,545],dec:[64,77],decemb:191,decend:209,decent:[5,349],decic:[106,349],decid:[15,16,22,28,30,44,46,67,68,86,95,96,104,114,124,126,135,137,141,156,162,164,175,191,194,197,209,283,308,394,477,545],decis:[47,90,158,162,515],declar:[60,488],declared_field:[500,501,502,504,505,506,508,532],declared_filt:512,declin:[28,79,283],decod:[16,440,469,492,540],decode_gmcp:440,decode_msdp:440,decoded_text:492,decompos:177,decompress:[425,488],deconstruct:[155,229,248,279,294,313,335,351,353,360,442,516],decor:[11,22,45,86,95,96,97,118,128,207,280,397,398,405,406,413,425,426,466,472,476,477,490,492,545],decoupl:[75,402],decoupled_mut:13,decreas:[157,311,372,474],decrease_ind:474,dedent:[27,31,492,545],dedic:[39,95,151,152,162,187,191,545],deduc:474,deduce_ind:474,deduct:[141,162,308,309,310,311,312],deem:[11,72,119,134,235,536,538,543],deep:[31,147,180,545],deeper:[24,77,113,138,155,386,545],deepest:218,deepli:[13,95,104],deepsiz:492,def:[3,5,8,13,19,20,22,27,28,30,32,33,34,37,39,41,42,45,48,54,62,76,79,82,85,86,88,91,95,99,103,106,109,110,112,116,117,120,124,125,126,127,128,129,130,131,132,133,134,135,136,137,139,140,141,142,143,149,150,151,152,153,161,162,164,165,167,170,171,172,173,174,176,177,178,180,188,241,266,270,275,289,316,322,325,329,343,350,354,401,445,458,474,476,477,479,490,492],def_down_mod:310,defafultobject:149,defalt_cmdset:188,default_access:[13,396,405,464,472],default_categori:389,default_charact:[93,296],default_client_width:30,default_cmd:[4,18,76,79,82,83,88,91,95,103,106,109,110,118,121,125,126,127,128,129,131,134,135,136,139,143,150,164,201,241,250,266,286,299,316,322,325,343,350,545],default_cmdset:[25,44,76,79,82,83,88,90,91,92,93,95,99,102,103,106,109,110,113,126,129,131,134,135,136,139,148,149,150,161,165,212,241,266,286,293,302,308,309,310,311,312,316,322,325,343,350,380,386],default_command:[126,148],default_confirm:[218,305],default_create_permiss:49,default_error_messag:488,default_help_categori:[31,225,388,540],default_hom:41,default_in:51,default_kei:[112,354],default_kwarg:[30,479],default_list_permiss:49,default_out:51,default_pass:[206,472],default_screen_width:22,default_set:[8,148,167],default_sit:523,default_transaction_isol:182,default_unload:51,default_weight:[118,338],default_xyz_path_interrupt_msg:331,defaultaccount:[12,48,121,123,149,150,201,204,205,219,398,490,515,532,536],defaultchannel:[18,48,121,149,201,223,232,537],defaultcharact:[13,37,48,67,76,82,93,95,112,121,126,134,135,136,139,149,150,161,162,165,201,204,220,241,286,296,308,309,310,311,312,350,353,354,398,464,490,532,538],defaultdict:407,defaultexit:[37,48,95,118,121,141,149,201,322,325,329,340,371,398,490],defaultguest:[121,201,204],defaultmod:485,defaultobject:[0,4,13,30,37,48,67,95,112,120,121,123,140,141,145,147,149,152,153,161,170,171,174,201,204,275,286,309,312,350,354,362,364,366,371,398,466,490,515,532,543,545],defaultpath:492,defaultroom:[37,48,95,118,121,130,132,133,141,149,176,201,276,316,329,340,350,372,398,490],defaultrout:[514,517],defaultscript:[42,48,121,133,149,164,173,174,201,205,247,257,277,283,305,308,309,310,311,312,329,339,349,359,382,402,408,409,449,480,490],defaultsess:[150,221],defaulttyp:461,defaultunloggedin:[150,222],defeat:[90,155,156,162,164,308,309,310,311,312,370,545],defeat_msg:370,defeat_msg_room:370,defend:[28,155,164,308,309,310,311,312,371,398],defens:[114,157,164,308,309,310,311,312],defense_valu:[308,309,310,311,312],defer:[19,22,54,128,177,207,209,228,234,316,325,390,397,398,406,410,413,423,425,426,457,461,464,466,467,484,485,500],deferredlist:461,defin:[2,3,4,5,6,7,8,12,13,14,15,19,25,27,31,32,37,39,41,47,48,49,51,53,54,55,59,60,62,65,68,70,72,73,76,77,78,82,83,84,86,92,95,96,97,99,106,112,113,121,122,123,124,125,126,129,131,132,133,134,135,136,137,139,141,142,143,144,146,148,150,151,152,156,158,161,162,165,169,170,171,174,175,177,179,195,201,203,207,209,211,212,213,215,218,224,225,226,228,229,230,232,233,234,239,241,244,247,250,256,257,260,273,279,286,292,305,310,311,316,337,343,349,350,354,359,366,371,372,380,382,386,387,388,389,390,392,393,394,395,396,397,398,402,403,405,406,409,411,412,413,416,423,426,447,448,455,456,457,460,463,464,465,466,467,469,470,471,474,476,479,480,484,487,489,492,496,502,504,505,515,518,525,532,540,541,545],define_charact:28,definin:151,definit:[3,12,15,22,31,36,37,39,41,47,54,55,59,68,85,95,97,118,122,130,137,140,148,161,211,213,218,226,233,254,266,289,305,371,392,394,397,402,403,408,470,472,476,479,488,545],deflist:461,degre:[31,154],deindent:492,del:[13,26,39,55,95,108,112,128,135,155,161,164,216,218,302,305,316,353,354,466],del_callback:[255,257],del_detail:316,del_pid:416,delai:[22,26,85,92,97,104,108,110,127,173,228,247,257,289,325,364,371,380,410,411,428,434,457,471,492,545],delaliaschan:266,delayed_import:457,delchanalia:266,delcom:[103,135,143,266],deleg:[207,234,390,397,406,464,466,467,484],delet:[8,9,11,12,13,14,18,20,26,27,28,30,33,36,37,42,44,45,46,50,55,63,76,80,86,95,112,118,124,148,149,150,155,161,164,170,182,185,192,193,198,204,212,215,216,217,218,223,224,225,228,232,234,254,255,257,258,266,276,280,289,292,299,302,305,316,322,339,353,354,371,390,394,398,402,405,407,408,409,410,411,422,434,455,464,466,469,470,476,483,500,501,508,513,517,533,538,542,543],delete_attribut:464,delete_default:[20,212],delete_dupl:280,delete_prototyp:402,delete_script:405,deleteobject:77,deletet:316,deleteview:542,deliber:[3,72,157,492],delic:[83,286],delimit:[64,142,226,470,545],deliv:[191,299,350],delpart:305,delresult:305,deltatim:492,delux:191,demand:[42,47,91,129,135,156,158,162,171,191,204,232,316,354,398,458,471],demo:[53,76,90,104,122,138,154,155,160,163,166,168,180,369,476,545],democommandsetcomm:369,democommandsethelp:369,democommandsetroom:369,demon:41,demonin:492,demonstr:[76,92,97,124,161,175,177,241,310,376,380],demowiki:124,deni:[18,181,194,256,260,545],denot:[8,133,178,337,470],denounc:475,depart:[95,132],depend:[5,6,7,13,15,16,18,19,20,22,28,30,32,35,42,44,47,48,51,54,55,56,60,62,64,65,68,76,86,90,91,95,96,97,106,108,112,117,118,119,122,123,124,132,134,135,137,141,148,149,150,155,156,158,161,162,164,165,170,172,177,178,182,185,189,190,191,193,194,195,203,209,211,213,215,228,241,255,316,329,337,338,340,343,349,354,364,388,394,398,402,411,416,436,439,445,447,457,466,467,474,476,477,479,492,496,545],depict:276,deplet:[112,310,354],deploi:[96,120,191,194,545],deploy:[2,7,78,120,180,191,193,197],depmsg:485,deprec:[19,28,201,202,403,412,469,476,485,492,545],deprecationwarn:415,depth:[2,17,31,56,118,155,225,386,391,403],dequ:[13,459],deriv:[8,48,69,133,182,185,187,193,270,469,493],desc1:28,desc2:28,desc3:28,desc:[15,18,26,32,33,34,37,41,42,50,76,82,86,91,95,99,102,103,104,117,118,125,134,135,137,140,141,143,144,149,157,164,170,173,178,212,215,218,223,225,229,233,235,241,266,275,286,292,293,302,305,311,316,322,329,341,352,364,386,398,405,406,414,470,472,474,475,476,532,538,543,545],desc_add_lamp_broken:364,desc_al:370,desc_closed_lid:364,desc_dead:370,desc_open_lid:364,descend:[146,532],descer:545,describ:[10,11,13,14,15,18,20,22,28,33,39,40,41,48,50,51,53,60,64,67,68,70,73,75,76,90,95,96,112,118,119,120,122,123,125,129,135,136,137,141,143,144,148,149,151,152,157,161,164,170,177,180,182,185,188,190,191,199,211,218,222,224,234,247,266,274,286,292,293,311,316,337,338,350,354,364,382,398,403,409,413,434,436,439,449,476,491,492,505],descripion:370,descript:[0,8,15,16,18,28,32,41,46,50,53,58,72,73,76,79,82,83,95,96,97,99,101,102,104,106,112,113,117,118,120,122,125,130,132,134,135,141,144,147,156,157,170,175,177,178,184,191,215,218,223,224,232,233,241,266,270,274,283,286,302,316,317,322,329,337,340,350,353,354,362,364,369,370,371,372,382,386,398,405,406,470,472,476,486,487,500,505,514,518,545],description_str:170,descriptor:464,descvalidateerror:302,deseri:[6,13,486,515],deserunt:29,design:[0,15,22,37,41,46,53,56,69,72,82,86,104,115,122,130,134,142,146,148,156,157,158,159,161,170,171,172,177,180,182,212,218,241,256,350,371,376,398,470,486,492,545],desir:[19,46,47,51,60,69,84,85,118,124,127,128,132,134,135,142,165,174,177,218,232,233,244,280,289,349,394,416,461,464,472,478,493],desired_effect:293,desired_perm:394,desk:161,desktop:[16,56],despit:[13,14,44,123,134,139,180,185,372],dest:[270,398],destin:[22,32,37,41,50,76,95,97,99,110,118,126,132,141,142,153,161,170,174,218,308,309,310,311,312,322,325,331,332,337,338,340,371,372,376,396,397,398,403,472,518,538],destinations_set:397,destroi:[18,26,37,86,97,103,105,108,143,144,164,194,204,205,218,223,266,305,310,398],destroy:[104,109,322],destroy_channel:223,destroy_compon:275,destroy_lock:513,destruct:[20,211],detach:7,detail:[0,5,9,11,12,13,16,18,22,28,31,33,37,41,42,44,48,50,55,57,60,68,72,73,75,76,82,86,95,96,104,106,119,120,123,129,135,142,144,148,149,150,151,155,156,157,159,164,169,170,172,178,182,185,191,201,202,212,213,218,232,235,241,275,292,305,309,314,316,317,327,337,350,354,372,382,388,390,391,403,410,418,419,455,457,466,469,474,479,492,495,500,505,517,518,533,540,542,543,545],detail_color:218,detail_desc:317,detailkei:[316,372],detailview:[540,542],detect:[2,18,20,22,37,44,68,120,139,156,161,172,194,210,213,428,479,517,545],determ:465,determin:[5,12,14,16,18,19,20,22,27,28,29,31,33,36,41,42,51,65,86,95,99,106,118,124,128,130,131,132,140,141,144,150,161,162,164,165,169,182,185,199,204,211,212,213,215,223,225,226,232,283,308,309,310,311,312,325,338,349,350,371,386,388,390,394,398,402,440,464,465,466,469,474,477,479,485,490,492,496,500,502,505,512,513,521],determinist:338,detour:[65,125,148,152,457],dev:[31,119,122,123,134,151,159,180,182,185,187,188,191,192,544],devel:[148,229],develop:[0,2,3,5,6,7,8,11,13,16,18,19,22,30,31,39,41,49,51,53,56,57,58,64,67,68,69,73,75,80,95,104,114,119,120,122,123,126,133,135,142,144,145,147,148,149,150,151,152,156,158,159,167,169,170,175,177,182,184,185,188,189,191,195,198,213,216,217,223,224,225,228,232,254,255,260,273,376,388,390,398,403,462,466,467,470,476,544,545],deviat:159,devoid:469,dex:[13,28,135,149,151,157,475],dexter:[157,308,309,310,311,312],diagnos:[6,129],diagon:[118,335],diagram:48,dialog:51,dialogu:[95,97,157,545],dice:[28,86,142,152,158,162,164,185,201,202,235,341,545],dicecmdset:343,dicenum:343,dicetyp:343,dict:[8,13,14,20,28,30,31,41,42,45,49,53,68,78,86,87,96,97,99,106,112,118,121,126,143,204,205,211,213,218,225,232,247,254,257,260,277,286,292,310,312,316,337,338,339,349,350,354,362,372,376,377,380,386,388,391,398,400,401,402,403,409,411,413,414,416,421,425,426,427,429,434,436,439,444,445,456,457,459,465,470,471,473,475,476,477,479,487,490,492,532,537,540,541,543],dict_of_kwarg_convert:30,dictat:[20,136,171],dictionari:[6,13,14,20,33,41,54,78,87,91,92,95,97,99,104,106,122,126,132,133,136,137,162,164,178,216,218,247,254,257,260,286,310,311,316,329,349,350,372,376,377,378,380,386,394,403,410,421,434,443,455,456,457,459,465,469,471,475,476,483,486,487,488,492,532,541,543,545],dicument:119,did:[11,12,64,76,123,125,128,134,142,143,144,149,150,151,161,165,170,195,204,283,398,410,467,488,492,497],did_declin:283,didn:[3,11,28,33,74,76,118,120,131,132,135,142,143,144,145,149,150,151,152,155,169,174,175,177,189,193,195,339],die:[7,142,155,158,162,171,343,349,457],dies:[158,370],diff:[11,190,343,403],differ:[3,5,7,8,12,13,14,15,16,19,20,22,27,28,30,31,33,34,36,41,42,44,45,46,47,51,56,57,60,62,63,65,68,70,71,72,74,75,76,80,82,85,86,90,95,96,97,98,104,106,112,114,117,118,119,120,122,123,125,126,130,131,132,134,135,136,137,138,140,142,143,144,145,146,148,149,150,151,152,154,156,159,161,162,164,169,170,172,173,174,175,177,180,181,183,184,185,193,194,198,199,201,204,209,211,212,215,218,225,227,228,230,232,241,247,251,257,258,270,274,275,278,289,292,299,308,309,310,311,312,325,329,335,337,338,340,343,350,354,382,386,396,398,400,403,405,406,411,414,418,440,445,447,464,466,470,472,476,479,485,488,492,496,497,500,501,508,512,517,518,541,543,545],differenti:[104,106,113,114,133,134,135,148,149,157,158,286,350,386,398,479,492,496],differnt:275,difficuli:13,difficult:[5,124,130,158,177,194,311,312],difficulti:[86,177],dig:[5,20,22,26,37,41,62,74,80,97,109,118,134,135,143,144,148,150,155,165,174,218,273,322,448],digit:[30,55,60,107,191,382,460,469,479,485],digitalocean:[187,191],dijkstra:[118,337,338],diku:[95,104,122,123,138,545],dikumud:72,dime:69,dimens:[122,132],dimension:[118,135],dimenst:152,diminish:60,dimli:170,dinner:[96,158],dip:151,dir:[2,9,11,42,53,64,75,78,90,120,123,125,135,138,149,151,152,178,180,182,184,185,187,190,191,193,485,492,521,545],direcetli:479,direct:[9,20,28,32,41,51,54,55,58,68,76,95,97,99,118,119,131,132,135,137,144,164,167,170,172,174,181,191,193,218,256,275,329,331,335,337,338,339,340,377,394,396,409,416,476,478,479,485,489,490,492,545],direction_alias:[118,338],direction_nam:338,direction_spawn_default:338,directli:[3,4,9,11,12,13,14,15,19,22,27,28,31,33,35,37,41,42,48,50,51,52,53,60,62,68,77,79,86,95,96,104,106,112,117,118,119,120,122,123,125,128,129,131,133,135,136,143,144,145,146,147,148,149,151,152,153,156,164,165,170,172,181,182,189,191,193,195,199,206,213,229,233,241,260,270,273,278,280,283,293,311,312,338,339,340,343,350,353,354,364,372,386,389,394,396,397,398,402,405,406,422,427,436,439,444,447,449,455,464,466,470,472,476,477,479,490,492],director:[106,350,398,545],directori:[1,2,5,7,8,9,10,11,14,19,48,51,53,73,75,77,95,104,119,123,124,126,135,136,137,147,148,165,169,177,178,181,182,185,190,193,218,376,416,436,437,461,470,485,492,545],directorylist:461,dirnam:416,dirti:122,disabl:[5,7,8,27,33,51,60,71,78,92,97,112,113,124,126,139,161,183,185,213,229,270,350,353,354,364,380,386,394,402,439,459,477,479,483,493,545],disableloc:439,disableremot:439,disadvantag:[106,135,158,164,191,312],disambigu:[189,213,398,466],disappear:194,discard:469,disconcert:159,disconnect:[6,9,12,13,18,40,44,45,46,51,55,62,134,158,164,165,198,199,204,215,218,223,226,228,232,398,426,427,428,434,435,436,439,444,445,448,454,455,456,457],disconnect_al:434,disconnect_all_sess:457,disconnect_duplicate_sess:457,disconnect_session_from_account:204,discontinu:183,discord:[75,119,159,180,185,189],discordia:69,discourag:[123,158,190],discours:158,discov:[142,155,158,464],discoveri:377,discret:[35,148,518],discrimin:194,discuss:[0,18,22,53,104,118,119,122,124,126,137,153,158,164,182,185,545],discworld:68,disengag:[164,204,308,309,310,311,312],disguis:[58,104,106],disk:[11,13,19,67,69,78,193,199,337,349,376,388,400],dislik:134,disonnect:13,dispel:175,displai:[3,5,17,20,22,27,28,31,33,37,42,49,51,52,53,59,60,65,68,73,76,91,94,95,96,97,104,118,120,126,129,135,137,139,140,141,142,149,156,161,164,165,169,170,177,178,194,195,204,213,215,218,223,225,228,230,241,250,251,255,257,270,274,278,280,283,286,299,316,329,335,337,338,340,346,350,354,364,369,371,372,380,386,388,398,402,403,414,416,433,451,454,459,466,467,474,475,476,477,478,486,487,488,490,491,492,493,502,504,506,507,508,515,532,537,541,542,543,545],display:411,display_all_channel:223,display_buff:474,display_choic:241,display_formdata:380,display_help:474,display_helptext:[400,476],display_len:492,display_map:335,display_met:[94,346],display_nam:479,display_nodetext:476,display_subbed_channel:223,display_symbol:[118,337,338,340],display_symbol_alias:338,display_titl:241,dispos:[105,170,305],disput:164,disregard:22,dissect:143,dist:[118,185,335,337],distanc:[8,19,48,96,104,106,114,118,123,130,132,145,311,312,335,337,349,398,492,510],distance_inc:312,distance_to_room:130,distant:[132,316,372],distinct:[44,74,122,123,146,312,512],distinguish:[76,213,312,386],distribut:[3,6,8,9,16,18,20,75,77,123,147,179,181,182,185,232,233,234,350,469,472,492,495],distribute_messag:232,distro:[181,182,185,187,189],disturb:[19,74],distutil:185,distutilserror:185,ditto:185,div:[17,30,41,51,56,120,167],dive:[76,152,153,154,185,545],diverg:65,divid:[14,30,80,123,137,247,372,492],dividend:247,divis:353,divisiblebi:137,divisor:247,divivid:157,django:[0,2,8,9,12,13,16,42,45,46,48,49,50,51,52,53,64,67,70,75,77,99,112,122,124,126,130,137,138,148,149,153,154,161,162,167,169,173,178,180,182,185,194,195,204,206,207,213,230,232,234,239,251,335,340,354,388,390,396,397,402,405,406,415,416,422,423,436,442,444,445,452,458,459,460,461,464,466,467,470,473,477,482,483,484,488,490,492,497,498,499,500,501,502,503,504,505,506,507,508,512,513,515,517,518,523,524,527,532,536,537,538,540,541,542,543,545],django_admin:533,django_filt:[512,518],django_nyt:124,djangofilterbackend:518,djangonytconfig:124,djangoproject:[64,149,182,532],djangowebroot:461,dmg:162,dnf:[181,185,187],do_attack:370,do_batch_delet:464,do_batch_finish:464,do_batch_update_attribut:464,do_craft:[86,292],do_create_attribut:464,do_delete_attribut:464,do_flush:[466,483],do_gmcp:440,do_hunt:370,do_mccp:429,do_msdp:440,do_mssp:430,do_mxp:431,do_naw:432,do_nested_lookup:218,do_not_exce:126,do_noth:369,do_patrol:370,do_pickl:473,do_power_attack:[85,289],do_search:225,do_sit:161,do_stand:161,do_task:[228,410,492],do_task_act:228,do_unpickl:473,do_update_attribut:464,do_xterm256:469,doabl:15,doc:[8,10,13,17,18,22,24,28,31,41,48,50,53,56,64,67,72,77,78,89,96,97,100,118,119,121,123,126,138,146,147,148,149,152,157,159,161,169,180,182,198,199,201,218,228,270,331,382,398,427,492,532,544,545],docker:[180,185,191,197,198,545],dockerfil:193,dockerhub:193,docstr:[31,32,126,143,149,150,161,213,218,229,241,255,270,273,293,337,349,350,354,364,372,386,391,447,476,545],document:[0,1,4,5,7,8,11,17,24,26,29,31,42,48,49,50,52,53,56,60,61,64,67,73,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,122,123,126,128,134,135,138,147,148,149,151,152,154,155,165,167,169,170,174,177,180,182,183,191,194,195,197,198,212,226,241,270,289,355,382,391,464,467,475,483,512,537,540,545],dodg:309,dodoo:77,doe:[0,8,12,13,18,20,22,28,30,31,33,35,37,39,41,42,46,48,51,52,53,58,59,60,62,68,70,72,74,75,77,84,86,88,89,90,99,102,104,113,117,118,119,120,122,123,124,125,126,128,130,132,133,134,135,137,141,142,143,144,147,148,149,151,152,155,156,157,161,162,164,165,169,170,171,172,174,175,176,177,179,182,183,184,185,187,193,195,199,204,205,215,226,228,230,244,251,270,273,280,286,289,292,302,305,308,309,310,311,312,316,329,337,338,354,371,372,386,398,402,403,407,409,410,415,416,420,421,422,425,428,436,437,443,464,466,471,476,479,485,488,490,492,524,532,540,543,545],doesn:[0,2,9,13,14,16,22,28,30,35,37,48,51,52,53,67,68,75,76,86,95,96,97,118,119,124,128,130,131,132,134,137,142,143,149,151,152,156,158,161,162,165,169,170,174,175,177,179,185,188,189,190,191,194,198,199,212,223,232,234,256,257,289,292,293,310,316,337,338,350,394,398,416,429,436,440,464,469,476,487,492,500],doesnotexist:[204,205,207,232,234,247,257,275,276,277,283,286,296,305,308,309,310,311,312,316,322,325,329,339,340,349,350,359,362,364,366,370,371,372,382,390,396,397,398,402,406,409,423,449,464,467,472,480,484],doff:309,dog:19,doing:[2,5,6,8,12,13,19,20,22,26,28,37,44,47,48,51,53,54,58,60,86,95,96,113,118,119,120,123,124,128,130,132,134,135,137,143,146,149,151,152,157,158,163,175,177,178,180,191,199,204,215,232,256,275,280,283,286,292,308,309,310,311,312,329,350,362,370,371,386,393,398,411,447,476,483,488,497,523,545],doll:[86,292],dolor:29,dolphin:143,dom:51,domain:[53,122,181,187,191,194,206,472],domexcept:191,domin:158,dominion:75,dompc:75,don:[0,3,5,6,7,8,9,11,13,18,19,20,22,27,28,30,31,33,39,42,44,48,53,54,60,64,65,67,68,73,74,75,76,77,80,86,95,96,97,104,106,112,114,115,117,118,119,120,123,124,125,126,128,129,130,131,135,136,137,138,139,141,142,143,144,146,148,149,150,151,152,154,155,156,157,158,159,162,164,165,167,169,170,175,176,177,178,182,184,185,187,189,190,191,194,195,204,205,211,212,218,223,224,225,226,227,230,232,241,256,260,266,270,275,276,289,293,309,310,311,329,331,337,338,343,349,350,353,354,364,372,394,397,398,402,403,411,421,428,433,434,439,441,448,455,462,466,469,470,476,483,485,488,492,501,513,532,541,545],donald:5,donat:[191,545],done:[0,2,5,8,9,11,13,20,22,28,30,31,33,36,45,47,50,51,52,53,54,64,69,75,76,95,106,108,117,118,119,120,122,123,124,125,126,128,129,130,131,132,133,134,135,136,137,140,141,142,144,148,149,151,152,158,161,162,164,165,169,171,172,173,174,175,177,182,185,187,191,193,199,204,213,215,223,234,250,283,312,329,337,339,343,349,394,397,398,409,410,411,416,420,429,433,435,437,441,445,451,454,455,457,462,464,469,470,477,479,483,490,492,497,541,545],donoth:409,dont:438,doom:[118,403],door:[19,22,31,33,37,76,95,97,104,109,118,132,141,144,153,156,194,218,280,321,322,338],doorwai:[109,322],dot:[4,53,76,212,218,470,492],dotal:[469,491],dotpath:492,doubl:[6,76,120,134,151,177,211,230,491,492],doublet:[211,212],doubt:[76,118,270],down:[2,4,5,7,13,20,22,27,28,51,55,67,69,76,81,86,95,97,113,114,117,120,122,124,125,128,130,132,134,135,139,141,142,147,151,154,155,156,158,160,161,162,163,165,166,168,169,170,185,191,193,194,195,204,218,223,228,257,275,289,309,310,329,335,337,338,371,376,386,391,393,398,403,409,411,416,418,425,426,433,434,454,455,457,469,477,478,492,545],download:[0,9,10,11,75,123,147,180,182,185,189,190,191,193,198],downmaplink:[118,338],downtim:[128,194,480],downward:215,dozen:[69,122,126],drag:51,dragon:[133,143,145,149,150,152,158],drain:[112,354],drama:31,dramat:[146,156,161,402,403],dramati:31,drape:[83,286],draw:[15,77,99,104,118,120,130,132,162,478],draw_room_on_map:132,drawback:[15,28,67,112,127,128,135,145,158,161,162,182,354,470],drawn:[132,135,170],drawtext:162,dread:99,dream:[0,72,122,156,159],dress:[83,286],drf:[512,515],drift:158,drink:[157,275,464,466],drinkabl:275,drive:[11,30,57,75,77,123,125,147,152,156,158,159,174,177,185,193],driven:[104,111,126,157,158,159,165,180,366,400],driver:182,drizzl:[42,176],drop:[9,15,22,26,33,35,36,37,51,62,67,68,75,77,80,95,101,105,108,111,119,122,125,126,134,135,137,141,143,144,145,148,149,150,151,158,161,171,172,174,182,191,218,224,230,286,305,309,312,364,366,398,425,466,470,492],drop_whitespac:478,dropbox:77,dropdown:7,droplet:187,dropper:[309,312,398],drum:191,dry:187,dtobj:492,duck:[19,151],duckclient:183,due:[5,20,22,45,48,55,62,74,76,123,128,135,136,142,151,175,185,191,195,212,228,397,398,418,454,457,469,485,501],dufresn:77,duh:69,dull:[0,95,144,170],dum:391,dumb:[144,457,469],dummi:[5,11,13,22,33,75,86,151,158,184,269,292,350,394,416,421,434,447,448,455],dummycharact:353,dummycli:447,dummyfactori:447,dummyrunn:[201,202,412,416,434,446,448,450,545],dummyrunner_act:447,dummyrunner_actions_modul:447,dummyrunner_echo_respons:447,dummyrunner_set:[5,201,202,412,416,446,545],dummyrunner_settings_modul:5,dummyrunnercmdset:447,dummysess:457,dump:[28,376,425],dungeon:[46,118,122,148,153],dungeonmap:118,dupic:20,duplic:[20,211,218,225,411,466,485],durat:[54,127,176,228,289,310,486,493,545],dure:[6,13,20,33,44,45,51,62,63,73,74,75,91,95,99,115,118,120,128,152,156,158,164,165,169,176,180,185,193,204,211,223,229,270,273,292,305,316,337,338,370,372,394,396,410,425,435,470,472,476,485,505,532,545],duti:123,dwarf:170,dwarv:158,dying:[158,308,309,310,311,312],dynam:[8,12,30,42,47,51,52,53,58,67,95,104,112,113,118,120,140,146,148,167,170,177,191,204,207,213,225,228,229,234,250,308,309,310,311,312,335,338,340,350,354,380,386,389,390,397,398,402,406,411,464,466,467,472,474,476,484,486,492,500,505,521,543,545],dyndns_system:191,each:[2,3,5,6,8,12,13,14,18,19,20,22,24,28,30,31,33,41,44,46,47,48,50,51,53,54,57,60,62,65,67,69,74,76,79,83,84,86,90,91,92,95,97,99,104,105,106,112,114,117,118,120,122,123,124,128,130,132,133,134,135,136,137,140,141,143,146,147,149,150,151,152,154,156,162,163,164,165,169,170,174,175,176,177,193,195,204,210,211,212,216,218,223,225,227,232,244,275,280,283,286,289,292,305,308,310,311,312,316,329,335,337,338,339,340,349,350,354,360,364,380,386,388,390,391,394,397,398,401,402,403,408,411,418,421,434,436,439,443,448,455,456,457,464,466,467,469,470,472,474,475,476,477,478,479,483,490,492,515,518,521,545],eagl:161,eaoiui:[106,349],earler:144,earli:[2,159,308,309,310,311,312,418],earlier:[2,7,14,18,20,28,31,32,75,112,123,135,136,141,143,150,151,152,156,165,167,174,178,184,338,354,388,421],earn:159,earnest:[153,158],earth:[140,194],eas:[20,22,67,130,149,175,191,193],easi:[0,7,9,14,17,22,28,31,37,42,48,53,54,58,68,69,70,74,76,83,90,96,97,104,112,118,120,122,128,130,133,136,137,139,140,141,143,150,151,152,156,158,159,161,162,164,165,170,172,175,177,178,180,182,187,189,191,193,212,216,278,286,292,354,380,386,476,483,545],easier:[13,28,31,41,42,49,50,53,54,55,67,76,90,95,106,113,118,119,122,124,126,130,133,134,135,136,137,142,143,146,149,150,151,152,154,155,156,158,159,161,162,169,175,191,218,293,308,309,310,311,312,331,340,349,371,386,458,464,467,492],easiest:[9,11,16,19,49,53,55,64,73,77,86,96,97,118,119,126,129,135,149,165,177,185,187,376,466],easili:[7,11,14,15,17,18,19,22,28,31,33,35,41,44,45,46,51,53,55,58,64,65,68,69,74,82,83,86,94,95,96,97,104,109,112,113,119,120,124,126,127,130,132,135,136,141,142,144,146,148,149,150,153,155,156,157,158,162,165,167,169,170,177,185,191,192,193,194,223,232,234,241,256,270,283,286,308,309,310,311,312,322,331,346,349,354,380,386,388,389,390,411,470,476,487],east:[77,99,118,126,131,132,170,218,337,338,372],east_exit:372,east_room:99,east_west:170,eastern:[136,170,337,339],eastward:372,eat:[95,273,275],echo1:128,echo2:128,echo3:128,echo:[0,2,19,22,27,28,30,41,54,55,58,74,81,88,101,120,127,128,131,132,143,144,150,151,157,164,165,172,176,186,188,191,192,193,195,199,204,205,216,218,223,228,286,331,343,350,362,370,371,372,398,414,421,436,439,474,476,490,492,545],echocmdset:143,echol:198,echowoo:143,econom:[67,122,148,149,152,158,180],economi:[42,69,156,162,173,283,545],ecosystem:193,edg:[11,19,56,118,293,337,338,478,490,492],edgi:132,edibl:275,edit:[0,6,7,9,11,13,14,15,18,22,25,26,31,33,39,41,49,51,52,62,64,67,73,75,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,124,126,129,133,135,136,137,139,149,154,158,169,170,177,178,180,182,184,187,190,193,195,216,218,225,228,241,242,251,254,255,257,258,302,305,380,394,398,400,402,403,464,474,504,505,513,532,538,542,543,545],edit_callback:[255,257],edit_handl:218,editcmd:76,editi:[112,354],editnpc:545,editor:[6,11,16,22,30,31,41,49,64,69,75,76,82,96,97,120,121,125,134,151,152,170,180,185,187,218,225,227,228,241,302,406,470,474,545],editor_command_group:474,editorcmdset:474,editsheet:135,edu:495,effect:[8,9,13,15,18,19,20,25,36,42,45,47,53,54,60,72,74,77,86,95,99,104,108,112,114,115,118,120,127,128,130,133,134,135,151,152,156,157,158,161,162,164,170,171,175,195,199,204,211,212,218,227,232,257,275,289,293,309,310,311,338,343,354,370,372,396,398,404,406,429,492,544],effici:[0,5,13,36,42,46,47,48,67,79,110,118,122,123,127,128,130,133,146,152,161,176,180,194,283,325,337,338,340,350,394,398,411,464,465,467,474,477],effort:[11,133,148,178,538],egg:[190,292],egg_info:185,egi:418,egiven:396,eight:275,eightbal:153,eirik:77,either:[5,6,9,11,14,17,19,20,22,28,30,33,39,41,42,44,46,48,51,53,55,58,59,65,75,80,82,95,96,97,98,104,106,109,118,119,120,124,128,130,131,132,133,134,135,137,142,143,145,146,148,149,151,152,155,158,161,162,164,165,170,174,175,182,191,194,199,204,205,211,212,213,218,223,233,241,254,260,292,299,308,311,312,322,337,338,339,340,349,350,354,364,386,394,398,401,403,406,408,409,411,414,425,437,441,448,465,466,467,476,478,479,485,487,489,492,495],elabor:[76,95,120,124,141,142,165],electr:191,eleg:119,element:[5,13,17,28,30,53,56,59,76,82,86,118,122,142,149,150,151,153,210,215,225,241,247,337,339,340,349,382,398,403,464,465,467,470,475,476,477,479,490,492],elev:[95,96,140,545],elif:[28,42,97,132,135,143,153,162,164,165,171],elig:[77,479],elimin:[193,469],elimit:492,ellow:[60,469],els:[3,11,12,18,19,22,28,31,33,34,39,42,47,51,53,54,55,57,58,75,76,77,79,85,86,95,96,97,117,120,125,126,128,129,130,132,135,137,139,140,141,142,143,144,150,151,153,156,159,161,162,164,165,170,171,173,174,177,178,182,191,194,223,229,283,286,289,308,309,310,311,312,329,380,382,397,445,466,476,492,545],elsennsometh:229,elsewher:[12,20,46,53,128,135,147,149,177,212,338,372,416,457,464],elv:158,elvish:[106,349],emac:[15,180],email:[11,23,35,104,123,148,153,154,185,187,198,204,206,249,251,252,472,486,492,493,500,532,545],email_login:[89,201,202,235,236,545],emailaddress:492,emailfield:[500,532],emb:[41,58,91,106,118,120,135,316,403],embark:174,embed:[30,41,48,53,71,118,148,157,225,232,337,401,475,479,492],emerg:[39,64,194],emi:[106,349],emit:[51,69,126,143,204,212,216,232,296,398,455,485],emit_to_obj:[212,398],emo:125,emoji:183,emot:[18,22,26,30,31,58,79,104,122,157,158,159,164,204,224,273,283,348,349,350,464,479,545],emoteerror:350,emoteexcept:350,empathi:293,emphas:120,emphasi:120,emploi:493,empti:[3,6,8,9,11,12,15,18,20,22,28,34,37,42,47,48,50,51,53,54,67,68,75,86,90,94,97,104,112,118,120,123,132,135,137,142,143,146,148,149,150,151,152,153,157,161,162,165,167,171,178,184,185,187,193,198,206,209,210,216,218,223,229,241,254,277,292,337,338,346,350,354,398,402,403,414,421,425,447,448,464,470,472,476,478,489,492,501,508],emptor:77,empty_color:346,empty_permit:[502,504,506,508,532],empty_symbol:337,empty_threadpool:461,emptyset:20,emul:[5,44,72,112,114,123,157,158,165,190,228,354,545],enabl:[7,51,60,77,78,85,92,175,178,181,182,183,188,193,194,204,239,289,350,353,380,439,493],enable_recog:350,enableloc:439,enableremot:439,enact:273,encamp:96,encapsul:486,encarnia:180,encas:474,enclos:[25,27,151,230,251,479],encod:[19,26,61,118,135,170,230,338,427,440,444,445,469,488,492,540,545],encode_gmcp:440,encode_msdp:440,encoded_text:492,encompass:19,encount:[212,338,396,479,493],encourag:[76,130,142,167,183],encrypt:[65,77,181,187,194,223,436,437,441,545],encumb:157,end:[0,5,9,11,14,15,19,20,22,27,28,30,31,33,36,41,44,45,51,54,57,59,60,62,64,65,67,68,69,73,74,75,76,77,80,95,102,104,106,113,114,117,118,120,122,123,125,126,127,128,130,135,136,137,139,142,144,146,148,150,151,152,154,155,157,158,161,162,164,165,172,174,175,177,178,181,182,184,186,187,191,193,198,204,205,211,212,218,224,225,233,275,278,283,286,293,302,308,309,310,311,312,337,338,346,350,366,372,386,389,420,427,428,436,439,440,447,450,455,459,461,465,469,470,472,476,477,478,479,485,492,541],end_convers:28,end_direct:338,end_turn:164,end_xi:[118,337],endblock:[53,137,167,177,178],endclr:479,endcolor:30,endcoord:335,endfor:[137,177,178],endhour:126,endif:[137,177,178],endless:53,endlessli:194,endpoint:[49,194,517,518],endsep:492,endswith:469,enemi:[13,28,41,128,155,156,164,310,311,312,370,371,372,545],enemynam:28,enforc:[8,22,39,54,60,156,162,175,436,439,477,478,490,538,545],enforce_s:478,engag:[122,312,370],engin:[2,8,22,28,31,37,74,76,90,104,123,133,150,155,162,169,180,182,194,195,197,209,212,225,227,228,271,292,372,377,389,416,427,433,436,439,444,454,456,470,472,496,545],english:[6,16,30,58,64,70,180,230,495,496],enhanc:[60,139,151,376,469,542],enigmat:144,enjoi:[7,142,155,156,159,185,545],enough:[3,8,18,33,34,36,46,47,69,86,117,118,119,120,122,123,124,125,128,130,134,135,137,141,142,143,146,147,149,150,152,156,161,165,169,175,185,187,191,212,218,292,329,338,349,364,382,476,477,478,490,545],enpoint:515,ensdep:492,ensur:[7,132,137,171,175,182,193,386,459,490,538],ensure_ascii:445,enter:[0,2,3,5,9,11,14,15,16,18,19,20,22,25,28,30,31,36,37,39,41,52,53,58,60,63,65,72,73,75,76,79,82,83,90,92,95,96,97,100,104,117,118,123,125,126,128,131,135,136,137,141,142,150,151,154,155,161,164,165,167,170,171,177,182,185,190,193,198,201,204,210,212,217,225,226,228,241,260,275,278,283,286,308,309,310,311,312,316,329,370,372,380,386,393,398,403,406,414,455,476,521,532,545],enter_guild:28,enter_nam:28,enter_wild:[117,329],enterpris:2,enthusiasm:159,enthusiast:158,entir:[8,13,14,15,19,22,27,28,30,31,33,41,47,48,53,54,57,67,69,76,95,96,104,105,106,113,118,128,132,137,142,147,148,151,156,158,165,169,170,191,241,270,337,338,339,340,349,350,386,394,398,402,403,466,467,470,476,478,483,492,541,545],entireti:[28,162,274,380,476],entit:[233,472,545],entiti:[8,13,18,19,28,30,31,33,34,35,36,37,39,41,42,44,45,46,48,50,53,58,118,121,123,145,146,147,148,149,153,156,161,164,175,203,204,213,218,223,228,232,233,234,275,292,322,339,340,350,362,388,390,391,393,396,398,400,401,402,403,404,405,406,407,409,411,457,464,465,467,472,476,477,479,482,489,492,508,518,545],entitiess:123,entitii:45,entitl:191,entranc:[118,170],entri:[11,16,19,20,22,24,28,33,45,53,99,124,126,135,137,142,143,147,149,153,158,174,183,184,185,189,204,213,225,226,229,275,292,308,309,310,311,312,346,382,386,387,388,389,390,391,394,398,411,435,448,459,464,470,472,474,476,478,485,486,489,492,493,504,512,515,518,533,537,540,545],entriest:215,entrypoint:193,entrytext:[31,137,388,389,390,472],enul:181,enumar:492,enumer:178,env:[416,426],environ:[1,2,8,9,14,52,75,77,120,123,124,126,140,151,156,158,159,185,186,191,193,194,228,229,242,267,279,284,290,294,306,313,317,328,335,351,360,369,416,426,442,451,470,476,490,516,533],environment:416,envvar:185,eof:436,epic:180,epilog:270,epoch:[19,136,480],epollreactor:461,epub:180,equal:[6,20,22,56,57,60,88,95,96,97,104,118,126,130,142,144,146,149,150,158,174,211,223,308,309,310,311,312,316,350,353,354,398,492],equip:[15,60,83,114,134,148,157,158,286,308,309,311,312],equival:[9,11,13,14,30,36,50,53,54,58,60,62,68,118,147,151,153,185,194,195,199,203,206,218,289,331,337,338,389,396,405,434,440,464,492,513,541],eras:[75,312],erik:77,err:[135,425,447,470],err_travers:[37,398],errback:[54,413,416,425,426,492],errmessag:211,errmsg:[165,485],erron:[70,165,425,478],error:[0,3,4,6,8,9,11,13,15,16,18,19,20,22,28,30,32,33,36,37,39,41,44,48,53,54,64,65,67,70,73,75,76,86,95,99,113,118,120,123,133,134,135,138,142,144,149,150,152,153,155,159,161,165,170,172,173,177,181,182,183,185,187,188,190,191,194,195,201,202,204,206,209,211,212,218,223,230,232,257,270,292,294,336,338,339,340,350,354,371,382,386,394,396,398,401,402,405,409,410,413,415,416,418,420,421,425,439,447,466,469,470,472,475,476,479,485,488,492,493,498,513,515,531,535,540,545],error_check_python_modul:416,error_class:[502,504,506,508,532],error_cmd:131,error_consumable_excess_messag:292,error_consumable_missing_messag:292,error_consumable_order_messag:292,error_msg:459,error_tool_excess_messag:292,error_tool_missing_messag:292,error_tool_order_messag:292,errorlist:[502,504,506,508,532],errorlog:181,escal:[12,39,57,158,215,393,467],escap:[30,60,90,104,118,137,224,228,270,273,276,469,479,491,532],escape_char:479,escaperoom:[90,276],escript:[76,82,241],esom:225,especi:[5,16,33,39,44,46,76,106,128,148,149,151,156,170,181,182,185,346,349,470],esqu:149,ess:29,essai:180,essenti:[7,58,70,127,132,133,148,158,180,187,190,233,416,472],est:[29,229],establish:[22,44,104,114,156,157,158,162,187,204,308,398,413,425,427,434,436,439,444,447,454,456],estim:[129,337,403,483],esult:398,etc:[0,8,11,12,13,18,19,22,25,28,30,31,33,34,35,36,37,39,41,42,44,45,48,50,51,52,53,55,58,62,65,67,68,69,71,76,77,80,86,87,90,92,94,95,104,106,109,112,118,119,120,121,122,123,126,128,129,132,133,134,135,136,143,144,146,147,148,156,157,158,161,162,164,173,175,176,180,181,182,185,187,193,194,199,204,207,209,210,211,212,215,217,218,223,226,228,230,233,244,247,270,275,276,283,293,305,309,311,322,337,338,339,340,346,349,350,354,364,380,398,402,403,434,436,439,443,444,445,455,456,464,466,469,470,472,473,474,475,476,479,485,492,496,501,508,512,518,521,543],etern:28,ethic:78,euclidian:118,eunpyo:77,ev_channel:205,evadventur:[158,163],eval:[30,41,283,492,545],evalstr:394,evalu:[22,28,30,79,120,146,157,159,210,283,394,476,479],evbot:[223,457],evcast:180,evcel:[475,478],evcolor:180,evcolumn:478,evdemo:90,eve:492,eveditor:[24,26,31,76,82,95,121,201,202,241,468,545],eveditorcmdset:474,even:[0,3,5,6,7,13,15,18,19,20,27,28,31,33,39,42,44,47,48,49,50,55,57,60,64,67,69,72,73,75,76,81,83,87,91,92,95,96,104,106,112,115,118,119,122,123,124,125,126,128,130,132,133,134,135,136,137,138,141,142,146,147,149,150,151,152,155,156,157,158,159,161,162,163,164,165,172,175,184,185,191,194,199,204,211,213,216,223,225,232,247,270,286,292,308,309,310,311,312,316,337,338,340,349,354,372,380,398,402,403,439,476,478,479,483,492,540,545],evenia:147,evenli:[19,118,247,338,492],evenn:193,evenna:75,evenni:124,evennia:[1,2,5,6,10,12,13,14,15,16,17,18,19,20,22,24,25,26,27,28,29,31,32,33,34,35,36,37,39,40,42,44,45,46,47,48,50,52,53,54,57,58,59,60,61,62,63,65,67,68,69,70,72,73,76,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,96,97,98,99,100,101,103,104,105,107,108,109,110,111,112,113,114,116,117,118,121,123,125,127,128,129,130,131,132,136,137,138,139,141,143,144,145,146,148,149,150,152,153,154,155,156,157,159,161,162,164,165,167,169,170,171,172,173,174,176,177,178,179,183,185,186,189,192,194,195,197,198,545],evennia_access:181,evennia_admin:503,evennia_channel:[186,189,192,223],evennia_dir:492,evennia_error:181,evennia_gener:169,evennia_launch:[7,201,202,412,414,545],evennia_logo:[53,169],evennia_runn:7,evennia_server_port:40,evennia_superuser_email:185,evennia_superuser_password:185,evennia_superuser_usernam:185,evennia_vers:416,evennia_websocket_webcli:444,evennia_wsgi_apach:181,evenniaadminapp:523,evenniaadminsit:523,evenniaapiroot:514,evenniacommandmixin:[8,490],evenniacommandtest:[8,490],evenniacommandtestmixin:490,evenniacreateview:[536,542,543],evenniadeleteview:[542,543],evenniadetailview:[542,543],evenniaform:532,evenniagameindexcli:418,evenniagameindexservic:419,evenniaindexview:[53,541],evennialogfil:485,evenniapasswordvalid:460,evenniapermiss:[513,518],evenniareverseproxyresourc:461,evenniaserv:40,evenniatest:[8,378,490],evenniatestcas:[8,490],evenniatestmixin:[8,490],evenniaupdateview:[542,543],evenniausernameavailabilityvalid:[204,460],evenniawebtest:533,event:[28,31,45,51,78,87,104,123,159,162,194,201,205,247,256,257,258,260,275,283,350,364,376,406,409,458,545],event_nam:[256,260],event_push:95,eventcharact:95,eventdict:485,eventexit:95,eventfunc:[97,201,202,235,236,253,257,545],eventfuncs_loc:95,eventhandl:[95,257],eventi:[213,241,270],eventobject:95,eventroom:95,events_calendar:95,events_dis:95,events_valid:95,events_with_valid:95,events_without_valid:95,eventu:[13,22,39,55,57,64,65,68,88,124,128,135,155,156,158,159,164,165,169,177,191,199,204,209,210,218,227,233,275,276,343,349,350,364,372,394,398,403,413,421,447,455,456,467,471,472,476,478,530],evenv:[2,6,7,123,124,185,190],evenwidth:478,ever:[9,11,13,14,15,16,22,30,42,44,46,48,55,67,70,76,106,118,123,134,142,146,149,157,162,170,172,182,198,199,273,276,338,349,411,427,428,434,464,476],everi:[0,2,5,8,9,10,11,14,18,19,20,22,28,30,31,32,35,41,42,46,47,48,58,67,69,70,73,77,78,81,85,87,92,95,96,97,118,119,120,123,124,125,127,130,132,134,136,137,141,142,143,144,146,148,149,151,152,157,162,164,165,169,170,173,174,176,177,178,185,187,190,191,193,195,204,218,223,257,274,286,289,294,308,309,310,311,312,329,337,338,349,350,359,369,380,386,398,403,409,411,421,438,448,454,463,464,466,476,477,478,479,490,492,501,508,545],everror:257,everyon:[9,11,18,22,28,31,33,36,42,46,57,58,64,90,123,125,135,149,152,153,156,158,159,162,164,165,174,176,179,183,188,192,198,199,218,223,224,225,275,276,278,308,309,310,311,312,343,434],everyong:58,everyth:[0,2,3,6,8,9,11,13,20,28,36,39,41,47,49,50,51,53,57,65,70,73,75,90,104,112,118,120,122,123,125,127,132,135,137,139,141,142,143,148,149,150,151,152,153,154,155,156,157,159,161,162,164,166,169,170,180,185,187,189,190,191,193,194,195,198,199,208,213,223,224,226,228,229,230,251,292,293,354,372,393,397,406,420,447,455,464,466,470,476,545],everywher:[75,133,148,187],evform:[19,121,201,202,468,545],evgam:223,evgamedir:120,evict:459,evid:189,evil:[5,15,187,364,403],evilus:223,evmenu:[19,22,24,76,82,92,100,104,111,113,115,121,135,141,158,201,202,228,241,274,366,369,380,386,400,468,477,490,545],evmenucmdset:476,evmenuerror:476,evmenugotoabortmessag:476,evmenugotomessag:476,evmor:[24,26,31,121,201,202,402,468,545],evscaperoom:[201,202,235,271,545],evscaperoom_start_st:90,evscaperoom_state_packag:90,evscaperoommenu:274,evscaperoomobject:[275,276],evtabl:[19,22,92,121,132,170,201,202,213,223,380,402,468,475,477,492,545],ewmaplink:[118,338],ewonewaymaplink:[118,338],exact:[5,11,22,28,39,72,112,146,149,153,204,206,210,218,223,227,233,292,312,350,354,389,396,398,402,403,465,466,488,489,492],exact_consum:292,exact_consumable_ord:[292,293],exact_tool:292,exact_tool_ord:292,exactli:[3,5,9,12,28,30,31,39,42,47,50,54,57,59,60,62,65,67,86,96,112,118,120,123,135,136,137,142,143,146,147,149,151,153,157,158,162,165,169,170,185,193,199,223,292,337,338,350,354,396,398,416,466,489],exam:[26,218],examin:[7,11,12,13,22,26,33,47,51,55,65,74,76,90,135,141,142,143,144,146,162,165,204,218,273,283,364,371,372,448,464,479,490,500,513,545],exampl:[2,4,5,6,7,8,10,11,12,13,14,15,16,17,18,19,20,22,26,31,32,34,35,36,37,41,44,46,47,48,49,50,54,57,58,59,60,62,64,65,67,68,72,73,74,76,77,78,79,82,83,87,88,90,92,93,95,97,104,106,110,112,113,114,115,116,119,120,122,123,124,125,126,127,128,129,131,132,133,134,135,136,139,140,141,142,143,144,145,146,148,149,150,151,152,153,155,156,157,158,159,161,165,169,170,171,172,174,175,176,177,181,182,185,187,188,192,193,194,195,199,201,202,204,207,210,211,212,213,216,217,218,223,224,225,226,227,228,229,232,234,235,241,247,266,270,273,275,280,283,286,289,292,293,294,296,299,305,308,309,310,311,312,314,316,322,325,327,330,331,335,337,338,339,340,343,346,349,350,353,354,355,356,358,359,364,366,370,372,376,380,382,386,388,390,391,394,397,398,403,406,409,411,416,421,436,439,440,445,448,457,461,464,466,467,468,469,471,475,476,477,478,479,480,484,485,486,489,490,492,493,495,496,501,508,517,518,532,541,545],example1_build_forest:99,example1_build_mountain:99,example1_build_templ:99,example1_legend:99,example1_map:99,example2_build_forest:99,example2_build_horizontal_exit:99,example2_build_verticle_exit:99,example2_legend:99,example2_map:99,example_batch_cmd:80,example_batch_cod:[14,80,201,202,235,355,356,545],example_recip:[201,202,235,281,291,292,545],example_recipi:292,excalibur:141,exce:[140,239,308,309,310,311,312,459,483],exceed:459,excel:[33,69,133,180,187],excempt:211,except:[6,13,15,19,20,22,27,28,30,31,33,37,41,42,49,50,53,54,57,60,65,75,76,86,95,96,117,118,120,123,124,125,127,128,130,135,142,144,146,148,150,151,152,153,158,164,165,170,172,173,174,175,177,178,185,190,191,204,205,207,209,212,213,226,227,232,233,234,247,256,257,260,270,275,276,277,283,286,292,296,302,305,308,309,310,311,312,316,322,325,329,336,337,338,339,340,349,350,354,359,362,364,366,370,371,372,382,390,393,394,396,397,398,402,405,406,409,410,416,421,423,425,437,439,441,445,449,461,464,467,469,472,475,476,478,479,480,484,485,487,492,500],excepteur:29,excerpt:27,excess:[33,41,76,161,226,292,397,470,492],exchang:[14,52,79,157,191,283,473],excit:[25,143,144,158,184],exclam:125,exclud:[58,95,123,146,153,165,173,232,286,305,372,396,397,398,474,476,510,512],exclude_cov:286,excluded_par:510,excluded_typeclass_path:218,excludeobj:396,exclus:[28,31,33,35,156,364,398,406,465,476,492],exclusiv:[405,472],exe:[7,9,185],exec:[28,30,141,403,476,492],exec_kwarg:476,exec_str:451,execcgi:181,execut:[2,7,9,14,15,20,22,27,28,30,36,37,41,42,51,52,53,54,55,57,59,65,71,75,76,80,90,95,96,97,99,116,123,126,127,128,136,137,141,142,148,151,155,158,170,185,190,204,205,207,208,209,213,216,217,226,228,229,234,241,257,269,270,273,293,350,362,364,372,386,390,393,394,397,398,403,404,406,410,413,421,423,426,427,433,436,439,444,447,448,451,454,455,464,466,467,470,476,477,479,484,490,492,521,545],execute_cmd:[12,22,37,165,171,172,204,205,213,398,421,455],execute_command:22,executor:2,exemplifi:[31,62,104,115,118,127,152,155,157],exercis:[3,125,135,141,151,164,165,170,176,239,294,353,442,452,484],exhaust:[18,76,383],exhaustedgener:382,exidbobj:398,exis:131,exist:[0,2,5,6,9,11,12,13,14,18,19,20,22,25,26,28,33,41,42,44,46,47,53,55,62,64,67,76,77,82,86,90,91,95,96,97,102,105,106,110,112,118,119,123,125,126,130,131,132,133,134,135,137,144,145,146,148,150,151,155,156,159,161,164,165,167,169,170,171,178,182,186,189,193,203,204,205,206,211,212,213,218,223,225,226,228,239,241,254,256,257,260,274,280,289,293,299,302,305,311,316,325,329,337,338,339,340,349,350,354,371,391,393,394,397,398,400,402,403,405,410,416,420,422,436,437,439,441,449,454,455,457,464,465,466,467,470,472,474,475,476,478,479,485,487,492,500,518,545],existen:455,exit:[7,8,9,20,27,28,33,41,48,49,50,67,76,79,82,95,99,104,109,115,117,118,121,125,130,132,135,138,141,142,143,144,145,148,149,151,152,153,155,165,170,174,182,185,193,198,201,209,211,212,218,228,235,241,242,258,270,276,283,289,312,314,322,324,326,329,331,332,337,338,339,340,364,370,371,372,386,393,396,397,398,403,420,436,448,464,472,474,476,477,490,512,515,518,533,545],exit_alias:[218,322],exit_back:135,exit_cmd:[28,477],exit_command:398,exit_dest_x_coordin:118,exit_dest_y_coordin:118,exit_dest_z_coordin:118,exit_nam:[132,218,322],exit_on_lastpag:477,exit_ther:135,exit_to_her:218,exit_to_ther:218,exit_typeclass:[329,490,533],exitbuildingmenu:76,exitcmdset:[20,398],exitcommand:398,exitnam:322,exitobject:131,exitviewset:518,exixt:434,exot:22,exp:475,expand:[11,32,37,49,58,60,73,74,89,90,97,104,109,114,123,124,125,132,134,135,139,141,143,144,146,148,149,150,151,152,156,157,158,159,165,166,170,171,173,176,182,191,195,201,202,218,235,251,308,309,310,311,312,322,331,341,352,398,469,478,545],expand_tab:478,expandtab:[469,478],expans:[131,156],expect:[5,6,8,9,22,30,35,36,37,45,47,53,54,58,64,65,68,70,75,95,97,107,118,120,133,135,142,148,149,151,153,155,156,158,159,165,175,178,187,190,191,218,226,229,241,254,256,289,292,329,335,337,338,382,393,398,402,403,414,416,466,476,477,479,483,490,492,497,501,508,518,524,543],expected1:490,expected2:490,expected_1st_or_2nd_person:497,expected_3rd_person:497,expected_direct:335,expected_input:490,expected_path:335,expected_return:8,expectlst:335,expectstr:335,expens:[47,191,396,489],experi:[0,3,28,30,73,86,101,104,114,115,134,136,139,143,146,151,152,155,156,162,163,170,185,191,193,223,275,362,545],experienc:[1,13,28,123,151,154,180],experienced_betray:28,experienced_viol:28,experiment:[32,53,228,502,505],expert:[112,354],expir:[77,289],explain:[11,22,26,28,49,53,67,72,76,95,118,122,123,130,135,144,148,158,161,169,174,175,178,180,188],explan:[20,22,50,60,95,123,126,130,137,276,460,545],explanatori:50,explicit:[20,62,68,72,76,97,120,137,142,169,182,188,195,382,416,438,464,476,496],explicitli:[6,13,20,31,33,34,36,39,41,42,46,47,48,60,65,67,75,112,118,124,125,129,135,141,149,150,152,157,158,185,187,212,213,218,225,233,338,354,382,388,398,403,405,411,464,466,469,472,488,490,515],exploit:[158,467,469,479,492],explor:[3,12,48,53,54,65,97,115,118,137,144,149,151,155,164,170,185,195,228,545],expos:[85,178,194,289,364,540],express:[22,28,30,33,41,52,73,74,78,87,107,120,133,146,149,153,167,178,218,247,312,382,464,492,521],ext:28,extend:[18,19,30,42,48,50,53,67,69,78,84,99,104,120,122,130,133,137,141,143,147,148,150,151,154,160,162,163,166,167,168,170,171,172,177,178,180,197,198,207,213,225,229,232,244,257,260,289,292,293,315,316,329,337,397,398,466,486,505,532,541,542,543,545],extended_room:[91,201,202,235,314,545],extendedloopingcal:411,extendedroom:[91,316,317],extendedroomcmdset:[91,316],extendng:293,extens:[6,8,28,31,60,68,75,118,120,122,123,133,144,148,149,156,167,170,182,185,195,207,308,332,377,389,431,439,472,482,491],extent:[76,95,133,158,162],exter:223,extern:[7,16,35,41,59,62,69,95,104,118,134,148,152,156,158,159,161,170,181,182,184,185,186,187,189,191,192,197,201,212,223,231,233,234,376,402,414,416,418,472,490,545],external_discord_hello:421,external_receiv:234,extra1:30,extra2:30,extra:[0,13,15,18,20,22,28,30,31,33,37,45,48,51,53,56,71,77,79,90,104,112,118,119,120,125,126,128,134,135,143,151,152,157,158,165,169,175,178,181,182,191,204,207,213,225,229,232,283,292,296,302,316,350,353,354,364,372,398,401,402,411,413,465,469,470,474,476,477,478,479,485,486,487,491,492,500,501,508,545],extra_environ:470,extra_launcher_command:[118,332,333],extra_opt:476,extra_spac:492,extract:[6,13,30,45,103,104,133,142,213,266,267,275,292,337,350,377,394,430,444,492],extract_goto_exec:476,extrainfoauthserv:436,extral:234,extran:380,extrem:[0,9,133,142,152,199,308,309,311,312,429,486],eye:[6,31,60,99,156,170,403,477],eyed:[53,161,169],eyes:[22,119,134],eyesight:[33,60,135],f6d4ca9b2b22:193,face:[93,95,118,143,155,158,187,191,194,230,296,460,476],facil:485,facilit:158,fact:[7,15,22,37,42,48,54,65,74,122,125,128,134,135,147,148,149,156,165,171,175,178,194,198,457,459,479],faction:185,factor:[97,136,140,309,311,413,427,428],factori:[62,354,413,418,426,427,428,434,435,436,437,439,447],factory_path:205,fade:[69,106,349],fail:[13,14,15,18,19,20,28,30,31,37,41,45,54,55,70,75,86,108,115,118,124,142,150,155,156,161,164,171,174,183,185,194,199,204,212,223,227,232,269,292,294,322,343,350,353,354,364,371,383,393,394,398,402,413,414,416,420,427,428,438,459,464,466,477,479,486,488,492,495,501,538,545],failmsg:459,failtext_templ:162,failur:[15,54,86,157,162,185,204,292,372,418,425,427,428,447,459,469,492],failure_effect:293,failure_messag:292,failure_teleport_msg:372,failure_teleport_to:372,faint:42,fair:[88,157,158,162,343],fairli:[83,92,130,137,190,286,309,380,386],fake:[8,84,118,244,338,447,457,464,469],fall:[0,6,20,42,70,93,95,115,118,120,123,136,149,162,170,201,204,227,292,296,350,364,372,492,532],fall_exit:372,fallback:[91,131,132,209,213,234,316,394,409,416,445,464,476,479,487,492],fals:[8,12,13,18,19,20,22,27,28,30,31,32,33,34,37,39,42,47,48,51,67,76,78,84,92,106,117,118,124,125,126,128,131,132,135,136,139,140,143,144,149,153,161,164,165,172,173,174,177,194,204,206,207,209,210,211,212,213,218,223,225,232,234,241,242,244,247,254,257,270,273,274,275,278,283,286,289,292,299,308,309,310,311,312,322,329,337,338,340,343,349,350,369,380,386,388,389,390,393,394,396,397,398,400,402,403,405,406,407,409,410,411,413,416,418,422,425,426,433,434,435,436,439,445,447,453,454,455,457,459,461,464,465,466,467,469,470,472,474,476,477,478,479,480,483,487,488,489,490,491,492,493,495,497,500,501,502,504,505,506,508,512,513,532,540],falsestr:[92,380],falsi:[143,150,232,292,337],fame:[155,159],famili:[28,75,134,161],familiar:[1,20,22,48,75,95,103,104,120,128,130,135,141,142,146,149,150,151,159,167,170,177,185,191,266,545],famou:[29,474],fan:180,fanci:[2,16,17,18,49,77,83,118,162,286,338],fantasi:[153,158,349],faq:[120,438,545],far:[7,11,14,18,20,22,53,60,68,76,95,96,97,99,117,118,122,125,130,131,132,134,142,144,146,148,149,151,152,170,184,190,191,193,211,312,329,337,340,418,443,464,474,483],fare:149,fart:161,fascilit:339,fashion:[41,170],fast:[0,11,13,16,19,37,47,69,104,118,123,128,133,136,140,151,158,159,182,216,391,448],faster:[5,13,118,136,153,158,182,234,283,464,545],fastest:[120,338],fatal:416,fault:159,faulti:151,favor:[19,118,338],favorit:[119,125],fear:19,feasibl:182,feat:158,featgmcp:440,featur:[0,2,3,8,9,11,16,17,19,20,22,27,41,45,48,53,59,60,72,76,90,95,96,97,104,106,113,115,118,119,120,122,123,124,126,132,133,134,136,138,139,141,142,143,144,155,156,157,158,165,170,179,185,189,194,204,212,213,257,270,316,350,386,411,433,454,458,466,474,492,539,544,545],feb:64,februari:136,fed:[22,33,54,434,464,473,475],fedora:[11,181,185,187],feed:[9,16,28,132,162,192,205,223,337,418,435,436,466,477],feedback:[3,11,37,119,156,159,172,233,474],feedpars:[192,435],feedread:205,feel:[11,17,48,54,64,69,76,95,96,97,106,113,119,120,122,123,130,134,137,142,146,149,154,155,156,158,159,161,162,165,168,172,177,185,188,191,275,309,349,364,372,386,545],feelabl:275,feend78:299,feint:164,fel:64,felin:19,fellow:475,felt:[42,176],femal:[58,93,296,479,496],fetch:[9,11,13,49,52,53,146,177,185,191,193,339,464,477,543],few:[0,2,3,5,11,13,16,17,20,22,27,30,31,32,33,37,50,53,54,60,63,67,68,75,78,90,97,106,119,120,122,123,124,132,142,144,147,149,151,156,157,158,159,162,164,165,174,175,180,182,187,194,199,228,247,349,364,397,431,440,459,469,478,492,541],fewer:[69,151,337,457,465],fg_colormap:491,fgstart:491,fgstop:491,fiction:[28,122,136,476],fictional_word:349,fictiv:349,fictou:280,fiddl:372,field:[7,9,13,30,31,32,34,35,36,37,41,42,45,46,48,50,53,64,67,73,104,112,133,135,145,149,167,177,182,184,207,234,254,312,331,350,354,370,380,390,391,393,396,397,398,402,403,406,407,411,423,464,465,466,467,475,484,488,489,500,501,502,504,505,506,508,512,515,520,532,543,545],field_class:532,field_nam:[391,512],field_or_argnam:32,field_ord:532,fieldevmenu:380,fieldfil:[92,201,202,235,374,545],fieldnam:[34,92,135,380,407,466,483,532],fieldset:[500,502,504,505,506,508],fieldtyp:[92,380],fifo:492,fifth:132,fight:[20,42,104,114,128,150,155,156,164,308,309,310,311,312,371,545],fighter:[114,308,309,310,311,312],figur:[0,3,5,6,11,22,31,55,58,65,90,106,119,132,137,142,147,149,156,159,167,174,177,191,247,283,292,338,350,402,416,495,545],file:[0,2,3,5,6,7,8,9,10,12,18,19,20,26,28,39,40,49,50,51,52,53,57,62,63,64,67,73,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,123,124,125,126,131,133,134,135,136,137,139,141,143,144,147,148,150,151,152,154,158,165,167,169,170,171,173,174,177,178,180,181,182,184,185,186,187,189,190,191,192,193,194,197,198,199,201,202,204,217,225,232,239,241,244,247,251,270,276,286,292,329,349,354,376,388,403,415,416,436,437,440,441,448,449,450,454,461,462,468,475,476,485,488,489,492,496,501,502,504,506,508,518,521,525,532,540,545],file_end:[470,492],file_help_entry_modul:[31,225,388],file_help_top:540,file_to_revert:11,fileentri:225,filehelp:[31,201,202,387,545],filehelpentri:[225,388,540],filehelpstoragehandl:388,filelogobserv:485,filenam:[11,19,80,106,147,232,349,470,475,485],filename1:416,filename2:416,filesystem:[185,193,194],filip:77,fill:[2,7,27,53,64,73,92,99,104,112,118,132,135,151,170,177,186,269,337,340,354,380,464,469,475,476,477,478,479,492,508,545],fill_char:478,fill_color:346,fillabl:[380,545],fillchar:[30,469,479,492],filler:496,filo:492,filter:[7,20,35,48,49,60,67,78,95,118,130,137,146,173,177,201,202,211,216,241,316,340,350,397,398,492,498,511,518,538,545],filter_backend:518,filter_famili:[48,146],filter_nam:512,filter_xyz:[118,340],filter_xyz_exit:[118,340],filterset:512,filterset_class:518,filthi:179,final_valu:54,find:[0,3,5,6,8,9,11,13,14,15,17,19,20,22,26,27,30,31,32,33,34,35,36,37,41,42,46,48,50,53,54,55,59,60,62,64,67,69,73,74,76,86,91,96,97,99,109,113,115,118,119,120,122,124,125,126,128,132,133,134,135,136,137,142,143,144,145,146,147,148,149,150,152,154,155,156,158,159,161,162,163,165,167,169,177,178,179,180,182,183,185,187,190,191,193,194,199,204,210,218,225,247,270,275,278,292,316,322,331,332,337,338,340,350,354,372,386,398,402,403,405,408,416,430,464,465,469,471,479,489,492,523,545],find_apropo:389,find_topicmatch:389,find_topics_with_categori:389,find_topicsuggest:389,findfoo:153,fine:[16,22,37,42,44,46,47,55,67,79,96,104,118,120,123,131,141,144,148,149,150,152,154,155,157,161,165,172,205,206,338,372,464,472,492],finer:[55,337,338],finish:[9,15,22,45,52,54,86,115,120,128,135,155,156,165,169,177,193,201,204,213,215,226,228,230,273,278,283,292,293,305,316,338,371,372,398,416,428,439,454,461,471,476,492,521],finish_chargen:28,finit:142,fire:[7,12,19,22,28,42,45,47,85,87,95,96,125,127,128,135,144,149,152,156,170,172,173,176,204,205,209,257,289,310,311,398,403,416,425,427,444,476,477,483],firebal:[86,158,292,293],fireball_recip:86,fireballrecip:293,firebreath:[135,149,152],firefox:[53,189],firemag:293,firestorm:127,firestorm_lastcast:127,firewal:[182,187,191,545],first:[0,3,5,6,7,9,11,12,13,14,15,16,19,20,22,25,27,28,30,31,33,37,39,41,42,44,45,48,50,51,53,54,55,56,57,58,60,62,64,65,67,69,70,73,75,82,84,90,95,99,112,114,117,119,120,122,124,125,128,130,132,133,135,136,137,138,139,141,142,143,144,145,146,147,148,150,152,153,154,155,156,157,158,159,161,162,164,165,167,168,169,172,173,174,175,176,177,178,182,183,185,186,188,190,191,192,193,194,195,197,199,204,205,207,210,211,218,225,226,229,230,232,234,241,244,247,250,251,270,275,276,277,278,283,286,289,308,309,310,311,312,316,322,329,332,337,338,349,350,353,354,359,364,366,370,371,372,382,390,393,397,398,402,403,405,406,409,416,420,421,423,434,436,439,444,445,447,448,454,457,464,466,467,469,470,472,474,475,476,478,479,480,483,484,490,491,492,513,545],first_lin:165,first_nam:500,firsthand:33,firstli:[6,37,53,75,145,146,191],fish:[162,212,305],fist:[150,403],fit:[10,30,31,39,68,72,85,130,135,148,159,161,168,174,177,182,289,293,309,312,475,477,478,492],five:[22,127,146,154,159,168,170,191,212,386,492,493],fix:[0,3,6,14,15,19,22,28,41,48,56,65,77,90,106,118,119,123,134,141,149,151,152,156,158,161,165,174,179,185,190,191,199,340,349,416,475,477,478,488,545],fix_sentence_end:478,fixer:146,fixtur:[229,239,248,279,294,313,335,351,353,360,442,452,484,516],fizzl:158,flag:[14,15,20,22,28,32,47,50,62,65,67,69,75,127,128,129,135,144,149,151,154,156,161,165,204,209,211,213,218,273,275,276,278,292,294,364,370,393,394,398,416,423,427,436,439,444,455,474,476,492],flagnam:[273,275,276],flair:161,flame:[127,293,311],flash:[15,108,364],flat:[0,19,48,76,121,133,147,201,403,495,545],flatfil:133,flatpag:523,flatten:403,flatten_diff:403,flatten_prototyp:403,flattened_diff:403,flavor:[58,144,157,191,311],flavour:[36,175],flaw:174,fled:[164,370],fledg:[16,69,71,104,115,158,165,166,177,191,217],flee:[164,171,312,370],fleevalu:164,flesh:[135,144,158],flexibl:[14,28,41,42,68,69,76,82,92,113,118,125,128,130,134,149,152,157,158,161,162,164,170,178,191,207,218,241,283,292,380,386,440,464,476,492,541,545],fli:152,flick:493,flicker:364,flip:[26,28,139,230],flood:[19,27],floor:[95,97,140,273,275,350,353],flour:[86,104,292],flourish:464,flourrecip:292,flow:[2,17,47,51,62,65,67,90,118,122,156,161,185,233,472,476,545],flower:[36,37,55,120,144,145,146,153,156,157,218,479,545],flowerpot:[55,134],fluent:180,fluffi:[149,150,152],fluid:[17,56],flurri:350,flush:[9,22,170,182,228,464,466,483],flush_cach:483,flush_cached_inst:483,flush_from_cach:483,flush_instance_cach:483,flusher:483,flushmem:228,fly:[19,20,22,28,30,31,41,42,55,86,123,125,141,146,148,149,153,167,204,224,226,234,390,398,402,411,423,434,437,441,464,470,480,492],fnmatch:464,foci:158,focu:[90,124,154,156,158,164,273,275],focus:[7,90,133,134,165,180,273,275,312,515],focused_object:273,foe:309,foilag:118,fold:[113,158,386],folder:[7,8,9,14,15,19,50,51,53,64,67,73,90,99,104,114,118,119,120,123,125,129,132,134,135,137,144,147,148,149,151,162,164,165,167,169,170,171,172,177,178,181,185,190,193,194,198,199,308,309,310,311,312,416,490,523,545],folder_nam:123,follow:[3,5,6,7,9,11,12,13,14,15,17,18,20,22,27,28,30,31,32,33,37,39,42,46,48,50,51,53,54,56,57,60,62,64,67,68,73,75,76,77,80,82,83,84,85,90,93,95,96,97,98,99,104,106,112,113,118,119,120,124,126,130,132,135,136,137,140,141,142,143,144,146,148,149,150,151,152,154,156,159,161,162,163,164,165,171,173,174,177,178,180,181,182,184,185,186,187,188,190,191,193,194,199,204,205,207,209,210,213,218,225,226,229,232,233,234,241,244,250,251,257,286,289,292,296,299,310,311,337,338,350,354,372,386,388,390,391,393,394,397,398,401,402,403,406,407,420,421,431,440,444,445,448,458,464,466,469,470,472,475,476,477,478,485,492,517],follwo:394,fond:136,font:[51,120,126,148,170,338],foo1:13,foo2:13,foo:[11,13,18,22,28,30,31,34,42,45,46,62,65,68,113,118,143,146,147,148,149,151,153,185,218,337,339,386,391,416,464,476,479,490],foo_bar:68,foobar:28,foobarfoo:55,food:[86,95,292],fooerror:476,fool:158,foolish:364,footer:[53,118,137,177,213,398,477],footnot:[16,120],footprint:228,footwear:134,for_cont:398,forai:148,forbidden:11,forc:[8,20,22,42,48,54,97,105,106,118,135,139,140,142,143,152,159,161,162,164,165,174,181,185,193,194,199,205,212,216,218,223,283,293,296,305,316,317,337,349,350,354,394,398,402,408,427,428,434,439,457,459,477,478,483,485,492],force_init:398,force_repeat:[42,164],force_str:488,forceutcdatetim:317,forcibl:408,fore:454,forebod:316,foreground:[3,60,84,175,193,244,416,469,479,545],foreign:[48,146],foreignkei:[207,397,406,466,484,501,508],forens:377,forest:[14,46,74,99,118,148,170,316],forest_meadow:46,forest_room:46,forestobj:74,forget:[14,19,22,54,67,75,126,136,141,143,149,151,152,165,167,184,189,193,350,470,545],forgiv:161,forgo:371,forgotten:[119,127,132,141,149],fork:[75,77,180,545],forloop:137,form:[6,8,11,13,14,18,19,20,22,28,30,31,32,33,37,39,41,46,47,48,50,52,58,65,68,70,71,72,73,86,90,93,102,104,106,112,118,119,120,121,122,123,135,143,148,150,152,153,154,156,159,164,165,172,201,202,204,205,206,210,212,213,216,218,223,226,229,232,233,234,273,280,283,292,296,340,349,350,354,377,380,388,390,393,394,396,398,402,403,407,409,411,414,434,436,440,444,455,457,464,465,466,469,470,472,473,474,475,476,478,479,480,485,488,489,492,493,495,496,498,500,501,502,504,505,506,508,510,515,531,536,538,543,545],form_char:475,form_class:[53,536,538],form_template_to_dict:380,form_url:500,form_valid:[536,538,543],formal:[33,156,398,440,496,545],format:[3,11,15,17,18,19,20,22,31,57,60,64,65,68,69,70,72,76,84,95,96,112,116,117,118,119,120,122,135,137,139,146,150,151,161,162,165,170,177,180,182,192,194,211,213,215,218,225,229,232,233,241,244,247,260,270,274,280,286,292,310,329,337,350,354,362,369,376,380,386,388,390,398,400,402,403,407,416,421,431,436,456,458,464,466,469,470,472,474,476,477,478,480,485,487,492,493,515,518,545],format_:218,format_account_kei:218,format_account_permiss:218,format_account_typeclass:218,format_alias:218,format_attribut:218,format_available_protfunc:402,format_callback:254,format_channel_account_sub:218,format_channel_object_sub:218,format_channel_sub_tot:218,format_char:218,format_current_cmd:218,format_destin:218,format_diff:403,format_email:218,format_exit:218,format_extern:232,format_grid:492,format_help:270,format_help_entri:225,format_help_index:225,format_hom:218,format_kei:218,format_loc:218,format_lock:218,format_merged_cmdset:218,format_messag:232,format_nattribut:218,format_output:218,format_permiss:218,format_script:218,format_script_desc:218,format_script_is_persist:218,format_script_timer_data:218,format_send:232,format_sess:218,format_single_attribut:218,format_single_attribute_detail:218,format_single_cmdset:218,format_single_cmdset_opt:218,format_single_tag:218,format_stored_cmdset:218,format_t:492,format_tag:218,format_text:241,format_th:218,format_typeclass:218,format_usag:270,formatt:[294,380,402,476,477],formcallback:[92,380],formchar:[135,475],formdata:[92,380],former:[17,123,175,182,292,476],formfield:488,formhelptext:380,formset:[501,508],formstr:135,formtempl:[92,380],formul:178,forth:[11,19,218,311],fortress:170,fortun:[9,22,95,124,130,137,149,155],forum:[9,64,75,104,119,122,134,158,159,185,191,192,545],forward:[3,14,15,27,28,136,137,144,154,157,158,174,175,191,204,207,234,299,376,390,397,406,461,464,466,467,475,477,484],forwardfor:187,forwardmanytoonedescriptor:[397,406,484],forwardonetoonedescriptor:[397,406,484],foster:18,foul:41,found:[3,4,6,8,9,12,13,14,15,16,18,19,20,22,28,31,32,33,37,38,39,41,46,48,49,50,51,53,54,58,62,64,65,73,75,76,77,79,90,99,104,115,118,120,122,124,126,130,132,134,135,141,142,143,146,147,148,149,150,151,153,155,161,162,164,165,178,179,182,185,191,194,195,201,204,206,208,209,210,211,213,218,223,226,227,230,232,241,254,256,257,283,337,338,339,340,350,354,372,388,390,394,396,398,401,402,403,405,408,411,415,416,422,431,434,445,455,457,464,465,466,469,470,471,472,476,478,479,483,487,489,492,521],foundat:[122,132,146,180,308],four:[15,19,36,60,62,67,91,120,124,130,140,153,162,166,170,212,234,316,394],fourth:130,fqdn:191,fractal:133,fraction:158,frame:51,framework:[49,51,52,53,56,104,123,159,167,169,177,229,308,311,488,512,513,515,517,518,545],frankli:72,free:[7,10,28,31,46,64,76,77,97,102,104,106,113,119,122,123,128,134,146,156,158,164,165,175,177,180,191,273,283,309,350,386,402],freedn:191,freedom:[0,15,131,158,185],freeform:[83,158,162,164,286],freeli:[118,193,194,470],freenod:[75,180,185,189,191,205,223,457],freetext:[35,233,489],freez:[3,22,95,128,256],french:64,frequenc:[5,349],frequent:[95,142,241],fresh:[9,20,90,118,135,149,198,416],freshli:170,fri:55,friend:[119,135,140,143,156,159,194],friendli:[76,112,119,120,151,177,179,207,354],friendlier:[232,398],frighten:310,from:[0,1,2,3,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,22,25,27,29,30,32,33,34,35,36,37,39,40,41,42,44,45,46,47,48,49,50,52,53,54,55,56,57,58,60,62,63,64,65,67,69,70,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,123,125,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,145,146,147,148,149,150,152,153,154,155,156,157,158,159,161,162,164,165,167,169,170,171,172,173,174,175,176,178,180,181,182,184,185,187,188,189,190,192,194,195,197,198,199,201,202,204,205,206,207,208,209,210,211,212,213,215,216,217,218,223,224,225,226,227,228,229,230,232,233,234,241,244,247,251,256,257,260,266,267,270,273,274,275,276,278,280,283,286,289,292,293,294,296,299,302,305,308,309,310,311,312,316,322,325,329,331,332,337,338,339,340,343,346,349,350,353,354,364,370,371,372,376,377,378,380,382,386,388,389,390,393,394,395,396,397,398,402,403,405,406,407,408,410,411,413,416,420,421,422,423,425,426,427,428,429,433,434,435,436,439,444,445,447,448,450,454,455,456,457,459,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,477,478,479,480,483,484,485,486,488,489,490,491,492,493,495,496,501,502,508,510,512,513,515,518,521,523,532,538,540,543,544,545],from_channel:205,from_db_valu:488,from_nod:476,from_obj:[58,65,139,172,204,205,213,296,362,398],from_pickl:473,from_tz:493,frombox:425,fromstr:425,fromtimestamp:[317,480],front:[11,14,33,41,51,141,143,146,151,162,181,194,197,200,545],frontend:[49,113,386,464],frontpag:[50,53,147,153,201,202,498,499,509,545],frost:157,frozen:[22,128,257],fruit:[104,105,305],ftabl:492,ftp:[77,491],fuel:[112,125,157,311,354],fugiat:29,fulfil:[86,149,155,159,416],full:[0,4,6,8,9,11,14,15,16,17,19,22,26,28,30,33,34,37,39,41,42,44,47,48,56,58,68,69,71,73,75,79,80,86,90,91,94,95,104,106,112,113,114,115,116,118,119,120,122,123,124,125,126,134,135,138,143,144,146,147,151,152,157,158,161,162,164,165,166,169,170,171,174,177,178,182,183,190,191,193,198,199,205,210,212,213,217,218,223,225,227,228,229,232,241,250,266,270,274,278,280,283,292,302,311,316,337,339,340,346,349,350,354,369,386,394,396,403,407,428,434,447,457,458,464,466,470,474,476,478,479,490,492,544,545],full_desc:275,full_justifi:41,full_nam:36,full_result:343,full_system:[90,201,202,235,545],fullchain:187,fuller:135,fullest:159,fullfil:396,fulli:[5,13,22,28,57,64,67,90,118,122,124,135,141,154,161,185,191,194,199,204,233,349,394,398,409,444,456,472,492],fun:[0,5,139,144,156,157,158,169,170,180],func1:[218,394,448],func2:[218,394,448],func:[3,22,27,28,30,33,54,58,65,76,82,85,95,116,120,125,126,127,128,129,131,133,135,136,139,140,141,142,143,148,150,153,161,162,164,165,174,188,209,213,215,216,217,218,223,224,225,226,227,228,229,230,241,247,251,255,266,269,270,273,283,286,289,292,293,296,299,302,305,308,309,310,311,312,316,322,325,331,343,350,364,366,370,371,372,380,386,393,394,398,427,447,448,452,461,474,476,477,479,480,490,492,541,545],func_test_cmd_task:229,funcdef:479,funciton:311,funcnam:[28,30,32,71,148,394,401,402,411,476,479,492],funcpars:[24,41,58,65,71,121,170,195,201,202,401,457,468,492,545],funcparser_cal:[401,479,545],funcparser_callable_add:479,funcparser_callable_center_justifi:479,funcparser_callable_choic:479,funcparser_callable_clr:479,funcparser_callable_conjug:479,funcparser_callable_crop:479,funcparser_callable_div:479,funcparser_callable_ev:479,funcparser_callable_justifi:479,funcparser_callable_left_justifi:479,funcparser_callable_mult:479,funcparser_callable_pad:479,funcparser_callable_pronoun:479,funcparser_callable_pronoun_capit:479,funcparser_callable_randint:479,funcparser_callable_random:479,funcparser_callable_right_justifi:479,funcparser_callable_round:479,funcparser_callable_search:479,funcparser_callable_search_list:479,funcparser_callable_spac:479,funcparser_callable_sub:479,funcparser_callable_toint:479,funcparser_callable_y:479,funcparser_callable_you_capit:479,funcparser_outgoing_messages_modul:457,funcparser_parse_outgoing_messages_en:71,function_nam:228,functioncal:425,functionnam:[30,425],functionpars:[30,402],functool:185,fundament:[22,37,46,134,148,149,151,152,158,398],fur:293,furnac:[292,293],furnitur:[14,46,48],furst:354,further:[3,7,10,11,13,18,19,20,31,41,44,48,49,65,67,75,77,86,97,104,118,120,131,132,134,141,142,149,153,161,170,191,193,195,199,212,218,310,312,338,340,349,403,416,440,492,545],furthermor:[120,175],fuss:193,futur:[11,13,27,36,54,75,117,120,135,136,144,150,151,154,156,159,160,161,163,165,166,168,182,185,193,215,257,293,329,371,421,465,486,493,545],futurist:136,fuzzi:[31,206,223,292,389,396,489,492],fuzzy_import_from_modul:492,gadea:77,gag:183,gain:[5,106,128,146,156,161,213,228,234,350,394,398,545],galosch:349,gambl:[28,343],game:[1,2,3,5,6,7,10,12,14,15,16,17,20,22,23,25,26,27,28,29,30,33,35,36,37,39,40,41,44,45,46,47,48,49,50,51,52,54,57,58,60,63,64,65,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,86,87,88,91,92,94,96,97,99,104,105,106,107,110,113,114,115,116,118,119,120,121,123,124,125,126,127,128,129,131,133,137,138,139,141,142,143,145,146,147,149,150,151,152,153,155,157,160,161,163,164,166,167,168,169,171,172,174,176,177,178,179,180,181,182,183,185,186,187,188,189,190,192,194,195,199,201,202,203,204,205,206,207,209,211,212,213,215,216,217,218,222,223,224,225,228,229,230,231,232,233,234,235,241,247,248,250,251,255,256,257,258,270,271,273,274,275,278,281,283,286,291,293,299,308,309,310,311,312,314,316,325,332,334,337,338,339,340,343,346,349,350,364,369,372,380,382,386,388,389,390,395,396,397,398,405,406,408,409,412,416,418,419,420,421,427,428,433,435,436,439,440,447,448,449,454,455,457,465,466,467,470,471,472,474,475,480,483,485,490,492,500,501,508,513,518,525,541,544,545],game_dir:[485,492],game_epoch:[19,480],game_index_cli:[201,202,412,545],game_index_en:184,game_index_list:184,game_nam:184,game_slogan:[53,75],game_statu:184,game_system:[79,83,85,86,93,98,102,105,114,119,201,202,235,545],game_templ:[53,147],game_websit:184,gamedir:[28,41,53,118,154,197,416,462,490,545],gamedirnam:135,gameim:545,gameindexcli:419,gamemap:99,gameplai:[77,104,158,191,273,545],gamer:[186,189],gamesrc:19,gametim:[19,30,87,91,104,121,201,202,246,247,257,316,468,545],gametime_to_realtim:247,gametimescript:247,gameworld:150,gammon:[180,431],gandalf:28,garbag:464,garbl:[104,106,157],garden:180,garment:[83,286],gate:[31,115,118,156,338],gatekeep:31,gatewai:[199,445],gather:[8,22,31,52,65,169,176,183,209,210,372,414,418,472,489],gaug:[157,201,235,341,352,353,545],gaugetrait:354,gave:[123,125,142,149,175,495,497],gbg:469,gcc:[151,152,185],gcreat:218,gear:[7,169,191,205,212,230,251],gemb:77,gemer:[107,382],gen:17,gender:[58,93,104,296,479,496],gendercharact:[93,296],gendersub:[201,202,235,281,545],gener:[2,5,7,8,13,18,20,22,26,28,31,33,36,39,41,42,44,46,50,51,53,54,55,60,64,65,67,68,75,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,97,98,99,100,101,102,103,104,105,106,108,109,110,111,112,113,114,115,116,117,118,119,120,122,123,126,128,132,134,135,136,138,143,144,148,153,156,157,161,162,164,170,175,178,182,185,187,191,195,201,202,204,205,206,208,213,214,215,218,225,226,227,229,230,232,239,241,251,257,269,270,273,275,276,283,286,292,293,296,299,302,308,309,310,311,312,316,322,325,331,338,343,349,350,364,366,369,370,372,376,377,380,381,382,383,386,389,390,394,396,398,400,402,403,405,427,434,436,439,440,444,447,455,456,457,461,464,467,468,469,471,472,474,477,478,479,480,485,487,488,492,516,517,518,524,532,536,537,538,540,541,542,544,545],general_context:[201,202,498,522,545],generalviewsetmixin:518,generate_prototype_kei:338,generate_sessid:434,generic_mud_communication_protocol:440,genericbuildingcmd:[82,241],genericbuildingmenu:241,genesi:191,geniu:[105,305],genr:[119,123,430],genuin:158,geoff:[104,116,270],geograph:74,geographi:130,geoip:376,geometr:170,geometri:170,get:[0,3,5,6,7,8,9,10,11,12,13,14,16,17,18,20,22,26,27,30,31,32,33,34,35,36,40,42,44,45,46,48,49,51,53,54,55,56,58,60,62,64,65,67,68,73,75,76,79,86,88,90,96,97,98,104,106,107,108,110,111,112,113,114,115,117,118,120,122,123,125,126,127,128,129,130,131,132,133,134,135,136,137,139,140,141,142,143,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,172,174,175,177,178,181,182,184,186,188,189,190,191,193,194,195,197,199,204,205,206,207,211,212,213,215,216,218,219,223,224,225,230,232,233,234,241,254,256,257,260,273,275,276,278,286,299,305,308,309,310,311,312,325,329,331,335,337,338,339,340,343,350,353,354,359,364,366,371,372,382,386,388,389,390,394,396,397,398,400,402,403,405,406,408,411,414,416,421,425,426,430,434,436,439,440,442,444,445,453,455,456,457,459,464,465,466,467,469,470,471,474,476,478,479,480,482,483,485,486,487,489,492,495,497,500,502,505,506,510,512,515,517,532,540,541,544,545],get_absolute_url:[178,232,390,466],get_account:[394,455],get_account_from_email:206,get_account_from_nam:206,get_account_from_uid:206,get_al:464,get_alia:465,get_alias:515,get_all_attribut:464,get_all_cached_inst:483,get_all_categori:389,get_all_channel:233,get_all_charact:276,get_all_cmd_keys_and_alias:211,get_all_cmdset:492,get_all_mail:299,get_all_puppet:204,get_all_script:405,get_all_scripts_on_obj:405,get_all_sync_data:457,get_all_top:389,get_all_typeclass:492,get_and_load_cmdset:510,get_and_load_typeclass:510,get_and_merge_cmdset:212,get_app_list:523,get_attack:[308,309,310,311,312],get_attr:218,get_attribut:[465,515],get_browserstr:445,get_buff:474,get_by_alia:465,get_by_attribut:465,get_by_nick:465,get_by_permiss:465,get_by_tag:465,get_cach:464,get_cache_kei:459,get_cached_inst:483,get_callback:257,get_channel:233,get_channel_alias:223,get_channel_histori:223,get_charact:455,get_client_opt:[421,545],get_client_s:455,get_client_sess:[444,445],get_client_sessid:445,get_cmd_signatur:275,get_command_info:[213,226],get_components_with_symbol:337,get_connected_account:206,get_cont:[396,515],get_content_nam:398,get_context_data:[53,537,540,541,543],get_damag:[308,309,310,311,312],get_db_prep_lookup:488,get_db_prep_valu:488,get_dbref_rang:[206,396,405,465],get_def:410,get_default:488,get_defens:[308,309,310,311,312],get_direct:[118,338],get_display_nam:[3,30,58,76,95,96,106,118,135,140,204,329,340,350,398,466],get_display_symbol:[118,338],get_err_msg:[33,144],get_ev:257,get_evennia_pid:492,get_evennia_vers:492,get_event_handl:260,get_exit:[118,339,515],get_exit_spawn_nam:[118,338],get_extra_info:[213,398,466],get_famili:[48,146],get_fieldset:505,get_form:[500,502,505,506],get_formatted_obj_data:218,get_formset:[501,508],get_game_dir_path:492,get_height:478,get_help:[22,31,137,213,229,255,270,275,476],get_help_categori:540,get_help_text:460,get_help_top:540,get_hint:278,get_id:[177,410,465],get_info_dict:[433,454],get_initi:543,get_input:[476,490,545],get_inputfunc:[68,421,440,457,545],get_internal_typ:488,get_kwarg:533,get_linked_neighbor:338,get_location_nam:[117,329],get_log_filenam:232,get_map:[118,339],get_mass:140,get_message_by_id:233,get_messages_by_receiv:233,get_messages_by_send:233,get_min_height:478,get_min_width:478,get_msg_by_receiv:35,get_msg_by_send:35,get_new:435,get_new_coordin:329,get_next_by_date_join:207,get_next_by_db_date_cr:[207,234,390,397,406,464,466],get_next_wait:260,get_nick:[465,515],get_nicklist:[205,428],get_node_from_coord:337,get_numbered_nam:398,get_obj_coordin:329,get_object:[278,518,537,540,543],get_object_with_account:[396,489],get_objs_at_coordin:329,get_objs_with_attr:396,get_objs_with_attr_match:396,get_objs_with_attr_valu:396,get_objs_with_db_properti:396,get_objs_with_db_property_match:396,get_objs_with_db_property_valu:396,get_objs_with_key_and_typeclass:396,get_objs_with_key_or_alia:396,get_oth:283,get_permiss:[465,515],get_pid:416,get_player_count:430,get_posit:275,get_previous_by_date_join:207,get_previous_by_db_date_cr:[207,234,390,397,406,464,466],get_puppet:[12,204,455],get_puppet_or_account:455,get_queryset:[537,538,540],get_rang:312,get_recently_connected_account:206,get_recently_created_account:206,get_redirect_url:538,get_regex_tupl:350,get_respons:526,get_room:[118,339],get_room_at:130,get_rooms_around:130,get_serializer_class:518,get_sess:457,get_session_id:515,get_short_desc:275,get_shortest_path:[118,337],get_spawn_xyz:338,get_stat:149,get_statu:426,get_subscript:233,get_success_url:543,get_sync_data:456,get_system_cmd:211,get_tag:[465,515],get_tag_queri:512,get_time_and_season:316,get_typeclass_tot:465,get_uptim:430,get_url:505,get_username_valid:204,get_valu:[68,421,440,545],get_value_displai:515,get_vari:[254,257],get_view_detail:516,get_visible_cont:398,get_visual_rang:[118,337],get_weight:338,get_width:478,get_wilderness_script:328,get_worn_cloth:286,get_xyz:[118,340],get_xyz_exit:[118,340],get_xyzgrid:[118,339],getattr:34,getbootstrap:56,getchild:461,getclientaddress:[62,436],getdefaultencod:540,getel:51,getenv:[416,426],getgl:51,getinput:476,getkeypair:436,getloadavg:190,getobject:77,getobjectacl:77,getpeer:436,getpid:492,getsizof:483,getsslcontext:[437,441],getstartedwiths3:77,getston:22,getter:[207,234,286,309,312,350,397,398,423,464,497],gettext:64,gfg:469,ghost:31,ghostli:372,giant:125,giantess:149,gid:[5,193,448],gidcount:447,gift:137,gig:158,girl:[154,398],gist:[53,349,492],git:[2,9,10,64,67,69,75,120,126,180,182,185,190,191,193,545],github:[0,10,64,75,85,90,96,119,120,126,134,147,155,156,180,185,190,192,241,289,444,461,492,544,545],gitignor:11,give:[0,4,5,8,9,12,13,14,16,18,19,22,26,28,29,30,33,37,39,41,42,44,45,46,47,48,50,53,54,55,57,58,68,70,74,75,76,79,95,96,97,99,104,106,107,113,114,115,117,118,120,122,123,124,125,126,129,130,134,135,136,137,138,140,141,142,143,144,146,147,148,149,150,151,152,153,154,156,157,159,162,163,164,165,167,169,170,171,172,177,178,180,182,185,190,191,192,193,194,199,204,209,211,212,215,218,223,224,226,232,233,241,273,275,276,278,286,293,308,309,310,311,312,316,329,337,338,349,364,366,372,382,386,396,398,405,406,420,442,448,455,461,464,469,476,478,489,490,492,495,497,515,545],given:[0,3,5,6,8,12,13,14,15,19,20,22,27,28,30,31,32,33,34,35,37,39,41,42,44,47,48,53,54,55,58,59,60,64,65,67,68,70,73,74,76,81,82,85,87,90,92,95,96,97,101,104,105,112,113,118,120,123,124,125,126,130,132,135,136,141,143,144,145,148,149,151,152,155,157,158,162,164,165,171,175,177,178,191,193,199,204,206,209,210,211,212,213,215,216,218,223,225,227,228,229,232,233,234,241,247,250,251,254,256,260,266,270,273,275,276,278,280,286,289,292,293,296,305,308,309,310,311,312,316,322,331,337,338,339,340,343,346,349,350,354,362,364,371,372,380,382,386,391,393,394,396,398,400,402,403,405,407,408,409,411,414,416,421,422,425,434,439,440,445,448,451,455,456,457,458,459,460,461,464,465,466,467,469,470,472,473,474,475,476,477,478,479,480,483,485,487,488,489,490,492,495,496,497,500,513,521,524,537,538,540,545],given_class:520,giver:[104,111,157,309,312,398],glad:142,glade:[118,148],glanc:[19,20,22,76,106,130,135,142,241,350],glance_exit:76,glass:[108,305,364],glob:[28,224,476],global:[5,11,14,22,25,28,30,32,37,41,42,44,47,48,51,69,74,76,77,86,91,95,118,123,133,141,153,156,173,176,187,193,195,218,232,257,277,292,316,322,331,339,350,382,396,398,403,404,405,406,410,413,416,421,423,426,447,448,470,471,472,476,479,480,489,490,492,525,545],global_script:[201,471,545],global_search:[14,19,76,135,142,204,350,398,465],globalscriptcontain:471,globalth:490,globe:[169,191],glori:155,glorifi:[112,354],gloriou:146,glossari:[185,545],glow:170,glu:40,glyph:425,gmcp:[32,65,440,545],gmsheet:135,gmt:[77,148],gmud:183,gno:76,gnome:[64,183],gnu:15,go_back:[386,476],go_up_one_categori:386,goal:[42,115,120,142,155,156,159,161,180,194,349,544],goals_of_input_valid:532,goblin:[28,41,148,218,403],goblin_arch:403,goblin_archwizard:403,goblin_wizard:403,goblinwieldingclub:41,god:[31,39,144,198,388],godhood:545,godlik:[106,350],goe:[0,3,22,24,42,62,67,75,76,97,117,118,123,128,132,137,152,155,158,162,165,172,174,190,191,211,212,275,278,312,329,337,338,398,436,439,454,455,491,492,543],goff:[95,104,107,382],going:[0,28,30,50,53,62,68,82,95,96,97,106,118,126,132,135,136,137,140,142,144,146,149,151,153,156,158,164,167,170,174,177,186,187,191,193,197,241,308,309,310,311,312,329,350,364,369,372,398,413,418,469,476,515],goings:418,gold:[28,41,140,141,152,157,470],gold_necklac:13,gold_val:141,gold_valu:141,goldenlayout:545,goldenlayout_config:51,goldenlayout_default_config:51,gone:[33,55,95,141,144,149,151,153,155,158,193,276,337],good:[0,5,6,7,8,11,12,13,15,18,19,20,22,28,30,33,35,36,41,42,48,50,53,55,60,62,75,76,79,85,86,95,96,97,104,115,119,120,122,124,125,126,130,132,133,134,137,138,141,142,143,144,146,147,151,154,156,157,158,159,161,162,163,165,170,174,175,177,178,180,184,185,189,191,193,194,195,199,204,211,212,213,229,256,283,289,335,350,439,448,476,479,545],goodby:[28,436],goodgui:394,googl:[77,120,180,190,191,223,478,545],googlegroup:40,googli:[53,169],gorgeou:118,gossip:[180,186,223],got:[9,11,14,49,54,113,143,149,150,151,152,164,371,386],goto_cal:[28,476],goto_cleanup_cmdset:369,goto_command_demo_comm:369,goto_command_demo_help:369,goto_command_demo_room:369,goto_kwarg:476,goto_next_room:174,gotostr_or_func:476,gotten:[122,159,312,371,398,443],gpl2:495,graaah:171,grab:[13,22,26,143,144,162,177,224,371,515,543],gracefulli:[0,215,228,350,398,416,492],gradual:[14,15,106,112,128,156,157,180,349,354],grai:[60,175],grain:[47,206,472],gram:140,grammar:[58,106,275,349],grammat:[58,106,159,349,350],grand:[13,31,99],grant:[11,33,39,57,182,234,308,309,310,311,312,393,394,402,464,513,536,542,545],granular:312,grapevin:[197,201,202,205,223,412,424,545],grapevine2chan:[26,31,143,186,223],grapevine_:223,grapevine_channel:[186,205,223],grapevine_client_id:186,grapevine_client_secret:186,grapevine_en:[186,223],grapevinebot:205,grapevinecli:427,graph:[11,132,337],graphic:[3,9,33,34,49,50,52,65,73,135,159,170,201,251,346,440,545],grasp:[175,177],grave:115,grayscal:[84,244],great:[15,28,30,31,42,45,50,56,69,76,77,82,86,92,95,97,104,115,118,119,124,125,128,130,134,137,142,151,156,159,162,165,178,180,241,380,461],greater:[6,20,33,44,76,146,393,476],greatli:[95,179],greek:16,green:[11,20,33,41,60,118,151,175,218,228,275,371,469],greenforest:118,greenskin:403,greet:[25,44,75,95,96,171,195],greetjack:36,greg:180,grei:[41,118,175,469],grenad:37,grep:[11,190],greyscal:[60,469],greyskinnedgoblin:41,griatch:[67,79,80,81,84,86,87,88,89,90,91,93,100,101,102,103,104,106,108,109,110,111,112,115,118,125,143,146,229,243,244,246,247,249,251,265,266,272,282,283,291,292,295,296,299,301,302,315,316,321,322,324,325,330,342,343,348,349,350,352,354,356,358,359,361,363,364,365,366,368,369,371,475,483,488,491,495,496],grid:[56,91,99,109,110,117,154,165,170,197,201,202,225,235,312,492,545],gridmap:118,gridpoint:[335,337],gridsiz:335,grief:55,griefer:178,grin:[22,157,464,479,497],grip:[120,293],gritti:22,ground:[95,115,122,125,144,146,150,154,170],group:[0,18,22,26,31,41,46,48,50,54,55,57,74,75,78,95,96,106,123,124,125,142,143,148,153,158,180,193,206,207,214,218,224,225,233,305,316,349,371,372,398,402,403,425,448,464,467,469,472,500,508,545],groupd:464,grow:[0,14,18,122,126,146,150,156,157,180,185,199,337,354,427,428,478,492],grown:[28,72,75,126],grudg:162,grungi:298,grungies1138:[98,104,111,299,365,366],grunt:[218,403],gsg:77,gstart:218,gthi:139,gtranslat:64,guarante:[13,39,42,67,88,119,157,187,191,257,343,402,434,455,466,479],guard:[28,118,158,293,338],guardian:115,guess:[16,27,70,76,96,137,142,194,241,403],guest1:63,guest9:63,guest:[24,39,121,204,545],guest_en:[39,63],guest_hom:[63,177],guest_list:63,guest_start_loc:63,guestaccount:46,gui:[51,52,65,134,158,299],guid:[2,9,89,100,139,169,177,512,545],guidelin:[120,180,545],guild:[18,46,67,90,104,158,172,180,223],guild_memb:28,gun:[58,125],gun_object:58,guru:122,gush:95,gzip:239,habit:133,habitu:47,hack:[122,162,164,425],hacker:[180,194],had:[0,9,11,15,16,20,42,57,73,75,86,119,122,125,128,144,146,149,150,151,152,156,158,165,181,191,193,213,217,229,273,286,338,371,403,406,416,466,470,477,495,497,532,545],hadn:[11,136,156],hair:293,half:[69,390],hall:[31,132],hallwai:132,halt:170,hammer:[86,292,293],hand:[16,28,36,37,44,58,62,69,79,95,99,104,119,122,133,134,135,146,150,152,157,160,162,178,213,218,224,226,228,283,293,515],hander:146,handi:[3,151,177,190,310],handl:[5,6,9,12,13,14,16,18,19,22,27,28,30,32,33,36,37,44,47,48,51,52,53,58,62,65,67,68,69,72,75,76,77,78,79,86,95,97,108,111,118,119,121,122,123,124,131,132,133,136,141,142,143,146,147,148,150,151,152,153,156,159,161,164,171,175,176,181,183,187,190,193,195,204,205,206,208,209,211,212,218,219,223,224,227,251,257,260,269,270,275,280,283,292,293,308,309,310,311,312,316,322,331,338,350,364,366,371,372,377,386,387,388,397,398,401,402,403,406,407,410,413,416,420,421,425,426,428,429,436,439,440,443,445,447,456,457,464,466,469,470,472,473,474,476,477,478,480,483,491,492,501,508,526,545],handle_answ:28,handle_appli:275,handle_consum:275,handle_egd_respons:418,handle_eof:436,handle_error:[223,257,410],handle_ff:436,handle_foo_messag:476,handle_int:436,handle_messag:476,handle_mix:275,handle_numb:476,handle_posit:275,handle_quit:436,handle_setup:420,handler:[12,13,20,22,33,34,35,36,37,39,42,44,46,47,48,65,67,85,95,104,112,123,147,148,149,157,162,195,204,209,212,227,231,234,254,257,258,260,278,283,289,329,350,353,354,370,393,394,397,398,403,407,408,410,411,421,433,434,454,457,463,464,466,467,471,472,475,476,486,487,492,501,508,540,545],handlertyp:467,handshak:[29,65,183,426,432,434,439],handshake_don:439,hang:[120,152,156,159,167],happen:[0,3,5,6,9,13,18,19,20,22,28,30,33,39,42,44,45,47,52,53,55,57,65,67,68,69,85,87,88,95,97,104,118,122,123,130,131,134,135,136,142,143,144,149,150,151,158,159,161,162,164,165,170,175,177,184,189,191,199,204,211,212,223,232,247,275,277,278,289,308,309,310,311,312,325,329,337,370,372,398,403,410,418,425,428,448,453,455,456,457,466,476,477,483,485,492,513],happend:403,happi:[14,157,158,476],happier:142,happili:[18,143],haproxi:[191,197,545],hard:[0,5,6,11,14,16,19,20,22,30,31,41,42,46,47,54,57,62,64,68,75,77,92,113,120,123,135,146,147,149,152,153,156,159,161,174,177,180,185,191,193,227,380,386,406,416,464,466,476],hardcod:[74,134,135,149,170,193,464],hardcor:118,harden:185,harder:[5,55,118,133,146,149,156,158,161,371],hardwar:[191,429],hare:180,harm:[13,115,128,161,310],harsh:158,harvest:538,has:[2,3,5,6,8,9,11,12,13,14,15,16,18,19,20,22,27,28,30,31,32,33,35,36,37,39,41,42,44,45,46,47,48,49,50,51,53,54,55,56,57,58,60,62,64,65,67,68,70,72,73,75,76,77,78,79,81,82,85,90,92,95,96,97,98,99,104,105,106,112,113,114,118,119,120,121,122,123,124,125,126,127,128,130,131,132,133,134,135,136,137,141,142,143,144,145,146,148,149,150,151,152,153,155,157,158,159,161,164,165,166,169,171,172,174,175,176,177,178,179,180,181,182,184,185,186,187,188,190,191,193,194,195,198,199,200,203,204,205,210,211,212,213,215,217,218,223,225,226,228,229,230,232,233,234,239,241,247,251,257,270,273,275,283,289,292,299,305,308,309,310,311,312,316,329,335,337,338,339,340,343,350,354,359,364,370,371,372,380,382,386,388,390,393,394,396,397,398,402,403,405,406,409,410,411,416,418,421,425,428,430,434,438,443,444,448,454,455,456,457,459,464,465,466,467,472,474,475,476,478,479,483,485,486,489,490,492,497,500,501,508,512,513,518,532,533,540,542,543],has_account:[37,370,393,397,398],has_add_permiss:500,has_attribut:464,has_cmdset:212,has_connect:[18,232],has_consum:275,has_delete_permiss:500,has_drawn:132,has_nick:464,has_object_permiss:513,has_par:492,has_perm:[226,394],has_permiss:513,has_sub:232,has_tag:467,has_thorn:[13,153],hasattr:[22,127],hasbutton:275,hash:[15,41,77,118,191,403,411,444,448,457,465],hasher:5,hasn:[76,132,371,382,464,508,539],hassl:136,hast:310,hat:[83,286],hau:[186,205,223,427],have:[0,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19,20,22,25,27,28,30,31,32,33,34,35,36,37,39,40,41,42,44,46,47,48,50,51,52,53,54,55,56,57,58,60,62,63,64,65,67,68,69,70,72,73,74,75,76,77,78,79,82,83,86,89,90,91,92,93,95,96,97,102,104,106,108,112,113,115,116,118,119,120,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,139,140,141,142,143,144,145,146,148,149,150,151,153,155,156,157,159,160,161,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,182,184,185,186,187,188,189,190,191,192,193,194,195,197,198,199,204,205,209,211,212,213,215,218,220,223,226,227,228,229,230,232,233,234,241,247,251,256,257,260,266,270,275,276,283,286,289,292,293,296,302,308,309,310,311,312,316,337,338,349,350,354,364,372,376,377,380,382,386,388,389,390,391,393,396,397,398,401,402,403,404,405,406,409,410,411,421,426,429,430,434,436,439,440,454,455,456,457,462,463,464,465,466,467,469,470,471,472,473,475,476,477,478,479,485,488,489,490,492,493,495,497,501,508,513,515,518,523,525,532,540,541,543,544,545],haven:[3,8,9,41,76,77,99,118,124,128,136,143,170,171,172,173,177,178,187,459],havint:50,hay:77,head:[7,20,31,64,95,96,125,137,144,146,154,157,159,165,174,198,545],header:[14,15,19,30,31,35,37,50,64,72,75,120,140,143,151,185,194,213,225,233,234,299,350,398,470,472,477,478],header_color:218,header_line_char:478,headi:478,heading1:[120,478],heading2:[120,478],heading3:120,headless:398,headlong:185,heal:[104,112,114,153,157,158,293,310,311,372],healing_rang:311,healingrecip:293,health:[34,41,68,104,112,129,148,157,158,162,164,191,293,345,346,347,353,354,403,440,545],health_bar:[94,201,202,235,341,545],healthi:354,hear:[18,96,128,156,490],heard:[155,170],heart:[31,149,175],heartbeat:[47,427],heat:293,heavi:[13,19,22,33,77,79,95,123,140,144,158,162,164,165,182,283,309,350,429,492],heavier:[42,309],heavili:[19,62,67,75,77,82,115,118,119,134,155,190,195,241,308,309,310,311,312,466,544],heed:[44,394],hei:[79,144,157,283,299,349],height:[29,32,51,201,337,421,436,455,475,478],held:[20,90,164,337,393],hello:[18,28,30,32,36,44,65,68,69,72,96,97,106,120,128,142,152,157,158,165,189,223,224,232,350,421,469,490,545],hello_valu:69,hello_world:[69,151,152],helmet:[13,128,157],help:[3,5,8,11,13,14,15,16,18,19,21,22,24,25,26,27,28,30,33,39,41,42,44,45,46,49,51,53,55,57,58,64,67,69,70,76,79,86,90,92,95,96,97,98,106,108,115,116,118,120,121,123,124,128,130,131,132,134,135,138,142,143,145,147,149,150,151,153,154,155,156,157,158,159,164,165,170,175,177,180,182,185,187,188,189,191,198,199,201,202,208,209,211,213,214,215,223,226,228,229,230,247,251,254,255,257,270,273,275,278,283,289,299,308,309,310,311,312,333,336,349,354,364,369,372,376,380,396,400,410,414,416,418,419,427,434,436,437,439,441,444,445,447,448,464,465,469,472,473,474,476,477,479,487,488,489,490,496,498,499,500,502,503,506,512,515,518,523,526,531,532,533,535,544,545],help_categori:[22,31,76,135,137,141,143,164,165,188,213,215,216,217,218,223,224,225,226,227,228,229,230,241,251,255,266,269,270,273,283,286,292,293,296,299,302,305,308,309,310,311,312,316,322,325,331,343,350,364,366,370,371,372,380,386,388,389,390,398,447,474,476,477,489,540],help_cateogori:474,help_detail:540,help_entri:[31,388,474,540],help_entry1:388,help_entry_dict:[31,388],help_file_modul:388,help_kei:218,help_list:540,help_messag:225,help_mor:225,help_more_en:31,help_search_with_index:391,help_sstem:137,help_summary_text:90,help_system:137,help_text:[225,257,532],help_top:540,helpact:270,helparg:229,helpdetailtest:533,helpdetailview:540,helpentri:[31,33,49,137,225,388,389,390,472,504,515,537,540],helpentry_db_tag:504,helpentry_set:467,helpentryadmin:504,helpentryform:504,helpentrymanag:[389,390],helper:[8,28,30,39,41,57,95,104,106,112,118,135,143,145,146,149,150,153,158,201,204,212,215,218,223,225,233,241,247,275,280,292,294,336,338,339,340,349,354,398,402,403,413,425,426,445,457,470,476,477,479,485,490,491,492,502,510,516],helpfil:225,helpfilterset:[512,518],helplistseri:[515,518],helplisttest:533,helplistview:540,helplockeddetailtest:533,helpmixin:540,helpseri:[515,518],helptaginlin:504,helptext:[28,400,476],helptext_formatt:[28,400,476],helpviewset:518,henc:[4,7,76,96,97,151,152,270,372,470],henceforth:[6,11,14,33,44,63,74,131,165,170,176,191,457],henddher:[104,105,304,305],her:[58,93,155,157,286,296,479,496,497],herbal:475,herd:182,here:[2,3,5,7,8,9,10,11,12,13,14,15,16,17,19,22,26,28,30,31,32,33,34,35,36,37,40,41,42,44,45,47,48,49,51,53,54,56,57,58,60,62,64,65,67,68,69,70,72,73,75,76,77,79,82,83,86,87,95,96,97,99,104,106,107,110,112,114,115,116,118,119,120,121,123,124,125,126,128,129,130,131,132,133,134,135,136,137,139,141,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,169,170,171,172,173,174,175,177,178,180,182,183,185,186,187,188,189,190,192,193,194,195,198,199,204,205,211,212,213,218,226,227,228,230,234,241,247,251,256,257,270,273,274,275,278,280,283,286,292,293,308,309,310,311,325,329,331,338,340,343,349,350,354,359,370,371,372,382,390,394,396,398,402,403,416,418,425,427,433,434,436,439,448,454,455,457,463,464,466,469,472,476,478,483,490,496,501,508,510,513,515,521,537,540,541,545],hereaft:157,herein:77,heroism:158,herself:[30,58,157,479,496,497],hesit:[76,130],hfill_char:478,hidden:[11,13,51,88,104,116,118,123,132,153,155,156,157,225,234,270,286,343,545],hide:[13,20,22,31,33,39,75,104,106,118,144,156,157,162,170,225,234,343,350,371,545],hide_from:[35,234],hide_from_accounts_set:207,hide_from_objects_set:397,hieararci:393,hierarach:467,hierarch:[12,39,57,215,393,467],hierarchi:[26,57,63,76,124,137,156,224,286,393,492,513,545],high:[20,39,58,118,122,124,144,146,152,155,181,185,211,292,293,311,398,458,467],higher:[5,9,18,20,28,33,39,44,49,57,69,106,118,126,131,133,135,136,146,149,157,161,162,165,185,191,204,211,215,218,228,308,309,310,311,312,338,349,372,393,418,467,476,492],highest:[20,39,112,135,354,469,492],highest_protocol:488,highli:[0,17,28,33,45,47,67,75,94,104,118,119,122,123,133,151,171,346,470,483],highlight:[15,60,120,134,135,175],hijack:[178,187],hilight:491,hilit:491,hill:[36,95],hilt:[158,293],him:[28,58,93,96,106,149,296,350,479,496],himself:[58,479,496,497],hint:[9,41,53,90,104,120,122,126,138,143,149,154,159,165,169,180,185,199,247,278,462,544,545],hire:[141,194],his:[28,30,41,58,93,96,106,135,157,286,296,350,477,479,491,496],histogram:492,histor:[22,42,72,136,154,415,485],histori:[11,18,27,51,92,123,124,135,144,151,158,182,193,212,223,232,380,485],hit:[29,75,114,125,128,150,155,162,164,205,292,308,309,310,311,312,370,371,414,455,485,488,545],hit_msg:370,hite:60,hitter:143,hnow:60,hoard:158,hobbi:[86,156,159,191],hobbit:136,hobbyist:191,hoc:122,hold:[0,2,6,7,12,14,15,20,28,31,33,37,41,44,46,48,56,63,74,75,95,104,111,112,113,118,120,123,125,132,135,141,143,148,149,156,161,162,164,165,169,170,177,185,193,195,211,212,235,241,275,278,286,292,293,308,309,310,311,312,343,354,366,370,371,382,386,387,391,393,394,402,403,404,407,412,423,425,434,444,445,447,457,466,467,468,472,475,476,478,479,481,485,492,498,545],holder:[75,191,464],hole:[95,158],home:[0,11,26,37,41,52,53,56,63,104,118,123,143,148,149,158,177,181,185,191,194,212,218,224,229,370,396,397,398,403,472,492],home_loc:218,homepag:[5,19,180,185,191],homes_set:397,homogen:[19,159,402,403,406],homogenize_prototyp:402,honcho:159,hong:77,honor:[158,350],honour:[77,104],hood:[9,18,22,28,30,36,41,42,48,67,100,103,104,112,116,123,134,144,146,149,156,157,270,292,350,353,354],hook:[12,18,22,32,33,37,42,45,47,86,95,106,118,126,129,132,139,149,162,164,165,171,172,173,174,176,199,204,209,211,213,215,218,223,224,226,228,229,230,232,234,239,248,257,273,275,279,286,292,294,305,308,309,310,311,312,313,316,322,325,329,331,335,338,350,351,353,360,362,369,370,371,372,377,382,398,406,409,411,420,427,439,442,444,447,452,454,455,456,458,466,474,477,479,483,484,486,492,502,505,506,516,532,536,537,538,540,543,545],hooligan:55,hop:122,hope:[3,135,142,155,158],hopefulli:[0,51,90,132,151,155,159,170,177,181,191],horizon:136,horizont:[337,371,478,492],hors:19,host1plu:191,host:[0,11,19,37,55,73,77,104,123,156,168,182,187,192,193,194,197,349,461,492,545],host_os_i:492,hotbutton:51,hotel:191,hotspot:194,hould:158,hour:[19,87,95,136,158,176,247,480,492],hous:[41,118,159,191,218,479,545],housecat:19,how:[0,3,5,6,7,8,9,10,11,13,14,15,16,17,18,19,20,25,26,28,30,33,34,35,36,39,41,42,44,46,49,50,51,52,53,54,55,57,58,62,63,65,67,68,69,73,74,76,77,85,86,90,93,95,96,97,104,106,107,110,112,113,114,115,117,118,120,122,123,124,125,126,127,128,129,130,131,132,133,134,136,137,139,140,141,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,175,176,177,178,181,182,185,187,189,190,191,194,195,197,198,199,205,206,210,212,213,225,227,228,229,232,241,247,273,275,278,286,289,292,293,296,310,311,312,325,329,337,338,339,340,343,349,350,354,364,370,382,386,391,393,397,398,403,406,411,416,421,426,430,435,440,443,447,448,454,455,456,457,461,466,470,474,476,477,478,479,485,486,491,492,501,502,504,507,508,532,544,545],howev:[9,12,13,14,15,16,17,20,22,27,30,33,41,42,47,48,50,54,55,58,60,62,68,69,70,72,73,76,82,92,94,95,96,97,104,113,118,120,122,124,128,129,131,135,136,141,142,144,149,151,153,155,157,158,161,162,165,170,173,176,182,191,199,212,213,218,225,228,229,241,257,311,346,364,380,382,386,393,469,515],howto:[120,544,545],hpad_char:478,href:[17,137,177],hrs:247,htm:431,html5:148,html:[51,52,60,73,77,120,122,123,137,143,148,155,169,170,178,180,183,194,213,228,232,270,382,388,390,438,440,444,445,461,466,488,491,492,512,521,536,537,538,540,541,543,545],htmlchar:491,htop:[5,199],http404:[137,178],http:[0,2,8,9,10,11,40,45,49,50,51,52,53,54,56,64,69,73,75,76,77,85,90,96,120,122,123,124,130,137,148,149,154,155,164,167,170,177,178,182,184,185,186,190,191,192,194,198,201,205,223,241,270,289,382,391,418,425,427,428,429,430,431,432,438,440,443,444,445,461,469,478,491,492,495,512,532,544,545],http_request:[73,194],httpchannel:461,httpchannelwithxforwardedfor:461,httpd:181,httprequest:204,httprespons:[500,502,505],httpresponseredirect:177,huawei:191,hub:[31,180,193,233,472],hue:60,huge:[56,67,104,117,125,128,130,136,152,156,158,167,329,477],huh:[22,76],human:[5,55,62,88,104,112,123,124,134,141,156,162,171,177,292,354,538,545],humanizeconfig:124,hundr:[70,158,177,189],hung:159,hungri:67,hunt:[104,112,157,162,353,354,370],hunting_pac:370,hunting_skil:162,hurdl:132,hurri:150,hurt:[115,129,157,158,354],huzzah:75,hwejfpoiwjrpw09:75,hybrid:[158,162],hype:197,i18n:[64,147,398],iac:68,iam:77,iattribut:464,iattributebackend:464,ice:118,ice_and_fir:153,icon:7,iconv:64,id_:[502,504,506,508,532],id_str:34,idcount:447,idea:[0,7,8,10,11,22,31,33,45,50,53,55,69,75,90,95,97,114,115,119,120,122,130,132,133,137,141,146,148,151,152,156,157,158,159,161,162,163,165,174,177,178,185,188,189,213,225,226,229,283,349,403,483,491,542,545],ideal:[22,64,72,96,191,207,394],idenfi:211,ident:[6,8,13,20,22,60,65,75,95,106,131,134,143,157,199,204,226,322,350,394,396,398,405,469,470,490],identif:[19,47,457],identifi:[3,5,6,20,22,27,28,32,34,41,42,47,48,65,68,86,89,97,104,106,127,129,130,132,135,137,146,149,150,156,164,178,181,182,210,213,218,223,226,229,233,241,278,292,316,338,349,350,372,386,394,398,402,405,408,411,413,416,421,423,426,440,444,453,455,457,464,465,469,472,475,476,479,492],identify_object:233,idl:[44,55,204,205,370,398,448,455,457],idle_command:22,idle_tim:[204,398],idle_timeout:205,idmap:483,idmapp:[48,67,201,202,228,234,390,423,449,464,465,466,468,545],idnum:233,ids:[55,135,174,316,447,457,475],idstr:[34,47,407,411,453,492],idtifi:233,idx:174,ietf:432,ifconfig:187,ifier:[112,354],ifram:51,ignor:[3,8,11,15,18,19,20,22,28,30,31,32,33,39,44,48,60,65,67,120,128,135,142,143,144,148,152,161,162,171,174,182,185,191,204,210,211,212,213,218,316,331,337,338,340,350,393,397,398,411,416,421,427,428,443,444,445,464,466,469,470,475,476,487,490,492,493],ignore_ansi:492,ignore_error:204,ignorecas:[213,218,224,225,228,230,273,286,292,350,469,474,476,491],ignoredext:461,illog:95,illumin:170,illus:54,illustr:95,imag:[7,17,51,52,53,73,77,104,124,137,148,169,177,185,191,521,545],imagesconfig:124,imagin:[15,20,28,86,96,114,128,143,150,155,156,159,161,164,171,176,364,470],imaginari:[125,170,180],imeplement:329,img:17,immedi:[16,19,22,28,32,41,42,50,65,95,97,118,123,128,132,143,146,149,151,161,164,173,177,178,191,193,198,216,228,289,292,338,370,405,420,427,470,472,476,477],immers:86,immobil:126,immort:[95,370],immut:[13,411],impact:175,impass:[118,155],impati:185,imper:108,implement:[0,6,8,9,13,18,20,22,23,28,30,33,35,37,46,47,48,51,53,58,60,62,67,68,69,73,74,78,79,86,95,104,110,113,114,115,116,118,122,125,126,127,128,132,133,134,135,138,139,145,148,150,152,156,157,161,164,165,170,171,172,173,179,180,187,201,202,206,207,211,212,215,216,217,218,219,220,223,224,225,226,227,228,230,232,233,234,235,247,266,271,283,286,292,296,302,308,309,312,314,316,322,325,327,331,337,343,349,350,353,366,370,371,372,377,386,389,390,394,396,397,398,405,406,408,411,422,427,429,430,431,432,433,434,436,438,439,440,443,444,445,447,454,461,464,465,466,467,469,470,473,474,476,477,484,487,488,491,492,500,517,539,541,545],impli:[46,76],implic:78,implicit:[60,142,175],implicit_keep:403,impmement:394,impopular:158,import_cmdset:212,importantli:[18,28,144,149,157,177,394],importerror:[4,75,124,492],impos:[122,180,459],imposs:[16,28,57,70,95,118,120,132,170,174,177,191,338,402,478],impract:[22,41,118,403],imprecis:483,impress:[3,158,170],improv:[9,64,97,119,142,150,151,156,159,544,545],impur:293,in_game_error:[0,194],inabl:[185,194],inaccess:[33,97],inact:[90,275,370],inactiv:228,inadvert:312,inadyn:191,inarticul:69,inbuilt:[46,165],incant:190,incapacit:158,incarn:532,incid:[78,104,377],includ:[0,2,5,7,11,12,13,14,19,20,22,26,28,30,32,33,34,37,44,45,46,47,48,50,51,53,55,56,60,68,69,73,75,76,78,79,86,92,99,104,106,112,113,114,115,118,119,120,121,122,123,124,125,129,130,131,135,136,137,141,142,143,144,145,148,149,150,151,152,153,154,156,157,158,160,161,162,163,164,166,168,169,170,174,177,178,179,180,185,190,193,195,204,209,210,211,213,216,217,218,226,229,232,233,257,270,273,278,283,286,292,293,294,296,308,309,310,311,312,316,329,335,337,338,339,340,349,350,354,372,377,380,386,391,393,398,402,409,416,434,436,439,440,448,453,456,464,465,466,467,469,470,471,472,473,475,476,478,480,485,490,492,515,521,525,541,544],include_account:464,include_children:465,include_par:465,include_prefix:210,include_unloggedin:[434,457],inclus:[31,465,479],incoher:175,incol:[135,475,478],incom:[22,52,62,68,182,191,195,205,210,227,273,309,338,377,416,425,429,432,435,439,440,444,445,447,455,456,457,461,476,477,479,500,502,505,506,513],incomplet:[110,213,325,478],inconsist:[6,13,54,382],incorpor:[215,478],incorrect:233,increas:[33,39,48,60,79,104,112,118,136,146,149,157,162,194,283,309,311,312,338,354,372,428,434,448,474,476],increase_ind:474,incred:[113,386,418],increment:[185,464],incur:19,indata:[62,464],inde:[75,88,122,142,191],indefinit:[310,371,405,472],indent:[14,15,19,27,30,51,72,75,97,120,134,143,151,152,337,445,470,474,476,479,492],independ:[35,42,52,90,95,97,104,123,133,175,198,283,289,376],indetermin:418,index:[31,52,53,67,69,73,113,119,120,132,133,141,149,156,169,170,174,180,191,197,201,202,210,223,224,225,275,283,337,338,371,386,388,390,391,396,414,418,419,461,467,469,477,478,492,498,531,532,533,535,537,540,545],index_category_clr:225,index_to_select:386,index_topic_clr:225,index_type_separator_clr:225,indexerror:[117,178,329,465],indexread:275,indextest:533,indic:[8,28,35,58,76,93,95,97,104,113,118,120,132,136,141,142,144,151,152,170,181,205,218,225,226,275,296,337,338,350,377,386,406,409,427,428,436,443,444,457,459,461,464,469,470,476,477,492,518],individu:[13,14,15,22,30,41,68,76,95,96,97,104,118,125,132,134,135,141,149,152,162,170,176,179,188,191,212,216,232,254,257,276,292,311,343,353,354,400,403,455,467,469,478,479,486,487],ineffici:[47,171,469],inert:8,inf:[495,497],infact:22,infinit:[42,95,97,118,156,185,205,329,338,402,495,497,545],infinitely_lock:275,inflat:158,inflect:[479,495],inflict:310,inflict_condit:310,influenc:[28,54,56,76,96,156,165,278,283,492,545],influenti:180,info1:366,info2:366,info3:366,info:[0,5,7,8,11,13,14,17,18,19,22,25,26,29,31,37,38,42,44,46,48,49,53,56,58,67,68,78,118,122,123,126,135,148,149,151,157,167,179,182,183,185,193,195,204,205,207,215,216,218,225,228,230,235,251,269,275,283,299,316,340,346,372,389,390,398,416,421,425,433,434,454,455,457,465,466,467,472,475,485,492,545],infomsg:485,inforamt:[329,340,350,398,466],inform:[0,2,5,11,12,13,19,22,28,34,35,41,42,44,46,51,53,60,63,65,67,71,73,75,76,82,85,88,95,96,97,104,107,118,120,126,127,137,141,142,143,144,148,151,158,162,164,165,167,169,171,173,176,177,178,181,182,186,187,193,194,195,204,205,213,216,218,223,224,228,233,234,241,273,289,292,310,311,312,343,350,354,377,378,382,389,390,398,416,421,430,431,432,434,443,456,457,465,466,469,472,474,485,492,532,545],infrastructur:[65,120,123,159,191,194,209,426,545],infrequ:96,ing:[15,75,90,135,150,158,343],ingam:[95,96],ingame_python:[95,96,201,202,235,236,545],ingame_tim:136,ingen:64,ingo:[20,28,32,58,118,135,211,396,428,479,495,545],ingot:[292,293],ingredi:[86,104,158,275,292],ingredient1:275,ingredient2:275,ingredient3:275,ingredient_recip:275,inher:[36,54,69,112,124,354],inherit:[2,3,8,12,18,19,20,22,37,48,50,53,60,62,67,76,82,83,86,93,95,106,110,112,116,118,123,129,134,137,139,143,145,147,149,150,153,158,165,171,207,211,213,218,226,228,229,232,234,241,270,273,275,283,286,292,296,305,308,309,310,311,312,316,322,325,331,350,354,369,370,372,395,397,398,403,406,408,447,456,463,465,466,474,477,478,483,490,492,515,518,536,537,538,540,542,543,545],inheritng:403,inherits_from:[171,178,228,492,545],inifinit:402,init:[7,11,51,62,75,76,82,118,120,132,135,154,185,190,195,198,241,242,278,283,332,380,397,416,434,435,445,457],init_delayed_messag:380,init_django_pagin:477,init_evt:477,init_f_str:477,init_fill_field:[92,380],init_game_directori:416,init_iter:477,init_menu:369,init_mod:212,init_new_account:492,init_pag:[402,477],init_pars:[116,269,270],init_queryset:477,init_rang:312,init_sess:[62,456],init_spawn_valu:402,init_st:278,init_str:477,init_tree_select:[113,386],init_tru:212,initi:[0,6,10,11,13,22,27,28,42,44,45,51,52,53,75,77,79,86,92,104,113,114,118,120,123,125,128,132,135,141,143,147,156,157,161,162,165,173,177,199,204,205,212,213,229,232,234,251,254,258,260,278,283,289,292,308,309,310,311,312,336,337,338,339,349,350,354,364,369,370,371,380,386,388,396,397,398,402,407,410,411,413,414,416,418,419,420,425,426,427,429,430,431,432,434,435,436,437,438,439,440,441,443,444,445,447,455,456,457,464,469,471,474,475,476,477,479,487,488,492,501,502,504,506,508,510,526,532,543,545],initial_formdata:380,initial_ind:478,initial_setup:[201,202,412,454,545],initialdelai:[413,427,428,447],initialize_for_combat:[308,309,310,311,312],initialize_nick_templ:464,initil:444,initpath:118,inject:[52,90,148,161,194,275,339,402,416,447,448,455,470,476],inlin:[51,58,121,134,141,398,414,479,500,501,502,504,505,506,508,545],inlinefunc:[41,58,148,195,479],inlinetagform:508,inmemori:464,inmemoryattribut:464,inmemoryattributebackend:464,inmemorybackend:464,inmemorysavehandl:487,inn:99,innermost:30,innoc:[55,216],innocu:194,inobject:425,inp:[28,218,233,402,414,477,479,492],inpect:28,input:[5,8,13,15,16,17,18,19,20,27,32,36,41,44,47,51,52,53,54,58,62,65,70,73,75,76,79,86,92,99,104,106,113,118,119,120,121,129,134,135,138,142,143,144,148,149,150,154,161,170,172,177,180,195,199,204,208,209,210,213,218,223,225,226,227,228,229,233,241,278,292,293,311,338,343,349,350,353,354,371,377,380,386,389,398,401,402,403,414,416,421,425,436,444,455,457,464,465,467,474,475,476,477,478,479,486,488,490,492,493,532,545],input_arg:490,input_cleanup_bypass_permiss:492,input_cmdset:476,input_func_modul:[32,421],input_str:[30,476],input_validation_cheat_sheet:532,inputcmdset:476,inputcommand:[32,65,68],inputcompon:51,inputdebug:[32,421],inputfuc:148,inputfunc:[24,62,68,148,195,201,202,205,412,444,455,457,545],inputfunc_nam:444,inputfunct:32,inputhandl:201,inputlin:[36,224,232,464,465],insecur:191,insensit:[31,39,146,153,225,316,350,372,388,396,465,524],insert:[13,14,15,27,30,36,41,58,86,93,104,120,123,126,135,151,154,185,188,212,275,292,296,302,350,402,470,476,478,479,492],insid:[3,5,7,8,13,14,16,19,20,22,28,30,33,37,40,41,42,44,48,49,53,54,57,60,64,67,68,69,73,77,91,94,95,96,97,104,106,117,118,120,123,125,126,127,134,137,140,141,142,143,144,146,147,148,151,152,153,161,162,165,169,170,171,174,176,177,178,182,185,187,188,189,193,199,201,205,228,232,241,256,257,316,329,346,350,370,372,393,397,398,401,416,433,454,461,470,471,479,492],inside_rec:393,insiderecurs:393,insight:[3,144,155,169],insist:[142,191],inspect:[28,55,118,141,182,204,218,228,283,414,416,476],inspectdb:67,inspir:[22,58,72,90,93,103,104,157,162,164,266,296,478,492],instac:[213,292,398,455],instal:[0,3,5,6,7,8,9,10,15,64,69,94,96,97,104,114,119,120,122,123,134,135,144,147,151,154,155,157,167,178,180,184,186,192,194,199,201,202,235,244,251,266,281,283,286,289,291,299,302,305,308,309,310,311,312,314,316,322,324,341,342,346,350,352,366,377,523,544,545],installed_app:[8,67,124,137,177,178,523],instanc:[3,6,10,12,13,17,19,27,28,30,34,41,44,45,50,51,56,64,76,77,82,95,96,97,99,104,107,113,118,123,126,127,128,130,133,134,135,136,137,141,142,143,145,146,148,149,151,153,161,164,167,169,174,175,181,194,204,207,209,210,211,212,213,222,225,227,228,232,234,239,241,257,260,270,280,292,329,340,382,386,390,397,398,402,403,405,406,410,411,413,416,425,426,427,428,429,430,431,432,434,438,439,443,447,448,456,457,461,464,466,467,469,472,473,476,478,483,484,488,490,492,493,500,501,502,504,505,506,508,512,513,515,517,532,540,545],instanci:241,instant:169,instanti:[8,22,67,152,204,212,229,354,364,408,411,433,454,457,464,475],instantli:[501,508],instead:[0,5,7,9,11,13,15,18,19,20,22,28,30,34,37,39,41,42,44,46,48,53,54,55,56,57,58,60,64,65,67,73,75,76,77,78,85,86,89,90,92,94,95,96,97,100,104,106,110,112,113,117,118,119,120,123,125,126,128,129,130,132,134,135,136,141,142,144,145,146,148,149,150,151,152,153,154,156,158,159,161,164,165,167,169,170,171,172,174,175,176,177,178,180,182,185,187,191,193,194,195,197,199,204,205,212,213,215,216,218,220,223,227,228,230,232,233,241,251,260,270,273,275,280,289,292,293,308,309,310,311,312,325,329,331,337,338,340,343,349,350,353,354,369,371,380,386,393,394,396,398,403,411,416,444,445,455,459,464,466,467,472,476,477,479,483,485,487,488,489,492,496,501,508,523,532,536,537,538,540],instig:216,instil:[74,310],instnac:410,instr:[425,492],instruct:[3,6,7,11,14,15,19,32,65,68,75,96,97,99,104,114,118,119,120,122,129,134,135,141,147,151,152,154,155,156,158,180,181,182,185,187,190,191,193,197,198,204,213,228,350,377,403,411,413,416,426,428,434,439,440,444,445,447,455,457,476,486],insur:158,intal:545,integ:[20,22,30,41,44,48,60,92,104,112,130,141,142,165,210,247,286,308,309,310,311,312,338,340,343,354,372,380,393,398,465,479,488,492,493],integerfield:[177,506,532],integr:[1,49,51,104,106,114,123,124,152,157,178,180,194,229,350,419,421,476,512,545],intel:151,intellig:[65,142,158,162,178,194,212,447],intend:[3,14,17,19,20,22,30,35,41,46,51,69,76,77,78,79,82,104,105,115,118,119,122,144,156,161,169,170,175,191,194,204,241,280,283,292,340,350,389,390,398,403,434,465,467,472,473,475,478,479,489,490,492,493,510,538,541],intens:[60,146,158,180],intent:[106,194,349,492],inter:[14,118,158,337],interact:[3,7,12,22,26,28,62,69,80,118,120,122,128,133,144,152,155,158,159,161,164,177,180,182,193,199,201,217,273,312,364,416,433,470,485,490,492,545],intercept:[78,95,104,457],interchang:[39,154,164,388,476,542],interconnect:337,interest:[0,3,5,15,22,31,41,62,67,76,79,86,96,97,117,118,122,124,125,132,134,142,144,152,154,155,156,159,163,165,169,173,174,180,191,194,212,227,247,283,289,329,338,372],interestingli:157,interf:[185,364],interfac:[0,2,3,6,33,50,51,52,62,73,75,76,123,125,126,137,147,151,170,177,180,182,185,191,195,215,218,232,396,398,409,427,456,461,464,467,469,492,502,507,541,545],interfaceclass:436,interfer:[6,182,402],interim:[47,128],interlink:[433,454],intermediari:[350,394,407,476],intern:[9,13,16,18,19,28,33,36,41,44,45,46,54,62,68,70,87,89,117,146,147,148,158,164,185,187,191,193,194,195,199,204,205,234,251,292,296,329,335,337,338,350,354,362,396,398,402,408,444,445,464,466,467,469,473,476,478,492,545],internal:476,internal_port:191,internation:[70,545],internet:[22,53,54,55,56,62,182,185,187,189,191,194,198,216,413,418,426,427,428,436,439,447,461],interpret:[3,5,22,41,42,133,142,151,152,178,194,195,213,217,218,340,402,403,444,469,488,545],interract:118,interrupt:[95,161,185,209,213,229,254,257,260,331,335,436,545],interrupt_path:[118,338],interruptcommand:[22,142,161,201,209,213],interruptev:260,interruptmaplink:[118,338],interruptmapnod:[118,338],intersect:[20,211],interv:[32,42,47,81,104,112,123,164,173,174,176,205,206,247,257,293,308,309,310,311,312,354,359,370,372,405,406,411,421,472,480,492],interval1:411,intim:[20,22],intimid:135,intoexit:[218,331],intpropv:165,intricaci:136,intrigu:184,intro:[115,124,137,143,152,154,155,178,369,372],intro_menu:[201,202,235,355,368,545],introduc:[0,6,8,11,20,30,86,106,128,134,157,158,159,162,165,350],introduct:[1,11,14,15,16,56,57,77,82,138,143,144,150,154,160,163,166,167,168,185,241,544,545],introductori:[122,185],introroom:372,introspect:[105,305],intrus:175,intuit:[11,28,67,76,142,156,158,161,211],intxt:19,inv:[20,26,140,224,273,286],invalid:[13,30,41,118,142,204,338,350,354,380,402,478,479,488,492,493,496],invalid_formchar:475,invent:[112,354],inventori:[6,19,20,26,33,86,90,125,126,141,142,143,144,146,150,153,158,159,224,273,286,292,293,350,393,398,466,545],invers:[33,60,118,143,149,175,338,350,353,442,491],invert:[60,175],investig:[53,78,104,149],invis:[118,183,335,338],invisiblesmartmaplink:338,invit:[54,97,156,168,364],invitingli:[144,364],invok:[14,15,42,376],involv:[13,33,37,42,44,45,61,62,92,118,133,150,156,158,164,165,190,292,293,312,338,380,466,467,469,513],ioerror:470,ipregex:216,ipstart:[185,193,199],iptabl:194,ipv4:182,ipython:[0,5,135,545],irc2chan:[26,31,143,189,223],irc:[0,75,122,159,180,185,192,197,201,202,205,223,231,412,421,424,434,457,545],irc_botnam:205,irc_channel:205,irc_en:[189,223,393],irc_network:205,irc_port:205,irc_rpl_endofnam:428,irc_rpl_namrepli:428,irc_ssl:205,ircbot:[205,428],ircbotfactori:[205,428],ircclient:[428,457],ircclientfactori:434,irchannel:[189,223],ircnetwork:[189,223],ircstatu:[26,143,223],iron:[79,157,283,292,293,544],ironrealm:440,irregular:[81,104,359,370,372],irregular_echo:370,irrelev:[194,425],irur:29,is_account_object:133,is_act:[406,500],is_aggress:171,is_anonym:[124,137],is_anyon:124,is_authent:177,is_ban:204,is_bot:207,is_build:124,is_categori:386,is_channel:22,is_connect:[207,398],is_craft:128,is_dark:149,is_exit:[22,213],is_fight:128,is_full_moon:126,is_giving_light:371,is_gm:135,is_in_chargen:165,is_in_combat:[308,309,310,311,312],is_inst:19,is_it:492,is_iter:492,is_lit:[371,372],is_next:[207,234,390,397,406,464,466],is_o:492,is_ouch:[13,153],is_poison:13,is_prototype_bas:402,is_rest:161,is_sai:172,is_sleepi:13,is_staff:500,is_subprocess:492,is_superus:[12,50,124,204,206,207,394,398,472,500],is_thief:225,is_turn:[308,309,310,311,312],is_typeclass:[204,466],is_valid:[42,174,177,283,406,409],is_valid_coordin:[117,329],isalnum:469,isalpha:469,isb:490,isbinari:[427,444],isclos:51,isconnect:51,isdigit:[135,469],isfiremag:127,isinst:[130,492],island:99,isleaf:445,islow:469,isn:[3,17,27,76,82,95,96,97,124,133,136,137,142,146,161,185,241,254,258,270,312,372,418,469,486,495,501,508,524],isnul:488,iso:[16,70,230],isol:[8,11,14,90,119,120,123,142,151,154,156,185,193,198],isp:[191,194],isspac:469,issu:[0,3,5,8,11,13,14,15,20,22,26,37,48,54,69,74,76,115,119,120,125,128,135,141,152,157,161,165,170,175,180,181,182,184,185,191,194,223,230,245,402,416,447,448,478,544,545],istart:[3,199,201],istep:448,istitl:469,isub:164,isupp:469,ital:545,italian:64,itch:[158,185],item:[28,51,67,77,79,83,86,90,92,104,106,114,120,137,140,141,144,147,148,157,158,164,171,185,224,276,283,286,292,310,329,350,364,380,435,464,479,492,545],item_consum:310,item_func:310,item_kwarg:310,item_selfonli:310,item_us:310,itemcoordin:329,itemfunc:310,itemfunc_add_condit:310,itemfunc_attack:310,itemfunc_cure_condit:310,itemfunc_h:310,itend:492,iter:[6,13,28,30,46,99,132,143,149,204,206,233,329,338,350,362,389,396,398,403,405,409,445,447,448,464,466,467,469,470,473,477,489,492],iter_cal:477,iter_to_str:492,itl:[76,82,241],its:[3,5,8,9,10,11,12,13,15,16,18,19,20,22,27,28,29,30,31,33,34,37,39,41,42,44,47,48,49,50,51,52,55,56,58,60,62,65,67,68,72,73,75,76,78,79,82,86,90,91,92,93,95,97,101,104,105,108,110,112,113,115,117,118,120,122,123,125,126,128,130,131,132,133,134,135,136,137,139,140,141,142,143,144,146,147,148,149,150,151,152,153,154,155,157,159,161,162,165,167,169,170,171,172,174,175,177,178,182,185,186,189,190,191,192,193,194,195,204,205,207,209,210,211,212,213,216,218,226,228,232,233,241,242,245,257,266,270,275,278,283,292,293,296,305,308,309,310,311,312,325,329,331,338,340,349,350,354,362,364,370,371,380,386,396,397,398,403,410,411,416,420,421,425,429,440,442,443,444,445,448,456,457,461,462,464,465,466,467,470,475,476,478,479,483,485,486,487,488,489,490,492,496,500,501,508,510,512,521,532,536,537,538,540,542],itself:[2,5,7,8,11,13,16,17,18,19,22,28,31,33,37,39,42,44,47,48,53,58,62,64,67,73,75,76,78,82,92,95,96,97,112,113,114,118,119,120,122,123,124,125,126,128,131,132,140,141,143,144,147,148,149,151,152,153,155,164,165,169,170,172,177,178,179,182,185,187,190,195,197,198,204,205,225,232,241,260,274,275,276,278,292,311,329,338,343,350,354,359,371,372,380,382,386,387,390,391,393,396,398,400,401,403,410,416,440,445,457,461,464,467,469,472,474,476,479,487,489,492,496,497,501,508,532,542,545],iusernamepassword:436,ivanov:77,iwar:141,iwebsocketclientchannelfactori:427,iwth:411,jack:36,jail:[14,55],jam:[90,104],jamochamud:183,jan:[55,136],janni:77,januari:[95,136],jarin:191,jason:77,java:151,javascript:[49,51,52,53,68,73,77,104,122,169,194,444,445],jenkin:[83,92,94,104,113,114,165,285,286,307,308,309,310,311,312,345,346,379,380,384,386],jet:311,jetbrain:[7,180],jinja:148,jiwjpowiwwerw:13,jnwidufhjw4545_oifej:75,job:[22,33,137,187,204],jodi:77,john:[111,135,366],johnni:[78,104,376,377],johnsson:36,join:[46,75,76,90,104,132,135,146,156,158,164,165,177,185,186,189,204,223,232,266,274,283,349,469,492,545],join_fight:[308,309,310,311,312],join_rangefield:312,joiner:232,jointli:[123,212],joker_kei:[76,241],jon:77,jonca:77,josh:77,journal:170,json:[49,51,65,68,78,376,427,440,444,445,473,515],jsondata:68,jsonencod:445,jsonifi:445,jtext:469,judgement:162,jumbotron:545,jump:[0,11,14,15,28,29,37,69,113,122,125,131,132,156,158,185,273,386,414,479],jumpei:77,jumpstat:273,june:[64,95],junk:425,jupyt:545,just:[0,3,4,5,6,7,8,9,11,13,14,15,16,17,18,19,20,22,28,29,30,31,32,33,35,36,37,41,42,44,45,46,47,48,50,51,53,54,55,57,58,60,62,64,65,67,68,70,73,74,75,76,77,78,79,82,85,86,89,90,94,95,96,97,99,103,104,112,113,117,118,119,120,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,139,141,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,159,161,162,164,165,167,169,170,171,172,173,174,175,176,177,178,180,182,184,185,187,191,193,198,199,204,211,212,213,216,218,223,226,227,229,232,241,254,256,257,273,277,278,280,283,286,289,292,293,308,309,310,311,312,316,329,331,338,340,346,349,350,354,364,366,370,372,386,394,398,403,407,421,434,444,448,454,461,464,465,466,469,473,474,476,478,479,487,488,490,492,493,538,541,545],justif:[477,492],justifi:[30,41,469,477,479,492],justifii:477,justify_kwarg:477,kafka:78,kaldara:95,kaledin:77,kcachegrind:5,keep:[0,3,5,6,9,14,15,16,22,28,31,40,41,44,53,56,75,91,94,95,97,99,104,123,124,126,128,129,133,134,135,136,137,139,140,141,142,143,146,150,151,152,155,156,157,158,159,161,162,164,172,174,175,176,177,178,179,182,185,187,190,193,198,205,212,257,289,316,346,364,371,372,376,382,402,403,418,459,476,478,492],keep_log:[232,233,472],keepal:[44,439,445],keeper:[141,158],keepint:123,kei:[0,3,6,8,11,13,14,18,19,20,22,27,29,30,31,32,33,34,37,39,42,45,46,47,48,49,51,53,54,64,67,68,72,75,77,78,82,86,93,95,97,99,104,106,112,113,116,118,120,121,125,126,127,128,129,130,131,132,133,134,135,136,137,139,140,141,142,143,145,149,150,151,152,161,163,164,165,170,173,174,177,181,188,204,205,206,207,209,211,212,213,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,232,233,234,241,242,247,251,255,256,266,269,270,273,274,275,278,280,283,286,289,292,293,296,299,302,305,308,309,310,311,312,316,322,325,329,331,337,338,339,340,343,349,350,354,364,366,369,370,371,372,380,386,388,389,390,391,393,396,397,398,401,402,403,405,406,407,408,409,410,411,414,416,421,422,423,425,434,437,440,441,443,444,445,447,448,455,456,457,459,464,465,466,467,471,472,474,475,476,477,479,485,486,487,489,490,492,512,532,543,545],keith:77,kept:[5,22,31,39,53,134,142,148,218,256,257,350,403,464],kept_opt:386,kernel:0,key1:[28,302],key2:[28,302,398],key3:28,key_mergetyp:[20,211,364],keydown:51,keyerror:[292,402,411,487,492],keyfil:[437,441],keynam:[232,233,389,401,403,472],keypair:436,keys_go_back:[76,241],keystr:467,keystrok:436,keywod:478,keyword:[5,8,13,19,22,27,28,29,30,32,33,41,42,45,47,48,54,58,65,67,76,91,95,97,106,126,128,129,135,136,139,142,145,146,151,161,165,178,204,205,206,209,213,218,224,232,233,247,254,256,257,260,270,278,280,286,308,309,310,311,312,316,340,346,349,350,372,377,394,396,398,402,403,405,407,410,411,414,416,421,425,427,428,434,435,436,439,444,445,455,456,457,459,464,465,466,472,475,476,477,478,479,483,486,488,489,492,541,545],keyword_ev:[95,260],kick:[18,20,28,55,135,158,191,205,211,216,223,230,251,266,477],kildclient:183,kill:[5,19,28,44,79,144,148,156,159,164,190,193,283,370,371,407,411,416,454,461,545],killsign:416,kilogram:140,kind:[6,13,33,62,85,95,97,119,120,142,149,150,151,156,160,164,172,174,177,195,289,308,309,310,311,394,466,493,545],kindli:175,kitchen:[131,150,161,218,331],klass:64,klein:77,knee:[118,275,338],kneeabl:275,kneed:275,kneel:275,kneelabl:275,knew:[149,151],knife:[86,292,293],knight:13,knob:13,knock:[28,155],knot:[83,286],know:[0,3,5,6,9,11,12,13,14,15,16,18,20,22,28,30,31,32,33,34,37,44,48,53,54,56,58,60,62,64,65,67,70,76,85,86,95,97,104,106,108,113,118,119,120,123,125,128,130,131,132,133,134,135,137,139,140,141,142,143,144,146,148,149,150,151,152,153,154,156,157,158,159,161,162,164,169,170,171,172,174,175,176,177,178,180,181,182,184,187,189,191,192,193,195,199,213,217,218,226,229,256,283,289,299,311,338,349,364,371,386,397,398,421,455,457,464,470,471,476,492,501,508,539,545],knowledg:[14,16,22,119,122,438,457],known:[22,27,31,36,39,40,47,48,51,144,156,161,162,178,180,183,197,203,227,311,477,544,545],knuth:5,korean:64,kornewald:77,koster:180,kovash:28,kwar:466,kwarg:[13,18,22,28,30,32,33,34,41,45,47,48,51,54,62,65,68,71,86,87,95,99,112,118,126,128,135,139,161,172,174,176,178,204,205,206,207,209,212,213,215,216,217,218,223,224,225,226,227,228,229,230,232,233,234,241,247,251,254,255,256,257,266,269,270,273,274,275,276,277,278,280,283,286,292,293,296,299,302,305,308,309,310,311,312,316,322,325,329,331,338,339,340,343,349,350,354,359,362,364,366,369,370,371,372,377,380,382,386,389,390,393,394,396,397,398,400,401,402,403,405,406,407,409,410,411,413,414,421,422,423,425,426,427,428,433,434,435,436,437,439,440,441,444,445,447,449,455,456,457,458,459,461,464,465,466,467,469,472,474,475,476,477,478,479,480,482,483,485,486,487,488,489,490,492,493,500,501,502,505,506,508,512,514,515,518,532,536,537,538,540,541,542,543],kwargtyp:492,label:[46,67,74,78,144,153,154,177,512,532],label_suffix:[502,504,506,508,532],laborum:29,labyrinth:118,lack:[14,53,72,120,133,143,156,159,350,364,398,464,492],laddad:64,ladder:135,ladi:149,lag:[5,132,185],lair:15,lambda:[28,41,54,130,137,257,403,492],lamp:[170,364],lamp_breaks_msg:364,land:[142,164,370,371],landscap:[170,194],lang:[106,349],langaug:106,langcod:350,langnam:350,languag:[10,16,30,39,48,51,52,53,58,61,62,69,70,72,104,113,120,122,123,133,134,135,142,143,146,147,148,149,150,151,157,159,172,180,194,348,349,350,545],language_cod:64,languageerror:[349,350],languageexistserror:349,languagehandl:349,larg:[6,8,14,15,28,41,42,53,54,56,67,69,77,99,104,106,117,118,119,122,133,144,154,155,156,159,161,182,191,275,329,332,349,364,402,434,470,475,483,545],larger:[15,30,33,67,69,91,120,132,134,140,151,156,316,398,442,469,483,492,521,544],largest:[112,354],largesword:67,larlet:77,last:[0,2,3,11,13,14,15,18,20,22,28,32,36,37,44,45,51,58,64,67,76,79,95,113,118,120,124,128,135,137,142,145,150,151,152,153,155,156,158,159,164,169,174,175,178,184,187,199,206,209,210,212,218,223,224,247,257,283,289,308,309,310,311,312,316,350,386,398,420,469,470,471,476,477,478,480,485,492,545],last_cmd:[22,149],last_initial_setup_step:454,last_login:500,last_nam:500,last_step:420,lastcast:127,lastli:[139,170,177,209,292],lastsit:126,late:[11,95,402,471],later:[6,11,12,13,14,18,22,31,32,34,41,42,47,48,55,62,65,67,74,75,76,77,86,90,95,96,97,105,118,122,123,135,137,139,143,144,146,149,150,151,152,154,156,157,158,159,161,162,163,165,170,171,173,174,177,182,185,191,211,215,216,218,226,232,247,305,338,350,402,403,411,436,467,479,492],latest:[2,19,20,53,77,90,120,123,125,135,185,187,190,192,218,223,228,398,403,435,459,476,479,485,512,545],latin:[16,64,70,230,398,492,545],latin_nam:398,latinifi:[398,492],latter:[19,28,33,37,47,106,112,118,123,128,142,175,350,354,388,406,408,467],launch:[7,15,95,118,125,141,155,184,185,190,191,199,212,364,415,416,426,428,447,474,492,545],launchcmd:[118,201,202,235,314,330,332,545],launcher:[5,7,118,332,333,415,416,425,426,447],lava:118,law:180,layer:[20,76,147,152,397,466],layout:[9,19,31,40,48,51,53,99,118,132,133,135,149,153,329,337,398,545],lazi:492,lazy_properti:[85,112,289,353,354,492],lazyencod:445,lazyset:485,lc_messag:64,lcnorth:59,ldesc:133,ldflag:190,lead:[8,13,14,17,20,28,30,42,50,52,53,65,67,71,76,95,97,106,118,122,123,132,133,137,144,146,153,156,158,170,174,180,182,194,204,210,211,218,228,257,260,292,322,331,336,338,339,340,350,382,398,402,403,455,464,466,476,478,479,492],leak:[53,73],lean:[35,157,350],leap:[136,151,161,172],learn:[3,7,16,17,20,22,49,53,56,69,76,90,95,96,97,104,106,115,118,128,132,133,134,137,139,143,145,146,147,149,150,151,152,155,156,157,158,159,161,169,175,178,180,185,198,311,349,350,545],learnspel:311,least:[3,7,13,22,28,33,35,50,67,79,95,106,112,122,130,132,134,135,149,151,152,154,156,159,162,167,174,181,187,191,204,212,233,275,283,349,354,389,398,403,409,469,475,478,479,489,492],leasur:370,leather:[141,158,293],leatherrecip:293,leav:[5,12,18,32,51,53,76,95,97,117,125,126,135,141,144,154,162,164,165,194,215,217,218,232,241,273,275,276,277,283,329,331,372,398,410,440,444,445,476,479,483,515,545],leaver:232,led:149,ledg:115,leer:77,left:[2,19,22,30,32,33,41,51,67,76,95,117,118,120,130,134,137,141,142,146,150,155,161,170,185,204,218,224,226,275,289,308,309,310,311,312,329,337,338,346,364,371,394,403,466,469,478,492],left_justifi:41,leftmost:118,leg:453,legaci:[30,41,42,68,84,104,158,198,204,266,267,350,479,545],legal:[191,194],legend:[27,99,132,183,201,202,235,314,330,337,339,545],legend_key_except:337,legenddict:339,leidel:77,leisur:493,leland:77,len:[41,126,132,135,141,146,153,164,173,174,188,210,227,247,492],lend:27,length:[63,67,76,87,92,104,106,118,126,132,136,142,151,155,158,182,188,191,210,247,260,280,292,337,338,346,349,350,380,418,459,464,469,478,479,492,543],lengthi:126,lenient:41,less:[7,28,31,53,64,67,69,76,118,123,131,133,142,149,150,156,158,161,162,164,176,177,191,247,309,311,338,464],lesson:[143,144,145,146,147,149,150,152,153,156,158,159,161,545],let:[5,7,8,11,13,15,16,18,20,22,28,30,32,33,37,39,47,51,53,55,60,62,65,74,75,76,86,90,92,94,95,96,97,104,113,117,118,119,120,123,125,126,127,130,131,132,133,134,135,136,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,165,166,167,168,169,170,171,172,174,175,177,178,181,185,186,189,190,192,194,204,212,213,218,224,229,233,283,286,329,337,343,346,354,380,386,394,398,426,445,457,472,476,486,491,512,532,539,540,545],letsencrypt:[187,191],letter:[16,28,35,60,64,70,76,106,107,118,120,130,151,165,170,177,191,215,224,230,241,275,349,354,382,460,469,492],leve:402,level10:293,level:[0,2,4,12,13,14,18,19,27,28,30,31,33,39,44,46,48,49,50,53,57,62,63,64,69,74,76,86,95,99,106,120,122,129,134,135,137,141,144,146,151,156,158,159,161,162,170,177,180,185,188,191,195,204,206,215,218,220,221,232,241,242,245,247,273,293,299,337,349,364,386,388,393,398,403,418,455,464,466,472,474,479,480,492,513,543],lever:[22,48,273],leverag:[52,120,161,167],levi:67,lexicon:275,lhs:[126,135,226],lhslist:226,liabl:275,lib:[6,182,185,187,190],libapache2:181,libcloud:77,libcrypt:190,libjpeg:190,librari:[0,4,8,9,14,41,48,49,51,64,69,104,116,118,121,123,133,134,138,142,149,152,154,169,177,179,180,185,190,193,194,198,235,270,382,402,403,429,464,466,478,492,545],licenc:469,licens:[7,104,107,119,158,382,469,495,496,545],lid:[108,364],lidclosedcmdset:364,lidopencmdset:364,lie:[170,275],lied:275,lies:[11,22,150],life:[36,119,136,154,158,159,161,175,247,370,544,545],lift:[33,144,162,165,275,312,394,545],lifter:33,light:[15,19,42,69,120,155,156,159,182,212,309,340,371,372,403,410,469],lightabl:371,lighter:[60,309],lightest:19,lightli:[56,309],lightsail:191,lightsourc:371,lightsource_cmdset:371,lightweight:[85,104,289],like:[0,2,3,5,6,7,8,9,11,12,13,15,16,17,18,19,20,22,23,25,28,29,30,31,32,33,34,35,37,39,41,42,44,45,46,47,48,50,51,52,53,54,55,56,57,58,60,62,64,65,67,68,69,72,73,74,75,76,78,82,83,85,86,87,90,91,92,93,94,95,96,97,99,104,106,107,108,109,110,112,113,114,115,117,118,119,120,121,122,123,125,126,127,128,129,130,131,132,134,135,136,137,139,141,142,143,144,145,146,148,149,150,151,152,153,154,155,156,157,159,161,162,164,167,169,170,171,173,174,175,176,177,178,180,181,182,184,185,186,187,188,189,190,191,193,194,195,198,204,205,207,208,210,211,212,215,217,218,223,226,230,231,232,233,241,251,260,266,268,270,275,283,286,289,292,293,296,308,309,310,311,312,316,322,325,329,338,346,349,350,354,362,364,372,380,382,386,389,390,391,393,394,396,397,398,402,403,416,421,429,445,448,450,454,456,457,464,465,466,469,470,472,475,476,477,478,479,480,483,486,488,489,490,492,495,517,532,541,545],limbo:[14,15,19,63,75,76,82,97,115,118,144,148,149,155,170,174,178,185,195,218,241,331,372,420],limbo_exit:170,limit:[0,5,12,13,18,19,20,22,28,30,31,33,35,41,42,46,48,49,50,56,57,67,74,83,85,96,97,104,112,113,114,118,121,122,123,126,127,135,142,144,146,148,150,151,153,156,157,159,164,165,175,182,188,191,195,197,204,206,213,215,216,217,218,232,233,257,275,286,289,308,310,311,337,350,353,354,364,386,388,389,390,391,394,396,398,403,405,406,411,421,434,459,464,465,466,467,470,472,474,485,489,492,495,510,538,545],limit_valu:204,limitedsizeordereddict:492,limp:155,line2:150,line:[0,2,5,6,8,9,13,14,15,16,18,19,20,22,28,30,32,35,36,37,40,41,48,51,53,54,57,60,64,65,67,69,75,76,77,78,82,86,89,95,96,97,99,102,104,106,113,117,118,119,120,121,124,126,128,129,130,133,134,135,136,137,139,142,143,144,147,149,150,152,153,158,165,170,174,177,178,182,184,185,187,191,192,193,195,199,201,204,209,212,218,223,225,227,228,241,270,302,329,333,337,349,350,364,380,386,398,402,416,421,436,439,444,455,466,469,470,474,475,476,477,478,485,492,532,537,545],linear:132,linebreak:[137,469,491],lineeditor:474,lineend:491,lineno:120,linenum:474,liner:428,linereceiv:[436,439],linesend:445,lingo:[44,67,73,134],linguist:492,link:[0,8,9,12,15,17,18,20,22,26,28,31,37,44,49,52,53,62,71,75,76,95,96,114,119,122,123,124,126,128,130,132,134,137,141,143,144,146,147,148,149,151,158,165,167,170,174,177,178,184,185,189,191,192,197,204,207,218,223,254,270,331,335,336,337,338,339,394,398,406,414,416,427,431,436,439,466,491,492,505,544,545],link_button:505,link_object_to_account:505,linknam:[120,184],linknod:338,linktext:120,linkweight:338,linod:191,linux:[0,5,6,7,11,36,75,78,120,123,124,126,151,152,181,182,187,189,190,191,193,376,492,545],liquid:466,list:[0,5,6,7,9,12,13,14,15,16,18,19,20,22,26,28,30,31,32,33,35,37,41,42,44,46,48,49,50,51,53,55,60,62,63,64,67,68,70,72,73,76,78,80,83,84,86,91,92,95,96,97,98,99,102,106,107,113,118,119,122,124,126,130,132,134,135,137,140,141,142,143,144,146,147,148,151,153,155,156,157,159,161,162,164,165,167,170,174,177,178,180,182,184,185,189,191,192,194,199,204,205,206,207,210,211,212,213,215,216,217,218,223,224,225,226,228,229,232,233,234,241,244,254,255,257,258,260,266,273,274,275,283,286,289,292,296,299,302,305,308,309,310,311,312,316,329,331,337,338,339,340,346,349,350,354,364,369,370,371,376,377,380,382,386,388,389,391,394,396,397,398,402,403,405,407,408,409,411,414,416,421,422,425,426,428,430,432,434,435,440,445,448,457,459,461,464,465,466,467,469,470,471,472,473,476,478,479,485,486,489,490,492,495,496,500,501,508,510,513,515,516,517,523,525,536,537,538,540,542,543,544,545],list_callback:255,list_channel:223,list_displai:[500,502,504,505,506,507,508],list_display_link:[500,502,504,505,506,507],list_filt:[500,504,505,508],list_nod:[476,545],list_of_fieldnam:135,list_of_myscript:42,list_prototyp:402,list_select_rel:[502,504,505,506,507],list_serializer_class:518,list_set:416,list_styl:215,list_task:255,list_to_str:492,listabl:218,listaccount:228,listbucket:77,listcmdset:218,listen:[12,18,33,44,51,55,106,138,182,187,194,223,232,266,275,349,350,364,537,545],listen_address:182,listing_contact:184,listnod:476,listobject:218,listview:[537,538,540],lit:[371,372,479],liter:[14,30,31,41,50,63,134,144,224,469,479,488,492],literal_ev:[30,476,479,492,501],literari:159,literatur:545,littl:[3,11,16,22,41,42,48,53,54,75,80,95,97,99,104,113,115,117,118,120,123,124,125,126,127,134,135,137,141,142,143,144,146,148,149,150,151,152,153,154,155,156,157,158,159,161,169,170,171,172,178,188,191,193,199,275,309,350,369,372,451,464,476,492,532],live:[7,13,53,120,149,158,180,181,182,185,187,191,193,545],ljust:[30,469,479],lne:386,load:[0,5,6,7,8,11,13,14,16,20,22,27,28,41,51,52,53,55,64,77,86,90,118,128,131,133,134,135,137,140,149,150,151,152,156,162,165,169,170,174,194,207,212,224,225,228,234,257,278,294,316,337,339,349,388,390,394,397,398,402,406,410,420,423,425,456,464,466,467,470,471,474,479,484,486,487,490,492,510,525,530],load_buff:474,load_data:471,load_game_set:525,load_kwarg:487,load_module_prototyp:402,load_stat:278,load_sync_data:456,loader:[28,339,466,492],loadfunc:[27,474,487],loaf:[86,104],loc:[218,331],local0:187,local:[2,6,7,11,30,49,50,53,60,64,95,106,118,119,123,126,136,143,147,150,169,177,182,187,189,193,194,254,257,350,403,439,464,545],local_and_global_search:396,local_non_red_ros:146,local_ros:146,localecho:421,localhost:[49,50,51,52,53,73,75,124,137,154,167,177,178,182,183,185,187,190,191,198,445],locat:[4,5,8,9,11,12,14,19,20,22,25,26,28,32,33,37,41,42,46,48,49,50,51,53,55,58,63,73,74,75,77,82,90,91,95,96,97,99,101,104,105,117,118,120,123,124,125,126,129,130,132,134,135,141,142,143,144,146,147,148,149,150,151,155,157,158,161,165,169,170,171,172,174,177,181,185,187,191,193,194,198,204,209,218,224,228,232,233,241,278,280,286,292,305,316,322,329,331,335,337,338,339,340,350,362,370,372,393,396,397,398,403,445,454,464,465,466,467,470,472,476,478,485,489,518,521,523,545],location_nam:329,location_set:146,locations_set:[146,397],locattr:[371,393],lock:[18,20,22,24,26,30,35,37,41,42,46,48,50,54,55,57,76,90,95,103,106,109,118,121,124,125,126,127,128,130,131,135,136,140,141,143,144,147,148,149,161,165,177,182,188,191,195,199,201,202,204,206,213,215,216,217,218,223,224,225,227,228,229,230,232,233,234,241,251,254,255,257,258,266,273,275,283,286,292,293,296,299,302,305,316,322,329,331,338,343,350,364,366,370,371,372,388,389,390,396,397,398,402,403,405,461,464,466,467,472,474,476,486,492,493,505,513,540,545],lock_definit:394,lock_func_modul:[33,394],lock_storag:[213,215,216,217,218,223,224,225,226,227,228,229,230,234,241,251,255,266,269,270,273,283,286,292,293,296,299,302,305,308,309,310,311,312,316,322,325,331,343,350,364,366,370,371,372,380,386,388,390,398,447,464,466,474,476,477],lock_typ:33,lockabl:[35,104,109,135,275,322],lockablethreadpool:461,lockdown:[33,464,545],lockdown_mod:191,lockexcept:394,lockfunc1:33,lockfunc2:33,lockfunc:[18,22,33,39,121,126,148,150,174,195,201,202,218,223,392,467,545],lockhandl:[13,31,33,48,143,201,202,213,241,270,392,393,545],lockset:398,lockstr:[6,13,18,22,31,33,41,124,150,161,206,218,223,225,232,233,234,266,322,389,394,396,398,403,405,464,467,472,513],locktyp:[18,211,223,292,403,467,479],log:[2,5,7,9,10,11,12,13,22,25,28,32,35,37,42,44,45,50,51,52,53,54,55,63,64,67,73,78,80,90,95,115,118,120,121,122,123,124,125,126,130,131,134,135,143,144,150,154,158,161,162,165,170,174,177,178,181,182,183,185,186,187,188,189,190,191,193,199,204,206,212,216,230,232,233,250,251,276,337,338,339,376,377,380,398,406,410,416,421,425,426,430,433,434,436,439,447,448,449,455,457,459,461,466,472,485,492,500,537,538,545],log_dep:[19,485],log_depmsg:485,log_dir:[18,232,376,485],log_err:[19,485],log_errmsg:485,log_fil:[18,19,232,485],log_file_exist:485,log_info:[19,485],log_infomsg:485,log_msg:485,log_sec:485,log_secmsg:485,log_serv:485,log_trac:[19,42,172,173,485],log_tracemsg:485,log_typ:485,log_typemsg:485,log_warn:[19,485],log_warnmsg:485,logdir:2,logentry_set:207,logfil:[416,485,537,545],loggad:64,logged_in:44,loggedin:[53,434],logger:[19,42,121,172,173,201,202,376,428,468,545],logic:[3,6,28,53,54,86,90,95,97,118,124,130,131,132,137,148,158,161,170,178,275,349,397,401,420,464,476,493,515],login:[5,6,11,12,22,25,28,33,44,45,52,53,75,78,104,118,124,126,137,158,177,191,204,215,230,249,250,251,252,394,420,421,436,439,444,445,448,457,492,524,526,533,545],login_func:448,loginrequiredmixin:[538,543],logintest:533,logo:[77,545],logout:[447,448,533],logout_func:448,logouttest:533,logprefix:[426,436,439,461],lon:479,lone:[156,170,218,225],long_descript:184,long_running_funct:54,long_text:29,longer:[22,27,29,30,47,48,58,67,72,95,97,110,115,125,126,128,135,137,142,143,149,151,152,175,180,184,211,216,232,286,308,309,310,311,312,325,349,350,407,410,474,478,492,545],longest:[19,350],longrun:22,longsword:49,loo:[213,229],look:[0,2,3,5,6,8,13,14,15,16,17,19,20,22,25,26,28,30,32,33,36,37,39,41,42,44,46,48,50,52,53,54,55,56,57,58,60,62,64,65,67,68,69,73,75,76,83,86,89,90,91,92,95,96,97,100,101,102,104,106,108,113,115,118,119,120,122,123,124,125,126,128,129,130,131,132,134,135,136,137,139,140,141,142,143,146,147,148,149,150,151,152,153,154,155,156,157,159,161,162,164,167,168,169,170,171,172,174,175,177,178,182,185,187,188,190,191,193,194,199,204,205,210,212,213,215,218,224,226,229,230,250,251,256,273,274,275,286,292,302,305,310,316,329,338,339,340,349,350,362,364,369,371,372,380,386,389,393,394,397,398,400,403,405,421,436,437,444,448,464,466,470,476,478,479,486,489,490,491,492,496,500,505,532,545],look_str:204,lookaccount:135,lookat:22,looker:[5,30,58,118,132,135,165,204,275,276,286,316,329,340,350,362,398,466],lookm:22,lookstr:398,lookup:[6,13,22,33,46,58,67,209,224,376,388,396,397,402,435,467,469,482,483,488,489,492,493,545],lookup_expr:512,lookup_typ:488,lookup_usernam:28,lookuperror:469,loom:170,loop:[5,13,30,48,95,96,97,104,114,118,122,123,125,132,137,141,146,164,172,201,205,308,338,403,434,545],loopingcal:419,loos:[15,28,83,204,223,286,312,389,436,447,470],loot:[156,545],lop:146,lore:[31,135,225,388],lose:[13,44,133,156,158,164,165,193,199,310,376,427,428,436,439],lost:[48,73,97,110,120,130,133,142,170,180,199,223,325,413,426,427,428,436,439,444,464,469],lot:[0,3,5,8,11,14,16,18,19,30,31,33,41,42,46,48,50,52,53,54,58,64,67,69,73,76,82,86,89,90,92,95,96,97,99,111,113,114,118,119,121,122,124,127,130,134,135,136,137,142,143,146,148,149,150,151,152,153,154,155,156,157,158,159,161,162,163,165,170,174,177,180,185,187,191,241,247,251,309,329,350,366,371,380,461],loud:[125,161],love:[31,51,159,388],low:[20,62,63,96,158,191,211],lower:[5,12,13,18,20,22,28,39,51,54,57,60,67,112,118,126,128,132,135,136,141,155,158,191,210,211,215,226,228,337,338,350,354,421,467,469,492],lower_bound_inclus:354,lowercas:[120,151,213,350,469],lowest:[39,63,112,191,354,393,469],lpmud:72,lsarmedpuzzl:305,lspuzzlerecip:305,lst:[132,389,472],lstart:27,lstrip:[142,469],ltthe:228,ltto:59,luc:475,luciano:180,luck:[28,86,142,149,181],luckili:[11,33,170],lue:[60,469],lug:122,luggag:153,luhttp:228,lunch:[95,96],lunr:[31,225,391],lunrj:391,lurk:158,luxuri:[46,463],lvl10:293,lycanthrophi:146,lycantrhopi:146,lycantrophi:146,lycantrroph:146,lying:[170,275],m2m:467,m2m_chang:45,m_len:492,mac:[5,7,11,75,120,123,151,154,182,183,193,198,492,545],machin:[7,11,14,126,151,158,182,193,370,545],macport:[11,185],macro:[124,164],macrosconfig:124,mad:[11,354],made:[0,2,11,13,25,28,30,33,39,41,49,53,57,77,79,83,88,90,95,104,113,118,120,125,126,133,135,143,144,149,150,152,153,156,158,161,165,167,170,174,178,191,192,194,195,209,211,228,229,232,283,286,310,311,312,333,354,380,386,394,410,418,448,462,469,470,474,476,479,492],mag:475,magazin:180,mage:[28,77,146],mage_guild_block:28,mage_guild_welcom:28,magenta:175,magic:[13,33,46,74,79,94,129,155,156,157,158,174,283,293,311,346,353,418,545],magic_meadow:46,magicalforest:74,magnific:28,mai:[1,3,5,6,7,8,9,10,11,13,14,18,19,20,22,28,30,31,33,34,36,37,41,42,44,47,48,49,53,54,57,58,60,62,63,64,65,67,68,69,73,75,77,79,83,86,90,94,95,97,104,106,112,113,114,115,118,119,120,123,124,125,126,127,128,133,134,136,137,139,144,146,148,149,151,153,154,155,156,157,159,161,162,164,165,169,170,172,173,177,178,180,181,182,184,185,187,188,190,191,193,194,195,199,204,205,209,210,211,213,215,216,218,223,225,228,229,232,233,234,235,247,275,278,283,286,292,293,308,309,310,311,312,337,338,346,349,350,354,371,372,380,394,396,398,402,403,404,418,455,457,458,462,464,466,467,469,471,472,473,474,476,478,479,480,486,489,492,495,501,508,521,538,545],mail:[5,9,28,35,75,119,122,134,143,164,180,201,202,233,234,235,281,545],mailbox:[35,299],main:[4,11,14,15,16,20,22,28,31,34,37,39,40,41,42,44,46,47,48,49,51,52,53,58,62,65,67,73,76,82,92,95,96,103,104,106,118,119,123,125,129,132,133,137,139,141,142,144,147,149,150,157,158,161,164,177,178,180,182,184,191,193,195,197,199,204,207,209,215,218,223,225,229,232,234,241,257,292,294,299,329,333,339,349,350,380,390,391,397,398,403,406,416,420,421,423,428,433,435,440,454,456,461,466,467,476,477,481,489,491,492,500,506,523,541,545],mainli:[5,13,22,28,35,37,44,54,55,58,65,134,150,151,180,215,387,464,470,492],maintain:[5,11,31,47,57,69,77,104,118,119,120,124,133,153,159,182,191,193,197,198,228,230,251,333,411,544],mainten:[191,194,544],major:[15,16,30,123,134,157,174,177,182,185],make:[0,1,2,3,5,6,7,9,10,12,13,14,15,16,18,20,22,26,27,28,30,31,32,33,35,36,37,39,41,42,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,62,64,65,67,69,70,74,75,76,77,78,79,81,86,91,93,94,95,96,97,98,99,104,106,109,110,112,113,115,117,118,120,122,123,124,126,127,128,129,130,131,132,133,136,137,138,139,141,142,145,146,147,148,150,152,153,154,155,156,157,159,160,162,163,164,166,168,169,170,171,172,175,176,177,178,179,180,181,182,183,184,185,188,189,190,191,193,194,195,198,199,204,205,207,210,211,212,213,215,216,218,223,226,229,233,241,247,258,273,275,283,286,292,293,299,308,309,310,311,316,322,325,331,337,338,340,346,349,350,354,359,364,370,371,372,378,380,386,389,393,394,396,398,402,403,405,408,411,416,420,428,433,447,448,454,455,457,458,460,461,464,465,466,467,469,470,471,472,473,474,476,478,479,480,483,489,490,491,492,501,508,510,533,541,543,545],make_it:492,make_shared_login:526,make_uniqu:211,makeconnect:425,makefactori:436,makefil:120,makeit:447,makemessag:64,makemigr:[2,67,177],makeshift_fishing_rod:86,male:[58,93,296,479,496],malevol:15,malform:[339,490,493],malici:[30,194],malign:394,malysh:77,man2x1:69,man:[36,58,69,72,106,157,191,224,299,350],mana:[127,129],mana_cost:293,manaag:504,manag:[5,8,9,12,18,20,33,37,42,44,47,48,62,65,67,75,102,104,106,118,121,130,133,134,141,146,148,157,161,177,193,199,201,202,203,204,207,218,223,228,229,231,232,234,266,278,302,312,340,350,372,387,390,395,397,398,402,404,406,411,412,416,423,463,464,466,467,468,471,472,481,484,485,489,492,533,536,537,538,543,545],manager_nam:464,manchest:492,mandat:532,mandatori:[41,45,72,76,95,97,99,118],mandatorytraitkei:354,maneuv:[113,386],mangl:442,mango:[105,305],manhol:436,manhole_ssh:436,mani:[0,5,8,9,11,12,13,15,16,17,18,19,20,22,28,30,31,37,41,42,44,45,47,48,49,52,53,54,55,60,61,62,63,64,67,68,69,70,72,73,74,75,77,83,92,97,104,106,110,111,113,114,116,118,120,122,123,124,129,131,132,133,134,135,136,141,142,143,144,145,146,148,150,151,152,156,158,159,162,164,165,170,172,173,174,175,177,178,185,189,191,192,194,195,199,206,207,211,213,218,223,229,234,245,251,270,275,283,286,292,294,310,311,325,337,338,340,350,366,370,380,386,390,391,394,396,397,403,406,411,416,430,438,440,459,464,466,467,469,476,477,479,483,484,485,541],manifest:[6,148],manipul:[13,20,28,39,41,42,50,67,76,91,95,97,104,112,123,131,143,165,206,218,228,233,254,314,316,354,389,396,398,405,422,472,477,538,540],manner:[15,329,350,398,434,466],manpow:119,manual:[5,6,9,13,15,22,31,33,37,41,42,48,50,52,60,62,64,67,74,95,104,112,113,118,120,122,124,125,129,135,141,144,148,149,151,156,159,161,170,171,174,178,180,182,185,187,191,199,201,205,218,270,277,338,354,364,369,386,398,403,409,416,433,440,476,477,479,544,545],manual_paus:[42,409],manual_transl:[106,349],manytomanydescriptor:[207,234,390,397,406,464,466,467],manytomanyfield:[207,234,390,397,406,464,466,467],map10:335,map11:335,map12a:335,map12atransit:335,map12b:335,map12btransit:335,map1:[118,335,338],map2:[118,335,338],map3:335,map4:335,map5:335,map6:335,map7:335,map8:335,map9:335,map:[6,16,18,28,30,36,58,68,73,77,84,87,95,96,97,104,106,117,123,126,130,134,135,187,193,201,202,215,223,232,235,244,245,247,275,314,329,330,331,332,334,335,336,337,339,340,349,350,354,391,398,402,403,440,464,466,469,475,476,479,490,492,496,497,545],map_align:[118,340],map_area_cli:340,map_character_symbol:[118,340],map_data:[335,337],map_displai:[118,335,340],map_exampl:332,map_fill_al:[118,340],map_legend:99,map_mod:[118,340],map_modul:170,map_module_or_dict:337,map_separator_char:[118,340],map_str:[117,132,170,329],map_target_path_styl:[118,340],map_visual_rang:[118,340],mapa:118,mapb:118,mapbuild:[99,201,202,235,314,545],mapc:118,mapcorner_symbol:337,mapdata:339,maperror:[336,337],maplegend:99,maplink:[118,337,338],mapnam:[99,331,339],mapnod:[118,337,338],mapp:479,mapparsererror:[336,338],mapper:[337,479,483,497,545],mapprovid:[117,329],maps_from_modul:339,mapstr:[118,339],mapstructur:337,maptransit:336,maptransitionnod:[118,338],march:[180,485],margin:17,mariadb:545,mark:[11,14,15,22,30,31,33,50,51,53,59,60,71,73,74,113,118,120,125,132,135,143,146,151,157,185,189,191,210,217,257,280,293,316,335,337,338,382,386,457,464,466,470,475,476,479,488],mark_categori:386,markdown:[31,120,124,184],marker:[14,18,22,30,36,53,58,60,93,104,113,118,123,151,157,161,223,224,275,280,292,296,316,337,338,350,386,398,428,436,439,444,445,464,467,469,475,476,477,521],market:[158,191],markup:[31,58,60,104,139,169,201,202,218,243,244,245,468,491,492,545],martei:77,marti:77,martiniussen:77,mask:[104,106,157,305,350,377,378],maskout_protodef:305,mass:[5,138,156,545],massiv:[122,127],master:[75,88,90,96,104,112,119,120,134,155,156,162,164,172,178,185,192,193,354,462,545],match:[8,9,11,13,19,20,22,28,30,31,32,33,36,37,39,41,42,44,46,48,50,51,53,60,65,67,68,73,75,76,84,86,91,99,112,117,118,130,131,132,134,135,136,142,144,146,148,153,161,169,170,172,177,178,182,195,204,206,209,210,211,212,213,216,218,223,224,225,227,229,233,241,244,247,260,292,299,302,305,311,316,329,337,338,340,350,354,380,388,389,391,393,394,396,398,402,403,405,408,411,421,422,434,447,457,464,465,466,467,469,474,476,478,479,487,489,490,491,492,493,495,521,543,545],match_index:210,matched_charact:380,matcher:28,matches2:67,matchobject:[469,491],mate:123,materi:[86,151,158,292,293],math:130,mathemat:[157,211],matlab:0,matplotlib:449,matric:[118,337],matrix:[118,478],matt:77,matter:[2,13,20,28,31,34,44,45,64,69,75,86,97,106,118,124,126,134,136,137,142,151,152,156,161,162,164,169,171,185,194,211,292,312,338,350,370,397,421,464,545],matur:[9,31,53,69,72,151],maverick:123,max:[18,56,77,92,112,132,157,158,164,188,225,337,350,353,354,380,391,459,485,492],max_damag:310,max_dbref:465,max_depth:492,max_dist:132,max_heal:310,max_l:132,max_length:[67,132,177,350],max_lin:478,max_nest:479,max_nr_charact:158,max_num_lin:537,max_pathfinding_length:337,max_popular:537,max_rmem:483,max_siz:[335,337,485],max_tim:335,max_valu:[346,532],max_w:132,max_width:132,maxconn:187,maxdelai:[413,427,428,447],maxdepth:403,maxdiff:[229,294,351,516,527],maximum:[56,60,67,92,94,104,118,130,142,157,158,170,188,204,289,308,309,310,311,312,337,346,354,380,398,403,461,469,476,478,479,492],maxiumum:335,maxlengthvalid:204,maxnum:492,maxrotatedfil:485,maxsplit:469,maxthread:461,maxval:[479,492],maxvalu:479,maxwidth:478,may_use_red_door:41,mayb:[13,14,15,19,20,22,28,41,67,74,75,76,79,86,118,120,125,126,131,132,137,140,141,146,148,149,150,153,156,158,159,162,164,184,185,191,212,260,283,293,349,434],mcclain:77,mccormick:77,mccp:[32,183,201,202,412,421,424,545],mccp_compress:429,mcintyr:77,md5:182,meadow:[46,74,76,157,479],mean:[3,4,5,6,8,9,11,13,14,15,16,18,19,20,22,28,32,33,34,35,36,39,41,42,44,46,48,52,54,55,58,60,62,65,67,68,70,73,76,86,95,96,97,104,106,112,116,117,118,119,122,123,127,132,134,135,136,139,141,144,146,147,148,149,150,151,152,155,156,159,161,162,164,165,169,170,171,174,175,178,179,182,191,193,194,195,199,204,205,206,212,218,225,257,270,275,293,337,340,343,349,354,371,393,396,398,402,403,407,411,416,440,456,464,466,469,476,478,479,483,485,488,489,545],meaning:[213,229],meaningless:165,meant:[20,31,35,42,48,49,51,52,56,65,74,76,93,104,112,114,117,131,136,144,148,150,157,175,184,211,241,275,296,308,309,310,311,312,329,350,354,366,372,388,398,421,470,492],meanwhil:31,measaur:5,measur:[5,165,191,210,227,337,447,448,492],meat:[154,160,163,166,168,177],mech:[138,545],mechan:[4,18,19,22,27,28,41,42,48,91,104,114,127,130,135,137,142,155,156,162,164,165,175,204,205,209,276,311,316,350,392,403,411,416,420,426,434,445,456,466,474,477,481,487,538,543,545],mechcmdset:125,mechcommand:125,mechcommandset:125,meck:125,med:64,medan:64,media:[56,77,104,148,444,461,488,500,501,502,504,505,506,507,508,532],median:132,mediat:162,mediev:293,medium:56,mediumbox:425,meet:[2,117,126,148,155,157,256,329,460],mele:[114,157,312],melt:[292,293],mem:228,member:[13,18,50,67,75,158,223,224,226,398,492],membership:[75,124,146],memori:[5,20,22,31,48,53,55,67,70,73,127,133,149,151,182,190,191,204,228,232,398,410,411,449,459,464,468,477,483,487,492,545],memoryerror:185,memoryusag:449,memplot:[201,202,412,446,545],meni:241,mental:175,mention:[13,14,15,16,22,31,32,47,54,62,69,70,75,125,128,132,133,134,144,146,151,156,175,185,191,212,251],menu:[0,7,9,20,41,44,53,92,96,104,111,115,120,121,126,137,147,156,157,158,163,165,184,185,186,199,201,202,218,235,240,241,242,271,272,273,276,366,369,380,384,386,399,403,414,416,468,486,545],menu_cmdset:476,menu_data:28,menu_edit:241,menu_login:[100,201,202,235,236,545],menu_modul:476,menu_module_path:476,menu_quit:241,menu_setattr:241,menu_start_nod:366,menu_templ:[28,476],menuchoic:[28,476],menudata:[274,369,380,400,476],menudebug:[28,476],menufil:476,menunode_fieldfil:380,menunode_inspect_and_bui:141,menunode_shopfront:141,menunode_treeselect:386,menunodename1:28,menunodename2:28,menunodename3:28,menuopt:386,menutest:143,menutre:[28,476],merchandis:158,merchant:[96,104,111],mercuri:69,mere:[94,104,171,228,346],merg:[6,11,22,28,30,76,95,117,119,120,123,131,134,136,146,149,150,161,167,209,210,211,212,329,364,372,403,406,440,476,545],merge_prior:476,merger:[20,170,211,212],mergetyp:[20,28,164,211,364,372,474,476,477],merit:161,mess:[5,13,18,19,57,113,120,158,191,386],messag:[5,8,9,11,14,16,18,19,22,23,24,27,28,29,30,32,33,35,37,40,42,44,51,54,61,62,64,70,71,74,76,78,86,92,93,95,96,99,104,108,120,121,123,125,127,128,131,135,136,139,140,141,142,143,144,151,153,156,157,158,161,162,164,165,170,172,176,181,185,186,188,191,194,195,197,199,204,205,209,212,213,216,218,223,224,225,231,232,233,234,241,255,257,270,275,276,278,283,286,292,294,296,299,305,308,309,310,311,312,331,338,350,354,359,360,362,364,369,370,371,372,377,380,382,396,398,405,416,418,425,427,428,434,435,436,439,440,442,444,453,455,457,459,461,472,474,476,477,479,485,489,490,492,545],message_rout:51,message_search:233,message_templ:165,message_transform:232,messagepath:545,messagewindow:51,messeng:362,messsag:278,meta:[35,48,148,195,466,483,500,501,502,504,505,508,512,515,518,532],metaclass:[48,67,213,466],metadata:[35,377,418],metavar:270,meteor:140,meter:[94,104,346,354],method:[3,8,11,12,13,18,19,20,28,30,31,33,37,39,41,44,45,46,47,48,51,53,54,58,62,65,67,68,75,76,78,82,86,95,96,102,103,106,107,108,112,116,118,120,122,123,126,127,128,129,130,132,135,136,137,142,143,145,146,147,150,152,153,161,162,164,165,170,171,172,173,174,176,177,178,195,197,204,206,207,209,211,212,213,215,218,219,223,225,226,228,229,232,233,234,239,241,242,247,248,254,257,266,270,273,275,278,279,280,283,289,292,294,302,305,308,309,310,311,312,313,316,322,325,329,331,335,338,340,349,350,351,353,354,360,364,369,370,371,372,376,377,382,388,389,390,393,394,396,398,405,410,411,413,418,421,422,423,425,426,427,428,429,434,436,439,442,444,445,447,448,452,454,455,456,457,459,464,466,469,470,472,474,476,477,478,479,480,483,484,485,486,487,489,490,491,492,502,508,512,513,515,516,518,538,541,543,545],methodnam:[229,239,242,245,248,252,258,267,269,279,284,287,290,294,297,300,303,306,313,317,323,326,328,335,344,347,351,353,360,367,373,378,383,385,411,442,452,484,490,497,516,527,533],metric:[140,349],michael:77,microsecond:13,microsoft:[170,185],mid:[69,128,174],middl:[22,128,132,191,309,335,469],middleman:187,middlewar:[201,202,498,522,545],midnight:[95,126,136],midst:155,midwai:60,mighht:142,might:[0,3,6,8,11,15,16,17,19,20,22,28,29,31,33,37,39,42,44,47,54,55,60,62,64,76,79,95,96,97,104,107,110,115,116,122,124,126,127,128,129,130,135,136,137,139,140,141,142,143,144,154,156,158,162,164,165,169,170,173,175,176,177,181,182,185,190,191,192,193,194,195,199,212,216,218,270,283,308,309,310,311,325,377,382,398,405,445,466,469,474,485,486,492,515,532],mighti:[18,128,149,170],migrat:[2,5,8,10,45,67,75,77,104,120,148,154,170,177,182,185,190,198,199,403,545],mike:218,million:[177,182],mime:[77,233,472],mimic:[5,8,13,27,42,122,158,162,182,234,354,388,455,474],mimick:[27,123,162,447,474,477],mimim:467,min:[42,87,92,112,132,136,157,247,353,354,380,479,480],min_damag:310,min_dbref:465,min_heal:310,min_height:478,min_shortcut:[76,241],min_valu:532,min_width:478,mind:[14,15,28,54,55,94,95,104,119,122,133,134,138,151,152,155,156,157,159,161,175,178,182,184,257,283,346,382,418,492,545],mindex:210,mine:[58,96,158,194,479,496],mini:[39,58,122,148,149,150,170],miniatur:155,minim:[5,44,53,77,106,118,156,159,164,194,349,403],minimalist:[22,69,135],minimap:545,minimum:[44,76,86,92,104,112,123,135,158,162,308,309,310,311,312,354,380,421,461,466,478,479,487,492],minimum_create_permiss:513,minimum_list_permiss:513,mininum:478,minlengthvalid:204,minor:212,mint:[11,185,187],minthread:461,minu:[67,146,398,480],minut:[19,42,95,127,136,142,159,164,180,193,223,228,247,283,459,480,492],minval:[479,492],mirc:428,mirror:[44,101,118,151,180,189,201,202,235,355,545],mirth:99,mis:134,misanthrop:146,misc:24,miscelan:468,miscellan:[104,147,148],misconfigur:182,mismatch:[32,492],miss:[6,18,53,64,119,132,134,143,158,185,191,292,294,308,309,310,311,312,402,421,544],missil:[125,311],mission:137,mistak:[50,120],misus:191,mit:[180,469],mitig:[134,194,542],mix:[8,13,22,28,58,60,64,79,104,112,118,121,129,146,161,175,177,204,225,234,275,283,293,337,350,354,398,402,403,460,467,470,478,479,492],mixabl:275,mixer:275,mixer_flag:275,mixin:[8,201,202,402,450,490,498,515,518,531,535,536,537,538,540,543,545],mixtur:[139,275,479],mkdir:[2,75,185],mktime:136,mlocati:64,mmo:114,mmorpg:159,mob0:133,mob:[15,33,44,115,122,133,155,156,201,202,212,218,235,355,368,372,373,403,470,545],mob_data:133,mob_db:133,mob_vnum_1:133,mobcmdset:370,mobdb:133,mobil:[15,41,138,155,158,188,197,370,393],moboff:370,mobon:370,mock:[293,410,490],mock_random:360,mock_repeat:229,mock_tim:[290,353,452],mock_tutori:229,mockdeferlat:490,mockdelai:490,mocked_idmapp:452,mocked_o:452,mocked_open:452,mocked_randint:344,mockrandom:294,mockval:490,mod:[112,181,353,354,402],mod_import:492,mod_import_from_path:492,mod_or_prototyp:402,mod_prototype_list:402,mod_proxi:545,mod_proxy_http:181,mod_proxy_wstunnel:181,mod_secur:194,mod_ssl:545,mod_sslj:181,mod_wsgi:545,mode:[3,5,7,12,20,26,27,28,32,53,61,73,80,95,98,108,118,137,144,149,151,152,158,164,165,171,177,180,181,187,193,194,201,217,225,228,230,239,299,335,337,340,364,370,398,416,421,426,433,444,445,454,470,474,476,479,485,492,545],mode_clos:445,mode_init:445,mode_input:445,mode_keepal:445,mode_rec:445,model:[13,31,33,35,36,42,46,47,48,49,50,58,61,73,75,85,104,112,114,120,123,137,146,158,162,169,176,195,201,202,203,204,206,231,232,233,289,354,387,395,398,404,407,411,412,422,463,464,465,467,468,473,481,482,484,488,489,492,500,501,502,504,505,506,507,508,512,515,532,536,537,538,542,543,545],model_inst:488,modeladmin:[502,504,505,506,507,508],modelattributebackend:464,modelbackend:524,modelbas:483,modelchoicefield:[500,505],modelclass:[13,46],modelform:[500,501,502,504,505,506,508,532],modelmultiplechoicefield:[500,502,504,505],modelnam:[213,232,388,390,466],modelseri:515,modelviewset:518,moder:[79,106,124,130,283],modern:[13,16,54,69,100,104,129,170,175,180,187,194,429],modif:[11,22,30,53,65,95,96,97,119,126,142,165,181,193,354,462,532,545],modifi:[0,9,11,12,13,18,20,22,28,30,31,37,41,42,44,48,49,51,52,60,62,73,74,76,86,89,90,93,95,96,97,100,104,106,110,112,114,118,120,121,122,124,126,130,131,133,134,135,141,143,144,148,150,151,152,153,155,157,158,159,161,162,165,168,170,172,179,182,193,195,199,204,212,225,232,241,257,270,275,276,278,292,293,296,305,308,309,310,311,312,316,325,343,350,353,354,371,390,396,398,403,411,466,470,476,483,488,491,500,521,532,536,537,538,540,542,543,545],modul:[0,4,5,6,8,13,14,16,19,20,22,25,27,28,30,31,32,33,37,42,44,45,48,53,62,65,69,73,78,79,82,83,84,86,87,88,89,90,92,94,95,99,100,103,104,106,107,109,110,113,114,116,118,119,120,122,125,128,133,134,135,136,139,140,141,143,144,147,148,149,150,152,157,158,161,163,165,167,170,171,174,186,190,192,194,195,199,209,210,212,213,218,220,221,222,225,227,229,241,244,245,247,250,251,254,255,256,258,266,270,273,275,278,280,283,286,289,292,293,294,308,309,310,311,312,316,322,325,331,337,339,343,346,349,350,353,354,364,370,371,372,378,380,382,386,388,393,394,397,398,401,402,403,407,409,410,411,413,415,416,420,421,425,433,435,436,439,440,443,445,447,448,449,454,456,457,458,464,466,467,468,469,470,471,472,473,474,475,476,477,479,480,490,492,545],module1:119,module2:119,module_path:339,module_with_cal:479,modulepath:425,mogilef:77,moifi:316,mold:152,mollit:29,moment:[20,31,47,64,73,96,125,134,141,142,149,157,204,337,406],mona_lisa_overdr:153,monei:[67,75,79,104,156,157,158,159,191],monetari:[119,283],mongodb:77,monitor:[5,34,68,121,407,421,440,483,545],monitor_handl:[34,121,201,407],monitorhandl:[24,32,201,202,404,545],monlit:146,mono:126,monster:[31,37,41,123,128,134,149,152,156,157,158,163,218,403],monster_move_around:152,month:[77,87,95,104,119,136,187,191,247,480,485,492],monthli:[119,136],montorhandl:34,moo:[69,72,122,134,154,180,391,479],mood:[96,112,155,158,159,354],moon:[126,136,140,146],moonlight:146,moonlit:146,moor:[99,155],moral:6,more:[2,3,4,5,6,8,11,12,13,14,15,16,17,18,19,20,22,25,27,28,29,30,31,32,35,36,37,39,42,44,46,47,48,51,53,54,55,57,61,62,63,64,65,67,68,69,70,75,76,78,79,80,82,83,85,89,90,91,94,95,96,97,99,102,103,104,106,107,108,110,111,112,113,114,115,117,118,119,122,123,124,125,126,127,130,131,132,133,135,136,137,138,141,142,143,144,146,147,148,149,151,152,153,154,155,156,157,159,160,161,162,164,165,166,167,169,170,172,174,175,176,177,178,180,182,185,187,188,189,190,191,193,194,195,199,201,203,204,206,207,210,211,212,217,218,223,224,225,228,229,230,232,233,235,241,247,250,251,257,260,270,273,275,283,286,289,292,308,309,310,311,312,316,325,329,337,338,339,340,346,349,350,354,364,366,370,371,372,382,386,389,391,396,398,402,403,405,426,428,431,440,447,448,457,462,464,465,466,469,470,472,473,474,475,476,477,478,479,483,489,490,492,493,505,514,515,532,541,545],more_command:477,more_funcparser_cal:30,morennanoth:229,morennthird:229,moreov:[42,191],morn:[91,92,157,316,380],morph_engli:495,morpholog:495,mortal:[31,155],mosso:77,most:[3,5,6,8,9,13,14,17,18,19,20,22,25,28,31,32,33,35,37,44,45,47,48,49,50,51,53,54,58,60,62,65,67,68,69,70,72,74,75,76,82,86,94,95,96,97,104,106,110,112,118,119,120,123,124,126,129,130,132,133,134,135,136,137,140,142,143,144,145,146,147,148,151,152,153,154,155,157,158,159,161,162,164,165,170,171,174,175,177,181,182,185,191,193,194,195,198,204,207,211,212,215,218,226,234,241,280,292,293,308,309,310,311,312,325,335,337,338,346,349,350,354,390,391,394,397,398,402,403,406,410,439,444,454,464,465,466,467,476,477,483,484,490,492,537,545],mostli:[28,48,51,53,62,95,118,134,137,142,162,165,191,211,230,310,329,338,343,349,436,500],motiv:[14,15,37,122,156,427,428,434,435,436,439,444,445,456,457,545],mount:193,mountain:[69,99,170],mous:[51,59,476],mouth:331,movabl:275,move:[11,15,16,18,22,27,28,29,37,75,76,79,92,95,96,97,104,112,115,117,118,124,125,128,131,132,135,137,140,141,142,148,149,151,152,155,156,157,158,163,164,170,171,175,177,178,180,182,184,185,212,218,224,241,256,275,276,278,283,308,309,310,311,312,314,325,329,331,338,354,370,371,372,380,389,393,398,448,466,470,477,545],move_around:[149,152],move_callback:228,move_delai:228,move_hook:398,move_obj:329,move_posit:275,move_to:[37,97,141,161,174,325,398],movecommand:131,moved_obj:[276,329,372,398],moved_object:398,movement:[41,104,110,114,118,135,157,174,228,308,309,310,311,312,325,337,338,398],mover:312,mptt:124,mratio:[210,227],msdp:[65,421,440,545],msdp_list:421,msdp_report:421,msdp_send:421,msdp_unreport:421,msdp_var:440,msg:[3,8,12,13,14,18,19,22,23,27,28,29,33,34,37,39,44,51,54,62,67,68,72,76,85,86,93,94,95,96,97,98,99,101,104,116,120,121,126,127,128,129,131,133,135,136,140,141,142,143,149,150,151,152,161,162,164,165,170,172,174,188,201,204,205,206,213,215,218,219,223,232,233,234,270,275,278,289,292,296,299,337,338,339,340,346,354,362,364,377,394,398,427,428,455,470,472,474,476,477,485,490,492,501,502,508,545],msg_all:164,msg_all_sess:[22,213],msg_already_sit:161,msg_arriv:[95,97],msg_channel:223,msg_char:275,msg_cinemat:280,msg_content:[19,22,30,37,42,58,95,96,97,125,136,165,172,174,176,398],msg_db_tag:502,msg_help:225,msg_leav:[95,97],msg_locat:398,msg_other:283,msg_other_sit:161,msg_receiv:398,msg_room:275,msg_self:398,msg_set:467,msg_sitting_down:161,msg_standing_fail:161,msg_standing_up:161,msg_system:275,msgadmin:502,msgform:502,msglauncher2port:[416,425],msgmanag:[233,234],msgobj:232,msgportal2serv:425,msgserver2port:425,msgstatu:[416,425],msgtaginlin:502,mssp:[148,195,201,202,412,424,545],mtt:443,much:[0,1,3,5,13,14,15,16,28,31,33,37,42,47,48,53,54,58,64,70,76,82,86,95,97,106,112,113,118,123,124,126,128,130,132,133,136,137,140,142,143,144,146,149,150,151,152,154,155,158,159,161,162,163,164,170,173,174,176,177,178,180,182,185,191,207,212,217,226,241,247,289,312,337,343,349,350,354,364,371,386,456,464,467,469,470,471,478,492,510,521],muck:[134,154],mud:[6,9,16,32,33,36,40,44,47,51,58,60,62,68,69,73,74,76,90,95,104,114,122,123,125,129,132,133,142,144,148,151,155,156,159,162,164,170,171,175,176,181,182,183,185,189,191,192,193,195,197,198,199,207,212,215,312,369,413,429,430,431,436,439,440,443,470,480,545],mudbyt:180,mudconnector:[180,230],mudderi:180,muddev:185,mudform:475,mudinfo:[143,230],mudlab:180,mudlet:[183,431],mudmast:183,mudprog:[95,104],mudramm:183,mudstat:230,muhammad:491,mukluk:183,mult:[30,41,479],multi:[20,28,44,54,76,104,113,115,119,120,122,149,153,154,155,156,161,165,193,195,210,228,242,275,293,335,337,338,350,386,391,398,457,476,492,540,545],multiaccount_mod:6,multidesc:[201,202,235,281,545],multilin:491,multilink:[118,338],multimatch:[20,153,210,350,398,479,492],multimatch_str:[204,350,398,492],multimedia:[51,77],multipl:[8,15,18,19,20,22,30,31,34,37,41,44,45,47,48,50,55,60,62,68,69,76,84,86,90,95,99,102,104,113,114,118,123,129,135,136,146,148,149,151,155,156,162,165,180,182,191,195,204,209,211,216,217,218,223,225,227,228,244,251,258,266,292,296,302,308,309,310,311,316,337,338,343,346,350,353,362,372,386,394,396,398,402,403,411,414,418,421,425,440,448,464,465,470,476,478,489,490,492,501,508,545],multiplay:[18,90,104,122,134,154,158,159,160,180],multipleobjectsreturn:[204,205,207,232,234,247,257,275,276,277,283,286,296,305,308,309,310,311,312,316,322,325,329,339,340,349,350,359,362,364,366,370,371,372,382,390,397,398,402,406,409,423,449,464,467,480,484],multipli:[30,151],multisess:[61,137,476,545],multisession_mod:[12,22,44,50,123,137,158,165,177,183,204,215,219,296,398,457],multisession_modd:28,multitud:[60,134,170],multumatch:398,mundan:125,murri:492,muscular:157,muse:180,mush:[2,69,75,84,102,104,122,138,154,162,164,180,244,302,545],mushclient:[32,183,421,431],musher:180,mushman:69,mushpark:191,music:52,musoapbox:[134,180],must:[0,5,6,8,9,11,12,13,16,20,22,27,28,30,31,32,33,34,35,36,37,39,41,42,46,47,48,49,50,51,52,53,54,58,59,62,64,65,70,73,74,78,79,84,85,95,97,104,105,106,108,112,118,119,120,123,124,126,128,132,133,135,136,139,141,143,145,148,149,150,151,152,153,156,157,159,161,164,165,169,171,177,181,183,185,186,187,188,189,191,193,194,195,199,205,210,211,213,218,223,229,232,233,234,244,247,250,251,275,278,283,286,289,292,305,308,309,310,311,312,337,338,340,349,350,354,364,369,371,372,377,386,388,390,391,393,398,401,402,405,407,411,416,421,434,436,439,456,458,459,464,465,466,469,470,471,472,473,474,475,476,477,479,480,486,487,488,489,490,491,492,493,495,501,508,515,523,540,541,545],must_be_default:212,mustn:118,mutabl:[473,545],mute:[17,18,103,204,223,232,266],mute_channel:223,mutelist:[18,232],mutual:[364,465],mux2:[72,230],mux:[22,61,69,84,103,104,122,125,135,144,154,194,208,226,244,265,266,267,545],mux_color_ansi_extra_map:[84,244],mux_color_xterm256_extra_bg:[84,244],mux_color_xterm256_extra_fg:[84,244],mux_color_xterm256_extra_gbg:[84,244],mux_color_xterm256_extra_gfg:[84,244],mux_comms_cmd:[103,201,202,235,236,545],muxaccountcommand:[226,299],muxaccountlookcommand:215,muxcommand:[22,121,126,127,128,129,131,135,140,143,165,201,202,208,214,215,216,217,218,223,224,225,227,228,230,251,255,273,286,299,302,305,310,311,316,322,331,343,366,372,398,474,545],mvattr:[26,143,218],mxp:[32,59,183,201,202,225,412,421,424,436,439,469,476,491,492,545],mxp_pars:431,mxp_re:469,mxp_sub:469,mxp_url_r:469,mxp_url_sub:469,my_callback:458,my_datastor:67,my_func:152,my_funct:128,my_github_password:11,my_github_usernam:11,my_identsystem:36,my_object:128,my_port:62,my_portal_plugin:62,my_script:42,my_server_plugin:62,my_servic:62,my_word_fil:[106,349],myaccount:46,myaccountnam:153,myapp:67,myarx:75,myattr:[13,204],mybool:13,mybot:223,mycar2:36,mychair:46,mychan:18,mychannel1:223,mychannel2:223,mychannel:[18,55,223],mycharact:139,mychargen:28,mycmd:[22,31,416],mycmdget:150,mycmdset:[20,22,143,150],mycommand1:20,mycommand2:20,mycommand3:20,mycommand:[8,20,22,31,65,129,143,150,153,490],mycommandtest:490,mycompon:51,myconf:2,mycontrib:8,mycontribnam:119,mycss:51,mycssdiv:51,mycustom_protocol:62,mycustomchannelcmd:18,mycustomcli:62,mycustomview:73,mydatastor:67,mydbobj:13,mydefault:30,mydhaccount:193,mydhaccountt:193,mydhacct:193,mydict:13,myevennia:189,myevilcmdset:[20,211],myevmenu:28,myfix:11,myformclass:53,myfunc:[8,28,47,54,492],myfuncparser_cal:30,myfunct:8,mygam:[0,3,5,7,8,9,11,12,13,14,15,18,19,20,25,28,32,33,37,41,42,48,49,50,51,53,62,64,67,73,75,77,79,82,83,84,86,88,90,91,93,99,100,102,103,106,109,110,112,117,118,120,121,125,126,129,131,132,133,134,135,136,137,139,140,141,143,147,148,149,150,151,152,154,161,162,164,165,167,169,170,172,173,174,177,178,182,184,185,186,187,188,190,191,193,195,198,199,201,235,241,244,266,293,299,302,314,316,322,324,332,334,343,350,354,441,490,492,545],mygamedir:120,mygamegam:139,mygrapevin:223,mygreatgam:53,mygreatpwd:185,myhandl:45,myhousetypeclass:218,myinstanc:67,myircchan:223,mykwarg:28,mylayout:51,mylink:120,mylist2:13,mylist:[6,13,466],mylog:19,mymap:[99,118],mymenu:28,mymethod:133,mymodul:47,mymud:[7,181],mymudgam:191,mynam:[158,193],mynestedlist:473,mynod:28,mynoinputcommand:22,mynpc:165,myobj1:46,myobj2:46,myobj:[13,19,33,42,218,411],myobjectcommand:126,myothercmdset:20,myownfactori:62,myownprototyp:41,mypassw:251,mypassword:49,myplugin:51,mypobj:13,myproc:62,myproc_en:62,myprotfunc:41,myrecip:86,myreserv:30,myroom:[42,46,133,146,218],myros:37,myscript:[42,46,48],myself:[13,58,159,479,496],myserv:251,myservic:62,mysess:44,mysql:[2,9,123,492,545],mysqlclient:182,myst:545,mysteri:[31,36,190],myston:153,mystr:13,mytag:51,mytestobject:8,mytestview:53,mythic:155,mytick:411,mytickerhandl:411,mytickerpool:411,mytrait:[112,354],mytup1:13,mytup:13,mytupl:13,myusernam:49,myvar:22,myview:73,myxyzroom:118,naccount:457,nail:[86,292],naiv:[213,232,317,329,388,390,466],nake:22,name1:218,name2:218,name:[2,3,4,5,7,8,9,10,11,12,13,14,15,16,18,20,22,26,28,29,30,31,32,33,34,36,37,39,41,42,44,45,46,48,49,50,51,53,54,57,58,62,63,65,67,68,70,73,74,75,76,77,78,82,86,87,90,92,95,96,97,100,104,106,107,112,113,117,118,120,123,124,126,128,131,132,133,134,135,136,137,139,140,141,142,143,144,145,146,147,148,150,151,152,153,154,155,156,157,161,164,165,167,169,170,171,174,175,176,177,178,180,182,183,184,186,187,188,189,190,191,193,194,195,198,199,201,204,205,206,207,209,210,211,212,213,215,216,218,223,224,225,226,227,228,229,230,232,233,234,241,247,251,254,256,257,260,266,270,273,275,276,278,280,286,289,292,293,305,310,311,322,328,329,331,337,338,339,340,349,350,353,354,370,372,380,382,386,388,389,390,391,396,397,398,402,403,405,406,407,409,411,416,419,421,422,423,425,426,428,433,436,439,440,443,444,445,448,457,459,461,464,465,466,467,469,470,471,472,474,475,476,477,479,483,484,485,486,488,489,490,491,492,493,495,496,501,508,512,516,517,518,523,524,532,537,538,543,545],namecolor:386,namedtupl:254,nameerror:[3,151],namelist:299,namesak:6,namespac:[48,51,137,257,270,403,459,470,509],namn:64,napoleon:120,narg:270,narr:312,narrow:[49,118,142,150,158,161],nativ:[3,42,49,58,68,77,78,120,146,158,376,459,461,543],nattempt:28,nattribut:[28,48,164,218,396,403,455,464,466,472,476,545],nattributehandl:464,nattributeproperti:[13,464],natur:[13,16,18,19,46,68,122,180,205,478],natural_height:478,natural_kei:464,natural_width:478,navbar:53,navig:[7,9,28,75,118,120,132,170,177,178,312,540],naw:[29,183,201,202,412,424,545],nbsp:491,nchar:173,nclient:447,ncolumn:478,ncurs:201,ndb:[13,14,22,28,42,44,48,76,126,128,164,204,207,228,397,406,455,466,476],ndb_:[218,403],ndb_del:455,ndb_get:455,ndb_set:455,ndk:190,nearbi:[118,211,212,213,312],nearli:[114,148,161,469],neat:[97,167,532],neatli:[69,492],necess:62,necessari:[2,11,48,60,62,69,76,86,95,97,99,118,124,130,134,135,142,147,148,156,172,174,182,199,212,213,234,257,270,275,338,372,377,402,403,445,470,476,478,479,486,488,492,501,508],necessarili:[41,68,104,118,120,134,155,191,492],necessit:458,neck:[13,41,83,286],neck_armor:13,neck_cloth:13,necklac:[83,157,286],need:[0,2,3,5,6,7,8,9,10,11,12,13,14,15,16,18,19,20,22,25,27,28,30,31,32,33,34,36,37,41,42,44,46,47,48,50,51,52,53,54,57,58,60,62,63,64,65,67,68,70,73,74,75,76,77,78,79,80,82,85,86,87,89,90,91,93,95,96,99,104,106,112,113,116,117,118,119,120,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,139,140,141,142,143,144,146,147,148,149,151,152,153,155,156,157,159,161,162,164,165,166,167,169,170,171,172,174,175,177,178,180,181,182,184,185,186,187,188,189,190,191,192,193,194,195,198,199,204,205,206,207,211,213,215,218,223,224,226,232,241,251,255,256,257,258,270,275,276,278,280,283,289,292,293,296,305,308,309,310,311,312,316,329,331,337,338,339,349,350,354,364,370,371,372,382,386,388,394,397,398,402,403,405,416,418,421,425,433,440,445,447,455,456,457,461,464,466,467,469,470,472,476,477,478,479,480,486,487,489,490,492,495,501,503,508,510,537,541,545],need_gamedir:416,needl:305,needless:149,neg:[136,175,211,474,492],negat:[60,146,394,495],negoti:[79,283,430,432,434,443,457],negotiate_s:432,neighbor:[130,158,338],neither:[6,13,28,162,184,199,225,343,402,440,464,467,476,493],nelson:77,nenter:28,neophyt:[112,354],nerror:64,nest:[4,13,15,22,28,30,31,106,113,204,218,350,386,393,398,403,440,473,479,545],nested_mut:13,nested_r:218,nestl:170,neswmaplink:[118,338],net:[75,134,158,180,185,189,191,205,223,230,429,430,440,443,457],netrc:11,network:[62,70,121,122,123,159,180,182,186,188,189,191,194,197,205,223,427,428,433,454,457,545],neu:241,neural:158,neutral:[30,58,93,296,479,496],never:[0,1,11,13,15,19,20,22,28,30,35,39,41,47,48,55,60,67,68,90,95,106,112,118,123,133,136,142,148,149,151,152,153,156,157,158,161,172,174,177,184,187,195,204,228,256,311,312,332,349,350,354,370,394,398,455,464,473,492],nevertheless:[0,28,67,175,215,241],new_alias:[213,396],new_arriv:372,new_attrobj:464,new_channel:[135,223],new_charact:370,new_coordin:329,new_create_dict:275,new_datastor:67,new_destin:396,new_goto:476,new_hom:396,new_kei:[45,213,396,398,405],new_loc:[218,396],new_lock:[396,405],new_menu:241,new_nam:[45,218],new_name2:218,new_obj:[33,278,280,398,403,405],new_obj_lockstr:218,new_object:[41,403],new_permiss:396,new_po:275,new_posit:275,new_progress:276,new_raw_str:210,new_room_lockstr:218,new_ros:37,new_scor:276,new_script:42,new_typeclass:[204,466],new_typeclass_path:48,new_valu:[34,464],new_word:492,newbi:[122,126],newcom:[22,158,171],newer:75,newindex:386,newli:[11,49,63,96,116,135,146,151,177,206,218,232,233,241,270,278,280,292,299,337,340,382,389,396,398,403,409,472],newlin:[22,51,225,470,478],newnam:[22,218,466],newpassword:216,newstr:51,nexist:76,nexit:[8,173],next:[0,2,3,7,14,15,20,22,27,28,29,30,31,33,37,39,42,49,50,51,52,53,54,55,58,60,64,65,67,75,76,82,86,90,95,96,97,99,102,113,118,120,123,124,125,126,127,128,129,130,132,133,135,136,138,139,141,143,144,146,147,148,149,151,152,153,154,155,156,157,158,159,161,162,164,165,170,174,177,178,180,182,186,187,189,190,191,192,193,194,199,241,247,275,278,302,308,309,310,311,312,338,371,386,394,416,470,476,477,480,492,540,545],next_nod:28,next_node_nam:28,next_stat:[275,278],next_turn:[308,309,310,311,312],nextnod:476,nextnodenam:476,nextrpi:180,nfkc:204,ng2:478,nginx:181,nice:[19,31,53,55,74,76,79,83,86,97,106,115,118,132,135,136,139,149,150,156,157,170,184,191,193,283,286,350,402,545],nicer:[144,151],niceti:218,nick:[12,13,18,24,26,32,37,72,106,134,143,180,204,205,218,223,224,232,350,397,398,428,464,465,515,545],nick_typ:36,nickhandl:[13,36,464],nicklist:[205,223,428],nicknam:[11,26,36,37,72,106,224,350,397,398,428,464,465],nickreplac:464,nickshandl:515,nicktemplateinvalid:464,nicktyp:[350,398],nifti:[150,181],night:[30,91,135,156,157,176,187,316,545],nine:63,nineti:493,nit:136,nline:485,nmisslyckad:64,nnode:338,no_act:476,no_channel:[20,22,211,476],no_db:[402,403],no_default:[48,204,466],no_exit:[20,22,164,211,364,369,476],no_gmcp:440,no_log:212,no_match:241,no_mccp:429,no_more_weapons_msg:371,no_msdp:440,no_mssp:430,no_mxp:431,no_naw:432,no_obj:[20,211,364,369,476],no_of_subscrib:502,no_prefix:[204,213,215,216,217,218,223,224,225,226,227,228,229,230,232,241,251,255,266,269,270,273,283,286,292,293,296,299,302,305,308,309,310,311,312,316,322,325,331,343,350,364,366,370,371,372,380,386,398,447,474,476,477],no_superuser_bypass:[204,232,394,398,466],no_tel:33,noansi:490,nobj:173,nocaptcha:177,nocaptcha_recaptcha:177,nocolor:[139,421,436,439,444,445],nod:157,nodaemon:7,node1:[28,476],node2:[28,476],node3:[28,476],node4:28,node5:28,node:[14,41,113,141,274,332,335,337,338,339,340,369,380,386,400,414,476,545],node_abort:28,node_apply_diff:400,node_attack:28,node_background:28,node_betrayal_background:28,node_border_char:[274,476],node_create_room:274,node_destin:400,node_end:28,node_examine_ent:400,node_exit:28,node_formatt:[28,274,380,476],node_four:28,node_game_index_field:414,node_game_index_start:414,node_guard:28,node_hom:400,node_index:[332,335,338,400,476],node_join_room:274,node_kei:400,node_loc:400,node_login:28,node_mssp_start:414,node_mylist:28,node_on:28,node_opt:274,node_or_link:[336,338],node_parse_input:28,node_password:28,node_prototype_desc:400,node_prototype_kei:400,node_prototype_sav:400,node_prototype_spawn:400,node_quest:28,node_quit:274,node_readus:28,node_select:28,node_set_desc:274,node_set_nam:28,node_start:414,node_test:28,node_usernam:28,node_validate_prototyp:400,node_view_and_apply_set:414,node_view_sheet:28,node_violent_background:28,node_with_other_nam:476,nodebox:495,nodefunc:476,nodekei:476,nodenam:[28,476],nodetext:[28,274,380,400,476],nodetext_formatt:[28,274,380,400,476],noecho:[151,228],noerror:398,nofound_str:[204,350,398,492],nogoahead:438,nohom:[396,472],nois:[125,161],noisi:[191,413,418,426,436,439,447,461],noloc:218,nomarkup:[32,139],nomatch:[76,227,241,474,492],nomatch_exit:76,nomatch_single_exit:76,nomigr:8,nomin:538,non:[11,15,16,18,19,20,22,27,29,30,31,32,39,41,42,44,48,51,53,60,67,68,74,76,86,104,109,112,118,120,122,123,124,128,131,132,135,136,140,144,146,149,150,153,156,158,161,175,186,199,204,205,206,207,209,211,223,228,230,232,234,257,278,293,322,331,340,343,354,366,371,382,386,388,389,393,396,397,398,401,402,403,406,407,409,411,416,425,439,440,454,455,457,464,466,469,472,473,474,476,477,478,479,489,492,515,518,545],nonc:444,nondatabas:[455,466],none:[3,5,12,13,14,15,16,18,20,22,27,28,30,32,33,34,36,41,42,44,46,49,54,58,60,62,65,67,68,76,86,95,97,99,112,118,123,126,129,130,131,132,133,135,136,137,139,141,142,143,145,146,149,150,153,161,164,165,170,172,174,204,205,206,209,210,211,212,213,215,218,219,220,221,222,223,224,225,226,229,232,233,234,239,241,242,254,256,257,260,266,270,273,274,275,276,278,280,283,286,292,294,296,305,308,309,310,311,312,316,322,325,329,331,332,335,336,337,338,339,340,343,349,350,351,354,362,364,366,369,370,371,372,380,382,386,388,389,391,393,394,396,397,398,400,402,403,405,407,408,410,411,413,414,416,418,420,422,425,426,427,428,435,436,444,445,447,455,456,457,459,460,461,464,465,466,467,469,470,471,472,473,474,475,476,477,478,479,480,483,485,487,488,489,490,492,493,496,497,500,501,502,504,505,506,508,510,512,516,518,524,527,532,537,540,543],nonpc:165,nonsens:349,noon:[33,64,95,144,162],nop:[439,545],nopkeepal:[183,439],nor:[3,7,13,14,20,64,69,89,104,115,118,128,149,158,164,175,184,251,270,343,398,402,440,464,467],norecapcha:177,norecaptcha_secret_kei:177,norecaptcha_site_kei:177,norecaptchafield:177,normal:[4,5,6,8,9,11,12,13,14,15,16,18,19,20,22,28,30,31,32,33,35,36,39,41,44,46,48,50,51,53,54,57,60,63,64,65,67,68,70,73,74,75,77,79,80,87,91,96,104,108,109,112,115,116,118,119,120,122,123,125,126,128,129,131,132,133,134,135,136,137,139,140,141,143,144,146,149,150,151,152,155,157,164,165,167,170,174,175,178,182,189,190,191,193,195,199,204,205,207,209,210,211,212,213,215,218,225,228,232,239,245,247,270,275,283,292,308,309,310,311,312,329,337,338,340,343,354,364,370,388,397,398,400,403,411,416,425,428,429,430,432,434,448,455,457,463,464,465,466,469,470,473,476,477,483,489,490,491,492,498,515],normal_turn_end:164,normalize_nam:398,normalize_usernam:204,north:[37,59,76,80,82,95,96,97,99,110,118,131,132,144,161,170,174,218,241,325,331,337,338,339,448],north_room:99,north_south:170,northeast:[118,144,218,329,338],northern:[76,170],northwest:[118,218,337,338,339],nose:464,nosql:78,not_don:461,not_error:416,not_found:[13,218],notabl:[5,6,11,18,54,62,75,185,213,218,229,283,420,466,469,473,492],notat:[4,53,218,469,492],notdatabas:48,note:[0,3,5,7,9,10,11,12,13,14,18,19,26,30,32,33,37,39,41,42,44,45,47,48,51,53,55,57,58,59,60,64,65,67,68,70,73,75,77,78,84,86,90,91,95,97,103,104,106,108,109,112,113,116,118,119,123,124,125,126,128,132,134,135,136,137,141,143,144,146,149,150,151,152,153,154,155,156,158,161,162,164,165,169,171,174,175,177,178,182,183,185,190,191,193,194,197,199,201,202,204,205,206,210,211,212,213,215,218,219,220,223,224,225,226,228,229,230,232,233,235,244,245,247,251,256,257,260,270,275,280,283,286,292,293,296,302,305,308,309,310,311,312,314,316,322,324,329,331,337,338,339,340,343,349,350,354,364,372,382,386,388,389,393,394,396,397,398,402,403,405,411,413,416,421,425,426,428,429,433,434,435,436,439,440,441,443,444,447,449,450,455,457,461,462,464,465,466,467,469,470,471,472,473,474,475,476,477,478,479,480,483,485,487,488,489,490,492,500,501,513,515,518,521,540,545],notebook:545,notepad:[154,185],noteworthi:120,notfound:492,notgm:135,noth:[3,13,15,19,22,30,37,47,54,65,69,76,95,97,99,118,119,128,133,134,136,141,143,144,149,151,153,158,161,164,170,204,218,227,308,311,312,329,338,370,386,398,409,428,464,466,476],nother:173,notic:[2,3,11,14,22,54,55,76,82,95,96,97,118,128,130,136,137,142,144,148,149,158,161,171,174,175,182,241,359,429,539],notif:[51,124,190,299],notifi:[95,153,192,197,266,292,308,309,310,311,312,372,402],notificationsconfig:124,notimplementederror:439,notion:[47,86,136,163,164,354],noun:[58,106,349,350],noun_postfix:[106,349],noun_prefix:349,noun_transl:[106,349],nov:64,now:[0,2,6,7,9,11,12,13,15,18,19,20,22,28,30,33,35,37,38,41,42,44,47,48,49,51,52,53,54,55,58,60,67,69,73,74,75,76,79,86,87,90,92,95,96,97,104,108,112,113,117,118,122,123,125,126,127,128,130,132,133,134,135,136,137,139,140,141,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,159,161,162,165,166,167,169,170,171,172,174,175,177,178,180,182,185,186,187,188,189,190,191,192,193,194,198,199,212,223,225,247,257,283,294,329,333,354,364,380,386,394,398,428,436,457,488,490,492,544],nowher:[151,158,170,338],noxterm256:439,npc:[13,22,28,39,75,95,96,104,123,156,162,170,283,365,366,367,393,545],npcname:172,npcshop:141,nprot:173,nr_start:408,nroom:[76,173],nroom_desc:8,nrow:478,nsmaplink:[118,337,338],nsonewaymaplink:[118,338],ntf:185,nthe:364,nuanc:60,nudg:[108,179,364,461],nuisanc:194,nulla:29,num:[30,33,132,350,398],num_lines_to_append:485,num_object:146,num_objects__gt:146,num_tag:146,num_total_account:206,number:[0,2,5,6,8,13,14,19,20,22,27,28,30,35,36,42,44,45,46,47,48,49,53,54,55,73,74,77,83,87,88,90,92,94,95,97,99,104,106,107,113,117,118,120,123,125,132,134,135,136,139,141,143,146,149,150,151,152,153,155,158,161,162,164,165,170,173,178,182,187,188,191,192,193,195,201,204,205,206,210,211,212,216,218,223,224,225,233,234,247,254,256,257,260,275,286,289,292,308,309,310,311,312,331,335,337,338,340,343,346,349,350,380,382,386,396,398,402,403,405,408,414,416,421,427,428,430,434,447,448,457,459,461,464,465,467,469,470,472,474,476,477,478,479,480,483,485,489,492,495,502,517,518,532,545],number_of_dummi:416,number_tweet_output:173,numberfilt:512,numbertweetoutput:173,numer:[6,94,112,156,162,337,346,353,354,469,545],numpi:449,oak:293,oakbarkrecip:293,oakwood:293,obelisk:[155,371],obfusc:[349,350,545],obfuscate_languag:[106,349,350],obfuscate_whisp:[106,349,350],obj1:[6,8,13,30,39,41,153,218,273,292,305,312],obj1_search:273,obj2:[6,8,13,30,39,41,153,218,273,292,305,312,470],obj2_search:273,obj3:[13,153,218,292],obj4:[13,153],obj5:13,obj:[3,8,12,13,19,20,22,30,33,34,36,37,41,42,46,47,48,54,58,67,76,95,112,126,133,135,140,142,143,145,146,150,153,161,171,174,204,211,212,213,216,218,224,226,228,229,233,234,239,241,242,254,256,257,260,273,275,278,286,289,292,296,299,305,308,309,310,311,312,316,329,350,354,362,364,371,372,380,386,393,394,396,397,398,403,405,406,407,408,445,447,448,455,464,465,466,467,470,472,473,477,479,487,488,489,490,492,500,501,502,505,506,508,513,515,545],obj_desc:311,obj_detail:372,obj_kei:311,obj_nam:76,obj_prototyp:403,obj_to_chang:48,obj_typeclass:311,objattr:[371,393],objclass:[483,492],object1:22,object2:[22,283,398],object:[0,2,3,4,5,8,12,14,15,16,18,20,22,23,24,26,27,28,29,30,31,32,34,35,36,39,41,45,47,48,49,51,52,54,55,57,62,65,67,68,69,72,73,74,75,76,78,79,80,82,85,86,90,91,92,93,95,96,97,99,101,104,105,106,107,108,111,112,114,115,117,118,120,121,122,125,128,129,130,131,132,133,134,135,136,137,138,139,141,142,143,147,148,154,155,157,162,164,165,171,172,173,176,177,178,180,182,194,195,199,201,202,203,204,205,206,207,209,210,211,212,213,215,216,217,218,219,220,223,224,225,226,228,229,230,232,233,234,235,241,242,251,254,255,256,257,258,260,266,270,271,272,273,274,276,278,280,283,286,289,292,293,296,299,305,308,309,310,311,312,316,322,325,329,331,335,337,338,339,340,350,353,354,355,359,361,362,363,364,366,368,369,370,372,376,377,378,380,382,386,388,389,390,393,394,400,401,402,403,404,405,406,407,408,409,410,411,414,416,418,420,421,422,423,425,426,429,430,431,432,433,434,435,436,438,440,443,445,447,448,454,455,456,457,459,460,461,464,465,466,467,469,470,471,472,473,474,475,476,477,478,479,483,484,486,487,488,489,490,491,492,493,496,498,499,500,501,502,504,506,508,512,513,515,517,518,523,524,526,531,532,533,535,536,537,538,540,541,542,545],object_confirm_delet:543,object_detail:[538,543],object_from_modul:492,object_id:[178,505],object_or_list_of_object:58,object_pronoun:496,object_search:[178,396],object_subscription_set:397,object_tot:[206,396,405,465],object_typ:218,object_typeclass:[490,533],objectadmin:[50,505],objectattributeinlin:505,objectcr:532,objectcreateform:[500,505],objectcreateview:[538,543],objectdb:[13,46,48,50,121,173,177,201,396,397,398,403,463,464,472,477,489,500,501,505,508,512,517],objectdb_db_attribut:505,objectdb_db_tag:[501,505,508],objectdb_set:[207,464,467],objectdbfilterset:[512,518],objectdbmanag:[396,397],objectdbseri:[515,518],objectdbviewset:[517,518],objectdeleteview:[538,543],objectdetailview:[537,538,543],objectdoesnotexist:[207,234,390,397,406,423,464,467,484],objecteditform:505,objectform:532,objectlistseri:[515,518],objectmanag:[340,396,398,465],objectnam:135,objectpuppetinlin:500,objects_objectdb:67,objectsessionhandl:[12,398],objecttaginlin:505,objectupd:532,objectupdateview:[538,543],objid:33,objlist:[30,41,479],objlocattr:[371,393],objmanip:218,objmanipcommand:218,objnam:[19,48,218],objparam:403,objs2:46,objsparam:403,objtag:393,objtyp:233,obnoxi:418,obs:466,obscur:[104,106,140,189,349,350],observ:[14,15,58,68,81,104,139,144,218,224,316,350,359,372,440,470,492],obtain:[5,22,82,97,130,142,185,191,193,241,371,545],obviou:[9,18,94,97,104,118,174,194,346,543],obvious:[15,44,69,78,95,97,122,124,132,174,467],occaecat:29,occas:9,occasion:[153,191],occat:151,occation:[158,478],occur:[3,22,42,51,54,75,126,134,227,270,310,382,394,398,410,448,476,485],occurr:[96,142,165,469],ocean:[155,191],oct:[151,152],odd:[76,132,156,175,194,337],odor:135,off:[2,11,13,15,18,20,22,27,28,31,32,33,42,45,47,53,60,62,63,67,68,69,73,86,90,92,97,99,104,108,115,118,122,123,128,132,139,144,145,151,153,154,156,159,161,163,165,175,182,183,191,193,194,199,204,213,228,229,230,232,233,266,286,293,340,350,364,370,372,380,394,398,421,429,436,439,455,466,469,470,472,474,476,477,478,485,493,544,545],off_bal:128,offend:55,offer:[0,7,8,9,11,15,20,22,27,28,32,36,37,39,41,42,47,51,60,62,65,67,69,72,76,77,79,82,95,104,106,113,118,119,122,123,124,127,130,131,133,134,136,142,143,147,148,149,151,156,157,162,164,165,170,176,189,191,204,211,212,217,218,225,228,241,275,283,316,349,372,400,407,457,476],offernam:283,offici:[11,50,77,120,189,193,194,485,545],officia:29,offlin:[16,18,41,75,180,191,217,223,470],offscreen:75,offset:[49,350,474,485],often:[0,3,5,6,9,11,12,13,16,18,20,22,24,28,30,39,44,46,47,53,54,60,61,62,64,67,68,76,85,95,96,104,118,119,120,123,127,132,134,136,138,142,148,149,151,152,153,154,158,161,164,191,194,195,205,211,216,218,226,228,232,233,241,289,308,309,310,311,312,386,394,397,406,408,416,421,435,455,464,466,470,472,478,479,485,492,515,538],okai:[3,9,28,118,132,135,158,161,165,170,190,260,338],olc:[26,147,218,400,403,545],olcmenu:400,old:[5,7,9,19,20,27,28,31,33,44,48,58,60,68,75,97,103,104,120,122,125,126,130,133,135,139,141,155,158,165,170,175,185,187,191,204,211,212,215,218,233,266,280,283,317,350,394,398,403,425,465,466,469,472],old_default_set:8,old_desc:317,old_kei:[45,398],old_nam:45,old_obj:275,old_po:275,older:[12,44,53,75,123,180,183,185,218],oldnam:466,oliv:60,omit:[41,142,193],on_:241,on_bad_request:418,on_ent:[76,241],on_leav:[76,241],on_nomatch:[76,241],onam:396,onbeforeunload:51,onbuild:193,onc:[3,5,6,9,11,12,13,14,18,22,28,31,33,35,37,42,44,48,51,53,54,56,60,62,64,65,69,75,76,79,80,85,90,92,96,98,99,100,104,105,106,109,112,113,115,116,117,118,119,120,122,123,125,126,130,132,134,135,136,141,144,146,147,148,149,150,151,152,156,158,159,161,164,174,175,177,180,182,185,187,189,191,193,198,204,205,210,213,218,223,226,229,232,241,257,270,273,275,276,277,283,289,296,299,305,308,309,310,311,312,322,329,333,338,349,354,359,364,370,371,372,380,386,398,402,406,409,421,426,439,443,454,464,469,476,477,485,490,492,545],onclos:[62,427,444],onconnectionclos:51,ond:467,one:[0,2,3,4,5,6,7,8,9,11,12,13,14,15,16,18,19,20,22,25,27,28,29,30,31,32,33,35,36,37,39,40,41,42,44,46,47,48,50,51,53,54,55,56,57,58,60,64,65,67,68,69,70,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,122,123,124,125,126,127,128,131,132,133,134,135,136,137,139,140,141,142,143,144,145,146,148,149,150,151,152,153,154,155,156,157,159,161,162,164,165,167,169,170,172,174,175,176,177,178,180,182,184,185,186,187,189,191,192,193,194,195,197,203,204,207,210,211,212,213,215,216,218,223,224,227,228,229,232,233,234,241,250,257,260,270,275,276,278,280,283,286,289,292,293,294,296,299,308,309,310,311,312,316,329,335,337,338,339,340,343,349,350,354,364,366,369,371,372,378,382,386,388,389,390,393,394,396,397,398,400,401,402,403,405,406,411,416,418,420,421,426,427,428,436,439,440,448,455,456,457,461,463,464,465,466,467,469,470,472,473,475,476,477,478,479,480,483,484,485,487,488,489,490,492,493,496,505,518,532,533,538,545],one_consume_onli:275,ones:[15,18,19,20,22,26,30,31,32,33,35,41,60,65,73,75,76,82,124,134,135,139,143,144,150,159,164,175,186,189,191,193,194,211,212,213,234,241,257,308,309,310,311,312,388,402,403,420,425,457,469,478,486],onewai:218,ongo:[42,90,104,110,127,142,158,164,283,325],ongotopt:51,onkeydown:51,onli:[0,3,5,7,8,11,12,13,14,15,16,18,19,20,22,27,28,29,30,31,32,33,35,36,37,39,41,42,44,45,46,48,49,50,51,52,53,54,55,57,58,59,60,62,65,67,68,73,74,75,76,77,79,80,86,90,91,92,95,96,97,98,99,104,106,112,113,114,115,116,118,119,121,122,123,124,125,126,127,128,130,131,132,133,134,135,136,137,139,140,141,142,143,144,145,148,149,150,151,152,153,154,155,156,157,159,161,162,164,165,169,170,171,172,174,175,176,177,178,180,182,183,184,185,186,187,188,189,191,193,194,195,201,204,205,206,209,210,211,212,213,215,216,217,218,223,224,225,226,227,228,229,230,232,233,234,241,257,270,273,275,276,277,280,283,286,292,293,294,299,308,309,310,311,312,316,329,331,332,337,338,339,343,346,349,350,354,359,366,371,372,380,386,390,393,394,396,398,402,403,405,406,407,409,410,411,416,420,421,428,431,433,434,436,439,448,454,455,457,459,460,461,464,465,466,467,469,470,471,472,474,476,477,478,479,483,485,487,488,489,490,492,495,500,501,508,532,537,538,540,541,543,544,545],onlin:[9,16,18,37,53,55,69,72,82,90,92,122,123,125,134,135,137,138,148,152,154,156,158,159,160,162,163,164,165,166,168,180,182,186,188,192,195,197,198,201,215,223,232,234,241,273,380,430,470,545],onloggedin:51,onlook:[58,398],only_:354,only_nod:337,only_tim:[405,489],only_valid:403,onmessag:[62,427,444],onopen:[62,427,444],onoptionsui:51,onprompt:51,onsend:51,onset:13,ontext:51,onto:[18,20,22,51,118,122,126,131,150,156,174,189,191,212,223,293,372,397,428,473,476],onunknowncmd:51,onward:45,oob:[22,38,51,65,129,183,195,204,205,225,296,362,398,421,439,440,444,445,457,476,545],oobfunc:195,oobhandl:483,oobobject:42,ooc:[12,18,26,44,98,121,135,143,145,149,165,204,207,215,218,219,226,234,299,398],ooclook:44,oop:150,opaqu:[16,194],open:[0,3,7,10,11,20,22,26,27,31,33,39,44,52,53,59,75,76,79,82,90,92,95,96,97,104,108,109,110,118,119,120,122,123,124,134,135,137,143,144,147,149,150,151,152,158,161,162,164,165,167,170,177,178,180,182,185,186,187,188,189,190,191,194,197,218,225,228,233,239,241,273,275,280,283,312,322,325,331,337,364,371,380,459,464,472,485,492,544,545],open_chest:39,open_flag:275,open_parent_menu:241,open_submenu:[76,241],open_wal:371,openadventur:158,openhatch:180,opensourc:469,oper:[3,6,13,15,18,19,22,28,30,32,37,39,42,46,47,49,51,52,55,64,68,75,76,77,88,90,95,96,118,123,134,140,145,146,149,151,157,175,185,187,189,191,198,199,204,206,209,211,213,215,218,223,228,232,241,266,273,278,292,338,343,350,353,371,394,398,403,411,413,416,425,426,430,432,436,438,439,445,447,448,455,456,464,465,466,469,472,476,477,478,479,483,490,492,517,518,545],opic:229,opinion:[86,157],opnli:464,oppon:[162,309,311,370],opportun:[76,97,124,142,177,312],oppos:[19,37,60,194,199,455,467],opposit:[118,135,143,170,174,218,338,364],opt:[51,116,135,270],optim:[5,13,18,19,22,35,42,47,67,118,123,130,133,161,182,213,232,402,403,451,454,464],option100:28,option10:28,option11:28,option12:28,option13:28,option14:28,option1:28,option2:28,option3:28,option4:28,option5:28,option6:28,option7:28,option8:28,option9:28,option:[2,3,5,7,8,12,13,17,18,19,20,22,26,27,30,31,32,33,35,41,42,46,51,53,54,58,60,65,67,69,70,72,73,78,79,83,86,90,95,98,104,106,112,113,114,116,119,120,122,123,124,126,128,134,136,139,141,143,144,147,148,150,154,157,161,164,165,170,171,177,178,180,181,182,183,184,185,187,193,195,198,201,204,205,206,209,210,211,212,213,215,216,218,223,225,226,229,230,232,233,234,241,247,254,256,257,269,270,273,274,275,276,277,278,280,283,286,292,296,299,305,310,312,316,329,331,333,335,337,338,339,340,343,349,350,353,354,362,364,366,369,372,380,382,386,388,389,391,393,394,396,397,398,400,402,403,405,406,407,408,409,410,411,413,414,416,418,421,422,425,426,428,429,430,431,432,433,434,435,436,438,439,440,443,444,445,447,448,455,457,459,464,465,466,467,469,470,471,472,474,475,476,477,478,479,480,483,485,486,487,488,489,490,491,492,493,495,496,497,500,501,502,504,505,506,507,508,510,512,524,525,545],option_class:[201,471],option_dict:476,option_gener:476,option_kei:493,option_str:270,option_typ:487,option_valu:487,optiona:[204,413,466],optionclass:[201,202,468,471,545],optioncontain:471,optionhandl:[201,202,468,486,545],optionlist:[28,274,369,400,476],options2:51,options_dict:487,options_formatt:[28,274,369,380,400,476],optionsl:402,optionslist:369,optionsmenu:274,optionstext:[28,274,380,476],optlist:386,optlist_to_menuopt:386,optuon:349,oracl:[182,492],orang:[60,105,116,151,270,305,469],orc:[41,134,171],orc_shaman:41,orchestr:193,order:[0,2,5,9,10,11,12,13,14,15,19,20,22,27,28,30,31,33,34,36,37,39,41,42,49,50,51,54,59,64,70,75,76,82,84,86,88,92,95,97,104,114,118,123,130,131,132,135,136,137,146,148,149,150,151,155,157,158,159,164,165,169,170,174,175,177,178,182,185,188,195,198,204,209,212,213,219,224,225,228,229,241,244,270,275,283,286,292,293,294,305,308,309,310,311,312,337,338,340,343,350,354,370,371,372,380,382,393,394,396,398,403,427,439,444,448,455,464,466,469,470,476,477,478,485,489,490,492,500,502,504,505,506,507,543],order_bi:146,order_clothes_list:286,ordered_clothes_list:286,ordered_permutation_regex:350,ordereddict:[13,492],ordin:469,ordinari:99,ore:[158,292,293],org:[64,69,120,123,164,191,270,382,432,438,444,469,492,532],organ:[13,18,31,37,39,42,46,50,69,72,75,76,118,119,120,137,146,152,161,162,170,176,213,225,229,339,495],organiz:161,orient:[114,122,123,134,152],oriented_program:123,origin:[7,11,28,37,44,49,50,53,64,75,87,90,95,97,103,104,106,122,124,125,126,128,132,134,139,142,146,149,150,159,169,180,187,190,194,204,205,211,218,241,266,270,299,338,349,350,396,398,402,403,405,425,459,466,469,476,488,491,492,495,496,544],original_object:396,original_script:405,origo:[118,337],orm:30,ormal:469,orthogon:118,oscar:[213,232,388,390,466],osnam:492,oss:7,ostr:[204,206,233,389,396,405,489],osx:[11,185],other:[2,6,8,9,12,13,14,15,16,17,18,19,20,23,27,28,30,31,32,33,35,36,37,41,44,45,46,47,48,49,51,52,54,55,56,57,59,60,62,64,65,67,68,69,70,73,74,75,76,77,78,79,83,86,87,92,95,96,97,98,99,104,106,109,112,113,114,117,118,119,120,121,122,123,124,125,126,127,128,130,131,132,134,135,136,137,139,140,141,142,143,144,145,146,148,149,150,152,154,156,157,159,161,162,164,165,169,170,171,172,173,174,175,177,178,181,185,186,187,188,193,194,197,198,199,204,206,209,210,211,212,213,218,223,224,225,226,229,230,232,233,245,247,251,256,270,273,274,275,280,283,286,289,292,299,308,309,310,311,312,322,329,337,338,340,349,350,354,364,372,377,380,386,388,390,394,397,398,402,403,407,409,411,414,416,421,425,427,428,434,436,439,448,455,456,458,464,466,468,469,470,472,474,475,476,477,478,479,486,487,489,490,492,493,496,508,537,538,540,545],other_modul:147,other_obj:275,othercondit:143,othermodul:53,otherroom:[109,322],others_act:275,otherwis:[3,5,6,11,16,19,20,22,28,30,37,41,42,44,60,64,65,67,73,84,95,97,101,112,117,118,120,124,126,128,130,136,137,142,146,151,153,156,165,174,179,182,191,193,194,201,206,210,211,215,218,223,232,244,254,257,275,278,280,283,292,308,309,310,311,312,316,329,331,350,354,362,380,388,394,398,401,402,403,410,416,427,428,436,455,459,460,469,476,477,479,485,489,490,492,501,536,537,538,540,542],otypeclass_path:396,ought:495,our:[0,2,3,9,11,12,13,15,20,22,26,33,39,47,51,56,58,62,64,65,68,72,73,74,75,86,95,96,99,104,113,117,119,120,122,123,124,125,126,129,130,131,132,134,135,136,138,139,140,141,142,144,146,148,150,152,153,154,157,159,160,161,162,163,164,165,166,167,168,169,170,171,176,178,179,180,181,182,185,187,189,190,191,192,193,194,198,207,212,226,234,293,316,329,370,371,386,394,407,461,479,485,496,497,501,508,515,545],ourself:[150,165],ourselv:[33,36,50,58,97,135,143,144,146,150,156,158,161,172,176,204,429,430,432,443,479,496,545],out:[0,3,5,6,8,11,14,15,16,17,18,22,24,28,30,31,35,37,39,41,42,44,49,51,52,53,54,55,56,57,58,63,67,68,69,72,73,75,76,78,79,86,89,90,92,95,96,97,98,99,103,104,106,109,110,112,115,118,119,120,121,122,123,125,126,127,128,130,131,132,133,134,136,137,142,144,145,146,147,148,149,150,151,152,153,154,155,156,157,159,160,161,163,164,165,166,167,168,170,171,174,175,177,180,181,182,184,185,187,188,191,193,195,198,203,204,210,211,215,217,218,223,247,251,266,269,273,275,283,292,293,299,308,309,310,311,312,322,325,331,337,338,339,340,349,350,354,369,371,376,377,380,402,403,409,416,418,440,444,445,447,456,457,464,473,475,476,478,479,491,492,495,500,508,532,544,545],outcom:[67,120,162,211,292,343,394,398,402],outdat:[181,187],outdata:[62,457],outdoor:[46,118,155,158,176,372],outer:[146,147,478],outermost:[13,30,32,128,147,151,161,250],outerwear:[83,286],outfunc_nam:62,outgo:[30,44,68,71,118,187,191,205,338,398,428,440,456,479,492,496,545],outgoing_port:191,outlet:191,outlin:[2,26,118,170,177,427],outlist:337,outmessag:398,output:[0,5,7,9,15,19,28,29,30,31,32,44,49,51,60,62,64,68,69,70,72,73,76,82,118,120,124,135,142,143,144,148,149,151,153,154,158,164,165,170,173,174,175,180,182,193,199,201,202,213,223,225,228,230,235,241,247,292,293,296,308,309,310,311,312,337,338,374,375,377,398,416,421,436,440,448,455,469,476,477,479,485,488,490,492,545],output_nam:292,output_prototyp:[86,292,293],outputcmd:440,outputcommand:[32,65,545],outputfunc:[24,62,65,68,398,421,427,545],outputfunc_nam:[62,421],outputfunct:65,outrank:465,outright:[55,191],outro:[115,155,372],outroroom:372,outsid:[14,16,30,31,41,46,49,52,53,64,68,69,77,95,97,99,114,118,120,123,125,130,134,144,148,151,152,153,157,158,162,174,178,187,193,195,199,225,311,332,337,338,370,382,388,393,440,455,456,464,467,478,523,545],outtempl:464,outtxt:19,outward:[132,191],oven:[86,104],over:[2,4,5,6,8,9,13,14,15,16,17,18,19,20,22,28,41,42,44,46,47,48,49,51,53,56,60,61,62,65,68,69,70,72,88,92,95,99,104,109,118,120,127,130,132,134,135,139,141,143,146,149,150,151,152,156,158,161,162,164,169,170,172,175,177,181,184,191,193,194,204,212,233,293,308,309,310,311,312,322,338,372,380,386,398,411,420,434,436,439,441,445,447,449,462,466,470,483,488,541],overal:[49,54,67,133,134,188,191,211,226,309,545],overcom:170,overdo:149,overhead:[19,42,70,117,176,182,329,350,464],overhear:[106,349],overheard:[104,106],overlap:[20,136,349,469,478],overload:[6,20,22,28,32,37,47,62,76,109,129,131,134,150,165,169,171,195,204,211,213,227,232,241,245,270,273,292,296,305,308,309,310,311,312,316,322,325,331,350,369,370,371,372,398,403,411,420,439,447,456,474,476,477,478,486,545],overpow:158,overrid:[2,5,13,18,20,28,30,31,33,41,42,44,45,49,50,51,53,65,73,75,76,77,82,86,95,116,118,121,124,125,126,137,142,143,144,148,150,152,167,171,172,174,184,204,213,218,223,225,229,232,233,241,257,269,270,277,278,292,310,312,316,331,338,339,340,349,362,372,378,388,394,398,402,403,409,439,457,461,464,469,476,477,479,483,485,486,489,500,501,502,506,508,518,537,538,540,543,545],overridden:[35,53,62,118,124,169,204,218,241,242,270,338,353,402,466,477,479,500,543],override_set:45,overriden:[204,225,350],overrod:56,overrul:[12,39,204,212,350,398,478],overseen:162,overshadow:156,overshoot:492,oversight:134,overview:[0,1,5,16,50,56,96,115,119,134,138,154,157,160,163,165,182,194,545],overwhelm:[96,113,146,156],overwrit:[64,77,150,169,218,225,434,465,541],overwritten:[22,30,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,178,372,467],owasp:532,owen:292,owllex:[85,104,288,289],own:[0,4,5,8,9,11,13,14,17,18,19,20,26,28,30,31,33,36,41,42,44,45,46,48,49,52,53,54,57,58,65,67,68,69,72,73,75,76,78,83,86,89,91,95,98,100,104,106,108,113,114,115,116,117,118,119,120,122,123,124,125,126,128,129,134,136,138,139,141,142,144,147,148,149,150,152,154,155,156,157,159,160,163,165,166,167,168,169,170,174,176,177,178,179,181,185,187,188,189,190,192,194,195,201,202,207,209,210,211,212,218,226,235,247,266,270,274,275,286,299,308,309,310,311,312,316,329,337,338,341,349,350,352,371,377,380,393,394,398,403,421,448,456,466,469,470,471,477,478,483,485,486,490,492,518,538,545],owner:[33,39,57,124,141,158,182,204,394,486],owner_object:33,ownership:[77,191,193],oxford:492,p_id:177,p_str:126,pace:[158,370],pack:[52,65,115,425],packag:[4,5,6,8,9,31,50,68,69,73,75,77,118,119,120,123,147,148,179,181,182,185,189,190,191,193,198,201,203,208,214,231,235,278,387,392,395,404,412,416,425,440,444,463,468,498,512],package_nam:123,packagenam:123,packed_data:425,packeddict:[6,466],packedlist:[6,466],packet:[65,436],pad:[17,30,469,478,479,492],pad_bottom:478,pad_char:478,pad_left:478,pad_right:478,pad_top:478,pad_width:478,page1:275,page2:275,page:[0,2,7,8,10,11,14,15,17,20,22,23,26,28,29,30,31,35,37,48,49,50,51,52,55,56,58,62,64,68,69,72,75,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,122,123,125,126,127,134,135,138,139,143,144,147,156,157,159,162,175,177,178,180,181,182,187,189,190,191,193,194,195,197,199,200,213,218,223,224,232,275,388,390,402,445,466,476,477,492,498,503,505,506,508,521,530,534,540,541,543,544,545],page_back:477,page_ban:[55,223],page_end:477,page_formatt:[402,477],page_next:477,page_quit:477,page_titl:[537,538,540,542],page_top:477,pageno:[402,477],pager:[29,31,477],pages:[28,476],pagin:[31,49,121,402,477],paginag:477,paginate_bi:[537,538,540],paginated_db_queri:402,paginator_django:477,paginator_index:477,paginator_slic:477,pai:[133,141,158,191,194,371],paid:[159,191],pain:191,painstakingli:14,pair:[20,51,65,78,83,118,164,204,211,286,338,393,398,457,532,543],pal:36,palac:118,palett:175,pallet:170,palm:[92,380],pane:[68,230,251,340,369],panel:[7,187],panic:[41,143],pant:156,pantheon:[31,388],paper:[138,164,180],paperback:162,paperwork:118,par:182,paradigm:[75,156,172,309],paragraph:[15,19,31,119,302,470,478,492],parallel:[113,134,136,137,154,465],paralyz:310,param:[95,187,218,398,411,418,428,461,491,512,513,515],paramat:[204,213,398,455],paramet:[2,3,7,20,49,76,85,96,97,130,132,136,142,146,153,158,183,193,201,204,205,206,209,210,211,212,213,223,225,232,233,234,241,242,247,254,255,256,257,260,270,273,274,275,276,277,278,280,283,286,289,292,296,299,308,309,310,311,312,316,322,329,337,338,339,340,343,346,349,350,354,362,364,369,372,376,377,380,382,386,388,389,390,391,394,396,397,398,400,402,403,405,407,408,409,410,411,413,414,415,416,418,420,421,422,423,425,426,427,428,429,430,431,432,433,434,435,436,438,439,440,441,443,444,445,447,453,454,455,456,457,459,460,461,464,465,466,467,469,470,471,472,473,474,475,476,477,478,479,480,483,485,486,487,489,490,491,492,493,495,496,500,502,505,506,510,513,524,540,545],paramt:493,paremt:403,parent1:41,parent2:41,parent:[11,12,19,20,22,26,37,41,42,48,62,74,76,86,118,120,123,126,131,139,143,145,149,150,152,165,172,174,207,215,218,226,228,241,242,270,273,275,292,294,338,350,353,354,386,397,398,402,403,406,464,465,466,474,484,485,490,492,510,512,518,541,545],parent_categori:386,parent_kei:[76,241],parent_model:[500,501,502,504,505,506,508],parenthes:[50,151],parenthesi:[151,152],paretn:510,pari:[180,191],pariatur:29,paricular:22,park:[82,241],parlanc:[53,167],parri:[164,293,371],parrot:172,pars:[6,16,20,22,27,28,30,58,60,62,65,68,69,72,86,104,116,118,119,120,121,138,139,149,154,161,165,167,178,185,195,208,209,210,213,218,224,225,226,228,229,241,250,251,269,270,273,275,280,283,292,293,299,316,331,337,338,339,343,350,351,364,371,372,376,377,378,386,391,394,398,401,402,403,421,428,431,440,444,445,447,457,464,469,470,474,475,476,479,490,491,492,545],parse_ansi:469,parse_ansi_to_irc:428,parse_entry_for_subcategori:391,parse_fil:470,parse_for_perspect:280,parse_for_th:280,parse_html:491,parse_input:476,parse_irc_to_ansi:428,parse_languag:350,parse_menu_templ:[28,476],parse_nick_templ:464,parse_opt:386,parse_sdescs_and_recog:[350,351],parse_to_ani:[30,479],parseabl:[402,479],parsed_str:[30,428],parsedfunc:479,parseerror:270,parser:[22,28,31,69,71,104,116,118,120,147,178,180,195,209,210,215,218,225,226,228,230,245,251,270,273,275,293,305,316,336,337,338,349,350,371,372,402,435,469,479,491,545],parsingerror:[30,479,492],part1:305,part2:305,part3:545,part:[0,2,3,4,7,8,11,14,15,16,18,22,28,31,33,39,40,42,44,48,49,51,52,53,56,62,67,68,71,73,74,75,76,77,80,95,96,105,106,118,119,120,124,128,130,131,132,134,135,137,141,142,144,146,148,149,150,151,152,155,156,157,159,162,164,165,169,170,171,182,191,210,211,213,223,226,227,229,232,241,273,283,292,293,305,311,335,337,338,343,350,364,372,386,389,393,394,401,402,409,416,420,445,447,456,459,461,464,465,469,470,474,476,479,490,492,545],part_a:283,part_b:283,parth:441,parti:[3,9,14,19,30,59,75,79,88,119,123,151,152,157,159,178,181,182,189,190,191,234,283,343,479,545],partial:[31,118,126,223,225,349,388,396,402,418,431,457,487,489,492,493],particip:[104,114,194,308,309,310,311,312],participl:[495,497],particular:[5,6,11,13,14,15,20,31,32,33,37,42,44,45,46,48,55,60,62,65,68,70,73,76,91,104,112,118,120,123,127,131,135,138,141,144,146,147,148,150,151,152,153,156,157,158,161,172,174,176,180,181,187,189,190,195,204,206,210,211,218,233,276,292,310,311,316,337,338,340,377,389,393,394,405,406,457,459,466,479,483,489,539,541,544],particularli:[28,55,58,77,95,97,106,112,120,124,130,213,226,229,350,354,403,420],partit:469,partli:[13,20,67,72,104,106,147,211],party_oth:283,pass:[2,8,10,18,19,22,28,29,30,32,33,35,39,41,42,44,45,47,48,54,62,65,68,78,85,86,92,95,99,104,106,109,112,113,118,124,125,126,127,128,129,132,136,137,140,141,142,143,145,149,150,152,153,158,161,170,171,174,178,182,191,193,199,204,205,211,223,230,232,247,256,273,278,280,286,289,292,296,308,309,310,311,312,322,337,338,340,343,350,354,362,364,371,376,377,380,386,393,394,398,401,402,407,410,411,414,416,426,434,436,439,444,445,455,461,464,466,467,475,476,477,478,479,480,485,486,487,488,490,491,492,512,518,538,541,543,545],passabl:338,passag:[65,164,286,371,372,480],passant:175,passavataridterminalrealm:436,passiv:[128,164,177],passthrough:[20,337,409],password123:49,password1:[500,532],password2:[500,532],password:[2,5,11,25,26,28,32,33,53,55,75,78,89,100,104,107,123,124,143,148,149,154,182,185,187,194,198,204,206,215,216,230,251,275,377,382,421,436,439,460,472,500,524,532],password_chang:533,passwordresettest:533,past:[0,11,14,27,50,51,69,77,96,97,118,119,135,136,137,144,148,158,164,165,170,177,187,195,206,310,338,462,470,480,495,497,541],pastebin:119,pastpl:495,pat:396,patch:[48,49,77,490,545],patfind:335,path:[4,7,8,12,15,19,28,30,31,32,33,35,37,41,42,44,48,52,53,62,63,64,67,68,73,76,77,78,95,97,99,106,118,120,123,124,125,128,130,137,141,144,145,146,149,151,152,154,161,165,169,171,172,174,178,181,185,187,191,193,204,205,207,210,211,212,213,217,218,219,220,221,222,223,232,234,239,241,247,257,260,266,273,275,276,277,278,280,283,286,292,296,305,308,309,310,311,312,316,322,325,329,331,335,337,338,339,340,343,349,350,359,362,364,366,369,370,371,372,382,388,390,396,397,398,402,403,405,406,408,409,411,416,423,425,434,441,447,449,453,457,461,464,465,466,470,472,474,475,476,477,479,480,483,484,489,492,510,518,538,545],path_or_typeclass:260,pathdata:331,pathfind:[104,331,335,337,338,545],pathnam:490,patient:28,patreon:119,patrol:[115,370],patrolling_pac:370,patron:99,pattern:[18,36,56,73,74,124,137,167,177,178,216,350,460,464,492,509],pattern_is_regex:464,paul:48,paus:[28,42,54,95,96,130,164,193,199,218,228,256,409,410,476,490,492,545],pausabl:492,pauseproduc:418,pax:545,paxboard:180,payload:[427,444],payment:[79,104,158],paypal:119,pdb:[201,545],pdbref:[33,393],pdf:180,peac:171,peek:[0,28,118,142,144,149],peer:[427,444],peform:421,peg:194,pem:187,pemit:[69,216],pen:138,penalti:[67,156,310,545],pend:461,pennmush:[69,72,134,230],pentagon:194,peopl:[0,6,12,18,30,31,33,53,58,60,69,89,90,95,104,106,119,122,123,125,135,139,141,144,146,148,156,157,158,159,161,162,164,180,184,188,189,191,194,197,223,224,233,251,350,371,372,472,501,508],pep8:[0,77],per:[5,11,12,13,18,22,30,37,41,44,57,61,65,67,77,85,86,87,91,97,104,106,112,114,118,120,123,124,135,136,137,151,157,158,161,164,165,193,204,223,275,276,289,308,309,310,311,312,316,337,338,349,354,370,396,398,402,429,430,432,440,443,459,476,477,478,483,485,486],perceiv:[136,158],percent:[22,235,341,352,492,545],percentag:[112,164,353,354,465,492],percentil:492,perception_method_test:452,perfect:[11,27,77,122,156,157,161,190,193,337],perfectli:[42,46,72,124,137,469],perform:[3,5,6,13,14,15,18,28,29,32,33,37,42,58,76,80,82,85,86,92,95,103,104,113,114,122,126,130,142,151,164,165,171,177,178,182,188,190,194,204,209,211,215,218,223,225,241,256,257,266,273,286,289,292,308,309,310,311,312,335,350,376,380,386,396,398,402,406,407,420,425,439,447,448,464,465,466,473,476,477,479,486,489,492,493,532],perhap:[3,6,18,56,69,76,95,96,136,137,142],period:[8,9,10,151,191,193,194,492],perist:48,perm1:467,perm2:467,perm:[13,18,22,31,33,39,41,46,55,57,76,95,124,126,135,141,143,149,165,177,188,207,216,217,218,223,224,225,228,255,266,273,305,316,322,331,372,390,393,394,397,398,406,464,466,467,492],perm_abov:[33,39,393],perm_us:216,perma:158,permadeath:158,perman:[18,28,53,55,77,118,124,155,156,183,191,215,218,223,224,228,349,410,466,545],permiss:[5,8,12,13,18,20,41,49,50,55,61,63,69,75,77,80,124,125,126,144,149,161,165,177,181,182,188,190,201,202,204,206,207,211,213,215,216,217,218,223,224,226,232,255,276,312,350,388,390,393,394,396,397,398,402,403,406,464,465,466,467,470,472,479,485,489,492,498,500,511,512,515,518,543,545],permission_account_default:[39,447],permission_class:518,permission_func_modul:393,permission_guest_default:63,permission_hierarchi:[39,57,393,394,467],permissiondeni:513,permissionerror:402,permissionfilt:512,permissionhandl:[39,177,467],permissionshandl:[508,515],permit:[179,182,218,460],permstr:[33,204,396,466,472],permut:350,perpetu:[5,545],perri:77,persion:58,persis:128,persist:[18,19,20,22,28,34,37,42,44,47,48,67,76,85,97,104,106,108,110,112,114,122,123,125,126,133,134,138,141,145,148,150,151,154,157,164,165,174,180,195,199,204,207,211,212,228,233,234,241,242,247,257,274,289,308,309,310,311,312,325,339,349,350,354,364,369,371,380,386,390,396,397,398,400,402,405,406,407,409,410,411,421,422,423,454,455,459,463,466,472,474,476,478,480,492,545],persit:35,person:[11,18,30,44,55,58,72,77,79,106,125,143,156,157,159,162,172,185,191,204,218,223,224,232,275,276,280,283,343,350,479,495,496,497,545],persona:31,perspect:[44,58,162,280,496],pertain:[169,175,194],pertin:177,perus:51,peski:141,pester:[134,156],petal:120,peter:273,pg_ctlcluster:182,pg_hba:182,pg_lscluster:182,phantom:31,phase:[132,156],philosophi:[33,151,275,545],phone:[56,104,107,123,190,382],phone_gener:[107,382],phonem:[106,349],php:[69,123,532],phrase:[95,96,260],phrase_ev:[95,260],physic:[12,35,132,156,311,370,545],pick:[7,14,16,20,22,25,28,30,31,33,42,53,58,75,90,95,118,119,122,125,130,136,141,144,150,151,154,157,158,161,162,170,176,189,191,193,195,210,215,218,224,226,250,286,312,346,350,371,372,398,402,448,479],pickl:[13,47,50,65,118,128,239,354,407,411,413,423,425,426,464,465,473,474,476,488,492],pickle_protocol:488,pickledfield:[396,488],pickledformfield:[488,501],pickledobject:488,pickledobjectfield:488,pickledwidget:488,picklefield:[201,202,468,501,545],pickpocket:225,pickup:[312,398],pictur:[7,62,125,134,545],pid:[2,11,33,50,177,193,199,393,398,416,426,492],piddir:2,pidfil:416,pie:273,piec:[5,14,35,53,54,86,90,105,123,150,151,157,187,292,293,305,443,470,477],piecem:104,pierc:371,pig:[292,293],piggyback:204,pigironrecip:[292,293],piglei:77,pii:78,pile:[212,470],pillow:190,pinch:158,ping:[205,223,416,428],pink:469,pip:[0,3,5,6,8,9,10,75,77,118,120,147,151,177,182,185,186,188,190,192,193,198,201,545],pipe:[44,78,428,473],pitfal:[0,15,60,175],pixel:[53,183],pizza:[207,234,390,397,406,464,466,467],pkg:190,pki:181,place:[0,9,12,13,15,16,18,28,33,35,37,41,42,44,49,52,53,64,65,66,72,73,75,79,82,86,92,95,96,97,104,112,115,118,122,123,124,125,126,129,132,136,137,142,144,147,148,150,151,153,158,161,162,165,167,169,170,174,175,176,177,181,185,188,190,191,193,194,195,204,216,218,224,232,241,247,275,283,286,293,305,308,309,310,311,312,329,337,338,340,350,354,364,371,372,376,380,398,405,409,425,434,439,455,456,457,464,470,471,473,476,492,545],placehold:[52,53,64,178,394,398,478],plai:[12,15,31,44,53,57,60,65,76,96,97,104,108,114,115,122,123,128,130,135,138,139,142,151,154,155,156,157,159,161,162,164,165,170,174,176,177,190,191,198,204,206,308,312,440,457,472,545],plain:[14,15,67,68,79,120,135,144,165,223,232,241,283,302,403,421,447,473,541],plaintext:377,plan:[3,15,16,18,48,62,75,95,122,133,138,146,150,153,154,160,163,166,168,191,193,470,545],plane:[118,153,174],planet:[136,148,180],plank:86,plant:[116,270],plate:[28,48,53,104,107,140,382],platform:[7,11,56,75,95,133,185,191],playabl:[158,177,533],player1:398,player2:398,player:[5,6,8,13,18,20,28,30,33,39,42,44,46,50,52,53,54,55,57,58,62,64,65,69,70,75,76,77,78,79,90,91,92,94,95,98,104,105,106,113,115,116,117,118,121,122,123,125,126,128,135,139,141,142,144,145,148,149,150,151,152,154,155,156,157,160,162,163,164,165,166,168,170,171,172,173,174,177,184,186,188,191,192,198,199,212,215,218,228,233,241,260,266,270,273,274,275,276,278,283,299,305,311,312,329,337,346,349,350,364,366,372,377,380,386,389,406,430,439,456,470,475,476,492,518,532,538,545],playercmdset:95,playernam:188,playerornpc:75,pleas:[0,5,8,11,17,20,28,31,41,48,56,60,78,115,119,124,144,150,158,161,170,171,172,173,177,179,181,185,188,189,190,191,228,418,447,483,488,532],pleasur:56,plenti:[15,72,122],plop:53,plot:449,plu:[0,7,19,76,123,228],pluck:22,plug:[35,45,169,194,329],plugin:[62,65,69,77,104,121,124,147,148,180,189,195,350,414,545],plugin_handl:51,plugin_manag:51,plural:[39,57,58,135,311,398,479,495,496],plusmaplink:[118,338],png:[40,53,169],pocoo:492,poeditor:64,poet:146,point:[2,3,5,6,7,10,11,12,14,15,16,19,20,22,28,30,31,35,37,41,42,44,46,47,48,50,53,58,65,67,68,70,73,76,79,89,90,93,95,97,99,100,104,114,118,120,122,124,125,126,128,130,132,133,136,137,138,139,141,142,143,144,148,149,150,151,152,156,158,159,162,164,165,166,169,174,177,178,181,185,187,190,191,193,195,198,204,209,213,218,223,226,270,273,283,289,292,296,308,322,329,331,335,337,338,350,372,398,400,402,411,416,420,434,436,444,455,457,464,466,470,476,479,492,501,508,521,543,545],pointer:[0,132,133,142],pointless:[37,47,54,225],poison:[13,104,112,157,310,354,403],pole:305,polici:[26,77,152,191,194,377,390,460,464,545],polish:64,polit:[152,158,194],poll:[62,169,215,370,416,445],pommel:[158,293],pong:428,pool:[20,47,182,411,461,473],poor:[58,135],poorli:194,pop:[7,54,120,126,135,141,182],popen:426,popul:[2,73,76,95,99,134,136,139,156,182,211,219,220,221,222,241,273,286,292,305,308,309,310,311,312,316,322,325,331,350,364,366,369,370,371,372,398,410,411,447,470,474,475,477,501,508],popular:[69,75,114,123,134,146,154,180,194,197,537],popup:51,port:[2,5,75,97,122,154,181,182,184,185,187,189,193,199,205,223,425,428,436,448,457,461,545],portal:[5,7,9,24,37,43,51,52,62,68,84,121,147,148,174,180,191,194,195,199,201,202,205,228,244,412,413,416,454,455,456,457,480,485,492,545],portal_connect:457,portal_disconnect:457,portal_disconnect_al:457,portal_l:426,portal_pid:[426,492],portal_receive_adminserver2port:426,portal_receive_launcher2port:426,portal_receive_server2port:426,portal_receive_statu:426,portal_reset_serv:457,portal_restart_serv:457,portal_run:416,portal_service_plugin_modul:62,portal_services_plugin:[62,148,195],portal_services_plugin_modul:62,portal_sess:62,portal_session_sync:457,portal_sessions_sync:457,portal_shutdown:457,portal_st:416,portal_uptim:480,portallogobserv:485,portalsess:[44,62,434,545],portalsessiondata:457,portalsessionhandl:[62,201,202,412,424,435,457,545],portalsessionsdata:457,portion:[77,104,241,346],portuges:64,pos:[275,338],pose:[26,58,104,106,128,135,143,157,158,164,204,224,257,273,350,364],pose_transform:232,posgresql:182,posit:[14,28,42,51,76,95,99,104,114,116,118,130,132,142,144,152,157,164,170,175,212,230,241,251,270,273,275,302,312,329,337,338,340,371,372,398,410,469,470,473,474,478,492,493],position:275,position_prep_map:275,positive_integ:493,positiveinteg:486,posix:[485,492],possess:[58,93,296,479,496],possibl:[0,5,9,13,18,20,22,27,28,30,31,32,33,35,41,42,44,46,50,52,53,54,60,63,75,76,78,79,95,96,97,99,104,106,111,112,115,117,118,119,120,122,123,126,130,134,135,142,146,147,148,151,152,155,157,158,159,161,162,164,165,169,170,175,178,182,185,190,193,195,201,204,206,207,209,211,218,225,226,233,245,256,275,283,292,305,316,329,337,338,340,349,350,354,366,370,372,391,394,396,398,401,402,403,407,411,421,441,445,455,457,464,465,467,469,472,474,475,476,478,480,488,489,492,495,510],post:[18,20,33,45,49,53,64,78,86,104,119,122,134,135,137,154,156,169,170,173,177,185,188,192,377,409,445,517,538,545],post_craft:[86,292],post_delet:45,post_init:45,post_join_channel:[18,232],post_leave_channel:[18,232],post_migr:45,post_mov:398,post_sav:45,post_send_messag:232,post_text:346,post_url_continu:[500,502,505],postfix:[106,349],postgr:[123,182],postgresql:[492,545],postgresql_psycopg2:182,postinit:51,posttext:380,postupd:[173,188],pot:[55,145],potato:[116,183,270],potenti:[0,13,14,30,54,60,65,86,95,104,106,140,152,157,158,164,165,170,191,192,213,225,233,377,378,393,394,398,402,486,489,492],potion:[153,157,158,275,466],pow:30,power:[3,16,20,22,27,28,30,35,37,39,41,50,51,53,57,58,85,95,96,104,106,113,116,122,123,128,129,133,135,144,146,150,151,152,153,155,157,158,161,164,165,170,211,212,217,218,270,289,311,386,391,470,476,492],powerattack:[85,289],powerfulli:97,ppart:495,pperm:[18,33,39,55,149,177,188,215,223,266,305,393,398],pperm_abov:[39,393],pprofil:416,pprogram:416,practial:16,practic:[0,2,14,15,22,37,42,44,50,76,97,123,128,134,135,149,150,151,152,153,157,158,161,175,185,187,191,338,470,545],pre:[22,37,49,132,156,158,170,184,185,188,191,204,218,225,292,349,394,398,402,403,444,445,448,474,479,488],pre_craft:[86,292],pre_delet:45,pre_init:45,pre_join_channel:[18,232],pre_leave_channel:[18,232],pre_migr:45,pre_sav:[45,488],pre_send_messag:232,pre_text:346,preced:[20,39,41,57,60,113,118,161,211,213,386,398,403,465,478,479,496],preceed:[30,144],precend:209,precis:[13,42,95,175,289,292,469],predefin:[174,460],predict:[48,151,159,177],prefer:[7,11,18,20,22,33,41,51,76,119,122,125,134,142,148,150,154,165,170,182,188,191,211,213,216,241,309,338,350,370,389,391,396,398],prefix:[3,6,18,48,67,76,106,182,194,204,210,225,227,232,346,349,396,421,428,459,469,479,485,489,492,501,502,504,506,508,512,532,545],prelogout_loc:149,prematur:[5,19,42,283],premis:[90,273],prep:273,prepai:191,prepar:[36,41,52,118,132,134,167,204,223,308,309,310,311,312,350,370,406,473,488,545],prepars:120,prepend:[299,350,398,469,470,476,479,492],prepopul:[501,508,541,543],preposit:275,preprocess:218,prerequisit:[2,75,545],prescrib:[122,134,157],presen:30,presenc:[17,30,75,118,122,133,148,149,169,175,182,191,204,398,461,498],present:[3,6,28,31,44,49,53,76,92,94,96,104,113,114,124,132,136,137,141,142,156,157,164,165,181,195,241,270,346,349,366,380,382,386,403,474,492,495,497,501,515],present_participl:497,preserv:[175,226,466,469,470,485,492],preset:479,press:[0,3,7,15,16,20,22,28,33,65,68,75,76,82,104,108,144,148,151,154,185,193,199,241,275,364,371,414,476,505],pressur:140,presto:144,presum:[35,136,162,212,485,486],pretend:190,pretext:380,pretti:[0,11,13,22,37,42,50,58,68,76,83,95,97,120,123,126,130,141,149,151,152,155,156,164,165,174,175,177,189,191,213,232,280,286,354,382,387,394,402,475,477,486,492],prettier:[5,97,532],prettifi:[134,492],prettili:136,pretty_corn:478,prettyt:[19,140,478],prev:[28,161,477],prev_entri:28,prevent:[22,95,96,120,136,144,151,256,270,312,459,501,538,545],preview:120,previou:[3,11,13,15,20,22,28,29,30,31,33,36,45,49,53,54,56,60,67,76,95,112,113,128,135,136,137,141,142,143,146,147,149,150,151,155,158,161,163,165,175,193,195,223,354,372,386,400,476,477,485,540],previous:[20,27,32,42,53,60,99,118,132,142,144,150,169,177,187,189,195,213,216,218,223,232,283,339,421,437,441,448,457,467,492],previu:42,prgmr:191,price:[77,158,191,371],primadonna:31,primari:[11,17,48,149,177,193,350,396,398,464,489],primarili:[2,11,12,55,69,79,119,120,122,156,157,204,283,350,389,391,434,473,492],primary_kei:177,prime:[79,209,283],primer:[53,54],primit:[158,218],princess:[155,170],princip:159,principl:[0,8,12,18,22,28,30,33,35,37,50,57,58,62,75,79,86,90,104,119,120,129,134,141,146,148,149,152,157,158,165,176,191,192,212,215,283,372],print:[0,3,4,5,6,13,19,27,42,48,54,62,67,70,75,106,112,120,124,125,126,135,142,146,149,151,152,199,215,270,337,339,343,349,354,402,415,416,475,476,477,478,485,492],print_debug_info:476,print_error:339,print_help:270,print_stat:5,print_usag:270,printabl:442,printable_order_list:337,printout:[152,439],prio:[20,22,126,149,209,372,467],prior:[171,256,398],priorit:[118,338,349,467],prioriti:[6,20,22,28,41,118,124,126,131,161,164,211,215,219,220,221,222,226,241,273,369,371,372,398,474,476,477,545],prison:[146,156,545],privaci:78,privat:[11,18,78,120,124,134,137,156,158,181,182,191,223,224,428,441],private_set:75,privatestaticroot:461,priveleg:150,privileg:[22,118,125,156,165,182,185,186,189,192,224,329,340,350,398,466,545],privkei:187,privkeyfil:436,privmsg:428,prize:155,proactiv:47,probabl:[5,9,22,28,31,37,42,49,50,53,56,67,69,76,77,82,95,96,112,118,122,123,124,125,126,128,134,137,141,149,158,161,164,169,174,177,178,182,191,225,241,242,260,354,372,382,418,428,436,483,492,493],problem:[0,2,6,8,13,14,16,19,22,26,33,70,74,76,119,123,125,126,133,137,138,143,151,153,156,158,159,161,170,182,183,187,190,191,193,194,199,204,212,257,292,337,398,425,470,479,545],problemat:[126,492],proce:[15,16,64,174,175,193,223,443,536,538],procedur:[113,386,436,439],proceed:[11,492],process:[0,2,3,5,7,11,13,14,15,16,22,28,30,35,37,40,49,52,53,64,65,68,75,76,86,95,97,99,118,119,120,123,124,126,128,130,132,142,148,151,156,158,160,161,162,177,181,182,187,190,191,193,204,209,211,218,228,232,270,283,292,293,333,350,356,386,392,394,398,402,407,410,416,421,425,426,433,436,439,444,445,448,454,455,457,464,469,470,473,476,486,491,492,493,510,545],process_languag:350,process_recog:350,process_sdesc:350,processed_result:492,processor:[24,26,104,158,166,170,199,201,202,217,228,229,468,545],procpool:492,produc:[11,18,22,28,31,60,80,95,106,157,159,165,215,218,250,275,280,292,293,305,329,349,371,398,402,403,415,447,464,466,475,476,492],produce_weapon:371,producion:19,product:[0,2,5,7,9,11,52,53,73,182,191,194,197,447,450,476,545],production_set:75,prof:5,profess:146,profession:[69,123,134,151,158,159,167],profil:[1,92,186,201,202,207,380,412,545],profile_templ:[92,380],profunc:41,prog:[270,495],program:[0,5,7,8,9,12,16,18,30,40,49,52,54,67,69,121,123,130,133,134,147,148,151,152,155,159,160,161,180,182,185,187,190,191,193,194,199,228,230,270,412,416,439,445,447,545],programiz:130,programm:[142,154,159],progress:[90,104,114,141,162,180,276,278,289,308,309,310,311,312,338,474],proident:29,project:[16,69,73,119,123,124,126,132,142,159,169,170,180,189,486,544,545],projectil:311,promin:31,promis:0,promisqu:175,prompt:[0,3,48,51,65,68,75,94,113,120,123,138,151,154,170,182,183,184,185,190,193,198,213,346,386,414,428,439,444,445,470,476,490,545],promptli:15,pron:[30,398,479,545],prone:[9,212,466],pronoun:[30,58,93,201,202,296,398,468,479,494,497,545],pronoun_to_viewpoint:496,pronoun_typ:[58,479,496],pronounc:280,pronount:496,prop:[156,479,545],propag:[181,211,420,488],proper:[2,13,16,19,30,31,51,58,73,79,106,123,125,130,131,133,134,141,142,156,158,161,164,165,177,182,193,194,218,241,258,283,349,398,475,479,490,496],properi:225,properli:[7,9,10,11,30,34,48,69,74,75,78,128,135,136,137,171,175,177,213,283,335,372,378,393,410,411,436,492,503],properti:[4,6,8,14,31,33,34,36,39,41,42,47,53,58,67,76,85,86,95,104,112,121,122,126,130,133,134,139,143,147,149,153,158,162,164,165,170,174,175,195,199,204,205,207,213,215,218,226,228,229,232,234,241,256,270,273,275,276,289,292,293,305,308,310,311,312,329,338,339,340,350,353,354,364,370,371,372,380,386,388,390,391,393,394,396,397,398,402,403,406,408,409,410,420,421,423,428,434,447,448,455,456,457,464,466,467,471,473,476,479,486,487,488,489,490,492,500,501,502,504,505,506,507,508,515,532,540,542,545],property_nam:396,property_valu:396,propnam:165,propos:27,proprietari:182,propval:165,propvalu:165,prose:159,prosimii:[177,178],prospect:[156,292],prot:403,prot_func_modul:[41,401],protect:[5,20,78,191,218,293,364],protfunc:[201,202,399,402,403,479,545],protfunc_callable_protkei:401,protfunc_modul:402,protfunc_pars:402,protfunct:402,protkei:[41,401,402],proto:[425,436],proto_def:305,protocol:[19,22,24,32,40,44,51,61,65,121,123,147,148,159,180,183,189,191,194,195,199,204,205,213,216,296,362,377,398,412,413,416,418,421,425,426,427,428,429,430,431,432,434,435,436,438,439,440,441,443,444,445,447,454,455,456,457,474,488,492,545],protocol_flag:[438,439,443,455],protocol_kei:456,protocol_path:[434,457],protodef:305,prototocol:228,protototyp:[400,402,403],protototype_tag:41,prototoyp:401,prototyp:[24,30,86,96,105,121,147,148,156,173,201,202,218,235,292,305,309,310,314,330,337,338,339,371,545],prototype1:403,prototype2:403,prototype_:41,prototype_desc:[41,403],prototype_dict:218,prototype_diff:403,prototype_diff_from_object:403,prototype_from_object:403,prototype_kei:[41,86,118,218,292,402,403],prototype_keykei:218,prototype_lock:[41,403],prototype_modul:[41,118,218,334,402,403],prototype_pagin:402,prototype_par:[41,118,218,334,403],prototype_tag:403,prototype_to_str:402,prototypeevmor:402,prototypefunc:403,protpar:[402,403],protpart:402,provid:[2,6,8,13,17,18,22,30,31,39,41,42,48,49,50,51,52,53,55,56,58,69,71,76,77,83,85,86,94,95,97,99,104,105,113,117,120,122,124,126,128,137,142,150,151,152,153,157,158,161,167,169,175,177,178,187,190,191,193,194,204,213,218,223,230,232,241,242,255,269,270,275,286,289,292,305,308,309,310,311,312,329,337,346,380,382,386,388,393,398,401,409,416,436,459,465,467,476,479,486,487,488,490,492,493,517,518,532,538,541,543],provok:[3,180],prowl:31,proxi:[48,147,187,194,197,461,501,508,545],proxypass:181,proxypassrevers:181,prudent:2,prune:20,pseudo:[62,69,104,106,132,142,349,381,382,545],psionic:311,psql:182,pstat:5,psycopg2:182,pty:75,pub:[223,232],pubkeyfil:436,publicli:[11,53,158,180,184],publish:[2,125,180,193],pudb:[201,545],puff:133,pull:[2,9,20,22,30,52,53,119,120,123,126,148,159,169,193,260,371,418,540,545],pummel:155,punch:[20,115,143],punish:[158,312],puppet:[6,12,20,22,26,32,33,39,44,45,50,57,62,75,76,86,95,98,125,130,134,135,136,149,165,172,177,203,204,209,215,218,226,234,292,299,331,393,398,455,457,466,467,500,505,533,538,540,545],puppet_object:[12,204],puppeted_object:500,purchas:[141,187],pure:[48,60,68,96,133,158,175,187,406,416,464,469],pure_ascii:492,purg:[13,48,199,228],purpos:[13,40,46,58,65,90,124,146,152,165,175,177,187,191,205,209,213,256,280,338,343,436,464,473,476,479,492,496],pursu:[155,370],push:[76,95,108,120,150,175,193,194,260,275,364,371,545],pushd:185,put:[3,7,8,12,14,15,22,27,28,33,36,37,39,41,44,48,49,53,54,55,57,60,65,67,72,73,77,83,85,86,90,95,96,97,113,118,119,120,123,125,126,132,134,135,141,143,144,148,150,151,153,156,157,159,161,162,164,165,167,169,170,174,177,180,182,191,194,195,197,212,215,216,218,220,224,239,280,286,289,292,293,308,309,310,311,312,346,350,359,380,386,394,425,439,477,478,492,545],putobject:77,putobjectacl:77,putti:191,puzzl:[86,90,115,155,180,201,202,235,281,292,371,372,545],puzzle_desc:371,puzzle_kei:372,puzzle_nam:305,puzzle_valu:372,puzzleedit:305,puzzlerecip:[105,305],puzzlesystemcmdset:[105,305],pvp:[156,545],pwd:[5,193],py3:425,py3k:77,pyc:148,pycharm:[1,120,154,545],pyflak:0,pylint:0,pyopenssl:186,pypath:492,pypath_prefix:492,pypath_to_realpath:492,pypi:[5,123,180,191,469],pypiwin32:[75,185],pyprof2calltre:5,pyramid:[117,329],pyramidmapprovid:[117,329],pyself:157,python2:[6,75,185],python37:185,python3:[185,190,354],python3_properti:123,python:[3,5,6,7,8,9,10,12,13,15,16,19,20,22,27,28,30,31,33,35,37,41,48,49,50,52,53,54,55,57,60,63,64,67,69,70,71,73,75,76,77,78,80,88,96,97,104,116,117,118,120,121,123,124,125,128,130,132,133,135,136,137,138,140,141,142,143,144,145,146,147,149,150,153,154,157,158,159,160,161,162,163,164,165,166,167,168,170,172,177,178,182,185,186,189,190,191,192,193,194,195,198,199,210,212,217,218,222,228,229,241,254,255,256,257,258,260,270,292,329,339,343,382,388,394,396,397,401,403,405,408,411,416,418,425,429,434,444,455,457,461,463,465,466,469,470,472,473,474,475,476,478,479,480,483,485,488,490,492,510,515,521,544,545],python_execut:123,python_path:[152,212,492],pythonista:180,pythonpath:[212,416,426,470],pytz:493,q_lycantrop:146,q_moonlit:146,q_recently_bitten:146,qualiti:[78,104,156,158,210],queen:118,quell:[12,26,109,115,143,144,149,151,155,161,174,215,322,393,545],quell_color:218,queri:[11,30,41,46,49,56,65,67,85,104,118,123,130,133,138,153,154,161,207,223,225,234,289,340,350,389,390,391,396,397,398,402,403,406,423,436,451,464,465,466,467,477,479,484,489,492,493,545],query_al:464,query_categori:464,query_info:416,query_kei:464,query_statu:416,query_util:512,queryset:[42,46,123,206,233,276,299,339,340,389,396,402,405,422,465,477,489,501,508,512,518,537,538,540,543,545],queryset_maxs:477,querystr:512,quest:[95,104,111,122,134,138,155,156,157,159,163,171,185,372,545],question:[0,8,11,22,27,28,54,73,76,100,104,134,156,158,159,160,162,181,185,187,191,218,397,413,414,464,474,476,490,492],queu:416,queue:[2,164,461],qui:29,quick:[6,20,22,35,42,46,69,74,76,80,82,86,95,104,105,120,122,130,142,151,152,156,164,180,191,197,205,218,241,349,388,403,421,464,467,478,517,545],quicker:[36,67,97,158],quickli:[9,13,16,22,28,35,37,46,54,60,67,82,102,104,106,118,126,130,158,159,169,173,197,218,241,278,280,349,467,470],quickstart:[6,64,67,135,151,190,191,193,195,199,544,545],quiescentcallback:418,quiet:[118,126,141,153,204,216,218,223,241,266,286,331,350,398,477,492,545],quiethttp11clientfactori:418,quietli:[30,65,68,128,464],quirk:[1,13,183,212,545],quit:[3,5,9,12,17,22,26,27,28,44,54,62,76,82,92,95,96,97,115,118,120,122,124,125,129,130,134,141,143,144,146,149,151,152,153,155,158,161,177,182,184,187,190,215,230,241,242,251,256,273,278,311,380,436,474,476,477],quitfunc:[27,474],quitfunc_arg:474,quitsave_yesno:474,quo:47,quot:[13,19,25,27,33,41,151,157,172,182,218,230,251,350,474,476,488,492],qux:[113,386],ra4d24e8a3cab:25,rabbit:158,race:[122,133,156,162,171,177,180,181,492,545],rack:[293,371],radio:[18,158],radiu:[130,132,170],rafal:77,rage:[112,155,354],ragetrait:[112,354],rail:[123,174],railroad:174,railwai:338,rain:[42,155,158,176],raini:372,rais:[13,16,19,22,30,41,54,65,86,95,137,142,146,162,178,204,205,206,233,241,247,254,256,257,292,316,337,338,339,340,343,349,350,354,382,394,396,401,402,411,415,416,434,439,445,460,464,465,467,469,470,472,475,476,478,479,485,486,487,488,490,492,493,513],raise_error:[30,479,487,492],raise_except:[13,292,464],ram:[13,191],ramalho:180,ran:[2,3,14,28,151,409],rand:42,randint:[30,41,86,95,99,142,149,162,164,165,173,308,309,310,311,312,403,479],random:[25,28,30,41,42,75,81,86,95,96,99,104,106,142,144,149,155,157,158,162,164,165,173,176,191,195,250,280,293,308,309,310,311,312,329,349,359,360,364,371,372,381,382,383,403,447,448,479,492,545],random_string_from_modul:492,random_string_gener:[107,201,202,235,374,545],randomli:[5,42,67,99,173,176,308,309,310,311,312,364,370,371,416,448,479],randomstringgener:[107,382],randomstringgeneratorscript:382,rang:[3,5,20,27,41,68,92,99,104,112,114,118,130,132,133,142,144,155,157,164,170,172,173,183,185,194,218,247,309,312,335,337,340,353,354,380,465,474,479,532,543],ranged_attack:293,rank:[57,393],raph:180,rapidli:212,rapier:146,raptur:440,rare:[7,9,22,47,54,58,67,76,99,120,185,195,223,339,394,396,472],rascal:46,rase:294,rate:[5,22,85,104,119,123,157,191,223,235,289,341,352,411,416,435,492,545],ratetarget:[112,157,353,354],rather:[0,6,8,9,11,12,13,14,22,31,37,42,46,47,53,67,72,73,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,122,123,126,128,130,134,142,144,148,151,153,154,157,158,161,164,167,170,178,187,188,195,199,204,207,211,215,218,219,225,226,228,232,256,266,283,302,308,309,310,311,312,338,339,346,350,354,387,398,400,402,403,464,466,469,478,487,488,491,501,508,541],ration:[79,157,283],raw:[13,22,32,41,55,60,65,67,120,123,133,144,151,152,154,158,167,204,210,213,218,226,227,229,270,350,354,377,398,421,436,439,444,445,455,464,469,474,476,486,492],raw_cmdnam:[143,210,227],raw_desc:316,raw_id_field:[502,505,506],raw_input:[28,141,476],raw_nick:36,raw_str:[22,28,141,143,204,205,209,210,213,274,369,380,386,398,400,455,464,476,490],raw_templ:36,rawhid:293,rawhiderecip:293,rawstr:[213,229],rcannot:76,rdelet:218,re_bg:491,re_bgfg:491,re_blink:491,re_bold:491,re_color:491,re_dblspac:491,re_double_spac:491,re_fg:491,re_format:469,re_hilit:491,re_invers:491,re_mxplink:491,re_mxpurl:491,re_norm:491,re_str:491,re_ulin:491,re_underlin:491,re_unhilit:491,re_url:491,reach:[28,36,64,68,76,118,130,143,144,155,161,162,174,191,201,213,254,312,338,354,380,436,440,459,476,477,489,544],reachabl:[47,123,337],react:[28,47,52,95,171,172,370,398],reactiv:228,reactor:[427,454,461,490],read:[5,8,9,11,13,14,16,17,19,20,22,28,30,31,33,35,41,44,49,53,56,64,67,68,75,76,77,82,86,90,94,95,96,97,104,107,112,115,118,119,120,122,123,124,126,128,130,133,135,137,141,142,143,144,146,147,148,149,150,151,152,155,157,158,159,161,165,175,177,178,180,181,182,188,189,191,194,195,198,204,207,217,224,225,234,241,260,275,299,316,337,338,346,350,354,371,372,382,388,390,397,398,402,403,406,423,425,448,464,466,467,470,471,475,477,484,485,492,500,537,540,545],read_batchfil:470,read_default_fil:2,read_flag:275,read_only_field:515,readabl:[5,19,47,48,60,69,95,120,132,225,239,275,292,337,371,469,476,540],readable_text:371,reader:[32,94,120,135,139,161,177,180,192,223,312,346,421,435],readi:[2,3,5,7,11,12,16,33,37,54,55,62,85,90,119,126,128,144,148,149,159,169,174,184,185,190,204,213,289,308,309,310,311,312,350,398,445,477,486,492],readili:[170,182],readin:475,readlin:485,readm:[10,11,15,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,98,99,100,101,102,103,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,148,235,377],readonly_field:[500,502,505,506],readonlypasswordhashfield:500,readthedoc:[180,512],real:[3,4,5,11,12,19,20,30,37,41,48,54,63,69,76,90,95,96,106,114,120,122,125,130,135,136,146,151,152,158,162,164,165,166,170,175,185,187,189,191,193,199,207,212,234,247,283,293,310,338,339,349,350,393,447,470,479,480,545],real_address:12,real_nam:12,real_seconds_until:[247,480],real_word:349,realist:[5,158,159,176,275],realiti:[5,122,125,133,156,170,175,180],realiz:[11,149,175],realli:[0,3,4,9,13,14,15,18,20,22,28,30,33,37,42,46,47,49,54,55,57,69,76,90,95,104,113,115,116,118,123,124,126,130,135,136,141,142,143,144,149,150,152,153,157,159,161,170,172,174,187,189,192,195,199,213,229,241,270,283,338,386,394,425,469,470,476,488,490],really_all_weapon:146,realm:436,realnam:37,realpython:54,realtim:[135,148,247],realtime_to_gametim:[87,247],reason:[5,6,7,11,13,14,18,28,31,33,35,36,37,39,41,42,47,50,55,60,62,65,67,72,75,76,86,89,106,112,118,119,120,123,126,128,130,131,132,133,134,135,137,140,143,149,150,156,158,159,161,162,164,175,181,185,187,194,195,204,216,218,223,228,251,266,276,292,337,338,349,354,382,396,398,402,407,413,418,425,426,427,428,434,435,436,439,444,445,447,455,456,457,466,474,479,485,492,543],reasourc:41,reassign:132,reattach:[7,427,428],reboot:[9,13,19,26,27,34,42,44,47,67,77,84,112,122,127,148,164,187,191,193,198,204,212,223,228,244,289,354,370,371,380,398,406,407,409,411,416,456,457,474,476,545],reboot_evennia:416,rebuild:[9,118,135,185,187,193,339,428],rebuilt:[22,118,187,337],rec:350,recach:372,recal:[371,537],recapcha:545,recaptcha:177,receipt:[78,194,418],receiv:[3,18,20,22,28,29,30,35,36,44,51,52,61,65,70,86,119,135,142,148,177,204,211,212,230,232,233,234,251,276,299,337,350,354,377,398,418,421,425,427,428,434,444,445,447,454,455,472,477,479,489,490,492,502,545],receive_functioncal:425,receive_status_from_port:416,receiver1:490,receiver2:490,receiver_account_set:207,receiver_extern:234,receiver_object_set:397,receiver_script_set:406,recent:[17,53,124,126,146,165,187,206,459],recently_bitten:146,recev:445,recip:[47,97,104,105,127,158,201,202,235,281,291,294,305,545],recipe_modul:292,recipe_nam:292,recipebread:86,recipenam:86,recipes_pot:292,recipes_weapon:292,recipi:[18,30,35,86,135,204,232,233,299,398,425,479],reckon:75,recoc:157,recog:[36,106,157,350,545],recog_regex:350,recogerror:350,recoghandl:350,recogn:[8,32,37,56,143,144,152,158,178,185,191,199,350,354,461],recognit:[58,104,106,159,350,464],recommend:[0,2,5,11,13,28,37,41,48,55,67,68,69,73,75,114,118,119,120,122,126,135,137,138,145,151,156,158,162,180,182,183,185,191,198,228,256,270,337,346,376,394,396,398,418,470,476,489],reconfigur:191,reconnect:[89,100,204,205,223,232,413,416,425,427,428,454,457],reconnectingclientfactori:[413,427,428,447],record:[16,78,165,182,191,312,377,459,532],record_ip:459,recours:55,recov:[19,112,127,128,133,308,309,310,311,312,354,394,492],recoveri:164,recreat:[9,42,148,170,182,185,205,212,339,470,471],rectangl:475,rectangular:[135,475],recur:123,recurs:[13,95,338,393,402],red:[14,15,20,36,39,41,53,60,80,104,118,120,144,148,150,151,152,175,218,228,275,363,364,371,469,479,493,545],red_button:[14,15,36,108,144,148,201,202,218,229,235,355,545],red_kei:39,red_ros:146,redbutton:[14,15,36,108,144,148,218,364],redd:194,reddit:194,redefin:[22,37,76,122,398,532],redhat:[185,187],redirect:[44,53,62,73,76,137,148,177,181,241,275,278,476,534,538,543],redirectlink:338,redirectview:538,redit:[82,241],redmapnod:118,redo:[27,151,152,156,474],redraw:436,reduc:[164,308,309,310,311,312,429],reduct:77,redund:469,reel:212,reen:[60,469],ref:[48,120,182,350,398,492,532],refactor:[134,398,495,544],refer:[7,10,11,13,14,20,22,28,30,36,37,41,42,44,48,53,57,58,62,67,68,72,75,76,77,79,86,95,96,97,99,104,106,107,112,119,123,132,133,134,136,137,138,143,146,148,149,150,151,152,154,157,158,159,162,164,170,175,177,178,180,181,191,193,195,199,204,212,218,223,227,232,266,278,283,293,308,309,310,311,312,331,337,340,350,354,380,382,393,398,407,408,410,411,418,428,448,456,465,476,479,483,488,489,492,501,508,543,544,545],referenc:[37,41,50,104,106,120,133,195,213,218,223,232,337,350,388,390,466,492,545],referenti:492,referr:191,refin:[132,293],reflect:[151,155,157,543],reflex:[58,479,496],reflow:56,reformat:[403,478,485],reformat_cel:478,reformat_column:[170,478],refresh:[0,53,118,178,436,459],refus:[18,55,158],regain:128,regard:[175,382,512,545],regardless:[8,20,22,39,44,48,55,57,58,65,135,139,156,162,174,204,211,232,275,283,296,350,398,411,433,436,439,454,456,464,467,470,483,485,492],regener:310,regex:[18,22,27,28,36,51,53,78,84,213,216,228,229,244,350,382,460,464,476,492,521],regex_nick:36,regex_tupl:350,regex_tuple_from_key_alia:350,regexfield:500,region:[74,118,135,191,216],regist:[11,51,52,53,65,73,95,118,164,173,177,186,188,194,195,197,204,206,223,228,260,289,370,371,407,416,427,428,434,457,459,461,469,479,517,523,533,536,545],register_error:469,register_ev:[95,260],registercompon:51,registertest:533,registr:[49,186,536],registrar:187,registri:[382,459,461,545],regress:402,regul:394,regular:[8,11,17,18,22,31,35,42,44,47,50,52,58,73,78,79,83,95,104,105,107,118,120,137,144,145,146,148,151,152,156,161,167,176,178,180,191,205,211,286,305,338,372,382,388,394,411,464,467,479,483,492,496,521,544,545],regulararticl:484,regulararticle_set:484,regularcategori:484,regularli:[9,95,141,173,176,187,192,247,277,370,372,409,411,419,449,480],reilli:180,reimplement:[87,104],reinforc:180,reiniti:199,reinstal:185,reinvent:134,reject:[92,95,380,382],rejectedregex:382,rejoin:18,rel:[11,14,15,20,28,31,50,54,57,76,99,104,117,118,120,132,140,158,165,177,195,247,275,312,470,476,545],relai:[19,22,44,189,204,223,283,296,337,398,434,457,476,477,492],relat:[18,20,22,28,31,48,51,53,104,112,118,127,133,134,146,148,149,152,158,161,176,180,189,194,195,199,207,208,211,226,231,233,234,247,260,274,275,276,308,309,310,311,312,314,337,338,354,369,372,377,390,397,398,405,406,411,421,457,464,466,467,469,476,484,485,498,500,501,508,515,525,532,545],related_field:[500,501,502,504,505,506,508],related_nam:[207,234,390,397,406,464,466,467,484],relationship:[35,48,132],relay:205,releas:[75,77,119,122,127,148,159,179,180,185,191,228,496,544,545],relev:[13,15,22,33,37,45,46,48,50,53,60,73,74,75,76,79,112,118,119,120,129,135,136,161,164,165,167,177,180,204,209,211,241,283,292,338,354,394,408,430,448,455,456,457,469,474,476,486,501,508,545],relevant_choic:241,reli:[8,28,47,60,67,68,73,75,93,95,104,106,136,139,141,142,153,158,175,296,350,354,372,416,466,476,545],reliabl:[14,48,126,128,182,483],reliant:99,religion:[31,388],reload:[0,2,3,7,9,12,13,14,15,19,20,22,25,26,27,28,31,32,40,42,44,47,48,50,52,53,55,57,62,63,73,76,86,89,90,91,95,97,100,102,103,106,110,112,118,125,127,128,130,131,134,135,136,137,139,143,148,149,150,151,161,162,164,165,167,169,171,172,174,177,178,185,186,187,188,192,195,204,205,212,217,218,228,232,241,251,257,266,302,316,325,329,337,339,350,354,371,372,388,394,396,398,405,407,409,411,416,425,426,428,430,454,457,461,464,470,472,474,475,476,480,492,545],reload_evennia:416,reluct:158,remain:[6,13,14,20,22,27,28,41,42,45,57,70,90,106,112,129,135,142,148,149,150,161,191,199,210,212,218,220,224,247,278,292,308,309,310,311,312,316,349,354,370,398,416,444,445,476,477,492],remaind:[22,125,247],remaining_repeat:42,remap:[151,464],remark:545,rememb:[1,5,6,8,9,11,13,14,20,22,28,31,39,41,46,47,51,53,55,60,67,68,76,95,97,118,124,125,127,128,130,132,133,135,136,137,142,149,151,153,155,156,157,158,159,161,165,170,175,184,185,191,216,218,256,338,398,407,470,489,545],remind:[27,97,120,124,545],remit:216,remnisc:134,remot:[126,187,193,194,197,223,425,427,439,545],remov:[2,9,11,13,18,19,20,23,27,28,30,31,34,36,37,39,42,47,55,75,76,77,78,90,97,106,107,108,112,118,122,124,125,130,135,137,139,141,142,143,148,149,155,158,164,169,177,192,201,211,212,216,218,223,224,225,228,229,232,234,241,254,258,266,275,280,286,293,305,308,309,310,311,312,316,338,339,349,350,353,354,364,380,382,386,394,397,398,403,407,410,411,416,434,445,457,459,464,467,469,473,476,483,488,490,491,492,518,545],remove_alia:223,remove_backspac:491,remove_bel:491,remove_charact:164,remove_default:[20,212],remove_map:339,remove_non_persist:405,remove_object:339,remove_receiv:234,remove_send:234,remove_user_channel_alia:[18,232],removeth:464,renam:[5,26,75,135,139,143,144,151,152,161,169,218,224,398,405,466],render:[45,52,53,76,94,120,137,139,167,169,177,178,225,346,461,486,488,500,501,502,504,505,506,508,515,521,530,532,543],render_post:445,renew:[128,135,187,459],repair:[125,156,545],repeat:[3,5,68,87,95,97,104,107,136,151,156,158,164,169,170,172,174,190,199,204,205,247,277,283,382,386,405,406,409,416,421,440,464,472,476,480,492,545],repeatedli:[3,15,32,136,148,277,370,406,409,411,416,421,447,525],repeatlist:32,repetit:[136,164,382],replac:[2,13,18,20,22,27,28,30,31,32,33,36,37,41,44,49,51,58,60,73,75,76,77,79,84,89,92,95,102,103,104,106,118,120,126,128,129,134,137,138,143,148,151,153,154,157,161,164,169,170,178,182,187,193,195,204,210,211,212,213,216,224,225,228,229,232,244,251,254,257,266,270,274,280,283,289,292,302,305,316,337,338,349,350,364,369,372,380,394,398,400,402,403,428,431,444,445,455,464,469,474,475,476,477,478,479,491,492,521,523,545],replace_data:478,replace_timeslot:316,replace_whitespac:478,replacement_str:224,replacement_templ:224,replenish:[308,309,310,311,312],repli:[22,28,79,158,186,205,283,299,414,438,439,445,457,476],replic:[76,159,169,467],replica:[11,149],repo:[7,11,64,119,120,134,147,156,180,492,545],repoint:53,report:[0,5,6,8,11,22,26,34,42,47,76,86,95,106,115,118,119,142,153,156,158,161,162,164,169,182,183,185,190,194,195,206,218,223,254,257,270,292,338,350,398,416,421,428,431,432,439,440,444,447,455,457,469,472,476,492],report_to:[206,396,405,472],repos:545,repositori:[2,10,64,75,77,119,120,126,147,179,181,182,185,193,403,545],repositri:64,repr:[142,492,540],reprehenderit:29,repres:[12,20,22,30,31,35,37,44,45,48,53,58,62,67,70,75,76,92,94,95,96,97,99,104,106,107,109,112,118,121,123,125,126,132,133,136,137,143,144,146,147,148,149,150,152,154,159,164,169,175,177,204,209,233,254,260,270,278,286,310,322,337,338,339,346,349,350,354,371,372,377,380,382,386,388,398,403,410,411,413,427,428,444,445,455,456,457,461,464,465,469,471,472,476,477,478,479,488,492,495,518],represen:149,represent:[12,13,30,35,36,44,62,67,68,70,123,127,135,149,162,175,233,254,257,337,350,396,402,406,425,444,445,467,473,480,515],reprocess:194,reproduc:[54,118,338,398],repurpos:77,reput:[156,376,545],reqhash:[465,492],reqiur:[92,380],request:[0,28,33,45,49,52,53,62,73,79,119,137,148,152,165,167,177,178,181,185,191,194,204,205,216,257,283,289,398,402,416,418,425,428,430,435,436,438,445,461,467,476,500,501,502,503,505,506,508,512,513,518,523,524,525,526,530,537,539,540,543,545],request_finish:45,request_start:45,requestavatarid:436,requestfactori:461,requestor:[204,459],requir:[0,2,5,8,15,16,22,27,28,30,31,33,34,37,39,41,47,48,49,50,51,52,53,54,59,67,72,75,76,77,78,86,90,95,96,99,100,102,104,107,113,118,119,120,124,132,135,137,141,143,156,158,159,161,164,169,170,172,175,176,177,178,179,180,181,182,184,187,188,190,191,197,199,206,217,218,223,233,234,251,266,270,289,292,293,302,310,311,316,337,338,340,343,350,354,372,380,382,386,389,393,396,398,402,410,416,427,428,441,449,460,465,470,475,476,477,478,479,483,487,488,489,492,500,501,502,504,505,506,508,532,538,545],require_al:[39,467],require_singl:402,requirements_extra:[0,77,118],requr:41,requri:[402,479],rerout:[52,215,219,428,509],rerun:[14,15,28,118,292],research:[158,180,256],resembl:[72,122,126],resend:22,reserv:[22,30,54,143,149,151,170,402,460,465,479,492],reserved_keyword:30,reserved_kwarg:[30,479],reset:[16,17,19,20,22,26,27,42,44,48,55,60,63,95,97,106,112,128,131,139,143,148,157,162,164,165,170,174,175,182,195,204,205,212,218,228,247,257,273,275,289,350,353,354,371,394,416,420,426,436,454,464,467,470,478,479,480,490,492,545],reset_cach:[464,467],reset_callcount:42,reset_gametim:[19,480],reset_serv:420,reset_tim:316,reshuffl:545,resid:[69,147,394],residu:[228,310],resist:[403,492],resiz:[52,135,475,478],resolut:[112,158,164,337,354],resolv:[0,3,11,90,120,128,138,151,152,158,159,164,191,195,305,308,309,310,311,312,515],resolve_attack:[308,309,310,311,312],resolve_combat:164,resort:[22,120,135,184,223,350,492],resourc:[0,8,47,49,52,53,69,73,75,77,104,112,119,120,121,127,133,143,146,147,148,149,150,151,152,153,158,169,182,191,194,204,311,336,354,391,407,414,445,461,471,490,544,545],respawn:[118,156,545],respect:[22,33,42,44,48,49,86,95,97,98,104,105,110,118,135,150,161,165,182,195,216,218,225,283,292,299,305,325,350,394,398,455,456,466,467,470,472,478,489,492,496,532],respond:[28,34,45,65,96,97,101,104,148,156,171,172,175,199,443,447],respons:[5,17,28,30,31,49,52,53,54,56,68,119,123,132,141,142,172,173,174,185,191,204,205,212,213,223,232,292,329,372,388,390,398,414,416,418,425,447,448,457,466,486,488,492,515],response_add:[500,502,505],resport:492,respositori:119,rest:[7,17,18,22,28,30,36,42,52,53,67,77,112,120,128,133,140,141,148,149,151,152,155,156,158,162,165,170,185,195,198,210,226,227,308,309,310,311,312,354,464,469,478,512,513,515,516,517,518,545],rest_api_en:[49,52],rest_framework:[49,512,513,514,515,516,518],restart:[0,3,7,9,26,40,42,51,55,64,73,84,88,95,135,149,152,164,182,187,191,194,195,199,201,204,228,232,241,244,257,343,398,405,407,409,410,411,420,433,454,455,456,492,545],restartingwebsocketserverfactori:[205,427],restock:141,restor:[20,97,175,241,293,311,407,411],restrain:[112,218,354,393,475,492],restrict:[13,33,41,47,48,51,57,83,95,107,124,144,147,148,153,157,162,170,178,181,191,218,266,286,311,312,337,382,388,389,394,396,403,405,472,474,476,478,489,545],restructur:[120,133],result1:305,result2:[28,305],result:[6,8,11,13,19,20,22,28,30,31,33,41,44,47,49,52,54,58,60,64,68,73,78,80,83,86,88,92,99,105,106,107,112,118,120,129,131,135,142,143,146,147,149,150,151,153,157,158,161,162,164,165,169,172,175,178,182,191,195,204,206,210,211,213,218,225,232,234,275,283,292,293,294,305,308,309,310,311,312,337,338,343,349,350,354,372,376,380,382,389,391,394,396,398,402,403,405,416,425,447,464,466,469,474,475,476,478,479,483,485,486,489,490,492,493,495,510,540],result_nam:305,resum:[22,118,128,161,410],resurrect:370,resync:[205,425,455],ret1:479,ret:[22,490],ret_index:492,retain:[6,19,20,31,41,53,54,64,93,152,170,233,296,354,388,390,403,462,466,470,472,479,485,492,496],retain_inst:213,retext:120,retract:283,retreat:312,retri:416,retriev:[6,18,22,32,46,49,67,69,74,95,97,112,118,137,165,204,207,209,212,218,223,228,229,233,256,316,331,338,354,389,393,397,402,414,421,422,428,434,443,464,467,473,483,487,489,492,497,512,513,517,518,537,540,543,545],retriv:[205,471],retro:18,retroact:[48,135],retur:29,return_alias:338,return_appear:[118,132,165,275,276,286,316,340,350,362,371,398],return_apper:[340,398],return_cmdset:225,return_detail:[316,372],return_dict:388,return_iter:402,return_key_and_categori:467,return_list:[30,464,467,479],return_map:170,return_minimap:170,return_obj:[13,36,464,467,487],return_par:403,return_prototyp:173,return_puppet:204,return_str:[30,337,479],return_tagobj:467,return_tupl:[36,343,464],returnvalu:[22,54],reus:[151,153,266,483],rev342453534:492,reveal:[95,118,155,286],reveng:159,reverend:[77,104],revers:[20,22,53,58,60,95,117,128,130,170,174,175,178,207,223,234,329,337,353,390,397,406,461,464,466,467,469,484,518],reverseerror:[416,425],reversemanytoonedescriptor:[207,397,484],reverseproxyresourc:461,revert:[11,53,175,191,215,389],review:[9,20,73,97,119,123,143,157],revis:156,revisit:[2,476],reviu:28,revok:135,revolutionari:11,reward:[115,163],rework:[100,104,128,149,156],rewrit:53,rfc1073:432,rfc858:438,rfc:[432,438],rfind:469,rgb:[60,151,469],rgbmatch:469,rgh:151,rhel:181,rhello:30,rhost:230,rhostmush:[69,72,134],rhs:[126,135,226,229],rhs_split:[218,224,226],rhslist:226,ricardo:492,riccardomurri:492,rich:[76,77,134,179,180,473],richard:180,rick:41,rid:[133,150],riddanc:55,riddick:[92,380],ride:174,right:[0,3,4,5,9,15,22,28,30,32,33,36,41,42,49,51,52,53,54,64,77,86,91,92,95,96,97,104,117,118,120,122,125,126,127,128,130,133,134,135,141,142,143,146,147,148,149,151,152,155,156,159,161,165,170,171,174,175,177,178,181,182,185,187,190,191,212,215,218,226,228,230,232,257,258,269,273,275,292,305,312,316,329,337,338,346,364,370,371,372,380,394,403,406,456,469,470,474,478,492,493],right_justifi:41,rightmost:[118,338],rigid:134,rindex:469,ring:[106,153,349],ringmail_armor:13,rink:77,rise:[20,136],risen:136,risk:[30,52,120,134,156,158,165,185,191,217,228,492],rival:170,rjust:[30,469,479],rm_attr:218,rnormal:60,rnote:228,road:[20,96,170,174,211],roam:[155,212,370],roar:170,robot:177,robust:[141,142,194],rock:[67,95,99,164,212],rocki:155,rod:212,rodrigo:77,role:[17,77,104,114,122,134,142,150,156,162,182,308,545],roleplai:[31,75,102,104,122,134,156,157,162,164,165,180,343,348,350,545],roll1:162,roll2:162,roll:[28,86,95,104,114,135,142,152,157,158,162,164,165,185,308,309,310,311,312,342,343,459,545],roll_challeng:162,roll_dic:343,roll_dmg:162,roll_hit:162,roll_init:[308,309,310,311,312],roll_result:343,roll_skil:162,roller:[88,104,157,158,162,164,292,343,545],rom:[180,545],roof:218,room1:8,room2:8,room56:14,room:[3,8,13,14,15,16,18,19,20,22,23,33,35,41,42,46,48,49,50,55,58,69,72,74,75,76,82,88,90,95,96,99,104,106,109,110,111,114,116,117,118,121,122,123,125,131,133,134,136,141,142,144,145,146,148,149,150,151,152,153,155,161,162,164,165,170,171,172,173,174,176,177,185,195,201,202,209,210,211,212,216,218,224,229,235,241,256,270,271,272,273,274,275,277,278,280,286,308,309,310,311,312,315,316,322,325,329,331,332,334,337,338,339,340,343,350,355,364,366,368,369,370,371,393,398,406,420,448,470,490,512,518,533,545],room_desc:[8,99],room_dict:99,room_flag:133,room_lava:133,room_replac:273,room_typeclass:[317,329,490,533],room_x_coordin:118,room_y_coordin:118,room_z_coordin:118,roombuildingmenu:[76,82,241],roomnam:[135,218],roomref:174,rooms_with_five_object:146,roomstat:275,roomviewset:518,root:[0,2,4,5,6,7,9,10,14,33,37,53,58,67,73,75,76,77,120,123,137,139,147,169,178,179,182,185,187,190,191,193,201,202,371,398,403,416,461,473,498,511,523,545],rose:[13,36,37,48,145,146,153],rostdev:191,roster:[75,157,308,309,310,311,312],rosterentri:75,rot:8,rotat:[18,148,275,485],rotate_flag:275,rotate_log_fil:485,rotatelength:485,rough:[120,156],roughli:[135,156,492],round:[5,17,30,106,112,289,312,349,354,447,478,479],rounder:[106,349],rout:[51,104,118,132,133,144,174,204,331,337,338],router:[191,514,517,545],routerlink:118,routermaplink:[118,338],routin:[106,350,396,451,489,492],row:[51,56,60,67,97,120,123,132,135,137,146,164,167,170,175,337,340,478,492],rowdi:99,rpcharact:350,rpcommand:350,rpg:[88,94,106,112,114,119,135,138,148,149,156,162,201,202,235,312,545],rpi:180,rplanguag:[106,157,201,202,235,341,348,350,545],rpm:185,rpobject:350,rpsystem:[58,102,106,120,157,201,202,235,302,341,545],rpsystemcmdset:[106,350],rred:469,rsa:[436,437],rspli8t:142,rsplit:[165,469],rss2chan:[26,143,192,223],rss:[9,180,197,201,202,205,223,231,412,421,424,434,545],rss_enabl:[192,223],rss_rate:205,rss_update_interv:223,rss_url:[192,205,223],rssbot:205,rssbotfactori:435,rsschan:223,rssfactori:435,rssreader:435,rst:545,rstop:218,rstrip:[142,469],rsyslog:376,rtest2:60,rtext:[141,479],rthe:76,rthi:[60,151],rtype:461,rubbish:215,rubbl:118,rubi:123,rudimentari:[115,370],ruin:[155,316,372],rule:[4,11,14,15,22,33,55,60,95,104,106,112,122,125,135,148,152,156,157,163,175,180,241,293,308,309,312,349,354,382,390,470,545],rulebook:[158,164],rumor:31,rumour:155,run:[0,2,5,6,9,10,11,12,13,14,15,16,18,19,20,25,28,30,31,33,40,41,42,47,48,49,50,51,52,53,54,62,64,67,71,75,77,80,81,90,95,96,97,115,118,120,121,123,125,126,127,128,133,134,136,137,139,141,142,143,144,146,148,149,150,151,152,154,155,156,157,158,159,161,162,165,167,169,170,174,175,176,177,178,180,181,182,183,184,185,187,189,191,194,195,198,199,201,204,205,209,210,212,213,217,218,224,225,228,229,232,245,257,258,266,274,292,308,309,310,311,312,317,325,329,337,338,350,369,376,386,393,394,398,402,403,405,406,409,410,411,416,420,422,426,433,434,441,445,447,450,454,455,459,461,466,469,470,474,476,477,479,480,485,489,490,492,518,543,544,545],run_async:[54,492],run_connect_wizard:416,run_custom_command:416,run_dummyrunn:416,run_evscaperoom_menu:274,run_exec:476,run_exec_then_goto:476,run_init_hook:454,run_initial_setup:454,run_menu:416,run_option_menu:274,run_start_hook:[48,466],rundown:154,runexec:476,runexec_kwarg:476,runnabl:41,runner:[2,5,7,371,447,545],runsnak:5,runsnakerun:5,runtest:[229,239,242,245,248,252,258,267,269,279,284,287,290,294,297,300,303,306,313,317,323,326,328,335,344,347,351,353,360,367,373,378,383,385,442,452,484,490,497,516,527,533],runtim:[19,22,55,136,213,241,270,480,492],runtimeerror:[162,204,205,254,257,260,292,336,339,349,354,382,402,434,464,476,479,492],runtimewarn:[336,402],rusernam:28,rush:128,russel:77,russian:64,rusti:[49,58,141],ruv:2,ryou:76,s3boto3storag:77,s3boto3storagetest:239,s3boto3testcas:239,sad:[177,439,476],sadli:230,safe:[0,6,11,20,37,52,53,79,96,104,118,123,129,133,140,157,158,177,187,195,197,204,215,283,394,411,425,457,461,466,470,473,479,483,492,545],safe_convert_input:492,safe_convert_to_typ:[30,492],safe_ev:492,safer:[14,55],safest:[44,97,191,466],safeti:[11,12,37,48,79,104,133,157,165,191,218,283,397,470,545],sai:[0,5,8,9,13,15,17,18,19,20,22,26,28,33,37,39,41,48,50,51,53,54,55,60,62,72,74,76,77,79,92,95,96,97,106,112,113,118,123,126,128,130,131,133,134,135,136,137,142,143,144,146,149,151,152,157,158,159,161,162,164,165,171,172,175,179,185,191,212,224,232,260,273,275,283,343,349,350,354,364,372,380,386,398,476,479],said:[0,28,46,54,65,76,95,96,97,124,131,132,134,142,149,151,157,158,170,172,178,210,223,227,329,337,350,398,428,464,466,476],sake:[14,73,134,151,156,158,159,175,230,251,542,543],sale:141,salt:[86,292],same:[0,3,5,6,7,8,9,11,12,13,14,15,16,18,19,20,22,27,30,31,32,33,34,35,37,39,41,42,44,46,47,48,50,52,53,54,55,56,57,58,60,62,63,64,65,67,68,69,70,75,76,77,80,87,90,95,97,99,104,106,107,111,112,113,117,118,119,120,122,123,125,127,128,131,133,134,135,136,137,139,141,142,143,144,146,147,148,149,150,151,152,153,158,159,161,162,164,165,169,170,174,175,177,178,179,182,185,187,191,192,193,195,198,199,204,209,210,211,212,213,216,218,223,226,227,228,229,230,233,239,241,247,256,257,270,275,276,280,286,289,292,299,308,309,310,311,312,316,322,329,331,338,340,346,349,350,354,366,370,372,382,386,388,393,398,402,403,406,407,411,420,425,437,440,441,455,456,457,459,461,464,465,466,467,469,470,472,476,477,478,479,480,485,486,490,492,495,501,508,518,532,543,545],sampl:[2,113,133,181,193,386],san:346,sand:[136,293],sandi:170,sandwitch:86,sane:[1,118,120,156,180,338,543],sanit:[532,543],saniti:[8,75,118,132,151,170,486],sarah:[72,224],sat:[74,125,275],satisfi:[69,226,464],satur:194,sauc:151,save:[2,3,6,11,16,19,22,27,28,34,35,36,37,41,42,44,45,46,47,48,50,53,67,75,76,77,78,95,96,97,106,123,125,128,133,143,145,148,149,151,164,165,177,183,184,187,193,194,199,204,215,218,228,232,234,239,241,257,289,349,394,397,398,400,402,403,407,409,410,411,414,421,434,449,454,461,464,466,473,474,483,486,487,488,492,500,501,502,505,506,508,545],save_a:[502,504,505,506,507],save_as_new:[501,508],save_buff:474,save_data:486,save_for_next:[22,213],save_handl:486,save_kwarg:487,save_model:[500,502,505,506],save_nam:411,save_on_top:[502,504,505,506,507],save_prototyp:402,save_recip:305,savefunc:[27,474,487],savehandl:487,saver:473,saverdict:473,saverlist:473,saverset:473,saveyesnocmdset:474,savvi:159,saw:[54,86,95,96,137,149,151],say_text:172,saytext:350,scale:[7,50,60,106,120,134,148,156,162,182,349,544],scalewai:191,scam:158,scan:[118,181,209,337,338,340,370,372],scarf:[83,286],scari:[149,151],scatter:[310,470],scedul:87,scenario:[135,335],scene:[6,13,32,41,46,60,95,107,122,125,152,155,158,162,164,175,354,372,382,406,411,483],schedul:[19,85,87,95,104,136,247,257,289,410,480],schema:[48,67,123,124,492,545],schemaless:78,scheme:[22,60,67,90,127,151,185,218,228,469],schneier:77,school:158,sci:118,scienc:132,scientif:180,scipi:[118,338],scissor:164,scm:75,scope:[32,50,95,122,123,128,156,157,158,161,178,250,382,405,472],score:[135,276,492,545],scott:77,scraper:538,scratch:[9,10,53,62,96,112,134,135,157,158,165,169,185,274,339,354,420],scream:155,screen:[6,22,24,28,29,31,32,41,42,44,56,60,63,89,94,100,118,139,141,148,150,177,193,195,230,250,251,312,346,421,436,477,479,492,500,545],screenheight:[32,421],screenread:[26,32,230,421,444,445],screenshot:177,screenwidth:[32,213,421],script:[2,5,7,8,10,13,14,15,19,24,26,30,33,34,35,37,41,44,45,46,47,48,49,51,67,69,79,80,91,104,105,107,110,117,118,121,122,133,134,136,141,143,144,147,148,149,153,155,158,159,164,171,173,176,177,185,188,191,194,195,199,201,202,204,205,217,218,228,233,234,235,236,247,253,254,260,271,272,283,305,308,309,310,311,312,316,325,329,339,349,358,359,364,372,382,397,398,402,403,416,449,454,470,471,472,479,480,487,489,490,492,498,499,512,515,518,523,533,545],script_copi:405,script_search:405,script_typeclass:[360,490,533],scriptadmin:506,scriptattributeinlin:506,scriptbas:409,scriptclass:408,scriptdb:[48,121,201,406,463,506,512,515],scriptdb_db_attribut:506,scriptdb_db_tag:506,scriptdb_set:[207,397,464,467],scriptdbfilterset:[512,518],scriptdbmanag:[405,406],scriptdbseri:[515,518],scriptdbviewset:518,scriptform:506,scripthandl:[201,202,404,545],scriptlistseri:[515,518],scriptmanag:405,scriptnam:[218,471],scripttaginlin:506,scroll:[6,29,31,95,147,151,165,185,477],scrollback:18,scrub:[78,457],sdesc:[106,133,157,302,350],sdesc_regex:350,sdescerror:350,sdeschandl:[106,350],sdk:185,sea:[155,170],seal:157,seamless:[106,350],seamlessli:40,search:[3,8,11,12,14,18,22,26,27,30,31,35,36,37,41,42,48,64,74,75,76,95,97,106,118,122,123,125,129,135,138,143,146,147,148,149,150,151,154,158,159,161,162,164,165,169,178,195,201,202,204,206,209,211,213,218,223,225,232,233,256,275,278,283,299,305,308,309,310,311,312,329,331,337,338,340,350,372,388,389,390,391,393,396,398,402,403,405,408,422,464,465,466,467,468,469,472,474,479,492,512,521,545],search_:[19,146,153],search_account:[19,45,121,135,153,201,206,398,489],search_account_tag:489,search_at_multimatch_input:398,search_at_result:[350,398],search_channel:[19,121,201,223,233,489],search_channel_tag:489,search_field:[225,500,502,504,505,506,507,508],search_for_obj:218,search_help:[19,31,121,201,389],search_help_entri:489,search_helpentri:389,search_index_entri:[213,215,216,217,218,223,224,225,226,227,228,229,230,241,251,255,266,269,270,273,283,286,292,293,296,299,302,305,308,309,310,311,312,316,322,325,331,343,350,364,366,370,371,372,380,386,388,390,391,398,447,474,476,477],search_messag:[19,35,121,201,233,489],search_mod:350,search_multimatch_regex:398,search_object:[13,14,18,19,48,80,121,149,151,153,170,174,201,204,396,489],search_object_attribut:153,search_objects_with_prototyp:402,search_prototyp:402,search_script:[19,42,118,121,201,405,489],search_script_tag:489,search_tag:[46,74,121,146,153,201,489],search_tag_account:46,search_tag_script:46,search_target:299,searchabl:[147,256],searchdata:[204,350,396,398,489],searching_cal:545,season:[91,104,156,157,159,316,545],seat:156,sebastian:77,sec:[32,54,87,128,136,247,428,480],secmsg:485,second:[5,13,15,19,20,22,28,30,33,39,41,42,47,54,56,58,60,67,68,76,77,85,95,97,99,104,110,112,114,118,120,125,126,128,130,136,137,140,141,142,143,149,151,153,157,164,165,173,174,175,176,178,185,191,194,195,199,204,205,210,218,223,225,229,247,256,257,260,280,289,292,308,309,310,311,312,325,337,350,354,359,370,393,398,403,405,410,411,416,421,430,435,448,459,469,472,476,479,480,485,492,493],secondari:[139,456],secondli:[37,145],secret:[75,77,78,88,104,148,156,186,188,343,416,545],secret_kei:75,secret_set:[75,77,124,148,182,186,416],sect_insid:132,section:[0,2,5,11,13,16,20,22,25,28,30,31,33,37,42,48,50,51,53,58,62,67,70,75,76,91,95,106,118,120,124,125,126,128,130,135,136,137,138,144,146,147,149,150,151,153,154,158,170,177,182,185,190,191,193,198,225,316,349,398,403,469,470,476,493,512,545],sector:132,sector_typ:132,secur:[0,13,14,30,33,41,60,69,76,77,104,107,134,141,165,177,178,185,191,197,213,217,228,232,377,388,390,398,436,466,479,485,492,532,545],secure_attr:33,sed:2,sedat:[112,354],see:[0,3,4,5,7,8,9,10,11,12,13,14,15,18,19,20,21,22,25,27,28,29,30,31,32,33,35,36,37,39,41,42,44,47,48,50,51,52,53,54,55,57,58,60,62,64,67,68,69,70,73,75,76,78,79,81,82,84,85,86,87,89,94,96,97,98,99,100,103,104,105,106,107,108,110,111,112,113,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,139,140,142,143,144,146,147,148,149,150,151,152,154,155,157,158,159,161,164,165,167,169,170,171,172,173,174,175,176,177,178,181,182,185,186,187,188,189,190,191,192,193,194,195,199,204,213,215,217,218,223,224,225,226,228,229,230,232,235,241,251,254,269,270,273,275,278,280,283,289,292,293,299,305,308,309,310,311,312,329,331,336,337,338,340,346,349,350,354,359,364,366,370,372,377,382,386,388,390,391,397,398,405,410,414,416,418,419,427,428,429,430,432,436,437,439,441,443,444,445,447,448,456,457,461,464,469,472,473,474,475,478,479,487,488,490,492,495,496,526,532,537,540,543,544,545],seed:[86,292,294,338],seek:[155,275,394,485],seem:[20,41,51,76,99,106,115,124,130,133,154,156,159,161,165,174,183,185,190,199,230,464,470],seen:[20,28,44,58,62,76,82,95,96,97,99,120,128,132,134,135,137,139,142,143,146,149,150,152,154,161,170,173,174,175,241,428,478],sefsefiwwj3:75,segment:[174,461],seldomli:[213,229],select:[7,11,12,19,20,28,39,44,50,51,52,53,67,74,76,99,137,141,144,157,165,170,173,177,184,185,195,210,211,216,274,309,384,385,386,466,474,476,510,515,545],selet:476,self:[3,8,12,13,14,19,20,22,27,28,33,36,37,39,41,42,47,48,50,54,62,64,67,72,75,76,79,82,83,85,86,88,90,91,95,97,98,99,102,103,105,106,109,110,112,116,117,118,120,125,126,127,128,129,130,131,132,133,134,135,136,139,140,141,143,144,149,150,151,152,153,157,158,161,162,164,165,171,172,173,174,176,178,185,188,189,204,205,207,209,211,212,213,215,218,219,223,226,228,229,230,232,234,241,254,266,270,273,274,275,278,283,286,289,292,293,299,302,305,308,309,310,311,312,316,322,325,329,331,336,339,343,350,354,359,364,369,370,371,372,380,386,388,393,398,410,414,416,418,419,423,427,428,434,436,437,439,441,443,444,445,447,455,456,457,464,466,467,469,474,476,477,479,483,486,487,488,490,492,526,545],self_fire_damag:293,self_pid:492,self_refer:13,selfaccount:135,selfself:42,sell:[141,157,158,179,283],semi:[5,106,144,151,176,280,349],semicolon:[33,394,396,405,472],send:[5,12,18,19,22,28,29,30,32,33,37,39,42,44,45,47,49,51,52,53,55,65,70,74,76,77,78,79,86,92,95,98,99,104,118,123,126,128,135,139,142,143,148,150,153,158,162,164,165,172,173,175,177,187,188,194,197,199,204,205,212,213,216,218,223,232,233,234,275,283,292,296,299,312,337,338,350,359,362,369,370,377,380,398,410,411,413,416,418,419,421,425,426,427,428,429,431,434,435,436,438,439,440,442,444,445,447,448,455,456,457,458,469,472,473,476,478,490,492,496,545],send_:[62,65,434],send_adminportal2serv:426,send_adminserver2port:413,send_authent:427,send_channel:[427,428],send_default:[62,65,427,428,434,436,439,444,445],send_defeated_to:370,send_emot:[106,350],send_functioncal:425,send_game_detail:418,send_heartbeat:427,send_instruct:416,send_mail:299,send_msgportal2serv:426,send_msgserver2port:413,send_p:428,send_privmsg:428,send_prompt:[65,436,439,444,445],send_random_messag:359,send_reconnect:428,send_request_nicklist:428,send_status2launch:426,send_subscrib:427,send_testing_tag:369,send_text:[62,65,436,439,444,445],send_to_online_onli:[18,232],send_unsubscrib:427,sender:[18,35,45,101,204,205,232,233,234,275,283,350,362,398,427,458,472,483,489,502],sender_account_set:207,sender_extern:234,sender_object:458,sender_object_set:397,sender_script_set:406,sender_str:232,senderobj:[233,472],sendlin:[436,439,444],sendmessag:[62,380],sens:[20,33,37,52,53,54,64,67,76,112,118,119,133,135,152,161,174,182,211,354,364,396,472,473,476],sensibl:[18,31,191],sensit:[13,28,31,33,39,78,135,146,206,233,241,247,257,316,340,351,377,378,389,465,467,480,489],sensivit:382,sent:[5,18,28,30,32,35,44,45,51,53,65,68,70,78,89,92,95,98,101,104,126,135,137,142,148,151,187,204,205,209,223,232,233,234,241,251,257,270,275,299,360,362,377,380,398,413,416,418,421,425,426,427,428,436,440,444,455,457,464,476,489,490,515,545],sentenc:[58,64,95,96,106,142,260,275,349,350,492],senwmaplink:[118,338],sep:[64,469,492],sep_kei:[76,241],separ:[5,7,8,11,13,14,15,18,20,22,28,31,33,34,36,37,40,42,44,46,47,51,53,58,62,67,72,74,80,86,95,96,98,103,104,106,112,113,117,118,119,120,123,128,134,135,136,141,142,143,144,146,150,151,152,156,157,165,169,174,175,177,181,182,188,189,190,192,194,210,212,213,218,224,225,226,228,241,257,260,266,289,292,299,308,309,310,311,312,329,333,337,338,340,349,350,354,372,386,389,394,396,397,398,402,405,407,411,435,440,445,457,466,469,470,472,475,479,489,490,492,496,501,545],separatli:128,sepat:292,seq:36,sequenc:[14,15,16,22,33,36,37,52,54,70,79,80,120,123,139,148,155,158,161,175,213,217,232,247,278,292,337,350,394,414,420,469,470,476,478,490,491,492],sequenti:158,seri:[4,11,18,28,60,90,100,104,151,157,158,159,161,169,180,478],serial:[13,50,65,201,202,401,410,411,434,473,486,488,492,498,500,502,505,506,511,518,545],serializ:445,serialized_str:[500,502,505,506],serializer_class:518,seriou:[130,199],serious:185,serrano:77,serv:[52,53,65,73,77,104,123,132,143,148,152,153,158,170,187,194,195,211,233,310,445,461,470,472,530],server:[0,2,5,6,7,8,9,11,12,13,14,16,18,19,20,22,25,26,28,30,31,32,33,34,37,41,42,45,47,48,50,51,52,53,54,55,57,62,63,65,67,68,70,73,75,77,78,84,86,88,89,90,95,97,100,102,103,104,106,110,112,118,120,121,122,123,124,125,126,127,128,133,134,135,136,137,139,142,143,147,149,150,151,152,154,155,158,159,161,162,164,169,170,172,174,177,178,179,180,184,185,186,187,188,189,190,193,194,199,201,202,204,205,206,212,216,218,223,228,230,232,235,241,244,251,257,266,273,277,292,302,316,325,329,332,333,339,343,350,354,370,371,372,374,375,376,388,398,405,406,407,409,411,462,466,470,472,473,476,480,483,485,492,498,499,515,523,544,545],server_connect:434,server_disconnect:434,server_disconnect_al:434,server_epoch:[19,480],server_l:426,server_logged_in:434,server_nam:195,server_pid:[426,492],server_receive_adminportal2serv:413,server_receive_msgportal2serv:413,server_receive_statu:413,server_reload:[407,411],server_run:416,server_runn:454,server_servic:492,server_services_plugin:[62,148,195],server_services_plugin_modul:62,server_session_class:[44,78],server_session_sync:434,server_st:416,server_twistd_cmd:426,server_twisted_cmd:426,serverconf:[216,411,545],serverconfig:[410,411,422,423],serverconfigadmin:507,serverconfigmanag:[422,423],serverfactori:[426,436,439],serverload:[26,228],serverlogobserv:485,servermsg:485,servernam:[32,53,75,124,181,184,191,195],serversess:[44,62,78,143,201,202,377,394,412,434,457,464,545],serversessionhandl:[44,62,457,545],serverset:[33,223,393],servic:[11,26,55,62,77,143,148,177,182,187,188,191,193,194,195,199,201,202,228,412,413,416,417,425,426,433,454,461,492,545],sessdata:[456,457],sessid:[8,12,22,44,165,397,398,413,425,426,434,457],session:[8,12,16,20,22,24,26,28,30,32,34,37,39,42,45,55,62,68,121,134,139,140,142,143,147,149,150,158,165,183,193,201,202,204,205,206,207,209,210,211,213,215,216,219,221,226,230,251,274,296,369,376,377,378,380,397,398,400,401,402,407,412,413,421,425,426,427,428,434,435,436,439,444,445,454,455,457,459,474,476,477,479,492,493,515,545],session_data:457,session_from_account:457,session_from_sessid:457,session_handl:[44,121,201],session_id:515,session_portal_partial_sync:457,session_portal_sync:457,sessioncmdset:[20,26,150,221],sessionhandl:[62,65,201,202,204,398,412,421,427,428,434,435,455,456,545],sessionid:434,sessions_from_account:457,sessions_from_charact:457,sessions_from_csessid:[434,457],sessions_from_puppet:457,sessionsmain:121,sesslen:398,set:[0,2,3,5,6,8,9,10,12,13,14,15,16,17,18,19,21,22,24,25,26,27,29,30,31,32,35,36,37,39,41,42,44,45,46,48,49,50,51,53,54,55,56,57,58,60,62,63,64,65,67,69,70,71,72,73,76,78,82,83,84,85,86,87,89,91,92,93,95,96,97,99,100,105,106,112,113,115,117,118,119,120,121,122,123,125,126,128,129,130,131,133,134,135,137,140,141,142,143,144,145,146,147,148,150,151,152,156,159,161,163,164,167,169,170,171,173,174,175,177,178,181,182,183,185,187,188,190,193,197,198,199,201,203,204,205,206,207,209,210,211,212,213,215,216,218,219,220,221,222,223,225,226,229,230,231,232,239,241,242,244,245,247,251,255,257,260,267,270,273,274,275,276,277,278,279,284,286,289,290,292,293,294,296,302,305,306,308,309,310,311,312,313,316,317,322,325,328,329,331,332,333,334,335,337,338,340,343,349,350,351,353,354,360,364,369,370,371,372,376,380,386,388,389,393,394,396,397,398,401,402,403,405,408,409,410,411,413,415,416,420,421,422,423,426,427,429,430,432,433,436,438,439,441,442,447,448,450,452,454,455,456,457,459,461,462,464,465,466,467,469,470,471,472,473,474,475,476,477,478,479,480,483,484,485,486,487,488,489,490,491,492,493,501,504,505,507,508,513,514,516,517,518,521,525,532,533,540,545],set_active_coordin:329,set_al:370,set_alias:213,set_atribut:518,set_attr:218,set_attribut:518,set_cach:464,set_character_flag:275,set_class_from_typeclass:466,set_dead:370,set_desc:223,set_descript:28,set_detail:[316,372],set_flag:[275,276],set_gamedir:416,set_kei:213,set_lock:223,set_log_filenam:232,set_nam:28,set_password:204,set_posit:275,set_task:257,set_trac:[3,201],setattr:242,setcolor:139,setdesc:[26,134,143,224,322],sete:8,setflag:[273,275],setgend:[93,296],sethelp:[26,31,143,144,225,388],sethom:[26,143,218],setlock:322,setnam:62,setobjalia:[26,218],setperm:216,setpow:545,setspe:[104,110,325],sett:192,settabl:[32,67,149,439],setter:130,settestattr:27,settingnam:33,settings_chang:45,settings_default:[8,121,124,147,149,195,201,202,485,492,545],settings_ful:195,settings_mixin:[5,201,202,412,446,545],settl:[164,170],setup:[0,5,6,8,11,16,31,49,53,62,64,67,72,118,120,135,141,156,164,173,187,188,190,193,195,199,204,215,223,229,239,242,247,258,267,279,284,290,294,306,313,317,328,335,351,353,360,364,369,372,391,398,409,420,433,442,447,451,452,454,461,464,466,483,484,490,516,533,544,545],setup_sess:[378,490],setup_str:451,setuptool:[185,190],sever:[2,3,13,15,20,22,27,29,33,39,41,42,48,49,51,53,57,70,76,95,97,104,118,120,128,133,134,136,137,146,151,154,157,158,163,164,180,195,217,218,226,228,233,256,257,316,370,372,398,442,443,467,472,492,545],sewag:118,sex:296,sftpstorag:77,shadow:31,shall:[175,178],shaman:[41,134],shape:[76,117,130,135,144,156,170,293,329,478],sharabl:41,share:[2,3,18,20,33,44,46,48,52,67,73,75,96,119,123,126,134,148,154,158,164,177,185,186,191,194,256,257,403,411,447,464,465,467,478,492,500,515,518,526,545],shared_field:515,sharedloginmiddlewar:526,sharedmemorymanag:[465,482],sharedmemorymodel:[234,390,464,466,483,484,545],sharedmemorymodelbas:[207,234,390,397,406,464,466,483,484],sharedmemorystest:484,sharp:293,shaung:77,shaw:180,she:[22,31,58,76,82,93,97,106,133,142,157,175,241,296,349,479,495,496],sheer:[99,218],sheet:[28,51,120,157,158,177,178,182,475,545],sheet_lock:135,shell:[0,2,5,9,36,48,67,69,120,126,134,135,151,182,185,187,190,191,193,194,199,436,464],shell_plu:0,shelv:99,shield:[67,128],shift:[15,16,19,69,118,257,371,389,492],shiftroot:371,shine:[118,125,372],shini:[49,492],shinier:49,ship:[78,122,123,144,155,170,190],shire:136,shirt:[83,286],shoe:[83,286],shoot:[125,311,312,475],shop:[28,69,134,158,545],shop_exit:141,shopcmdset:141,shopkeep:[138,157],shopnam:141,shopper:141,short_descript:184,shortcom:141,shortcut:[4,13,18,19,20,22,30,45,48,72,76,82,86,95,97,120,128,137,142,147,151,164,167,177,178,182,193,201,205,212,213,218,223,241,254,292,329,394,398,486,492,545],shorten:[3,48,96,403,515],shorter:[48,62,69,118,120,149,161,171,172,176,195,232,233,349,389,464,465,472,485],shortest:[104,118,130,331,335,337,338,350],shorthand:[37,175,218],shortli:[76,97,161],shortsword:146,shot:311,should:[0,3,5,6,7,8,9,10,11,12,13,14,15,16,18,19,20,22,28,30,31,32,33,35,37,39,41,42,44,45,46,47,48,50,51,53,54,55,56,57,58,60,62,63,64,65,67,68,69,70,72,73,74,75,76,77,78,82,86,90,95,96,97,98,99,102,106,112,116,118,119,120,122,123,124,126,128,130,134,135,136,137,139,140,141,142,143,144,146,148,149,150,151,152,153,154,155,156,157,159,161,162,164,165,167,169,170,174,175,177,178,181,182,183,185,186,187,189,190,191,192,193,194,195,198,199,204,205,206,207,209,211,212,213,215,217,218,219,222,223,225,226,228,229,230,232,233,234,239,241,247,250,254,257,260,269,270,273,275,276,278,280,286,292,293,294,299,302,305,308,309,310,311,312,316,322,325,331,333,335,337,338,339,340,349,350,353,354,369,370,372,376,382,388,393,394,397,398,400,402,403,406,409,410,411,414,415,416,420,423,427,433,436,439,440,442,444,445,447,448,454,455,456,457,459,460,462,464,466,467,469,470,472,473,474,476,477,478,479,480,485,486,487,488,490,492,493,500,501,508,532,533,538,545],should_join:232,should_leav:232,should_list_top:225,should_show_help:225,shoulddrop:[312,398],shoulder:[83,135,286],shouldget:[312,398],shouldgiv:[312,398],shouldmov:[308,309,310,311,312,398],shouldn:[14,76,77,97,125,128,135,175,241,257,260,311,398,447],shouldrot:485,shout:[128,273,275],shove:125,show:[0,3,6,7,9,11,13,14,15,18,19,22,25,28,29,30,31,42,44,50,51,53,55,58,59,60,62,67,72,76,86,91,92,96,97,103,104,112,113,115,117,118,119,120,122,123,129,130,132,134,135,136,137,139,140,141,142,143,144,148,149,150,151,152,154,155,156,157,158,160,161,162,163,164,166,168,169,170,171,172,173,175,177,178,183,184,185,187,188,191,192,194,195,199,204,215,216,218,223,224,225,226,228,230,250,251,266,270,273,283,286,302,311,312,316,329,331,335,337,338,340,343,346,354,364,372,380,386,388,398,400,402,403,414,416,425,464,474,476,485,486,487,492,496,532,545],show_change_link:500,show_foot:477,show_map:132,show_non_edit:402,show_non_us:402,show_valu:346,show_version_info:416,show_warn:416,showcas:[20,99,148,155,170],shown:[22,25,28,31,41,42,50,59,75,76,90,97,106,107,112,124,126,128,132,134,136,149,161,174,177,184,213,216,223,227,229,241,250,266,280,286,292,337,338,350,354,364,371,382,398,416,476,477,521],showtim:136,shrink:[150,478],shrug:96,shuffl:19,shun:[0,69,191],shut:[5,51,97,124,128,151,193,195,204,228,398,409,411,416,418,425,426,433,434,454,457,545],shutdown:[5,20,26,42,44,55,57,135,143,199,204,205,228,405,411,416,425,426,433,454,455,466,472,476],shy:[0,72,156,159],sibl:[13,42,54,134,152],sid:[77,216],side:[2,8,13,30,32,42,44,46,51,53,65,79,88,97,104,109,118,120,132,135,142,146,157,158,162,175,177,183,204,205,207,218,224,226,234,283,322,338,343,390,397,406,413,421,425,426,434,437,440,441,444,455,456,457,464,466,467,469,478,484],sidebar:[53,163,166,545],sidestep:57,sidewai:478,sigint:416,sign:[7,15,47,65,95,96,97,118,142,144,146,148,153,165,176,191,223,275,316,337,398,411,464,469,493],signal:[5,24,95,199,201,202,308,309,310,311,312,336,412,416,439,445,447,483,545],signal_acccount_post_first_login:45,signal_account_:45,signal_account_post_connect:45,signal_account_post_cr:45,signal_account_post_last_logout:45,signal_account_post_login:45,signal_account_post_login_fail:45,signal_account_post_logout:45,signal_account_post_renam:45,signal_channel_post_cr:45,signal_helpentry_post_cr:45,signal_object_:45,signal_object_post_cr:45,signal_object_post_puppet:45,signal_object_post_unpuppet:45,signal_script_post_cr:45,signal_typed_object_post_renam:45,signatur:[22,30,162,213,254,278,289,336,354,388,410,414,416,418,419,427,436,437,439,441,444,445,464,469,476,487,488,526],signed_integ:493,signedinteg:486,signedon:428,signifi:[15,22,393,464],signific:[6,30,118,479,490],significantli:27,signup:124,silenc:[223,418],silenced_system_check:8,silent:[13,54,136,172,216,223,364,420,428],silli:[37,41,146],silmarillion:153,silvren:191,similar:[0,7,13,14,22,28,31,37,48,49,51,52,53,67,72,74,76,95,97,104,114,117,118,122,123,125,126,135,144,149,155,156,162,169,174,187,191,204,213,215,229,232,241,292,308,309,310,311,312,329,349,380,390,398,405,457,467,472,476,492,515,541,545],similarli:[46,112,118,135,136,191,270,309,354,501,508,515],simpl:[0,8,12,13,14,15,16,17,20,22,25,27,30,31,32,37,39,41,44,46,53,54,58,62,64,67,68,69,73,75,79,80,81,82,85,86,90,91,92,93,95,96,97,98,101,104,105,106,107,109,111,113,114,117,120,122,123,124,126,127,129,130,132,133,134,135,137,139,141,142,143,149,150,152,153,155,156,157,161,162,163,164,165,166,170,171,172,173,175,176,177,187,191,192,193,194,218,232,241,242,251,256,273,275,277,283,289,292,293,296,299,305,308,309,310,311,312,316,321,322,325,329,335,349,350,354,359,362,364,366,370,371,372,380,382,386,387,397,398,403,409,426,435,437,464,470,471,476,479,492,529,530,532,545],simple_ev:30,simpledoor:[201,202,235,314,545],simpledoorcmdset:[109,322],simpleev:30,simplemu:183,simpleobjectdbseri:515,simpler:[16,28,54,133,217,218,473,541],simpleresponsereceiv:418,simplest:[13,39,53,114,128,135,143,162,164,191,212,470,493],simpli:[8,9,11,13,14,17,20,28,33,39,46,48,53,55,60,62,65,74,76,77,82,85,90,91,99,110,113,119,120,125,126,128,130,132,135,139,141,144,147,150,156,157,161,162,165,172,174,176,181,182,185,188,189,194,195,204,211,212,213,229,230,232,241,251,258,289,308,309,310,311,312,316,325,337,362,364,371,386,388,390,398,434,464,466,470,471,475,477,492],simplic:[58,76,130,175,230,251,371],simplif:[158,164],simplifi:[5,54,64,137,149,164,170,172,193,254],simplist:[51,111,164,165,176,349,366],simul:[5,22,104,110,152,158,162,325],simultan:[68,135,158,164,396,492],sinc:[0,3,5,6,8,11,13,14,15,18,19,20,22,25,27,28,30,31,32,33,34,35,37,39,42,47,48,52,53,54,57,58,60,62,64,65,67,68,73,75,76,78,79,97,104,106,113,118,120,122,123,124,125,126,127,128,130,131,132,133,134,135,136,137,141,142,143,145,146,147,148,149,150,151,152,153,154,155,156,158,159,161,164,165,167,170,172,174,175,177,178,182,184,187,191,193,195,199,204,205,207,211,212,213,218,226,227,228,233,241,245,247,275,283,292,299,308,309,310,311,312,316,333,337,338,350,364,371,372,386,393,396,398,402,403,407,410,411,416,418,421,433,438,440,454,455,457,459,464,465,466,470,471,472,474,476,479,480,483,485,488,489,490,492,501,508,532],singl:[5,9,11,15,20,22,28,30,35,36,42,44,46,48,54,56,65,68,69,72,76,78,95,97,103,104,107,112,115,116,118,120,122,123,131,134,135,146,150,151,152,155,157,158,162,170,182,187,191,204,216,223,224,228,234,241,266,270,293,308,309,310,311,312,329,335,337,338,340,354,372,376,382,386,398,402,403,410,411,448,455,457,464,465,467,469,470,475,476,478,492,495,532,545],single_type_count:286,singleton:[34,44,47,118,407,410,471,545],singular:[120,135,398,495,497],sink:0,sint:29,sir:96,sit:[15,18,22,39,48,65,98,122,128,143,148,150,151,152,158,161,165,174,185,191,226,232,234,260,275,278,299,338,350,371,372,394,405,408,411,429,467,472,487,490],sitabl:48,sitat:372,site:[6,17,33,40,50,53,56,119,137,170,177,178,180,181,182,187,188,191,192,193,194,338,461,503,523,545],site_head:[50,523],site_id:53,sitekei:545,sitsondthi:161,sitsonthi:161,sittabl:[275,545],sittablein:161,sitter:161,situ:[13,466,473],situat:[3,13,22,30,31,42,44,48,52,64,65,67,76,95,96,97,119,136,150,153,161,212,213,218,256,276,483],six:[95,142,162,343,386],sixti:136,sizabl:77,size:[3,6,51,56,69,104,117,118,132,135,159,170,183,201,239,329,337,338,418,432,469,475,477,478,483,485,492],size_limit:492,skeleton:165,sketch:164,skill:[28,58,104,106,112,122,127,128,129,138,146,148,151,156,157,162,164,174,177,178,180,199,293,340,349,350,353,354,475,545],skill_combat:162,skill_craft:86,skill_requir:293,skill_rol:293,skillnam:162,skillrecip:86,skim:[104,115,146,159],skin:[41,293],skip:[0,7,18,20,22,28,41,47,53,58,68,77,80,99,118,120,132,136,143,144,146,148,150,152,156,159,190,193,204,217,218,293,398,402,464,473,492,510],skip_cal:275,skipkei:445,skippabl:[22,72],skull:41,sky:[42,176],slack:180,slam:[92,380],slash:[53,122,144,154,155,162,164,239,371],slate:[150,170],sleep:[22,30,54,128,158,162],sleepi:13,slew:[162,190,470],slice:[215,469,477],slice_bright_bg:215,slice_bright_fg:215,slice_dark_bg:215,slice_dark_fg:215,slide:[293,364],slider:53,slight:[142,181,247,257],slightli:[3,31,136,157,164,165,180,185,234,270,309,316,500,543],slip:491,slogan:75,sloppi:120,slot:[53,92,112,135,178,309,311,316,354,380,403,492,545],slow:[5,19,104,115,157,164,228,233,324,325,326,329,333,338,370,402,429,435,469,489,492,545],slow_exit:[110,201,202,228,235,314,545],slowdoorcmdset:[110,325],slower:[5,42,136,158,191],slowexit:[110,325],slowexitcmdset:325,slowli:[112,180,354,544],slug:[213,232,388,390,466,540,543],slugifi:[537,540],slugify_cat:540,small:[5,6,9,15,16,22,35,52,56,69,81,86,90,104,115,117,118,119,122,124,126,129,134,135,137,138,139,141,142,155,156,157,158,159,161,165,166,170,180,185,191,192,289,292,311,329,331,332,335,337,343,354,364,439,474,475,478,492],smaller:[14,15,56,120,335,354,478],smallest:[39,87,95,106,112,135,136,191,247,349,354,475,492],smallshield:67,smart:[117,142,329,338],smarter:41,smartmaplink:338,smartreroutermaplink:338,smartteleportermaplink:338,smash:[108,364],smaug:[143,149,150,152],smedt:495,smell:[118,156,275],smellabl:275,smelli:41,smile:[22,30,149,157,224,273,497],smith:[58,475],smithi:128,smoothi:[104,105,305],smoothli:178,snake:[53,169],snap:140,snapshot:11,snazzi:179,sneak:394,snippet:[14,20,33,52,54,60,85,104,122,123,125,143,157,228,289,425,491,492],snonewaymaplink:[118,338],snoop:[187,194],snow:[86,292],snowbal:[86,292],snowball_recip:86,snuff:0,soak:150,social:[122,158,188],socializechat:448,societi:146,sofa:161,soft:[61,106,123,124,349,545],softcod:[30,72,95,104,158,545],softli:179,softwar:[2,11,185,191],solar:136,soldier:[141,152],sole:[134,137,205],solid:[60,122,132,159],solo:[148,158,185],solut:[8,15,19,28,31,47,48,75,97,112,118,126,128,130,133,137,141,142,155,158,161,162,170,172,174,191,194,227,337,338,354,394,545],solv:[6,19,90,104,105,118,125,131,132,138,155,156,170,185,278,305,337,371,545],some:[0,1,2,3,6,7,8,9,11,13,14,15,16,18,19,20,22,26,27,28,30,31,32,33,35,36,37,41,42,44,45,46,47,48,49,50,51,53,55,56,58,60,62,64,65,67,69,70,75,76,78,79,86,89,90,95,96,97,107,112,113,114,115,118,119,120,122,123,124,125,126,127,128,132,134,135,136,137,138,140,141,142,143,144,145,146,148,149,150,152,154,155,156,159,160,161,162,163,164,165,167,169,170,171,172,174,175,177,178,179,180,181,182,183,185,187,189,190,191,194,195,197,198,199,204,212,213,218,220,223,224,227,228,230,232,233,241,251,257,260,270,275,278,283,289,292,309,310,311,312,322,329,338,349,354,364,369,371,372,382,386,394,398,402,403,406,418,420,425,428,454,464,466,469,470,475,476,479,480,483,485,486,492,495,496,500,505,518,532,543,545],some_long_text_output:477,some_modul:147,somebodi:[95,97],someclass:147,somehow:[22,36,53,62,70,74,99,161,162,191,286,474],someon:[22,33,45,47,50,58,95,96,97,128,132,135,141,143,146,151,159,161,171,172,191,194,204,224,286,364,370,371,398],somepassword:182,someplac:370,someth:[5,8,9,11,13,15,18,19,22,28,29,30,31,33,37,39,41,42,45,47,48,50,51,52,54,55,58,60,62,65,67,69,72,73,75,76,77,79,85,86,95,96,97,99,104,107,110,112,116,118,119,120,122,123,124,126,128,129,130,131,132,133,134,135,136,137,140,141,142,143,144,146,149,151,152,153,155,156,159,161,162,165,167,170,177,178,181,182,186,187,188,189,190,191,195,197,204,211,213,218,224,226,229,241,260,270,283,286,289,293,296,308,309,310,311,312,325,329,338,350,354,371,372,382,394,398,403,455,466,470,476,477,479,486,492,538,545],something_els:42,sometim:[3,5,19,22,27,28,33,39,41,42,53,62,67,76,95,123,136,142,146,150,151,153,169,199,225,396],sometypeclass:[95,145],somewhat:[76,124,134,241],somewher:[8,11,41,42,48,55,90,97,118,119,150,161,162,174,191,213,218,232,331,388,390,466,492,545],somon:275,soon:[3,13,44,137,156,158,189,193,445,492],sophist:[19,54,69,122,164],sorl:124,sorri:[33,200,394],sort:[13,20,34,39,44,46,53,58,65,73,74,79,86,94,104,112,114,115,123,130,132,137,146,149,150,151,156,162,164,167,171,191,199,275,283,308,309,310,311,312,338,346,354,372,398,403,406,464,465,466,476,492,523,532,537,538,540,541,542,545],sort_kei:445,sort_stat:5,sortkei:5,sought:[204,210,232,388,390,398,464,466],soul:[159,170],sound:[33,47,64,65,76,90,99,104,106,119,128,135,140,146,156,157,161,170,195,349,440],sourc:[1,2,6,8,9,10,11,16,17,19,20,26,30,37,54,55,56,64,68,69,75,76,77,95,96,97,113,115,119,121,122,123,124,125,134,147,151,154,155,157,178,180,182,185,187,189,190,201,204,205,206,207,209,210,211,212,213,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,232,233,234,239,241,242,245,247,248,251,252,254,255,256,257,258,260,266,267,269,270,273,274,275,276,277,278,279,280,283,284,286,287,289,290,292,293,294,296,297,299,300,302,303,305,306,308,309,310,311,312,313,316,317,322,323,325,326,328,329,331,332,333,335,336,337,338,339,340,343,344,346,347,349,350,351,353,354,359,360,362,364,366,367,369,370,371,372,373,376,377,378,380,382,383,385,386,388,389,390,391,393,394,396,397,398,400,401,402,403,405,406,407,408,409,410,411,413,414,415,416,418,419,420,421,422,423,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,447,448,449,451,452,453,454,455,456,457,459,460,461,464,465,466,467,469,470,471,473,474,475,476,477,478,479,480,482,483,484,485,486,487,488,489,490,491,492,493,495,496,497,500,501,502,503,504,505,506,507,508,510,512,513,514,515,516,518,520,523,524,525,526,527,530,532,533,536,537,538,539,540,541,542,543,544,545],source_loc:[126,171,276,329,371,372,398],source_object:[230,251],sourceforg:[429,430,440,443],sourceurl:428,south:[76,97,99,118,131,132,161,170,174,218,331,337,338,448],south_north:170,south_room:99,southeast:[218,338],southern:170,southwest:[118,144,218,338],space:[13,18,22,25,30,31,33,36,41,42,51,58,60,72,75,76,77,78,95,96,99,118,120,125,126,132,134,142,143,144,150,151,152,154,164,170,172,175,210,213,218,223,224,225,226,229,230,293,302,312,337,338,349,350,371,398,460,466,469,470,475,476,478,479,491,492,496,521,545],spaceship:174,spacestart:491,spaghetti:[14,476],spam:[18,42,55,80,127,138,164,194,223,459],spammi:[55,164],span:[17,56,69],spanish:64,spare:[308,309,310,311,312,337],sparkly_mag:146,spars:78,spatial:170,spawen:[105,305],spawn:[5,18,26,35,51,86,90,104,105,118,121,143,147,155,158,173,201,216,218,292,305,309,310,332,335,337,338,339,400,401,402,403,545],spawn_alias:[118,338],spawn_link:[337,338],spawn_nod:337,spawner:[24,37,118,173,201,202,218,310,311,399,401,545],spawng:86,spd:178,speak:[16,18,57,70,96,97,104,106,158,171,172,175,177,224,275,350,398],speaker:[95,96,106,275,349,350],spear:41,special:[0,3,8,12,13,14,15,16,18,19,20,22,25,28,30,33,37,39,45,46,48,50,51,52,53,54,57,60,64,65,67,68,70,91,93,95,104,118,120,123,126,129,135,137,139,141,144,146,147,148,149,150,151,152,153,157,164,165,170,178,194,195,205,207,209,212,224,227,273,275,276,280,296,310,311,316,329,340,350,371,372,386,391,394,398,420,421,444,448,464,466,470,476,491,505,545],specic:337,specif:[0,2,3,8,11,12,13,19,20,22,27,28,33,36,37,39,44,45,46,47,48,49,51,55,58,62,68,73,75,76,79,82,85,86,95,96,97,104,107,118,119,120,121,122,123,124,126,130,133,136,137,140,142,146,147,148,149,151,152,153,155,156,158,164,165,170,174,175,176,177,178,179,180,182,183,187,191,193,199,204,206,209,216,218,225,228,230,234,235,241,254,255,256,257,273,275,283,289,292,293,299,331,337,338,339,350,382,389,393,396,398,405,407,416,420,421,428,444,445,455,464,466,469,470,474,476,477,478,492,496,501,503,512,543,544],specifi:[8,13,18,19,20,28,31,34,41,44,46,47,53,55,56,57,58,60,65,67,68,76,82,83,84,86,88,92,95,96,105,112,113,117,118,120,125,128,130,132,135,136,142,144,145,149,150,152,153,161,165,167,169,170,178,184,185,191,192,193,194,209,210,218,225,232,233,241,242,244,254,256,257,275,286,292,299,305,309,310,311,316,329,331,337,338,343,350,354,380,382,386,393,394,398,401,402,403,407,427,453,464,467,469,470,472,475,476,479,480,486,487,488,490,492,495,496,512,515,532,540,543],specifici:276,specii:58,spectacular:3,spectrum:158,speech:[273,398],speed:[5,13,36,67,79,104,110,136,140,158,164,178,325,396,403,434,467,489],speedup:402,spefifi:479,spell:[16,41,46,57,113,114,127,134,201,202,235,281,291,311,386,403,545],spell_attack:311,spell_book:86,spell_conjur:311,spell_heal:311,spell_nam:311,spellbook:[292,293],spellcast:[114,157],spellnam:[293,311],spend:[37,114,130,142,153,158,159,308,309,310,311,312],spend_act:[308,309,310,311,312],spend_item_us:310,spent:311,sphinx:120,spike:292,spiked_club:292,spin:[52,136,191,490],spit:[151,164,167,292],splashscreen:251,splinter:155,split:[20,22,44,75,117,118,126,135,142,150,151,158,165,169,170,172,174,195,210,226,247,329,371,391,400,442,457,469,470,480],split_nested_attr:218,spoiler:115,spoken:[96,97,106,157,189,349,350,398],spoof:[187,501,508],spool:185,sport:36,spot:[53,99,123,134,204,335,338],spread:[5,30,41,146,161,162,545],spring:[91,140,316,317],spring_desc:317,sprint:325,sprofil:416,spruce:58,spuriou:545,spy:35,spyrit:183,sql:[2,48,67,123,133,134,153,451,545],sqlite3:[5,8,9,11,67,123,148,165,197,198,492,545],sqlite3_prep:454,sqlite:[9,67,182,454],sqllite:2,sqrt:130,squar:[30,72,99,120,130],squeez:[67,120],src:[17,33,37,51,54,144,177,190,193,377],srcobj:[213,226],srun:420,srv:2,ssessionhandl:65,ssh:[44,62,65,75,123,126,191,199,201,202,412,424,455,456,545],ssh_interfac:191,ssh_port:191,sshd_config:194,sshfactori:436,sshprotocol:436,sshserverfactori:436,sshuserauthserv:436,ssl:[65,68,123,181,187,201,202,205,223,412,424,428,441,456,545],ssl_context:[437,441],ssl_interfac:191,ssl_port:191,sslcertificatefil:181,sslcertificatekeyfil:181,sslciphersuit:181,sslengin:181,ssllab:181,sslprotocol:[181,437,441],ssltest:181,sslv3:187,sta:475,stab:[128,155,371],stabil:[156,229,349],stabl:[53,62,133,193],stabli:[6,411],stack:[14,20,51,156,161,174,211,212,398,402,457,476,545],stackedinlin:500,stackexchang:8,stackoverflow:8,stacktrac:402,staf:69,staff:[18,22,39,41,50,57,69,75,95,104,126,134,156,162,165,170,177,211,340,403,470,545],staffer:[50,75,158],staffernam:75,stage:[2,11,12,133,156,165,170,177,500,502,505],stagger:428,stai:[20,28,48,90,132,142,151,174,175,185,191,197,329,338],stale:[48,193,410],stale_timeout:410,stalker:538,stamina:[94,112,129,157,311,346,354],stamp:[19,44,48,51,204,207,216,228,397,406,448,453,466],stanc:[30,106,158,164,350,398,479,495,545],stand:[8,11,14,17,33,50,67,76,95,104,106,115,118,120,125,126,128,132,133,144,147,151,153,155,157,161,162,164,165,170,174,177,185,189,191,224,273,275,283,340,350,370,398,406,411,447,467,470,472,478,508],standalon:[187,194],standard:[13,16,18,19,27,49,53,60,61,65,68,70,75,88,89,95,97,104,116,118,123,125,129,134,135,142,146,149,151,164,169,173,175,180,181,185,187,194,201,204,215,251,270,340,343,350,398,436,438,443,460,464,469,478,480,490,493,517,545],stander:161,stanislav:77,stanza:[58,426],stapl:158,star:218,start:[3,5,6,7,8,9,10,11,12,14,15,16,18,19,20,22,27,28,30,32,33,34,36,39,41,42,44,45,48,51,52,53,55,56,59,60,62,63,64,65,67,69,77,79,86,90,91,92,93,97,104,106,111,112,114,115,118,119,120,122,123,124,125,126,128,130,131,132,134,136,137,142,144,146,147,148,149,152,156,157,158,159,161,162,164,165,167,169,170,173,174,176,177,180,182,184,186,187,189,190,191,192,194,195,197,204,205,210,211,217,218,223,224,225,226,227,228,229,232,241,247,257,273,274,275,277,283,292,296,308,309,310,311,312,316,329,337,338,343,346,349,350,354,364,366,369,370,372,380,386,398,400,402,405,406,407,408,409,410,411,413,416,418,420,421,426,427,428,429,433,434,435,440,441,447,448,453,454,457,461,465,469,470,471,472,474,476,477,478,479,480,485,492,521,544,545],start_all_dummy_cli:447,start_attack:370,start_bot_sess:457,start_char:479,start_delai:[42,164,173,174,405,406,411,472],start_direct:338,start_driv:174,start_evennia:416,start_hunt:370,start_idl:370,start_index:223,start_lines1:416,start_lines2:416,start_loc_on_grid:132,start_of_messag:502,start_olc:400,start_only_serv:416,start_open:275,start_ov:28,start_patrol:370,start_plugin_servic:62,start_portal_interact:416,start_posit:275,start_read:275,start_rotat:275,start_serv:426,start_server_interact:416,start_sunrise_ev:136,start_text:386,start_turn:[308,309,310,311,312],start_xi:[118,337],startapp:[67,137,177,178],startclr:479,startcolor:30,startcoord:335,startedconnect:[413,427,428],starter:[75,154,155,169],starthour:126,startnod:[28,141,274,369,380,400,476],startnode_input:[28,274,369,380,400,476],startproduc:418,startservic:[419,461],startset:372,startswith:[31,34,218,469,490],starttupl:436,startup:[13,25,62,136,148,169,191,195,398,406,409,445,454,485,492],stat:[5,13,17,28,53,79,112,138,141,148,149,151,152,156,157,164,165,169,177,178,188,283,308,309,310,311,312,354,541,545],state:[3,11,13,14,15,20,22,26,27,28,33,42,44,51,60,85,90,104,108,122,123,133,148,149,152,155,158,164,174,175,193,199,201,202,204,209,211,212,215,222,230,232,235,271,272,273,275,276,279,280,289,308,309,310,311,312,322,364,370,372,403,406,408,409,411,416,436,464,474,476,545],state_001_start:90,state_chang:278,state_nam:278,state_unlog:222,statefultelnetprotocol:[439,447],statehandl:[276,278],statement:[3,14,15,19,20,28,53,54,67,77,122,132,135,146,151,172,364,470,491],statenam:[273,275,278],static_overrid:[51,73,148,169],static_root:169,staticfil:[77,104],staticfiles_storag:77,statict:218,statictrait:[112,354],station:[95,158,174],stationari:370,statist:[44,52,53,55,73,94,167,173,195,218,228,346,449,465,483],statu:[11,28,44,47,50,68,79,114,128,135,144,148,156,157,182,187,191,195,228,283,310,311,312,370,411,414,416,425,426,427,430,444,500,545],status:[156,545],status_cod:418,stderr:270,stdin_open:193,stdout:[193,270,416,485],steadi:123,steal:[35,141,225],stealth:158,steel:293,steer:174,step1:128,step2:128,step3:128,step:[0,2,6,7,9,14,15,18,20,22,27,28,41,67,69,82,95,96,97,104,118,120,124,125,128,130,135,137,138,140,141,142,158,159,160,162,165,174,175,178,181,182,185,193,217,223,241,293,335,337,338,353,372,411,420,432,443,447,448,457,466,470,473,474,476,477,545],step_sequ:331,stepper:[118,338],stick:[16,22,28,70,86,120,185,216],still:[0,1,7,9,11,13,14,15,16,18,20,22,44,45,48,50,57,58,60,62,64,65,69,75,76,86,90,95,97,103,104,112,113,117,118,120,122,123,124,126,128,130,132,134,135,136,142,143,144,148,149,150,151,158,161,165,174,175,178,179,180,185,187,194,199,204,211,218,223,225,230,232,251,266,278,292,308,309,310,311,312,329,338,353,354,369,372,386,396,398,402,408,448,476,478,479,480,488,492,540],sting:170,stock:[122,141,159,377,532],stolen:[194,469],stone:[22,28,58,144,153,159],stop:[3,5,7,9,15,18,19,30,32,37,39,42,44,47,51,54,55,64,69,75,95,104,108,109,110,112,118,126,128,132,134,135,136,140,144,147,148,151,154,157,158,161,164,165,173,174,185,187,191,193,195,197,215,218,223,228,232,247,256,258,283,293,309,312,322,325,338,350,354,364,398,405,408,409,410,411,415,416,418,421,433,434,454,455,461,469,470,472,492,545],stop_driv:174,stop_evennia:416,stop_serv:426,stop_server_onli:416,stopproduc:418,stopservic:[419,461],storag:[13,14,22,48,67,77,85,123,127,128,133,141,147,159,162,177,182,207,228,234,237,239,260,289,329,349,354,388,394,397,398,402,403,406,409,411,423,459,463,464,466,471,486,487,545],storage_modul:471,storagecontain:42,storagescript:42,store:[4,6,9,11,12,14,16,18,19,20,22,23,27,31,33,35,36,37,39,42,44,46,47,48,50,51,62,67,70,73,75,77,79,80,86,91,96,97,104,106,107,112,117,118,123,125,127,128,130,131,132,133,134,135,137,140,141,142,143,146,148,149,150,151,152,156,161,162,164,165,169,174,177,178,182,190,193,195,204,205,207,212,215,216,218,219,221,225,226,234,257,276,278,283,292,293,302,310,316,325,329,338,339,349,350,354,359,366,371,372,377,380,382,388,389,393,394,397,401,402,403,404,407,408,409,410,411,416,420,421,422,423,426,428,429,430,432,440,443,448,454,455,456,457,459,461,464,465,466,467,469,471,472,473,474,475,476,477,480,483,486,487,488,492,518,532,543,545],store_kei:[411,492],store_tru:[116,270],stored_obj:126,storekei:[141,411],storenam:141,storeroom:141,storeroom_exit:141,storeroom_kei:141,storeroom_key_nam:141,stori:[6,31,75,114,167,177],storm:127,storm_drain:86,storypag:167,storytel:165,stove:398,str:[13,19,27,28,30,32,34,35,42,48,54,62,70,76,92,95,97,99,104,112,118,126,130,135,140,142,143,149,150,151,157,162,177,178,201,204,205,206,209,210,211,212,213,218,223,225,232,233,234,241,247,254,255,256,257,260,270,274,275,276,278,280,283,286,289,292,296,299,308,309,310,311,312,316,322,329,337,338,339,340,346,349,350,353,354,362,364,369,372,377,380,382,386,388,389,390,391,394,396,397,398,401,402,403,405,407,408,409,411,413,414,416,420,421,422,423,425,426,427,428,429,431,434,435,436,439,440,441,444,445,447,453,454,455,456,457,459,460,461,464,465,466,467,469,470,471,472,474,475,476,477,478,479,485,486,487,488,489,490,491,492,493,495,496,501,510,512,515,524,538,540],straght:338,straight:[118,132,159,175,338,467],straightforward:[126,141,142,165,174],strang:[15,42,128,133,149,181,212,230],strange_bug:11,strangl:191,strap:158,strategi:[3,312],strattr:[13,464],strawberri:[116,270],stream:[7,425,429,455],streamlin:[2,283],streeter:77,stren:151,strengh:13,strength:[13,33,112,134,135,148,149,157,158,162,164,178,353,354],stress:[5,335,447],stretch:[118,120,170],stribg:492,strict:[54,294,402,469,540],stricter:[159,402],strictli:[28,57,89,146,177,251,311,478],strike:[28,140,164,224,311,312,366],string1:492,string2:492,string:[3,5,6,8,13,14,16,18,19,20,22,24,25,27,28,30,31,34,36,37,39,41,46,47,48,50,51,55,57,58,64,65,67,68,70,72,75,76,86,92,99,104,106,107,113,117,120,122,126,128,132,134,135,140,143,144,146,148,149,150,151,152,153,157,158,161,164,170,177,178,182,184,185,188,191,195,201,202,204,205,206,207,209,210,213,216,218,223,224,225,226,227,228,229,232,233,234,241,250,251,260,275,280,283,286,289,292,299,305,308,309,310,311,312,329,337,339,340,349,350,354,364,369,370,377,378,380,382,383,386,389,390,392,393,394,396,397,398,401,402,403,405,406,409,411,416,418,421,425,428,436,439,440,442,445,448,453,455,457,460,464,465,466,467,468,469,470,472,473,474,475,477,478,479,485,486,488,489,490,491,492,493,495,496,501,508,515,540,543,545],string_from_modul:492,string_partial_match:[396,492],string_similar:492,string_suggest:492,stringproduc:418,stringvalu:[112,354],strip:[22,28,30,31,32,60,69,76,95,120,125,135,139,141,143,150,161,165,172,210,218,225,226,227,275,293,350,396,403,421,436,439,440,469,470,474,476,479,490,492,545],strip_ansi:[139,469,491],strip_cmd_prefix:225,strip_control_sequ:492,strip_dir:5,strip_mxp:469,strip_raw_ansi:469,strip_raw_cod:469,strip_unsafe_input:492,strip_unsafe_token:469,strippabl:476,stroll:325,strong:[33,60,159,165,491],strongest:33,strongli:[11,18,49,119,123,151,158,162,349],strr:382,struct:133,structur:[13,22,28,30,31,39,41,53,65,68,75,77,104,119,122,123,132,133,137,143,146,147,148,151,158,169,177,178,185,218,223,232,337,339,350,391,398,402,403,440,445,467,473,476,513,529,541,545],strvalu:[13,464,465],stuck:[28,143,155,161,185],studi:545,stuff:[8,13,20,28,30,33,39,41,42,44,45,53,75,93,104,112,116,119,120,125,128,132,134,138,141,143,150,151,152,153,154,155,156,157,158,161,162,167,187,212,229,270,296,353,354,411,454,525,545],stumbl:[6,159],stupid:[11,153,159],sturdi:475,stutter:69,style:[7,13,18,19,22,26,28,36,56,60,62,72,83,84,86,98,104,105,112,113,114,119,120,122,125,134,135,138,143,151,154,155,156,158,159,163,164,167,170,180,207,213,215,226,244,265,268,270,280,286,292,299,308,354,380,402,474,478,479,492,545],styled_foot:213,styled_head:[22,213],styled_separ:213,styled_t:[22,213],sub:[2,13,18,30,31,41,42,51,53,68,69,75,103,106,120,134,137,146,148,164,186,191,203,208,223,225,231,235,241,242,266,270,335,350,387,389,391,392,395,403,404,412,463,468,469,479,491,498,502,534,545],sub_ansi:469,sub_app:177,sub_brightbg:469,sub_dblspac:491,sub_mxp_link:491,sub_mxp_url:491,sub_text:491,sub_to_channel:223,sub_xterm256:469,subbed_chan:223,subcategori:[225,391],subclass:[19,41,44,48,112,117,118,123,146,148,172,218,241,242,329,354,397,402,406,426,439,445,466,484,488,492,500,501,508,545],subcommand:118,subcrib:18,subdir:8,subdirectori:8,subdomain:[181,191,194],subfold:[67,73,119,148,151,178],subhead:120,subject:[2,35,58,67,93,130,139,146,191,296,299,479,496],sublim:154,submarin:174,submenu:[7,241,242,400],submenu_class:241,submenu_obj:241,submiss:[92,380,532],submit:[17,53,92,104,119,177,194,230,380,532,536,538,543],submitcmd:380,submodul:440,subnegoti:440,subnet:[55,182,216],subpackag:[8,68],subprocess:[126,492],subreddit:180,subscrib:[9,18,22,33,47,55,121,123,135,176,205,223,232,233,234,266,310,411,427,458],subscribernam:223,subscript:[18,22,42,47,135,176,180,223,233,234,411,502],subscriptionhandl:[18,234],subsect:337,subsequ:[22,54,106,151,164,185,266,273,349,470,492],subsequent_ind:478,subset:[8,46,133,148,158,337],subsid:48,substanti:[77,292],substitut:[7,36,188,398,469,491],substr:[150,469,479],subsub:[31,225,229],subsubhead:120,subsubsubhead:120,subsubtop:[31,225,229],subsubtopicn:229,subsystem:[67,75,114,157,185,394],subtext:276,subtitl:17,subtop:[223,225,229,388,391,545],subtopic_separator_char:225,subtract:[30,104,112,141,353],subturn:164,subwai:95,subword:492,suc:86,succe:[86,155,156,164,269,292,343,545],succeed:[28,116,223,270,343],success:[86,146,157,158,162,164,165,178,204,223,232,283,292,308,309,310,311,312,343,364,371,372,394,402,410,416,420,466,474,486,492,543],success_messag:[292,293],success_teleport_msg:372,success_teleport_to:372,success_url:[536,538],successfuli:[105,292,305],successfulli:[2,10,22,54,105,127,152,161,170,199,204,292,293,294,305,329,371,398,410,416,428,460,466,543],suddenli:[0,6,466],sudo:[185,187,193,194],sue:157,suffic:[17,134,151],suffici:[67,77,191],suffix:[6,19,30,469,479,485,492,518],suggest:[0,6,28,29,31,48,74,77,112,115,119,120,122,126,156,157,158,159,182,191,210,225,283,293,350,354,372,391,398,492],suggestion_cutoff:225,suggestion_maxnum:[225,391],suggests:31,suit:[10,114,123,128,159,171,229,492,541,545],suitabl:[11,22,30,33,36,42,46,50,65,68,104,111,118,119,122,123,125,126,143,146,151,154,185,191,206,211,223,275,292,337,394,450,457,472,476,479],sum:[118,119,140,142,147,154,212,276],summar:[97,104,119,143,180],summari:[50,95,96,97,119,165,180,199,241,545],summer:[91,157,158,316],sun:[118,136],sunris:136,sunt:29,super_long_text:477,superclass:500,superfici:[106,349],superflu:[11,491],supersus:394,superus:[5,8,12,14,15,33,50,57,75,80,83,95,109,115,124,125,126,135,139,144,148,149,150,151,154,155,158,161,170,178,182,185,198,204,206,207,217,228,232,286,322,370,393,394,398,403,416,466,470,472,500,545],supplement:28,suppli:[5,13,19,28,31,32,34,41,42,44,46,47,49,54,58,68,89,91,95,112,119,135,150,158,164,165,185,189,207,212,213,216,218,223,228,229,233,241,247,251,316,337,346,354,396,397,398,402,406,411,427,457,466,474,479,480,489,492],supporst:443,support:[3,12,13,18,22,27,28,30,31,32,35,36,41,42,59,60,62,63,64,65,67,70,75,77,84,85,88,91,95,103,104,116,118,119,120,122,123,124,131,132,133,134,135,139,142,147,150,151,153,154,156,157,158,159,165,175,181,182,185,186,190,191,192,193,194,197,198,199,204,215,224,225,228,244,247,260,266,270,275,289,316,338,343,355,393,398,402,403,411,421,429,430,431,432,436,438,439,440,441,443,445,456,464,469,473,476,477,478,479,489,490,492,495,524,540,545],supports_set:[32,421],suppos:[0,22,28,41,49,65,97,146,204,241],supposedli:[106,187,349,440],suppress:[183,438],suppress_ga:[201,202,412,424,545],suppressga:438,supress:438,sur:180,sure:[2,3,6,7,8,9,11,12,13,14,15,16,18,20,22,28,31,33,36,37,39,41,42,44,46,47,48,49,50,51,53,55,57,64,67,70,74,75,78,90,97,99,106,112,113,118,120,124,125,126,127,128,129,131,132,134,135,136,139,142,144,146,149,150,151,154,155,156,157,158,159,161,162,164,165,169,170,172,175,177,178,179,181,182,185,187,188,189,190,191,193,198,199,204,205,211,212,213,215,218,226,233,241,258,275,286,292,311,338,349,350,354,359,370,371,372,378,382,386,389,393,394,398,402,403,408,416,420,426,428,433,454,460,461,462,465,466,469,471,473,476,483,488,489,491,492,501,508,510,533,541,543],surfac:[104,115,135,140,194,275],surpris:[13,33,76,130,137,142,151],surround:[20,22,30,72,99,115,118,164,170,216,280,338,370,488,492,545],surviv:[13,19,20,27,28,30,34,42,44,47,112,127,149,164,175,205,212,228,241,289,354,396,405,406,407,411,472,474,476,492],survivor:158,suscept:[19,133,394],suspect:177,suspend:[7,193,194],suspici:28,suspicion:177,svn:[2,69],swallow:[172,421,425,491],swam:[495,497],swap:[8,26,51,60,91,218,302,316,466,474,545],swap_autoind:474,swap_object:466,swap_typeclass:[48,204,466],swapcas:469,swapper:466,swedish:64,sweep:42,swiftli:54,swim:[495,497],swing:[22,127,128,140,150],switch1:72,switch2:72,switch_map:218,switch_opt:[215,216,217,218,223,224,225,226,228,266,316],sword:[13,22,49,67,79,86,95,104,112,127,141,144,146,153,155,157,158,161,162,201,202,235,275,281,283,291,292,294,350,354,396,403,489,492,545],swordbladerecip:293,swordguardrecip:293,swordhandlerecip:293,swordmanship:157,swordpommelrecip:293,swordrecip:[292,293],swordsmithingbaserecip:293,swum:[495,497],sylliaa:77,symbol:[7,15,16,22,69,117,118,132,146,190,230,329,332,335,337,338,340,350,386,477],symlink:[120,185],symlinkorcopi:77,symmetr:478,symmetri:8,sync:[11,44,52,65,123,337,338,339,405,434,439,454,455,456,457,464,473],sync_node_to_grid:338,sync_port:457,syncdata:[456,457],syncdb:8,synchron:[485,545],syntact:[394,492],syntax:[6,11,14,15,16,22,28,33,60,72,76,80,92,95,96,103,104,116,122,125,128,135,136,142,144,149,165,178,182,201,202,213,217,218,225,226,229,241,270,273,292,316,343,380,394,398,416,428,455,464,466,468,469,545],syntaxerror:151,sys:540,sys_cmd:211,syscmdkei:[22,121,201],syscommand:[201,202,208,214,398,545],syslog:[78,376],sysroot:190,system:[0,2,5,6,8,9,11,12,13,18,19,20,23,24,26,32,34,35,36,39,41,42,44,45,46,47,48,53,54,57,62,64,65,67,69,72,74,75,76,78,83,87,90,96,97,102,104,113,115,118,119,120,121,122,123,124,125,127,128,130,131,132,133,136,139,141,147,148,149,151,154,155,161,169,170,174,175,176,178,180,182,185,187,190,191,194,195,198,199,201,202,205,207,208,209,211,213,214,215,217,218,225,227,229,231,232,233,234,237,241,251,255,256,257,258,260,275,283,284,286,292,293,294,298,299,302,305,307,308,309,310,311,312,329,335,336,337,338,340,349,350,351,369,372,376,377,378,386,387,388,390,393,394,397,398,400,402,403,404,416,439,445,453,463,466,470,472,475,476,479,485,496,500,518,544,545],system_command:22,systemat:130,systemctl:181,systemd:187,systemmultimatch:227,systemnoinput:227,systemnomatch:227,tab:[0,2,7,15,51,52,60,75,129,137,151,152,154,159,469,478,491],tabl:[6,9,14,16,48,58,60,68,70,80,95,96,97,99,121,123,124,135,137,140,146,153,170,178,213,215,223,225,228,380,440,459,469,475,477,478,479,489,492,544,545],table_char:475,table_format:215,table_lin:478,table_str:135,tablea:475,tableb:475,tablechar:[135,475],tableclos:[68,440],tablecol:478,tableopen:[68,440],tablet:56,tabletop:[104,114,135,162,180,308,312],tabsiz:[469,478],tabstop:491,tabularinlin:[501,508],tack:[144,212],tackl:119,tactic:[158,162,164],taction:164,tag:[14,18,22,24,26,28,31,32,35,36,39,41,42,48,50,51,52,53,55,60,61,64,67,68,74,75,84,86,93,104,105,106,118,134,135,138,143,144,146,151,169,178,183,193,201,202,206,213,215,216,217,218,223,224,225,226,227,228,229,230,232,233,234,241,244,251,255,266,269,270,273,275,276,283,286,292,293,296,299,302,305,308,309,310,311,312,316,322,325,331,338,340,343,350,354,364,366,369,370,371,372,376,380,382,386,389,390,391,393,396,398,402,403,405,431,445,447,453,463,465,466,469,472,474,475,476,477,478,489,490,492,498,499,500,502,504,505,506,512,515,545],tag_all_charact:276,tag_categori:508,tag_charact:276,tag_data:508,tag_kei:508,tag_typ:[508,512],tagadmin:508,tagcategori:[275,276],tagcount:146,taget_map_xyz:338,tagform:508,tagformset:[501,508],taghandl:[46,48,467,508],taginlin:[500,502,504,505,506,508],tagkei:[393,396,467,472],taglin:17,tagnam:403,tagseri:515,tagshandl:515,tagstr:[403,467],tagtyp:[46,465,467,489,512],tagtypefilt:512,tail:[148,191,193,416,485],tail_log_fil:[416,485],tail_log_funct:485,tailor:[124,137,532],take:[0,3,7,8,14,15,16,17,18,19,20,22,28,29,30,32,33,39,41,44,48,54,56,57,60,62,64,65,69,75,76,78,86,87,90,92,95,96,97,99,104,107,113,115,118,119,120,122,123,124,125,126,127,128,132,133,134,135,136,137,138,141,142,144,148,149,150,151,154,155,157,158,159,160,161,163,164,165,166,167,168,169,170,174,175,177,178,180,190,191,194,195,197,204,205,210,211,215,227,232,234,247,250,273,278,280,283,286,292,305,308,309,310,311,312,316,322,325,331,335,350,364,369,370,372,376,380,382,386,394,403,436,444,447,456,457,465,466,469,474,475,476,477,479,486,490,492,493,496],taken:[0,20,123,133,152,164,165,173,174,194,224,251,308,309,310,311,312,376,389,398,436,460,469,472],takeov:458,tale:167,talk:[11,19,22,28,52,62,96,106,119,135,142,151,158,159,182,191,223,224,266,283,349,350,365,366,367,372,413,496,545],talker:122,talki:[18,123,158],talking_npc:[111,201,202,235,355,545],talkingcmdset:366,talkingnpc:[111,366],tall:[58,72,106,157,158,224,350],tallman:224,tan:293,tang:[143,293],tannin:293,tantal:15,tap:[78,104],target1:311,target2:311,target:[8,11,22,35,58,62,68,88,91,104,106,113,118,125,126,127,128,129,135,143,144,150,151,158,161,162,164,165,169,194,204,213,218,223,224,228,232,234,273,275,278,286,293,299,308,309,310,311,312,316,329,331,332,335,337,338,343,370,386,396,398,407,465,469,472,476,492],target_fire_damag:293,target_flag:275,target_loc:[276,325,329,372,398],target_map_xyz:[118,332,335,338],target_obj:394,target_path_styl:337,targetlist:299,task:[2,5,18,19,26,42,46,62,95,97,142,148,187,199,228,229,255,257,331,386,410,411,492],task_handl:[201,410,492],task_id:[228,257,410],taskhandl:[201,202,404,492,545],taskhandlertask:[410,492],tast:[76,155,159,177],tasti:292,tavern:[106,350],tax:[5,190],taylor:180,tb_basic:[114,201,202,235,281,307,545],tb_equip:[114,201,202,235,281,307,545],tb_filenam:470,tb_item:[114,201,202,235,281,307,545],tb_iter:470,tb_magic:[114,201,202,235,281,307,545],tb_rang:[114,201,202,235,281,307,545],tbbasiccharact:308,tbbasicturnhandl:308,tbearmor:309,tbequipcharact:309,tbequipturnhandl:309,tbeweapon:309,tbitemscharact:310,tbitemscharactertest:310,tbitemsturnhandl:310,tbmagiccharact:311,tbmagicturnhandl:311,tbodi:178,tbrangecharact:312,tbrangeobject:312,tbrangeturnhandl:312,tchar:164,tcp:194,tcpserver:[62,461],teach:[104,138,159],team:[2,11,22,31,69,123,156,158,159],teamciti:545,teardown:[8,229,248,258,279,294,313,335,351,353,360,442,490,516],teardown_account:490,teardown_sess:490,teaser:191,tech:[138,154,159,160,163,166,168,180,545],technic:[28,46,48,54,57,58,60,62,64,65,69,75,118,123,124,130,144,156,159,182,191,201,202,235,283,355,363,464,545],techniqu:[128,158,161,469],technolog:158,tediou:[7,170],teenag:[125,194],tehom:[75,146],tehomcd:75,tel:[26,55,97,135,142,143,174,185,218,331],telepath:158,telephathi:18,teleport:[15,26,55,74,104,135,141,144,155,218,224,331,335,338,372,470,545],teleport_her:218,teleportermaplink:[118,338],teleportmaplink:118,teleportroom:372,televis:20,tell:[0,3,4,9,10,11,13,14,20,22,26,28,32,33,35,36,39,41,42,54,55,57,64,65,67,73,76,78,86,88,90,95,96,97,106,125,128,132,135,137,142,143,144,148,149,150,151,152,158,162,164,167,171,174,176,178,181,182,190,191,193,194,199,205,215,223,224,234,338,343,350,372,398,416,434,445,457,474,541],telnet:[5,16,44,51,52,59,62,65,71,75,122,123,126,129,151,154,180,185,190,193,194,198,199,201,202,225,228,412,424,429,430,431,432,436,437,438,440,441,443,447,455,456,491,545],telnet_:191,telnet_hostnam:184,telnet_interfac:191,telnet_oob:[68,201,202,412,424,545],telnet_port:[2,5,75,148,184,191,448],telnet_ssl:[201,202,412,424,545],telnetoob:440,telnetprotocol:[437,439,441],telnetserverfactori:439,telport:155,temp:234,tempat:380,templ:[99,115],templat:[11,12,19,20,36,41,45,48,49,50,51,52,53,73,113,123,124,139,148,152,158,165,167,169,178,195,198,201,202,223,224,226,232,369,380,398,416,445,455,456,464,468,475,521,525,530,540,541,543,545],template2menu:[28,476],template_nam:[53,536,537,538,540,541,543],template_overrid:[51,73,124,148,169],template_regex:464,template_rend:45,template_str:[28,36],templates_overrid:73,templatestr:475,templatetag:[201,202,498,545],templateview:[53,541],tempmsg:[234,545],temporari:[8,11,13,155,199,212,234,260,308,309,310,311,312,411,476,545],temporarili:[0,6,8,18,20,28,42,52,112,144,149,157,191,223,228,257,292,305,354,364],tempt:[30,149,151,156,195,216],ten:[128,170,191],tend:[5,6,67,72,106,123,134,158,162,174,191,194,218,349,376],tens:[495,497],tent:170,term:[20,31,54,64,97,123,136,137,142,148,149,150,159,175,185,191,213,275,382,459],term_siz:[3,201],termin:[0,3,5,6,7,11,19,53,60,113,118,120,123,124,143,151,152,154,165,175,182,185,190,191,193,194,198,199,201,228,256,308,309,310,311,312,386,415,416,436,443,459,541],terminalrealm:436,terminals:436,terminalsessiontransport:436,terminalsessiontransport_getp:436,termux:545,terrain:[132,338],terribl:429,ters:42,test1:[13,32,478],test2010:143,test2028:143,test2:[13,22,32,60],test3:[13,478],test4:[13,478],test5:13,test6:13,test7:13,test8:13,test:[1,2,3,7,10,11,13,14,15,16,17,20,22,27,28,30,31,32,33,37,39,41,42,45,47,51,53,54,57,76,78,80,81,83,86,92,96,97,104,105,114,119,120,125,126,128,133,135,136,137,139,141,142,144,146,150,152,156,158,159,161,163,164,166,170,173,176,177,180,182,183,185,186,187,189,191,192,201,202,206,208,210,214,215,217,225,228,235,236,237,240,243,246,249,253,261,265,268,271,272,281,282,285,286,288,291,292,293,295,298,301,304,307,308,309,310,311,312,314,315,316,318,321,324,327,330,337,341,342,343,345,348,352,355,358,359,365,368,369,374,375,380,381,384,386,402,412,418,421,424,445,446,447,451,466,468,469,470,472,476,481,490,492,494,498,511,522,531,540,545],test_:8,test_about:229,test_accept:258,test_access:229,test_active_task:229,test_add:[258,290],test_add_choice_without_kei:242,test_add_float:290,test_add_multi:290,test_add_neg:290,test_add_non:290,test_add_overwrit:290,test_add_trait:353,test_add_valid:258,test_al:353,test_all_com:267,test_all_st:279,test_alternative_cal:8,test_amp_in:442,test_amp_out:442,test_at_repeat:360,test_attribute_command:229,test_audit:378,test_auto_creating_bucket:239,test_auto_creating_bucket_with_acl:239,test_available_languag:351,test_ban:229,test_base_pars:279,test_base_search:279,test_base_st:279,test_batch_command:229,test_bold:442,test_boundaries__bigmod:353,test_boundaries__change_boundari:353,test_boundaries__dis:353,test_boundaries__invers:353,test_boundaries__minmax:353,test_bridgeroom:373,test_build:335,test_c_creates_button:452,test_c_creates_obj:452,test_c_dig:452,test_c_examin:452,test_c_help:452,test_c_login:452,test_c_login_no_dig:452,test_c_logout:452,test_c_look:452,test_c_mov:452,test_c_move_:452,test_c_move_n:452,test_c_soci:452,test_cach:353,test_cal:[229,258],test_callback:242,test_cancel:229,test_cas:8,test_cboot:267,test_cdesc:267,test_cdestroi:267,test_channel__al:229,test_channel__alias__unalia:229,test_channel__ban__unban:229,test_channel__boot:229,test_channel__cr:229,test_channel__desc:229,test_channel__destroi:229,test_channel__histori:229,test_channel__list:229,test_channel__lock:229,test_channel__msg:229,test_channel__mut:229,test_channel__noarg:229,test_channel__sub:229,test_channel__unlock:229,test_channel__unmut:229,test_channel__unsub:229,test_channel__who:229,test_char_cr:229,test_char_delet:229,test_clean_nam:239,test_clean_name_norm:239,test_clean_name_trailing_slash:239,test_clean_name_window:239,test_cleanup:290,test_cleanup_doesnt_delete_anyth:290,test_clear:[290,353],test_climb:373,test_clock:267,test_clothingcommand:287,test_clothingfunct:287,test_cmd_armpuzzl:306,test_cmd_puzzl:306,test_cmd_us:306,test_cmddic:344,test_cmdextendedlook:317,test_cmdgametim:317,test_cmdmultidesc:303,test_cmdopen:323,test_cmdset_puzzl:306,test_cmdsetdetail:317,test_cmdtrad:284,test_cmdtradehelp:284,test_cmdtutori:373,test_color:442,test_color_test:229,test_command:351,test_comparisons_numer:353,test_comparisons_trait:353,test_compress_content_len:239,test_connect:252,test_connection_thread:239,test_content_typ:239,test_copi:229,test_craft__nocons__failur:294,test_craft__notools__failur:294,test_craft__success:294,test_craft_cons_excess__fail:294,test_craft_cons_excess__sucess:294,test_craft_cons_order__fail:294,test_craft_hook__fail:294,test_craft_hook__succe:294,test_craft_missing_cons__always_consume__fail:294,test_craft_missing_cons__fail:294,test_craft_missing_tool__fail:294,test_craft_sword:294,test_craft_tool_excess__fail:294,test_craft_tool_excess__sucess:294,test_craft_tool_order__fail:294,test_craft_wrong_tool__fail:294,test_creat:[229,516],test_create_wilderness_custom_nam:328,test_create_wilderness_default_nam:328,test_crumblingwal:373,test_curly_markup:245,test_curr:353,test_custom_gametim:248,test_cwho:267,test_darkroom:373,test_data_in:442,test_data_out:442,test_del:258,test_delet:[353,516],test_desc:[229,353],test_desc_default_to_room:229,test_destroi:229,test_destroy_sequ:229,test_dig:229,test_do_nested_lookup:229,test_do_task:229,test_e2:306,test_e2e_accumul:306,test_e2e_interchangeable_parts_and_result:306,test_echo:490,test_edit:258,test_edit_valid:258,test_emit:229,test_emot:279,test_empti:290,test_empty_desc:229,test_enter_wild:328,test_enter_wilderness_custom_coordin:328,test_enter_wilderness_custom_nam:328,test_error_format:294,test_examin:229,test_exit:[258,326],test_exit_command:229,test_extend:290,test_extend_float:290,test_extend_neg:290,test_extend_non:290,test_extended_path_tracking__horizont:335,test_extended_path_tracking__vert:335,test_failur:269,test_faulty_languag:351,test_field_funct:385,test_find:229,test_floordiv:353,test_focu:279,test_focus_interact:279,test_forc:229,test_func_name_manipul:229,test_gametime_to_realtim:248,test_gendercharact:297,test_gener:383,test_general_context:527,test_generated_url_is_encod:239,test_get:[353,533],test_get_and_drop:229,test_get_authent:533,test_get_dis:533,test_get_new_coordin:328,test_get_shortest_path:335,test_get_visual_range__nodes__charact:335,test_get_visual_range__nodes__character_0:335,test_get_visual_range__nodes__character_1:335,test_get_visual_range__nodes__character_2:335,test_get_visual_range__nodes__character_3:335,test_get_visual_range__nodes__character_4:335,test_get_visual_range__nodes__character_5:335,test_get_visual_range__nodes__character_6:335,test_get_visual_range__nodes__character_7:335,test_get_visual_range__nodes__character_8:335,test_get_visual_range__nodes__character_9:335,test_get_visual_range__scan:335,test_get_visual_range__scan_0:335,test_get_visual_range__scan_1:335,test_get_visual_range__scan_2:335,test_get_visual_range__scan_3:335,test_get_visual_range__scan__charact:335,test_get_visual_range__scan__character_0:335,test_get_visual_range__scan__character_1:335,test_get_visual_range__scan__character_2:335,test_get_visual_range__scan__character_3:335,test_get_visual_range_with_path:335,test_get_visual_range_with_path_0:335,test_get_visual_range_with_path_1:335,test_get_visual_range_with_path_2:335,test_get_visual_range_with_path_3:335,test_get_visual_range_with_path_4:335,test_giv:229,test_grid_cr:335,test_grid_creation_0:335,test_grid_creation_1:335,test_grid_pathfind:335,test_grid_pathfind_0:335,test_grid_pathfind_1:335,test_grid_vis:335,test_grid_visibility_0:335,test_grid_visibility_1:335,test_handl:258,test_healthbar:347,test_hello_world:152,test_help:229,test_hom:229,test_ic:229,test_ic__nonaccess:229,test_ic__other_object:229,test_ident:442,test_idl:452,test_info_command:229,test_init:353,test_interrupt_command:229,test_introroom:373,test_invalid_access:533,test_inventori:229,test_ital:442,test_large_msg:442,test_lightsourc:373,test_list:[258,516],test_list_cmdset:229,test_load_recip:294,test_location_leading_slash:239,test_location_search:8,test_lock:[229,258],test_lock_with_perm:533,test_locked_entri:533,test_look:[229,279],test_lspuzzlerecipes_lsarmedpuzzl:306,test_mail:300,test_mapping_with_opt:497,test_mapping_with_options_00_y:497,test_mapping_with_options_01_y:497,test_mapping_with_options_02_i:497,test_mapping_with_options_03_i:497,test_mapping_with_options_04_i:497,test_mapping_with_options_05_m:497,test_mapping_with_options_06_your:497,test_mapping_with_options_07_our:497,test_mapping_with_options_08_yourself:497,test_mapping_with_options_09_yourself:497,test_mapping_with_options_10_yourself:497,test_mapping_with_options_11_yourself:497,test_mapping_with_options_12_yourselv:497,test_mapping_with_options_13_h:497,test_mapping_with_options_14_h:497,test_mapping_with_options_15_h:497,test_mapping_with_options_16_h:497,test_mapping_with_options_17_h:497,test_mapping_with_options_18_their:497,test_mapping_with_options_19_their:497,test_mapping_with_options_20_itself:497,test_mapping_with_options_21_themselv:497,test_mapping_with_options_22_herself:497,test_mask:378,test_memplot:452,test_menu:[113,386],test_messag:453,test_misformed_command:229,test_mob:373,test_msg:294,test_mudlet_ttyp:442,test_mul_trait:353,test_multi_level:242,test_multimatch:229,test_mux_command:229,test_mux_markup:245,test_mycmd_char:8,test_mycmd_room:8,test_nam:229,test_nested_attribute_command:229,test_new_task_waiting_input:229,test_nick:229,test_no_input:229,test_no_task:229,test_node_from_coord:335,test_obelisk:373,test_obfuscate_languag:351,test_obfuscate_whisp:351,test_object:229,test_object_cach:533,test_object_search_charact:8,test_ooc:229,test_ooc_look:229,test_opt:229,test_ordered_permutation_regex:351,test_outroroom:373,test_override_class_vari:239,test_override_init_argu:239,test_overwrit:279,test_pag:229,test_parse_for_perspect:279,test_parse_for_th:279,test_parse_languag:351,test_password:229,test_path:335,test_paths_0:335,test_paths_1:335,test_pause_unpaus:229,test_percentag:353,test_perm:229,test_persistent_task:229,test_pi:229,test_pickle_with_bucket:239,test_pickle_without_bucket:239,test_plain_ansi:442,test_pos:229,test_pos_shortcut:353,test_pre_craft:294,test_pre_craft_fail:294,test_puzzleedit:306,test_puzzleedit_add_remove_parts_result:306,test_quel:229,test_queri:[201,202,412,446,545],test_quit:[229,242,252],test_read:373,test_real_seconds_until:248,test_realtime_to_gametim:248,test_recog_handl:351,test_regex_tuple_from_key_alia:351,test_remov:[229,353],test_repr:353,test_reset:290,test_reset_non_exist:290,test_resourc:[8,201,202,229,242,245,248,252,258,267,269,279,284,287,290,294,297,300,303,306,313,317,323,326,328,335,344,347,351,353,360,367,373,378,383,385,442,468,516,533,545],test_responce_of_y:229,test_retriev:516,test_return_appear:317,test_return_detail:317,test_return_valu:8,test_roll_dic:344,test_room_cr:328,test_room_method:279,test_rpsearch:351,test_sai:229,test_schedul:248,test_script:229,test_script_multi_delet:229,test_sdesc_handl:351,test_seed__success:294,test_send_case_sensitive_emot:351,test_send_emot:351,test_send_random_messag:360,test_server_load:229,test_sess:229,test_set:353,test_set_attribut:516,test_set_focu:279,test_set_help:229,test_set_hom:229,test_set_obj_alia:229,test_setattr:242,test_setgend:297,test_shortest_path:335,test_shortest_path_00:335,test_shortest_path_01:335,test_shortest_path_02:335,test_shortest_path_03:335,test_shortest_path_04:335,test_shortest_path_05:335,test_shortest_path_06:335,test_shortest_path_07:335,test_shortest_path_08:335,test_shortest_path_09:335,test_shortest_path_0:335,test_shortest_path_10:335,test_shortest_path_1:335,test_shortest_path_2:335,test_shortest_path_3:335,test_shortest_path_4:335,test_shortest_path_5:335,test_shortest_path_6:335,test_shortest_path_7:335,test_shortest_path_8:335,test_shortest_path_9:335,test_simple_default:229,test_spawn:[229,335],test_special_charact:239,test_speech:279,test_split_nested_attr:229,test_start:258,test_storage_delet:239,test_storage_exist:239,test_storage_exists_doesnt_create_bucket:239,test_storage_exists_fals:239,test_storage_listdir_bas:239,test_storage_listdir_subdir:239,test_storage_mtim:239,test_storage_open_no_overwrite_exist:239,test_storage_open_no_writ:239,test_storage_open_writ:239,test_storage_s:239,test_storage_sav:239,test_storage_save_gzip:239,test_storage_save_gzip_twic:239,test_storage_save_with_acl:239,test_storage_url:239,test_storage_url_slash:239,test_storage_write_beyond_buffer_s:239,test_str_output:335,test_strip_signing_paramet:239,test_sub_trait:353,test_submenu:242,test_subtopic_fetch:229,test_subtopic_fetch_00_test:229,test_subtopic_fetch_01_test_creating_extra_stuff:229,test_subtopic_fetch_02_test_cr:229,test_subtopic_fetch_03_test_extra:229,test_subtopic_fetch_04_test_extra_subsubtop:229,test_subtopic_fetch_05_test_creating_extra_subsub:229,test_subtopic_fetch_06_test_something_els:229,test_subtopic_fetch_07_test_mor:229,test_subtopic_fetch_08_test_more_second_mor:229,test_subtopic_fetch_09_test_more_mor:229,test_subtopic_fetch_10_test_more_second_more_again:229,test_subtopic_fetch_11_test_more_second_third:229,test_success:269,test_tag:229,test_talkingnpc:367,test_task_complete_waiting_input:229,test_tbbasicfunc:313,test_tbequipfunc:313,test_tbitemsfunc:313,test_tbrangefunc:313,test_teleport:229,test_teleportroom:373,test_time_to_tupl:248,test_timer_r:353,test_timer_ratetarget:353,test_toggle_com:267,test_tradehandler_bas:284,test_tradehandler_join:284,test_tradehandler_off:284,test_trait_db_connect:353,test_trait_getset:353,test_traitfield:353,test_tree_funct:385,test_tunnel:229,test_tunnel_exit_typeclass:229,test_turnbattlecmd:313,test_turnbattleequipcmd:313,test_turnbattleitemcmd:313,test_turnbattlemagiccmd:313,test_turnbattlerangecmd:313,test_tutorialobj:373,test_typeclass:229,test_unconnectedhelp:252,test_unconnectedlook:252,test_upd:516,test_valid_access:533,test_valid_access_multisession_0:533,test_valid_access_multisession_2:533,test_valid_char:533,test_validate_input__fail:353,test_validate_input__valid:353,test_valu:353,test_verb_actor_stance_compon:497,test_verb_actor_stance_components_00_hav:497,test_verb_actor_stance_components_01_swim:497,test_verb_actor_stance_components_02_g:497,test_verb_actor_stance_components_03_given:497,test_verb_actor_stance_components_04_am:497,test_verb_actor_stance_components_05_do:497,test_verb_actor_stance_components_06_ar:497,test_verb_actor_stance_components_07_had:497,test_verb_actor_stance_components_08_grin:497,test_verb_actor_stance_components_09_smil:497,test_verb_actor_stance_components_10_vex:497,test_verb_actor_stance_components_11_thrust:497,test_verb_conjug:497,test_verb_conjugate_0_inf:497,test_verb_conjugate_1_inf:497,test_verb_conjugate_2_inf:497,test_verb_conjugate_3_inf:497,test_verb_conjugate_4_inf:497,test_verb_conjugate_5_inf:497,test_verb_conjugate_6_inf:497,test_verb_conjugate_7_2sgpr:497,test_verb_conjugate_8_3sgpr:497,test_verb_get_all_tens:497,test_verb_infinit:497,test_verb_infinitive_0_hav:497,test_verb_infinitive_1_swim:497,test_verb_infinitive_2_g:497,test_verb_infinitive_3_given:497,test_verb_infinitive_4_am:497,test_verb_infinitive_5_do:497,test_verb_infinitive_6_ar:497,test_verb_is_past:497,test_verb_is_past_0_1st:497,test_verb_is_past_1_1st:497,test_verb_is_past_2_1st:497,test_verb_is_past_3_1st:497,test_verb_is_past_4_1st:497,test_verb_is_past_5_1st:497,test_verb_is_past_6_1st:497,test_verb_is_past_7_2nd:497,test_verb_is_past_participl:497,test_verb_is_past_participle_0_hav:497,test_verb_is_past_participle_1_swim:497,test_verb_is_past_participle_2_g:497,test_verb_is_past_participle_3_given:497,test_verb_is_past_participle_4_am:497,test_verb_is_past_participle_5_do:497,test_verb_is_past_participle_6_ar:497,test_verb_is_past_participle_7_had:497,test_verb_is_pres:497,test_verb_is_present_0_1st:497,test_verb_is_present_1_1st:497,test_verb_is_present_2_1st:497,test_verb_is_present_3_1st:497,test_verb_is_present_4_1st:497,test_verb_is_present_5_1st:497,test_verb_is_present_6_1st:497,test_verb_is_present_7_1st:497,test_verb_is_present_participl:497,test_verb_is_present_participle_0_hav:497,test_verb_is_present_participle_1_swim:497,test_verb_is_present_participle_2_g:497,test_verb_is_present_participle_3_given:497,test_verb_is_present_participle_4_am:497,test_verb_is_present_participle_5_do:497,test_verb_is_present_participle_6_ar:497,test_verb_is_tens:497,test_verb_is_tense_0_inf:497,test_verb_is_tense_1_inf:497,test_verb_is_tense_2_inf:497,test_verb_is_tense_3_inf:497,test_verb_is_tense_4_inf:497,test_verb_is_tense_5_inf:497,test_verb_is_tense_6_inf:497,test_verb_past:497,test_verb_past_0_1st:497,test_verb_past_1_1st:497,test_verb_past_2_1st:497,test_verb_past_3_1st:497,test_verb_past_4_1st:497,test_verb_past_5_1st:497,test_verb_past_6_1st:497,test_verb_past_7_2nd:497,test_verb_past_participl:497,test_verb_past_participle_0_hav:497,test_verb_past_participle_1_swim:497,test_verb_past_participle_2_g:497,test_verb_past_participle_3_given:497,test_verb_past_participle_4_am:497,test_verb_past_participle_5_do:497,test_verb_past_participle_6_ar:497,test_verb_pres:497,test_verb_present_0_1st:497,test_verb_present_1_1st:497,test_verb_present_2_1st:497,test_verb_present_3_1st:497,test_verb_present_4_1st:497,test_verb_present_5_1st:497,test_verb_present_6_1st:497,test_verb_present_7_2nd:497,test_verb_present_8_3rd:497,test_verb_present_participl:497,test_verb_present_participle_0_hav:497,test_verb_present_participle_1_swim:497,test_verb_present_participle_2_g:497,test_verb_present_participle_3_given:497,test_verb_present_participle_4_am:497,test_verb_present_participle_5_do:497,test_verb_present_participle_6_ar:497,test_verb_tens:497,test_verb_tense_0_hav:497,test_verb_tense_1_swim:497,test_verb_tense_2_g:497,test_verb_tense_3_given:497,test_verb_tense_4_am:497,test_verb_tense_5_do:497,test_verb_tense_6_ar:497,test_view:533,test_wal:229,test_weapon:373,test_weaponrack:373,test_weatherroom:373,test_whisp:229,test_who:229,test_wilderness_correct_exit:328,test_without_migr:8,test_wrong_func_nam:229,testaccount2:8,testaccount:[8,229],testadmin:229,testampserv:442,testapp:177,testbart:284,testbatchprocess:229,testbodyfunct:360,testbuild:229,testbuildexamplegrid:335,testbuildingmenu:242,testcas:[8,239,335,373,442,452,484,490,497,527],testclothingcmd:287,testclothingfunc:287,testcmdcallback:258,testcmdtask:229,testcolormarkup:245,testcomm:229,testcommand:28,testcommschannel:229,testcooldown:290,testcraftcommand:294,testcraftingrecip:294,testcraftingrecipebas:294,testcraftsword:294,testcraftutil:294,testcustomgametim:248,testdefaultcallback:258,testdic:344,testdummyrunnerset:452,testemaillogin:252,tester:[8,146,191,434],testevenniarestapi:516,testeventhandl:258,testevscaperoom:279,testevscaperoomcommand:279,testextendedroom:317,testfieldfillfunc:385,testform:475,testgendersub:297,testgener:229,testgeneralcontext:527,testhealthbar:347,testhelp:229,testid:22,testinterruptcommand:229,testirc:442,testlanguag:351,testlegacymuxcomm:267,testmail:300,testmap10:335,testmap11:335,testmap1:335,testmap2:335,testmap3:335,testmap4:335,testmap5:335,testmap6:335,testmap7:335,testmap8:335,testmap9:335,testmapstresstest:335,testmemplot:452,testmenu:[380,476],testmixedrefer:484,testmod:457,testmultidesc:303,testmymodel:8,testnnmain:229,testnumerictraitoper:353,testobj:[8,278,280],testobject:8,testobjectdelet:484,testok:142,testpronounmap:497,testpuzzl:306,testrandomstringgener:383,testregularrefer:484,testrenam:143,testrpsystem:351,testrpsystemcommand:351,testset:8,testsharedmemoryrefer:484,testsimpledoor:323,testslowexit:326,teststat:279,testsystem:229,testsystemcommand:229,testtabl:143,testtalkingnpc:367,testtelnet:442,testtrait:353,testtraitcount:353,testtraitcountertim:353,testtraitfield:353,testtraitgaug:353,testtraitgaugetim:353,testtraitstat:353,testtreeselectfunc:385,testturnbattlebasiccmd:313,testturnbattlebasicfunc:313,testturnbattleequipcmd:313,testturnbattleequipfunc:313,testturnbattleitemscmd:313,testturnbattleitemsfunc:313,testturnbattlemagiccmd:313,testturnbattlemagicfunc:313,testturnbattlerangecmd:313,testturnbattlerangefunc:313,testtutorialworldmob:373,testtutorialworldobject:373,testtutorialworldroom:373,testunconnectedcommand:229,testunixcommand:269,testutil:279,testverbconjug:497,testview:53,testwebsocket:442,testwild:328,testxyzgrid:335,testxyzgridtransit:335,text2html:[201,202,468,545],text:[0,6,11,12,13,14,15,16,17,18,22,25,26,27,29,30,31,33,35,36,39,41,42,46,51,53,54,58,59,60,62,64,65,67,68,69,75,76,82,90,91,92,93,94,96,97,104,106,112,118,119,121,122,125,129,133,134,135,139,141,142,144,148,150,152,154,155,157,158,159,160,161,162,165,170,172,174,175,177,179,180,183,185,187,189,191,192,193,199,204,205,210,213,215,216,217,218,223,224,225,226,227,228,229,230,233,234,241,250,251,255,257,266,269,270,273,274,275,280,283,286,292,293,296,299,302,305,308,309,310,311,312,316,322,325,331,343,346,349,350,354,362,364,366,370,371,372,377,380,386,388,390,391,394,398,400,403,406,413,414,421,427,428,431,434,435,436,439,440,444,445,447,455,456,457,460,461,464,465,467,469,470,472,474,475,476,477,478,479,486,489,490,491,492,493,500,502,506,532,544,545],text_:120,text_color:346,text_descript:[112,354],text_exit:[76,241],text_single_exit:76,textarea:[488,532],textbook:62,textbox:532,textfield:[67,177],textn:229,textstr:32,texttag:[139,175],texttohtmlpars:491,textual:130,textwrap:478,textwrapp:478,than:[0,3,4,5,6,7,8,9,11,12,13,14,15,18,20,22,24,25,28,29,30,31,33,37,39,41,42,44,46,47,48,51,53,56,57,58,60,64,67,70,72,73,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,122,123,124,126,128,130,132,134,135,136,137,140,142,143,146,148,149,150,151,153,154,155,156,157,159,161,162,164,165,175,178,181,182,184,187,188,191,194,195,197,199,204,207,210,211,212,215,216,217,218,219,225,226,228,229,241,247,250,257,266,270,275,278,283,292,308,309,310,311,312,325,333,337,338,339,340,346,349,350,354,371,382,386,393,396,398,400,402,416,442,457,462,464,465,466,467,469,470,476,477,478,479,483,485,487,488,489,491,492,501,508,521,541,545],thank:[28,124,178,299,461],thankfulli:177,the_answ:153,the_one_r:153,thead:178,theathr:31,theatr:31,thei:[3,4,5,6,7,8,11,12,13,14,15,16,17,18,19,20,22,28,30,31,33,37,39,40,41,42,44,45,46,48,50,51,52,53,54,55,56,57,58,60,62,63,64,65,67,68,69,70,74,75,76,77,79,80,85,86,91,93,95,96,97,99,104,106,109,112,116,117,118,120,122,123,124,125,126,128,129,130,131,133,134,135,137,138,139,141,142,143,144,145,146,148,149,150,151,152,153,156,157,159,161,162,164,165,169,170,172,174,175,176,178,179,181,182,185,190,191,194,198,199,204,211,212,215,217,218,223,224,226,227,228,232,241,250,256,266,270,275,283,286,289,292,293,296,308,309,310,311,312,316,329,337,338,340,343,349,350,354,371,372,388,393,394,397,398,402,403,404,406,408,409,411,416,436,437,439,440,441,445,448,454,455,456,457,459,464,469,470,471,473,476,478,479,492,493,496,501,508,513,515,518,532,538,542,543,545],theirs:[58,93,164,296,479,496,497],them:[0,5,6,7,8,9,11,12,13,14,15,16,18,19,20,22,25,27,28,30,31,32,33,35,36,37,39,41,42,44,46,47,48,50,51,53,54,55,56,58,60,62,63,64,65,67,68,70,73,74,75,76,77,78,84,86,90,91,93,94,95,96,97,104,105,106,112,113,118,119,120,122,123,124,125,127,128,129,130,134,135,136,137,140,141,142,143,146,148,149,150,151,152,153,155,156,157,159,161,162,164,165,168,169,170,172,174,175,177,178,182,184,188,190,191,192,194,195,199,204,209,210,211,213,215,217,218,223,225,226,229,232,233,244,250,254,256,270,276,286,292,293,296,305,308,309,310,311,312,316,337,346,350,354,364,370,372,380,382,386,389,394,398,403,408,411,416,434,436,439,447,451,454,455,457,464,466,467,469,470,472,476,479,488,490,491,496,501,508,510,515,523,538,541,543,545],themat:156,theme:[53,148,156,158,178],themself:310,themselv:[6,13,18,20,22,28,33,37,45,48,57,58,70,74,90,95,97,104,106,112,120,122,125,127,132,135,137,139,141,148,157,158,161,162,165,174,176,189,218,275,338,350,398,406,409,416,465,467,479,488,496,497],theoret:[20,69,118,160,340],theori:[3,20,134,165,180,204,211,545],thereaft:36,therefor:[42,97,118,132,136,142,155,217,241,254,275],therein:[16,22,215,226,228,230,273,305,316,372],thereof:[350,398],thess:396,thet:148,thi:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19,20,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,160,161,162,163,164,165,166,167,169,170,171,172,173,174,175,176,177,178,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,197,198,199,200,201,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,241,242,244,245,247,250,251,254,255,256,257,260,266,270,273,274,275,276,277,278,280,283,286,289,292,293,294,296,299,302,305,308,309,310,311,312,316,322,325,329,331,332,333,334,335,337,338,339,340,343,346,349,350,353,354,359,362,364,366,369,370,371,372,376,377,380,382,386,387,388,389,390,391,392,393,394,395,396,397,398,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,418,420,421,422,423,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,443,444,445,447,448,449,450,451,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,483,484,485,486,487,488,489,490,491,492,493,495,496,498,500,501,502,504,505,506,507,508,510,512,513,515,518,521,523,524,525,529,530,532,534,536,537,538,539,540,541,542,543,544,545],thie:28,thieveri:225,thin:[54,76,83,128,170,286,485],thing:[0,1,5,6,8,9,10,11,13,14,16,18,19,20,22,27,28,30,31,32,37,39,41,44,45,47,48,51,53,54,55,57,58,60,62,64,65,67,69,72,73,75,76,78,79,82,86,95,96,97,104,106,112,113,115,116,118,119,122,123,124,125,126,127,128,129,130,132,135,137,138,140,141,142,143,144,146,147,148,150,151,155,156,157,159,161,162,163,164,165,167,169,170,172,174,175,176,177,178,180,181,185,188,190,191,193,194,195,197,198,199,204,211,212,218,241,257,270,275,280,283,292,293,312,316,349,350,354,364,369,372,386,394,397,398,425,429,461,464,466,469,470,478,479,488,501,508,510,541,543,544,545],things_styl:280,think:[0,6,11,20,35,39,41,46,47,52,53,60,73,95,96,104,115,118,119,122,128,136,139,142,143,144,151,153,154,156,160,161,162,163,166,168,170,180,187,197,457,541],third:[3,9,13,19,28,30,59,75,95,97,119,120,123,130,137,151,159,161,174,178,181,182,189,190,191,218,229,275,469,476,479,545],third_person:280,thirdnod:28,this_is_provided_by_amazon:77,this_sign:458,thoma:[36,55,216],thorn:[37,153],thorough:0,those:[2,8,9,10,11,12,13,14,15,16,18,20,22,25,28,30,33,37,39,41,44,46,48,53,57,58,60,67,68,73,75,77,78,99,104,106,112,113,114,118,122,123,124,125,127,129,131,133,134,135,136,138,139,141,143,144,146,149,150,151,153,154,155,156,157,159,161,162,165,167,169,170,172,174,179,180,182,185,188,191,194,197,199,212,213,215,218,223,224,225,229,233,241,273,280,292,293,308,350,354,364,371,372,377,386,394,402,403,405,410,439,444,447,465,466,476,477,478,486,487,490,492,515,532,537,538,540,545],though:[0,6,9,12,13,14,15,16,19,20,28,37,50,54,55,64,72,76,81,82,95,103,104,112,118,119,123,129,130,134,136,137,139,142,143,145,147,149,151,155,157,158,159,161,164,165,174,175,180,182,185,187,189,190,191,193,194,195,199,204,213,241,270,308,309,311,312,338,346,354,372,398,402,403,464,469,476,492],thought:[33,34,130,151,156,158,180,182],thousand:[130,170,177,191],thread:[19,180,182,199,435,461,485,492],threadpool:461,threadsaf:[501,508],threat:194,three:[13,14,18,20,22,28,31,33,36,37,55,56,58,60,65,73,76,77,95,96,97,113,120,124,126,137,141,145,151,153,157,163,177,178,191,210,223,225,311,339,386,394,469,476],threshold:[118,360,459,470],thrill:141,throttl:[201,202,204,412,421,434,545],through:[5,6,7,12,14,15,17,19,20,22,28,29,30,31,33,36,37,41,42,44,45,50,52,53,62,65,68,69,74,75,79,90,91,95,96,97,104,109,114,115,118,120,122,123,126,129,130,131,133,134,135,136,137,141,142,147,148,152,153,154,155,158,159,160,161,163,164,168,169,171,174,182,188,191,192,194,195,197,199,201,204,212,218,223,225,245,254,278,279,283,308,309,310,311,312,316,322,329,337,338,377,392,394,397,398,407,408,411,416,418,423,432,436,439,445,448,453,455,456,465,466,470,472,475,476,477,490,491,492,501,508,532,541,545],throughout:[28,90,122,132,144,195,310,335],throughput:[232,233,472],thrown:[164,293],thrust:[371,497],thu:[15,18,20,22,28,30,33,35,39,48,57,60,65,67,69,73,77,130,131,134,135,146,151,158,162,165,169,170,174,178,184,206,215,219,337,338,340,349,350,394,398,411,448,462,464,465,472],thud:[93,296],thumb:[4,11,60],thumbnail:124,thunder:[99,182],thunderstorm:155,thusli:190,tick:[5,22,28,42,47,81,115,120,123,176,182,279,310,370,372,411,448],ticker1:[47,411],ticker2:[47,411],ticker:[26,32,42,121,143,176,205,228,370,372,407,411,421,492,545],ticker_class:411,ticker_handl:[47,121,176,201,411,492],ticker_pool_class:411,ticker_storag:411,tickerhandl:[19,24,42,85,110,164,176,201,202,228,289,310,325,372,404,492,545],tickerpool:411,tickerpool_layout:411,tidbit:122,tidi:193,tie:[137,164,340,545],tied:[18,83,95,104,123,153,212,225,275,278,286,339,364,390,405],tier:[77,191],ties:[53,73,132,220],tight:[83,286],tightli:[39,77,194,232],tild:146,tim:[83,92,94,104,113,114,285,286,307,308,309,310,311,312,345,346,379,380,384,386],time:[0,2,3,5,7,8,9,11,12,13,14,15,17,18,20,26,28,29,30,31,33,35,37,41,44,47,48,54,55,60,62,63,65,67,68,70,72,73,75,76,77,79,80,85,86,87,90,97,99,104,105,106,108,110,112,113,114,115,118,119,121,122,123,124,125,126,127,128,129,130,132,133,135,137,138,142,143,144,146,148,149,150,151,152,153,155,156,157,159,161,162,164,165,171,174,176,177,181,182,184,185,186,187,189,190,191,193,195,199,204,205,207,209,210,212,213,216,223,228,232,233,234,247,248,256,257,260,275,283,289,292,293,305,308,309,310,311,312,316,322,325,343,349,353,354,359,364,370,371,372,382,386,390,397,398,401,403,404,405,406,409,410,411,416,418,420,422,423,428,434,439,441,447,448,449,453,454,455,457,459,464,466,467,469,470,471,472,477,480,483,484,485,488,492,501,508,545],time_ev:260,time_factor:[19,136,247,480],time_format:[492,545],time_game_epoch:[19,136,480],time_left:289,time_str:136,time_to_tupl:247,time_unit:[87,136,247],time_until_next_repeat:42,timed_script:42,timedelai:[128,410,490,492],timedelta:[486,493],timeeventscript:257,timefactor:136,timeformat:[485,492],timeit:5,timelin:159,timeout:[164,173,185,187,439,459,483],timer:[19,22,47,65,81,85,91,104,108,123,133,144,147,148,158,164,218,289,310,316,353,359,364,371,404,405,409,410,411,447,455,489,518,545],timerobject:42,timerscript:42,timescript:480,timeslot:[91,316],timestamp:[19,64,126,317,447,448,459,480],timestep:[5,448],timestr:485,timetrac:[201,202,412,446,545],timetupl:136,timezon:[182,485,486,493],tin:152,tini:[130,139,182],tinker:6,tintin:[183,429,430,440,443],tinyfugu:183,tinymud:[69,134],tinymush:[69,72,134,230],tinymux:[69,134],tip:[46,180,194,545],tire:[144,212],titeuf87:[104,117,327,329],titl:[0,17,51,76,82,120,137,192,223,225,233,241,242,276,350,389,469,472,543,545],title_lone_categori:225,titlebar:51,titleblock:137,tlen:188,tls:181,tlsv10:187,tlsv1:181,tmp:[2,185],tmpmsg:18,to_be_impl:539,to_byt:[492,545],to_closed_st:364,to_cur:310,to_displai:241,to_dupl:211,to_execut:492,to_exit:[95,97],to_fil:[78,376],to_init:312,to_non:398,to_obj:[204,213,398],to_object:233,to_open_st:364,to_pickl:473,to_str:[492,545],to_syslog:376,tobox:425,todai:[94,158,346],todo:[23,38,43,66,135,145,163,166,168,196],toe:[69,151],togeth:[13,15,20,22,30,31,37,40,48,61,65,75,76,90,97,98,102,104,105,118,120,123,128,132,134,135,146,148,151,152,153,155,156,157,158,159,161,162,164,165,166,167,175,181,188,191,209,218,220,225,276,292,293,302,305,316,337,338,349,350,371,372,396,397,403,425,444,457,469,470,489,501,508,545],toggl:[139,439],toggle_nop_keepal:439,togglecolor:139,togrid:118,toi:86,toint:[30,41,479],token:[18,161,188,436,439,470,479],told:[9,58,60,70,131,142,148,151,165,191,488],tolimbo:118,tolkien:136,tom:[30,36,58,72,93,106,135,157,165,218,224,296,350,475,479,495],tomb:115,tomdesmedt:495,tommi:[36,39,57,479],ton:[134,140],tone:60,tonon:[218,331],too:[3,5,7,9,13,14,15,17,18,19,22,28,31,34,48,50,55,58,60,65,75,76,95,96,97,113,115,120,124,125,126,128,130,132,134,135,141,142,143,144,147,149,150,153,154,156,157,158,159,161,162,164,165,174,177,185,216,218,235,293,294,311,338,339,364,386,393,396,421,425,459,461,467,470,475,476,477,478,489,492],took:[8,147,492],tool2:294,tool:[30,39,41,46,50,53,60,67,69,86,104,118,121,123,124,128,134,136,149,151,153,154,156,158,159,160,163,166,168,169,170,181,182,185,187,191,193,292,293,294,544,545],tool_kwarg:292,tool_nam:292,tool_tag:[86,292,293],tool_tag_categori:[86,292],toolbox:180,toolkit:53,tooltip:51,top:[0,5,10,11,14,20,22,27,29,30,31,42,46,48,50,53,58,75,76,83,86,90,102,117,118,120,128,130,134,135,137,141,143,147,150,151,152,165,170,171,177,178,180,185,190,195,199,207,212,234,241,247,270,273,286,302,329,337,338,350,386,388,390,397,406,416,458,464,466,467,470,477,478,485],topcistr:389,topic:[3,5,20,22,31,44,50,54,62,64,67,78,122,124,137,144,146,149,151,158,175,225,273,275,308,309,310,311,312,389,391,489,532,540],topicstr:389,topolog:[104,118,337,338],toppl:95,tostr:425,total:[5,19,33,44,49,60,77,95,118,136,140,142,157,172,195,206,228,338,343,453,477,478,480],total_num:483,touch:[6,60,120,148,149,181,184,194,195,459],tour:[142,148,154,160,163,166,168],toward:[3,22,62,76,99,118,142,156,158,159,170,312,346,370],tower:[170,316,372],town:[118,331],trace:[65,118,257,338,453,476],traceback:[6,8,14,19,42,53,64,73,95,134,143,151,165,177,199,257,302,401,425,466,470,485,492,545],tracemessag:453,track:[9,13,19,42,44,67,85,90,104,108,112,114,123,129,132,134,140,148,151,156,157,162,164,174,176,177,192,193,204,212,232,289,312,335,338,354,407,427,428,433,436,439,454,459,473,474,486,545],tracker:[26,115],trade:[79,96,104,157,158,283],tradehandl:[79,283],trader:96,tradetimeout:283,tradit:[2,16,32,54,60,65,144,148,151,158,162,164,191,194,292,329,439,455,477],tradition:[65,134,156,158,159,293],traffic:[77,181,194,429],trail:[53,239],train:[112,138,143,158,180,354,545],traindriv:174,traindrivingscript:174,trainobject:174,trainscript:174,trainstop:174,trainstoppedscript:174,trait1:[112,354],trait2:[112,354],trait:[19,120,158,162,201,202,235,341,403,545],trait_class_path:[112,354],trait_data:354,trait_kei:[112,354],trait_properti:354,trait_typ:[112,353,354],traitexcept:354,traitfield:[353,354],traithandl:[201,235,341,352,353,545],traithandler_nam:354,traithandlertest:353,traitproperti:[201,235,341,352,353,545],traitshandl:[353,354],transact:[79,104,157,283],transfer:[141,177,212,427,437,441,478],transform:[2,146],transit:[37,90,104,332,335,337,338,545],transitionmapnod:[118,332,335,338],transitiontocav:332,transitiontolargetre:332,transitiontomapa:118,transitiontomapc:118,translat:[15,36,41,58,60,62,68,70,106,148,175,180,349,350,403,418,469,545],transmiss:376,transmit:[70,515],transpar:[18,44,51,175,187,396,397,411],transport:[425,436,445],transportfactori:436,transpos:175,trap:[15,115,140,155],traumat:28,travel:[65,68,110,132,140,325,329],travers:[13,33,37,77,95,104,110,118,131,132,141,174,322,325,329,337,338,370,371,393,398,518],traverse_:22,traversing_object:[322,325,329,398],travi:[1,545],travis_build_dir:10,treasur:[75,153,157,329],treasurechest:39,treat:[13,15,22,44,46,48,54,118,123,146,152,153,170,204,209,212,296,338,362,388,396,398,403,448,457,476,478,489,545],tree:[11,22,28,39,74,86,90,116,118,120,121,123,156,157,167,185,201,202,235,241,270,281,291,332,350,384,385,386,398,403,416,445,461,476,492,514,545],tree_select:[113,201,202,235,374,545],treestr:[113,386],trembl:[149,152],treshold:483,trhr:[77,104,237],tri:[15,22,33,35,36,44,45,55,64,65,70,77,92,128,135,142,143,150,153,156,158,161,164,177,183,191,210,228,283,371,372,380,420,459,492,493],trial:[7,373,442],tribal:170,trick:[76,150,161,180,181,466,532,545],tricki:[41,175],trickier:[75,137],tried_kei:39,trigger:[2,3,18,20,22,28,32,34,37,44,45,47,59,65,73,82,95,96,99,104,108,125,132,133,134,137,159,164,171,172,174,178,183,193,204,205,209,210,213,215,229,241,260,275,289,364,370,372,397,398,403,405,411,418,421,425,447,454,458,472,476],trim:469,tripl:[19,120,151,492],triumph:[155,158],trivial:[3,5,19,22,62,142,155,161],troll:55,troubl:[35,44,75,96,119,135,142,144,151,154,181,182,185,190,197,198,464],troubleshoot:[75,198,545],troublesom:[14,15,55],trove:[75,157],truestr:[92,380],truli:[44,55,97,130,316],trust:[28,30,57,95,104,134,157,158,228,470],truth:3,truthfulli:22,truthi:[143,410],try_num_differenti:210,ttarget:164,tto:439,tty:[75,193],ttype:[201,202,412,424,436,439,545],ttype_step:443,tuck:170,tulip:153,tun:[26,218],tune:[148,158,175,187],tunnel:[26,76,97,118,131,132,135,143,144,150,161,174,218,441],tup:[130,350],tupl:[3,5,13,28,30,36,39,41,50,67,68,95,99,117,130,143,146,161,164,178,191,201,204,210,216,218,223,225,226,233,241,247,254,274,280,283,292,296,310,311,329,331,337,338,339,340,343,350,362,369,389,391,393,394,396,398,402,403,405,411,413,416,425,426,436,437,441,448,455,457,464,467,469,471,472,474,476,480,485,487,492,495,496,516],tuple_of_arg_convert:30,tupled:485,turbo:190,turkish:204,turn:[8,11,13,19,20,22,27,28,33,44,45,53,54,55,60,63,65,68,73,90,97,99,104,113,118,120,123,134,135,139,143,149,150,151,152,153,155,157,158,161,170,171,172,174,175,177,180,191,199,204,213,228,229,232,233,260,266,308,309,310,311,312,340,350,370,372,386,398,403,416,421,429,436,439,447,457,463,466,470,472,476,477,478,479,490,492,501,521,523,545],turn_act:164,turn_end_check:[308,309,310,311,312],turnbattl:[114,201,202,235,281,545],turnchar:310,tut:[155,372],tutor:[115,369],tutori:[3,17,20,21,22,25,28,46,47,53,54,56,60,73,76,80,81,82,101,108,110,111,119,120,122,123,124,126,127,128,130,132,134,135,139,140,142,143,144,146,148,149,150,151,152,157,159,167,170,175,177,180,185,188,191,198,201,202,229,235,241,309,544,545],tutorial_bridge_posist:372,tutorial_cmdset:372,tutorial_exampl:[14,15,144,148,151,359],tutorial_info:372,tutorial_world:[76,115,155,185,201,202,235,355,545],tutorialclimb:371,tutorialevmenu:369,tutorialmirror:[151,362,545],tutorialobject:[370,371],tutorialread:371,tutorialroom:[370,372],tutorialroomcmdset:372,tutorialroomlook:372,tutorialweapon:[370,371],tutorialweaponrack:371,tutorialworld:[371,372],tutoru:151,tweak:[6,13,18,31,41,48,53,75,104,118,126,134,135,143,149,157,163,171,181,187,204,364,461,469,490,500,505],tweet:[138,545],tweet_output:173,tweet_stat:173,tweetstat:173,twenti:135,twice:[28,99,126,136,155,164,239,257,312,476],twist:[6,19,22,52,54,62,128,180,185,189,190,194,373,398,410,413,416,418,419,425,426,427,428,433,436,439,442,444,445,447,454,457,461,485,545],twistd:[7,185,199,433,454],twistedcli:62,twistedweb:194,twitch:164,twitter:[173,197,545],twitter_api:188,two:[4,5,6,8,11,13,14,15,16,19,20,22,27,28,30,31,32,33,34,37,40,41,42,44,46,48,51,56,57,58,62,64,65,67,68,69,70,72,73,74,76,79,80,90,95,96,97,98,104,106,107,109,110,112,113,116,118,120,123,124,126,127,128,130,131,132,134,135,137,141,142,144,145,146,147,148,149,150,151,152,153,154,155,157,158,159,160,161,162,163,164,165,170,174,175,177,178,182,186,187,191,193,194,195,199,211,218,223,232,234,241,270,275,283,292,293,299,310,312,322,325,335,337,338,343,354,364,372,382,386,398,400,416,445,456,457,465,467,470,476,478,479,485,492,493,545],twowai:218,txt:[0,27,62,75,77,106,118,120,151,179,190,191,205,349,432,440,474,476,492,495],tyepclass:396,tying:[191,521],type:[0,3,6,9,15,17,18,19,20,22,25,26,27,28,30,31,33,35,36,41,42,44,45,46,47,48,49,50,51,55,56,57,58,60,65,67,68,69,70,76,77,80,83,85,86,90,92,95,96,97,98,104,106,110,116,118,120,122,123,125,126,127,128,131,132,133,134,135,136,139,140,142,144,145,146,147,148,149,151,152,155,156,157,158,161,162,163,164,165,170,171,172,173,174,175,177,180,181,183,190,191,194,199,201,202,204,205,213,218,223,225,228,229,230,232,233,234,235,239,241,251,254,257,260,270,273,275,276,278,286,289,292,293,299,308,309,310,311,312,325,336,337,338,340,341,350,352,353,364,371,372,380,388,390,393,394,397,398,402,403,405,410,411,414,416,418,419,425,427,428,434,436,437,439,440,441,443,444,445,447,455,457,461,464,465,466,467,469,470,472,473,476,477,478,479,487,488,489,491,492,496,500,501,508,512,513,515,518,526,532,540,545],type_count:286,typecalass:464,typecalss:257,typeclas:149,typeclass:[0,8,12,13,14,18,19,22,24,26,31,33,34,35,37,39,41,42,44,45,46,50,53,55,63,64,65,75,76,83,85,86,91,97,99,104,105,106,110,111,112,117,118,120,125,126,130,131,132,133,135,136,137,138,140,141,142,144,145,146,147,152,154,157,162,163,164,165,170,171,172,173,174,176,177,178,201,202,204,205,206,207,212,218,223,232,233,234,235,236,253,256,257,260,273,275,278,280,286,289,292,305,308,309,310,311,312,314,316,322,324,329,331,340,350,354,364,366,372,389,394,396,397,398,402,403,405,406,407,409,411,454,471,472,489,490,492,510,512,515,518,523,533,542,545],typeclass_path:[42,48,207,218,406,465,466],typeclass_search:[206,396,405,465],typeclasses:149,typeclasslistserializermixin:515,typeclassmanag:[206,233,396,405],typeclassmixin:[536,537,538,542],typeclassserializermixin:515,typeclassviewsetmixin:518,typedobject:[48,207,213,234,329,340,350,397,398,406,464,465,466,467,487,492],typedobjectmanag:[206,233,389,396,405,465],typeerror:[3,343,445],typelass:18,typenam:[76,204,205,207,232,234,247,257,275,276,277,283,286,296,305,308,309,310,311,312,316,322,325,329,339,340,349,350,359,362,364,366,370,371,372,382,390,397,398,402,406,409,423,449,464,466,480,483,484],typeobject:467,types_count:286,typic:[8,19,95,112,122,142,311,312,354,515,542],typo:[119,120,194],ubuntu:[6,11,181,182,185,187,191,194],uemail:206,ufw:194,ugli:[41,51,133,151,486],uid:[193,206,207,428,435,456,457],uit:[76,82,241],ulrik:135,ultima:180,umlaut:16,unabl:[188,346],unaccept:22,unaffect:[28,164,310,410],unalia:[18,103,223,266],unam:206,unari:353,unarm:309,unarmor:309,unauthenticated_respons:533,unavoid:47,unban:[18,55,103,143,216,223,229,232,266],unban_us:223,unbias:[88,343],unbroken:475,uncal:410,uncas:469,uncategor:489,unchang:[6,36,106,112,349,354,403,492],uncleanli:277,unclear:[58,118,129,159,338],uncolor:[60,139],uncom:[187,191],uncommit:11,uncompress:429,unconnect:[118,230,251],uncov:286,undefin:[2,46,67],under:[2,3,5,7,9,18,22,28,30,31,41,42,48,51,53,64,67,69,73,75,77,88,90,92,95,96,100,103,104,112,113,115,116,119,120,123,134,143,144,146,149,150,152,156,157,158,162,165,169,177,178,179,180,183,185,190,193,199,213,215,218,270,292,353,354,380,386,394,409,416,443,464,469,476,477,478,492,495,496,509,545],undergar:[83,286],undergon:257,underground:118,underli:[11,33,50,123,134,156],underlin:[478,491],underneath:[75,466],underpin:166,underscor:[6,28,30,32,68,86,97,120,151,211,479,492],underscror:211,understand:[0,3,11,16,20,22,39,41,44,52,54,60,65,70,71,86,107,114,119,120,122,124,126,128,129,130,131,132,138,139,142,143,146,148,149,150,151,152,156,157,158,159,161,165,169,170,177,178,180,182,183,185,194,195,210,211,223,293,349,350,382,461,469,492,545],understood:[31,58,65,86,142,158,170,338,444,445],undertak:159,undestand:126,undo:[27,194,474],undon:215,undoubtedli:134,uneven:338,unexpect:[8,142,175,476,492],unexpectedli:483,unfair:158,unfamiliar:[32,33,53,68,151,172,185,191],unfocu:273,unfocus:275,unformat:[28,476,480],unfortun:[124,156],ungm:545,unhappi:75,unheard:58,unhilit:491,unicod:[16,65,70,118,204,338,469,492],unicodeencodeerror:469,unifi:[177,456],uniform:44,unimpl:545,uninflect:495,uninform:181,uninstal:[185,545],uninstati:492,unintent:270,union:[20,28,149,211,364,476],uniqu:[2,12,14,20,22,25,33,34,35,41,42,44,46,48,50,51,55,58,62,65,96,99,104,105,118,120,123,134,144,146,149,153,165,188,191,204,206,209,211,213,218,223,230,232,233,247,251,256,275,289,292,309,310,322,331,337,338,340,349,350,370,372,382,386,389,398,402,403,405,411,413,425,426,434,447,448,456,457,464,465,466,467,472,474,479,486,489,492,496],unit:[1,2,10,11,19,20,45,53,78,87,95,119,123,136,140,180,233,247,260,279,294,310,353,418,472,480,492,497,545],unittest:[8,10,126,229,396,457,472,490],univers:[15,16,136,266],unix:[0,29,36,104,120,183,185,187,224,268,270,477,485,492,545],unixcommand:[116,201,202,235,236,545],unixcommandpars:270,unixtim:485,unjoin:283,unknown:[51,133,137,149,338,402,492],unknown_top:540,unleash:127,unless:[13,18,19,22,28,30,33,34,35,37,47,55,68,74,76,77,104,115,118,120,124,125,128,149,152,156,158,165,179,182,187,189,191,199,204,211,212,216,218,223,225,226,232,256,312,349,350,371,382,388,393,394,398,403,414,429,445,457,464,466,479,489,490,492,493,540],unlik:[45,82,104,105,112,118,119,123,158,162,191,204,241,310,338,354,466],unlimit:[117,329,337],unlink:[26,143,218],unload:[118,490],unload_modul:490,unlock:[18,39,135,149,223,275,464],unlock_flag:275,unlocks_red_chest:39,unlog:[5,216,221,222,230,250,251,457],unloggedin:[44,201,202,208,214,457,545],unloggedincmdset:[25,26,44,89,100,150,222,250,251],unlucki:[55,115],unmask:350,unmodifi:[104,115,210,227,316,476],unmonitor:[421,545],unmut:[18,103,223,232,266],unmute_channel:223,unnam:[46,211],unneccesari:70,unnecessari:[2,156],unnecessarili:146,unneed:[117,329],unpaced_data:425,unpack:[142,393],unpars:[32,36,210,444,445,479],unpaus:[42,193,218,228,410],unpickl:[50,65,425,464,473,488],unplay:[44,126],unpredict:492,unprivileg:403,unprogram:162,unpuppet:[26,45,95,165,215,500],unpuppet_al:204,unpuppet_object:[12,204],unquel:[26,39,144,151,215],unreal:180,unrecogn:479,unrecord_ip:459,unregist:73,unrel:[11,28,245],unrepat:492,unrepeat:[421,492,545],unreport:421,unrestrict:157,unsaf:[199,211,372,492],unsafe_token:469,unsatisfactori:170,unsav:474,unsel:141,unset:[13,22,37,78,112,132,135,164,216,275,276,278,337,339,350,354,370,394,398,402,403,405,411,464,472,476,477,478,479,485,490],unset_character_flag:275,unset_flag:[275,276],unset_lock:223,unsign:493,unsigned_integ:[486,493],unsignedinteg:486,unskil:[112,354],unspawn:338,unstabl:193,unstrip:210,unsuar:119,unsub:[18,103,223,266],unsub_from_channel:223,unsubscrib:[18,47,135,266,411,427],unsuccessful:64,unsuit:[57,402,467],unsupport:13,unsur:[16,30,110,119,143,164,185,188,191],unsurprisingli:151,untag:51,untest:[8,183,185],until:[0,2,5,6,13,14,20,22,28,36,42,47,51,52,54,55,60,67,79,85,99,104,106,108,114,118,123,128,129,144,146,151,152,155,156,157,158,161,165,169,175,181,185,247,260,283,286,289,308,309,310,311,312,337,353,364,370,371,372,398,410,416,445,447,464,469,470,480,492],untouch:[118,152,469],untrust:[14,30,95,158,492],unus:[22,86,118,139,158,204,209,213,223,232,277,312,316,340,362,372,386,398,409,439,455,460,465],unusu:[87,104,159,194],unwant:95,unwield:309,unwieldli:212,unwil:78,upcom:[184,197],updat:[1,2,5,6,8,12,13,14,15,22,26,28,31,34,37,42,47,49,64,65,67,68,73,75,77,84,90,91,95,104,111,118,120,123,124,127,128,129,130,132,134,135,136,139,142,148,151,156,161,162,164,165,169,177,178,180,181,182,183,185,187,188,190,191,192,193,197,205,212,213,218,223,226,228,229,232,244,257,311,316,333,339,350,353,372,390,394,397,398,400,401,403,405,407,432,434,435,440,454,455,457,459,464,466,473,474,475,476,477,478,483,492,500,501,508,513,517,532,533,542,543,545],update_attribut:464,update_buff:474,update_cached_inst:483,update_charsheet:135,update_current_descript:316,update_default:454,update_flag:455,update_lock:513,update_method:51,update_po:132,update_scripts_after_server_start:405,update_session_count:455,update_undo:474,update_weath:372,updated_bi:254,updated_on:254,updatemethod:51,updateview:[542,543],upenn:495,upfir:7,upgrad:[123,185,190,545],upload:[77,123,124,185,191,193,545],upmaplink:[118,338],upon:[15,33,49,53,67,70,78,92,128,156,165,171,191,193,194,308,309,310,311,312,377,380,408,418,427,459,477,542],upp:372,upper:[49,60,67,112,118,128,130,215,337,338,354,469],upper_bound:[112,354],upper_bound_inclus:354,uppercas:[60,350,469],upping:60,upsel:191,upset:143,upsid:[117,329],upstart:62,upstream:[0,9,11,123,195,545],upt:212,uptim:[19,26,30,55,136,228,430,480],urfgar:41,uri:[213,232,388,390,466],url:[11,49,50,52,53,59,73,123,148,169,178,181,191,192,201,202,205,213,223,232,239,388,390,435,445,461,466,491,498,499,511,518,528,531,537,538,540,543,545],url_nam:[518,533],url_or_ref:120,url_path:518,url_to_online_repo:11,urlencod:137,urlpattern:[53,73,124,137,167,177,178],usabl:[63,86,114,124,151,157,165,218,241,275,310,346,393,459,476],usag:[3,5,22,28,31,35,41,47,55,72,76,95,97,119,120,123,125,127,128,129,135,139,140,141,142,143,150,151,161,162,164,165,174,188,191,198,201,202,213,215,216,217,218,223,224,225,228,229,230,235,241,247,251,266,270,273,283,286,292,293,296,299,302,305,308,309,310,311,312,314,316,322,325,327,331,333,341,342,349,350,364,366,369,370,371,372,377,380,393,401,410,416,447,476,478,479,483,545],use:[0,2,3,4,5,7,8,9,10,11,12,13,14,15,16,17,19,20,22,25,27,28,29,30,31,32,33,34,35,36,37,39,41,42,44,45,46,48,49,50,51,52,53,54,55,56,57,58,60,62,63,64,65,67,68,69,70,72,73,74,75,76,77,78,79,81,83,85,86,87,88,90,91,93,94,95,96,97,98,99,102,103,104,105,106,107,109,111,112,113,114,115,116,117,118,119,120,123,124,125,126,127,128,130,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,148,149,150,151,152,153,154,155,156,159,160,161,162,163,164,165,166,167,168,169,170,172,173,174,175,176,177,178,180,181,182,183,184,185,186,187,188,189,191,192,193,194,195,197,198,201,204,205,206,207,209,210,211,212,213,215,218,219,223,224,225,226,228,229,230,232,233,234,241,256,260,270,273,275,276,280,283,286,289,292,293,296,299,302,305,308,309,310,311,312,316,322,325,329,331,332,333,337,338,340,343,346,349,350,354,359,364,366,369,370,371,372,382,386,388,393,394,396,397,398,402,403,410,411,414,421,425,438,440,441,444,447,448,455,456,457,464,465,466,467,469,470,471,472,474,475,476,477,478,479,483,485,486,488,490,492,493,496,501,503,508,513,515,518,538,541,545],use_dbref:[350,396,398,489],use_destin:398,use_i18n:64,use_int:289,use_item:310,use_nick:[204,350,398],use_required_attribut:[502,504,506,508,532],use_success_location_messag:305,use_success_messag:305,use_xterm256:469,useabl:[117,329],used:[5,8,9,11,12,13,14,16,17,18,19,20,23,25,27,28,29,30,31,32,33,34,35,36,37,39,41,42,44,45,46,47,48,50,51,52,53,54,56,57,58,60,62,64,65,67,68,69,70,71,72,73,75,76,78,79,80,83,85,86,87,89,91,92,93,94,95,96,97,98,99,103,104,105,106,107,112,113,114,116,117,118,119,120,123,128,129,133,134,135,136,137,140,141,142,144,145,146,147,148,149,150,151,152,153,154,155,158,161,162,164,165,167,169,170,172,173,174,175,177,178,180,182,183,184,185,187,189,191,193,194,195,199,201,202,204,205,209,211,212,213,215,218,223,225,226,227,228,229,230,232,233,235,241,245,247,250,251,254,256,257,260,266,270,275,276,278,281,283,286,289,291,292,296,299,308,309,310,311,312,316,325,329,331,334,337,338,339,340,346,349,350,354,364,370,371,372,380,382,386,388,389,390,391,392,393,394,396,398,402,403,407,409,410,411,412,413,414,418,421,422,425,426,427,428,429,430,431,432,433,434,436,438,439,440,443,444,445,448,455,457,458,464,465,466,467,468,469,470,472,473,474,476,477,478,479,485,486,487,488,489,490,492,493,496,500,501,505,508,510,515,518,532,536,538,540,541,542,545],useful:[0,1,2,3,5,8,11,13,14,15,16,17,19,20,27,28,30,31,33,36,37,39,41,42,45,46,47,48,50,53,54,55,56,57,60,63,76,79,82,86,95,96,97,104,106,112,116,118,119,120,121,123,124,126,127,128,129,130,134,135,137,138,139,142,143,144,146,147,149,150,151,152,153,155,158,160,161,164,165,170,173,176,177,182,185,191,195,197,199,209,211,212,213,215,217,218,225,226,229,232,235,241,256,257,270,275,280,283,292,299,329,338,339,349,350,354,364,372,377,393,398,402,403,416,436,464,466,470,476,480,488,492,514,544,545],usefulli:150,useless:[149,161,370],user:[0,2,3,5,6,8,10,12,14,15,18,20,25,27,28,29,30,31,32,33,36,39,44,45,48,49,50,51,52,54,55,59,60,62,63,68,70,71,73,76,77,78,83,86,90,93,95,99,103,104,106,109,115,118,119,120,122,123,124,126,127,128,129,132,138,139,141,142,143,144,148,149,151,153,154,158,161,165,169,174,175,177,178,180,181,182,185,186,187,188,189,190,191,192,193,195,198,204,205,207,210,213,216,218,223,225,228,232,233,234,239,241,250,255,257,266,274,275,277,286,289,292,296,310,312,316,329,338,340,350,362,372,376,377,386,388,390,394,398,403,409,412,414,420,428,435,436,439,444,445,455,457,460,464,466,469,474,476,477,478,479,486,490,492,493,500,513,521,524,532,537,538,539,540,541,543,545],user_change_password:500,user_input:28,user_permiss:[207,500],useradmin:500,userauth:436,userchangeform:500,usercreationform:[500,532],userguid:77,usermanag:206,usernam:[11,12,25,28,32,45,49,89,104,124,157,178,185,193,204,207,251,436,460,500,512,515,524,532],usernamefield:532,userpassword:[55,143,216],uses:[5,8,10,11,13,14,16,17,18,20,22,28,30,31,33,35,41,42,45,46,47,48,50,51,53,56,58,60,62,67,68,70,75,76,79,87,89,91,95,97,98,100,104,106,109,112,116,123,128,129,130,131,134,137,139,146,148,149,151,152,157,169,182,191,192,211,225,270,275,283,292,299,310,316,329,337,338,343,349,350,353,354,372,394,396,406,411,425,445,459,464,467,485,486,490,492,512,515,521,540],uses_databas:492,using:[0,2,5,6,8,9,11,12,13,14,15,16,18,19,20,22,26,27,28,30,31,32,33,36,37,39,41,42,44,45,46,47,48,49,50,51,52,53,54,55,57,58,60,65,67,68,69,72,74,75,76,77,82,86,87,94,95,96,99,104,105,106,110,113,117,118,119,120,121,122,123,124,125,126,127,128,129,130,132,133,134,135,136,139,141,142,143,144,145,146,147,148,151,152,156,157,158,159,161,162,163,164,165,170,171,172,173,174,175,176,177,178,179,180,181,182,183,185,187,188,189,191,193,194,198,199,204,207,209,212,213,215,217,218,223,225,226,227,228,232,241,247,256,270,275,283,292,293,294,305,308,309,310,311,312,316,322,325,329,331,332,337,338,340,343,346,349,350,354,366,369,370,372,380,386,388,391,394,396,398,401,402,403,406,410,411,427,428,429,434,435,439,445,448,457,458,459,461,464,466,467,469,470,474,476,477,480,485,486,487,488,489,490,492,498,513,517,518,532,540,541,544,545],usr:[123,185,190,193],usu:42,usual:[0,5,6,7,11,12,13,18,19,20,22,27,28,29,32,33,35,36,37,39,41,42,44,46,47,48,50,52,53,57,58,60,62,64,75,76,95,96,97,104,112,118,119,120,123,124,125,126,128,129,134,136,139,142,143,145,146,148,149,151,152,153,155,158,159,161,169,175,177,181,182,185,187,189,191,193,199,204,205,206,210,211,212,213,215,218,223,224,228,229,234,247,256,257,260,270,278,289,337,338,340,349,350,354,372,382,394,396,397,398,402,403,416,418,423,448,455,464,466,469,471,472,476,477,479,485,487,489,490,492,501,508],usuallyj:118,utc:[182,317,493],utf8:[2,182],utf:[16,32,70,99,135,170,183,230,421,427,444,478,492],util:[6,8,13,14,15,27,28,29,37,42,50,51,54,56,60,67,78,85,87,90,91,92,95,99,107,108,112,113,119,132,134,135,136,139,141,145,147,154,159,170,171,177,178,181,185,194,201,202,217,228,229,232,234,235,236,242,245,247,248,252,253,257,258,267,269,271,272,274,279,284,287,289,290,294,297,300,303,306,311,313,314,316,317,323,325,326,328,330,335,344,347,351,353,354,360,364,367,369,373,387,390,396,398,400,402,409,410,423,442,447,464,465,466,498,499,501,502,504,506,508,516,532,533,545],utilis:476,uyi:[106,349],v19:185,vagu:125,val1:[13,479],val2:[13,479],val:[13,68,204,215,440,492],vala:13,valb:13,valid:[0,3,6,10,13,14,20,22,28,30,37,41,53,59,60,68,86,92,95,99,104,107,113,117,118,129,131,135,137,142,148,151,165,177,178,187,191,194,199,201,202,204,206,210,212,218,226,232,233,241,254,257,258,270,283,292,294,311,329,337,350,353,354,371,372,380,382,386,394,398,400,402,403,405,407,409,410,411,412,414,416,440,444,455,464,465,467,470,472,476,479,486,487,488,489,490,491,492,493,496,515,532,536,538,543,545],valid_handl:486,validate_cal:479,validate_email_address:492,validate_input:354,validate_nam:398,validate_onli:394,validate_password:[28,204],validate_prototyp:402,validate_sess:457,validate_usernam:204,validated_consum:[86,292],validated_input:292,validated_tool:[86,292],validationerror:[204,402,460,486,488],validator_config:204,validator_kei:486,validatorfunc:[201,202,468,545],valign:478,valu:[3,6,8,9,12,13,17,19,20,22,27,30,32,33,34,36,42,47,48,49,50,51,54,55,60,67,68,76,77,78,85,92,94,95,97,104,106,112,114,118,120,123,124,126,127,130,132,135,136,137,139,140,141,143,144,146,148,149,150,151,153,156,157,162,164,165,170,175,177,178,185,187,191,204,206,207,209,211,213,215,216,218,232,234,241,254,257,258,275,286,289,296,305,308,309,310,311,312,329,337,338,340,343,346,349,350,353,354,360,362,372,378,380,382,390,393,394,396,397,398,401,402,403,405,406,410,411,414,421,422,423,425,434,439,440,455,456,457,462,464,465,466,467,469,471,472,473,474,475,476,479,483,484,486,487,488,489,490,492,493,496,512,515,532,541,543,545],valuabl:155,value1:[41,120],value2:[41,120],value3:120,value_a:13,value_b:13,value_displai:515,value_from_datadict:488,value_to_obj:402,value_to_obj_or_ani:402,value_to_str:488,valueerror:[41,142,165,206,241,247,302,382,464,467,469,472,492,493],valuei:170,values_list:146,valuex:170,vampir:146,vanilla:[0,48,67,75,77,132,133,135,149,156,545],vaniti:28,vari:[31,48,62,64,69,95,104,106,112,118,119,123,129,140,148,151,255,312,340,349,354,455,464,466],variabl:[4,5,6,7,13,14,20,22,28,30,31,33,41,42,51,63,64,68,70,73,77,84,86,92,96,97,118,120,122,123,127,132,133,135,137,142,143,146,149,150,151,152,167,174,177,178,185,193,194,195,204,207,209,213,215,218,223,226,228,229,230,232,244,250,254,256,257,260,273,305,316,337,339,354,372,380,393,397,398,402,403,413,416,426,429,430,432,436,438,448,455,462,469,470,476,479,492,525,545],variable_from_modul:492,variable_nam:[254,257],variablenam:492,varianc:349,variant:[13,46,89,104,110,122,151,212,241,242,251,325,427,469,545],variat:[39,91,136,146,158,161,162,164,211,316,349,492],varieti:[114,122,140,164,173,310,311],variou:[5,6,13,16,22,35,37,41,42,44,46,47,48,51,53,62,66,68,71,95,96,104,106,113,115,118,119,121,134,136,137,139,146,147,148,151,153,157,161,162,164,165,166,187,191,194,199,211,227,247,275,310,311,338,349,350,364,370,371,386,394,397,398,403,404,411,448,472,478,489,490,521],varnam:440,vast:[67,69,170,182],vastli:123,vavera:77,vcc:[106,349],vccv:[106,349],vccvccvc:349,vcpython27:75,vcv:349,vcvccv:[106,349],vcvcvcc:[106,349],vcvcvvccvcvv:[106,349],vcvvccvvc:[106,349],vector:492,vehicl:[125,545],velit:29,venu:[11,233],venv:[185,190],ver:182,verb:[30,58,126,398,452,479,495,497],verb_actor_stance_compon:495,verb_all_tens:495,verb_conjug:[30,201,202,468,545],verb_infinit:495,verb_is_past:495,verb_is_past_participl:495,verb_is_pres:495,verb_is_present_participl:495,verb_is_tens:495,verb_past:495,verb_past_participl:495,verb_pres:495,verb_present_participl:495,verb_tens:495,verb_tenses_kei:495,verbal:[81,104,398],verbatim:[30,144,151,496,545],verbatim_el:492,verbos:[0,8,164],verbose_nam:[177,466,500,501,508],verbose_name_plur:[501,508],veri:[0,3,5,6,8,9,11,12,13,14,15,17,18,19,20,22,25,27,28,29,30,31,32,33,41,42,45,46,47,48,50,51,53,54,58,60,62,67,68,69,72,74,75,76,82,83,90,95,96,97,104,106,107,111,113,114,115,117,118,119,120,122,123,124,125,127,128,130,132,133,134,135,138,141,142,144,146,148,149,151,152,153,154,155,156,157,158,159,161,162,164,165,170,174,176,178,179,180,181,182,187,189,191,195,199,204,205,211,213,229,232,233,234,241,256,257,270,286,292,311,322,325,329,349,350,366,370,382,386,389,397,402,420,465,467,472,474,476,492,541],verif:191,verifi:[2,5,11,28,89,92,104,149,185,191,218,292,311,380,441,490],verify_online_play:380,verify_or_create_ssl_key_and_cert:441,verify_ssl_key_and_cert:437,verifyfunc:[92,380],versa:[44,53,58,62,68,118,164,223,331,425,479,496],version:[1,2,9,12,13,14,15,18,20,22,25,26,28,31,32,35,36,42,48,51,53,60,64,67,69,80,90,104,118,119,123,124,125,128,129,134,139,142,143,144,148,150,151,156,158,161,165,169,170,175,180,182,183,184,185,190,191,193,198,218,226,228,230,251,280,286,309,310,311,312,316,350,364,371,398,403,416,421,435,459,464,469,477,492,500,501,502,505,506,509,515,532,544,545],version_info:416,versionad:120,versionchang:120,versu:[122,545],vertic:[335,337,338,371,478,492],very_strong:394,very_weak:33,vest:194,vet:41,veteran:180,vex:497,vfill_char:478,vhost:545,via:[5,11,13,18,19,28,29,30,32,39,40,41,42,48,49,51,54,60,62,65,67,69,77,119,122,133,134,141,146,148,149,151,156,162,165,175,185,187,191,194,231,233,234,331,364,376,397,406,464,467,469,479,484,545],viabl:[86,158,370],vice:[44,53,58,62,68,118,164,223,331,425,479,496],vicin:[22,224,316,372],video:[51,60,148,180],vidual:118,vienv:75,view:[0,3,11,13,17,19,27,28,29,31,33,42,47,49,50,52,53,58,67,104,106,115,118,120,122,123,124,135,138,140,143,148,149,151,154,158,164,165,169,170,185,189,191,197,198,199,201,202,204,213,215,216,218,223,224,225,228,232,266,286,308,309,310,311,312,329,350,388,390,398,400,451,466,477,479,498,503,510,511,513,515,517,521,525,528,531,532,545],view_attr:218,view_lock:513,view_on_sit:[500,502,504,505,506,508],viewabl:[121,122,225],viewer:[120,126,137,329,350,398,466],viewpoint:[479,496,497,545],viewport:3,viewset:[49,517,518],vim:[15,27,154,180,474],vincent:[82,91,95,100,104,107,116,240,241,270,315,316,382],violent:28,virginia:77,virtual:[91,118,122,124,134,180,185,191,228,316,338,480],virtual_env:190,virtualenv:[0,2,5,6,7,9,64,75,77,120,182,185,190,191,193,198,199,545],virtualhost:181,viru:185,visibl:[2,11,13,14,20,31,35,44,48,53,60,106,118,120,126,137,139,156,157,158,161,165,184,185,187,191,198,224,225,335,337,338,350,398,428,461,476,492,540],vision:[13,135,156],visit:[76,77,116,132,170,177,178,191,270,476],visitor:[73,178,194],vista:185,visual:[5,31,51,60,94,104,118,126,134,185,204,225,335,337,338,340,346,469],visual_rang:340,vital:142,vlgeoff:[87,104,107,116,246,247,268,381],vniftg:185,vnum:133,vocabulari:[96,492,545],voic:[22,95,96,545],volatil:402,volcano:153,volum:[125,156,170,193,545],volund:146,volunt:64,voluntari:119,volupt:29,vowel:[106,349],vpad_char:478,vscode:154,vulner:[128,194],vvc:[106,349],vvcc:[106,349],vvccv:[106,349],vvccvvcc:[106,349],w001:8,wai:[3,5,6,7,8,9,11,12,13,14,15,16,19,20,22,30,31,32,33,34,35,36,37,39,40,41,42,44,45,46,47,48,52,53,54,55,57,58,60,62,65,67,68,70,72,74,75,76,77,79,80,86,87,88,89,90,92,94,95,96,97,100,102,104,106,109,112,113,115,119,120,122,123,125,127,129,130,131,132,133,134,135,136,137,138,140,141,142,143,144,145,146,147,148,149,152,153,155,156,158,159,161,162,164,165,169,170,171,172,174,175,176,177,180,182,184,185,189,190,191,192,194,195,198,199,204,210,211,218,225,232,247,256,260,270,275,278,283,292,293,308,309,310,311,312,316,322,325,331,335,338,343,346,349,354,364,369,370,371,380,386,388,394,398,402,411,416,421,425,436,457,459,461,462,463,464,465,467,470,475,476,478,483,485,488,492,496,510,517,518,541,543,545],wail:132,waist:286,wait:[3,19,22,28,42,54,95,97,108,112,115,126,127,128,144,155,157,158,174,205,229,256,260,308,309,310,311,312,354,364,405,416,426,445,447,459,472,476,492],wait_for_disconnect:426,wait_for_server_connect:426,wait_for_statu:416,wait_for_status_repli:416,waiter:416,waitinf:229,wake:[92,380],waldemar:77,walias:218,walk:[15,20,58,95,96,97,113,117,118,122,125,130,132,136,141,156,158,161,325,329,331,338,364,386,470],walki:[18,123,158],wall:[99,115,143,151,155,161,170,216,224,316,371,372],wand:[86,292,293],wanna:[79,157,283,364],want:[0,3,4,5,6,7,8,9,11,12,13,14,15,16,18,19,20,22,25,27,28,30,31,32,33,34,35,36,37,39,41,42,44,45,47,48,49,50,51,53,54,55,57,58,60,62,63,64,65,67,68,69,70,73,74,75,76,77,78,79,80,85,86,89,90,95,96,97,100,104,106,108,112,118,119,120,123,124,125,126,127,128,129,130,131,132,134,135,136,137,139,140,141,142,143,144,146,147,148,149,150,151,152,153,154,156,157,159,160,161,162,163,165,166,167,168,169,170,172,174,175,176,177,178,179,181,182,183,184,185,187,188,189,190,191,192,194,195,197,198,199,204,211,212,213,215,218,224,225,229,230,241,251,275,283,289,292,308,309,310,311,312,316,329,337,338,340,346,350,354,364,372,376,380,382,386,393,394,398,403,407,409,411,432,434,440,447,457,462,464,466,474,476,477,483,488,490,492,501,508,510,517,532,537,540,541,543,544,545],wanted_id:33,war:[31,388],warchannel:223,ware:141,warehous:[376,470],wari:[60,329,398,466],warm:[42,199,420],warn:[9,13,19,20,31,44,74,104,118,123,142,148,151,170,178,181,185,191,195,211,232,377,415,416,441,485,544,545],warnmsg:485,warrior:[39,127,134,135,155,158,165,223],wasclean:[427,444],wasn:[3,97,178],wast:[15,47],watch:[7,15,34],water:[86,99,104,212,292,293,305],waterballon:305,watt:77,wave:170,wavi:118,wcach:228,wcactu:311,wcommandnam:270,wcure:311,wdestin:218,weak:403,weakref:483,weaksharedmemorymodel:[423,483],weaksharedmemorymodelbas:[423,483],weakvalu:483,wealth:141,weap:13,weapon:[13,28,41,67,114,115,123,128,140,141,143,145,146,150,155,156,157,162,163,164,293,309,370,371,403,545],weapon_ineffective_msg:370,weapon_prototyp:371,weaponrack_cmdset:371,weaponstr:150,weapoon:155,wear:[83,108,140,157,163,286,309,350,364],wearabl:[83,104,286],wearer:286,wearstyl:286,weather:[42,46,47,74,129,138,148,155,156,162,170,372,545],weather_script:42,weatherroom:[176,372],web:[17,31,33,41,49,52,56,59,64,75,77,104,120,121,122,123,124,126,129,137,144,147,151,154,156,168,180,181,182,185,189,190,198,199,201,202,418,420,430,434,440,444,445,455,459,461,467,473,545],web_client_url:184,web_get_admin_url:[213,232,388,390,466],web_get_create_url:[232,390,466],web_get_delete_url:[232,390,466],web_get_detail_url:[213,232,388,390,466],web_get_puppet_url:466,web_get_update_url:[232,390,466],web_help_entri:540,web_plugin:148,webclient:[24,44,51,53,59,60,62,65,68,71,73,77,121,123,129,137,148,151,183,184,187,194,199,201,202,225,228,275,369,412,421,424,440,445,456,476,498,526,533,545],webclient_ajax:[51,201,202,412,424,545],webclient_en:194,webclient_gui:545,webclient_opt:421,webclientdata:445,webclienttest:533,webpag:[17,181,191,529,545],webport:2,webserv:[24,49,53,62,73,75,147,148,167,181,182,187,191,193,195,197,201,202,412,545],webserver_en:194,webserver_interfac:[187,191],webserver_port:[2,191],webservic:194,websit:[17,49,50,51,52,75,77,120,121,122,123,134,137,138,148,167,169,177,180,187,191,192,194,201,202,445,461,498,500,526,545],websocket:[51,52,62,123,191,193,427,433,444,456,545],websocket_client_interfac:[187,191],websocket_client_port:191,websocket_client_url:[181,187,191],websocket_clos:444,websocketcli:444,websocketclientfactori:427,websocketclientprotocol:427,websocketserverfactori:433,websocketserverprotocol:444,weed:[0,211],week:[87,95,104,136,148,247,485,493],weeklylogfil:485,weigh:[140,447],weight:[69,106,118,120,156,182,337,338,346,349,465,545],weird:[31,143,158,161,492],welcom:[25,53,64,76,119,124,141,154,167,185,189],well:[0,7,8,9,11,12,13,17,18,22,26,27,28,29,30,31,32,37,39,41,44,48,50,53,55,56,57,62,63,68,69,70,73,75,76,77,88,91,95,96,102,104,106,113,114,118,119,120,122,123,124,125,126,130,131,132,134,135,136,137,139,141,142,146,149,150,151,152,153,155,157,158,159,161,164,165,169,172,173,177,178,182,188,190,192,194,195,198,207,211,212,213,218,231,232,256,266,273,274,275,283,286,302,310,311,312,316,337,340,349,350,354,364,370,386,398,406,410,412,416,425,427,428,434,451,459,464,465,469,473,476,479,480,488,492,501,508],went:[8,11,134,152,161,198,199,407,411],weonewaymaplink:[118,338],were:[3,8,13,14,18,20,22,28,30,41,42,48,51,54,67,69,86,95,103,104,113,118,119,123,131,135,137,140,141,142,146,148,149,150,151,152,158,165,175,183,193,195,204,210,211,212,223,232,266,337,338,382,386,398,402,463,466,470,479,489,492,495,497],weren:136,werewolf:[126,545],werewolv:146,werkzeug:492,wesson:58,west:[99,118,126,131,132,144,170,218,337,338,372],west_east:170,west_exit:372,west_room:99,western:170,westward:372,wet:158,wether:[206,283,472],wevennia:76,wflame:311,wflushmem:228,wfull:311,wguild:223,what:[0,3,5,6,8,9,10,11,12,14,15,18,19,20,22,28,30,31,32,33,35,37,41,42,44,47,48,49,52,53,54,55,57,58,60,62,65,67,68,69,70,72,74,75,76,80,86,88,95,96,97,99,104,105,106,107,112,115,118,119,120,123,124,125,126,128,130,131,132,133,134,135,136,137,139,141,143,144,146,147,149,150,151,155,156,157,160,161,162,163,164,165,166,168,169,170,171,172,174,175,176,177,178,179,180,181,182,185,187,189,191,192,194,195,199,204,209,211,212,213,215,218,229,232,257,273,275,276,280,292,293,305,310,311,337,338,339,340,350,354,366,370,372,376,382,388,390,394,398,401,402,403,416,418,421,428,440,445,460,462,464,466,467,469,470,476,486,487,490,492,493,515,521,523,524,532,541,542,545],whatev:[8,11,12,13,15,19,22,28,30,37,62,76,92,95,96,101,118,123,125,133,135,140,142,151,152,156,157,159,165,170,177,178,179,182,187,193,198,204,205,212,218,273,292,311,362,370,371,380,398,403,406,407,427,436,439,444,457,464,477,486,541],wheat:292,wheel:[47,86,134,185,190],whelp:[225,270],when:[0,1,2,3,6,7,8,9,11,12,13,14,15,16,17,18,19,20,22,25,27,28,29,30,31,32,33,34,36,37,39,41,42,44,45,46,48,50,51,52,53,54,55,57,58,60,62,63,64,65,67,68,69,70,72,75,76,77,80,82,83,87,89,90,91,92,93,95,96,97,98,99,102,104,106,108,112,113,116,117,118,119,120,123,124,125,128,129,130,131,132,133,134,135,136,137,140,141,142,143,144,146,147,148,149,150,151,152,153,154,155,157,158,159,160,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,179,180,181,182,183,185,186,187,190,191,192,193,194,195,198,199,201,204,205,207,209,211,212,213,215,217,218,223,224,225,226,227,228,230,232,233,234,239,241,247,250,251,257,258,260,270,275,276,277,278,283,286,289,292,293,296,299,302,305,308,309,310,311,312,316,322,329,336,337,338,339,343,346,349,350,354,359,360,364,366,369,370,371,372,380,382,383,386,389,390,393,394,396,397,398,400,402,403,405,406,407,409,410,411,413,416,418,422,423,425,426,427,428,429,430,431,432,434,436,437,438,439,440,441,444,445,447,448,454,455,456,457,458,459,464,466,467,469,470,472,473,474,475,476,477,478,483,484,485,487,492,496,505,521,523,532,536,538,543,545],when_stop:416,whenev:[7,9,13,18,22,32,33,34,36,41,42,45,54,58,63,70,76,96,123,126,149,161,170,171,191,192,193,204,212,232,278,370,371,372,396,398,407,409,418,435,455,456,457],where:[0,2,3,4,5,11,13,14,15,18,20,22,27,28,29,30,31,33,35,39,41,42,44,48,50,51,53,54,55,58,59,60,62,64,65,67,68,69,70,73,75,76,77,78,85,86,95,96,97,99,104,106,112,118,120,123,125,126,128,130,132,133,134,135,136,137,141,142,143,144,148,149,150,151,152,154,155,156,158,160,161,162,163,165,167,169,170,171,172,174,177,178,182,190,191,193,194,195,197,198,210,211,216,218,224,225,227,232,233,275,289,293,299,310,329,337,338,339,340,343,349,350,353,354,371,372,377,391,393,394,396,398,402,403,407,416,418,421,425,448,453,457,464,466,469,470,474,476,477,478,479,480,486,487,490,492,496,508,515,543,545],wherea:[0,3,5,6,9,13,14,20,22,28,33,44,48,55,57,58,60,62,67,70,86,118,125,133,139,141,151,164,194,206,292,338,349,396,405,411,445,464,483],whereabout:155,wherebi:311,wherev:[8,58,82,112,123,153,170,185,187,193,241,310,338,354,376],whether:[28,55,78,96,97,122,130,136,137,150,174,204,205,212,218,223,225,232,289,308,309,310,311,312,380,386,398,411,427,444,459,464,465,469,486,488,492,495],whewiu:75,which:[0,2,3,4,5,6,7,8,11,13,14,15,16,18,19,20,22,24,26,28,29,30,31,32,33,35,36,37,39,41,42,44,45,46,47,48,49,51,52,54,55,57,58,60,62,63,65,67,68,69,70,73,74,75,76,77,82,83,84,86,90,91,92,94,95,96,97,99,104,109,111,112,113,114,116,118,119,120,123,124,126,127,128,129,130,131,132,133,134,135,136,137,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,155,156,157,158,159,161,162,164,165,167,169,170,171,172,173,174,175,176,177,178,182,183,185,186,187,188,189,191,193,194,195,198,199,204,205,209,211,212,213,215,216,218,224,225,226,229,230,232,233,234,241,244,247,260,270,273,275,280,283,286,289,292,293,299,302,308,309,310,311,312,316,322,329,337,338,339,340,346,350,354,364,366,370,371,372,376,377,380,386,390,394,396,397,398,402,403,405,406,407,409,411,413,415,416,420,421,428,434,436,444,445,447,448,455,456,457,459,462,464,465,466,467,469,470,472,473,476,477,478,479,480,483,485,486,488,489,490,492,495,501,508,515,518,521,523,524,525,532,538,541,543],whichev:[19,156,159,191,194,372],whilst:[99,170],whimper:155,whisk:278,whisp:[106,349],whisper:[26,95,96,104,143,224,260,273,275,349,350,398,545],whistl:58,white:[32,60,77,175,469,492],whitelist:32,whitenois:[104,112,352,354],whitespac:[15,19,22,135,139,143,146,154,161,165,226,302,350,469,470,478,492],who:[13,18,26,28,30,31,33,36,39,41,42,48,49,54,55,58,60,64,90,95,96,103,122,124,125,132,133,135,146,150,151,152,155,156,157,159,161,162,164,165,174,176,177,194,205,213,215,218,223,232,234,257,266,273,275,283,308,309,310,311,312,349,350,371,380,388,390,394,398,403,466,474,476,479,496,513,545],whoever:177,whole:[36,46,56,72,104,118,122,124,132,134,143,156,158,161,165,170,187,211,218,273,312,478,523],wholist:[18,232],whome:218,whomev:[162,174,364],whoopi:161,whose:[30,48,68,86,146,148,149,204,213,229,257,308,309,310,311,312,350,386,405,421,471,476,479,492],whould:476,why:[0,13,28,48,55,76,90,95,96,97,122,123,126,130,131,140,142,144,157,159,161,165,170,175,185,194,198,216,308,311,312,338,382,413,414,476],wick:464,wide:[19,30,35,56,67,117,118,126,130,135,142,151,162,187,216,310,311,329,475,478,492],widen:[55,161],wider:[55,126,130,216,478],widest:492,widget:[488,500,501,502,504,505,506,508,515,532],width:[17,19,22,30,31,32,41,56,118,126,132,170,201,213,337,340,421,436,455,469,474,475,477,478,479,492],wield:[41,114,140,157,163,309],wifi:[191,194],wiki:[22,48,64,69,75,85,122,123,135,138,164,170,180,241,289,444,544,545],wiki_account_handl:124,wiki_account_signup_allow:124,wiki_can:124,wiki_can_admin:124,wiki_can_assign:124,wiki_can_assign_own:124,wiki_can_change_permiss:124,wiki_can_delet:124,wiki_can_moder:124,wiki_can_read:124,wiki_can_writ:124,wikiconfig:124,wikipedia:[8,11,16,70,122,123,164,444],wil:[13,18],wild:[53,69,118,146,156,175,339,340],wildcard:[36,55,118,134,216,218,337,339,340,492],wildcard_to_regexp:492,wilder:[201,202,235,314,545],wildernessexit:329,wildernessmap:329,wildernessmapprovid:[117,329],wildernessroom:329,wildernessscript:329,wildli:349,wildr:95,wilfr:95,will_suppress_ga:438,will_transform:146,will_ttyp:443,willing:[135,156,159,180,545],wim:77,win10:185,win7:185,win8:185,win:[28,75,142,164,183,273],wind:[95,155,176],winder:158,windmil:292,window:[0,5,6,7,9,11,20,29,37,44,51,52,65,68,118,120,123,124,126,131,132,144,151,154,157,182,189,198,199,213,225,275,277,416,432,455,459,492,545],windowid:455,windows10:185,wine:[153,155],wingd:170,winpti:75,winter:[91,316],wintertim:157,wintext_templ:162,wip:[120,544],wipe:[9,11,13,14,18,26,75,90,143,151,170,182,211,218,228,277,310],wire:[19,62,65,68,70,123,187,191,227,413,425,426,457,469],wis:135,wisdom:5,wise:[0,11,14,15,16,33,73,135,149,157,172],wiser:[42,144,161],wish:[2,11,22,82,130,169,173,190,241,312,469,491,532],with_tag:305,withdraw:[164,312],withdrawl:312,within:[0,6,11,13,20,22,28,30,31,47,51,54,75,76,77,90,91,94,118,119,120,123,130,132,133,135,146,148,151,153,161,164,169,171,172,173,175,178,181,182,183,191,193,204,207,209,218,254,283,316,339,346,377,389,398,403,410,459,464,465,469,479,485,492,532,538,543],withot:338,without:[3,5,6,8,9,11,13,14,15,18,19,20,22,25,27,28,30,35,40,41,42,45,47,48,50,52,53,55,56,60,62,63,64,67,68,69,72,76,86,88,90,91,95,96,97,99,104,106,109,113,117,118,120,123,125,126,128,129,131,132,134,135,142,143,144,145,146,148,150,151,152,156,157,158,159,161,165,169,172,174,175,177,181,182,185,187,191,193,195,198,204,205,210,213,215,216,218,223,224,225,226,227,228,229,232,233,234,239,242,254,257,266,278,283,286,292,308,311,312,316,322,338,349,350,354,364,370,372,386,394,396,398,401,402,403,409,410,425,436,439,440,447,457,458,464,466,469,470,472,473,474,476,477,479,485,488,489,490,492,525],withstand:33,wiz:135,wizard:[41,95,158,372,403,414,416,545],wkei:218,wlocat:218,wlock:218,wmagic:311,wmass:311,wndb_:218,wnn:18,woah:[149,150],woman:[157,158],won:[3,12,13,14,16,20,48,49,51,54,55,60,65,67,76,90,92,96,97,104,107,120,124,125,128,134,137,139,141,142,143,146,150,151,156,158,160,162,165,170,178,179,182,185,193,212,335,359,364,380,382,461,469,488],wonder:[56,75,133,140],wont_suppress_ga:438,wont_ttyp:443,woo:143,wood:[86,158,292,293],wooden:[41,86,292,293],woodenpuppetrecip:86,woosh:125,word:[5,6,11,15,18,19,22,27,30,31,37,58,64,68,95,96,104,106,132,136,137,142,143,149,151,154,157,159,169,170,175,189,210,225,226,230,251,260,280,349,350,396,428,474,479,489,492,496,545],word_fil:349,word_length_vari:[106,349],wordi:349,work:[0,2,3,4,5,6,7,8,9,12,13,14,15,16,18,19,20,26,28,30,31,33,34,37,41,42,44,46,47,50,52,53,54,56,58,60,63,65,67,69,72,75,76,79,86,90,91,97,102,104,109,113,119,120,123,124,125,126,127,128,131,132,133,134,135,136,139,141,143,144,146,147,148,149,150,151,152,153,154,156,157,159,161,164,165,166,168,169,170,171,175,176,177,178,181,182,183,185,187,188,189,190,191,194,197,198,209,212,213,215,218,223,224,226,228,230,232,241,266,270,273,283,292,294,302,305,310,311,312,316,322,329,338,350,372,386,388,390,393,394,398,402,403,416,420,421,433,448,461,463,464,466,467,470,475,476,477,478,486,492,525,536,537,538,540,542,545],workaround:[11,185,193,545],workflow:[500,545],world:[8,13,14,15,16,18,19,20,22,28,31,39,41,53,54,67,69,70,75,79,86,87,90,95,99,102,104,112,117,118,120,122,123,125,130,132,134,135,136,140,145,149,150,152,154,159,160,162,163,164,165,166,168,170,171,174,179,180,185,189,191,195,204,217,218,223,225,247,283,292,302,308,309,310,311,312,314,329,337,350,354,368,371,372,388,390,406,455,457,469,470,480,490,545],world_map:170,worm:[132,158],worm_has_map:132,worn:[83,104,286,309],worri:[2,13,16,28,50,60,70,95,97,119,130,146,155,161,165,195,275,276,283],wors:[157,159],worst:156,worth:[5,28,42,48,58,97,119,125,128,142,157,158,159,177,180,181,283],worthi:156,worthless:191,would:[2,3,5,7,8,9,13,14,15,16,19,20,22,28,30,31,33,35,37,41,42,44,46,47,48,52,53,54,56,57,60,67,68,73,74,75,76,77,79,83,86,87,95,96,97,104,112,113,118,122,123,124,125,126,128,130,131,132,133,134,135,136,137,139,140,141,142,143,144,146,147,148,149,150,151,152,154,156,157,158,159,161,162,164,165,169,170,171,172,174,175,177,178,181,185,191,193,204,210,211,212,213,218,227,232,245,247,257,270,275,283,292,293,329,337,338,349,354,364,386,388,390,394,402,403,428,440,466,469,470,473,476,487,488,490,492,501,508],wouldn:[31,130,150,175],wound:311,wow:[137,159],wpermiss:218,wprototype_desc:218,wprototype_kei:218,wprototype_lock:218,wprototype_par:218,wprototype_tag:218,wrap:[28,41,42,54,92,129,132,146,151,153,161,169,275,286,293,350,380,423,463,478,492],wrap_conflictual_object:488,wrapper:[5,19,28,32,44,48,54,67,86,128,204,207,233,234,278,280,322,354,390,391,397,398,406,410,421,423,455,464,466,467,469,478,479,483,484,485,492,503,508],wresid:228,write:[5,10,13,15,16,19,20,22,28,31,36,48,54,56,58,68,69,72,76,78,82,90,95,96,97,119,120,124,126,131,133,135,136,142,143,144,146,149,150,151,152,155,157,158,159,161,165,182,185,186,188,189,218,223,225,232,239,241,270,376,377,398,429,485,490,541,543,545],writeabl:190,written:[16,18,19,41,52,118,120,133,134,135,137,143,146,148,149,150,151,152,153,177,178,180,184,194,200,225,338,376,470,541],wrong:[0,3,8,139,141,151,157,182,185,199,211,218,228,292,294,350],wrote:[146,149,490],wserver:228,wservic:223,wsgi:[181,461],wsgi_resourc:461,wsgiwebserv:461,wsl:[120,185],wss:[181,191,545],wtypeclass:218,wwhere:398,www:[9,49,69,75,76,120,122,123,130,177,181,191,201,228,431,432,438,440,491,495,532],wyou:140,x0c:218,x1b:[469,491],x2x:135,x4x:475,x5x:475,x6x:475,x7x:475,x8x:475,x9x:475,x_r:130,xcode:185,xforward:461,xgettext:64,xgiven:340,xit:[76,82,241],xmlcharrefreplac:469,xp_gain:162,xpo:478,xtag:495,xterm256:[32,51,65,71,84,139,151,215,244,346,421,436,439,469,545],xterm256_bg:469,xterm256_bg_sub:469,xterm256_fg:469,xterm256_fg_sub:469,xterm256_gbg:469,xterm256_gbg_sub:469,xterm256_gfg:469,xterm256_gfg_sub:469,xterm:[60,151,175],xterms256:60,xval:22,xxx:[3,107,126,382],xxxx:[107,382],xxxxx1xxxxx:475,xxxxx3xxxxx:475,xxxxx:95,xxxxxxx2xxxxxxx:475,xxxxxxxxxx3xxxxxxxxxxx:135,xxxxxxxxxx4xxxxxxxxxxx:135,xxxxxxxxxxx:475,xxxxxxxxxxxxxx1xxxxxxxxxxxxxxx:135,xxxxxxxxxxxxxxxxxxxxxx:135,xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:135,xygrid:[337,338],xymap:[201,202,235,314,330,331,332,335,338,339,340,545],xymap_data:[118,337,339],xymap_data_list:[118,337,339],xymap_legend:[118,201,202,235,314,330,332,335,545],xyroom:340,xyz:[36,118,331,334,338,339,340],xyz_destin:[118,340],xyz_destination_coord:340,xyz_exit:[118,334,338],xyz_room:[118,334,338],xyzcommand:[118,332,333],xyzexit:[339,340,545],xyzexit_prototype_overrid:118,xyzexitmanag:340,xyzgrid:[201,202,235,314,545],xyzgrid_cmdset:331,xyzgrid_use_db_prototyp:118,xyzgridcmdset:[118,331],xyzmanag:340,xyzmap:118,xyzroom:[201,202,235,314,330,339,545],xyzroom_prototype_overrid:118,y_r:130,yan:[60,469],yank:27,yard:115,year:[68,69,77,87,95,104,119,122,136,154,158,191,247,480,485,492,532],yearli:[136,191],yeast:[86,104,292],yellow:[11,60,118,175,371],yer:157,yes:[22,28,54,58,96,120,130,175,218,228,260,414,474,476,492],yes_act:476,yes_no_question_cmdset:476,yesno:[28,120,474],yesnoquestioncmdset:476,yet:[2,3,9,11,12,15,25,28,41,44,55,64,67,76,85,96,97,99,104,118,123,124,126,127,132,143,146,149,159,161,170,174,177,178,180,184,185,187,191,198,200,204,223,230,251,257,283,289,338,364,394,397,410,434,457,461,469,539],yield:[22,33,54,69,78,182,218,377,478,490,492,545],yml:[10,193],yogurt:[105,305],yoshimura:77,you:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,22,25,27,28,30,31,32,33,34,35,36,37,39,40,41,42,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,62,63,64,65,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,89,90,91,92,94,95,96,97,98,99,100,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,151,152,153,156,157,159,160,161,162,163,164,165,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,197,198,199,204,212,213,215,218,223,224,225,226,227,228,229,230,232,241,244,247,255,256,257,260,266,270,273,275,276,280,283,286,289,292,293,299,302,305,308,309,310,311,312,316,322,325,329,331,333,337,338,346,349,350,353,354,359,364,366,371,372,376,377,380,382,386,388,393,394,398,403,407,408,409,410,411,418,427,428,429,445,447,457,459,461,462,464,466,469,470,472,475,476,478,479,480,488,489,490,492,495,496,497,512,515,517,518,532,541,543,544,545],you_obj:30,you_replac:273,your:[2,3,5,7,10,13,14,15,16,17,18,19,20,25,27,28,30,31,33,35,36,39,41,42,44,45,46,47,48,49,50,52,53,54,55,56,58,60,63,64,65,68,70,72,73,74,75,76,77,78,79,81,82,83,84,85,86,87,88,89,91,92,93,94,95,96,97,99,100,102,104,106,108,109,110,113,114,115,116,117,118,119,120,122,123,125,126,128,129,131,132,133,134,135,136,137,138,139,140,141,142,146,147,149,150,151,152,153,154,155,156,157,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,178,179,180,181,182,184,185,186,187,188,189,190,192,195,197,198,199,201,202,204,207,210,212,213,215,216,218,223,224,225,228,229,230,235,241,242,244,247,251,256,270,273,275,283,286,289,292,293,308,309,310,311,312,316,322,325,329,331,332,337,341,343,346,349,350,352,359,364,371,372,376,377,380,382,386,393,394,397,447,466,469,474,476,478,479,488,489,490,492,493,496,497,501,508,518,532,538,541,545],your_act:275,your_bucket_nam:77,your_email:11,yourchar:151,yourgam:376,yourgamenam:77,yourhostnam:187,yournam:[119,143,149,150,181],yourpassword:182,yourrepo:7,yourself:[0,3,8,10,11,12,15,20,28,33,37,48,53,56,57,58,67,69,73,76,77,95,97,99,104,109,112,115,118,119,120,122,135,137,142,150,151,153,157,158,159,161,162,165,170,179,182,185,191,218,224,273,275,283,296,311,322,331,350,354,359,476,479,496,497,545],yourselv:[58,479,496,497],yoursit:177,yourtest:8,yourusernam:11,yourwebsit:177,yousuck:55,yousuckmor:55,youth:[92,380],youtub:11,ypo:478,yrs:247,ythi:60,yum:[11,181,187],yvonn:135,z_destin:340,z_r:130,z_sourc:340,zcoord:[331,335,337,339,545],zed:180,zero:[19,35,41,144,149,151,153,223,289,292,339,350,391,398,464,469,479],zip:194,zlib:[190,425,429],zmud:[183,431],zone:[46,96,133,138,148,159,180,467,485,545],zoord:339,zope:6,zopeinterfac:185,zuggsoft:431},titles:["Coding Introduction","Coding and development help","Continuous Integration","Debugging","Things to remember about the flat API","Profiling","Quirks","Setting up PyCharm","Unit Testing","Updating Your Game","Using Travis","Version Control","Accounts","Attributes","Batch Code Processor","Batch Command Processor","Batch Processors","Bootstrap Components and Utilities","Channels","Coding Utils","Command Sets","Command System","Commands","Communications","Core Components","Connection Screen","Default Commands","EvEditor","EvMenu","EvMore","The Inline Function Parser","Help System","Inputfuncs","Locks","MonitorHandler","Msg","Nicks","Objects","Outputfuncs","Permissions","Portal And Server","Spawner and Prototypes","Scripts","Server component","Sessions","Signals","Tags","TickerHandler","Typeclasses","Evennia REST API","The Web Admin","Web Client","Webserver","Game website","Async Process","Banning","Bootstrap & Evennia","Building Permissions","Sending different messages depending on viewpoint and receiver","Clickable links","Colors","Core Concepts","Custom Protocols","Guest Logins","Internationalization","Messagepath","Multisession modes","New Models","OOB","Soft Code","Text Encodings","In-text tags parsed by Evennia","Using MUX as a Standard","Web Features","Zones","Arxcode installing help","Building menus","AWSstorage system","Input/Output Auditing","Barter system","Batch processor examples","Script example","Building menu","Clothing","Color markups","Cooldowns","Crafting system","Custom gameime","Dice","Email-based login system","EvscapeRoom","Extended Room","Easy fillable form","Gendersub","Health Bar","Evennia in-game Python system","Dialogues in events","A voice operated elevator using events","In-Game Mail system","Map Builder","Menu-based login system","TutorialMirror","Evennia Multidescer","Legacy Comms-commands","Contribs","Puzzles System","Roleplaying base system for Evennia","Pseudo-random generator and registry","Red Button example","SimpleDoor","Slow Exit","Talkative NPC example","Traits","Easy menu selection tree","Turn based battle system framework","Evennia Tutorial World","Unix-like Command style parent","Wilderness system","XYZgrid","How To Contribute And Get Help","Contributing to Evennia Docs","API Summary","Evennia Introduction","Glossary","Add a wiki on your website","Building a mech tutorial","Coding FAQ","Command Cooldown","Command Duration","Command Prompt","Coordinates","Default Exit Errors","Dynamic In Game Map","Evennia for Diku Users","Evennia for MUSH Users","Evennia for roleplaying sessions","Gametime Tutorial","Help System Tutorial","Tutorials and Howto\u2019s","Manually Configuring Color","Mass and weight for objects","NPC shop Tutorial","Parsing command arguments, theory and best practices","Our own commands","Using the game and building stuff","Creating things","Django Database queries","Overview of the Evennia library","Overview of your new Game Dir","Persistent objects and typeclasses","More about Commands","Starting to code Evennia","Python Classes and objects","Searching for things","Starting Tutorial (Part 1)","The Tutorial World","On Planning a Game","Planning the use of some useful contribs","Planning our tutorial game","Where do I begin?","Evennia Starting Tutorial (Part 2)","Making a sittable object","Implementing a game rule system","Evennia Starting Tutorial (Part 3)","Turn based Combat System","Tutorial for basic MUSH like game","Evennia Starting Tutorial (Part 4)","Add a simple new web page","Evennia Starting Tutorial (part 5)","Web Tutorial","Static In Game Map","Tutorial Aggressive NPCs","Tutorial NPCs listening","Tutorial Tweeting Game Stats","Tutorial Vehicles","Understanding Color Tags","Weather Tutorial","Web Character Generation","Web Character View Tutorial","Licensing","Links","Apache Config","Choosing An SQL Server","Client Support Grid","Evennia Game Index","Getting Started","Grapevine","Making Evennia, HTTPS and WSS (Secure Websockets) play nicely together","How to connect Evennia to Twitter","IRC","Installing on Android","Online Setup","RSS","Running Evennia in Docker","Security","Server Conf","The Evennia Default Settings file","Server Setup and Life","Setup quickstart","Start Stop Reload","Unimplemented","evennia","evennia","evennia.accounts","evennia.accounts.accounts","evennia.accounts.bots","evennia.accounts.manager","evennia.accounts.models","evennia.commands","evennia.commands.cmdhandler","evennia.commands.cmdparser","evennia.commands.cmdset","evennia.commands.cmdsethandler","evennia.commands.command","evennia.commands.default","evennia.commands.default.account","evennia.commands.default.admin","evennia.commands.default.batchprocess","evennia.commands.default.building","evennia.commands.default.cmdset_account","evennia.commands.default.cmdset_character","evennia.commands.default.cmdset_session","evennia.commands.default.cmdset_unloggedin","evennia.commands.default.comms","evennia.commands.default.general","evennia.commands.default.help","evennia.commands.default.muxcommand","evennia.commands.default.syscommands","evennia.commands.default.system","evennia.commands.default.tests","evennia.commands.default.unloggedin","evennia.comms","evennia.comms.comms","evennia.comms.managers","evennia.comms.models","evennia.contrib","evennia.contrib.base_systems","evennia.contrib.base_systems.awsstorage","evennia.contrib.base_systems.awsstorage.aws_s3_cdn","evennia.contrib.base_systems.awsstorage.tests","evennia.contrib.base_systems.building_menu","evennia.contrib.base_systems.building_menu.building_menu","evennia.contrib.base_systems.building_menu.tests","evennia.contrib.base_systems.color_markups","evennia.contrib.base_systems.color_markups.color_markups","evennia.contrib.base_systems.color_markups.tests","evennia.contrib.base_systems.custom_gametime","evennia.contrib.base_systems.custom_gametime.custom_gametime","evennia.contrib.base_systems.custom_gametime.tests","evennia.contrib.base_systems.email_login","evennia.contrib.base_systems.email_login.connection_screens","evennia.contrib.base_systems.email_login.email_login","evennia.contrib.base_systems.email_login.tests","evennia.contrib.base_systems.ingame_python","evennia.contrib.base_systems.ingame_python.callbackhandler","evennia.contrib.base_systems.ingame_python.commands","evennia.contrib.base_systems.ingame_python.eventfuncs","evennia.contrib.base_systems.ingame_python.scripts","evennia.contrib.base_systems.ingame_python.tests","evennia.contrib.base_systems.ingame_python.typeclasses","evennia.contrib.base_systems.ingame_python.utils","evennia.contrib.base_systems.menu_login","evennia.contrib.base_systems.menu_login.connection_screens","evennia.contrib.base_systems.menu_login.menu_login","evennia.contrib.base_systems.menu_login.tests","evennia.contrib.base_systems.mux_comms_cmds","evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds","evennia.contrib.base_systems.mux_comms_cmds.tests","evennia.contrib.base_systems.unixcommand","evennia.contrib.base_systems.unixcommand.tests","evennia.contrib.base_systems.unixcommand.unixcommand","evennia.contrib.full_systems","evennia.contrib.full_systems.evscaperoom","evennia.contrib.full_systems.evscaperoom.commands","evennia.contrib.full_systems.evscaperoom.menu","evennia.contrib.full_systems.evscaperoom.objects","evennia.contrib.full_systems.evscaperoom.room","evennia.contrib.full_systems.evscaperoom.scripts","evennia.contrib.full_systems.evscaperoom.state","evennia.contrib.full_systems.evscaperoom.tests","evennia.contrib.full_systems.evscaperoom.utils","evennia.contrib.game_systems","evennia.contrib.game_systems.barter","evennia.contrib.game_systems.barter.barter","evennia.contrib.game_systems.barter.tests","evennia.contrib.game_systems.clothing","evennia.contrib.game_systems.clothing.clothing","evennia.contrib.game_systems.clothing.tests","evennia.contrib.game_systems.cooldowns","evennia.contrib.game_systems.cooldowns.cooldowns","evennia.contrib.game_systems.cooldowns.tests","evennia.contrib.game_systems.crafting","evennia.contrib.game_systems.crafting.crafting","evennia.contrib.game_systems.crafting.example_recipes","evennia.contrib.game_systems.crafting.tests","evennia.contrib.game_systems.gendersub","evennia.contrib.game_systems.gendersub.gendersub","evennia.contrib.game_systems.gendersub.tests","evennia.contrib.game_systems.mail","evennia.contrib.game_systems.mail.mail","evennia.contrib.game_systems.mail.tests","evennia.contrib.game_systems.multidescer","evennia.contrib.game_systems.multidescer.multidescer","evennia.contrib.game_systems.multidescer.tests","evennia.contrib.game_systems.puzzles","evennia.contrib.game_systems.puzzles.puzzles","evennia.contrib.game_systems.puzzles.tests","evennia.contrib.game_systems.turnbattle","evennia.contrib.game_systems.turnbattle.tb_basic","evennia.contrib.game_systems.turnbattle.tb_equip","evennia.contrib.game_systems.turnbattle.tb_items","evennia.contrib.game_systems.turnbattle.tb_magic","evennia.contrib.game_systems.turnbattle.tb_range","evennia.contrib.game_systems.turnbattle.tests","evennia.contrib.grid","evennia.contrib.grid.extended_room","evennia.contrib.grid.extended_room.extended_room","evennia.contrib.grid.extended_room.tests","evennia.contrib.grid.mapbuilder","evennia.contrib.grid.mapbuilder.mapbuilder","evennia.contrib.grid.mapbuilder.tests","evennia.contrib.grid.simpledoor","evennia.contrib.grid.simpledoor.simpledoor","evennia.contrib.grid.simpledoor.tests","evennia.contrib.grid.slow_exit","evennia.contrib.grid.slow_exit.slow_exit","evennia.contrib.grid.slow_exit.tests","evennia.contrib.grid.wilderness","evennia.contrib.grid.wilderness.tests","evennia.contrib.grid.wilderness.wilderness","evennia.contrib.grid.xyzgrid","evennia.contrib.grid.xyzgrid.commands","evennia.contrib.grid.xyzgrid.example","evennia.contrib.grid.xyzgrid.launchcmd","evennia.contrib.grid.xyzgrid.prototypes","evennia.contrib.grid.xyzgrid.tests","evennia.contrib.grid.xyzgrid.utils","evennia.contrib.grid.xyzgrid.xymap","evennia.contrib.grid.xyzgrid.xymap_legend","evennia.contrib.grid.xyzgrid.xyzgrid","evennia.contrib.grid.xyzgrid.xyzroom","evennia.contrib.rpg","evennia.contrib.rpg.dice","evennia.contrib.rpg.dice.dice","evennia.contrib.rpg.dice.tests","evennia.contrib.rpg.health_bar","evennia.contrib.rpg.health_bar.health_bar","evennia.contrib.rpg.health_bar.tests","evennia.contrib.rpg.rpsystem","evennia.contrib.rpg.rpsystem.rplanguage","evennia.contrib.rpg.rpsystem.rpsystem","evennia.contrib.rpg.rpsystem.tests","evennia.contrib.rpg.traits","evennia.contrib.rpg.traits.tests","evennia.contrib.rpg.traits.traits","evennia.contrib.tutorials","evennia.contrib.tutorials.batchprocessor","evennia.contrib.tutorials.batchprocessor.example_batch_code","evennia.contrib.tutorials.bodyfunctions","evennia.contrib.tutorials.bodyfunctions.bodyfunctions","evennia.contrib.tutorials.bodyfunctions.tests","evennia.contrib.tutorials.mirror","evennia.contrib.tutorials.mirror.mirror","evennia.contrib.tutorials.red_button","evennia.contrib.tutorials.red_button.red_button","evennia.contrib.tutorials.talking_npc","evennia.contrib.tutorials.talking_npc.talking_npc","evennia.contrib.tutorials.talking_npc.tests","evennia.contrib.tutorials.tutorial_world","evennia.contrib.tutorials.tutorial_world.intro_menu","evennia.contrib.tutorials.tutorial_world.mob","evennia.contrib.tutorials.tutorial_world.objects","evennia.contrib.tutorials.tutorial_world.rooms","evennia.contrib.tutorials.tutorial_world.tests","evennia.contrib.utils","evennia.contrib.utils.auditing","evennia.contrib.utils.auditing.outputs","evennia.contrib.utils.auditing.server","evennia.contrib.utils.auditing.tests","evennia.contrib.utils.fieldfill","evennia.contrib.utils.fieldfill.fieldfill","evennia.contrib.utils.random_string_generator","evennia.contrib.utils.random_string_generator.random_string_generator","evennia.contrib.utils.random_string_generator.tests","evennia.contrib.utils.tree_select","evennia.contrib.utils.tree_select.tests","evennia.contrib.utils.tree_select.tree_select","evennia.help","evennia.help.filehelp","evennia.help.manager","evennia.help.models","evennia.help.utils","evennia.locks","evennia.locks.lockfuncs","evennia.locks.lockhandler","evennia.objects","evennia.objects.manager","evennia.objects.models","evennia.objects.objects","evennia.prototypes","evennia.prototypes.menus","evennia.prototypes.protfuncs","evennia.prototypes.prototypes","evennia.prototypes.spawner","evennia.scripts","evennia.scripts.manager","evennia.scripts.models","evennia.scripts.monitorhandler","evennia.scripts.scripthandler","evennia.scripts.scripts","evennia.scripts.taskhandler","evennia.scripts.tickerhandler","evennia.server","evennia.server.amp_client","evennia.server.connection_wizard","evennia.server.deprecations","evennia.server.evennia_launcher","evennia.server.game_index_client","evennia.server.game_index_client.client","evennia.server.game_index_client.service","evennia.server.initial_setup","evennia.server.inputfuncs","evennia.server.manager","evennia.server.models","evennia.server.portal","evennia.server.portal.amp","evennia.server.portal.amp_server","evennia.server.portal.grapevine","evennia.server.portal.irc","evennia.server.portal.mccp","evennia.server.portal.mssp","evennia.server.portal.mxp","evennia.server.portal.naws","evennia.server.portal.portal","evennia.server.portal.portalsessionhandler","evennia.server.portal.rss","evennia.server.portal.ssh","evennia.server.portal.ssl","evennia.server.portal.suppress_ga","evennia.server.portal.telnet","evennia.server.portal.telnet_oob","evennia.server.portal.telnet_ssl","evennia.server.portal.tests","evennia.server.portal.ttype","evennia.server.portal.webclient","evennia.server.portal.webclient_ajax","evennia.server.profiling","evennia.server.profiling.dummyrunner","evennia.server.profiling.dummyrunner_settings","evennia.server.profiling.memplot","evennia.server.profiling.settings_mixin","evennia.server.profiling.test_queries","evennia.server.profiling.tests","evennia.server.profiling.timetrace","evennia.server.server","evennia.server.serversession","evennia.server.session","evennia.server.sessionhandler","evennia.server.signals","evennia.server.throttle","evennia.server.validators","evennia.server.webserver","evennia.settings_default","evennia.typeclasses","evennia.typeclasses.attributes","evennia.typeclasses.managers","evennia.typeclasses.models","evennia.typeclasses.tags","evennia.utils","evennia.utils.ansi","evennia.utils.batchprocessors","evennia.utils.containers","evennia.utils.create","evennia.utils.dbserialize","evennia.utils.eveditor","evennia.utils.evform","evennia.utils.evmenu","evennia.utils.evmore","evennia.utils.evtable","evennia.utils.funcparser","evennia.utils.gametime","evennia.utils.idmapper","evennia.utils.idmapper.manager","evennia.utils.idmapper.models","evennia.utils.idmapper.tests","evennia.utils.logger","evennia.utils.optionclasses","evennia.utils.optionhandler","evennia.utils.picklefield","evennia.utils.search","evennia.utils.test_resources","evennia.utils.text2html","evennia.utils.utils","evennia.utils.validatorfuncs","evennia.utils.verb_conjugation","evennia.utils.verb_conjugation.conjugate","evennia.utils.verb_conjugation.pronouns","evennia.utils.verb_conjugation.tests","evennia.web","evennia.web.admin","evennia.web.admin.accounts","evennia.web.admin.attributes","evennia.web.admin.comms","evennia.web.admin.frontpage","evennia.web.admin.help","evennia.web.admin.objects","evennia.web.admin.scripts","evennia.web.admin.server","evennia.web.admin.tags","evennia.web.admin.urls","evennia.web.admin.utils","evennia.web.api","evennia.web.api.filters","evennia.web.api.permissions","evennia.web.api.root","evennia.web.api.serializers","evennia.web.api.tests","evennia.web.api.urls","evennia.web.api.views","evennia.web.templatetags","evennia.web.templatetags.addclass","evennia.web.urls","evennia.web.utils","evennia.web.utils.adminsite","evennia.web.utils.backends","evennia.web.utils.general_context","evennia.web.utils.middleware","evennia.web.utils.tests","evennia.web.webclient","evennia.web.webclient.urls","evennia.web.webclient.views","evennia.web.website","evennia.web.website.forms","evennia.web.website.tests","evennia.web.website.urls","evennia.web.website.views","evennia.web.website.views.accounts","evennia.web.website.views.channels","evennia.web.website.views.characters","evennia.web.website.views.errors","evennia.web.website.views.help","evennia.web.website.views.index","evennia.web.website.views.mixins","evennia.web.website.views.objects","Evennia Documentation","<no title>"],titleterms:{"break":146,"case":[97,158],"class":[8,19,22,48,76,95,148,149,152,158],"default":[26,30,32,33,51,53,118,126,129,131,149,150,196,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230],"final":[132,190],"function":[3,30,33,37,53,76,121,151,153],"goto":28,"import":[0,4,107,118,120,147,151,152],"new":[6,8,42,48,53,67,86,95,124,135,137,148,149,158,167,177,198],"public":[184,197],"return":[28,44,146,151],"static":[112,170,354],"super":[57,150],AWS:77,Adding:[20,32,46,50,53,62,67,75,86,95,97,124,126,130,131,144,150,174,177],And:[40,119],Are:158,Going:197,One:[99,118],PMs:135,TLS:181,The:[0,5,14,15,27,28,30,31,39,41,42,50,54,56,57,65,73,76,95,96,118,128,132,135,137,138,141,155,156,159,164,165,167,196,198],Use:[0,194],Uses:30,Using:[5,8,10,13,18,29,30,31,34,41,46,53,67,72,74,95,112,119,132,138,144,191,354],Will:158,Yes:28,_famili:146,_should:158,abl:158,abort:128,about:[4,9,47,48,118,128,150,152,158],absolut:147,abus:55,access:[50,61],access_typ:33,account:[6,12,50,77,123,135,145,158,203,204,205,206,207,215,500,536],accountcmdset:98,across:161,action:158,activ:[134,158,177],actor:58,actor_stance_cal:30,actual:[22,48],add:[53,124,126,167,182],add_choic:76,addclass:520,addit:[75,130,131,193],address:126,admin:[6,50,73,123,216,499,500,501,502,503,504,505,506,507,508,509,510],administr:[18,156,158],adminsit:523,advanc:[1,36,121,128,150,182,199],aggress:171,alia:6,alias:[46,153],all:[95,126,137,149,158,187],allow:[18,158],alpha:156,also:158,altern:[7,75],amount:158,amp:425,amp_client:413,amp_serv:426,analyz:5,android:190,ani:[14,122],annot:146,anoth:[42,120,150],ansi:[19,60,175,469],apach:181,api:[4,49,51,120,121,147,511,512,513,514,515,516,517,518],app:[137,177],appear:158,arbitrari:28,area:[165,170],arg:142,arg_regex:22,argument:[28,142,149,151],arm:125,around:144,arx:75,arxcod:75,ascii:19,ask:[22,28],asset:159,assign:[22,57],assort:[15,20,22,28,46,54,62,172],async:54,asynchron:54,at_cmdset_cr:98,at_object_cr:149,attach:[7,42,45],attack:[158,165],attribut:[6,13,50,123,149,153,464,501],attributeproperti:13,audit:[78,104,375,376,377,378],auto:31,automat:126,avail:[25,45],awai:1,aws_s3_cdn:238,awsstorag:[77,104,237,238,239],backend:524,ban:55,bank:158,bar:94,barter:[79,104,157,158,282,283,284],base:[41,89,100,106,114,118,126,158,164],base_system:[104,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270],basic:[14,15,52,95,122,124,165,169,188],batch:[14,15,16,80,470],batchcod:14,batchprocess:217,batchprocessor:[104,356,357,470],battl:114,befor:0,begin:159,behavior:18,best:142,beta:156,between:[14,28,48],block:[14,118,120,128],blockquot:120,blurb:53,board:158,bodyfunct:[104,358,359,360],bold:120,boot:55,bootstrap:[17,56],border:17,bot:205,branch:28,brief:137,briefli:68,broken:158,bug:6,build:[50,57,76,82,120,125,132,135,141,144,156,158,170,218],builder:[99,158],building_menu:[76,104,240,241,242],built:158,bulletin:158,busi:141,button:[17,108,144],calendar:136,call:[22,95,149],call_ev:95,callabl:30,callback:[51,95,96,97],callbackhandl:254,caller:28,can:[13,76,122,152,153,158],cannot:158,capabl:158,capcha:177,card:17,care:194,carri:158,cast:293,caveat:[14,15,48,60,190],certain:146,certif:187,chain:95,chair:[158,161],chang:[6,9,11,50,53,64,69,91,95,97,120,126,135,149,158,169,194],channel:[18,123,126,135,158,537],charact:[18,37,50,96,123,126,135,140,149,156,158,161,162,165,177,178,183,538],charactercmdset:98,chargen:165,chat:18,cheat:3,check:[13,33,39,77],checker:0,checkpoint:177,children:152,choic:76,choos:182,clean:75,clickabl:59,client:[51,65,68,73,154,183,191,418],client_opt:32,clone:[11,75],cloth:[83,104,157,285,286,287],cloud9:191,cmdhandler:209,cmdparser:210,cmdset:[143,150,211],cmdset_account:219,cmdset_charact:220,cmdset_sess:221,cmdset_unloggedin:222,cmdsethandl:212,code:[0,1,3,9,11,13,14,18,19,27,35,36,42,69,76,88,95,119,120,126,141,143,151,156,158,162,181,292,470],coin:158,collabor:134,color:[17,19,53,60,84,126,139,175],color_markup:[104,243,244,245],colour:60,combat:[164,165],comfort:193,comm:[103,223,231,232,233,234,502],command:[3,6,15,20,21,22,24,25,26,31,42,76,91,95,98,103,116,121,126,127,128,129,131,135,136,139,141,142,143,148,149,150,151,154,161,164,165,174,188,193,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,255,273,331,470],comment:[115,131,132,152],commit:11,commom:53,commun:[14,23,119],complet:33,complex:[76,146],compon:[17,24,43,338],comput:191,concept:[1,61,132,158,164],conclud:[130,165],conclus:[76,142,146,149,151,157,158,159,161,170],condit:126,conf:[148,195],config:[121,139,181],configur:[7,11,77,78,139,177,181,182,186,187,188,189,192,197],congratul:156,conjug:495,connect:[6,25,184,188,191],connection_screen:[250,262],connection_wizard:414,contain:[42,193,471],content:126,continu:[2,161],contrib:[8,76,104,119,123,157,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386],contribut:[119,120,121],control:11,convert:[30,142],cooldown:[85,104,127,288,289,290],coordin:130,copi:181,core:[8,24,61,121,123,133],cost:77,counter:[112,354],cprofil:5,craft:[86,104,158,291,292,293,294],crafter:86,creat:[2,6,12,19,22,37,48,55,67,95,97,121,125,137,138,143,144,145,149,151,158,165,167,170,174,177,193,472],create_object:149,createnpc:165,creation:159,creatur:193,credit:[149,155],crop:19,current:[3,136],custom:[8,18,28,30,31,33,44,49,50,51,53,54,62,70,73,76,86,87,124,134,136,139,143,197],custom_gametim:[104,246,247,248],customis:[117,329],dai:158,data:[7,13,28,44,52,62],databas:[6,9,24,31,41,67,75,121,146,149],dbref:153,dbserial:473,deal:42,death:158,debug:[3,14,194],debugg:7,decid:158,decor:[28,54],dedent:19,dedic:177,deep:138,deeper:86,default_cmd:98,defaultobject:6,defeat:158,defin:[11,20,22,28,30,33,42,67,118],definit:33,delai:[19,42,54,128],delimit:126,demo:156,deni:95,depend:[9,58,75,77],deploi:193,deprec:[120,415],desc:[28,112,354],descer:134,descript:[91,158,193],design:[90,141],detail:[77,91,105,117,118,137,177,329],detect:158,develop:[1,134,180,193,194,199],dialogu:96,dice:[88,104,135,157,342,343,344],dictionari:28,differ:[48,58,133,158],diku:133,dir:[8,148,154,197],direct:[7,120],director:58,directori:[191,195],disabl:[95,194],discuss:180,displai:[19,132,136,183],dive:138,django:[33,73,123,146,177,199],doc:[0,120],docker:193,docstr:[120,152],document:[72,119,120,544],doe:158,doing:159,don:[14,122,161,193],donat:119,done:155,down:[118,144,174,199],dummyrunn:[5,447],dummyrunner_set:448,durat:128,dure:199,dynam:[22,28,132],each:[153,158],easi:[92,113],echo:32,economi:158,edit:[27,76,95,120,165],editnpc:165,editor:[27,95,154],elev:97,els:158,email:89,email_login:[104,249,250,251,252],emot:106,emul:133,encod:[16,70],encrypt:191,enemi:158,enforc:158,engin:159,enjoi:181,enough:[155,158],enter:174,entir:97,entit:24,entiti:158,entri:[31,144],error:[42,131,143,151,199,539],eval:120,eveditor:[27,474],even:86,evennia:[0,3,4,7,8,9,11,30,41,49,51,56,64,71,74,75,77,95,102,106,115,119,120,122,124,126,133,134,135,142,147,151,158,160,163,166,168,175,180,181,182,184,187,188,190,191,193,196,199,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544],evennia_launch:416,event:[95,96,97,136],eventfunc:[95,256],everi:129,everyth:76,evform:[135,475],evmenu:[28,126,476],evmor:[29,477],evscaperoom:[90,104,272,273,274,275,276,277,278,279,280],evtabl:[126,135,478],examin:[3,95,149],exampl:[3,27,28,30,33,39,42,51,53,69,80,81,84,85,86,96,99,107,108,111,117,118,130,147,162,164,191,329,332,470],example_batch_cod:357,example_recip:293,except:161,execut:3,exist:[48,158],exit:[22,37,97,110,126,131,325],expand:[112,164,174,354],experi:158,explan:76,explor:[0,147],extend:[61,91,118,157],extended_room:[104,315,316,317],extern:[120,194],extra:[91,95,149,155],fail:158,familiar:[133,134],faq:[126,138],faster:8,featur:[61,73,91,137],feel:133,field:[92,123,146],fieldfil:[104,379,380],fight:158,figur:143,file:[11,14,15,16,31,120,195,196,470],filehelp:388,fill:19,fillabl:92,filter:512,find:[1,130,151,153],firewal:194,first:[76,96,97,118,134,149,151],fix:11,flat:[4,53],flexibl:120,flow:[52,158],flower:158,folder:[0,11,75],foreground:199,forget:6,fork:[11,119],form:[17,53,92,158,177,532],formal:158,format:28,forum:180,framework:[114,180],from:[4,28,31,51,88,122,124,126,144,151,177,191,193,476],front:[53,169],frontpag:503,full:[76,137],full_system:[104,271,272,273,274,275,276,277,278,279,280],func:39,funcpars:[30,479],funcparser_cal:30,further:[54,169,181],futur:125,gain:158,game:[0,8,9,11,13,18,19,31,42,53,90,95,98,122,130,132,134,135,136,144,148,154,156,158,159,162,165,170,173,184,191,193,197,198,292],game_index_cli:[417,418,419],game_system:[104,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313],gamedir:120,gameim:87,gameplai:155,gametim:[136,480],gaug:[112,354],gendersub:[93,104,295,296,297],gener:[17,61,76,107,158,165,177,180,224,476],general_context:525,get:[28,95,119,138,144,146,185,187],get_client_opt:32,get_input:28,get_inputfunc:32,get_valu:32,git:[11,123],github:[11,123],give:158,given:46,global:[121,142,158],global_script:42,glossari:123,gmcp:68,godhood:144,goldenlayout:51,good:152,googl:177,grant:[50,135],grapevin:[186,427],graphic:151,grid:[104,118,132,183,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340],group:146,guest:63,guid:75,guidelin:119,had:155,handl:[55,137,158,194,199],handler:[45,121,164],haproxi:187,have:[138,152,154,158,165],head:120,health:94,health_bar:[104,345,346,347],hello:151,help:[0,1,31,75,119,137,144,225,387,388,389,390,391,504,540],here:[0,122],hidden:158,hide:158,hierarchi:[39,135,158],hint:[5,42,64,115,155,181],hit:143,hold:150,hook:48,host:191,hous:144,how:[12,22,37,48,70,119,135,138,158,174,188,193],howto:138,html:[53,167,177],http:[181,187],human:158,idea:79,idmapp:[481,482,483,484],imag:[193,194],implement:[117,158,162,329],improv:[137,158],index:[137,177,184,541],infinit:158,influenc:158,info:[79,180,199],inform:191,infrastructur:162,ingame_python:[104,253,254,255,256,257,258,259,260],ingo:65,inherit:[41,74,152],inherits_from:19,init:[147,149],initi:[126,164,182,198],initial_setup:420,inlin:30,input:[22,28,30,68,78,151],inputfunc:[32,65,421],instal:[11,75,77,78,79,82,83,84,85,87,88,89,90,91,93,95,98,99,100,101,102,103,105,106,109,110,111,112,115,116,117,118,124,177,181,182,185,187,188,190,191,193,197,198,292,325,343,354],instanc:[22,48,67,152],intal:86,integr:2,interact:[0,14,15,54,151,185],interfac:194,intern:120,internation:64,interpret:7,interrupt:118,intro_menu:369,introduct:[0,5,28,75,90,122,132,170,177],inventori:140,ipython:151,irc:[189,428],issu:183,ital:120,item:156,itself:161,join:18,jumbotron:17,jupyt:0,just:[122,158],kei:[28,41,76,92,153],keyword:[96,149],kill:[158,199],kind:158,know:[122,194],known:[6,158],languag:[28,64,106],larg:158,last:126,latest:[9,11,193],latin:126,launch:[27,28],launchcmd:333,layout:56,learn:[0,122],leav:174,legaci:103,legend:[118,338],lesson:[154,160],let:[3,14,137,191],librari:147,licens:[77,179],life:197,lift:55,like:[14,116,133,158,165],limit:[14,15,158],line:[3,27,125,146,151,154,161],link:[50,59,118,120,180],linux:[2,185,199],list:[3,120,149,150,158],list_nod:28,listen:172,literatur:180,live:199,local:[120,142,191],locat:153,lock:[13,31,33,39,150,174,392,393,394],lockdown:191,lockfunc:[161,393],lockhandl:394,log:[18,19,75,137,148,151,194,198],logfil:7,logger:485,login:[32,63,89,100],logo:[53,169],longer:96,look:[31,133,144,158,165],lookup:[121,146],loop:149,loot:158,mac:[185,199],machin:191,magic:6,mai:158,mail:[11,98,104,298,299,300],main:[120,121,153,544],make:[8,11,19,90,119,125,134,135,143,144,149,151,158,161,165,174,187],manag:[13,39,51,124,206,233,389,396,405,422,465,482],manual:[139,158,184],map:[99,115,118,132,170,338],mapbuild:[104,318,319,320],mapper:132,mariadb:182,markup:[84,469],mass:140,master:[11,135,158],match:[6,150],matter:158,mccp:429,mean:158,mech:125,mechan:158,memori:13,memplot:449,menu:[19,28,76,82,100,113,141,274,400,476],menu_login:[104,261,262,263,264],merg:20,messag:[58,65,68,97,126],messagepath:65,method:[6,22,42,139,149,151],middlewar:526,migrat:[9,123,124],mind:11,minimap:170,mirror:[104,361,362],mixin:542,mob:[138,158,370],mod_proxi:181,mod_ssl:181,mod_wsgi:181,mode:[14,15,44,66,123,191,199],model:[8,67,121,177,207,234,390,397,406,423,466,483],modif:135,modifi:[53,129,149,181],modul:[41,151,162,164,188],monitor:32,monitorhandl:[34,407],more:[0,9,33,41,56,58,60,73,86,120,121,128,134,139,150,158],most:0,motiv:159,move:[126,161,174],msdp:68,msg:[35,65,139],mssp:430,mud:[154,180],multi:[134,150,151,152,158],multidesc:[102,104,134,301,302,303],multipl:[13,158,161],multisess:[44,66,123],mush:[134,165],must:158,mutabl:[6,13],mux:72,mux_comms_cmd:[104,265,266,267],muxcommand:226,mxp:431,mygam:[98,325],mysql:182,myst:120,name:[6,55,149,158],nattribut:13,naw:432,need:[97,122,150,154,158],nest:76,network:24,next:[134,185,188,198],nice:187,nick:36,night:158,node:[28,118],non:[13,126,127,184,185],nop:183,note:[8,15,16,20,22,28,31,36,46,52,54,62,81,89,100,110,115,120,172,181,325],notebook:0,npc:[79,111,138,141,157,158,165,171,172],number:142,numer:158,obfusc:106,obj:39,object:[6,13,19,33,37,42,44,46,50,58,123,126,140,144,145,146,149,150,151,152,153,156,158,161,170,174,275,371,395,396,397,398,505,543],obtain:177,off:[126,158],offici:180,olc:41,onc:[95,155],one:[120,130,158],onli:[120,146,158,199],onlin:[11,191],oob:68,oop:152,open:141,oper:[54,97],option:[28,76,92,118,135,142,191,194,199],optionclass:486,optionhandl:487,other:[22,42,50,53,58,90,151,153,158,180,182,191,195],our:[69,76,97,137,143,149,151,156,158,174,177],ourselv:149,out:[62,135,143,158],outgo:65,output:[18,78,376],outputcommand:68,outputfunc:38,outsid:191,overal:162,overload:[48,73,139],overrid:6,overview:[2,67,118,147,148,164,169],own:[12,22,32,37,51,62,90,112,143,151,158,191,193,354],page:[53,73,124,137,167,169],paramet:95,parent:[67,95,116,134],pars:[71,126,142,150,151],parser:30,part3:138,part:[138,154,160,163,166,168],parti:180,pass:151,patch:119,path:[14,65,148],pathfind:118,paus:[22,97,128],pax:75,pdb:3,penalti:158,percent:[112,354],perman:158,permiss:[33,39,46,57,95,135,513],perpetu:156,persist:[13,27,127,128,143,149],person:[144,158],philosophi:90,physic:158,picklefield:488,pictur:177,pip:[123,124],place:120,plai:[90,158,187],plan:[0,156,157,158,170],player:[134,158],plugin:51,point:0,polici:72,port:[191,194],portal:[40,44,65,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445],portalsess:65,portalsessionhandl:[65,434],post:158,postgresql:182,practic:142,prefix:22,prepar:2,prerequisit:190,prevent:126,prioriti:31,prison:158,privileg:[124,158],problem:69,process:[54,61,199],processor:[14,15,16,80,470],product:[125,193],profil:[5,446,447,448,449,450,451,452,453],program:[3,122],project:[2,7],prompt:[28,129],pron:58,pronoun:496,prop:158,properti:[12,13,18,20,22,28,35,37,44,46,48,118,123,146],protfunc:[41,401],protocol:[62,68],prototyp:[41,118,334,399,400,401,402,403],proxi:[181,191],pseudo:107,pudb:3,pull:11,puppet:123,push:[11,144],put:[11,137,187],puzzl:[104,105,304,305,306],pvp:158,pycharm:7,python:[0,14,95,122,134,148,151,152,180,188],quell:[39,57,150],queri:[48,146,149],queryset:[146,153],quest:158,quick:[2,158,185],quickstart:198,quiet:142,quirk:6,race:158,rais:161,random:107,random_string_gener:[104,381,382,383],rate:[112,354],read:[0,54,60,73,169],real:14,reboot:199,recapcha:177,receiv:[58,62,68],recip:[86,292,293],recog:58,red:108,red_button:[104,363,364],refer:[120,126],referenc:58,regard:95,regist:191,registri:107,regular:158,rel:[147,153],relat:[95,136,138],releas:[120,156],relev:191,reli:14,reload:[6,126,152,181,199],remark:165,rememb:[4,120,152],remind:137,remot:[11,182,191],remov:[46,95,126,150],repair:158,repeat:[28,32,42],replac:150,repo:75,repos:119,repositori:[0,11,123],reput:158,request:11,requir:[92,185],reset:[9,199],reshuffl:144,resourc:180,respawn:158,rest:[49,161],restart:[181,198],restrict:18,retriev:13,role:[135,158],roleplai:[58,106,135,158],roll:88,roller:135,rom:133,room:[37,91,97,115,126,130,132,135,140,156,157,158,276,372],root:514,router:118,rpg:[104,158,341,342,343,344,345,346,347,348,349,350,351,352,353,354],rplanguag:349,rpsystem:[104,348,349,350,351],rss:[192,435],rst:120,rule:[20,158,162,164],run:[3,7,8,22,122,124,190,193,197],runner:8,safe:30,safeti:14,same:[28,96],save:13,schema:9,score:165,screen:25,script:[42,81,95,123,174,257,277,404,405,406,407,408,409,410,411,506],scripthandl:408,search:[19,20,46,67,121,130,142,153,489],searching_cal:30,season:158,secret:177,section:544,secur:[95,181,187,194],see:[6,95,137,198],select:[113,126],self:142,send:[58,62,68,129,151],sent:129,separ:[76,158,161],serial:515,server:[24,40,43,44,61,64,148,165,181,182,191,195,197,198,377,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,507],serverconf:195,serversess:[65,455],serversessionhandl:65,servic:419,session:[44,65,123,126,135,456],sessionhandl:[44,457],set:[1,7,11,20,28,33,75,77,90,124,132,136,139,149,154,158,165,184,186,189,191,192,194,195,196],setpow:165,settings_default:462,settings_mixin:450,setup:[2,75,181,182,185,191,197,198],sever:[96,130,142],share:11,sharedmemorymodel:67,sheet:[3,135],shop:141,shortcut:121,should:158,show:[138,165],shut:199,sidebar:120,signal:[45,458],similar:158,simpl:[3,5,28,33,42,76,128,158,167],simpledoor:[104,109,321,322,323],singl:13,singleton:121,site:[73,123],sitekei:177,sittabl:161,skill:[86,158,159],slot:91,slow:110,slow_exit:[104,324,325,326],soft:69,softcod:[69,134],solut:69,solv:158,some:[39,130,133,151,157,158],someth:158,somewher:122,sort:158,sourc:[7,31,120],space:[17,149],spawn:[41,134],spawner:[41,403],special:158,spell:293,spread:119,spuriou:183,sql:[146,182],sqlite3:182,ssh:[68,194,436],ssl:[191,437],stack:158,staff:158,stanc:58,standard:[72,136],start:[0,75,95,135,138,141,151,154,160,163,166,168,185,193,198,199],stat:173,state:278,statement:143,statu:[158,199],status:158,step:[3,11,75,134,144,156,177,186,188,189,190,192,198],stop:[198,199],storag:[28,42],store:[13,28,41,126,158],string:[33,118,142,476],strip:142,structur:[95,120],studi:97,stuff:[122,144,165],style:[17,53,116],sub:76,subclass:37,subtop:31,succe:158,suit:8,summari:[55,121,143,150,152,153],superus:39,support:[0,68,183],suppress_ga:438,surround:3,swap:48,sword:[150,293],synchron:54,syntax:[0,120,134,199,470],syscommand:227,system:[21,22,31,33,56,58,77,79,86,89,95,98,100,105,106,114,117,137,138,156,157,158,162,164,165,228],tabl:[19,67,120,126],tag:[46,71,91,123,130,153,175,467,508],talk:[111,157],talking_npc:[104,365,366,367],taskhandl:410,tb_basic:308,tb_equip:309,tb_item:310,tb_magic:311,tb_rang:312,teamciti:2,tech:156,technic:[31,77,79,90,108,120,364],teleport:118,telnet:[68,183,191,439],telnet_oob:440,telnet_ssl:441,templat:[2,28,92,137,177,476],templatetag:[519,520],tempmsg:35,temporari:28,term:152,termux:190,test:[5,8,91,122,151,165,229,239,242,245,248,252,258,264,267,269,279,284,287,290,294,297,300,303,306,313,317,320,323,326,328,335,344,347,351,353,360,367,373,378,383,385,442,452,484,497,516,527,533],test_queri:451,test_resourc:490,text2html:491,text:[19,28,32,61,70,71,120,151,169],than:158,thei:158,them:158,theori:142,thi:[137,159],thing:[4,120,133,134,145,149,152,153,154,158],third:180,those:158,throttl:459,through:[3,193],ticker:[47,123],tickerhandl:[47,411],tie:135,time:[19,22,42,69,91,95,136,158],time_format:19,timer:[5,42],timetrac:453,tip:11,titl:[50,53],to_byt:19,to_str:19,togeth:[137,187],tool:[19,24,55,180],traceback:0,track:[11,158],train:174,trait:[104,112,157,352,353,354],traithandl:[112,354],traitproperti:[112,354],transit:118,translat:64,travi:10,treat:14,tree:[113,158,293],tree_select:[104,384,385,386],trick:11,troubleshoot:[11,185,190],ttype:443,tupl:[149,150],turn:[6,114,126,164],turnbattl:[104,157,307,308,309,310,311,312,313],tutori:[0,95,96,97,104,115,125,136,137,138,141,154,155,156,158,160,163,164,165,166,168,169,171,172,173,174,176,178,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373],tutorial_world:[104,368,369,370,371,372,373],tutorialmirror:101,tweet:[173,188],twist:123,twitter:188,two:99,type:[12,13,37,112,354],typeclass:[6,48,74,95,121,123,134,139,143,148,149,153,161,259,325,463,464,465,466,467],under:11,understand:175,ungm:135,unimpl:200,uninstal:[77,155],unit:8,unix:116,unixcommand:[104,268,269,270],unloggedin:230,unmonitor:32,unquel:150,unrepeat:32,updat:[9,11,48,126,149],upgrad:9,upload:194,upstream:6,url:[120,124,137,167,177,509,517,521,529,534],usag:[14,15,27,49,50,79,80,82,86,87,88,92,93,94,99,105,106,107,109,117,118,182,329,343],use:[6,18,47,122,157,158],used:[22,126,293],useful:[22,90,157,180],user:[11,22,53,57,64,133,134,137,194],using:[3,97,149,153],util:[7,17,19,22,24,30,104,121,128,180,260,280,336,374,375,376,377,378,379,380,381,382,383,384,385,386,391,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,510,522,523,524,525,526,527],valid:[33,460],validatorfunc:493,valu:[28,41,158],vanilla:158,variabl:[3,95],variant:161,vehicl:[138,174],verb_conjug:[494,495,496,497],verbatim:120,version:[11,77,120],versu:54,vhost:181,via:158,view:[18,73,137,167,177,178,518,530,535,536,537,538,539,540,541,542,543],viewpoint:58,virtualenv:123,vocabulari:95,voic:97,volum:158,wai:[1,28,118,128,150,151],want:[122,138,158,193],warn:[95,120],weapon:158,weather:[158,176],web:[6,50,51,53,61,68,73,138,148,167,169,177,178,191,194,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543],webclient:[52,444,528,529,530],webclient_ajax:445,webclient_gui:51,webpag:53,webserv:[52,194,461],websit:[53,73,124,531,532,533,534,535,536,537,538,539,540,541,542,543],websocket:[181,187],weight:[140,158],werewolf:146,what:[2,13,56,122,138,142,152,153,154,158,159,193],when:[4,47,126,161],where:[122,147,159,185],whisper:106,who:[22,143],wiki:124,wilder:[104,117,327,328,329],willing:122,window:[64,75,185],wizard:184,word:119,work:[11,22,48,77,95,118,122,137,142,158,174,193],workaround:183,workflow:1,world:[115,138,144,148,151,155,156,158],write:[8,51,62],wss:187,xterm256:[60,175],xymap:[118,337],xymap_legend:338,xyzexit:118,xyzgrid:[104,118,330,331,332,333,334,335,336,337,338,339,340],xyzroom:[118,340],yield:[28,128],you:[0,122,150,154,155,158],your:[0,1,6,8,9,11,12,22,32,37,51,57,62,67,69,90,112,124,130,143,144,148,158,159,177,191,193,194,354],yourself:[144,156],zcoord:118,zone:74}}) \ No newline at end of file +Search.setIndex({docnames:["Coding/Coding-Introduction","Coding/Coding-Overview","Coding/Continuous-Integration","Coding/Debugging","Coding/Flat-API","Coding/Profiling","Coding/Quirks","Coding/Setting-up-PyCharm","Coding/Unit-Testing","Coding/Updating-Your-Game","Coding/Using-Travis","Coding/Version-Control","Components/Accounts","Components/Attributes","Components/Batch-Code-Processor","Components/Batch-Command-Processor","Components/Batch-Processors","Components/Bootstrap-Components-and-Utilities","Components/Channels","Components/Coding-Utils","Components/Command-Sets","Components/Command-System","Components/Commands","Components/Communications","Components/Components-Overview","Components/Connection-Screen","Components/Default-Commands","Components/EvEditor","Components/EvMenu","Components/EvMore","Components/FuncParser","Components/Help-System","Components/Inputfuncs","Components/Locks","Components/MonitorHandler","Components/Msg","Components/Nicks","Components/Objects","Components/Outputfuncs","Components/Permissions","Components/Portal-And-Server","Components/Prototypes","Components/Scripts","Components/Server","Components/Sessions","Components/Signals","Components/Tags","Components/TickerHandler","Components/Typeclasses","Components/Web-API","Components/Web-Admin","Components/Webclient","Components/Webserver","Components/Website","Concepts/Async-Process","Concepts/Banning","Concepts/Bootstrap-&-Evennia","Concepts/Building-Permissions","Concepts/Change-Messages-Per-Receiver","Concepts/Clickable-Links","Concepts/Colors","Concepts/Concepts-Overview","Concepts/Custom-Protocols","Concepts/Guest-Logins","Concepts/Internationalization","Concepts/Messagepath","Concepts/Multisession-modes","Concepts/New-Models","Concepts/OOB","Concepts/Soft-Code","Concepts/Text-Encodings","Concepts/TextTags","Concepts/Using-MUX-as-a-Standard","Concepts/Web-Features","Concepts/Zones","Contribs/Arxcode-installing-help","Contribs/Building-menus","Contribs/Contrib-AWSStorage","Contribs/Contrib-Auditing","Contribs/Contrib-Barter","Contribs/Contrib-Batchprocessor","Contribs/Contrib-Bodyfunctions","Contribs/Contrib-Building-Menu","Contribs/Contrib-Clothing","Contribs/Contrib-Color-Markups","Contribs/Contrib-Cooldowns","Contribs/Contrib-Crafting","Contribs/Contrib-Custom-Gametime","Contribs/Contrib-Dice","Contribs/Contrib-Email-Login","Contribs/Contrib-Evscaperoom","Contribs/Contrib-Extended-Room","Contribs/Contrib-Fieldfill","Contribs/Contrib-Gendersub","Contribs/Contrib-Health-Bar","Contribs/Contrib-Ingame-Python","Contribs/Contrib-Ingame-Python-Tutorial-Dialogue","Contribs/Contrib-Ingame-Python-Tutorial-Elevator","Contribs/Contrib-Mail","Contribs/Contrib-Mapbuilder","Contribs/Contrib-Menu-Login","Contribs/Contrib-Mirror","Contribs/Contrib-Multidescer","Contribs/Contrib-Mux-Comms-Cmds","Contribs/Contrib-Overview","Contribs/Contrib-Puzzles","Contribs/Contrib-RPSystem","Contribs/Contrib-Random-String-Generator","Contribs/Contrib-Red-Button","Contribs/Contrib-Simpledoor","Contribs/Contrib-Slow-Exit","Contribs/Contrib-Talking-Npc","Contribs/Contrib-Traits","Contribs/Contrib-Tree-Select","Contribs/Contrib-Turnbattle","Contribs/Contrib-Tutorial-World","Contribs/Contrib-Unixcommand","Contribs/Contrib-Wilderness","Contribs/Contrib-XYZGrid","Contributing","Contributing-Docs","Evennia-API","Evennia-Introduction","Glossary","Howto/Add-a-wiki-on-your-website","Howto/Building-a-mech-tutorial","Howto/Coding-FAQ","Howto/Command-Cooldown","Howto/Command-Duration","Howto/Command-Prompt","Howto/Coordinates","Howto/Default-Exit-Errors","Howto/Dynamic-In-Game-Map","Howto/Evennia-for-Diku-Users","Howto/Evennia-for-MUSH-Users","Howto/Evennia-for-roleplaying-sessions","Howto/Gametime-Tutorial","Howto/Help-System-Tutorial","Howto/Howto-Overview","Howto/Manually-Configuring-Color","Howto/Mass-and-weight-for-objects","Howto/NPC-shop-Tutorial","Howto/Parsing-commands-tutorial","Howto/Starting/Part1/Adding-Commands","Howto/Starting/Part1/Building-Quickstart","Howto/Starting/Part1/Creating-Things","Howto/Starting/Part1/Django-queries","Howto/Starting/Part1/Evennia-Library-Overview","Howto/Starting/Part1/Gamedir-Overview","Howto/Starting/Part1/Learning-Typeclasses","Howto/Starting/Part1/More-on-Commands","Howto/Starting/Part1/Python-basic-introduction","Howto/Starting/Part1/Python-classes-and-objects","Howto/Starting/Part1/Searching-Things","Howto/Starting/Part1/Starting-Part1","Howto/Starting/Part1/Tutorial-World-Introduction","Howto/Starting/Part2/Game-Planning","Howto/Starting/Part2/Planning-Some-Useful-Contribs","Howto/Starting/Part2/Planning-The-Tutorial-Game","Howto/Starting/Part2/Planning-Where-Do-I-Begin","Howto/Starting/Part2/Starting-Part2","Howto/Starting/Part3/A-Sittable-Object","Howto/Starting/Part3/Implementing-a-game-rule-system","Howto/Starting/Part3/Starting-Part3","Howto/Starting/Part3/Turn-based-Combat-System","Howto/Starting/Part3/Tutorial-for-basic-MUSH-like-game","Howto/Starting/Part4/Starting-Part4","Howto/Starting/Part5/Add-a-simple-new-web-page","Howto/Starting/Part5/Starting-Part5","Howto/Starting/Part5/Web-Tutorial","Howto/Static-In-Game-Map","Howto/Tutorial-Aggressive-NPCs","Howto/Tutorial-NPCs-listening","Howto/Tutorial-Tweeting-Game-Stats","Howto/Tutorial-Vehicles","Howto/Understanding-Color-Tags","Howto/Weather-Tutorial","Howto/Web-Character-Generation","Howto/Web-Character-View-Tutorial","Licensing","Links","Setup/Apache-Config","Setup/Choosing-An-SQL-Server","Setup/Client-Support-Grid","Setup/Evennia-Game-Index","Setup/Extended-Installation","Setup/Grapevine","Setup/HAProxy-Config","Setup/How-to-connect-Evennia-to-Twitter","Setup/IRC","Setup/Installing-on-Android","Setup/Online-Setup","Setup/RSS","Setup/Running-Evennia-in-Docker","Setup/Security","Setup/Server-Conf","Setup/Settings-File","Setup/Setup-Overview","Setup/Setup-Quickstart","Setup/Start-Stop-Reload","Unimplemented","api/evennia","api/evennia-api","api/evennia.accounts","api/evennia.accounts.accounts","api/evennia.accounts.bots","api/evennia.accounts.manager","api/evennia.accounts.models","api/evennia.commands","api/evennia.commands.cmdhandler","api/evennia.commands.cmdparser","api/evennia.commands.cmdset","api/evennia.commands.cmdsethandler","api/evennia.commands.command","api/evennia.commands.default","api/evennia.commands.default.account","api/evennia.commands.default.admin","api/evennia.commands.default.batchprocess","api/evennia.commands.default.building","api/evennia.commands.default.cmdset_account","api/evennia.commands.default.cmdset_character","api/evennia.commands.default.cmdset_session","api/evennia.commands.default.cmdset_unloggedin","api/evennia.commands.default.comms","api/evennia.commands.default.general","api/evennia.commands.default.help","api/evennia.commands.default.muxcommand","api/evennia.commands.default.syscommands","api/evennia.commands.default.system","api/evennia.commands.default.tests","api/evennia.commands.default.unloggedin","api/evennia.comms","api/evennia.comms.comms","api/evennia.comms.managers","api/evennia.comms.models","api/evennia.contrib","api/evennia.contrib.base_systems","api/evennia.contrib.base_systems.awsstorage","api/evennia.contrib.base_systems.awsstorage.aws_s3_cdn","api/evennia.contrib.base_systems.awsstorage.tests","api/evennia.contrib.base_systems.building_menu","api/evennia.contrib.base_systems.building_menu.building_menu","api/evennia.contrib.base_systems.building_menu.tests","api/evennia.contrib.base_systems.color_markups","api/evennia.contrib.base_systems.color_markups.color_markups","api/evennia.contrib.base_systems.color_markups.tests","api/evennia.contrib.base_systems.custom_gametime","api/evennia.contrib.base_systems.custom_gametime.custom_gametime","api/evennia.contrib.base_systems.custom_gametime.tests","api/evennia.contrib.base_systems.email_login","api/evennia.contrib.base_systems.email_login.connection_screens","api/evennia.contrib.base_systems.email_login.email_login","api/evennia.contrib.base_systems.email_login.tests","api/evennia.contrib.base_systems.ingame_python","api/evennia.contrib.base_systems.ingame_python.callbackhandler","api/evennia.contrib.base_systems.ingame_python.commands","api/evennia.contrib.base_systems.ingame_python.eventfuncs","api/evennia.contrib.base_systems.ingame_python.scripts","api/evennia.contrib.base_systems.ingame_python.tests","api/evennia.contrib.base_systems.ingame_python.typeclasses","api/evennia.contrib.base_systems.ingame_python.utils","api/evennia.contrib.base_systems.menu_login","api/evennia.contrib.base_systems.menu_login.connection_screens","api/evennia.contrib.base_systems.menu_login.menu_login","api/evennia.contrib.base_systems.menu_login.tests","api/evennia.contrib.base_systems.mux_comms_cmds","api/evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds","api/evennia.contrib.base_systems.mux_comms_cmds.tests","api/evennia.contrib.base_systems.unixcommand","api/evennia.contrib.base_systems.unixcommand.tests","api/evennia.contrib.base_systems.unixcommand.unixcommand","api/evennia.contrib.full_systems","api/evennia.contrib.full_systems.evscaperoom","api/evennia.contrib.full_systems.evscaperoom.commands","api/evennia.contrib.full_systems.evscaperoom.menu","api/evennia.contrib.full_systems.evscaperoom.objects","api/evennia.contrib.full_systems.evscaperoom.room","api/evennia.contrib.full_systems.evscaperoom.scripts","api/evennia.contrib.full_systems.evscaperoom.state","api/evennia.contrib.full_systems.evscaperoom.tests","api/evennia.contrib.full_systems.evscaperoom.utils","api/evennia.contrib.game_systems","api/evennia.contrib.game_systems.barter","api/evennia.contrib.game_systems.barter.barter","api/evennia.contrib.game_systems.barter.tests","api/evennia.contrib.game_systems.clothing","api/evennia.contrib.game_systems.clothing.clothing","api/evennia.contrib.game_systems.clothing.tests","api/evennia.contrib.game_systems.cooldowns","api/evennia.contrib.game_systems.cooldowns.cooldowns","api/evennia.contrib.game_systems.cooldowns.tests","api/evennia.contrib.game_systems.crafting","api/evennia.contrib.game_systems.crafting.crafting","api/evennia.contrib.game_systems.crafting.example_recipes","api/evennia.contrib.game_systems.crafting.tests","api/evennia.contrib.game_systems.gendersub","api/evennia.contrib.game_systems.gendersub.gendersub","api/evennia.contrib.game_systems.gendersub.tests","api/evennia.contrib.game_systems.mail","api/evennia.contrib.game_systems.mail.mail","api/evennia.contrib.game_systems.mail.tests","api/evennia.contrib.game_systems.multidescer","api/evennia.contrib.game_systems.multidescer.multidescer","api/evennia.contrib.game_systems.multidescer.tests","api/evennia.contrib.game_systems.puzzles","api/evennia.contrib.game_systems.puzzles.puzzles","api/evennia.contrib.game_systems.puzzles.tests","api/evennia.contrib.game_systems.turnbattle","api/evennia.contrib.game_systems.turnbattle.tb_basic","api/evennia.contrib.game_systems.turnbattle.tb_equip","api/evennia.contrib.game_systems.turnbattle.tb_items","api/evennia.contrib.game_systems.turnbattle.tb_magic","api/evennia.contrib.game_systems.turnbattle.tb_range","api/evennia.contrib.game_systems.turnbattle.tests","api/evennia.contrib.grid","api/evennia.contrib.grid.extended_room","api/evennia.contrib.grid.extended_room.extended_room","api/evennia.contrib.grid.extended_room.tests","api/evennia.contrib.grid.mapbuilder","api/evennia.contrib.grid.mapbuilder.mapbuilder","api/evennia.contrib.grid.mapbuilder.tests","api/evennia.contrib.grid.simpledoor","api/evennia.contrib.grid.simpledoor.simpledoor","api/evennia.contrib.grid.simpledoor.tests","api/evennia.contrib.grid.slow_exit","api/evennia.contrib.grid.slow_exit.slow_exit","api/evennia.contrib.grid.slow_exit.tests","api/evennia.contrib.grid.wilderness","api/evennia.contrib.grid.wilderness.tests","api/evennia.contrib.grid.wilderness.wilderness","api/evennia.contrib.grid.xyzgrid","api/evennia.contrib.grid.xyzgrid.commands","api/evennia.contrib.grid.xyzgrid.example","api/evennia.contrib.grid.xyzgrid.launchcmd","api/evennia.contrib.grid.xyzgrid.prototypes","api/evennia.contrib.grid.xyzgrid.tests","api/evennia.contrib.grid.xyzgrid.utils","api/evennia.contrib.grid.xyzgrid.xymap","api/evennia.contrib.grid.xyzgrid.xymap_legend","api/evennia.contrib.grid.xyzgrid.xyzgrid","api/evennia.contrib.grid.xyzgrid.xyzroom","api/evennia.contrib.rpg","api/evennia.contrib.rpg.dice","api/evennia.contrib.rpg.dice.dice","api/evennia.contrib.rpg.dice.tests","api/evennia.contrib.rpg.health_bar","api/evennia.contrib.rpg.health_bar.health_bar","api/evennia.contrib.rpg.health_bar.tests","api/evennia.contrib.rpg.rpsystem","api/evennia.contrib.rpg.rpsystem.rplanguage","api/evennia.contrib.rpg.rpsystem.rpsystem","api/evennia.contrib.rpg.rpsystem.tests","api/evennia.contrib.rpg.traits","api/evennia.contrib.rpg.traits.tests","api/evennia.contrib.rpg.traits.traits","api/evennia.contrib.tutorials","api/evennia.contrib.tutorials.batchprocessor","api/evennia.contrib.tutorials.batchprocessor.example_batch_code","api/evennia.contrib.tutorials.bodyfunctions","api/evennia.contrib.tutorials.bodyfunctions.bodyfunctions","api/evennia.contrib.tutorials.bodyfunctions.tests","api/evennia.contrib.tutorials.mirror","api/evennia.contrib.tutorials.mirror.mirror","api/evennia.contrib.tutorials.red_button","api/evennia.contrib.tutorials.red_button.red_button","api/evennia.contrib.tutorials.talking_npc","api/evennia.contrib.tutorials.talking_npc.talking_npc","api/evennia.contrib.tutorials.talking_npc.tests","api/evennia.contrib.tutorials.tutorial_world","api/evennia.contrib.tutorials.tutorial_world.intro_menu","api/evennia.contrib.tutorials.tutorial_world.mob","api/evennia.contrib.tutorials.tutorial_world.objects","api/evennia.contrib.tutorials.tutorial_world.rooms","api/evennia.contrib.tutorials.tutorial_world.tests","api/evennia.contrib.utils","api/evennia.contrib.utils.auditing","api/evennia.contrib.utils.auditing.outputs","api/evennia.contrib.utils.auditing.server","api/evennia.contrib.utils.auditing.tests","api/evennia.contrib.utils.fieldfill","api/evennia.contrib.utils.fieldfill.fieldfill","api/evennia.contrib.utils.random_string_generator","api/evennia.contrib.utils.random_string_generator.random_string_generator","api/evennia.contrib.utils.random_string_generator.tests","api/evennia.contrib.utils.tree_select","api/evennia.contrib.utils.tree_select.tests","api/evennia.contrib.utils.tree_select.tree_select","api/evennia.help","api/evennia.help.filehelp","api/evennia.help.manager","api/evennia.help.models","api/evennia.help.utils","api/evennia.locks","api/evennia.locks.lockfuncs","api/evennia.locks.lockhandler","api/evennia.objects","api/evennia.objects.manager","api/evennia.objects.models","api/evennia.objects.objects","api/evennia.prototypes","api/evennia.prototypes.menus","api/evennia.prototypes.protfuncs","api/evennia.prototypes.prototypes","api/evennia.prototypes.spawner","api/evennia.scripts","api/evennia.scripts.manager","api/evennia.scripts.models","api/evennia.scripts.monitorhandler","api/evennia.scripts.scripthandler","api/evennia.scripts.scripts","api/evennia.scripts.taskhandler","api/evennia.scripts.tickerhandler","api/evennia.server","api/evennia.server.amp_client","api/evennia.server.connection_wizard","api/evennia.server.deprecations","api/evennia.server.evennia_launcher","api/evennia.server.game_index_client","api/evennia.server.game_index_client.client","api/evennia.server.game_index_client.service","api/evennia.server.initial_setup","api/evennia.server.inputfuncs","api/evennia.server.manager","api/evennia.server.models","api/evennia.server.portal","api/evennia.server.portal.amp","api/evennia.server.portal.amp_server","api/evennia.server.portal.grapevine","api/evennia.server.portal.irc","api/evennia.server.portal.mccp","api/evennia.server.portal.mssp","api/evennia.server.portal.mxp","api/evennia.server.portal.naws","api/evennia.server.portal.portal","api/evennia.server.portal.portalsessionhandler","api/evennia.server.portal.rss","api/evennia.server.portal.ssh","api/evennia.server.portal.ssl","api/evennia.server.portal.suppress_ga","api/evennia.server.portal.telnet","api/evennia.server.portal.telnet_oob","api/evennia.server.portal.telnet_ssl","api/evennia.server.portal.tests","api/evennia.server.portal.ttype","api/evennia.server.portal.webclient","api/evennia.server.portal.webclient_ajax","api/evennia.server.profiling","api/evennia.server.profiling.dummyrunner","api/evennia.server.profiling.dummyrunner_settings","api/evennia.server.profiling.memplot","api/evennia.server.profiling.settings_mixin","api/evennia.server.profiling.test_queries","api/evennia.server.profiling.tests","api/evennia.server.profiling.timetrace","api/evennia.server.server","api/evennia.server.serversession","api/evennia.server.session","api/evennia.server.sessionhandler","api/evennia.server.signals","api/evennia.server.throttle","api/evennia.server.validators","api/evennia.server.webserver","api/evennia.settings_default","api/evennia.typeclasses","api/evennia.typeclasses.attributes","api/evennia.typeclasses.managers","api/evennia.typeclasses.models","api/evennia.typeclasses.tags","api/evennia.utils","api/evennia.utils.ansi","api/evennia.utils.batchprocessors","api/evennia.utils.containers","api/evennia.utils.create","api/evennia.utils.dbserialize","api/evennia.utils.eveditor","api/evennia.utils.evform","api/evennia.utils.evmenu","api/evennia.utils.evmore","api/evennia.utils.evtable","api/evennia.utils.funcparser","api/evennia.utils.gametime","api/evennia.utils.idmapper","api/evennia.utils.idmapper.manager","api/evennia.utils.idmapper.models","api/evennia.utils.idmapper.tests","api/evennia.utils.logger","api/evennia.utils.optionclasses","api/evennia.utils.optionhandler","api/evennia.utils.picklefield","api/evennia.utils.search","api/evennia.utils.test_resources","api/evennia.utils.text2html","api/evennia.utils.utils","api/evennia.utils.validatorfuncs","api/evennia.utils.verb_conjugation","api/evennia.utils.verb_conjugation.conjugate","api/evennia.utils.verb_conjugation.pronouns","api/evennia.utils.verb_conjugation.tests","api/evennia.web","api/evennia.web.admin","api/evennia.web.admin.accounts","api/evennia.web.admin.attributes","api/evennia.web.admin.comms","api/evennia.web.admin.frontpage","api/evennia.web.admin.help","api/evennia.web.admin.objects","api/evennia.web.admin.scripts","api/evennia.web.admin.server","api/evennia.web.admin.tags","api/evennia.web.admin.urls","api/evennia.web.admin.utils","api/evennia.web.api","api/evennia.web.api.filters","api/evennia.web.api.permissions","api/evennia.web.api.root","api/evennia.web.api.serializers","api/evennia.web.api.tests","api/evennia.web.api.urls","api/evennia.web.api.views","api/evennia.web.templatetags","api/evennia.web.templatetags.addclass","api/evennia.web.urls","api/evennia.web.utils","api/evennia.web.utils.adminsite","api/evennia.web.utils.backends","api/evennia.web.utils.general_context","api/evennia.web.utils.middleware","api/evennia.web.utils.tests","api/evennia.web.webclient","api/evennia.web.webclient.urls","api/evennia.web.webclient.views","api/evennia.web.website","api/evennia.web.website.forms","api/evennia.web.website.tests","api/evennia.web.website.urls","api/evennia.web.website.views","api/evennia.web.website.views.accounts","api/evennia.web.website.views.channels","api/evennia.web.website.views.characters","api/evennia.web.website.views.errors","api/evennia.web.website.views.help","api/evennia.web.website.views.index","api/evennia.web.website.views.mixins","api/evennia.web.website.views.objects","index","toc"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":3,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":2,"sphinx.domains.rst":2,"sphinx.domains.std":1,"sphinx.ext.todo":2,"sphinx.ext.viewcode":1,sphinx:56},filenames:["Coding/Coding-Introduction.md","Coding/Coding-Overview.md","Coding/Continuous-Integration.md","Coding/Debugging.md","Coding/Flat-API.md","Coding/Profiling.md","Coding/Quirks.md","Coding/Setting-up-PyCharm.md","Coding/Unit-Testing.md","Coding/Updating-Your-Game.md","Coding/Using-Travis.md","Coding/Version-Control.md","Components/Accounts.md","Components/Attributes.md","Components/Batch-Code-Processor.md","Components/Batch-Command-Processor.md","Components/Batch-Processors.md","Components/Bootstrap-Components-and-Utilities.md","Components/Channels.md","Components/Coding-Utils.md","Components/Command-Sets.md","Components/Command-System.md","Components/Commands.md","Components/Communications.md","Components/Components-Overview.md","Components/Connection-Screen.md","Components/Default-Commands.md","Components/EvEditor.md","Components/EvMenu.md","Components/EvMore.md","Components/FuncParser.md","Components/Help-System.md","Components/Inputfuncs.md","Components/Locks.md","Components/MonitorHandler.md","Components/Msg.md","Components/Nicks.md","Components/Objects.md","Components/Outputfuncs.md","Components/Permissions.md","Components/Portal-And-Server.md","Components/Prototypes.md","Components/Scripts.md","Components/Server.md","Components/Sessions.md","Components/Signals.md","Components/Tags.md","Components/TickerHandler.md","Components/Typeclasses.md","Components/Web-API.md","Components/Web-Admin.md","Components/Webclient.md","Components/Webserver.md","Components/Website.md","Concepts/Async-Process.md","Concepts/Banning.md","Concepts/Bootstrap-&-Evennia.md","Concepts/Building-Permissions.md","Concepts/Change-Messages-Per-Receiver.md","Concepts/Clickable-Links.md","Concepts/Colors.md","Concepts/Concepts-Overview.md","Concepts/Custom-Protocols.md","Concepts/Guest-Logins.md","Concepts/Internationalization.md","Concepts/Messagepath.md","Concepts/Multisession-modes.md","Concepts/New-Models.md","Concepts/OOB.md","Concepts/Soft-Code.md","Concepts/Text-Encodings.md","Concepts/TextTags.md","Concepts/Using-MUX-as-a-Standard.md","Concepts/Web-Features.md","Concepts/Zones.md","Contribs/Arxcode-installing-help.md","Contribs/Building-menus.md","Contribs/Contrib-AWSStorage.md","Contribs/Contrib-Auditing.md","Contribs/Contrib-Barter.md","Contribs/Contrib-Batchprocessor.md","Contribs/Contrib-Bodyfunctions.md","Contribs/Contrib-Building-Menu.md","Contribs/Contrib-Clothing.md","Contribs/Contrib-Color-Markups.md","Contribs/Contrib-Cooldowns.md","Contribs/Contrib-Crafting.md","Contribs/Contrib-Custom-Gametime.md","Contribs/Contrib-Dice.md","Contribs/Contrib-Email-Login.md","Contribs/Contrib-Evscaperoom.md","Contribs/Contrib-Extended-Room.md","Contribs/Contrib-Fieldfill.md","Contribs/Contrib-Gendersub.md","Contribs/Contrib-Health-Bar.md","Contribs/Contrib-Ingame-Python.md","Contribs/Contrib-Ingame-Python-Tutorial-Dialogue.md","Contribs/Contrib-Ingame-Python-Tutorial-Elevator.md","Contribs/Contrib-Mail.md","Contribs/Contrib-Mapbuilder.md","Contribs/Contrib-Menu-Login.md","Contribs/Contrib-Mirror.md","Contribs/Contrib-Multidescer.md","Contribs/Contrib-Mux-Comms-Cmds.md","Contribs/Contrib-Overview.md","Contribs/Contrib-Puzzles.md","Contribs/Contrib-RPSystem.md","Contribs/Contrib-Random-String-Generator.md","Contribs/Contrib-Red-Button.md","Contribs/Contrib-Simpledoor.md","Contribs/Contrib-Slow-Exit.md","Contribs/Contrib-Talking-Npc.md","Contribs/Contrib-Traits.md","Contribs/Contrib-Tree-Select.md","Contribs/Contrib-Turnbattle.md","Contribs/Contrib-Tutorial-World.md","Contribs/Contrib-Unixcommand.md","Contribs/Contrib-Wilderness.md","Contribs/Contrib-XYZGrid.md","Contributing.md","Contributing-Docs.md","Evennia-API.md","Evennia-Introduction.md","Glossary.md","Howto/Add-a-wiki-on-your-website.md","Howto/Building-a-mech-tutorial.md","Howto/Coding-FAQ.md","Howto/Command-Cooldown.md","Howto/Command-Duration.md","Howto/Command-Prompt.md","Howto/Coordinates.md","Howto/Default-Exit-Errors.md","Howto/Dynamic-In-Game-Map.md","Howto/Evennia-for-Diku-Users.md","Howto/Evennia-for-MUSH-Users.md","Howto/Evennia-for-roleplaying-sessions.md","Howto/Gametime-Tutorial.md","Howto/Help-System-Tutorial.md","Howto/Howto-Overview.md","Howto/Manually-Configuring-Color.md","Howto/Mass-and-weight-for-objects.md","Howto/NPC-shop-Tutorial.md","Howto/Parsing-commands-tutorial.md","Howto/Starting/Part1/Adding-Commands.md","Howto/Starting/Part1/Building-Quickstart.md","Howto/Starting/Part1/Creating-Things.md","Howto/Starting/Part1/Django-queries.md","Howto/Starting/Part1/Evennia-Library-Overview.md","Howto/Starting/Part1/Gamedir-Overview.md","Howto/Starting/Part1/Learning-Typeclasses.md","Howto/Starting/Part1/More-on-Commands.md","Howto/Starting/Part1/Python-basic-introduction.md","Howto/Starting/Part1/Python-classes-and-objects.md","Howto/Starting/Part1/Searching-Things.md","Howto/Starting/Part1/Starting-Part1.md","Howto/Starting/Part1/Tutorial-World-Introduction.md","Howto/Starting/Part2/Game-Planning.md","Howto/Starting/Part2/Planning-Some-Useful-Contribs.md","Howto/Starting/Part2/Planning-The-Tutorial-Game.md","Howto/Starting/Part2/Planning-Where-Do-I-Begin.md","Howto/Starting/Part2/Starting-Part2.md","Howto/Starting/Part3/A-Sittable-Object.md","Howto/Starting/Part3/Implementing-a-game-rule-system.md","Howto/Starting/Part3/Starting-Part3.md","Howto/Starting/Part3/Turn-based-Combat-System.md","Howto/Starting/Part3/Tutorial-for-basic-MUSH-like-game.md","Howto/Starting/Part4/Starting-Part4.md","Howto/Starting/Part5/Add-a-simple-new-web-page.md","Howto/Starting/Part5/Starting-Part5.md","Howto/Starting/Part5/Web-Tutorial.md","Howto/Static-In-Game-Map.md","Howto/Tutorial-Aggressive-NPCs.md","Howto/Tutorial-NPCs-listening.md","Howto/Tutorial-Tweeting-Game-Stats.md","Howto/Tutorial-Vehicles.md","Howto/Understanding-Color-Tags.md","Howto/Weather-Tutorial.md","Howto/Web-Character-Generation.md","Howto/Web-Character-View-Tutorial.md","Licensing.md","Links.md","Setup/Apache-Config.md","Setup/Choosing-An-SQL-Server.md","Setup/Client-Support-Grid.md","Setup/Evennia-Game-Index.md","Setup/Extended-Installation.md","Setup/Grapevine.md","Setup/HAProxy-Config.md","Setup/How-to-connect-Evennia-to-Twitter.md","Setup/IRC.md","Setup/Installing-on-Android.md","Setup/Online-Setup.md","Setup/RSS.md","Setup/Running-Evennia-in-Docker.md","Setup/Security.md","Setup/Server-Conf.md","Setup/Settings-File.md","Setup/Setup-Overview.md","Setup/Setup-Quickstart.md","Setup/Start-Stop-Reload.md","Unimplemented.md","api/evennia.md","api/evennia-api.md","api/evennia.accounts.md","api/evennia.accounts.accounts.md","api/evennia.accounts.bots.md","api/evennia.accounts.manager.md","api/evennia.accounts.models.md","api/evennia.commands.md","api/evennia.commands.cmdhandler.md","api/evennia.commands.cmdparser.md","api/evennia.commands.cmdset.md","api/evennia.commands.cmdsethandler.md","api/evennia.commands.command.md","api/evennia.commands.default.md","api/evennia.commands.default.account.md","api/evennia.commands.default.admin.md","api/evennia.commands.default.batchprocess.md","api/evennia.commands.default.building.md","api/evennia.commands.default.cmdset_account.md","api/evennia.commands.default.cmdset_character.md","api/evennia.commands.default.cmdset_session.md","api/evennia.commands.default.cmdset_unloggedin.md","api/evennia.commands.default.comms.md","api/evennia.commands.default.general.md","api/evennia.commands.default.help.md","api/evennia.commands.default.muxcommand.md","api/evennia.commands.default.syscommands.md","api/evennia.commands.default.system.md","api/evennia.commands.default.tests.md","api/evennia.commands.default.unloggedin.md","api/evennia.comms.md","api/evennia.comms.comms.md","api/evennia.comms.managers.md","api/evennia.comms.models.md","api/evennia.contrib.md","api/evennia.contrib.base_systems.md","api/evennia.contrib.base_systems.awsstorage.md","api/evennia.contrib.base_systems.awsstorage.aws_s3_cdn.md","api/evennia.contrib.base_systems.awsstorage.tests.md","api/evennia.contrib.base_systems.building_menu.md","api/evennia.contrib.base_systems.building_menu.building_menu.md","api/evennia.contrib.base_systems.building_menu.tests.md","api/evennia.contrib.base_systems.color_markups.md","api/evennia.contrib.base_systems.color_markups.color_markups.md","api/evennia.contrib.base_systems.color_markups.tests.md","api/evennia.contrib.base_systems.custom_gametime.md","api/evennia.contrib.base_systems.custom_gametime.custom_gametime.md","api/evennia.contrib.base_systems.custom_gametime.tests.md","api/evennia.contrib.base_systems.email_login.md","api/evennia.contrib.base_systems.email_login.connection_screens.md","api/evennia.contrib.base_systems.email_login.email_login.md","api/evennia.contrib.base_systems.email_login.tests.md","api/evennia.contrib.base_systems.ingame_python.md","api/evennia.contrib.base_systems.ingame_python.callbackhandler.md","api/evennia.contrib.base_systems.ingame_python.commands.md","api/evennia.contrib.base_systems.ingame_python.eventfuncs.md","api/evennia.contrib.base_systems.ingame_python.scripts.md","api/evennia.contrib.base_systems.ingame_python.tests.md","api/evennia.contrib.base_systems.ingame_python.typeclasses.md","api/evennia.contrib.base_systems.ingame_python.utils.md","api/evennia.contrib.base_systems.menu_login.md","api/evennia.contrib.base_systems.menu_login.connection_screens.md","api/evennia.contrib.base_systems.menu_login.menu_login.md","api/evennia.contrib.base_systems.menu_login.tests.md","api/evennia.contrib.base_systems.mux_comms_cmds.md","api/evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.md","api/evennia.contrib.base_systems.mux_comms_cmds.tests.md","api/evennia.contrib.base_systems.unixcommand.md","api/evennia.contrib.base_systems.unixcommand.tests.md","api/evennia.contrib.base_systems.unixcommand.unixcommand.md","api/evennia.contrib.full_systems.md","api/evennia.contrib.full_systems.evscaperoom.md","api/evennia.contrib.full_systems.evscaperoom.commands.md","api/evennia.contrib.full_systems.evscaperoom.menu.md","api/evennia.contrib.full_systems.evscaperoom.objects.md","api/evennia.contrib.full_systems.evscaperoom.room.md","api/evennia.contrib.full_systems.evscaperoom.scripts.md","api/evennia.contrib.full_systems.evscaperoom.state.md","api/evennia.contrib.full_systems.evscaperoom.tests.md","api/evennia.contrib.full_systems.evscaperoom.utils.md","api/evennia.contrib.game_systems.md","api/evennia.contrib.game_systems.barter.md","api/evennia.contrib.game_systems.barter.barter.md","api/evennia.contrib.game_systems.barter.tests.md","api/evennia.contrib.game_systems.clothing.md","api/evennia.contrib.game_systems.clothing.clothing.md","api/evennia.contrib.game_systems.clothing.tests.md","api/evennia.contrib.game_systems.cooldowns.md","api/evennia.contrib.game_systems.cooldowns.cooldowns.md","api/evennia.contrib.game_systems.cooldowns.tests.md","api/evennia.contrib.game_systems.crafting.md","api/evennia.contrib.game_systems.crafting.crafting.md","api/evennia.contrib.game_systems.crafting.example_recipes.md","api/evennia.contrib.game_systems.crafting.tests.md","api/evennia.contrib.game_systems.gendersub.md","api/evennia.contrib.game_systems.gendersub.gendersub.md","api/evennia.contrib.game_systems.gendersub.tests.md","api/evennia.contrib.game_systems.mail.md","api/evennia.contrib.game_systems.mail.mail.md","api/evennia.contrib.game_systems.mail.tests.md","api/evennia.contrib.game_systems.multidescer.md","api/evennia.contrib.game_systems.multidescer.multidescer.md","api/evennia.contrib.game_systems.multidescer.tests.md","api/evennia.contrib.game_systems.puzzles.md","api/evennia.contrib.game_systems.puzzles.puzzles.md","api/evennia.contrib.game_systems.puzzles.tests.md","api/evennia.contrib.game_systems.turnbattle.md","api/evennia.contrib.game_systems.turnbattle.tb_basic.md","api/evennia.contrib.game_systems.turnbattle.tb_equip.md","api/evennia.contrib.game_systems.turnbattle.tb_items.md","api/evennia.contrib.game_systems.turnbattle.tb_magic.md","api/evennia.contrib.game_systems.turnbattle.tb_range.md","api/evennia.contrib.game_systems.turnbattle.tests.md","api/evennia.contrib.grid.md","api/evennia.contrib.grid.extended_room.md","api/evennia.contrib.grid.extended_room.extended_room.md","api/evennia.contrib.grid.extended_room.tests.md","api/evennia.contrib.grid.mapbuilder.md","api/evennia.contrib.grid.mapbuilder.mapbuilder.md","api/evennia.contrib.grid.mapbuilder.tests.md","api/evennia.contrib.grid.simpledoor.md","api/evennia.contrib.grid.simpledoor.simpledoor.md","api/evennia.contrib.grid.simpledoor.tests.md","api/evennia.contrib.grid.slow_exit.md","api/evennia.contrib.grid.slow_exit.slow_exit.md","api/evennia.contrib.grid.slow_exit.tests.md","api/evennia.contrib.grid.wilderness.md","api/evennia.contrib.grid.wilderness.tests.md","api/evennia.contrib.grid.wilderness.wilderness.md","api/evennia.contrib.grid.xyzgrid.md","api/evennia.contrib.grid.xyzgrid.commands.md","api/evennia.contrib.grid.xyzgrid.example.md","api/evennia.contrib.grid.xyzgrid.launchcmd.md","api/evennia.contrib.grid.xyzgrid.prototypes.md","api/evennia.contrib.grid.xyzgrid.tests.md","api/evennia.contrib.grid.xyzgrid.utils.md","api/evennia.contrib.grid.xyzgrid.xymap.md","api/evennia.contrib.grid.xyzgrid.xymap_legend.md","api/evennia.contrib.grid.xyzgrid.xyzgrid.md","api/evennia.contrib.grid.xyzgrid.xyzroom.md","api/evennia.contrib.rpg.md","api/evennia.contrib.rpg.dice.md","api/evennia.contrib.rpg.dice.dice.md","api/evennia.contrib.rpg.dice.tests.md","api/evennia.contrib.rpg.health_bar.md","api/evennia.contrib.rpg.health_bar.health_bar.md","api/evennia.contrib.rpg.health_bar.tests.md","api/evennia.contrib.rpg.rpsystem.md","api/evennia.contrib.rpg.rpsystem.rplanguage.md","api/evennia.contrib.rpg.rpsystem.rpsystem.md","api/evennia.contrib.rpg.rpsystem.tests.md","api/evennia.contrib.rpg.traits.md","api/evennia.contrib.rpg.traits.tests.md","api/evennia.contrib.rpg.traits.traits.md","api/evennia.contrib.tutorials.md","api/evennia.contrib.tutorials.batchprocessor.md","api/evennia.contrib.tutorials.batchprocessor.example_batch_code.md","api/evennia.contrib.tutorials.bodyfunctions.md","api/evennia.contrib.tutorials.bodyfunctions.bodyfunctions.md","api/evennia.contrib.tutorials.bodyfunctions.tests.md","api/evennia.contrib.tutorials.mirror.md","api/evennia.contrib.tutorials.mirror.mirror.md","api/evennia.contrib.tutorials.red_button.md","api/evennia.contrib.tutorials.red_button.red_button.md","api/evennia.contrib.tutorials.talking_npc.md","api/evennia.contrib.tutorials.talking_npc.talking_npc.md","api/evennia.contrib.tutorials.talking_npc.tests.md","api/evennia.contrib.tutorials.tutorial_world.md","api/evennia.contrib.tutorials.tutorial_world.intro_menu.md","api/evennia.contrib.tutorials.tutorial_world.mob.md","api/evennia.contrib.tutorials.tutorial_world.objects.md","api/evennia.contrib.tutorials.tutorial_world.rooms.md","api/evennia.contrib.tutorials.tutorial_world.tests.md","api/evennia.contrib.utils.md","api/evennia.contrib.utils.auditing.md","api/evennia.contrib.utils.auditing.outputs.md","api/evennia.contrib.utils.auditing.server.md","api/evennia.contrib.utils.auditing.tests.md","api/evennia.contrib.utils.fieldfill.md","api/evennia.contrib.utils.fieldfill.fieldfill.md","api/evennia.contrib.utils.random_string_generator.md","api/evennia.contrib.utils.random_string_generator.random_string_generator.md","api/evennia.contrib.utils.random_string_generator.tests.md","api/evennia.contrib.utils.tree_select.md","api/evennia.contrib.utils.tree_select.tests.md","api/evennia.contrib.utils.tree_select.tree_select.md","api/evennia.help.md","api/evennia.help.filehelp.md","api/evennia.help.manager.md","api/evennia.help.models.md","api/evennia.help.utils.md","api/evennia.locks.md","api/evennia.locks.lockfuncs.md","api/evennia.locks.lockhandler.md","api/evennia.objects.md","api/evennia.objects.manager.md","api/evennia.objects.models.md","api/evennia.objects.objects.md","api/evennia.prototypes.md","api/evennia.prototypes.menus.md","api/evennia.prototypes.protfuncs.md","api/evennia.prototypes.prototypes.md","api/evennia.prototypes.spawner.md","api/evennia.scripts.md","api/evennia.scripts.manager.md","api/evennia.scripts.models.md","api/evennia.scripts.monitorhandler.md","api/evennia.scripts.scripthandler.md","api/evennia.scripts.scripts.md","api/evennia.scripts.taskhandler.md","api/evennia.scripts.tickerhandler.md","api/evennia.server.md","api/evennia.server.amp_client.md","api/evennia.server.connection_wizard.md","api/evennia.server.deprecations.md","api/evennia.server.evennia_launcher.md","api/evennia.server.game_index_client.md","api/evennia.server.game_index_client.client.md","api/evennia.server.game_index_client.service.md","api/evennia.server.initial_setup.md","api/evennia.server.inputfuncs.md","api/evennia.server.manager.md","api/evennia.server.models.md","api/evennia.server.portal.md","api/evennia.server.portal.amp.md","api/evennia.server.portal.amp_server.md","api/evennia.server.portal.grapevine.md","api/evennia.server.portal.irc.md","api/evennia.server.portal.mccp.md","api/evennia.server.portal.mssp.md","api/evennia.server.portal.mxp.md","api/evennia.server.portal.naws.md","api/evennia.server.portal.portal.md","api/evennia.server.portal.portalsessionhandler.md","api/evennia.server.portal.rss.md","api/evennia.server.portal.ssh.md","api/evennia.server.portal.ssl.md","api/evennia.server.portal.suppress_ga.md","api/evennia.server.portal.telnet.md","api/evennia.server.portal.telnet_oob.md","api/evennia.server.portal.telnet_ssl.md","api/evennia.server.portal.tests.md","api/evennia.server.portal.ttype.md","api/evennia.server.portal.webclient.md","api/evennia.server.portal.webclient_ajax.md","api/evennia.server.profiling.md","api/evennia.server.profiling.dummyrunner.md","api/evennia.server.profiling.dummyrunner_settings.md","api/evennia.server.profiling.memplot.md","api/evennia.server.profiling.settings_mixin.md","api/evennia.server.profiling.test_queries.md","api/evennia.server.profiling.tests.md","api/evennia.server.profiling.timetrace.md","api/evennia.server.server.md","api/evennia.server.serversession.md","api/evennia.server.session.md","api/evennia.server.sessionhandler.md","api/evennia.server.signals.md","api/evennia.server.throttle.md","api/evennia.server.validators.md","api/evennia.server.webserver.md","api/evennia.settings_default.md","api/evennia.typeclasses.md","api/evennia.typeclasses.attributes.md","api/evennia.typeclasses.managers.md","api/evennia.typeclasses.models.md","api/evennia.typeclasses.tags.md","api/evennia.utils.md","api/evennia.utils.ansi.md","api/evennia.utils.batchprocessors.md","api/evennia.utils.containers.md","api/evennia.utils.create.md","api/evennia.utils.dbserialize.md","api/evennia.utils.eveditor.md","api/evennia.utils.evform.md","api/evennia.utils.evmenu.md","api/evennia.utils.evmore.md","api/evennia.utils.evtable.md","api/evennia.utils.funcparser.md","api/evennia.utils.gametime.md","api/evennia.utils.idmapper.md","api/evennia.utils.idmapper.manager.md","api/evennia.utils.idmapper.models.md","api/evennia.utils.idmapper.tests.md","api/evennia.utils.logger.md","api/evennia.utils.optionclasses.md","api/evennia.utils.optionhandler.md","api/evennia.utils.picklefield.md","api/evennia.utils.search.md","api/evennia.utils.test_resources.md","api/evennia.utils.text2html.md","api/evennia.utils.utils.md","api/evennia.utils.validatorfuncs.md","api/evennia.utils.verb_conjugation.md","api/evennia.utils.verb_conjugation.conjugate.md","api/evennia.utils.verb_conjugation.pronouns.md","api/evennia.utils.verb_conjugation.tests.md","api/evennia.web.md","api/evennia.web.admin.md","api/evennia.web.admin.accounts.md","api/evennia.web.admin.attributes.md","api/evennia.web.admin.comms.md","api/evennia.web.admin.frontpage.md","api/evennia.web.admin.help.md","api/evennia.web.admin.objects.md","api/evennia.web.admin.scripts.md","api/evennia.web.admin.server.md","api/evennia.web.admin.tags.md","api/evennia.web.admin.urls.md","api/evennia.web.admin.utils.md","api/evennia.web.api.md","api/evennia.web.api.filters.md","api/evennia.web.api.permissions.md","api/evennia.web.api.root.md","api/evennia.web.api.serializers.md","api/evennia.web.api.tests.md","api/evennia.web.api.urls.md","api/evennia.web.api.views.md","api/evennia.web.templatetags.md","api/evennia.web.templatetags.addclass.md","api/evennia.web.urls.md","api/evennia.web.utils.md","api/evennia.web.utils.adminsite.md","api/evennia.web.utils.backends.md","api/evennia.web.utils.general_context.md","api/evennia.web.utils.middleware.md","api/evennia.web.utils.tests.md","api/evennia.web.webclient.md","api/evennia.web.webclient.urls.md","api/evennia.web.webclient.views.md","api/evennia.web.website.md","api/evennia.web.website.forms.md","api/evennia.web.website.tests.md","api/evennia.web.website.urls.md","api/evennia.web.website.views.md","api/evennia.web.website.views.accounts.md","api/evennia.web.website.views.channels.md","api/evennia.web.website.views.characters.md","api/evennia.web.website.views.errors.md","api/evennia.web.website.views.help.md","api/evennia.web.website.views.index.md","api/evennia.web.website.views.mixins.md","api/evennia.web.website.views.objects.md","index.md","toc.md"],objects:{"":{evennia:[201,0,0,"-"]},"evennia.accounts":{accounts:[204,0,0,"-"],bots:[205,0,0,"-"],manager:[206,0,0,"-"],models:[207,0,0,"-"]},"evennia.accounts.accounts":{DefaultAccount:[204,1,1,""],DefaultGuest:[204,1,1,""]},"evennia.accounts.accounts.DefaultAccount":{"delete":[204,3,1,""],DoesNotExist:[204,2,1,""],MultipleObjectsReturned:[204,2,1,""],access:[204,3,1,""],at_access:[204,3,1,""],at_account_creation:[204,3,1,""],at_cmdset_get:[204,3,1,""],at_disconnect:[204,3,1,""],at_failed_login:[204,3,1,""],at_first_login:[204,3,1,""],at_first_save:[204,3,1,""],at_init:[204,3,1,""],at_look:[204,3,1,""],at_msg_receive:[204,3,1,""],at_msg_send:[204,3,1,""],at_password_change:[204,3,1,""],at_post_channel_msg:[204,3,1,""],at_post_disconnect:[204,3,1,""],at_post_login:[204,3,1,""],at_pre_channel_msg:[204,3,1,""],at_pre_login:[204,3,1,""],at_server_reload:[204,3,1,""],at_server_shutdown:[204,3,1,""],authenticate:[204,3,1,""],basetype_setup:[204,3,1,""],channel_msg:[204,3,1,""],character:[204,3,1,""],characters:[204,3,1,""],cmdset:[204,4,1,""],connection_time:[204,3,1,""],create:[204,3,1,""],create_character:[204,3,1,""],disconnect_session_from_account:[204,3,1,""],execute_cmd:[204,3,1,""],get_all_puppets:[204,3,1,""],get_display_name:[204,3,1,""],get_puppet:[204,3,1,""],get_username_validators:[204,3,1,""],idle_time:[204,3,1,""],is_banned:[204,3,1,""],msg:[204,3,1,""],nicks:[204,4,1,""],normalize_username:[204,3,1,""],objects:[204,4,1,""],options:[204,4,1,""],path:[204,4,1,""],puppet:[204,3,1,""],puppet_object:[204,3,1,""],scripts:[204,4,1,""],search:[204,3,1,""],sessions:[204,4,1,""],set_password:[204,3,1,""],typename:[204,4,1,""],unpuppet_all:[204,3,1,""],unpuppet_object:[204,3,1,""],validate_password:[204,3,1,""],validate_username:[204,3,1,""]},"evennia.accounts.accounts.DefaultGuest":{DoesNotExist:[204,2,1,""],MultipleObjectsReturned:[204,2,1,""],at_post_disconnect:[204,3,1,""],at_post_login:[204,3,1,""],at_server_shutdown:[204,3,1,""],authenticate:[204,3,1,""],create:[204,3,1,""],path:[204,4,1,""],typename:[204,4,1,""]},"evennia.accounts.bots":{Bot:[205,1,1,""],BotStarter:[205,1,1,""],GrapevineBot:[205,1,1,""],IRCBot:[205,1,1,""],RSSBot:[205,1,1,""]},"evennia.accounts.bots.Bot":{DoesNotExist:[205,2,1,""],MultipleObjectsReturned:[205,2,1,""],at_server_shutdown:[205,3,1,""],basetype_setup:[205,3,1,""],execute_cmd:[205,3,1,""],msg:[205,3,1,""],path:[205,4,1,""],start:[205,3,1,""],typename:[205,4,1,""]},"evennia.accounts.bots.BotStarter":{DoesNotExist:[205,2,1,""],MultipleObjectsReturned:[205,2,1,""],at_repeat:[205,3,1,""],at_script_creation:[205,3,1,""],at_server_reload:[205,3,1,""],at_server_shutdown:[205,3,1,""],at_start:[205,3,1,""],path:[205,4,1,""],typename:[205,4,1,""]},"evennia.accounts.bots.GrapevineBot":{DoesNotExist:[205,2,1,""],MultipleObjectsReturned:[205,2,1,""],at_msg_send:[205,3,1,""],execute_cmd:[205,3,1,""],factory_path:[205,4,1,""],msg:[205,3,1,""],path:[205,4,1,""],start:[205,3,1,""],typename:[205,4,1,""]},"evennia.accounts.bots.IRCBot":{DoesNotExist:[205,2,1,""],MultipleObjectsReturned:[205,2,1,""],at_msg_send:[205,3,1,""],execute_cmd:[205,3,1,""],factory_path:[205,4,1,""],get_nicklist:[205,3,1,""],msg:[205,3,1,""],path:[205,4,1,""],ping:[205,3,1,""],reconnect:[205,3,1,""],start:[205,3,1,""],typename:[205,4,1,""]},"evennia.accounts.bots.RSSBot":{DoesNotExist:[205,2,1,""],MultipleObjectsReturned:[205,2,1,""],execute_cmd:[205,3,1,""],path:[205,4,1,""],start:[205,3,1,""],typename:[205,4,1,""]},"evennia.accounts.manager":{AccountDBManager:[206,1,1,""],AccountManager:[206,1,1,""]},"evennia.accounts.manager.AccountDBManager":{account_search:[206,3,1,""],create_account:[206,3,1,""],get_account_from_email:[206,3,1,""],get_account_from_name:[206,3,1,""],get_account_from_uid:[206,3,1,""],get_connected_accounts:[206,3,1,""],get_recently_connected_accounts:[206,3,1,""],get_recently_created_accounts:[206,3,1,""],num_total_accounts:[206,3,1,""],search_account:[206,3,1,""]},"evennia.accounts.models":{AccountDB:[207,1,1,""]},"evennia.accounts.models.AccountDB":{DoesNotExist:[207,2,1,""],MultipleObjectsReturned:[207,2,1,""],account_subscription_set:[207,4,1,""],cmdset_storage:[207,3,1,""],db_attributes:[207,4,1,""],db_cmdset_storage:[207,4,1,""],db_is_bot:[207,4,1,""],db_is_connected:[207,4,1,""],db_tags:[207,4,1,""],get_next_by_date_joined:[207,3,1,""],get_next_by_db_date_created:[207,3,1,""],get_previous_by_date_joined:[207,3,1,""],get_previous_by_db_date_created:[207,3,1,""],groups:[207,4,1,""],hide_from_accounts_set:[207,4,1,""],id:[207,4,1,""],is_bot:[207,3,1,""],is_connected:[207,3,1,""],key:[207,3,1,""],logentry_set:[207,4,1,""],name:[207,3,1,""],objectdb_set:[207,4,1,""],objects:[207,4,1,""],path:[207,4,1,""],receiver_account_set:[207,4,1,""],scriptdb_set:[207,4,1,""],sender_account_set:[207,4,1,""],typename:[207,4,1,""],uid:[207,3,1,""],user_permissions:[207,4,1,""]},"evennia.commands":{"default":[214,0,0,"-"],cmdhandler:[209,0,0,"-"],cmdparser:[210,0,0,"-"],cmdset:[211,0,0,"-"],cmdsethandler:[212,0,0,"-"],command:[213,0,0,"-"]},"evennia.commands.cmdhandler":{InterruptCommand:[209,2,1,""],cmdhandler:[209,5,1,""]},"evennia.commands.cmdparser":{build_matches:[210,5,1,""],cmdparser:[210,5,1,""],create_match:[210,5,1,""],try_num_differentiators:[210,5,1,""]},"evennia.commands.cmdset":{CmdSet:[211,1,1,""]},"evennia.commands.cmdset.CmdSet":{__init__:[211,3,1,""],add:[211,3,1,""],at_cmdset_creation:[211,3,1,""],count:[211,3,1,""],duplicates:[211,4,1,""],errmessage:[211,4,1,""],get:[211,3,1,""],get_all_cmd_keys_and_aliases:[211,3,1,""],get_system_cmds:[211,3,1,""],key:[211,4,1,""],key_mergetypes:[211,4,1,""],make_unique:[211,3,1,""],mergetype:[211,4,1,""],no_channels:[211,4,1,""],no_exits:[211,4,1,""],no_objs:[211,4,1,""],path:[211,4,1,""],persistent:[211,4,1,""],priority:[211,4,1,""],remove:[211,3,1,""],to_duplicate:[211,4,1,""]},"evennia.commands.cmdsethandler":{CmdSetHandler:[212,1,1,""],import_cmdset:[212,5,1,""]},"evennia.commands.cmdsethandler.CmdSetHandler":{"delete":[212,3,1,""],__init__:[212,3,1,""],add:[212,3,1,""],add_default:[212,3,1,""],all:[212,3,1,""],clear:[212,3,1,""],delete_default:[212,3,1,""],get:[212,3,1,""],has:[212,3,1,""],has_cmdset:[212,3,1,""],remove:[212,3,1,""],remove_default:[212,3,1,""],reset:[212,3,1,""],update:[212,3,1,""]},"evennia.commands.command":{Command:[213,1,1,""],CommandMeta:[213,1,1,""],InterruptCommand:[213,2,1,""]},"evennia.commands.command.Command":{__init__:[213,3,1,""],access:[213,3,1,""],aliases:[213,4,1,""],arg_regex:[213,4,1,""],at_post_cmd:[213,3,1,""],at_pre_cmd:[213,3,1,""],auto_help:[213,4,1,""],client_width:[213,3,1,""],execute_cmd:[213,3,1,""],func:[213,3,1,""],get_command_info:[213,3,1,""],get_extra_info:[213,3,1,""],get_help:[213,3,1,""],help_category:[213,4,1,""],is_exit:[213,4,1,""],key:[213,4,1,""],lock_storage:[213,4,1,""],lockhandler:[213,4,1,""],locks:[213,4,1,""],match:[213,3,1,""],msg:[213,3,1,""],msg_all_sessions:[213,4,1,""],parse:[213,3,1,""],retain_instance:[213,4,1,""],save_for_next:[213,4,1,""],search_index_entry:[213,4,1,""],set_aliases:[213,3,1,""],set_key:[213,3,1,""],styled_footer:[213,3,1,""],styled_header:[213,3,1,""],styled_separator:[213,3,1,""],styled_table:[213,3,1,""],web_get_admin_url:[213,3,1,""],web_get_detail_url:[213,3,1,""]},"evennia.commands.command.CommandMeta":{__init__:[213,3,1,""]},"evennia.commands.default":{account:[215,0,0,"-"],admin:[216,0,0,"-"],batchprocess:[217,0,0,"-"],building:[218,0,0,"-"],cmdset_account:[219,0,0,"-"],cmdset_character:[220,0,0,"-"],cmdset_session:[221,0,0,"-"],cmdset_unloggedin:[222,0,0,"-"],comms:[223,0,0,"-"],general:[224,0,0,"-"],help:[225,0,0,"-"],muxcommand:[226,0,0,"-"],syscommands:[227,0,0,"-"],system:[228,0,0,"-"],unloggedin:[230,0,0,"-"]},"evennia.commands.default.account":{CmdCharCreate:[215,1,1,""],CmdCharDelete:[215,1,1,""],CmdColorTest:[215,1,1,""],CmdIC:[215,1,1,""],CmdOOC:[215,1,1,""],CmdOOCLook:[215,1,1,""],CmdOption:[215,1,1,""],CmdPassword:[215,1,1,""],CmdQuell:[215,1,1,""],CmdQuit:[215,1,1,""],CmdSessions:[215,1,1,""],CmdStyle:[215,1,1,""],CmdWho:[215,1,1,""]},"evennia.commands.default.account.CmdCharCreate":{account_caller:[215,4,1,""],aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""]},"evennia.commands.default.account.CmdCharDelete":{aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""]},"evennia.commands.default.account.CmdColorTest":{account_caller:[215,4,1,""],aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""],slice_bright_bg:[215,4,1,""],slice_bright_fg:[215,4,1,""],slice_dark_bg:[215,4,1,""],slice_dark_fg:[215,4,1,""],table_format:[215,3,1,""]},"evennia.commands.default.account.CmdIC":{account_caller:[215,4,1,""],aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""]},"evennia.commands.default.account.CmdOOC":{account_caller:[215,4,1,""],aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""]},"evennia.commands.default.account.CmdOOCLook":{account_caller:[215,4,1,""],aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""]},"evennia.commands.default.account.CmdOption":{account_caller:[215,4,1,""],aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""],switch_options:[215,4,1,""]},"evennia.commands.default.account.CmdPassword":{account_caller:[215,4,1,""],aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""]},"evennia.commands.default.account.CmdQuell":{account_caller:[215,4,1,""],aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""]},"evennia.commands.default.account.CmdQuit":{account_caller:[215,4,1,""],aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""],switch_options:[215,4,1,""]},"evennia.commands.default.account.CmdSessions":{account_caller:[215,4,1,""],aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""]},"evennia.commands.default.account.CmdStyle":{aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],list_styles:[215,3,1,""],lock_storage:[215,4,1,""],search_index_entry:[215,4,1,""],set:[215,3,1,""],switch_options:[215,4,1,""]},"evennia.commands.default.account.CmdWho":{account_caller:[215,4,1,""],aliases:[215,4,1,""],func:[215,3,1,""],help_category:[215,4,1,""],key:[215,4,1,""],lock_storage:[215,4,1,""],locks:[215,4,1,""],search_index_entry:[215,4,1,""]},"evennia.commands.default.admin":{CmdBan:[216,1,1,""],CmdBoot:[216,1,1,""],CmdEmit:[216,1,1,""],CmdForce:[216,1,1,""],CmdNewPassword:[216,1,1,""],CmdPerm:[216,1,1,""],CmdUnban:[216,1,1,""],CmdWall:[216,1,1,""]},"evennia.commands.default.admin.CmdBan":{aliases:[216,4,1,""],func:[216,3,1,""],help_category:[216,4,1,""],key:[216,4,1,""],lock_storage:[216,4,1,""],locks:[216,4,1,""],search_index_entry:[216,4,1,""]},"evennia.commands.default.admin.CmdBoot":{aliases:[216,4,1,""],func:[216,3,1,""],help_category:[216,4,1,""],key:[216,4,1,""],lock_storage:[216,4,1,""],locks:[216,4,1,""],search_index_entry:[216,4,1,""],switch_options:[216,4,1,""]},"evennia.commands.default.admin.CmdEmit":{aliases:[216,4,1,""],func:[216,3,1,""],help_category:[216,4,1,""],key:[216,4,1,""],lock_storage:[216,4,1,""],locks:[216,4,1,""],search_index_entry:[216,4,1,""],switch_options:[216,4,1,""]},"evennia.commands.default.admin.CmdForce":{aliases:[216,4,1,""],func:[216,3,1,""],help_category:[216,4,1,""],key:[216,4,1,""],lock_storage:[216,4,1,""],locks:[216,4,1,""],perm_used:[216,4,1,""],search_index_entry:[216,4,1,""]},"evennia.commands.default.admin.CmdNewPassword":{aliases:[216,4,1,""],func:[216,3,1,""],help_category:[216,4,1,""],key:[216,4,1,""],lock_storage:[216,4,1,""],locks:[216,4,1,""],search_index_entry:[216,4,1,""]},"evennia.commands.default.admin.CmdPerm":{aliases:[216,4,1,""],func:[216,3,1,""],help_category:[216,4,1,""],key:[216,4,1,""],lock_storage:[216,4,1,""],locks:[216,4,1,""],search_index_entry:[216,4,1,""],switch_options:[216,4,1,""]},"evennia.commands.default.admin.CmdUnban":{aliases:[216,4,1,""],func:[216,3,1,""],help_category:[216,4,1,""],key:[216,4,1,""],lock_storage:[216,4,1,""],locks:[216,4,1,""],search_index_entry:[216,4,1,""]},"evennia.commands.default.admin.CmdWall":{aliases:[216,4,1,""],func:[216,3,1,""],help_category:[216,4,1,""],key:[216,4,1,""],lock_storage:[216,4,1,""],locks:[216,4,1,""],search_index_entry:[216,4,1,""]},"evennia.commands.default.batchprocess":{CmdBatchCode:[217,1,1,""],CmdBatchCommands:[217,1,1,""]},"evennia.commands.default.batchprocess.CmdBatchCode":{aliases:[217,4,1,""],func:[217,3,1,""],help_category:[217,4,1,""],key:[217,4,1,""],lock_storage:[217,4,1,""],locks:[217,4,1,""],search_index_entry:[217,4,1,""],switch_options:[217,4,1,""]},"evennia.commands.default.batchprocess.CmdBatchCommands":{aliases:[217,4,1,""],func:[217,3,1,""],help_category:[217,4,1,""],key:[217,4,1,""],lock_storage:[217,4,1,""],locks:[217,4,1,""],search_index_entry:[217,4,1,""],switch_options:[217,4,1,""]},"evennia.commands.default.building":{CmdCopy:[218,1,1,""],CmdCpAttr:[218,1,1,""],CmdCreate:[218,1,1,""],CmdDesc:[218,1,1,""],CmdDestroy:[218,1,1,""],CmdDig:[218,1,1,""],CmdExamine:[218,1,1,""],CmdFind:[218,1,1,""],CmdLink:[218,1,1,""],CmdListCmdSets:[218,1,1,""],CmdLock:[218,1,1,""],CmdMvAttr:[218,1,1,""],CmdName:[218,1,1,""],CmdObjects:[218,1,1,""],CmdOpen:[218,1,1,""],CmdScripts:[218,1,1,""],CmdSetAttribute:[218,1,1,""],CmdSetHome:[218,1,1,""],CmdSetObjAlias:[218,1,1,""],CmdSpawn:[218,1,1,""],CmdTag:[218,1,1,""],CmdTeleport:[218,1,1,""],CmdTunnel:[218,1,1,""],CmdTypeclass:[218,1,1,""],CmdUnLink:[218,1,1,""],CmdWipe:[218,1,1,""],ObjManipCommand:[218,1,1,""]},"evennia.commands.default.building.CmdCopy":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.building.CmdCpAttr":{aliases:[218,4,1,""],check_from_attr:[218,3,1,""],check_has_attr:[218,3,1,""],check_to_attr:[218,3,1,""],func:[218,3,1,""],get_attr:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdCreate":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],new_obj_lockstring:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdDesc":{aliases:[218,4,1,""],edit_handler:[218,3,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdDestroy":{aliases:[218,4,1,""],confirm:[218,4,1,""],default_confirm:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdDig":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],new_room_lockstring:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdExamine":{aliases:[218,4,1,""],arg_regex:[218,4,1,""],detail_color:[218,4,1,""],format_account_key:[218,3,1,""],format_account_permissions:[218,3,1,""],format_account_typeclass:[218,3,1,""],format_aliases:[218,3,1,""],format_attributes:[218,3,1,""],format_channel_account_subs:[218,3,1,""],format_channel_object_subs:[218,3,1,""],format_channel_sub_totals:[218,3,1,""],format_chars:[218,3,1,""],format_current_cmds:[218,3,1,""],format_destination:[218,3,1,""],format_email:[218,3,1,""],format_exits:[218,3,1,""],format_home:[218,3,1,""],format_key:[218,3,1,""],format_location:[218,3,1,""],format_locks:[218,3,1,""],format_merged_cmdsets:[218,3,1,""],format_nattributes:[218,3,1,""],format_output:[218,3,1,""],format_permissions:[218,3,1,""],format_script_desc:[218,3,1,""],format_script_is_persistent:[218,3,1,""],format_script_timer_data:[218,3,1,""],format_scripts:[218,3,1,""],format_sessions:[218,3,1,""],format_single_attribute:[218,3,1,""],format_single_attribute_detail:[218,3,1,""],format_single_cmdset:[218,3,1,""],format_single_cmdset_options:[218,3,1,""],format_single_tag:[218,3,1,""],format_stored_cmdsets:[218,3,1,""],format_tags:[218,3,1,""],format_things:[218,3,1,""],format_typeclass:[218,3,1,""],func:[218,3,1,""],get_formatted_obj_data:[218,3,1,""],header_color:[218,4,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],msg:[218,3,1,""],object_type:[218,4,1,""],parse:[218,3,1,""],quell_color:[218,4,1,""],search_index_entry:[218,4,1,""],separator:[218,4,1,""],switch_options:[218,4,1,""],text:[218,4,1,""]},"evennia.commands.default.building.CmdFind":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdLink":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.building.CmdListCmdSets":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.building.CmdLock":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.building.CmdMvAttr":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdName":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.building.CmdObjects":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.building.CmdOpen":{aliases:[218,4,1,""],create_exit:[218,3,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],new_obj_lockstring:[218,4,1,""],parse:[218,3,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.building.CmdScripts":{aliases:[218,4,1,""],excluded_typeclass_paths:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""],switch_mapping:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdSetAttribute":{aliases:[218,4,1,""],check_attr:[218,3,1,""],check_obj:[218,3,1,""],do_nested_lookup:[218,3,1,""],edit_handler:[218,3,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],nested_re:[218,4,1,""],not_found:[218,4,1,""],rm_attr:[218,3,1,""],search_for_obj:[218,3,1,""],search_index_entry:[218,4,1,""],set_attr:[218,3,1,""],split_nested_attr:[218,3,1,""],view_attr:[218,3,1,""]},"evennia.commands.default.building.CmdSetHome":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.building.CmdSetObjAlias":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdSpawn":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdTag":{aliases:[218,4,1,""],arg_regex:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],options:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.building.CmdTeleport":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],parse:[218,3,1,""],rhs_split:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdTunnel":{aliases:[218,4,1,""],directions:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdTypeclass":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""],switch_options:[218,4,1,""]},"evennia.commands.default.building.CmdUnLink":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],help_key:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.building.CmdWipe":{aliases:[218,4,1,""],func:[218,3,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],locks:[218,4,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.building.ObjManipCommand":{aliases:[218,4,1,""],help_category:[218,4,1,""],key:[218,4,1,""],lock_storage:[218,4,1,""],parse:[218,3,1,""],search_index_entry:[218,4,1,""]},"evennia.commands.default.cmdset_account":{AccountCmdSet:[219,1,1,""]},"evennia.commands.default.cmdset_account.AccountCmdSet":{at_cmdset_creation:[219,3,1,""],key:[219,4,1,""],path:[219,4,1,""],priority:[219,4,1,""]},"evennia.commands.default.cmdset_character":{CharacterCmdSet:[220,1,1,""]},"evennia.commands.default.cmdset_character.CharacterCmdSet":{at_cmdset_creation:[220,3,1,""],key:[220,4,1,""],path:[220,4,1,""],priority:[220,4,1,""]},"evennia.commands.default.cmdset_session":{SessionCmdSet:[221,1,1,""]},"evennia.commands.default.cmdset_session.SessionCmdSet":{at_cmdset_creation:[221,3,1,""],key:[221,4,1,""],path:[221,4,1,""],priority:[221,4,1,""]},"evennia.commands.default.cmdset_unloggedin":{UnloggedinCmdSet:[222,1,1,""]},"evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet":{at_cmdset_creation:[222,3,1,""],key:[222,4,1,""],path:[222,4,1,""],priority:[222,4,1,""]},"evennia.commands.default.comms":{CmdChannel:[223,1,1,""],CmdGrapevine2Chan:[223,1,1,""],CmdIRC2Chan:[223,1,1,""],CmdIRCStatus:[223,1,1,""],CmdObjectChannel:[223,1,1,""],CmdPage:[223,1,1,""],CmdRSS2Chan:[223,1,1,""]},"evennia.commands.default.comms.CmdChannel":{account_caller:[223,4,1,""],add_alias:[223,3,1,""],aliases:[223,4,1,""],ban_user:[223,3,1,""],boot_user:[223,3,1,""],channel_list_bans:[223,3,1,""],channel_list_who:[223,3,1,""],create_channel:[223,3,1,""],destroy_channel:[223,3,1,""],display_all_channels:[223,3,1,""],display_subbed_channels:[223,3,1,""],func:[223,3,1,""],get_channel_aliases:[223,3,1,""],get_channel_history:[223,3,1,""],help_category:[223,4,1,""],key:[223,4,1,""],list_channels:[223,3,1,""],lock_storage:[223,4,1,""],locks:[223,4,1,""],msg_channel:[223,3,1,""],mute_channel:[223,3,1,""],remove_alias:[223,3,1,""],search_channel:[223,3,1,""],search_index_entry:[223,4,1,""],set_desc:[223,3,1,""],set_lock:[223,3,1,""],sub_to_channel:[223,3,1,""],switch_options:[223,4,1,""],unban_user:[223,3,1,""],unmute_channel:[223,3,1,""],unset_lock:[223,3,1,""],unsub_from_channel:[223,3,1,""]},"evennia.commands.default.comms.CmdGrapevine2Chan":{aliases:[223,4,1,""],func:[223,3,1,""],help_category:[223,4,1,""],key:[223,4,1,""],lock_storage:[223,4,1,""],locks:[223,4,1,""],search_index_entry:[223,4,1,""],switch_options:[223,4,1,""]},"evennia.commands.default.comms.CmdIRC2Chan":{aliases:[223,4,1,""],func:[223,3,1,""],help_category:[223,4,1,""],key:[223,4,1,""],lock_storage:[223,4,1,""],locks:[223,4,1,""],search_index_entry:[223,4,1,""],switch_options:[223,4,1,""]},"evennia.commands.default.comms.CmdIRCStatus":{aliases:[223,4,1,""],func:[223,3,1,""],help_category:[223,4,1,""],key:[223,4,1,""],lock_storage:[223,4,1,""],locks:[223,4,1,""],search_index_entry:[223,4,1,""]},"evennia.commands.default.comms.CmdObjectChannel":{account_caller:[223,4,1,""],aliases:[223,4,1,""],help_category:[223,4,1,""],key:[223,4,1,""],lock_storage:[223,4,1,""],search_index_entry:[223,4,1,""]},"evennia.commands.default.comms.CmdPage":{account_caller:[223,4,1,""],aliases:[223,4,1,""],func:[223,3,1,""],help_category:[223,4,1,""],key:[223,4,1,""],lock_storage:[223,4,1,""],locks:[223,4,1,""],search_index_entry:[223,4,1,""],switch_options:[223,4,1,""]},"evennia.commands.default.comms.CmdRSS2Chan":{aliases:[223,4,1,""],func:[223,3,1,""],help_category:[223,4,1,""],key:[223,4,1,""],lock_storage:[223,4,1,""],locks:[223,4,1,""],search_index_entry:[223,4,1,""],switch_options:[223,4,1,""]},"evennia.commands.default.general":{CmdAccess:[224,1,1,""],CmdDrop:[224,1,1,""],CmdGet:[224,1,1,""],CmdGive:[224,1,1,""],CmdHome:[224,1,1,""],CmdInventory:[224,1,1,""],CmdLook:[224,1,1,""],CmdNick:[224,1,1,""],CmdPose:[224,1,1,""],CmdSay:[224,1,1,""],CmdSetDesc:[224,1,1,""],CmdWhisper:[224,1,1,""]},"evennia.commands.default.general.CmdAccess":{aliases:[224,4,1,""],arg_regex:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],search_index_entry:[224,4,1,""]},"evennia.commands.default.general.CmdDrop":{aliases:[224,4,1,""],arg_regex:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],search_index_entry:[224,4,1,""]},"evennia.commands.default.general.CmdGet":{aliases:[224,4,1,""],arg_regex:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],search_index_entry:[224,4,1,""]},"evennia.commands.default.general.CmdGive":{aliases:[224,4,1,""],arg_regex:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],rhs_split:[224,4,1,""],search_index_entry:[224,4,1,""]},"evennia.commands.default.general.CmdHome":{aliases:[224,4,1,""],arg_regex:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],search_index_entry:[224,4,1,""]},"evennia.commands.default.general.CmdInventory":{aliases:[224,4,1,""],arg_regex:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],search_index_entry:[224,4,1,""]},"evennia.commands.default.general.CmdLook":{aliases:[224,4,1,""],arg_regex:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],search_index_entry:[224,4,1,""]},"evennia.commands.default.general.CmdNick":{aliases:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],parse:[224,3,1,""],search_index_entry:[224,4,1,""],switch_options:[224,4,1,""]},"evennia.commands.default.general.CmdPose":{aliases:[224,4,1,""],arg_regex:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],parse:[224,3,1,""],search_index_entry:[224,4,1,""]},"evennia.commands.default.general.CmdSay":{aliases:[224,4,1,""],arg_regex:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],search_index_entry:[224,4,1,""]},"evennia.commands.default.general.CmdSetDesc":{aliases:[224,4,1,""],arg_regex:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],search_index_entry:[224,4,1,""]},"evennia.commands.default.general.CmdWhisper":{aliases:[224,4,1,""],func:[224,3,1,""],help_category:[224,4,1,""],key:[224,4,1,""],lock_storage:[224,4,1,""],locks:[224,4,1,""],search_index_entry:[224,4,1,""]},"evennia.commands.default.help":{CmdHelp:[225,1,1,""],CmdSetHelp:[225,1,1,""]},"evennia.commands.default.help.CmdHelp":{aliases:[225,4,1,""],arg_regex:[225,4,1,""],can_list_topic:[225,3,1,""],can_read_topic:[225,3,1,""],clickable_topics:[225,4,1,""],collect_topics:[225,3,1,""],do_search:[225,3,1,""],format_help_entry:[225,3,1,""],format_help_index:[225,3,1,""],func:[225,3,1,""],help_category:[225,4,1,""],help_more:[225,4,1,""],index_category_clr:[225,4,1,""],index_topic_clr:[225,4,1,""],index_type_separator_clr:[225,4,1,""],key:[225,4,1,""],lock_storage:[225,4,1,""],locks:[225,4,1,""],msg_help:[225,3,1,""],parse:[225,3,1,""],return_cmdset:[225,4,1,""],search_index_entry:[225,4,1,""],strip_cmd_prefix:[225,3,1,""],subtopic_separator_char:[225,4,1,""],suggestion_cutoff:[225,4,1,""],suggestion_maxnum:[225,4,1,""]},"evennia.commands.default.help.CmdSetHelp":{aliases:[225,4,1,""],arg_regex:[225,4,1,""],func:[225,3,1,""],help_category:[225,4,1,""],key:[225,4,1,""],lock_storage:[225,4,1,""],locks:[225,4,1,""],parse:[225,3,1,""],search_index_entry:[225,4,1,""],switch_options:[225,4,1,""]},"evennia.commands.default.muxcommand":{MuxAccountCommand:[226,1,1,""],MuxCommand:[226,1,1,""]},"evennia.commands.default.muxcommand.MuxAccountCommand":{account_caller:[226,4,1,""],aliases:[226,4,1,""],help_category:[226,4,1,""],key:[226,4,1,""],lock_storage:[226,4,1,""],search_index_entry:[226,4,1,""]},"evennia.commands.default.muxcommand.MuxCommand":{aliases:[226,4,1,""],at_post_cmd:[226,3,1,""],at_pre_cmd:[226,3,1,""],func:[226,3,1,""],get_command_info:[226,3,1,""],has_perm:[226,3,1,""],help_category:[226,4,1,""],key:[226,4,1,""],lock_storage:[226,4,1,""],parse:[226,3,1,""],search_index_entry:[226,4,1,""]},"evennia.commands.default.syscommands":{SystemMultimatch:[227,1,1,""],SystemNoInput:[227,1,1,""],SystemNoMatch:[227,1,1,""]},"evennia.commands.default.syscommands.SystemMultimatch":{aliases:[227,4,1,""],func:[227,3,1,""],help_category:[227,4,1,""],key:[227,4,1,""],lock_storage:[227,4,1,""],locks:[227,4,1,""],search_index_entry:[227,4,1,""]},"evennia.commands.default.syscommands.SystemNoInput":{aliases:[227,4,1,""],func:[227,3,1,""],help_category:[227,4,1,""],key:[227,4,1,""],lock_storage:[227,4,1,""],locks:[227,4,1,""],search_index_entry:[227,4,1,""]},"evennia.commands.default.syscommands.SystemNoMatch":{aliases:[227,4,1,""],func:[227,3,1,""],help_category:[227,4,1,""],key:[227,4,1,""],lock_storage:[227,4,1,""],locks:[227,4,1,""],search_index_entry:[227,4,1,""]},"evennia.commands.default.system":{CmdAbout:[228,1,1,""],CmdAccounts:[228,1,1,""],CmdPy:[228,1,1,""],CmdReload:[228,1,1,""],CmdReset:[228,1,1,""],CmdServerLoad:[228,1,1,""],CmdService:[228,1,1,""],CmdShutdown:[228,1,1,""],CmdTasks:[228,1,1,""],CmdTickers:[228,1,1,""],CmdTime:[228,1,1,""]},"evennia.commands.default.system.CmdAbout":{aliases:[228,4,1,""],func:[228,3,1,""],help_category:[228,4,1,""],key:[228,4,1,""],lock_storage:[228,4,1,""],locks:[228,4,1,""],search_index_entry:[228,4,1,""]},"evennia.commands.default.system.CmdAccounts":{aliases:[228,4,1,""],func:[228,3,1,""],help_category:[228,4,1,""],key:[228,4,1,""],lock_storage:[228,4,1,""],locks:[228,4,1,""],search_index_entry:[228,4,1,""],switch_options:[228,4,1,""]},"evennia.commands.default.system.CmdPy":{aliases:[228,4,1,""],arg_regex:[228,4,1,""],func:[228,3,1,""],help_category:[228,4,1,""],key:[228,4,1,""],lock_storage:[228,4,1,""],locks:[228,4,1,""],search_index_entry:[228,4,1,""],switch_options:[228,4,1,""]},"evennia.commands.default.system.CmdReload":{aliases:[228,4,1,""],func:[228,3,1,""],help_category:[228,4,1,""],key:[228,4,1,""],lock_storage:[228,4,1,""],locks:[228,4,1,""],search_index_entry:[228,4,1,""]},"evennia.commands.default.system.CmdReset":{aliases:[228,4,1,""],func:[228,3,1,""],help_category:[228,4,1,""],key:[228,4,1,""],lock_storage:[228,4,1,""],locks:[228,4,1,""],search_index_entry:[228,4,1,""]},"evennia.commands.default.system.CmdServerLoad":{aliases:[228,4,1,""],func:[228,3,1,""],help_category:[228,4,1,""],key:[228,4,1,""],lock_storage:[228,4,1,""],locks:[228,4,1,""],search_index_entry:[228,4,1,""],switch_options:[228,4,1,""]},"evennia.commands.default.system.CmdService":{aliases:[228,4,1,""],func:[228,3,1,""],help_category:[228,4,1,""],key:[228,4,1,""],lock_storage:[228,4,1,""],locks:[228,4,1,""],search_index_entry:[228,4,1,""],switch_options:[228,4,1,""]},"evennia.commands.default.system.CmdShutdown":{aliases:[228,4,1,""],func:[228,3,1,""],help_category:[228,4,1,""],key:[228,4,1,""],lock_storage:[228,4,1,""],locks:[228,4,1,""],search_index_entry:[228,4,1,""]},"evennia.commands.default.system.CmdTasks":{aliases:[228,4,1,""],coll_date_func:[228,3,1,""],do_task_action:[228,3,1,""],func:[228,3,1,""],help_category:[228,4,1,""],key:[228,4,1,""],lock_storage:[228,4,1,""],locks:[228,4,1,""],search_index_entry:[228,4,1,""],switch_options:[228,4,1,""]},"evennia.commands.default.system.CmdTickers":{aliases:[228,4,1,""],func:[228,3,1,""],help_category:[228,4,1,""],key:[228,4,1,""],lock_storage:[228,4,1,""],locks:[228,4,1,""],search_index_entry:[228,4,1,""]},"evennia.commands.default.system.CmdTime":{aliases:[228,4,1,""],func:[228,3,1,""],help_category:[228,4,1,""],key:[228,4,1,""],lock_storage:[228,4,1,""],locks:[228,4,1,""],search_index_entry:[228,4,1,""]},"evennia.commands.default.tests":{CmdInterrupt:[229,1,1,""],TestAccount:[229,1,1,""],TestAdmin:[229,1,1,""],TestBatchProcess:[229,1,1,""],TestBuilding:[229,1,1,""],TestCmdTasks:[229,1,1,""],TestComms:[229,1,1,""],TestCommsChannel:[229,1,1,""],TestGeneral:[229,1,1,""],TestHelp:[229,1,1,""],TestInterruptCommand:[229,1,1,""],TestSystem:[229,1,1,""],TestSystemCommands:[229,1,1,""],TestUnconnectedCommand:[229,1,1,""],func_test_cmd_tasks:[229,5,1,""]},"evennia.commands.default.tests.CmdInterrupt":{aliases:[229,4,1,""],func:[229,3,1,""],help_category:[229,4,1,""],key:[229,4,1,""],lock_storage:[229,4,1,""],parse:[229,3,1,""],search_index_entry:[229,4,1,""]},"evennia.commands.default.tests.TestAccount":{test_char_create:[229,3,1,""],test_char_delete:[229,3,1,""],test_color_test:[229,3,1,""],test_ic:[229,3,1,""],test_ic__nonaccess:[229,3,1,""],test_ic__other_object:[229,3,1,""],test_ooc:[229,3,1,""],test_ooc_look:[229,3,1,""],test_option:[229,3,1,""],test_password:[229,3,1,""],test_quell:[229,3,1,""],test_quit:[229,3,1,""],test_sessions:[229,3,1,""],test_who:[229,3,1,""]},"evennia.commands.default.tests.TestAdmin":{test_ban:[229,3,1,""],test_emit:[229,3,1,""],test_force:[229,3,1,""],test_perm:[229,3,1,""],test_wall:[229,3,1,""]},"evennia.commands.default.tests.TestBatchProcess":{red_button:[229,4,1,""],test_batch_commands:[229,3,1,""]},"evennia.commands.default.tests.TestBuilding":{test_attribute_commands:[229,3,1,""],test_copy:[229,3,1,""],test_create:[229,3,1,""],test_desc:[229,3,1,""],test_desc_default_to_room:[229,3,1,""],test_destroy:[229,3,1,""],test_destroy_sequence:[229,3,1,""],test_dig:[229,3,1,""],test_do_nested_lookup:[229,3,1,""],test_empty_desc:[229,3,1,""],test_examine:[229,3,1,""],test_exit_commands:[229,3,1,""],test_find:[229,3,1,""],test_list_cmdsets:[229,3,1,""],test_lock:[229,3,1,""],test_name:[229,3,1,""],test_nested_attribute_commands:[229,3,1,""],test_script:[229,3,1,""],test_script_multi_delete:[229,3,1,""],test_set_home:[229,3,1,""],test_set_obj_alias:[229,3,1,""],test_spawn:[229,3,1,""],test_split_nested_attr:[229,3,1,""],test_tag:[229,3,1,""],test_teleport:[229,3,1,""],test_tunnel:[229,3,1,""],test_tunnel_exit_typeclass:[229,3,1,""],test_typeclass:[229,3,1,""]},"evennia.commands.default.tests.TestCmdTasks":{setUp:[229,3,1,""],tearDown:[229,3,1,""],test_active_task:[229,3,1,""],test_call:[229,3,1,""],test_cancel:[229,3,1,""],test_do_task:[229,3,1,""],test_func_name_manipulation:[229,3,1,""],test_misformed_command:[229,3,1,""],test_new_task_waiting_input:[229,3,1,""],test_no_input:[229,3,1,""],test_no_tasks:[229,3,1,""],test_pause_unpause:[229,3,1,""],test_persistent_task:[229,3,1,""],test_remove:[229,3,1,""],test_responce_of_yes:[229,3,1,""],test_task_complete_waiting_input:[229,3,1,""],test_wrong_func_name:[229,3,1,""]},"evennia.commands.default.tests.TestComms":{test_page:[229,3,1,""]},"evennia.commands.default.tests.TestCommsChannel":{setUp:[229,3,1,""],tearDown:[229,3,1,""],test_channel__alias__unalias:[229,3,1,""],test_channel__all:[229,3,1,""],test_channel__ban__unban:[229,3,1,""],test_channel__boot:[229,3,1,""],test_channel__create:[229,3,1,""],test_channel__desc:[229,3,1,""],test_channel__destroy:[229,3,1,""],test_channel__history:[229,3,1,""],test_channel__list:[229,3,1,""],test_channel__lock:[229,3,1,""],test_channel__msg:[229,3,1,""],test_channel__mute:[229,3,1,""],test_channel__noarg:[229,3,1,""],test_channel__sub:[229,3,1,""],test_channel__unlock:[229,3,1,""],test_channel__unmute:[229,3,1,""],test_channel__unsub:[229,3,1,""],test_channel__who:[229,3,1,""]},"evennia.commands.default.tests.TestGeneral":{test_access:[229,3,1,""],test_get_and_drop:[229,3,1,""],test_give:[229,3,1,""],test_home:[229,3,1,""],test_inventory:[229,3,1,""],test_look:[229,3,1,""],test_mux_command:[229,3,1,""],test_nick:[229,3,1,""],test_pose:[229,3,1,""],test_say:[229,3,1,""],test_whisper:[229,3,1,""]},"evennia.commands.default.tests.TestHelp":{maxDiff:[229,4,1,""],setUp:[229,3,1,""],tearDown:[229,3,1,""],test_help:[229,3,1,""],test_set_help:[229,3,1,""],test_subtopic_fetch:[229,4,1,""],test_subtopic_fetch_00_test:[229,3,1,""],test_subtopic_fetch_01_test_creating_extra_stuff:[229,3,1,""],test_subtopic_fetch_02_test_creating:[229,3,1,""],test_subtopic_fetch_03_test_extra:[229,3,1,""],test_subtopic_fetch_04_test_extra_subsubtopic:[229,3,1,""],test_subtopic_fetch_05_test_creating_extra_subsub:[229,3,1,""],test_subtopic_fetch_06_test_Something_else:[229,3,1,""],test_subtopic_fetch_07_test_More:[229,3,1,""],test_subtopic_fetch_08_test_More_Second_more:[229,3,1,""],test_subtopic_fetch_09_test_More_more:[229,3,1,""],test_subtopic_fetch_10_test_more_second_more_again:[229,3,1,""],test_subtopic_fetch_11_test_more_second_third:[229,3,1,""]},"evennia.commands.default.tests.TestInterruptCommand":{test_interrupt_command:[229,3,1,""]},"evennia.commands.default.tests.TestSystem":{test_about:[229,3,1,""],test_objects:[229,3,1,""],test_py:[229,3,1,""],test_scripts:[229,3,1,""],test_server_load:[229,3,1,""]},"evennia.commands.default.tests.TestSystemCommands":{test_multimatch:[229,3,1,""],test_simple_defaults:[229,3,1,""]},"evennia.commands.default.tests.TestUnconnectedCommand":{test_info_command:[229,3,1,""]},"evennia.commands.default.unloggedin":{CmdUnconnectedConnect:[230,1,1,""],CmdUnconnectedCreate:[230,1,1,""],CmdUnconnectedEncoding:[230,1,1,""],CmdUnconnectedHelp:[230,1,1,""],CmdUnconnectedInfo:[230,1,1,""],CmdUnconnectedLook:[230,1,1,""],CmdUnconnectedQuit:[230,1,1,""],CmdUnconnectedScreenreader:[230,1,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedConnect":{aliases:[230,4,1,""],arg_regex:[230,4,1,""],func:[230,3,1,""],help_category:[230,4,1,""],key:[230,4,1,""],lock_storage:[230,4,1,""],locks:[230,4,1,""],search_index_entry:[230,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedCreate":{aliases:[230,4,1,""],arg_regex:[230,4,1,""],func:[230,3,1,""],help_category:[230,4,1,""],key:[230,4,1,""],lock_storage:[230,4,1,""],locks:[230,4,1,""],search_index_entry:[230,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedEncoding":{aliases:[230,4,1,""],func:[230,3,1,""],help_category:[230,4,1,""],key:[230,4,1,""],lock_storage:[230,4,1,""],locks:[230,4,1,""],search_index_entry:[230,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedHelp":{aliases:[230,4,1,""],func:[230,3,1,""],help_category:[230,4,1,""],key:[230,4,1,""],lock_storage:[230,4,1,""],locks:[230,4,1,""],search_index_entry:[230,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedInfo":{aliases:[230,4,1,""],func:[230,3,1,""],help_category:[230,4,1,""],key:[230,4,1,""],lock_storage:[230,4,1,""],locks:[230,4,1,""],search_index_entry:[230,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedLook":{aliases:[230,4,1,""],func:[230,3,1,""],help_category:[230,4,1,""],key:[230,4,1,""],lock_storage:[230,4,1,""],locks:[230,4,1,""],search_index_entry:[230,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedQuit":{aliases:[230,4,1,""],func:[230,3,1,""],help_category:[230,4,1,""],key:[230,4,1,""],lock_storage:[230,4,1,""],locks:[230,4,1,""],search_index_entry:[230,4,1,""]},"evennia.commands.default.unloggedin.CmdUnconnectedScreenreader":{aliases:[230,4,1,""],func:[230,3,1,""],help_category:[230,4,1,""],key:[230,4,1,""],lock_storage:[230,4,1,""],search_index_entry:[230,4,1,""]},"evennia.comms":{comms:[232,0,0,"-"],managers:[233,0,0,"-"],models:[234,0,0,"-"]},"evennia.comms.comms":{DefaultChannel:[232,1,1,""]},"evennia.comms.comms.DefaultChannel":{"delete":[232,3,1,""],DoesNotExist:[232,2,1,""],MultipleObjectsReturned:[232,2,1,""],access:[232,3,1,""],add_user_channel_alias:[232,3,1,""],at_channel_creation:[232,3,1,""],at_first_save:[232,3,1,""],at_init:[232,3,1,""],at_post_msg:[232,3,1,""],at_pre_msg:[232,3,1,""],ban:[232,3,1,""],banlist:[232,3,1,""],basetype_setup:[232,3,1,""],channel_msg_nick_pattern:[232,4,1,""],channel_msg_nick_replacement:[232,4,1,""],channel_prefix:[232,3,1,""],channel_prefix_string:[232,4,1,""],connect:[232,3,1,""],create:[232,3,1,""],disconnect:[232,3,1,""],distribute_message:[232,3,1,""],format_external:[232,3,1,""],format_message:[232,3,1,""],format_senders:[232,3,1,""],get_absolute_url:[232,3,1,""],get_log_filename:[232,3,1,""],has_connection:[232,3,1,""],log_file:[232,4,1,""],message_transform:[232,3,1,""],msg:[232,3,1,""],mute:[232,3,1,""],mutelist:[232,3,1,""],objects:[232,4,1,""],path:[232,4,1,""],pose_transform:[232,3,1,""],post_join_channel:[232,3,1,""],post_leave_channel:[232,3,1,""],post_send_message:[232,3,1,""],pre_join_channel:[232,3,1,""],pre_leave_channel:[232,3,1,""],pre_send_message:[232,3,1,""],remove_user_channel_alias:[232,3,1,""],send_to_online_only:[232,4,1,""],set_log_filename:[232,3,1,""],typename:[232,4,1,""],unban:[232,3,1,""],unmute:[232,3,1,""],web_get_admin_url:[232,3,1,""],web_get_create_url:[232,3,1,""],web_get_delete_url:[232,3,1,""],web_get_detail_url:[232,3,1,""],web_get_update_url:[232,3,1,""],wholist:[232,3,1,""]},"evennia.comms.managers":{ChannelDBManager:[233,1,1,""],ChannelManager:[233,1,1,""],CommError:[233,2,1,""],MsgManager:[233,1,1,""],identify_object:[233,5,1,""],to_object:[233,5,1,""]},"evennia.comms.managers.ChannelDBManager":{channel_search:[233,3,1,""],create_channel:[233,3,1,""],get_all_channels:[233,3,1,""],get_channel:[233,3,1,""],get_subscriptions:[233,3,1,""],search_channel:[233,3,1,""]},"evennia.comms.managers.MsgManager":{create_message:[233,3,1,""],get_message_by_id:[233,3,1,""],get_messages_by_receiver:[233,3,1,""],get_messages_by_sender:[233,3,1,""],identify_object:[233,3,1,""],message_search:[233,3,1,""],search_message:[233,3,1,""]},"evennia.comms.models":{ChannelDB:[234,1,1,""],Msg:[234,1,1,""],SubscriptionHandler:[234,1,1,""],TempMsg:[234,1,1,""]},"evennia.comms.models.ChannelDB":{DoesNotExist:[234,2,1,""],MultipleObjectsReturned:[234,2,1,""],db_account_subscriptions:[234,4,1,""],db_attributes:[234,4,1,""],db_object_subscriptions:[234,4,1,""],db_tags:[234,4,1,""],get_next_by_db_date_created:[234,3,1,""],get_previous_by_db_date_created:[234,3,1,""],id:[234,4,1,""],objects:[234,4,1,""],path:[234,4,1,""],subscriptions:[234,4,1,""],typename:[234,4,1,""]},"evennia.comms.models.Msg":{DoesNotExist:[234,2,1,""],MultipleObjectsReturned:[234,2,1,""],access:[234,3,1,""],date_created:[234,3,1,""],db_date_created:[234,4,1,""],db_header:[234,4,1,""],db_hide_from_accounts:[234,4,1,""],db_hide_from_objects:[234,4,1,""],db_lock_storage:[234,4,1,""],db_message:[234,4,1,""],db_receiver_external:[234,4,1,""],db_receivers_accounts:[234,4,1,""],db_receivers_objects:[234,4,1,""],db_receivers_scripts:[234,4,1,""],db_sender_accounts:[234,4,1,""],db_sender_external:[234,4,1,""],db_sender_objects:[234,4,1,""],db_sender_scripts:[234,4,1,""],db_tags:[234,4,1,""],get_next_by_db_date_created:[234,3,1,""],get_previous_by_db_date_created:[234,3,1,""],header:[234,3,1,""],hide_from:[234,3,1,""],id:[234,4,1,""],lock_storage:[234,3,1,""],locks:[234,4,1,""],message:[234,3,1,""],objects:[234,4,1,""],path:[234,4,1,""],receiver_external:[234,3,1,""],receivers:[234,3,1,""],remove_receiver:[234,3,1,""],remove_sender:[234,3,1,""],sender_external:[234,3,1,""],senders:[234,3,1,""],tags:[234,4,1,""],typename:[234,4,1,""]},"evennia.comms.models.SubscriptionHandler":{__init__:[234,3,1,""],add:[234,3,1,""],all:[234,3,1,""],clear:[234,3,1,""],get:[234,3,1,""],has:[234,3,1,""],online:[234,3,1,""],remove:[234,3,1,""]},"evennia.comms.models.TempMsg":{__init__:[234,3,1,""],access:[234,3,1,""],locks:[234,4,1,""],remove_receiver:[234,3,1,""],remove_sender:[234,3,1,""]},"evennia.contrib":{base_systems:[236,0,0,"-"],full_systems:[271,0,0,"-"],game_systems:[281,0,0,"-"],grid:[314,0,0,"-"],rpg:[341,0,0,"-"],tutorials:[355,0,0,"-"],utils:[374,0,0,"-"]},"evennia.contrib.base_systems":{awsstorage:[237,0,0,"-"],building_menu:[240,0,0,"-"],color_markups:[243,0,0,"-"],custom_gametime:[246,0,0,"-"],email_login:[249,0,0,"-"],mux_comms_cmds:[265,0,0,"-"],unixcommand:[268,0,0,"-"]},"evennia.contrib.base_systems.awsstorage":{aws_s3_cdn:[238,0,0,"-"],tests:[239,0,0,"-"]},"evennia.contrib.base_systems.awsstorage.aws_s3_cdn":{S3Boto3Storage:[238,1,1,""],S3Boto3StorageFile:[238,1,1,""],check_location:[238,5,1,""],get_available_overwrite_name:[238,5,1,""],lookup_env:[238,5,1,""],safe_join:[238,5,1,""],setting:[238,5,1,""]},"evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3Storage":{"delete":[238,3,1,""],__init__:[238,3,1,""],access_key:[238,4,1,""],access_key_names:[238,4,1,""],addressing_style:[238,4,1,""],auto_create_bucket:[238,4,1,""],bucket:[238,3,1,""],bucket_acl:[238,4,1,""],bucket_name:[238,4,1,""],config:[238,4,1,""],connection:[238,3,1,""],custom_domain:[238,4,1,""],deconstruct:[238,3,1,""],default_acl:[238,4,1,""],default_content_type:[238,4,1,""],encryption:[238,4,1,""],endpoint_url:[238,4,1,""],entries:[238,3,1,""],exists:[238,3,1,""],file_name_charset:[238,4,1,""],file_overwrite:[238,4,1,""],get_available_name:[238,3,1,""],get_modified_time:[238,3,1,""],get_object_parameters:[238,3,1,""],gzip:[238,4,1,""],gzip_content_types:[238,4,1,""],listdir:[238,3,1,""],location:[238,4,1,""],max_memory_size:[238,4,1,""],modified_time:[238,3,1,""],object_parameters:[238,4,1,""],preload_metadata:[238,4,1,""],proxies:[238,4,1,""],querystring_auth:[238,4,1,""],querystring_expire:[238,4,1,""],reduced_redundancy:[238,4,1,""],region_name:[238,4,1,""],secret_key:[238,4,1,""],secret_key_names:[238,4,1,""],secure_urls:[238,4,1,""],security_token:[238,4,1,""],security_token_names:[238,4,1,""],signature_version:[238,4,1,""],size:[238,3,1,""],url:[238,3,1,""],url_protocol:[238,4,1,""],use_ssl:[238,4,1,""],verify:[238,4,1,""]},"evennia.contrib.base_systems.awsstorage.aws_s3_cdn.S3Boto3StorageFile":{__init__:[238,3,1,""],buffer_size:[238,4,1,""],close:[238,3,1,""],deconstruct:[238,3,1,""],file:[238,3,1,""],read:[238,3,1,""],readline:[238,3,1,""],size:[238,3,1,""],write:[238,3,1,""]},"evennia.contrib.base_systems.awsstorage.tests":{S3Boto3StorageTests:[239,1,1,""],S3Boto3TestCase:[239,1,1,""]},"evennia.contrib.base_systems.awsstorage.tests.S3Boto3StorageTests":{test_auto_creating_bucket:[239,3,1,""],test_auto_creating_bucket_with_acl:[239,3,1,""],test_clean_name:[239,3,1,""],test_clean_name_normalize:[239,3,1,""],test_clean_name_trailing_slash:[239,3,1,""],test_clean_name_windows:[239,3,1,""],test_compress_content_len:[239,3,1,""],test_connection_threading:[239,3,1,""],test_content_type:[239,3,1,""],test_generated_url_is_encoded:[239,3,1,""],test_location_leading_slash:[239,3,1,""],test_override_class_variable:[239,3,1,""],test_override_init_argument:[239,3,1,""],test_pickle_with_bucket:[239,3,1,""],test_pickle_without_bucket:[239,3,1,""],test_special_characters:[239,3,1,""],test_storage_delete:[239,3,1,""],test_storage_exists:[239,3,1,""],test_storage_exists_doesnt_create_bucket:[239,3,1,""],test_storage_exists_false:[239,3,1,""],test_storage_listdir_base:[239,3,1,""],test_storage_listdir_subdir:[239,3,1,""],test_storage_mtime:[239,3,1,""],test_storage_open_no_overwrite_existing:[239,3,1,""],test_storage_open_no_write:[239,3,1,""],test_storage_open_write:[239,3,1,""],test_storage_save:[239,3,1,""],test_storage_save_gzip:[239,3,1,""],test_storage_save_gzip_twice:[239,3,1,""],test_storage_save_gzipped:[239,3,1,""],test_storage_save_with_acl:[239,3,1,""],test_storage_size:[239,3,1,""],test_storage_url:[239,3,1,""],test_storage_url_slashes:[239,3,1,""],test_storage_write_beyond_buffer_size:[239,3,1,""],test_strip_signing_parameters:[239,3,1,""]},"evennia.contrib.base_systems.awsstorage.tests.S3Boto3TestCase":{setUp:[239,3,1,""]},"evennia.contrib.base_systems.building_menu":{building_menu:[241,0,0,"-"],tests:[242,0,0,"-"]},"evennia.contrib.base_systems.building_menu.building_menu":{BuildingMenu:[241,1,1,""],BuildingMenuCmdSet:[241,1,1,""],Choice:[241,1,1,""],CmdNoInput:[241,1,1,""],CmdNoMatch:[241,1,1,""],GenericBuildingCmd:[241,1,1,""],GenericBuildingMenu:[241,1,1,""],menu_edit:[241,5,1,""],menu_quit:[241,5,1,""],menu_setattr:[241,5,1,""]},"evennia.contrib.base_systems.building_menu.building_menu.BuildingMenu":{__init__:[241,3,1,""],add_choice:[241,3,1,""],add_choice_edit:[241,3,1,""],add_choice_quit:[241,3,1,""],close:[241,3,1,""],current_choice:[241,3,1,""],display:[241,3,1,""],display_choice:[241,3,1,""],display_title:[241,3,1,""],init:[241,3,1,""],joker_key:[241,4,1,""],keys_go_back:[241,4,1,""],min_shortcut:[241,4,1,""],move:[241,3,1,""],open:[241,3,1,""],open_parent_menu:[241,3,1,""],open_submenu:[241,3,1,""],relevant_choices:[241,3,1,""],restore:[241,3,1,""],sep_keys:[241,4,1,""]},"evennia.contrib.base_systems.building_menu.building_menu.BuildingMenuCmdSet":{at_cmdset_creation:[241,3,1,""],key:[241,4,1,""],path:[241,4,1,""],priority:[241,4,1,""]},"evennia.contrib.base_systems.building_menu.building_menu.Choice":{__init__:[241,3,1,""],enter:[241,3,1,""],format_text:[241,3,1,""],keys:[241,3,1,""],leave:[241,3,1,""],nomatch:[241,3,1,""]},"evennia.contrib.base_systems.building_menu.building_menu.CmdNoInput":{__init__:[241,3,1,""],aliases:[241,4,1,""],func:[241,3,1,""],help_category:[241,4,1,""],key:[241,4,1,""],lock_storage:[241,4,1,""],locks:[241,4,1,""],search_index_entry:[241,4,1,""]},"evennia.contrib.base_systems.building_menu.building_menu.CmdNoMatch":{__init__:[241,3,1,""],aliases:[241,4,1,""],func:[241,3,1,""],help_category:[241,4,1,""],key:[241,4,1,""],lock_storage:[241,4,1,""],locks:[241,4,1,""],search_index_entry:[241,4,1,""]},"evennia.contrib.base_systems.building_menu.building_menu.GenericBuildingCmd":{aliases:[241,4,1,""],func:[241,3,1,""],help_category:[241,4,1,""],key:[241,4,1,""],lock_storage:[241,4,1,""],search_index_entry:[241,4,1,""]},"evennia.contrib.base_systems.building_menu.building_menu.GenericBuildingMenu":{init:[241,3,1,""]},"evennia.contrib.base_systems.building_menu.tests":{Submenu:[242,1,1,""],TestBuildingMenu:[242,1,1,""]},"evennia.contrib.base_systems.building_menu.tests.Submenu":{init:[242,3,1,""]},"evennia.contrib.base_systems.building_menu.tests.TestBuildingMenu":{setUp:[242,3,1,""],test_add_choice_without_key:[242,3,1,""],test_callbacks:[242,3,1,""],test_multi_level:[242,3,1,""],test_quit:[242,3,1,""],test_setattr:[242,3,1,""],test_submenu:[242,3,1,""]},"evennia.contrib.base_systems.color_markups":{color_markups:[244,0,0,"-"],tests:[245,0,0,"-"]},"evennia.contrib.base_systems.color_markups.tests":{TestColorMarkup:[245,1,1,""]},"evennia.contrib.base_systems.color_markups.tests.TestColorMarkup":{test_curly_markup:[245,3,1,""],test_mux_markup:[245,3,1,""]},"evennia.contrib.base_systems.custom_gametime":{custom_gametime:[247,0,0,"-"],tests:[248,0,0,"-"]},"evennia.contrib.base_systems.custom_gametime.custom_gametime":{GametimeScript:[247,1,1,""],custom_gametime:[247,5,1,""],gametime_to_realtime:[247,5,1,""],real_seconds_until:[247,5,1,""],realtime_to_gametime:[247,5,1,""],schedule:[247,5,1,""],time_to_tuple:[247,5,1,""]},"evennia.contrib.base_systems.custom_gametime.custom_gametime.GametimeScript":{DoesNotExist:[247,2,1,""],MultipleObjectsReturned:[247,2,1,""],at_repeat:[247,3,1,""],at_script_creation:[247,3,1,""],path:[247,4,1,""],typename:[247,4,1,""]},"evennia.contrib.base_systems.custom_gametime.tests":{TestCustomGameTime:[248,1,1,""]},"evennia.contrib.base_systems.custom_gametime.tests.TestCustomGameTime":{tearDown:[248,3,1,""],test_custom_gametime:[248,3,1,""],test_gametime_to_realtime:[248,3,1,""],test_real_seconds_until:[248,3,1,""],test_realtime_to_gametime:[248,3,1,""],test_schedule:[248,3,1,""],test_time_to_tuple:[248,3,1,""]},"evennia.contrib.base_systems.email_login":{connection_screens:[250,0,0,"-"],email_login:[251,0,0,"-"],tests:[252,0,0,"-"]},"evennia.contrib.base_systems.email_login.email_login":{CmdUnconnectedConnect:[251,1,1,""],CmdUnconnectedCreate:[251,1,1,""],CmdUnconnectedHelp:[251,1,1,""],CmdUnconnectedLook:[251,1,1,""],CmdUnconnectedQuit:[251,1,1,""]},"evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedConnect":{aliases:[251,4,1,""],func:[251,3,1,""],help_category:[251,4,1,""],key:[251,4,1,""],lock_storage:[251,4,1,""],locks:[251,4,1,""],search_index_entry:[251,4,1,""]},"evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedCreate":{aliases:[251,4,1,""],func:[251,3,1,""],help_category:[251,4,1,""],key:[251,4,1,""],lock_storage:[251,4,1,""],locks:[251,4,1,""],parse:[251,3,1,""],search_index_entry:[251,4,1,""]},"evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedHelp":{aliases:[251,4,1,""],func:[251,3,1,""],help_category:[251,4,1,""],key:[251,4,1,""],lock_storage:[251,4,1,""],locks:[251,4,1,""],search_index_entry:[251,4,1,""]},"evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedLook":{aliases:[251,4,1,""],func:[251,3,1,""],help_category:[251,4,1,""],key:[251,4,1,""],lock_storage:[251,4,1,""],locks:[251,4,1,""],search_index_entry:[251,4,1,""]},"evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedQuit":{aliases:[251,4,1,""],func:[251,3,1,""],help_category:[251,4,1,""],key:[251,4,1,""],lock_storage:[251,4,1,""],locks:[251,4,1,""],search_index_entry:[251,4,1,""]},"evennia.contrib.base_systems.email_login.tests":{TestEmailLogin:[252,1,1,""]},"evennia.contrib.base_systems.email_login.tests.TestEmailLogin":{test_connect:[252,3,1,""],test_quit:[252,3,1,""],test_unconnectedhelp:[252,3,1,""],test_unconnectedlook:[252,3,1,""]},"evennia.contrib.base_systems.ingame_python":{callbackhandler:[254,0,0,"-"],commands:[255,0,0,"-"],eventfuncs:[256,0,0,"-"],scripts:[257,0,0,"-"],tests:[258,0,0,"-"],utils:[260,0,0,"-"]},"evennia.contrib.base_systems.ingame_python.callbackhandler":{Callback:[254,1,1,""],CallbackHandler:[254,1,1,""]},"evennia.contrib.base_systems.ingame_python.callbackhandler.Callback":{author:[254,3,1,""],code:[254,3,1,""],created_on:[254,3,1,""],name:[254,3,1,""],number:[254,3,1,""],obj:[254,3,1,""],parameters:[254,3,1,""],updated_by:[254,3,1,""],updated_on:[254,3,1,""],valid:[254,3,1,""]},"evennia.contrib.base_systems.ingame_python.callbackhandler.CallbackHandler":{__init__:[254,3,1,""],add:[254,3,1,""],all:[254,3,1,""],call:[254,3,1,""],edit:[254,3,1,""],format_callback:[254,3,1,""],get:[254,3,1,""],get_variable:[254,3,1,""],remove:[254,3,1,""],script:[254,4,1,""]},"evennia.contrib.base_systems.ingame_python.commands":{CmdCallback:[255,1,1,""]},"evennia.contrib.base_systems.ingame_python.commands.CmdCallback":{accept_callback:[255,3,1,""],add_callback:[255,3,1,""],aliases:[255,4,1,""],del_callback:[255,3,1,""],edit_callback:[255,3,1,""],func:[255,3,1,""],get_help:[255,3,1,""],help_category:[255,4,1,""],key:[255,4,1,""],list_callbacks:[255,3,1,""],list_tasks:[255,3,1,""],lock_storage:[255,4,1,""],locks:[255,4,1,""],search_index_entry:[255,4,1,""]},"evennia.contrib.base_systems.ingame_python.eventfuncs":{call_event:[256,5,1,""],deny:[256,5,1,""],get:[256,5,1,""]},"evennia.contrib.base_systems.ingame_python.scripts":{EventHandler:[257,1,1,""],TimeEventScript:[257,1,1,""],complete_task:[257,5,1,""]},"evennia.contrib.base_systems.ingame_python.scripts.EventHandler":{DoesNotExist:[257,2,1,""],MultipleObjectsReturned:[257,2,1,""],accept_callback:[257,3,1,""],add_callback:[257,3,1,""],add_event:[257,3,1,""],at_script_creation:[257,3,1,""],at_server_start:[257,3,1,""],call:[257,3,1,""],del_callback:[257,3,1,""],edit_callback:[257,3,1,""],get_callbacks:[257,3,1,""],get_events:[257,3,1,""],get_variable:[257,3,1,""],handle_error:[257,3,1,""],path:[257,4,1,""],set_task:[257,3,1,""],typename:[257,4,1,""]},"evennia.contrib.base_systems.ingame_python.scripts.TimeEventScript":{DoesNotExist:[257,2,1,""],MultipleObjectsReturned:[257,2,1,""],at_repeat:[257,3,1,""],at_script_creation:[257,3,1,""],path:[257,4,1,""],typename:[257,4,1,""]},"evennia.contrib.base_systems.ingame_python.tests":{TestCmdCallback:[258,1,1,""],TestDefaultCallbacks:[258,1,1,""],TestEventHandler:[258,1,1,""]},"evennia.contrib.base_systems.ingame_python.tests.TestCmdCallback":{setUp:[258,3,1,""],tearDown:[258,3,1,""],test_accept:[258,3,1,""],test_add:[258,3,1,""],test_del:[258,3,1,""],test_list:[258,3,1,""],test_lock:[258,3,1,""]},"evennia.contrib.base_systems.ingame_python.tests.TestDefaultCallbacks":{setUp:[258,3,1,""],tearDown:[258,3,1,""],test_exit:[258,3,1,""]},"evennia.contrib.base_systems.ingame_python.tests.TestEventHandler":{setUp:[258,3,1,""],tearDown:[258,3,1,""],test_accept:[258,3,1,""],test_add_validation:[258,3,1,""],test_call:[258,3,1,""],test_del:[258,3,1,""],test_edit:[258,3,1,""],test_edit_validation:[258,3,1,""],test_handler:[258,3,1,""],test_start:[258,3,1,""]},"evennia.contrib.base_systems.ingame_python.utils":{InterruptEvent:[260,2,1,""],get_event_handler:[260,5,1,""],get_next_wait:[260,5,1,""],keyword_event:[260,5,1,""],phrase_event:[260,5,1,""],register_events:[260,5,1,""],time_event:[260,5,1,""]},"evennia.contrib.base_systems.mux_comms_cmds":{mux_comms_cmds:[266,0,0,"-"],tests:[267,0,0,"-"]},"evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds":{CmdAddCom:[266,1,1,""],CmdAllCom:[266,1,1,""],CmdCBoot:[266,1,1,""],CmdCWho:[266,1,1,""],CmdCdesc:[266,1,1,""],CmdCdestroy:[266,1,1,""],CmdChannelCreate:[266,1,1,""],CmdClock:[266,1,1,""],CmdDelCom:[266,1,1,""],CmdSetLegacyComms:[266,1,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdAddCom":{account_caller:[266,4,1,""],aliases:[266,4,1,""],func:[266,3,1,""],help_category:[266,4,1,""],key:[266,4,1,""],lock_storage:[266,4,1,""],locks:[266,4,1,""],search_index_entry:[266,4,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdAllCom":{account_caller:[266,4,1,""],aliases:[266,4,1,""],func:[266,3,1,""],help_category:[266,4,1,""],key:[266,4,1,""],lock_storage:[266,4,1,""],locks:[266,4,1,""],search_index_entry:[266,4,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdCBoot":{account_caller:[266,4,1,""],aliases:[266,4,1,""],func:[266,3,1,""],help_category:[266,4,1,""],key:[266,4,1,""],lock_storage:[266,4,1,""],locks:[266,4,1,""],search_index_entry:[266,4,1,""],switch_options:[266,4,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdCWho":{account_caller:[266,4,1,""],aliases:[266,4,1,""],func:[266,3,1,""],help_category:[266,4,1,""],key:[266,4,1,""],lock_storage:[266,4,1,""],locks:[266,4,1,""],search_index_entry:[266,4,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdCdesc":{account_caller:[266,4,1,""],aliases:[266,4,1,""],func:[266,3,1,""],help_category:[266,4,1,""],key:[266,4,1,""],lock_storage:[266,4,1,""],locks:[266,4,1,""],search_index_entry:[266,4,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdCdestroy":{account_caller:[266,4,1,""],aliases:[266,4,1,""],func:[266,3,1,""],help_category:[266,4,1,""],key:[266,4,1,""],lock_storage:[266,4,1,""],locks:[266,4,1,""],search_index_entry:[266,4,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdChannelCreate":{account_caller:[266,4,1,""],aliases:[266,4,1,""],func:[266,3,1,""],help_category:[266,4,1,""],key:[266,4,1,""],lock_storage:[266,4,1,""],locks:[266,4,1,""],search_index_entry:[266,4,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdClock":{account_caller:[266,4,1,""],aliases:[266,4,1,""],func:[266,3,1,""],help_category:[266,4,1,""],key:[266,4,1,""],lock_storage:[266,4,1,""],locks:[266,4,1,""],search_index_entry:[266,4,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdDelCom":{account_caller:[266,4,1,""],aliases:[266,4,1,""],func:[266,3,1,""],help_category:[266,4,1,""],key:[266,4,1,""],lock_storage:[266,4,1,""],locks:[266,4,1,""],search_index_entry:[266,4,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdSetLegacyComms":{at_cmdset_createion:[266,3,1,""],path:[266,4,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.tests":{TestLegacyMuxComms:[267,1,1,""]},"evennia.contrib.base_systems.mux_comms_cmds.tests.TestLegacyMuxComms":{setUp:[267,3,1,""],test_all_com:[267,3,1,""],test_cboot:[267,3,1,""],test_cdesc:[267,3,1,""],test_cdestroy:[267,3,1,""],test_clock:[267,3,1,""],test_cwho:[267,3,1,""],test_toggle_com:[267,3,1,""]},"evennia.contrib.base_systems.unixcommand":{tests:[269,0,0,"-"],unixcommand:[270,0,0,"-"]},"evennia.contrib.base_systems.unixcommand.tests":{CmdDummy:[269,1,1,""],TestUnixCommand:[269,1,1,""]},"evennia.contrib.base_systems.unixcommand.tests.CmdDummy":{aliases:[269,4,1,""],func:[269,3,1,""],help_category:[269,4,1,""],init_parser:[269,3,1,""],key:[269,4,1,""],lock_storage:[269,4,1,""],search_index_entry:[269,4,1,""]},"evennia.contrib.base_systems.unixcommand.tests.TestUnixCommand":{test_failure:[269,3,1,""],test_success:[269,3,1,""]},"evennia.contrib.base_systems.unixcommand.unixcommand":{HelpAction:[270,1,1,""],ParseError:[270,2,1,""],UnixCommand:[270,1,1,""],UnixCommandParser:[270,1,1,""]},"evennia.contrib.base_systems.unixcommand.unixcommand.UnixCommand":{__init__:[270,3,1,""],aliases:[270,4,1,""],func:[270,3,1,""],get_help:[270,3,1,""],help_category:[270,4,1,""],init_parser:[270,3,1,""],key:[270,4,1,""],lock_storage:[270,4,1,""],parse:[270,3,1,""],search_index_entry:[270,4,1,""]},"evennia.contrib.base_systems.unixcommand.unixcommand.UnixCommandParser":{__init__:[270,3,1,""],format_help:[270,3,1,""],format_usage:[270,3,1,""],print_help:[270,3,1,""],print_usage:[270,3,1,""]},"evennia.contrib.full_systems":{evscaperoom:[272,0,0,"-"]},"evennia.contrib.full_systems.evscaperoom":{commands:[273,0,0,"-"],menu:[274,0,0,"-"],objects:[275,0,0,"-"],room:[276,0,0,"-"],scripts:[277,0,0,"-"],state:[278,0,0,"-"],tests:[279,0,0,"-"],utils:[280,0,0,"-"]},"evennia.contrib.full_systems.evscaperoom.commands":{CmdCreateObj:[273,1,1,""],CmdEmote:[273,1,1,""],CmdEvscapeRoom:[273,1,1,""],CmdEvscapeRoomStart:[273,1,1,""],CmdFocus:[273,1,1,""],CmdFocusInteraction:[273,1,1,""],CmdGet:[273,1,1,""],CmdGiveUp:[273,1,1,""],CmdHelp:[273,1,1,""],CmdJumpState:[273,1,1,""],CmdLook:[273,1,1,""],CmdOptions:[273,1,1,""],CmdRerouter:[273,1,1,""],CmdSetEvScapeRoom:[273,1,1,""],CmdSetFlag:[273,1,1,""],CmdSpeak:[273,1,1,""],CmdStand:[273,1,1,""],CmdWho:[273,1,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdCreateObj":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],locks:[273,4,1,""],obj1_search:[273,4,1,""],obj2_search:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdEmote":{aliases:[273,4,1,""],arg_regex:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],room_replace:[273,3,1,""],search_index_entry:[273,4,1,""],you_replace:[273,3,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdEvscapeRoom":{aliases:[273,4,1,""],arg_regex:[273,4,1,""],focus:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],obj1_search:[273,4,1,""],obj2_search:[273,4,1,""],parse:[273,3,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdEvscapeRoomStart":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdFocus":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],obj1_search:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdFocusInteraction":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],obj1_search:[273,4,1,""],obj2_search:[273,4,1,""],parse:[273,3,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdGet":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdGiveUp":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdHelp":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdJumpState":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],locks:[273,4,1,""],obj1_search:[273,4,1,""],obj2_search:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdLook":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],obj1_search:[273,4,1,""],obj2_search:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdOptions":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdRerouter":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdSetEvScapeRoom":{at_cmdset_creation:[273,3,1,""],path:[273,4,1,""],priority:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdSetFlag":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],locks:[273,4,1,""],obj1_search:[273,4,1,""],obj2_search:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdSpeak":{aliases:[273,4,1,""],arg_regex:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdStand":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.commands.CmdWho":{aliases:[273,4,1,""],func:[273,3,1,""],help_category:[273,4,1,""],key:[273,4,1,""],lock_storage:[273,4,1,""],obj1_search:[273,4,1,""],obj2_search:[273,4,1,""],search_index_entry:[273,4,1,""]},"evennia.contrib.full_systems.evscaperoom.menu":{EvscaperoomMenu:[274,1,1,""],OptionsMenu:[274,1,1,""],node_create_room:[274,5,1,""],node_join_room:[274,5,1,""],node_options:[274,5,1,""],node_quit:[274,5,1,""],node_set_desc:[274,5,1,""],run_evscaperoom_menu:[274,5,1,""],run_option_menu:[274,5,1,""]},"evennia.contrib.full_systems.evscaperoom.menu.EvscaperoomMenu":{node_border_char:[274,4,1,""],nodetext_formatter:[274,3,1,""],options_formatter:[274,3,1,""]},"evennia.contrib.full_systems.evscaperoom.menu.OptionsMenu":{node_formatter:[274,3,1,""]},"evennia.contrib.full_systems.evscaperoom.objects":{BaseApplicable:[275,1,1,""],BaseConsumable:[275,1,1,""],BasePositionable:[275,1,1,""],Climbable:[275,1,1,""],CodeInput:[275,1,1,""],Combinable:[275,1,1,""],Drinkable:[275,1,1,""],Edible:[275,1,1,""],EvscaperoomObject:[275,1,1,""],Feelable:[275,1,1,""],HasButtons:[275,1,1,""],IndexReadable:[275,1,1,""],Insertable:[275,1,1,""],Kneelable:[275,1,1,""],Liable:[275,1,1,""],Listenable:[275,1,1,""],Mixable:[275,1,1,""],Movable:[275,1,1,""],Openable:[275,1,1,""],Positionable:[275,1,1,""],Readable:[275,1,1,""],Rotatable:[275,1,1,""],Sittable:[275,1,1,""],Smellable:[275,1,1,""],Usable:[275,1,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.BaseApplicable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_apply:[275,3,1,""],at_cannot_apply:[275,3,1,""],handle_apply:[275,3,1,""],path:[275,4,1,""],target_flag:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.BaseConsumable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_already_consumed:[275,3,1,""],at_consume:[275,3,1,""],consume_flag:[275,4,1,""],handle_consume:[275,3,1,""],has_consumed:[275,3,1,""],one_consume_only:[275,4,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.BasePositionable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_again_position:[275,3,1,""],at_cannot_position:[275,3,1,""],at_object_creation:[275,3,1,""],at_position:[275,3,1,""],handle_position:[275,3,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Climbable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_focus_climb:[275,3,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.CodeInput":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_code_correct:[275,3,1,""],at_code_incorrect:[275,3,1,""],at_focus_code:[275,3,1,""],at_no_code:[275,3,1,""],case_insensitive:[275,4,1,""],code:[275,4,1,""],code_hint:[275,4,1,""],get_cmd_signatures:[275,3,1,""],infinitely_locked:[275,4,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Combinable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_apply:[275,3,1,""],at_cannot_apply:[275,3,1,""],at_focus_combine:[275,3,1,""],destroy_components:[275,4,1,""],get_cmd_signatures:[275,3,1,""],new_create_dict:[275,4,1,""],path:[275,4,1,""],target_flag:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Drinkable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_already_consumed:[275,3,1,""],at_consume:[275,3,1,""],at_focus_drink:[275,3,1,""],at_focus_sip:[275,3,1,""],consume_flag:[275,4,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Edible":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_focus_eat:[275,3,1,""],consume_flag:[275,4,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.EvscaperoomObject":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],action_prepositions:[275,4,1,""],at_focus:[275,3,1,""],at_object_creation:[275,3,1,""],at_speech:[275,3,1,""],at_unfocus:[275,3,1,""],check_character_flag:[275,3,1,""],check_flag:[275,3,1,""],get_cmd_signatures:[275,3,1,""],get_help:[275,3,1,""],get_position:[275,3,1,""],get_short_desc:[275,3,1,""],msg_char:[275,3,1,""],msg_room:[275,3,1,""],msg_system:[275,3,1,""],next_state:[275,3,1,""],parse:[275,3,1,""],path:[275,4,1,""],position_prep_map:[275,4,1,""],return_appearance:[275,3,1,""],room:[275,3,1,""],roomstate:[275,3,1,""],set_character_flag:[275,3,1,""],set_flag:[275,3,1,""],set_position:[275,3,1,""],tagcategory:[275,3,1,""],typename:[275,4,1,""],unset_character_flag:[275,3,1,""],unset_flag:[275,3,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Feelable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_focus_feel:[275,3,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.HasButtons":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_focus_press:[275,3,1,""],at_focus_push:[275,3,1,""],at_green_button:[275,3,1,""],at_nomatch:[275,3,1,""],at_red_button:[275,3,1,""],buttons:[275,4,1,""],get_cmd_signatures:[275,3,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.IndexReadable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_cannot_read:[275,3,1,""],at_focus_read:[275,3,1,""],at_read:[275,3,1,""],get_cmd_signatures:[275,3,1,""],index:[275,4,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Insertable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_apply:[275,3,1,""],at_cannot_apply:[275,3,1,""],at_focus_insert:[275,3,1,""],get_cmd_signatures:[275,3,1,""],path:[275,4,1,""],target_flag:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Kneelable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_focus_kneel:[275,3,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Liable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_focus_lie:[275,3,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Listenable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_focus_listen:[275,3,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Mixable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_mix:[275,3,1,""],at_mix_failure:[275,3,1,""],at_mix_success:[275,3,1,""],at_object_creation:[275,3,1,""],check_mixture:[275,3,1,""],handle_mix:[275,3,1,""],ingredient_recipe:[275,4,1,""],mixer_flag:[275,4,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Movable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_already_moved:[275,3,1,""],at_cannot_move:[275,3,1,""],at_focus_move:[275,3,1,""],at_focus_push:[275,3,1,""],at_focus_shove:[275,3,1,""],at_left:[275,3,1,""],at_object_creation:[275,3,1,""],at_right:[275,3,1,""],get_cmd_signatures:[275,3,1,""],move_positions:[275,4,1,""],path:[275,4,1,""],start_position:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Openable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_already_closed:[275,3,1,""],at_already_open:[275,3,1,""],at_close:[275,3,1,""],at_focus_close:[275,3,1,""],at_focus_open:[275,3,1,""],at_locked:[275,3,1,""],at_object_creation:[275,3,1,""],at_open:[275,3,1,""],open_flag:[275,4,1,""],path:[275,4,1,""],start_open:[275,4,1,""],typename:[275,4,1,""],unlock_flag:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Positionable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],get_cmd_signatures:[275,3,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Readable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_cannot_read:[275,3,1,""],at_focus_read:[275,3,1,""],at_object_creation:[275,3,1,""],at_read:[275,3,1,""],path:[275,4,1,""],read_flag:[275,4,1,""],start_readable:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Rotatable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_cannot_rotate:[275,3,1,""],at_focus_rotate:[275,3,1,""],at_focus_turn:[275,3,1,""],at_object_creation:[275,3,1,""],at_rotate:[275,3,1,""],path:[275,4,1,""],rotate_flag:[275,4,1,""],start_rotatable:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Sittable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_focus_sit:[275,3,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Smellable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_focus_smell:[275,3,1,""],path:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.objects.Usable":{DoesNotExist:[275,2,1,""],MultipleObjectsReturned:[275,2,1,""],at_apply:[275,3,1,""],at_cannot_apply:[275,3,1,""],at_focus_use:[275,3,1,""],path:[275,4,1,""],target_flag:[275,4,1,""],typename:[275,4,1,""]},"evennia.contrib.full_systems.evscaperoom.room":{EvscapeRoom:[276,1,1,""]},"evennia.contrib.full_systems.evscaperoom.room.EvscapeRoom":{"delete":[276,3,1,""],DoesNotExist:[276,2,1,""],MultipleObjectsReturned:[276,2,1,""],achievement:[276,3,1,""],at_object_creation:[276,3,1,""],at_object_leave:[276,3,1,""],at_object_receive:[276,3,1,""],character_cleanup:[276,3,1,""],character_exit:[276,3,1,""],check_flag:[276,3,1,""],check_perm:[276,3,1,""],get_all_characters:[276,3,1,""],log:[276,3,1,""],path:[276,4,1,""],progress:[276,3,1,""],return_appearance:[276,3,1,""],score:[276,3,1,""],set_flag:[276,3,1,""],state:[276,3,1,""],statehandler:[276,4,1,""],tag_all_characters:[276,3,1,""],tag_character:[276,3,1,""],typename:[276,4,1,""],unset_flag:[276,3,1,""]},"evennia.contrib.full_systems.evscaperoom.scripts":{CleanupScript:[277,1,1,""]},"evennia.contrib.full_systems.evscaperoom.scripts.CleanupScript":{DoesNotExist:[277,2,1,""],MultipleObjectsReturned:[277,2,1,""],at_repeat:[277,3,1,""],at_script_creation:[277,3,1,""],path:[277,4,1,""],typename:[277,4,1,""]},"evennia.contrib.full_systems.evscaperoom.state":{BaseState:[278,1,1,""],StateHandler:[278,1,1,""]},"evennia.contrib.full_systems.evscaperoom.state.BaseState":{__init__:[278,3,1,""],character_enters:[278,3,1,""],character_leaves:[278,3,1,""],cinematic:[278,3,1,""],clean:[278,3,1,""],create_object:[278,3,1,""],get_hint:[278,3,1,""],get_object:[278,3,1,""],hints:[278,4,1,""],init:[278,3,1,""],msg:[278,3,1,""],next:[278,3,1,""],next_state:[278,4,1,""]},"evennia.contrib.full_systems.evscaperoom.state.StateHandler":{__init__:[278,3,1,""],init_state:[278,3,1,""],load_state:[278,3,1,""],next_state:[278,3,1,""]},"evennia.contrib.full_systems.evscaperoom.tests":{TestEvScapeRoom:[279,1,1,""],TestEvscaperoomCommands:[279,1,1,""],TestStates:[279,1,1,""],TestUtils:[279,1,1,""]},"evennia.contrib.full_systems.evscaperoom.tests.TestEvScapeRoom":{setUp:[279,3,1,""],tearDown:[279,3,1,""],test_room_methods:[279,3,1,""]},"evennia.contrib.full_systems.evscaperoom.tests.TestEvscaperoomCommands":{setUp:[279,3,1,""],test_base_parse:[279,3,1,""],test_base_search:[279,3,1,""],test_emote:[279,3,1,""],test_focus:[279,3,1,""],test_focus_interaction:[279,3,1,""],test_look:[279,3,1,""],test_set_focus:[279,3,1,""],test_speech:[279,3,1,""]},"evennia.contrib.full_systems.evscaperoom.tests.TestStates":{setUp:[279,3,1,""],tearDown:[279,3,1,""],test_all_states:[279,3,1,""],test_base_state:[279,3,1,""]},"evennia.contrib.full_systems.evscaperoom.tests.TestUtils":{test_overwrite:[279,3,1,""],test_parse_for_perspectives:[279,3,1,""],test_parse_for_things:[279,3,1,""]},"evennia.contrib.full_systems.evscaperoom.utils":{add_msg_borders:[280,5,1,""],create_evscaperoom_object:[280,5,1,""],create_fantasy_word:[280,5,1,""],msg_cinematic:[280,5,1,""],parse_for_perspectives:[280,5,1,""],parse_for_things:[280,5,1,""]},"evennia.contrib.game_systems":{barter:[282,0,0,"-"],clothing:[285,0,0,"-"],cooldowns:[288,0,0,"-"],crafting:[291,0,0,"-"],gendersub:[295,0,0,"-"],mail:[298,0,0,"-"],multidescer:[301,0,0,"-"],puzzles:[304,0,0,"-"],turnbattle:[307,0,0,"-"]},"evennia.contrib.game_systems.barter":{barter:[283,0,0,"-"],tests:[284,0,0,"-"]},"evennia.contrib.game_systems.barter.barter":{CmdAccept:[283,1,1,""],CmdDecline:[283,1,1,""],CmdEvaluate:[283,1,1,""],CmdFinish:[283,1,1,""],CmdOffer:[283,1,1,""],CmdStatus:[283,1,1,""],CmdTrade:[283,1,1,""],CmdTradeBase:[283,1,1,""],CmdTradeHelp:[283,1,1,""],CmdsetTrade:[283,1,1,""],TradeHandler:[283,1,1,""],TradeTimeout:[283,1,1,""]},"evennia.contrib.game_systems.barter.barter.CmdAccept":{aliases:[283,4,1,""],func:[283,3,1,""],help_category:[283,4,1,""],key:[283,4,1,""],lock_storage:[283,4,1,""],locks:[283,4,1,""],search_index_entry:[283,4,1,""]},"evennia.contrib.game_systems.barter.barter.CmdDecline":{aliases:[283,4,1,""],func:[283,3,1,""],help_category:[283,4,1,""],key:[283,4,1,""],lock_storage:[283,4,1,""],locks:[283,4,1,""],search_index_entry:[283,4,1,""]},"evennia.contrib.game_systems.barter.barter.CmdEvaluate":{aliases:[283,4,1,""],func:[283,3,1,""],help_category:[283,4,1,""],key:[283,4,1,""],lock_storage:[283,4,1,""],locks:[283,4,1,""],search_index_entry:[283,4,1,""]},"evennia.contrib.game_systems.barter.barter.CmdFinish":{aliases:[283,4,1,""],func:[283,3,1,""],help_category:[283,4,1,""],key:[283,4,1,""],lock_storage:[283,4,1,""],locks:[283,4,1,""],search_index_entry:[283,4,1,""]},"evennia.contrib.game_systems.barter.barter.CmdOffer":{aliases:[283,4,1,""],func:[283,3,1,""],help_category:[283,4,1,""],key:[283,4,1,""],lock_storage:[283,4,1,""],locks:[283,4,1,""],search_index_entry:[283,4,1,""]},"evennia.contrib.game_systems.barter.barter.CmdStatus":{aliases:[283,4,1,""],func:[283,3,1,""],help_category:[283,4,1,""],key:[283,4,1,""],lock_storage:[283,4,1,""],locks:[283,4,1,""],search_index_entry:[283,4,1,""]},"evennia.contrib.game_systems.barter.barter.CmdTrade":{aliases:[283,4,1,""],func:[283,3,1,""],help_category:[283,4,1,""],key:[283,4,1,""],lock_storage:[283,4,1,""],locks:[283,4,1,""],search_index_entry:[283,4,1,""]},"evennia.contrib.game_systems.barter.barter.CmdTradeBase":{aliases:[283,4,1,""],help_category:[283,4,1,""],key:[283,4,1,""],lock_storage:[283,4,1,""],parse:[283,3,1,""],search_index_entry:[283,4,1,""]},"evennia.contrib.game_systems.barter.barter.CmdTradeHelp":{aliases:[283,4,1,""],func:[283,3,1,""],help_category:[283,4,1,""],key:[283,4,1,""],lock_storage:[283,4,1,""],locks:[283,4,1,""],search_index_entry:[283,4,1,""]},"evennia.contrib.game_systems.barter.barter.CmdsetTrade":{at_cmdset_creation:[283,3,1,""],key:[283,4,1,""],path:[283,4,1,""]},"evennia.contrib.game_systems.barter.barter.TradeHandler":{__init__:[283,3,1,""],accept:[283,3,1,""],decline:[283,3,1,""],finish:[283,3,1,""],get_other:[283,3,1,""],join:[283,3,1,""],list:[283,3,1,""],msg_other:[283,3,1,""],offer:[283,3,1,""],search:[283,3,1,""],unjoin:[283,3,1,""]},"evennia.contrib.game_systems.barter.barter.TradeTimeout":{DoesNotExist:[283,2,1,""],MultipleObjectsReturned:[283,2,1,""],at_repeat:[283,3,1,""],at_script_creation:[283,3,1,""],is_valid:[283,3,1,""],path:[283,4,1,""],typename:[283,4,1,""]},"evennia.contrib.game_systems.barter.tests":{TestBarter:[284,1,1,""]},"evennia.contrib.game_systems.barter.tests.TestBarter":{setUp:[284,3,1,""],test_cmdtrade:[284,3,1,""],test_cmdtradehelp:[284,3,1,""],test_tradehandler_base:[284,3,1,""],test_tradehandler_joins:[284,3,1,""],test_tradehandler_offers:[284,3,1,""]},"evennia.contrib.game_systems.clothing":{clothing:[286,0,0,"-"],tests:[287,0,0,"-"]},"evennia.contrib.game_systems.clothing.clothing":{ClothedCharacter:[286,1,1,""],ClothedCharacterCmdSet:[286,1,1,""],CmdCover:[286,1,1,""],CmdDrop:[286,1,1,""],CmdGive:[286,1,1,""],CmdInventory:[286,1,1,""],CmdRemove:[286,1,1,""],CmdUncover:[286,1,1,""],CmdWear:[286,1,1,""],ContribClothing:[286,1,1,""],clothing_type_count:[286,5,1,""],get_worn_clothes:[286,5,1,""],order_clothes_list:[286,5,1,""],single_type_count:[286,5,1,""]},"evennia.contrib.game_systems.clothing.clothing.ClothedCharacter":{DoesNotExist:[286,2,1,""],MultipleObjectsReturned:[286,2,1,""],path:[286,4,1,""],return_appearance:[286,3,1,""],typename:[286,4,1,""]},"evennia.contrib.game_systems.clothing.clothing.ClothedCharacterCmdSet":{at_cmdset_creation:[286,3,1,""],key:[286,4,1,""],path:[286,4,1,""]},"evennia.contrib.game_systems.clothing.clothing.CmdCover":{aliases:[286,4,1,""],func:[286,3,1,""],help_category:[286,4,1,""],key:[286,4,1,""],lock_storage:[286,4,1,""],search_index_entry:[286,4,1,""]},"evennia.contrib.game_systems.clothing.clothing.CmdDrop":{aliases:[286,4,1,""],arg_regex:[286,4,1,""],func:[286,3,1,""],help_category:[286,4,1,""],key:[286,4,1,""],lock_storage:[286,4,1,""],locks:[286,4,1,""],search_index_entry:[286,4,1,""]},"evennia.contrib.game_systems.clothing.clothing.CmdGive":{aliases:[286,4,1,""],arg_regex:[286,4,1,""],func:[286,3,1,""],help_category:[286,4,1,""],key:[286,4,1,""],lock_storage:[286,4,1,""],locks:[286,4,1,""],search_index_entry:[286,4,1,""]},"evennia.contrib.game_systems.clothing.clothing.CmdInventory":{aliases:[286,4,1,""],arg_regex:[286,4,1,""],func:[286,3,1,""],help_category:[286,4,1,""],key:[286,4,1,""],lock_storage:[286,4,1,""],locks:[286,4,1,""],search_index_entry:[286,4,1,""]},"evennia.contrib.game_systems.clothing.clothing.CmdRemove":{aliases:[286,4,1,""],func:[286,3,1,""],help_category:[286,4,1,""],key:[286,4,1,""],lock_storage:[286,4,1,""],search_index_entry:[286,4,1,""]},"evennia.contrib.game_systems.clothing.clothing.CmdUncover":{aliases:[286,4,1,""],func:[286,3,1,""],help_category:[286,4,1,""],key:[286,4,1,""],lock_storage:[286,4,1,""],search_index_entry:[286,4,1,""]},"evennia.contrib.game_systems.clothing.clothing.CmdWear":{aliases:[286,4,1,""],func:[286,3,1,""],help_category:[286,4,1,""],key:[286,4,1,""],lock_storage:[286,4,1,""],search_index_entry:[286,4,1,""]},"evennia.contrib.game_systems.clothing.clothing.ContribClothing":{DoesNotExist:[286,2,1,""],MultipleObjectsReturned:[286,2,1,""],at_get:[286,3,1,""],path:[286,4,1,""],remove:[286,3,1,""],typename:[286,4,1,""],wear:[286,3,1,""]},"evennia.contrib.game_systems.clothing.tests":{TestClothingCmd:[287,1,1,""],TestClothingFunc:[287,1,1,""]},"evennia.contrib.game_systems.clothing.tests.TestClothingCmd":{test_clothingcommands:[287,3,1,""]},"evennia.contrib.game_systems.clothing.tests.TestClothingFunc":{test_clothingfunctions:[287,3,1,""]},"evennia.contrib.game_systems.cooldowns":{cooldowns:[289,0,0,"-"],tests:[290,0,0,"-"]},"evennia.contrib.game_systems.cooldowns.cooldowns":{CooldownHandler:[289,1,1,""]},"evennia.contrib.game_systems.cooldowns.cooldowns.CooldownHandler":{__init__:[289,3,1,""],add:[289,3,1,""],all:[289,3,1,""],cleanup:[289,3,1,""],clear:[289,3,1,""],data:[289,4,1,""],db_attribute:[289,4,1,""],extend:[289,3,1,""],obj:[289,4,1,""],ready:[289,3,1,""],reset:[289,3,1,""],set:[289,3,1,""],time_left:[289,3,1,""]},"evennia.contrib.game_systems.cooldowns.tests":{TestCooldowns:[290,1,1,""]},"evennia.contrib.game_systems.cooldowns.tests.TestCooldowns":{setUp:[290,3,1,""],test_add:[290,3,1,""],test_add_float:[290,3,1,""],test_add_multi:[290,3,1,""],test_add_negative:[290,3,1,""],test_add_none:[290,3,1,""],test_add_overwrite:[290,3,1,""],test_cleanup:[290,3,1,""],test_cleanup_doesnt_delete_anything:[290,3,1,""],test_clear:[290,3,1,""],test_empty:[290,3,1,""],test_extend:[290,3,1,""],test_extend_float:[290,3,1,""],test_extend_negative:[290,3,1,""],test_extend_none:[290,3,1,""],test_reset:[290,3,1,""],test_reset_non_existent:[290,3,1,""]},"evennia.contrib.game_systems.crafting":{crafting:[292,0,0,"-"],example_recipes:[293,0,0,"-"],tests:[294,0,0,"-"]},"evennia.contrib.game_systems.crafting.crafting":{CmdCraft:[292,1,1,""],CraftingCmdSet:[292,1,1,""],CraftingError:[292,2,1,""],CraftingRecipe:[292,1,1,""],CraftingRecipeBase:[292,1,1,""],CraftingValidationError:[292,2,1,""],craft:[292,5,1,""]},"evennia.contrib.game_systems.crafting.crafting.CmdCraft":{aliases:[292,4,1,""],arg_regex:[292,4,1,""],func:[292,3,1,""],help_category:[292,4,1,""],key:[292,4,1,""],lock_storage:[292,4,1,""],locks:[292,4,1,""],parse:[292,3,1,""],search_index_entry:[292,4,1,""]},"evennia.contrib.game_systems.crafting.crafting.CraftingCmdSet":{at_cmdset_creation:[292,3,1,""],key:[292,4,1,""],path:[292,4,1,""]},"evennia.contrib.game_systems.crafting.crafting.CraftingRecipe":{__init__:[292,3,1,""],consumable_names:[292,4,1,""],consumable_tag_category:[292,4,1,""],consumable_tags:[292,4,1,""],consume_on_fail:[292,4,1,""],do_craft:[292,3,1,""],error_consumable_excess_message:[292,4,1,""],error_consumable_missing_message:[292,4,1,""],error_consumable_order_message:[292,4,1,""],error_tool_excess_message:[292,4,1,""],error_tool_missing_message:[292,4,1,""],error_tool_order_message:[292,4,1,""],exact_consumable_order:[292,4,1,""],exact_consumables:[292,4,1,""],exact_tool_order:[292,4,1,""],exact_tools:[292,4,1,""],failure_message:[292,4,1,""],name:[292,4,1,""],output_names:[292,4,1,""],output_prototypes:[292,4,1,""],post_craft:[292,3,1,""],pre_craft:[292,3,1,""],seed:[292,3,1,""],success_message:[292,4,1,""],tool_names:[292,4,1,""],tool_tag_category:[292,4,1,""],tool_tags:[292,4,1,""]},"evennia.contrib.game_systems.crafting.crafting.CraftingRecipeBase":{__init__:[292,3,1,""],allow_reuse:[292,4,1,""],craft:[292,3,1,""],do_craft:[292,3,1,""],msg:[292,3,1,""],name:[292,4,1,""],post_craft:[292,3,1,""],pre_craft:[292,3,1,""]},"evennia.contrib.game_systems.crafting.example_recipes":{CmdCast:[293,1,1,""],CrucibleSteelRecipe:[293,1,1,""],FireballRecipe:[293,1,1,""],HealingRecipe:[293,1,1,""],LeatherRecipe:[293,1,1,""],OakBarkRecipe:[293,1,1,""],PigIronRecipe:[293,1,1,""],RawhideRecipe:[293,1,1,""],SwordBladeRecipe:[293,1,1,""],SwordGuardRecipe:[293,1,1,""],SwordHandleRecipe:[293,1,1,""],SwordPommelRecipe:[293,1,1,""],SwordRecipe:[293,1,1,""],random:[293,5,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.CmdCast":{aliases:[293,4,1,""],func:[293,3,1,""],help_category:[293,4,1,""],key:[293,4,1,""],lock_storage:[293,4,1,""],parse:[293,3,1,""],search_index_entry:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.CrucibleSteelRecipe":{consumable_tags:[293,4,1,""],name:[293,4,1,""],output_prototypes:[293,4,1,""],tool_tags:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.FireballRecipe":{desired_effects:[293,4,1,""],failure_effects:[293,4,1,""],name:[293,4,1,""],skill_requirements:[293,4,1,""],skill_roll:[293,4,1,""],success_message:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.HealingRecipe":{desired_effects:[293,4,1,""],failure_effects:[293,4,1,""],name:[293,4,1,""],skill_requirements:[293,4,1,""],skill_roll:[293,4,1,""],success_message:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.LeatherRecipe":{consumable_tags:[293,4,1,""],name:[293,4,1,""],output_prototypes:[293,4,1,""],tool_tags:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.OakBarkRecipe":{consumable_tags:[293,4,1,""],name:[293,4,1,""],output_prototypes:[293,4,1,""],tool_tags:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.PigIronRecipe":{consumable_tags:[293,4,1,""],name:[293,4,1,""],output_prototypes:[293,4,1,""],tool_tags:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.RawhideRecipe":{consumable_tags:[293,4,1,""],name:[293,4,1,""],output_prototypes:[293,4,1,""],tool_tags:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.SwordBladeRecipe":{consumable_tags:[293,4,1,""],name:[293,4,1,""],output_prototypes:[293,4,1,""],tool_tags:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.SwordGuardRecipe":{consumable_tags:[293,4,1,""],name:[293,4,1,""],output_prototypes:[293,4,1,""],tool_tags:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.SwordHandleRecipe":{consumable_tags:[293,4,1,""],name:[293,4,1,""],output_prototypes:[293,4,1,""],tool_tags:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.SwordPommelRecipe":{consumable_tags:[293,4,1,""],name:[293,4,1,""],output_prototypes:[293,4,1,""],tool_tags:[293,4,1,""]},"evennia.contrib.game_systems.crafting.example_recipes.SwordRecipe":{consumable_tags:[293,4,1,""],exact_consumable_order:[293,4,1,""],name:[293,4,1,""],output_prototypes:[293,4,1,""],tool_tags:[293,4,1,""]},"evennia.contrib.game_systems.crafting.tests":{TestCraftCommand:[294,1,1,""],TestCraftSword:[294,1,1,""],TestCraftUtils:[294,1,1,""],TestCraftingRecipe:[294,1,1,""],TestCraftingRecipeBase:[294,1,1,""]},"evennia.contrib.game_systems.crafting.tests.TestCraftCommand":{setUp:[294,3,1,""],test_craft__nocons__failure:[294,3,1,""],test_craft__notools__failure:[294,3,1,""],test_craft__success:[294,3,1,""]},"evennia.contrib.game_systems.crafting.tests.TestCraftSword":{setUp:[294,3,1,""],test_craft_sword:[294,3,1,""]},"evennia.contrib.game_systems.crafting.tests.TestCraftUtils":{maxDiff:[294,4,1,""],test_load_recipes:[294,3,1,""]},"evennia.contrib.game_systems.crafting.tests.TestCraftingRecipe":{maxDiff:[294,4,1,""],setUp:[294,3,1,""],tearDown:[294,3,1,""],test_craft__success:[294,3,1,""],test_craft_cons_excess__fail:[294,3,1,""],test_craft_cons_excess__sucess:[294,3,1,""],test_craft_cons_order__fail:[294,3,1,""],test_craft_missing_cons__always_consume__fail:[294,3,1,""],test_craft_missing_cons__fail:[294,3,1,""],test_craft_missing_tool__fail:[294,3,1,""],test_craft_tool_excess__fail:[294,3,1,""],test_craft_tool_excess__sucess:[294,3,1,""],test_craft_tool_order__fail:[294,3,1,""],test_craft_wrong_tool__fail:[294,3,1,""],test_error_format:[294,3,1,""],test_seed__success:[294,3,1,""]},"evennia.contrib.game_systems.crafting.tests.TestCraftingRecipeBase":{setUp:[294,3,1,""],test_craft_hook__fail:[294,3,1,""],test_craft_hook__succeed:[294,3,1,""],test_msg:[294,3,1,""],test_pre_craft:[294,3,1,""],test_pre_craft_fail:[294,3,1,""]},"evennia.contrib.game_systems.gendersub":{gendersub:[296,0,0,"-"],tests:[297,0,0,"-"]},"evennia.contrib.game_systems.gendersub.gendersub":{GenderCharacter:[296,1,1,""],SetGender:[296,1,1,""]},"evennia.contrib.game_systems.gendersub.gendersub.GenderCharacter":{DoesNotExist:[296,2,1,""],MultipleObjectsReturned:[296,2,1,""],at_object_creation:[296,3,1,""],msg:[296,3,1,""],path:[296,4,1,""],typename:[296,4,1,""]},"evennia.contrib.game_systems.gendersub.gendersub.SetGender":{aliases:[296,4,1,""],func:[296,3,1,""],help_category:[296,4,1,""],key:[296,4,1,""],lock_storage:[296,4,1,""],locks:[296,4,1,""],search_index_entry:[296,4,1,""]},"evennia.contrib.game_systems.gendersub.tests":{TestGenderSub:[297,1,1,""]},"evennia.contrib.game_systems.gendersub.tests.TestGenderSub":{test_gendercharacter:[297,3,1,""],test_setgender:[297,3,1,""]},"evennia.contrib.game_systems.mail":{mail:[299,0,0,"-"],tests:[300,0,0,"-"]},"evennia.contrib.game_systems.mail.mail":{CmdMail:[299,1,1,""],CmdMailCharacter:[299,1,1,""]},"evennia.contrib.game_systems.mail.mail.CmdMail":{aliases:[299,4,1,""],func:[299,3,1,""],get_all_mail:[299,3,1,""],help_category:[299,4,1,""],key:[299,4,1,""],lock:[299,4,1,""],lock_storage:[299,4,1,""],parse:[299,3,1,""],search_index_entry:[299,4,1,""],search_targets:[299,3,1,""],send_mail:[299,3,1,""]},"evennia.contrib.game_systems.mail.mail.CmdMailCharacter":{account_caller:[299,4,1,""],aliases:[299,4,1,""],help_category:[299,4,1,""],key:[299,4,1,""],lock_storage:[299,4,1,""],search_index_entry:[299,4,1,""]},"evennia.contrib.game_systems.mail.tests":{TestMail:[300,1,1,""]},"evennia.contrib.game_systems.mail.tests.TestMail":{test_mail:[300,3,1,""]},"evennia.contrib.game_systems.multidescer":{multidescer:[302,0,0,"-"],tests:[303,0,0,"-"]},"evennia.contrib.game_systems.multidescer.multidescer":{CmdMultiDesc:[302,1,1,""],DescValidateError:[302,2,1,""]},"evennia.contrib.game_systems.multidescer.multidescer.CmdMultiDesc":{aliases:[302,4,1,""],func:[302,3,1,""],help_category:[302,4,1,""],key:[302,4,1,""],lock_storage:[302,4,1,""],locks:[302,4,1,""],search_index_entry:[302,4,1,""]},"evennia.contrib.game_systems.multidescer.tests":{TestMultidescer:[303,1,1,""]},"evennia.contrib.game_systems.multidescer.tests.TestMultidescer":{test_cmdmultidesc:[303,3,1,""]},"evennia.contrib.game_systems.puzzles":{puzzles:[305,0,0,"-"],tests:[306,0,0,"-"]},"evennia.contrib.game_systems.puzzles.puzzles":{CmdArmPuzzle:[305,1,1,""],CmdCreatePuzzleRecipe:[305,1,1,""],CmdEditPuzzle:[305,1,1,""],CmdListArmedPuzzles:[305,1,1,""],CmdListPuzzleRecipes:[305,1,1,""],CmdUsePuzzleParts:[305,1,1,""],PuzzleRecipe:[305,1,1,""],PuzzleSystemCmdSet:[305,1,1,""],maskout_protodef:[305,5,1,""],proto_def:[305,5,1,""]},"evennia.contrib.game_systems.puzzles.puzzles.CmdArmPuzzle":{aliases:[305,4,1,""],func:[305,3,1,""],help_category:[305,4,1,""],key:[305,4,1,""],lock_storage:[305,4,1,""],locks:[305,4,1,""],search_index_entry:[305,4,1,""]},"evennia.contrib.game_systems.puzzles.puzzles.CmdCreatePuzzleRecipe":{aliases:[305,4,1,""],confirm:[305,4,1,""],default_confirm:[305,4,1,""],func:[305,3,1,""],help_category:[305,4,1,""],key:[305,4,1,""],lock_storage:[305,4,1,""],locks:[305,4,1,""],search_index_entry:[305,4,1,""]},"evennia.contrib.game_systems.puzzles.puzzles.CmdEditPuzzle":{aliases:[305,4,1,""],func:[305,3,1,""],help_category:[305,4,1,""],key:[305,4,1,""],lock_storage:[305,4,1,""],locks:[305,4,1,""],search_index_entry:[305,4,1,""]},"evennia.contrib.game_systems.puzzles.puzzles.CmdListArmedPuzzles":{aliases:[305,4,1,""],func:[305,3,1,""],help_category:[305,4,1,""],key:[305,4,1,""],lock_storage:[305,4,1,""],locks:[305,4,1,""],search_index_entry:[305,4,1,""]},"evennia.contrib.game_systems.puzzles.puzzles.CmdListPuzzleRecipes":{aliases:[305,4,1,""],func:[305,3,1,""],help_category:[305,4,1,""],key:[305,4,1,""],lock_storage:[305,4,1,""],locks:[305,4,1,""],search_index_entry:[305,4,1,""]},"evennia.contrib.game_systems.puzzles.puzzles.CmdUsePuzzleParts":{aliases:[305,4,1,""],func:[305,3,1,""],help_category:[305,4,1,""],key:[305,4,1,""],lock_storage:[305,4,1,""],locks:[305,4,1,""],search_index_entry:[305,4,1,""]},"evennia.contrib.game_systems.puzzles.puzzles.PuzzleRecipe":{DoesNotExist:[305,2,1,""],MultipleObjectsReturned:[305,2,1,""],path:[305,4,1,""],save_recipe:[305,3,1,""],typename:[305,4,1,""]},"evennia.contrib.game_systems.puzzles.puzzles.PuzzleSystemCmdSet":{at_cmdset_creation:[305,3,1,""],path:[305,4,1,""]},"evennia.contrib.game_systems.puzzles.tests":{TestPuzzles:[306,1,1,""]},"evennia.contrib.game_systems.puzzles.tests.TestPuzzles":{setUp:[306,3,1,""],test_cmd_armpuzzle:[306,3,1,""],test_cmd_puzzle:[306,3,1,""],test_cmd_use:[306,3,1,""],test_cmdset_puzzle:[306,3,1,""],test_e2e:[306,3,1,""],test_e2e_accumulative:[306,3,1,""],test_e2e_interchangeable_parts_and_results:[306,3,1,""],test_lspuzzlerecipes_lsarmedpuzzles:[306,3,1,""],test_puzzleedit:[306,3,1,""],test_puzzleedit_add_remove_parts_results:[306,3,1,""]},"evennia.contrib.game_systems.turnbattle":{tb_basic:[308,0,0,"-"],tb_equip:[309,0,0,"-"],tb_items:[310,0,0,"-"],tb_magic:[311,0,0,"-"],tb_range:[312,0,0,"-"],tests:[313,0,0,"-"]},"evennia.contrib.game_systems.turnbattle.tb_basic":{ACTIONS_PER_TURN:[308,6,1,""],BattleCmdSet:[308,1,1,""],CmdAttack:[308,1,1,""],CmdCombatHelp:[308,1,1,""],CmdDisengage:[308,1,1,""],CmdFight:[308,1,1,""],CmdPass:[308,1,1,""],CmdRest:[308,1,1,""],TBBasicCharacter:[308,1,1,""],TBBasicTurnHandler:[308,1,1,""],apply_damage:[308,5,1,""],at_defeat:[308,5,1,""],combat_cleanup:[308,5,1,""],get_attack:[308,5,1,""],get_damage:[308,5,1,""],get_defense:[308,5,1,""],is_in_combat:[308,5,1,""],is_turn:[308,5,1,""],resolve_attack:[308,5,1,""],roll_init:[308,5,1,""],spend_action:[308,5,1,""]},"evennia.contrib.game_systems.turnbattle.tb_basic.BattleCmdSet":{at_cmdset_creation:[308,3,1,""],key:[308,4,1,""],path:[308,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_basic.CmdAttack":{aliases:[308,4,1,""],func:[308,3,1,""],help_category:[308,4,1,""],key:[308,4,1,""],lock_storage:[308,4,1,""],search_index_entry:[308,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_basic.CmdCombatHelp":{aliases:[308,4,1,""],func:[308,3,1,""],help_category:[308,4,1,""],key:[308,4,1,""],lock_storage:[308,4,1,""],search_index_entry:[308,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_basic.CmdDisengage":{aliases:[308,4,1,""],func:[308,3,1,""],help_category:[308,4,1,""],key:[308,4,1,""],lock_storage:[308,4,1,""],search_index_entry:[308,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_basic.CmdFight":{aliases:[308,4,1,""],func:[308,3,1,""],help_category:[308,4,1,""],key:[308,4,1,""],lock_storage:[308,4,1,""],search_index_entry:[308,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_basic.CmdPass":{aliases:[308,4,1,""],func:[308,3,1,""],help_category:[308,4,1,""],key:[308,4,1,""],lock_storage:[308,4,1,""],search_index_entry:[308,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_basic.CmdRest":{aliases:[308,4,1,""],func:[308,3,1,""],help_category:[308,4,1,""],key:[308,4,1,""],lock_storage:[308,4,1,""],search_index_entry:[308,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_basic.TBBasicCharacter":{DoesNotExist:[308,2,1,""],MultipleObjectsReturned:[308,2,1,""],at_object_creation:[308,3,1,""],at_pre_move:[308,3,1,""],path:[308,4,1,""],typename:[308,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_basic.TBBasicTurnHandler":{DoesNotExist:[308,2,1,""],MultipleObjectsReturned:[308,2,1,""],at_repeat:[308,3,1,""],at_script_creation:[308,3,1,""],at_stop:[308,3,1,""],initialize_for_combat:[308,3,1,""],join_fight:[308,3,1,""],next_turn:[308,3,1,""],path:[308,4,1,""],start_turn:[308,3,1,""],turn_end_check:[308,3,1,""],typename:[308,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip":{ACTIONS_PER_TURN:[309,6,1,""],BattleCmdSet:[309,1,1,""],CmdAttack:[309,1,1,""],CmdCombatHelp:[309,1,1,""],CmdDisengage:[309,1,1,""],CmdDoff:[309,1,1,""],CmdDon:[309,1,1,""],CmdFight:[309,1,1,""],CmdPass:[309,1,1,""],CmdRest:[309,1,1,""],CmdUnwield:[309,1,1,""],CmdWield:[309,1,1,""],TBEArmor:[309,1,1,""],TBEWeapon:[309,1,1,""],TBEquipCharacter:[309,1,1,""],TBEquipTurnHandler:[309,1,1,""],apply_damage:[309,5,1,""],at_defeat:[309,5,1,""],combat_cleanup:[309,5,1,""],get_attack:[309,5,1,""],get_damage:[309,5,1,""],get_defense:[309,5,1,""],is_in_combat:[309,5,1,""],is_turn:[309,5,1,""],resolve_attack:[309,5,1,""],roll_init:[309,5,1,""],spend_action:[309,5,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.BattleCmdSet":{at_cmdset_creation:[309,3,1,""],key:[309,4,1,""],path:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.CmdAttack":{aliases:[309,4,1,""],func:[309,3,1,""],help_category:[309,4,1,""],key:[309,4,1,""],lock_storage:[309,4,1,""],search_index_entry:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.CmdCombatHelp":{aliases:[309,4,1,""],func:[309,3,1,""],help_category:[309,4,1,""],key:[309,4,1,""],lock_storage:[309,4,1,""],search_index_entry:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.CmdDisengage":{aliases:[309,4,1,""],func:[309,3,1,""],help_category:[309,4,1,""],key:[309,4,1,""],lock_storage:[309,4,1,""],search_index_entry:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.CmdDoff":{aliases:[309,4,1,""],func:[309,3,1,""],help_category:[309,4,1,""],key:[309,4,1,""],lock_storage:[309,4,1,""],search_index_entry:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.CmdDon":{aliases:[309,4,1,""],func:[309,3,1,""],help_category:[309,4,1,""],key:[309,4,1,""],lock_storage:[309,4,1,""],search_index_entry:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.CmdFight":{aliases:[309,4,1,""],func:[309,3,1,""],help_category:[309,4,1,""],key:[309,4,1,""],lock_storage:[309,4,1,""],search_index_entry:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.CmdPass":{aliases:[309,4,1,""],func:[309,3,1,""],help_category:[309,4,1,""],key:[309,4,1,""],lock_storage:[309,4,1,""],search_index_entry:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.CmdRest":{aliases:[309,4,1,""],func:[309,3,1,""],help_category:[309,4,1,""],key:[309,4,1,""],lock_storage:[309,4,1,""],search_index_entry:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.CmdUnwield":{aliases:[309,4,1,""],func:[309,3,1,""],help_category:[309,4,1,""],key:[309,4,1,""],lock_storage:[309,4,1,""],search_index_entry:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.CmdWield":{aliases:[309,4,1,""],func:[309,3,1,""],help_category:[309,4,1,""],key:[309,4,1,""],lock_storage:[309,4,1,""],search_index_entry:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.TBEArmor":{DoesNotExist:[309,2,1,""],MultipleObjectsReturned:[309,2,1,""],at_drop:[309,3,1,""],at_give:[309,3,1,""],at_object_creation:[309,3,1,""],at_pre_drop:[309,3,1,""],at_pre_give:[309,3,1,""],path:[309,4,1,""],typename:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.TBEWeapon":{DoesNotExist:[309,2,1,""],MultipleObjectsReturned:[309,2,1,""],at_drop:[309,3,1,""],at_give:[309,3,1,""],at_object_creation:[309,3,1,""],path:[309,4,1,""],typename:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.TBEquipCharacter":{DoesNotExist:[309,2,1,""],MultipleObjectsReturned:[309,2,1,""],at_object_creation:[309,3,1,""],at_pre_move:[309,3,1,""],path:[309,4,1,""],typename:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_equip.TBEquipTurnHandler":{DoesNotExist:[309,2,1,""],MultipleObjectsReturned:[309,2,1,""],at_repeat:[309,3,1,""],at_script_creation:[309,3,1,""],at_stop:[309,3,1,""],initialize_for_combat:[309,3,1,""],join_fight:[309,3,1,""],next_turn:[309,3,1,""],path:[309,4,1,""],start_turn:[309,3,1,""],turn_end_check:[309,3,1,""],typename:[309,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items":{BattleCmdSet:[310,1,1,""],CmdAttack:[310,1,1,""],CmdCombatHelp:[310,1,1,""],CmdDisengage:[310,1,1,""],CmdFight:[310,1,1,""],CmdPass:[310,1,1,""],CmdRest:[310,1,1,""],CmdUse:[310,1,1,""],DEF_DOWN_MOD:[310,6,1,""],ITEMFUNCS:[310,6,1,""],TBItemsCharacter:[310,1,1,""],TBItemsCharacterTest:[310,1,1,""],TBItemsTurnHandler:[310,1,1,""],add_condition:[310,5,1,""],apply_damage:[310,5,1,""],at_defeat:[310,5,1,""],combat_cleanup:[310,5,1,""],condition_tickdown:[310,5,1,""],get_attack:[310,5,1,""],get_damage:[310,5,1,""],get_defense:[310,5,1,""],is_in_combat:[310,5,1,""],is_turn:[310,5,1,""],itemfunc_add_condition:[310,5,1,""],itemfunc_attack:[310,5,1,""],itemfunc_cure_condition:[310,5,1,""],itemfunc_heal:[310,5,1,""],resolve_attack:[310,5,1,""],roll_init:[310,5,1,""],spend_action:[310,5,1,""],spend_item_use:[310,5,1,""],use_item:[310,5,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items.BattleCmdSet":{at_cmdset_creation:[310,3,1,""],key:[310,4,1,""],path:[310,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items.CmdAttack":{aliases:[310,4,1,""],func:[310,3,1,""],help_category:[310,4,1,""],key:[310,4,1,""],lock_storage:[310,4,1,""],search_index_entry:[310,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items.CmdCombatHelp":{aliases:[310,4,1,""],func:[310,3,1,""],help_category:[310,4,1,""],key:[310,4,1,""],lock_storage:[310,4,1,""],search_index_entry:[310,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items.CmdDisengage":{aliases:[310,4,1,""],func:[310,3,1,""],help_category:[310,4,1,""],key:[310,4,1,""],lock_storage:[310,4,1,""],search_index_entry:[310,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items.CmdFight":{aliases:[310,4,1,""],func:[310,3,1,""],help_category:[310,4,1,""],key:[310,4,1,""],lock_storage:[310,4,1,""],search_index_entry:[310,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items.CmdPass":{aliases:[310,4,1,""],func:[310,3,1,""],help_category:[310,4,1,""],key:[310,4,1,""],lock_storage:[310,4,1,""],search_index_entry:[310,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items.CmdRest":{aliases:[310,4,1,""],func:[310,3,1,""],help_category:[310,4,1,""],key:[310,4,1,""],lock_storage:[310,4,1,""],search_index_entry:[310,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items.CmdUse":{aliases:[310,4,1,""],func:[310,3,1,""],help_category:[310,4,1,""],key:[310,4,1,""],lock_storage:[310,4,1,""],search_index_entry:[310,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items.TBItemsCharacter":{DoesNotExist:[310,2,1,""],MultipleObjectsReturned:[310,2,1,""],apply_turn_conditions:[310,3,1,""],at_object_creation:[310,3,1,""],at_pre_move:[310,3,1,""],at_turn_start:[310,3,1,""],at_update:[310,3,1,""],path:[310,4,1,""],typename:[310,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items.TBItemsCharacterTest":{DoesNotExist:[310,2,1,""],MultipleObjectsReturned:[310,2,1,""],at_object_creation:[310,3,1,""],path:[310,4,1,""],typename:[310,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_items.TBItemsTurnHandler":{DoesNotExist:[310,2,1,""],MultipleObjectsReturned:[310,2,1,""],at_repeat:[310,3,1,""],at_script_creation:[310,3,1,""],at_stop:[310,3,1,""],initialize_for_combat:[310,3,1,""],join_fight:[310,3,1,""],next_turn:[310,3,1,""],path:[310,4,1,""],start_turn:[310,3,1,""],turn_end_check:[310,3,1,""],typename:[310,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic":{ACTIONS_PER_TURN:[311,6,1,""],BattleCmdSet:[311,1,1,""],CmdAttack:[311,1,1,""],CmdCast:[311,1,1,""],CmdCombatHelp:[311,1,1,""],CmdDisengage:[311,1,1,""],CmdFight:[311,1,1,""],CmdLearnSpell:[311,1,1,""],CmdPass:[311,1,1,""],CmdRest:[311,1,1,""],CmdStatus:[311,1,1,""],TBMagicCharacter:[311,1,1,""],TBMagicTurnHandler:[311,1,1,""],apply_damage:[311,5,1,""],at_defeat:[311,5,1,""],combat_cleanup:[311,5,1,""],get_attack:[311,5,1,""],get_damage:[311,5,1,""],get_defense:[311,5,1,""],is_in_combat:[311,5,1,""],is_turn:[311,5,1,""],resolve_attack:[311,5,1,""],roll_init:[311,5,1,""],spell_attack:[311,5,1,""],spell_conjure:[311,5,1,""],spell_healing:[311,5,1,""],spend_action:[311,5,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.BattleCmdSet":{at_cmdset_creation:[311,3,1,""],key:[311,4,1,""],path:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.CmdAttack":{aliases:[311,4,1,""],func:[311,3,1,""],help_category:[311,4,1,""],key:[311,4,1,""],lock_storage:[311,4,1,""],search_index_entry:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.CmdCast":{aliases:[311,4,1,""],func:[311,3,1,""],help_category:[311,4,1,""],key:[311,4,1,""],lock_storage:[311,4,1,""],search_index_entry:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.CmdCombatHelp":{aliases:[311,4,1,""],func:[311,3,1,""],help_category:[311,4,1,""],key:[311,4,1,""],lock_storage:[311,4,1,""],search_index_entry:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.CmdDisengage":{aliases:[311,4,1,""],func:[311,3,1,""],help_category:[311,4,1,""],key:[311,4,1,""],lock_storage:[311,4,1,""],search_index_entry:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.CmdFight":{aliases:[311,4,1,""],func:[311,3,1,""],help_category:[311,4,1,""],key:[311,4,1,""],lock_storage:[311,4,1,""],search_index_entry:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.CmdLearnSpell":{aliases:[311,4,1,""],func:[311,3,1,""],help_category:[311,4,1,""],key:[311,4,1,""],lock_storage:[311,4,1,""],search_index_entry:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.CmdPass":{aliases:[311,4,1,""],func:[311,3,1,""],help_category:[311,4,1,""],key:[311,4,1,""],lock_storage:[311,4,1,""],search_index_entry:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.CmdRest":{aliases:[311,4,1,""],func:[311,3,1,""],help_category:[311,4,1,""],key:[311,4,1,""],lock_storage:[311,4,1,""],search_index_entry:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.CmdStatus":{aliases:[311,4,1,""],func:[311,3,1,""],help_category:[311,4,1,""],key:[311,4,1,""],lock_storage:[311,4,1,""],search_index_entry:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.TBMagicCharacter":{DoesNotExist:[311,2,1,""],MultipleObjectsReturned:[311,2,1,""],at_object_creation:[311,3,1,""],at_pre_move:[311,3,1,""],path:[311,4,1,""],typename:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_magic.TBMagicTurnHandler":{DoesNotExist:[311,2,1,""],MultipleObjectsReturned:[311,2,1,""],at_repeat:[311,3,1,""],at_script_creation:[311,3,1,""],at_stop:[311,3,1,""],initialize_for_combat:[311,3,1,""],join_fight:[311,3,1,""],next_turn:[311,3,1,""],path:[311,4,1,""],start_turn:[311,3,1,""],turn_end_check:[311,3,1,""],typename:[311,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range":{ACTIONS_PER_TURN:[312,6,1,""],BattleCmdSet:[312,1,1,""],CmdApproach:[312,1,1,""],CmdAttack:[312,1,1,""],CmdCombatHelp:[312,1,1,""],CmdDisengage:[312,1,1,""],CmdFight:[312,1,1,""],CmdPass:[312,1,1,""],CmdRest:[312,1,1,""],CmdShoot:[312,1,1,""],CmdStatus:[312,1,1,""],CmdWithdraw:[312,1,1,""],TBRangeCharacter:[312,1,1,""],TBRangeObject:[312,1,1,""],TBRangeTurnHandler:[312,1,1,""],apply_damage:[312,5,1,""],approach:[312,5,1,""],at_defeat:[312,5,1,""],combat_cleanup:[312,5,1,""],combat_status_message:[312,5,1,""],distance_inc:[312,5,1,""],get_attack:[312,5,1,""],get_damage:[312,5,1,""],get_defense:[312,5,1,""],get_range:[312,5,1,""],is_in_combat:[312,5,1,""],is_turn:[312,5,1,""],resolve_attack:[312,5,1,""],roll_init:[312,5,1,""],spend_action:[312,5,1,""],withdraw:[312,5,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.BattleCmdSet":{at_cmdset_creation:[312,3,1,""],key:[312,4,1,""],path:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.CmdApproach":{aliases:[312,4,1,""],func:[312,3,1,""],help_category:[312,4,1,""],key:[312,4,1,""],lock_storage:[312,4,1,""],search_index_entry:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.CmdAttack":{aliases:[312,4,1,""],func:[312,3,1,""],help_category:[312,4,1,""],key:[312,4,1,""],lock_storage:[312,4,1,""],search_index_entry:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.CmdCombatHelp":{aliases:[312,4,1,""],func:[312,3,1,""],help_category:[312,4,1,""],key:[312,4,1,""],lock_storage:[312,4,1,""],search_index_entry:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.CmdDisengage":{aliases:[312,4,1,""],func:[312,3,1,""],help_category:[312,4,1,""],key:[312,4,1,""],lock_storage:[312,4,1,""],search_index_entry:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.CmdFight":{aliases:[312,4,1,""],func:[312,3,1,""],help_category:[312,4,1,""],key:[312,4,1,""],lock_storage:[312,4,1,""],search_index_entry:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.CmdPass":{aliases:[312,4,1,""],func:[312,3,1,""],help_category:[312,4,1,""],key:[312,4,1,""],lock_storage:[312,4,1,""],search_index_entry:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.CmdRest":{aliases:[312,4,1,""],func:[312,3,1,""],help_category:[312,4,1,""],key:[312,4,1,""],lock_storage:[312,4,1,""],search_index_entry:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.CmdShoot":{aliases:[312,4,1,""],func:[312,3,1,""],help_category:[312,4,1,""],key:[312,4,1,""],lock_storage:[312,4,1,""],search_index_entry:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.CmdStatus":{aliases:[312,4,1,""],func:[312,3,1,""],help_category:[312,4,1,""],key:[312,4,1,""],lock_storage:[312,4,1,""],search_index_entry:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.CmdWithdraw":{aliases:[312,4,1,""],func:[312,3,1,""],help_category:[312,4,1,""],key:[312,4,1,""],lock_storage:[312,4,1,""],search_index_entry:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.TBRangeCharacter":{DoesNotExist:[312,2,1,""],MultipleObjectsReturned:[312,2,1,""],at_object_creation:[312,3,1,""],at_pre_move:[312,3,1,""],path:[312,4,1,""],typename:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.TBRangeObject":{DoesNotExist:[312,2,1,""],MultipleObjectsReturned:[312,2,1,""],at_drop:[312,3,1,""],at_get:[312,3,1,""],at_give:[312,3,1,""],at_pre_drop:[312,3,1,""],at_pre_get:[312,3,1,""],at_pre_give:[312,3,1,""],path:[312,4,1,""],typename:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tb_range.TBRangeTurnHandler":{DoesNotExist:[312,2,1,""],MultipleObjectsReturned:[312,2,1,""],at_repeat:[312,3,1,""],at_script_creation:[312,3,1,""],at_stop:[312,3,1,""],init_range:[312,3,1,""],initialize_for_combat:[312,3,1,""],join_fight:[312,3,1,""],join_rangefield:[312,3,1,""],next_turn:[312,3,1,""],path:[312,4,1,""],start_turn:[312,3,1,""],turn_end_check:[312,3,1,""],typename:[312,4,1,""]},"evennia.contrib.game_systems.turnbattle.tests":{TestTurnBattleBasicCmd:[313,1,1,""],TestTurnBattleBasicFunc:[313,1,1,""],TestTurnBattleEquipCmd:[313,1,1,""],TestTurnBattleEquipFunc:[313,1,1,""],TestTurnBattleItemsCmd:[313,1,1,""],TestTurnBattleItemsFunc:[313,1,1,""],TestTurnBattleMagicCmd:[313,1,1,""],TestTurnBattleMagicFunc:[313,1,1,""],TestTurnBattleRangeCmd:[313,1,1,""],TestTurnBattleRangeFunc:[313,1,1,""]},"evennia.contrib.game_systems.turnbattle.tests.TestTurnBattleBasicCmd":{test_turnbattlecmd:[313,3,1,""]},"evennia.contrib.game_systems.turnbattle.tests.TestTurnBattleBasicFunc":{setUp:[313,3,1,""],tearDown:[313,3,1,""],test_tbbasicfunc:[313,3,1,""]},"evennia.contrib.game_systems.turnbattle.tests.TestTurnBattleEquipCmd":{setUp:[313,3,1,""],test_turnbattleequipcmd:[313,3,1,""]},"evennia.contrib.game_systems.turnbattle.tests.TestTurnBattleEquipFunc":{setUp:[313,3,1,""],tearDown:[313,3,1,""],test_tbequipfunc:[313,3,1,""]},"evennia.contrib.game_systems.turnbattle.tests.TestTurnBattleItemsCmd":{setUp:[313,3,1,""],test_turnbattleitemcmd:[313,3,1,""]},"evennia.contrib.game_systems.turnbattle.tests.TestTurnBattleItemsFunc":{setUp:[313,3,1,""],tearDown:[313,3,1,""],test_tbitemsfunc:[313,3,1,""]},"evennia.contrib.game_systems.turnbattle.tests.TestTurnBattleMagicCmd":{test_turnbattlemagiccmd:[313,3,1,""]},"evennia.contrib.game_systems.turnbattle.tests.TestTurnBattleMagicFunc":{setUp:[313,3,1,""],tearDown:[313,3,1,""],test_tbbasicfunc:[313,3,1,""]},"evennia.contrib.game_systems.turnbattle.tests.TestTurnBattleRangeCmd":{test_turnbattlerangecmd:[313,3,1,""]},"evennia.contrib.game_systems.turnbattle.tests.TestTurnBattleRangeFunc":{setUp:[313,3,1,""],tearDown:[313,3,1,""],test_tbrangefunc:[313,3,1,""]},"evennia.contrib.grid":{extended_room:[315,0,0,"-"],simpledoor:[321,0,0,"-"],slow_exit:[324,0,0,"-"],wilderness:[327,0,0,"-"],xyzgrid:[330,0,0,"-"]},"evennia.contrib.grid.extended_room":{extended_room:[316,0,0,"-"],tests:[317,0,0,"-"]},"evennia.contrib.grid.extended_room.extended_room":{CmdExtendedRoomDesc:[316,1,1,""],CmdExtendedRoomDetail:[316,1,1,""],CmdExtendedRoomGameTime:[316,1,1,""],CmdExtendedRoomLook:[316,1,1,""],ExtendedRoom:[316,1,1,""],ExtendedRoomCmdSet:[316,1,1,""]},"evennia.contrib.grid.extended_room.extended_room.CmdExtendedRoomDesc":{aliases:[316,4,1,""],func:[316,3,1,""],help_category:[316,4,1,""],key:[316,4,1,""],lock_storage:[316,4,1,""],reset_times:[316,3,1,""],search_index_entry:[316,4,1,""],switch_options:[316,4,1,""]},"evennia.contrib.grid.extended_room.extended_room.CmdExtendedRoomDetail":{aliases:[316,4,1,""],func:[316,3,1,""],help_category:[316,4,1,""],key:[316,4,1,""],lock_storage:[316,4,1,""],locks:[316,4,1,""],search_index_entry:[316,4,1,""]},"evennia.contrib.grid.extended_room.extended_room.CmdExtendedRoomGameTime":{aliases:[316,4,1,""],func:[316,3,1,""],help_category:[316,4,1,""],key:[316,4,1,""],lock_storage:[316,4,1,""],locks:[316,4,1,""],search_index_entry:[316,4,1,""]},"evennia.contrib.grid.extended_room.extended_room.CmdExtendedRoomLook":{aliases:[316,4,1,""],func:[316,3,1,""],help_category:[316,4,1,""],key:[316,4,1,""],lock_storage:[316,4,1,""],search_index_entry:[316,4,1,""]},"evennia.contrib.grid.extended_room.extended_room.ExtendedRoom":{DoesNotExist:[316,2,1,""],MultipleObjectsReturned:[316,2,1,""],at_object_creation:[316,3,1,""],del_detail:[316,3,1,""],get_time_and_season:[316,3,1,""],path:[316,4,1,""],replace_timeslots:[316,3,1,""],return_appearance:[316,3,1,""],return_detail:[316,3,1,""],set_detail:[316,3,1,""],typename:[316,4,1,""],update_current_description:[316,3,1,""]},"evennia.contrib.grid.extended_room.extended_room.ExtendedRoomCmdSet":{at_cmdset_creation:[316,3,1,""],path:[316,4,1,""]},"evennia.contrib.grid.extended_room.tests":{ForceUTCDatetime:[317,1,1,""],TestExtendedRoom:[317,1,1,""]},"evennia.contrib.grid.extended_room.tests.ForceUTCDatetime":{fromtimestamp:[317,3,1,""]},"evennia.contrib.grid.extended_room.tests.TestExtendedRoom":{DETAIL_DESC:[317,4,1,""],OLD_DESC:[317,4,1,""],SPRING_DESC:[317,4,1,""],room_typeclass:[317,4,1,""],setUp:[317,3,1,""],test_cmdextendedlook:[317,3,1,""],test_cmdgametime:[317,3,1,""],test_cmdsetdetail:[317,3,1,""],test_return_appearance:[317,3,1,""],test_return_detail:[317,3,1,""]},"evennia.contrib.grid.simpledoor":{simpledoor:[322,0,0,"-"],tests:[323,0,0,"-"]},"evennia.contrib.grid.simpledoor.simpledoor":{CmdOpen:[322,1,1,""],CmdOpenCloseDoor:[322,1,1,""],SimpleDoor:[322,1,1,""],SimpleDoorCmdSet:[322,1,1,""]},"evennia.contrib.grid.simpledoor.simpledoor.CmdOpen":{aliases:[322,4,1,""],create_exit:[322,3,1,""],help_category:[322,4,1,""],key:[322,4,1,""],lock_storage:[322,4,1,""],search_index_entry:[322,4,1,""]},"evennia.contrib.grid.simpledoor.simpledoor.CmdOpenCloseDoor":{aliases:[322,4,1,""],func:[322,3,1,""],help_category:[322,4,1,""],key:[322,4,1,""],lock_storage:[322,4,1,""],locks:[322,4,1,""],search_index_entry:[322,4,1,""]},"evennia.contrib.grid.simpledoor.simpledoor.SimpleDoor":{"delete":[322,3,1,""],DoesNotExist:[322,2,1,""],MultipleObjectsReturned:[322,2,1,""],at_failed_traverse:[322,3,1,""],at_object_creation:[322,3,1,""],path:[322,4,1,""],setdesc:[322,3,1,""],setlock:[322,3,1,""],typename:[322,4,1,""]},"evennia.contrib.grid.simpledoor.simpledoor.SimpleDoorCmdSet":{at_cmdset_creation:[322,3,1,""],path:[322,4,1,""]},"evennia.contrib.grid.simpledoor.tests":{TestSimpleDoor:[323,1,1,""]},"evennia.contrib.grid.simpledoor.tests.TestSimpleDoor":{test_cmdopen:[323,3,1,""]},"evennia.contrib.grid.slow_exit":{slow_exit:[325,0,0,"-"],tests:[326,0,0,"-"]},"evennia.contrib.grid.slow_exit.slow_exit":{CmdSetSpeed:[325,1,1,""],CmdStop:[325,1,1,""],SlowExit:[325,1,1,""],SlowExitCmdSet:[325,1,1,""]},"evennia.contrib.grid.slow_exit.slow_exit.CmdSetSpeed":{aliases:[325,4,1,""],func:[325,3,1,""],help_category:[325,4,1,""],key:[325,4,1,""],lock_storage:[325,4,1,""],search_index_entry:[325,4,1,""]},"evennia.contrib.grid.slow_exit.slow_exit.CmdStop":{aliases:[325,4,1,""],func:[325,3,1,""],help_category:[325,4,1,""],key:[325,4,1,""],lock_storage:[325,4,1,""],search_index_entry:[325,4,1,""]},"evennia.contrib.grid.slow_exit.slow_exit.SlowExit":{DoesNotExist:[325,2,1,""],MultipleObjectsReturned:[325,2,1,""],at_traverse:[325,3,1,""],path:[325,4,1,""],typename:[325,4,1,""]},"evennia.contrib.grid.slow_exit.slow_exit.SlowExitCmdSet":{at_cmdset_creation:[325,3,1,""],path:[325,4,1,""]},"evennia.contrib.grid.slow_exit.tests":{TestSlowExit:[326,1,1,""]},"evennia.contrib.grid.slow_exit.tests.TestSlowExit":{test_exit:[326,3,1,""]},"evennia.contrib.grid.wilderness":{tests:[328,0,0,"-"],wilderness:[329,0,0,"-"]},"evennia.contrib.grid.wilderness.tests":{TestWilderness:[328,1,1,""]},"evennia.contrib.grid.wilderness.tests.TestWilderness":{get_wilderness_script:[328,3,1,""],setUp:[328,3,1,""],test_create_wilderness_custom_name:[328,3,1,""],test_create_wilderness_default_name:[328,3,1,""],test_enter_wilderness:[328,3,1,""],test_enter_wilderness_custom_coordinates:[328,3,1,""],test_enter_wilderness_custom_name:[328,3,1,""],test_get_new_coordinates:[328,3,1,""],test_room_creation:[328,3,1,""],test_wilderness_correct_exits:[328,3,1,""]},"evennia.contrib.grid.wilderness.wilderness":{WildernessExit:[329,1,1,""],WildernessMapProvider:[329,1,1,""],WildernessRoom:[329,1,1,""],WildernessScript:[329,1,1,""],create_wilderness:[329,5,1,""],enter_wilderness:[329,5,1,""],get_new_coordinates:[329,5,1,""]},"evennia.contrib.grid.wilderness.wilderness.WildernessExit":{DoesNotExist:[329,2,1,""],MultipleObjectsReturned:[329,2,1,""],at_traverse:[329,3,1,""],at_traverse_coordinates:[329,3,1,""],mapprovider:[329,3,1,""],path:[329,4,1,""],typename:[329,4,1,""],wilderness:[329,3,1,""]},"evennia.contrib.grid.wilderness.wilderness.WildernessMapProvider":{at_prepare_room:[329,3,1,""],exit_typeclass:[329,4,1,""],get_location_name:[329,3,1,""],is_valid_coordinates:[329,3,1,""],room_typeclass:[329,4,1,""]},"evennia.contrib.grid.wilderness.wilderness.WildernessRoom":{DoesNotExist:[329,2,1,""],MultipleObjectsReturned:[329,2,1,""],at_object_leave:[329,3,1,""],at_object_receive:[329,3,1,""],coordinates:[329,3,1,""],get_display_name:[329,3,1,""],location_name:[329,3,1,""],path:[329,4,1,""],set_active_coordinates:[329,3,1,""],typename:[329,4,1,""],wilderness:[329,3,1,""]},"evennia.contrib.grid.wilderness.wilderness.WildernessScript":{DoesNotExist:[329,2,1,""],MultipleObjectsReturned:[329,2,1,""],at_post_object_leave:[329,3,1,""],at_script_creation:[329,3,1,""],at_start:[329,3,1,""],get_obj_coordinates:[329,3,1,""],get_objs_at_coordinates:[329,3,1,""],is_valid_coordinates:[329,3,1,""],itemcoordinates:[329,3,1,""],mapprovider:[329,3,1,""],move_obj:[329,3,1,""],path:[329,4,1,""],typename:[329,4,1,""]},"evennia.contrib.grid.xyzgrid":{commands:[331,0,0,"-"],example:[332,0,0,"-"],launchcmd:[333,0,0,"-"],prototypes:[334,0,0,"-"],tests:[335,0,0,"-"],utils:[336,0,0,"-"],xymap:[337,0,0,"-"],xymap_legend:[338,0,0,"-"],xyzgrid:[339,0,0,"-"],xyzroom:[340,0,0,"-"]},"evennia.contrib.grid.xyzgrid.commands":{CmdGoto:[331,1,1,""],CmdMap:[331,1,1,""],CmdXYZOpen:[331,1,1,""],CmdXYZTeleport:[331,1,1,""],PathData:[331,1,1,""],XYZGridCmdSet:[331,1,1,""]},"evennia.contrib.grid.xyzgrid.commands.CmdGoto":{aliases:[331,4,1,""],auto_step_delay:[331,4,1,""],default_xyz_path_interrupt_msg:[331,4,1,""],func:[331,3,1,""],help_category:[331,4,1,""],key:[331,4,1,""],lock_storage:[331,4,1,""],locks:[331,4,1,""],search_index_entry:[331,4,1,""]},"evennia.contrib.grid.xyzgrid.commands.CmdMap":{aliases:[331,4,1,""],func:[331,3,1,""],help_category:[331,4,1,""],key:[331,4,1,""],lock_storage:[331,4,1,""],locks:[331,4,1,""],search_index_entry:[331,4,1,""]},"evennia.contrib.grid.xyzgrid.commands.CmdXYZOpen":{aliases:[331,4,1,""],help_category:[331,4,1,""],key:[331,4,1,""],lock_storage:[331,4,1,""],parse:[331,3,1,""],search_index_entry:[331,4,1,""]},"evennia.contrib.grid.xyzgrid.commands.CmdXYZTeleport":{aliases:[331,4,1,""],help_category:[331,4,1,""],key:[331,4,1,""],lock_storage:[331,4,1,""],parse:[331,3,1,""],search_index_entry:[331,4,1,""]},"evennia.contrib.grid.xyzgrid.commands.PathData":{directions:[331,3,1,""],step_sequence:[331,3,1,""],target:[331,3,1,""],task:[331,3,1,""],xymap:[331,3,1,""]},"evennia.contrib.grid.xyzgrid.commands.XYZGridCmdSet":{at_cmdset_creation:[331,3,1,""],key:[331,4,1,""],path:[331,4,1,""]},"evennia.contrib.grid.xyzgrid.example":{TransitionToCave:[332,1,1,""],TransitionToLargeTree:[332,1,1,""]},"evennia.contrib.grid.xyzgrid.example.TransitionToCave":{symbol:[332,4,1,""],target_map_xyz:[332,4,1,""]},"evennia.contrib.grid.xyzgrid.example.TransitionToLargeTree":{symbol:[332,4,1,""],target_map_xyz:[332,4,1,""]},"evennia.contrib.grid.xyzgrid.launchcmd":{xyzcommand:[333,5,1,""]},"evennia.contrib.grid.xyzgrid.tests":{Map12aTransition:[335,1,1,""],Map12bTransition:[335,1,1,""],TestBuildExampleGrid:[335,1,1,""],TestMap10:[335,1,1,""],TestMap11:[335,1,1,""],TestMap1:[335,1,1,""],TestMap2:[335,1,1,""],TestMap3:[335,1,1,""],TestMap4:[335,1,1,""],TestMap5:[335,1,1,""],TestMap6:[335,1,1,""],TestMap7:[335,1,1,""],TestMap8:[335,1,1,""],TestMap9:[335,1,1,""],TestMapStressTest:[335,1,1,""],TestXYZGrid:[335,1,1,""],TestXYZGridTransition:[335,1,1,""]},"evennia.contrib.grid.xyzgrid.tests.Map12aTransition":{symbol:[335,4,1,""],target_map_xyz:[335,4,1,""]},"evennia.contrib.grid.xyzgrid.tests.Map12bTransition":{symbol:[335,4,1,""],target_map_xyz:[335,4,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestBuildExampleGrid":{setUp:[335,3,1,""],tearDown:[335,3,1,""],test_build:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMap1":{test_get_shortest_path:[335,3,1,""],test_get_visual_range__nodes__character:[335,4,1,""],test_get_visual_range__nodes__character_0:[335,3,1,""],test_get_visual_range__nodes__character_1:[335,3,1,""],test_get_visual_range__nodes__character_2:[335,3,1,""],test_get_visual_range__nodes__character_3:[335,3,1,""],test_get_visual_range__nodes__character_4:[335,3,1,""],test_get_visual_range__scan:[335,4,1,""],test_get_visual_range__scan_0:[335,3,1,""],test_get_visual_range__scan_1:[335,3,1,""],test_get_visual_range__scan_2:[335,3,1,""],test_get_visual_range__scan_3:[335,3,1,""],test_get_visual_range__scan__character:[335,4,1,""],test_get_visual_range__scan__character_0:[335,3,1,""],test_get_visual_range__scan__character_1:[335,3,1,""],test_get_visual_range__scan__character_2:[335,3,1,""],test_get_visual_range__scan__character_3:[335,3,1,""],test_node_from_coord:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMap10":{map_data:[335,4,1,""],map_display:[335,4,1,""],test_paths:[335,4,1,""],test_paths_0:[335,3,1,""],test_paths_1:[335,3,1,""],test_shortest_path:[335,4,1,""],test_shortest_path_0:[335,3,1,""],test_shortest_path_1:[335,3,1,""],test_shortest_path_2:[335,3,1,""],test_shortest_path_3:[335,3,1,""],test_shortest_path_4:[335,3,1,""],test_shortest_path_5:[335,3,1,""],test_shortest_path_6:[335,3,1,""],test_shortest_path_7:[335,3,1,""],test_shortest_path_8:[335,3,1,""],test_shortest_path_9:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMap11":{map_data:[335,4,1,""],map_display:[335,4,1,""],test_get_visual_range_with_path:[335,4,1,""],test_get_visual_range_with_path_0:[335,3,1,""],test_get_visual_range_with_path_1:[335,3,1,""],test_paths:[335,4,1,""],test_paths_0:[335,3,1,""],test_paths_1:[335,3,1,""],test_shortest_path:[335,4,1,""],test_shortest_path_0:[335,3,1,""],test_shortest_path_1:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMap2":{map_data:[335,4,1,""],map_display:[335,4,1,""],test_extended_path_tracking__horizontal:[335,3,1,""],test_extended_path_tracking__vertical:[335,3,1,""],test_get_visual_range__nodes__character:[335,4,1,""],test_get_visual_range__nodes__character_0:[335,3,1,""],test_get_visual_range__nodes__character_1:[335,3,1,""],test_get_visual_range__nodes__character_2:[335,3,1,""],test_get_visual_range__nodes__character_3:[335,3,1,""],test_get_visual_range__nodes__character_4:[335,3,1,""],test_get_visual_range__nodes__character_5:[335,3,1,""],test_get_visual_range__nodes__character_6:[335,3,1,""],test_get_visual_range__nodes__character_7:[335,3,1,""],test_get_visual_range__nodes__character_8:[335,3,1,""],test_get_visual_range__nodes__character_9:[335,3,1,""],test_get_visual_range__scan__character:[335,4,1,""],test_get_visual_range__scan__character_0:[335,3,1,""],test_get_visual_range__scan__character_1:[335,3,1,""],test_get_visual_range__scan__character_2:[335,3,1,""],test_get_visual_range__scan__character_3:[335,3,1,""],test_node_from_coord:[335,3,1,""],test_shortest_path:[335,4,1,""],test_shortest_path_0:[335,3,1,""],test_shortest_path_1:[335,3,1,""],test_shortest_path_2:[335,3,1,""],test_shortest_path_3:[335,3,1,""],test_shortest_path_4:[335,3,1,""],test_shortest_path_5:[335,3,1,""],test_shortest_path_6:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMap3":{map_data:[335,4,1,""],map_display:[335,4,1,""],test_get_visual_range__nodes__character:[335,4,1,""],test_get_visual_range__nodes__character_0:[335,3,1,""],test_get_visual_range__nodes__character_1:[335,3,1,""],test_shortest_path:[335,4,1,""],test_shortest_path_00:[335,3,1,""],test_shortest_path_01:[335,3,1,""],test_shortest_path_02:[335,3,1,""],test_shortest_path_03:[335,3,1,""],test_shortest_path_04:[335,3,1,""],test_shortest_path_05:[335,3,1,""],test_shortest_path_06:[335,3,1,""],test_shortest_path_07:[335,3,1,""],test_shortest_path_08:[335,3,1,""],test_shortest_path_09:[335,3,1,""],test_shortest_path_10:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMap4":{map_data:[335,4,1,""],map_display:[335,4,1,""],test_shortest_path:[335,4,1,""],test_shortest_path_0:[335,3,1,""],test_shortest_path_1:[335,3,1,""],test_shortest_path_2:[335,3,1,""],test_shortest_path_3:[335,3,1,""],test_shortest_path_4:[335,3,1,""],test_shortest_path_5:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMap5":{map_data:[335,4,1,""],map_display:[335,4,1,""],test_shortest_path:[335,4,1,""],test_shortest_path_0:[335,3,1,""],test_shortest_path_1:[335,3,1,""],test_shortest_path_2:[335,3,1,""],test_shortest_path_3:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMap6":{map_data:[335,4,1,""],map_display:[335,4,1,""],test_shortest_path:[335,4,1,""],test_shortest_path_0:[335,3,1,""],test_shortest_path_1:[335,3,1,""],test_shortest_path_2:[335,3,1,""],test_shortest_path_3:[335,3,1,""],test_shortest_path_4:[335,3,1,""],test_shortest_path_5:[335,3,1,""],test_shortest_path_6:[335,3,1,""],test_shortest_path_7:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMap7":{map_data:[335,4,1,""],map_display:[335,4,1,""],test_shortest_path:[335,4,1,""],test_shortest_path_0:[335,3,1,""],test_shortest_path_1:[335,3,1,""],test_shortest_path_2:[335,3,1,""],test_shortest_path_3:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMap8":{map_data:[335,4,1,""],map_display:[335,4,1,""],test_get_visual_range__nodes__character:[335,4,1,""],test_get_visual_range__nodes__character_0:[335,3,1,""],test_get_visual_range_with_path:[335,4,1,""],test_get_visual_range_with_path_0:[335,3,1,""],test_get_visual_range_with_path_1:[335,3,1,""],test_get_visual_range_with_path_2:[335,3,1,""],test_get_visual_range_with_path_3:[335,3,1,""],test_get_visual_range_with_path_4:[335,3,1,""],test_shortest_path:[335,4,1,""],test_shortest_path_0:[335,3,1,""],test_shortest_path_1:[335,3,1,""],test_shortest_path_2:[335,3,1,""],test_shortest_path_3:[335,3,1,""],test_shortest_path_4:[335,3,1,""],test_shortest_path_5:[335,3,1,""],test_shortest_path_6:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMap9":{map_data:[335,4,1,""],map_display:[335,4,1,""],test_shortest_path:[335,4,1,""],test_shortest_path_0:[335,3,1,""],test_shortest_path_1:[335,3,1,""],test_shortest_path_2:[335,3,1,""],test_shortest_path_3:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestMapStressTest":{test_grid_creation:[335,4,1,""],test_grid_creation_0:[335,3,1,""],test_grid_creation_1:[335,3,1,""],test_grid_pathfind:[335,4,1,""],test_grid_pathfind_0:[335,3,1,""],test_grid_pathfind_1:[335,3,1,""],test_grid_visibility:[335,4,1,""],test_grid_visibility_0:[335,3,1,""],test_grid_visibility_1:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestXYZGrid":{setUp:[335,3,1,""],tearDown:[335,3,1,""],test_spawn:[335,3,1,""],test_str_output:[335,3,1,""],zcoord:[335,4,1,""]},"evennia.contrib.grid.xyzgrid.tests.TestXYZGridTransition":{setUp:[335,3,1,""],tearDown:[335,3,1,""],test_shortest_path:[335,4,1,""],test_shortest_path_0:[335,3,1,""],test_shortest_path_1:[335,3,1,""],test_spawn:[335,3,1,""]},"evennia.contrib.grid.xyzgrid.utils":{MapError:[336,2,1,""],MapParserError:[336,2,1,""],MapTransition:[336,2,1,""]},"evennia.contrib.grid.xyzgrid.utils.MapError":{__init__:[336,3,1,""]},"evennia.contrib.grid.xyzgrid.xymap":{XYMap:[337,1,1,""]},"evennia.contrib.grid.xyzgrid.xymap.XYMap":{__init__:[337,3,1,""],calculate_path_matrix:[337,3,1,""],empty_symbol:[337,4,1,""],get_components_with_symbol:[337,3,1,""],get_node_from_coord:[337,3,1,""],get_shortest_path:[337,3,1,""],get_visual_range:[337,3,1,""],legend_key_exceptions:[337,4,1,""],log:[337,3,1,""],mapcorner_symbol:[337,4,1,""],max_pathfinding_length:[337,4,1,""],parse:[337,3,1,""],reload:[337,3,1,""],spawn_links:[337,3,1,""],spawn_nodes:[337,3,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend":{BasicMapNode:[338,1,1,""],BlockedMapLink:[338,1,1,""],CrossMapLink:[338,1,1,""],DownMapLink:[338,1,1,""],EWMapLink:[338,1,1,""],EWOneWayMapLink:[338,1,1,""],InterruptMapLink:[338,1,1,""],InterruptMapNode:[338,1,1,""],InvisibleSmartMapLink:[338,1,1,""],MapLink:[338,1,1,""],MapNode:[338,1,1,""],MapTransitionNode:[338,1,1,""],NESWMapLink:[338,1,1,""],NSMapLink:[338,1,1,""],NSOneWayMapLink:[338,1,1,""],PlusMapLink:[338,1,1,""],RouterMapLink:[338,1,1,""],SENWMapLink:[338,1,1,""],SNOneWayMapLink:[338,1,1,""],SmartMapLink:[338,1,1,""],SmartRerouterMapLink:[338,1,1,""],SmartTeleporterMapLink:[338,1,1,""],TeleporterMapLink:[338,1,1,""],TransitionMapNode:[338,1,1,""],UpMapLink:[338,1,1,""],WEOneWayMapLink:[338,1,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.BasicMapNode":{prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.BlockedMapLink":{prototype:[338,4,1,""],symbol:[338,4,1,""],weights:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.CrossMapLink":{directions:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.DownMapLink":{direction_aliases:[338,4,1,""],prototype:[338,4,1,""],spawn_aliases:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.EWMapLink":{directions:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.EWOneWayMapLink":{directions:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.InterruptMapLink":{interrupt_path:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.InterruptMapNode":{display_symbol:[338,4,1,""],interrupt_path:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.InvisibleSmartMapLink":{direction_aliases:[338,4,1,""],display_symbol_aliases:[338,4,1,""],get_display_symbol:[338,3,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.MapLink":{__init__:[338,3,1,""],at_empty_target:[338,3,1,""],average_long_link_weights:[338,4,1,""],default_weight:[338,4,1,""],direction_aliases:[338,4,1,""],directions:[338,4,1,""],display_symbol:[338,4,1,""],generate_prototype_key:[338,3,1,""],get_direction:[338,3,1,""],get_display_symbol:[338,3,1,""],get_linked_neighbors:[338,3,1,""],get_weight:[338,3,1,""],interrupt_path:[338,4,1,""],multilink:[338,4,1,""],prototype:[338,4,1,""],spawn_aliases:[338,4,1,""],symbol:[338,4,1,""],traverse:[338,3,1,""],weights:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.MapNode":{__init__:[338,3,1,""],build_links:[338,3,1,""],direction_spawn_defaults:[338,4,1,""],display_symbol:[338,4,1,""],generate_prototype_key:[338,3,1,""],get_display_symbol:[338,3,1,""],get_exit_spawn_name:[338,3,1,""],get_spawn_xyz:[338,3,1,""],interrupt_path:[338,4,1,""],linkweights:[338,3,1,""],log:[338,3,1,""],multilink:[338,4,1,""],node_index:[338,4,1,""],prototype:[338,4,1,""],spawn:[338,3,1,""],spawn_links:[338,3,1,""],symbol:[338,4,1,""],unspawn:[338,3,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.MapTransitionNode":{display_symbol:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""],target_map_xyz:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.NESWMapLink":{directions:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.NSMapLink":{directions:[338,4,1,""],display_symbol:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.NSOneWayMapLink":{directions:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.PlusMapLink":{directions:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.RouterMapLink":{symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.SENWMapLink":{directions:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.SNOneWayMapLink":{directions:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.SmartMapLink":{get_direction:[338,3,1,""],multilink:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.SmartRerouterMapLink":{get_direction:[338,3,1,""],multilink:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.SmartTeleporterMapLink":{__init__:[338,3,1,""],at_empty_target:[338,3,1,""],direction_name:[338,4,1,""],display_symbol:[338,4,1,""],get_direction:[338,3,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.TeleporterMapLink":{symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.TransitionMapNode":{build_links:[338,3,1,""],display_symbol:[338,4,1,""],get_spawn_xyz:[338,3,1,""],symbol:[338,4,1,""],taget_map_xyz:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.UpMapLink":{direction_aliases:[338,4,1,""],prototype:[338,4,1,""],spawn_aliases:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xymap_legend.WEOneWayMapLink":{directions:[338,4,1,""],prototype:[338,4,1,""],symbol:[338,4,1,""]},"evennia.contrib.grid.xyzgrid.xyzgrid":{XYZGrid:[339,1,1,""],get_xyzgrid:[339,5,1,""]},"evennia.contrib.grid.xyzgrid.xyzgrid.XYZGrid":{"delete":[339,3,1,""],DoesNotExist:[339,2,1,""],MultipleObjectsReturned:[339,2,1,""],add_maps:[339,3,1,""],all_maps:[339,3,1,""],at_script_creation:[339,3,1,""],get_exit:[339,3,1,""],get_map:[339,3,1,""],get_room:[339,3,1,""],grid:[339,3,1,""],log:[339,3,1,""],maps_from_module:[339,3,1,""],path:[339,4,1,""],reload:[339,3,1,""],remove_map:[339,3,1,""],spawn:[339,3,1,""],typename:[339,4,1,""]},"evennia.contrib.grid.xyzgrid.xyzroom":{XYZExit:[340,1,1,""],XYZExitManager:[340,1,1,""],XYZManager:[340,1,1,""],XYZRoom:[340,1,1,""]},"evennia.contrib.grid.xyzgrid.xyzroom.XYZExit":{DoesNotExist:[340,2,1,""],MultipleObjectsReturned:[340,2,1,""],create:[340,3,1,""],objects:[340,4,1,""],path:[340,4,1,""],typename:[340,4,1,""],xyz:[340,3,1,""],xyz_destination:[340,3,1,""],xyzgrid:[340,3,1,""]},"evennia.contrib.grid.xyzgrid.xyzroom.XYZExitManager":{filter_xyz_exit:[340,3,1,""],get_xyz_exit:[340,3,1,""]},"evennia.contrib.grid.xyzgrid.xyzroom.XYZManager":{filter_xyz:[340,3,1,""],get_xyz:[340,3,1,""]},"evennia.contrib.grid.xyzgrid.xyzroom.XYZRoom":{DoesNotExist:[340,2,1,""],MultipleObjectsReturned:[340,2,1,""],create:[340,3,1,""],get_display_name:[340,3,1,""],map_align:[340,4,1,""],map_character_symbol:[340,4,1,""],map_display:[340,4,1,""],map_fill_all:[340,4,1,""],map_mode:[340,4,1,""],map_separator_char:[340,4,1,""],map_target_path_style:[340,4,1,""],map_visual_range:[340,4,1,""],objects:[340,4,1,""],path:[340,4,1,""],return_appearance:[340,3,1,""],typename:[340,4,1,""],xymap:[340,3,1,""],xyz:[340,3,1,""],xyzgrid:[340,3,1,""]},"evennia.contrib.rpg":{dice:[342,0,0,"-"],health_bar:[345,0,0,"-"],rpsystem:[348,0,0,"-"],traits:[352,0,0,"-"]},"evennia.contrib.rpg.dice":{dice:[343,0,0,"-"],tests:[344,0,0,"-"]},"evennia.contrib.rpg.dice.dice":{CmdDice:[343,1,1,""],DiceCmdSet:[343,1,1,""],roll:[343,5,1,""],roll_dice:[343,5,1,""]},"evennia.contrib.rpg.dice.dice.CmdDice":{aliases:[343,4,1,""],func:[343,3,1,""],help_category:[343,4,1,""],key:[343,4,1,""],lock_storage:[343,4,1,""],locks:[343,4,1,""],search_index_entry:[343,4,1,""]},"evennia.contrib.rpg.dice.dice.DiceCmdSet":{at_cmdset_creation:[343,3,1,""],path:[343,4,1,""]},"evennia.contrib.rpg.dice.tests":{TestDice:[344,1,1,""]},"evennia.contrib.rpg.dice.tests.TestDice":{test_cmddice:[344,3,1,""],test_roll_dice:[344,3,1,""]},"evennia.contrib.rpg.health_bar":{health_bar:[346,0,0,"-"],tests:[347,0,0,"-"]},"evennia.contrib.rpg.health_bar.health_bar":{display_meter:[346,5,1,""]},"evennia.contrib.rpg.health_bar.tests":{TestHealthBar:[347,1,1,""]},"evennia.contrib.rpg.health_bar.tests.TestHealthBar":{test_healthbar:[347,3,1,""]},"evennia.contrib.rpg.rpsystem":{rplanguage:[349,0,0,"-"],rpsystem:[350,0,0,"-"],tests:[351,0,0,"-"]},"evennia.contrib.rpg.rpsystem.rplanguage":{LanguageError:[349,2,1,""],LanguageExistsError:[349,2,1,""],LanguageHandler:[349,1,1,""],add_language:[349,5,1,""],available_languages:[349,5,1,""],obfuscate_language:[349,5,1,""],obfuscate_whisper:[349,5,1,""]},"evennia.contrib.rpg.rpsystem.rplanguage.LanguageHandler":{DoesNotExist:[349,2,1,""],MultipleObjectsReturned:[349,2,1,""],add:[349,3,1,""],at_script_creation:[349,3,1,""],path:[349,4,1,""],translate:[349,3,1,""],typename:[349,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem":{CmdEmote:[350,1,1,""],CmdMask:[350,1,1,""],CmdPose:[350,1,1,""],CmdRecog:[350,1,1,""],CmdSay:[350,1,1,""],CmdSdesc:[350,1,1,""],ContribRPCharacter:[350,1,1,""],ContribRPObject:[350,1,1,""],ContribRPRoom:[350,1,1,""],EmoteError:[350,2,1,""],LanguageError:[350,2,1,""],RPCommand:[350,1,1,""],RPSystemCmdSet:[350,1,1,""],RecogError:[350,2,1,""],RecogHandler:[350,1,1,""],SdescError:[350,2,1,""],SdescHandler:[350,1,1,""],ordered_permutation_regex:[350,5,1,""],parse_language:[350,5,1,""],parse_sdescs_and_recogs:[350,5,1,""],regex_tuple_from_key_alias:[350,5,1,""],send_emote:[350,5,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.CmdEmote":{aliases:[350,4,1,""],arg_regex:[350,4,1,""],func:[350,3,1,""],help_category:[350,4,1,""],key:[350,4,1,""],lock_storage:[350,4,1,""],locks:[350,4,1,""],search_index_entry:[350,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.CmdMask":{aliases:[350,4,1,""],func:[350,3,1,""],help_category:[350,4,1,""],key:[350,4,1,""],lock_storage:[350,4,1,""],search_index_entry:[350,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.CmdPose":{aliases:[350,4,1,""],func:[350,3,1,""],help_category:[350,4,1,""],key:[350,4,1,""],lock_storage:[350,4,1,""],parse:[350,3,1,""],search_index_entry:[350,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.CmdRecog":{aliases:[350,4,1,""],func:[350,3,1,""],help_category:[350,4,1,""],key:[350,4,1,""],lock_storage:[350,4,1,""],parse:[350,3,1,""],search_index_entry:[350,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.CmdSay":{aliases:[350,4,1,""],arg_regex:[350,4,1,""],func:[350,3,1,""],help_category:[350,4,1,""],key:[350,4,1,""],lock_storage:[350,4,1,""],locks:[350,4,1,""],search_index_entry:[350,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.CmdSdesc":{aliases:[350,4,1,""],func:[350,3,1,""],help_category:[350,4,1,""],key:[350,4,1,""],lock_storage:[350,4,1,""],locks:[350,4,1,""],search_index_entry:[350,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.ContribRPCharacter":{DoesNotExist:[350,2,1,""],MultipleObjectsReturned:[350,2,1,""],at_object_creation:[350,3,1,""],at_pre_say:[350,3,1,""],get_display_name:[350,3,1,""],path:[350,4,1,""],process_language:[350,3,1,""],process_recog:[350,3,1,""],process_sdesc:[350,3,1,""],recog:[350,4,1,""],sdesc:[350,4,1,""],typename:[350,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.ContribRPObject":{DoesNotExist:[350,2,1,""],MultipleObjectsReturned:[350,2,1,""],at_object_creation:[350,3,1,""],get_display_name:[350,3,1,""],path:[350,4,1,""],return_appearance:[350,3,1,""],search:[350,3,1,""],typename:[350,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.ContribRPRoom":{DoesNotExist:[350,2,1,""],MultipleObjectsReturned:[350,2,1,""],path:[350,4,1,""],typename:[350,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.RPCommand":{aliases:[350,4,1,""],help_category:[350,4,1,""],key:[350,4,1,""],lock_storage:[350,4,1,""],parse:[350,3,1,""],search_index_entry:[350,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.RPSystemCmdSet":{at_cmdset_creation:[350,3,1,""],path:[350,4,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.RecogHandler":{__init__:[350,3,1,""],add:[350,3,1,""],all:[350,3,1,""],get:[350,3,1,""],get_regex_tuple:[350,3,1,""],remove:[350,3,1,""]},"evennia.contrib.rpg.rpsystem.rpsystem.SdescHandler":{__init__:[350,3,1,""],add:[350,3,1,""],get:[350,3,1,""],get_regex_tuple:[350,3,1,""]},"evennia.contrib.rpg.rpsystem.tests":{TestLanguage:[351,1,1,""],TestRPSystem:[351,1,1,""],TestRPSystemCommands:[351,1,1,""]},"evennia.contrib.rpg.rpsystem.tests.TestLanguage":{setUp:[351,3,1,""],tearDown:[351,3,1,""],test_available_languages:[351,3,1,""],test_faulty_language:[351,3,1,""],test_obfuscate_language:[351,3,1,""],test_obfuscate_whisper:[351,3,1,""]},"evennia.contrib.rpg.rpsystem.tests.TestRPSystem":{maxDiff:[351,4,1,""],parse_sdescs_and_recogs:[351,3,1,""],setUp:[351,3,1,""],test_ordered_permutation_regex:[351,3,1,""],test_parse_language:[351,3,1,""],test_recog_handler:[351,3,1,""],test_regex_tuple_from_key_alias:[351,3,1,""],test_rpsearch:[351,3,1,""],test_sdesc_handler:[351,3,1,""],test_send_case_sensitive_emote:[351,3,1,""],test_send_emote:[351,3,1,""]},"evennia.contrib.rpg.rpsystem.tests.TestRPSystemCommands":{setUp:[351,3,1,""],test_commands:[351,3,1,""]},"evennia.contrib.rpg.traits":{tests:[353,0,0,"-"],traits:[354,0,0,"-"]},"evennia.contrib.rpg.traits.tests":{DummyCharacter:[353,1,1,""],TestNumericTraitOperators:[353,1,1,""],TestTrait:[353,1,1,""],TestTraitCounter:[353,1,1,""],TestTraitCounterTimed:[353,1,1,""],TestTraitFields:[353,1,1,""],TestTraitGauge:[353,1,1,""],TestTraitGaugeTimed:[353,1,1,""],TestTraitStatic:[353,1,1,""],TraitHandlerTest:[353,1,1,""]},"evennia.contrib.rpg.traits.tests.DummyCharacter":{health:[353,4,1,""],hunting:[353,4,1,""],strength:[353,4,1,""]},"evennia.contrib.rpg.traits.tests.TestNumericTraitOperators":{setUp:[353,3,1,""],tearDown:[353,3,1,""],test_add_traits:[353,3,1,""],test_comparisons_numeric:[353,3,1,""],test_comparisons_traits:[353,3,1,""],test_floordiv:[353,3,1,""],test_mul_traits:[353,3,1,""],test_pos_shortcut:[353,3,1,""],test_sub_traits:[353,3,1,""]},"evennia.contrib.rpg.traits.tests.TestTrait":{setUp:[353,3,1,""],test_init:[353,3,1,""],test_repr:[353,3,1,""],test_trait_getset:[353,3,1,""],test_validate_input__fail:[353,3,1,""],test_validate_input__valid:[353,3,1,""]},"evennia.contrib.rpg.traits.tests.TestTraitCounter":{setUp:[353,3,1,""],test_boundaries__bigmod:[353,3,1,""],test_boundaries__change_boundaries:[353,3,1,""],test_boundaries__disable:[353,3,1,""],test_boundaries__inverse:[353,3,1,""],test_boundaries__minmax:[353,3,1,""],test_current:[353,3,1,""],test_delete:[353,3,1,""],test_descs:[353,3,1,""],test_init:[353,3,1,""],test_percentage:[353,3,1,""],test_value:[353,3,1,""]},"evennia.contrib.rpg.traits.tests.TestTraitCounterTimed":{setUp:[353,3,1,""],test_timer_rate:[353,3,1,""],test_timer_ratetarget:[353,3,1,""]},"evennia.contrib.rpg.traits.tests.TestTraitFields":{test_traitfields:[353,3,1,""]},"evennia.contrib.rpg.traits.tests.TestTraitGauge":{setUp:[353,3,1,""],test_boundaries__bigmod:[353,3,1,""],test_boundaries__change_boundaries:[353,3,1,""],test_boundaries__disable:[353,3,1,""],test_boundaries__inverse:[353,3,1,""],test_boundaries__minmax:[353,3,1,""],test_current:[353,3,1,""],test_delete:[353,3,1,""],test_descs:[353,3,1,""],test_init:[353,3,1,""],test_percentage:[353,3,1,""],test_value:[353,3,1,""]},"evennia.contrib.rpg.traits.tests.TestTraitGaugeTimed":{setUp:[353,3,1,""],test_timer_rate:[353,3,1,""],test_timer_ratetarget:[353,3,1,""]},"evennia.contrib.rpg.traits.tests.TestTraitStatic":{setUp:[353,3,1,""],test_delete:[353,3,1,""],test_init:[353,3,1,""],test_value:[353,3,1,""]},"evennia.contrib.rpg.traits.tests.TraitHandlerTest":{setUp:[353,3,1,""],test_add_trait:[353,3,1,""],test_all:[353,3,1,""],test_cache:[353,3,1,""],test_clear:[353,3,1,""],test_getting:[353,3,1,""],test_remove:[353,3,1,""],test_setting:[353,3,1,""],test_trait_db_connection:[353,3,1,""]},"evennia.contrib.rpg.traits.traits":{CounterTrait:[354,1,1,""],GaugeTrait:[354,1,1,""],MandatoryTraitKey:[354,1,1,""],StaticTrait:[354,1,1,""],Trait:[354,1,1,""],TraitException:[354,2,1,""],TraitHandler:[354,1,1,""],TraitProperty:[354,1,1,""]},"evennia.contrib.rpg.traits.traits.CounterTrait":{base:[354,3,1,""],current:[354,3,1,""],default_keys:[354,4,1,""],desc:[354,3,1,""],max:[354,3,1,""],min:[354,3,1,""],mod:[354,3,1,""],percent:[354,3,1,""],ratetarget:[354,3,1,""],reset:[354,3,1,""],trait_type:[354,4,1,""],validate_input:[354,3,1,""],value:[354,3,1,""]},"evennia.contrib.rpg.traits.traits.GaugeTrait":{base:[354,3,1,""],current:[354,3,1,""],default_keys:[354,4,1,""],max:[354,3,1,""],min:[354,3,1,""],mod:[354,3,1,""],percent:[354,3,1,""],reset:[354,3,1,""],trait_type:[354,4,1,""],value:[354,3,1,""]},"evennia.contrib.rpg.traits.traits.StaticTrait":{base:[354,3,1,""],default_keys:[354,4,1,""],mod:[354,3,1,""],trait_type:[354,4,1,""],value:[354,3,1,""]},"evennia.contrib.rpg.traits.traits.Trait":{__init__:[354,3,1,""],allow_extra_properties:[354,4,1,""],default_keys:[354,4,1,""],key:[354,3,1,""],name:[354,3,1,""],trait_type:[354,4,1,""],validate_input:[354,3,1,""],value:[354,3,1,""]},"evennia.contrib.rpg.traits.traits.TraitException":{__init__:[354,3,1,""]},"evennia.contrib.rpg.traits.traits.TraitHandler":{__init__:[354,3,1,""],add:[354,3,1,""],all:[354,3,1,""],clear:[354,3,1,""],get:[354,3,1,""],remove:[354,3,1,""]},"evennia.contrib.rpg.traits.traits.TraitProperty":{__init__:[354,3,1,""]},"evennia.contrib.tutorials":{batchprocessor:[356,0,0,"-"],bodyfunctions:[358,0,0,"-"],mirror:[361,0,0,"-"],red_button:[363,0,0,"-"],talking_npc:[365,0,0,"-"],tutorial_world:[368,0,0,"-"]},"evennia.contrib.tutorials.bodyfunctions":{bodyfunctions:[359,0,0,"-"],tests:[360,0,0,"-"]},"evennia.contrib.tutorials.bodyfunctions.bodyfunctions":{BodyFunctions:[359,1,1,""]},"evennia.contrib.tutorials.bodyfunctions.bodyfunctions.BodyFunctions":{DoesNotExist:[359,2,1,""],MultipleObjectsReturned:[359,2,1,""],at_repeat:[359,3,1,""],at_script_creation:[359,3,1,""],path:[359,4,1,""],send_random_message:[359,3,1,""],typename:[359,4,1,""]},"evennia.contrib.tutorials.bodyfunctions.tests":{TestBodyFunctions:[360,1,1,""]},"evennia.contrib.tutorials.bodyfunctions.tests.TestBodyFunctions":{script_typeclass:[360,4,1,""],setUp:[360,3,1,""],tearDown:[360,3,1,""],test_at_repeat:[360,3,1,""],test_send_random_message:[360,3,1,""]},"evennia.contrib.tutorials.mirror":{mirror:[362,0,0,"-"]},"evennia.contrib.tutorials.mirror.mirror":{TutorialMirror:[362,1,1,""]},"evennia.contrib.tutorials.mirror.mirror.TutorialMirror":{DoesNotExist:[362,2,1,""],MultipleObjectsReturned:[362,2,1,""],msg:[362,3,1,""],path:[362,4,1,""],return_appearance:[362,3,1,""],typename:[362,4,1,""]},"evennia.contrib.tutorials.red_button":{red_button:[364,0,0,"-"]},"evennia.contrib.tutorials.red_button.red_button":{BlindCmdSet:[364,1,1,""],CmdBlindHelp:[364,1,1,""],CmdBlindLook:[364,1,1,""],CmdCloseLid:[364,1,1,""],CmdNudge:[364,1,1,""],CmdOpenLid:[364,1,1,""],CmdPushLidClosed:[364,1,1,""],CmdPushLidOpen:[364,1,1,""],CmdSmashGlass:[364,1,1,""],LidClosedCmdSet:[364,1,1,""],LidOpenCmdSet:[364,1,1,""],RedButton:[364,1,1,""]},"evennia.contrib.tutorials.red_button.red_button.BlindCmdSet":{at_cmdset_creation:[364,3,1,""],key:[364,4,1,""],mergetype:[364,4,1,""],no_exits:[364,4,1,""],no_objs:[364,4,1,""],path:[364,4,1,""]},"evennia.contrib.tutorials.red_button.red_button.CmdBlindHelp":{aliases:[364,4,1,""],func:[364,3,1,""],help_category:[364,4,1,""],key:[364,4,1,""],lock_storage:[364,4,1,""],locks:[364,4,1,""],search_index_entry:[364,4,1,""]},"evennia.contrib.tutorials.red_button.red_button.CmdBlindLook":{aliases:[364,4,1,""],func:[364,3,1,""],help_category:[364,4,1,""],key:[364,4,1,""],lock_storage:[364,4,1,""],locks:[364,4,1,""],search_index_entry:[364,4,1,""]},"evennia.contrib.tutorials.red_button.red_button.CmdCloseLid":{aliases:[364,4,1,""],func:[364,3,1,""],help_category:[364,4,1,""],key:[364,4,1,""],lock_storage:[364,4,1,""],locks:[364,4,1,""],search_index_entry:[364,4,1,""]},"evennia.contrib.tutorials.red_button.red_button.CmdNudge":{aliases:[364,4,1,""],func:[364,3,1,""],help_category:[364,4,1,""],key:[364,4,1,""],lock_storage:[364,4,1,""],locks:[364,4,1,""],search_index_entry:[364,4,1,""]},"evennia.contrib.tutorials.red_button.red_button.CmdOpenLid":{aliases:[364,4,1,""],func:[364,3,1,""],help_category:[364,4,1,""],key:[364,4,1,""],lock_storage:[364,4,1,""],locks:[364,4,1,""],search_index_entry:[364,4,1,""]},"evennia.contrib.tutorials.red_button.red_button.CmdPushLidClosed":{aliases:[364,4,1,""],func:[364,3,1,""],help_category:[364,4,1,""],key:[364,4,1,""],lock_storage:[364,4,1,""],locks:[364,4,1,""],search_index_entry:[364,4,1,""]},"evennia.contrib.tutorials.red_button.red_button.CmdPushLidOpen":{aliases:[364,4,1,""],func:[364,3,1,""],help_category:[364,4,1,""],key:[364,4,1,""],lock_storage:[364,4,1,""],locks:[364,4,1,""],search_index_entry:[364,4,1,""]},"evennia.contrib.tutorials.red_button.red_button.CmdSmashGlass":{aliases:[364,4,1,""],func:[364,3,1,""],help_category:[364,4,1,""],key:[364,4,1,""],lock_storage:[364,4,1,""],locks:[364,4,1,""],search_index_entry:[364,4,1,""]},"evennia.contrib.tutorials.red_button.red_button.LidClosedCmdSet":{at_cmdset_creation:[364,3,1,""],key:[364,4,1,""],path:[364,4,1,""]},"evennia.contrib.tutorials.red_button.red_button.LidOpenCmdSet":{at_cmdset_creation:[364,3,1,""],key:[364,4,1,""],path:[364,4,1,""]},"evennia.contrib.tutorials.red_button.red_button.RedButton":{DoesNotExist:[364,2,1,""],MultipleObjectsReturned:[364,2,1,""],at_object_creation:[364,3,1,""],auto_close_msg:[364,4,1,""],blind_target:[364,3,1,""],blink_msgs:[364,4,1,""],break_lamp:[364,3,1,""],desc_add_lamp_broken:[364,4,1,""],desc_closed_lid:[364,4,1,""],desc_open_lid:[364,4,1,""],lamp_breaks_msg:[364,4,1,""],path:[364,4,1,""],to_closed_state:[364,3,1,""],to_open_state:[364,3,1,""],typename:[364,4,1,""]},"evennia.contrib.tutorials.talking_npc":{talking_npc:[366,0,0,"-"],tests:[367,0,0,"-"]},"evennia.contrib.tutorials.talking_npc.talking_npc":{CmdTalk:[366,1,1,""],END:[366,5,1,""],TalkingCmdSet:[366,1,1,""],TalkingNPC:[366,1,1,""],info1:[366,5,1,""],info2:[366,5,1,""],info3:[366,5,1,""],menu_start_node:[366,5,1,""]},"evennia.contrib.tutorials.talking_npc.talking_npc.CmdTalk":{aliases:[366,4,1,""],func:[366,3,1,""],help_category:[366,4,1,""],key:[366,4,1,""],lock_storage:[366,4,1,""],locks:[366,4,1,""],search_index_entry:[366,4,1,""]},"evennia.contrib.tutorials.talking_npc.talking_npc.TalkingCmdSet":{at_cmdset_creation:[366,3,1,""],key:[366,4,1,""],path:[366,4,1,""]},"evennia.contrib.tutorials.talking_npc.talking_npc.TalkingNPC":{DoesNotExist:[366,2,1,""],MultipleObjectsReturned:[366,2,1,""],at_object_creation:[366,3,1,""],path:[366,4,1,""],typename:[366,4,1,""]},"evennia.contrib.tutorials.talking_npc.tests":{TestTalkingNPC:[367,1,1,""]},"evennia.contrib.tutorials.talking_npc.tests.TestTalkingNPC":{test_talkingnpc:[367,3,1,""]},"evennia.contrib.tutorials.tutorial_world":{intro_menu:[369,0,0,"-"],mob:[370,0,0,"-"],objects:[371,0,0,"-"],rooms:[372,0,0,"-"],tests:[373,0,0,"-"]},"evennia.contrib.tutorials.tutorial_world.intro_menu":{DemoCommandSetComms:[369,1,1,""],DemoCommandSetHelp:[369,1,1,""],DemoCommandSetRoom:[369,1,1,""],TutorialEvMenu:[369,1,1,""],do_nothing:[369,5,1,""],goto_cleanup_cmdsets:[369,5,1,""],goto_command_demo_comms:[369,5,1,""],goto_command_demo_help:[369,5,1,""],goto_command_demo_room:[369,5,1,""],init_menu:[369,5,1,""],send_testing_tagged:[369,5,1,""]},"evennia.contrib.tutorials.tutorial_world.intro_menu.DemoCommandSetComms":{at_cmdset_creation:[369,3,1,""],key:[369,4,1,""],no_exits:[369,4,1,""],no_objs:[369,4,1,""],path:[369,4,1,""],priority:[369,4,1,""]},"evennia.contrib.tutorials.tutorial_world.intro_menu.DemoCommandSetHelp":{at_cmdset_creation:[369,3,1,""],key:[369,4,1,""],path:[369,4,1,""],priority:[369,4,1,""]},"evennia.contrib.tutorials.tutorial_world.intro_menu.DemoCommandSetRoom":{at_cmdset_creation:[369,3,1,""],key:[369,4,1,""],no_exits:[369,4,1,""],no_objs:[369,4,1,""],path:[369,4,1,""],priority:[369,4,1,""]},"evennia.contrib.tutorials.tutorial_world.intro_menu.TutorialEvMenu":{close_menu:[369,3,1,""],options_formatter:[369,3,1,""]},"evennia.contrib.tutorials.tutorial_world.mob":{CmdMobOnOff:[370,1,1,""],Mob:[370,1,1,""],MobCmdSet:[370,1,1,""]},"evennia.contrib.tutorials.tutorial_world.mob.CmdMobOnOff":{aliases:[370,4,1,""],func:[370,3,1,""],help_category:[370,4,1,""],key:[370,4,1,""],lock_storage:[370,4,1,""],locks:[370,4,1,""],search_index_entry:[370,4,1,""]},"evennia.contrib.tutorials.tutorial_world.mob.Mob":{DoesNotExist:[370,2,1,""],MultipleObjectsReturned:[370,2,1,""],at_hit:[370,3,1,""],at_init:[370,3,1,""],at_new_arrival:[370,3,1,""],at_object_creation:[370,3,1,""],do_attack:[370,3,1,""],do_hunting:[370,3,1,""],do_patrol:[370,3,1,""],path:[370,4,1,""],set_alive:[370,3,1,""],set_dead:[370,3,1,""],start_attacking:[370,3,1,""],start_hunting:[370,3,1,""],start_idle:[370,3,1,""],start_patrolling:[370,3,1,""],typename:[370,4,1,""]},"evennia.contrib.tutorials.tutorial_world.mob.MobCmdSet":{at_cmdset_creation:[370,3,1,""],path:[370,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects":{CmdAttack:[371,1,1,""],CmdClimb:[371,1,1,""],CmdGetWeapon:[371,1,1,""],CmdLight:[371,1,1,""],CmdPressButton:[371,1,1,""],CmdRead:[371,1,1,""],CmdSetClimbable:[371,1,1,""],CmdSetCrumblingWall:[371,1,1,""],CmdSetLight:[371,1,1,""],CmdSetReadable:[371,1,1,""],CmdSetWeapon:[371,1,1,""],CmdSetWeaponRack:[371,1,1,""],CmdShiftRoot:[371,1,1,""],CrumblingWall:[371,1,1,""],LightSource:[371,1,1,""],Obelisk:[371,1,1,""],TutorialClimbable:[371,1,1,""],TutorialObject:[371,1,1,""],TutorialReadable:[371,1,1,""],TutorialWeapon:[371,1,1,""],TutorialWeaponRack:[371,1,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdAttack":{aliases:[371,4,1,""],func:[371,3,1,""],help_category:[371,4,1,""],key:[371,4,1,""],lock_storage:[371,4,1,""],locks:[371,4,1,""],search_index_entry:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdClimb":{aliases:[371,4,1,""],func:[371,3,1,""],help_category:[371,4,1,""],key:[371,4,1,""],lock_storage:[371,4,1,""],locks:[371,4,1,""],search_index_entry:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdGetWeapon":{aliases:[371,4,1,""],func:[371,3,1,""],help_category:[371,4,1,""],key:[371,4,1,""],lock_storage:[371,4,1,""],locks:[371,4,1,""],search_index_entry:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdLight":{aliases:[371,4,1,""],func:[371,3,1,""],help_category:[371,4,1,""],key:[371,4,1,""],lock_storage:[371,4,1,""],locks:[371,4,1,""],search_index_entry:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdPressButton":{aliases:[371,4,1,""],func:[371,3,1,""],help_category:[371,4,1,""],key:[371,4,1,""],lock_storage:[371,4,1,""],locks:[371,4,1,""],search_index_entry:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdRead":{aliases:[371,4,1,""],func:[371,3,1,""],help_category:[371,4,1,""],key:[371,4,1,""],lock_storage:[371,4,1,""],locks:[371,4,1,""],search_index_entry:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdSetClimbable":{at_cmdset_creation:[371,3,1,""],path:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdSetCrumblingWall":{at_cmdset_creation:[371,3,1,""],key:[371,4,1,""],path:[371,4,1,""],priority:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdSetLight":{at_cmdset_creation:[371,3,1,""],key:[371,4,1,""],path:[371,4,1,""],priority:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdSetReadable":{at_cmdset_creation:[371,3,1,""],path:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdSetWeapon":{at_cmdset_creation:[371,3,1,""],path:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdSetWeaponRack":{at_cmdset_creation:[371,3,1,""],key:[371,4,1,""],path:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CmdShiftRoot":{aliases:[371,4,1,""],func:[371,3,1,""],help_category:[371,4,1,""],key:[371,4,1,""],lock_storage:[371,4,1,""],locks:[371,4,1,""],parse:[371,3,1,""],search_index_entry:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.CrumblingWall":{DoesNotExist:[371,2,1,""],MultipleObjectsReturned:[371,2,1,""],at_failed_traverse:[371,3,1,""],at_init:[371,3,1,""],at_object_creation:[371,3,1,""],at_post_traverse:[371,3,1,""],open_wall:[371,3,1,""],path:[371,4,1,""],reset:[371,3,1,""],return_appearance:[371,3,1,""],typename:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.LightSource":{DoesNotExist:[371,2,1,""],MultipleObjectsReturned:[371,2,1,""],at_init:[371,3,1,""],at_object_creation:[371,3,1,""],light:[371,3,1,""],path:[371,4,1,""],typename:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.Obelisk":{DoesNotExist:[371,2,1,""],MultipleObjectsReturned:[371,2,1,""],at_object_creation:[371,3,1,""],path:[371,4,1,""],return_appearance:[371,3,1,""],typename:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.TutorialClimbable":{DoesNotExist:[371,2,1,""],MultipleObjectsReturned:[371,2,1,""],at_object_creation:[371,3,1,""],path:[371,4,1,""],typename:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.TutorialObject":{DoesNotExist:[371,2,1,""],MultipleObjectsReturned:[371,2,1,""],at_object_creation:[371,3,1,""],path:[371,4,1,""],reset:[371,3,1,""],typename:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.TutorialReadable":{DoesNotExist:[371,2,1,""],MultipleObjectsReturned:[371,2,1,""],at_object_creation:[371,3,1,""],path:[371,4,1,""],typename:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.TutorialWeapon":{DoesNotExist:[371,2,1,""],MultipleObjectsReturned:[371,2,1,""],at_object_creation:[371,3,1,""],path:[371,4,1,""],reset:[371,3,1,""],typename:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.objects.TutorialWeaponRack":{DoesNotExist:[371,2,1,""],MultipleObjectsReturned:[371,2,1,""],at_object_creation:[371,3,1,""],path:[371,4,1,""],produce_weapon:[371,3,1,""],typename:[371,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms":{BridgeCmdSet:[372,1,1,""],BridgeRoom:[372,1,1,""],CmdBridgeHelp:[372,1,1,""],CmdDarkHelp:[372,1,1,""],CmdDarkNoMatch:[372,1,1,""],CmdEast:[372,1,1,""],CmdEvenniaIntro:[372,1,1,""],CmdLookBridge:[372,1,1,""],CmdLookDark:[372,1,1,""],CmdSetEvenniaIntro:[372,1,1,""],CmdTutorial:[372,1,1,""],CmdTutorialGiveUp:[372,1,1,""],CmdTutorialLook:[372,1,1,""],CmdTutorialSetDetail:[372,1,1,""],CmdWest:[372,1,1,""],DarkCmdSet:[372,1,1,""],DarkRoom:[372,1,1,""],IntroRoom:[372,1,1,""],OutroRoom:[372,1,1,""],TeleportRoom:[372,1,1,""],TutorialRoom:[372,1,1,""],TutorialRoomCmdSet:[372,1,1,""],WeatherRoom:[372,1,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.BridgeCmdSet":{at_cmdset_creation:[372,3,1,""],key:[372,4,1,""],path:[372,4,1,""],priority:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.BridgeRoom":{DoesNotExist:[372,2,1,""],MultipleObjectsReturned:[372,2,1,""],at_object_creation:[372,3,1,""],at_object_leave:[372,3,1,""],at_object_receive:[372,3,1,""],path:[372,4,1,""],typename:[372,4,1,""],update_weather:[372,3,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdBridgeHelp":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],locks:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdDarkHelp":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],locks:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdDarkNoMatch":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],locks:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdEast":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],locks:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdEvenniaIntro":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdLookBridge":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],locks:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdLookDark":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],locks:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdSetEvenniaIntro":{at_cmdset_creation:[372,3,1,""],key:[372,4,1,""],path:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdTutorial":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],locks:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdTutorialGiveUp":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdTutorialLook":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdTutorialSetDetail":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],locks:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.CmdWest":{aliases:[372,4,1,""],func:[372,3,1,""],help_category:[372,4,1,""],key:[372,4,1,""],lock_storage:[372,4,1,""],locks:[372,4,1,""],search_index_entry:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.DarkCmdSet":{at_cmdset_creation:[372,3,1,""],key:[372,4,1,""],mergetype:[372,4,1,""],path:[372,4,1,""],priority:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.DarkRoom":{DoesNotExist:[372,2,1,""],MultipleObjectsReturned:[372,2,1,""],at_init:[372,3,1,""],at_object_creation:[372,3,1,""],at_object_leave:[372,3,1,""],at_object_receive:[372,3,1,""],check_light_state:[372,3,1,""],path:[372,4,1,""],typename:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.IntroRoom":{DoesNotExist:[372,2,1,""],MultipleObjectsReturned:[372,2,1,""],at_object_creation:[372,3,1,""],at_object_receive:[372,3,1,""],path:[372,4,1,""],typename:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.OutroRoom":{DoesNotExist:[372,2,1,""],MultipleObjectsReturned:[372,2,1,""],at_object_creation:[372,3,1,""],at_object_leave:[372,3,1,""],at_object_receive:[372,3,1,""],path:[372,4,1,""],typename:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.TeleportRoom":{DoesNotExist:[372,2,1,""],MultipleObjectsReturned:[372,2,1,""],at_object_creation:[372,3,1,""],at_object_receive:[372,3,1,""],path:[372,4,1,""],typename:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.TutorialRoom":{DoesNotExist:[372,2,1,""],MultipleObjectsReturned:[372,2,1,""],at_object_creation:[372,3,1,""],at_object_receive:[372,3,1,""],path:[372,4,1,""],return_detail:[372,3,1,""],set_detail:[372,3,1,""],typename:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.TutorialRoomCmdSet":{at_cmdset_creation:[372,3,1,""],key:[372,4,1,""],path:[372,4,1,""],priority:[372,4,1,""]},"evennia.contrib.tutorials.tutorial_world.rooms.WeatherRoom":{DoesNotExist:[372,2,1,""],MultipleObjectsReturned:[372,2,1,""],at_object_creation:[372,3,1,""],path:[372,4,1,""],typename:[372,4,1,""],update_weather:[372,3,1,""]},"evennia.contrib.tutorials.tutorial_world.tests":{TestTutorialWorldMob:[373,1,1,""],TestTutorialWorldObjects:[373,1,1,""],TestTutorialWorldRooms:[373,1,1,""]},"evennia.contrib.tutorials.tutorial_world.tests.TestTutorialWorldMob":{test_mob:[373,3,1,""]},"evennia.contrib.tutorials.tutorial_world.tests.TestTutorialWorldObjects":{test_climbable:[373,3,1,""],test_crumblingwall:[373,3,1,""],test_lightsource:[373,3,1,""],test_obelisk:[373,3,1,""],test_readable:[373,3,1,""],test_tutorialobj:[373,3,1,""],test_weapon:[373,3,1,""],test_weaponrack:[373,3,1,""]},"evennia.contrib.tutorials.tutorial_world.tests.TestTutorialWorldRooms":{test_bridgeroom:[373,3,1,""],test_cmdtutorial:[373,3,1,""],test_darkroom:[373,3,1,""],test_introroom:[373,3,1,""],test_outroroom:[373,3,1,""],test_teleportroom:[373,3,1,""],test_weatherroom:[373,3,1,""]},"evennia.contrib.utils":{auditing:[375,0,0,"-"],fieldfill:[379,0,0,"-"],random_string_generator:[381,0,0,"-"],tree_select:[384,0,0,"-"]},"evennia.contrib.utils.auditing":{outputs:[376,0,0,"-"],server:[377,0,0,"-"],tests:[378,0,0,"-"]},"evennia.contrib.utils.auditing.outputs":{to_file:[376,5,1,""],to_syslog:[376,5,1,""]},"evennia.contrib.utils.auditing.server":{AuditedServerSession:[377,1,1,""]},"evennia.contrib.utils.auditing.server.AuditedServerSession":{audit:[377,3,1,""],data_in:[377,3,1,""],data_out:[377,3,1,""],mask:[377,3,1,""]},"evennia.contrib.utils.auditing.tests":{AuditingTest:[378,1,1,""]},"evennia.contrib.utils.auditing.tests.AuditingTest":{setup_session:[378,3,1,""],test_audit:[378,3,1,""],test_mask:[378,3,1,""]},"evennia.contrib.utils.fieldfill":{fieldfill:[380,0,0,"-"]},"evennia.contrib.utils.fieldfill.fieldfill":{CmdTestMenu:[380,1,1,""],FieldEvMenu:[380,1,1,""],display_formdata:[380,5,1,""],form_template_to_dict:[380,5,1,""],init_delayed_message:[380,5,1,""],init_fill_field:[380,5,1,""],menunode_fieldfill:[380,5,1,""],sendmessage:[380,5,1,""],verify_online_player:[380,5,1,""]},"evennia.contrib.utils.fieldfill.fieldfill.CmdTestMenu":{aliases:[380,4,1,""],func:[380,3,1,""],help_category:[380,4,1,""],key:[380,4,1,""],lock_storage:[380,4,1,""],search_index_entry:[380,4,1,""]},"evennia.contrib.utils.fieldfill.fieldfill.FieldEvMenu":{node_formatter:[380,3,1,""]},"evennia.contrib.utils.random_string_generator":{random_string_generator:[382,0,0,"-"],tests:[383,0,0,"-"]},"evennia.contrib.utils.random_string_generator.random_string_generator":{ExhaustedGenerator:[382,2,1,""],RandomStringGenerator:[382,1,1,""],RandomStringGeneratorScript:[382,1,1,""],RejectedRegex:[382,2,1,""]},"evennia.contrib.utils.random_string_generator.random_string_generator.RandomStringGenerator":{__init__:[382,3,1,""],all:[382,3,1,""],clear:[382,3,1,""],get:[382,3,1,""],remove:[382,3,1,""],script:[382,4,1,""]},"evennia.contrib.utils.random_string_generator.random_string_generator.RandomStringGeneratorScript":{DoesNotExist:[382,2,1,""],MultipleObjectsReturned:[382,2,1,""],at_script_creation:[382,3,1,""],path:[382,4,1,""],typename:[382,4,1,""]},"evennia.contrib.utils.random_string_generator.tests":{TestRandomStringGenerator:[383,1,1,""]},"evennia.contrib.utils.random_string_generator.tests.TestRandomStringGenerator":{test_generate:[383,3,1,""]},"evennia.contrib.utils.tree_select":{tests:[385,0,0,"-"],tree_select:[386,0,0,"-"]},"evennia.contrib.utils.tree_select.tests":{TestFieldFillFunc:[385,1,1,""],TestTreeSelectFunc:[385,1,1,""]},"evennia.contrib.utils.tree_select.tests.TestFieldFillFunc":{test_field_functions:[385,3,1,""]},"evennia.contrib.utils.tree_select.tests.TestTreeSelectFunc":{test_tree_functions:[385,3,1,""]},"evennia.contrib.utils.tree_select.tree_select":{CmdNameColor:[386,1,1,""],change_name_color:[386,5,1,""],dashcount:[386,5,1,""],go_up_one_category:[386,5,1,""],index_to_selection:[386,5,1,""],init_tree_selection:[386,5,1,""],is_category:[386,5,1,""],menunode_treeselect:[386,5,1,""],optlist_to_menuoptions:[386,5,1,""],parse_opts:[386,5,1,""]},"evennia.contrib.utils.tree_select.tree_select.CmdNameColor":{aliases:[386,4,1,""],func:[386,3,1,""],help_category:[386,4,1,""],key:[386,4,1,""],lock_storage:[386,4,1,""],search_index_entry:[386,4,1,""]},"evennia.help":{filehelp:[388,0,0,"-"],manager:[389,0,0,"-"],models:[390,0,0,"-"],utils:[391,0,0,"-"]},"evennia.help.filehelp":{FileHelpEntry:[388,1,1,""],FileHelpStorageHandler:[388,1,1,""]},"evennia.help.filehelp.FileHelpEntry":{__init__:[388,3,1,""],access:[388,3,1,""],aliases:[388,4,1,""],entrytext:[388,4,1,""],help_category:[388,4,1,""],key:[388,4,1,""],lock_storage:[388,4,1,""],locks:[388,4,1,""],search_index_entry:[388,3,1,""],web_get_admin_url:[388,3,1,""],web_get_detail_url:[388,3,1,""]},"evennia.help.filehelp.FileHelpStorageHandler":{__init__:[388,3,1,""],all:[388,3,1,""],load:[388,3,1,""]},"evennia.help.manager":{HelpEntryManager:[389,1,1,""]},"evennia.help.manager.HelpEntryManager":{all_to_category:[389,3,1,""],create_help:[389,3,1,""],find_apropos:[389,3,1,""],find_topicmatch:[389,3,1,""],find_topics_with_category:[389,3,1,""],find_topicsuggestions:[389,3,1,""],get_all_categories:[389,3,1,""],get_all_topics:[389,3,1,""],search_help:[389,3,1,""]},"evennia.help.models":{HelpEntry:[390,1,1,""]},"evennia.help.models.HelpEntry":{DoesNotExist:[390,2,1,""],MultipleObjectsReturned:[390,2,1,""],access:[390,3,1,""],aliases:[390,4,1,""],date_created:[390,3,1,""],db_date_created:[390,4,1,""],db_entrytext:[390,4,1,""],db_help_category:[390,4,1,""],db_key:[390,4,1,""],db_lock_storage:[390,4,1,""],db_tags:[390,4,1,""],entrytext:[390,3,1,""],get_absolute_url:[390,3,1,""],get_next_by_db_date_created:[390,3,1,""],get_previous_by_db_date_created:[390,3,1,""],help_category:[390,3,1,""],id:[390,4,1,""],key:[390,3,1,""],lock_storage:[390,3,1,""],locks:[390,4,1,""],objects:[390,4,1,""],path:[390,4,1,""],search_index_entry:[390,3,1,""],tags:[390,4,1,""],typename:[390,4,1,""],web_get_admin_url:[390,3,1,""],web_get_create_url:[390,3,1,""],web_get_delete_url:[390,3,1,""],web_get_detail_url:[390,3,1,""],web_get_update_url:[390,3,1,""]},"evennia.help.utils":{help_search_with_index:[391,5,1,""],parse_entry_for_subcategories:[391,5,1,""]},"evennia.locks":{lockfuncs:[393,0,0,"-"],lockhandler:[394,0,0,"-"]},"evennia.locks.lockfuncs":{"false":[393,5,1,""],"true":[393,5,1,""],all:[393,5,1,""],attr:[393,5,1,""],attr_eq:[393,5,1,""],attr_ge:[393,5,1,""],attr_gt:[393,5,1,""],attr_le:[393,5,1,""],attr_lt:[393,5,1,""],attr_ne:[393,5,1,""],dbref:[393,5,1,""],has_account:[393,5,1,""],holds:[393,5,1,""],id:[393,5,1,""],inside:[393,5,1,""],inside_rec:[393,5,1,""],locattr:[393,5,1,""],none:[393,5,1,""],objattr:[393,5,1,""],objlocattr:[393,5,1,""],objtag:[393,5,1,""],pdbref:[393,5,1,""],perm:[393,5,1,""],perm_above:[393,5,1,""],pid:[393,5,1,""],pperm:[393,5,1,""],pperm_above:[393,5,1,""],self:[393,5,1,""],serversetting:[393,5,1,""],superuser:[393,5,1,""],tag:[393,5,1,""]},"evennia.locks.lockhandler":{LockException:[394,2,1,""],LockHandler:[394,1,1,""]},"evennia.locks.lockhandler.LockHandler":{"delete":[394,3,1,""],__init__:[394,3,1,""],add:[394,3,1,""],all:[394,3,1,""],append:[394,3,1,""],cache_lock_bypass:[394,3,1,""],check:[394,3,1,""],check_lockstring:[394,3,1,""],clear:[394,3,1,""],get:[394,3,1,""],remove:[394,3,1,""],replace:[394,3,1,""],reset:[394,3,1,""],validate:[394,3,1,""]},"evennia.objects":{manager:[396,0,0,"-"],models:[397,0,0,"-"],objects:[398,0,0,"-"]},"evennia.objects.manager":{ObjectDBManager:[396,1,1,""],ObjectManager:[396,1,1,""]},"evennia.objects.manager.ObjectDBManager":{clear_all_sessids:[396,3,1,""],copy_object:[396,3,1,""],create_object:[396,3,1,""],get_contents:[396,3,1,""],get_object_with_account:[396,3,1,""],get_objs_with_attr:[396,3,1,""],get_objs_with_attr_value:[396,3,1,""],get_objs_with_db_property:[396,3,1,""],get_objs_with_db_property_value:[396,3,1,""],get_objs_with_key_and_typeclass:[396,3,1,""],get_objs_with_key_or_alias:[396,3,1,""],object_search:[396,3,1,""],search:[396,3,1,""],search_object:[396,3,1,""]},"evennia.objects.models":{ContentsHandler:[397,1,1,""],ObjectDB:[397,1,1,""]},"evennia.objects.models.ContentsHandler":{__init__:[397,3,1,""],add:[397,3,1,""],clear:[397,3,1,""],get:[397,3,1,""],init:[397,3,1,""],load:[397,3,1,""],remove:[397,3,1,""]},"evennia.objects.models.ObjectDB":{DoesNotExist:[397,2,1,""],MultipleObjectsReturned:[397,2,1,""],account:[397,3,1,""],at_db_location_postsave:[397,3,1,""],cmdset_storage:[397,3,1,""],contents_cache:[397,4,1,""],db_account:[397,4,1,""],db_account_id:[397,4,1,""],db_attributes:[397,4,1,""],db_cmdset_storage:[397,4,1,""],db_destination:[397,4,1,""],db_destination_id:[397,4,1,""],db_home:[397,4,1,""],db_home_id:[397,4,1,""],db_location:[397,4,1,""],db_location_id:[397,4,1,""],db_sessid:[397,4,1,""],db_tags:[397,4,1,""],destination:[397,3,1,""],destinations_set:[397,4,1,""],get_next_by_db_date_created:[397,3,1,""],get_previous_by_db_date_created:[397,3,1,""],hide_from_objects_set:[397,4,1,""],home:[397,3,1,""],homes_set:[397,4,1,""],id:[397,4,1,""],location:[397,3,1,""],locations_set:[397,4,1,""],object_subscription_set:[397,4,1,""],objects:[397,4,1,""],path:[397,4,1,""],receiver_object_set:[397,4,1,""],scriptdb_set:[397,4,1,""],sender_object_set:[397,4,1,""],sessid:[397,3,1,""],typename:[397,4,1,""]},"evennia.objects.objects":{DefaultCharacter:[398,1,1,""],DefaultExit:[398,1,1,""],DefaultObject:[398,1,1,""],DefaultRoom:[398,1,1,""],ExitCommand:[398,1,1,""],ObjectSessionHandler:[398,1,1,""]},"evennia.objects.objects.DefaultCharacter":{DoesNotExist:[398,2,1,""],MultipleObjectsReturned:[398,2,1,""],at_after_move:[398,3,1,""],at_post_move:[398,3,1,""],at_post_puppet:[398,3,1,""],at_post_unpuppet:[398,3,1,""],at_pre_puppet:[398,3,1,""],basetype_setup:[398,3,1,""],connection_time:[398,3,1,""],create:[398,3,1,""],idle_time:[398,3,1,""],lockstring:[398,4,1,""],normalize_name:[398,3,1,""],path:[398,4,1,""],typename:[398,4,1,""],validate_name:[398,3,1,""]},"evennia.objects.objects.DefaultExit":{DoesNotExist:[398,2,1,""],MultipleObjectsReturned:[398,2,1,""],at_cmdset_get:[398,3,1,""],at_failed_traverse:[398,3,1,""],at_init:[398,3,1,""],at_traverse:[398,3,1,""],basetype_setup:[398,3,1,""],create:[398,3,1,""],create_exit_cmdset:[398,3,1,""],exit_command:[398,4,1,""],lockstring:[398,4,1,""],path:[398,4,1,""],priority:[398,4,1,""],typename:[398,4,1,""]},"evennia.objects.objects.DefaultObject":{"delete":[398,3,1,""],DoesNotExist:[398,2,1,""],MultipleObjectsReturned:[398,2,1,""],access:[398,3,1,""],announce_move_from:[398,3,1,""],announce_move_to:[398,3,1,""],appearance_template:[398,4,1,""],at_access:[398,3,1,""],at_after_move:[398,3,1,""],at_after_traverse:[398,3,1,""],at_before_drop:[398,3,1,""],at_before_get:[398,3,1,""],at_before_give:[398,3,1,""],at_before_move:[398,3,1,""],at_before_say:[398,3,1,""],at_cmdset_get:[398,3,1,""],at_desc:[398,3,1,""],at_drop:[398,3,1,""],at_failed_traverse:[398,3,1,""],at_first_save:[398,3,1,""],at_get:[398,3,1,""],at_give:[398,3,1,""],at_init:[398,3,1,""],at_look:[398,3,1,""],at_msg_receive:[398,3,1,""],at_msg_send:[398,3,1,""],at_object_creation:[398,3,1,""],at_object_delete:[398,3,1,""],at_object_leave:[398,3,1,""],at_object_post_copy:[398,3,1,""],at_object_receive:[398,3,1,""],at_post_move:[398,3,1,""],at_post_puppet:[398,3,1,""],at_post_traverse:[398,3,1,""],at_post_unpuppet:[398,3,1,""],at_pre_drop:[398,3,1,""],at_pre_get:[398,3,1,""],at_pre_give:[398,3,1,""],at_pre_move:[398,3,1,""],at_pre_puppet:[398,3,1,""],at_pre_say:[398,3,1,""],at_pre_unpuppet:[398,3,1,""],at_say:[398,3,1,""],at_server_reload:[398,3,1,""],at_server_shutdown:[398,3,1,""],at_traverse:[398,3,1,""],basetype_posthook_setup:[398,3,1,""],basetype_setup:[398,3,1,""],clear_contents:[398,3,1,""],clear_exits:[398,3,1,""],cmdset:[398,4,1,""],contents:[398,3,1,""],contents_get:[398,3,1,""],contents_set:[398,3,1,""],copy:[398,3,1,""],create:[398,3,1,""],execute_cmd:[398,3,1,""],exits:[398,3,1,""],for_contents:[398,3,1,""],get_content_names:[398,3,1,""],get_display_name:[398,3,1,""],get_numbered_name:[398,3,1,""],get_visible_contents:[398,3,1,""],has_account:[398,3,1,""],is_connected:[398,3,1,""],is_superuser:[398,3,1,""],lockstring:[398,4,1,""],move_to:[398,3,1,""],msg:[398,3,1,""],msg_contents:[398,3,1,""],nicks:[398,4,1,""],objects:[398,4,1,""],path:[398,4,1,""],return_appearance:[398,3,1,""],scripts:[398,4,1,""],search:[398,3,1,""],search_account:[398,3,1,""],sessions:[398,4,1,""],typename:[398,4,1,""]},"evennia.objects.objects.DefaultRoom":{DoesNotExist:[398,2,1,""],MultipleObjectsReturned:[398,2,1,""],basetype_setup:[398,3,1,""],create:[398,3,1,""],lockstring:[398,4,1,""],path:[398,4,1,""],typename:[398,4,1,""]},"evennia.objects.objects.ExitCommand":{aliases:[398,4,1,""],func:[398,3,1,""],get_extra_info:[398,3,1,""],help_category:[398,4,1,""],key:[398,4,1,""],lock_storage:[398,4,1,""],obj:[398,4,1,""],search_index_entry:[398,4,1,""]},"evennia.objects.objects.ObjectSessionHandler":{__init__:[398,3,1,""],add:[398,3,1,""],all:[398,3,1,""],clear:[398,3,1,""],count:[398,3,1,""],get:[398,3,1,""],remove:[398,3,1,""]},"evennia.prototypes":{menus:[400,0,0,"-"],protfuncs:[401,0,0,"-"],prototypes:[402,0,0,"-"],spawner:[403,0,0,"-"]},"evennia.prototypes.menus":{OLCMenu:[400,1,1,""],node_apply_diff:[400,5,1,""],node_destination:[400,5,1,""],node_examine_entity:[400,5,1,""],node_home:[400,5,1,""],node_index:[400,5,1,""],node_key:[400,5,1,""],node_location:[400,5,1,""],node_prototype_desc:[400,5,1,""],node_prototype_key:[400,5,1,""],node_prototype_save:[400,5,1,""],node_prototype_spawn:[400,5,1,""],node_validate_prototype:[400,5,1,""],start_olc:[400,5,1,""]},"evennia.prototypes.menus.OLCMenu":{display_helptext:[400,3,1,""],helptext_formatter:[400,3,1,""],nodetext_formatter:[400,3,1,""],options_formatter:[400,3,1,""]},"evennia.prototypes.protfuncs":{protfunc_callable_protkey:[401,5,1,""]},"evennia.prototypes.prototypes":{DbPrototype:[402,1,1,""],PermissionError:[402,2,1,""],PrototypeEvMore:[402,1,1,""],ValidationError:[402,2,1,""],check_permission:[402,5,1,""],create_prototype:[402,5,1,""],delete_prototype:[402,5,1,""],format_available_protfuncs:[402,5,1,""],homogenize_prototype:[402,5,1,""],init_spawn_value:[402,5,1,""],list_prototypes:[402,5,1,""],load_module_prototypes:[402,5,1,""],protfunc_parser:[402,5,1,""],prototype_to_str:[402,5,1,""],save_prototype:[402,5,1,""],search_objects_with_prototype:[402,5,1,""],search_prototype:[402,5,1,""],validate_prototype:[402,5,1,""],value_to_obj:[402,5,1,""],value_to_obj_or_any:[402,5,1,""]},"evennia.prototypes.prototypes.DbPrototype":{DoesNotExist:[402,2,1,""],MultipleObjectsReturned:[402,2,1,""],at_script_creation:[402,3,1,""],path:[402,4,1,""],prototype:[402,3,1,""],typename:[402,4,1,""]},"evennia.prototypes.prototypes.PrototypeEvMore":{__init__:[402,3,1,""],init_pages:[402,3,1,""],page_formatter:[402,3,1,""],prototype_paginator:[402,3,1,""]},"evennia.prototypes.spawner":{Unset:[403,1,1,""],batch_create_object:[403,5,1,""],batch_update_objects_with_prototype:[403,5,1,""],flatten_diff:[403,5,1,""],flatten_prototype:[403,5,1,""],format_diff:[403,5,1,""],prototype_diff:[403,5,1,""],prototype_diff_from_object:[403,5,1,""],prototype_from_object:[403,5,1,""],spawn:[403,5,1,""]},"evennia.scripts":{manager:[405,0,0,"-"],models:[406,0,0,"-"],monitorhandler:[407,0,0,"-"],scripthandler:[408,0,0,"-"],scripts:[409,0,0,"-"],taskhandler:[410,0,0,"-"],tickerhandler:[411,0,0,"-"]},"evennia.scripts.manager":{ScriptDBManager:[405,1,1,""],ScriptManager:[405,1,1,""]},"evennia.scripts.manager.ScriptDBManager":{copy_script:[405,3,1,""],create_script:[405,3,1,""],delete_script:[405,3,1,""],get_all_scripts:[405,3,1,""],get_all_scripts_on_obj:[405,3,1,""],script_search:[405,3,1,""],search_script:[405,3,1,""],update_scripts_after_server_start:[405,3,1,""]},"evennia.scripts.models":{ScriptDB:[406,1,1,""]},"evennia.scripts.models.ScriptDB":{DoesNotExist:[406,2,1,""],MultipleObjectsReturned:[406,2,1,""],account:[406,3,1,""],db_account:[406,4,1,""],db_account_id:[406,4,1,""],db_attributes:[406,4,1,""],db_desc:[406,4,1,""],db_interval:[406,4,1,""],db_is_active:[406,4,1,""],db_obj:[406,4,1,""],db_obj_id:[406,4,1,""],db_persistent:[406,4,1,""],db_repeats:[406,4,1,""],db_start_delay:[406,4,1,""],db_tags:[406,4,1,""],desc:[406,3,1,""],get_next_by_db_date_created:[406,3,1,""],get_previous_by_db_date_created:[406,3,1,""],id:[406,4,1,""],interval:[406,3,1,""],is_active:[406,3,1,""],obj:[406,3,1,""],object:[406,3,1,""],objects:[406,4,1,""],path:[406,4,1,""],persistent:[406,3,1,""],receiver_script_set:[406,4,1,""],repeats:[406,3,1,""],sender_script_set:[406,4,1,""],start_delay:[406,3,1,""],typename:[406,4,1,""]},"evennia.scripts.monitorhandler":{MonitorHandler:[407,1,1,""]},"evennia.scripts.monitorhandler.MonitorHandler":{__init__:[407,3,1,""],add:[407,3,1,""],all:[407,3,1,""],at_update:[407,3,1,""],clear:[407,3,1,""],remove:[407,3,1,""],restore:[407,3,1,""],save:[407,3,1,""]},"evennia.scripts.scripthandler":{ScriptHandler:[408,1,1,""]},"evennia.scripts.scripthandler.ScriptHandler":{"delete":[408,3,1,""],__init__:[408,3,1,""],add:[408,3,1,""],all:[408,3,1,""],get:[408,3,1,""],start:[408,3,1,""],stop:[408,3,1,""]},"evennia.scripts.scripts":{DefaultScript:[409,1,1,""],DoNothing:[409,1,1,""],Store:[409,1,1,""]},"evennia.scripts.scripts.DefaultScript":{DoesNotExist:[409,2,1,""],MultipleObjectsReturned:[409,2,1,""],at_pause:[409,3,1,""],at_repeat:[409,3,1,""],at_script_creation:[409,3,1,""],at_script_delete:[409,3,1,""],at_server_reload:[409,3,1,""],at_server_shutdown:[409,3,1,""],at_server_start:[409,3,1,""],at_start:[409,3,1,""],at_stop:[409,3,1,""],create:[409,3,1,""],is_valid:[409,3,1,""],path:[409,4,1,""],typename:[409,4,1,""]},"evennia.scripts.scripts.DoNothing":{DoesNotExist:[409,2,1,""],MultipleObjectsReturned:[409,2,1,""],at_script_creation:[409,3,1,""],path:[409,4,1,""],typename:[409,4,1,""]},"evennia.scripts.scripts.Store":{DoesNotExist:[409,2,1,""],MultipleObjectsReturned:[409,2,1,""],at_script_creation:[409,3,1,""],path:[409,4,1,""],typename:[409,4,1,""]},"evennia.scripts.taskhandler":{TaskHandler:[410,1,1,""],TaskHandlerTask:[410,1,1,""],handle_error:[410,5,1,""]},"evennia.scripts.taskhandler.TaskHandler":{__init__:[410,3,1,""],active:[410,3,1,""],add:[410,3,1,""],call_task:[410,3,1,""],cancel:[410,3,1,""],clean_stale_tasks:[410,3,1,""],clear:[410,3,1,""],create_delays:[410,3,1,""],do_task:[410,3,1,""],exists:[410,3,1,""],get_deferred:[410,3,1,""],load:[410,3,1,""],remove:[410,3,1,""],save:[410,3,1,""]},"evennia.scripts.taskhandler.TaskHandlerTask":{__init__:[410,3,1,""],active:[410,3,1,"id6"],call:[410,3,1,"id3"],called:[410,3,1,""],cancel:[410,3,1,"id5"],do_task:[410,3,1,"id2"],exists:[410,3,1,"id7"],get_deferred:[410,3,1,""],get_id:[410,3,1,"id8"],pause:[410,3,1,"id0"],paused:[410,3,1,""],remove:[410,3,1,"id4"],unpause:[410,3,1,"id1"]},"evennia.scripts.tickerhandler":{Ticker:[411,1,1,""],TickerHandler:[411,1,1,""],TickerPool:[411,1,1,""]},"evennia.scripts.tickerhandler.Ticker":{__init__:[411,3,1,""],add:[411,3,1,""],remove:[411,3,1,""],stop:[411,3,1,""],validate:[411,3,1,""]},"evennia.scripts.tickerhandler.TickerHandler":{__init__:[411,3,1,""],add:[411,3,1,""],all:[411,3,1,""],all_display:[411,3,1,""],clear:[411,3,1,""],remove:[411,3,1,""],restore:[411,3,1,""],save:[411,3,1,""],ticker_pool_class:[411,4,1,""]},"evennia.scripts.tickerhandler.TickerPool":{__init__:[411,3,1,""],add:[411,3,1,""],remove:[411,3,1,""],stop:[411,3,1,""],ticker_class:[411,4,1,""]},"evennia.server":{amp_client:[413,0,0,"-"],connection_wizard:[414,0,0,"-"],deprecations:[415,0,0,"-"],evennia_launcher:[416,0,0,"-"],game_index_client:[417,0,0,"-"],initial_setup:[420,0,0,"-"],inputfuncs:[421,0,0,"-"],manager:[422,0,0,"-"],models:[423,0,0,"-"],portal:[424,0,0,"-"],profiling:[446,0,0,"-"],server:[454,0,0,"-"],serversession:[455,0,0,"-"],session:[456,0,0,"-"],sessionhandler:[457,0,0,"-"],signals:[458,0,0,"-"],throttle:[459,0,0,"-"],validators:[460,0,0,"-"],webserver:[461,0,0,"-"]},"evennia.server.amp_client":{AMPClientFactory:[413,1,1,""],AMPServerClientProtocol:[413,1,1,""]},"evennia.server.amp_client.AMPClientFactory":{__init__:[413,3,1,""],buildProtocol:[413,3,1,""],clientConnectionFailed:[413,3,1,""],clientConnectionLost:[413,3,1,""],factor:[413,4,1,""],initialDelay:[413,4,1,""],maxDelay:[413,4,1,""],noisy:[413,4,1,""],startedConnecting:[413,3,1,""]},"evennia.server.amp_client.AMPServerClientProtocol":{connectionMade:[413,3,1,""],data_to_portal:[413,3,1,""],send_AdminServer2Portal:[413,3,1,""],send_MsgServer2Portal:[413,3,1,""],server_receive_adminportal2server:[413,3,1,""],server_receive_msgportal2server:[413,3,1,""],server_receive_status:[413,3,1,""]},"evennia.server.connection_wizard":{ConnectionWizard:[414,1,1,""],node_game_index_fields:[414,5,1,""],node_game_index_start:[414,5,1,""],node_mssp_start:[414,5,1,""],node_start:[414,5,1,""],node_view_and_apply_settings:[414,5,1,""]},"evennia.server.connection_wizard.ConnectionWizard":{__init__:[414,3,1,""],ask_choice:[414,3,1,""],ask_continue:[414,3,1,""],ask_input:[414,3,1,""],ask_node:[414,3,1,""],ask_yesno:[414,3,1,""],display:[414,3,1,""]},"evennia.server.deprecations":{check_errors:[415,5,1,""],check_warnings:[415,5,1,""]},"evennia.server.evennia_launcher":{AMPLauncherProtocol:[416,1,1,""],MsgLauncher2Portal:[416,1,1,""],MsgStatus:[416,1,1,""],check_database:[416,5,1,""],check_main_evennia_dependencies:[416,5,1,""],collectstatic:[416,5,1,""],create_game_directory:[416,5,1,""],create_secret_key:[416,5,1,""],create_settings_file:[416,5,1,""],create_superuser:[416,5,1,""],del_pid:[416,5,1,""],error_check_python_modules:[416,5,1,""],evennia_version:[416,5,1,""],get_pid:[416,5,1,""],getenv:[416,5,1,""],init_game_directory:[416,5,1,""],kill:[416,5,1,""],list_settings:[416,5,1,""],main:[416,5,1,""],query_info:[416,5,1,""],query_status:[416,5,1,""],reboot_evennia:[416,5,1,""],reload_evennia:[416,5,1,""],run_connect_wizard:[416,5,1,""],run_custom_commands:[416,5,1,""],run_dummyrunner:[416,5,1,""],run_menu:[416,5,1,""],send_instruction:[416,5,1,""],set_gamedir:[416,5,1,""],show_version_info:[416,5,1,""],start_evennia:[416,5,1,""],start_only_server:[416,5,1,""],start_portal_interactive:[416,5,1,""],start_server_interactive:[416,5,1,""],stop_evennia:[416,5,1,""],stop_server_only:[416,5,1,""],tail_log_files:[416,5,1,""],wait_for_status:[416,5,1,""],wait_for_status_reply:[416,5,1,""]},"evennia.server.evennia_launcher.AMPLauncherProtocol":{__init__:[416,3,1,""],receive_status_from_portal:[416,3,1,""],wait_for_status:[416,3,1,""]},"evennia.server.evennia_launcher.MsgLauncher2Portal":{allErrors:[416,4,1,""],arguments:[416,4,1,""],commandName:[416,4,1,""],errors:[416,4,1,""],key:[416,4,1,""],response:[416,4,1,""],reverseErrors:[416,4,1,""]},"evennia.server.evennia_launcher.MsgStatus":{allErrors:[416,4,1,""],arguments:[416,4,1,""],commandName:[416,4,1,""],errors:[416,4,1,""],key:[416,4,1,""],response:[416,4,1,""],reverseErrors:[416,4,1,""]},"evennia.server.game_index_client":{client:[418,0,0,"-"],service:[419,0,0,"-"]},"evennia.server.game_index_client.client":{EvenniaGameIndexClient:[418,1,1,""],QuietHTTP11ClientFactory:[418,1,1,""],SimpleResponseReceiver:[418,1,1,""],StringProducer:[418,1,1,""]},"evennia.server.game_index_client.client.EvenniaGameIndexClient":{__init__:[418,3,1,""],handle_egd_response:[418,3,1,""],send_game_details:[418,3,1,""]},"evennia.server.game_index_client.client.QuietHTTP11ClientFactory":{noisy:[418,4,1,""]},"evennia.server.game_index_client.client.SimpleResponseReceiver":{__init__:[418,3,1,""],connectionLost:[418,3,1,""],dataReceived:[418,3,1,""]},"evennia.server.game_index_client.client.StringProducer":{__init__:[418,3,1,""],pauseProducing:[418,3,1,""],startProducing:[418,3,1,""],stopProducing:[418,3,1,""]},"evennia.server.game_index_client.service":{EvenniaGameIndexService:[419,1,1,""]},"evennia.server.game_index_client.service.EvenniaGameIndexService":{__init__:[419,3,1,""],name:[419,4,1,""],startService:[419,3,1,""],stopService:[419,3,1,""]},"evennia.server.initial_setup":{at_initial_setup:[420,5,1,""],collectstatic:[420,5,1,""],create_objects:[420,5,1,""],handle_setup:[420,5,1,""],reset_server:[420,5,1,""]},"evennia.server.inputfuncs":{"default":[421,5,1,""],bot_data_in:[421,5,1,""],client_gui:[421,5,1,""],client_options:[421,5,1,""],echo:[421,5,1,""],external_discord_hello:[421,5,1,""],get_client_options:[421,5,1,""],get_inputfuncs:[421,5,1,""],get_value:[421,5,1,""],hello:[421,5,1,""],login:[421,5,1,""],monitor:[421,5,1,""],monitored:[421,5,1,""],msdp_list:[421,5,1,""],msdp_report:[421,5,1,""],msdp_send:[421,5,1,""],msdp_unreport:[421,5,1,""],repeat:[421,5,1,""],supports_set:[421,5,1,""],text:[421,5,1,""],unmonitor:[421,5,1,""],unrepeat:[421,5,1,""],webclient_options:[421,5,1,""]},"evennia.server.manager":{ServerConfigManager:[422,1,1,""]},"evennia.server.manager.ServerConfigManager":{conf:[422,3,1,""]},"evennia.server.models":{ServerConfig:[423,1,1,""]},"evennia.server.models.ServerConfig":{DoesNotExist:[423,2,1,""],MultipleObjectsReturned:[423,2,1,""],db_key:[423,4,1,""],db_value:[423,4,1,""],id:[423,4,1,""],key:[423,3,1,""],objects:[423,4,1,""],path:[423,4,1,""],store:[423,3,1,""],typename:[423,4,1,""],value:[423,3,1,""]},"evennia.server.portal":{amp:[425,0,0,"-"],amp_server:[426,0,0,"-"],grapevine:[427,0,0,"-"],irc:[428,0,0,"-"],mccp:[429,0,0,"-"],mssp:[430,0,0,"-"],mxp:[431,0,0,"-"],naws:[432,0,0,"-"],portal:[433,0,0,"-"],portalsessionhandler:[434,0,0,"-"],rss:[435,0,0,"-"],ssh:[436,0,0,"-"],ssl:[437,0,0,"-"],suppress_ga:[438,0,0,"-"],telnet:[439,0,0,"-"],telnet_oob:[440,0,0,"-"],telnet_ssl:[441,0,0,"-"],tests:[442,0,0,"-"],ttype:[443,0,0,"-"],webclient:[444,0,0,"-"],webclient_ajax:[445,0,0,"-"]},"evennia.server.portal.amp":{AMPMultiConnectionProtocol:[425,1,1,""],AdminPortal2Server:[425,1,1,""],AdminServer2Portal:[425,1,1,""],Compressed:[425,1,1,""],FunctionCall:[425,1,1,""],MsgLauncher2Portal:[425,1,1,""],MsgPortal2Server:[425,1,1,""],MsgServer2Portal:[425,1,1,""],MsgStatus:[425,1,1,""],dumps:[425,5,1,""],loads:[425,5,1,""]},"evennia.server.portal.amp.AMPMultiConnectionProtocol":{__init__:[425,3,1,""],broadcast:[425,3,1,""],connectionLost:[425,3,1,""],connectionMade:[425,3,1,""],dataReceived:[425,3,1,""],data_in:[425,3,1,""],errback:[425,3,1,""],makeConnection:[425,3,1,""],receive_functioncall:[425,3,1,""],send_FunctionCall:[425,3,1,""]},"evennia.server.portal.amp.AdminPortal2Server":{allErrors:[425,4,1,""],arguments:[425,4,1,""],commandName:[425,4,1,""],errors:[425,4,1,""],key:[425,4,1,""],response:[425,4,1,""],reverseErrors:[425,4,1,""]},"evennia.server.portal.amp.AdminServer2Portal":{allErrors:[425,4,1,""],arguments:[425,4,1,""],commandName:[425,4,1,""],errors:[425,4,1,""],key:[425,4,1,""],response:[425,4,1,""],reverseErrors:[425,4,1,""]},"evennia.server.portal.amp.Compressed":{fromBox:[425,3,1,""],fromString:[425,3,1,""],toBox:[425,3,1,""],toString:[425,3,1,""]},"evennia.server.portal.amp.FunctionCall":{allErrors:[425,4,1,""],arguments:[425,4,1,""],commandName:[425,4,1,""],errors:[425,4,1,""],key:[425,4,1,""],response:[425,4,1,""],reverseErrors:[425,4,1,""]},"evennia.server.portal.amp.MsgLauncher2Portal":{allErrors:[425,4,1,""],arguments:[425,4,1,""],commandName:[425,4,1,""],errors:[425,4,1,""],key:[425,4,1,""],response:[425,4,1,""],reverseErrors:[425,4,1,""]},"evennia.server.portal.amp.MsgPortal2Server":{allErrors:[425,4,1,""],arguments:[425,4,1,""],commandName:[425,4,1,""],errors:[425,4,1,""],key:[425,4,1,""],response:[425,4,1,""],reverseErrors:[425,4,1,""]},"evennia.server.portal.amp.MsgServer2Portal":{allErrors:[425,4,1,""],arguments:[425,4,1,""],commandName:[425,4,1,""],errors:[425,4,1,""],key:[425,4,1,""],response:[425,4,1,""],reverseErrors:[425,4,1,""]},"evennia.server.portal.amp.MsgStatus":{allErrors:[425,4,1,""],arguments:[425,4,1,""],commandName:[425,4,1,""],errors:[425,4,1,""],key:[425,4,1,""],response:[425,4,1,""],reverseErrors:[425,4,1,""]},"evennia.server.portal.amp_server":{AMPServerFactory:[426,1,1,""],AMPServerProtocol:[426,1,1,""],getenv:[426,5,1,""]},"evennia.server.portal.amp_server.AMPServerFactory":{__init__:[426,3,1,""],buildProtocol:[426,3,1,""],logPrefix:[426,3,1,""],noisy:[426,4,1,""]},"evennia.server.portal.amp_server.AMPServerProtocol":{connectionLost:[426,3,1,""],data_to_server:[426,3,1,""],get_status:[426,3,1,""],portal_receive_adminserver2portal:[426,3,1,""],portal_receive_launcher2portal:[426,3,1,""],portal_receive_server2portal:[426,3,1,""],portal_receive_status:[426,3,1,""],send_AdminPortal2Server:[426,3,1,""],send_MsgPortal2Server:[426,3,1,""],send_Status2Launcher:[426,3,1,""],start_server:[426,3,1,""],stop_server:[426,3,1,""],wait_for_disconnect:[426,3,1,""],wait_for_server_connect:[426,3,1,""]},"evennia.server.portal.grapevine":{GrapevineClient:[427,1,1,""],RestartingWebsocketServerFactory:[427,1,1,""]},"evennia.server.portal.grapevine.GrapevineClient":{__init__:[427,3,1,""],at_login:[427,3,1,""],data_in:[427,3,1,""],disconnect:[427,3,1,""],onClose:[427,3,1,""],onMessage:[427,3,1,""],onOpen:[427,3,1,""],send_authenticate:[427,3,1,""],send_channel:[427,3,1,""],send_default:[427,3,1,""],send_heartbeat:[427,3,1,""],send_subscribe:[427,3,1,""],send_unsubscribe:[427,3,1,""]},"evennia.server.portal.grapevine.RestartingWebsocketServerFactory":{__init__:[427,3,1,""],buildProtocol:[427,3,1,""],clientConnectionFailed:[427,3,1,""],clientConnectionLost:[427,3,1,""],factor:[427,4,1,""],initialDelay:[427,4,1,""],maxDelay:[427,4,1,""],reconnect:[427,3,1,""],start:[427,3,1,""],startedConnecting:[427,3,1,""]},"evennia.server.portal.irc":{IRCBot:[428,1,1,""],IRCBotFactory:[428,1,1,""],parse_ansi_to_irc:[428,5,1,""],parse_irc_to_ansi:[428,5,1,""]},"evennia.server.portal.irc.IRCBot":{action:[428,3,1,""],at_login:[428,3,1,""],channel:[428,4,1,""],data_in:[428,3,1,""],disconnect:[428,3,1,""],factory:[428,4,1,""],get_nicklist:[428,3,1,""],irc_RPL_ENDOFNAMES:[428,3,1,""],irc_RPL_NAMREPLY:[428,3,1,""],lineRate:[428,4,1,""],logger:[428,4,1,""],nickname:[428,4,1,""],pong:[428,3,1,""],privmsg:[428,3,1,""],send_channel:[428,3,1,""],send_default:[428,3,1,""],send_ping:[428,3,1,""],send_privmsg:[428,3,1,""],send_reconnect:[428,3,1,""],send_request_nicklist:[428,3,1,""],signedOn:[428,3,1,""],sourceURL:[428,4,1,""]},"evennia.server.portal.irc.IRCBotFactory":{__init__:[428,3,1,""],buildProtocol:[428,3,1,""],clientConnectionFailed:[428,3,1,""],clientConnectionLost:[428,3,1,""],factor:[428,4,1,""],initialDelay:[428,4,1,""],maxDelay:[428,4,1,""],reconnect:[428,3,1,""],start:[428,3,1,""],startedConnecting:[428,3,1,""]},"evennia.server.portal.mccp":{Mccp:[429,1,1,""],mccp_compress:[429,5,1,""]},"evennia.server.portal.mccp.Mccp":{__init__:[429,3,1,""],do_mccp:[429,3,1,""],no_mccp:[429,3,1,""]},"evennia.server.portal.mssp":{Mssp:[430,1,1,""]},"evennia.server.portal.mssp.Mssp":{__init__:[430,3,1,""],do_mssp:[430,3,1,""],get_player_count:[430,3,1,""],get_uptime:[430,3,1,""],no_mssp:[430,3,1,""]},"evennia.server.portal.mxp":{Mxp:[431,1,1,""],mxp_parse:[431,5,1,""]},"evennia.server.portal.mxp.Mxp":{__init__:[431,3,1,""],do_mxp:[431,3,1,""],no_mxp:[431,3,1,""]},"evennia.server.portal.naws":{Naws:[432,1,1,""]},"evennia.server.portal.naws.Naws":{__init__:[432,3,1,""],do_naws:[432,3,1,""],negotiate_sizes:[432,3,1,""],no_naws:[432,3,1,""]},"evennia.server.portal.portal":{Portal:[433,1,1,""],Websocket:[433,1,1,""]},"evennia.server.portal.portal.Portal":{__init__:[433,3,1,""],get_info_dict:[433,3,1,""],shutdown:[433,3,1,""]},"evennia.server.portal.portalsessionhandler":{PortalSessionHandler:[434,1,1,""]},"evennia.server.portal.portalsessionhandler.PortalSessionHandler":{__init__:[434,3,1,""],announce_all:[434,3,1,""],at_server_connection:[434,3,1,""],connect:[434,3,1,""],count_loggedin:[434,3,1,""],data_in:[434,3,1,""],data_out:[434,3,1,""],disconnect:[434,3,1,""],disconnect_all:[434,3,1,""],generate_sessid:[434,3,1,""],server_connect:[434,3,1,""],server_disconnect:[434,3,1,""],server_disconnect_all:[434,3,1,""],server_logged_in:[434,3,1,""],server_session_sync:[434,3,1,""],sessions_from_csessid:[434,3,1,""],sync:[434,3,1,""]},"evennia.server.portal.rss":{RSSBotFactory:[435,1,1,""],RSSReader:[435,1,1,""]},"evennia.server.portal.rss.RSSBotFactory":{__init__:[435,3,1,""],start:[435,3,1,""]},"evennia.server.portal.rss.RSSReader":{__init__:[435,3,1,""],data_in:[435,3,1,""],disconnect:[435,3,1,""],get_new:[435,3,1,""],update:[435,3,1,""]},"evennia.server.portal.ssh":{AccountDBPasswordChecker:[436,1,1,""],ExtraInfoAuthServer:[436,1,1,""],PassAvatarIdTerminalRealm:[436,1,1,""],SSHServerFactory:[436,1,1,""],SshProtocol:[436,1,1,""],TerminalSessionTransport_getPeer:[436,1,1,""],getKeyPair:[436,5,1,""],makeFactory:[436,5,1,""]},"evennia.server.portal.ssh.AccountDBPasswordChecker":{__init__:[436,3,1,""],credentialInterfaces:[436,4,1,""],noisy:[436,4,1,""],requestAvatarId:[436,3,1,""]},"evennia.server.portal.ssh.ExtraInfoAuthServer":{auth_password:[436,3,1,""],noisy:[436,4,1,""]},"evennia.server.portal.ssh.PassAvatarIdTerminalRealm":{noisy:[436,4,1,""]},"evennia.server.portal.ssh.SSHServerFactory":{logPrefix:[436,3,1,""],noisy:[436,4,1,""]},"evennia.server.portal.ssh.SshProtocol":{__init__:[436,3,1,""],at_login:[436,3,1,""],connectionLost:[436,3,1,""],connectionMade:[436,3,1,""],data_out:[436,3,1,""],disconnect:[436,3,1,""],getClientAddress:[436,3,1,""],handle_EOF:[436,3,1,""],handle_FF:[436,3,1,""],handle_INT:[436,3,1,""],handle_QUIT:[436,3,1,""],lineReceived:[436,3,1,""],noisy:[436,4,1,""],sendLine:[436,3,1,""],send_default:[436,3,1,""],send_prompt:[436,3,1,""],send_text:[436,3,1,""],terminalSize:[436,3,1,""]},"evennia.server.portal.ssh.TerminalSessionTransport_getPeer":{__init__:[436,3,1,""],noisy:[436,4,1,""]},"evennia.server.portal.ssl":{SSLProtocol:[437,1,1,""],getSSLContext:[437,5,1,""],verify_SSL_key_and_cert:[437,5,1,""]},"evennia.server.portal.ssl.SSLProtocol":{__init__:[437,3,1,""]},"evennia.server.portal.suppress_ga":{SuppressGA:[438,1,1,""]},"evennia.server.portal.suppress_ga.SuppressGA":{__init__:[438,3,1,""],will_suppress_ga:[438,3,1,""],wont_suppress_ga:[438,3,1,""]},"evennia.server.portal.telnet":{TelnetProtocol:[439,1,1,""],TelnetServerFactory:[439,1,1,""]},"evennia.server.portal.telnet.TelnetProtocol":{__init__:[439,3,1,""],applicationDataReceived:[439,3,1,""],at_login:[439,3,1,""],connectionLost:[439,3,1,""],connectionMade:[439,3,1,""],dataReceived:[439,3,1,""],data_in:[439,3,1,""],data_out:[439,3,1,""],disableLocal:[439,3,1,""],disableRemote:[439,3,1,""],disconnect:[439,3,1,""],enableLocal:[439,3,1,""],enableRemote:[439,3,1,""],handshake_done:[439,3,1,""],sendLine:[439,3,1,""],send_default:[439,3,1,""],send_prompt:[439,3,1,""],send_text:[439,3,1,""],toggle_nop_keepalive:[439,3,1,""]},"evennia.server.portal.telnet.TelnetServerFactory":{logPrefix:[439,3,1,""],noisy:[439,4,1,""]},"evennia.server.portal.telnet_oob":{TelnetOOB:[440,1,1,""]},"evennia.server.portal.telnet_oob.TelnetOOB":{__init__:[440,3,1,""],data_out:[440,3,1,""],decode_gmcp:[440,3,1,""],decode_msdp:[440,3,1,""],do_gmcp:[440,3,1,""],do_msdp:[440,3,1,""],encode_gmcp:[440,3,1,""],encode_msdp:[440,3,1,""],no_gmcp:[440,3,1,""],no_msdp:[440,3,1,""]},"evennia.server.portal.telnet_ssl":{SSLProtocol:[441,1,1,""],getSSLContext:[441,5,1,""],verify_or_create_SSL_key_and_cert:[441,5,1,""]},"evennia.server.portal.telnet_ssl.SSLProtocol":{__init__:[441,3,1,""]},"evennia.server.portal.tests":{TestAMPServer:[442,1,1,""],TestIRC:[442,1,1,""],TestTelnet:[442,1,1,""],TestWebSocket:[442,1,1,""]},"evennia.server.portal.tests.TestAMPServer":{setUp:[442,3,1,""],test_amp_in:[442,3,1,""],test_amp_out:[442,3,1,""],test_large_msg:[442,3,1,""]},"evennia.server.portal.tests.TestIRC":{test_bold:[442,3,1,""],test_colors:[442,3,1,""],test_identity:[442,3,1,""],test_italic:[442,3,1,""],test_plain_ansi:[442,3,1,""]},"evennia.server.portal.tests.TestTelnet":{setUp:[442,3,1,""],test_mudlet_ttype:[442,3,1,""]},"evennia.server.portal.tests.TestWebSocket":{setUp:[442,3,1,""],tearDown:[442,3,1,""],test_data_in:[442,3,1,""],test_data_out:[442,3,1,""]},"evennia.server.portal.ttype":{Ttype:[443,1,1,""]},"evennia.server.portal.ttype.Ttype":{__init__:[443,3,1,""],will_ttype:[443,3,1,""],wont_ttype:[443,3,1,""]},"evennia.server.portal.webclient":{WebSocketClient:[444,1,1,""]},"evennia.server.portal.webclient.WebSocketClient":{__init__:[444,3,1,""],at_login:[444,3,1,""],data_in:[444,3,1,""],disconnect:[444,3,1,""],get_client_session:[444,3,1,""],nonce:[444,4,1,""],onClose:[444,3,1,""],onMessage:[444,3,1,""],onOpen:[444,3,1,""],sendLine:[444,3,1,""],send_default:[444,3,1,""],send_prompt:[444,3,1,""],send_text:[444,3,1,""]},"evennia.server.portal.webclient_ajax":{AjaxWebClient:[445,1,1,""],AjaxWebClientSession:[445,1,1,""],LazyEncoder:[445,1,1,""],jsonify:[445,5,1,""]},"evennia.server.portal.webclient_ajax.AjaxWebClient":{__init__:[445,3,1,""],allowedMethods:[445,4,1,""],at_login:[445,3,1,""],client_disconnect:[445,3,1,""],get_browserstr:[445,3,1,""],get_client_sessid:[445,3,1,""],isLeaf:[445,4,1,""],lineSend:[445,3,1,""],mode_close:[445,3,1,""],mode_init:[445,3,1,""],mode_input:[445,3,1,""],mode_keepalive:[445,3,1,""],mode_receive:[445,3,1,""],render_POST:[445,3,1,""]},"evennia.server.portal.webclient_ajax.AjaxWebClientSession":{__init__:[445,3,1,""],at_login:[445,3,1,""],data_in:[445,3,1,""],data_out:[445,3,1,""],disconnect:[445,3,1,""],get_client_session:[445,3,1,""],send_default:[445,3,1,""],send_prompt:[445,3,1,""],send_text:[445,3,1,""]},"evennia.server.portal.webclient_ajax.LazyEncoder":{"default":[445,3,1,""]},"evennia.server.profiling":{dummyrunner:[447,0,0,"-"],dummyrunner_settings:[448,0,0,"-"],memplot:[449,0,0,"-"],settings_mixin:[450,0,0,"-"],test_queries:[451,0,0,"-"],tests:[452,0,0,"-"],timetrace:[453,0,0,"-"]},"evennia.server.profiling.dummyrunner":{CmdDummyRunnerEchoResponse:[447,1,1,""],DummyClient:[447,1,1,""],DummyFactory:[447,1,1,""],DummyRunnerCmdSet:[447,1,1,""],gidcounter:[447,5,1,""],idcounter:[447,5,1,""],makeiter:[447,5,1,""],start_all_dummy_clients:[447,5,1,""]},"evennia.server.profiling.dummyrunner.CmdDummyRunnerEchoResponse":{aliases:[447,4,1,""],func:[447,3,1,""],help_category:[447,4,1,""],key:[447,4,1,""],lock_storage:[447,4,1,""],search_index_entry:[447,4,1,""]},"evennia.server.profiling.dummyrunner.DummyClient":{connectionLost:[447,3,1,""],connectionMade:[447,3,1,""],counter:[447,3,1,""],dataReceived:[447,3,1,""],error:[447,3,1,""],logout:[447,3,1,""],report:[447,3,1,""],step:[447,3,1,""]},"evennia.server.profiling.dummyrunner.DummyFactory":{__init__:[447,3,1,""],initialDelay:[447,4,1,""],maxDelay:[447,4,1,""],noisy:[447,4,1,""],protocol:[447,4,1,""]},"evennia.server.profiling.dummyrunner.DummyRunnerCmdSet":{at_cmdset_creation:[447,3,1,""],path:[447,4,1,""]},"evennia.server.profiling.dummyrunner_settings":{c_creates_button:[448,5,1,""],c_creates_obj:[448,5,1,""],c_digs:[448,5,1,""],c_examines:[448,5,1,""],c_help:[448,5,1,""],c_idles:[448,5,1,""],c_login:[448,5,1,""],c_login_nodig:[448,5,1,""],c_logout:[448,5,1,""],c_looks:[448,5,1,""],c_measure_lag:[448,5,1,""],c_moves:[448,5,1,""],c_moves_n:[448,5,1,""],c_moves_s:[448,5,1,""],c_socialize:[448,5,1,""]},"evennia.server.profiling.memplot":{Memplot:[449,1,1,""]},"evennia.server.profiling.memplot.Memplot":{DoesNotExist:[449,2,1,""],MultipleObjectsReturned:[449,2,1,""],at_repeat:[449,3,1,""],at_script_creation:[449,3,1,""],path:[449,4,1,""],typename:[449,4,1,""]},"evennia.server.profiling.test_queries":{count_queries:[451,5,1,""]},"evennia.server.profiling.tests":{TestDummyrunnerSettings:[452,1,1,""],TestMemPlot:[452,1,1,""]},"evennia.server.profiling.tests.TestDummyrunnerSettings":{clear_client_lists:[452,3,1,""],perception_method_tests:[452,3,1,""],setUp:[452,3,1,""],test_c_creates_button:[452,3,1,""],test_c_creates_obj:[452,3,1,""],test_c_digs:[452,3,1,""],test_c_examines:[452,3,1,""],test_c_help:[452,3,1,""],test_c_login:[452,3,1,""],test_c_login_no_dig:[452,3,1,""],test_c_logout:[452,3,1,""],test_c_looks:[452,3,1,""],test_c_move_n:[452,3,1,""],test_c_move_s:[452,3,1,""],test_c_moves:[452,3,1,""],test_c_socialize:[452,3,1,""],test_idles:[452,3,1,""]},"evennia.server.profiling.tests.TestMemPlot":{test_memplot:[452,3,1,""]},"evennia.server.profiling.timetrace":{timetrace:[453,5,1,""]},"evennia.server.server":{Evennia:[454,1,1,""]},"evennia.server.server.Evennia":{__init__:[454,3,1,""],at_post_portal_sync:[454,3,1,""],at_server_cold_start:[454,3,1,""],at_server_cold_stop:[454,3,1,""],at_server_reload_start:[454,3,1,""],at_server_reload_stop:[454,3,1,""],at_server_start:[454,3,1,""],at_server_stop:[454,3,1,""],create_default_channels:[454,3,1,""],get_info_dict:[454,3,1,""],run_init_hooks:[454,3,1,""],run_initial_setup:[454,3,1,""],shutdown:[454,3,1,""],sqlite3_prep:[454,3,1,""],update_defaults:[454,3,1,""]},"evennia.server.serversession":{ServerSession:[455,1,1,""]},"evennia.server.serversession.ServerSession":{__init__:[455,3,1,""],access:[455,3,1,""],at_cmdset_get:[455,3,1,""],at_disconnect:[455,3,1,""],at_login:[455,3,1,""],at_sync:[455,3,1,""],attributes:[455,4,1,""],cmdset_storage:[455,3,1,""],data_in:[455,3,1,""],data_out:[455,3,1,""],db:[455,3,1,""],execute_cmd:[455,3,1,""],get_account:[455,3,1,""],get_character:[455,3,1,""],get_client_size:[455,3,1,""],get_puppet:[455,3,1,""],get_puppet_or_account:[455,3,1,""],id:[455,3,1,""],log:[455,3,1,""],msg:[455,3,1,""],nattributes:[455,4,1,""],ndb:[455,3,1,""],ndb_del:[455,3,1,""],ndb_get:[455,3,1,""],ndb_set:[455,3,1,""],update_flags:[455,3,1,""],update_session_counters:[455,3,1,""]},"evennia.server.session":{Session:[456,1,1,""]},"evennia.server.session.Session":{at_sync:[456,3,1,""],data_in:[456,3,1,""],data_out:[456,3,1,""],disconnect:[456,3,1,""],get_sync_data:[456,3,1,""],init_session:[456,3,1,""],load_sync_data:[456,3,1,""]},"evennia.server.sessionhandler":{DummySession:[457,1,1,""],ServerSessionHandler:[457,1,1,""],SessionHandler:[457,1,1,""],delayed_import:[457,5,1,""]},"evennia.server.sessionhandler.DummySession":{sessid:[457,4,1,""]},"evennia.server.sessionhandler.ServerSessionHandler":{__init__:[457,3,1,""],account_count:[457,3,1,""],all_connected_accounts:[457,3,1,""],all_sessions_portal_sync:[457,3,1,""],announce_all:[457,3,1,""],call_inputfuncs:[457,3,1,""],data_in:[457,3,1,""],data_out:[457,3,1,""],disconnect:[457,3,1,""],disconnect_all_sessions:[457,3,1,""],disconnect_duplicate_sessions:[457,3,1,""],get_inputfuncs:[457,3,1,""],login:[457,3,1,""],portal_connect:[457,3,1,""],portal_disconnect:[457,3,1,""],portal_disconnect_all:[457,3,1,""],portal_reset_server:[457,3,1,""],portal_restart_server:[457,3,1,""],portal_session_sync:[457,3,1,""],portal_sessions_sync:[457,3,1,""],portal_shutdown:[457,3,1,""],session_from_account:[457,3,1,""],session_from_sessid:[457,3,1,""],session_portal_partial_sync:[457,3,1,""],session_portal_sync:[457,3,1,""],sessions_from_account:[457,3,1,""],sessions_from_character:[457,3,1,""],sessions_from_csessid:[457,3,1,""],sessions_from_puppet:[457,3,1,""],start_bot_session:[457,3,1,""],validate_sessions:[457,3,1,""]},"evennia.server.sessionhandler.SessionHandler":{clean_senddata:[457,3,1,""],get:[457,3,1,""],get_all_sync_data:[457,3,1,""],get_sessions:[457,3,1,""]},"evennia.server.throttle":{Throttle:[459,1,1,""]},"evennia.server.throttle.Throttle":{__init__:[459,3,1,""],check:[459,3,1,""],error_msg:[459,4,1,""],get:[459,3,1,""],get_cache_key:[459,3,1,""],record_ip:[459,3,1,""],remove:[459,3,1,""],touch:[459,3,1,""],unrecord_ip:[459,3,1,""],update:[459,3,1,""]},"evennia.server.validators":{EvenniaPasswordValidator:[460,1,1,""],EvenniaUsernameAvailabilityValidator:[460,1,1,""]},"evennia.server.validators.EvenniaPasswordValidator":{__init__:[460,3,1,""],get_help_text:[460,3,1,""],validate:[460,3,1,""]},"evennia.server.webserver":{DjangoWebRoot:[461,1,1,""],EvenniaReverseProxyResource:[461,1,1,""],HTTPChannelWithXForwardedFor:[461,1,1,""],LockableThreadPool:[461,1,1,""],PrivateStaticRoot:[461,1,1,""],WSGIWebServer:[461,1,1,""],Website:[461,1,1,""]},"evennia.server.webserver.DjangoWebRoot":{__init__:[461,3,1,""],empty_threadpool:[461,3,1,""],getChild:[461,3,1,""]},"evennia.server.webserver.EvenniaReverseProxyResource":{getChild:[461,3,1,""],render:[461,3,1,""]},"evennia.server.webserver.HTTPChannelWithXForwardedFor":{allHeadersReceived:[461,3,1,""]},"evennia.server.webserver.LockableThreadPool":{__init__:[461,3,1,""],callInThread:[461,3,1,""],lock:[461,3,1,""]},"evennia.server.webserver.PrivateStaticRoot":{directoryListing:[461,3,1,""]},"evennia.server.webserver.WSGIWebServer":{__init__:[461,3,1,""],startService:[461,3,1,""],stopService:[461,3,1,""]},"evennia.server.webserver.Website":{log:[461,3,1,""],logPrefix:[461,3,1,""],noisy:[461,4,1,""]},"evennia.typeclasses":{attributes:[464,0,0,"-"],managers:[465,0,0,"-"],models:[466,0,0,"-"],tags:[467,0,0,"-"]},"evennia.typeclasses.attributes":{Attribute:[464,1,1,""],AttributeHandler:[464,1,1,""],AttributeProperty:[464,1,1,""],DbHolder:[464,1,1,""],IAttribute:[464,1,1,""],IAttributeBackend:[464,1,1,""],InMemoryAttribute:[464,1,1,""],InMemoryAttributeBackend:[464,1,1,""],ModelAttributeBackend:[464,1,1,""],NAttributeProperty:[464,1,1,""],NickHandler:[464,1,1,""],NickTemplateInvalid:[464,2,1,""],initialize_nick_templates:[464,5,1,""],parse_nick_template:[464,5,1,""]},"evennia.typeclasses.attributes.Attribute":{DoesNotExist:[464,2,1,""],MultipleObjectsReturned:[464,2,1,""],accountdb_set:[464,4,1,""],attrtype:[464,3,1,""],category:[464,3,1,""],channeldb_set:[464,4,1,""],date_created:[464,3,1,""],db_attrtype:[464,4,1,""],db_category:[464,4,1,""],db_date_created:[464,4,1,""],db_key:[464,4,1,""],db_lock_storage:[464,4,1,""],db_model:[464,4,1,""],db_strvalue:[464,4,1,""],db_value:[464,4,1,""],get_next_by_db_date_created:[464,3,1,""],get_previous_by_db_date_created:[464,3,1,""],id:[464,4,1,""],key:[464,3,1,""],lock_storage:[464,3,1,""],model:[464,3,1,""],objectdb_set:[464,4,1,""],path:[464,4,1,""],scriptdb_set:[464,4,1,""],strvalue:[464,3,1,""],typename:[464,4,1,""],value:[464,3,1,""]},"evennia.typeclasses.attributes.AttributeHandler":{__init__:[464,3,1,""],add:[464,3,1,""],all:[464,3,1,""],batch_add:[464,3,1,""],clear:[464,3,1,""],get:[464,3,1,""],has:[464,3,1,""],remove:[464,3,1,""],reset_cache:[464,3,1,""]},"evennia.typeclasses.attributes.AttributeProperty":{__init__:[464,3,1,""],attrhandler_name:[464,4,1,""]},"evennia.typeclasses.attributes.DbHolder":{__init__:[464,3,1,""],all:[464,3,1,""],get_all:[464,3,1,""]},"evennia.typeclasses.attributes.IAttribute":{access:[464,3,1,""],attrtype:[464,3,1,""],category:[464,3,1,""],date_created:[464,3,1,""],key:[464,3,1,""],lock_storage:[464,3,1,""],locks:[464,4,1,""],model:[464,3,1,""],strvalue:[464,3,1,""]},"evennia.typeclasses.attributes.IAttributeBackend":{__init__:[464,3,1,""],batch_add:[464,3,1,""],clear_attributes:[464,3,1,""],create_attribute:[464,3,1,""],delete_attribute:[464,3,1,""],do_batch_delete:[464,3,1,""],do_batch_finish:[464,3,1,""],do_batch_update_attribute:[464,3,1,""],do_create_attribute:[464,3,1,""],do_delete_attribute:[464,3,1,""],do_update_attribute:[464,3,1,""],get:[464,3,1,""],get_all_attributes:[464,3,1,""],query_all:[464,3,1,""],query_category:[464,3,1,""],query_key:[464,3,1,""],reset_cache:[464,3,1,""],update_attribute:[464,3,1,""]},"evennia.typeclasses.attributes.InMemoryAttribute":{__init__:[464,3,1,""],value:[464,3,1,""]},"evennia.typeclasses.attributes.InMemoryAttributeBackend":{__init__:[464,3,1,""],do_batch_finish:[464,3,1,""],do_batch_update_attribute:[464,3,1,""],do_create_attribute:[464,3,1,""],do_delete_attribute:[464,3,1,""],do_update_attribute:[464,3,1,""],query_all:[464,3,1,""],query_category:[464,3,1,""],query_key:[464,3,1,""]},"evennia.typeclasses.attributes.ModelAttributeBackend":{__init__:[464,3,1,""],do_batch_finish:[464,3,1,""],do_batch_update_attribute:[464,3,1,""],do_create_attribute:[464,3,1,""],do_delete_attribute:[464,3,1,""],do_update_attribute:[464,3,1,""],query_all:[464,3,1,""],query_category:[464,3,1,""],query_key:[464,3,1,""]},"evennia.typeclasses.attributes.NAttributeProperty":{attrhandler_name:[464,4,1,""]},"evennia.typeclasses.attributes.NickHandler":{__init__:[464,3,1,""],add:[464,3,1,""],get:[464,3,1,""],has:[464,3,1,""],nickreplace:[464,3,1,""],remove:[464,3,1,""]},"evennia.typeclasses.managers":{TypedObjectManager:[465,1,1,""]},"evennia.typeclasses.managers.TypedObjectManager":{create_tag:[465,3,1,""],dbref:[465,3,1,""],dbref_search:[465,3,1,""],get_alias:[465,3,1,""],get_attribute:[465,3,1,""],get_by_alias:[465,3,1,""],get_by_attribute:[465,3,1,""],get_by_nick:[465,3,1,""],get_by_permission:[465,3,1,""],get_by_tag:[465,3,1,""],get_dbref_range:[465,3,1,""],get_id:[465,3,1,""],get_nick:[465,3,1,""],get_permission:[465,3,1,""],get_tag:[465,3,1,""],get_typeclass_totals:[465,3,1,""],object_totals:[465,3,1,""],typeclass_search:[465,3,1,""]},"evennia.typeclasses.models":{TypedObject:[466,1,1,""]},"evennia.typeclasses.models.TypedObject":{"delete":[466,3,1,""],Meta:[466,1,1,""],__init__:[466,3,1,""],access:[466,3,1,""],aliases:[466,4,1,""],at_idmapper_flush:[466,3,1,""],at_rename:[466,3,1,""],attributes:[466,4,1,""],check_permstring:[466,3,1,""],date_created:[466,3,1,""],db:[466,3,1,""],db_attributes:[466,4,1,""],db_date_created:[466,4,1,""],db_key:[466,4,1,""],db_lock_storage:[466,4,1,""],db_tags:[466,4,1,""],db_typeclass_path:[466,4,1,""],dbid:[466,3,1,""],dbref:[466,3,1,""],get_absolute_url:[466,3,1,""],get_display_name:[466,3,1,""],get_extra_info:[466,3,1,""],get_next_by_db_date_created:[466,3,1,""],get_previous_by_db_date_created:[466,3,1,""],is_typeclass:[466,3,1,""],key:[466,3,1,""],lock_storage:[466,3,1,""],locks:[466,4,1,""],name:[466,3,1,""],nattributes:[466,4,1,""],ndb:[466,3,1,""],objects:[466,4,1,""],path:[466,4,1,""],permissions:[466,4,1,""],search:[466,3,1,""],set_class_from_typeclass:[466,3,1,""],swap_typeclass:[466,3,1,""],tags:[466,4,1,""],typeclass_path:[466,3,1,""],typename:[466,4,1,""],web_get_admin_url:[466,3,1,""],web_get_create_url:[466,3,1,""],web_get_delete_url:[466,3,1,""],web_get_detail_url:[466,3,1,""],web_get_puppet_url:[466,3,1,""],web_get_update_url:[466,3,1,""]},"evennia.typeclasses.models.TypedObject.Meta":{"abstract":[466,4,1,""],ordering:[466,4,1,""],verbose_name:[466,4,1,""]},"evennia.typeclasses.tags":{AliasHandler:[467,1,1,""],PermissionHandler:[467,1,1,""],Tag:[467,1,1,""],TagHandler:[467,1,1,""]},"evennia.typeclasses.tags.PermissionHandler":{check:[467,3,1,""]},"evennia.typeclasses.tags.Tag":{DoesNotExist:[467,2,1,""],MultipleObjectsReturned:[467,2,1,""],accountdb_set:[467,4,1,""],channeldb_set:[467,4,1,""],db_category:[467,4,1,""],db_data:[467,4,1,""],db_key:[467,4,1,""],db_model:[467,4,1,""],db_tagtype:[467,4,1,""],helpentry_set:[467,4,1,""],id:[467,4,1,""],msg_set:[467,4,1,""],objectdb_set:[467,4,1,""],objects:[467,4,1,""],scriptdb_set:[467,4,1,""]},"evennia.typeclasses.tags.TagHandler":{__init__:[467,3,1,""],add:[467,3,1,""],all:[467,3,1,""],batch_add:[467,3,1,""],clear:[467,3,1,""],get:[467,3,1,""],has:[467,3,1,""],remove:[467,3,1,""],reset_cache:[467,3,1,""]},"evennia.utils":{ansi:[469,0,0,"-"],batchprocessors:[470,0,0,"-"],containers:[471,0,0,"-"],create:[472,0,0,"-"],dbserialize:[473,0,0,"-"],eveditor:[474,0,0,"-"],evform:[475,0,0,"-"],evmenu:[476,0,0,"-"],evmore:[477,0,0,"-"],evtable:[478,0,0,"-"],funcparser:[479,0,0,"-"],gametime:[480,0,0,"-"],idmapper:[481,0,0,"-"],logger:[485,0,0,"-"],optionclasses:[486,0,0,"-"],optionhandler:[487,0,0,"-"],picklefield:[488,0,0,"-"],search:[489,0,0,"-"],test_resources:[490,0,0,"-"],text2html:[491,0,0,"-"],utils:[492,0,0,"-"],validatorfuncs:[493,0,0,"-"],verb_conjugation:[494,0,0,"-"]},"evennia.utils.ansi":{ANSIMeta:[469,1,1,""],ANSIParser:[469,1,1,""],ANSIString:[469,1,1,""],parse_ansi:[469,5,1,""],raw:[469,5,1,""],strip_ansi:[469,5,1,""],strip_mxp:[469,5,1,""],strip_raw_ansi:[469,5,1,""],strip_unsafe_tokens:[469,5,1,""]},"evennia.utils.ansi.ANSIMeta":{__init__:[469,3,1,""]},"evennia.utils.ansi.ANSIParser":{ansi_escapes:[469,4,1,""],ansi_map:[469,4,1,""],ansi_map_dict:[469,4,1,""],ansi_re:[469,4,1,""],ansi_regex:[469,4,1,""],ansi_sub:[469,4,1,""],ansi_xterm256_bright_bg_map:[469,4,1,""],ansi_xterm256_bright_bg_map_dict:[469,4,1,""],brightbg_sub:[469,4,1,""],mxp_re:[469,4,1,""],mxp_sub:[469,4,1,""],mxp_url_re:[469,4,1,""],mxp_url_sub:[469,4,1,""],parse_ansi:[469,3,1,""],strip_mxp:[469,3,1,""],strip_raw_codes:[469,3,1,""],strip_unsafe_tokens:[469,3,1,""],sub_ansi:[469,3,1,""],sub_brightbg:[469,3,1,""],sub_xterm256:[469,3,1,""],unsafe_tokens:[469,4,1,""],xterm256_bg:[469,4,1,""],xterm256_bg_sub:[469,4,1,""],xterm256_fg:[469,4,1,""],xterm256_fg_sub:[469,4,1,""],xterm256_gbg:[469,4,1,""],xterm256_gbg_sub:[469,4,1,""],xterm256_gfg:[469,4,1,""],xterm256_gfg_sub:[469,4,1,""]},"evennia.utils.ansi.ANSIString":{__init__:[469,3,1,""],capitalize:[469,3,1,""],center:[469,3,1,""],clean:[469,3,1,""],count:[469,3,1,""],decode:[469,3,1,""],encode:[469,3,1,""],endswith:[469,3,1,""],expandtabs:[469,3,1,""],find:[469,3,1,""],format:[469,3,1,""],index:[469,3,1,""],isalnum:[469,3,1,""],isalpha:[469,3,1,""],isdigit:[469,3,1,""],islower:[469,3,1,""],isspace:[469,3,1,""],istitle:[469,3,1,""],isupper:[469,3,1,""],join:[469,3,1,""],ljust:[469,3,1,""],lower:[469,3,1,""],lstrip:[469,3,1,""],partition:[469,3,1,""],raw:[469,3,1,""],re_format:[469,4,1,""],replace:[469,3,1,""],rfind:[469,3,1,""],rindex:[469,3,1,""],rjust:[469,3,1,""],rsplit:[469,3,1,""],rstrip:[469,3,1,""],split:[469,3,1,""],startswith:[469,3,1,""],strip:[469,3,1,""],swapcase:[469,3,1,""],translate:[469,3,1,""],upper:[469,3,1,""]},"evennia.utils.batchprocessors":{BatchCodeProcessor:[470,1,1,""],BatchCommandProcessor:[470,1,1,""],read_batchfile:[470,5,1,""],tb_filename:[470,5,1,""],tb_iter:[470,5,1,""]},"evennia.utils.batchprocessors.BatchCodeProcessor":{code_exec:[470,3,1,""],parse_file:[470,3,1,""]},"evennia.utils.batchprocessors.BatchCommandProcessor":{parse_file:[470,3,1,""]},"evennia.utils.containers":{Container:[471,1,1,""],GlobalScriptContainer:[471,1,1,""],OptionContainer:[471,1,1,""]},"evennia.utils.containers.Container":{__init__:[471,3,1,""],all:[471,3,1,""],get:[471,3,1,""],load_data:[471,3,1,""],storage_modules:[471,4,1,""]},"evennia.utils.containers.GlobalScriptContainer":{__init__:[471,3,1,""],all:[471,3,1,""],get:[471,3,1,""],load_data:[471,3,1,""],start:[471,3,1,""]},"evennia.utils.containers.OptionContainer":{storage_modules:[471,4,1,""]},"evennia.utils.create":{create_account:[472,5,1,""],create_channel:[472,5,1,""],create_help_entry:[472,5,1,""],create_message:[472,5,1,""],create_object:[472,5,1,""],create_script:[472,5,1,""]},"evennia.utils.dbserialize":{dbserialize:[473,5,1,""],dbunserialize:[473,5,1,""],do_pickle:[473,5,1,""],do_unpickle:[473,5,1,""],from_pickle:[473,5,1,""],to_pickle:[473,5,1,""]},"evennia.utils.eveditor":{CmdEditorBase:[474,1,1,""],CmdEditorGroup:[474,1,1,""],CmdLineInput:[474,1,1,""],CmdSaveYesNo:[474,1,1,""],EvEditor:[474,1,1,""],EvEditorCmdSet:[474,1,1,""],SaveYesNoCmdSet:[474,1,1,""]},"evennia.utils.eveditor.CmdEditorBase":{aliases:[474,4,1,""],editor:[474,4,1,""],help_category:[474,4,1,""],help_entry:[474,4,1,""],key:[474,4,1,""],lock_storage:[474,4,1,""],locks:[474,4,1,""],parse:[474,3,1,""],search_index_entry:[474,4,1,""]},"evennia.utils.eveditor.CmdEditorGroup":{aliases:[474,4,1,""],arg_regex:[474,4,1,""],func:[474,3,1,""],help_category:[474,4,1,""],key:[474,4,1,""],lock_storage:[474,4,1,""],search_index_entry:[474,4,1,""]},"evennia.utils.eveditor.CmdLineInput":{aliases:[474,4,1,""],func:[474,3,1,""],help_category:[474,4,1,""],key:[474,4,1,""],lock_storage:[474,4,1,""],search_index_entry:[474,4,1,""]},"evennia.utils.eveditor.CmdSaveYesNo":{aliases:[474,4,1,""],func:[474,3,1,""],help_category:[474,4,1,""],help_cateogory:[474,4,1,""],key:[474,4,1,""],lock_storage:[474,4,1,""],locks:[474,4,1,""],search_index_entry:[474,4,1,""]},"evennia.utils.eveditor.EvEditor":{__init__:[474,3,1,""],decrease_indent:[474,3,1,""],deduce_indent:[474,3,1,""],display_buffer:[474,3,1,""],display_help:[474,3,1,""],get_buffer:[474,3,1,""],increase_indent:[474,3,1,""],load_buffer:[474,3,1,""],quit:[474,3,1,""],save_buffer:[474,3,1,""],swap_autoindent:[474,3,1,""],update_buffer:[474,3,1,""],update_undo:[474,3,1,""]},"evennia.utils.eveditor.EvEditorCmdSet":{at_cmdset_creation:[474,3,1,""],key:[474,4,1,""],mergetype:[474,4,1,""],path:[474,4,1,""]},"evennia.utils.eveditor.SaveYesNoCmdSet":{at_cmdset_creation:[474,3,1,""],key:[474,4,1,""],mergetype:[474,4,1,""],path:[474,4,1,""],priority:[474,4,1,""]},"evennia.utils.evform":{EvForm:[475,1,1,""]},"evennia.utils.evform.EvForm":{__init__:[475,3,1,""],map:[475,3,1,""],reload:[475,3,1,""]},"evennia.utils.evmenu":{CmdEvMenuNode:[476,1,1,""],CmdGetInput:[476,1,1,""],CmdYesNoQuestion:[476,1,1,""],EvMenu:[476,1,1,""],EvMenuCmdSet:[476,1,1,""],EvMenuError:[476,2,1,""],EvMenuGotoAbortMessage:[476,2,1,""],InputCmdSet:[476,1,1,""],YesNoQuestionCmdSet:[476,1,1,""],ask_yes_no:[476,5,1,""],get_input:[476,5,1,""],list_node:[476,5,1,""],parse_menu_template:[476,5,1,""],template2menu:[476,5,1,""]},"evennia.utils.evmenu.CmdEvMenuNode":{aliases:[476,4,1,""],auto_help_display_key:[476,4,1,""],func:[476,3,1,""],get_help:[476,3,1,""],help_category:[476,4,1,""],key:[476,4,1,""],lock_storage:[476,4,1,""],locks:[476,4,1,""],search_index_entry:[476,4,1,""]},"evennia.utils.evmenu.CmdGetInput":{aliases:[476,4,1,""],func:[476,3,1,""],help_category:[476,4,1,""],key:[476,4,1,""],lock_storage:[476,4,1,""],search_index_entry:[476,4,1,""]},"evennia.utils.evmenu.CmdYesNoQuestion":{aliases:[476,4,1,""],arg_regex:[476,4,1,""],func:[476,3,1,""],help_category:[476,4,1,""],key:[476,4,1,""],lock_storage:[476,4,1,""],search_index_entry:[476,4,1,""]},"evennia.utils.evmenu.EvMenu":{"goto":[476,3,1,""],__init__:[476,3,1,""],close_menu:[476,3,1,""],display_helptext:[476,3,1,""],display_nodetext:[476,3,1,""],extract_goto_exec:[476,3,1,""],helptext_formatter:[476,3,1,""],msg:[476,3,1,""],node_border_char:[476,4,1,""],node_formatter:[476,3,1,""],nodetext_formatter:[476,3,1,""],options_formatter:[476,3,1,""],parse_input:[476,3,1,""],print_debug_info:[476,3,1,""],run_exec:[476,3,1,""],run_exec_then_goto:[476,3,1,""]},"evennia.utils.evmenu.EvMenuCmdSet":{at_cmdset_creation:[476,3,1,""],key:[476,4,1,""],mergetype:[476,4,1,""],no_channels:[476,4,1,""],no_exits:[476,4,1,""],no_objs:[476,4,1,""],path:[476,4,1,""],priority:[476,4,1,""]},"evennia.utils.evmenu.InputCmdSet":{at_cmdset_creation:[476,3,1,""],key:[476,4,1,""],mergetype:[476,4,1,""],no_channels:[476,4,1,""],no_exits:[476,4,1,""],no_objs:[476,4,1,""],path:[476,4,1,""],priority:[476,4,1,""]},"evennia.utils.evmenu.YesNoQuestionCmdSet":{at_cmdset_creation:[476,3,1,""],key:[476,4,1,""],mergetype:[476,4,1,""],no_channels:[476,4,1,""],no_exits:[476,4,1,""],no_objs:[476,4,1,""],path:[476,4,1,""],priority:[476,4,1,""]},"evennia.utils.evmore":{CmdMore:[477,1,1,""],CmdMoreExit:[477,1,1,""],CmdSetMore:[477,1,1,""],EvMore:[477,1,1,""],msg:[477,5,1,""],queryset_maxsize:[477,5,1,""]},"evennia.utils.evmore.CmdMore":{aliases:[477,4,1,""],auto_help:[477,4,1,""],func:[477,3,1,""],help_category:[477,4,1,""],key:[477,4,1,""],lock_storage:[477,4,1,""],search_index_entry:[477,4,1,""]},"evennia.utils.evmore.CmdMoreExit":{aliases:[477,4,1,""],func:[477,3,1,""],help_category:[477,4,1,""],key:[477,4,1,""],lock_storage:[477,4,1,""],search_index_entry:[477,4,1,""]},"evennia.utils.evmore.CmdSetMore":{at_cmdset_creation:[477,3,1,""],key:[477,4,1,""],mergetype:[477,4,1,""],path:[477,4,1,""],priority:[477,4,1,""]},"evennia.utils.evmore.EvMore":{__init__:[477,3,1,""],display:[477,3,1,""],init_django_paginator:[477,3,1,""],init_evtable:[477,3,1,""],init_f_str:[477,3,1,""],init_iterable:[477,3,1,""],init_pages:[477,3,1,""],init_queryset:[477,3,1,""],init_str:[477,3,1,""],page_back:[477,3,1,""],page_end:[477,3,1,""],page_formatter:[477,3,1,""],page_next:[477,3,1,""],page_quit:[477,3,1,""],page_top:[477,3,1,""],paginator:[477,3,1,""],paginator_django:[477,3,1,""],paginator_index:[477,3,1,""],paginator_slice:[477,3,1,""],start:[477,3,1,""]},"evennia.utils.evtable":{ANSITextWrapper:[478,1,1,""],EvCell:[478,1,1,""],EvColumn:[478,1,1,""],EvTable:[478,1,1,""],fill:[478,5,1,""],wrap:[478,5,1,""]},"evennia.utils.evtable.EvCell":{__init__:[478,3,1,""],get:[478,3,1,""],get_height:[478,3,1,""],get_min_height:[478,3,1,""],get_min_width:[478,3,1,""],get_width:[478,3,1,""],reformat:[478,3,1,""],replace_data:[478,3,1,""]},"evennia.utils.evtable.EvColumn":{__init__:[478,3,1,""],add_rows:[478,3,1,""],reformat:[478,3,1,""],reformat_cell:[478,3,1,""]},"evennia.utils.evtable.EvTable":{__init__:[478,3,1,""],add_column:[478,3,1,""],add_header:[478,3,1,""],add_row:[478,3,1,""],get:[478,3,1,""],reformat:[478,3,1,""],reformat_column:[478,3,1,""]},"evennia.utils.funcparser":{FuncParser:[479,1,1,""],ParsingError:[479,2,1,""],funcparser_callable_add:[479,5,1,""],funcparser_callable_center_justify:[479,5,1,""],funcparser_callable_choice:[479,5,1,""],funcparser_callable_clr:[479,5,1,""],funcparser_callable_conjugate:[479,5,1,""],funcparser_callable_crop:[479,5,1,""],funcparser_callable_div:[479,5,1,""],funcparser_callable_eval:[479,5,1,""],funcparser_callable_justify:[479,5,1,""],funcparser_callable_left_justify:[479,5,1,""],funcparser_callable_mult:[479,5,1,""],funcparser_callable_pad:[479,5,1,""],funcparser_callable_pronoun:[479,5,1,""],funcparser_callable_pronoun_capitalize:[479,5,1,""],funcparser_callable_randint:[479,5,1,""],funcparser_callable_random:[479,5,1,""],funcparser_callable_right_justify:[479,5,1,""],funcparser_callable_round:[479,5,1,""],funcparser_callable_search:[479,5,1,""],funcparser_callable_search_list:[479,5,1,""],funcparser_callable_space:[479,5,1,""],funcparser_callable_sub:[479,5,1,""],funcparser_callable_toint:[479,5,1,""],funcparser_callable_you:[479,5,1,""],funcparser_callable_you_capitalize:[479,5,1,""]},"evennia.utils.funcparser.FuncParser":{__init__:[479,3,1,""],execute:[479,3,1,""],parse:[479,3,1,""],parse_to_any:[479,3,1,""],validate_callables:[479,3,1,""]},"evennia.utils.gametime":{TimeScript:[480,1,1,""],game_epoch:[480,5,1,""],gametime:[480,5,1,""],portal_uptime:[480,5,1,""],real_seconds_until:[480,5,1,""],reset_gametime:[480,5,1,""],runtime:[480,5,1,""],schedule:[480,5,1,""],server_epoch:[480,5,1,""],uptime:[480,5,1,""]},"evennia.utils.gametime.TimeScript":{DoesNotExist:[480,2,1,""],MultipleObjectsReturned:[480,2,1,""],at_repeat:[480,3,1,""],at_script_creation:[480,3,1,""],path:[480,4,1,""],typename:[480,4,1,""]},"evennia.utils.idmapper":{manager:[482,0,0,"-"],models:[483,0,0,"-"],tests:[484,0,0,"-"]},"evennia.utils.idmapper.manager":{SharedMemoryManager:[482,1,1,""]},"evennia.utils.idmapper.manager.SharedMemoryManager":{get:[482,3,1,""]},"evennia.utils.idmapper.models":{SharedMemoryModel:[483,1,1,""],SharedMemoryModelBase:[483,1,1,""],WeakSharedMemoryModel:[483,1,1,""],WeakSharedMemoryModelBase:[483,1,1,""],cache_size:[483,5,1,""],conditional_flush:[483,5,1,""],flush_cache:[483,5,1,""],flush_cached_instance:[483,5,1,""],update_cached_instance:[483,5,1,""]},"evennia.utils.idmapper.models.SharedMemoryModel":{"delete":[483,3,1,""],Meta:[483,1,1,""],at_idmapper_flush:[483,3,1,""],cache_instance:[483,3,1,""],flush_cached_instance:[483,3,1,""],flush_from_cache:[483,3,1,""],flush_instance_cache:[483,3,1,""],get_all_cached_instances:[483,3,1,""],get_cached_instance:[483,3,1,""],objects:[483,4,1,""],path:[483,4,1,""],save:[483,3,1,""],typename:[483,4,1,""]},"evennia.utils.idmapper.models.SharedMemoryModel.Meta":{"abstract":[483,4,1,""]},"evennia.utils.idmapper.models.WeakSharedMemoryModel":{Meta:[483,1,1,""],path:[483,4,1,""],typename:[483,4,1,""]},"evennia.utils.idmapper.models.WeakSharedMemoryModel.Meta":{"abstract":[483,4,1,""]},"evennia.utils.idmapper.tests":{Article:[484,1,1,""],Category:[484,1,1,""],RegularArticle:[484,1,1,""],RegularCategory:[484,1,1,""],SharedMemorysTest:[484,1,1,""]},"evennia.utils.idmapper.tests.Article":{DoesNotExist:[484,2,1,""],MultipleObjectsReturned:[484,2,1,""],category2:[484,4,1,""],category2_id:[484,4,1,""],category:[484,4,1,""],category_id:[484,4,1,""],id:[484,4,1,""],name:[484,4,1,""],path:[484,4,1,""],typename:[484,4,1,""]},"evennia.utils.idmapper.tests.Category":{DoesNotExist:[484,2,1,""],MultipleObjectsReturned:[484,2,1,""],article_set:[484,4,1,""],id:[484,4,1,""],name:[484,4,1,""],path:[484,4,1,""],regulararticle_set:[484,4,1,""],typename:[484,4,1,""]},"evennia.utils.idmapper.tests.RegularArticle":{DoesNotExist:[484,2,1,""],MultipleObjectsReturned:[484,2,1,""],category2:[484,4,1,""],category2_id:[484,4,1,""],category:[484,4,1,""],category_id:[484,4,1,""],id:[484,4,1,""],name:[484,4,1,""],objects:[484,4,1,""]},"evennia.utils.idmapper.tests.RegularCategory":{DoesNotExist:[484,2,1,""],MultipleObjectsReturned:[484,2,1,""],article_set:[484,4,1,""],id:[484,4,1,""],name:[484,4,1,""],objects:[484,4,1,""],regulararticle_set:[484,4,1,""]},"evennia.utils.idmapper.tests.SharedMemorysTest":{setUp:[484,3,1,""],testMixedReferences:[484,3,1,""],testObjectDeletion:[484,3,1,""],testRegularReferences:[484,3,1,""],testSharedMemoryReferences:[484,3,1,""]},"evennia.utils.logger":{EvenniaLogFile:[485,1,1,""],PortalLogObserver:[485,1,1,""],ServerLogObserver:[485,1,1,""],WeeklyLogFile:[485,1,1,""],log_dep:[485,5,1,""],log_depmsg:[485,5,1,""],log_err:[485,5,1,""],log_errmsg:[485,5,1,""],log_file:[485,5,1,""],log_file_exists:[485,5,1,""],log_info:[485,5,1,""],log_infomsg:[485,5,1,""],log_msg:[485,5,1,""],log_sec:[485,5,1,""],log_secmsg:[485,5,1,""],log_server:[485,5,1,""],log_trace:[485,5,1,""],log_tracemsg:[485,5,1,""],log_warn:[485,5,1,""],log_warnmsg:[485,5,1,""],rotate_log_file:[485,5,1,""],tail_log_file:[485,5,1,""],timeformat:[485,5,1,""]},"evennia.utils.logger.EvenniaLogFile":{num_lines_to_append:[485,4,1,""],readlines:[485,3,1,""],rotate:[485,3,1,""],seek:[485,3,1,""],settings:[485,4,1,""]},"evennia.utils.logger.PortalLogObserver":{emit:[485,3,1,""],prefix:[485,4,1,""],timeFormat:[485,4,1,""]},"evennia.utils.logger.ServerLogObserver":{prefix:[485,4,1,""]},"evennia.utils.logger.WeeklyLogFile":{__init__:[485,3,1,""],shouldRotate:[485,3,1,""],suffix:[485,3,1,""],write:[485,3,1,""]},"evennia.utils.optionclasses":{BaseOption:[486,1,1,""],Boolean:[486,1,1,""],Color:[486,1,1,""],Datetime:[486,1,1,""],Duration:[486,1,1,""],Email:[486,1,1,""],Future:[486,1,1,""],Lock:[486,1,1,""],PositiveInteger:[486,1,1,""],SignedInteger:[486,1,1,""],Text:[486,1,1,""],Timezone:[486,1,1,""],UnsignedInteger:[486,1,1,""]},"evennia.utils.optionclasses.BaseOption":{"default":[486,3,1,""],__init__:[486,3,1,""],changed:[486,3,1,""],deserialize:[486,3,1,""],display:[486,3,1,""],load:[486,3,1,""],save:[486,3,1,""],serialize:[486,3,1,""],set:[486,3,1,""],validate:[486,3,1,""],value:[486,3,1,""]},"evennia.utils.optionclasses.Boolean":{deserialize:[486,3,1,""],display:[486,3,1,""],serialize:[486,3,1,""],validate:[486,3,1,""]},"evennia.utils.optionclasses.Color":{deserialize:[486,3,1,""],display:[486,3,1,""],validate:[486,3,1,""]},"evennia.utils.optionclasses.Datetime":{deserialize:[486,3,1,""],serialize:[486,3,1,""],validate:[486,3,1,""]},"evennia.utils.optionclasses.Duration":{deserialize:[486,3,1,""],serialize:[486,3,1,""],validate:[486,3,1,""]},"evennia.utils.optionclasses.Email":{deserialize:[486,3,1,""],validate:[486,3,1,""]},"evennia.utils.optionclasses.Future":{validate:[486,3,1,""]},"evennia.utils.optionclasses.Lock":{validate:[486,3,1,""]},"evennia.utils.optionclasses.PositiveInteger":{deserialize:[486,3,1,""],validate:[486,3,1,""]},"evennia.utils.optionclasses.SignedInteger":{deserialize:[486,3,1,""],validate:[486,3,1,""]},"evennia.utils.optionclasses.Text":{deserialize:[486,3,1,""]},"evennia.utils.optionclasses.Timezone":{"default":[486,3,1,""],deserialize:[486,3,1,""],serialize:[486,3,1,""],validate:[486,3,1,""]},"evennia.utils.optionclasses.UnsignedInteger":{deserialize:[486,3,1,""],validate:[486,3,1,""],validator_key:[486,4,1,""]},"evennia.utils.optionhandler":{InMemorySaveHandler:[487,1,1,""],OptionHandler:[487,1,1,""]},"evennia.utils.optionhandler.InMemorySaveHandler":{__init__:[487,3,1,""],add:[487,3,1,""],get:[487,3,1,""]},"evennia.utils.optionhandler.OptionHandler":{__init__:[487,3,1,""],all:[487,3,1,""],get:[487,3,1,""],set:[487,3,1,""]},"evennia.utils.picklefield":{PickledFormField:[488,1,1,""],PickledObject:[488,1,1,""],PickledObjectField:[488,1,1,""],PickledWidget:[488,1,1,""],dbsafe_decode:[488,5,1,""],dbsafe_encode:[488,5,1,""],wrap_conflictual_object:[488,5,1,""]},"evennia.utils.picklefield.PickledFormField":{__init__:[488,3,1,""],clean:[488,3,1,""],default_error_messages:[488,4,1,""],widget:[488,4,1,""]},"evennia.utils.picklefield.PickledObjectField":{__init__:[488,3,1,""],formfield:[488,3,1,""],from_db_value:[488,3,1,""],get_db_prep_lookup:[488,3,1,""],get_db_prep_value:[488,3,1,""],get_default:[488,3,1,""],get_internal_type:[488,3,1,""],pre_save:[488,3,1,""],value_to_string:[488,3,1,""]},"evennia.utils.picklefield.PickledWidget":{media:[488,3,1,""],render:[488,3,1,""],value_from_datadict:[488,3,1,""]},"evennia.utils.search":{search_account:[489,5,1,""],search_account_tag:[489,5,1,""],search_channel:[489,5,1,""],search_channel_tag:[489,5,1,""],search_help_entry:[489,5,1,""],search_message:[489,5,1,""],search_object:[489,5,1,""],search_script:[489,5,1,""],search_script_tag:[489,5,1,""],search_tag:[489,5,1,""]},"evennia.utils.test_resources":{BaseEvenniaCommandTest:[490,1,1,""],BaseEvenniaTest:[490,1,1,""],BaseEvenniaTestCase:[490,1,1,""],EvenniaCommandTest:[490,1,1,""],EvenniaCommandTestMixin:[490,1,1,""],EvenniaTest:[490,1,1,""],EvenniaTestCase:[490,1,1,""],EvenniaTestMixin:[490,1,1,""],mockdeferLater:[490,5,1,""],mockdelay:[490,5,1,""],unload_module:[490,5,1,""]},"evennia.utils.test_resources.EvenniaCommandTestMixin":{call:[490,3,1,""]},"evennia.utils.test_resources.EvenniaTest":{account_typeclass:[490,4,1,""],character_typeclass:[490,4,1,""],exit_typeclass:[490,4,1,""],object_typeclass:[490,4,1,""],room_typeclass:[490,4,1,""],script_typeclass:[490,4,1,""]},"evennia.utils.test_resources.EvenniaTestMixin":{account_typeclass:[490,4,1,""],character_typeclass:[490,4,1,""],create_accounts:[490,3,1,""],create_chars:[490,3,1,""],create_objs:[490,3,1,""],create_rooms:[490,3,1,""],create_script:[490,3,1,""],exit_typeclass:[490,4,1,""],object_typeclass:[490,4,1,""],room_typeclass:[490,4,1,""],script_typeclass:[490,4,1,""],setUp:[490,3,1,""],setup_session:[490,3,1,""],tearDown:[490,3,1,""],teardown_accounts:[490,3,1,""],teardown_session:[490,3,1,""]},"evennia.utils.text2html":{TextToHTMLparser:[491,1,1,""],parse_html:[491,5,1,""]},"evennia.utils.text2html.TextToHTMLparser":{bg_colormap:[491,4,1,""],bgfgstart:[491,4,1,""],bgfgstop:[491,4,1,""],bgstart:[491,4,1,""],bgstop:[491,4,1,""],blink:[491,4,1,""],colorback:[491,4,1,""],colorcodes:[491,4,1,""],convert_linebreaks:[491,3,1,""],convert_urls:[491,3,1,""],fg_colormap:[491,4,1,""],fgstart:[491,4,1,""],fgstop:[491,4,1,""],hilite:[491,4,1,""],inverse:[491,4,1,""],normal:[491,4,1,""],parse:[491,3,1,""],re_bgfg:[491,4,1,""],re_bgs:[491,4,1,""],re_blink:[491,4,1,""],re_blinking:[491,3,1,""],re_bold:[491,3,1,""],re_color:[491,3,1,""],re_dblspace:[491,4,1,""],re_double_space:[491,3,1,""],re_fgs:[491,4,1,""],re_hilite:[491,4,1,""],re_inverse:[491,4,1,""],re_inversing:[491,3,1,""],re_mxplink:[491,4,1,""],re_mxpurl:[491,4,1,""],re_normal:[491,4,1,""],re_string:[491,4,1,""],re_uline:[491,4,1,""],re_underline:[491,3,1,""],re_unhilite:[491,4,1,""],re_url:[491,4,1,""],remove_backspaces:[491,3,1,""],remove_bells:[491,3,1,""],sub_dblspace:[491,3,1,""],sub_mxp_links:[491,3,1,""],sub_mxp_urls:[491,3,1,""],sub_text:[491,3,1,""],tabstop:[491,4,1,""],underline:[491,4,1,""],unhilite:[491,4,1,""]},"evennia.utils.utils":{LimitedSizeOrderedDict:[492,1,1,""],all_from_module:[492,5,1,""],at_search_result:[492,5,1,""],callables_from_module:[492,5,1,""],calledby:[492,5,1,""],check_evennia_dependencies:[492,5,1,""],class_from_module:[492,5,1,""],columnize:[492,5,1,""],copy_word_case:[492,5,1,""],crop:[492,5,1,""],datetime_format:[492,5,1,""],dbid_to_obj:[492,5,1,""],dbref:[492,5,1,""],dbref_to_obj:[492,5,1,""],dedent:[492,5,1,""],deepsize:[492,5,1,""],delay:[492,5,1,""],display_len:[492,5,1,""],fill:[492,5,1,""],format_grid:[492,5,1,""],format_table:[492,5,1,""],fuzzy_import_from_module:[492,5,1,""],get_all_cmdsets:[492,5,1,""],get_all_typeclasses:[492,5,1,""],get_evennia_pids:[492,5,1,""],get_evennia_version:[492,5,1,""],get_game_dir_path:[492,5,1,""],has_parent:[492,5,1,""],host_os_is:[492,5,1,""],inherits_from:[492,5,1,""],init_new_account:[492,5,1,""],interactive:[492,5,1,""],is_iter:[492,5,1,""],iter_to_str:[492,5,1,""],iter_to_string:[492,5,1,""],justify:[492,5,1,""],latinify:[492,5,1,""],lazy_property:[492,1,1,""],list_to_string:[492,5,1,""],m_len:[492,5,1,""],make_iter:[492,5,1,""],mod_import:[492,5,1,""],mod_import_from_path:[492,5,1,""],object_from_module:[492,5,1,""],pad:[492,5,1,""],percent:[492,5,1,""],percentile:[492,5,1,""],pypath_to_realpath:[492,5,1,""],random_string_from_module:[492,5,1,""],repeat:[492,5,1,""],run_async:[492,5,1,""],safe_convert_to_types:[492,5,1,""],server_services:[492,5,1,""],string_from_module:[492,5,1,""],string_partial_matching:[492,5,1,""],string_similarity:[492,5,1,""],string_suggestions:[492,5,1,""],strip_control_sequences:[492,5,1,""],strip_unsafe_input:[492,5,1,""],time_format:[492,5,1,""],to_bytes:[492,5,1,""],to_str:[492,5,1,""],unrepeat:[492,5,1,""],uses_database:[492,5,1,""],validate_email_address:[492,5,1,""],variable_from_module:[492,5,1,""],wildcard_to_regexp:[492,5,1,""],wrap:[492,5,1,""]},"evennia.utils.utils.LimitedSizeOrderedDict":{__init__:[492,3,1,""],update:[492,3,1,""]},"evennia.utils.utils.lazy_property":{__init__:[492,3,1,""]},"evennia.utils.validatorfuncs":{"boolean":[493,5,1,""],color:[493,5,1,""],datetime:[493,5,1,""],duration:[493,5,1,""],email:[493,5,1,""],future:[493,5,1,""],lock:[493,5,1,""],positive_integer:[493,5,1,""],signed_integer:[493,5,1,""],text:[493,5,1,""],timezone:[493,5,1,""],unsigned_integer:[493,5,1,""]},"evennia.utils.verb_conjugation":{conjugate:[495,0,0,"-"],pronouns:[496,0,0,"-"],tests:[497,0,0,"-"]},"evennia.utils.verb_conjugation.conjugate":{verb_actor_stance_components:[495,5,1,""],verb_all_tenses:[495,5,1,""],verb_conjugate:[495,5,1,""],verb_infinitive:[495,5,1,""],verb_is_past:[495,5,1,""],verb_is_past_participle:[495,5,1,""],verb_is_present:[495,5,1,""],verb_is_present_participle:[495,5,1,""],verb_is_tense:[495,5,1,""],verb_past:[495,5,1,""],verb_past_participle:[495,5,1,""],verb_present:[495,5,1,""],verb_present_participle:[495,5,1,""],verb_tense:[495,5,1,""]},"evennia.utils.verb_conjugation.pronouns":{pronoun_to_viewpoints:[496,5,1,""]},"evennia.utils.verb_conjugation.tests":{TestPronounMapping:[497,1,1,""],TestVerbConjugate:[497,1,1,""]},"evennia.utils.verb_conjugation.tests.TestPronounMapping":{test_mapping_with_options:[497,4,1,""],test_mapping_with_options_00_you:[497,3,1,""],test_mapping_with_options_01_you:[497,3,1,""],test_mapping_with_options_02_I:[497,3,1,""],test_mapping_with_options_03_I:[497,3,1,""],test_mapping_with_options_04_I:[497,3,1,""],test_mapping_with_options_05_Me:[497,3,1,""],test_mapping_with_options_06_your:[497,3,1,""],test_mapping_with_options_07_ours:[497,3,1,""],test_mapping_with_options_08_yourself:[497,3,1,""],test_mapping_with_options_09_yourself:[497,3,1,""],test_mapping_with_options_10_yourself:[497,3,1,""],test_mapping_with_options_11_yourself:[497,3,1,""],test_mapping_with_options_12_yourselves:[497,3,1,""],test_mapping_with_options_13_he:[497,3,1,""],test_mapping_with_options_14_he:[497,3,1,""],test_mapping_with_options_15_he:[497,3,1,""],test_mapping_with_options_16_her:[497,3,1,""],test_mapping_with_options_17_her:[497,3,1,""],test_mapping_with_options_18_their:[497,3,1,""],test_mapping_with_options_19_their:[497,3,1,""],test_mapping_with_options_20_itself:[497,3,1,""],test_mapping_with_options_21_themselves:[497,3,1,""],test_mapping_with_options_22_herself:[497,3,1,""]},"evennia.utils.verb_conjugation.tests.TestVerbConjugate":{test_verb_actor_stance_components:[497,4,1,""],test_verb_actor_stance_components_00_have:[497,3,1,""],test_verb_actor_stance_components_01_swimming:[497,3,1,""],test_verb_actor_stance_components_02_give:[497,3,1,""],test_verb_actor_stance_components_03_given:[497,3,1,""],test_verb_actor_stance_components_04_am:[497,3,1,""],test_verb_actor_stance_components_05_doing:[497,3,1,""],test_verb_actor_stance_components_06_are:[497,3,1,""],test_verb_actor_stance_components_07_had:[497,3,1,""],test_verb_actor_stance_components_08_grin:[497,3,1,""],test_verb_actor_stance_components_09_smile:[497,3,1,""],test_verb_actor_stance_components_10_vex:[497,3,1,""],test_verb_actor_stance_components_11_thrust:[497,3,1,""],test_verb_conjugate:[497,4,1,""],test_verb_conjugate_0_inf:[497,3,1,""],test_verb_conjugate_1_inf:[497,3,1,""],test_verb_conjugate_2_inf:[497,3,1,""],test_verb_conjugate_3_inf:[497,3,1,""],test_verb_conjugate_4_inf:[497,3,1,""],test_verb_conjugate_5_inf:[497,3,1,""],test_verb_conjugate_6_inf:[497,3,1,""],test_verb_conjugate_7_2sgpres:[497,3,1,""],test_verb_conjugate_8_3sgpres:[497,3,1,""],test_verb_get_all_tenses:[497,3,1,""],test_verb_infinitive:[497,4,1,""],test_verb_infinitive_0_have:[497,3,1,""],test_verb_infinitive_1_swim:[497,3,1,""],test_verb_infinitive_2_give:[497,3,1,""],test_verb_infinitive_3_given:[497,3,1,""],test_verb_infinitive_4_am:[497,3,1,""],test_verb_infinitive_5_doing:[497,3,1,""],test_verb_infinitive_6_are:[497,3,1,""],test_verb_is_past:[497,4,1,""],test_verb_is_past_0_1st:[497,3,1,""],test_verb_is_past_1_1st:[497,3,1,""],test_verb_is_past_2_1st:[497,3,1,""],test_verb_is_past_3_1st:[497,3,1,""],test_verb_is_past_4_1st:[497,3,1,""],test_verb_is_past_5_1st:[497,3,1,""],test_verb_is_past_6_1st:[497,3,1,""],test_verb_is_past_7_2nd:[497,3,1,""],test_verb_is_past_participle:[497,4,1,""],test_verb_is_past_participle_0_have:[497,3,1,""],test_verb_is_past_participle_1_swimming:[497,3,1,""],test_verb_is_past_participle_2_give:[497,3,1,""],test_verb_is_past_participle_3_given:[497,3,1,""],test_verb_is_past_participle_4_am:[497,3,1,""],test_verb_is_past_participle_5_doing:[497,3,1,""],test_verb_is_past_participle_6_are:[497,3,1,""],test_verb_is_past_participle_7_had:[497,3,1,""],test_verb_is_present:[497,4,1,""],test_verb_is_present_0_1st:[497,3,1,""],test_verb_is_present_1_1st:[497,3,1,""],test_verb_is_present_2_1st:[497,3,1,""],test_verb_is_present_3_1st:[497,3,1,""],test_verb_is_present_4_1st:[497,3,1,""],test_verb_is_present_5_1st:[497,3,1,""],test_verb_is_present_6_1st:[497,3,1,""],test_verb_is_present_7_1st:[497,3,1,""],test_verb_is_present_participle:[497,4,1,""],test_verb_is_present_participle_0_have:[497,3,1,""],test_verb_is_present_participle_1_swim:[497,3,1,""],test_verb_is_present_participle_2_give:[497,3,1,""],test_verb_is_present_participle_3_given:[497,3,1,""],test_verb_is_present_participle_4_am:[497,3,1,""],test_verb_is_present_participle_5_doing:[497,3,1,""],test_verb_is_present_participle_6_are:[497,3,1,""],test_verb_is_tense:[497,4,1,""],test_verb_is_tense_0_inf:[497,3,1,""],test_verb_is_tense_1_inf:[497,3,1,""],test_verb_is_tense_2_inf:[497,3,1,""],test_verb_is_tense_3_inf:[497,3,1,""],test_verb_is_tense_4_inf:[497,3,1,""],test_verb_is_tense_5_inf:[497,3,1,""],test_verb_is_tense_6_inf:[497,3,1,""],test_verb_past:[497,4,1,""],test_verb_past_0_1st:[497,3,1,""],test_verb_past_1_1st:[497,3,1,""],test_verb_past_2_1st:[497,3,1,""],test_verb_past_3_1st:[497,3,1,""],test_verb_past_4_1st:[497,3,1,""],test_verb_past_5_1st:[497,3,1,""],test_verb_past_6_1st:[497,3,1,""],test_verb_past_7_2nd:[497,3,1,""],test_verb_past_participle:[497,4,1,""],test_verb_past_participle_0_have:[497,3,1,""],test_verb_past_participle_1_swim:[497,3,1,""],test_verb_past_participle_2_give:[497,3,1,""],test_verb_past_participle_3_given:[497,3,1,""],test_verb_past_participle_4_am:[497,3,1,""],test_verb_past_participle_5_doing:[497,3,1,""],test_verb_past_participle_6_are:[497,3,1,""],test_verb_present:[497,4,1,""],test_verb_present_0_1st:[497,3,1,""],test_verb_present_1_1st:[497,3,1,""],test_verb_present_2_1st:[497,3,1,""],test_verb_present_3_1st:[497,3,1,""],test_verb_present_4_1st:[497,3,1,""],test_verb_present_5_1st:[497,3,1,""],test_verb_present_6_1st:[497,3,1,""],test_verb_present_7_2nd:[497,3,1,""],test_verb_present_8_3rd:[497,3,1,""],test_verb_present_participle:[497,4,1,""],test_verb_present_participle_0_have:[497,3,1,""],test_verb_present_participle_1_swim:[497,3,1,""],test_verb_present_participle_2_give:[497,3,1,""],test_verb_present_participle_3_given:[497,3,1,""],test_verb_present_participle_4_am:[497,3,1,""],test_verb_present_participle_5_doing:[497,3,1,""],test_verb_present_participle_6_are:[497,3,1,""],test_verb_tense:[497,4,1,""],test_verb_tense_0_have:[497,3,1,""],test_verb_tense_1_swim:[497,3,1,""],test_verb_tense_2_give:[497,3,1,""],test_verb_tense_3_given:[497,3,1,""],test_verb_tense_4_am:[497,3,1,""],test_verb_tense_5_doing:[497,3,1,""],test_verb_tense_6_are:[497,3,1,""]},"evennia.web":{admin:[499,0,0,"-"],api:[511,0,0,"-"],templatetags:[519,0,0,"-"],urls:[521,0,0,"-"],utils:[522,0,0,"-"],webclient:[528,0,0,"-"],website:[531,0,0,"-"]},"evennia.web.admin":{accounts:[500,0,0,"-"],attributes:[501,0,0,"-"],comms:[502,0,0,"-"],frontpage:[503,0,0,"-"],help:[504,0,0,"-"],objects:[505,0,0,"-"],scripts:[506,0,0,"-"],server:[507,0,0,"-"],tags:[508,0,0,"-"],urls:[509,0,0,"-"],utils:[510,0,0,"-"]},"evennia.web.admin.accounts":{AccountAdmin:[500,1,1,""],AccountAttributeInline:[500,1,1,""],AccountChangeForm:[500,1,1,""],AccountCreationForm:[500,1,1,""],AccountTagInline:[500,1,1,""],ObjectPuppetInline:[500,1,1,""]},"evennia.web.admin.accounts.AccountAdmin":{add_fieldsets:[500,4,1,""],add_form:[500,4,1,""],fieldsets:[500,4,1,""],form:[500,4,1,""],get_form:[500,3,1,""],inlines:[500,4,1,""],list_display:[500,4,1,""],list_display_links:[500,4,1,""],list_filter:[500,4,1,""],media:[500,3,1,""],ordering:[500,4,1,""],puppeted_objects:[500,3,1,""],readonly_fields:[500,4,1,""],response_add:[500,3,1,""],save_model:[500,3,1,""],search_fields:[500,4,1,""],serialized_string:[500,3,1,""],user_change_password:[500,3,1,""],view_on_site:[500,4,1,""]},"evennia.web.admin.accounts.AccountAttributeInline":{media:[500,3,1,""],model:[500,4,1,""],related_field:[500,4,1,""]},"evennia.web.admin.accounts.AccountChangeForm":{Meta:[500,1,1,""],__init__:[500,3,1,""],base_fields:[500,4,1,""],clean_username:[500,3,1,""],declared_fields:[500,4,1,""],media:[500,3,1,""]},"evennia.web.admin.accounts.AccountChangeForm.Meta":{fields:[500,4,1,""],model:[500,4,1,""]},"evennia.web.admin.accounts.AccountCreationForm":{Meta:[500,1,1,""],base_fields:[500,4,1,""],clean_username:[500,3,1,""],declared_fields:[500,4,1,""],media:[500,3,1,""]},"evennia.web.admin.accounts.AccountCreationForm.Meta":{fields:[500,4,1,""],model:[500,4,1,""]},"evennia.web.admin.accounts.AccountTagInline":{media:[500,3,1,""],model:[500,4,1,""],related_field:[500,4,1,""]},"evennia.web.admin.accounts.ObjectPuppetInline":{ObjectCreateForm:[500,1,1,""],extra:[500,4,1,""],fieldsets:[500,4,1,""],form:[500,4,1,""],has_add_permission:[500,3,1,""],has_delete_permission:[500,3,1,""],media:[500,3,1,""],model:[500,4,1,""],readonly_fields:[500,4,1,""],show_change_link:[500,4,1,""],verbose_name:[500,4,1,""],view_on_site:[500,4,1,""]},"evennia.web.admin.accounts.ObjectPuppetInline.ObjectCreateForm":{Meta:[500,1,1,""],__init__:[500,3,1,""],base_fields:[500,4,1,""],declared_fields:[500,4,1,""],media:[500,3,1,""]},"evennia.web.admin.accounts.ObjectPuppetInline.ObjectCreateForm.Meta":{fields:[500,4,1,""],model:[500,4,1,""]},"evennia.web.admin.attributes":{AttributeForm:[501,1,1,""],AttributeFormSet:[501,1,1,""],AttributeInline:[501,1,1,""]},"evennia.web.admin.attributes.AttributeForm":{Meta:[501,1,1,""],__init__:[501,3,1,""],base_fields:[501,4,1,""],clean_attr_value:[501,3,1,""],declared_fields:[501,4,1,""],media:[501,3,1,""],save:[501,3,1,""]},"evennia.web.admin.attributes.AttributeForm.Meta":{fields:[501,4,1,""]},"evennia.web.admin.attributes.AttributeFormSet":{save:[501,3,1,""]},"evennia.web.admin.attributes.AttributeInline":{extra:[501,4,1,""],form:[501,4,1,""],formset:[501,4,1,""],get_formset:[501,3,1,""],media:[501,3,1,""],model:[501,4,1,""],related_field:[501,4,1,""],verbose_name:[501,4,1,""],verbose_name_plural:[501,4,1,""]},"evennia.web.admin.comms":{ChannelAdmin:[502,1,1,""],ChannelAttributeInline:[502,1,1,""],ChannelForm:[502,1,1,""],ChannelTagInline:[502,1,1,""],MsgAdmin:[502,1,1,""],MsgForm:[502,1,1,""],MsgTagInline:[502,1,1,""]},"evennia.web.admin.comms.ChannelAdmin":{fieldsets:[502,4,1,""],form:[502,4,1,""],get_form:[502,3,1,""],inlines:[502,4,1,""],list_display:[502,4,1,""],list_display_links:[502,4,1,""],list_select_related:[502,4,1,""],media:[502,3,1,""],no_of_subscribers:[502,3,1,""],ordering:[502,4,1,""],raw_id_fields:[502,4,1,""],readonly_fields:[502,4,1,""],response_add:[502,3,1,""],save_as:[502,4,1,""],save_model:[502,3,1,""],save_on_top:[502,4,1,""],search_fields:[502,4,1,""],serialized_string:[502,3,1,""],subscriptions:[502,3,1,""]},"evennia.web.admin.comms.ChannelAttributeInline":{media:[502,3,1,""],model:[502,4,1,""],related_field:[502,4,1,""]},"evennia.web.admin.comms.ChannelForm":{Meta:[502,1,1,""],base_fields:[502,4,1,""],declared_fields:[502,4,1,""],media:[502,3,1,""]},"evennia.web.admin.comms.ChannelForm.Meta":{fields:[502,4,1,""],model:[502,4,1,""]},"evennia.web.admin.comms.ChannelTagInline":{media:[502,3,1,""],model:[502,4,1,""],related_field:[502,4,1,""]},"evennia.web.admin.comms.MsgAdmin":{fieldsets:[502,4,1,""],form:[502,4,1,""],get_form:[502,3,1,""],inlines:[502,4,1,""],list_display:[502,4,1,""],list_display_links:[502,4,1,""],list_select_related:[502,4,1,""],media:[502,3,1,""],ordering:[502,4,1,""],raw_id_fields:[502,4,1,""],readonly_fields:[502,4,1,""],receiver:[502,3,1,""],save_as:[502,4,1,""],save_on_top:[502,4,1,""],search_fields:[502,4,1,""],sender:[502,3,1,""],serialized_string:[502,3,1,""],start_of_message:[502,3,1,""],view_on_site:[502,4,1,""]},"evennia.web.admin.comms.MsgForm":{Meta:[502,1,1,""],base_fields:[502,4,1,""],declared_fields:[502,4,1,""],media:[502,3,1,""]},"evennia.web.admin.comms.MsgForm.Meta":{fields:[502,4,1,""],models:[502,4,1,""]},"evennia.web.admin.comms.MsgTagInline":{media:[502,3,1,""],model:[502,4,1,""],related_field:[502,4,1,""]},"evennia.web.admin.frontpage":{admin_wrapper:[503,5,1,""],evennia_admin:[503,5,1,""]},"evennia.web.admin.help":{HelpEntryAdmin:[504,1,1,""],HelpEntryForm:[504,1,1,""],HelpTagInline:[504,1,1,""]},"evennia.web.admin.help.HelpEntryAdmin":{fieldsets:[504,4,1,""],form:[504,4,1,""],inlines:[504,4,1,""],list_display:[504,4,1,""],list_display_links:[504,4,1,""],list_filter:[504,4,1,""],list_select_related:[504,4,1,""],media:[504,3,1,""],ordering:[504,4,1,""],save_as:[504,4,1,""],save_on_top:[504,4,1,""],search_fields:[504,4,1,""],view_on_site:[504,4,1,""]},"evennia.web.admin.help.HelpEntryForm":{Meta:[504,1,1,""],base_fields:[504,4,1,""],declared_fields:[504,4,1,""],media:[504,3,1,""]},"evennia.web.admin.help.HelpEntryForm.Meta":{fields:[504,4,1,""],model:[504,4,1,""]},"evennia.web.admin.help.HelpTagInline":{media:[504,3,1,""],model:[504,4,1,""],related_field:[504,4,1,""]},"evennia.web.admin.objects":{ObjectAdmin:[505,1,1,""],ObjectAttributeInline:[505,1,1,""],ObjectCreateForm:[505,1,1,""],ObjectEditForm:[505,1,1,""],ObjectTagInline:[505,1,1,""]},"evennia.web.admin.objects.ObjectAdmin":{add_fieldsets:[505,4,1,""],add_form:[505,4,1,""],fieldsets:[505,4,1,""],form:[505,4,1,""],get_fieldsets:[505,3,1,""],get_form:[505,3,1,""],get_urls:[505,3,1,""],inlines:[505,4,1,""],link_button:[505,3,1,""],link_object_to_account:[505,3,1,""],list_display:[505,4,1,""],list_display_links:[505,4,1,""],list_filter:[505,4,1,""],list_select_related:[505,4,1,""],media:[505,3,1,""],ordering:[505,4,1,""],raw_id_fields:[505,4,1,""],readonly_fields:[505,4,1,""],response_add:[505,3,1,""],save_as:[505,4,1,""],save_model:[505,3,1,""],save_on_top:[505,4,1,""],search_fields:[505,4,1,""],serialized_string:[505,3,1,""],view_on_site:[505,4,1,""]},"evennia.web.admin.objects.ObjectAttributeInline":{media:[505,3,1,""],model:[505,4,1,""],related_field:[505,4,1,""]},"evennia.web.admin.objects.ObjectCreateForm":{Meta:[505,1,1,""],__init__:[505,3,1,""],base_fields:[505,4,1,""],declared_fields:[505,4,1,""],media:[505,3,1,""]},"evennia.web.admin.objects.ObjectCreateForm.Meta":{fields:[505,4,1,""],model:[505,4,1,""]},"evennia.web.admin.objects.ObjectEditForm":{Meta:[505,1,1,""],base_fields:[505,4,1,""],declared_fields:[505,4,1,""],media:[505,3,1,""]},"evennia.web.admin.objects.ObjectEditForm.Meta":{fields:[505,4,1,""],model:[505,4,1,""]},"evennia.web.admin.objects.ObjectTagInline":{media:[505,3,1,""],model:[505,4,1,""],related_field:[505,4,1,""]},"evennia.web.admin.scripts":{ScriptAdmin:[506,1,1,""],ScriptAttributeInline:[506,1,1,""],ScriptForm:[506,1,1,""],ScriptTagInline:[506,1,1,""]},"evennia.web.admin.scripts.ScriptAdmin":{fieldsets:[506,4,1,""],form:[506,4,1,""],get_form:[506,3,1,""],inlines:[506,4,1,""],list_display:[506,4,1,""],list_display_links:[506,4,1,""],list_select_related:[506,4,1,""],media:[506,3,1,""],ordering:[506,4,1,""],raw_id_fields:[506,4,1,""],readonly_fields:[506,4,1,""],save_as:[506,4,1,""],save_model:[506,3,1,""],save_on_top:[506,4,1,""],search_fields:[506,4,1,""],serialized_string:[506,3,1,""],view_on_site:[506,4,1,""]},"evennia.web.admin.scripts.ScriptAttributeInline":{media:[506,3,1,""],model:[506,4,1,""],related_field:[506,4,1,""]},"evennia.web.admin.scripts.ScriptForm":{base_fields:[506,4,1,""],declared_fields:[506,4,1,""],media:[506,3,1,""]},"evennia.web.admin.scripts.ScriptTagInline":{media:[506,3,1,""],model:[506,4,1,""],related_field:[506,4,1,""]},"evennia.web.admin.server":{ServerConfigAdmin:[507,1,1,""]},"evennia.web.admin.server.ServerConfigAdmin":{list_display:[507,4,1,""],list_display_links:[507,4,1,""],list_select_related:[507,4,1,""],media:[507,3,1,""],ordering:[507,4,1,""],save_as:[507,4,1,""],save_on_top:[507,4,1,""],search_fields:[507,4,1,""]},"evennia.web.admin.tags":{InlineTagForm:[508,1,1,""],TagAdmin:[508,1,1,""],TagForm:[508,1,1,""],TagFormSet:[508,1,1,""],TagInline:[508,1,1,""]},"evennia.web.admin.tags.InlineTagForm":{Meta:[508,1,1,""],__init__:[508,3,1,""],base_fields:[508,4,1,""],declared_fields:[508,4,1,""],media:[508,3,1,""],save:[508,3,1,""]},"evennia.web.admin.tags.InlineTagForm.Meta":{fields:[508,4,1,""]},"evennia.web.admin.tags.TagAdmin":{fieldsets:[508,4,1,""],form:[508,4,1,""],list_display:[508,4,1,""],list_filter:[508,4,1,""],media:[508,3,1,""],search_fields:[508,4,1,""],view_on_site:[508,4,1,""]},"evennia.web.admin.tags.TagForm":{Meta:[508,1,1,""],base_fields:[508,4,1,""],declared_fields:[508,4,1,""],media:[508,3,1,""]},"evennia.web.admin.tags.TagForm.Meta":{fields:[508,4,1,""]},"evennia.web.admin.tags.TagFormSet":{save:[508,3,1,""],verbose_name:[508,4,1,""],verbose_name_plural:[508,4,1,""]},"evennia.web.admin.tags.TagInline":{extra:[508,4,1,""],form:[508,4,1,""],formset:[508,4,1,""],get_formset:[508,3,1,""],media:[508,3,1,""],model:[508,4,1,""],related_field:[508,4,1,""],verbose_name:[508,4,1,""],verbose_name_plural:[508,4,1,""]},"evennia.web.admin.utils":{get_and_load_cmdsets:[510,5,1,""],get_and_load_typeclasses:[510,5,1,""]},"evennia.web.api":{filters:[512,0,0,"-"],permissions:[513,0,0,"-"],root:[514,0,0,"-"],serializers:[515,0,0,"-"],tests:[516,0,0,"-"],urls:[517,0,0,"-"],views:[518,0,0,"-"]},"evennia.web.api.filters":{AccountDBFilterSet:[512,1,1,""],AliasFilter:[512,1,1,""],BaseTypeclassFilterSet:[512,1,1,""],HelpFilterSet:[512,1,1,""],ObjectDBFilterSet:[512,1,1,""],PermissionFilter:[512,1,1,""],ScriptDBFilterSet:[512,1,1,""],TagTypeFilter:[512,1,1,""],get_tag_query:[512,5,1,""]},"evennia.web.api.filters.AccountDBFilterSet":{Meta:[512,1,1,""],base_filters:[512,4,1,""],declared_filters:[512,4,1,""]},"evennia.web.api.filters.AccountDBFilterSet.Meta":{fields:[512,4,1,""],model:[512,4,1,""]},"evennia.web.api.filters.AliasFilter":{tag_type:[512,4,1,""]},"evennia.web.api.filters.BaseTypeclassFilterSet":{base_filters:[512,4,1,""],declared_filters:[512,4,1,""],filter_name:[512,3,1,""]},"evennia.web.api.filters.HelpFilterSet":{base_filters:[512,4,1,""],declared_filters:[512,4,1,""]},"evennia.web.api.filters.ObjectDBFilterSet":{Meta:[512,1,1,""],base_filters:[512,4,1,""],declared_filters:[512,4,1,""]},"evennia.web.api.filters.ObjectDBFilterSet.Meta":{fields:[512,4,1,""],model:[512,4,1,""]},"evennia.web.api.filters.PermissionFilter":{tag_type:[512,4,1,""]},"evennia.web.api.filters.ScriptDBFilterSet":{Meta:[512,1,1,""],base_filters:[512,4,1,""],declared_filters:[512,4,1,""]},"evennia.web.api.filters.ScriptDBFilterSet.Meta":{fields:[512,4,1,""],model:[512,4,1,""]},"evennia.web.api.filters.TagTypeFilter":{filter:[512,3,1,""],tag_type:[512,4,1,""]},"evennia.web.api.permissions":{EvenniaPermission:[513,1,1,""]},"evennia.web.api.permissions.EvenniaPermission":{MINIMUM_CREATE_PERMISSION:[513,4,1,""],MINIMUM_LIST_PERMISSION:[513,4,1,""],check_locks:[513,3,1,""],destroy_locks:[513,4,1,""],has_object_permission:[513,3,1,""],has_permission:[513,3,1,""],update_locks:[513,4,1,""],view_locks:[513,4,1,""]},"evennia.web.api.root":{APIRootRouter:[514,1,1,""],EvenniaAPIRoot:[514,1,1,""]},"evennia.web.api.root.APIRootRouter":{APIRootView:[514,4,1,""]},"evennia.web.api.serializers":{AccountListSerializer:[515,1,1,""],AccountSerializer:[515,1,1,""],AttributeSerializer:[515,1,1,""],HelpListSerializer:[515,1,1,""],HelpSerializer:[515,1,1,""],ObjectDBSerializer:[515,1,1,""],ObjectListSerializer:[515,1,1,""],ScriptDBSerializer:[515,1,1,""],ScriptListSerializer:[515,1,1,""],SimpleObjectDBSerializer:[515,1,1,""],TagSerializer:[515,1,1,""],TypeclassListSerializerMixin:[515,1,1,""],TypeclassSerializerMixin:[515,1,1,""]},"evennia.web.api.serializers.AccountListSerializer":{Meta:[515,1,1,""]},"evennia.web.api.serializers.AccountListSerializer.Meta":{fields:[515,4,1,""],model:[515,4,1,""],read_only_fields:[515,4,1,""]},"evennia.web.api.serializers.AccountSerializer":{Meta:[515,1,1,""],get_session_ids:[515,3,1,""]},"evennia.web.api.serializers.AccountSerializer.Meta":{fields:[515,4,1,""],model:[515,4,1,""],read_only_fields:[515,4,1,""]},"evennia.web.api.serializers.AttributeSerializer":{Meta:[515,1,1,""],get_value_display:[515,3,1,""]},"evennia.web.api.serializers.AttributeSerializer.Meta":{fields:[515,4,1,""],model:[515,4,1,""]},"evennia.web.api.serializers.HelpListSerializer":{Meta:[515,1,1,""]},"evennia.web.api.serializers.HelpListSerializer.Meta":{fields:[515,4,1,""],model:[515,4,1,""],read_only_fields:[515,4,1,""]},"evennia.web.api.serializers.HelpSerializer":{Meta:[515,1,1,""]},"evennia.web.api.serializers.HelpSerializer.Meta":{fields:[515,4,1,""],model:[515,4,1,""],read_only_fields:[515,4,1,""]},"evennia.web.api.serializers.ObjectDBSerializer":{Meta:[515,1,1,""],get_contents:[515,3,1,""],get_exits:[515,3,1,""]},"evennia.web.api.serializers.ObjectDBSerializer.Meta":{fields:[515,4,1,""],model:[515,4,1,""],read_only_fields:[515,4,1,""]},"evennia.web.api.serializers.ObjectListSerializer":{Meta:[515,1,1,""]},"evennia.web.api.serializers.ObjectListSerializer.Meta":{fields:[515,4,1,""],model:[515,4,1,""],read_only_fields:[515,4,1,""]},"evennia.web.api.serializers.ScriptDBSerializer":{Meta:[515,1,1,""]},"evennia.web.api.serializers.ScriptDBSerializer.Meta":{fields:[515,4,1,""],model:[515,4,1,""],read_only_fields:[515,4,1,""]},"evennia.web.api.serializers.ScriptListSerializer":{Meta:[515,1,1,""]},"evennia.web.api.serializers.ScriptListSerializer.Meta":{fields:[515,4,1,""],model:[515,4,1,""],read_only_fields:[515,4,1,""]},"evennia.web.api.serializers.SimpleObjectDBSerializer":{Meta:[515,1,1,""]},"evennia.web.api.serializers.SimpleObjectDBSerializer.Meta":{fields:[515,4,1,""],model:[515,4,1,""]},"evennia.web.api.serializers.TagSerializer":{Meta:[515,1,1,""]},"evennia.web.api.serializers.TagSerializer.Meta":{fields:[515,4,1,""],model:[515,4,1,""]},"evennia.web.api.serializers.TypeclassListSerializerMixin":{shared_fields:[515,4,1,""]},"evennia.web.api.serializers.TypeclassSerializerMixin":{get_aliases:[515,3,1,""],get_attributes:[515,3,1,""],get_nicks:[515,3,1,""],get_permissions:[515,3,1,""],get_tags:[515,3,1,""],shared_fields:[515,4,1,""]},"evennia.web.api.tests":{TestEvenniaRESTApi:[516,1,1,""]},"evennia.web.api.tests.TestEvenniaRESTApi":{client_class:[516,4,1,""],get_view_details:[516,3,1,""],maxDiff:[516,4,1,""],setUp:[516,3,1,""],tearDown:[516,3,1,""],test_create:[516,3,1,""],test_delete:[516,3,1,""],test_list:[516,3,1,""],test_retrieve:[516,3,1,""],test_set_attribute:[516,3,1,""],test_update:[516,3,1,""]},"evennia.web.api.views":{AccountDBViewSet:[518,1,1,""],CharacterViewSet:[518,1,1,""],ExitViewSet:[518,1,1,""],GeneralViewSetMixin:[518,1,1,""],HelpViewSet:[518,1,1,""],ObjectDBViewSet:[518,1,1,""],RoomViewSet:[518,1,1,""],ScriptDBViewSet:[518,1,1,""],TypeclassViewSetMixin:[518,1,1,""]},"evennia.web.api.views.AccountDBViewSet":{basename:[518,4,1,""],description:[518,4,1,""],detail:[518,4,1,""],filterset_class:[518,4,1,""],list_serializer_class:[518,4,1,""],name:[518,4,1,""],queryset:[518,4,1,""],serializer_class:[518,4,1,""],suffix:[518,4,1,""]},"evennia.web.api.views.CharacterViewSet":{basename:[518,4,1,""],description:[518,4,1,""],detail:[518,4,1,""],list_serializer_class:[518,4,1,""],name:[518,4,1,""],queryset:[518,4,1,""],suffix:[518,4,1,""]},"evennia.web.api.views.ExitViewSet":{basename:[518,4,1,""],description:[518,4,1,""],detail:[518,4,1,""],list_serializer_class:[518,4,1,""],name:[518,4,1,""],queryset:[518,4,1,""],suffix:[518,4,1,""]},"evennia.web.api.views.GeneralViewSetMixin":{get_serializer_class:[518,3,1,""]},"evennia.web.api.views.HelpViewSet":{basename:[518,4,1,""],description:[518,4,1,""],detail:[518,4,1,""],filterset_class:[518,4,1,""],list_serializer_class:[518,4,1,""],name:[518,4,1,""],queryset:[518,4,1,""],serializer_class:[518,4,1,""],suffix:[518,4,1,""]},"evennia.web.api.views.ObjectDBViewSet":{basename:[518,4,1,""],description:[518,4,1,""],detail:[518,4,1,""],filterset_class:[518,4,1,""],list_serializer_class:[518,4,1,""],name:[518,4,1,""],queryset:[518,4,1,""],serializer_class:[518,4,1,""],suffix:[518,4,1,""]},"evennia.web.api.views.RoomViewSet":{basename:[518,4,1,""],description:[518,4,1,""],detail:[518,4,1,""],list_serializer_class:[518,4,1,""],name:[518,4,1,""],queryset:[518,4,1,""],suffix:[518,4,1,""]},"evennia.web.api.views.ScriptDBViewSet":{basename:[518,4,1,""],description:[518,4,1,""],detail:[518,4,1,""],filterset_class:[518,4,1,""],list_serializer_class:[518,4,1,""],name:[518,4,1,""],queryset:[518,4,1,""],serializer_class:[518,4,1,""],suffix:[518,4,1,""]},"evennia.web.api.views.TypeclassViewSetMixin":{filter_backends:[518,4,1,""],permission_classes:[518,4,1,""],set_attribute:[518,3,1,""]},"evennia.web.templatetags":{addclass:[520,0,0,"-"]},"evennia.web.templatetags.addclass":{addclass:[520,5,1,""]},"evennia.web.utils":{adminsite:[523,0,0,"-"],backends:[524,0,0,"-"],general_context:[525,0,0,"-"],middleware:[526,0,0,"-"],tests:[527,0,0,"-"]},"evennia.web.utils.adminsite":{EvenniaAdminApp:[523,1,1,""],EvenniaAdminSite:[523,1,1,""]},"evennia.web.utils.adminsite.EvenniaAdminApp":{default_site:[523,4,1,""]},"evennia.web.utils.adminsite.EvenniaAdminSite":{app_order:[523,4,1,""],get_app_list:[523,3,1,""],site_header:[523,4,1,""]},"evennia.web.utils.backends":{CaseInsensitiveModelBackend:[524,1,1,""]},"evennia.web.utils.backends.CaseInsensitiveModelBackend":{authenticate:[524,3,1,""]},"evennia.web.utils.general_context":{general_context:[525,5,1,""],load_game_settings:[525,5,1,""]},"evennia.web.utils.middleware":{SharedLoginMiddleware:[526,1,1,""]},"evennia.web.utils.middleware.SharedLoginMiddleware":{__init__:[526,3,1,""],make_shared_login:[526,3,1,""]},"evennia.web.utils.tests":{TestGeneralContext:[527,1,1,""]},"evennia.web.utils.tests.TestGeneralContext":{maxDiff:[527,4,1,""],test_general_context:[527,3,1,""]},"evennia.web.webclient":{urls:[529,0,0,"-"],views:[530,0,0,"-"]},"evennia.web.webclient.views":{webclient:[530,5,1,""]},"evennia.web.website":{forms:[532,0,0,"-"],tests:[533,0,0,"-"],urls:[534,0,0,"-"],views:[535,0,0,"-"]},"evennia.web.website.forms":{AccountForm:[532,1,1,""],CharacterForm:[532,1,1,""],CharacterUpdateForm:[532,1,1,""],EvenniaForm:[532,1,1,""],ObjectForm:[532,1,1,""]},"evennia.web.website.forms.AccountForm":{Meta:[532,1,1,""],base_fields:[532,4,1,""],declared_fields:[532,4,1,""],media:[532,3,1,""]},"evennia.web.website.forms.AccountForm.Meta":{field_classes:[532,4,1,""],fields:[532,4,1,""],model:[532,4,1,""]},"evennia.web.website.forms.CharacterForm":{Meta:[532,1,1,""],base_fields:[532,4,1,""],declared_fields:[532,4,1,""],media:[532,3,1,""]},"evennia.web.website.forms.CharacterForm.Meta":{fields:[532,4,1,""],labels:[532,4,1,""],model:[532,4,1,""]},"evennia.web.website.forms.CharacterUpdateForm":{base_fields:[532,4,1,""],declared_fields:[532,4,1,""],media:[532,3,1,""]},"evennia.web.website.forms.EvenniaForm":{base_fields:[532,4,1,""],clean:[532,3,1,""],declared_fields:[532,4,1,""],media:[532,3,1,""]},"evennia.web.website.forms.ObjectForm":{Meta:[532,1,1,""],base_fields:[532,4,1,""],declared_fields:[532,4,1,""],media:[532,3,1,""]},"evennia.web.website.forms.ObjectForm.Meta":{fields:[532,4,1,""],labels:[532,4,1,""],model:[532,4,1,""]},"evennia.web.website.tests":{AdminTest:[533,1,1,""],ChannelDetailTest:[533,1,1,""],ChannelListTest:[533,1,1,""],CharacterCreateView:[533,1,1,""],CharacterDeleteView:[533,1,1,""],CharacterListView:[533,1,1,""],CharacterManageView:[533,1,1,""],CharacterPuppetView:[533,1,1,""],CharacterUpdateView:[533,1,1,""],EvenniaWebTest:[533,1,1,""],HelpDetailTest:[533,1,1,""],HelpListTest:[533,1,1,""],HelpLockedDetailTest:[533,1,1,""],IndexTest:[533,1,1,""],LoginTest:[533,1,1,""],LogoutTest:[533,1,1,""],PasswordResetTest:[533,1,1,""],RegisterTest:[533,1,1,""],WebclientTest:[533,1,1,""]},"evennia.web.website.tests.AdminTest":{unauthenticated_response:[533,4,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.ChannelDetailTest":{get_kwargs:[533,3,1,""],setUp:[533,3,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.ChannelListTest":{url_name:[533,4,1,""]},"evennia.web.website.tests.CharacterCreateView":{test_valid_access_multisession_0:[533,3,1,""],test_valid_access_multisession_2:[533,3,1,""],unauthenticated_response:[533,4,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.CharacterDeleteView":{get_kwargs:[533,3,1,""],test_invalid_access:[533,3,1,""],test_valid_access:[533,3,1,""],unauthenticated_response:[533,4,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.CharacterListView":{unauthenticated_response:[533,4,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.CharacterManageView":{unauthenticated_response:[533,4,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.CharacterPuppetView":{get_kwargs:[533,3,1,""],test_invalid_access:[533,3,1,""],unauthenticated_response:[533,4,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.CharacterUpdateView":{get_kwargs:[533,3,1,""],test_invalid_access:[533,3,1,""],test_valid_access:[533,3,1,""],unauthenticated_response:[533,4,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.EvenniaWebTest":{account_typeclass:[533,4,1,""],authenticated_response:[533,4,1,""],channel_typeclass:[533,4,1,""],character_typeclass:[533,4,1,""],exit_typeclass:[533,4,1,""],get_kwargs:[533,3,1,""],login:[533,3,1,""],object_typeclass:[533,4,1,""],room_typeclass:[533,4,1,""],script_typeclass:[533,4,1,""],setUp:[533,3,1,""],test_get:[533,3,1,""],test_get_authenticated:[533,3,1,""],test_valid_chars:[533,3,1,""],unauthenticated_response:[533,4,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.HelpDetailTest":{get_kwargs:[533,3,1,""],setUp:[533,3,1,""],test_object_cache:[533,3,1,""],test_view:[533,3,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.HelpListTest":{url_name:[533,4,1,""]},"evennia.web.website.tests.HelpLockedDetailTest":{get_kwargs:[533,3,1,""],setUp:[533,3,1,""],test_lock_with_perm:[533,3,1,""],test_locked_entry:[533,3,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.IndexTest":{url_name:[533,4,1,""]},"evennia.web.website.tests.LoginTest":{url_name:[533,4,1,""]},"evennia.web.website.tests.LogoutTest":{url_name:[533,4,1,""]},"evennia.web.website.tests.PasswordResetTest":{unauthenticated_response:[533,4,1,""],url_name:[533,4,1,""]},"evennia.web.website.tests.RegisterTest":{url_name:[533,4,1,""]},"evennia.web.website.tests.WebclientTest":{test_get:[533,3,1,""],test_get_disabled:[533,3,1,""],url_name:[533,4,1,""]},"evennia.web.website.views":{accounts:[536,0,0,"-"],channels:[537,0,0,"-"],characters:[538,0,0,"-"],errors:[539,0,0,"-"],help:[540,0,0,"-"],index:[541,0,0,"-"],mixins:[542,0,0,"-"],objects:[543,0,0,"-"]},"evennia.web.website.views.accounts":{AccountCreateView:[536,1,1,""],AccountMixin:[536,1,1,""]},"evennia.web.website.views.accounts.AccountCreateView":{form_valid:[536,3,1,""],success_url:[536,4,1,""],template_name:[536,4,1,""]},"evennia.web.website.views.accounts.AccountMixin":{form_class:[536,4,1,""],model:[536,4,1,""]},"evennia.web.website.views.channels":{ChannelDetailView:[537,1,1,""],ChannelListView:[537,1,1,""],ChannelMixin:[537,1,1,""]},"evennia.web.website.views.channels.ChannelDetailView":{attributes:[537,4,1,""],get_context_data:[537,3,1,""],get_object:[537,3,1,""],max_num_lines:[537,4,1,""],template_name:[537,4,1,""]},"evennia.web.website.views.channels.ChannelListView":{get_context_data:[537,3,1,""],max_popular:[537,4,1,""],page_title:[537,4,1,""],paginate_by:[537,4,1,""],template_name:[537,4,1,""]},"evennia.web.website.views.channels.ChannelMixin":{access_type:[537,4,1,""],get_queryset:[537,3,1,""],model:[537,4,1,""],page_title:[537,4,1,""]},"evennia.web.website.views.characters":{CharacterCreateView:[538,1,1,""],CharacterDeleteView:[538,1,1,""],CharacterDetailView:[538,1,1,""],CharacterListView:[538,1,1,""],CharacterManageView:[538,1,1,""],CharacterMixin:[538,1,1,""],CharacterPuppetView:[538,1,1,""],CharacterUpdateView:[538,1,1,""]},"evennia.web.website.views.characters.CharacterCreateView":{form_valid:[538,3,1,""],template_name:[538,4,1,""]},"evennia.web.website.views.characters.CharacterDetailView":{access_type:[538,4,1,""],attributes:[538,4,1,""],get_queryset:[538,3,1,""],template_name:[538,4,1,""]},"evennia.web.website.views.characters.CharacterListView":{access_type:[538,4,1,""],get_queryset:[538,3,1,""],page_title:[538,4,1,""],paginate_by:[538,4,1,""],template_name:[538,4,1,""]},"evennia.web.website.views.characters.CharacterManageView":{page_title:[538,4,1,""],paginate_by:[538,4,1,""],template_name:[538,4,1,""]},"evennia.web.website.views.characters.CharacterMixin":{form_class:[538,4,1,""],get_queryset:[538,3,1,""],model:[538,4,1,""],success_url:[538,4,1,""]},"evennia.web.website.views.characters.CharacterPuppetView":{get_redirect_url:[538,3,1,""]},"evennia.web.website.views.characters.CharacterUpdateView":{form_class:[538,4,1,""],template_name:[538,4,1,""]},"evennia.web.website.views.errors":{to_be_implemented:[539,5,1,""]},"evennia.web.website.views.help":{HelpDetailView:[540,1,1,""],HelpListView:[540,1,1,""],HelpMixin:[540,1,1,""],can_read_topic:[540,5,1,""],collect_topics:[540,5,1,""],get_help_category:[540,5,1,""],get_help_topic:[540,5,1,""]},"evennia.web.website.views.help.HelpDetailView":{get_context_data:[540,3,1,""],get_object:[540,3,1,""],page_title:[540,3,1,""],template_name:[540,4,1,""]},"evennia.web.website.views.help.HelpListView":{page_title:[540,4,1,""],paginate_by:[540,4,1,""],template_name:[540,4,1,""]},"evennia.web.website.views.help.HelpMixin":{get_queryset:[540,3,1,""],page_title:[540,4,1,""]},"evennia.web.website.views.index":{EvenniaIndexView:[541,1,1,""]},"evennia.web.website.views.index.EvenniaIndexView":{get_context_data:[541,3,1,""],template_name:[541,4,1,""]},"evennia.web.website.views.mixins":{EvenniaCreateView:[542,1,1,""],EvenniaDeleteView:[542,1,1,""],EvenniaDetailView:[542,1,1,""],EvenniaUpdateView:[542,1,1,""],TypeclassMixin:[542,1,1,""]},"evennia.web.website.views.mixins.EvenniaCreateView":{page_title:[542,3,1,""]},"evennia.web.website.views.mixins.EvenniaDeleteView":{page_title:[542,3,1,""]},"evennia.web.website.views.mixins.EvenniaDetailView":{page_title:[542,3,1,""]},"evennia.web.website.views.mixins.EvenniaUpdateView":{page_title:[542,3,1,""]},"evennia.web.website.views.mixins.TypeclassMixin":{typeclass:[542,3,1,""]},"evennia.web.website.views.objects":{ObjectCreateView:[543,1,1,""],ObjectDeleteView:[543,1,1,""],ObjectDetailView:[543,1,1,""],ObjectUpdateView:[543,1,1,""]},"evennia.web.website.views.objects.ObjectCreateView":{model:[543,4,1,""]},"evennia.web.website.views.objects.ObjectDeleteView":{"delete":[543,3,1,""],access_type:[543,4,1,""],model:[543,4,1,""],template_name:[543,4,1,""]},"evennia.web.website.views.objects.ObjectDetailView":{access_type:[543,4,1,""],attributes:[543,4,1,""],get_context_data:[543,3,1,""],get_object:[543,3,1,""],model:[543,4,1,""],template_name:[543,4,1,""]},"evennia.web.website.views.objects.ObjectUpdateView":{access_type:[543,4,1,""],form_valid:[543,3,1,""],get_initial:[543,3,1,""],get_success_url:[543,3,1,""],model:[543,4,1,""]},evennia:{accounts:[203,0,0,"-"],commands:[208,0,0,"-"],comms:[231,0,0,"-"],contrib:[235,0,0,"-"],help:[387,0,0,"-"],locks:[392,0,0,"-"],objects:[395,0,0,"-"],prototypes:[399,0,0,"-"],scripts:[404,0,0,"-"],server:[412,0,0,"-"],set_trace:[201,5,1,""],settings_default:[462,0,0,"-"],typeclasses:[463,0,0,"-"],utils:[468,0,0,"-"],web:[498,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","exception","Python exception"],"3":["py","method","Python method"],"4":["py","attribute","Python attribute"],"5":["py","function","Python function"],"6":["py","data","Python data"]},objtypes:{"0":"py:module","1":"py:class","2":"py:exception","3":"py:method","4":"py:attribute","5":"py:function","6":"py:data"},terms:{"000":[60,96,97,118,140,491],"0000":[96,97],"0004":76,"0005":[77,238],"001":[76,335,491],"002":491,"003":[151,491],"004":491,"005":[60,469,491],"006":491,"007":491,"008":491,"009":491,"010":[126,491],"011":491,"012":491,"013":491,"014":491,"015":491,"015public":126,"016":491,"017":491,"018":491,"019":491,"020":491,"020t":126,"021":491,"022":491,"023":491,"024":491,"0247":76,"025":491,"026":491,"027":491,"028":491,"029":491,"030":491,"030a":126,"031":491,"032":491,"033":[469,491],"034":[76,491],"035":491,"036":491,"037":491,"038":491,"039":491,"040":491,"040f":126,"041":491,"042":491,"043":491,"043thi":151,"044":491,"045":491,"046":491,"047":491,"048":491,"049":491,"050":[469,491],"050f":126,"051":491,"052":491,"053":491,"054":[60,491],"055":[469,491],"056":491,"057":491,"058":491,"059":491,"060":491,"061":491,"062":491,"063":491,"064":491,"065":491,"066":491,"067":491,"068":491,"069":491,"070":491,"071":491,"072":491,"073":491,"074":491,"075":491,"076":491,"077":491,"078":491,"079":491,"080":491,"081":491,"082":491,"083":491,"084":491,"085":491,"086":491,"087":491,"088":491,"089":491,"090":491,"091":491,"092":491,"093":491,"094":491,"095":491,"096":491,"097":491,"098":491,"099":491,"0b16":183,"0d0":133,"0th":13,"0x045a0990":3,"100":[5,20,48,86,92,94,112,133,141,157,162,170,228,276,308,311,312,335,343,346,353,354,380,491,492,537,538],"1000":[5,42,133,164,193,308,309,310,311,312,402],"10000":537,"1000000":[5,140,485],"100m":491,"100mb":191,"101":[20,398,491],"101m":491,"102":[112,354,491],"102m":491,"103":491,"103m":491,"104":491,"104m":491,"105":491,"105m":491,"106":491,"106m":491,"107":491,"107m":491,"108":491,"108m":491,"109":491,"1098":48,"109m":491,"10gold":157,"10m":187,"110":[112,354,469,477,491],"110m":491,"111":[55,60,216,491],"111m":491,"112":491,"112m":491,"113":[191,491],"113m":491,"114":491,"114m":491,"115":491,"115600":133,"115m":491,"116":491,"116m":491,"117":491,"117m":491,"118":[47,491],"1184":182,"118m":491,"119":491,"119m":491,"120":[20,491],"1200":475,"120m":491,"121":491,"121m":491,"122":491,"122m":491,"123":[11,84,104,178,398,479,491],"1234":[13,41,105,184,305],"123dark":139,"123m":491,"124":491,"12400":140,"124m":491,"125":[49,491],"125m":491,"126":491,"126m":491,"127":[53,75,154,181,182,183,185,187,191,198,436,491],"127m":491,"128":491,"128m":491,"129":491,"129m":491,"12s":19,"130":491,"130m":491,"131":491,"131m":491,"132":491,"132m":491,"133":491,"133m":491,"134":[55,216,491],"134m":491,"135":491,"135m":491,"136":491,"136m":491,"137":491,"137m":491,"138":491,"138m":491,"139":491,"139m":491,"140":[3,201,491],"1400":475,"140313967648552":22,"140m":491,"141":491,"141m":491,"142":[76,241,491],"142m":491,"143":491,"143m":491,"144":491,"144m":491,"145":491,"145m":491,"146":491,"146m":491,"147":491,"147m":491,"148":491,"148m":491,"149":491,"149m":491,"150":[474,491],"150m":491,"151":491,"151m":491,"152":491,"152m":491,"153":491,"153m":491,"154":491,"154m":491,"155":491,"155m":491,"156":491,"156m":491,"157":491,"1577865600":136,"157m":491,"158":491,"158m":491,"159":[147,491],"159m":491,"15th":95,"160":491,"160m":491,"161":491,"161m":491,"162":491,"162m":491,"163":491,"163m":491,"164":491,"164m":491,"165":491,"165m":491,"166":491,"166m":491,"167":491,"167m":491,"168":491,"168m":491,"169":491,"169m":491,"16m":491,"170":491,"170m":491,"171":491,"171m":491,"172":491,"172m":491,"173":491,"1730":180,"173m":491,"174":491,"174m":491,"175":491,"175m":491,"176":491,"1763":146,"1764":146,"176m":491,"177":491,"177m":491,"178":491,"178m":491,"179":491,"179m":491,"17m":491,"180":491,"180m":491,"181":491,"181m":491,"182":491,"182m":491,"183":491,"183m":491,"184":491,"184m":491,"185":491,"185m":491,"186":491,"186m":491,"187":491,"187m":491,"188":491,"188m":491,"189":491,"189m":491,"18m":491,"190":491,"1903":146,"190m":491,"191":491,"191m":491,"192":491,"192m":491,"193":491,"193m":491,"194":491,"194m":491,"195":491,"195m":491,"196":491,"196m":491,"197":491,"1970":136,"197m":491,"198":491,"198m":491,"199":491,"1996":180,"1998":180,"199m":491,"19m":491,"1_7":8,"1d100":[88,157,162,343],"1d2":133,"1d20":[88,157,343],"1d6":162,"1gb":191,"1st":[30,58,95,136,479,495,496,497],"200":[112,354,491,533],"2001":180,"2003":180,"2004":180,"2008":492,"200m":491,"201":491,"2010":491,"2011":[104,108,111,115,363,364,365,366,368,371],"2012":[77,79,80,81,88,89,91,104,249,251,282,283,315,316,342,343,356,358,359],"2014":[104,110,112,125,324,325,352,354],"2015":[64,93,104,106,115,183,295,296,348,349,350,361,368],"2016":[98,99,100,102,104,109,111,298,299,301,302,321,322,365,366],"2017":[6,78,83,84,87,94,95,101,104,107,113,114,116,117,136,191,243,244,246,247,268,270,285,286,307,308,309,310,311,312,327,329,345,346,376,377,381,382,384,386],"2018":[64,75,82,92,104,105,151,152,240,241,260,304,305,379,380],"2019":[64,90,91,100,104,180,272,315,316],"201m":491,"202":491,"2020":[55,64,77,86,104,112,136,237,238,291,292,352,354,369],"2020_01_29":485,"2020_01_29__1":485,"2020_01_29__2":485,"2021":[50,64,85,103,104,118,265,266,288,289,330,495,496,540],"2025":95,"202m":491,"203":[191,491],"203m":491,"204":491,"2048":187,"204m":491,"205":[475,491],"205m":491,"206":491,"206m":491,"207":491,"2076":146,"207m":491,"208":[142,491],"208m":491,"209":491,"2099":77,"209m":491,"20m":491,"210":491,"210m":491,"211":491,"211m":491,"212":[55,491],"2128":133,"212m":491,"213":[49,491],"213m":491,"214":[49,491],"214m":491,"215":491,"215m":491,"216":491,"216m":491,"217":491,"217m":491,"218":491,"218m":491,"219":[75,491],"219m":491,"21m":491,"220":491,"2207":[107,382],"220m":491,"221":[470,491],"221m":491,"222":[60,469,491],"222m":491,"223":[55,491],"223m":491,"224":491,"224m":491,"225":[55,491],"225m":491,"226":491,"226m":491,"227":491,"227m":491,"228":491,"228m":491,"229":491,"229m":491,"22m":[469,491],"22nd":492,"230":[60,491],"230m":491,"231":491,"231m":491,"232":491,"232m":491,"233":[55,216,479,491],"233m":491,"234":[84,104,244,491],"234m":491,"235":491,"235m":491,"236":491,"236m":491,"237":[55,491],"237m":491,"238":491,"238m":491,"239":491,"239m":491,"23fwsf23sdfw23wef23":5,"23m":491,"240":491,"240m":491,"241":491,"241m":491,"242":491,"2429":540,"242m":491,"243":491,"243m":491,"244":[42,491],"244m":491,"245":491,"245m":491,"246":491,"246m":491,"247":491,"247m":491,"248":491,"248m":491,"249":491,"249m":491,"24m":491,"250":491,"250m":491,"251":491,"251m":491,"252":491,"252m":491,"253":491,"253m":491,"254":491,"254m":491,"255":[183,469,491],"255m":491,"256":[55,60,215,469],"25m":491,"26m":491,"27m":491,"280":188,"28gmcp":440,"28m":491,"29m":491,"2d10":[88,104],"2d6":[88,135,157,343],"2gb":191,"2nd":[30,58,280,479,495,496,497],"2nd_person_pronoun":496,"2sgpre":497,"2xcoal":293,"300":[60,175,247,480],"3000000":140,"302":533,"30m":[469,491],"30s":[157,335],"31m":[469,491],"31st":136,"32bit":[183,185],"32m":[469,491],"32nd":135,"333":[55,60],"33m":[469,491],"340":133,"343":30,"34m":[469,491],"358":50,"358283996582031":5,"35m":[469,491],"360":136,"3600":[136,238],"36m":[469,491],"37m":[469,491],"3872":146,"38m":491,"39m":491,"3c3ccec30f037be174d3":492,"3d10":[88,343],"3d6":343,"3rd":[30,58,136,280,479,495,496,497],"3rd_person_pronoun":496,"3sgpast":495,"3sgpre":[495,497],"4000":[2,75,122,154,185,187,190,191,193,194,198],"4001":[2,49,50,51,52,53,73,75,124,137,154,167,177,178,181,185,187,190,191,193,194,198,445],"4002":[2,181,187,191,193],"4003":191,"4004":191,"4005":191,"4006":191,"403":11,"404":[53,137],"40m":[469,491],"41917":436,"41m":[469,491],"4201":191,"425":469,"42m":[469,491],"430000":136,"431":469,"43m":[469,491],"443":[181,187,194],"444":60,"44m":[469,491],"45m":[19,469,491],"46m":[469,491],"474a3b9f":40,"47m":[469,491],"48m":491,"49m":491,"4er43233fwefwfw":75,"4th":[118,120,180],"500":[53,60,118,175,337,469,540],"50000":140,"500red":469,"502916":8,"503435":8,"505":469,"50m":491,"50mb":191,"516106":133,"51m":491,"520":60,"5242880":238,"52m":491,"530":151,"53m":491,"543":[30,479],"5432":182,"54343":30,"5434343":479,"54m":491,"550":[469,475],"550n":126,"551e":126,"552w":126,"553b":126,"554i":126,"555":[60,107,382,469],"555e":126,"55m":491,"565000":136,"566":42,"56m":491,"577349":491,"57m":491,"58m":491,"593":492,"59m":491,"5d5":133,"5mb":[77,238],"5x5":170,"600":492,"60m":491,"61m":491,"624660":50,"62cb3a1a":40,"62m":491,"63m":491,"64m":491,"64x64":53,"65m":491,"6666":62,"6667":[180,189,205,223,457],"66m":491,"67m":491,"686":58,"68m":491,"69m":491,"6d6":133,"70982813835144":5,"70m":491,"71m":491,"72m":491,"73m":491,"74m":491,"75m":491,"760000":136,"76m":491,"775":2,"77m":491,"78m":491,"79m":491,"7a3d54":53,"8080":191,"80m":491,"8111":2,"81m":491,"82m":491,"83m":491,"84m":491,"85000":140,"85m":491,"86400":173,"86m":491,"87m":491,"8859":[16,70,230],"88m":491,"89m":491,"8f64fec2670c":191,"900":[92,380,475],"9000":532,"90m":491,"90s":493,"91m":491,"92m":491,"93m":491,"94608000":77,"94m":491,"95m":491,"96m":491,"97m":491,"981":[107,382],"98m":491,"990":475,"99999":156,"999999999999":338,"99m":491,"\u6d4b\u8bd5":126,"abstract":[67,114,118,123,147,157,275,312,464,465,466,483,486,492],"ansl\u00f6t":64,"boolean":[13,14,18,22,30,51,92,143,177,213,343,380,394,398,409,436,464,467,469,470,486,493],"break":[3,8,15,31,48,51,54,55,60,64,69,103,104,129,134,135,142,150,151,152,156,158,161,170,184,194,201,218,225,226,266,302,331,340,364,425,469,476,477,492],"byte":[16,19,30,70,416,418,425,427,436,444,492],"case":[3,8,9,11,13,14,15,16,18,19,20,22,28,31,32,33,37,39,41,44,45,48,49,50,51,52,53,54,55,60,62,64,65,67,68,69,70,76,77,85,90,95,96,106,118,119,120,123,125,126,127,128,131,132,135,136,137,139,140,142,143,144,145,146,147,148,149,150,151,152,153,155,156,159,161,164,165,170,173,174,177,180,181,182,193,194,198,199,204,205,206,210,212,213,215,218,224,225,226,232,233,238,239,241,258,283,286,289,292,293,316,331,338,340,343,350,351,353,364,372,378,380,382,388,389,390,393,394,396,398,402,406,408,421,425,429,433,447,454,457,464,465,466,467,469,471,479,483,489,490,492,496,500,524,545],"catch":[0,6,16,19,28,36,42,47,129,135,142,161,172,205,224,273,372,407,416,421,428,454,455,464,474,476,477,483,485,488,541],"char":[8,13,44,68,93,95,118,133,135,141,146,149,162,164,170,173,177,188,204,218,224,275,276,296,337,340,372,398,413,426,439,440,461,469,475,478],"class":[0,3,6,12,13,17,18,20,27,28,29,30,31,37,39,41,42,44,49,50,52,53,54,55,56,62,64,67,73,79,82,83,85,86,88,90,91,93,98,102,103,104,106,107,109,110,112,116,117,118,120,121,122,123,125,126,127,128,129,130,131,132,133,134,135,136,138,139,140,141,142,143,144,145,146,147,150,153,154,156,157,161,162,164,165,167,171,172,173,174,176,177,178,188,204,205,206,207,208,211,212,213,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,232,233,234,238,239,241,242,245,247,248,251,252,254,255,257,258,260,266,267,269,270,273,274,275,276,277,278,279,280,283,284,286,287,289,290,292,293,294,296,297,299,300,302,303,305,306,308,309,310,311,312,313,316,317,322,323,325,326,328,329,331,332,335,337,338,339,340,343,344,347,349,350,351,353,354,359,360,362,364,366,367,369,370,371,372,373,377,378,380,382,383,385,386,388,389,390,394,395,396,397,398,400,402,403,405,406,407,408,409,410,411,413,414,416,418,419,422,423,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,447,449,452,454,455,456,457,459,460,461,463,464,465,466,467,469,470,471,472,473,474,475,476,477,478,479,480,482,483,484,485,486,487,488,489,490,491,492,497,500,501,502,504,505,506,507,508,510,512,513,514,515,516,518,521,523,524,526,527,532,533,536,537,538,540,541,542,543,545],"const":270,"default":[2,3,5,6,7,8,9,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,27,28,31,35,36,37,39,41,42,44,45,46,48,49,50,52,54,55,56,57,60,61,62,63,64,65,67,68,70,71,72,73,74,75,76,77,78,79,82,83,84,85,86,87,89,90,91,92,93,94,95,96,97,99,100,102,103,104,106,110,112,113,114,116,117,120,121,122,123,124,125,128,130,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,151,152,153,154,157,158,159,161,164,165,167,169,170,171,172,174,175,177,178,181,182,185,186,187,188,189,190,191,193,194,195,198,201,202,204,205,207,208,209,210,211,212,213,232,233,234,238,241,244,247,251,255,257,258,266,270,273,275,276,277,278,280,283,286,289,292,296,299,302,305,308,309,310,311,312,316,322,325,328,329,331,334,337,338,339,340,343,346,349,350,353,354,362,364,366,370,372,376,377,378,380,386,387,388,389,390,391,392,394,396,398,402,403,406,407,409,410,411,414,416,418,420,421,422,426,438,439,440,445,447,448,454,455,456,457,461,462,464,465,466,467,469,471,472,474,476,477,478,479,482,483,485,486,487,488,489,490,492,493,500,512,518,523,524,532,538,540,541,542,543,544,545],"elsd\u00f6rfer":77,"export":[77,190],"final":[0,2,19,22,41,44,48,53,54,60,64,65,67,95,120,128,130,135,137,141,143,145,146,147,149,150,155,158,162,164,165,169,175,177,178,182,185,187,194,209,210,211,218,223,227,238,292,337,343,386,394,403,453,457,469,471,476,477,545],"float":[30,112,120,132,150,205,247,256,257,260,289,354,410,416,428,465,479,480,488,492],"function":[0,5,7,8,9,13,14,15,19,22,27,28,29,31,32,39,41,42,45,47,48,49,51,52,54,57,58,60,62,65,67,68,69,71,73,74,75,77,78,79,82,86,87,88,92,94,95,96,99,103,104,106,108,112,113,114,117,118,120,122,123,124,125,126,128,131,134,135,136,137,139,140,141,142,143,144,146,148,149,150,152,155,156,157,158,159,161,162,165,167,170,172,174,177,178,182,185,190,195,199,201,204,207,210,212,213,215,216,217,218,219,223,224,225,226,228,229,230,232,233,238,241,247,250,256,257,260,266,270,273,275,280,283,289,292,294,299,305,308,309,310,311,312,316,322,329,337,338,339,343,346,349,350,354,364,369,371,372,378,380,386,390,392,393,394,398,401,402,403,407,409,410,411,416,420,421,425,436,437,442,445,448,455,457,459,466,467,468,469,470,472,473,474,476,477,479,480,485,486,487,490,491,492,493,496,516,518,521,541,542,543,545],"g\u00e9n\u00e9ral":180,"goto":[118,141,331,369,476,545],"import":[1,3,5,6,7,8,10,12,13,14,15,16,18,19,20,22,27,28,29,30,31,32,33,34,35,37,39,42,44,45,46,47,48,49,50,51,53,54,56,57,58,62,64,65,67,70,73,74,75,76,79,82,83,84,85,86,87,88,90,91,92,93,94,95,96,97,98,99,102,103,104,106,109,110,112,113,116,117,119,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,139,141,142,143,145,146,148,149,150,153,156,158,159,161,162,164,165,167,169,170,171,172,173,174,175,176,177,178,184,185,188,189,191,194,195,199,201,212,218,228,238,241,244,245,247,260,266,270,280,283,286,289,292,299,302,308,309,310,311,312,316,322,325,329,343,346,349,350,353,354,364,371,372,380,382,386,389,394,402,403,411,416,420,428,429,450,454,457,458,464,466,470,471,474,475,476,477,478,479,489,490,492,523,543,545],"int":[13,20,28,30,32,42,48,92,112,116,118,126,130,132,133,135,141,142,149,151,165,178,204,205,206,210,211,213,233,238,247,254,256,257,260,270,280,283,286,289,308,309,310,311,312,337,338,340,343,346,350,354,380,386,391,396,398,403,405,408,410,411,413,414,416,421,425,426,427,428,430,434,435,436,444,445,447,457,459,461,464,465,469,472,474,475,476,477,478,479,480,483,485,489,492,495],"long":[0,8,11,13,16,18,19,22,28,29,31,33,36,44,47,48,54,62,67,69,70,72,73,75,76,95,96,104,106,115,117,118,120,123,126,128,131,132,135,136,139,141,143,144,146,149,151,152,158,159,161,162,170,172,174,175,177,179,180,182,188,189,191,215,225,251,257,270,283,293,305,311,325,338,425,430,445,469,470,477,478,479,492,495],"n\u00fa\u00f1ez":77,"new":[0,2,5,7,9,11,12,13,14,15,18,19,20,22,25,26,27,28,31,33,34,35,37,39,40,41,44,45,46,49,50,51,55,56,57,61,62,64,65,68,69,72,73,75,76,80,82,85,90,91,92,97,104,105,106,109,110,113,115,117,118,119,120,122,123,125,126,128,130,131,132,134,136,139,140,141,142,143,144,146,150,151,152,153,154,155,156,157,159,160,161,162,163,164,165,166,168,169,170,171,172,174,176,178,179,180,182,183,184,185,186,187,188,189,190,191,192,193,195,204,205,206,211,212,213,215,216,218,223,225,226,229,230,232,233,241,251,254,257,266,273,274,275,278,280,286,289,292,299,302,305,308,309,310,311,312,316,322,325,329,331,337,338,339,340,349,350,351,354,370,371,372,380,382,386,388,390,394,396,397,398,400,402,403,405,406,409,410,411,413,416,425,426,427,428,434,435,436,441,448,456,457,461,464,465,466,467,469,470,472,475,476,477,478,483,485,486,492,500,502,505,506,533,538,540,542,544,545],"null":[49,67,78,143,181,501,508],"public":[11,18,53,77,78,90,126,135,143,148,158,178,186,187,189,191,193,194,223,238,398,461,478,545],"return":[2,3,5,6,8,13,16,18,19,22,27,29,30,31,32,33,37,39,41,42,45,46,48,49,51,52,53,54,58,60,62,64,69,72,76,85,86,92,95,99,107,112,113,117,118,120,123,124,125,126,127,128,129,130,131,132,135,136,137,139,140,141,142,143,144,149,150,153,155,161,162,164,165,167,170,171,172,174,177,178,188,193,194,199,200,204,205,206,207,209,210,211,212,213,215,218,223,225,228,229,232,233,234,238,239,241,247,250,254,255,256,257,260,270,273,274,275,276,278,280,283,286,289,292,299,305,308,309,310,311,312,316,322,329,331,337,338,339,340,343,346,349,350,353,354,359,364,369,370,371,372,377,378,380,382,386,388,389,390,391,393,394,396,397,398,400,401,402,403,405,407,408,409,410,411,413,414,416,421,422,425,426,428,429,430,431,433,434,435,436,437,439,440,441,443,444,445,447,448,454,455,457,459,460,461,464,465,466,467,469,470,471,472,473,474,476,477,478,479,480,483,485,486,487,488,489,490,491,492,493,495,496,500,501,502,504,505,506,508,510,512,513,515,521,523,525,532,537,538,540,541,543,545],"short":[3,13,28,36,37,46,51,58,60,65,72,74,76,82,95,96,104,106,116,118,128,130,134,135,136,144,147,149,151,157,165,184,188,194,199,223,241,257,270,275,286,302,338,349,350,403,470,492,495],"static":[31,49,51,52,53,73,77,80,104,106,111,120,132,135,148,157,158,169,201,202,228,235,241,254,341,350,352,353,366,389,402,403,461,472,512,513,515,521,530,541,545],"super":[8,20,37,48,62,76,82,83,86,95,126,132,134,135,136,139,149,152,165,172,174,241,286,350,545],"switch":[11,12,14,15,18,20,22,27,31,39,48,54,56,57,60,68,72,75,80,95,96,97,98,99,102,104,126,135,139,140,144,164,165,174,175,182,186,189,191,192,198,215,216,217,218,223,224,225,226,228,230,233,266,275,278,299,302,305,309,316,331,343,364,406,466,472,477,493],"th\u00ed":144,"throw":[11,13,41,63,76,177,190,212,410,492],"true":[0,8,12,13,14,18,19,20,22,27,28,30,31,32,33,34,36,39,42,44,47,48,49,50,51,52,53,54,60,62,63,64,67,71,73,76,77,84,87,92,95,118,124,125,126,128,132,133,135,136,137,139,141,142,143,144,148,149,150,153,155,158,161,164,165,171,173,174,175,177,184,186,189,191,192,193,204,206,207,209,211,212,213,215,218,223,225,226,229,232,233,234,238,241,244,247,254,257,266,273,274,275,278,280,283,286,289,292,293,305,308,309,310,311,312,322,329,337,338,339,340,343,346,349,350,354,364,369,370,380,382,386,388,390,393,394,396,397,398,400,402,403,405,406,407,408,409,410,411,414,416,421,422,425,427,434,439,444,445,455,457,459,461,464,465,466,469,472,474,476,477,478,479,480,483,487,488,489,490,492,493,497,500,501,502,504,505,506,507,508,513,540],"try":[0,3,5,6,13,14,16,18,19,27,28,30,31,32,33,39,42,50,51,54,55,56,58,63,64,67,69,70,73,74,75,76,86,90,95,96,97,108,109,110,112,117,118,119,120,122,123,124,125,126,128,129,130,131,132,133,134,135,137,139,142,143,144,145,146,147,149,150,151,152,154,156,157,159,160,161,162,163,165,166,168,169,170,172,173,174,175,177,178,181,182,184,185,186,187,190,191,194,199,204,207,211,213,218,232,234,241,242,245,247,251,258,283,292,308,309,310,311,312,322,325,329,337,340,349,350,353,354,364,370,371,372,382,388,390,396,398,402,413,416,425,440,441,445,459,464,466,469,471,472,474,475,479,488,492,501,508],"var":[51,68,99,182,187,238,376,440,470],"void":133,"while":[5,11,13,14,15,18,20,22,25,27,28,30,35,39,42,49,51,54,58,60,64,65,67,69,72,75,76,77,92,95,97,105,106,115,117,118,119,120,122,126,127,128,132,133,134,135,136,142,144,145,147,148,149,151,152,155,156,157,158,161,164,169,170,172,174,177,178,182,185,187,190,191,194,199,204,215,218,225,226,229,238,258,283,292,305,309,312,329,337,340,350,364,370,372,380,382,398,402,403,409,440,463,464,466,476,478,479,490,492,493,501,508,541],AIs:180,AND:[13,33,39,92,146,162,218,380,394,464,467],ARE:28,AWS:[104,191,193,237,238,545],Adding:[1,11,21,22,39,41,69,91,134,138,140,141,148,151,157,158,161,164,188,225,316,337,476,545],Age:[92,380,532],And:[0,2,3,18,22,28,44,54,67,75,76,83,95,96,97,113,124,125,126,128,134,136,137,142,149,151,152,157,159,162,170,175,177,212,286,308,309,310,311,312,340,386,545],Are:[22,140,144,156,180,476,545],Aye:96,BGs:175,Being:[95,119,135,139,151,155,165],But:[0,3,8,13,14,16,18,19,20,22,28,31,39,41,42,45,48,54,58,60,65,67,76,79,90,95,97,112,118,119,120,122,123,125,126,127,128,130,131,134,136,137,140,141,142,143,144,146,148,149,150,151,152,153,156,158,159,161,162,166,170,175,177,178,184,187,189,193,195,211,212,283,340,354,402,467,542],DNS:[187,191],DOING:[92,380],DoS:[5,434],Doing:[11,22,42,122,128,133,143,162,178,212,215],For:[2,3,4,5,10,11,12,13,14,15,17,18,19,20,22,28,30,31,33,35,38,41,42,44,49,50,52,53,55,56,57,58,59,60,64,65,67,68,70,72,73,74,75,76,77,78,82,83,86,88,90,92,93,95,96,97,99,111,113,118,119,120,122,123,125,126,128,130,132,133,134,135,136,137,139,141,142,144,146,148,149,150,151,152,153,157,158,161,162,164,165,169,170,174,175,176,177,178,180,181,182,185,187,189,191,192,193,194,199,204,211,212,213,218,223,225,228,232,233,234,241,260,275,286,294,296,309,316,322,338,340,343,350,354,366,370,380,386,388,390,393,394,398,403,410,436,440,445,464,466,469,473,476,479,486,488,490,492,517,525,532,542],GMs:[135,157,158],Going:[116,158,159,270,545],Has:[183,308,309,310,311,312],His:[93,134,296],IDE:[7,120],IDEs:134,IDs:[97,177,178,193,256,464,492,515],INTO:[92,218,331,380],IOS:183,IPs:[55,182,194,376,459],IRE:[68,440],Its:[4,22,33,37,42,44,58,65,67,93,136,137,223,296,364,403,474,476,492],LTS:6,NOT:[13,22,33,51,115,126,146,191,194,218,338,394,403,459,479],Near:147,Not:[18,32,46,47,51,58,69,95,129,134,143,146,151,152,156,159,176,177,181,183,184,191,205,212,226,398,413,426,427,428,430,431,432,438,440,443,464,465,486,496],OBS:57,ONE:194,One:[2,9,10,28,30,33,36,42,44,47,55,58,76,79,88,90,95,96,97,104,112,113,120,123,126,128,132,134,135,137,142,143,144,146,149,151,152,153,158,161,165,171,174,175,176,180,181,182,185,199,201,207,209,225,275,283,289,292,337,338,340,343,349,354,370,371,386,396,402,403,426,454,464,465,469,470,476,477,479,492,501,508,540,545],PMs:545,Such:[8,14,22,28,50,95,123,127,134,156,158,162,218,403,469,476],THAT:142,THE:[92,380],THEN:[92,212,380],THERE:[92,380],TLS:[194,545],That:[0,3,4,5,11,16,20,22,30,32,39,41,42,44,46,47,48,54,74,75,76,79,82,85,89,95,96,97,112,113,118,122,123,124,125,126,130,132,134,136,137,142,143,144,146,147,149,150,151,155,157,158,161,162,167,169,170,178,192,241,251,266,283,289,338,354,386,394,403,457,476,517],The:[2,3,4,6,7,8,9,10,11,12,13,16,17,18,19,20,22,24,26,29,32,33,34,35,36,37,40,44,45,46,47,48,49,51,52,53,55,58,60,62,63,64,67,68,69,70,71,72,74,75,77,78,79,80,82,83,85,86,87,88,89,90,91,92,93,94,97,98,99,104,105,106,107,108,109,110,112,113,114,115,116,117,119,120,121,122,123,124,125,126,127,129,130,131,133,134,136,139,140,142,143,144,145,146,147,148,149,150,151,152,153,154,157,158,161,162,169,170,172,173,174,175,176,177,178,179,180,181,182,183,184,185,187,189,190,191,192,193,194,195,197,199,204,205,206,207,209,210,211,212,213,215,218,222,223,224,225,226,227,228,229,230,232,233,234,238,241,247,250,251,254,255,256,257,260,270,273,274,275,276,278,280,283,286,289,292,293,296,299,305,308,309,310,311,312,316,322,325,329,331,334,337,338,339,340,343,346,349,350,354,359,362,364,369,370,371,372,380,382,386,387,388,389,390,391,393,394,396,397,398,400,401,402,403,405,406,407,408,409,410,411,413,414,415,416,418,420,421,423,425,426,427,428,429,430,431,432,433,434,435,436,438,439,440,441,443,444,445,447,448,453,454,455,456,457,461,464,465,466,467,469,470,471,472,473,474,475,476,477,478,479,480,481,483,485,486,487,488,489,490,492,493,495,496,501,502,508,512,513,515,517,518,521,523,532,540,541,544,545],Their:[28,41,53,93,162,194,296],Theirs:[93,296],Then:[3,5,8,11,16,45,51,53,64,75,76,91,95,96,97,101,118,120,130,133,137,142,149,185,193,316,332],There:[0,5,6,8,9,13,14,15,16,18,19,20,22,28,30,31,37,39,42,44,45,46,48,49,50,53,54,57,58,60,67,68,69,70,76,77,80,90,91,92,95,96,97,112,113,117,118,120,123,125,126,132,134,135,136,137,139,141,142,143,144,145,146,148,150,151,153,156,157,158,159,161,162,164,165,169,170,171,172,174,177,180,181,182,187,189,191,192,194,195,226,292,308,309,310,311,312,316,329,337,354,380,386,403,411,421,440,457,469,470,476,479,544],These:[5,8,11,13,14,17,22,24,25,28,30,31,32,35,41,42,44,45,46,48,50,51,52,53,58,60,62,65,67,68,71,75,76,82,83,86,90,95,97,104,105,106,108,118,120,124,126,130,132,137,142,143,144,145,146,148,149,151,152,153,157,158,161,162,170,174,177,186,187,191,193,194,199,203,204,209,211,213,215,217,219,223,227,233,241,247,260,292,299,305,335,337,338,340,349,350,354,364,372,377,388,389,394,398,402,403,411,415,422,441,444,445,447,456,457,458,464,466,469,473,476,477,478,479,480,485,486,487,492,496,500,509,542],USING:292,Use:[5,8,11,12,14,15,20,28,30,31,35,37,41,44,48,51,55,58,60,75,76,79,81,89,98,99,100,107,108,111,118,120,124,126,135,137,144,150,151,152,155,164,165,181,182,183,184,185,186,187,191,193,198,204,210,215,216,218,223,224,225,228,230,232,241,242,247,251,270,273,283,292,299,302,305,309,310,311,312,333,350,366,382,388,396,397,398,416,418,422,427,444,445,447,451,464,466,469,475,476,478,479,483,489,492,505,545],Used:[22,174,209,212,218,230,302,329,336,337,340,380,386,396,397,409,418,436,464,466,477,478,490,492,500],Useful:[28,118,191],Uses:[218,230,251,370,376,416,464,478,483,545],Using:[1,4,19,28,33,35,39,47,58,61,71,76,86,96,104,108,122,135,136,142,146,149,150,151,152,154,158,160,163,165,166,168,174,197,201,202,235,270,309,341,350,352,364,398,436,463,476,545],VCS:2,VHS:[92,380],VPS:191,WILL:[142,183],WIS:135,WITH:[28,92,182,380],Was:223,Will:[20,32,107,118,144,156,199,204,223,247,278,280,292,340,350,382,398,401,403,414,416,425,426,466,476,478,479,480,487,492,545],With:[13,16,18,28,36,53,57,77,95,118,122,134,143,146,153,155,156,157,158,161,165,170,181,182,193,201,204,238,241,292,338,350,403,464,469,479],Yes:[22,92,95,380,474,476,545],__1:485,__2:485,_________________:48,_________________________:28,___________________________:113,______________________________:28,_______________________________:113,________________________________:28,_________________________________:48,______________________________________:476,_________________________________________:28,______________________________________________:28,_______________________________________________:28,____________________________________________________:28,_________________________________________________________:141,__________________________________________________________:141,_______________________________________________________________:113,________________________________________________________________:113,__all__:[500,502,504,505],__defaultclasspath__:466,__dict__:416,__doc__:[22,31,213,226,228,229,389,390,472,476],__example__:6,__ge:146,__ge__:6,__getitem__:469,__gt:146,__iendswith:146,__in:146,__init_:478,__init__:[4,6,13,45,48,62,82,119,121,132,147,148,149,152,167,211,212,213,234,238,241,254,270,278,283,289,292,336,337,338,350,354,382,388,394,397,398,402,407,408,410,411,413,414,416,418,419,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,443,444,445,447,454,455,457,459,460,461,464,466,467,469,471,474,475,476,477,478,479,485,486,487,488,492,500,501,505,508,523,526],__istartswith:146,__iter__:13,__le:146,__lt:146,__multimatch_command:227,__noinput_command:[211,227,241,474,476,477],__nomatch_command:[227,241,273,372,474,476,477],__packed_dbobj__:50,__pycache__:148,__settingsclasspath__:466,__str__:540,__unloggedin_look_command:[26,230,251],_action_thre:28,_action_two:28,_actual_myfunc_cal:28,_all_:211,_always_:[292,479],_and_:[479,492],_ask_again:28,_asynctest:[373,442],_attrs_to_sync:456,_attrtyp:464,_by_tag:19,_cach:466,_cached_cmdset:212,_call_or_get:241,_callable_no:476,_callable_y:476,_callback:[19,411],_char_index:469,_check_password:28,_check_usernam:28,_clean_nam:239,_clean_str:469,_cleanup_charact:164,_code_index:469,_compress_cont:239,_copi:[218,398],_create_charact:177,_creation:48,_dashlin:30,_data:477,_default:[28,476],_defend:28,_differ:469,_errorcmdset:212,_event:[95,260],_every_:292,_evmenu:476,_file:485,_flag:402,_footer:22,_format_diff_text_and_opt:403,_funcnam:492,_gambl:28,_get_a_random_goblin_nam:41,_get_db_hold:[455,466],_get_top:137,_getinput:476,_gettabl:421,_guaranteed_:479,_handle_answ:28,_helper:479,_http11clientfactori:418,_init:0,_init_charact:164,_is_fight:128,_is_in_mage_guild:28,_ital:120,_italic_:184,_last_puppet:[50,505],_linklen:338,_loadfunc:474,_magicrecip:293,_maptest:335,_menutre:[28,126,476],_mockobj:353,_monitor:421,_monitor_callback:34,_nicklist_cal:205,_npage:477,_oob_at_:483,_option:28,_os:238,_overrid:[51,73],_page_formatt:477,_pagin:477,_parsedfunc:479,_pending_request:461,_permission_hierarchi:393,_ping_cal:205,_playabel_charact:50,_playable_charact:[137,177,505],_postsav:483,_power_cal:30,_prefix:350,_process_cal:30,_quell:393,_quitfunc:474,_raw_str:469,_reactor_stop:[433,454],_read:354,_recog_obj2recog:350,_recog_obj2regex:350,_recog_ref2recog:350,_regex:350,_repeat:421,_safe_contents_upd:397,_savefunc:474,_saver:[13,473],_saverdict:[13,354,473],_saverlist:[13,473],_saverset:473,_sdesc:350,_select:28,_sensitive_:524,_session:476,_set:146,_set_attribut:28,_set_nam:28,_should:545,_skill_check:28,_some_other_monitor_callback:34,_start_delai:411,_static:120,_step:338,_stop_:492,_stop_serv:433,_swordsmithingbaserecip:293,_templat:120,_test:[30,209],_to_evt:477,_traithandlerbas:353,_transit_:340,_try_again:28,_typeclass:53,_uptim:30,_validate_fieldnam:135,_weight:338,_yes_no_quest:476,a2enmod:181,a8oc3d5b:193,a_off:283,aaaaaargh:151,aardwolf:68,abandon:273,abat:159,abbrevi:[60,64,218,293,302,479],abcd:224,abid:175,abil:[13,20,22,29,33,41,51,54,69,95,104,106,110,118,133,134,135,144,148,151,155,157,158,162,165,178,191,193,308,309,310,311,312,325,349,350,398,409,416,464,536],abl:[0,2,3,5,7,10,11,13,14,15,18,19,20,22,28,29,30,36,37,41,42,46,50,52,53,57,67,74,76,86,90,94,95,97,103,109,112,118,120,122,123,124,125,127,128,132,134,135,137,139,141,142,144,150,151,155,156,159,161,162,164,165,167,170,174,177,178,181,182,185,187,188,190,191,193,194,195,212,215,216,218,219,223,225,232,234,241,247,275,299,308,309,310,311,312,322,333,337,338,346,350,354,464,466,473,488,492,533,545],abort:[19,22,28,29,37,104,110,118,126,153,161,204,213,218,232,273,292,325,331,338,372,398,401,409,476,477,479,492,545],about:[0,2,3,5,6,11,13,14,15,16,17,20,22,26,28,30,31,35,38,41,46,49,50,53,54,55,56,60,65,67,69,70,73,75,76,78,82,85,95,96,97,104,119,120,122,123,125,126,129,130,131,134,137,138,139,141,142,143,144,145,146,147,148,149,151,154,155,156,159,160,161,162,163,164,165,166,167,168,169,172,173,175,178,179,180,182,183,184,185,188,190,191,193,194,195,197,199,204,218,225,228,238,241,273,275,276,283,286,289,292,310,311,312,335,337,343,366,371,372,390,398,416,418,421,430,432,434,443,445,447,448,455,457,465,467,469,477,483,492,501,508,515,545],abov:[0,2,7,8,11,12,13,14,15,19,20,22,27,28,30,31,32,33,34,41,42,44,46,48,49,51,52,53,54,55,58,62,64,67,73,74,75,77,82,86,90,94,95,96,98,99,106,107,112,118,119,120,123,124,125,127,128,129,131,132,133,134,135,136,137,139,141,142,144,146,148,149,150,151,152,153,154,157,161,164,165,170,172,174,176,177,181,182,183,185,187,191,193,199,211,212,218,241,280,292,299,308,310,311,312,325,331,337,343,346,350,354,366,380,382,386,394,396,398,421,476,479,487,501],above_str:30,abruptli:[112,354],absolut:[19,53,93,120,133,136,138,142,180,247,286,296,343,475,480,492],absorb:32,abspath:492,abstractus:207,abus:[78,194,545],academi:180,acccount:24,accecss:479,accept:[13,15,18,19,20,28,30,32,33,47,48,68,76,79,92,95,106,110,118,119,135,150,151,157,158,177,178,182,184,191,204,209,210,228,255,258,283,325,337,338,340,343,349,350,370,372,380,382,398,416,421,434,460,461,465,470,476,479,488,492],accept_callback:[255,257],access:[0,8,9,11,13,14,15,18,19,20,22,26,28,29,30,31,32,33,34,35,36,39,41,42,44,45,46,48,49,51,52,53,55,57,62,63,65,67,69,73,76,77,82,86,94,95,97,104,112,118,119,120,121,123,124,125,126,128,130,132,133,134,135,137,138,141,142,143,145,146,147,148,149,150,151,154,155,157,158,161,162,164,165,170,174,175,177,178,181,182,185,187,188,191,193,194,195,198,204,206,207,211,212,213,215,216,218,223,224,225,226,228,230,232,233,234,238,241,254,256,266,270,273,292,294,305,308,309,310,311,312,316,340,346,349,350,353,354,372,388,389,390,391,392,393,394,397,398,401,402,403,406,408,410,411,413,416,425,426,455,457,463,464,466,467,470,471,472,479,485,491,492,496,501,502,508,513,515,518,532,538,540,543,545],access_kei:238,access_key_nam:238,access_obj:[393,464],access_object:33,access_opt:493,access_token_kei:[173,188],access_token_secret:[173,188],access_typ:[37,204,213,218,232,234,388,390,393,394,398,464,466,537,538,543,545],accessed_obj:[33,126,161,174,393,394],accessing_obj:[13,33,126,161,174,204,232,234,388,390,393,394,398,464,466],accessing_object:[13,33,393],accessor:[207,234,390,397,406,464,466,467,484],accessori:185,accident:[16,20,58,118,120,158,165,216,218,293,455],accommod:124,accomod:478,accompani:165,accomplish:[55,115,122,126,132,156,158,161,479],accord:[20,22,106,146,158,164,170,175,241,280,286,309,337,349,382,410,469,470,479],accordingli:[7,132,135,191,270],account1:[8,533],account2:[8,533],account:[5,8,11,13,15,17,18,20,22,25,26,27,28,29,30,32,33,35,36,37,39,40,41,42,44,45,46,48,49,53,55,57,60,63,65,69,72,73,75,76,87,94,97,98,99,100,104,109,120,121,124,125,126,132,133,134,136,137,139,142,143,144,147,148,149,150,153,156,165,170,173,175,177,178,183,186,188,191,193,195,199,201,202,208,209,210,211,212,213,214,216,218,219,220,223,224,225,226,228,230,232,233,234,241,247,251,254,255,257,266,273,274,286,289,299,308,310,311,312,316,322,329,340,346,350,364,369,370,371,372,376,380,388,390,393,394,396,397,398,400,402,403,404,405,406,416,420,421,436,447,448,455,456,457,464,466,467,469,472,476,477,479,486,487,489,490,492,493,498,499,505,512,513,515,518,523,524,531,532,533,535,538,540,542,545],account_cal:[215,223,226,266,299],account_count:457,account_id:[177,398],account_nam:133,account_search:[206,350,398],account_subscription_set:207,account_typeclass:[490,533],accountadmin:[50,500],accountattributeinlin:500,accountchangeform:500,accountcmdset:[12,20,26,76,134,135,136,150,215,219,299,545],accountcreateview:536,accountcreationform:500,accountdb:[48,121,177,201,204,207,213,232,388,390,463,466,486,493,500,501,508,512],accountdb_db_attribut:500,accountdb_db_tag:500,accountdb_set:[464,467],accountdbfilterset:[512,518],accountdbmanag:[206,207],accountdbpasswordcheck:436,accountdbviewset:518,accountform:[532,536],accountid:177,accountlist:135,accountlistseri:[515,518],accountmanag:[204,206],accountmixin:536,accountnam:[135,218,230,233,251],accountseri:[515,518],accounttaginlin:500,accross:118,accru:204,acct:153,accur:[76,213,254,278,289,309,312,336,354,388,403,410,414,416,418,419,427,436,437,439,441,444,445,464,469,487,488,526],accuraci:[96,114,142,157,309,310,311],accus:162,accustom:36,acept:[92,380],achiev:[19,22,60,76,97,120,134,146,155,159,175,276,311,416],ack:29,acl:[77,238,239],acquaint:[134,159],acquir:471,across:[28,30,41,42,44,48,56,62,67,69,83,106,118,133,142,151,156,158,187,204,211,212,286,338,340,349,372,380,389,398,409,411,413,425,426,440,457,477,478,479],act:[5,12,14,18,20,28,42,44,52,61,92,95,112,113,118,128,132,133,135,146,151,156,158,165,170,181,182,199,201,204,218,223,234,250,275,276,332,337,338,339,340,354,355,380,386,413,425,426,445,464,467,471,476],action1:164,action2:164,action:[3,5,28,42,49,50,58,60,68,76,77,80,85,90,92,95,96,97,104,114,116,118,122,123,128,130,134,136,142,148,149,151,156,161,162,164,165,171,172,177,191,204,205,213,223,224,228,232,270,273,275,278,280,283,289,308,309,310,311,312,338,350,364,369,380,388,389,390,402,406,407,428,447,448,449,459,466,476,477,483,500,513,516,517,518,545],action_count:164,action_nam:[308,309,310,311,312],action_preposit:275,actiondict:164,actions_per_turn:[308,309,311,312],activ:[0,2,9,14,19,20,22,37,39,42,44,49,55,60,63,64,65,73,75,77,95,119,120,123,124,127,136,139,143,156,169,180,185,186,189,190,191,192,198,199,204,209,212,216,218,228,230,232,255,329,364,370,377,397,398,401,410,421,428,429,430,431,432,436,438,439,440,447,457,459,464,465,476,477,478,479,492,545],activest:491,actor:[30,312,398,479,495,545],actor_stance_cal:545,actual:[0,2,3,5,6,7,8,9,11,12,13,14,15,18,19,28,30,31,33,35,36,37,39,41,44,46,47,50,51,52,53,54,57,58,60,62,65,67,68,70,76,77,90,96,103,104,117,118,120,123,125,128,131,132,135,137,139,141,142,143,144,145,146,147,148,150,151,152,153,155,156,157,158,159,161,162,164,165,166,169,170,174,175,177,178,180,181,185,188,191,193,195,204,209,213,215,218,223,224,226,228,229,230,232,234,238,241,260,273,278,283,286,292,293,302,305,308,309,310,311,312,316,325,329,334,335,337,338,339,349,350,353,364,366,371,372,380,386,388,390,393,394,397,398,403,436,439,445,447,453,455,456,457,461,462,464,466,469,471,474,476,483,486,487,488,490,492,510,543,545],actual_return:8,ada:31,adam:77,adapt:[62,97,124,125,137,157,162,177,292],add:[0,2,3,5,7,8,9,10,11,12,13,14,15,16,17,18,20,22,25,26,27,28,30,31,32,33,34,35,36,37,39,41,42,44,46,47,48,49,50,51,54,56,57,60,62,63,64,67,68,70,73,74,75,76,79,81,82,83,84,85,86,88,89,90,91,93,95,96,97,98,99,100,102,103,104,105,106,109,110,112,113,114,116,118,119,120,122,123,125,128,129,130,131,132,134,135,136,137,138,139,140,141,142,143,144,146,148,149,150,151,152,153,154,156,157,158,159,161,162,164,165,170,171,172,173,174,176,177,178,179,180,181,183,184,186,187,188,191,192,193,195,201,204,207,211,212,218,223,224,225,227,229,232,234,241,242,244,247,251,254,255,257,258,260,266,270,273,275,280,283,286,289,292,299,302,305,308,309,310,311,312,316,322,325,331,332,333,334,337,338,339,343,349,350,353,354,359,364,369,370,371,372,376,386,393,394,397,398,402,403,406,407,408,409,410,411,416,421,422,426,429,430,432,434,438,445,447,448,450,458,464,467,470,474,475,476,477,478,479,483,485,487,488,490,500,505,512,518,540,543,545],add_:478,add_act:164,add_alia:223,add_argu:[116,270],add_callback:[255,257],add_charact:164,add_choic:[82,241,242,545],add_choice_:241,add_choice_edit:[76,82,241],add_choice_quit:[76,241],add_collumn:213,add_column:[135,478],add_condit:310,add_default:[20,125,141,161,174,212],add_dist:312,add_ev:257,add_fieldset:[500,505],add_form:[500,505],add_head:478,add_languag:[106,349],add_map:339,add_msg_bord:280,add_row:[135,140,213,478],add_user_channel_alia:[18,232],add_view:[500,502,505],add_xp:162,addcallback:[22,398],addclass:[51,201,202,498,519,545],addcom:[103,135,143,266],added:[2,3,7,9,11,17,19,20,22,31,33,41,42,46,49,62,67,68,69,76,77,83,84,93,95,97,106,108,112,114,117,118,119,120,124,125,126,134,135,137,142,143,146,148,149,150,151,152,157,161,162,164,165,170,171,174,176,177,179,183,186,190,193,199,204,209,211,212,213,223,227,228,230,241,244,254,257,260,283,286,289,292,293,296,308,309,310,311,312,329,333,337,338,343,349,350,354,364,388,394,398,401,403,408,410,421,455,459,464,467,470,476,477,478,485,492,518,525,536,540,544],addendum:119,adding:[2,5,6,7,8,9,13,15,17,19,20,25,26,28,33,41,46,47,48,51,53,60,62,64,67,69,75,76,86,87,90,92,95,96,97,98,112,113,114,118,120,125,128,134,135,136,137,138,139,141,142,146,150,151,152,158,164,165,167,174,175,177,195,211,212,216,218,225,241,247,254,257,270,292,299,308,309,310,311,331,346,349,350,354,372,380,386,396,398,402,403,408,416,447,464,472,478,492,501,508],addingservermxp:431,addit:[2,20,27,30,42,50,53,60,68,76,84,95,96,99,104,113,118,119,120,124,126,132,135,136,137,140,142,178,181,191,194,195,204,205,212,213,225,232,241,244,254,255,257,270,312,338,340,349,353,376,386,394,398,401,410,427,455,464,466,476,532,545],addition:[126,170,312],additionalcmdset:20,addpart:305,addquot:492,addr:[206,413,426,427,428,472],address:[11,22,36,44,55,58,62,73,75,89,93,104,132,142,167,182,187,191,194,204,206,216,232,251,296,398,413,426,428,436,456,459,492,493,545],address_and_port:436,addressing_styl:238,addresult:305,addscript:42,addservic:62,adjac:[99,118,312,370],adject:[6,58,161,479,496],adjoin:350,adjust:[22,97,119,157,175,177,185,238,346,410,476,478,479],admin:[0,12,13,16,18,22,33,39,52,53,55,57,67,75,78,125,132,135,137,141,148,149,156,158,165,174,177,178,189,192,199,201,202,206,207,208,213,214,218,223,228,230,232,251,266,273,280,370,388,390,394,397,398,425,426,466,472,488,498,523,545],admin_sit:[500,501,502,504,505,506,507,508],admin_wrapp:503,adminconfig:523,administr:[2,22,33,39,54,72,95,120,122,123,135,182,185,194,413,425,426,545],adminportal2serv:425,adminserver2port:425,adminsit:[50,201,202,498,522,545],adminstr:413,admintest:533,admit:130,admittedli:[118,155],adopt:[0,76,104,123,125,134,158,234,440,495],advanc:[5,14,20,22,28,30,41,44,48,53,54,55,62,67,69,76,77,99,104,106,108,112,115,122,123,127,130,131,135,138,146,151,154,158,165,170,180,195,218,226,308,309,310,311,312,316,350,354,364,382,431,470,474,475,476,478,545],advantag:[2,15,16,28,31,41,58,96,106,118,122,127,130,133,135,136,137,158,161,162,164,165,167,172,177,191,194,195,241,283,308,309,310,311,312,376,386,467,470],adventur:[86,104,105,115,148,155,158,170],advic:180,advis:[76,97,126],aesthet:27,affair:471,affect:[5,9,13,14,15,20,22,39,42,44,46,50,57,60,84,108,114,118,126,136,139,151,156,158,161,162,164,175,198,204,211,228,244,260,278,292,310,322,337,349,364,398,402,466,470,478,486],affili:410,affliat:410,afford:[44,141],afraid:191,after:[0,2,8,9,10,11,13,15,16,19,20,22,27,28,33,42,45,52,53,54,60,64,65,67,75,76,77,79,83,86,92,95,96,97,108,112,114,115,118,120,122,125,126,127,128,129,130,131,132,135,141,142,143,144,148,149,150,151,152,155,156,158,159,164,165,169,171,174,175,177,180,181,185,187,191,193,194,204,211,212,213,214,215,218,225,226,228,229,230,232,238,241,247,248,251,257,270,273,278,279,283,286,292,293,294,305,308,309,310,311,312,313,316,329,335,338,346,349,350,351,353,354,360,364,370,371,372,380,386,388,397,398,403,405,407,409,410,416,438,439,442,447,454,455,456,457,459,461,464,469,470,471,474,476,477,483,487,491,492,513,516,536,538,543],afterlif:158,afternoon:[91,316],afterward:[11,67,80,118,128,137,142,149,153,155,241],again:[3,7,9,13,14,15,18,22,28,35,42,44,52,55,60,67,76,85,90,95,97,104,107,108,115,117,118,123,125,127,128,130,132,133,134,135,136,137,139,141,142,143,144,147,149,150,151,152,154,156,158,161,162,164,165,170,174,175,177,182,184,185,187,191,192,193,198,199,205,212,223,229,247,257,289,308,311,312,329,364,382,409,416,433,436,439,459,469,470,473,488,490],againnneven:229,against:[11,13,20,22,48,64,65,95,114,119,125,134,135,146,155,157,164,191,194,204,210,211,293,308,309,310,311,312,350,394,396,398,402,403,434,459,464,466,467,489,492],age:[77,92,116,270,380,532],agenc:194,agent:2,agenta:[60,469],ages:[92,380],aggreg:180,aggress:[13,15,115,155,190,370,466,545],aggressive_pac:370,agi:[13,104,112,354],agil:13,agnost:[119,123],ago:[95,126,149,193,492],agre:[70,79,104,158,159,162,278,283],agree:283,ahead:[2,15,69,76,132,150,174,183,191,438],aid:[70,79,104,118,154,225,226,283,461],aim:[1,67,69,122,135,138,141,151,156,157,159,162,175,191,402],ain:96,ainnev:[104,112,146,162,354],air:[125,144,152,170],airport:153,ajax:[51,62,191,445,456],ajaxwebcli:445,ajaxwebclientsess:445,aka:[5,13,75,105,158,305,492],akin:149,alarm:[140,144],alchin:77,ale:99,alert:[18,232,398],alex:77,alexandrian:180,algebra:132,algorith:349,algorithm:[31,118,158,337,338,396,492],alia:[11,12,18,20,22,26,30,36,37,42,44,46,48,50,72,75,76,103,106,118,125,131,134,135,143,144,151,153,170,185,191,207,210,213,215,218,223,224,225,226,229,232,254,266,289,316,317,322,329,331,338,350,354,360,370,372,393,397,398,403,406,411,421,447,465,466,467,472,479,488,489,490,496,500,501,502,504,505,506,508,512,514,515,516,518,532,536,537,538,543,545],alias1:[218,316],alias2:[218,316],alias3:316,alias:[11,12,14,18,19,20,22,28,30,31,32,36,37,41,50,58,72,74,76,86,95,99,125,126,128,131,135,139,140,141,143,144,161,164,165,170,204,211,213,215,216,217,218,223,224,225,226,227,228,229,230,232,233,241,251,255,266,269,270,273,275,283,286,292,293,296,299,302,305,308,309,310,311,312,316,322,325,329,331,338,343,350,364,366,370,371,372,380,386,388,389,390,391,396,397,398,403,447,465,466,467,472,474,476,477,485,489,490,496,512,515,545],aliaschan:266,aliasdb:204,aliasfilt:512,aliashandl:[467,508,515],aliasnam:403,aliasstr:[396,472],align:[30,41,135,346,469,478,479,492],alist:6,aliv:[122,370],alkarouri:491,all:[0,2,5,6,7,8,9,11,12,13,14,15,16,17,18,19,20,22,25,27,28,30,31,32,33,35,36,37,39,41,42,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,62,64,65,67,68,69,70,71,72,73,74,75,76,77,78,80,82,86,88,90,91,92,96,97,103,104,105,106,107,109,112,113,115,117,118,119,120,121,122,123,125,127,128,129,130,131,132,133,134,135,136,139,140,141,142,143,144,145,146,147,148,150,151,152,153,154,155,156,157,159,161,162,163,164,165,166,167,169,170,171,172,174,175,176,177,178,179,180,181,182,184,185,189,190,191,192,193,194,195,198,199,204,205,206,208,209,210,211,212,213,214,215,216,217,218,219,220,223,224,225,226,227,228,229,230,232,233,234,241,251,254,257,266,269,270,273,275,276,278,279,283,286,289,292,293,296,299,302,305,308,309,310,311,312,316,322,325,329,331,337,338,339,340,343,349,350,353,354,362,364,366,369,370,371,372,377,380,382,386,388,389,390,391,392,393,394,395,396,397,398,401,402,403,405,407,408,409,410,411,412,415,416,420,421,422,425,427,428,430,432,433,434,435,436,439,440,443,444,445,447,448,454,455,456,457,459,461,462,463,464,465,466,467,469,470,471,472,473,474,475,476,477,478,479,483,485,487,489,490,491,492,493,495,497,500,501,502,504,505,506,508,509,510,518,521,523,525,532,538,540,541,543,544,545],all_alias:46,all_attr:466,all_book:153,all_cannon:146,all_cloth:13,all_cmd:225,all_connected_account:457,all_displai:411,all_famili:146,all_fantasy_book:153,all_flow:153,all_from_modul:492,all_kei:225,all_map:[118,339],all_opt:487,all_receiv:398,all_room:[14,146],all_ros:153,all_script:42,all_scripts_on_obj:42,all_sessions_portal_sync:457,all_to_categori:389,all_weapon:146,allcom:[103,143,266],allerror:[416,425],allevi:[8,13,69,461],allheadersreceiv:461,alli:312,alloc:191,allow:[0,2,3,6,7,8,11,12,13,14,15,16,19,20,22,28,30,31,32,33,35,36,37,39,40,41,46,48,49,50,51,52,53,54,55,56,57,58,64,67,69,70,71,72,73,75,76,77,78,79,82,86,87,90,91,92,93,95,96,97,99,102,104,106,112,113,114,117,118,120,121,122,123,124,125,128,129,130,131,132,134,135,138,139,141,142,144,146,148,149,150,151,152,153,156,157,161,162,164,165,167,170,174,175,177,178,179,181,182,184,185,186,187,188,189,190,191,192,193,194,195,204,205,207,209,211,212,213,215,216,217,218,223,225,226,228,229,232,233,234,241,247,257,266,270,273,275,278,280,283,286,292,294,296,302,308,309,310,311,312,316,329,337,338,340,343,349,350,353,354,364,370,371,372,380,382,386,388,390,391,393,394,396,398,402,403,407,410,411,416,420,421,423,427,429,430,431,432,439,440,441,443,448,454,455,457,459,460,464,466,467,469,470,472,474,476,477,478,479,480,483,486,487,488,490,492,503,505,512,513,518,532,537,540,545],allow_abort:476,allow_dupl:211,allow_extra_properti:354,allow_nan:445,allow_quit:476,allow_reus:292,allowed_attr:135,allowed_fieldnam:135,allowed_host:[191,194],allowed_propnam:165,allowedmethod:445,allowext:461,almost:[13,22,31,47,48,50,57,82,83,151,152,241,286,418,425,463],alon:[8,11,14,28,33,36,67,90,104,115,128,132,133,135,151,159,162,164,211,225,340,411,421,447,470,472,478,479,508],alone_suffix:452,along:[5,22,28,32,42,45,55,60,68,78,79,80,95,99,106,112,113,115,118,123,142,146,147,151,155,156,159,161,163,174,179,195,204,215,283,311,338,343,349,354,376,386,394,398,445,463,518],alongsid:[92,187,339,380],alonw:406,alpha:[184,191,469,545],alphabet:[16,70,170,469,544],alreadi:[0,7,8,9,11,12,13,14,16,19,20,22,27,28,30,31,33,37,42,44,46,48,51,53,62,68,73,75,76,78,90,95,96,97,115,118,119,120,123,125,126,128,132,133,134,135,137,139,140,141,142,143,144,145,148,149,150,151,152,153,154,156,159,161,162,164,165,169,171,172,173,174,177,178,184,185,189,193,194,199,204,206,211,212,215,218,226,228,232,233,266,275,280,283,286,289,292,293,308,309,310,311,312,329,337,338,340,349,350,354,370,371,382,394,398,402,403,416,425,433,434,436,441,444,449,454,455,457,464,467,469,472,477,485,490,492,513,524],alredi:62,alright:[79,283],also:[0,1,2,3,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,25,27,28,30,31,32,33,34,36,37,39,41,42,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,60,62,63,64,65,67,68,69,70,72,73,74,75,76,77,79,83,85,86,88,89,90,91,92,94,95,96,97,100,102,104,106,107,110,112,113,115,117,118,119,120,121,122,123,125,126,127,128,129,130,131,132,133,134,135,136,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,159,161,162,163,164,165,166,167,168,169,170,171,172,174,175,176,177,178,180,181,182,183,184,185,186,187,189,190,191,192,193,194,195,198,199,204,206,207,210,211,212,213,215,216,217,218,220,223,224,225,226,228,229,232,233,234,241,257,275,276,280,283,286,289,292,293,299,302,310,311,312,316,325,329,331,337,338,340,343,346,349,350,354,364,370,371,372,380,382,386,388,392,393,394,396,397,398,402,403,404,406,409,411,412,416,420,421,425,427,434,436,439,440,443,444,447,448,457,461,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,483,489,490,492,512,538,540,541,543,545],alt:469,alter:[51,95,97,123,124,170,182,464],altern:[13,18,22,28,31,36,42,46,50,60,64,74,86,104,105,112,116,120,123,128,134,139,143,154,161,170,172,177,182,185,189,191,197,223,226,232,233,250,305,312,350,354,364,389,393,394,396,434,469,472,492,545],although:[3,76,95,128,130,152,185,215,241,343,461,488,492],althougn:96,altogeth:[27,60,118,194],alwai:[4,8,9,12,13,14,15,18,19,20,22,28,30,31,32,33,35,37,39,41,42,44,45,46,47,48,51,55,58,60,67,68,73,86,95,97,98,106,109,112,118,119,120,123,124,125,126,129,130,132,134,135,136,137,141,142,143,144,149,150,151,152,153,154,156,158,161,162,165,174,175,178,181,182,185,189,191,204,211,212,213,215,217,218,223,225,226,229,232,233,234,273,278,292,294,299,322,337,338,340,349,350,354,364,391,393,394,396,397,398,402,403,411,416,418,421,425,433,436,439,440,444,445,448,455,457,462,464,465,466,467,469,472,479,483,488,489,492,493,513,525,541],always_pag:477,always_return:416,amaz:190,amazon:[77,104,180,191,238],amazonaw:77,amazons3:77,ambianc:69,ambigu:[93,118,213,296,338,398,466],ambiti:[69,72],amend:11,amfl:15,ammo:125,among:[2,12,25,37,123,136,153,159,165,170,180,195,224,286,371,394,396,478,489],amongst:99,amor:258,amount:[18,42,56,60,156,157,162,165,194,228,289,293,308,309,310,311,312,398,457,474,545],amp:[40,44,62,65,201,202,412,413,416,424,426,434,442,454,457,545],amp_client:[201,202,412,545],amp_maxlen:442,amp_port:191,amp_serv:[201,202,412,424,545],ampclientfactori:413,ampersand:69,amphack:425,ampl:151,amplauncherprotocol:416,ampmulticonnectionprotocol:[413,425,426],ampprotocol:413,ampserverclientprotocol:413,ampserverfactori:426,ampserverprotocol:426,amsterdam:191,amus:143,anaconda:75,analog:[65,132],analys:28,analysi:377,analyz:[16,22,28,33,86,115,158,172,209,225,292,350,398,402,403,407,416,477,492,495,545],anchor:[213,232,312,388,390,466],anchor_obj:312,ancient:[60,99],andr:183,andrei:77,andrew:77,android:[197,545],anew:[150,151,170,185,232,416],angelica:157,angl:[72,118,275],angri:31,angular:228,ani:[2,3,6,8,9,11,12,13,15,16,18,19,20,22,27,28,30,31,32,33,34,35,36,37,39,41,42,44,45,46,47,48,49,51,54,55,56,57,60,62,64,65,67,68,72,73,74,76,77,78,82,83,85,86,88,89,90,92,94,95,97,102,104,106,112,114,115,116,117,118,119,120,123,125,126,129,130,131,132,133,134,135,139,140,141,142,143,144,145,146,148,149,150,151,152,153,155,157,158,159,160,161,162,164,165,169,171,172,174,175,177,178,180,181,182,183,184,185,186,189,191,192,193,194,195,198,204,207,209,210,211,212,213,215,216,218,224,225,228,229,232,233,234,241,251,256,270,273,275,278,280,283,286,289,292,296,299,302,308,309,310,311,312,316,325,329,337,338,340,346,349,350,354,359,362,364,370,372,376,377,380,382,388,391,393,394,396,398,401,402,403,406,407,409,410,411,413,414,416,418,420,421,425,426,428,434,435,436,439,440,444,445,447,455,456,457,461,464,465,466,467,469,470,471,473,474,475,476,477,478,479,485,486,487,488,489,491,492,500,510,517,518,523,536,537,538,540,541,542,543,545],anim:[19,29,52,293],anna:[58,135,165,171,172,185,189,218],anna_object:58,annoi:[55,90,141,142,143,152,158],annot:[180,545],announc:[9,126,164,165,180,216,223,228,232,308,309,310,311,312,398],announce_al:[434,457],announce_move_from:[37,126,398],announce_move_to:[37,126,398],annoy:204,annoyinguser123:18,anonym:[63,124,137,350],anonymous_add:350,anoth:[2,3,5,6,7,8,13,14,15,20,22,28,31,33,37,41,44,46,49,51,54,56,58,60,69,70,74,76,86,90,92,95,96,97,107,113,117,118,119,123,125,128,130,132,133,134,135,136,137,142,143,144,146,148,151,152,154,157,158,161,164,165,169,170,174,176,179,181,185,187,191,192,204,211,212,215,218,223,224,232,241,256,275,278,283,286,292,299,308,309,310,311,312,329,331,336,338,350,371,380,382,386,388,390,391,398,401,457,464,466,470,474,476,477,479,490,492,518,545],another_batch_fil:470,another_nod:476,another_script:42,anotherusernam:49,ansi:[32,51,71,84,121,139,151,183,201,202,215,244,245,302,346,421,428,436,439,444,445,468,478,479,491,492,545],ansi_escap:469,ansi_map:469,ansi_map_dict:469,ansi_pars:469,ansi_r:469,ansi_regex:469,ansi_sub:469,ansi_xterm256_bright_bg_map:469,ansi_xterm256_bright_bg_map_dict:469,ansimatch:469,ansimeta:469,ansipars:469,ansistr:[201,469,478],ansitextwrapp:478,answer:[0,8,13,22,28,96,97,125,126,137,151,156,158,159,161,162,185,187,194,414,476],ant:95,antechamb:115,anthoni:77,anti:185,anticip:118,anul:181,anvil:[292,293],anwer:131,any_options_her:120,anybodi:194,anymor:[107,124,161,257,305,329,382,476,488],anyon:[3,33,55,64,90,124,125,126,128,135,141,158,164,165,172,184,191],anyth:[0,3,7,9,11,13,14,18,20,22,28,33,36,37,42,48,50,51,53,56,57,62,65,73,76,77,82,90,96,97,99,113,118,119,123,128,132,133,137,140,141,142,143,144,148,149,151,152,153,156,158,159,161,164,165,169,170,172,174,177,182,185,191,193,195,198,211,213,227,241,308,309,310,311,312,337,350,354,386,394,428,462,464,470,476,479],anytim:158,anywai:[15,18,28,60,69,74,89,97,118,122,124,142,144,161,190,251,283,337],anywher:[22,28,42,48,118,123,149,151,154,161,178,337,474],apach:[77,182,191,194,197,461,545],apache2:181,apache_wsgi:181,apart:[12,13,19,33,48,104,115,122,139,175,178,185,193,195,312,331],api:[0,3,8,13,14,16,18,19,24,29,31,35,37,41,42,44,48,52,58,80,86,149,153,155,162,170,173,177,188,201,202,204,217,228,230,234,251,292,388,455,464,466,470,471,477,498,544,545],api_kei:188,api_secret:188,apicli:516,apirootrout:514,apirootview:514,apocalyps:158,apostroph:16,app:[33,53,62,64,67,73,77,124,169,178,188,191,523,545],app_id:177,app_modul:523,app_nam:523,app_ord:523,appar:[95,135,175],apparit:372,appeal:[28,60],appear:[0,7,11,18,19,28,31,33,41,42,50,51,53,54,59,60,63,75,76,83,99,109,118,120,125,126,129,140,143,146,151,155,156,165,170,175,185,186,189,191,193,195,201,215,225,245,257,286,293,322,329,338,350,398,440,441,466,478,485,508,545],appearance_templ:398,append:[5,6,19,20,27,33,37,62,68,76,78,83,104,126,130,132,137,141,142,146,164,165,177,187,191,213,218,225,286,299,350,394,396,449,470,485,492],appendto:51,appform:177,appl:[79,275,283,398],appli:[2,7,9,14,20,22,30,31,33,41,47,48,53,56,65,75,76,80,84,95,97,104,112,118,119,139,150,158,159,163,170,174,175,177,181,182,204,209,211,226,244,273,275,308,309,310,311,312,329,337,338,353,354,394,398,402,403,406,411,457,464,465,466,469,470,475,478,480,489,492],applic:[9,33,46,49,62,67,73,91,147,169,177,178,180,181,185,193,194,204,238,275,292,312,316,380,416,419,429,433,454,455,461,529],applicationdatareceiv:439,applied_d:177,apply_damag:[308,309,310,311,312],apply_turn_condit:310,appnam:[13,33],appreci:[8,11,42,76,119,179,483],approach:[7,28,47,76,82,104,126,130,133,142,158,177,241,312,338],appropri:[2,7,20,22,58,72,75,94,95,104,142,174,177,181,182,188,204,216,275,346,416,455,486,488,492,521],approrpri:62,approv:[11,95,177,178],approxim:[228,492],apr:64,april:[90,104,136],apt:[11,181,185,187,190,191,194],arbitrari:[6,13,14,19,30,33,48,51,57,74,95,96,112,113,118,123,149,170,193,204,232,273,277,289,312,316,354,362,372,386,398,403,409,414,425,445,459,464,473,485,488,492,545],arcan:72,arcanist:158,arch:61,archer:403,archetyp:158,architectur:[33,159,403],archiv:[148,180,194],archwizard:403,area:[12,76,104,115,117,118,132,135,155,156,159,171,180,183,329,331,337,340,370,393,475,476,478,492,545],aren:[11,92,97,124,128,130,137,169,177,194,204,257,286,305,310,380,485,488,495],arg1:[33,213,226,229,232,273,464],arg2:[213,226,229,273,464],arg:[3,22,28,30,31,32,33,35,41,47,51,54,62,65,68,71,72,76,95,112,120,125,126,128,129,130,135,139,141,143,148,150,161,162,164,165,174,176,188,204,205,206,207,210,213,218,226,227,228,229,232,233,234,238,247,254,257,270,273,275,276,283,286,289,296,305,308,309,310,311,312,316,322,325,329,333,338,339,340,349,350,354,359,362,364,366,370,371,372,382,386,389,390,391,393,394,396,397,398,401,402,403,405,406,409,410,411,413,416,421,422,423,425,426,427,428,433,434,436,437,439,440,441,444,445,449,455,457,459,461,464,465,466,467,469,476,478,479,480,482,483,485,488,490,492,493,500,501,505,508,514,515,532,538,543,545],arg_regex:[131,213,218,224,225,228,229,230,273,286,292,350,474,476,545],arglist:226,argn:464,argpars:[116,270],argtyp:492,argu:13,arguabl:[118,151,157],argument:[0,3,5,8,13,15,18,19,20,22,27,29,30,32,33,36,37,41,42,47,48,54,55,58,62,65,68,72,76,78,82,90,92,95,96,99,104,107,116,124,125,126,128,134,135,136,137,139,141,143,144,145,146,152,161,165,167,170,178,182,204,205,206,209,210,212,213,215,216,218,223,224,225,226,228,229,232,233,238,241,247,250,254,256,257,266,270,273,275,277,278,280,286,292,296,308,309,310,311,312,316,322,331,339,340,346,349,350,362,372,377,380,382,394,396,398,402,403,405,407,409,410,411,414,416,421,425,427,428,434,435,436,439,440,444,445,447,448,455,456,457,459,460,464,465,466,467,469,470,472,474,475,476,477,478,479,483,486,488,489,492,518,541,545],argumentpars:[104,116,270],argumnet:478,aribtrarili:492,ariel:77,aris:194,arithmet:[13,30,112,354],arm:[0,22,105,305,545],armchair:161,armi:141,armor:[13,83,114,128,140,157,163,286,309],armour:128,armpuzzl:[105,305],armscii:[16,70],arn:77,arnold:36,around:[3,14,15,16,20,30,33,37,41,52,53,54,60,70,72,83,90,95,97,118,120,122,123,124,125,128,130,132,135,137,141,142,143,146,148,149,150,151,152,153,156,157,158,161,162,164,165,169,170,171,174,180,182,185,188,191,218,226,247,256,286,293,305,312,329,335,338,350,364,370,371,372,398,469,470,478,485,545],arrai:[49,68,142,338,440,492],arrang:76,arrayclos:[68,440],arrayopen:[68,440],arrest:118,arriv:[44,65,95,97,126,128,162,218,276,331,428],arrow:[3,51,118,151],art:[60,475],articl:[8,11,16,70,124,125,130,134,180,484],article_set:484,artifact:478,artifici:[158,162],artsi:159,arx:[180,197,545],arxcod:[180,197,545],as_view:[53,213,232,388,390,466],ascii:[16,70,75,99,104,118,170,204,230,337,475,478,492,545],asciiusernamevalid:204,asdf:218,ash:293,ashlei:[83,92,94,104,113,114,285,286,307,308,309,310,311,312,345,346,379,380,384,386],asian:492,asid:75,ask:[0,3,5,6,11,27,31,34,54,58,89,95,96,100,104,118,119,125,135,137,142,144,149,150,156,158,159,161,162,177,182,184,185,191,211,213,218,247,255,270,283,382,414,416,443,476,480,492,545],ask_again:28,ask_choic:414,ask_continu:414,ask_input:414,ask_nod:414,ask_yes_no:476,ask_yesno:414,askew:157,asn:376,aspect:[28,41,53,67,123,134,148,151,162,292,346],assert:[8,164,479],assertequ:8,assertionerror:[479,490],asset:[77,169,194,238,420,521,545],assetown:75,assign:[2,6,12,13,14,18,28,33,36,37,39,41,42,46,47,51,55,84,92,104,106,115,118,133,135,144,148,149,150,151,153,161,164,165,174,204,209,210,212,218,223,225,226,244,273,308,309,310,311,312,316,350,354,372,380,394,397,398,402,403,421,428,434,436,439,455,473,490,545],assist:191,associ:[13,28,44,65,73,124,128,143,149,153,180,191,204,208,218,232,254,257,350,398,455,457,465,538],assort:545,assum:[6,7,8,9,11,13,14,15,16,18,19,20,22,28,31,32,33,34,37,41,42,44,47,55,57,58,62,69,70,75,76,85,86,90,95,96,97,106,110,112,118,119,120,122,125,126,127,128,130,131,132,133,135,136,139,140,141,144,146,148,153,159,162,164,165,167,170,171,172,173,174,176,177,178,187,190,191,193,194,199,209,211,212,213,215,218,223,225,229,232,234,241,273,275,289,293,325,339,340,350,354,371,372,388,393,398,403,407,440,457,469,470,476,479,492,496,513,524,540,543],assumpt:[161,210],assur:[48,78,104,132],ast:[30,479],asterisk:[12,55,120,150,216],astronom:136,async:[177,492,545],asynccommand:54,asynchron:[5,19,22,40,61,85,104,123,127,128,205,289,398,425,426,440,485,492,545],at_:[48,483],at_access:[204,398],at_account_cr:[12,204],at_after_mov:398,at_after_travers:398,at_again_posit:275,at_already_clos:275,at_already_consum:275,at_already_mov:275,at_already_open:275,at_appli:275,at_before_drop:398,at_before_g:398,at_before_get:398,at_before_mov:398,at_before_sai:398,at_cannot_appli:275,at_cannot_mov:275,at_cannot_posit:275,at_cannot_read:275,at_cannot_rot:275,at_channel_cr:232,at_channel_msg:232,at_char_ent:171,at_clos:275,at_cmdset_cr:[20,22,76,82,83,91,95,102,103,106,109,110,125,126,129,131,134,135,136,139,141,143,150,161,164,165,174,211,219,220,221,222,241,266,273,283,286,292,299,302,305,308,309,310,311,312,316,322,325,331,343,350,364,366,369,370,371,372,447,474,476,477,545],at_cmdset_createion:266,at_cmdset_get:[204,398,455],at_code_correct:275,at_code_incorrect:275,at_consum:275,at_db_location_postsav:397,at_defeat:[308,309,310,311,312],at_desc:398,at_disconnect:[204,455],at_drink:275,at_drop:[309,312,398],at_empty_target:338,at_end:406,at_err:[54,492],at_err_funct:54,at_err_kwarg:[54,492],at_failed_login:204,at_failed_travers:[37,322,371,398],at_first_login:204,at_first_sav:[204,232,398],at_first_start:466,at_focu:275,at_focus_:[273,275],at_focus_climb:275,at_focus_clos:275,at_focus_cod:275,at_focus_combin:275,at_focus_drink:275,at_focus_eat:275,at_focus_feel:275,at_focus_insert:275,at_focus_kneel:275,at_focus_li:275,at_focus_listen:275,at_focus_mov:275,at_focus_open:275,at_focus_press:275,at_focus_push:275,at_focus_read:275,at_focus_rot:275,at_focus_shov:275,at_focus_sip:275,at_focus_sit:275,at_focus_smel:275,at_focus_turn:275,at_focus_us:275,at_get:[95,286,312,398],at_giv:[309,312,398],at_green_button:275,at_heard_sai:172,at_hit:370,at_idmapper_flush:[466,483],at_init:[45,48,204,232,370,371,372,398],at_initial_setup:[148,195,420],at_initial_setup_hook_modul:420,at_left:275,at_lock:275,at_login:[48,62,427,428,436,439,444,445,455],at_look:[204,398],at_message_rec:204,at_message_send:204,at_mix:275,at_mix_failur:275,at_mix_success:275,at_msg_rec:[204,296,398],at_msg_send:[204,205,296,362,398],at_new_arriv:370,at_no_cod:275,at_nomatch:275,at_now_add:67,at_object_cr:[13,20,33,37,48,88,112,125,126,130,132,135,139,141,161,162,165,174,176,218,275,276,296,308,309,310,311,312,316,322,343,350,354,364,366,370,371,372,398,466],at_object_delet:398,at_object_leav:[276,329,372,398],at_object_post_copi:398,at_object_rec:[37,171,276,329,372,398],at_open:275,at_password_chang:204,at_paus:[42,409],at_posit:275,at_post_all_msg:232,at_post_channel_msg:[18,204,232],at_post_cmd:[22,129,209,213,226,490],at_post_command:22,at_post_disconnect:204,at_post_func:161,at_post_login:[126,204],at_post_mov:[37,171,398],at_post_msg:232,at_post_object_leav:329,at_post_portal_sync:454,at_post_puppet:398,at_post_travers:[37,371,398],at_post_unpuppet:398,at_pr:398,at_pre_channel_msg:[18,204,232],at_pre_cmd:[22,209,213,226,490],at_pre_command:[22,161],at_pre_drop:[309,312,398],at_pre_g:[309,312,398],at_pre_get:[312,398],at_pre_leav:37,at_pre_login:204,at_pre_mov:[37,126,161,308,309,310,311,312,398],at_pre_msg:[18,232],at_pre_puppet:398,at_pre_sai:[350,398],at_pre_unpuppet:398,at_prepare_room:[117,329],at_read:275,at_red_button:275,at_reload:[228,454],at_renam:466,at_repeat:[42,48,164,173,174,205,247,257,277,283,308,309,310,311,312,359,409,449,480],at_return:[54,492],at_return_funct:54,at_return_kwarg:[54,492],at_right:275,at_rot:275,at_sai:[172,275,398],at_script_cr:[42,164,173,174,205,247,257,277,283,308,309,310,311,312,329,339,349,359,382,402,409,449,480],at_script_delet:409,at_search:[148,195],at_search_result:[227,492],at_server_cold_start:454,at_server_cold_stop:454,at_server_connect:434,at_server_reload:[42,199,204,205,398,409],at_server_reload_start:454,at_server_reload_stop:[126,454],at_server_shutdown:[42,199,204,205,398,409],at_server_start:[42,257,409,454],at_server_startstop:[126,148,195],at_server_stop:454,at_shutdown:454,at_smel:275,at_speech:275,at_start:[42,164,205,329,406,409],at_startstop_modul:411,at_stop:[42,164,174,308,309,310,311,312,409],at_sunris:136,at_sync:[455,456],at_tick:[47,411],at_travers:[37,325,329,398],at_traverse_coordin:329,at_turn_start:310,at_unfocu:275,at_upd:[310,407],at_weather_upd:176,ating:229,atlanti:183,atleast:[106,349],atom:[154,192],atop:[117,329],atribut:473,att:[28,64],attach:[13,37,44,46,64,74,85,104,113,123,124,125,133,135,143,150,151,153,199,213,218,226,239,289,296,299,329,386,394,398,408,453,467,501,508,545],attachmentsconfig:124,attack:[15,28,85,96,113,114,127,128,129,138,150,155,156,157,162,164,178,191,194,212,289,308,309,310,311,312,350,370,371,386,398,403,434,545],attack_count:311,attack_nam:311,attack_skil:403,attack_typ:312,attack_valu:[308,309,310,311,312],attempt:[7,12,20,28,36,73,76,97,118,128,142,173,183,194,215,218,273,308,309,310,311,312,316,322,377,413,416,421,454,459,466,479,492,538],attemt:30,attent:[37,120,133,135,170,194,273],attitud:134,attr1:[218,305],attr2:[218,305],attr3:218,attr:[13,28,33,41,51,76,82,132,135,146,218,225,234,241,276,372,393,402,403,455,464,466,483,488],attr_categori:501,attr_eq:393,attr_g:[33,393],attr_gt:[33,393],attr_kei:501,attr_l:[33,393],attr_lockstr:501,attr_lt:[33,393],attr_n:[33,393],attr_nam:218,attr_obj:[464,466],attr_object:466,attr_typ:501,attr_valu:501,attrcreat:[33,464],attread:13,attredit:[13,33,464],attrhandler_nam:464,attrib:394,attribiut:464,attribut:[3,12,18,19,24,27,28,32,33,34,35,36,37,41,42,44,46,47,48,55,67,69,76,82,85,96,97,102,104,106,112,114,126,127,129,130,132,133,134,135,137,139,140,141,142,144,146,151,157,161,162,164,165,177,178,201,202,204,206,207,212,218,227,228,232,238,241,256,257,275,289,292,293,302,305,308,309,310,311,312,316,325,338,350,354,364,370,371,372,393,396,397,398,401,402,403,405,406,407,410,421,455,463,465,466,467,472,473,474,480,485,486,489,492,498,499,500,502,505,506,508,515,517,518,532,537,538,540,543,545],attribute1:165,attribute2:165,attribute_list:464,attribute_nam:[161,204,350,396,398,489],attribute_valu:396,attributeerror:[3,13,67,149,161,455,464],attributeform:501,attributeformset:501,attributehandl:[13,48,464,487,492,515],attributeinlin:[500,501,502,505,506],attributemanag:13,attributeproperti:[464,545],attributeseri:515,attrkei:403,attrlist:464,attrnam:[13,28,33,41,48,112,218,354,393,396,466],attrread:[13,33,464],attrtyp:[13,464,465],attrvalu:28,attryp:465,atttribut:132,atyp:394,audibl:[106,349],audio:51,audit:[201,202,232,235,374,398,545],audit_allow_spars:78,audit_callback:[78,376],audit_in:78,audit_mask:78,audit_out:78,auditedserversess:[78,376,377],auditingtest:378,aug:[64,75],august:[75,492],aura:293,aut:29,auth:[49,78,204,206,207,223,436,500,523,524,532,538,543],auth_password:436,auth_profile_modul:207,authent:[44,45,53,62,78,177,194,204,427,434,436,439,445,455,457,524,537,538,540,543],authenticated_respons:533,author:[77,95,175,191,204,254,257,495],auto:[3,4,11,13,15,18,20,21,22,26,28,35,37,41,42,44,52,55,97,104,112,118,120,125,147,155,158,177,185,187,188,201,204,207,213,217,218,225,228,229,331,337,338,349,350,354,364,387,390,394,398,403,406,411,413,416,427,437,444,445,454,457,464,466,471,476,477,478,479,518,524,545],auto_close_msg:364,auto_create_bucket:238,auto_help:[22,28,31,131,137,213,225,229,274,369,380,400,476,477],auto_help_display_kei:[213,229,476],auto_id:[502,504,506,508,532],auto_look:[28,274,369,380,400,476],auto_now_add:67,auto_quit:[28,274,369,380,400,476],auto_step_delai:331,auto_transl:[106,349],autobahn:[427,433,444],autocr:[13,464],autodoc:[49,120],autofield:177,autologin:524,autom:[2,15,30,49,50,67,134,135,180,185,187,193,194,199,538],automat:[6,9,15,18,19,20,27,28,30,31,33,34,41,42,44,48,50,53,54,57,63,67,73,74,76,79,83,95,96,97,99,104,105,111,115,118,119,122,123,129,135,136,139,141,143,146,148,149,150,151,152,153,157,161,164,165,169,170,171,172,174,175,182,186,187,188,189,191,193,195,204,211,212,213,218,223,224,226,228,238,241,256,257,258,270,275,283,286,292,294,305,312,331,339,349,350,366,382,394,397,398,408,410,411,421,430,433,436,441,454,457,459,470,474,476,477,478,479,490,492,517,518,525,545],automatical:411,autostart:[42,405,408,472],autumn:[6,91,316],avail:[0,2,3,5,7,8,9,11,13,14,18,20,22,24,28,30,31,32,33,35,37,41,42,44,48,49,51,53,54,56,58,60,62,64,68,69,70,71,76,77,79,82,86,90,91,93,95,96,97,98,102,106,107,112,118,120,121,123,125,126,130,131,132,134,135,136,139,140,141,142,143,144,145,148,149,150,151,152,153,155,156,158,159,161,164,165,170,174,177,178,179,180,181,182,185,186,189,190,191,192,193,195,198,199,201,204,209,210,211,212,213,215,218,220,223,224,225,226,228,229,230,241,250,257,273,275,280,283,292,293,296,299,302,308,309,310,311,312,316,333,349,350,354,364,366,371,372,382,386,394,398,401,402,403,406,421,445,447,448,459,470,471,476,477,478,479,490,492,510,525,537,540,545],available_chan:223,available_choic:[28,476],available_funct:402,available_languag:349,available_weapon:371,avatar:[68,123,148,149,151,398,436,518],avatarid:436,avenu:[83,286],averag:[5,14,104,106,116,118,191,228,257,270,349],average_long_link_weight:[118,338],avoid:[0,3,6,8,11,13,19,20,22,28,39,41,48,53,60,62,72,90,117,118,119,139,141,149,151,152,156,158,161,170,175,181,182,193,211,218,270,329,338,349,364,382,393,397,425,435,445,455,464,466,467,469,470,471,474,477,479,483,515],awai:[0,3,11,13,15,16,28,31,33,41,42,44,54,63,67,75,86,95,96,97,104,113,117,118,122,125,128,132,137,149,152,155,157,161,162,165,170,174,191,224,234,278,286,309,312,329,337,340,364,370,372,386,398,406,456,469,492,500,545],await:54,awak:158,awar:[0,11,13,15,20,22,28,48,68,93,104,118,131,154,157,175,176,177,199,238,270,275,296,329,331,338,340,350,370,382,398,466,469],award:158,awesom:[53,73,151,185],awesome_func:152,awesomegam:187,awhil:95,awkward:64,aws:[77,191],aws_access_key_id:[77,238],aws_auto_create_bucket:77,aws_bucket_nam:77,aws_default_acl:77,aws_s3_access_key_id:238,aws_s3_cdn:[201,202,235,236,237,545],aws_s3_custom_domain:77,aws_s3_object_paramet:[77,238],aws_s3_region_nam:77,aws_s3_secret_access_kei:238,aws_secret_access_kei:[77,238],aws_security_token:238,aws_session_token:238,aws_storage_bucket_nam:77,awsstorag:[201,202,235,236,545],axe:158,axel:77,axes:[118,337],axi:[99,337],axio:49,azur:[77,191,193],b64decod:488,b64encod:488,b_offer:283,baaad:8,back:[0,2,6,7,11,13,14,15,18,19,20,22,27,28,30,32,36,42,44,48,49,51,52,53,54,55,64,65,67,70,73,76,82,95,96,97,101,104,112,113,115,117,118,120,123,125,128,132,133,135,137,139,141,142,144,146,148,149,150,151,152,153,154,155,156,157,158,159,160,162,164,165,167,170,172,174,175,177,182,185,187,191,193,199,200,201,204,212,215,218,223,227,241,275,278,283,289,292,311,322,331,350,354,362,364,386,400,416,421,425,428,434,436,439,454,466,473,476,477,485,492,496],back_exit:[95,97],backbon:[177,470],backend:[2,8,41,42,49,50,53,73,77,182,201,202,238,464,492,498,512,518,522,545],backend_class:464,background:[0,17,28,53,54,60,84,128,151,175,177,187,191,194,199,244,346,469,479,541],backpack:20,backtick:[120,479],backtrack:11,backup:[11,37,44,54,148,191,227,470],backward:[18,27,28,135,174,206,485],bad:[8,42,64,76,97,118,119,123,135,141,151,153,158,159,183,377,418],bad_back:394,baddi:155,badg:10,badli:354,bag:[31,143,292,492],bake:[86,104,337],baker:158,balanc:[128,133,156,158,164,180,478],ball:[20,195,210,211,293,403],ballon:305,balloon:305,ban:[18,33,61,103,126,143,158,204,216,223,229,232,266,394,545],ban_us:223,band:[51,68,436,439,440],bandit:96,bandwidth:[77,238,429],banid:216,bank:[156,545],banlist:[18,232],bar:[11,13,18,28,30,34,42,46,51,65,68,73,104,106,113,118,140,143,148,153,157,218,345,346,347,350,386,391,416,440,464,476,479,492,545],bardisk:99,bare:[22,94,122,135,150,157,162,195,309,346],barehandattack:133,bargain:67,bark:293,barkeep:[3,99,350],barrel:[99,155],barriento:77,barstool:161,barter:[42,156,171,185,201,202,235,281,545],bartl:180,base:[2,3,8,11,14,17,18,22,28,30,31,33,35,37,42,44,47,48,51,52,53,56,65,67,69,70,72,75,76,77,85,86,87,90,93,95,104,109,112,120,121,122,123,124,125,129,130,132,133,134,135,137,138,141,144,146,148,149,152,153,154,155,156,157,159,162,163,165,167,169,170,173,175,177,178,180,182,185,187,189,190,191,193,194,197,201,204,205,206,207,209,211,212,213,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,232,233,234,238,239,241,242,245,247,248,251,252,254,255,257,258,260,266,267,269,270,273,274,275,276,277,278,279,283,284,286,287,289,290,292,293,294,296,297,299,300,302,303,305,306,308,309,310,311,312,313,316,317,322,323,325,326,328,329,331,332,335,336,337,338,339,340,343,344,347,349,350,351,353,354,359,360,362,364,366,367,369,370,371,372,373,377,378,380,382,383,385,386,388,389,390,394,396,397,398,400,402,403,405,406,407,408,409,410,411,413,414,416,418,419,422,423,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,447,448,449,452,454,455,456,457,459,460,461,464,465,466,467,469,470,471,474,475,476,477,478,479,480,482,483,484,485,486,487,488,489,490,491,492,497,500,501,502,503,504,505,506,507,508,510,512,513,514,515,516,517,518,523,524,526,527,532,533,536,537,538,540,541,542,543,544,545],base_account_typeclass:12,base_channel_typeclass:18,base_char_typeclass:173,base_character_typeclass:[139,173,177,178,204,218],base_exit_typeclass:118,base_field:[500,501,502,504,505,506,508,532],base_filt:512,base_guest_typeclass:63,base_object_typeclass:[41,145,149,403,466],base_room_typeclass:118,base_script_path:393,base_script_typeclass:42,base_set:75,base_system:[77,82,84,87,89,95,100,103,116,201,202,235,545],base_systesm:95,base_word:492,baseapplic:275,baseclass:371,basecommand:143,baseconsum:275,basecontain:471,baseevenniacommandtest:[8,229,242,252,258,267,269,279,284,287,294,297,300,303,306,313,317,323,326,344,351,367,373,490],baseevenniatest:[8,245,248,258,279,287,290,313,328,335,347,351,360,373,378,383,385,442,490,516,533],baseevenniatestcas:[8,294,353,490],baseinlineformset:[501,508],baseline_index:492,basenam:518,baseobject:48,baseopt:486,basepath:492,basepermiss:513,baseposition:275,basest:278,basetyp:[398,470],basetype_posthook_setup:398,basetype_setup:[33,130,204,205,232,398],basetypeclassfilterset:512,bash:[2,120,185,371],basi:[22,95,118,119,124,136,148,169,191,226,234,238,338,350,445,466,475],basic:[0,2,9,12,16,17,20,22,33,36,51,53,56,57,58,62,65,67,70,73,75,76,90,92,96,97,99,114,118,128,130,133,134,135,136,137,138,139,143,144,148,149,150,151,152,154,155,156,157,158,161,162,164,167,170,171,172,174,175,177,178,180,199,204,205,218,223,225,232,234,256,292,305,309,311,371,380,393,395,398,447,532,541,545],basicmapnod:[118,338],bat:[75,185],batch:[24,26,104,148,170,180,185,201,202,217,229,356,403,425,464,467,468,545],batch_add:[403,464,467],batch_cmd:[15,148],batch_cod:[14,470],batch_code_insert:14,batch_create_object:403,batch_exampl:470,batch_import_path:[14,15],batch_insert_fil:15,batch_update_objects_with_prototyp:403,batchcmd:[26,156,158,217],batchcmdfil:[15,470],batchcod:[15,26,80,143,158,166,170,180,217,545],batchcode_map:170,batchcode_world:170,batchcodefil:14,batchcodeprocessor:470,batchcommand:[15,26,76,80,115,143,155,166,185,217,470],batchcommandprocessor:470,batchfil:[15,16,170,470],batchprocess:[201,202,208,214,545],batchprocessor:[14,80,201,202,217,235,355,468,545],batchscript:[14,470],batteri:204,battl:[155,164,180,194,308,309,310,311,312,545],battlecmdset:[308,309,310,311,312],bayonet:86,baz:[113,386],bazaar:69,beach:170,bear:[370,382],beat:[156,158,164],beaten:[164,372],beauti:[76,95,132,177],beazlei:180,becam:[128,175],becasu:4,becaus:[2,3,12,13,14,16,20,28,30,31,33,37,41,45,47,48,49,50,53,54,55,56,58,62,64,69,75,76,90,96,97,117,118,120,123,125,126,128,131,133,142,143,146,149,150,151,152,157,159,161,162,164,169,170,171,175,177,178,181,184,187,212,225,230,232,251,256,278,311,329,335,337,349,398,409,428,434,447,457,469,479,486,488,492,500,501,508,518,523],becom:[3,9,28,33,36,41,54,67,68,71,76,93,97,105,106,112,113,120,123,132,133,139,143,147,148,149,150,151,156,158,161,162,170,179,195,215,289,293,296,305,309,349,350,354,386,398,403,455,470,476,479,490],been:[2,3,5,9,13,14,15,28,30,31,42,44,57,64,73,76,78,82,95,96,97,99,104,105,106,112,118,120,124,125,132,135,137,141,142,146,151,153,164,165,171,175,177,178,180,182,194,200,204,211,212,213,217,218,223,226,232,234,241,257,292,305,308,309,310,311,312,329,338,350,354,372,382,388,390,394,397,398,402,403,410,411,418,430,434,436,444,454,455,456,457,459,464,466,470,474,475,492,495,497,508,523,539,544],befit:48,befor:[1,3,5,6,7,8,10,11,13,14,15,16,18,19,20,22,28,31,33,34,39,41,42,45,46,47,48,50,51,53,54,55,64,66,67,69,70,73,76,77,78,86,89,93,95,96,99,104,108,113,117,118,119,124,125,126,127,128,132,133,134,135,137,139,141,142,143,144,146,149,150,151,152,154,156,158,161,164,165,170,171,172,174,175,176,177,178,180,182,187,188,190,191,193,194,195,204,209,210,213,218,223,225,226,230,232,234,239,247,250,251,256,260,278,289,292,294,296,308,309,310,311,312,316,329,337,338,346,349,350,353,354,364,369,371,372,376,377,380,386,393,394,397,398,401,402,403,405,409,410,411,416,425,434,436,442,448,450,452,454,455,459,461,464,469,470,471,472,476,477,478,480,484,485,488,492,523,537,543,545],beforehand:[13,471],beg:15,beggar:97,begin:[0,3,5,7,8,14,15,22,27,31,33,45,54,76,95,96,97,106,120,122,124,126,135,137,142,144,146,151,156,160,164,170,171,176,178,189,224,225,256,308,309,310,311,312,337,349,350,386,396,398,469,470,476,479,489,545],beginn:[122,138,142,149,154,156,180],behav:[13,14,45,76,95,104,128,136,137,142,144,150,151,152,199,492],behavior:[5,20,22,27,31,41,51,60,73,83,92,95,97,106,118,137,148,175,204,213,229,270,286,292,310,312,338,350,372,380,416,464,476,501,508,545],behaviour:[20,22,33,99,175,405,462,472,478,492],behind:[6,11,13,22,32,41,46,55,60,95,107,118,122,125,132,152,155,175,185,217,354,372,382,406,411,483],behvaior:477,being:[2,3,5,11,13,14,20,22,28,30,31,35,39,41,42,45,47,48,52,54,58,65,68,72,76,77,80,86,88,93,95,97,101,104,106,112,114,118,123,125,126,127,133,137,142,145,147,148,149,151,155,157,158,159,170,172,175,177,184,185,187,191,194,204,210,218,224,228,229,232,238,247,296,299,308,309,310,311,312,338,343,349,350,354,362,364,372,390,398,405,418,421,428,448,457,459,464,466,469,470,472,476,477,478,479,492,495,497,501,508,512,515,523,544],beipmu:183,belong:[15,46,65,74,118,123,124,146,151,177,194,212,329,350,386,390,401],belov:158,below:[2,3,5,7,8,11,14,15,16,18,19,20,22,27,28,31,32,33,36,39,41,42,44,48,54,55,57,60,64,68,74,75,76,77,78,79,82,84,86,87,88,94,95,97,99,103,106,112,113,115,118,120,123,126,128,130,132,134,135,136,137,139,150,151,152,156,161,162,165,169,170,171,172,177,178,181,182,185,187,191,193,199,207,218,226,234,241,270,280,286,292,293,308,309,310,311,312,337,338,343,346,349,350,354,360,386,390,397,398,406,428,448,464,466,467,476,478,479,484,517],beneath:19,benefici:[132,310],benefit:[64,69,157,159,179,187,191,193,194,212,464,470,476],berserk:[112,354],besid:[7,15,20,39,64,94,97,104,150,170,346],best:[0,27,42,53,64,69,73,75,76,82,95,104,113,116,119,134,135,145,148,156,159,177,183,187,189,194,195,225,241,270,349,386,403,416,436,478,486,544,545],bet:[20,44,50,466],beta:[25,184,191,545],betray:28,better:[3,5,16,28,30,31,41,42,46,58,60,67,69,75,86,97,110,114,118,119,120,122,123,126,131,135,139,141,142,148,149,156,159,161,162,177,178,182,293,309,325,338,372,398,403,433,436,439,447,464,470,523],bettween:162,between:[2,5,11,12,13,15,18,20,22,30,31,36,41,42,44,46,51,54,58,60,62,64,68,70,74,76,78,79,84,90,95,96,97,98,99,102,104,107,112,113,114,118,120,123,126,127,130,132,133,134,135,137,141,142,143,148,149,151,152,155,157,158,162,164,165,173,174,175,187,191,193,210,213,218,223,225,228,229,233,234,244,256,257,260,283,286,292,293,299,302,308,309,310,311,312,335,337,338,339,340,349,350,353,354,382,386,398,403,411,416,425,428,435,436,439,440,447,448,455,467,469,470,472,476,478,479,480,492,496,526,545],bew:[91,316],bewar:130,beyond:[12,22,29,37,50,68,75,76,95,119,123,126,134,158,178,191,213,218,229,234,241,273,293,350,364,372,386,398,402,447,464,466,476,478],bg_colormap:491,bgcolor:491,bgfgstart:491,bgfgstop:491,bgstart:491,bgstop:491,bias:218,bidirect:425,big:[14,15,18,22,33,50,53,74,75,86,115,119,127,128,134,143,144,152,155,158,159,162,210,225,227,353,354,364,396,470,477,489,492],bigger:[62,106,112,125,137,146,165,335,337,349,354],biggest:[189,354,492],biggui:22,bigmech:125,bigsw:128,bikesh:146,bill:[191,194],bin:[2,75,123,124,147,185,190,193],binari:[5,118,182,185,427,429,444],bind:187,birth:532,bit:[0,3,7,11,13,17,25,41,42,51,53,55,58,64,75,76,95,96,97,115,124,128,130,136,137,139,143,146,147,148,151,152,154,156,158,159,161,174,178,185,190,223,230,251,293,394,398,470],bitbucket:134,bite:[156,170],bitten:146,black:[60,152,162,175,469],blackbird:180,blackbox:292,blackhaven:118,blacklist:[18,194,223],blacksmith:[39,467],blade:[158,293,371],blank:[28,67,78,92,171,178,204,380,469],blankmsg:[92,380],blargh:41,blast:[292,293],blatant:55,blaufeuer:146,bleed:[11,60,148,354,478],blend:[105,305],blender:[104,105,305],blind:[60,108,172,364],blind_target:364,blindcmdset:364,blindli:394,blink:[144,364,491],blink_msg:364,blist:6,blob:[96,120,155],block:[5,6,23,24,27,28,30,33,42,53,55,60,72,90,91,109,122,123,126,127,135,137,142,143,151,154,165,167,177,178,191,194,199,216,217,218,274,275,280,312,316,329,335,338,369,370,371,391,400,435,470,476,479,492,541,544,545],blockedmaplink:[118,338],blocker:118,blocking_cmdset:126,blockingcmdset:126,blockingroom:126,blocknam:53,blockquot:545,blocktitl:137,blog:[119,122,154,180,191,192],blond:157,blowtorch:183,blue:[14,60,134,139,150,151,158,175,371,469],blueprint:[51,134,170],blurb:[90,184,545],board:[33,35,132,156,174,180,545],boat:[20,174,212],bob:[13,22,49,139,216,280],bodi:[0,17,19,22,28,41,53,72,76,96,135,151,157,167,177,255,299,389,391,418,472],bodyfunct:[42,81,144,201,202,235,355,545],bodymag:293,bog:[125,156],boi:46,boiler:[28,48,53],bold:[184,545],bolt:403,bone:[28,122,157,162],bonu:[115,158,162,191,309,310,406],bonus:[128,158,309],book:[41,53,73,132,136,142,153,158,162,167,180,275],bool:[12,20,22,28,32,34,42,92,118,204,205,206,207,209,210,211,212,213,223,225,232,233,234,241,247,254,257,275,278,280,283,286,289,292,308,309,310,311,312,329,337,338,339,340,343,346,349,350,354,380,382,386,388,389,390,394,396,397,398,402,403,405,406,407,408,409,410,411,416,421,422,427,428,433,434,435,439,444,445,453,455,457,459,464,465,466,467,469,470,472,474,476,477,478,479,480,483,485,487,489,491,492,495,500,502,505,506,513,540],booleanfield:[177,500,506],booleanfilt:512,boom:[125,149],boost:391,boot:[18,33,103,143,149,193,199,216,223,232,266,411,545],boot_us:223,bootstrap:[24,53,61,124,545],border:[135,140,170,215,275,278,280,380,475,478,490,545],border_bottom:478,border_bottom_char:478,border_char:478,border_left:478,border_left_char:478,border_right:478,border_right_char:478,border_top:478,border_top_char:478,border_width:478,borderless:135,borderstyl:380,bore:[55,122,156,157,194],borrow:[20,185,211,425],bort:[28,29,476],boss:135,bot:[5,147,177,186,189,194,201,202,203,207,223,421,427,428,435,457,538,545],bot_data_in:[205,421],both:[0,2,6,7,8,9,13,16,18,19,20,22,28,30,31,32,34,36,39,44,48,49,53,57,58,62,67,68,76,79,80,84,95,97,98,99,100,104,109,112,113,118,119,120,126,131,132,133,134,135,136,137,141,142,146,148,150,151,152,157,158,159,161,164,169,170,174,177,178,180,182,186,187,188,191,194,195,199,209,211,218,223,228,233,234,244,275,280,283,292,299,305,311,312,322,331,337,338,340,346,354,372,386,394,396,398,402,403,404,406,409,411,425,434,444,445,447,454,456,459,464,465,469,472,476,478,479,487,492,515,518],bother:[9,128,194,464],botnam:[189,223,428,457],botnet:194,boto3:[77,238],boto:[77,238],botstart:205,bottl:99,bottom:[5,7,29,48,50,51,53,77,117,118,124,130,134,135,137,141,143,151,161,170,177,184,187,212,238,299,311,329,337,403,470,477,478],bottommost:118,bought:141,bouncer:[19,194,475],bound:[19,69,112,120,134,148,149,254,337,354,388,492],boundari:[112,118,353,354,492],bow:[158,403],bowl:[86,292],box:[3,7,30,33,35,36,41,49,63,73,86,96,97,122,135,137,144,146,149,150,151,152,154,157,162,165,167,170,181,185,188,191,195,218,273,331,337,350,393,425,470,532,544],brace:[76,95,97,126,142,398,469],bracket:[72,84,120,228,244,479],branch:[2,11,75,104,107,113,118,119,120,143,185,193,278,382,386,544,545],branchnam:11,brandymail:[98,104,299],braymer:77,bread:[56,86,104,292],breadrecip:292,breadth:312,break_lamp:364,break_long_word:478,break_on_hyphen:478,breakag:158,breakdown:228,breakpoint:[7,56,201],breath:[149,152],breez:[42,176],breviti:[135,151],bribe:28,brick:140,bridg:[44,65,76,115,121,155,180,182,372],bridgecmdset:372,bridgeroom:372,brief:[11,50,56,57,67,92,96,125,126,135,141,144,147,154,167,199,270,380,398,460,545],briefer:[37,199],briefli:[56,149,158,191,199,364,545],bright:[60,84,108,118,139,151,175,244,364,469],brightbg_sub:469,brighten:60,brighter:60,bring:[113,118,132,157,159,165,168,169,174,177,182,193,194,312,338,370,386,458],broad:130,broadcast:[78,204,232,425],broader:[130,350,398],brodowski:77,broken:[31,60,69,120,156,349,364,545],brown:469,brows:[7,51,75,104,122,126,130,135,136,137,141,142,147,165,167,169,191,194,538],browser:[0,49,51,52,53,56,59,73,75,120,123,137,147,148,154,167,169,177,178,181,185,187,190,191,194,198,277,444,445,540,541],brunt:158,brutal:270,bsd:[77,179,496],bsubtopicnna:229,btest:60,btn:17,bucket:[77,238,239,376],bucket_acl:238,bucket_nam:238,buf:[157,474],buff:157,buffer:[22,27,51,76,227,238,239,418,445,474,540],buffer_s:238,bug:[0,3,8,11,14,54,77,90,115,119,134,151,156,158,159,165,179,184,199,398,466,545],bugfix:77,buggi:[13,476],bui:[79,141,158,283],build:[2,5,7,10,13,14,15,16,18,19,20,22,23,24,26,28,31,35,36,37,41,44,46,48,51,53,54,58,67,69,70,72,74,75,80,86,92,99,104,106,115,118,122,123,134,137,138,139,143,145,146,148,149,150,151,154,155,157,159,160,161,163,165,168,169,173,180,185,190,193,201,202,208,210,214,216,217,224,225,240,241,242,255,270,278,280,316,322,331,332,334,335,337,338,339,349,350,370,394,398,402,403,416,427,428,470,478,532,544,545],build_forest:99,build_link:338,build_match:210,build_mountain:99,build_templ:99,buildchannel:18,builder:[12,13,15,18,30,31,33,39,41,46,49,50,57,69,76,82,83,92,95,104,105,116,118,124,126,133,135,141,145,149,156,159,161,165,216,218,223,224,228,241,270,286,305,316,322,329,331,350,364,372,380,394,398,447,466,467,470,513,545],buildier:403,building_menu:[82,201,202,235,236,545],buildingmenu:[76,82,241,242],buildingmenucmdset:241,buildprotocol:[413,426,427,428],buildshop:141,built:[5,14,19,24,28,30,56,62,73,104,105,120,123,134,135,148,151,156,157,159,162,165,174,184,185,190,193,194,207,234,305,337,338,339,349,390,397,406,411,464,466,467,470,474,476,484,545],builtin:429,bulk:[31,194],bullet:[120,156],bulletin:[33,35,156,180,545],bulletpoint:120,bunch:[16,19,69,70,135,146,150,152,157,161],burden:140,buri:[69,155],burn:[155,156,159,162,191,371],busi:[78,79,99,123,157,191,283,545],butter:[56,292],button:[7,11,14,15,20,22,33,36,49,50,51,52,53,65,68,73,75,80,95,104,148,150,151,177,178,218,275,293,363,364,371,448,477,505,545],button_expos:371,buy_ware_result:141,byngyri:[106,349],bypass:[4,33,39,54,57,109,124,135,144,149,155,161,164,175,204,206,218,232,322,394,396,466,472,489,492,524],bypass_mut:[18,232],bypass_perm:492,bypass_superus:33,byt:398,bytecod:469,bytes_or_buff:540,bytestr:[425,492],bytestream:492,c123:[84,104],c20:223,c_creates_button:448,c_creates_obj:448,c_dig:448,c_examin:448,c_help:448,c_idl:448,c_login:[5,448],c_login_nodig:448,c_logout:[5,448],c_look:[5,448],c_measure_lag:448,c_move:448,c_moves_:448,c_moves_n:448,c_score:165,c_social:448,cabinet:40,cabl:140,cach:[8,13,22,42,48,51,52,53,55,67,118,127,130,149,181,204,213,228,232,234,238,316,337,353,370,371,394,397,398,420,459,464,466,467,468,481,483,492,501,508,525],cache_inst:483,cache_lock_bypass:394,cache_s:[459,483],cachecontrol:77,cached_properti:492,cactu:311,cake:20,calcul:[19,42,54,91,112,118,126,130,146,162,164,165,212,247,260,308,309,311,312,316,335,338,349,353,354,403,480,483,492,537,543],calculate_path_matrix:337,calculated_node_to_go_to:28,calculu:133,calendar:[87,95,104,247,260,480,545],call:[0,2,3,5,8,9,11,12,13,14,15,18,19,20,27,28,30,32,33,34,37,41,42,44,45,47,48,49,51,52,54,56,58,62,65,67,68,69,71,73,76,80,82,86,96,97,99,103,104,107,108,111,112,113,116,117,118,120,123,124,125,126,127,128,129,130,132,133,134,135,136,137,139,141,142,143,144,145,146,147,148,150,151,152,153,156,159,161,162,164,165,167,170,171,172,173,174,175,176,177,178,182,185,186,188,189,190,191,193,195,198,199,204,205,209,210,211,212,213,215,218,223,226,227,228,229,230,232,234,241,247,250,251,254,255,256,257,258,260,266,270,273,275,276,277,278,280,283,286,289,292,293,294,296,305,308,309,310,311,312,316,322,329,338,340,343,349,350,354,359,362,364,366,369,370,371,372,380,382,386,393,394,397,398,401,402,403,405,407,409,410,411,413,416,418,420,421,425,426,427,428,429,430,431,432,434,435,436,437,438,439,440,441,443,444,445,447,448,449,454,455,456,457,458,461,464,466,467,469,470,471,472,474,476,477,478,479,480,483,485,487,488,489,490,492,501,508,513,518,532,536,538,541,542,543,545],call_async:54,call_command:8,call_ev:[97,256,545],call_inputfunc:[65,455,457],call_task:410,callabl:[27,28,34,41,47,52,53,58,71,92,104,113,132,165,241,257,278,310,337,380,386,398,401,402,403,407,411,414,416,418,426,457,471,474,476,477,479,480,485,487,488,492,545],callables_from_modul:492,callbac:76,callback1:476,callback:[19,22,27,28,32,34,47,54,76,78,82,85,87,92,104,113,124,128,136,205,228,241,242,247,254,255,256,257,258,260,289,369,377,380,386,398,407,410,411,414,416,418,421,425,426,427,429,443,444,447,458,476,480,485,490,492,545],callback_nam:[254,257],callbackhandl:[201,202,235,236,253,545],called_bi:209,calledbi:492,caller:[3,13,14,18,19,22,27,30,31,33,36,37,47,48,54,58,65,67,68,72,76,80,82,85,86,92,94,95,99,113,117,118,120,125,126,127,128,129,131,132,133,135,139,140,141,142,143,149,150,153,161,162,164,165,170,174,188,205,209,210,211,213,215,218,219,223,224,225,226,228,229,241,242,255,270,273,274,275,276,289,292,299,305,329,346,350,364,366,369,371,372,380,386,394,398,400,402,403,470,474,476,477,479,486,490,492,545],callerdepth:492,callertyp:209,callinthread:461,calllback:256,callsign:[28,275,421],calm:170,came:[75,95,122,125,126,143,151,170,176,180,329,370,398],camp:170,campfir:170,campsit:170,can:[0,2,3,4,5,6,7,8,9,10,11,12,14,15,16,17,18,19,20,22,25,27,28,30,31,32,33,34,35,36,37,39,40,41,42,44,45,46,47,48,49,50,51,52,53,54,55,57,58,59,60,62,63,64,65,67,68,69,70,71,73,74,75,77,78,79,80,82,83,84,85,86,87,88,90,91,92,93,94,95,96,97,98,99,104,105,106,107,108,109,112,113,114,115,116,117,118,119,120,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,139,140,141,142,143,144,145,146,147,148,149,150,151,154,155,156,157,159,161,162,164,165,167,168,169,170,171,172,173,174,175,177,178,179,180,182,183,184,185,186,187,188,189,190,191,192,193,194,195,198,199,203,204,205,206,207,210,211,212,213,215,216,218,223,224,225,226,227,228,229,230,232,233,234,238,239,241,244,247,250,256,257,260,266,270,274,275,276,277,278,280,283,286,289,292,293,296,299,305,308,309,310,311,312,316,322,329,331,333,334,337,338,340,343,346,349,350,354,362,364,370,371,372,376,380,382,386,388,390,393,394,396,397,398,401,402,403,404,405,406,407,409,411,416,427,431,434,436,439,440,444,445,447,448,454,455,456,457,458,461,462,463,464,465,466,467,469,470,471,472,474,475,476,477,478,479,486,487,488,489,490,492,493,495,496,500,513,515,518,532,537,538,540,541,543,545],can_:[95,256],can_delet:95,can_eat:95,can_ent:467,can_list_top:[225,540],can_mov:95,can_part:95,can_read_top:[225,540],can_sai:95,can_travers:95,cancel:[19,32,95,128,161,228,256,308,309,310,311,312,398,410],candid:[22,76,153,161,177,210,305,350,391,396,398,489],candidate_entri:391,candl:212,cannon:146,cannot:[4,8,9,13,14,15,19,20,22,27,28,35,39,41,46,50,54,57,60,64,75,76,90,91,92,96,109,115,118,119,125,126,127,128,130,131,133,137,141,148,149,150,153,155,156,159,162,165,177,185,191,195,204,205,212,215,218,225,241,254,257,278,292,312,316,322,331,370,371,380,386,389,394,396,398,402,411,464,471,473,475,478,483,492,545],cantanker:486,cantclear:[92,380],cantillon:180,cantmov:126,canva:132,capabl:[2,33,44,65,68,104,111,123,132,135,156,215,366,421,443,532,545],capcha:545,cape:134,capfirst:137,capit:[30,55,58,68,75,93,106,107,123,126,128,151,152,158,165,218,280,296,349,354,382,440,469,479,492,496],captcha:177,caption:120,captur:[78,126,142,485,543],car:[36,86,174],carbon:[292,293],card:[118,194,339,340,545],cardin:[118,131,132,135,218,337,338,339],care:[22,28,54,55,67,78,95,97,112,118,120,123,124,131,132,133,134,136,142,149,151,158,159,164,174,175,176,179,182,199,204,211,232,273,292,305,316,322,325,331,337,350,354,369,370,372,393,398,447,466,470,474,476,477,478,492,545],career:159,carefulli:[5,44,50,95,104,122,170,177],carri:[20,33,140,141,144,148,156,161,164,171,234,286,293,309,370,393,455,465,545],carv:86,cascad:483,case_insensit:275,case_sensit:[106,350],caseinsensitivemodelbackend:524,cast:[41,46,113,114,127,152,201,202,235,281,291,311,386,545],caster:[127,293,311],castl:[14,115,118,145,155,170,316,372],cat:[187,190],catchi:124,categor:[46,123,398],categori:[2,13,22,26,28,31,41,46,67,74,86,104,113,118,119,120,130,137,143,146,153,206,213,214,215,216,217,218,223,224,225,226,227,228,229,230,233,241,251,255,266,269,270,273,276,283,286,292,293,296,299,302,305,308,309,310,311,312,316,322,325,331,343,350,354,364,366,370,371,372,380,386,388,389,390,391,393,396,398,402,403,405,407,447,464,465,467,472,474,476,477,484,486,489,492,512,540],categoris:133,category2:484,category2_id:484,category_id:484,category_index:386,cater:[128,159],caught:[3,6,28,161,233],cauldron:293,caus:[3,8,13,20,33,51,55,74,89,123,128,129,143,149,164,165,171,182,191,212,232,245,251,289,293,329,338,364,398,447,476,478,492],caution:[51,95,136,476],cave:[96,118,331,332],caveat:[54,77,161,238,545],caveman:133,cblue:11,cboot:[55,103,143,266],cc1:185,cccacccc:475,ccccc2ccccc:135,cccccccc:475,ccccccccccc:135,cccccccccccccccccbccccccccccccccccc:475,ccccccccccccccccccccccccccccccccccc:475,ccreat:[103,135,143,186,189,192,266],cdesc:[103,143,266],cdestroi:[103,143,266],cdmset:20,cdn:[77,194],ceas:218,cel:475,celebr:156,cell:[0,115,135,137,155,170,380,475,478],celltext:475,cemit:143,censu:465,center:[30,41,53,56,118,124,130,132,170,278,280,331,337,346,469,478,492],center_justifi:41,centos7:187,centr:[31,170],central:[8,18,32,86,118,123,170,176,193,204,212,218,229,232,233,234,276,292,335,398,403,425,472,476,483,521],centre_east:170,centre_north:170,centre_south:170,centre_west:170,centric:[33,44,75,106,165,350],cert:[181,437,441],certain:[6,13,14,15,20,22,33,42,44,45,47,56,57,59,68,69,79,85,86,104,108,112,120,123,126,128,148,157,158,174,182,190,191,218,233,283,289,293,329,337,349,354,364,371,376,393,396,402,409,416,422,439,440,443,458,464,465,474,478,479,489,492,501,518,532,545],certainli:[16,131],certbot:[187,191,194],certfil:[437,441],certif:[181,191,437,441,545],certonli:187,cet:485,cfg:187,cflag:190,cgi:191,cha:[28,135],chain:[28,41,54,96,97,118,128,146,256,257,338,416,448,476,545],chain_1:[95,97],chain_2:[95,97],chain_3:95,chain_:[95,97],chain_flood_room:95,chain_open_door:97,chain_x:[95,97],chainedprotocol:436,chainsol:146,chair:[14,37,46,48,80,142,156,545],challeng:[90,104,115,138,152,155,162,180,276],chamber:115,chan:[18,26,223],chanalia:266,chanc:[5,11,20,30,47,63,76,86,125,127,149,155,156,162,164,184,211,293,308,309,310,311,312,364,371,372,448],chance_of_act:[5,448],chance_of_login:[5,448],chandler:164,chang:[0,2,3,5,8,10,12,13,14,15,16,18,20,22,25,27,28,30,31,32,33,34,35,36,37,41,42,44,45,46,47,48,51,55,56,57,58,60,61,63,65,67,73,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,92,93,94,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,121,123,124,125,128,129,130,132,134,136,139,141,142,143,144,146,148,150,151,152,154,156,157,161,162,163,164,165,167,170,172,174,175,176,177,178,179,181,182,184,185,187,188,190,191,193,195,197,199,204,212,213,215,216,218,224,229,232,241,250,251,254,257,266,270,275,278,283,286,292,296,302,308,309,310,311,312,316,322,325,329,338,339,340,346,349,350,353,354,370,371,372,386,388,390,396,398,402,403,406,407,409,410,411,416,421,432,447,454,455,462,464,466,470,473,474,477,478,479,485,486,487,488,500,501,502,505,506,508,541,543,545],change_name_color:386,changelock:[18,223],changelog:147,changepag:178,channel:[12,13,20,22,23,24,26,33,35,36,45,46,48,52,53,55,57,67,103,104,119,121,122,140,143,148,149,153,156,165,180,186,188,189,191,192,197,201,202,204,205,211,212,218,223,229,231,232,233,234,257,266,364,427,428,435,448,454,455,457,464,472,485,489,498,502,531,533,535,545],channel_:[18,232],channel_ban:[18,223,266],channel_color:126,channel_connectinfo:455,channel_detail:537,channel_list:537,channel_list_ban:223,channel_list_who:223,channel_msg:[18,204],channel_msg_nick_pattern:[18,232],channel_msg_nick_replac:[18,223,232],channel_msg_pattern:223,channel_prefix:[18,126,232],channel_prefix_str:[18,232],channel_search:233,channel_typeclass:533,channeladmin:502,channelalia:[18,223,232],channelattributeinlin:502,channelcl:223,channelcmdset:[20,143],channelconnect:234,channelcr:266,channelcreateview:232,channeldb:[48,121,201,232,234,463,502],channeldb_db_attribut:502,channeldb_db_tag:502,channeldb_set:[464,467],channeldbmanag:[233,234],channeldeleteview:232,channeldetailtest:533,channeldetailview:[232,537],channelform:502,channelhandl:18,channelkei:233,channellisttest:533,channellistview:537,channelmanag:[232,233],channelmixin:537,channelnam:[18,189,204,205,223,232,427],channeltaginlin:502,channelupdateview:232,char1:[8,162,224,490,533],char2:[8,162,224,533],char_health:372,char_nam:177,charac:34,charact:[2,3,5,6,8,12,13,15,16,17,19,20,22,27,28,30,31,32,33,36,39,42,44,48,49,53,57,60,62,64,67,68,70,72,73,75,76,81,83,85,86,88,90,91,92,93,95,97,98,99,102,104,105,106,107,108,112,113,114,115,117,118,121,122,125,127,128,129,130,132,133,134,136,137,138,139,141,142,143,144,145,146,147,148,150,151,152,153,154,157,163,164,169,170,171,172,173,174,182,188,201,202,203,204,206,210,211,213,215,218,219,220,224,225,226,228,230,232,241,254,256,257,273,275,276,278,286,289,296,299,302,305,308,309,310,311,312,316,329,331,335,337,338,340,343,346,349,350,353,354,359,364,366,370,371,372,376,380,382,386,388,390,394,398,409,421,442,455,460,464,466,467,469,470,475,476,478,479,490,492,493,498,512,518,531,532,533,535,540,542,543,545],character1:162,character2:162,character_cleanup:[276,278],character_cmdset:[91,316],character_ent:278,character_exit:276,character_form:538,character_id:398,character_leav:278,character_list:538,character_manage_list:538,character_sai:95,character_typeclass:[204,490,533],charactercmdset:[18,20,26,50,76,79,82,83,88,90,91,95,102,103,106,109,110,118,125,126,129,131,134,135,136,139,149,150,161,165,220,241,266,286,293,299,302,308,309,310,311,312,316,322,325,343,350,372,545],charactercreateview:[533,538],characterdeleteview:[533,538],characterdetailview:538,characterform:[532,538],characterlistview:[533,538],charactermanageview:[533,538],charactermixin:538,characterpuppetview:[533,538],charactersheet:28,characterupdateform:[532,538],characterupdateview:[533,538],characterviewset:518,charapp:177,charat:[92,380],charcreat:[26,96,97,137,143,215],charcter:18,chardata:135,chardelet:[26,143,215],chardeleteview:[390,466],chardetailview:[213,388,390,466],charfield:[67,177,488,500,501,502,504,505,506,508,532],charfilt:512,charg:191,chargen:[177,232,390,466,545],chargencmdset:165,chargenroom:165,chargenview:[390,466],charnam:[135,215,479],charpuppetview:466,charset:492,charsheet:135,charsheetform:135,charupdateview:[390,466],chase:155,chat:[0,12,23,39,53,75,99,119,122,135,156,158,159,165,180,185,186,189,192,197,445,485,545],chatroom:134,chatzilla:189,cheap:159,cheaper:47,cheapest:[118,191],cheapli:372,cheat:[120,162,182,545],chec:490,check:[0,2,3,5,6,7,8,9,10,11,14,15,18,19,20,22,28,30,35,36,37,41,42,46,47,48,49,55,57,58,62,64,67,76,78,86,92,95,96,97,104,119,120,124,126,127,128,130,131,132,133,135,137,139,140,141,142,148,149,150,154,158,159,161,162,164,165,169,170,171,172,174,177,184,185,186,187,188,191,192,193,194,198,199,204,206,209,210,211,212,213,215,217,218,223,224,225,226,228,229,230,232,234,238,251,257,270,275,276,278,283,286,289,292,299,308,309,310,311,312,316,329,335,338,340,354,359,364,370,372,380,393,394,397,398,402,403,406,408,409,410,415,416,420,425,431,436,454,455,457,459,460,461,464,466,467,469,470,472,479,486,487,490,492,493,495,500,501,508,513,540,543,545],check_attr:218,check_character_flag:275,check_circular:445,check_databas:416,check_db:416,check_defeat:162,check_end_turn:164,check_error:415,check_evennia_depend:492,check_flag:[275,276],check_from_attr:218,check_grid:132,check_has_attr:218,check_light_st:372,check_loc:238,check_lock:513,check_lockstr:[33,124,394],check_main_evennia_depend:416,check_mixtur:275,check_obj:218,check_perm:276,check_permiss:402,check_permstr:[204,466],check_to_attr:218,check_warn:415,checkbox:177,checker:[16,132,393,436,493,497,545],checklockstr:143,checkout:[11,75,193],checkoutdir:2,checkpoint:545,cheer:99,chemic:293,cheng:77,chest:[39,90,142,152,153],chicken:273,child:[18,22,28,33,41,118,123,143,149,150,152,161,164,205,207,213,218,229,273,275,278,292,372,397,403,406,461,484,515],childhood:28,children:[22,46,48,123,125,146,171,207,340,397,398,406,416,465,466,484,510,538,545],chillout:218,chime:19,chines:[64,70,126,180],chip:135,chmod:2,choci:241,choic:[16,22,28,30,41,42,44,45,70,72,82,92,99,104,113,122,124,142,150,151,152,154,161,164,176,179,182,191,204,215,218,241,242,270,283,308,380,414,474,476,479,545],choice1:72,choice2:72,choice3:72,choicefield:[500,501,505,506,508,510],choos:[7,14,28,30,53,54,73,74,75,78,104,111,113,118,120,123,132,134,136,141,146,157,158,162,164,165,173,175,177,189,308,309,310,311,312,364,366,370,386,429,476,479,490,491,545],chop:[22,371],chore:156,chose:[28,67,135,151,177,184,194,198,386,476],chosen:[7,28,68,76,95,164,176,346,380,476,479],chown:193,chractercmdset:372,chraract:337,chri:77,christa:77,christian:77,chrome:183,chronicl:[92,380],chroot:187,chug:22,chunk:[14,80,137,170,238,418,470],church:[19,157],church_clock:19,churn:161,cid:448,cillum:29,cinemat:[278,280],circl:130,circuit:51,circular:[418,471],circumst:[28,71,96,134,141,148,150,151,161,211,311,532],circumv:216,cis:495,citi:[31,118,158,337],citymap:118,cjust:[30,479],clang:190,clank:[95,97],clarifi:126,clariti:[64,67,142,152,165,190,293],clash:[20,31,154,182,191,218,466,476],class_from_modul:492,classic:[14,44,46,47,149,158,164,167,180],classmethod:[130,204,232,292,294,317,340,390,398,409,466,483,526],classnam:[13,64,152],classobj:466,clatter:28,claus:[77,172,179],clean:[11,13,17,18,28,115,124,126,127,149,150,155,161,164,170,199,211,213,218,228,276,278,283,293,308,309,310,311,312,329,350,371,372,398,406,416,420,434,444,457,466,469,474,476,483,488,491,492,500,501,508,532,545],clean_attr_valu:501,clean_attribut:[48,204,466],clean_cmdset:[48,466],clean_senddata:457,clean_stale_task:410,clean_str:469,clean_usernam:500,cleaned_data:177,cleaner:[142,152,165],cleanli:[44,92,123,199,209,213,266,380,418,427,433,444,457,474],cleanup:[13,22,27,28,62,76,277,278,283,289,292,369,372,476,500],cleanupscript:277,clear:[9,13,16,18,22,27,46,47,48,51,55,58,62,70,72,76,92,118,119,120,123,124,128,137,139,156,159,161,162,170,176,195,199,212,215,216,218,224,230,234,289,331,339,350,353,354,372,380,382,394,396,397,398,407,410,411,418,455,459,464,466,467,476,483],clear_all_sessid:396,clear_attribut:464,clear_client_list:452,clear_cont:[37,398],clear_exit:[37,398],clearal:[72,224],clearli:[9,55,95,119,149,483],cleartext:[78,206,377,472],clemesha:461,clever:[18,20,28,54,394],cleverli:44,click:[2,7,9,11,49,50,51,52,53,59,71,73,120,137,147,177,191,476],click_top:225,clickabl:[71,120,225,545],clickable_top:225,client:[2,5,9,22,27,29,30,32,34,44,45,49,52,55,59,60,62,69,70,75,76,78,104,118,120,122,123,126,129,139,142,144,148,149,150,151,158,164,167,169,170,171,175,180,181,182,184,185,186,187,189,190,193,194,195,197,198,201,202,204,205,213,215,218,223,225,228,230,338,340,377,412,413,417,419,421,425,426,427,428,429,430,431,432,434,436,438,439,440,441,443,444,445,447,448,454,455,456,457,473,474,476,491,492,512,515,541,545],client_address:62,client_class:516,client_default_height:29,client_disconnect:445,client_encod:182,client_gui:421,client_opt:[68,421,440,545],client_secret:186,client_typ:275,client_width:[22,213],clientconnectionfail:[413,427,428],clientconnectionlost:[413,427,428],clienthelp:51,clientkei:447,clientraw:228,clientsess:[444,445],clientwidth:143,cliff:[99,115,144,218],climat:46,climb:[5,22,122,218,275,371],climbabl:[275,371],clipboard:50,clock:[19,22,55,103,143,162,266],clone:[9,10,64,120,123,147,185,545],close:[7,11,15,27,28,44,48,51,52,62,76,82,90,95,96,97,104,108,109,114,120,123,126,130,137,149,151,152,177,187,191,193,194,199,228,230,238,239,241,251,275,277,283,312,322,346,364,369,418,426,427,434,436,444,445,457,464,470,476,479],close_menu:[369,476],closer:[312,349],closest:[60,112,130,354,492],cloth:[13,102,201,202,235,281,470,545],clothedcharact:[83,286],clothedcharactercmdset:[83,286],clothes_list:286,clothing_typ:[83,286],clothing_type_count:286,clothing_type_ord:286,cloud9:545,cloud:[42,77,104,176,191,193,194,238],cloud_keep:[99,104],cloudi:42,clr:[30,280,402,479],cls:[130,204,354],club:292,clue:371,clump:152,clunki:[11,312],cluster:182,clutter:[120,212],cma:11,cmd:[5,15,18,20,22,31,33,55,68,76,80,126,127,128,131,135,136,140,141,143,151,154,161,165,174,188,198,211,213,215,216,217,218,223,224,225,226,227,228,229,230,241,251,255,266,269,270,273,283,286,292,293,296,299,302,305,308,309,310,311,312,316,322,325,331,343,350,364,366,370,371,372,380,386,387,398,440,444,445,447,470,474,476,477,540],cmd_arg:142,cmd_channel:22,cmd_help_dict:225,cmd_help_top:540,cmd_ignore_prefix:[22,210],cmd_kei:142,cmd_last:44,cmd_last_vis:44,cmd_loginstart:22,cmd_multimatch:[22,209],cmd_na_m:68,cmd_name:[68,440],cmd_noinput:[22,209,476],cmd_nomatch:[22,209,372,476],cmd_noperm:22,cmd_on_exit:[28,274,369,380,386,400,476],cmd_or_top:[225,540],cmd_total:44,cmdabout:228,cmdaccept:283,cmdaccess:224,cmdaccount:228,cmdaddcom:266,cmdallcom:266,cmdapproach:312,cmdarmpuzzl:305,cmdasync:54,cmdattack:[128,162,164,165,308,309,310,311,312,371],cmdban:216,cmdbare:143,cmdbatchcod:217,cmdbatchcommand:217,cmdbigsw:128,cmdblindhelp:364,cmdblindlook:364,cmdblock:126,cmdboot:216,cmdbridgehelp:372,cmdbui:141,cmdbuildshop:141,cmdcallback:[95,255],cmdcast:[293,311],cmdcboot:266,cmdcdesc:266,cmdcdestroi:266,cmdchannel:[18,223,266],cmdchannelcr:266,cmdcharcreat:215,cmdchardelet:215,cmdclimb:371,cmdclock:266,cmdcloselid:364,cmdcolortest:215,cmdcombathelp:[308,309,310,311,312],cmdconfigcolor:139,cmdconfirm:22,cmdcopi:218,cmdcover:286,cmdcpattr:218,cmdcraft:[86,292],cmdcraftarmour:128,cmdcreat:218,cmdcreatenpc:165,cmdcreateobj:273,cmdcreatepuzzlerecip:305,cmdcwho:266,cmddarkhelp:372,cmddarknomatch:372,cmddeclin:283,cmddefend:164,cmddelcom:266,cmddesc:[218,316],cmddestroi:218,cmddiagnos:129,cmddice:[88,135,343],cmddig:218,cmddisengag:[164,308,309,310,311,312],cmddoff:309,cmddon:309,cmddrop:[224,286],cmddummi:269,cmddummyrunnerechorespons:447,cmdeast:372,cmdecho:[22,120,128,143,150,490],cmdedit:[82,241],cmdeditnpc:165,cmdeditorbas:474,cmdeditorgroup:474,cmdeditpuzzl:305,cmdemit:216,cmdemot:[273,350],cmdentertrain:174,cmdevalu:283,cmdevenniaintro:372,cmdevmenunod:476,cmdevscaperoom:273,cmdevscaperoomstart:[90,273],cmdexamin:218,cmdexiterror:131,cmdexiterroreast:131,cmdexiterrornorth:131,cmdexiterrorsouth:131,cmdexiterrorwest:131,cmdextendedroomdesc:[91,316],cmdextendedroomdetail:[91,316],cmdextendedroomgametim:[91,316],cmdextendedroomlook:[91,316],cmdfeint:164,cmdfight:[308,309,310,311,312],cmdfind:218,cmdfinish:283,cmdfocu:273,cmdfocusinteract:273,cmdforc:216,cmdget:[126,150,224,273],cmdgetinput:476,cmdgetweapon:371,cmdgive:[224,286],cmdgiveup:273,cmdgmsheet:135,cmdgoto:331,cmdgrapevine2chan:223,cmdhandler:[20,22,37,65,148,201,202,204,208,210,211,212,213,215,226,227,228,229,230,273,305,316,372,397,398,406,490,492,545],cmdhelp:[31,164,225,273,308,309,310,311,312],cmdhit:[143,150,164],cmdhome:224,cmdic:215,cmdid:421,cmdinsid:174,cmdinterrupt:229,cmdinventori:[140,224,286],cmdirc2chan:223,cmdircstatu:223,cmdjumpstat:273,cmdlaunch:125,cmdlearnspel:311,cmdleavetrain:174,cmdlen:[210,227],cmdlight:371,cmdline:416,cmdlineinput:474,cmdlink:218,cmdlistarmedpuzzl:305,cmdlistcmdset:218,cmdlistpuzzlerecip:305,cmdlock:218,cmdlook:[4,129,224,273,316,372],cmdlookbridg:372,cmdlookdark:372,cmdmail:[98,299],cmdmailcharact:[98,299],cmdmakegm:135,cmdmap:331,cmdmapbuild:99,cmdmask:350,cmdmobonoff:370,cmdmore:477,cmdmoreexit:477,cmdmultidesc:[102,134,302],cmdmvattr:218,cmdmycmd:[31,133],cmdmylook:8,cmdname2:210,cmdname3:210,cmdname:[32,51,62,65,68,143,161,165,209,210,213,218,226,227,229,421,439,440,444,445,457,490],cmdnamecolor:[113,386],cmdnewpassword:216,cmdnick:224,cmdnoinput:241,cmdnomatch:241,cmdnositstand:161,cmdnpc:165,cmdnudg:364,cmdobj:[209,210,227,490],cmdobj_kei:209,cmdobject:[209,210,218],cmdobjectchannel:[18,223],cmdoffer:283,cmdooc:215,cmdooclook:215,cmdopen:[218,322,331],cmdopenclosedoor:322,cmdopenlid:364,cmdoption:[215,273],cmdpage:223,cmdparri:164,cmdparser:[195,201,202,208,545],cmdpass:[308,309,310,311,312],cmdpassword:215,cmdperm:216,cmdplant:[116,270],cmdpose:[164,224,350],cmdpressbutton:371,cmdpush:95,cmdpushlidclos:364,cmdpushlidopen:364,cmdpy:228,cmdquell:215,cmdquit:215,cmdread:371,cmdrecog:350,cmdreload:228,cmdremov:286,cmdrerout:273,cmdreset:228,cmdrest:[308,309,310,311,312],cmdroll:142,cmdrss2chan:223,cmdsai:[164,224,350],cmdsaveyesno:474,cmdscript:218,cmdsdesc:350,cmdser:476,cmdserverload:228,cmdservic:228,cmdsession:215,cmdset:[3,6,12,15,18,20,22,26,28,31,37,42,44,62,64,76,79,86,88,90,91,93,95,98,103,105,108,110,118,121,125,126,131,134,136,137,139,141,147,148,149,161,164,165,174,201,202,204,208,209,210,212,213,218,219,220,221,222,226,227,228,229,241,255,266,270,273,283,286,292,296,299,305,308,309,310,311,312,316,322,325,331,343,350,364,366,369,370,371,372,397,398,406,447,454,455,466,474,476,477,490,492,510,545],cmdset_account:[12,201,202,208,214,545],cmdset_charact:[201,202,208,214,286,308,309,310,311,312,545],cmdset_creat:79,cmdset_mergetyp:[28,274,369,380,400,476],cmdset_prior:[28,274,369,380,400,476],cmdset_sess:[44,201,202,208,214,545],cmdset_stack:212,cmdset_storag:[207,397,455],cmdset_trad:283,cmdset_unloggedin:[22,89,100,201,202,208,214,251,545],cmdsetattribut:218,cmdsetclimb:371,cmdsetcrumblingwal:371,cmdsetdesc:224,cmdsetevenniaintro:372,cmdsetevscaperoom:273,cmdsetflag:273,cmdsethandl:[44,201,202,208,545],cmdsethelp:225,cmdsethom:218,cmdsetkei:20,cmdsetkeystr:211,cmdsetlegacycomm:[103,266],cmdsetlight:371,cmdsetmor:477,cmdsetobj:[211,212,219,220,221,222,241,266,273,283,286,292,305,308,309,310,311,312,316,322,325,331,343,350,364,366,369,370,371,372,447,474,476,477],cmdsetobjalia:218,cmdsetpow:165,cmdsetread:371,cmdsetsit:161,cmdsetspe:[110,325],cmdsettestattr:27,cmdsettrad:[79,283],cmdsettrain:174,cmdsetweapon:371,cmdsetweaponrack:371,cmdsheet:135,cmdshiftroot:371,cmdshoot:[125,312],cmdshutdown:228,cmdsit2:161,cmdsit:161,cmdsmashglass:364,cmdsmile:22,cmdspawn:218,cmdspeak:273,cmdspellfirestorm:127,cmdstand2:161,cmdstand:[161,273],cmdstatu:[283,311,312],cmdstop:[110,325],cmdstring:[22,135,143,209,213,226,229,490],cmdstyle:215,cmdtag:218,cmdtalk:366,cmdtask:228,cmdteleport:[218,331],cmdtest:[3,128,142],cmdtestid:22,cmdtestinput:28,cmdtestmenu:[28,92,380,476],cmdticker:228,cmdtime:[136,228],cmdtrade:283,cmdtradebas:283,cmdtradehelp:283,cmdtunnel:218,cmdtutori:372,cmdtutorialgiveup:372,cmdtutoriallook:372,cmdtutorialsetdetail:372,cmdtweet:188,cmdtypeclass:218,cmdunban:216,cmdunconnectedconnect:[230,251],cmdunconnectedcr:[230,251],cmdunconnectedencod:230,cmdunconnectedhelp:[230,251],cmdunconnectedinfo:230,cmdunconnectedlook:[230,251],cmdunconnectedquit:[230,251],cmdunconnectedscreenread:230,cmduncov:286,cmdunlink:218,cmdunwield:309,cmduse:310,cmdusepuzzlepart:305,cmdwait:22,cmdwall:216,cmdwear:286,cmdwerewolf:126,cmdwest:372,cmdwhisper:224,cmdwho:[215,273],cmdwield:309,cmdwipe:218,cmdwithdraw:312,cmdxyzopen:331,cmdxyzteleport:331,cmdyesnoquest:476,cmset:[212,510],cmud:183,cnf:[2,182],coal:[292,293],coast:[155,170],coastal:170,cobj:273,cockpit:125,code:[2,5,6,7,8,12,15,16,20,22,24,28,30,31,33,34,37,39,41,44,46,47,48,49,50,52,53,54,55,56,57,60,61,62,64,67,68,72,73,75,77,79,80,82,85,86,90,96,97,99,104,107,112,115,118,121,122,123,124,128,130,132,133,134,135,136,137,138,142,144,146,147,148,149,150,152,153,154,155,157,159,160,161,163,164,165,166,168,169,170,171,172,174,175,176,178,180,182,185,192,193,194,195,197,199,201,202,204,208,209,212,215,217,218,223,225,228,231,235,241,247,254,257,270,275,278,281,283,289,291,310,337,343,346,372,382,394,403,406,427,428,444,455,458,466,468,469,474,476,478,489,490,491,492,499,541,544,545],code_exec:470,code_hint:275,code_tri:275,codebas:[11,72,74,120,122,133,153,229],codeblock:120,codec:469,codefunc:474,codeinput:275,coder:[0,1,76,90,104,133,156,158,159,180,209,398],coding_styl:120,coerc:487,coexist:175,coher:166,coin:[79,104,119,152,153,156,157,283,545],col:[56,167,478],cold:[55,199,228,403,407,411,454],cole:492,coll_date_func:228,collabor:[11,90,123,124,156,159,191,225,545],collat:[31,65,402],collect:[0,13,20,30,31,49,105,118,152,169,209,211,225,228,305,354,464,492,518,540],collect_top:[225,540],collector:169,collectstat:[51,53,169,416,420],collid:[20,41,112,184,191,275,354,476,479],collis:[20,22,459],collist:152,colon:[19,33,95,144,151,394],color:[18,22,26,28,30,32,41,51,56,71,72,94,104,113,118,120,121,132,135,137,138,143,144,151,170,180,185,213,215,243,244,245,270,280,293,337,338,340,346,350,369,386,398,402,421,428,436,439,444,445,469,478,479,486,490,491,493,545],color_ansi_bright_bg_extra_map:[84,244],color_ansi_bright_bgs_extra_map:[84,244],color_ansi_extra_map:[84,244],color_markup:[84,201,202,235,236,545],color_no_default:[84,244],color_typ:469,color_xterm256_extra_bg:[84,244],color_xterm256_extra_fg:[84,244],color_xterm256_extra_gbg:[84,244],color_xterm256_extra_gfg:[84,244],colorablecharact:139,colorback:491,colorcod:491,colour:[19,218,443,469,478,545],column:[51,56,58,67,95,96,117,118,120,123,132,135,137,170,213,215,329,340,478,492],com:[0,8,9,10,11,40,49,53,54,56,64,69,73,75,76,77,85,90,96,120,122,130,149,153,155,156,170,177,180,181,182,184,185,187,190,191,192,193,194,201,223,228,241,251,289,391,428,431,440,444,461,478,491,492,532,544],coman:77,combat:[11,15,20,28,41,48,69,96,104,114,115,122,123,126,127,138,143,148,149,155,157,158,162,163,170,171,180,185,212,308,309,310,311,312,370,406,545],combat_:[308,309,310,311,312],combat_cleanup:[308,309,310,311,312],combat_cmdset:164,combat_handl:164,combat_handler_:164,combat_movesleft:[308,309,310,311],combat_scor:165,combat_status_messag:312,combatcmdset:164,combathandl:164,combatscor:165,combin:[8,13,19,20,22,34,35,41,46,47,55,60,86,104,105,112,118,122,127,129,134,135,144,146,150,151,158,172,174,181,187,191,209,210,211,218,275,292,293,302,305,338,340,349,354,364,394,402,405,411,416,465,467,472,479,486,490,492],combo:44,come:[5,11,12,13,16,19,22,28,29,31,33,42,44,51,52,53,54,56,60,62,65,68,72,73,90,91,95,96,104,115,118,122,123,124,125,126,128,132,134,135,136,137,141,142,144,148,149,151,152,156,158,159,161,162,164,165,167,170,172,174,175,177,178,182,187,193,198,204,211,308,309,310,311,312,316,350,382,402,403,434,439,444,445,447,453,469,477,515,541],comet:[51,62,445],comfi:161,comfort:[11,16,122,137,142,159,545],comg:49,comlist:266,comm:[18,22,26,35,121,123,147,188,201,202,208,214,265,266,267,472,498,499,523,537,545],comma:[18,50,58,67,95,96,144,151,152,178,182,218,226,260,292,299,394,398,479,492],comman:144,command:[0,2,5,7,8,9,11,12,13,14,16,18,19,23,27,28,29,32,33,35,36,37,39,40,41,44,46,48,50,51,52,54,55,57,58,59,60,61,62,63,64,65,67,68,69,70,71,72,74,75,78,79,80,82,83,85,86,88,90,92,93,96,97,99,102,104,105,106,108,109,110,111,113,114,115,117,118,120,122,123,124,125,132,133,134,137,138,144,145,147,153,155,156,158,159,162,169,170,171,172,173,175,180,181,182,183,185,186,187,189,190,191,192,194,195,198,199,201,202,204,205,232,233,235,236,241,250,251,253,256,258,265,266,268,269,270,271,272,274,275,280,283,286,289,292,293,294,296,299,302,305,308,309,310,311,312,314,316,322,325,329,330,332,333,343,350,362,364,366,369,370,371,372,377,380,386,387,388,389,390,391,393,394,398,402,403,406,413,416,421,425,426,434,436,439,440,444,445,447,448,454,455,466,468,469,472,474,476,477,486,489,490,492,518,540,541,544,545],command_default_arg_regex:22,command_default_class:126,command_default_help_categori:31,command_pars:210,commandhandl:[32,212,227],commandmeta:213,commandnam:[22,32,65,144,270,416,425,455,457],commandset:[33,37,143,212],commandtestmixin:490,comment:[14,15,28,48,75,80,126,143,161,172,181,183,191,337,470,476,545],commerc:180,commerci:[7,159,191],commerror:233,commit:[2,9,10,16,63,69,119,120,123,126,182,192,193,376,501,508,545],commmand:[109,308,309,310,311,312,322],commom:545,common:[0,6,8,11,16,18,19,22,28,32,33,41,42,44,45,46,47,48,54,55,56,58,62,65,68,70,79,86,104,106,110,120,121,123,129,136,137,142,144,145,148,149,151,152,153,156,158,159,160,162,164,165,177,185,187,191,211,218,223,230,283,292,325,349,350,394,396,406,421,444,448,465,466,475,477,487,489,492,518,525,541],commonli:[9,30,31,36,42,44,45,47,53,58,65,67,95,112,118,123,146,150,158,182,185,195,338,354,398,490,518],commonmark:120,commun:[7,18,22,35,40,51,52,62,65,68,70,76,77,78,104,121,122,123,134,142,143,147,148,149,158,159,180,181,182,189,191,194,204,220,223,230,231,232,233,234,273,299,339,369,397,405,413,425,426,436,437,439,440,441,442,455,457,472,473,488,544,545],compact:[141,146,178,364],compani:[68,123],compar:[6,8,11,14,16,19,20,65,75,95,99,106,112,118,124,127,128,131,135,141,142,146,159,162,164,165,305,308,309,310,311,312,349,354,393,394,403,447,469,490,492],comparison:[5,14,30,146,147,353,393,403,476,490],compartment:135,compass:144,compat:[15,28,77,112,113,125,218,354,478,485,492],compet:[16,68,158],compil:[5,22,64,69,75,120,133,148,185,190,191,213,218,224,225,228,230,273,286,292,350,469,474,476,491],compilemessag:64,complain:[3,9,67,142,161,199],complement:[0,45,159,354],complementari:[24,30,41,42,70],complet:[2,5,9,11,12,13,14,15,16,19,20,22,27,37,39,41,44,45,50,52,54,68,76,78,84,85,94,95,99,104,115,119,123,126,131,132,135,136,139,141,146,150,151,155,156,157,158,159,165,170,182,187,191,195,198,199,204,211,212,213,226,228,229,244,257,271,289,309,316,338,346,364,372,380,398,410,416,418,426,427,444,464,470,475,476,477,489,492,513,532,545],complete_task:257,complex:[5,15,16,20,22,30,47,58,67,69,90,95,104,107,111,118,120,123,136,144,148,150,151,152,153,156,157,158,161,162,164,165,170,193,195,212,232,258,275,364,366,382,403,448,464,545],complianc:[183,316],compliant:[130,440],complic:[54,76,92,97,113,128,132,137,142,146,170,177,178,191,230,251,380,386,464],compon:[0,5,8,22,35,42,49,50,51,53,60,61,62,73,118,120,128,132,135,138,147,156,159,164,165,166,168,191,199,201,202,218,228,233,234,235,238,247,292,305,314,330,337,339,349,353,396,403,404,405,406,409,416,445,472,475,479,489,492,495,521,544,545],componenta:4,componentid:51,componentnam:51,componentst:51,compos:[92,193,380],composit:[442,465],comprehens:[5,8,33,35,48,122,157,161,185,194],compress:[32,421,425,429,488],compress_object:488,compris:204,compromis:[194,376],comput:[11,47,54,55,70,123,132,133,146,147,158,162,176,185,189,193,198,216,228,350,492,493,545],computation:47,comsystem:234,con:[26,135,180,230,251],concaten:[148,469],concept:[11,40,47,62,64,85,96,102,104,119,120,130,134,137,138,139,151,152,154,156,157,161,289,302,354,544,545],conceptu:[28,132],concern:[64,68,95,104,118,131,151,185,211,382,390],conch:[436,439,447],concis:159,conclud:[146,283,476,545],conclus:545,concret:95,concurr:182,conda:75,conder:470,condit:[5,30,58,88,95,96,104,114,122,132,141,142,143,146,150,156,157,162,165,181,209,225,310,343,350,394,398,409,415,416,461,467,492,545],condition:126,condition_result:343,condition_tickdown:310,conditional_flush:483,conduct:169,conductor:174,conect:457,conf:[2,5,8,11,24,25,32,33,41,42,50,53,62,64,67,73,75,78,84,86,90,95,99,100,118,120,124,126,136,137,139,149,161,173,174,177,178,181,182,184,186,187,191,194,204,244,292,332,334,416,422,423,462,470,545],confer:[180,492],confid:[3,119,130],config:[2,7,10,11,12,30,62,75,124,185,187,191,192,238,354,416,418,422,423,434,507,545],config_1:12,config_2:12,config_3:12,config_color:139,configcmd:139,configdict:[436,457],configur:[2,8,12,50,95,97,120,123,126,136,137,138,148,169,173,184,185,191,193,194,204,207,210,215,238,270,354,376,377,418,423,434,457,459,461,462,465,532,545],configut:7,confirm:[22,51,77,89,118,144,181,185,194,218,251,305,440,443,543],conflict:[3,158,175],confus:[0,5,6,11,20,22,36,39,42,51,54,60,64,74,76,89,95,118,120,123,131,135,142,146,149,152,169,175,191,223,251,338,542],congratul:545,conid:435,conj:[30,58,398,479],conjug:[30,58,201,202,398,468,479,494,497,545],conjunct:95,conjur:[114,311],conn:[26,230,251],conn_tim:44,connect:[5,8,12,13,14,17,18,20,22,24,26,32,37,39,40,42,44,45,48,50,51,52,53,55,60,62,63,64,65,68,71,75,78,89,90,94,95,96,97,99,100,104,110,115,118,122,123,124,126,132,134,137,141,142,144,146,147,148,149,150,158,165,169,170,173,175,181,182,183,185,186,187,189,192,193,194,195,198,199,204,205,206,207,215,216,218,223,230,232,233,234,238,250,251,254,255,257,266,325,335,337,338,340,346,377,397,398,404,412,413,416,418,425,426,427,428,429,434,435,436,439,444,445,447,448,454,455,456,457,458,461,464,466,472,488,515,518,545],connection_cr:45,connection_screen:[25,89,100,148,195,201,202,235,236,249,251,261,545],connection_screen_modul:[89,100,251],connection_set:184,connection_tim:[204,398],connection_wizard:[201,202,412,545],connectiondon:418,connectionlost:[418,425,426,436,439,447],connectionmad:[413,425,436,439,447],connectionwizard:414,connector:[413,427,428,434,457],conquer:155,cons3:294,consecut:28,consequ:[191,212],consid:[0,5,6,13,14,15,18,19,20,22,28,30,32,33,39,41,42,44,46,47,48,50,52,54,55,58,60,62,67,70,73,86,92,96,97,105,106,112,118,119,122,123,124,130,131,134,140,141,146,148,151,153,156,157,159,161,174,177,178,179,182,185,191,194,204,211,212,270,289,305,312,335,337,338,349,350,354,380,398,402,403,406,421,436,439,465,467,470,471,476,477,479],consider:[67,78,149,158,170,172,195,403,478],consist:[12,13,17,22,28,31,33,40,41,51,58,60,67,73,96,99,106,118,120,131,136,151,154,155,157,164,165,199,204,210,225,226,232,233,247,283,293,305,339,349,387,394,403,440,445,455,464,466,472,478,490,492,501,508,543],consitut:149,consol:[0,3,6,7,51,57,60,64,75,77,120,123,149,151,152,154,165,182,185,190,191,193,198,225,228,339,350,416],conson:[106,349],constant:[68,97,425,490],constantli:[171,372],constitu:[212,226],constitut:13,constraint:[97,182],construct:[2,123,128,161,177,403,460,464,469,477,532],constructor:[22,76,86,112,241,292,354,427],consum:[54,86,104,275,292,293,294,418,492],consumable_kwarg:292,consumable_nam:292,consumable_tag:[86,292,293],consumable_tag_categori:[86,292],consume_flag:275,consume_on_fail:292,consumer_kei:[173,188],consumer_secret:[173,188],consumpt:[5,182,459],contact:[18,37,191,193],contain:[0,6,9,13,14,15,17,20,22,26,28,30,31,33,35,37,41,44,51,52,53,54,56,60,62,67,72,75,76,78,90,92,93,95,96,97,99,104,106,107,110,113,114,116,118,119,120,121,122,123,125,126,130,133,134,136,137,142,143,144,146,147,148,149,150,151,157,161,165,169,172,175,177,178,180,185,190,195,198,201,202,204,205,206,208,209,210,211,212,214,217,218,223,225,231,238,241,254,255,256,257,258,260,270,273,292,296,305,310,325,329,337,338,339,340,349,350,354,364,371,377,378,380,382,386,388,389,392,398,400,402,403,410,412,415,419,421,447,459,460,461,464,465,466,467,468,469,470,473,475,476,477,478,479,489,490,491,492,493,515,521,530,540,541,543,545],container:193,contempl:133,content:[5,11,14,17,19,30,35,37,48,50,51,52,53,56,80,90,95,104,120,124,125,130,132,133,135,137,140,141,142,146,148,150,151,153,154,158,159,160,161,163,165,166,167,168,171,174,177,178,180,187,191,213,216,218,238,239,275,276,331,350,388,396,397,398,467,469,470,471,474,476,478,489,490,498,508,515,521,530,544,545],content_typ:[397,398],contentdisposit:238,contentencod:238,contentof:478,contents_cach:397,contents_get:[153,398],contents_set:398,contentshandl:397,contest:[90,273],context:[53,60,95,96,122,137,142,154,175,177,241,257,437,441,525,537,538,540,541,543],context_processor:525,contextu:46,contibut:[80,104],continu:[1,3,13,19,22,28,46,47,53,54,59,67,77,95,96,99,104,118,119,122,125,128,132,135,137,141,143,150,151,164,165,169,188,190,191,238,338,398,414,425,461,464,476,485,492,545],contrari:[49,95,97,112,136,148,158,228,354,467],contrast:[39,42,70,133,191,440],contrib:[14,15,50,58,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,98,99,100,101,102,103,105,106,107,108,109,110,111,112,113,114,115,116,117,118,120,121,122,124,134,135,136,138,144,147,148,151,155,158,160,162,163,164,179,185,201,202,204,206,207,228,229,458,469,470,500,501,502,504,505,506,507,508,523,524,532,538,543,545],contribcloth:286,contribrpcharact:[106,350],contribrpobject:[106,350],contribrproom:[106,350],contribu:11,contribut:[0,8,11,64,76,77,78,79,81,83,85,86,88,90,91,92,93,94,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,123,124,140,147,157,169,179,197,198,235,244,270,283,286,299,305,316,322,325,343,350,366,376,377,382,544,545],contributor:[77,179,241,354],control:[1,2,3,4,9,12,14,15,18,20,22,27,28,29,30,31,32,33,37,40,41,42,44,49,50,55,57,58,60,65,67,69,73,75,77,79,80,86,104,108,118,119,120,121,123,125,134,135,139,144,146,147,148,149,150,154,156,158,159,162,165,172,174,185,187,191,194,197,199,204,205,215,217,218,223,256,266,275,283,329,340,350,364,370,372,393,398,406,416,455,457,466,476,479,490,513,532,545],contrub:86,convei:[350,398],convenei:45,conveni:[2,7,18,28,31,32,33,37,39,41,42,48,53,54,62,67,69,74,75,82,99,118,120,122,125,134,137,149,150,151,153,154,177,181,192,199,204,218,228,241,278,280,292,299,398,448,459,470,471,476,477,479,485,488,489],convent:[20,45,67,97,146,175],convention:[213,398,466],convers:[18,28,30,36,86,104,111,174,349,366,444,445,469,492,544],convert:[9,13,18,19,36,41,60,62,65,68,70,87,92,118,119,123,130,132,136,139,141,146,149,154,161,175,180,194,206,216,247,337,343,380,386,393,396,402,403,405,407,425,427,436,439,440,457,461,469,473,476,477,478,479,480,488,491,492,495,515,545],convert_linebreak:491,convert_url:491,convinc:[28,191],cool:[0,75,76,95,125,156,167,180,218,223],cool_gui:39,cooldown:[128,164,201,202,235,281,545],cooldownhandl:[85,289],coord:[130,335,337,338,340],coordi:130,coordin:[51,99,104,117,118,132,312,329,331,337,338,339,340,545],coordx:130,coordz:130,cope:311,copi:[0,2,5,9,11,14,15,22,26,27,28,41,44,49,50,51,53,73,77,90,97,104,123,124,126,136,139,143,144,147,148,165,169,170,177,187,191,193,195,217,218,257,286,308,309,310,311,312,372,396,398,405,416,425,462,469,485,540,541,545],copy_object:[396,398],copy_script:405,copy_word_cas:492,copyright:[179,191],core:[7,11,37,48,57,64,68,87,98,104,119,132,147,152,157,179,195,204,207,228,234,235,238,293,299,390,397,398,406,412,423,433,440,454,464,466,467,470,477,484,490,532,543,544,545],corner:[17,115,117,118,130,134,180,329,337,478],corner_bottom_left_char:478,corner_bottom_right_char:478,corner_char:478,corner_top_left_char:478,corner_top_right_char:478,corpu:[106,349],correct:[15,19,20,22,27,30,53,54,60,70,115,119,120,125,129,142,149,152,159,165,174,175,182,209,215,218,233,275,305,316,337,350,360,394,431,434,436,442,456,469,490,492],correctli:[2,3,6,19,22,27,28,46,47,75,118,120,124,128,131,132,136,141,142,148,165,174,175,181,189,191,199,204,207,212,215,238,292,407,416,425,461,488,515],correl:403,correspond:[22,33,44,53,73,99,105,118,141,144,247,305,386,464,501,508,513,532],correspondingli:9,corrupt:133,cosi:170,cosin:492,cosmet:329,cost:[117,118,127,141,191,238,311,329,350,545],cottag:[59,170],couchdb:77,could:[2,3,5,7,8,9,12,13,14,15,16,18,20,22,28,30,31,33,34,35,36,37,39,41,42,46,47,48,53,54,55,57,58,60,62,65,67,68,69,70,72,73,74,75,76,79,82,86,90,95,96,97,104,107,110,112,113,118,120,122,123,124,125,126,127,128,129,130,131,132,134,135,136,137,139,140,141,142,143,144,146,148,149,150,151,152,154,156,157,158,159,161,162,164,165,167,169,170,171,172,173,174,175,176,177,180,185,186,187,188,189,191,192,204,212,218,225,233,234,241,260,275,276,283,292,325,329,338,340,343,346,350,353,354,364,372,382,386,394,398,409,421,440,445,461,466,467,469,470,474,478,479,480,483,487,492,496],couldn:[57,74,123,130,131,142,143,151,175,178,382],count:[18,49,52,114,123,146,149,151,164,173,195,206,211,286,289,310,386,398,430,434,447,451,457,459,465,469,476,479,485,496],count_loggedin:434,count_queri:451,countdown:[42,128,144],counter:[9,42,44,76,128,137,141,157,164,201,205,235,341,352,353,372,434,447,448,455,476,545],counterpart:[14,60,157,421,457,473],countertrait:354,countri:216,coupl:[11,39,76,110,137,171,193,232,325],cours:[0,5,7,10,16,22,47,53,55,69,74,75,76,78,86,95,96,97,104,115,118,120,123,124,125,134,142,149,150,151,152,155,156,165,176,179,198,309,312,369],court:115,courtesi:55,cousin:[72,95,104,142],cover:[0,11,14,15,31,53,61,62,66,67,75,83,95,108,118,119,128,134,146,147,148,150,151,157,158,159,173,180,181,182,185,191,197,275,286,293,316,338,364,372,398,492],coverag:8,coveral:8,cpanel:191,cpattr:[26,143,218],cprofil:545,cpu:[5,55,191,194,228],cpython:5,crack:67,craft:[33,58,92,105,128,156,170,201,202,235,281,380,545],craft_recipe_modul:[86,292],craft_recipes_modul:292,craft_result:292,crafted_result:292,crafter:[292,293,294,545],crafting_consumable_err_msg:292,crafting_materi:[86,292,293],crafting_recipe_modul:86,crafting_result:292,crafting_skil:86,crafting_tool:[86,292],crafting_tool_err_msg:292,craftingcmdset:292,craftingerror:292,craftingrecip:[86,292,293,294],craftingrecipebas:[86,292],craftingvalidationerror:[86,292],craftrecip:292,cram:155,crank:47,crash:[0,151,156,170,180,194,420,464],crate:[36,144],crave:197,crawl:194,crawler:[230,430],cre:[26,230,251],creat:[0,3,5,7,8,10,11,13,14,15,16,18,20,25,26,27,28,30,31,33,35,36,39,41,42,44,45,46,49,50,51,53,56,57,61,62,63,69,72,73,74,75,76,77,79,80,82,83,86,90,91,92,96,99,101,102,103,104,105,106,107,108,111,112,113,115,117,118,119,120,122,123,124,126,128,130,131,132,133,134,135,136,139,141,142,146,148,150,152,153,154,155,156,157,159,160,161,162,163,164,166,168,169,171,172,173,176,178,179,180,182,184,185,186,188,189,190,191,194,195,198,201,202,204,205,206,207,210,211,212,213,215,218,223,224,225,226,227,228,229,230,232,233,234,238,239,241,242,245,247,251,256,257,258,260,266,270,273,274,275,276,277,278,280,283,286,292,293,294,296,299,302,305,308,309,310,311,312,316,322,329,337,338,339,340,343,349,350,354,359,364,366,369,370,371,372,377,380,382,386,388,389,390,394,396,397,398,400,401,402,403,405,406,409,410,411,413,416,420,421,426,428,429,434,436,437,441,448,454,456,457,459,461,464,465,466,467,468,469,470,471,474,475,476,478,479,480,485,490,492,500,505,512,517,518,533,536,538,540,541,542,543,545],creataion:335,create_:[37,48],create_account:[19,45,48,121,201,206,472,490],create_attribut:464,create_cal:204,create_channel:[18,19,121,201,223,232,233,472],create_char:490,create_charact:[204,398],create_default_channel:454,create_delai:410,create_evscaperoom_object:280,create_exit:[218,322],create_exit_cmdset:398,create_fantasy_word:280,create_forward_many_to_many_manag:[207,234,390,397,406,464,466,467,484],create_game_directori:416,create_grid:132,create_help:389,create_help_entri:[19,31,121,201,472],create_kwarg:403,create_match:210,create_messag:[19,35,121,201,233,472],create_obj:490,create_object:[8,13,14,19,33,37,48,80,86,99,121,141,145,165,170,177,201,278,280,292,364,396,398,403,420,470,472,545],create_prototyp:[402,403],create_room:490,create_script:[19,42,48,95,121,133,164,201,405,409,470,472,490],create_secret_kei:416,create_settings_fil:416,create_superus:416,create_tag:465,create_wild:[117,329],createbucket:77,created_on:254,createnpc:545,createobj:273,creater:121,createview:542,creation:[6,11,13,15,28,33,37,44,48,67,74,78,99,118,120,125,135,139,144,145,147,149,156,158,163,165,170,177,180,201,204,207,218,223,225,232,277,292,305,308,309,310,311,312,322,331,337,340,350,354,371,372,377,390,396,397,398,403,406,411,449,466,472,474,475,476,478,500,501,505,508,532,536,538,543,544,545],creation_:472,creativ:[69,158],creator:[28,33,74,121,159,165,170,180,225,232,308,309,310,311,312,398,478],creatur:545,cred:[11,436],credenti:[11,52,53,77,191,194,204,436],credentialinterfac:436,credit:[11,119,151,191,194,491,492,545],creset:11,crew:146,criteria:[28,104,107,146,233,256,382,402,465,489],criterion:[11,146,149,150,155,204,283,350,389,396,398,405,408,489,492],critic:[0,6,9,20,42,44,57,60,90,185,187,394,415,416,485],critici:466,cron:187,crontab:187,crop:[30,60,135,337,475,478,479,492,545],crop_str:478,cross:[115,118,170,293,335,338,372,478],crossbario:444,crossbow:128,crossmaplink:[118,338],crossroad:170,crowd:[156,194],crt:[181,187],crucial:[47,142],crucibl:293,crucible_steel:293,cruciblesteelrecip:293,crud:[517,518],crude:[97,292,293],crumblingwal:371,crumblingwall_cmdset:371,crush:125,crypt:155,cryptocurr:194,cscore:165,csessid:[434,444,445,457],csession:[444,445],csrf_token:177,css:[17,50,51,53,71,73,122,148,169,238,491,521],cssclass:51,ctrl:[5,53,151,154,185,187,191,193,198,199,447],cuddli:[149,152],culpa:29,cumbersom:[9,28,174,386],cumul:448,cup:119,cupidatat:29,cur_valu:346,cure:[114,310,311],cure_condit:310,curi:132,curiou:69,curli:[84,244],curly_color_ansi_bright_bg_extra_map:[84,244],curly_color_ansi_bright_bgs_extra_map:[84,244],curly_color_ansi_extra_map:[84,244],curly_color_xterm256_extra_bg:[84,244],curly_color_xterm256_extra_fg:[84,244],curly_color_xterm256_extra_gbg:[84,244],curly_color_xterm256_extra_gfg:[84,244],curr_sess:457,curr_tim:316,currenc:[141,173],current:[5,6,7,8,9,11,12,14,15,18,19,20,22,26,27,28,30,32,37,39,42,43,44,46,47,51,52,53,55,57,58,60,67,75,76,77,79,82,91,92,94,95,96,97,99,104,107,112,114,118,123,125,126,127,128,132,135,141,143,144,146,147,148,149,150,152,157,161,164,165,173,174,177,180,187,193,195,198,204,206,207,209,210,212,213,215,216,218,223,224,225,227,228,230,238,241,257,260,266,273,275,278,283,286,292,302,308,309,310,311,312,316,322,325,329,331,338,340,346,350,353,354,362,369,371,372,380,382,386,389,396,397,398,403,406,410,411,416,421,426,432,433,436,437,440,448,455,457,459,465,466,474,476,478,479,480,485,486,489,492,500,515,537,538,540,541,545],current_choic:241,current_cmdset:218,current_coordin:329,current_kei:[401,402],current_tim:447,current_us:177,current_weath:42,current_weight:338,currentroom:174,curriculum:180,curs:[3,157],curtain:31,curv:[122,133],curx:132,cushion:161,custom:[0,6,12,13,15,16,17,19,20,22,25,26,32,36,37,41,46,48,52,55,56,58,61,63,65,67,74,77,78,83,85,92,93,95,97,99,104,106,112,114,115,117,118,121,122,123,125,126,129,132,133,135,137,138,141,144,146,148,150,155,156,157,158,161,162,164,165,169,171,172,174,175,176,177,179,180,186,188,191,193,195,199,204,205,206,207,209,211,212,213,218,223,224,225,230,232,246,247,248,257,260,273,274,275,276,278,283,286,289,292,296,305,316,329,333,337,338,349,350,354,364,369,371,372,376,377,380,388,389,396,398,400,401,402,403,405,411,416,420,422,425,447,456,466,471,474,476,477,478,483,486,487,490,491,492,499,500,502,507,517,518,523,524,541,545],custom_add:257,custom_cal:[257,260],custom_domain:238,custom_evennia_launcher_command:416,custom_gametim:[87,95,136,201,202,235,236,545],custom_helpstr:275,custom_kei:402,custom_pattern:[124,167,177,178],customis:[201,202,235,314,327,545],customiz:[17,82,94,104,106,161,241,346,350,364,380],customlog:181,customt:490,cut:[18,27,62,86,122,132,142,144,158,165,170,337,403],cute:169,cutoff:492,cvcc:349,cvccv:349,cvccvcv:349,cvcvcc:349,cvcvccc:349,cvcvccvv:349,cvcvcvcvv:349,cvcvvcvvcc:[106,349],cvv:349,cvvc:[106,349],cwho:[103,143,266],cyan:[60,175],cyberpunk:[18,153],cyberspac:180,cycl:[14,15,126,133,136,156,176,308,309,310,311,312],cyril:16,daemon:[5,78,181,187,193,194,199,433,461],daffodil:153,dai:[2,19,69,87,91,95,104,133,136,156,157,173,175,176,187,193,194,206,247,293,316,480,485,492,493,545],daili:36,dailylogfil:485,dali:[106,349],dalnet:223,dalton:146,dam:133,damag:[15,114,125,127,141,155,157,158,162,164,194,293,308,309,310,311,312,370,371],damage_rang:311,damage_taken:133,damage_valu:[308,309,310,311,312],damascu:293,danc:118,dandi:74,danger:[6,14,20,44,95,120,140,211],dare:[22,143,495],dark:[14,15,17,20,31,60,112,118,151,155,157,159,162,170,175,180,212,316,354,364,372,406,469,470],darkcmdset:372,darker:[60,175],darkgrai:175,darkroom:372,darkroom_cmdset:372,darkstat:372,dash:[95,107,120,382,386],dashcount:386,dashlin:30,data:[5,6,9,12,14,16,18,19,30,31,36,41,42,46,48,49,50,51,53,54,65,67,68,70,73,76,78,85,86,92,94,104,112,118,123,126,133,134,135,148,149,152,156,159,177,178,182,187,190,191,193,195,204,205,206,213,218,225,228,238,256,257,289,292,337,338,339,346,350,353,354,376,377,380,396,397,398,400,402,404,409,411,413,414,418,422,423,425,426,427,428,429,434,435,436,437,439,440,441,443,444,445,447,449,454,455,456,457,459,463,464,465,466,467,469,470,471,472,473,475,476,477,478,479,482,485,486,487,488,492,501,502,504,506,508,512,515,518,523,532,536,538,540,541,543,545],data_default_valu:354,data_in:[62,65,377,425,427,428,434,435,439,444,445,455,456,457],data_out:[62,377,434,436,439,440,445,455,456,457],data_to_port:413,data_to_serv:426,databa:416,databas:[2,5,8,10,11,13,14,16,17,18,19,20,23,32,33,34,35,36,37,42,44,45,46,47,48,49,50,52,53,55,57,73,74,77,78,91,95,97,104,117,118,120,122,123,124,125,127,128,130,133,134,135,142,143,145,147,148,150,151,153,156,157,158,161,164,165,169,170,177,178,182,185,193,195,197,198,199,204,206,207,211,212,218,225,228,232,233,234,256,257,311,316,339,340,350,372,387,388,389,390,393,396,397,398,402,404,405,406,407,410,411,416,420,422,433,447,454,463,464,465,466,467,470,472,473,481,483,488,489,492,498,502,505,506,508,518,545],dataclass:479,datareceiv:[418,425,439,447],dataset:402,datastor:67,date:[9,11,13,31,55,64,67,77,132,136,175,177,182,187,190,212,216,228,376,480,485,493],date_appli:177,date_cr:[48,204,207,234,390,406,464,466],date_join:[207,500],date_s:35,datetim:[48,136,177,238,247,317,464,480,485,486,492,493],datetime_format:492,datetimefield:[67,177,207,234,390,397,406,464,466,492,500],davewiththenicehat:540,david:[77,180],dawn:144,day_rot:485,daylight:157,db3:[5,9,11,148,170,182,198],db3_backup:5,db_:[34,48,67,146,350,396,398,407,421,489],db_account:[277,286,396,397,406,500,505],db_account__db_kei:505,db_account__id:512,db_account__usernam:512,db_account_id:[397,406],db_account_subscript:[234,502],db_attribut:[45,85,207,234,289,397,406,466,500,502,505],db_attribute_categori:354,db_attribute_kei:354,db_attributes__db_kei:146,db_attributes__db_value__gt:146,db_attrtyp:[464,515],db_attryp:36,db_categori:[67,146,464,467,508,515],db_category__iequ:67,db_cmdset_storag:[207,286,397,500,505],db_data:[467,508,515],db_date_cr:[67,207,234,277,286,390,397,406,464,466,500,502,504,505,506,515],db_desc:[277,406,512],db_destin:[286,397,500,505],db_destination__isnul:173,db_destination_id:397,db_entrytext:[390,504,515],db_header:[234,502],db_help_categori:[390,504,515],db_help_dict:225,db_help_top:540,db_hide_from_account:[234,502],db_hide_from_object:[234,502],db_hide_from_receiv:234,db_hide_from_send:234,db_home:[286,397,500,505,515],db_home__db_kei:512,db_home__id:512,db_home_id:397,db_index:67,db_interv:[277,406,506,512,515],db_is_act:[277,406,512,515],db_is_bot:[207,500,512],db_is_connect:[207,500,512],db_kei:[34,48,49,67,118,137,145,146,149,256,277,286,390,407,423,464,466,467,500,502,504,505,506,507,508,512,515,532],db_key__contain:48,db_key__exact:146,db_key__icontain:[67,146],db_key__iexact:146,db_key__in:146,db_key__startswith:48,db_locat:[34,49,146,149,286,397,500,505,515],db_location__db_kei:[505,512],db_location__db_tags__db_key__iexact:146,db_location__id:512,db_location__isnul:173,db_location_id:397,db_lock_storag:[234,277,286,390,464,466,500,502,504,505,506],db_messag:[234,502],db_model:[464,467,508],db_obj:[277,406,473,506],db_obj__db_kei:512,db_obj__id:512,db_obj_id:406,db_object_subscript:[234,502],db_permiss:67,db_persist:[277,406,506,512,515],db_properti:421,db_protototyp:402,db_receiver_extern:[234,502],db_receivers_account:[234,502],db_receivers_accounts__db_kei:502,db_receivers_object:[234,502],db_receivers_objects__db_kei:502,db_receivers_script:[234,502],db_receivers_scripts__db_kei:502,db_repeat:[277,406,506,515],db_sender_account:[234,502],db_sender_accounts__db_kei:502,db_sender_extern:[234,502],db_sender_object:[234,502],db_sender_objects__db_kei:502,db_sender_script:[234,502],db_sender_scripts__db_kei:502,db_sessid:[286,396,397,500,505],db_start_delai:[277,406,506,515],db_strvalu:464,db_tag:[146,207,234,390,397,406,466,467,500,502,504,505],db_tags__db_categori:[130,146,512],db_tags__db_kei:[130,146,502,512],db_tags__db_key__iexact:146,db_tags__db_key__in:130,db_tagtyp:[467,508,512,515],db_text:67,db_typeclass_path:[67,173,277,286,397,466,492,500,502,505,506,512,515],db_valu:[34,36,146,423,464,507,515,518],dbef:[218,405,489],dbentri:225,dbhandler:532,dbholder:464,dbid:[48,205,223,466],dbid_to_obj:492,dbmodel:465,dbobj:[13,464],dbobject:[13,465,466],dbprototyp:[218,402],dbref:[9,14,30,33,35,41,48,55,63,92,95,99,118,135,144,149,155,164,170,174,204,206,207,216,218,223,233,234,305,322,329,331,340,350,372,380,393,396,397,398,403,405,406,408,465,466,472,479,489,492,545],dbref_search:[206,396,405,465],dbref_to_obj:492,dbrefmax:218,dbrefmin:218,dbsafe_decod:488,dbsafe_encod:488,dbserial:[6,13,201,202,407,468,545],dbshell:[9,67,182,199],dbstore:353,dbunseri:473,ddesc:133,deactiv:[91,123,139,171,185,223,316,370,476],dead:[46,158,354,370,371,454,457,483],deadli:155,deal:[16,18,28,31,44,46,53,54,55,70,78,79,82,92,123,137,142,157,162,164,175,178,194,204,241,247,283,308,309,310,311,312,337,338,380,397,398,455,466,469,486,543,545],dealt:[226,310,311],dealth:310,death:[28,156,162,173,545],death_msg:370,death_pac:370,debat:142,debian:[11,181,182,185,187],debuff:[112,354],debug:[1,7,15,19,28,32,42,53,73,78,80,95,104,142,150,151,189,209,213,217,228,273,274,369,380,400,416,421,427,428,439,461,470,476,485,492,545],debugg:[3,16,199,201,545],dec:[64,77],decemb:191,decend:209,decent:[5,349],decic:[106,349],decid:[15,16,22,28,30,44,46,67,68,86,95,96,104,114,124,126,135,137,141,156,162,164,175,191,194,197,209,283,308,394,477,545],decis:[47,90,158,162,515],declar:[60,488],declared_field:[500,501,502,504,505,506,508,532],declared_filt:512,declin:[28,79,283],decod:[16,440,469,492,540],decode_gmcp:440,decode_msdp:440,decoded_text:492,decompos:177,decompress:[425,488],deconstruct:[155,229,238,248,279,294,313,335,351,353,360,442,516],decor:[11,22,45,86,95,96,97,118,128,207,280,397,398,405,406,413,425,426,466,472,476,477,490,492,545],decoupl:[75,402],decoupled_mut:13,decreas:[157,311,372,474],decrease_ind:474,dedent:[27,31,492,545],dedic:[39,95,151,152,162,187,191,545],deduc:474,deduce_ind:474,deduct:[141,162,308,309,310,311,312],deem:[11,72,119,134,235,536,538,543],deep:[31,147,180,545],deeper:[24,77,113,138,155,386,545],deepest:218,deepli:[13,95,104],deepsiz:492,def:[3,5,8,13,19,20,22,27,28,30,32,33,34,37,39,41,42,45,48,54,62,76,79,82,85,86,88,91,95,99,103,106,109,110,112,116,117,120,124,125,126,127,128,129,130,131,132,133,134,135,136,137,139,140,141,142,143,149,150,151,152,153,161,162,164,165,167,170,171,172,173,174,176,177,178,180,188,241,266,270,275,289,316,322,325,329,343,350,354,401,445,458,474,476,477,479,490,492],def_down_mod:310,defafultobject:149,defalt_cmdset:188,default_access:[13,396,405,464,472],default_acl:238,default_categori:389,default_charact:[93,296],default_client_width:30,default_cmd:[4,18,76,79,82,83,88,91,95,103,106,109,110,118,121,125,126,127,128,129,131,134,135,136,139,143,150,164,201,241,250,266,286,299,316,322,325,343,350,545],default_cmdset:[25,44,76,79,82,83,88,90,91,92,93,95,99,102,103,106,109,110,113,126,129,131,134,135,136,139,148,149,150,161,165,212,241,266,286,293,302,308,309,310,311,312,316,322,325,343,350,380,386],default_command:[126,148],default_confirm:[218,305],default_content_typ:238,default_create_permiss:49,default_error_messag:488,default_help_categori:[31,225,388,540],default_hom:41,default_in:51,default_kei:[112,354],default_kwarg:[30,479],default_list_permiss:49,default_out:51,default_pass:[206,472],default_screen_width:22,default_set:[8,148,167],default_sit:523,default_transaction_isol:182,default_unload:51,default_weight:[118,338],default_xyz_path_interrupt_msg:331,defaultaccount:[12,48,121,123,149,150,201,204,205,219,398,490,515,532,536],defaultchannel:[18,48,121,149,201,223,232,537],defaultcharact:[13,37,48,67,76,82,93,95,112,121,126,134,135,136,139,149,150,161,162,165,201,204,220,241,286,296,308,309,310,311,312,350,353,354,398,464,490,532,538],defaultdict:407,defaultexit:[37,48,95,118,121,141,149,201,322,325,329,340,371,398,490],defaultguest:[121,201,204],defaultmod:485,defaultobject:[0,4,13,30,37,48,67,95,112,120,121,123,140,141,145,147,149,152,153,161,170,171,174,201,204,275,286,309,312,350,354,362,364,366,371,398,466,490,515,532,543,545],defaultpath:492,defaultroom:[37,48,95,118,121,130,132,133,141,149,176,201,276,316,329,340,350,372,398,490],defaultrout:[514,517],defaultscript:[42,48,121,133,149,164,173,174,201,205,247,257,277,283,305,308,309,310,311,312,329,339,349,359,382,402,408,409,449,480,490],defaultsess:[150,221],defaulttyp:461,defaultunloggedin:[150,222],defeat:[90,155,156,162,164,308,309,310,311,312,370,545],defeat_msg:370,defeat_msg_room:370,defend:[28,155,164,308,309,310,311,312,371,398],defens:[114,157,164,308,309,310,311,312],defense_valu:[308,309,310,311,312],defer:[19,22,54,128,177,207,209,228,234,316,325,390,397,398,406,410,413,423,425,426,457,461,464,466,467,484,485,500],deferredlist:461,defin:[2,3,4,5,6,7,8,12,13,14,15,19,25,27,31,32,37,39,41,47,48,49,51,53,54,55,59,60,62,65,68,70,72,73,76,77,78,82,83,84,86,92,95,96,97,99,106,112,113,121,122,123,124,125,126,129,131,132,133,134,135,136,137,139,141,142,143,144,146,148,150,151,152,156,158,161,162,165,169,170,171,174,175,177,179,195,201,203,207,209,211,212,213,215,218,224,225,226,228,229,230,232,233,234,239,241,244,247,250,256,257,260,273,279,286,292,305,310,311,316,337,343,349,350,354,359,366,371,372,380,382,386,387,388,389,390,392,393,394,395,396,397,398,402,403,405,406,409,411,412,413,416,423,426,447,448,455,456,457,460,463,464,465,466,467,469,470,471,474,476,479,480,484,487,489,492,496,502,504,505,515,518,525,532,540,541,545],define_charact:28,definin:151,definit:[3,12,15,22,31,36,37,39,41,47,54,55,59,68,85,95,97,118,122,130,137,140,148,161,211,213,218,226,233,254,266,289,305,371,392,394,397,402,403,408,470,472,476,479,488,545],deflist:461,degre:[31,154],deindent:492,del:[13,26,39,55,95,108,112,128,135,155,161,164,216,218,302,305,316,353,354,466],del_callback:[255,257],del_detail:316,del_pid:416,delai:[22,26,85,92,97,104,108,110,127,173,228,247,257,289,325,364,371,380,410,411,428,434,457,471,492,545],delaliaschan:266,delayed_import:457,delchanalia:266,delcom:[103,135,143,266],deleg:[207,234,390,397,406,464,466,467,484],delet:[8,9,11,12,13,14,18,20,26,27,28,30,33,36,37,42,44,45,46,50,55,63,76,80,86,95,112,118,124,148,149,150,155,161,164,170,182,185,192,193,198,204,212,215,216,217,218,223,224,225,228,232,234,238,254,255,257,258,266,276,280,289,292,299,302,305,316,322,339,353,354,371,390,394,398,402,405,407,408,409,410,411,422,434,455,464,466,469,470,476,483,500,501,508,513,517,533,538,542,543],delete_attribut:464,delete_default:[20,212],delete_dupl:280,delete_prototyp:402,delete_script:405,deleteobject:77,deletet:316,deleteview:542,deliber:[3,72,157,492],delic:[83,286],delimit:[64,142,226,470,545],deliv:[191,299,350],delpart:305,delresult:305,deltatim:492,delux:191,demand:[42,47,91,129,135,156,158,162,171,191,204,232,316,354,398,458,471],demo:[53,76,90,104,122,138,154,155,160,163,166,168,180,369,476,545],democommandsetcomm:369,democommandsethelp:369,democommandsetroom:369,demon:41,demonin:492,demonstr:[76,92,97,124,161,175,177,241,310,376,380],demowiki:124,deni:[18,181,194,256,260,545],denot:[8,133,178,337,470],denounc:475,depart:[95,132],depend:[5,6,7,13,15,16,18,19,20,22,28,30,32,35,42,44,47,48,51,54,55,56,60,62,64,65,68,76,86,90,91,95,96,97,106,108,112,117,118,119,122,123,124,132,134,135,137,141,148,149,150,155,156,158,161,162,164,165,170,172,177,178,182,185,189,190,191,193,194,195,203,209,211,213,215,228,241,255,316,329,337,338,340,343,349,354,364,388,394,398,402,411,416,436,439,445,447,457,466,467,474,476,477,479,492,496,545],depict:276,deplet:[112,310,354],deploi:[96,120,191,194,545],deploy:[2,7,78,120,180,191,193,197],depmsg:485,deprec:[19,28,201,202,403,412,469,476,485,492,545],deprecationwarn:415,depth:[2,17,31,56,118,155,225,386,391,403],dequ:[13,459],deriv:[8,48,69,133,182,185,187,193,270,469,493],desc1:28,desc2:28,desc3:28,desc:[15,18,26,32,33,34,37,41,42,50,76,82,86,91,95,99,102,103,104,117,118,125,134,135,137,140,141,143,144,149,157,164,170,173,178,212,215,218,223,225,229,233,235,241,266,275,286,292,293,302,305,311,316,322,329,341,352,364,386,398,405,406,414,470,472,474,475,476,532,538,543,545],desc_add_lamp_broken:364,desc_al:370,desc_closed_lid:364,desc_dead:370,desc_open_lid:364,descend:[146,532],descer:545,describ:[10,11,13,14,15,18,20,22,28,33,39,40,41,48,50,51,53,60,64,67,68,70,73,75,76,90,95,96,112,118,119,120,122,123,125,129,135,136,137,141,143,144,148,149,151,152,157,161,164,170,177,180,182,185,188,190,191,199,211,218,222,224,234,247,266,274,286,292,293,311,316,337,338,350,354,364,382,398,403,409,413,434,436,439,449,476,491,492,505],descripion:370,descript:[0,8,15,16,18,28,32,41,46,50,53,58,72,73,76,79,82,83,95,96,97,99,101,102,104,106,112,113,117,118,120,122,125,130,132,134,135,141,144,147,156,157,170,175,177,178,184,191,215,218,223,224,232,233,241,266,270,274,283,286,302,316,317,322,329,337,340,350,353,354,362,364,369,370,371,372,382,386,398,405,406,470,472,476,486,487,500,505,514,518,545],description_str:170,descriptor:464,descvalidateerror:302,deseri:[6,13,486,515],deserunt:29,design:[0,15,22,37,41,46,53,56,69,72,82,86,104,115,122,130,134,142,146,148,156,157,158,159,161,170,171,172,177,180,182,212,218,241,256,350,371,376,398,470,486,492,545],desir:[19,46,47,51,60,69,84,85,118,124,127,128,132,134,135,142,165,174,177,218,232,233,244,280,289,349,394,416,461,464,472,478,493],desired_effect:293,desired_perm:394,desk:161,desktop:[16,56],despit:[13,14,44,123,134,139,180,185,372],dest:[270,398],destin:[22,32,37,41,50,76,95,97,99,110,118,126,132,141,142,153,161,170,174,218,308,309,310,311,312,322,325,331,332,337,338,340,371,372,376,396,397,398,403,472,518,538],destinations_set:397,destroi:[18,26,37,86,97,103,105,108,143,144,164,194,204,205,218,223,266,305,310,398],destroy:[104,109,322],destroy_channel:223,destroy_compon:275,destroy_lock:513,destruct:[20,211],detach:7,detail:[0,5,9,11,12,13,16,18,22,28,31,33,37,41,42,44,48,50,55,57,60,68,72,73,75,76,82,86,95,96,104,106,119,120,123,129,135,142,144,148,149,150,151,155,156,157,159,164,169,170,172,178,182,185,191,201,202,212,213,218,232,235,238,241,275,292,305,309,314,316,317,327,337,350,354,372,382,388,390,391,403,410,418,419,455,457,466,469,474,479,492,495,500,505,517,518,533,540,542,543,545],detail_color:218,detail_desc:317,detailkei:[316,372],detailview:[540,542],detect:[2,18,20,22,37,44,68,120,139,156,161,172,194,210,213,428,479,517,545],determ:465,determin:[5,12,14,16,18,19,20,22,27,28,29,31,33,36,41,42,51,65,86,95,99,106,118,124,128,130,131,132,140,141,144,150,161,162,164,165,169,182,185,199,204,211,212,213,215,223,225,226,232,283,308,309,310,311,312,325,338,349,350,371,386,388,390,394,398,402,440,464,465,466,469,474,477,479,485,490,492,496,500,502,505,512,513,521],determinist:338,detour:[65,125,148,152,457],dev:[31,119,122,123,134,151,159,180,182,185,187,188,191,192,544],devel:148,develop:[0,2,3,5,6,7,8,11,13,16,18,19,22,30,31,39,41,49,51,53,56,57,58,64,67,68,69,73,75,80,95,104,114,119,120,122,123,126,133,135,142,144,145,147,148,149,150,151,152,156,158,159,167,169,170,175,177,182,184,185,188,189,191,195,198,213,216,217,223,224,225,228,232,254,255,260,273,376,388,390,398,403,462,466,467,470,476,544,545],deviat:159,devoid:469,dex:[13,28,135,149,151,157,475],dexter:[157,308,309,310,311,312],diagnos:[6,129],diagon:[118,335],diagram:48,dialog:51,dialogu:[95,97,157,545],dice:[28,86,142,152,158,162,164,185,201,202,235,341,545],dicecmdset:343,dicenum:343,dicetyp:343,dict:[8,13,14,20,28,30,31,41,42,45,49,53,68,78,86,87,96,97,99,106,112,118,121,126,143,204,205,211,213,218,225,232,247,254,257,260,277,286,292,310,312,316,337,338,339,349,350,354,362,372,376,377,380,386,388,391,398,400,401,402,403,409,411,413,414,416,421,425,426,427,429,434,436,439,444,445,456,457,459,465,470,471,473,475,476,477,479,487,490,492,532,537,540,541,543],dict_of_kwarg_convert:30,dictat:[20,136,171],dictionari:[6,13,14,20,33,41,54,78,87,91,92,95,97,99,104,106,122,126,132,133,136,137,162,164,178,216,218,238,247,254,257,260,286,310,311,316,329,349,350,372,376,377,378,380,386,394,403,410,421,434,443,455,456,457,459,465,469,471,475,476,483,486,487,488,492,532,541,543,545],dicument:119,did:[11,12,64,76,123,125,128,134,142,143,144,149,150,151,161,165,170,195,204,283,398,410,467,488,492,497],did_declin:283,didn:[3,11,28,33,74,76,118,120,131,132,135,142,143,144,145,149,150,151,152,155,169,174,175,177,189,193,195,339],die:[7,142,155,158,162,171,343,349,457],dies:[158,370],diff:[11,190,343,403],differ:[3,5,7,8,12,13,14,15,16,19,20,22,27,28,30,31,33,34,36,41,42,44,45,46,47,51,56,57,60,62,63,65,68,70,71,72,74,75,76,80,82,85,86,90,95,96,97,98,104,106,112,114,117,118,119,120,122,123,125,126,130,131,132,134,135,136,137,138,140,142,143,144,145,146,148,149,150,151,152,154,156,159,161,162,164,169,170,172,173,174,175,177,180,181,183,184,185,193,194,198,199,201,204,209,211,212,215,218,225,227,228,230,232,241,247,251,257,258,270,274,275,278,289,292,299,308,309,310,311,312,325,329,335,337,338,340,343,350,354,382,386,396,398,400,403,405,406,411,414,418,440,445,447,464,466,470,472,476,479,485,488,492,496,497,500,501,508,512,517,518,541,543,545],differenti:[104,106,113,114,133,134,135,148,149,157,158,286,350,386,398,479,492,496],differnt:275,difficuli:13,difficult:[5,124,130,158,177,194,311,312],difficulti:[86,177],dig:[5,20,22,26,37,41,62,74,80,97,109,118,134,135,143,144,148,150,155,165,174,218,273,322,448],digit:[30,55,60,107,191,382,460,469,479,485],digitalocean:[187,191],dijkstra:[118,337,338],diku:[95,104,122,123,138,545],dikumud:72,dime:69,dimens:[122,132],dimension:[118,135],dimenst:152,diminish:60,dimli:170,dinner:[96,158],dip:151,dir:[2,9,11,42,53,64,75,78,90,120,123,125,135,138,149,151,152,178,180,182,184,185,187,190,191,193,485,492,521,545],direcetli:479,direct:[9,20,28,32,41,51,54,55,58,68,76,95,97,99,118,119,131,132,135,137,144,164,167,170,172,174,181,191,193,218,256,275,329,331,335,337,338,339,340,377,394,396,409,416,476,478,479,485,489,490,492,545],direction_alias:[118,338],direction_nam:338,direction_spawn_default:338,directli:[3,4,9,11,12,13,14,15,19,22,27,28,31,33,35,37,41,42,48,50,51,52,53,60,62,68,77,79,86,95,96,104,106,112,117,118,119,120,122,123,125,128,129,131,133,135,136,143,144,145,146,147,148,149,151,152,153,156,164,165,170,172,181,182,189,191,193,195,199,206,213,229,233,238,241,260,270,273,278,280,283,293,311,312,338,339,340,343,350,353,354,364,372,386,389,394,396,397,398,402,405,406,422,427,436,439,444,447,449,455,464,466,470,472,476,477,479,490,492],director:[106,350,398,545],directori:[1,2,5,7,8,9,10,11,14,19,48,51,53,73,75,77,95,104,119,123,124,126,135,136,137,147,148,165,169,177,178,181,182,185,190,193,218,238,376,416,436,437,461,470,485,492,545],directorylist:461,dirnam:416,dirti:122,disabl:[5,7,8,27,33,51,60,71,78,92,97,112,113,124,126,139,161,183,185,213,229,270,350,353,354,364,380,386,394,402,439,459,477,479,483,493,545],disableloc:439,disableremot:439,disadvantag:[106,135,158,164,191,312],disambigu:[189,213,398,466],disappear:194,discard:469,disconcert:159,disconnect:[6,9,12,13,18,40,44,45,46,51,55,62,134,158,164,165,198,199,204,215,218,223,226,228,232,398,426,427,428,434,435,436,439,444,445,448,454,455,456,457],disconnect_al:434,disconnect_all_sess:457,disconnect_duplicate_sess:457,disconnect_session_from_account:204,discontinu:183,discord:[75,119,159,180,185,189],discordia:69,discourag:[123,158,190],discours:158,discov:[142,155,158,464],discoveri:377,discret:[35,148,518],discrimin:194,discuss:[0,18,22,53,104,118,119,122,124,126,137,153,158,164,182,185,545],discworld:68,disengag:[164,204,308,309,310,311,312],disguis:[58,104,106],disk:[11,13,19,67,69,78,193,199,337,349,376,388,400],dislik:134,disonnect:13,dispel:175,displai:[3,5,17,20,22,27,28,31,33,37,42,49,51,52,53,59,60,65,68,73,76,91,94,95,96,97,104,118,120,126,129,135,137,139,140,141,142,149,156,161,164,165,169,170,177,178,194,195,204,213,215,218,223,225,228,230,241,250,251,255,257,270,274,278,280,283,286,299,316,329,335,337,338,340,346,350,354,364,369,371,372,380,386,388,398,402,403,414,416,433,451,454,459,466,467,474,475,476,477,478,486,487,488,490,491,492,493,502,504,506,507,508,515,532,537,541,542,543,545],display:411,display_all_channel:223,display_buff:474,display_choic:241,display_formdata:380,display_help:474,display_helptext:[400,476],display_len:492,display_map:335,display_met:[94,346],display_nam:479,display_nodetext:476,display_subbed_channel:223,display_symbol:[118,337,338,340],display_symbol_alias:338,display_titl:241,dispos:[105,170,305],disput:164,disregard:22,dissect:143,dist:[118,185,335,337],distanc:[8,19,48,96,104,106,114,118,123,130,132,145,311,312,335,337,349,398,492,510],distance_inc:312,distance_to_room:130,distant:[132,316,372],distinct:[44,74,122,123,146,312,512],distinguish:[76,213,312,386],distribut:[3,6,8,9,16,18,20,75,77,123,147,179,181,182,185,232,233,234,238,350,469,472,492,495],distribute_messag:232,distro:[181,182,185,187,189],disturb:[19,74],distutil:185,distutilserror:185,ditto:185,div:[17,30,41,51,56,120,167],dive:[76,152,153,154,185,545],diverg:65,divid:[14,30,80,123,137,247,372,492],dividend:247,divis:353,divisiblebi:137,divisor:247,divivid:157,django:[0,2,8,9,12,13,16,42,45,46,48,49,50,51,52,53,64,67,70,75,77,99,112,122,124,126,130,137,138,148,149,153,154,161,162,167,169,173,178,180,182,185,194,195,204,206,207,213,230,232,234,238,239,251,335,340,354,388,390,396,397,402,405,406,415,416,422,423,436,442,444,445,452,458,459,460,461,464,466,467,470,473,477,482,483,484,488,490,492,497,498,499,500,501,502,503,504,505,506,507,508,512,513,515,517,518,523,524,527,532,536,537,538,540,541,542,543,545],django_admin:533,django_filt:[512,518],django_nyt:124,djangofilterbackend:518,djangonytconfig:124,djangoproject:[64,149,182,532],djangowebroot:461,dmg:162,dnf:[181,185,187],do_attack:370,do_batch_delet:464,do_batch_finish:464,do_batch_update_attribut:464,do_craft:[86,292],do_create_attribut:464,do_delete_attribut:464,do_flush:[466,483],do_gmcp:440,do_hunt:370,do_mccp:429,do_msdp:440,do_mssp:430,do_mxp:431,do_naw:432,do_nested_lookup:218,do_not_exce:126,do_noth:369,do_patrol:370,do_pickl:473,do_power_attack:[85,289],do_search:225,do_sit:161,do_stand:161,do_task:[228,410,492],do_task_act:228,do_unpickl:473,do_update_attribut:464,do_xterm256:469,doabl:15,doc:[8,10,13,17,18,22,24,28,31,41,48,50,53,56,64,67,72,77,78,89,96,97,100,118,119,121,123,126,138,146,147,148,149,152,157,159,161,169,180,182,198,199,201,218,228,270,331,382,398,427,492,532,544,545],docker:[180,185,191,197,198,545],dockerfil:193,dockerhub:193,docstr:[31,32,126,143,149,150,161,213,218,229,241,255,270,273,293,337,349,350,354,364,372,386,391,447,476,545],document:[0,1,4,5,7,8,11,17,24,26,29,31,42,48,49,50,52,53,56,60,61,64,67,73,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,122,123,126,128,134,135,138,147,148,149,151,152,154,155,165,167,169,170,174,177,180,182,183,191,194,195,197,198,212,226,241,270,289,355,382,391,464,467,475,483,512,537,540,545],dodg:309,dodoo:77,doe:[0,8,12,13,18,20,22,28,30,31,33,35,37,39,41,42,46,48,51,52,53,58,59,60,62,68,70,72,74,75,77,84,86,88,89,90,99,102,104,113,117,118,119,120,122,123,124,125,126,128,130,132,133,134,135,137,141,142,143,144,147,148,149,151,152,155,156,157,161,162,164,165,169,170,171,172,174,175,176,177,179,182,183,184,185,187,193,195,199,204,205,215,226,228,230,244,251,270,273,280,286,289,292,302,305,308,309,310,311,312,316,329,337,338,354,371,372,386,398,402,403,407,409,410,415,416,420,421,422,425,428,436,437,443,464,466,471,476,479,485,488,490,492,524,532,540,543,545],doesn:[0,2,9,13,14,16,22,28,30,35,37,48,51,52,53,67,68,75,76,86,95,96,97,118,119,124,128,130,131,132,134,137,142,143,149,151,152,156,158,161,162,165,169,170,174,175,177,179,185,188,189,190,191,194,198,199,212,223,232,234,238,256,257,289,292,293,310,316,337,338,350,394,398,416,429,436,440,464,469,476,487,492,500],doesnotexist:[204,205,207,232,234,247,257,275,276,277,283,286,296,305,308,309,310,311,312,316,322,325,329,339,340,349,350,359,362,364,366,370,371,372,382,390,396,397,398,402,406,409,423,449,464,467,472,480,484],doff:309,dog:19,doing:[2,5,6,8,12,13,19,20,22,26,28,37,44,47,48,51,53,54,58,60,86,95,96,113,118,119,120,123,124,128,130,132,134,135,137,143,146,149,151,152,157,158,163,175,177,178,180,191,199,204,215,232,256,275,280,283,286,292,308,309,310,311,312,329,350,362,370,371,386,393,398,411,447,476,483,488,497,523,545],doll:[86,292],dolor:29,dolphin:143,dom:51,domain:[53,122,181,187,191,194,206,472],domexcept:191,domin:158,dominion:75,dompc:75,don:[0,3,5,6,7,8,9,11,13,18,19,20,22,27,28,30,31,33,39,42,44,48,53,54,60,64,65,67,68,73,74,75,76,77,80,86,95,96,97,104,106,112,114,115,117,118,119,120,123,124,125,126,128,129,130,131,135,136,137,138,139,141,142,143,144,146,148,149,150,151,152,154,155,156,157,158,159,162,164,165,167,169,170,175,176,177,178,182,184,185,187,189,190,191,194,195,204,205,211,212,218,223,224,225,226,227,230,232,241,256,260,266,270,275,276,289,293,309,310,311,329,331,337,338,343,349,350,353,354,364,372,394,397,398,402,403,411,421,428,433,434,439,441,448,455,462,466,469,470,476,483,485,488,492,501,513,532,541,545],donald:5,donat:[191,545],done:[0,2,5,8,9,11,13,20,22,28,30,31,33,36,45,47,50,51,52,53,54,64,69,75,76,95,106,108,117,118,119,120,122,123,124,125,126,128,129,130,131,132,133,134,135,136,137,140,141,142,144,148,149,151,152,158,161,162,164,165,169,171,172,173,174,175,177,182,185,187,191,193,199,204,213,215,223,234,250,283,312,329,337,339,343,349,394,397,398,409,410,411,416,420,429,433,435,437,441,445,451,454,455,457,462,464,469,470,477,479,483,490,492,497,541,545],donoth:409,dont:438,doom:[118,403],door:[19,22,31,33,37,76,95,97,104,109,118,132,141,144,153,156,194,218,280,321,322,338],doorwai:[109,322],dot:[4,53,76,212,218,470,492],dotal:[469,491],dotpath:492,doubl:[6,76,120,134,151,177,211,230,491,492],doublet:[211,212],doubt:[76,118,270],down:[2,4,5,7,13,20,22,27,28,51,55,67,69,76,81,86,95,97,113,114,117,120,122,124,125,128,130,132,134,135,139,141,142,147,151,154,155,156,158,160,161,162,163,165,166,168,169,170,185,191,193,194,195,204,218,223,228,257,275,289,309,310,329,335,337,338,371,376,386,391,393,398,403,409,411,416,418,425,426,433,434,454,455,457,469,477,478,492,545],download:[0,9,10,11,75,123,147,180,182,185,189,190,191,193,198],downmaplink:[118,338],downtim:[128,194,480],downward:215,dozen:[69,122,126],drag:51,dragon:[133,143,145,149,150,152,158],drain:[112,354],drama:31,dramat:[146,156,161,402,403],dramati:31,drape:[83,286],draw:[15,77,99,104,118,120,130,132,162,478],draw_room_on_map:132,drawback:[15,28,67,112,127,128,135,145,158,161,162,182,354,470],drawn:[132,135,170],drawtext:162,dread:99,dream:[0,72,122,156,159],dress:[83,286],drf:[512,515],drift:158,drink:[157,275,464,466],drinkabl:275,drive:[11,30,57,75,77,123,125,147,152,156,158,159,174,177,185,193],driven:[104,111,126,157,158,159,165,180,366,400],driver:182,drizzl:[42,176],drop:[9,15,22,26,33,35,36,37,51,62,67,68,75,77,80,95,101,105,108,111,119,122,125,126,134,135,137,141,143,144,145,148,149,150,151,158,161,171,172,174,182,191,218,224,230,286,305,309,312,364,366,398,425,466,470,492],drop_whitespac:478,dropbox:77,dropdown:7,droplet:187,dropper:[309,312,398],drum:191,dry:187,dtobj:492,duck:[19,151],duckclient:183,due:[5,20,22,45,48,55,62,74,76,123,128,135,136,142,151,175,185,191,195,212,228,397,398,418,454,457,469,485,501],dufresn:77,duh:69,dull:[0,95,144,170],dum:391,dumb:[144,457,469],dummi:[5,11,13,22,33,75,86,151,158,184,269,292,350,394,416,421,434,447,448,455],dummycharact:353,dummycli:447,dummyfactori:447,dummyrunn:[201,202,412,416,434,446,448,450,545],dummyrunner_act:447,dummyrunner_actions_modul:447,dummyrunner_echo_respons:447,dummyrunner_set:[5,201,202,412,416,446,545],dummyrunner_settings_modul:5,dummyrunnercmdset:447,dummysess:457,dump:[28,376,425],dungeon:[46,118,122,148,153],dungeonmap:118,dupic:20,duplic:[20,211,218,225,411,466,485],durat:[54,127,176,228,289,310,486,493,545],dure:[6,13,20,33,44,45,51,62,63,73,74,75,91,95,99,115,118,120,128,152,156,158,164,165,169,176,180,185,193,204,211,223,229,238,270,273,292,305,316,337,338,370,372,394,396,410,425,435,470,472,476,485,505,532,545],duti:123,dwarf:170,dwarv:158,dying:[158,308,309,310,311,312],dynam:[8,12,30,42,47,51,52,53,58,67,95,104,112,113,118,120,140,146,148,167,170,177,191,204,207,213,225,228,229,234,250,308,309,310,311,312,335,338,340,350,354,380,386,389,390,397,398,402,406,411,464,466,467,472,474,476,484,486,492,500,505,521,543,545],dyndns_system:191,each:[2,3,5,6,8,12,13,14,18,19,20,22,24,28,30,31,33,41,44,46,47,48,50,51,53,54,57,60,62,65,67,69,74,76,79,83,84,86,90,91,92,95,97,99,104,105,106,112,114,117,118,120,122,123,124,128,130,132,133,134,135,136,137,140,141,143,146,147,149,150,151,152,154,156,162,163,164,165,169,170,174,175,176,177,193,195,204,210,211,212,216,218,223,225,227,232,244,275,280,283,286,289,292,305,308,310,311,312,316,329,335,337,338,339,340,349,350,354,360,364,380,386,388,390,391,394,397,398,401,402,403,408,411,418,421,434,436,439,443,448,455,456,457,464,466,467,469,470,472,474,475,476,477,478,479,483,490,492,515,518,521,545],eagl:161,eaoiui:[106,349],earler:144,earli:[2,159,308,309,310,311,312,418],earlier:[2,7,14,18,20,28,31,32,75,112,123,135,136,141,143,150,151,152,156,165,167,174,178,184,338,354,388,421],earn:159,earnest:[153,158],earth:[140,194],eas:[20,22,67,130,149,175,191,193],easi:[0,7,9,14,17,22,28,31,37,42,48,53,54,58,68,69,70,74,76,83,90,96,97,104,112,118,120,122,128,130,133,136,137,139,140,141,143,150,151,152,156,158,159,161,162,164,165,170,172,175,177,178,180,182,187,189,191,193,212,216,278,286,292,354,380,386,476,483,545],easier:[13,28,31,41,42,49,50,53,54,55,67,76,90,95,106,113,118,119,122,124,126,130,133,134,135,136,137,142,143,146,149,150,151,152,154,155,156,158,159,161,162,169,175,191,218,293,308,309,310,311,312,331,340,349,371,386,458,464,467,492],easiest:[9,11,16,19,49,53,55,64,73,77,86,96,97,118,119,126,129,135,149,165,177,185,187,376,466],easili:[7,11,14,15,17,18,19,22,28,31,33,35,41,44,45,46,51,53,55,58,64,65,68,69,74,82,83,86,94,95,96,97,104,109,112,113,119,120,124,126,127,130,132,135,136,141,142,144,146,148,149,150,153,155,156,157,158,162,165,167,169,170,177,185,191,192,193,194,223,232,234,241,256,270,283,286,308,309,310,311,312,322,331,346,349,354,380,386,388,389,390,411,470,476,487],east:[77,99,118,126,131,132,170,218,337,338,372],east_exit:372,east_room:99,east_west:170,eastern:[136,170,337,339],eastward:372,eat:[95,273,275],echo1:128,echo2:128,echo3:128,echo:[0,2,19,22,27,28,30,41,54,55,58,74,81,88,101,120,127,128,131,132,143,144,150,151,157,164,165,172,176,186,188,191,192,193,195,199,204,205,216,218,223,228,286,331,343,350,362,370,371,372,398,414,421,436,439,474,476,490,492,545],echocmdset:143,echol:198,echowoo:143,econom:[67,122,148,149,152,158,180],economi:[42,69,156,162,173,283,545],ecosystem:193,edg:[11,19,56,118,293,337,338,478,490,492],edgi:132,edibl:275,edit:[0,6,7,9,11,13,14,15,18,22,25,26,31,33,39,41,49,51,52,62,64,67,73,75,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,124,126,129,133,135,136,137,139,149,154,158,169,170,177,178,180,182,184,187,190,193,195,216,218,225,228,241,242,251,254,255,257,258,302,305,380,394,398,400,402,403,464,474,504,505,513,532,538,542,543,545],edit_callback:[255,257],edit_handl:218,editcmd:76,editi:[112,354],editnpc:545,editor:[6,11,16,22,30,31,41,49,64,69,75,76,82,96,97,120,121,125,134,151,152,170,180,185,187,218,225,227,228,241,302,406,470,474,545],editor_command_group:474,editorcmdset:474,editsheet:135,edu:495,effect:[8,9,13,15,18,19,20,25,36,42,45,47,53,54,60,72,74,77,86,95,99,104,108,112,114,115,118,120,127,128,130,133,134,135,151,152,156,157,158,161,162,164,170,171,175,195,199,204,211,212,218,227,232,257,275,289,293,309,310,311,338,343,354,370,372,396,398,404,406,429,492,544],effici:[0,5,13,36,42,46,47,48,67,79,110,118,122,123,127,128,130,133,146,152,161,176,180,194,283,325,337,338,340,350,394,398,411,464,465,467,474,477],effort:[11,133,148,178,538],egg:[190,292],egg_info:185,egi:418,egiven:396,eight:275,eightbal:153,eirik:77,either:[5,6,9,11,14,17,19,20,22,28,30,33,39,41,42,44,46,48,51,53,55,58,59,65,75,80,82,95,96,97,98,104,106,109,118,119,120,124,128,130,131,132,133,134,135,137,142,143,145,146,148,149,151,152,155,158,161,162,164,165,170,174,175,182,191,194,199,204,205,211,212,213,218,223,233,241,254,260,292,299,308,311,312,322,337,338,339,340,349,350,354,364,386,394,398,401,403,406,408,409,411,414,425,437,441,448,465,466,467,476,478,479,485,487,489,492,495],elabor:[76,95,120,124,141,142,165],electr:191,eleg:119,element:[5,13,17,28,30,53,56,59,76,82,86,118,122,142,149,150,151,153,210,215,225,238,241,247,337,339,340,349,382,398,403,464,465,467,470,475,476,477,479,490,492],elev:[95,96,140,545],elif:[28,42,97,132,135,143,153,162,164,165,171],elig:[77,238,479],elimin:[193,469],elimit:492,ellow:[60,469],els:[3,11,12,18,19,22,28,31,33,34,39,42,47,51,53,54,55,57,58,75,76,77,79,85,86,95,96,97,117,120,125,126,128,129,130,132,135,137,139,140,141,142,143,144,150,151,153,156,159,161,162,164,165,170,171,173,174,177,178,182,191,194,223,229,238,283,286,289,308,309,310,311,312,329,380,382,397,445,466,476,492,545],elsennsometh:229,elsewher:[12,20,46,53,128,135,147,149,177,212,338,372,416,457,464],elv:158,elvish:[106,349],emac:[15,180],email:[11,23,35,104,123,148,153,154,185,187,198,204,206,249,251,252,472,486,492,493,500,532,545],email_login:[89,201,202,235,236,545],emailaddress:492,emailfield:[500,532],emb:[41,58,91,106,118,120,135,316,403],embark:174,embed:[30,41,48,53,71,118,148,157,225,232,337,401,475,479,492],emerg:[39,64,194],emi:[106,349],emit:[51,69,126,143,204,212,216,232,296,398,455,485],emit_to_obj:[212,398],emo:125,emoji:183,emot:[18,22,26,30,31,58,79,104,122,157,158,159,164,204,224,273,283,348,349,350,464,479,545],emoteerror:350,emoteexcept:350,empathi:293,emphas:120,emphasi:120,emploi:493,empti:[3,6,8,9,11,12,15,18,20,22,28,34,37,42,47,48,50,51,53,54,67,68,75,86,90,94,97,104,112,118,120,123,132,135,137,142,143,146,148,149,150,151,152,153,157,161,162,165,167,171,178,184,185,187,193,198,206,209,210,216,218,223,229,241,254,277,292,337,338,346,350,354,398,402,403,414,421,425,447,448,464,470,472,476,478,489,492,501,508],emptor:[77,238],empty_color:346,empty_permit:[502,504,506,508,532],empty_symbol:337,empty_threadpool:461,emptyset:20,emul:[5,44,72,112,114,123,157,158,165,190,228,354,545],enabl:[7,51,60,77,78,85,92,175,178,181,182,183,188,193,194,204,239,289,350,353,380,439,493],enable_recog:350,enableloc:439,enableremot:439,enact:273,encamp:96,encapsul:486,encarnia:180,encas:474,enclos:[25,27,151,230,251,479],encod:[19,26,61,118,135,170,230,338,427,440,444,445,469,488,492,540,545],encode_gmcp:440,encode_msdp:440,encoded_text:492,encompass:19,encount:[212,338,396,479,493],encourag:[76,130,142,167,183],encrypt:[65,77,181,187,194,223,238,436,437,441,545],encumb:157,end:[0,5,9,11,14,15,19,20,22,27,28,30,31,33,36,41,44,45,51,54,57,59,60,62,64,65,67,68,69,73,74,75,76,77,80,95,102,104,106,113,114,117,118,120,122,123,125,126,127,128,130,135,136,137,139,142,144,146,148,150,151,152,154,155,157,158,161,162,164,165,172,174,175,177,178,181,182,184,186,187,191,193,198,204,205,211,212,218,224,225,233,275,278,283,286,293,302,308,309,310,311,312,337,338,346,350,366,372,386,389,420,427,428,436,439,440,447,450,455,459,461,465,469,470,472,476,477,478,479,485,492,541],end_convers:28,end_direct:338,end_turn:164,end_xi:[118,337],endblock:[53,137,167,177,178],endclr:479,endcolor:30,endcoord:335,endfor:[137,177,178],endhour:126,endif:[137,177,178],endless:53,endlessli:194,endpoint:[49,194,517,518],endpoint_url:238,endsep:492,endswith:469,enemi:[13,28,41,128,155,156,164,310,311,312,370,371,372,545],enemynam:28,enforc:[8,22,39,54,60,156,162,175,436,439,477,478,490,538,545],enforce_s:478,engag:[122,312,370],engin:[2,8,22,28,31,37,74,76,90,104,123,133,150,155,162,169,180,182,194,195,197,209,212,225,227,228,271,292,372,377,389,416,427,433,436,439,444,454,456,470,472,496,545],english:[6,16,30,58,64,70,180,230,495,496],enhanc:[60,139,151,376,469,542],enigmat:144,enjoi:[7,142,155,156,159,185,545],enough:[3,8,18,33,34,36,46,47,69,86,117,118,119,120,122,123,124,125,128,130,134,135,137,141,142,143,146,147,149,150,152,156,161,165,169,175,185,187,191,212,218,292,329,338,349,364,382,476,477,478,490,545],enpoint:515,ensdep:492,ensur:[7,132,137,171,175,182,193,386,459,490,538],ensure_ascii:445,enter:[0,2,3,5,9,11,14,15,16,18,19,20,22,25,28,30,31,36,37,39,41,52,53,58,60,63,65,72,73,75,76,79,82,83,90,92,95,96,97,100,104,117,118,123,125,126,128,131,135,136,137,141,142,150,151,154,155,161,164,165,167,170,171,177,182,185,190,193,198,201,204,210,212,217,225,226,228,241,260,275,278,283,286,308,309,310,311,312,316,329,370,372,380,386,393,398,403,406,414,455,476,521,532,545],enter_guild:28,enter_nam:28,enter_wild:[117,329],enterpris:2,enthusiasm:159,enthusiast:158,entir:[8,13,14,15,19,22,27,28,30,31,33,41,47,48,53,54,57,67,69,76,95,96,104,105,106,113,118,128,132,137,142,147,148,151,156,158,165,169,170,191,241,270,337,338,339,340,349,350,386,394,398,402,403,466,467,470,476,478,483,492,541,545],entireti:[28,162,274,380,476],entit:[233,472,545],entiti:[8,13,18,19,28,30,31,33,34,35,36,37,39,41,42,44,45,46,48,50,53,58,118,121,123,145,146,147,148,149,153,156,161,164,175,203,204,213,218,223,228,232,233,234,275,292,322,339,340,350,362,388,390,391,393,396,398,400,401,402,403,404,405,406,407,409,411,457,464,465,467,472,476,477,479,482,489,492,508,518,545],entitiess:123,entitii:45,entitl:191,entranc:[118,170],entri:[11,16,19,20,22,24,28,33,45,53,99,124,126,135,137,142,143,147,149,153,158,174,183,184,185,189,204,213,225,226,229,238,275,292,308,309,310,311,312,346,382,386,387,388,389,390,391,394,398,411,435,448,459,464,470,472,474,476,478,485,486,489,492,493,504,512,515,518,533,537,540,545],entriest:215,entrypoint:193,entrytext:[31,137,388,389,390,472],enul:181,enumar:492,enumer:178,env:[238,416,426],environ:[1,2,8,9,14,52,75,77,120,123,124,126,140,151,156,158,159,185,186,191,193,194,228,229,238,242,267,279,284,290,294,306,313,317,328,335,351,360,369,416,426,442,451,470,476,490,516,533],environment:416,envvar:185,eof:436,epic:180,epilog:270,epoch:[19,136,480],epollreactor:461,epub:180,equal:[6,20,22,56,57,60,88,95,96,97,104,118,126,130,142,144,146,149,150,158,174,211,223,308,309,310,311,312,316,350,353,354,398,492],equip:[15,60,83,114,134,148,157,158,286,308,309,311,312],equival:[9,11,13,14,30,36,50,53,54,58,60,62,68,118,147,151,153,185,194,195,199,203,206,218,289,331,337,338,389,396,405,434,440,464,492,513,541],eras:[75,312],erik:77,err:[135,425,447,470],err_travers:[37,398],errback:[54,413,416,425,426,492],errmessag:211,errmsg:[165,485],erron:[70,165,425,478],error:[0,3,4,6,8,9,11,13,15,16,18,19,20,22,28,30,32,33,36,37,39,41,44,48,53,54,64,65,67,70,73,75,76,86,95,99,113,118,120,123,133,134,135,138,142,144,149,150,152,153,155,159,161,165,170,172,173,177,181,182,183,185,187,188,190,191,194,195,201,202,204,206,209,211,212,218,223,230,232,257,270,292,294,336,338,339,340,350,354,371,382,386,394,396,398,401,402,405,409,410,413,415,416,418,420,421,425,439,447,466,469,470,472,475,476,479,485,488,492,493,498,513,515,531,535,540,545],error_check_python_modul:416,error_class:[502,504,506,508,532],error_cmd:131,error_consumable_excess_messag:292,error_consumable_missing_messag:292,error_consumable_order_messag:292,error_msg:459,error_tool_excess_messag:292,error_tool_missing_messag:292,error_tool_order_messag:292,errorlist:[502,504,506,508,532],errorlog:181,escal:[12,39,57,158,215,393,467],escap:[30,60,90,104,118,137,224,228,270,273,276,469,479,491,532],escape_char:479,escaperoom:[90,276],escript:[76,82,241],esom:225,especi:[5,16,33,39,44,46,76,106,128,148,149,151,156,170,181,182,185,346,349,470],esqu:149,ess:29,essai:180,essenti:[7,58,70,127,132,133,148,158,180,187,190,233,416,472],est:[29,229],establish:[22,44,104,114,156,157,158,162,187,204,308,398,413,425,427,434,436,439,444,447,454,456],estim:[129,337,403,483],esult:398,etc:[0,8,11,12,13,18,19,22,25,28,30,31,33,34,35,36,37,39,41,42,44,45,48,50,51,52,53,55,58,62,65,67,68,69,71,76,77,80,86,87,90,92,94,95,104,106,109,112,118,119,120,121,122,123,126,128,129,132,133,134,135,136,143,144,146,147,148,156,157,158,161,162,164,173,175,176,180,181,182,185,187,193,194,199,204,207,209,210,211,212,215,217,218,223,226,228,230,233,238,244,247,270,275,276,283,293,305,309,311,322,337,338,339,340,346,349,350,354,364,380,398,402,403,434,436,439,443,444,445,455,456,464,466,469,470,472,473,474,475,476,479,485,492,496,501,508,512,518,521,543],etern:28,ethic:78,euclidian:118,eunpyo:77,ev_channel:205,evadventur:[158,163],eval:[30,41,283,492,545],evalstr:394,evalu:[22,28,30,79,120,146,157,159,210,283,394,476,479],evbot:[223,457],evcast:180,evcel:[475,478],evcolor:180,evcolumn:478,evdemo:90,eve:492,eveditor:[24,26,31,76,82,95,121,201,202,241,468,545],eveditorcmdset:474,even:[0,3,5,6,7,13,15,18,19,20,27,28,31,33,39,42,44,47,48,49,50,55,57,60,64,67,69,72,73,75,76,81,83,87,91,92,95,96,104,106,112,115,118,119,122,123,124,125,126,128,130,132,133,134,135,136,137,138,141,142,146,147,149,150,151,152,155,156,157,158,159,161,162,163,164,165,172,175,184,185,191,194,199,204,211,213,216,223,225,232,247,270,286,292,308,309,310,311,312,316,337,338,340,349,354,372,380,398,402,403,439,476,478,479,483,492,540,545],evenia:147,evenli:[19,118,247,338,492],evenn:193,evenna:75,evenni:124,evennia:[1,2,5,6,10,12,13,14,15,16,17,18,19,20,22,24,25,26,27,28,29,31,32,33,34,35,36,37,39,40,42,44,45,46,47,48,50,52,53,54,57,58,59,60,61,62,63,65,67,68,69,70,72,73,76,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,96,97,98,99,100,101,103,104,105,107,108,109,110,111,112,113,114,116,117,118,121,123,125,127,128,129,130,131,132,136,137,138,139,141,143,144,145,146,148,149,150,152,153,154,155,156,157,159,161,162,164,165,167,169,170,171,172,173,174,176,177,178,179,183,185,186,189,192,194,195,197,198,545],evennia_access:181,evennia_admin:503,evennia_channel:[186,189,192,223],evennia_dir:492,evennia_error:181,evennia_gener:169,evennia_launch:[7,201,202,412,414,545],evennia_logo:[53,169],evennia_runn:7,evennia_server_port:40,evennia_superuser_email:185,evennia_superuser_password:185,evennia_superuser_usernam:185,evennia_vers:416,evennia_websocket_webcli:444,evennia_wsgi_apach:181,evenniaadminapp:523,evenniaadminsit:523,evenniaapiroot:514,evenniacommandmixin:[8,490],evenniacommandtest:[8,490],evenniacommandtestmixin:490,evenniacreateview:[536,542,543],evenniadeleteview:[542,543],evenniadetailview:[542,543],evenniaform:532,evenniagameindexcli:418,evenniagameindexservic:419,evenniaindexview:[53,541],evennialogfil:485,evenniapasswordvalid:460,evenniapermiss:[513,518],evenniareverseproxyresourc:461,evenniaserv:40,evenniatest:[8,378,490],evenniatestcas:[8,490],evenniatestmixin:[8,490],evenniaupdateview:[542,543],evenniausernameavailabilityvalid:[204,460],evenniawebtest:533,event:[28,31,45,51,78,87,104,123,159,162,194,201,205,247,256,257,258,260,275,283,350,364,376,406,409,458,545],event_nam:[256,260],event_push:95,eventcharact:95,eventdict:485,eventexit:95,eventfunc:[97,201,202,235,236,253,257,545],eventfuncs_loc:95,eventhandl:[95,257],eventi:[213,241,270],eventobject:95,eventroom:95,events_calendar:95,events_dis:95,events_valid:95,events_with_valid:95,events_without_valid:95,eventu:[13,22,39,55,57,64,65,68,88,124,128,135,155,156,158,159,164,165,169,177,191,199,204,209,210,218,227,233,275,276,343,349,350,364,372,394,398,403,413,421,447,455,456,467,471,472,476,478,530],evenv:[2,6,7,123,124,185,190],evenwidth:478,ever:[9,11,13,14,15,16,22,30,42,44,46,48,55,67,70,76,106,118,123,134,142,146,149,157,162,170,172,182,198,199,273,276,338,349,411,427,428,434,464,476],everi:[0,2,5,8,9,10,11,14,18,19,20,22,28,30,31,32,35,41,42,46,47,48,58,67,69,70,73,77,78,81,85,87,92,95,96,97,118,119,120,123,124,125,127,130,132,134,136,137,141,142,143,144,146,148,149,151,152,157,162,164,165,169,170,173,174,176,177,178,185,187,190,191,193,195,204,218,223,238,257,274,286,289,294,308,309,310,311,312,329,337,338,349,350,359,369,380,386,398,403,409,411,421,438,448,454,463,464,466,476,477,478,479,490,492,501,508,545],everror:257,everyon:[9,11,18,22,28,31,33,36,42,46,57,58,64,90,123,125,135,149,152,153,156,158,159,162,164,165,174,176,179,183,188,192,198,199,218,223,224,225,275,276,278,308,309,310,311,312,343,434],everyong:58,everyth:[0,2,3,6,8,9,11,13,20,28,36,39,41,47,49,50,51,53,57,65,70,73,75,90,104,112,118,120,122,123,125,127,132,135,137,139,141,142,143,148,149,150,151,152,153,154,155,156,157,159,161,162,164,166,169,170,180,185,187,189,190,191,193,194,195,198,199,208,213,223,224,226,228,229,230,251,292,293,354,372,393,397,406,420,447,455,464,466,470,476,545],everywher:[75,133,148,187],evform:[19,121,201,202,468,545],evgam:223,evgamedir:120,evict:459,evid:189,evil:[5,15,187,364,403],evilus:223,evmenu:[19,22,24,76,82,92,100,104,111,113,115,121,135,141,158,201,202,228,241,274,366,369,380,386,400,468,477,490,545],evmenucmdset:476,evmenuerror:476,evmenugotoabortmessag:476,evmenugotomessag:476,evmor:[24,26,31,121,201,202,402,468,545],evscaperoom:[201,202,235,271,545],evscaperoom_start_st:90,evscaperoom_state_packag:90,evscaperoommenu:274,evscaperoomobject:[275,276],evtabl:[19,22,92,121,132,170,201,202,213,223,380,402,468,475,477,492,545],ewmaplink:[118,338],ewonewaymaplink:[118,338],exact:[5,11,22,28,39,72,112,146,149,153,204,206,210,218,223,227,233,292,312,350,354,389,396,398,402,403,465,466,488,489,492],exact_consum:292,exact_consumable_ord:[292,293],exact_tool:292,exact_tool_ord:292,exactli:[3,5,9,12,28,30,31,39,42,47,50,54,57,59,60,62,65,67,86,96,112,118,120,123,135,136,137,142,143,146,147,149,151,153,157,158,162,165,169,170,185,193,199,223,292,337,338,350,354,396,398,416,466,489],exam:[26,218],examin:[7,11,12,13,22,26,33,47,51,55,65,74,76,90,135,141,142,143,144,146,162,165,204,218,273,283,364,371,372,448,464,479,490,500,513,545],exampl:[2,4,5,6,7,8,10,11,12,13,14,15,16,17,18,19,20,22,26,31,32,34,35,36,37,41,44,46,47,48,49,50,54,57,58,59,60,62,64,65,67,68,72,73,74,76,77,78,79,82,83,87,88,90,92,93,95,97,104,106,110,112,113,114,115,116,119,120,122,123,124,125,126,127,128,129,131,132,133,134,135,136,139,140,141,142,143,144,145,146,148,149,150,151,152,153,155,156,157,158,159,161,165,169,170,171,172,174,175,176,177,181,182,185,187,188,192,193,194,195,199,201,202,204,207,210,211,212,213,216,217,218,223,224,225,226,227,228,229,232,234,235,241,247,266,270,273,275,280,283,286,289,292,293,294,296,299,305,308,309,310,311,312,314,316,322,325,327,330,331,335,337,338,339,340,343,346,349,350,353,354,355,356,358,359,364,366,370,372,376,380,382,386,388,390,391,394,397,398,403,406,409,411,416,421,436,439,440,445,448,457,461,464,466,467,468,469,471,475,476,477,478,479,480,484,485,486,489,490,492,493,495,496,501,508,517,518,532,541,545],example1_build_forest:99,example1_build_mountain:99,example1_build_templ:99,example1_legend:99,example1_map:99,example2_build_forest:99,example2_build_horizontal_exit:99,example2_build_verticle_exit:99,example2_legend:99,example2_map:99,example_batch_cmd:80,example_batch_cod:[14,80,201,202,235,355,356,545],example_recip:[201,202,235,281,291,292,545],example_recipi:292,excalibur:141,exce:[140,239,308,309,310,311,312,459,483],exceed:459,excel:[33,69,133,180,187],excempt:211,except:[6,13,15,19,20,22,27,28,30,31,33,37,41,42,49,50,53,54,57,60,65,75,76,86,95,96,117,118,120,123,124,125,127,128,130,135,142,144,146,148,150,151,152,153,158,164,165,170,172,173,174,175,177,178,185,190,191,204,205,207,209,212,213,226,227,232,233,234,247,256,257,260,270,275,276,277,283,286,292,296,302,305,308,309,310,311,312,316,322,325,329,336,337,338,339,340,349,350,354,359,362,364,366,370,371,372,382,390,393,394,396,397,398,402,405,406,409,410,416,421,423,425,437,439,441,445,449,461,464,467,469,472,475,476,478,479,480,484,485,487,492,500],excepteur:29,excerpt:27,excess:[33,41,76,161,226,292,397,470,492],exchang:[14,52,79,157,191,283,473],excit:[25,143,144,158,184],exclam:125,exclud:[58,95,123,146,153,165,173,232,286,305,372,396,397,398,474,476,510,512],exclude_cov:286,excluded_par:510,excluded_typeclass_path:218,excludeobj:396,exclus:[28,31,33,35,156,364,398,406,465,476,492],exclusiv:[405,472],exe:[7,9,185],exec:[28,30,141,403,476,492],exec_kwarg:476,exec_str:451,execcgi:181,execut:[2,7,9,14,15,20,22,27,28,30,36,37,41,42,51,52,53,54,55,57,59,65,71,75,76,80,90,95,96,97,99,116,123,126,127,128,136,137,141,142,148,151,155,158,170,185,190,204,205,207,208,209,213,216,217,226,228,229,234,241,257,269,270,273,293,350,362,364,372,386,390,393,394,397,398,403,404,406,410,413,421,423,426,427,433,436,439,444,447,448,451,454,455,464,466,467,470,476,477,479,484,490,492,521,545],execute_cmd:[12,22,37,165,171,172,204,205,213,398,421,455],execute_command:22,executor:2,exemplifi:[31,62,104,115,118,127,152,155,157],exercis:[3,125,135,141,151,164,165,170,176,239,294,353,442,452,484],exhaust:[18,76,383],exhaustedgener:382,exidbobj:398,exis:131,exist:[0,2,5,6,9,11,12,13,14,18,19,20,22,25,26,28,33,41,42,44,46,47,53,55,62,64,67,76,77,82,86,90,91,95,96,97,102,105,106,110,112,118,119,123,125,126,130,131,132,133,134,135,137,144,145,146,148,150,151,155,156,159,161,164,165,167,169,170,171,178,182,186,189,193,203,204,205,206,211,212,213,218,223,225,226,228,238,239,241,254,256,257,260,274,280,289,293,299,302,305,311,316,325,329,337,338,339,340,349,350,354,371,391,393,394,397,398,400,402,403,405,410,416,420,422,436,437,439,441,449,454,455,457,464,465,466,467,470,472,474,475,476,478,479,485,487,492,500,518,545],existen:455,exit:[7,8,9,20,27,28,33,41,48,49,50,67,76,79,82,95,99,104,109,115,117,118,121,125,130,132,135,138,141,142,143,144,145,148,149,151,152,153,155,165,170,174,182,185,193,198,201,209,211,212,218,228,235,241,242,258,270,276,283,289,312,314,322,324,326,329,331,332,337,338,339,340,364,370,371,372,386,393,396,397,398,403,420,436,448,464,472,474,476,477,490,512,515,518,533,545],exit_alias:[218,322],exit_back:135,exit_cmd:[28,477],exit_command:398,exit_dest_x_coordin:118,exit_dest_y_coordin:118,exit_dest_z_coordin:118,exit_nam:[132,218,322],exit_on_lastpag:477,exit_ther:135,exit_to_her:218,exit_to_ther:218,exit_typeclass:[329,490,533],exitbuildingmenu:76,exitcmdset:[20,398],exitcommand:398,exitnam:322,exitobject:131,exitviewset:518,exixt:434,exot:22,exp:475,expand:[11,32,37,49,58,60,73,74,89,90,97,104,109,114,123,124,125,132,134,135,139,141,143,144,146,148,149,150,151,152,156,157,158,159,165,166,170,171,173,176,182,191,195,201,202,218,235,251,308,309,310,311,312,322,331,341,352,398,469,478,545],expand_tab:478,expandtab:[469,478],expans:[131,156],expect:[5,6,8,9,22,30,35,36,37,45,47,53,54,58,64,65,68,70,75,95,97,107,118,120,133,135,142,148,149,151,153,155,156,158,159,165,175,178,187,190,191,218,226,229,238,241,254,256,289,292,329,335,337,338,382,393,398,402,403,414,416,466,476,477,479,483,490,492,497,501,508,518,524,543],expected1:490,expected2:490,expected_1st_or_2nd_person:497,expected_3rd_person:497,expected_direct:335,expected_input:490,expected_path:335,expected_return:8,expectlst:335,expectstr:335,expens:[47,191,396,489],experi:[0,3,28,30,73,86,101,104,114,115,134,136,139,143,146,151,152,155,156,162,163,170,185,191,193,223,275,362,545],experienc:[1,13,28,123,151,154,180],experienced_betray:28,experienced_viol:28,experiment:[32,53,228,502,505],expert:[112,354],expir:[77,238,289],explain:[11,22,26,28,49,53,67,72,76,95,118,122,123,130,135,144,148,158,161,169,174,175,178,180,188],explan:[20,22,50,60,95,123,126,130,137,276,460,545],explanatori:50,explicit:[20,62,68,72,76,97,120,137,142,169,182,188,195,382,416,438,464,476,496],explicitli:[6,13,20,31,33,34,36,39,41,42,46,47,48,60,65,67,75,112,118,124,125,129,135,141,149,150,152,157,158,185,187,212,213,218,225,233,338,354,382,388,398,403,405,411,464,466,469,472,488,490,515],exploit:[158,467,469,479,492],explor:[3,12,48,53,54,65,97,115,118,137,144,149,151,155,164,170,185,195,228,545],expos:[85,178,194,289,364,540],express:[22,28,30,33,41,52,73,74,78,87,107,120,133,146,149,153,167,178,218,247,312,382,464,492,521],ext:28,extend:[18,19,30,42,48,50,53,67,69,78,84,99,104,120,122,130,133,137,141,143,147,148,150,151,154,160,162,163,166,167,168,170,171,172,177,178,180,197,198,207,213,225,229,232,238,244,257,260,289,292,293,315,316,329,337,397,398,466,486,505,532,541,542,543,545],extended_room:[91,201,202,235,314,545],extendedloopingcal:411,extendedroom:[91,316,317],extendedroomcmdset:[91,316],extendng:293,extens:[6,8,28,31,60,68,75,118,120,122,123,133,144,148,149,156,167,170,182,185,195,207,238,308,332,377,389,431,439,472,482,491],extent:[76,95,133,158,162],exter:223,extern:[7,16,35,41,59,62,69,95,104,118,134,148,152,156,158,159,161,170,181,182,184,185,186,187,189,191,192,197,201,212,223,231,233,234,376,402,414,416,418,472,490,545],external_discord_hello:421,external_receiv:234,extra1:30,extra2:30,extra:[0,13,15,18,20,22,28,30,31,33,37,45,48,51,53,56,71,77,79,90,104,112,118,119,120,125,126,128,134,135,143,151,152,157,158,165,169,175,178,181,182,191,204,207,213,225,229,232,283,292,296,302,316,350,353,354,364,372,398,401,402,411,413,465,469,470,474,476,477,478,479,485,486,487,491,492,500,501,508,545],extra_environ:470,extra_launcher_command:[118,332,333],extra_opt:476,extra_spac:492,extract:[6,13,30,45,103,104,133,142,213,266,267,275,292,337,350,377,394,430,444,492],extract_goto_exec:476,extrainfoauthserv:436,extral:234,extran:380,extrem:[0,9,133,142,152,199,308,309,311,312,429,486],eye:[6,31,60,99,156,170,403,477],eyed:[53,161,169],eyes:[22,119,134],eyesight:[33,60,135],f6d4ca9b2b22:193,face:[93,95,118,143,155,158,187,191,194,230,296,460,476],facil:485,facilit:158,fact:[7,15,22,37,42,48,54,65,74,122,125,128,134,135,147,148,149,156,165,171,175,178,194,198,457,459,479],faction:185,factor:[97,136,140,309,311,413,427,428],factori:[62,354,413,418,426,427,428,434,435,436,437,439,447],factory_path:205,fade:[69,106,349],fail:[13,14,15,18,19,20,28,30,31,37,41,45,54,55,70,75,86,108,115,118,124,142,150,155,156,161,164,171,174,183,185,194,199,204,212,223,227,232,269,292,294,322,343,350,353,354,364,371,383,393,394,398,402,413,414,416,420,427,428,438,459,464,466,477,479,486,488,492,495,501,538,545],failmsg:459,failtext_templ:162,failur:[15,54,86,157,162,185,204,292,372,418,425,427,428,447,459,469,492],failure_effect:293,failure_messag:292,failure_teleport_msg:372,failure_teleport_to:372,faint:42,fair:[88,157,158,162,343],fairli:[83,92,130,137,190,286,309,380,386],fake:[8,84,118,244,338,447,457,464,469],fall:[0,6,20,42,70,93,95,115,118,120,123,136,149,162,170,201,204,227,292,296,350,364,372,492,532],fall_exit:372,fallback:[91,131,132,209,213,234,316,394,409,416,445,464,476,479,487,492],fals:[8,12,13,18,19,20,22,27,28,30,31,32,33,34,37,39,42,47,48,51,67,76,78,84,92,106,117,118,124,125,126,128,131,132,135,136,139,140,143,144,149,153,161,164,165,172,173,174,177,194,204,206,207,209,210,211,212,213,218,223,225,232,234,238,241,242,244,247,254,257,270,273,274,275,278,283,286,289,292,299,308,309,310,311,312,322,329,337,338,340,343,349,350,369,380,386,388,389,390,393,394,396,397,398,400,402,403,405,406,407,409,410,411,413,416,418,422,425,426,433,434,435,436,439,445,447,453,454,455,457,459,461,464,465,466,467,469,470,472,474,476,477,478,479,480,483,487,488,489,490,491,492,493,495,497,500,501,502,504,505,506,508,512,513,532,540],falsestr:[92,380],falsi:[143,150,232,292,337],fame:[155,159],famili:[28,75,134,161],familiar:[1,20,22,48,75,95,103,104,120,128,130,135,141,142,146,149,150,151,159,167,170,177,185,191,266,545],famou:[29,474],fan:180,fanci:[2,16,17,18,49,77,83,118,162,286,338],fantasi:[153,158,349],faq:[120,438,545],far:[7,11,14,18,20,22,53,60,68,76,95,96,97,99,117,118,122,125,130,131,132,134,142,144,146,148,149,151,152,170,184,190,191,193,211,312,329,337,340,418,443,464,474,483],fare:149,fart:161,fascilit:339,fashion:[41,170],fast:[0,11,13,16,19,37,47,69,104,118,123,128,133,136,140,151,158,159,182,216,391,448],faster:[5,13,118,136,153,158,182,234,283,464,545],fastest:[120,338],fatal:416,fault:159,faulti:151,favor:[19,118,338],favorit:[119,125],fear:19,feasibl:182,feat:158,featgmcp:440,featur:[0,2,3,8,9,11,16,17,19,20,22,27,41,45,48,53,59,60,72,76,90,95,96,97,104,106,113,115,118,119,120,122,123,124,126,132,133,134,136,138,139,141,142,143,144,155,156,157,158,165,170,179,185,189,194,204,212,213,257,270,316,350,386,411,433,454,458,466,474,492,539,544,545],feb:64,februari:136,fed:[22,33,54,434,464,473,475],fedora:[11,181,185,187],feed:[9,16,28,132,162,192,205,223,337,418,435,436,466,477],feedback:[3,11,37,119,156,159,172,233,474],feedpars:[192,435],feedread:205,feel:[11,17,48,54,64,69,76,95,96,97,106,113,119,120,122,123,130,134,137,142,146,149,154,155,156,158,159,161,162,165,168,172,177,185,188,191,275,309,349,364,372,386,545],feelabl:275,feend78:299,feint:164,fel:64,felin:19,fellow:475,felt:[42,176],femal:[58,93,296,479,496],fetch:[9,11,13,49,52,53,146,177,185,191,193,339,464,477,543],few:[0,2,3,5,11,13,16,17,20,22,27,30,31,32,33,37,50,53,54,60,63,67,68,75,78,90,97,106,119,120,122,123,124,132,142,144,147,149,151,156,157,158,159,162,164,165,174,175,180,182,187,194,199,228,247,349,364,397,431,440,459,469,478,492,541],fewer:[69,151,337,457,465],fg_colormap:491,fgstart:491,fgstop:491,fiction:[28,122,136,476],fictional_word:349,fictiv:349,fictou:280,fiddl:372,field:[7,9,13,30,31,32,34,35,36,37,41,42,45,46,48,50,53,64,67,73,104,112,133,135,145,149,167,177,182,184,207,234,254,312,331,350,354,370,380,390,391,393,396,397,398,402,403,406,407,411,423,464,465,466,467,475,484,488,489,500,501,502,504,505,506,508,512,515,520,532,543,545],field_class:532,field_nam:[391,512],field_or_argnam:32,field_ord:532,fieldevmenu:380,fieldfil:[92,201,202,235,374,545],fieldnam:[34,92,135,380,407,466,483,532],fieldset:[500,502,504,505,506,508],fieldtyp:[92,380],fifo:492,fifth:132,fight:[20,42,104,114,128,150,155,156,164,308,309,310,311,312,371,545],fighter:[114,308,309,310,311,312],figur:[0,3,5,6,11,22,31,55,58,65,90,106,119,132,137,142,147,149,156,159,167,174,177,191,247,283,292,338,350,402,416,495,545],file:[0,2,3,5,6,7,8,9,10,12,18,19,20,26,28,39,40,49,50,51,52,53,57,62,63,64,67,73,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,123,124,125,126,131,133,134,135,136,137,139,141,143,144,147,148,150,151,152,154,158,165,167,169,170,171,173,174,177,178,180,181,182,184,185,186,187,189,190,191,192,193,194,197,198,199,201,202,204,217,225,232,238,239,241,244,247,251,270,276,286,292,329,349,354,376,388,403,415,416,436,437,440,441,448,449,450,454,461,462,468,475,476,485,488,489,492,496,501,502,504,506,508,518,521,525,532,540,545],file_end:[470,492],file_help_entry_modul:[31,225,388],file_help_top:540,file_name_charset:238,file_overwrit:238,file_to_revert:11,fileentri:225,filehelp:[31,201,202,387,545],filehelpentri:[225,388,540],filehelpstoragehandl:388,filelogobserv:485,filenam:[11,19,80,106,147,232,238,349,470,475,485],filename1:416,filename2:416,filepath:238,files:238,filesystem:[185,193,194],filip:77,fill:[2,7,27,53,64,73,92,99,104,112,118,132,135,151,170,177,186,269,337,340,354,380,464,469,475,476,477,478,479,492,508,545],fill_char:478,fill_color:346,fillabl:[380,545],fillchar:[30,469,479,492],filler:496,filo:492,filter:[7,20,35,48,49,60,67,78,95,118,130,137,146,173,177,201,202,211,216,241,316,340,350,397,398,492,498,511,518,538,545],filter_backend:518,filter_famili:[48,146],filter_nam:512,filter_xyz:[118,340],filter_xyz_exit:[118,340],filterset:512,filterset_class:518,filthi:179,final_path:238,final_valu:54,find:[0,3,5,6,8,9,11,13,14,15,17,19,20,22,26,27,30,31,32,33,34,35,36,37,41,42,46,48,50,53,54,55,59,60,62,64,67,69,73,74,76,86,91,96,97,99,109,113,115,118,119,120,122,124,125,126,128,132,133,134,135,136,137,142,143,144,145,146,147,148,149,150,152,154,155,156,158,159,161,162,163,165,167,169,177,178,179,180,182,183,185,187,190,191,193,194,199,204,210,218,225,247,270,275,278,292,316,322,331,332,337,338,340,350,354,372,386,398,402,403,405,408,416,430,464,465,469,471,479,489,492,523,545],find_apropo:389,find_topicmatch:389,find_topics_with_categori:389,find_topicsuggest:389,findfoo:153,fine:[16,22,37,42,44,46,47,55,67,79,96,104,118,120,123,131,141,144,148,149,150,152,154,155,157,161,165,172,205,206,338,372,464,472,492],finer:[55,337,338],finish:[9,15,22,45,52,54,86,115,120,128,135,155,156,165,169,177,193,201,204,213,215,226,228,230,273,278,283,292,293,305,316,338,371,372,398,416,428,439,454,461,471,476,492,521],finish_chargen:28,finit:142,fire:[7,12,19,22,28,42,45,47,85,87,95,96,125,127,128,135,144,149,152,156,170,172,173,176,204,205,209,257,289,310,311,398,403,416,425,427,444,476,477,483],firebal:[86,158,292,293],fireball_recip:86,fireballrecip:293,firebreath:[135,149,152],firefox:[53,189],firemag:293,firestorm:127,firestorm_lastcast:127,firewal:[182,187,191,545],first:[0,3,5,6,7,9,11,12,13,14,15,16,19,20,22,25,27,28,30,31,33,37,39,41,42,44,45,48,50,51,53,54,55,56,57,58,60,62,64,65,67,69,70,73,75,82,84,90,95,99,112,114,117,119,120,122,124,125,128,130,132,133,135,136,137,138,139,141,142,143,144,145,146,147,148,150,152,153,154,155,156,157,158,159,161,162,164,165,167,168,169,172,173,174,175,176,177,178,182,183,185,186,188,190,191,192,193,194,195,197,199,204,205,207,210,211,218,225,226,229,230,232,234,238,241,244,247,250,251,270,275,276,277,278,283,286,289,308,309,310,311,312,316,322,329,332,337,338,349,350,353,354,359,364,366,370,371,372,382,390,393,397,398,402,403,405,406,409,416,420,421,423,434,436,439,444,445,447,448,454,457,464,466,467,469,470,472,474,475,476,478,479,480,483,484,490,491,492,513,545],first_lin:165,first_nam:500,firsthand:33,firstli:[6,37,53,75,145,146,191],fish:[162,212,305],fist:[150,403],fit:[10,30,31,39,68,72,85,130,135,148,159,161,168,174,177,182,289,293,309,312,475,477,478,492],five:[22,127,146,154,159,168,170,191,212,386,492,493],fix:[0,3,6,14,15,19,22,28,41,48,56,65,77,90,106,118,119,123,134,141,149,151,152,156,158,161,165,174,179,185,190,191,199,340,349,416,475,477,478,488,545],fix_sentence_end:478,fixer:146,fixtur:[229,239,248,279,294,313,335,351,353,360,442,452,484,516],fizzl:158,flag:[14,15,20,22,28,32,47,50,62,65,67,69,75,127,128,129,135,144,149,151,154,156,161,165,204,209,211,213,218,273,275,276,278,292,294,364,370,393,394,398,416,423,427,436,439,444,455,474,476,492],flagnam:[273,275,276],flair:161,flame:[127,293,311],flash:[15,108,364],flat:[0,19,48,76,121,133,147,201,403,495,545],flatfil:133,flatpag:523,flatten:403,flatten_diff:403,flatten_prototyp:403,flattened_diff:403,flavor:[58,144,157,191,311],flavour:[36,175],flaw:174,fled:[164,370],fledg:[16,69,71,104,115,158,165,166,177,191,217],flee:[164,171,312,370],fleevalu:164,flesh:[135,144,158],flexibl:[14,28,41,42,68,69,76,82,92,113,118,125,128,130,134,149,152,157,158,161,162,164,170,178,191,207,218,241,283,292,380,386,440,464,476,492,541,545],fli:152,flick:493,flicker:364,flip:[26,28,139,230],flood:[19,27],floor:[95,97,140,273,275,350,353],flour:[86,104,292],flourish:464,flourrecip:292,flow:[2,17,47,51,62,65,67,90,118,122,156,161,185,233,472,476,545],flower:[36,37,55,120,144,145,146,153,156,157,218,479,545],flowerpot:[55,134],fluent:180,fluffi:[149,150,152],fluid:[17,56],flurri:350,flush:[9,22,170,182,228,464,466,483],flush_cach:483,flush_cached_inst:483,flush_from_cach:483,flush_instance_cach:483,flusher:483,flushmem:228,fly:[19,20,22,28,30,31,41,42,55,86,123,125,141,146,148,149,153,167,204,224,226,234,390,398,402,411,423,434,437,441,464,470,480,492],fnmatch:464,foci:158,focu:[90,124,154,156,158,164,273,275],focus:[7,90,133,134,165,180,273,275,312,515],focused_object:273,foe:309,foilag:118,fold:[113,158,386],folder:[7,8,9,14,15,19,50,51,53,64,67,73,90,99,104,114,118,119,120,123,125,129,132,134,135,137,144,147,148,149,151,162,164,165,167,169,170,171,172,177,178,181,185,190,193,194,198,199,308,309,310,311,312,416,490,523,545],folder_nam:123,follow:[3,5,6,7,9,11,12,13,14,15,17,18,20,22,27,28,30,31,32,33,37,39,42,46,48,50,51,53,54,56,57,60,62,64,67,68,73,75,76,77,80,82,83,84,85,90,93,95,96,97,98,99,104,106,112,113,118,119,120,124,126,130,132,135,136,137,140,141,142,143,144,146,148,149,150,151,152,154,156,159,161,162,163,164,165,171,173,174,177,178,180,181,182,184,185,186,187,188,190,191,193,194,199,204,205,207,209,210,213,218,225,226,229,232,233,234,241,244,250,251,257,286,289,292,296,299,310,311,337,338,350,354,372,386,388,390,391,393,394,397,398,401,402,403,406,407,420,421,431,440,444,445,448,458,464,466,469,470,472,475,476,477,478,485,492,517],follwo:394,fond:136,font:[51,120,126,148,170,338],foo1:13,foo2:13,foo:[11,13,18,22,28,30,31,34,42,45,46,62,65,68,113,118,143,146,147,148,149,151,153,185,218,337,339,386,391,416,464,476,479,490],foo_bar:68,foobar:28,foobarfoo:55,food:[86,95,292],fooerror:476,fool:158,foolish:364,footer:[53,118,137,177,213,398,477],footnot:[16,120],footprint:228,footwear:134,for_cont:398,forai:148,forbidden:11,forc:[8,20,22,42,48,54,97,105,106,118,135,139,140,142,143,152,159,161,162,164,165,174,181,185,193,194,199,205,212,216,218,223,283,293,296,305,316,317,337,349,350,354,394,398,402,408,427,428,434,439,457,459,477,478,483,485,492],force_init:398,force_repeat:[42,164],force_str:488,forceutcdatetim:317,forcibl:408,fore:454,forebod:316,foreground:[3,60,84,175,193,244,416,469,479,545],foreign:[48,146],foreignkei:[207,397,406,466,484,501,508],forens:377,forest:[14,46,74,99,118,148,170,316],forest_meadow:46,forest_room:46,forestobj:74,forget:[14,19,22,54,67,75,126,136,141,143,149,151,152,165,167,184,189,193,350,470,545],forgiv:161,forgo:371,forgotten:[119,127,132,141,149],fork:[75,77,180,545],forloop:137,form:[6,8,11,13,14,18,19,20,22,28,30,31,32,33,37,39,41,46,47,48,50,52,58,65,68,70,71,72,73,86,90,93,102,104,106,112,118,119,120,121,122,123,135,143,148,150,152,153,154,156,159,164,165,172,201,202,204,205,206,210,212,213,216,218,223,226,229,232,233,234,273,280,283,292,296,340,349,350,354,377,380,388,390,393,394,396,398,402,403,407,409,411,414,434,436,440,444,455,457,464,465,466,469,470,472,473,474,475,476,478,479,480,485,488,489,492,493,495,496,498,500,501,502,504,505,506,508,510,515,531,536,538,543,545],form_char:475,form_class:[53,536,538],form_template_to_dict:380,form_url:500,form_valid:[536,538,543],formal:[33,156,398,440,496,545],format:[3,11,15,17,18,19,20,22,31,57,60,64,65,68,69,70,72,76,84,95,96,112,116,117,118,119,120,122,135,137,139,146,150,151,161,162,165,170,177,180,182,192,194,211,213,215,218,225,229,232,233,238,241,244,247,260,270,274,280,286,292,310,329,337,350,354,362,369,376,380,386,388,390,398,400,402,403,407,416,421,431,436,456,458,464,466,469,470,472,474,476,477,478,480,485,487,492,493,515,518,545],format_:218,format_account_kei:218,format_account_permiss:218,format_account_typeclass:218,format_alias:218,format_attribut:218,format_available_protfunc:402,format_callback:254,format_channel_account_sub:218,format_channel_object_sub:218,format_channel_sub_tot:218,format_char:218,format_current_cmd:218,format_destin:218,format_diff:403,format_email:218,format_exit:218,format_extern:232,format_grid:492,format_help:270,format_help_entri:225,format_help_index:225,format_hom:218,format_kei:218,format_loc:218,format_lock:218,format_merged_cmdset:218,format_messag:232,format_nattribut:218,format_output:218,format_permiss:218,format_script:218,format_script_desc:218,format_script_is_persist:218,format_script_timer_data:218,format_send:232,format_sess:218,format_single_attribut:218,format_single_attribute_detail:218,format_single_cmdset:218,format_single_cmdset_opt:218,format_single_tag:218,format_stored_cmdset:218,format_t:492,format_tag:218,format_text:241,format_th:218,format_typeclass:218,format_usag:270,formatt:[294,380,402,476,477],formcallback:[92,380],formchar:[135,475],formdata:[92,380],former:[17,123,175,182,292,476],formfield:488,formhelptext:380,formset:[501,508],formstr:135,formtempl:[92,380],formul:178,forth:[11,19,218,311],fortress:170,fortun:[9,22,95,124,130,137,149,155],forum:[9,64,75,104,119,122,134,158,159,185,191,192,545],forward:[3,14,15,27,28,136,137,144,154,157,158,174,175,191,204,207,234,299,376,390,397,406,461,464,466,467,475,477,484],forwardfor:187,forwardmanytoonedescriptor:[397,406,484],forwardonetoonedescriptor:[397,406,484],foster:18,foul:41,found:[3,4,6,8,9,12,13,14,15,16,18,19,20,22,28,31,32,33,37,38,39,41,46,48,49,50,51,53,54,58,62,64,65,73,75,76,77,79,90,99,104,115,118,120,122,124,126,130,132,134,135,141,142,143,146,147,148,149,150,151,153,155,161,162,164,165,178,179,182,185,191,194,195,201,204,206,208,209,210,211,213,218,223,226,227,230,232,238,241,254,256,257,283,337,338,339,340,350,354,372,388,390,394,396,398,401,402,403,405,408,411,415,416,422,431,434,445,455,457,464,465,466,469,470,471,472,476,478,479,483,487,489,492,521],foundat:[122,132,146,180,308],four:[15,19,36,60,62,67,91,120,124,130,140,153,162,166,170,212,234,316,394],fourth:130,fqdn:191,fractal:133,fraction:158,frame:51,framework:[49,51,52,53,56,104,123,159,167,169,177,229,308,311,488,512,513,515,517,518,545],frankli:72,free:[7,10,28,31,46,64,76,77,97,102,104,106,113,119,122,123,128,134,146,156,158,164,165,175,177,180,191,238,273,283,309,350,386,402],freedn:191,freedom:[0,15,131,158,185],freeform:[83,158,162,164,286],freeli:[118,193,194,470],freenod:[75,180,185,189,191,205,223,457],freetext:[35,233,489],freez:[3,22,95,128,256],french:64,frequenc:[5,349],frequent:[95,142,241],fresh:[9,20,90,118,135,149,198,416],freshli:170,fri:55,friend:[119,135,140,143,156,159,194],friendli:[76,112,119,120,151,177,179,207,354],friendlier:[232,398],frighten:310,from:[0,1,2,3,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,22,25,27,29,30,32,33,34,35,36,37,39,40,41,42,44,45,46,47,48,49,50,52,53,54,55,56,57,58,60,62,63,64,65,67,69,70,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,123,125,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,145,146,147,148,149,150,152,153,154,155,156,157,158,159,161,162,164,165,167,169,170,171,172,173,174,175,176,178,180,181,182,184,185,187,188,189,190,192,194,195,197,198,199,201,202,204,205,206,207,208,209,210,211,212,213,215,216,217,218,223,224,225,226,227,228,229,230,232,233,234,238,241,244,247,251,256,257,260,266,267,270,273,274,275,276,278,280,283,286,289,292,293,294,296,299,302,305,308,309,310,311,312,316,322,325,329,331,332,337,338,339,340,343,346,349,350,353,354,364,370,371,372,376,377,378,380,382,386,388,389,390,393,394,395,396,397,398,402,403,405,406,407,408,410,411,413,416,420,421,422,423,425,426,427,428,429,433,434,435,436,439,444,445,447,448,450,454,455,456,457,459,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,477,478,479,480,483,484,485,486,488,489,490,491,492,493,495,496,501,502,508,510,512,513,515,518,521,523,532,538,540,543,544,545],from_channel:205,from_db_valu:488,from_nod:476,from_obj:[58,65,139,172,204,205,213,296,362,398],from_pickl:473,from_tz:493,frombox:425,fromstr:425,fromtimestamp:[317,480],front:[11,14,33,41,51,141,143,146,151,162,181,194,197,200,545],frontend:[49,113,386,464],frontpag:[50,53,147,153,201,202,498,499,509,545],frost:157,frozen:[22,128,257],fruit:[104,105,305],ftabl:492,ftp:[77,491],fuel:[112,125,157,311,354],fugiat:29,fulfil:[86,149,155,159,416],full:[0,4,6,8,9,11,14,15,16,17,19,22,26,28,30,33,34,37,39,41,42,44,47,48,56,58,68,69,71,73,75,79,80,86,90,91,94,95,104,106,112,113,114,115,116,118,119,120,122,123,124,125,126,134,135,138,143,144,146,147,151,152,157,158,161,162,164,165,166,169,170,171,174,177,178,182,183,190,191,193,198,199,205,210,212,213,217,218,223,225,227,228,229,232,241,250,266,270,274,278,280,283,292,302,311,316,337,339,340,346,349,350,354,369,386,394,396,403,407,428,434,447,457,458,464,466,470,474,476,478,479,490,492,544,545],full_desc:275,full_justifi:41,full_nam:36,full_result:343,full_system:[90,201,202,235,545],fullchain:187,fuller:135,fullest:159,fullfil:396,fulli:[5,13,22,28,57,64,67,90,118,122,124,135,141,154,161,185,191,194,199,204,233,349,394,398,409,444,456,472,492],fun:[0,5,139,144,156,157,158,169,170,180],func1:[218,394,448],func2:[218,394,448],func:[3,22,27,28,30,33,54,58,65,76,82,85,95,116,120,125,126,127,128,129,131,133,135,136,139,140,141,142,143,148,150,153,161,162,164,165,174,188,209,213,215,216,217,218,223,224,225,226,227,228,229,230,241,247,251,255,266,269,270,273,283,286,289,292,293,296,299,302,305,308,309,310,311,312,316,322,325,331,343,350,364,366,370,371,372,380,386,393,394,398,427,447,448,452,461,474,476,477,479,480,490,492,541,545],func_test_cmd_task:229,funcdef:479,funciton:311,funcnam:[28,30,32,71,148,394,401,402,411,476,479,492],funcpars:[24,41,58,65,71,121,170,195,201,202,401,457,468,492,545],funcparser_cal:[401,479,545],funcparser_callable_add:479,funcparser_callable_center_justifi:479,funcparser_callable_choic:479,funcparser_callable_clr:479,funcparser_callable_conjug:479,funcparser_callable_crop:479,funcparser_callable_div:479,funcparser_callable_ev:479,funcparser_callable_justifi:479,funcparser_callable_left_justifi:479,funcparser_callable_mult:479,funcparser_callable_pad:479,funcparser_callable_pronoun:479,funcparser_callable_pronoun_capit:479,funcparser_callable_randint:479,funcparser_callable_random:479,funcparser_callable_right_justifi:479,funcparser_callable_round:479,funcparser_callable_search:479,funcparser_callable_search_list:479,funcparser_callable_spac:479,funcparser_callable_sub:479,funcparser_callable_toint:479,funcparser_callable_y:479,funcparser_callable_you_capit:479,funcparser_outgoing_messages_modul:457,funcparser_parse_outgoing_messages_en:71,function_nam:228,functioncal:425,functionnam:[30,425],functionpars:[30,402],functool:185,fundament:[22,37,46,134,148,149,151,152,158,398],fur:293,furnac:[292,293],furnitur:[14,46,48],furst:354,further:[3,7,10,11,13,18,19,20,31,41,44,48,49,65,67,75,77,86,97,104,118,120,131,132,134,141,142,149,153,161,170,191,193,195,199,212,218,310,312,338,340,349,403,416,440,492,545],furthermor:[120,175],fuss:193,futur:[11,13,27,36,54,75,117,120,135,136,144,150,151,154,156,159,160,161,163,165,166,168,182,185,193,215,257,293,329,371,421,465,486,493,545],futurist:136,fuzzi:[31,206,223,292,389,396,489,492],fuzzy_import_from_modul:492,gadea:77,gag:183,gain:[5,106,128,146,156,161,213,228,234,350,394,398,545],galosch:349,gambl:[28,343],game:[1,2,3,5,6,7,10,12,14,15,16,17,20,22,23,25,26,27,28,29,30,33,35,36,37,39,40,41,44,45,46,47,48,49,50,51,52,54,57,58,60,63,64,65,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,86,87,88,91,92,94,96,97,99,104,105,106,107,110,113,114,115,116,118,119,120,121,123,124,125,126,127,128,129,131,133,137,138,139,141,142,143,145,146,147,149,150,151,152,153,155,157,160,161,163,164,166,167,168,169,171,172,174,176,177,178,179,180,181,182,183,185,186,187,188,189,190,192,194,195,199,201,202,203,204,205,206,207,209,211,212,213,215,216,217,218,222,223,224,225,228,229,230,231,232,233,234,235,241,247,248,250,251,255,256,257,258,270,271,273,274,275,278,281,283,286,291,293,299,308,309,310,311,312,314,316,325,332,334,337,338,339,340,343,346,349,350,364,369,372,380,382,386,388,389,390,395,396,397,398,405,406,408,409,412,416,418,419,420,421,427,428,433,435,436,439,440,447,448,449,454,455,457,465,466,467,470,471,472,474,475,480,483,485,490,492,500,501,508,513,518,525,541,544,545],game_dir:[485,492],game_epoch:[19,480],game_index_cli:[201,202,412,545],game_index_en:184,game_index_list:184,game_nam:184,game_slogan:[53,75],game_statu:184,game_system:[79,83,85,86,93,98,102,105,114,119,201,202,235,545],game_templ:[53,147],game_websit:184,gamedir:[28,41,53,118,154,197,416,462,490,545],gamedirnam:135,gameim:545,gameindexcli:419,gamemap:99,gameplai:[77,104,158,191,238,273,545],gamer:[186,189],gamesrc:19,gametim:[19,30,87,91,104,121,201,202,246,247,257,316,468,545],gametime_to_realtim:247,gametimescript:247,gameworld:150,gammon:[180,431],gandalf:28,garbag:464,garbl:[104,106,157],garden:180,garment:[83,286],gate:[31,115,118,156,338],gatekeep:31,gatewai:[199,445],gather:[8,22,31,52,65,169,176,183,209,210,372,414,418,472,489],gaug:[157,201,235,341,352,353,545],gaugetrait:354,gave:[123,125,142,149,175,495,497],gbg:469,gcc:[151,152,185],gcreat:218,gear:[7,169,191,205,212,230,251],gemb:77,gemer:[107,382],gen:17,gender:[58,93,104,296,479,496],gendercharact:[93,296],gendersub:[201,202,235,281,545],gener:[2,5,7,8,13,18,20,22,26,28,31,33,36,39,41,42,44,46,50,51,53,54,55,60,64,65,67,68,75,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,97,98,99,100,101,102,103,104,105,106,108,109,110,111,112,113,114,115,116,117,118,119,120,122,123,126,128,132,134,135,136,138,143,144,148,153,156,157,161,162,164,170,175,178,182,185,187,191,195,201,202,204,205,206,208,213,214,215,218,225,226,227,229,230,232,239,241,251,257,269,270,273,275,276,283,286,292,293,296,299,302,308,309,310,311,312,316,322,325,331,338,343,349,350,364,366,369,370,372,376,377,380,381,382,383,386,389,390,394,396,398,400,402,403,405,427,434,436,439,440,444,447,455,456,457,461,464,467,468,469,471,472,474,477,478,479,480,485,487,488,492,516,517,518,524,532,536,537,538,540,541,542,544,545],general_context:[201,202,498,522,545],generalviewsetmixin:518,generate_prototype_kei:338,generate_sessid:434,generic_mud_communication_protocol:440,genericbuildingcmd:[82,241],genericbuildingmenu:241,genesi:191,geniu:[105,305],genr:[119,123,430],genuin:158,geoff:[104,116,270],geograph:74,geographi:130,geoip:376,geometr:170,geometri:170,get:[0,3,5,6,7,8,9,10,11,12,13,14,16,17,18,20,22,26,27,30,31,32,33,34,35,36,40,42,44,45,46,48,49,51,53,54,55,56,58,60,62,64,65,67,68,73,75,76,79,86,88,90,96,97,98,104,106,107,108,110,111,112,113,114,115,117,118,120,122,123,125,126,127,128,129,130,131,132,133,134,135,136,137,139,140,141,142,143,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,172,174,175,177,178,181,182,184,186,188,189,190,191,193,194,195,197,199,204,205,206,207,211,212,213,215,216,218,219,223,224,225,230,232,233,234,238,241,254,256,257,260,273,275,276,278,286,299,305,308,309,310,311,312,325,329,331,335,337,338,339,340,343,350,353,354,359,364,366,371,372,382,386,388,389,390,394,396,397,398,400,402,403,405,406,408,411,414,416,421,425,426,430,434,436,439,440,442,444,445,453,455,456,457,459,464,465,466,467,469,470,471,474,476,478,479,480,482,483,485,486,487,489,492,495,497,500,502,505,506,510,512,515,517,532,540,541,544,545],get_absolute_url:[178,232,390,466],get_account:[394,455],get_account_from_email:206,get_account_from_nam:206,get_account_from_uid:206,get_al:464,get_alia:465,get_alias:515,get_all_attribut:464,get_all_cached_inst:483,get_all_categori:389,get_all_channel:233,get_all_charact:276,get_all_cmd_keys_and_alias:211,get_all_cmdset:492,get_all_mail:299,get_all_puppet:204,get_all_script:405,get_all_scripts_on_obj:405,get_all_sync_data:457,get_all_top:389,get_all_typeclass:492,get_and_load_cmdset:510,get_and_load_typeclass:510,get_and_merge_cmdset:212,get_app_list:523,get_attack:[308,309,310,311,312],get_attr:218,get_attribut:[465,515],get_available_nam:238,get_available_overwrite_nam:238,get_browserstr:445,get_buff:474,get_by_alia:465,get_by_attribut:465,get_by_nick:465,get_by_permiss:465,get_by_tag:465,get_cach:464,get_cache_kei:459,get_cached_inst:483,get_callback:257,get_channel:233,get_channel_alias:223,get_channel_histori:223,get_charact:455,get_client_opt:[421,545],get_client_s:455,get_client_sess:[444,445],get_client_sessid:445,get_cmd_signatur:275,get_command_info:[213,226],get_components_with_symbol:337,get_connected_account:206,get_cont:[396,515],get_content_nam:398,get_context_data:[53,537,540,541,543],get_damag:[308,309,310,311,312],get_db_prep_lookup:488,get_db_prep_valu:488,get_dbref_rang:[206,396,405,465],get_def:410,get_default:488,get_defens:[308,309,310,311,312],get_direct:[118,338],get_display_nam:[3,30,58,76,95,96,106,118,135,140,204,329,340,350,398,466],get_display_symbol:[118,338],get_err_msg:[33,144],get_ev:257,get_evennia_pid:492,get_evennia_vers:492,get_event_handl:260,get_exit:[118,339,515],get_exit_spawn_nam:[118,338],get_extra_info:[213,398,466],get_famili:[48,146],get_fieldset:505,get_form:[500,502,505,506],get_formatted_obj_data:218,get_formset:[501,508],get_game_dir_path:492,get_height:478,get_help:[22,31,137,213,229,255,270,275,476],get_help_categori:540,get_help_text:460,get_help_top:540,get_hint:278,get_id:[177,410,465],get_info_dict:[433,454],get_initi:543,get_input:[476,490,545],get_inputfunc:[68,421,440,457,545],get_internal_typ:488,get_kwarg:533,get_linked_neighbor:338,get_location_nam:[117,329],get_log_filenam:232,get_map:[118,339],get_mass:140,get_message_by_id:233,get_messages_by_receiv:233,get_messages_by_send:233,get_min_height:478,get_min_width:478,get_modified_tim:238,get_msg_by_receiv:35,get_msg_by_send:35,get_new:435,get_new_coordin:329,get_next_by_date_join:207,get_next_by_db_date_cr:[207,234,390,397,406,464,466],get_next_wait:260,get_nick:[465,515],get_nicklist:[205,428],get_node_from_coord:337,get_numbered_nam:398,get_obj_coordin:329,get_object:[278,518,537,540,543],get_object_paramet:238,get_object_with_account:[396,489],get_objs_at_coordin:329,get_objs_with_attr:396,get_objs_with_attr_match:396,get_objs_with_attr_valu:396,get_objs_with_db_properti:396,get_objs_with_db_property_match:396,get_objs_with_db_property_valu:396,get_objs_with_key_and_typeclass:396,get_objs_with_key_or_alia:396,get_oth:283,get_permiss:[465,515],get_pid:416,get_player_count:430,get_posit:275,get_previous_by_date_join:207,get_previous_by_db_date_cr:[207,234,390,397,406,464,466],get_puppet:[12,204,455],get_puppet_or_account:455,get_queryset:[537,538,540],get_rang:312,get_recently_connected_account:206,get_recently_created_account:206,get_redirect_url:538,get_regex_tupl:350,get_respons:526,get_room:[118,339],get_room_at:130,get_rooms_around:130,get_serializer_class:518,get_sess:457,get_session_id:515,get_short_desc:275,get_shortest_path:[118,337],get_spawn_xyz:338,get_stat:149,get_statu:426,get_subscript:233,get_success_url:543,get_sync_data:456,get_system_cmd:211,get_tag:[465,515],get_tag_queri:512,get_time_and_season:316,get_typeclass_tot:465,get_uptim:430,get_url:505,get_username_valid:204,get_valu:[68,421,440,545],get_value_displai:515,get_vari:[254,257],get_view_detail:516,get_visible_cont:398,get_visual_rang:[118,337],get_weight:338,get_width:478,get_wilderness_script:328,get_worn_cloth:286,get_xyz:[118,340],get_xyz_exit:[118,340],get_xyzgrid:[118,339],getattr:34,getbootstrap:56,getchild:461,getclientaddress:[62,436],getdefaultencod:540,getel:51,getenv:[416,426],getgl:51,getinput:476,getkeypair:436,getloadavg:190,getobject:77,getobjectacl:77,getpeer:436,getpid:492,getsizof:483,getsslcontext:[437,441],getstartedwiths3:77,getston:22,getter:[207,234,286,309,312,350,397,398,423,464,497],gettext:64,gfg:469,ghost:31,ghostli:372,giant:125,giantess:149,gid:[5,193,448],gidcount:447,gift:137,gig:158,girl:[154,398],gist:[53,349,492],git:[2,9,10,64,67,69,75,120,126,180,182,185,190,191,193,545],github:[0,10,64,75,85,90,96,119,120,126,134,147,155,156,180,185,190,192,241,289,444,461,492,544,545],gitignor:11,give:[0,4,5,8,9,12,13,14,16,18,19,22,26,28,29,30,33,37,39,41,42,44,45,46,47,48,50,53,54,55,57,58,68,70,74,75,76,79,95,96,97,99,104,106,107,113,114,115,117,118,120,122,123,124,125,126,129,130,134,135,136,137,138,140,141,142,143,144,146,147,148,149,150,151,152,153,154,156,157,159,162,163,164,165,167,169,170,171,172,177,178,180,182,185,190,191,192,193,194,199,204,209,211,212,215,218,223,224,226,232,233,241,273,275,276,278,286,293,308,309,310,311,312,316,329,337,338,349,364,366,372,382,386,396,398,405,406,420,442,448,455,461,464,469,476,478,489,490,492,495,497,515,545],given:[0,3,5,6,8,12,13,14,15,19,20,22,27,28,30,31,32,33,34,35,37,39,41,42,44,47,48,53,54,55,58,59,60,64,65,67,68,70,73,74,76,81,82,85,87,90,92,95,96,97,101,104,105,112,113,118,120,123,124,125,126,130,132,135,136,141,143,144,145,148,149,151,152,155,157,158,162,164,165,171,175,177,178,191,193,199,204,206,209,210,211,212,213,215,216,218,223,225,227,228,229,232,233,234,241,247,250,251,254,256,260,266,270,273,275,276,278,280,286,289,292,293,296,305,308,309,310,311,312,316,322,331,337,338,339,340,343,346,349,350,354,362,364,371,372,380,382,386,391,393,394,396,398,400,402,403,405,407,408,409,411,414,416,421,422,425,434,439,440,445,448,451,455,456,457,458,459,460,461,464,465,466,467,469,470,472,473,474,475,476,477,478,479,480,483,485,487,488,489,490,492,495,496,497,500,513,521,524,537,538,540,545],given_class:520,giver:[104,111,157,309,312,398],glad:142,glade:[118,148],glanc:[19,20,22,76,106,130,135,142,241,350],glance_exit:76,glass:[108,305,364],glob:[28,224,476],global:[5,11,14,22,25,28,30,32,37,41,42,44,47,48,51,69,74,76,77,86,91,95,118,123,133,141,153,156,173,176,187,193,195,218,232,238,257,277,292,316,322,331,339,350,382,396,398,403,404,405,406,410,413,416,421,423,426,447,448,470,471,472,476,479,480,489,490,492,525,545],global_script:[201,471,545],global_search:[14,19,76,135,142,204,350,398,465],globalscriptcontain:471,globalth:490,globe:[169,191],glori:155,glorifi:[112,354],gloriou:146,glossari:[185,545],glow:170,glu:40,glyph:425,gmcp:[32,65,440,545],gmsheet:135,gmt:[77,148],gmud:183,gno:76,gnome:[64,183],gnu:15,go_back:[386,476],go_up_one_categori:386,goal:[42,115,120,142,155,156,159,161,180,194,349,544],goals_of_input_valid:532,goblin:[28,41,148,218,403],goblin_arch:403,goblin_archwizard:403,goblin_wizard:403,goblinwieldingclub:41,god:[31,39,144,198,388],godhood:545,godlik:[106,350],goe:[0,3,22,24,42,62,67,75,76,97,117,118,123,128,132,137,152,155,158,162,165,172,174,190,191,211,212,275,278,312,329,337,338,398,436,439,454,455,491,492,543],goff:[95,104,107,382],going:[0,28,30,50,53,62,68,82,95,96,97,106,118,126,132,135,136,137,140,142,144,146,149,151,153,156,158,164,167,170,174,177,186,187,191,193,197,241,308,309,310,311,312,329,350,364,369,372,398,413,418,469,476,515],goings:418,gold:[28,41,140,141,152,157,470],gold_necklac:13,gold_val:141,gold_valu:141,goldenlayout:545,goldenlayout_config:51,goldenlayout_default_config:51,gone:[33,55,95,141,144,149,151,153,155,158,193,276,337],good:[0,5,6,7,8,11,12,13,15,18,19,20,22,28,30,33,35,36,41,42,48,50,53,55,60,62,75,76,79,85,86,95,96,97,104,115,119,120,122,124,125,126,130,132,133,134,137,138,141,142,143,144,146,147,151,154,156,157,158,159,161,162,163,165,170,174,175,177,178,180,184,185,189,191,193,194,195,199,204,211,212,213,229,256,283,289,335,350,439,448,476,479,545],goodby:[28,436],goodgui:394,googl:[77,120,180,190,191,223,478,545],googlegroup:40,googli:[53,169],gorgeou:118,gossip:[180,186,223],got:[9,11,14,49,54,113,143,149,150,151,152,164,371,386],goto_cal:[28,476],goto_cleanup_cmdset:369,goto_command_demo_comm:369,goto_command_demo_help:369,goto_command_demo_room:369,goto_kwarg:476,goto_next_room:174,gotostr_or_func:476,gotten:[122,159,312,371,398,443],gpl2:495,graaah:171,grab:[13,22,26,143,144,162,177,224,371,515,543],gracefulli:[0,215,228,350,398,416,492],gradual:[14,15,106,112,128,156,157,180,349,354],grai:[60,175],grain:[47,206,472],gram:140,grammar:[58,106,275,349],grammat:[58,106,159,349,350],grand:[13,31,99],grant:[11,33,39,57,182,234,308,309,310,311,312,393,394,402,464,513,536,542,545],granular:312,grapevin:[197,201,202,205,223,412,424,545],grapevine2chan:[26,31,143,186,223],grapevine_:223,grapevine_channel:[186,205,223],grapevine_client_id:186,grapevine_client_secret:186,grapevine_en:[186,223],grapevinebot:205,grapevinecli:427,graph:[11,132,337],graphic:[3,9,33,34,49,50,52,65,73,135,159,170,201,251,346,440,545],grasp:[175,177],grave:115,grayscal:[84,244],great:[15,28,30,31,42,45,50,56,69,76,77,82,86,92,95,97,104,115,118,119,124,125,128,130,134,137,142,151,156,159,162,165,178,180,241,380,461],greater:[6,20,33,44,76,146,393,476],greatli:[95,179],greek:16,green:[11,20,33,41,60,118,151,175,218,228,275,371,469],greenforest:118,greenskin:403,greet:[25,44,75,95,96,171,195],greetjack:36,greg:180,grei:[41,118,175,469],grenad:37,grep:[11,190],greyscal:[60,469],greyskinnedgoblin:41,griatch:[67,79,80,81,84,86,87,88,89,90,91,93,100,101,102,103,104,106,108,109,110,111,112,115,118,125,143,146,243,244,246,247,249,251,265,266,272,282,283,291,292,295,296,299,301,302,315,316,321,322,324,325,330,342,343,348,349,350,352,354,356,358,359,361,363,364,365,366,368,369,371,475,483,488,491,495,496],grid:[56,91,99,109,110,117,154,165,170,197,201,202,225,235,312,492,545],gridmap:118,gridpoint:[335,337],gridsiz:335,grief:55,griefer:178,grin:[22,157,464,479,497],grip:[120,293],gritti:22,ground:[95,115,122,125,144,146,150,154,170],group:[0,18,22,26,31,41,46,48,50,54,55,57,74,75,78,95,96,106,123,124,125,142,143,148,153,158,180,193,206,207,214,218,224,225,233,305,316,349,371,372,398,402,403,425,448,464,467,469,472,500,508,545],groupd:464,grow:[0,14,18,122,126,146,150,156,157,180,185,199,337,354,427,428,478,492],grown:[28,72,75,126],grudg:162,grungi:298,grungies1138:[98,104,111,299,365,366],grunt:[218,403],gsg:77,gstart:218,gthi:139,gtranslat:64,guarante:[13,39,42,67,88,119,157,187,191,257,343,402,434,455,466,479],guard:[28,118,158,293,338],guardian:115,guess:[16,27,70,76,96,137,142,194,241,403],guest1:63,guest9:63,guest:[24,39,121,204,545],guest_en:[39,63],guest_hom:[63,177],guest_list:63,guest_start_loc:63,guestaccount:46,gui:[51,52,65,134,158,299],guid:[2,9,89,100,139,169,177,512,545],guidelin:[120,180,545],guild:[18,46,67,90,104,158,172,180,223],guild_memb:28,gun:[58,125],gun_object:58,guru:122,gush:95,gzip:[238,239],gzip_content_typ:238,habit:133,habitu:47,hack:[122,162,164,425],hacker:[180,194],had:[0,9,11,15,16,20,42,57,73,75,86,119,122,125,128,144,146,149,150,151,152,156,158,165,181,191,193,213,217,229,273,286,338,371,403,406,416,466,470,477,495,497,532,545],hadn:[11,136,156],hair:293,half:[69,390],hall:[31,132],hallwai:132,halt:170,hammer:[86,292,293],hand:[16,28,36,37,44,58,62,69,79,95,99,104,119,122,133,134,135,146,150,152,157,160,162,178,213,218,224,226,228,283,293,515],hander:146,handi:[3,151,177,190,310],handl:[5,6,9,12,13,14,16,18,19,22,27,28,30,32,33,36,37,44,47,48,51,52,53,58,62,65,67,68,69,72,75,76,77,78,79,86,95,97,108,111,118,119,121,122,123,124,131,132,133,136,141,142,143,146,147,148,150,151,152,153,156,159,161,164,171,175,176,181,183,187,190,193,195,204,205,206,208,209,211,212,218,219,223,224,227,238,251,257,260,269,270,275,280,283,292,293,308,309,310,311,312,316,322,331,338,350,364,366,371,372,377,386,387,388,397,398,401,402,403,406,407,410,413,416,420,421,425,426,428,429,436,439,440,443,445,447,456,457,464,466,469,470,472,473,474,476,477,478,480,483,491,492,501,508,526,545],handle_answ:28,handle_appli:275,handle_consum:275,handle_egd_respons:418,handle_eof:436,handle_error:[223,257,410],handle_ff:436,handle_foo_messag:476,handle_int:436,handle_messag:476,handle_mix:275,handle_numb:476,handle_posit:275,handle_quit:436,handle_setup:420,handler:[12,13,20,22,33,34,35,36,37,39,42,44,46,47,48,65,67,85,95,104,112,123,147,148,149,157,162,195,204,209,212,227,231,234,254,257,258,260,278,283,289,329,350,353,354,370,393,394,397,398,403,407,408,410,411,421,433,434,454,457,463,464,466,467,471,472,475,476,486,487,492,501,508,540,545],handlertyp:467,handshak:[29,65,183,426,432,434,439],handshake_don:439,hang:[120,152,156,159,167],happen:[0,3,5,6,9,13,18,19,20,22,28,30,33,39,42,44,45,47,52,53,55,57,65,67,68,69,85,87,88,95,97,104,118,122,123,130,131,134,135,136,142,143,144,149,150,151,158,159,161,162,164,165,170,175,177,184,189,191,199,204,211,212,223,232,247,275,277,278,289,308,309,310,311,312,325,329,337,370,372,398,403,410,418,425,428,448,453,455,456,457,466,476,477,483,485,492,513],happend:403,happi:[14,157,158,476],happier:142,happili:[18,143],haproxi:[191,197,545],hard:[0,5,6,11,14,16,19,20,22,30,31,41,42,46,47,54,57,62,64,68,75,77,92,113,120,123,135,146,147,149,152,153,156,159,161,174,177,180,185,191,193,227,380,386,406,416,464,466,476],hardcod:[74,134,135,149,170,193,464],hardcor:118,harden:185,harder:[5,55,118,133,146,149,156,158,161,371],hardwar:[191,429],hare:180,harm:[13,115,128,161,310],harsh:158,harvest:538,has:[2,3,5,6,8,9,11,12,13,14,15,16,18,19,20,22,27,28,30,31,32,33,35,36,37,39,41,42,44,45,46,47,48,49,50,51,53,54,55,56,57,58,60,62,64,65,67,68,70,72,73,75,76,77,78,79,81,82,85,90,92,95,96,97,98,99,104,105,106,112,113,114,118,119,120,121,122,123,124,125,126,127,128,130,131,132,133,134,135,136,137,141,142,143,144,145,146,148,149,150,151,152,153,155,157,158,159,161,164,165,166,169,171,172,174,175,176,177,178,179,180,181,182,184,185,186,187,188,190,191,193,194,195,198,199,200,203,204,205,210,211,212,213,215,217,218,223,225,226,228,229,230,232,233,234,239,241,247,251,257,270,273,275,283,289,292,299,305,308,309,310,311,312,316,329,335,337,338,339,340,343,350,354,359,364,370,371,372,380,382,386,388,390,393,394,396,397,398,402,403,405,406,409,410,411,416,418,421,425,428,430,434,438,443,444,448,454,455,456,457,459,464,465,466,467,472,474,475,476,478,479,483,485,486,489,490,492,497,500,501,508,512,513,518,532,533,540,542,543],has_account:[37,370,393,397,398],has_add_permiss:500,has_attribut:464,has_cmdset:212,has_connect:[18,232],has_consum:275,has_delete_permiss:500,has_drawn:132,has_nick:464,has_object_permiss:513,has_par:492,has_perm:[226,394],has_permiss:513,has_sub:232,has_tag:467,has_thorn:[13,153],hasattr:[22,127],hasbutton:275,hash:[15,41,77,118,191,403,411,444,448,457,465],hasher:5,hasn:[76,132,371,382,464,508,539],hassl:136,hast:310,hat:[83,286],hau:[186,205,223,427],have:[0,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19,20,22,25,27,28,30,31,32,33,34,35,36,37,39,40,41,42,44,46,47,48,50,51,52,53,54,55,56,57,58,60,62,63,64,65,67,68,69,70,72,73,74,75,76,77,78,79,82,83,86,89,90,91,92,93,95,96,97,102,104,106,108,112,113,115,116,118,119,120,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,139,140,141,142,143,144,145,146,148,149,150,151,153,155,156,157,159,160,161,162,163,164,166,167,168,169,170,171,172,173,174,175,176,177,178,179,182,184,185,186,187,188,189,190,191,192,193,194,195,197,198,199,204,205,209,211,212,213,215,218,220,223,226,227,228,229,230,232,233,234,238,241,247,251,256,257,260,266,270,275,276,283,286,289,292,293,296,302,308,309,310,311,312,316,337,338,349,350,354,364,372,376,377,380,382,386,388,389,390,391,393,396,397,398,401,402,403,404,405,406,409,410,411,421,426,429,430,434,436,439,440,454,455,456,457,462,463,464,465,466,467,469,470,471,472,473,475,476,477,478,479,485,488,489,490,492,493,495,497,501,508,513,515,518,523,525,532,540,541,543,544,545],haven:[3,8,9,41,76,77,99,118,124,128,136,143,170,171,172,173,177,178,187,459],havint:50,hay:77,head:[7,20,31,64,95,96,125,137,144,146,154,157,159,165,174,198,545],header:[14,15,19,30,31,35,37,50,64,72,75,120,140,143,151,185,194,213,225,233,234,299,350,398,470,472,477,478],header_color:218,header_line_char:478,headi:478,heading1:[120,478],heading2:[120,478],heading3:120,headless:398,headlong:185,heal:[104,112,114,153,157,158,293,310,311,372],healing_rang:311,healingrecip:293,health:[34,41,68,104,112,129,148,157,158,162,164,191,293,345,346,347,353,354,403,440,545],health_bar:[94,201,202,235,341,545],healthi:354,hear:[18,96,128,156,490],heard:[155,170],heart:[31,149,175],heartbeat:[47,427],heat:293,heavi:[13,19,22,33,77,79,95,123,140,144,158,162,164,165,182,238,283,309,350,429,492],heavier:[42,309],heavili:[19,62,67,75,77,82,115,118,119,134,155,190,195,241,308,309,310,311,312,466,544],heed:[44,394],hei:[79,144,157,283,299,349],height:[29,32,51,201,337,421,436,455,475,478],held:[20,90,164,337,393],hello:[18,28,30,32,36,44,65,68,69,72,96,97,106,120,128,142,152,157,158,165,189,223,224,232,350,421,469,490,545],hello_valu:69,hello_world:[69,151,152],helmet:[13,128,157],help:[3,5,8,11,13,14,15,16,18,19,21,22,24,25,26,27,28,30,33,39,41,42,44,45,46,49,51,53,55,57,58,64,67,69,70,76,79,86,90,92,95,96,97,98,106,108,115,116,118,120,121,123,124,128,130,131,132,134,135,138,142,143,145,147,149,150,151,153,154,155,156,157,158,159,164,165,170,175,177,180,182,185,187,188,189,191,198,199,201,202,208,209,211,213,214,215,223,226,228,229,230,247,251,254,255,257,270,273,275,278,283,289,299,308,309,310,311,312,333,336,349,354,364,369,372,376,380,396,400,410,414,416,418,419,427,434,436,437,439,441,444,445,447,448,464,465,469,472,473,474,476,477,479,487,488,489,490,496,498,499,500,502,503,506,512,515,518,523,526,531,532,533,535,544,545],help_categori:[22,31,76,135,137,141,143,164,165,188,213,215,216,217,218,223,224,225,226,227,228,229,230,241,251,255,266,269,270,273,283,286,292,293,296,299,302,305,308,309,310,311,312,316,322,325,331,343,350,364,366,370,371,372,380,386,388,389,390,398,447,474,476,477,489,540],help_cateogori:474,help_detail:540,help_entri:[31,388,474,540],help_entry1:388,help_entry_dict:[31,388],help_file_modul:388,help_kei:218,help_list:540,help_messag:225,help_mor:225,help_more_en:31,help_search_with_index:391,help_sstem:137,help_summary_text:90,help_system:137,help_text:[225,257,532],help_top:540,helpact:270,helparg:229,helpdetailtest:533,helpdetailview:540,helpentri:[31,33,49,137,225,388,389,390,472,504,515,537,540],helpentry_db_tag:504,helpentry_set:467,helpentryadmin:504,helpentryform:504,helpentrymanag:[389,390],helper:[8,28,30,39,41,57,95,104,106,112,118,135,143,145,146,149,150,153,158,201,204,212,215,218,223,225,233,238,241,247,275,280,292,294,336,338,339,340,349,354,398,402,403,413,425,426,445,457,470,476,477,479,485,490,491,492,502,510,516],helpfil:225,helpfilterset:[512,518],helplistseri:[515,518],helplisttest:533,helplistview:540,helplockeddetailtest:533,helpmixin:540,helpseri:[515,518],helptaginlin:504,helptext:[28,400,476],helptext_formatt:[28,400,476],helpviewset:518,henc:[4,7,76,96,97,151,152,270,372,470],henceforth:[6,11,14,33,44,63,74,131,165,170,176,191,457],henddher:[104,105,304,305],her:[58,93,155,157,286,296,479,496,497],herbal:475,herd:182,here:[2,3,5,7,8,9,10,11,12,13,14,15,16,17,19,22,26,28,30,31,32,33,34,35,36,37,40,41,42,44,45,47,48,49,51,53,54,56,57,58,60,62,64,65,67,68,69,70,72,73,75,76,77,79,82,83,86,87,95,96,97,99,104,106,107,110,112,114,115,116,118,119,120,121,123,124,125,126,128,129,130,131,132,133,134,135,136,137,139,141,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,167,169,170,171,172,173,174,175,177,178,180,182,183,185,186,187,188,189,190,192,193,194,195,198,199,204,205,211,212,213,218,226,227,228,230,234,238,241,247,251,256,257,270,273,274,275,278,280,283,286,292,293,308,309,310,311,325,329,331,338,340,343,349,350,354,359,370,371,372,382,390,394,396,398,402,403,416,418,425,427,433,434,436,439,448,454,455,457,463,464,466,469,472,476,478,483,490,496,501,508,510,513,515,521,537,540,541,545],hereaft:157,herein:77,heroism:158,herself:[30,58,157,479,496,497],hesit:[76,130],hfill_char:478,hidden:[11,13,51,88,104,116,118,123,132,153,155,156,157,225,234,270,286,343,545],hide:[13,20,22,31,33,39,75,104,106,118,144,156,157,162,170,225,234,343,350,371,545],hide_from:[35,234],hide_from_accounts_set:207,hide_from_objects_set:397,hieararci:393,hierarach:467,hierarch:[12,39,57,215,393,467],hierarchi:[26,57,63,76,124,137,156,224,286,393,492,513,545],high:[20,39,58,118,122,124,144,146,152,155,181,185,211,292,293,311,398,458,467],higher:[5,9,18,20,28,33,39,44,49,57,69,106,118,126,131,133,135,136,146,149,157,161,162,165,185,191,204,211,215,218,228,308,309,310,311,312,338,349,372,393,418,467,476,492],highest:[20,39,112,135,354,469,492],highest_protocol:488,highli:[0,17,28,33,45,47,67,75,94,104,118,119,122,123,133,151,171,346,470,483],highlight:[15,60,120,134,135,175],hijack:[178,187],hilight:491,hilit:491,hill:[36,95],hilt:[158,293],him:[28,58,93,96,106,149,296,350,479,496],himself:[58,479,496,497],hint:[9,41,53,90,104,120,122,126,138,143,149,154,159,165,169,180,185,199,247,278,462,544,545],hire:[141,194],his:[28,30,41,58,93,96,106,135,157,286,296,350,477,479,491,496],histogram:492,histor:[22,42,72,136,154,415,485],histori:[11,18,27,51,92,123,124,135,144,151,158,182,193,212,223,232,380,485],hit:[29,75,114,125,128,150,155,162,164,205,292,308,309,310,311,312,370,371,414,455,485,488,545],hit_msg:370,hite:60,hitter:143,hnow:60,hoard:158,hobbi:[86,156,159,191],hobbit:136,hobbyist:191,hoc:122,hold:[0,2,6,7,12,14,15,20,28,31,33,37,41,44,46,48,56,63,74,75,95,104,111,112,113,118,120,123,125,132,135,141,143,148,149,156,161,162,164,165,169,170,177,185,193,195,211,212,235,241,275,278,286,292,293,308,309,310,311,312,343,354,366,370,371,382,386,387,391,393,394,402,403,404,407,412,423,425,434,444,445,447,457,466,467,468,472,475,476,478,479,481,485,492,498,545],holder:[75,191,464],hole:[95,158],home:[0,11,26,37,41,52,53,56,63,104,118,123,143,148,149,158,177,181,185,191,194,212,218,224,229,370,396,397,398,403,472,492],home_loc:218,homepag:[5,19,180,185,191],homes_set:397,homogen:[19,159,402,403,406],homogenize_prototyp:402,honcho:159,hong:77,honor:[158,350],honour:[77,104,238],hood:[9,18,22,28,30,36,41,42,48,67,100,103,104,112,116,123,134,144,146,149,156,157,270,292,350,353,354],hook:[12,18,22,32,33,37,42,45,47,86,95,106,118,126,129,132,139,149,162,164,165,171,172,173,174,176,199,204,209,211,213,215,218,223,224,226,228,229,230,232,234,239,248,257,273,275,279,286,292,294,305,308,309,310,311,312,313,316,322,325,329,331,335,338,350,351,353,360,362,369,370,371,372,377,382,398,406,409,411,420,427,439,442,444,447,452,454,455,456,458,466,474,477,479,483,484,486,492,502,505,506,516,532,536,537,538,540,543,545],hooligan:55,hop:122,hope:[3,135,142,155,158],hopefulli:[0,51,90,132,151,155,159,170,177,181,191],horizon:136,horizont:[337,371,478,492],hors:19,host1plu:191,host:[0,11,19,37,55,73,77,104,123,156,168,182,187,192,193,194,197,238,349,461,492,545],host_os_i:492,hotbutton:51,hotel:191,hotspot:194,hould:158,hour:[19,87,95,136,158,176,247,480,492],hous:[41,118,159,191,218,479,545],housecat:19,how:[0,3,5,6,7,8,9,10,11,13,14,15,16,17,18,19,20,25,26,28,30,33,34,35,36,39,41,42,44,46,49,50,51,52,53,54,55,57,58,62,63,65,67,68,69,73,74,76,77,85,86,90,93,95,96,97,104,106,107,110,112,113,114,115,117,118,120,122,123,124,125,126,127,128,129,130,131,132,133,134,136,137,139,140,141,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,175,176,177,178,181,182,185,187,189,190,191,194,195,197,198,199,205,206,210,212,213,225,227,228,229,232,241,247,273,275,278,286,289,292,293,296,310,311,312,325,329,337,338,339,340,343,349,350,354,364,370,382,386,391,393,397,398,403,406,411,416,421,426,430,435,440,443,447,448,454,455,456,457,461,466,470,474,476,477,478,479,485,486,491,492,501,502,504,507,508,532,544,545],howev:[9,12,13,14,15,16,17,20,22,27,30,33,41,42,47,48,50,54,55,58,60,62,68,69,70,72,73,76,82,92,94,95,96,97,104,113,118,120,122,124,128,129,131,135,136,141,142,144,149,151,153,155,157,158,161,162,165,170,173,176,182,191,199,212,213,218,225,228,229,238,241,257,311,346,364,380,382,386,393,469,515],howto:[120,544,545],hpad_char:478,href:[17,137,177],hrs:247,htm:431,html5:148,html:[51,52,60,73,77,120,122,123,137,143,148,155,169,170,178,180,183,194,213,228,232,270,382,388,390,438,440,444,445,461,466,488,491,492,512,521,536,537,538,540,541,543,545],htmlchar:491,htop:[5,199],http404:[137,178],http:[0,2,8,9,10,11,40,45,49,50,51,52,53,54,56,64,69,73,75,76,77,85,90,96,120,122,123,124,130,137,148,149,154,155,164,167,170,177,178,182,184,185,186,190,191,192,194,198,201,205,223,238,241,270,289,382,391,418,425,427,428,429,430,431,432,438,440,443,444,445,461,469,478,491,492,495,512,532,544,545],http_request:[73,194],httpchannel:461,httpchannelwithxforwardedfor:461,httpd:181,httprequest:204,httprespons:[500,502,505],httpresponseredirect:177,huawei:191,hub:[31,180,193,233,472],hue:60,huge:[56,67,104,117,125,128,130,136,152,156,158,167,329,477],huh:[22,76],human:[5,55,62,88,104,112,123,124,134,141,156,162,171,177,292,354,538,545],humanizeconfig:124,hundr:[70,158,177,189],hung:159,hungri:67,hunt:[104,112,157,162,353,354,370],hunting_pac:370,hunting_skil:162,hurdl:132,hurri:150,hurt:[115,129,157,158,354],huzzah:75,hwejfpoiwjrpw09:75,hybrid:[158,162],hype:197,i18n:[64,147,398],iac:68,iam:77,iattribut:464,iattributebackend:464,ice:118,ice_and_fir:153,icon:7,iconv:64,id_:[502,504,506,508,532],id_str:34,idcount:447,idea:[0,7,8,10,11,22,31,33,45,50,53,55,69,75,90,95,97,114,115,119,120,122,130,132,133,137,141,146,148,151,152,156,157,158,159,161,162,163,165,174,177,178,185,188,189,213,225,226,229,283,349,403,483,491,542,545],ideal:[22,64,72,96,191,207,394],idenfi:211,ident:[6,8,13,20,22,60,65,75,95,106,131,134,143,157,199,204,226,322,350,394,396,398,405,469,470,490],identif:[19,47,457],identifi:[3,5,6,20,22,27,28,32,34,41,42,47,48,65,68,86,89,97,104,106,127,129,130,132,135,137,146,149,150,156,164,178,181,182,210,213,218,223,226,229,233,241,278,292,316,338,349,350,372,386,394,398,402,405,408,411,413,416,421,423,426,440,444,453,455,457,464,465,469,472,475,476,479,492],identify_object:233,idl:[44,55,204,205,370,398,448,455,457],idle_command:22,idle_tim:[204,398],idle_timeout:205,idmap:483,idmapp:[48,67,201,202,228,234,390,423,449,464,465,466,468,545],idnum:233,ids:[55,135,174,316,447,457,475],idstr:[34,47,407,411,453,492],idtifi:233,idx:174,ietf:432,ifconfig:187,ifier:[112,354],ifram:51,ignor:[3,8,11,15,18,19,20,22,28,30,31,32,33,39,44,48,60,65,67,120,128,135,142,143,144,148,152,161,162,171,174,182,185,191,204,210,211,212,213,218,316,331,337,338,340,350,393,397,398,411,416,421,427,428,443,444,445,464,466,469,470,475,476,487,490,492,493],ignore_ansi:492,ignore_error:204,ignorecas:[213,218,224,225,228,230,273,286,292,350,469,474,476,491],ignoredext:461,illog:95,illumin:170,illus:54,illustr:95,imag:[7,17,51,52,53,73,77,104,124,137,148,169,177,185,191,238,521,545],imagesconfig:124,imagin:[15,20,28,86,96,114,128,143,150,155,156,159,161,164,171,176,364,470],imaginari:[125,170,180],imeplement:329,img:17,immedi:[16,19,22,28,32,41,42,50,65,95,97,118,123,128,132,143,146,149,151,161,164,173,177,178,191,193,198,216,228,289,292,338,370,405,420,427,470,472,476,477],immers:86,immobil:126,immort:[95,370],immut:[13,411],impact:175,impass:[118,155],impati:185,imper:108,implement:[0,6,8,9,13,18,20,22,23,28,30,33,35,37,46,47,48,51,53,58,60,62,67,68,69,73,74,78,79,86,95,104,110,113,114,115,116,118,122,125,126,127,128,132,133,134,135,138,139,145,148,150,152,156,157,161,164,165,170,171,172,173,179,180,187,201,202,206,207,211,212,215,216,217,218,219,220,223,224,225,226,227,228,230,232,233,234,235,238,247,266,271,283,286,292,296,302,308,309,312,314,316,322,325,327,331,337,343,349,350,353,366,370,371,372,377,386,389,390,394,396,397,398,405,406,408,411,422,427,429,430,431,432,433,434,436,438,439,440,443,444,445,447,454,461,464,465,466,467,469,470,473,474,476,477,484,487,488,491,492,500,517,539,541,545],impli:[46,76],implic:78,implicit:[60,142,175],implicit_keep:403,impmement:394,impopular:158,import_cmdset:212,importantli:[18,28,144,149,157,177,394],importerror:[4,75,124,492],impos:[122,180,459],imposs:[16,28,57,70,95,118,120,132,170,174,177,191,338,402,478],impract:[22,41,118,403],imprecis:483,impress:[3,158,170],improperlyconfigur:238,improv:[9,64,97,119,142,150,151,156,159,544,545],impur:293,in_game_error:[0,194],inabl:[185,194],inaccess:[33,97],inact:[90,275,370],inactiv:228,inadvert:312,inadyn:191,inarticul:69,inbuilt:[46,165],incant:190,incapacit:158,incarn:532,incid:[78,104,377],includ:[0,2,5,7,11,12,13,14,19,20,22,26,28,30,32,33,34,37,44,45,46,47,48,50,51,53,55,56,60,68,69,73,75,76,78,79,86,92,99,104,106,112,113,114,115,118,119,120,121,122,123,124,125,129,130,131,135,136,137,141,142,143,144,145,148,149,150,151,152,153,154,156,157,158,160,161,162,163,164,166,168,169,170,174,177,178,179,180,185,190,193,195,204,209,210,211,213,216,217,218,226,229,232,233,238,257,270,273,278,283,286,292,293,294,296,308,309,310,311,312,316,329,335,337,338,339,340,349,350,354,372,377,380,386,391,393,398,402,409,416,434,436,439,440,448,453,456,464,465,466,467,469,470,471,472,473,475,476,478,480,485,490,492,515,521,525,541,544],include_account:464,include_children:465,include_par:465,include_prefix:210,include_unloggedin:[434,457],inclus:[31,465,479],incoher:175,incol:[135,475,478],incom:[22,52,62,68,182,191,195,205,210,227,273,309,338,377,416,425,429,432,435,439,440,444,445,447,455,456,457,461,476,477,479,500,502,505,506,513],incomplet:[110,213,325,478],inconsist:[6,13,54,382],incorpor:[215,478],incorrect:233,increas:[33,39,48,60,79,104,112,118,136,146,149,157,162,194,283,309,311,312,338,354,372,428,434,448,474,476],increase_ind:474,incred:[113,386,418],increment:[185,464],incur:19,indata:[62,464],inde:[75,88,122,142,191],indefinit:[310,371,405,472],indent:[14,15,19,27,30,51,72,75,97,120,134,143,151,152,337,445,470,474,476,479,492],independ:[35,42,52,90,95,97,104,123,133,175,198,283,289,376],indetermin:418,index:[31,52,53,67,69,73,113,119,120,132,133,141,149,156,169,170,174,180,191,197,201,202,210,223,224,225,275,283,337,338,371,386,388,390,391,396,414,418,419,461,467,469,477,478,492,498,531,532,533,535,537,540,545],index_category_clr:225,index_to_select:386,index_topic_clr:225,index_type_separator_clr:225,indexerror:[117,178,329,465],indexread:275,indextest:533,indic:[8,28,35,58,76,93,95,97,104,113,118,120,132,136,141,142,144,151,152,170,181,205,218,225,226,238,275,296,337,338,350,377,386,406,409,427,428,436,443,444,457,459,461,464,469,470,476,477,492,518],individu:[13,14,15,22,30,41,68,76,95,96,97,104,118,125,132,134,135,141,149,152,162,170,176,179,188,191,212,216,232,254,257,276,292,311,343,353,354,400,403,455,467,469,478,479,486,487],ineffici:[47,171,469],inert:8,inf:[495,497],infact:22,infinit:[42,95,97,118,156,185,205,329,338,402,495,497,545],infinitely_lock:275,inflat:158,inflect:[479,495],inflict:310,inflict_condit:310,influenc:[28,54,56,76,96,156,165,278,283,492,545],influenti:180,info1:366,info2:366,info3:366,info:[0,5,7,8,11,13,14,17,18,19,22,25,26,29,31,37,38,42,44,46,48,49,53,56,58,67,68,78,118,122,123,126,135,148,149,151,157,167,179,182,183,185,193,195,204,205,207,215,216,218,225,228,230,235,251,269,275,283,299,316,340,346,372,389,390,398,416,421,425,433,434,454,455,457,465,466,467,472,475,485,492,545],infomsg:485,inforamt:[329,340,350,398,466],inform:[0,2,5,11,12,13,19,22,28,34,35,41,42,44,46,51,53,60,63,65,67,71,73,75,76,82,85,88,95,96,97,104,107,118,120,126,127,137,141,142,143,144,148,151,158,162,164,165,167,169,171,173,176,177,178,181,182,186,187,193,194,195,204,205,213,216,218,223,224,228,233,234,241,273,289,292,310,311,312,343,350,354,377,378,382,389,390,398,416,421,430,431,432,434,443,456,457,465,466,469,472,474,485,492,532,545],infrastructur:[65,120,123,159,191,194,209,426,545],infrequ:96,ing:[15,75,90,135,150,158,343],ingam:[95,96],ingame_python:[95,96,201,202,235,236,545],ingame_tim:136,ingen:64,ingo:[20,28,32,58,118,135,211,396,428,479,495,545],ingot:[292,293],ingredi:[86,104,158,275,292],ingredient1:275,ingredient2:275,ingredient3:275,ingredient_recip:275,inher:[36,54,69,112,124,354],inherit:[2,3,8,12,18,19,20,22,37,48,50,53,60,62,67,76,82,83,86,93,95,106,110,112,116,118,123,129,134,137,139,143,145,147,149,150,153,158,165,171,207,211,213,218,226,228,229,232,234,241,270,273,275,283,286,292,296,305,308,309,310,311,312,316,322,325,331,350,354,369,370,372,395,397,398,403,406,408,447,456,463,465,466,474,477,478,483,490,492,515,518,536,537,538,540,542,543,545],inheritng:403,inherits_from:[171,178,228,492,545],inifinit:402,init:[7,11,51,62,75,76,82,118,120,132,135,154,185,190,195,198,241,242,278,283,332,380,397,416,434,435,445,457],init_delayed_messag:380,init_django_pagin:477,init_evt:477,init_f_str:477,init_fill_field:[92,380],init_game_directori:416,init_iter:477,init_menu:369,init_mod:212,init_new_account:492,init_pag:[402,477],init_pars:[116,269,270],init_queryset:477,init_rang:312,init_sess:[62,456],init_spawn_valu:402,init_st:278,init_str:477,init_tree_select:[113,386],init_tru:212,initi:[0,6,10,11,13,22,27,28,42,44,45,51,52,53,75,77,79,86,92,104,113,114,118,120,123,125,128,132,135,141,143,147,156,157,161,162,165,173,177,199,204,205,212,213,229,232,234,238,251,254,258,260,278,283,289,292,308,309,310,311,312,336,337,338,339,349,350,354,364,369,370,371,380,386,388,396,397,398,402,407,410,411,413,414,416,418,419,420,425,426,427,429,430,431,432,434,435,436,437,438,439,440,441,443,444,445,447,455,456,457,464,469,471,474,475,476,477,479,487,488,492,501,502,504,506,508,510,526,532,543,545],initial_formdata:380,initial_ind:478,initial_setup:[201,202,412,454,545],initialdelai:[413,427,428,447],initialize_for_combat:[308,309,310,311,312],initialize_nick_templ:464,initil:444,initpath:118,inject:[52,90,148,161,194,275,339,402,416,447,448,455,470,476],inlin:[51,58,121,134,141,398,414,479,500,501,502,504,505,506,508,545],inlinefunc:[41,58,148,195,479],inlinetagform:508,inmemori:464,inmemoryattribut:464,inmemoryattributebackend:464,inmemorybackend:464,inmemorysavehandl:487,inn:99,innermost:30,innoc:[55,216],innocu:194,inobject:425,inp:[28,218,233,402,414,477,479,492],inpect:28,input:[5,8,13,15,16,17,18,19,20,27,32,36,41,44,47,51,52,53,54,58,62,65,70,73,75,76,79,86,92,99,104,106,113,118,119,120,121,129,134,135,138,142,143,144,148,149,150,154,161,170,172,177,180,195,199,204,208,209,210,213,218,223,225,226,227,228,229,233,241,278,292,293,311,338,343,349,350,353,354,371,377,380,386,389,398,401,402,403,414,416,421,425,436,444,455,457,464,465,467,474,475,476,477,478,479,486,488,490,492,493,532,545],input_arg:490,input_cleanup_bypass_permiss:492,input_cmdset:476,input_func_modul:[32,421],input_str:[30,476],input_validation_cheat_sheet:532,inputcmdset:476,inputcommand:[32,65,68],inputcompon:51,inputdebug:[32,421],inputfuc:148,inputfunc:[24,62,68,148,195,201,202,205,412,444,455,457,545],inputfunc_nam:444,inputfunct:32,inputhandl:201,inputlin:[36,224,232,464,465],insecur:191,insensit:[31,39,146,153,225,316,350,372,388,396,465,524],insert:[13,14,15,27,30,36,41,58,86,93,104,120,123,126,135,151,154,185,188,212,275,292,296,302,350,402,470,476,478,479,492],insid:[3,5,7,8,13,14,16,19,20,22,28,30,33,37,40,41,42,44,48,49,53,54,57,60,64,67,68,69,73,77,91,94,95,96,97,104,106,117,118,120,123,125,126,127,134,137,140,141,142,143,144,146,147,148,151,152,153,161,162,165,169,170,171,174,176,177,178,182,185,187,188,189,193,199,201,205,228,232,238,241,256,257,316,329,346,350,370,372,393,397,398,401,416,433,454,461,470,471,479,492],inside_rec:393,insiderecurs:393,insight:[3,144,155,169],insist:[142,191],inspect:[28,55,118,141,182,204,218,228,283,414,416,476],inspectdb:67,inspir:[22,58,72,90,93,103,104,157,162,164,266,296,478,492],instac:[213,292,398,455],instal:[0,3,5,6,7,8,9,10,15,64,69,94,96,97,104,114,119,120,122,123,134,135,144,147,151,154,155,157,167,178,180,184,186,192,194,199,201,202,235,238,244,251,266,281,283,286,289,291,299,302,305,308,309,310,311,312,314,316,322,324,341,342,346,350,352,366,377,523,544,545],installed_app:[8,67,124,137,177,178,523],instanc:[3,6,10,12,13,17,19,27,28,30,34,41,44,45,50,51,56,64,76,77,82,95,96,97,99,104,107,113,118,123,126,127,128,130,133,134,135,136,137,141,142,143,145,146,148,149,151,153,161,164,167,169,174,175,181,194,204,207,209,210,211,212,213,222,225,227,228,232,234,239,241,257,260,270,280,292,329,340,382,386,390,397,398,402,403,405,406,410,411,413,416,425,426,427,428,429,430,431,432,434,438,439,443,447,448,456,457,461,464,466,467,469,472,473,476,478,483,484,488,490,492,493,500,501,502,504,505,506,508,512,513,515,517,532,540,545],instanci:241,instant:169,instanti:[8,22,67,152,204,212,229,354,364,408,411,433,454,457,464,475],instantli:[501,508],instead:[0,5,7,9,11,13,15,18,19,20,22,28,30,34,37,39,41,42,44,46,48,53,54,55,56,57,58,60,64,65,67,73,75,76,77,78,85,86,89,90,92,94,95,96,97,100,104,106,110,112,113,117,118,119,120,123,125,126,128,129,130,132,134,135,136,141,142,144,145,146,148,149,150,151,152,153,154,156,158,159,161,164,165,167,169,170,171,172,174,175,176,177,178,180,182,185,187,191,193,194,195,197,199,204,205,212,213,215,216,218,220,223,227,228,230,232,233,241,251,260,270,273,275,280,289,292,293,308,309,310,311,312,325,329,331,337,338,340,343,349,350,353,354,369,371,380,386,393,394,396,398,403,411,416,444,445,455,459,464,466,467,472,476,477,479,483,485,487,488,489,492,496,501,508,523,532,536,537,538,540],instig:216,instil:[74,310],instnac:410,instr:[425,492],instruct:[3,6,7,11,14,15,19,32,65,68,75,96,97,99,104,114,118,119,120,122,129,134,135,141,147,151,152,154,155,156,158,180,181,182,185,187,190,191,193,197,198,204,213,228,238,350,377,403,411,413,416,426,428,434,439,440,444,445,447,455,457,476,486],insur:158,intal:545,integ:[20,22,30,41,44,48,60,92,104,112,130,141,142,165,210,247,286,308,309,310,311,312,338,340,343,354,372,380,393,398,465,479,488,492,493],integerfield:[177,506,532],integr:[1,49,51,104,106,114,123,124,152,157,178,180,194,229,350,419,421,476,512,545],intel:151,intellig:[65,142,158,162,178,194,212,238,447],intend:[3,14,17,19,20,22,30,35,41,46,51,69,76,77,78,79,82,104,105,115,118,119,122,144,156,161,169,170,175,191,194,204,238,241,280,283,292,340,350,389,390,398,403,434,465,467,472,473,475,478,479,489,490,492,493,510,538,541],intens:[60,146,158,180],intent:[106,194,349,492],inter:[14,118,158,337],interact:[3,7,12,22,26,28,62,69,80,118,120,122,128,133,144,152,155,158,159,161,164,177,180,182,193,199,201,217,273,312,364,416,433,470,485,490,492,545],intercept:[78,95,104,457],interchang:[39,154,164,388,476,542],interconnect:337,interest:[0,3,5,15,22,31,41,62,67,76,79,86,96,97,117,118,122,124,125,132,134,142,144,152,154,155,156,159,163,165,169,173,174,180,191,194,212,227,247,283,289,329,338,372],interestingli:157,interf:[185,364],interfac:[0,2,3,6,33,50,51,52,62,73,75,76,123,125,126,137,147,151,170,177,180,182,185,191,195,215,218,232,396,398,409,427,456,461,464,467,469,492,502,507,541,545],interfaceclass:436,interfer:[6,182,402],interim:[47,128],interlink:[433,454],intermediari:[350,394,407,476],intern:[9,13,16,18,19,28,33,36,41,44,45,46,54,62,68,70,87,89,117,146,147,148,158,164,185,187,191,193,194,195,199,204,205,234,251,292,296,329,335,337,338,350,354,362,396,398,402,408,444,445,464,466,467,469,473,476,478,492,545],internal:476,internal_port:191,internation:[70,545],internet:[22,53,54,55,56,62,182,185,187,189,191,194,198,216,413,418,426,427,428,436,439,447,461],interpret:[3,5,22,41,42,133,142,151,152,178,194,195,213,217,218,340,402,403,444,469,488,545],interract:118,interrupt:[95,161,185,209,213,229,254,257,260,331,335,436,545],interrupt_path:[118,338],interruptcommand:[22,142,161,201,209,213],interruptev:260,interruptmaplink:[118,338],interruptmapnod:[118,338],intersect:[20,211],interv:[32,42,47,81,104,112,123,164,173,174,176,205,206,247,257,293,308,309,310,311,312,354,359,370,372,405,406,411,421,472,480,492],interval1:411,intim:[20,22],intimid:135,intoexit:[218,331],intpropv:165,intricaci:136,intrigu:184,intro:[115,124,137,143,152,154,155,178,369,372],intro_menu:[201,202,235,355,368,545],introduc:[0,6,8,11,20,30,86,106,128,134,157,158,159,162,165,350],introduct:[1,11,14,15,16,56,57,77,82,138,143,144,150,154,160,163,166,167,168,185,241,544,545],introductori:[122,185],introroom:372,introspect:[105,305],intrus:175,intuit:[11,28,67,76,142,156,158,161,211],intxt:19,inv:[20,26,140,224,273,286],invalid:[13,30,41,118,142,204,338,350,354,380,402,478,479,488,492,493,496],invalid_formchar:475,invent:[112,354],inventori:[6,19,20,26,33,86,90,125,126,141,142,143,144,146,150,153,158,159,224,273,286,292,293,350,393,398,466,545],invers:[33,60,118,143,149,175,338,350,353,442,491],invert:[60,175],investig:[53,78,104,149],invis:[118,183,335,338],invisiblesmartmaplink:338,invit:[54,97,156,168,364],invitingli:[144,364],invok:[14,15,42,376],involv:[13,33,37,42,44,45,61,62,92,118,133,150,156,158,164,165,190,292,293,312,338,380,466,467,469,513],ioerror:470,ipregex:216,ipstart:[185,193,199],iptabl:194,ipv4:182,ipython:[0,5,135,545],irc2chan:[26,31,143,189,223],irc:[0,75,122,159,180,185,192,197,201,202,205,223,231,412,421,424,434,457,545],irc_botnam:205,irc_channel:205,irc_en:[189,223,393],irc_network:205,irc_port:205,irc_rpl_endofnam:428,irc_rpl_namrepli:428,irc_ssl:205,ircbot:[205,428],ircbotfactori:[205,428],ircclient:[428,457],ircclientfactori:434,irchannel:[189,223],ircnetwork:[189,223],ircstatu:[26,143,223],iron:[79,157,283,292,293,544],ironrealm:440,irregular:[81,104,359,370,372],irregular_echo:370,irrelev:[194,425],irur:29,is_account_object:133,is_act:[406,500],is_aggress:171,is_anonym:[124,137],is_anyon:124,is_authent:177,is_ban:204,is_bot:207,is_build:124,is_categori:386,is_channel:22,is_connect:[207,398],is_craft:128,is_dark:149,is_exit:[22,213],is_fight:128,is_full_moon:126,is_giving_light:371,is_gm:135,is_in_chargen:165,is_in_combat:[308,309,310,311,312],is_inst:19,is_it:492,is_iter:492,is_lit:[371,372],is_next:[207,234,390,397,406,464,466],is_o:492,is_ouch:[13,153],is_poison:13,is_prototype_bas:402,is_rest:161,is_sai:172,is_sleepi:13,is_staff:500,is_subprocess:492,is_superus:[12,50,124,204,206,207,394,398,472,500],is_thief:225,is_turn:[308,309,310,311,312],is_typeclass:[204,466],is_valid:[42,174,177,283,406,409],is_valid_coordin:[117,329],isalnum:469,isalpha:469,isb:490,isbinari:[427,444],isclos:51,isconnect:51,isdigit:[135,469],isfiremag:127,isinst:[130,492],island:99,isleaf:445,islow:469,isn:[3,17,27,76,82,95,96,97,124,133,136,137,142,146,161,185,241,254,258,270,312,372,418,469,486,495,501,508,524],isnul:488,iso:[16,70,230],isol:[8,11,14,90,119,120,123,142,151,154,156,185,193,198],isp:[191,194],isspac:469,issu:[0,3,5,8,11,13,14,15,20,22,26,37,48,54,69,74,76,115,119,120,125,128,135,141,152,157,161,165,170,175,180,181,182,184,185,191,194,223,230,245,402,416,447,448,478,544,545],istart:[3,199,201],istep:448,istitl:469,isub:164,isupp:469,ital:545,italian:64,itch:[158,185],item:[28,51,67,77,79,83,86,90,92,104,106,114,120,137,140,141,144,147,148,157,158,164,171,185,224,238,276,283,286,292,310,329,350,364,380,435,464,479,492,545],item_consum:310,item_func:310,item_kwarg:310,item_selfonli:310,item_us:310,itemcoordin:329,itemfunc:310,itemfunc_add_condit:310,itemfunc_attack:310,itemfunc_cure_condit:310,itemfunc_h:310,itend:492,iter:[6,13,28,30,46,99,132,143,149,204,206,233,329,338,350,362,389,396,398,403,405,409,445,447,448,464,466,467,469,470,473,477,489,492],iter_cal:477,iter_to_str:492,itl:[76,82,241],its:[3,5,8,9,10,11,12,13,15,16,18,19,20,22,27,28,29,30,31,33,34,37,39,41,42,44,47,48,49,50,51,52,55,56,58,60,62,65,67,68,72,73,75,76,78,79,82,86,90,91,92,93,95,97,101,104,105,108,110,112,113,115,117,118,120,122,123,125,126,128,130,131,132,133,134,135,136,137,139,140,141,142,143,144,146,147,148,149,150,151,152,153,154,155,157,159,161,162,165,167,169,170,171,172,174,175,177,178,182,185,186,189,190,191,192,193,194,195,204,205,207,209,210,211,212,213,216,218,226,228,232,233,241,242,245,257,266,270,275,278,283,292,293,296,305,308,309,310,311,312,325,329,331,338,340,349,350,354,362,364,370,371,380,386,396,397,398,403,410,411,416,420,421,425,429,440,442,443,444,445,448,456,457,461,462,464,465,466,467,470,475,476,478,479,483,485,486,487,488,489,490,492,496,500,501,508,510,512,521,532,536,537,538,540,542],itself:[2,5,7,8,11,13,16,17,18,19,22,28,31,33,37,39,42,44,47,48,53,58,62,64,67,73,75,76,78,82,92,95,96,97,112,113,114,118,119,120,122,123,124,125,126,128,131,132,140,141,143,144,147,148,149,151,152,153,155,164,165,169,170,172,177,178,179,182,185,187,190,195,197,198,204,205,225,232,241,260,274,275,276,278,292,311,329,338,343,350,354,359,371,372,380,382,386,387,390,391,393,396,398,400,401,403,410,416,440,445,457,461,464,467,469,472,474,476,479,487,489,492,496,497,501,508,532,542,545],iusernamepassword:436,ivanov:77,iwar:141,iwebsocketclientchannelfactori:427,iwth:411,jack:36,jail:[14,55],jam:[90,104],jamochamud:183,jan:[55,136],janni:77,januari:[95,136],jarin:191,jason:77,java:151,javascript:[49,51,52,53,68,73,77,104,122,169,194,238,444,445],jenkin:[83,92,94,104,113,114,165,285,286,307,308,309,310,311,312,345,346,379,380,384,386],jet:311,jetbrain:[7,180],jinja:148,jiwjpowiwwerw:13,jnwidufhjw4545_oifej:75,job:[22,33,137,187,204],jodi:77,john:[111,135,366],johnni:[78,104,376,377],johnsson:36,join:[46,75,76,90,104,132,135,146,156,158,164,165,177,185,186,189,204,223,232,238,266,274,283,349,469,492,545],join_fight:[308,309,310,311,312],join_rangefield:312,joiner:232,jointli:[123,212],joker_kei:[76,241],jon:77,jonca:77,josh:77,journal:170,json:[49,51,65,68,78,376,427,440,444,445,473,515],jsondata:68,jsonencod:445,jsonifi:445,jtext:469,judgement:162,jumbotron:545,jump:[0,11,14,15,28,29,37,69,113,122,125,131,132,156,158,185,273,386,414,479],jumpei:77,jumpstat:273,june:[64,95],junk:425,jupyt:545,just:[0,3,4,5,6,7,8,9,11,13,14,15,16,17,18,19,20,22,28,29,30,31,32,33,35,36,37,41,42,44,45,46,47,48,50,51,53,54,55,57,58,60,62,64,65,67,68,70,73,74,75,76,77,78,79,82,85,86,89,90,94,95,96,97,99,103,104,112,113,117,118,119,120,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,139,141,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,159,161,162,164,165,167,169,170,171,172,173,174,175,176,177,178,180,182,184,185,187,191,193,198,199,204,211,212,213,216,218,223,226,227,229,232,238,241,254,256,257,273,277,278,280,283,286,289,292,293,308,309,310,311,312,316,329,331,338,340,346,349,350,354,364,366,370,372,386,394,398,403,407,421,434,444,448,454,461,464,465,466,469,473,474,476,478,479,487,488,490,492,493,538,541,545],justif:[477,492],justifi:[30,41,469,477,479,492],justifii:477,justify_kwarg:477,kafka:78,kaldara:95,kaledin:77,kcachegrind:5,keep:[0,3,5,6,9,14,15,16,22,28,31,40,41,44,53,56,75,91,94,95,97,99,104,123,124,126,128,129,133,134,135,136,137,139,140,141,142,143,146,150,151,152,155,156,157,158,159,161,162,164,172,174,175,176,177,178,179,182,185,187,190,193,198,205,212,257,289,316,346,364,371,372,376,382,402,403,418,459,476,478,492],keep_log:[232,233,472],keepal:[44,439,445],keeper:[141,158],keepint:123,kei:[0,3,6,8,11,13,14,18,19,20,22,27,29,30,31,32,33,34,37,39,42,45,46,47,48,49,51,53,54,64,67,68,72,75,77,78,82,86,93,95,97,99,104,106,112,113,116,118,120,121,125,126,127,128,129,130,131,132,133,134,135,136,137,139,140,141,142,143,145,149,150,151,152,161,163,164,165,170,173,174,177,181,188,204,205,206,207,209,211,212,213,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,232,233,234,241,242,247,251,255,256,266,269,270,273,274,275,278,280,283,286,289,292,293,296,299,302,305,308,309,310,311,312,316,322,325,329,331,337,338,339,340,343,349,350,354,364,366,369,370,371,372,380,386,388,389,390,391,393,396,397,398,401,402,403,405,406,407,408,409,410,411,414,416,421,422,423,425,434,437,440,441,443,444,445,447,448,455,456,457,459,464,465,466,467,471,472,474,475,476,477,479,485,486,487,489,490,492,512,532,543,545],keith:77,kept:[5,22,31,39,53,134,142,148,218,256,257,350,403,464],kept_opt:386,kernel:0,key1:[28,302],key2:[28,302,398],key3:28,key_mergetyp:[20,211,364],keydown:51,keyerror:[292,402,411,487,492],keyfil:[437,441],keynam:[232,233,389,401,403,472],keypair:436,keys_go_back:[76,241],keystr:467,keystrok:436,keywod:478,keyword:[5,8,13,19,22,27,28,29,30,32,33,41,42,45,47,48,54,58,65,67,76,91,95,97,106,126,128,129,135,136,139,142,145,146,151,161,165,178,204,205,206,209,213,218,224,232,233,238,247,254,256,257,260,270,278,280,286,308,309,310,311,312,316,340,346,349,350,372,377,394,396,398,402,403,405,407,410,411,414,416,421,425,427,428,434,435,436,439,444,445,455,456,457,459,464,465,466,472,475,476,477,478,479,483,486,488,489,492,541,545],keyword_ev:[95,260],kick:[18,20,28,55,135,158,191,205,211,216,223,230,251,266,477],kildclient:183,kill:[5,19,28,44,79,144,148,156,159,164,190,193,283,370,371,407,411,416,454,461,545],killsign:416,kilogram:140,kind:[6,13,33,62,85,95,97,119,120,142,149,150,151,156,160,164,172,174,177,195,289,308,309,310,311,394,466,493,545],kindli:175,kitchen:[131,150,161,218,331],klass:64,klein:77,knee:[118,275,338],kneeabl:275,kneed:275,kneel:275,kneelabl:275,knew:[149,151],knife:[86,292,293],knight:13,knob:13,knock:[28,155],knot:[83,286],know:[0,3,5,6,9,11,12,13,14,15,16,18,20,22,28,30,31,32,33,34,37,44,48,53,54,56,58,60,62,64,65,67,70,76,85,86,95,97,104,106,108,113,118,119,120,123,125,128,130,131,132,133,134,135,137,139,140,141,142,143,144,146,148,149,150,151,152,153,154,156,157,158,159,161,162,164,169,170,171,172,174,175,176,177,178,180,181,182,184,187,189,191,192,193,195,199,213,217,218,226,229,256,283,289,299,311,338,349,364,371,386,397,398,421,455,457,464,470,471,476,492,501,508,539,545],knowledg:[14,16,22,119,122,438,457],known:[22,27,31,36,39,40,47,48,51,144,156,161,162,178,180,183,197,203,227,311,477,544,545],knuth:5,korean:64,kornewald:77,koster:180,kovash:28,kwar:466,kwarg:[13,18,22,28,30,32,33,34,41,45,47,48,51,54,62,65,68,71,86,87,95,99,112,118,126,128,135,139,161,172,174,176,178,204,205,206,207,209,212,213,215,216,217,218,223,224,225,226,227,228,229,230,232,233,234,238,241,247,251,254,255,256,257,266,269,270,273,274,275,276,277,278,280,283,286,292,293,296,299,302,305,308,309,310,311,312,316,322,325,329,331,338,339,340,343,349,350,354,359,362,364,366,369,370,371,372,377,380,382,386,389,390,393,394,396,397,398,400,401,402,403,405,406,407,409,410,411,413,414,421,422,423,425,426,427,428,433,434,435,436,437,439,440,441,444,445,447,449,455,456,457,458,459,461,464,465,466,467,469,472,474,475,476,477,478,479,480,482,483,485,486,487,488,489,490,492,493,500,501,502,505,506,508,512,514,515,518,532,536,537,538,540,541,542,543],kwargtyp:492,label:[46,67,74,78,144,153,154,177,512,532],label_suffix:[502,504,506,508,532],laborum:29,labyrinth:118,lack:[14,53,72,120,133,143,156,159,350,364,398,464,492],laddad:64,ladder:135,ladi:149,lag:[5,132,185],lair:15,lambda:[28,41,54,130,137,257,403,492],lamp:[170,364],lamp_breaks_msg:364,land:[142,164,370,371],landscap:[170,194],lang:[106,349],langaug:106,langcod:350,langnam:350,languag:[10,16,30,39,48,51,52,53,58,61,62,69,70,72,104,113,120,122,123,133,134,135,142,143,146,147,148,149,150,151,157,159,172,180,194,348,349,350,545],language_cod:64,languageerror:[349,350],languageexistserror:349,languagehandl:349,larg:[6,8,14,15,28,41,42,53,54,56,67,69,77,99,104,106,117,118,119,122,133,144,154,155,156,159,161,182,191,275,329,332,349,364,402,434,470,475,483,545],larger:[15,30,33,67,69,91,120,132,134,140,151,156,316,398,442,469,483,492,521,544],largest:[112,354],largesword:67,larlet:77,last:[0,2,3,11,13,14,15,18,20,22,28,32,36,37,44,45,51,58,64,67,76,79,95,113,118,120,124,128,135,137,142,145,150,151,152,153,155,156,158,159,164,169,174,175,178,184,187,199,206,209,210,212,218,223,224,238,247,257,283,289,308,309,310,311,312,316,350,386,398,420,469,470,471,476,477,478,480,485,492,545],last_cmd:[22,149],last_initial_setup_step:454,last_login:500,last_nam:500,last_step:420,lastcast:127,lastli:[139,170,177,209,292],lastsit:126,late:[11,95,402,471],later:[6,11,12,13,14,18,22,31,32,34,41,42,47,48,55,62,65,67,74,75,76,77,86,90,95,96,97,105,118,122,123,135,137,139,143,144,146,149,150,151,152,154,156,157,158,159,161,162,163,165,170,171,173,174,177,182,185,191,211,215,216,218,226,232,247,305,338,350,402,403,411,436,467,479,492],latest:[2,19,20,53,77,90,120,123,125,135,185,187,190,192,218,223,228,398,403,435,459,476,479,485,512,545],latin:[16,64,70,230,398,492,545],latin_nam:398,latinifi:[398,492],latter:[19,28,33,37,47,106,112,118,123,128,142,175,350,354,388,406,408,467],launch:[7,15,95,118,125,141,155,184,185,190,191,199,212,364,415,416,426,428,447,474,492,545],launchcmd:[118,201,202,235,314,330,332,545],launcher:[5,7,118,332,333,415,416,425,426,447],lava:118,law:180,layer:[20,76,147,152,397,466],layout:[9,19,31,40,48,51,53,99,118,132,133,135,149,153,329,337,398,545],lazi:492,lazy_properti:[85,112,289,353,354,492],lazyencod:445,lazyset:485,lc_messag:64,lcnorth:59,ldesc:133,ldflag:190,lead:[8,13,14,17,20,28,30,42,50,52,53,65,67,71,76,95,97,106,118,122,123,132,133,137,144,146,153,156,158,170,174,180,182,194,204,210,211,218,228,257,260,292,322,331,336,338,339,340,350,382,398,402,403,455,464,466,476,478,479,492],leak:[53,73],lean:[35,157,350],leap:[136,151,161,172],learn:[3,7,16,17,20,22,49,53,56,69,76,90,95,96,97,104,106,115,118,128,132,133,134,137,139,143,145,146,147,149,150,151,152,155,156,157,158,159,161,169,175,178,180,185,198,311,349,350,545],learnspel:311,least:[3,7,13,22,28,33,35,50,67,79,95,106,112,122,130,132,134,135,149,151,152,154,156,159,162,167,174,181,187,191,204,212,233,275,283,349,354,389,398,403,409,469,475,478,479,489,492],leasur:370,leather:[141,158,293],leatherrecip:293,leav:[5,12,18,32,51,53,76,95,97,117,125,126,135,141,144,154,162,164,165,194,215,217,218,232,241,273,275,276,277,283,329,331,372,398,410,440,444,445,476,479,483,515,545],leaver:232,led:149,ledg:115,leer:77,left:[2,19,22,30,32,33,41,51,67,76,95,117,118,120,130,134,137,141,142,146,150,155,161,170,185,204,218,224,226,275,289,308,309,310,311,312,329,337,338,346,364,371,394,403,466,469,478,492],left_justifi:41,leftmost:118,leg:453,legaci:[30,41,42,68,84,104,158,198,204,266,267,350,479,545],legal:[191,194],legend:[27,99,132,183,201,202,235,314,330,337,339,545],legend_key_except:337,legenddict:339,leidel:77,leisur:493,leland:77,len:[41,126,132,135,141,146,153,164,173,174,188,210,227,247,492],lend:27,length:[63,67,76,87,92,104,106,118,126,132,136,142,151,155,158,182,188,191,210,238,247,260,280,292,337,338,346,349,350,380,418,459,464,469,478,479,492,543],lengthi:126,lenient:41,less:[7,28,31,53,64,67,69,76,118,123,131,133,142,149,150,156,158,161,162,164,176,177,191,247,309,311,338,464],lesson:[143,144,145,146,147,149,150,152,153,156,158,159,161,545],let:[5,7,8,11,13,15,16,18,20,22,28,30,32,33,37,39,47,51,53,55,60,62,65,74,75,76,86,90,92,94,95,96,97,104,113,117,118,119,120,123,125,126,127,130,131,132,133,134,135,136,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,165,166,167,168,169,170,171,172,174,175,177,178,181,185,186,189,190,192,194,204,212,213,218,224,229,233,283,286,329,337,343,346,354,380,386,394,398,426,445,457,472,476,486,491,512,532,539,540,545],letsencrypt:[187,191],letter:[16,28,35,60,64,70,76,106,107,118,120,130,151,165,170,177,191,215,224,230,241,275,349,354,382,460,469,492],leve:402,level10:293,level:[0,2,4,12,13,14,18,19,27,28,30,31,33,39,44,46,48,49,50,53,57,62,63,64,69,74,76,86,95,99,106,120,122,129,134,135,137,141,144,146,151,156,158,159,161,162,170,177,180,185,188,191,195,204,206,215,218,220,221,232,241,242,245,247,273,293,299,337,349,364,386,388,393,398,403,418,455,464,466,472,474,479,480,492,513,543],lever:[22,48,273],leverag:[52,120,161,167],levi:67,lexicon:275,lhs:[126,135,226],lhslist:226,liabl:275,lib:[6,182,185,187,190],libapache2:181,libcloud:77,libcrypt:190,libjpeg:190,librari:[0,4,8,9,14,41,48,49,51,64,69,104,116,118,121,123,133,134,138,142,149,152,154,169,177,179,180,185,190,193,194,198,235,270,382,402,403,429,464,466,478,492,545],licenc:469,licens:[7,104,107,119,158,382,469,495,496,545],lid:[108,364],lidclosedcmdset:364,lidopencmdset:364,lie:[170,275],lied:275,lies:[11,22,150],life:[36,119,136,154,158,159,161,175,247,370,544,545],lift:[33,144,162,165,275,312,394,545],lifter:33,light:[15,19,42,69,120,155,156,159,182,212,309,340,371,372,403,410,469],lightabl:371,lighter:[60,309],lightest:19,lightli:[56,309],lightsail:191,lightsourc:371,lightsource_cmdset:371,lightweight:[85,104,289],like:[0,2,3,5,6,7,8,9,11,12,13,15,16,17,18,19,20,22,23,25,28,29,30,31,32,33,34,35,37,39,41,42,44,45,46,47,48,50,51,52,53,54,55,56,57,58,60,62,64,65,67,68,69,72,73,74,75,76,78,82,83,85,86,87,90,91,92,93,94,95,96,97,99,104,106,107,108,109,110,112,113,114,115,117,118,119,120,121,122,123,125,126,127,128,129,130,131,132,134,135,136,137,139,141,142,143,144,145,146,148,149,150,151,152,153,154,155,156,157,159,161,162,164,167,169,170,171,173,174,175,176,177,178,180,181,182,184,185,186,187,188,189,190,191,193,194,195,198,204,205,207,208,210,211,212,215,217,218,223,226,230,231,232,233,241,251,260,266,268,270,275,283,286,289,292,293,296,308,309,310,311,312,316,322,325,329,338,346,349,350,354,362,364,372,380,382,386,389,390,391,393,394,396,397,398,402,403,416,421,429,445,448,450,454,456,457,464,465,466,469,470,472,475,476,477,478,479,480,483,486,488,489,490,492,495,517,532,541,545],limbo:[14,15,19,63,75,76,82,97,115,118,144,148,149,155,170,174,178,185,195,218,241,331,372,420],limbo_exit:170,limit:[0,5,12,13,18,19,20,22,28,30,31,33,35,41,42,46,48,49,50,56,57,67,74,83,85,96,97,104,112,113,114,118,121,122,123,126,127,135,142,144,146,148,150,151,153,156,157,159,164,165,175,182,188,191,195,197,204,206,213,215,216,217,218,232,233,257,275,286,289,308,310,311,337,350,353,354,364,386,388,389,390,391,394,396,398,403,405,406,411,421,434,459,464,465,466,467,470,472,474,485,489,492,495,510,538,545],limit_valu:204,limitedsizeordereddict:492,limp:155,line2:150,line:[0,2,5,6,8,9,13,14,15,16,18,19,20,22,28,30,32,35,36,37,40,41,48,51,53,54,57,60,64,65,67,69,75,76,77,78,82,86,89,95,96,97,99,102,104,106,113,117,118,119,120,121,124,126,128,129,130,133,134,135,136,137,139,142,143,144,147,149,150,152,153,158,165,170,174,177,178,182,184,185,187,191,192,193,195,199,201,204,209,212,218,223,225,227,228,238,241,270,302,329,333,337,349,350,364,380,386,398,402,416,421,436,439,444,455,466,469,470,474,475,476,477,478,485,492,532,537,545],linear:132,linebreak:[137,469,491],lineeditor:474,lineend:491,lineno:120,linenum:474,liner:428,linereceiv:[436,439],linesend:445,lingo:[44,67,73,134],linguist:492,link:[0,8,9,12,15,17,18,20,22,26,28,31,37,44,49,52,53,62,71,75,76,95,96,114,119,122,123,124,126,128,130,132,134,137,141,143,144,146,147,148,149,151,158,165,167,170,174,177,178,184,185,189,191,192,197,204,207,218,223,254,270,331,335,336,337,338,339,394,398,406,414,416,427,431,436,439,466,491,492,505,544,545],link_button:505,link_object_to_account:505,linknam:[120,184],linknod:338,linktext:120,linkweight:338,linod:191,linux:[0,5,6,7,11,36,75,78,120,123,124,126,151,152,181,182,187,189,190,191,193,376,492,545],liquid:466,list:[0,5,6,7,9,12,13,14,15,16,18,19,20,22,26,28,30,31,32,33,35,37,41,42,44,46,48,49,50,51,53,55,60,62,63,64,67,68,70,72,73,76,78,80,83,84,86,91,92,95,96,97,98,99,102,106,107,113,118,119,122,124,126,130,132,134,135,137,140,141,142,143,144,146,147,148,151,153,155,156,157,159,161,162,164,165,167,170,174,177,178,180,182,184,185,189,191,192,194,199,204,205,206,207,210,211,212,213,215,216,217,218,223,224,225,226,228,229,232,233,234,238,241,244,254,255,257,258,260,266,273,274,275,283,286,289,292,296,299,302,305,308,309,310,311,312,316,329,331,337,338,339,340,346,349,350,354,364,369,370,371,376,377,380,382,386,388,389,391,394,396,397,398,402,403,405,407,408,409,411,414,416,421,422,425,426,428,430,432,434,435,440,445,448,457,459,461,464,465,466,467,469,470,471,472,473,476,478,479,485,486,489,490,492,495,496,500,501,508,510,513,515,516,517,523,525,536,537,538,540,542,543,544,545],list_callback:255,list_channel:223,list_displai:[500,502,504,505,506,507,508],list_display_link:[500,502,504,505,506,507],list_filt:[500,504,505,508],list_nod:[476,545],list_of_fieldnam:135,list_of_myscript:42,list_prototyp:402,list_select_rel:[502,504,505,506,507],list_serializer_class:518,list_set:416,list_styl:215,list_task:255,list_to_str:492,listabl:218,listaccount:228,listbucket:77,listcmdset:218,listdir:238,listen:[12,18,33,44,51,55,106,138,182,187,194,223,232,266,275,349,350,364,537,545],listen_address:182,listing_contact:184,listnod:476,listobject:218,listview:[537,538,540],lit:[371,372,479],liter:[14,30,31,41,50,63,134,144,224,469,479,488,492],literal_ev:[30,476,479,492,501],literari:159,literatur:545,littl:[3,11,16,22,41,42,48,53,54,75,80,95,97,99,104,113,115,117,118,120,123,124,125,126,127,134,135,137,141,142,143,144,146,148,149,150,151,152,153,154,155,156,157,158,159,161,169,170,171,172,178,188,191,193,199,275,309,350,369,372,451,464,476,492,532],live:[7,13,53,120,149,158,180,181,182,185,187,191,193,545],ljust:[30,469,479],lne:386,load:[0,5,6,7,8,11,13,14,16,20,22,27,28,41,51,52,53,55,64,77,86,90,118,128,131,133,134,135,137,140,149,150,151,152,156,162,165,169,170,174,194,207,212,224,225,228,234,257,278,294,316,337,339,349,388,390,394,397,398,402,406,410,420,423,425,456,464,466,467,470,471,474,479,484,486,487,490,492,510,525,530],load_buff:474,load_data:471,load_game_set:525,load_kwarg:487,load_module_prototyp:402,load_stat:278,load_sync_data:456,loader:[28,339,466,492],loadfunc:[27,474,487],loaf:[86,104],loc:[218,331],local0:187,local:[2,6,7,11,30,49,50,53,60,64,95,106,118,119,123,126,136,143,147,150,169,177,182,187,189,193,194,238,254,257,350,403,439,464,545],local_and_global_search:396,local_non_red_ros:146,local_ros:146,localecho:421,localhost:[49,50,51,52,53,73,75,124,137,154,167,177,178,182,183,185,187,190,191,198,445],locat:[4,5,8,9,11,12,14,19,20,22,25,26,28,32,33,37,41,42,46,48,49,50,51,53,55,58,63,73,74,75,77,82,90,91,95,96,97,99,101,104,105,117,118,120,123,124,125,126,129,130,132,134,135,141,142,143,144,146,147,148,149,150,151,155,157,158,161,165,169,170,171,172,174,177,181,185,187,191,193,194,198,204,209,218,224,228,232,233,238,241,278,280,286,292,305,316,322,329,331,335,337,338,339,340,350,362,370,372,393,396,397,398,403,445,454,464,465,466,467,470,472,476,478,485,489,518,521,523,545],location_nam:329,location_set:146,locations_set:[146,397],locattr:[371,393],lock:[18,20,22,24,26,30,35,37,41,42,46,48,50,54,55,57,76,90,95,103,106,109,118,121,124,125,126,127,128,130,131,135,136,140,141,143,144,147,148,149,161,165,177,182,188,191,195,199,201,202,204,206,213,215,216,217,218,223,224,225,227,228,229,230,232,233,234,241,251,254,255,257,258,266,273,275,283,286,292,293,296,299,302,305,316,322,329,331,338,343,350,364,366,370,371,372,388,389,390,396,397,398,402,403,405,461,464,466,467,472,474,476,486,492,493,505,513,540,545],lock_definit:394,lock_func_modul:[33,394],lock_storag:[213,215,216,217,218,223,224,225,226,227,228,229,230,234,241,251,255,266,269,270,273,283,286,292,293,296,299,302,305,308,309,310,311,312,316,322,325,331,343,350,364,366,370,371,372,380,386,388,390,398,447,464,466,474,476,477],lock_typ:33,lockabl:[35,104,109,135,275,322],lockablethreadpool:461,lockdown:[33,464,545],lockdown_mod:191,lockexcept:394,lockfunc1:33,lockfunc2:33,lockfunc:[18,22,33,39,121,126,148,150,174,195,201,202,218,223,392,467,545],lockhandl:[13,31,33,48,143,201,202,213,241,270,392,393,545],lockset:398,lockstr:[6,13,18,22,31,33,41,124,150,161,206,218,223,225,232,233,234,266,322,389,394,396,398,403,405,464,467,472,513],locktyp:[18,211,223,292,403,467,479],log:[2,5,7,9,10,11,12,13,22,25,28,32,35,37,42,44,45,50,51,52,53,54,55,63,64,67,73,78,80,90,95,115,118,120,121,122,123,124,125,126,130,131,134,135,143,144,150,154,158,161,162,165,170,174,177,178,181,182,183,185,186,187,188,189,190,191,193,199,204,206,212,216,230,232,233,250,251,276,337,338,339,376,377,380,398,406,410,416,421,425,426,430,433,434,436,439,447,448,449,455,457,459,461,466,472,485,492,500,537,538,545],log_dep:[19,485],log_depmsg:485,log_dir:[18,232,376,485],log_err:[19,485],log_errmsg:485,log_fil:[18,19,232,485],log_file_exist:485,log_info:[19,485],log_infomsg:485,log_msg:485,log_sec:485,log_secmsg:485,log_serv:485,log_trac:[19,42,172,173,485],log_tracemsg:485,log_typ:485,log_typemsg:485,log_warn:[19,485],log_warnmsg:485,logdir:2,logentry_set:207,logfil:[416,485,537,545],loggad:64,logged_in:44,loggedin:[53,434],logger:[19,42,121,172,173,201,202,376,428,468,545],logic:[3,6,28,53,54,86,90,95,97,118,124,130,131,132,137,148,158,161,170,178,275,349,397,401,420,464,476,493,515],login:[5,6,11,12,22,25,28,33,44,45,52,53,75,78,104,118,124,126,137,158,177,191,204,215,230,249,250,251,252,394,420,421,436,439,444,445,448,457,492,524,526,533,545],login_func:448,loginrequiredmixin:[538,543],logintest:533,logo:[77,545],logout:[447,448,533],logout_func:448,logouttest:533,logprefix:[426,436,439,461],lon:479,lone:[156,170,218,225],long_descript:184,long_running_funct:54,long_text:29,longer:[22,27,29,30,47,48,58,67,72,95,97,110,115,125,126,128,135,137,142,143,149,151,152,175,180,184,211,216,232,286,308,309,310,311,312,325,349,350,407,410,474,478,492,545],longest:[19,350],longrun:22,longsword:49,loo:[213,229],look:[0,2,3,5,6,8,13,14,15,16,17,19,20,22,25,26,28,30,32,33,36,37,39,41,42,44,46,48,50,52,53,54,55,56,57,58,60,62,64,65,67,68,69,73,75,76,83,86,89,90,91,92,95,96,97,100,101,102,104,106,108,113,115,118,119,120,122,123,124,125,126,128,129,130,131,132,134,135,136,137,139,140,141,142,143,146,147,148,149,150,151,152,153,154,155,156,157,159,161,162,164,167,168,169,170,171,172,174,175,177,178,182,185,187,188,190,191,193,194,199,204,205,210,212,213,215,218,224,226,229,230,238,250,251,256,273,274,275,286,292,302,305,310,316,329,338,339,340,349,350,362,364,369,371,372,380,386,389,393,394,397,398,400,403,405,421,436,437,444,448,464,466,470,476,478,479,486,489,490,491,492,496,500,505,532,545],look_str:204,lookaccount:135,lookat:22,looker:[5,30,58,118,132,135,165,204,275,276,286,316,329,340,350,362,398,466],lookm:22,lookstr:398,lookup:[6,13,22,33,46,58,67,209,224,376,388,396,397,402,435,467,469,482,483,488,489,492,493,545],lookup_env:238,lookup_expr:512,lookup_typ:488,lookup_usernam:28,lookuperror:469,loom:170,loop:[5,13,30,48,95,96,97,104,114,118,122,123,125,132,137,141,146,164,172,201,205,308,338,403,434,545],loopingcal:419,loos:[15,28,83,204,223,286,312,389,436,447,470],loot:[156,545],lop:146,lore:[31,135,225,388],lose:[13,44,133,156,158,164,165,193,199,310,376,427,428,436,439],lost:[48,73,97,110,120,130,133,142,170,180,199,223,325,413,426,427,428,436,439,444,464,469],lot:[0,3,5,8,11,14,16,18,19,30,31,33,41,42,46,48,50,52,53,54,58,64,67,69,73,76,82,86,89,90,92,95,96,97,99,111,113,114,118,119,121,122,124,127,130,134,135,136,137,142,143,146,148,149,150,151,152,153,154,155,156,157,158,159,161,162,163,165,170,174,177,180,185,187,191,241,247,251,309,329,350,366,371,380,461],loud:[125,161],love:[31,51,159,388],low:[20,62,63,96,158,191,211],lower:[5,12,13,18,20,22,28,39,51,54,57,60,67,112,118,126,128,132,135,136,141,155,158,191,210,211,215,226,228,337,338,350,354,421,467,469,492],lower_bound_inclus:354,lowercas:[120,151,213,350,469],lowest:[39,63,112,191,354,393,469],lpmud:72,lsarmedpuzzl:305,lspuzzlerecip:305,lst:[132,389,472],lstart:27,lstrip:[142,469],ltthe:228,ltto:59,luc:475,luciano:180,luck:[28,86,142,149,181],luckili:[11,33,170],lue:[60,469],lug:122,luggag:153,luhttp:228,lunch:[95,96],lunr:[31,225,391],lunrj:391,lurk:158,luxuri:[46,463],lvl10:293,lycanthrophi:146,lycantrhopi:146,lycantrophi:146,lycantrroph:146,lying:[170,275],m2m:467,m2m_chang:45,m_len:492,mac:[5,7,11,75,120,123,151,154,182,183,193,198,492,545],machin:[7,11,14,126,151,158,182,193,370,545],macport:[11,185],macro:[124,164],macrosconfig:124,mad:[11,354],made:[0,2,11,13,25,28,30,33,39,41,49,53,57,77,79,83,88,90,95,104,113,118,120,125,126,133,135,143,144,149,150,152,153,156,158,161,165,167,170,174,178,191,192,194,195,209,211,228,229,232,283,286,310,311,312,333,354,380,386,394,410,418,448,462,469,470,474,476,479,492],mag:475,magazin:180,mage:[28,77,146],mage_guild_block:28,mage_guild_welcom:28,magenta:175,magic:[13,33,46,74,79,94,129,155,156,157,158,174,283,293,311,346,353,418,545],magic_meadow:46,magicalforest:74,magnific:28,mai:[1,3,5,6,7,8,9,10,11,13,14,18,19,20,22,28,30,31,33,34,36,37,41,42,44,47,48,49,53,54,57,58,60,62,63,64,65,67,68,69,73,75,77,79,83,86,90,94,95,97,104,106,112,113,114,115,118,119,120,123,124,125,126,127,128,133,134,136,137,139,144,146,148,149,151,153,154,155,156,157,159,161,162,164,165,169,170,172,173,177,178,180,181,182,184,185,187,188,190,191,193,194,195,199,204,205,209,210,211,213,215,216,218,223,225,228,229,232,233,234,235,238,247,275,278,283,286,292,293,308,309,310,311,312,337,338,346,349,350,354,371,372,380,394,396,398,402,403,404,418,455,457,458,462,464,466,467,469,471,472,473,474,476,478,479,480,486,489,492,495,501,508,521,538,545],mail:[5,9,28,35,75,119,122,134,143,164,180,201,202,233,234,235,281,545],mailbox:[35,299],main:[4,11,14,15,16,20,22,28,31,34,37,39,40,41,42,44,46,47,48,49,51,52,53,58,62,65,67,73,76,82,92,95,96,103,104,106,118,119,123,125,129,132,133,137,139,141,142,144,147,149,150,157,158,161,164,177,178,180,182,184,191,193,195,197,199,204,207,209,215,218,223,225,229,232,234,241,257,292,294,299,329,333,339,349,350,380,390,391,397,398,403,406,416,420,421,423,428,433,435,440,454,456,461,466,467,476,477,481,489,491,492,500,506,523,541,545],mainli:[5,13,22,28,35,37,44,54,55,58,65,134,150,151,180,215,387,464,470,492],maintain:[5,11,31,47,57,69,77,104,118,119,120,124,133,153,159,182,191,193,197,198,228,230,251,333,411,544],mainten:[191,194,544],major:[15,16,30,123,134,157,174,177,182,185],make:[0,1,2,3,5,6,7,9,10,12,13,14,15,16,18,20,22,26,27,28,30,31,32,33,35,36,37,39,41,42,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,62,64,65,67,69,70,74,75,76,77,78,79,81,86,91,93,94,95,96,97,98,99,104,106,109,110,112,113,115,117,118,120,122,123,124,126,127,128,129,130,131,132,133,136,137,138,139,141,142,145,146,147,148,150,152,153,154,155,156,157,159,160,162,163,164,166,168,169,170,171,172,175,176,177,178,179,180,181,182,183,184,185,188,189,190,191,193,194,195,198,199,204,205,207,210,211,212,213,215,216,218,223,226,229,233,238,241,247,258,273,275,283,286,292,293,299,308,309,310,311,316,322,325,331,337,338,340,346,349,350,354,359,364,370,371,372,378,380,386,389,393,394,396,398,402,403,405,408,411,416,420,428,433,447,448,454,455,457,458,460,461,464,465,466,467,469,470,471,472,473,474,476,478,479,480,483,489,490,491,492,501,508,510,533,541,543,545],make_it:492,make_shared_login:526,make_uniqu:211,makeconnect:425,makefactori:436,makefil:120,makeit:447,makemessag:64,makemigr:[2,67,177],makeshift_fishing_rod:86,male:[58,93,296,479,496],malevol:15,malform:[339,490,493],malici:[30,194],malign:394,malysh:77,man2x1:69,man:[36,58,69,72,106,157,191,224,299,350],mana:[127,129],mana_cost:293,manaag:504,manag:[5,8,9,12,18,20,33,37,42,44,47,48,62,65,67,75,102,104,106,118,121,130,133,134,141,146,148,157,161,177,193,199,201,202,203,204,207,218,223,228,229,231,232,234,238,266,278,302,312,340,350,372,387,390,395,397,398,402,404,406,411,412,416,423,463,464,466,467,468,471,472,481,484,485,489,492,533,536,537,538,543,545],manager_nam:464,manchest:492,mandat:532,mandatori:[41,45,72,76,95,97,99,118],mandatorytraitkei:354,maneuv:[113,386],mangl:442,mango:[105,305],manhol:436,manhole_ssh:436,mani:[0,5,8,9,11,12,13,15,16,17,18,19,20,22,28,30,31,37,41,42,44,45,47,48,49,52,53,54,55,60,61,62,63,64,67,68,69,70,72,73,74,75,77,83,92,97,104,106,110,111,113,114,116,118,120,122,123,124,129,131,132,133,134,135,136,141,142,143,144,145,146,148,150,151,152,156,158,159,162,164,165,170,172,173,174,175,177,178,185,189,191,192,194,195,199,206,207,211,213,218,223,229,234,238,245,251,270,275,283,286,292,294,310,311,325,337,338,340,350,366,370,380,386,390,391,394,396,397,403,406,411,416,430,438,440,459,464,466,467,469,476,477,479,483,484,485,541],manifest:[6,148],manipul:[13,20,28,39,41,42,50,67,76,91,95,97,104,112,123,131,143,165,206,218,228,233,254,314,316,354,389,396,398,405,422,472,477,538,540],manner:[15,329,350,398,434,466],manpow:119,manual:[5,6,9,13,15,22,31,33,37,41,42,48,50,52,60,62,64,67,74,95,104,112,113,118,120,122,124,125,129,135,141,144,148,149,151,156,159,161,170,171,174,178,180,182,185,187,191,199,201,205,218,270,277,338,354,364,369,386,398,403,409,416,433,440,476,477,479,544,545],manual_paus:[42,409],manual_transl:[106,349],manytomanydescriptor:[207,234,390,397,406,464,466,467],manytomanyfield:[207,234,390,397,406,464,466,467],map10:335,map11:335,map12a:335,map12atransit:335,map12b:335,map12btransit:335,map1:[118,335,338],map2:[118,335,338],map3:335,map4:335,map5:335,map6:335,map7:335,map8:335,map9:335,map:[6,16,18,28,30,36,58,68,73,77,84,87,95,96,97,104,106,117,123,126,130,134,135,187,193,201,202,215,223,232,235,238,244,245,247,275,314,329,330,331,332,334,335,336,337,339,340,349,350,354,391,398,402,403,440,464,466,469,475,476,479,490,492,496,497,545],map_align:[118,340],map_area_cli:340,map_character_symbol:[118,340],map_data:[335,337],map_displai:[118,335,340],map_exampl:332,map_fill_al:[118,340],map_legend:99,map_mod:[118,340],map_modul:170,map_module_or_dict:337,map_separator_char:[118,340],map_str:[117,132,170,329],map_target_path_styl:[118,340],map_visual_rang:[118,340],mapa:118,mapb:118,mapbuild:[99,201,202,235,314,545],mapc:118,mapcorner_symbol:337,mapdata:339,maperror:[336,337],maplegend:99,maplink:[118,337,338],mapnam:[99,331,339],mapnod:[118,337,338],mapp:479,mapparsererror:[336,338],mapper:[337,479,483,497,545],mapprovid:[117,329],maps_from_modul:339,mapstr:[118,339],mapstructur:337,maptransit:336,maptransitionnod:[118,338],march:[180,485],margin:17,mariadb:545,mark:[11,14,15,22,30,31,33,50,51,53,59,60,71,73,74,113,118,120,125,132,135,143,146,151,157,185,189,191,210,217,257,280,293,316,335,337,338,382,386,457,464,466,470,475,476,479,488],mark_categori:386,markdown:[31,120,124,184],marker:[14,18,22,30,36,53,58,60,93,104,113,118,123,151,157,161,223,224,275,280,292,296,316,337,338,350,386,398,428,436,439,444,445,464,467,469,475,476,477,521],market:[158,191],markup:[31,58,60,104,139,169,201,202,218,243,244,245,468,491,492,545],martei:77,marti:77,martiniussen:77,mask:[104,106,157,305,350,377,378],maskout_protodef:305,mass:[5,138,156,545],massiv:[122,127],master:[75,88,90,96,104,112,119,120,134,155,156,162,164,172,178,185,192,193,354,462,545],match:[8,9,11,13,19,20,22,28,30,31,32,33,36,37,39,41,42,44,46,48,50,51,53,60,65,67,68,73,75,76,84,86,91,99,112,117,118,130,131,132,134,135,136,142,144,146,148,153,161,169,170,172,177,178,182,195,204,206,209,210,211,212,213,216,218,223,224,225,227,229,233,241,244,247,260,292,299,302,305,311,316,329,337,338,340,350,354,380,388,389,391,393,394,396,398,402,403,405,408,411,421,422,434,447,457,464,465,466,467,469,474,476,478,479,487,489,490,491,492,493,495,521,543,545],match_index:210,matched_charact:380,matcher:28,matches2:67,matchobject:[469,491],mate:123,materi:[86,151,158,292,293],math:130,mathemat:[157,211],matlab:0,matplotlib:449,matric:[118,337],matrix:[118,478],matt:77,matter:[2,13,20,28,31,34,44,45,64,69,75,86,97,106,118,124,126,134,136,137,142,151,152,156,161,162,164,169,171,185,194,211,292,312,338,350,370,397,421,464,545],matur:[9,31,53,69,72,151],maverick:123,max:[18,56,77,92,112,132,157,158,164,188,225,337,350,353,354,380,391,459,485,492],max_damag:310,max_dbref:465,max_depth:492,max_dist:132,max_heal:310,max_l:132,max_length:[67,132,177,238,350],max_lin:478,max_memory_s:238,max_nest:479,max_nr_charact:158,max_num_lin:537,max_pathfinding_length:337,max_popular:537,max_rmem:483,max_siz:[335,337,485],max_tim:335,max_valu:[346,532],max_w:132,max_width:132,maxconn:187,maxdelai:[413,427,428,447],maxdepth:403,maxdiff:[229,294,351,516,527],maximum:[56,60,67,92,94,104,118,130,142,157,158,170,188,204,238,289,308,309,310,311,312,337,346,354,380,398,403,461,469,476,478,479,492],maxiumum:335,maxlengthvalid:204,maxnum:492,maxrotatedfil:485,maxsplit:469,maxthread:461,maxval:[479,492],maxvalu:479,maxwidth:478,may_use_red_door:41,mayb:[13,14,15,19,20,22,28,41,67,74,75,76,79,86,118,120,125,126,131,132,137,140,141,146,148,149,150,153,156,158,159,162,164,184,185,191,212,260,283,293,349,434],mcclain:77,mccormick:77,mccp:[32,183,201,202,412,421,424,545],mccp_compress:429,mcintyr:77,md5:182,meadow:[46,74,76,157,479],mean:[3,4,5,6,8,9,11,13,14,15,16,18,19,20,22,28,32,33,34,35,36,39,41,42,44,46,48,52,54,55,58,60,62,65,67,68,70,73,76,86,95,96,97,104,106,112,116,117,118,119,122,123,127,132,134,135,136,139,141,144,146,147,148,149,150,151,152,155,156,159,161,162,164,165,169,170,171,174,175,178,179,182,191,193,194,195,199,204,205,206,212,218,225,257,270,275,293,337,340,343,349,354,371,393,396,398,402,403,407,411,416,440,456,464,466,469,476,478,479,483,485,488,489,545],meaning:[213,229],meaningless:165,meant:[20,31,35,42,48,49,51,52,56,65,74,76,93,104,112,114,117,131,136,144,148,150,157,175,184,211,241,275,296,308,309,310,311,312,329,350,354,366,372,388,398,421,470,492],meanwhil:31,measaur:5,measur:[5,165,191,210,227,337,447,448,492],meat:[154,160,163,166,168,177],mech:[138,545],mechan:[4,18,19,22,27,28,41,42,48,91,104,114,127,130,135,137,142,155,156,162,164,165,175,204,205,209,276,311,316,350,392,403,411,416,420,426,434,445,456,466,474,477,481,487,538,543,545],mechcmdset:125,mechcommand:125,mechcommandset:125,meck:125,med:64,medan:64,media:[56,77,104,148,238,444,461,488,500,501,502,504,505,506,507,508,532],median:132,mediat:162,mediev:293,medium:56,mediumbox:425,meet:[2,117,126,148,155,157,256,329,460],mele:[114,157,312],melt:[292,293],mem:228,member:[13,18,50,67,75,158,223,224,226,398,492],membership:[75,124,146],memori:[5,20,22,31,48,53,55,67,70,73,127,133,149,151,182,190,191,204,228,232,398,410,411,449,459,464,468,477,483,487,492,545],memoryerror:185,memoryusag:449,memplot:[201,202,412,446,545],meni:241,mental:175,mention:[13,14,15,16,22,31,32,47,54,62,69,70,75,125,128,132,133,134,144,146,151,156,175,185,191,212,251],menu:[0,7,9,20,41,44,53,92,96,104,111,115,120,121,126,137,147,156,157,158,163,165,184,185,186,199,201,202,218,235,240,241,242,271,272,273,276,366,369,380,384,386,399,403,414,416,468,486,545],menu_cmdset:476,menu_data:28,menu_edit:241,menu_login:[100,201,202,235,236,545],menu_modul:476,menu_module_path:476,menu_quit:241,menu_setattr:241,menu_start_nod:366,menu_templ:[28,476],menuchoic:[28,476],menudata:[274,369,380,400,476],menudebug:[28,476],menufil:476,menunode_fieldfil:380,menunode_inspect_and_bui:141,menunode_shopfront:141,menunode_treeselect:386,menunodename1:28,menunodename2:28,menunodename3:28,menuopt:386,menutest:143,menutre:[28,476],merchandis:158,merchant:[96,104,111],mercuri:69,mere:[94,104,171,228,346],merg:[6,11,22,28,30,76,95,117,119,120,123,131,134,136,146,149,150,161,167,209,210,211,212,329,364,372,403,406,440,476,545],merge_prior:476,merger:[20,170,211,212],mergetyp:[20,28,164,211,364,372,474,476,477],merit:161,mess:[5,13,18,19,57,113,120,158,191,386],messag:[5,8,9,11,14,16,18,19,22,23,24,27,28,29,30,32,33,35,37,40,42,44,51,54,61,62,64,70,71,74,76,78,86,92,93,95,96,99,104,108,120,121,123,125,127,128,131,135,136,139,140,141,142,143,144,151,153,156,157,158,161,162,164,165,170,172,176,181,185,186,188,191,194,195,197,199,204,205,209,212,213,216,218,223,224,225,231,232,233,234,241,255,257,270,275,276,278,283,286,292,294,296,299,305,308,309,310,311,312,331,338,350,354,359,360,362,364,369,370,371,372,377,380,382,396,398,405,416,418,425,427,428,434,435,436,439,440,442,444,453,455,457,459,461,472,474,476,477,479,485,489,490,492,545],message_rout:51,message_search:233,message_templ:165,message_transform:232,messagepath:545,messagewindow:51,messeng:362,messsag:278,meta:[35,48,148,195,466,483,500,501,502,504,505,508,512,515,518,532],metaclass:[48,67,213,466],metadata:[35,377,418],metavar:270,meteor:140,meter:[94,104,346,354],method:[3,8,11,12,13,18,19,20,28,30,31,33,37,39,41,44,45,46,47,48,51,53,54,58,62,65,67,68,75,76,78,82,86,95,96,102,103,106,107,108,112,116,118,120,122,123,126,127,128,129,130,132,135,136,137,142,143,145,146,147,150,152,153,161,162,164,165,170,171,172,173,174,176,177,178,195,197,204,206,207,209,211,212,213,215,218,219,223,225,226,228,229,232,233,234,238,239,241,242,247,248,254,257,266,270,273,275,278,279,280,283,289,292,294,302,305,308,309,310,311,312,313,316,322,325,329,331,335,338,340,349,350,351,353,354,360,364,369,370,371,372,376,377,382,388,389,390,393,394,396,398,405,410,411,413,418,421,422,423,425,426,427,428,429,434,436,439,442,444,445,447,448,452,454,455,456,457,459,464,466,469,470,472,474,476,477,478,479,480,483,484,485,486,487,489,490,491,492,502,508,512,513,515,516,518,538,541,543,545],methodnam:[229,239,242,245,248,252,258,267,269,279,284,287,290,294,297,300,303,306,313,317,323,326,328,335,344,347,351,353,360,367,373,378,383,385,411,442,452,484,490,497,516,527,533],metric:[140,349],michael:77,microsecond:13,microsoft:[170,185],mid:[69,128,174],middl:[22,128,132,191,309,335,469],middleman:187,middlewar:[201,202,498,522,545],midnight:[95,126,136],midst:155,midwai:60,mighht:142,might:[0,3,6,8,11,15,16,17,19,20,22,28,29,31,33,37,39,42,44,47,54,55,60,62,64,76,79,95,96,97,104,107,110,115,116,122,124,126,127,128,129,130,135,136,137,139,140,141,142,143,144,154,156,158,162,164,165,169,170,173,175,176,177,181,182,185,190,191,192,193,194,195,199,212,216,218,270,283,308,309,310,311,325,377,382,398,405,445,466,469,474,485,486,492,515,532],mighti:[18,128,149,170],migrat:[2,5,8,10,45,67,75,77,104,120,148,154,170,177,182,185,190,198,199,238,403,545],mike:218,million:[177,182],mime:[77,233,472],mimic:[5,8,13,27,42,122,158,162,182,234,354,388,455,474],mimick:[27,123,162,447,474,477],mimim:467,min:[42,87,92,112,132,136,157,247,353,354,380,479,480],min_damag:310,min_dbref:465,min_heal:310,min_height:478,min_shortcut:[76,241],min_valu:532,min_width:478,mind:[14,15,28,54,55,94,95,104,119,122,133,134,138,151,152,155,156,157,159,161,175,178,182,184,257,283,346,382,418,492,545],mindex:210,mine:[58,96,158,194,479,496],mini:[39,58,122,148,149,150,170],miniatur:155,minim:[5,44,53,77,106,118,156,159,164,194,238,349,403],minimalist:[22,69,135],minimap:545,minimum:[44,76,86,92,104,112,123,135,158,162,308,309,310,311,312,354,380,421,461,466,478,479,487,492],minimum_create_permiss:513,minimum_list_permiss:513,mininum:478,minlengthvalid:204,minor:212,mint:[11,185,187],minthread:461,minu:[67,146,398,480],minut:[19,42,95,127,136,142,159,164,180,193,223,228,247,283,459,480,492],minval:[479,492],mirc:428,mirror:[44,101,118,151,180,189,201,202,235,355,545],mirth:99,mis:134,misanthrop:146,misc:24,miscelan:468,miscellan:[104,147,148],misconfigur:182,mismatch:[32,492],miss:[6,18,53,64,119,132,134,143,158,185,191,292,294,308,309,310,311,312,402,421,544],missil:[125,311],mission:137,mistak:[50,120],misus:191,mit:[180,469],mitig:[134,194,542],mix:[8,13,22,28,58,60,64,79,104,112,118,121,129,146,161,175,177,204,225,234,275,283,293,337,350,354,398,402,403,460,467,470,478,479,492],mixabl:275,mixer:275,mixer_flag:275,mixin:[8,201,202,402,450,490,498,515,518,531,535,536,537,538,540,543,545],mixtur:[139,275,479],mkdir:[2,75,185],mktime:136,mlocati:64,mmo:114,mmorpg:159,mob0:133,mob:[15,33,44,115,122,133,155,156,201,202,212,218,235,355,368,372,373,403,470,545],mob_data:133,mob_db:133,mob_vnum_1:133,mobcmdset:370,mobdb:133,mobil:[15,41,138,155,158,188,197,370,393],moboff:370,mobon:370,mock:[293,410,490],mock_random:360,mock_repeat:229,mock_tim:[290,353,452],mock_tutori:229,mockdeferlat:490,mockdelai:490,mocked_idmapp:452,mocked_o:452,mocked_open:452,mocked_randint:344,mockrandom:294,mockval:490,mod:[112,181,353,354,402],mod_import:492,mod_import_from_path:492,mod_or_prototyp:402,mod_prototype_list:402,mod_proxi:545,mod_proxy_http:181,mod_proxy_wstunnel:181,mod_secur:194,mod_ssl:545,mod_sslj:181,mod_wsgi:545,mode:[3,5,7,12,20,26,27,28,32,53,61,73,80,95,98,108,118,137,144,149,151,152,158,164,165,171,177,180,181,187,193,194,201,217,225,228,230,238,239,299,335,337,340,364,370,398,416,421,426,433,444,445,454,470,474,476,479,485,492,545],mode_clos:445,mode_init:445,mode_input:445,mode_keepal:445,mode_rec:445,model:[13,31,33,35,36,42,46,47,48,49,50,58,61,73,75,85,104,112,114,120,123,137,146,158,162,169,176,195,201,202,203,204,206,231,232,233,289,354,387,395,398,404,407,411,412,422,463,464,465,467,468,473,481,482,484,488,489,492,500,501,502,504,505,506,507,508,512,515,532,536,537,538,542,543,545],model_inst:488,modeladmin:[502,504,505,506,507,508],modelattributebackend:464,modelbackend:524,modelbas:483,modelchoicefield:[500,505],modelclass:[13,46],modelform:[500,501,502,504,505,506,508,532],modelmultiplechoicefield:[500,502,504,505],modelnam:[213,232,388,390,466],modelseri:515,modelviewset:518,moder:[79,106,124,130,283],modern:[13,16,54,69,100,104,129,170,175,180,187,194,429],modif:[11,22,30,53,65,95,96,97,119,126,142,165,181,193,354,462,532,545],modifi:[0,9,11,12,13,18,20,22,28,30,31,37,41,42,44,48,49,51,52,60,62,73,74,76,86,89,90,93,95,96,97,100,104,106,110,112,114,118,120,121,122,124,126,130,131,133,134,135,141,143,144,148,150,151,152,153,155,157,158,159,161,162,165,168,170,172,179,182,193,195,199,204,212,225,232,238,241,257,270,275,276,278,292,293,296,305,308,309,310,311,312,316,325,343,350,353,354,371,390,396,398,403,411,466,470,476,483,488,491,500,521,532,536,537,538,540,542,543,545],modified_tim:238,modul:[0,4,5,6,8,13,14,16,19,20,22,25,27,28,30,31,32,33,37,42,44,45,48,53,62,65,69,73,78,79,82,83,84,86,87,88,89,90,92,94,95,99,100,103,104,106,107,109,110,113,114,116,118,119,120,122,125,128,133,134,135,136,139,140,141,143,144,147,148,149,150,152,157,158,161,163,165,167,170,171,174,186,190,192,194,195,199,209,210,212,213,218,220,221,222,225,227,229,241,244,245,247,250,251,254,255,256,258,266,270,273,275,278,280,283,286,289,292,293,294,308,309,310,311,312,316,322,325,331,337,339,343,346,349,350,353,354,364,370,371,372,378,380,382,386,388,393,394,397,398,401,402,403,407,409,410,411,413,415,416,420,421,425,433,435,436,439,440,443,445,447,448,449,454,456,457,458,464,466,467,468,469,470,471,472,473,474,475,476,477,479,480,490,492,545],module1:119,module2:119,module_path:339,module_with_cal:479,modulepath:425,mogilef:77,moifi:316,mold:152,mollit:29,moment:[20,31,47,64,73,96,125,134,141,142,149,157,204,337,406],mona_lisa_overdr:153,monei:[67,75,79,104,156,157,158,159,191],monetari:[119,283],mongodb:77,monitor:[5,34,68,121,407,421,440,483,545],monitor_handl:[34,121,201,407],monitorhandl:[24,32,201,202,404,545],monlit:146,mono:126,monster:[31,37,41,123,128,134,149,152,156,157,158,163,218,403],monster_move_around:152,month:[77,87,95,104,119,136,187,191,247,480,485,492],monthli:[119,136],montorhandl:34,moo:[69,72,122,134,154,180,391,479],mood:[96,112,155,158,159,354],moon:[126,136,140,146],moonlight:146,moonlit:146,moor:[99,155],moral:6,more:[2,3,4,5,6,8,11,12,13,14,15,16,17,18,19,20,22,25,27,28,29,30,31,32,35,36,37,39,42,44,46,47,48,51,53,54,55,57,61,62,63,64,65,67,68,69,70,75,76,78,79,80,82,83,85,89,90,91,94,95,96,97,99,102,103,104,106,107,108,110,111,112,113,114,115,117,118,119,122,123,124,125,126,127,130,131,132,133,135,136,137,138,141,142,143,144,146,147,148,149,151,152,153,154,155,156,157,159,160,161,162,164,165,166,167,169,170,172,174,175,176,177,178,180,182,185,187,188,189,190,191,193,194,195,199,201,203,204,206,207,210,211,212,217,218,223,224,225,228,229,230,232,233,235,238,241,247,250,251,257,260,270,273,275,283,286,289,292,308,309,310,311,312,316,325,329,337,338,339,340,346,349,350,354,364,366,370,371,372,382,386,389,391,396,398,402,403,405,426,428,431,440,447,448,457,462,464,465,466,469,470,472,473,474,475,476,477,478,479,483,489,490,492,493,505,514,515,532,541,545],more_command:477,more_funcparser_cal:30,morennanoth:229,morennthird:229,moreov:[42,191],morn:[91,92,157,316,380],morph_engli:495,morpholog:495,mortal:[31,155],mosso:77,most:[3,5,6,8,9,13,14,17,18,19,20,22,25,28,31,32,33,35,37,44,45,47,48,49,50,51,53,54,58,60,62,65,67,68,69,70,72,74,75,76,82,86,94,95,96,97,104,106,110,112,118,119,120,123,124,126,129,130,132,133,134,135,136,137,140,142,143,144,145,146,147,148,151,152,153,154,155,157,158,159,161,162,164,165,170,171,174,175,177,181,182,185,191,193,194,195,198,204,207,211,212,215,218,226,234,241,280,292,293,308,309,310,311,312,325,335,337,338,346,349,350,354,390,391,394,397,398,402,403,406,410,439,444,454,464,465,466,467,476,477,483,484,490,492,537,545],mostli:[28,48,51,53,62,95,118,134,137,142,162,165,191,211,230,310,329,338,343,349,436,500],motiv:[14,15,37,122,156,427,428,434,435,436,439,444,445,456,457,545],mount:193,mountain:[69,99,170],mous:[51,59,476],mouth:331,movabl:275,move:[11,15,16,18,22,27,28,29,37,75,76,79,92,95,96,97,104,112,115,117,118,124,125,128,131,132,135,137,140,141,142,148,149,151,152,155,156,157,158,163,164,170,171,175,177,178,180,182,184,185,212,218,224,241,256,275,276,278,283,308,309,310,311,312,314,325,329,331,338,354,370,371,372,380,389,393,398,448,466,470,477,545],move_around:[149,152],move_callback:228,move_delai:228,move_hook:398,move_obj:329,move_posit:275,move_to:[37,97,141,161,174,325,398],movecommand:131,moved_obj:[276,329,372,398],moved_object:398,movement:[41,104,110,114,118,135,157,174,228,308,309,310,311,312,325,337,338,398],mover:312,mptt:124,mratio:[210,227],msdp:[65,421,440,545],msdp_list:421,msdp_report:421,msdp_send:421,msdp_unreport:421,msdp_var:440,msg:[3,8,12,13,14,18,19,22,23,27,28,29,33,34,37,39,44,51,54,62,67,68,72,76,85,86,93,94,95,96,97,98,99,101,104,116,120,121,126,127,128,129,131,133,135,136,140,141,142,143,149,150,151,152,161,162,164,165,170,172,174,188,201,204,205,206,213,215,218,219,223,232,233,234,270,275,278,289,292,296,299,337,338,339,340,346,354,362,364,377,394,398,427,428,455,470,472,474,476,477,485,490,492,501,502,508,545],msg_all:164,msg_all_sess:[22,213],msg_already_sit:161,msg_arriv:[95,97],msg_channel:223,msg_char:275,msg_cinemat:280,msg_content:[19,22,30,37,42,58,95,96,97,125,136,165,172,174,176,398],msg_db_tag:502,msg_help:225,msg_leav:[95,97],msg_locat:398,msg_other:283,msg_other_sit:161,msg_receiv:398,msg_room:275,msg_self:398,msg_set:467,msg_sitting_down:161,msg_standing_fail:161,msg_standing_up:161,msg_system:275,msgadmin:502,msgform:502,msglauncher2port:[416,425],msgmanag:[233,234],msgobj:232,msgportal2serv:425,msgserver2port:425,msgstatu:[416,425],msgtaginlin:502,mssp:[148,195,201,202,412,424,545],mtt:443,much:[0,1,3,5,13,14,15,16,28,31,33,37,42,47,48,53,54,58,64,70,76,82,86,95,97,106,112,113,118,123,124,126,128,130,132,133,136,137,140,142,143,144,146,149,150,151,152,154,155,158,159,161,162,163,164,170,173,174,176,177,178,180,182,185,191,207,212,217,226,241,247,289,312,337,343,349,350,354,364,371,386,456,464,467,469,470,471,478,492,510,521],muck:[134,154],mud:[6,9,16,32,33,36,40,44,47,51,58,60,62,68,69,73,74,76,90,95,104,114,122,123,125,129,132,133,142,144,148,151,155,156,159,162,164,170,171,175,176,181,182,183,185,189,191,192,193,195,197,198,199,207,212,215,312,369,413,429,430,431,436,439,440,443,470,480,545],mudbyt:180,mudconnector:[180,230],mudderi:180,muddev:185,mudform:475,mudinfo:[143,230],mudlab:180,mudlet:[183,431],mudmast:183,mudprog:[95,104],mudramm:183,mudstat:230,muhammad:491,mukluk:183,mult:[30,41,479],multi:[20,28,44,54,76,104,113,115,119,120,122,149,153,154,155,156,161,165,193,195,210,228,242,275,293,335,337,338,350,386,391,398,457,476,492,540,545],multiaccount_mod:6,multidesc:[201,202,235,281,545],multilin:491,multilink:[118,338],multimatch:[20,153,210,350,398,479,492],multimatch_str:[204,350,398,492],multimedia:[51,77,238],multipart:238,multipl:[8,15,18,19,20,22,30,31,34,37,41,44,45,47,48,50,55,60,62,68,69,76,84,86,90,95,99,102,104,113,114,118,123,129,135,136,146,148,149,151,155,156,162,165,180,182,191,195,204,209,211,216,217,218,223,225,227,228,244,251,258,266,292,296,302,308,309,310,311,316,337,338,343,346,350,353,362,372,386,394,396,398,402,403,411,414,418,421,425,440,448,464,465,470,476,478,489,490,492,501,508,545],multiplay:[18,90,104,122,134,154,158,159,160,180],multipleobjectsreturn:[204,205,207,232,234,247,257,275,276,277,283,286,296,305,308,309,310,311,312,316,322,325,329,339,340,349,350,359,362,364,366,370,371,372,382,390,397,398,402,406,409,423,449,464,467,480,484],multipli:[30,151],multisess:[61,137,476,545],multisession_mod:[12,22,44,50,123,137,158,165,177,183,204,215,219,296,398,457],multisession_modd:28,multitud:[60,134,170],multumatch:398,mundan:125,murri:492,muscular:157,muse:180,mush:[2,69,75,84,102,104,122,138,154,162,164,180,244,302,545],mushclient:[32,183,421,431],musher:180,mushman:69,mushpark:191,music:52,musoapbox:[134,180],must:[0,5,6,8,9,11,12,13,16,20,22,27,28,30,31,32,33,34,35,36,37,39,41,42,46,47,48,49,50,51,52,53,54,58,59,62,64,65,70,73,74,78,79,84,85,95,97,104,105,106,108,112,118,119,120,123,124,126,128,132,133,135,136,139,141,143,145,148,149,150,151,152,153,156,157,159,161,164,165,169,171,177,181,183,185,186,187,188,189,191,193,194,195,199,205,210,211,213,218,223,229,232,233,234,238,244,247,250,251,275,278,283,286,289,292,305,308,309,310,311,312,337,338,340,349,350,354,364,369,371,372,377,386,388,390,391,393,398,401,402,405,407,411,416,421,434,436,439,456,458,459,464,465,466,469,470,471,472,473,474,475,476,477,479,480,486,487,488,489,490,491,492,493,495,501,508,515,523,540,541,545],must_be_default:212,mustn:118,mutabl:[473,545],mute:[17,18,103,204,223,232,266],mute_channel:223,mutelist:[18,232],mutual:[364,465],mux2:[72,230],mux:[22,61,69,84,103,104,122,125,135,144,154,194,208,226,244,265,266,267,545],mux_color_ansi_extra_map:[84,244],mux_color_xterm256_extra_bg:[84,244],mux_color_xterm256_extra_fg:[84,244],mux_color_xterm256_extra_gbg:[84,244],mux_color_xterm256_extra_gfg:[84,244],mux_comms_cmd:[103,201,202,235,236,545],muxaccountcommand:[226,299],muxaccountlookcommand:215,muxcommand:[22,121,126,127,128,129,131,135,140,143,165,201,202,208,214,215,216,217,218,223,224,225,227,228,230,251,255,273,286,299,302,305,310,311,316,322,331,343,366,372,398,474,545],mvattr:[26,143,218],mxp:[32,59,183,201,202,225,412,421,424,436,439,469,476,491,492,545],mxp_pars:431,mxp_re:469,mxp_sub:469,mxp_url_r:469,mxp_url_sub:469,my_callback:458,my_datastor:67,my_func:152,my_funct:128,my_github_password:11,my_github_usernam:11,my_identsystem:36,my_object:128,my_port:62,my_portal_plugin:62,my_script:42,my_server_plugin:62,my_servic:62,my_word_fil:[106,349],myaccount:46,myaccountnam:153,myapp:67,myarx:75,myattr:[13,204],mybool:13,mybot:223,mycar2:36,mychair:46,mychan:18,mychannel1:223,mychannel2:223,mychannel:[18,55,223],mycharact:139,mychargen:28,mycmd:[22,31,416],mycmdget:150,mycmdset:[20,22,143,150],mycommand1:20,mycommand2:20,mycommand3:20,mycommand:[8,20,22,31,65,129,143,150,153,490],mycommandtest:490,mycompon:51,myconf:2,mycontrib:8,mycontribnam:119,mycss:51,mycssdiv:51,mycustom_protocol:62,mycustomchannelcmd:18,mycustomcli:62,mycustomview:73,mydatastor:67,mydbobj:13,mydefault:30,mydhaccount:193,mydhaccountt:193,mydhacct:193,mydict:13,myevennia:189,myevilcmdset:[20,211],myevmenu:28,myfix:11,myformclass:53,myfunc:[8,28,47,54,492],myfuncparser_cal:30,myfunct:8,mygam:[0,3,5,7,8,9,11,12,13,14,15,18,19,20,25,28,32,33,37,41,42,48,49,50,51,53,62,64,67,73,75,77,79,82,83,84,86,88,90,91,93,99,100,102,103,106,109,110,112,117,118,120,121,125,126,129,131,132,133,134,135,136,137,139,140,141,143,147,148,149,150,151,152,154,161,162,164,165,167,169,170,172,173,174,177,178,182,184,185,186,187,188,190,191,193,195,198,199,201,235,241,244,266,293,299,302,314,316,322,324,332,334,343,350,354,441,490,492,545],mygamedir:120,mygamegam:139,mygrapevin:223,mygreatgam:53,mygreatpwd:185,myhandl:45,myhousetypeclass:218,myinstanc:67,myircchan:223,mykwarg:28,mylayout:51,mylink:120,mylist2:13,mylist:[6,13,466],mylog:19,mymap:[99,118],mymenu:28,mymethod:133,mymodul:47,mymud:[7,181],mymudgam:191,mynam:[158,193],mynestedlist:473,mynod:28,mynoinputcommand:22,mynpc:165,myobj1:46,myobj2:46,myobj:[13,19,33,42,218,411],myobjectcommand:126,myothercmdset:20,myownfactori:62,myownprototyp:41,mypassw:251,mypassword:49,myplugin:51,mypobj:13,myproc:62,myproc_en:62,myprotfunc:41,myrecip:86,myreserv:30,myroom:[42,46,133,146,218],myros:37,myscript:[42,46,48],myself:[13,58,159,479,496],myserv:251,myservic:62,mysess:44,mysql:[2,9,123,492,545],mysqlclient:182,myst:545,mysteri:[31,36,190],myston:153,mystr:13,mytag:51,mytestobject:8,mytestview:53,mythic:155,mytick:411,mytickerhandl:411,mytickerpool:411,mytrait:[112,354],mytup1:13,mytup:13,mytupl:13,myusernam:49,myvar:22,myview:73,myxyzroom:118,naccount:457,nail:[86,292],naiv:[213,232,238,317,329,388,390,466],nake:22,name1:218,name2:218,name:[2,3,4,5,7,8,9,10,11,12,13,14,15,16,18,20,22,26,28,29,30,31,32,33,34,36,37,39,41,42,44,45,46,48,49,50,51,53,54,57,58,62,63,65,67,68,70,73,74,75,76,77,78,82,86,87,90,92,95,96,97,100,104,106,107,112,113,117,118,120,123,124,126,128,131,132,133,134,135,136,137,139,140,141,142,143,144,145,146,147,148,150,151,152,153,154,155,156,157,161,164,165,167,169,170,171,174,175,176,177,178,180,182,183,184,186,187,188,189,190,191,193,194,195,198,199,201,204,205,206,207,209,210,211,212,213,215,216,218,223,224,225,226,227,228,229,230,232,233,234,238,241,247,251,254,256,257,260,266,270,273,275,276,278,280,286,289,292,293,305,310,311,322,328,329,331,337,338,339,340,349,350,353,354,370,372,380,382,386,388,389,390,391,396,397,398,402,403,405,406,407,409,411,416,419,421,422,423,425,426,428,433,436,439,440,443,444,445,448,457,459,461,464,465,466,467,469,470,471,472,474,475,476,477,479,483,484,485,486,488,489,490,491,492,493,495,496,501,508,512,516,517,518,523,524,532,537,538,543,545],namecolor:386,namedtupl:254,nameerror:[3,151],namelist:299,namesak:6,namespac:[48,51,137,257,270,403,459,470,509],namn:64,napoleon:120,narg:270,narr:312,narrow:[49,118,142,150,158,161],nativ:[3,42,49,58,68,77,78,120,146,158,376,459,461,543],nattempt:28,nattribut:[28,48,164,218,396,403,455,464,466,472,476,545],nattributehandl:464,nattributeproperti:[13,464],natur:[13,16,18,19,46,68,122,180,205,478],natural_height:478,natural_kei:464,natural_width:478,navbar:53,navig:[7,9,28,75,118,120,132,170,177,178,312,540],naw:[29,183,201,202,412,424,545],nbsp:491,nchar:173,nclient:447,ncolumn:478,ncurs:201,ndb:[13,14,22,28,42,44,48,76,126,128,164,204,207,228,397,406,455,466,476],ndb_:[218,403],ndb_del:455,ndb_get:455,ndb_set:455,ndk:190,nearbi:[118,211,212,213,312],nearli:[114,148,161,469],neat:[97,167,532],neatli:[69,492],necess:62,necessari:[2,11,48,60,62,69,76,86,95,97,99,118,124,130,134,135,142,147,148,156,172,174,182,199,212,213,234,257,270,275,338,372,377,402,403,445,470,476,478,479,486,488,492,501,508],necessarili:[41,68,104,118,120,134,155,191,492],necessit:458,neck:[13,41,83,286],neck_armor:13,neck_cloth:13,necklac:[83,157,286],need:[0,2,3,5,6,7,8,9,10,11,12,13,14,15,16,18,19,20,22,25,27,28,30,31,32,33,34,36,37,41,42,44,46,47,48,50,51,52,53,54,57,58,60,62,63,64,65,67,68,70,73,74,75,76,77,78,79,80,82,85,86,87,89,90,91,93,95,96,99,104,106,112,113,116,117,118,119,120,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,139,140,141,142,143,144,146,147,148,149,151,152,153,155,156,157,159,161,162,164,165,166,167,169,170,171,172,174,175,177,178,180,181,182,184,185,186,187,188,189,190,191,192,193,194,195,198,199,204,205,206,207,211,213,215,218,223,224,226,232,238,241,251,255,256,257,258,270,275,276,278,280,283,289,292,293,296,305,308,309,310,311,312,316,329,331,337,338,339,349,350,354,364,370,371,372,382,386,388,394,397,398,402,403,405,416,418,421,425,433,440,445,447,455,456,457,461,464,466,467,469,470,472,476,477,478,479,480,486,487,489,490,492,495,501,503,508,510,537,541,545],need_gamedir:416,needl:305,needless:149,neg:[136,175,211,474,492],negat:[60,146,394,495],negoti:[79,283,430,432,434,443,457],negotiate_s:432,neighbor:[130,158,338],neither:[6,13,28,162,184,199,225,343,402,440,464,467,476,493],nelson:77,nenter:28,neophyt:[112,354],nerror:64,nest:[4,13,15,22,28,30,31,106,113,204,218,350,386,393,398,403,440,473,479,545],nested_mut:13,nested_r:218,nestl:170,neswmaplink:[118,338],net:[75,134,158,180,185,189,191,205,223,230,429,430,440,443,457],netrc:11,network:[62,70,121,122,123,159,180,182,186,188,189,191,194,197,205,223,427,428,433,454,457,545],neu:241,neural:158,neutral:[30,58,93,296,479,496],never:[0,1,11,13,15,19,20,22,28,30,35,39,41,47,48,55,60,67,68,90,95,106,112,118,123,133,136,142,148,149,151,152,153,156,157,158,161,172,174,177,184,187,195,204,228,256,311,312,332,349,350,354,370,394,398,455,464,473,492],nevertheless:[0,28,67,175,215,241],new_alias:[213,396],new_arriv:372,new_attrobj:464,new_channel:[135,223],new_charact:370,new_coordin:329,new_create_dict:275,new_datastor:67,new_destin:396,new_goto:476,new_hom:396,new_kei:[45,213,396,398,405],new_loc:[218,396],new_lock:[396,405],new_menu:241,new_nam:[45,218],new_name2:218,new_obj:[33,278,280,398,403,405],new_obj_lockstr:218,new_object:[41,403],new_permiss:396,new_po:275,new_posit:275,new_progress:276,new_raw_str:210,new_room_lockstr:218,new_ros:37,new_scor:276,new_script:42,new_typeclass:[204,466],new_typeclass_path:48,new_valu:[34,464],new_word:492,newbi:[122,126],newcom:[22,158,171],newer:75,newindex:386,newli:[11,49,63,96,116,135,146,151,177,206,218,232,233,241,270,278,280,292,299,337,340,382,389,396,398,403,409,472],newlin:[22,51,225,470,478],newnam:[22,218,466],newpassword:216,newstr:51,nexist:76,nexit:[8,173],next:[0,2,3,7,14,15,20,22,27,28,29,30,31,33,37,39,42,49,50,51,52,53,54,55,58,60,64,65,67,75,76,82,86,90,95,96,97,99,102,113,118,120,123,124,125,126,127,128,129,130,132,133,135,136,138,139,141,143,144,146,147,148,149,151,152,153,154,155,156,157,158,159,161,162,164,165,170,174,177,178,180,182,186,187,189,190,191,192,193,194,199,241,247,275,278,302,308,309,310,311,312,338,371,386,394,416,470,476,477,480,492,540,545],next_nod:28,next_node_nam:28,next_stat:[275,278],next_turn:[308,309,310,311,312],nextnod:476,nextnodenam:476,nextrpi:180,nfkc:204,ng2:478,nginx:181,nice:[19,31,53,55,74,76,79,83,86,97,106,115,118,132,135,136,139,149,150,156,157,170,184,191,193,283,286,350,402,545],nicer:[144,151],niceti:218,nick:[12,13,18,24,26,32,37,72,106,134,143,180,204,205,218,223,224,232,350,397,398,428,464,465,515,545],nick_typ:36,nickhandl:[13,36,464],nicklist:[205,223,428],nicknam:[11,26,36,37,72,106,224,350,397,398,428,464,465],nickreplac:464,nickshandl:515,nicktemplateinvalid:464,nicktyp:[350,398],nifti:[150,181],night:[30,91,135,156,157,176,187,316,545],nine:63,nineti:493,nit:136,nline:485,nmisslyckad:64,nnode:338,no_act:476,no_channel:[20,22,211,476],no_db:[402,403],no_default:[48,204,466],no_exit:[20,22,164,211,364,369,476],no_gmcp:440,no_log:212,no_match:241,no_mccp:429,no_more_weapons_msg:371,no_msdp:440,no_mssp:430,no_mxp:431,no_naw:432,no_obj:[20,211,364,369,476],no_of_subscrib:502,no_prefix:[204,213,215,216,217,218,223,224,225,226,227,228,229,230,232,241,251,255,266,269,270,273,283,286,292,293,296,299,302,305,308,309,310,311,312,316,322,325,331,343,350,364,366,370,371,372,380,386,398,447,474,476,477],no_superuser_bypass:[204,232,394,398,466],no_tel:33,noansi:490,nobj:173,nocaptcha:177,nocaptcha_recaptcha:177,nocolor:[139,421,436,439,444,445],nod:157,nodaemon:7,node1:[28,476],node2:[28,476],node3:[28,476],node4:28,node5:28,node:[14,41,113,141,274,332,335,337,338,339,340,369,380,386,400,414,476,545],node_abort:28,node_apply_diff:400,node_attack:28,node_background:28,node_betrayal_background:28,node_border_char:[274,476],node_create_room:274,node_destin:400,node_end:28,node_examine_ent:400,node_exit:28,node_formatt:[28,274,380,476],node_four:28,node_game_index_field:414,node_game_index_start:414,node_guard:28,node_hom:400,node_index:[332,335,338,400,476],node_join_room:274,node_kei:400,node_loc:400,node_login:28,node_mssp_start:414,node_mylist:28,node_on:28,node_opt:274,node_or_link:[336,338],node_parse_input:28,node_password:28,node_prototype_desc:400,node_prototype_kei:400,node_prototype_sav:400,node_prototype_spawn:400,node_quest:28,node_quit:274,node_readus:28,node_select:28,node_set_desc:274,node_set_nam:28,node_start:414,node_test:28,node_usernam:28,node_validate_prototyp:400,node_view_and_apply_set:414,node_view_sheet:28,node_violent_background:28,node_with_other_nam:476,nodebox:495,nodefunc:476,nodekei:476,nodenam:[28,476],nodetext:[28,274,380,400,476],nodetext_formatt:[28,274,380,400,476],noecho:[151,228],noerror:398,nofound_str:[204,350,398,492],nogoahead:438,nohom:[396,472],nois:[125,161],noisi:[191,413,418,426,436,439,447,461],noloc:218,nomarkup:[32,139],nomatch:[76,227,241,474,492],nomatch_exit:76,nomatch_single_exit:76,nomigr:8,nomin:538,non:[11,15,16,18,19,20,22,27,29,30,31,32,39,41,42,44,48,51,53,60,67,68,74,76,86,104,109,112,118,120,122,123,124,128,131,132,135,136,140,144,146,149,150,153,156,158,161,175,186,199,204,205,206,207,209,211,223,228,230,232,234,257,278,293,322,331,340,343,354,366,371,382,386,388,389,393,396,397,398,401,402,403,406,407,409,411,416,425,439,440,454,455,457,464,466,469,472,473,474,476,477,478,479,489,492,515,518,545],nonc:444,nondatabas:[455,466],none:[3,5,12,13,14,15,16,18,20,22,27,28,30,32,33,34,36,41,42,44,46,49,54,58,60,62,65,67,68,76,86,95,97,99,112,118,123,126,129,130,131,132,133,135,136,137,139,141,142,143,145,146,149,150,153,161,164,165,170,172,174,204,205,206,209,210,211,212,213,215,218,219,220,221,222,223,224,225,226,229,232,233,234,238,239,241,242,254,256,257,260,266,270,273,274,275,276,278,280,283,286,292,294,296,305,308,309,310,311,312,316,322,325,329,331,332,335,336,337,338,339,340,343,349,350,351,354,362,364,366,369,370,371,372,380,382,386,388,389,391,393,394,396,397,398,400,402,403,405,407,408,410,411,413,414,416,418,420,422,425,426,427,428,435,436,444,445,447,455,456,457,459,460,461,464,465,466,467,469,470,471,472,473,474,475,476,477,478,479,480,483,485,487,488,489,490,492,493,496,497,500,501,502,504,505,506,508,510,512,516,518,524,527,532,537,540,543],nonpc:165,nonsens:349,noon:[33,64,95,144,162],nop:[439,545],nopkeepal:[183,439],nor:[3,7,13,14,20,64,69,89,104,115,118,128,149,158,164,175,184,251,270,343,398,402,440,464,467],norecapcha:177,norecaptcha_secret_kei:177,norecaptcha_site_kei:177,norecaptchafield:177,normal:[4,5,6,8,9,11,12,13,14,15,16,18,19,20,22,28,30,31,32,33,35,36,39,41,44,46,48,50,51,53,54,57,60,63,64,65,67,68,70,73,74,75,77,79,80,87,91,96,104,108,109,112,115,116,118,119,120,122,123,125,126,128,129,131,132,133,134,135,136,137,139,140,141,143,144,146,149,150,151,152,155,157,164,165,167,170,174,175,178,182,189,190,191,193,195,199,204,205,207,209,210,211,212,213,215,218,225,228,232,238,239,245,247,270,275,283,292,308,309,310,311,312,329,337,338,340,343,354,364,370,388,397,398,400,403,411,416,425,428,429,430,432,434,448,455,457,463,464,465,466,469,470,473,476,477,483,489,490,491,492,498,515],normal_turn_end:164,normalize_nam:398,normalize_usernam:204,north:[37,59,76,80,82,95,96,97,99,110,118,131,132,144,161,170,174,218,241,325,331,337,338,339,448],north_room:99,north_south:170,northeast:[118,144,218,329,338],northern:[76,170],northwest:[118,218,337,338,339],nose:464,nosql:78,not_don:461,not_error:416,not_found:[13,218],notabl:[5,6,11,18,54,62,75,185,213,218,229,283,420,466,469,473,492],notat:[4,53,218,469,492],notdatabas:48,note:[0,3,5,7,9,10,11,12,13,14,18,19,26,30,32,33,37,39,41,42,44,45,47,48,51,53,55,57,58,59,60,64,65,67,68,70,73,75,77,78,84,86,90,91,95,97,103,104,106,108,109,112,113,116,118,119,123,124,125,126,128,132,134,135,136,137,141,143,144,146,149,150,151,152,153,154,155,156,158,161,162,164,165,169,171,174,175,177,178,182,183,185,190,191,193,194,197,199,201,202,204,205,206,210,211,212,213,215,218,219,220,223,224,225,226,228,229,230,232,233,235,238,244,245,247,251,256,257,260,270,275,280,283,286,292,293,296,302,305,308,309,310,311,312,314,316,322,324,329,331,337,338,339,340,343,349,350,354,364,372,382,386,388,389,393,394,396,397,398,402,403,405,411,413,416,421,425,426,428,429,433,434,435,436,439,440,441,443,444,447,449,450,455,457,461,462,464,465,466,467,469,470,471,472,473,474,475,476,477,478,479,480,483,485,487,488,489,490,492,500,501,513,515,518,521,540,545],notebook:545,notepad:[154,185],noteworthi:120,notfound:492,notgm:135,noth:[3,13,15,19,22,30,37,47,54,65,69,76,95,97,99,118,119,128,133,134,136,141,143,144,149,151,153,158,161,164,170,204,218,227,308,311,312,329,338,370,386,398,409,428,464,466,476],nother:173,notic:[2,3,11,14,22,54,55,76,82,95,96,97,118,128,130,136,137,142,144,148,149,158,161,171,174,175,182,241,359,429,539],notif:[51,124,190,299],notifi:[95,153,192,197,266,292,308,309,310,311,312,372,402],notificationsconfig:124,notimplementederror:439,notion:[47,86,136,163,164,354],noun:[58,106,349,350],noun_postfix:[106,349],noun_prefix:349,noun_transl:[106,349],nov:64,now:[0,2,6,7,9,11,12,13,15,18,19,20,22,28,30,33,35,37,38,41,42,44,47,48,49,51,52,53,54,55,58,60,67,69,73,74,75,76,79,86,87,90,92,95,96,97,104,108,112,113,117,118,122,123,125,126,127,128,130,132,133,134,135,136,137,139,140,141,142,143,144,146,147,148,149,150,151,152,153,154,155,156,157,158,159,161,162,165,166,167,169,170,171,172,174,175,177,178,180,182,185,186,187,188,189,190,191,192,193,194,198,199,212,223,225,247,257,283,294,329,333,354,364,380,386,394,398,428,436,457,488,490,492,544],nowher:[151,158,170,338],noxterm256:439,npc:[13,22,28,39,75,95,96,104,123,156,162,170,283,365,366,367,393,545],npcname:172,npcshop:141,nprot:173,nr_start:408,nroom:[76,173],nroom_desc:8,nrow:478,nsmaplink:[118,337,338],nsonewaymaplink:[118,338],ntf:185,nthe:364,nuanc:60,nudg:[108,179,364,461],nuisanc:194,nulla:29,num:[30,33,132,350,398],num_lines_to_append:485,num_object:146,num_objects__gt:146,num_tag:146,num_total_account:206,number:[0,2,5,6,8,13,14,19,20,22,27,28,30,35,36,42,44,45,46,47,48,49,53,54,55,73,74,77,83,87,88,90,92,94,95,97,99,104,106,107,113,117,118,120,123,125,132,134,135,136,139,141,143,146,149,150,151,152,153,155,158,161,162,164,165,170,173,178,182,187,188,191,192,193,195,201,204,205,206,210,211,212,216,218,223,224,225,233,234,238,247,254,256,257,260,275,286,289,292,308,309,310,311,312,331,335,337,338,340,343,346,349,350,380,382,386,396,398,402,403,405,408,414,416,421,427,428,430,434,447,448,457,459,461,464,465,467,469,470,472,474,476,477,478,479,480,483,485,489,492,495,502,517,518,532,545],number_of_dummi:416,number_tweet_output:173,numberfilt:512,numbertweetoutput:173,numer:[6,94,112,156,162,337,346,353,354,469,545],numpi:449,oak:293,oakbarkrecip:293,oakwood:293,obelisk:[155,371],obfusc:[349,350,545],obfuscate_languag:[106,349,350],obfuscate_whisp:[106,349,350],obj1:[6,8,13,30,39,41,153,218,273,292,305,312],obj1_search:273,obj2:[6,8,13,30,39,41,153,218,273,292,305,312,470],obj2_search:273,obj3:[13,153,218,292],obj4:[13,153],obj5:13,obj:[3,8,12,13,19,20,22,30,33,34,36,37,41,42,46,47,48,54,58,67,76,95,112,126,133,135,140,142,143,145,146,150,153,161,171,174,204,211,212,213,216,218,224,226,228,229,233,234,239,241,242,254,256,257,260,273,275,278,286,289,292,296,299,305,308,309,310,311,312,316,329,350,354,362,364,371,372,380,386,393,394,396,397,398,403,405,406,407,408,445,447,448,455,464,465,466,467,470,472,473,477,479,487,488,489,490,492,500,501,502,505,506,508,513,515,545],obj_desc:311,obj_detail:372,obj_kei:311,obj_nam:76,obj_prototyp:403,obj_to_chang:48,obj_typeclass:311,objattr:[371,393],objclass:[483,492],object1:22,object2:[22,283,398],object:[0,2,3,4,5,8,12,14,15,16,18,20,22,23,24,26,27,28,29,30,31,32,34,35,36,39,41,45,47,48,49,51,52,54,55,57,62,65,67,68,69,72,73,74,75,76,78,79,80,82,85,86,90,91,92,93,95,96,97,99,101,104,105,106,107,108,111,112,114,115,117,118,120,121,122,125,128,129,130,131,132,133,134,135,136,137,138,139,141,142,143,147,148,154,155,157,162,164,165,171,172,173,176,177,178,180,182,194,195,199,201,202,203,204,205,206,207,209,210,211,212,213,215,216,217,218,219,220,223,224,225,226,228,229,230,232,233,234,235,238,241,242,251,254,255,256,257,258,260,266,270,271,272,273,274,276,278,280,283,286,289,292,293,296,299,305,308,309,310,311,312,316,322,325,329,331,335,337,338,339,340,350,353,354,355,359,361,362,363,364,366,368,369,370,372,376,377,378,380,382,386,388,389,390,393,394,400,401,402,403,404,405,406,407,408,409,410,411,414,416,418,420,421,422,423,425,426,429,430,431,432,433,434,435,436,438,440,443,445,447,448,454,455,456,457,459,460,461,464,465,466,467,469,470,471,472,473,474,475,476,477,478,479,483,484,486,487,488,489,490,491,492,493,496,498,499,500,501,502,504,506,508,512,513,515,517,518,523,524,526,531,532,533,535,536,537,538,540,541,542,545],object_confirm_delet:543,object_detail:[538,543],object_from_modul:492,object_id:[178,505],object_or_list_of_object:58,object_paramet:238,object_pronoun:496,object_search:[178,396],object_subscription_set:397,object_tot:[206,396,405,465],object_typ:218,object_typeclass:[490,533],objectadmin:[50,505],objectattributeinlin:505,objectcr:532,objectcreateform:[500,505],objectcreateview:[538,543],objectdb:[13,46,48,50,121,173,177,201,396,397,398,403,463,464,472,477,489,500,501,505,508,512,517],objectdb_db_attribut:505,objectdb_db_tag:[501,505,508],objectdb_set:[207,464,467],objectdbfilterset:[512,518],objectdbmanag:[396,397],objectdbseri:[515,518],objectdbviewset:[517,518],objectdeleteview:[538,543],objectdetailview:[537,538,543],objectdoesnotexist:[207,234,390,397,406,423,464,467,484],objecteditform:505,objectform:532,objectlistseri:[515,518],objectmanag:[340,396,398,465],objectnam:135,objectpuppetinlin:500,objects_objectdb:67,objectsessionhandl:[12,398],objecttaginlin:505,objectupd:532,objectupdateview:[538,543],objid:33,objlist:[30,41,479],objlocattr:[371,393],objmanip:218,objmanipcommand:218,objnam:[19,48,218],objparam:403,objs2:46,objsparam:403,objtag:393,objtyp:233,obnoxi:418,obs:466,obscur:[104,106,140,189,349,350],observ:[14,15,58,68,81,104,139,144,218,224,316,350,359,372,440,470,492],obtain:[5,22,82,97,130,142,185,191,193,241,371,545],obviou:[9,18,94,97,104,118,174,194,346,543],obvious:[15,44,69,78,95,97,122,124,132,174,467],occaecat:29,occas:9,occasion:[153,191],occat:151,occation:[158,478],occur:[3,22,42,51,54,75,126,134,227,270,310,382,394,398,410,448,476,485],occurr:[96,142,165,469],ocean:[155,191],oct:[151,152],octet:238,odd:[76,132,156,175,194,337],odor:135,off:[2,11,13,15,18,20,22,27,28,31,32,33,42,45,47,53,60,62,63,67,68,69,73,86,90,92,97,99,104,108,115,118,122,123,128,132,139,144,145,151,153,154,156,159,161,163,165,175,182,183,191,193,194,199,204,213,228,229,230,232,233,266,286,293,340,350,364,370,372,380,394,398,421,429,436,439,455,466,469,470,472,474,476,477,478,485,493,544,545],off_bal:128,offend:55,offer:[0,7,8,9,11,15,20,22,27,28,32,36,37,39,41,42,47,51,60,62,65,67,69,72,76,77,79,82,95,104,106,113,118,119,122,123,124,127,130,131,133,134,136,142,143,147,148,149,151,156,157,162,164,165,170,176,189,191,204,211,212,217,218,225,228,238,241,275,283,316,349,372,400,407,457,476],offernam:283,offici:[11,50,77,120,189,193,194,485,545],officia:29,offlin:[16,18,41,75,180,191,217,223,470],offscreen:75,offset:[49,350,474,485],often:[0,3,5,6,9,11,12,13,16,18,20,22,24,28,30,39,44,46,47,53,54,60,61,62,64,67,68,76,85,95,96,104,118,119,120,123,127,132,134,136,138,142,148,149,151,152,153,154,158,161,164,191,194,195,205,211,216,218,226,228,232,233,241,289,308,309,310,311,312,386,394,397,406,408,416,421,435,455,464,466,470,472,478,479,485,492,515,538],okai:[3,9,28,118,132,135,158,161,165,170,190,260,338],olc:[26,147,218,400,403,545],olcmenu:400,old:[5,7,9,19,20,27,28,31,33,44,48,58,60,68,75,97,103,104,120,122,125,126,130,133,135,139,141,155,158,165,170,175,185,187,191,204,211,212,215,218,233,266,280,283,317,350,394,398,403,425,465,466,469,472],old_default_set:8,old_desc:317,old_kei:[45,398],old_nam:45,old_obj:275,old_po:275,older:[12,44,53,75,123,180,183,185,218],oldnam:466,oliv:60,omit:[41,142,193],on_:241,on_bad_request:418,on_ent:[76,241],on_leav:[76,241],on_nomatch:[76,241],onam:396,onbeforeunload:51,onbuild:193,onc:[3,5,6,9,11,12,13,14,18,22,28,31,33,35,37,42,44,48,51,53,54,56,60,62,64,65,69,75,76,79,80,85,90,92,96,98,99,100,104,105,106,109,112,113,115,116,117,118,119,120,122,123,125,126,130,132,134,135,136,141,144,146,147,148,149,150,151,152,156,158,159,161,164,174,175,177,180,182,185,187,189,191,193,198,204,205,210,213,218,223,226,229,232,241,257,270,273,275,276,277,283,289,296,299,305,308,309,310,311,312,322,329,333,338,349,354,359,364,370,371,372,380,386,398,402,406,409,421,426,439,443,454,464,469,476,477,485,490,492,545],onclos:[62,427,444],onconnectionclos:51,ond:467,one:[0,2,3,4,5,6,7,8,9,11,12,13,14,15,16,18,19,20,22,25,27,28,29,30,31,32,33,35,36,37,39,40,41,42,44,46,47,48,50,51,53,54,55,56,57,58,60,64,65,67,68,69,70,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,122,123,124,125,126,127,128,131,132,133,134,135,136,137,139,140,141,142,143,144,145,146,148,149,150,151,152,153,154,155,156,157,159,161,162,164,165,167,169,170,172,174,175,176,177,178,180,182,184,185,186,187,189,191,192,193,194,195,197,203,204,207,210,211,212,213,215,216,218,223,224,227,228,229,232,233,234,238,241,250,257,260,270,275,276,278,280,283,286,289,292,293,294,296,299,308,309,310,311,312,316,329,335,337,338,339,340,343,349,350,354,364,366,369,371,372,378,382,386,388,389,390,393,394,396,397,398,400,401,402,403,405,406,411,416,418,420,421,426,427,428,436,439,440,448,455,456,457,461,463,464,465,466,467,469,470,472,473,475,476,477,478,479,480,483,484,485,487,488,489,490,492,493,496,505,518,532,533,538,545],one_consume_onli:275,ones:[15,18,19,20,22,26,30,31,32,33,35,41,60,65,73,75,76,82,124,134,135,139,143,144,150,159,164,175,186,189,191,193,194,211,212,213,234,241,257,308,309,310,311,312,388,402,403,420,425,457,469,478,486],onewai:218,ongo:[42,90,104,110,127,142,158,164,283,325],ongotopt:51,onkeydown:51,onli:[0,3,5,7,8,11,12,13,14,15,16,18,19,20,22,27,28,29,30,31,32,33,35,36,37,39,41,42,44,45,46,48,49,50,51,52,53,54,55,57,58,59,60,62,65,67,68,73,74,75,76,77,79,80,86,90,91,92,95,96,97,98,99,104,106,112,113,114,115,116,118,119,121,122,123,124,125,126,127,128,130,131,132,133,134,135,136,137,139,140,141,142,143,144,145,148,149,150,151,152,153,154,155,156,157,159,161,162,164,165,169,170,171,172,174,175,176,177,178,180,182,183,184,185,186,187,188,189,191,193,194,195,201,204,205,206,209,210,211,212,213,215,216,217,218,223,224,225,226,227,228,229,230,232,233,234,238,241,257,270,273,275,276,277,280,283,286,292,293,294,299,308,309,310,311,312,316,329,331,332,337,338,339,343,346,349,350,354,359,366,371,372,380,386,390,393,394,396,398,402,403,405,406,407,409,410,411,416,420,421,428,431,433,434,436,439,448,454,455,457,459,460,461,464,465,466,467,469,470,471,472,474,476,477,478,479,483,485,487,488,489,490,492,495,500,501,508,532,537,538,540,541,543,544,545],onlin:[9,16,18,37,53,55,69,72,82,90,92,122,123,125,134,135,137,138,148,152,154,156,158,159,160,162,163,164,165,166,168,180,182,186,188,192,195,197,198,201,215,223,232,234,241,273,380,430,470,545],onloggedin:51,onlook:[58,398],only_:354,only_nod:337,only_tim:[405,489],only_valid:403,onmessag:[62,427,444],onopen:[62,427,444],onoptionsui:51,onprompt:51,onsend:51,onset:13,ontext:51,onto:[18,20,22,51,118,122,126,131,150,156,174,189,191,212,223,293,372,397,428,473,476],onunknowncmd:51,onward:45,oob:[22,38,51,65,129,183,195,204,205,225,296,362,398,421,439,440,444,445,457,476,545],oobfunc:195,oobhandl:483,oobobject:42,ooc:[12,18,26,44,98,121,135,143,145,149,165,204,207,215,218,219,226,234,299,398],ooclook:44,oop:150,opaqu:[16,194],open:[0,3,7,10,11,20,22,26,27,31,33,39,44,52,53,59,75,76,79,82,90,92,95,96,97,104,108,109,110,118,119,120,122,123,124,134,135,137,143,144,147,149,150,151,152,158,161,162,164,165,167,170,177,178,180,182,185,186,187,188,189,190,191,194,197,218,225,228,233,238,239,241,273,275,280,283,312,322,325,331,337,364,371,380,459,464,472,485,492,544,545],open_chest:39,open_flag:275,open_parent_menu:241,open_submenu:[76,241],open_wal:371,openadventur:158,openhatch:180,opensourc:469,oper:[3,6,13,15,18,19,22,28,30,32,37,39,42,46,47,49,51,52,55,64,68,75,76,77,88,90,95,96,118,123,134,140,145,146,149,151,157,175,185,187,189,191,198,199,204,206,209,211,213,215,218,223,228,232,238,241,266,273,278,292,338,343,350,353,371,394,398,403,411,413,416,425,426,430,432,436,438,439,445,447,448,455,456,464,465,466,469,472,476,477,478,479,483,490,492,517,518,545],opic:229,opinion:[86,157],opnli:464,oppon:[162,309,311,370],opportun:[76,97,124,142,177,312],oppos:[19,37,60,194,199,455,467],opposit:[118,135,143,170,174,218,338,364],opt:[51,116,135,270],optim:[5,13,18,19,22,35,42,47,67,118,123,130,133,161,182,213,232,402,403,451,454,464],option100:28,option10:28,option11:28,option12:28,option13:28,option14:28,option1:28,option2:28,option3:28,option4:28,option5:28,option6:28,option7:28,option8:28,option9:28,option:[2,3,5,7,8,12,13,17,18,19,20,22,26,27,30,31,32,33,35,41,42,46,51,53,54,58,60,65,67,69,70,72,73,78,79,83,86,90,95,98,104,106,112,113,114,116,119,120,122,123,124,126,128,134,136,139,141,143,144,147,148,150,154,157,161,164,165,170,171,177,178,180,181,182,183,184,185,187,193,195,198,201,204,205,206,209,210,211,212,213,215,216,218,223,225,226,229,230,232,233,234,241,247,254,256,257,269,270,273,274,275,276,277,278,280,283,286,292,296,299,305,310,312,316,329,331,333,335,337,338,339,340,343,349,350,353,354,362,364,366,369,372,380,382,386,388,389,391,393,394,396,397,398,400,402,403,405,406,407,408,409,410,411,413,414,416,418,421,422,425,426,428,429,430,431,432,433,434,435,436,438,439,440,443,444,445,447,448,455,457,459,464,465,466,467,469,470,471,472,474,475,476,477,478,479,480,483,485,486,487,488,489,490,491,492,493,495,496,497,500,501,502,504,505,506,507,508,510,512,524,525,545],option_class:[201,471],option_dict:476,option_gener:476,option_kei:493,option_str:270,option_typ:487,option_valu:487,optiona:[204,413,466],optionclass:[201,202,468,471,545],optioncontain:471,optionhandl:[201,202,468,486,545],optionlist:[28,274,369,400,476],options2:51,options_dict:487,options_formatt:[28,274,369,380,400,476],optionsl:402,optionslist:369,optionsmenu:274,optionstext:[28,274,380,476],optlist:386,optlist_to_menuopt:386,optuon:349,oracl:[182,492],orang:[60,105,116,151,270,305,469],orc:[41,134,171],orc_shaman:41,orchestr:193,order:[0,2,5,9,10,11,12,13,14,15,19,20,22,27,28,30,31,33,34,36,37,39,41,42,49,50,51,54,59,64,70,75,76,82,84,86,88,92,95,97,104,114,118,123,130,131,132,135,136,137,146,148,149,150,151,155,157,158,159,164,165,169,170,174,175,177,178,182,185,188,195,198,204,209,212,213,219,224,225,228,229,238,241,244,270,275,283,286,292,293,294,305,308,309,310,311,312,337,338,340,343,350,354,370,371,372,380,382,393,394,396,398,403,427,439,444,448,455,464,466,469,470,476,477,478,485,489,490,492,500,502,504,505,506,507,543],order_bi:146,order_clothes_list:286,ordered_clothes_list:286,ordered_permutation_regex:350,ordereddict:[13,492],ordin:469,ordinari:99,ore:[158,292,293],org:[64,69,120,123,164,191,270,382,432,438,444,469,492,532],organ:[13,18,31,37,39,42,46,50,69,72,75,76,118,119,120,137,146,152,161,162,170,176,213,225,229,339,495],organiz:161,orient:[114,122,123,134,152],oriented_program:123,origin:[7,11,28,37,44,49,50,53,64,75,87,90,95,97,103,104,106,122,124,125,126,128,132,134,139,142,146,149,150,159,169,180,187,190,194,204,205,211,218,241,266,270,299,338,349,350,396,398,402,403,405,425,459,466,469,476,488,491,492,495,496,544],original_object:396,original_script:405,origo:[118,337],orm:30,ormal:469,orthogon:118,oscar:[213,232,388,390,466],osnam:492,oss:7,ostr:[204,206,233,389,396,405,489],osx:[11,185],other:[2,6,8,9,12,13,14,15,16,17,18,19,20,23,27,28,30,31,32,33,35,36,37,41,44,45,46,47,48,49,51,52,54,55,56,57,59,60,62,64,65,67,68,69,70,73,74,75,76,77,78,79,83,86,87,92,95,96,97,98,99,104,106,109,112,113,114,117,118,119,120,121,122,123,124,125,126,127,128,130,131,132,134,135,136,137,139,140,141,142,143,144,145,146,148,149,150,152,154,156,157,159,161,162,164,165,169,170,171,172,173,174,175,177,178,181,185,186,187,188,193,194,197,198,199,204,206,209,210,211,212,213,218,223,224,225,226,229,230,232,233,238,245,247,251,256,270,273,274,275,280,283,286,289,292,299,308,309,310,311,312,322,329,337,338,340,349,350,354,364,372,377,380,386,388,390,394,397,398,402,403,407,409,411,414,416,421,425,427,428,434,436,439,448,455,456,458,464,466,468,469,470,472,474,475,476,477,478,479,486,487,489,490,492,493,496,508,537,538,540,545],other_modul:147,other_obj:275,othercondit:143,othermodul:53,otherroom:[109,322],others_act:275,otherwis:[3,5,6,11,16,19,20,22,28,30,37,41,42,44,60,64,65,67,73,84,95,97,101,112,117,118,120,124,126,128,130,136,137,142,146,151,153,156,165,174,179,182,191,193,194,201,206,210,211,215,218,223,232,238,244,254,257,275,278,280,283,292,308,309,310,311,312,316,329,331,350,354,362,380,388,394,398,401,402,403,410,416,427,428,436,455,459,460,469,476,477,479,485,489,490,492,501,536,537,538,540,542],otypeclass_path:396,ought:495,our:[0,2,3,9,11,12,13,15,20,22,26,33,39,47,51,56,58,62,64,65,68,72,73,74,75,86,95,96,99,104,113,117,119,120,122,123,124,125,126,129,130,131,132,134,135,136,138,139,140,141,142,144,146,148,150,152,153,154,157,159,160,161,162,163,164,165,166,167,168,169,170,171,176,178,179,180,181,182,185,187,189,190,191,192,193,194,198,207,212,226,234,293,316,329,370,371,386,394,407,461,479,485,496,497,501,508,515,545],ourself:[150,165],ourselv:[33,36,50,58,97,135,143,144,146,150,156,158,161,172,176,204,429,430,432,443,479,496,545],out:[0,3,5,6,8,11,14,15,16,17,18,22,24,28,30,31,35,37,39,41,42,44,49,51,52,53,54,55,56,57,58,63,67,68,69,72,73,75,76,78,79,86,89,90,92,95,96,97,98,99,103,104,106,109,110,112,115,118,119,120,121,122,123,125,126,127,128,130,131,132,133,134,136,137,142,144,145,146,147,148,149,150,151,152,153,154,155,156,157,159,160,161,163,164,165,166,167,168,170,171,174,175,177,180,181,182,184,185,187,188,191,193,195,198,203,204,210,211,215,217,218,223,247,251,266,269,273,275,283,292,293,299,308,309,310,311,312,322,325,331,337,338,339,340,349,350,354,369,371,376,377,380,402,403,409,416,418,440,444,445,447,456,457,464,473,475,476,478,479,491,492,495,500,508,532,544,545],outcom:[67,120,162,211,292,343,394,398,402],outdat:[181,187],outdata:[62,457],outdoor:[46,118,155,158,176,372],outer:[146,147,478],outermost:[13,30,32,128,147,151,161,250],outerwear:[83,286],outfunc_nam:62,outgo:[30,44,68,71,118,187,191,205,338,398,428,440,456,479,492,496,545],outgoing_port:191,outlet:191,outlin:[2,26,118,170,177,427],outlist:337,outmessag:398,output:[0,5,7,9,15,19,28,29,30,31,32,44,49,51,60,62,64,68,69,70,72,73,76,82,118,120,124,135,142,143,144,148,149,151,153,154,158,164,165,170,173,174,175,180,182,193,199,201,202,213,223,225,228,230,235,241,247,292,293,296,308,309,310,311,312,337,338,374,375,377,398,416,421,436,440,448,455,469,476,477,479,485,488,490,492,545],output_nam:292,output_prototyp:[86,292,293],outputcmd:440,outputcommand:[32,65,545],outputfunc:[24,62,65,68,398,421,427,545],outputfunc_nam:[62,421],outputfunct:65,outrank:465,outright:[55,191],outro:[115,155,372],outroroom:372,outsid:[14,16,30,31,41,46,49,52,53,64,68,69,77,95,97,99,114,118,120,123,125,130,134,144,148,151,152,153,157,158,162,174,178,187,193,195,199,225,238,311,332,337,338,370,382,388,393,440,455,456,464,467,478,523,545],outtempl:464,outtxt:19,outward:[132,191],oven:[86,104],over:[2,4,5,6,8,9,13,14,15,16,17,18,19,20,22,28,41,42,44,46,47,48,49,51,53,56,60,61,62,65,68,69,70,72,88,92,95,99,104,109,118,120,127,130,132,134,135,139,141,143,146,149,150,151,152,156,158,161,162,164,169,170,172,175,177,181,184,191,193,194,204,212,233,293,308,309,310,311,312,322,338,372,380,386,398,411,420,434,436,439,441,445,447,449,462,466,470,483,488,541],overal:[49,54,67,133,134,188,191,211,226,309,545],overcom:170,overdo:149,overhead:[19,42,70,117,176,182,329,350,464],overhear:[106,349],overheard:[104,106],overlap:[20,136,349,469,478],overload:[6,20,22,28,32,37,47,62,76,109,129,131,134,150,165,169,171,195,204,211,213,227,232,241,245,270,273,292,296,305,308,309,310,311,312,316,322,325,331,350,369,370,371,372,398,403,411,420,439,447,456,474,476,477,478,486,545],overpow:158,overrid:[2,5,13,18,20,28,30,31,33,41,42,44,45,49,50,51,53,65,73,75,76,77,82,86,95,116,118,121,124,125,126,137,142,143,144,148,150,152,167,171,172,174,184,204,213,218,223,225,229,232,233,238,241,257,269,270,277,278,292,310,312,316,331,338,339,340,349,362,372,378,388,394,398,402,403,409,439,457,461,464,469,476,477,479,483,485,486,489,500,501,502,506,508,518,537,538,540,543,545],overridden:[35,53,62,118,124,169,204,218,241,242,270,338,353,402,466,477,479,500,543],override_set:45,overriden:[204,225,350],overrod:56,overrul:[12,39,204,212,350,398,478],overseen:162,overshadow:156,overshoot:492,oversight:134,overview:[0,1,5,16,50,56,96,115,119,134,138,154,157,160,163,165,182,194,545],overwhelm:[96,113,146,156],overwrit:[64,77,150,169,218,225,238,434,465,541],overwritten:[22,30,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,178,238,372,467],owasp:532,owen:292,owllex:[85,104,288,289],own:[0,4,5,8,9,11,13,14,17,18,19,20,26,28,30,31,33,36,41,42,44,45,46,48,49,52,53,54,57,58,65,67,68,69,72,73,75,76,78,83,86,89,91,95,98,100,104,106,108,113,114,115,116,117,118,119,120,122,123,124,125,126,128,129,134,136,138,139,141,142,144,147,148,149,150,152,154,155,156,157,159,160,163,165,166,167,168,169,170,174,176,177,178,179,181,185,187,188,189,190,192,194,195,201,202,207,209,210,211,212,218,226,235,247,266,270,274,275,286,299,308,309,310,311,312,316,329,337,338,341,349,350,352,371,377,380,393,394,398,403,421,448,456,466,469,470,471,477,478,483,485,486,490,492,518,538,545],owner:[33,39,57,124,141,158,182,204,394,486],owner_object:33,ownership:[77,191,193,238],oxford:492,p_id:177,p_str:126,pace:[158,370],pack:[52,65,115,425],packag:[4,5,6,8,9,31,50,68,69,73,75,77,118,119,120,123,147,148,179,181,182,185,189,190,191,193,198,201,203,208,214,231,235,278,387,392,395,404,412,416,425,440,444,463,468,498,512],package_nam:123,packagenam:123,packed_data:425,packeddict:[6,466],packedlist:[6,466],packet:[65,436],pad:[17,30,469,478,479,492],pad_bottom:478,pad_char:478,pad_left:478,pad_right:478,pad_top:478,pad_width:478,page1:275,page2:275,page:[0,2,7,8,10,11,14,15,17,20,22,23,26,28,29,30,31,35,37,48,49,50,51,52,55,56,58,62,64,68,69,72,75,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,122,123,125,126,127,134,135,138,139,143,144,147,156,157,159,162,175,177,178,180,181,182,187,189,190,191,193,194,195,197,199,200,213,218,223,224,232,275,388,390,402,445,466,476,477,492,498,503,505,506,508,521,530,534,540,541,543,544,545],page_back:477,page_ban:[55,223],page_end:477,page_formatt:[402,477],page_next:477,page_quit:477,page_titl:[537,538,540,542],page_top:477,pageno:[402,477],pager:[29,31,477],pages:[28,476],pagin:[31,49,121,402,477],paginag:477,paginate_bi:[537,538,540],paginated_db_queri:402,paginator_django:477,paginator_index:477,paginator_slic:477,pai:[133,141,158,191,194,371],paid:[159,191],pain:191,painstakingli:14,pair:[20,51,65,78,83,118,164,204,211,286,338,393,398,457,532,543],pal:36,palac:118,palett:175,pallet:170,palm:[92,380],pane:[68,230,251,340,369],panel:[7,187],panic:[41,143],pant:156,pantheon:[31,388],paper:[138,164,180],paperback:162,paperwork:118,par:182,paradigm:[75,156,172,309],paragraph:[15,19,31,119,302,470,478,492],parallel:[113,134,136,137,154,465],paralyz:310,param:[95,187,218,398,411,418,428,461,491,512,513,515],paramat:[204,213,398,455],paramet:[2,3,7,20,49,76,85,96,97,130,132,136,142,146,153,158,183,193,201,204,205,206,209,210,211,212,213,223,225,232,233,234,238,241,242,247,254,255,256,257,260,270,273,274,275,276,277,278,280,283,286,289,292,296,299,308,309,310,311,312,316,322,329,337,338,339,340,343,346,349,350,354,362,364,369,372,376,377,380,382,386,388,389,390,391,394,396,397,398,400,402,403,405,407,408,409,410,411,413,414,415,416,418,420,421,422,423,425,426,427,428,429,430,431,432,433,434,435,436,438,439,440,441,443,444,445,447,453,454,455,456,457,459,460,461,464,465,466,467,469,470,471,472,473,474,475,476,477,478,479,480,483,485,486,487,489,490,491,492,493,495,496,500,502,505,506,510,513,524,540,545],paramt:493,paremt:403,parent1:41,parent2:41,parent:[11,12,19,20,22,26,37,41,42,48,62,74,76,86,118,120,123,126,131,139,143,145,149,150,152,165,172,174,207,215,218,226,228,241,242,270,273,275,292,294,338,350,353,354,386,397,398,402,403,406,464,465,466,474,484,485,490,492,510,512,518,541,545],parent_categori:386,parent_kei:[76,241],parent_model:[500,501,502,504,505,506,508],parenthes:[50,151],parenthesi:[151,152],paretn:510,pari:[180,191],pariatur:29,paricular:22,park:[82,241],parlanc:[53,167],parri:[164,293,371],parrot:172,pars:[6,16,20,22,27,28,30,58,60,62,65,68,69,72,86,104,116,118,119,120,121,138,139,149,154,161,165,167,178,185,195,208,209,210,213,218,224,225,226,228,229,241,250,251,269,270,273,275,280,283,292,293,299,316,331,337,338,339,343,350,351,364,371,372,376,377,378,386,391,394,398,401,402,403,421,428,431,440,444,445,447,457,464,469,470,474,475,476,479,490,491,492,545],parse_ansi:469,parse_ansi_to_irc:428,parse_entry_for_subcategori:391,parse_fil:470,parse_for_perspect:280,parse_for_th:280,parse_html:491,parse_input:476,parse_irc_to_ansi:428,parse_languag:350,parse_menu_templ:[28,476],parse_nick_templ:464,parse_opt:386,parse_sdescs_and_recog:[350,351],parse_to_ani:[30,479],parseabl:[402,479],parsed_str:[30,428],parsedfunc:479,parseerror:270,parser:[22,28,31,69,71,104,116,118,120,147,178,180,195,209,210,215,218,225,226,228,230,245,251,270,273,275,293,305,316,336,337,338,349,350,371,372,402,435,469,479,491,545],parsingerror:[30,479,492],part1:305,part2:305,part3:545,part:[0,2,3,4,7,8,11,14,15,16,18,22,28,31,33,39,40,42,44,48,49,51,52,53,56,62,67,68,71,73,74,75,76,77,80,95,96,105,106,118,119,120,124,128,130,131,132,134,135,137,141,142,144,146,148,149,150,151,152,155,156,157,159,162,164,165,169,170,171,182,191,210,211,213,223,226,227,229,232,238,241,273,283,292,293,305,311,335,337,338,343,350,364,372,386,389,393,394,401,402,409,416,420,445,447,456,459,461,464,465,469,470,474,476,479,490,492,545],part_a:283,part_b:283,parth:441,parti:[3,9,14,19,30,59,75,79,88,119,123,151,152,157,159,178,181,182,189,190,191,234,283,343,479,545],partial:[31,118,126,223,225,349,388,396,402,418,431,457,487,489,492,493],particip:[104,114,194,308,309,310,311,312],participl:[495,497],particular:[5,6,11,13,14,15,20,31,32,33,37,42,44,45,46,48,55,60,62,65,68,70,73,76,91,104,112,118,120,123,127,131,135,138,141,144,146,147,148,150,151,152,153,156,157,158,161,172,174,176,180,181,187,189,190,195,204,206,210,211,218,233,276,292,310,311,316,337,338,340,377,389,393,394,405,406,457,459,466,479,483,489,539,541,544],particularli:[28,55,58,77,95,97,106,112,120,124,130,213,226,229,350,354,403,420],partit:469,partli:[13,20,67,72,104,106,147,211],party_oth:283,pass:[2,8,10,18,19,22,28,29,30,32,33,35,39,41,42,44,45,47,48,54,62,65,68,78,85,86,92,95,99,104,106,109,112,113,118,124,125,126,127,128,129,132,136,137,140,141,142,143,145,149,150,152,153,158,161,170,171,174,178,182,191,193,199,204,205,211,223,230,232,238,247,256,273,278,280,286,289,292,296,308,309,310,311,312,322,337,338,340,343,350,354,362,364,371,376,377,380,386,393,394,398,401,402,407,410,411,414,416,426,434,436,439,444,445,455,461,464,466,467,475,476,477,478,479,480,485,486,487,488,490,491,492,512,518,538,541,543,545],passabl:338,passag:[65,164,286,371,372,480],passant:175,passavataridterminalrealm:436,passiv:[128,164,177],passthrough:[20,337,409],password123:49,password1:[500,532],password2:[500,532],password:[2,5,11,25,26,28,32,33,53,55,75,78,89,100,104,107,123,124,143,148,149,154,182,185,187,194,198,204,206,215,216,230,251,275,377,382,421,436,439,460,472,500,524,532],password_chang:533,passwordresettest:533,past:[0,11,14,27,50,51,69,77,96,97,118,119,135,136,137,144,148,158,164,165,170,177,187,195,206,310,338,462,470,480,495,497,541],pastebin:119,pastpl:495,pat:396,patch:[48,49,77,490,545],patfind:335,path:[4,7,8,12,15,19,28,30,31,32,33,35,37,41,42,44,48,52,53,62,63,64,67,68,73,76,77,78,95,97,99,106,118,120,123,124,125,128,130,137,141,144,145,146,149,151,152,154,161,165,169,171,172,174,178,181,185,187,191,193,204,205,207,210,211,212,213,217,218,219,220,221,222,223,232,234,238,239,241,247,257,260,266,273,275,276,277,278,280,283,286,292,296,305,308,309,310,311,312,316,322,325,329,331,335,337,338,339,340,343,349,350,359,362,364,366,369,370,371,372,382,388,390,396,397,398,402,403,405,406,408,409,411,416,423,425,434,441,447,449,453,457,461,464,465,466,470,472,474,475,476,477,479,480,483,484,489,492,510,518,538,545],path_or_typeclass:260,pathdata:331,pathfind:[104,331,335,337,338,545],pathnam:490,patient:28,patreon:119,patrol:[115,370],patrolling_pac:370,patron:99,pattern:[18,36,56,73,74,124,137,167,177,178,216,350,460,464,492,509],pattern_is_regex:464,paul:48,paus:[28,42,54,95,96,130,164,193,199,218,228,256,409,410,476,490,492,545],pausabl:492,pauseproduc:418,pax:545,paxboard:180,payload:[427,444],payment:[79,104,158],paypal:119,pdb:[201,545],pdbref:[33,393],pdf:180,peac:171,peek:[0,28,118,142,144,149],peer:[427,444],peform:421,peg:194,pem:187,pemit:[69,216],pen:138,penalti:[67,156,310,545],pend:461,pennmush:[69,72,134,230],pentagon:194,peopl:[0,6,12,18,30,31,33,53,58,60,69,89,90,95,104,106,119,122,123,125,135,139,141,144,146,148,156,157,158,159,161,162,164,180,184,188,189,191,194,197,223,224,233,251,350,371,372,472,501,508],pep8:[0,77],per:[5,11,12,13,18,22,30,37,41,44,57,61,65,67,77,85,86,87,91,97,104,106,112,114,118,120,123,124,135,136,137,151,157,158,161,164,165,193,204,223,238,275,276,289,308,309,310,311,312,316,337,338,349,354,370,396,398,402,429,430,432,440,443,459,476,477,478,483,485,486],perceiv:[136,158],percent:[22,235,341,352,492,545],percentag:[112,164,353,354,465,492],percentil:492,perception_method_test:452,perfect:[11,27,77,122,156,157,161,190,193,238,337],perfectli:[42,46,72,124,137,469],perform:[3,5,6,13,14,15,18,28,29,32,33,37,42,58,76,80,82,85,86,92,95,103,104,113,114,122,126,130,142,151,164,165,171,177,178,182,188,190,194,204,209,211,215,218,223,225,241,256,257,266,273,286,289,292,308,309,310,311,312,335,350,376,380,386,396,398,402,406,407,420,425,439,447,448,464,465,466,473,476,477,479,486,489,492,493,532],perhap:[3,6,18,56,69,76,95,96,136,137,142],period:[8,9,10,151,191,193,194,492],perist:48,perm1:467,perm2:467,perm:[13,18,22,31,33,39,41,46,55,57,76,95,124,126,135,141,143,149,165,177,188,207,216,217,218,223,224,225,228,255,266,273,305,316,322,331,372,390,393,394,397,398,406,464,466,467,492],perm_abov:[33,39,393],perm_us:216,perma:158,permadeath:158,perman:[18,28,53,55,77,118,124,155,156,183,191,215,218,223,224,228,349,410,466,545],permiss:[5,8,12,13,18,20,41,49,50,55,61,63,69,75,77,80,124,125,126,144,149,161,165,177,181,182,188,190,201,202,204,206,207,211,213,215,216,217,218,223,224,226,232,255,276,312,350,388,390,393,394,396,397,398,402,403,406,464,465,466,467,470,472,479,485,489,492,498,500,511,512,515,518,543,545],permission_account_default:[39,447],permission_class:518,permission_func_modul:393,permission_guest_default:63,permission_hierarchi:[39,57,393,394,467],permissiondeni:513,permissionerror:402,permissionfilt:512,permissionhandl:[39,177,467],permissionshandl:[508,515],permit:[179,182,218,460],permstr:[33,204,396,466,472],permut:350,perpetu:[5,545],perri:77,persion:58,persis:128,persist:[18,19,20,22,28,34,37,42,44,47,48,67,76,85,97,104,106,108,110,112,114,122,123,125,126,133,134,138,141,145,148,150,151,154,157,164,165,174,180,195,199,204,207,211,212,228,233,234,241,242,247,257,274,289,308,309,310,311,312,325,339,349,350,354,364,369,371,380,386,390,396,397,398,400,402,405,406,407,409,410,411,421,422,423,454,455,459,463,466,472,474,476,478,480,492,545],persit:35,person:[11,18,30,44,55,58,72,77,79,106,125,143,156,157,159,162,172,185,191,204,218,223,224,232,238,275,276,280,283,343,350,479,495,496,497,545],persona:31,perspect:[44,58,162,280,496],pertain:[169,175,194],pertin:177,perus:51,peski:141,pester:[134,156],petal:120,peter:273,pg_ctlcluster:182,pg_hba:182,pg_lscluster:182,phantom:31,phase:[132,156],philosophi:[33,151,275,545],phone:[56,104,107,123,190,382],phone_gener:[107,382],phonem:[106,349],php:[69,123,532],phrase:[95,96,260],phrase_ev:[95,260],physic:[12,35,132,156,311,370,545],pick:[7,14,16,20,22,25,28,30,31,33,42,53,58,75,90,95,118,119,122,125,130,136,141,144,150,151,154,157,158,161,162,170,176,189,191,193,195,210,215,218,224,226,250,286,312,346,350,371,372,398,402,448,479],pickl:[13,47,50,65,118,128,239,354,407,411,413,423,425,426,464,465,473,474,476,488,492],pickle_protocol:488,pickledfield:[396,488],pickledformfield:[488,501],pickledobject:488,pickledobjectfield:488,pickledwidget:488,picklefield:[201,202,468,501,545],pickpocket:225,pickup:[312,398],pictur:[7,62,125,134,545],pid:[2,11,33,50,177,193,199,393,398,416,426,492],piddir:2,pidfil:416,pie:273,piec:[5,14,35,53,54,86,90,105,123,150,151,157,187,292,293,305,443,470,477],piecem:104,pierc:371,pig:[292,293],piggyback:204,pigironrecip:[292,293],piglei:77,pii:78,pile:[212,470],pillow:190,pinch:158,ping:[205,223,416,428],pink:469,pip:[0,3,5,6,8,9,10,75,77,118,120,147,151,177,182,185,186,188,190,192,193,198,201,545],pipe:[44,78,428,473],pitfal:[0,15,60,175],pixel:[53,183],pizza:[207,234,390,397,406,464,466,467],pkg:190,pki:181,place:[0,9,12,13,15,16,18,28,33,35,37,41,42,44,49,52,53,64,65,66,72,73,75,79,82,86,92,95,96,97,104,112,115,118,122,123,124,125,126,129,132,136,137,142,144,147,148,150,151,153,158,161,162,165,167,169,170,174,175,176,177,181,185,188,190,191,193,194,195,204,216,218,224,232,241,247,275,283,286,293,305,308,309,310,311,312,329,337,338,340,350,354,364,371,372,376,380,398,405,409,425,434,439,455,456,457,464,470,471,473,476,492,545],placehold:[52,53,64,178,394,398,478],plai:[12,15,31,44,53,57,60,65,76,96,97,104,108,114,115,122,123,128,130,135,138,139,142,151,154,155,156,157,159,161,162,164,165,170,174,176,177,190,191,198,204,206,308,312,440,457,472,545],plain:[14,15,67,68,79,120,135,144,165,223,232,241,283,302,403,421,447,473,541],plaintext:377,plan:[3,15,16,18,48,62,75,95,122,133,138,146,150,153,154,160,163,166,168,191,193,470,545],plane:[118,153,174],planet:[136,148,180],plank:86,plant:[116,270],plate:[28,48,53,104,107,140,382],platform:[7,11,56,75,95,133,185,191],playabl:[158,177,533],player1:398,player2:398,player:[5,6,8,13,18,20,28,30,33,39,42,44,46,50,52,53,54,55,57,58,62,64,65,69,70,75,76,77,78,79,90,91,92,94,95,98,104,105,106,113,115,116,117,118,121,122,123,125,126,128,135,139,141,142,144,145,148,149,150,151,152,154,155,156,157,160,162,163,164,165,166,168,170,171,172,173,174,177,184,186,188,191,192,198,199,212,215,218,228,233,238,241,260,266,270,273,274,275,276,278,283,299,305,311,312,329,337,346,349,350,364,366,372,377,380,386,389,406,430,439,456,470,475,476,492,518,532,538,545],playercmdset:95,playernam:188,playerornpc:75,pleas:[0,5,8,11,17,20,28,31,41,48,56,60,78,115,119,124,144,150,158,161,170,171,172,173,177,179,181,185,188,189,190,191,228,418,447,483,488,532],pleasur:56,plenti:[15,72,122],plop:53,plot:449,plu:[0,7,19,76,123,228],pluck:22,plug:[35,45,169,194,329],plugin:[62,65,69,77,104,121,124,147,148,180,189,195,238,350,414,545],plugin_handl:51,plugin_manag:51,plural:[39,57,58,135,311,398,479,495,496],plusmaplink:[118,338],png:[40,53,169],pocoo:492,poeditor:64,poet:146,point:[2,3,5,6,7,10,11,12,14,15,16,19,20,22,28,30,31,35,37,41,42,44,46,47,48,50,53,58,65,67,68,70,73,76,79,89,90,93,95,97,99,100,104,114,118,120,122,124,125,126,128,130,132,133,136,137,138,139,141,142,143,144,148,149,150,151,152,156,158,159,162,164,165,166,169,174,177,178,181,185,187,190,191,193,195,198,204,209,213,218,223,226,270,273,283,289,292,296,308,322,329,331,335,337,338,350,372,398,400,402,411,416,420,434,436,444,455,457,464,466,470,476,479,492,501,508,521,543,545],pointer:[0,132,133,142],pointless:[37,47,54,225],poison:[13,104,112,157,310,354,403],pole:305,polici:[26,77,152,191,194,377,390,460,464,545],polish:64,polit:[152,158,194],poll:[62,169,215,370,416,445],pommel:[158,293],pong:428,pool:[20,47,182,411,461,473],poor:[58,135],poorli:194,pop:[7,54,120,126,135,141,182],popen:426,popul:[2,73,76,95,99,134,136,139,156,182,211,219,220,221,222,241,273,286,292,305,308,309,310,311,312,316,322,325,331,350,364,366,369,370,371,372,398,410,411,447,470,474,475,477,501,508],popular:[69,75,114,123,134,146,154,180,194,197,537],popup:51,port:[2,5,75,97,122,154,181,182,184,185,187,189,193,199,205,223,425,428,436,448,457,461,545],portal:[5,7,9,24,37,43,51,52,62,68,84,121,147,148,174,180,191,194,195,199,201,202,205,228,244,412,413,416,454,455,456,457,480,485,492,545],portal_connect:457,portal_disconnect:457,portal_disconnect_al:457,portal_l:426,portal_pid:[426,492],portal_receive_adminserver2port:426,portal_receive_launcher2port:426,portal_receive_server2port:426,portal_receive_statu:426,portal_reset_serv:457,portal_restart_serv:457,portal_run:416,portal_service_plugin_modul:62,portal_services_plugin:[62,148,195],portal_services_plugin_modul:62,portal_sess:62,portal_session_sync:457,portal_sessions_sync:457,portal_shutdown:457,portal_st:416,portal_uptim:480,portallogobserv:485,portalsess:[44,62,434,545],portalsessiondata:457,portalsessionhandl:[62,201,202,412,424,435,457,545],portalsessionsdata:457,portion:[77,104,238,241,346],portuges:64,pos:[275,338],pose:[26,58,104,106,128,135,143,157,158,164,204,224,257,273,350,364],pose_transform:232,posgresql:182,posit:[14,28,42,51,76,95,99,104,114,116,118,130,132,142,144,152,157,164,170,175,212,230,238,241,251,270,273,275,302,312,329,337,338,340,371,372,398,410,469,470,473,474,478,492,493],position:275,position_prep_map:275,positive_integ:493,positiveinteg:486,posix:[485,492],possess:[58,93,296,479,496],possibl:[0,5,9,13,18,20,22,27,28,30,31,32,33,35,41,42,44,46,50,52,53,54,60,63,75,76,78,79,95,96,97,99,104,106,111,112,115,117,118,119,120,122,123,126,130,134,135,142,146,147,148,151,152,155,157,158,159,161,162,164,165,169,170,175,178,182,185,190,193,195,201,204,206,207,209,211,218,225,226,233,238,245,256,275,283,292,305,316,329,337,338,340,349,350,354,366,370,372,391,394,396,398,401,402,403,407,411,421,441,445,455,457,464,465,467,469,472,474,475,476,478,480,488,489,492,495,510],post:[18,20,33,45,49,53,64,78,86,104,119,122,134,135,137,154,156,169,170,173,177,185,188,192,377,409,445,517,538,545],post_craft:[86,292],post_delet:45,post_init:45,post_join_channel:[18,232],post_leave_channel:[18,232],post_migr:45,post_mov:398,post_sav:45,post_send_messag:232,post_text:346,post_url_continu:[500,502,505],postfix:[106,349],postgr:[123,182],postgresql:[492,545],postgresql_psycopg2:182,postinit:51,posttext:380,postupd:[173,188],pot:[55,145],potato:[116,183,270],potenti:[0,13,14,30,54,60,65,86,95,104,106,140,152,157,158,164,165,170,191,192,213,225,233,377,378,393,394,398,402,486,489,492],potion:[153,157,158,275,466],pow:30,power:[3,16,20,22,27,28,30,35,37,39,41,50,51,53,57,58,85,95,96,104,106,113,116,122,123,128,129,133,135,144,146,150,151,152,153,155,157,158,161,164,165,170,211,212,217,218,270,289,311,386,391,470,476,492],powerattack:[85,289],powerfulli:97,ppart:495,pperm:[18,33,39,55,149,177,188,215,223,266,305,393,398],pperm_abov:[39,393],pprofil:416,pprogram:416,practial:16,practic:[0,2,14,15,22,37,42,44,50,76,97,123,128,134,135,149,150,151,152,153,157,158,161,175,185,187,191,338,470,545],pre:[22,37,49,132,156,158,170,184,185,188,191,204,218,225,292,349,394,398,402,403,444,445,448,474,479,488],pre_craft:[86,292],pre_delet:45,pre_init:45,pre_join_channel:[18,232],pre_leave_channel:[18,232],pre_migr:45,pre_sav:[45,488],pre_send_messag:232,pre_text:346,preced:[20,39,41,57,60,113,118,161,211,213,386,398,403,465,478,479,496],preceed:[30,144],precend:209,precis:[13,42,95,175,289,292,469],predefin:[174,460],predict:[48,151,159,177],prefer:[7,11,18,20,22,33,41,51,76,119,122,125,134,142,148,150,154,165,170,182,188,191,211,213,216,241,309,338,350,370,389,391,396,398],prefix:[3,6,18,48,67,76,106,182,194,204,210,225,227,232,346,349,396,421,428,459,469,479,485,489,492,501,502,504,506,508,512,532,545],preload_metadata:238,prelogout_loc:149,prematur:[5,19,42,283],premis:[90,273],prep:273,prepai:191,prepar:[36,41,52,118,132,134,167,204,223,308,309,310,311,312,350,370,406,473,488,545],prepars:120,prepend:[299,350,398,469,470,476,479,492],prepopul:[501,508,541,543],preposit:275,preprocess:218,prerequisit:[2,75,545],prescrib:[122,134,157],presen:30,presenc:[17,30,75,118,122,133,148,149,169,175,182,191,204,398,461,498],present:[3,6,28,31,44,49,53,76,92,94,96,104,113,114,124,132,136,137,141,142,156,157,164,165,181,195,241,270,346,349,366,380,382,386,403,474,492,495,497,501,515],present_participl:497,preserv:[175,226,466,469,470,485,492],preset:479,press:[0,3,7,15,16,20,22,28,33,65,68,75,76,82,104,108,144,148,151,154,185,193,199,241,275,364,371,414,476,505],pressur:140,presto:144,presum:[35,136,162,212,485,486],pretend:190,pretext:380,pretti:[0,11,13,22,37,42,50,58,68,76,83,95,97,120,123,126,130,141,149,151,152,155,156,164,165,174,175,177,189,191,213,232,280,286,354,382,387,394,402,475,477,486,492],prettier:[5,97,532],prettifi:[134,492],prettili:136,pretty_corn:478,prettyt:[19,140,478],prev:[28,161,477],prev_entri:28,prevent:[22,95,96,120,136,144,151,238,256,270,312,459,501,538,545],preview:120,previou:[3,11,13,15,20,22,28,29,30,31,33,36,45,49,53,54,56,60,67,76,95,112,113,128,135,136,137,141,142,143,146,147,149,150,151,155,158,161,163,165,175,193,195,223,354,372,386,400,476,477,485,540],previous:[20,27,32,42,53,60,99,118,132,142,144,150,169,177,187,189,195,213,216,218,223,232,283,339,421,437,441,448,457,467,492],previu:42,prgmr:191,price:[77,158,191,238,371],primadonna:31,primari:[11,17,48,149,177,193,350,396,398,464,489],primarili:[2,11,12,55,69,79,119,120,122,156,157,204,283,350,389,391,434,473,492],primary_kei:177,prime:[79,209,283],primer:[53,54],primit:[158,218],princess:[155,170],princip:159,principl:[0,8,12,18,22,28,30,33,35,37,50,57,58,62,75,79,86,90,104,119,120,129,134,141,146,148,149,152,157,158,165,176,191,192,212,215,283,372],print:[0,3,4,5,6,13,19,27,42,48,54,62,67,70,75,106,112,120,124,125,126,135,142,146,149,151,152,199,215,270,337,339,343,349,354,402,415,416,475,476,477,478,485,492],print_debug_info:476,print_error:339,print_help:270,print_stat:5,print_usag:270,printabl:442,printable_order_list:337,printout:[152,439],prio:[20,22,126,149,209,372,467],prior:[171,256,398],priorit:[118,338,349,467],prioriti:[6,20,22,28,41,118,124,126,131,161,164,211,215,219,220,221,222,226,241,273,369,371,372,398,474,476,477,545],prison:[146,156,545],privaci:78,privat:[11,18,78,120,124,134,137,156,158,181,182,191,223,224,428,441],private_set:75,privatestaticroot:461,priveleg:150,privileg:[22,118,125,156,165,182,185,186,189,192,224,329,340,350,398,466,545],privkei:187,privkeyfil:436,privmsg:428,prize:155,proactiv:47,probabl:[5,9,22,28,31,37,42,49,50,53,56,67,69,76,77,82,95,96,112,118,122,123,124,125,126,128,134,137,141,149,158,161,164,169,174,177,178,182,191,225,238,241,242,260,354,372,382,418,428,436,483,492,493],problem:[0,2,6,8,13,14,16,19,22,26,33,70,74,76,119,123,125,126,133,137,138,143,151,153,156,158,159,161,170,182,183,187,190,191,193,194,199,204,212,257,292,337,398,425,470,479,545],problemat:[126,492],proce:[15,16,64,174,175,193,223,443,536,538],procedur:[113,386,436,439],proceed:[11,492],process:[0,2,3,5,7,11,13,14,15,16,22,28,30,35,37,40,49,52,53,64,65,68,75,76,86,95,97,99,118,119,120,123,124,126,128,130,132,142,148,151,156,158,160,161,162,177,181,182,187,190,191,193,204,209,211,218,228,232,270,283,292,293,333,350,356,386,392,394,398,402,407,410,416,421,425,426,433,436,439,444,445,448,454,455,457,464,469,470,473,476,486,491,492,493,510,545],process_languag:350,process_recog:350,process_sdesc:350,processed_result:492,processor:[24,26,104,158,166,170,199,201,202,217,228,229,468,545],procpool:492,produc:[11,18,22,28,31,60,80,95,106,157,159,165,215,218,250,275,280,292,293,305,329,349,371,398,402,403,415,447,464,466,475,476,492],produce_weapon:371,producion:19,product:[0,2,5,7,9,11,52,53,73,182,191,194,197,447,450,476,545],production_set:75,prof:5,profess:146,profession:[69,123,134,151,158,159,167],profil:[1,92,186,201,202,207,380,412,545],profile_templ:[92,380],profunc:41,prog:[270,495],program:[0,5,7,8,9,12,16,18,30,40,49,52,54,67,69,121,123,130,133,134,147,148,151,152,155,159,160,161,180,182,185,187,190,191,193,194,199,228,230,270,412,416,439,445,447,545],programiz:130,programm:[142,154,159],progress:[90,104,114,141,162,180,276,278,289,308,309,310,311,312,338,474],proident:29,project:[16,69,73,119,123,124,126,132,142,159,169,170,180,189,486,544,545],projectil:311,promin:31,promis:0,promisqu:175,prompt:[0,3,48,51,65,68,75,94,113,120,123,138,151,154,170,182,183,184,185,190,193,198,213,346,386,414,428,439,444,445,470,476,490,545],promptli:15,pron:[30,398,479,545],prone:[9,212,466],pronoun:[30,58,93,201,202,296,398,468,479,494,497,545],pronoun_to_viewpoint:496,pronoun_typ:[58,479,496],pronounc:280,pronount:496,prop:[156,479,545],propag:[181,211,420,488],proper:[2,13,16,19,30,31,51,58,73,79,106,123,125,130,131,133,134,141,142,156,158,161,164,165,177,182,193,194,218,241,258,283,349,398,475,479,490,496],properi:225,properli:[7,9,10,11,30,34,48,69,74,75,78,128,135,136,137,171,175,177,213,238,283,335,372,378,393,410,411,436,492,503],properti:[4,6,8,14,31,33,34,36,39,41,42,47,53,58,67,76,85,86,95,104,112,121,122,126,130,133,134,139,143,147,149,153,158,162,164,165,170,174,175,195,199,204,205,207,213,215,218,226,228,229,232,234,238,241,254,256,270,273,275,276,289,292,293,305,308,310,311,312,329,331,338,339,340,350,353,354,364,370,371,372,380,386,388,390,391,393,394,396,397,398,402,403,406,408,409,410,420,421,423,428,434,447,448,455,456,457,464,466,467,471,473,476,479,486,487,488,489,490,492,500,501,502,504,505,506,507,508,515,532,540,542,545],property_nam:396,property_valu:396,propnam:165,propos:27,proprietari:182,propval:165,propvalu:165,prose:159,prosimii:[177,178],prospect:[156,292],prot:403,prot_func_modul:[41,401],protect:[5,20,78,191,218,293,364],protfunc:[201,202,399,402,403,479,545],protfunc_callable_protkei:401,protfunc_modul:402,protfunc_pars:402,protfunct:402,protkei:[41,401,402],proto:[425,436],proto_def:305,protocol:[19,22,24,32,40,44,51,61,65,121,123,147,148,159,180,183,189,191,194,195,199,204,205,213,216,296,362,377,398,412,413,416,418,421,425,426,427,428,429,430,431,432,434,435,436,438,439,440,441,443,444,445,447,454,455,456,457,474,488,492,545],protocol_flag:[438,439,443,455],protocol_kei:456,protocol_path:[434,457],protodef:305,prototocol:228,protototyp:[400,402,403],protototype_tag:41,prototoyp:401,prototyp:[24,30,86,96,105,121,147,148,156,173,201,202,218,235,292,305,309,310,314,330,337,338,339,371,545],prototype1:403,prototype2:403,prototype_:41,prototype_desc:[41,403],prototype_dict:218,prototype_diff:403,prototype_diff_from_object:403,prototype_from_object:403,prototype_kei:[41,86,118,218,292,402,403],prototype_keykei:218,prototype_lock:[41,403],prototype_modul:[41,118,218,334,402,403],prototype_pagin:402,prototype_par:[41,118,218,334,403],prototype_tag:403,prototype_to_str:402,prototypeevmor:402,prototypefunc:403,protpar:[402,403],protpart:402,provid:[2,6,8,13,17,18,22,30,31,39,41,42,48,49,50,51,52,53,55,56,58,69,71,76,77,83,85,86,94,95,97,99,104,105,113,117,120,122,124,126,128,137,142,150,151,152,153,157,158,161,167,169,175,177,178,187,190,191,193,194,204,213,218,223,230,232,238,241,242,255,269,270,275,286,289,292,305,308,309,310,311,312,329,337,346,380,382,386,388,393,398,401,409,416,436,459,465,467,476,479,486,487,488,490,492,493,517,518,532,538,541,543],provok:[3,180],prowl:31,proxi:[48,147,187,194,197,238,461,501,508,545],proxypass:181,proxypassrevers:181,prudent:2,prune:20,pseudo:[62,69,104,106,132,142,349,381,382,545],psionic:311,psql:182,pstat:5,psycopg2:182,pty:75,pub:[223,232],pubkeyfil:436,publicli:[11,53,158,180,184],publish:[2,125,180,193],pudb:[201,545],puff:133,pull:[2,9,20,22,30,52,53,119,120,123,126,148,159,169,193,260,371,418,540,545],pummel:155,punch:[20,115,143],punish:[158,312],puppet:[6,12,20,22,26,32,33,39,44,45,50,57,62,75,76,86,95,98,125,130,134,135,136,149,165,172,177,203,204,209,215,218,226,234,292,299,331,393,398,455,457,466,467,500,505,533,538,540,545],puppet_object:[12,204],puppeted_object:500,purchas:[141,187],pure:[48,60,68,96,133,158,175,187,406,416,464,469],pure_ascii:492,purg:[13,48,199,228],purpos:[13,40,46,58,65,90,124,146,152,165,175,177,187,191,205,209,213,256,280,338,343,436,464,473,476,479,492,496],pursu:[155,370],push:[76,95,108,120,150,175,193,194,260,275,364,371,545],pushd:185,put:[3,7,8,12,14,15,22,27,28,33,36,37,39,41,44,48,49,53,54,55,57,60,65,67,72,73,77,83,85,86,90,95,96,97,113,118,119,120,123,125,126,132,134,135,141,143,144,148,150,151,153,156,157,159,161,162,164,165,167,169,170,174,177,180,182,191,194,195,197,212,215,216,218,220,224,239,280,286,289,292,293,308,309,310,311,312,346,350,359,380,386,394,425,439,477,478,492,545],putobject:77,putobjectacl:77,putti:191,puzzl:[86,90,115,155,180,201,202,235,281,292,371,372,545],puzzle_desc:371,puzzle_kei:372,puzzle_nam:305,puzzle_valu:372,puzzleedit:305,puzzlerecip:[105,305],puzzlesystemcmdset:[105,305],pvp:[156,545],pwd:[5,193],py3:425,py3k:77,pyc:148,pycharm:[1,120,154,545],pyflak:0,pylint:0,pyopenssl:186,pypath:492,pypath_prefix:492,pypath_to_realpath:492,pypi:[5,123,180,191,469],pypiwin32:[75,185],pyprof2calltre:5,pyramid:[117,329],pyramidmapprovid:[117,329],pyself:157,python2:[6,75,185],python37:185,python3:[185,190,354],python3_properti:123,python:[3,5,6,7,8,9,10,12,13,15,16,19,20,22,27,28,30,31,33,35,37,41,48,49,50,52,53,54,55,57,60,63,64,67,69,70,71,73,75,76,77,78,80,88,96,97,104,116,117,118,120,121,123,124,125,128,130,132,133,135,136,137,138,140,141,142,143,144,145,146,147,149,150,153,154,157,158,159,160,161,162,163,164,165,166,167,168,170,172,177,178,182,185,186,189,190,191,192,193,194,195,198,199,210,212,217,218,222,228,229,241,254,255,256,257,258,260,270,292,329,339,343,382,388,394,396,397,401,403,405,408,411,416,418,425,429,434,444,455,457,461,463,465,466,469,470,472,473,474,475,476,478,479,480,483,485,488,490,492,510,515,521,544,545],python_execut:123,python_path:[152,212,492],pythonista:180,pythonpath:[212,416,426,470],pytz:493,q_lycantrop:146,q_moonlit:146,q_recently_bitten:146,qualiti:[78,104,156,158,210],queen:118,quell:[12,26,109,115,143,144,149,151,155,161,174,215,322,393,545],quell_color:218,queri:[11,30,41,46,49,56,65,67,85,104,118,123,130,133,138,153,154,161,207,223,225,234,289,340,350,389,390,391,396,397,398,402,403,406,423,436,451,464,465,466,467,477,479,484,489,492,493,545],query_al:464,query_categori:464,query_info:416,query_kei:464,query_statu:416,query_util:512,queryset:[42,46,123,206,233,276,299,339,340,389,396,402,405,422,465,477,489,501,508,512,518,537,538,540,543,545],queryset_maxs:477,querystr:512,querystring_auth:238,querystring_expir:238,quest:[95,104,111,122,134,138,155,156,157,159,163,171,185,372,545],question:[0,8,11,22,27,28,54,73,76,100,104,134,156,158,159,160,162,181,185,187,191,218,397,413,414,464,474,476,490,492],queu:416,queue:[2,164,461],qui:29,quick:[6,20,22,35,42,46,69,74,76,80,82,86,95,104,105,120,122,130,142,151,152,156,164,180,191,197,205,218,241,349,388,403,421,464,467,478,517,545],quicker:[36,67,97,158],quickli:[9,13,16,22,28,35,37,46,54,60,67,82,102,104,106,118,126,130,158,159,169,173,197,218,241,278,280,349,467,470],quickstart:[6,64,67,135,151,190,191,193,195,199,544,545],quiescentcallback:418,quiet:[118,126,141,153,204,216,218,223,241,266,286,331,350,398,477,492,545],quiethttp11clientfactori:418,quietli:[30,65,68,128,464],quirk:[1,13,183,212,545],quit:[3,5,9,12,17,22,26,27,28,44,54,62,76,82,92,95,96,97,115,118,120,122,124,125,129,130,134,141,143,144,146,149,151,152,153,155,158,161,177,182,184,187,190,215,230,241,242,251,256,273,278,311,380,436,474,476,477],quitfunc:[27,474],quitfunc_arg:474,quitsave_yesno:474,quo:47,quot:[13,19,25,27,33,41,151,157,172,182,218,230,251,350,474,476,488,492],qux:[113,386],ra4d24e8a3cab:25,rabbit:158,race:[122,133,156,162,171,177,180,181,492,545],rack:[293,371],radio:[18,158],radiu:[130,132,170],rafal:77,rage:[112,155,354],ragetrait:[112,354],rail:[123,174],railroad:174,railwai:338,rain:[42,155,158,176],raini:372,rais:[13,16,19,22,30,41,54,65,86,95,137,142,146,162,178,204,205,206,233,238,241,247,254,256,257,292,316,337,338,339,340,343,349,350,354,382,394,396,401,402,411,415,416,434,439,445,460,464,465,467,469,470,472,475,476,478,479,485,486,487,488,490,492,493,513],raise_error:[30,479,487,492],raise_except:[13,292,464],ram:[13,191],ramalho:180,ran:[2,3,14,28,151,409],rand:42,randint:[30,41,86,95,99,142,149,162,164,165,173,308,309,310,311,312,403,479],random:[25,28,30,41,42,75,81,86,95,96,99,104,106,142,144,149,155,157,158,162,164,165,173,176,191,195,250,280,293,308,309,310,311,312,329,349,359,360,364,371,372,381,382,383,403,447,448,479,492,545],random_string_from_modul:492,random_string_gener:[107,201,202,235,374,545],randomli:[5,42,67,99,173,176,308,309,310,311,312,364,370,371,416,448,479],randomstringgener:[107,382],randomstringgeneratorscript:382,rang:[3,5,20,27,41,68,92,99,104,112,114,118,130,132,133,142,144,155,157,164,170,172,173,183,185,194,218,247,309,312,335,337,340,353,354,380,465,474,479,532,543],ranged_attack:293,rank:[57,393],raph:180,rapidli:212,rapier:146,raptur:440,rare:[7,9,22,47,54,58,67,76,99,120,185,195,223,339,394,396,472],rascal:46,rase:294,rate:[5,22,85,104,119,123,157,191,223,235,289,341,352,411,416,435,492,545],ratetarget:[112,157,353,354],rather:[0,6,8,9,11,12,13,14,22,31,37,42,46,47,53,67,72,73,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,122,123,126,128,130,134,142,144,148,151,153,154,157,158,161,164,167,170,178,187,188,195,199,204,207,211,215,218,219,225,226,228,232,256,266,283,302,308,309,310,311,312,338,339,346,350,354,387,398,400,402,403,464,466,469,478,487,488,491,501,508,541],ration:[79,157,283],raw:[13,22,32,41,55,60,65,67,120,123,133,144,151,152,154,158,167,204,210,213,218,226,227,229,270,350,354,377,398,421,436,439,444,445,455,464,469,474,476,486,492],raw_cmdnam:[143,210,227],raw_desc:316,raw_id_field:[502,505,506],raw_input:[28,141,476],raw_nick:36,raw_str:[22,28,141,143,204,205,209,210,213,274,369,380,386,398,400,455,464,476,490],raw_templ:36,rawhid:293,rawhiderecip:293,rawstr:[213,229],rcannot:76,rdelet:218,re_bg:491,re_bgfg:491,re_blink:491,re_bold:491,re_color:491,re_dblspac:491,re_double_spac:491,re_fg:491,re_format:469,re_hilit:491,re_invers:491,re_mxplink:491,re_mxpurl:491,re_norm:491,re_str:491,re_ulin:491,re_underlin:491,re_unhilit:491,re_url:491,reach:[28,36,64,68,76,118,130,143,144,155,161,162,174,191,201,213,254,312,338,354,380,436,440,459,476,477,489,544],reachabl:[47,123,337],react:[28,47,52,95,171,172,370,398],reactiv:228,reactor:[427,454,461,490],read:[5,8,9,11,13,14,16,17,19,20,22,28,30,31,33,35,41,44,49,53,56,64,67,68,75,76,77,82,86,90,94,95,96,97,104,107,112,115,118,119,120,122,123,124,126,128,130,133,135,137,141,142,143,144,146,147,148,149,150,151,152,155,157,158,159,161,165,175,177,178,180,181,182,188,189,191,194,195,198,204,207,217,224,225,234,238,241,260,275,299,316,337,338,346,350,354,371,372,382,388,390,397,398,402,403,406,423,425,448,464,466,467,470,471,475,477,484,485,492,500,537,540,545],read_batchfil:470,read_default_fil:2,read_flag:275,read_only_field:515,readabl:[5,19,47,48,60,69,95,120,132,225,239,275,292,337,371,469,476,540],readable_text:371,reader:[32,94,120,135,139,161,177,180,192,223,312,346,421,435],readi:[2,3,5,7,11,12,16,33,37,54,55,62,85,90,119,126,128,144,148,149,159,169,174,184,185,190,204,213,289,308,309,310,311,312,350,398,445,477,486,492],readili:[170,182],readin:475,readlin:[238,485],readm:[10,11,15,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,98,99,100,101,102,103,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,148,235,238,377],readonly_field:[500,502,505,506],readonlypasswordhashfield:500,readthedoc:[180,512],real:[3,4,5,11,12,19,20,30,37,41,48,54,63,69,76,90,95,96,106,114,120,122,125,130,135,136,146,151,152,158,162,164,165,166,170,175,185,187,189,191,193,199,207,212,234,247,283,293,310,338,339,349,350,393,447,470,479,480,545],real_address:12,real_nam:12,real_seconds_until:[247,480],real_word:349,realist:[5,158,159,176,275],realiti:[5,122,125,133,156,170,175,180],realiz:[11,149,175],realli:[0,3,4,9,13,14,15,18,20,22,28,30,33,37,42,46,47,49,54,55,57,69,76,90,95,104,113,115,116,118,123,124,126,130,135,136,141,142,143,144,149,150,152,153,157,159,161,170,172,174,187,189,192,195,199,213,229,241,270,283,338,386,394,425,469,470,476,488,490],really_all_weapon:146,realm:436,realnam:37,realpython:54,realtim:[135,148,247],realtime_to_gametim:[87,247],reason:[5,6,7,11,13,14,18,28,31,33,35,36,37,39,41,42,47,50,55,60,62,65,67,72,75,76,86,89,106,112,118,119,120,123,126,128,130,131,132,133,134,135,137,140,143,149,150,156,158,159,161,162,164,175,181,185,187,194,195,204,216,218,223,228,251,266,276,292,337,338,349,354,382,396,398,402,407,413,418,425,426,427,428,434,435,436,439,444,445,447,455,456,457,466,474,479,485,492,543],reasourc:41,reassign:132,reattach:[7,427,428],reboot:[9,13,19,26,27,34,42,44,47,67,77,84,112,122,127,148,164,187,191,193,198,204,212,223,228,244,289,354,370,371,380,398,406,407,409,411,416,456,457,474,476,545],reboot_evennia:416,rebuild:[9,118,135,185,187,193,339,428],rebuilt:[22,118,187,337],rec:350,recach:372,recal:[371,537],recapcha:545,recaptcha:177,receipt:[78,194,418],receiv:[3,18,20,22,28,29,30,35,36,44,51,52,61,65,70,86,119,135,142,148,177,204,211,212,230,232,233,234,251,276,299,337,350,354,377,398,418,421,425,427,428,434,444,445,447,454,455,472,477,479,489,490,492,502,545],receive_functioncal:425,receive_status_from_port:416,receiver1:490,receiver2:490,receiver_account_set:207,receiver_extern:234,receiver_object_set:397,receiver_script_set:406,recent:[17,53,124,126,146,165,187,206,459],recently_bitten:146,recev:445,recip:[47,97,104,105,127,158,201,202,235,281,291,294,305,545],recipe_modul:292,recipe_nam:292,recipebread:86,recipenam:86,recipes_pot:292,recipes_weapon:292,recipi:[18,30,35,86,135,204,232,233,299,398,425,479],reckon:75,recoc:157,recog:[36,106,157,350,545],recog_regex:350,recogerror:350,recoghandl:350,recogn:[8,32,37,56,143,144,152,158,178,185,191,199,350,354,461],recognit:[58,104,106,159,350,464],recommend:[0,2,5,11,13,28,37,41,48,55,67,68,69,73,75,114,118,119,120,122,126,135,137,138,145,151,156,158,162,180,182,183,185,191,198,228,256,270,337,346,376,394,396,398,418,470,476,489],reconfigur:191,reconnect:[89,100,204,205,223,232,413,416,425,427,428,454,457],reconnectingclientfactori:[413,427,428,447],record:[16,78,165,182,191,312,377,459,532],record_ip:459,recours:55,recov:[19,112,127,128,133,308,309,310,311,312,354,394,492],recoveri:164,recreat:[9,42,148,170,182,185,205,212,339,470,471],rectangl:475,rectangular:[135,475],recur:123,recurs:[13,95,338,393,402],red:[14,15,20,36,39,41,53,60,80,104,118,120,144,148,150,151,152,175,218,228,275,363,364,371,469,479,493,545],red_button:[14,15,36,108,144,148,201,202,218,229,235,355,545],red_kei:39,red_ros:146,redbutton:[14,15,36,108,144,148,218,364],redd:194,reddit:194,redefin:[22,37,76,122,398,532],redhat:[185,187],redirect:[44,53,62,73,76,137,148,177,181,241,275,278,476,534,538,543],redirectlink:338,redirectview:538,redit:[82,241],redmapnod:118,redo:[27,151,152,156,474],redraw:436,reduc:[164,308,309,310,311,312,429],reduced_redund:238,reduct:[77,238],redund:469,reel:212,reen:[60,469],ref:[48,120,182,350,398,492,532],refactor:[134,398,495,544],refer:[7,10,11,13,14,20,22,28,30,36,37,41,42,44,48,53,57,58,62,67,68,72,75,76,77,79,86,95,96,97,99,104,106,107,112,119,123,132,133,134,136,137,138,143,146,148,149,150,151,152,154,157,158,159,162,164,170,175,177,178,180,181,191,193,195,199,204,212,218,223,227,232,266,278,283,293,308,309,310,311,312,331,337,340,350,354,380,382,393,398,407,408,410,411,418,428,448,456,465,476,479,483,488,489,492,501,508,543,544,545],referenc:[37,41,50,104,106,120,133,195,213,218,223,232,238,337,350,388,390,466,492,545],referenti:492,referr:191,refin:[132,293],reflect:[151,155,157,543],reflex:[58,479,496],reflow:56,reformat:[403,478,485],reformat_cel:478,reformat_column:[170,478],refresh:[0,53,118,178,436,459],refus:[18,55,158],regain:128,regard:[175,382,512,545],regardless:[8,20,22,39,44,48,55,57,58,65,135,139,156,162,174,204,211,232,275,283,296,350,398,411,433,436,439,454,456,464,467,470,483,485,492],regener:310,regex:[18,22,27,28,36,51,53,78,84,213,216,228,229,244,350,382,460,464,476,492,521],regex_nick:36,regex_tupl:350,regex_tuple_from_key_alia:350,regexfield:500,region:[74,118,135,191,216],region_nam:238,regist:[11,51,52,53,65,73,95,118,164,173,177,186,188,194,195,197,204,206,223,228,260,289,370,371,407,416,427,428,434,457,459,461,469,479,517,523,533,536,545],register_error:469,register_ev:[95,260],registercompon:51,registertest:533,registr:[49,186,536],registrar:187,registri:[382,459,461,545],regress:402,regul:394,regular:[8,11,17,18,22,31,35,42,44,47,50,52,58,73,78,79,83,95,104,105,107,118,120,137,144,145,146,148,151,152,156,161,167,176,178,180,191,205,211,286,305,338,372,382,388,394,411,464,467,479,483,492,496,521,544,545],regulararticl:484,regulararticle_set:484,regularcategori:484,regularli:[9,95,141,173,176,187,192,247,277,370,372,409,411,419,449,480],reilli:180,reimplement:[87,104],reinforc:180,reiniti:199,reinstal:185,reinvent:134,reject:[92,95,380,382],rejectedregex:382,rejoin:18,rel:[11,14,15,20,28,31,50,54,57,76,99,104,117,118,120,132,140,158,165,177,195,247,275,312,470,476,545],relai:[19,22,44,189,204,223,283,296,337,398,434,457,476,477,492],relat:[18,20,22,28,31,48,51,53,104,112,118,127,133,134,146,148,149,152,158,161,176,180,189,194,195,199,207,208,211,226,231,233,234,247,260,274,275,276,308,309,310,311,312,314,337,338,354,369,372,377,390,397,398,405,406,411,421,457,464,466,467,469,476,484,485,498,500,501,508,515,525,532,545],related_field:[500,501,502,504,505,506,508],related_nam:[207,234,390,397,406,464,466,467,484],relationship:[35,48,132],relay:205,releas:[75,77,119,122,127,148,159,179,180,185,191,228,496,544,545],relev:[13,15,22,33,37,45,46,48,50,53,60,73,74,75,76,79,112,118,119,120,129,135,136,161,164,165,167,177,180,204,209,211,241,283,292,338,354,394,408,430,448,455,456,457,469,474,476,486,501,508,545],relevant_choic:241,reli:[8,28,47,60,67,68,73,75,93,95,104,106,136,139,141,142,153,158,175,296,350,354,372,416,466,476,545],reliabl:[14,48,126,128,182,483],reliant:99,religion:[31,388],reload:[0,2,3,7,9,12,13,14,15,19,20,22,25,26,27,28,31,32,40,42,44,47,48,50,52,53,55,57,62,63,73,76,86,89,90,91,95,97,100,102,103,106,110,112,118,125,127,128,130,131,134,135,136,137,139,143,148,149,150,151,161,162,164,165,167,169,171,172,174,177,178,185,186,187,188,192,195,204,205,212,217,218,228,232,241,251,257,266,302,316,325,329,337,339,350,354,371,372,388,394,396,398,405,407,409,411,416,425,426,428,430,454,457,461,464,470,472,474,475,476,480,492,545],reload_evennia:416,reluct:158,remain:[6,13,14,20,22,27,28,41,42,45,57,70,90,106,112,129,135,142,148,149,150,161,191,199,210,212,218,220,224,247,278,292,308,309,310,311,312,316,349,354,370,398,416,444,445,476,477,492],remaind:[22,125,247],remaining_repeat:42,remap:[151,464],remark:545,rememb:[1,5,6,8,9,11,13,14,20,22,28,31,39,41,46,47,51,53,55,60,67,68,76,95,97,118,124,125,127,128,130,132,133,135,136,137,142,149,151,153,155,156,157,158,159,161,165,170,175,184,185,191,216,218,256,338,398,407,470,489,545],remind:[27,97,120,124,545],remit:216,remnisc:134,remot:[126,187,193,194,197,223,238,425,427,439,545],remov:[2,9,11,13,18,19,20,23,27,28,30,31,34,36,37,39,42,47,55,75,76,77,78,90,97,106,107,108,112,118,122,124,125,130,135,137,139,141,142,143,148,149,155,158,164,169,177,192,201,211,212,216,218,223,224,225,228,229,232,234,241,254,258,266,275,280,286,293,305,308,309,310,311,312,316,338,339,349,350,353,354,364,380,382,386,394,397,398,403,407,410,411,416,434,445,457,459,464,467,469,473,476,483,488,490,491,492,518,545],remove_alia:223,remove_backspac:491,remove_bel:491,remove_charact:164,remove_default:[20,212],remove_map:339,remove_non_persist:405,remove_object:339,remove_receiv:234,remove_send:234,remove_user_channel_alia:[18,232],removeth:464,renam:[5,26,75,135,139,143,144,151,152,161,169,218,224,398,405,466],render:[45,52,53,76,94,120,137,139,167,169,177,178,225,346,461,486,488,500,501,502,504,505,506,508,515,521,530,532,543],render_post:445,renew:[128,135,187,459],repair:[125,156,545],repeat:[3,5,68,87,95,97,104,107,136,151,156,158,164,169,170,172,174,190,199,204,205,247,277,283,382,386,405,406,409,416,421,440,464,472,476,480,492,545],repeatedli:[3,15,32,136,148,277,370,406,409,411,416,421,447,525],repeatlist:32,repetit:[136,164,382],replac:[2,13,18,20,22,27,28,30,31,32,33,36,37,41,44,49,51,58,60,73,75,76,77,79,84,89,92,95,102,103,104,106,118,120,126,128,129,134,137,138,143,148,151,153,154,157,161,164,169,170,178,182,187,193,195,204,210,211,212,213,216,224,225,228,229,232,244,251,254,257,266,270,274,280,283,289,292,302,305,316,337,338,349,350,364,369,372,380,394,398,400,402,403,428,431,444,445,455,464,469,474,475,476,477,478,479,491,492,521,523,545],replace_data:478,replace_timeslot:316,replace_whitespac:478,replacement_str:224,replacement_templ:224,replenish:[308,309,310,311,312],repli:[22,28,79,158,186,205,283,299,414,438,439,445,457,476],replic:[76,159,169,467],replica:[11,149],repo:[7,11,64,119,120,134,147,156,180,492,545],repoint:53,report:[0,5,6,8,11,22,26,34,42,47,76,86,95,106,115,118,119,142,153,156,158,161,162,164,169,182,183,185,190,194,195,206,218,223,254,257,270,292,338,350,398,416,421,428,431,432,439,440,444,447,455,457,469,472,476,492],report_to:[206,396,405,472],repos:545,repositori:[2,10,64,75,77,119,120,126,147,179,181,182,185,193,403,545],repositri:64,repr:[142,492,540],reprehenderit:29,repres:[12,20,22,30,31,35,37,44,45,48,53,58,62,67,70,75,76,92,94,95,96,97,99,104,106,107,109,112,118,121,123,125,126,132,133,136,137,143,144,146,147,148,149,150,152,154,159,164,169,175,177,204,209,233,254,260,270,278,286,310,322,337,338,339,346,349,350,354,371,372,377,380,382,386,388,398,403,410,411,413,427,428,444,445,455,456,457,461,464,465,469,471,472,476,477,478,479,488,492,495,518],represen:149,represent:[12,13,30,35,36,44,62,67,68,70,123,127,135,149,162,175,233,254,257,337,350,396,402,406,425,444,445,467,473,480,515],reprocess:194,reproduc:[54,118,338,398],repurpos:77,reput:[156,376,545],reqhash:[465,492],reqiur:[92,380],request:[0,28,33,45,49,52,53,62,73,79,119,137,148,152,165,167,177,178,181,185,191,194,204,205,216,257,283,289,398,402,416,418,425,428,430,435,436,438,445,461,467,476,500,501,502,503,505,506,508,512,513,518,523,524,525,526,530,537,539,540,543,545],request_finish:45,request_start:45,requestavatarid:436,requestfactori:461,requestor:[204,459],requir:[0,2,5,8,15,16,22,27,28,30,31,33,34,37,39,41,47,48,49,50,51,52,53,54,59,67,72,75,76,77,78,86,90,95,96,99,100,102,104,107,113,118,119,120,124,132,135,137,141,143,156,158,159,161,164,169,170,172,175,176,177,178,179,180,181,182,184,187,188,190,191,197,199,206,217,218,223,233,234,238,251,266,270,289,292,293,302,310,311,316,337,338,340,343,350,354,372,380,382,386,389,393,396,398,402,410,416,427,428,441,449,460,465,470,475,476,477,478,479,483,487,488,489,492,500,501,502,504,505,506,508,532,538,545],require_al:[39,467],require_singl:402,requirements_extra:[0,77,118],requr:41,requri:[402,479],rerout:[52,215,219,428,509],rerun:[14,15,28,118,292],research:[158,180,256],resembl:[72,122,126],resend:22,reserv:[22,30,54,143,149,151,170,402,460,465,479,492],reserved_keyword:30,reserved_kwarg:[30,479],reset:[16,17,19,20,22,26,27,42,44,48,55,60,63,95,97,106,112,128,131,139,143,148,157,162,164,165,170,174,175,182,195,204,205,212,218,228,247,257,273,275,289,350,353,354,371,394,416,420,426,436,454,464,467,470,478,479,480,490,492,545],reset_cach:[464,467],reset_callcount:42,reset_gametim:[19,480],reset_serv:420,reset_tim:316,reshuffl:545,resid:[69,147,394],residu:[228,310],resist:[403,492],resiz:[52,135,475,478],resolut:[112,158,164,337,354],resolv:[0,3,11,90,120,128,138,151,152,158,159,164,191,195,305,308,309,310,311,312,515],resolve_attack:[308,309,310,311,312],resolve_combat:164,resort:[22,120,135,184,223,350,492],resourc:[0,8,47,49,52,53,69,73,75,77,104,112,119,120,121,127,133,143,146,147,148,149,150,151,152,153,158,169,182,191,194,204,311,336,354,391,407,414,445,461,471,490,544,545],respawn:[118,156,545],respect:[22,33,42,44,48,49,86,95,97,98,104,105,110,118,135,150,161,165,182,195,216,218,225,283,292,299,305,325,350,394,398,455,456,466,467,470,472,478,489,492,496,532],respond:[28,34,45,65,96,97,101,104,148,156,171,172,175,199,443,447],respons:[5,17,28,30,31,49,52,53,54,56,68,119,123,132,141,142,172,173,174,185,191,204,205,212,213,223,232,292,329,372,388,390,398,414,416,418,425,447,448,457,466,486,488,492,515],response_add:[500,502,505],resport:492,respositori:119,rest:[7,17,18,22,28,30,36,42,52,53,67,77,112,120,128,133,140,141,148,149,151,152,155,156,158,162,165,170,185,195,198,210,226,227,308,309,310,311,312,354,464,469,478,512,513,515,516,517,518,545],rest_api_en:[49,52],rest_framework:[49,512,513,514,515,516,518],restart:[0,3,7,9,26,40,42,51,55,64,73,84,88,95,135,149,152,164,182,187,191,194,195,199,201,204,228,232,241,244,257,343,398,405,407,409,410,411,420,433,454,455,456,492,545],restartingwebsocketserverfactori:[205,427],restock:141,restor:[20,97,175,241,293,311,407,411],restrain:[112,218,354,393,475,492],restrict:[13,33,41,47,48,51,57,83,95,107,124,144,147,148,153,157,162,170,178,181,191,218,266,286,311,312,337,382,388,389,394,396,403,405,472,474,476,478,489,545],restructur:[120,133],result1:305,result2:[28,305],result:[6,8,11,13,19,20,22,28,30,31,33,41,44,47,49,52,54,58,60,64,68,73,78,80,83,86,88,92,99,105,106,107,112,118,120,129,131,135,142,143,146,147,149,150,151,153,157,158,161,162,164,165,169,172,175,178,182,191,195,204,206,210,211,213,218,225,232,234,275,283,292,293,294,305,308,309,310,311,312,337,338,343,349,350,354,372,376,380,382,389,391,394,396,398,402,403,405,416,425,447,464,466,469,474,475,476,478,479,483,485,486,489,490,492,493,495,510,540],result_nam:305,resum:[22,118,128,161,410],resurrect:370,resync:[205,425,455],ret1:479,ret:[22,490],ret_index:492,retain:[6,19,20,31,41,53,54,64,93,152,170,233,296,354,388,390,403,462,466,470,472,479,485,492,496],retain_inst:213,retext:120,retract:283,retreat:312,retri:416,retriev:[6,18,22,32,46,49,67,69,74,95,97,112,118,137,165,204,207,209,212,218,223,228,229,233,256,316,331,338,354,389,393,397,402,414,421,422,428,434,443,464,467,473,483,487,489,492,497,512,513,517,518,537,540,543,545],retriv:[205,471],retro:18,retroact:[48,135],retur:29,return_alias:338,return_appear:[118,132,165,275,276,286,316,340,350,362,371,398],return_apper:[340,398],return_cmdset:225,return_detail:[316,372],return_dict:388,return_iter:402,return_key_and_categori:467,return_list:[30,464,467,479],return_map:170,return_minimap:170,return_obj:[13,36,464,467,487],return_par:403,return_prototyp:173,return_puppet:204,return_str:[30,337,479],return_tagobj:467,return_tupl:[36,343,464],returnvalu:[22,54],reus:[151,153,266,483],rev342453534:492,reveal:[95,118,155,286],reveng:159,reverend:[77,104,238],revers:[20,22,53,58,60,95,117,128,130,170,174,175,178,207,223,234,329,337,353,390,397,406,461,464,466,467,469,484,518],reverseerror:[416,425],reversemanytoonedescriptor:[207,397,484],reverseproxyresourc:461,revert:[11,53,175,191,215,389],review:[9,20,73,97,119,123,143,157],revis:156,revisit:[2,476],reviu:28,revok:135,revolutionari:11,reward:[115,163],rework:[100,104,128,149,156],rewrit:53,rfc1073:432,rfc858:438,rfc:[432,438],rfind:469,rgb:[60,151,469],rgbmatch:469,rgh:151,rhel:181,rhello:30,rhost:230,rhostmush:[69,72,134],rhs:[126,135,226,229],rhs_split:[218,224,226],rhslist:226,ricardo:492,riccardomurri:492,rich:[76,77,134,179,180,473],richard:180,rick:41,rid:[133,150],riddanc:55,riddick:[92,380],ride:174,right:[0,3,4,5,9,15,22,28,30,32,33,36,41,42,49,51,52,53,54,64,77,86,91,92,95,96,97,104,117,118,120,122,125,126,127,128,130,133,134,135,141,142,143,146,147,148,149,151,152,155,156,159,161,165,170,171,174,175,177,178,181,182,185,187,190,191,212,215,218,226,228,230,232,238,257,258,269,273,275,292,305,312,316,329,337,338,346,364,370,371,372,380,394,403,406,456,469,470,474,478,492,493],right_justifi:41,rightmost:[118,338],rigid:134,rindex:469,ring:[106,153,349],ringmail_armor:13,rink:77,rise:[20,136],risen:136,risk:[30,52,120,134,156,158,165,185,191,217,228,492],rival:170,rjust:[30,469,479],rm_attr:218,rnormal:60,rnote:228,road:[20,96,170,174,211],roam:[155,212,370],roar:170,robot:177,robust:[141,142,194],rock:[67,95,99,164,212],rocki:155,rod:212,rodrigo:77,role:[17,77,104,114,122,134,142,150,156,162,182,308,545],roleplai:[31,75,102,104,122,134,156,157,162,164,165,180,343,348,350,545],roll1:162,roll2:162,roll:[28,86,95,104,114,135,142,152,157,158,162,164,165,185,308,309,310,311,312,342,343,459,545],roll_challeng:162,roll_dic:343,roll_dmg:162,roll_hit:162,roll_init:[308,309,310,311,312],roll_result:343,roll_skil:162,roller:[88,104,157,158,162,164,292,343,545],rom:[180,545],roof:218,room1:8,room2:8,room56:14,room:[3,8,13,14,15,16,18,19,20,22,23,33,35,41,42,46,48,49,50,55,58,69,72,74,75,76,82,88,90,95,96,99,104,106,109,110,111,114,116,117,118,121,122,123,125,131,133,134,136,141,142,144,145,146,148,149,150,151,152,153,155,161,162,164,165,170,171,172,173,174,176,177,185,195,201,202,209,210,211,212,216,218,224,229,235,241,256,270,271,272,273,274,275,277,278,280,286,308,309,310,311,312,315,316,322,325,329,331,332,334,337,338,339,340,343,350,355,364,366,368,369,370,371,393,398,406,420,448,470,490,512,518,533,545],room_desc:[8,99],room_dict:99,room_flag:133,room_lava:133,room_replac:273,room_typeclass:[317,329,490,533],room_x_coordin:118,room_y_coordin:118,room_z_coordin:118,roombuildingmenu:[76,82,241],roomnam:[135,218],roomref:174,rooms_with_five_object:146,roomstat:275,roomviewset:518,root:[0,2,4,5,6,7,9,10,14,33,37,53,58,67,73,75,76,77,120,123,137,139,147,169,178,179,182,185,187,190,191,193,201,202,371,398,403,416,461,473,498,511,523,545],rose:[13,36,37,48,145,146,153],rostdev:191,roster:[75,157,308,309,310,311,312],rosterentri:75,rot:8,rotat:[18,148,275,485],rotate_flag:275,rotate_log_fil:485,rotatelength:485,rough:[120,156],roughli:[135,156,492],round:[5,17,30,106,112,289,312,349,354,447,478,479],rounder:[106,349],rout:[51,104,118,132,133,144,174,204,331,337,338],router:[191,514,517,545],routerlink:118,routermaplink:[118,338],routin:[106,350,396,451,489,492],row:[51,56,60,67,97,120,123,132,135,137,146,164,167,170,175,337,340,478,492],rowdi:99,rpcharact:350,rpcommand:350,rpg:[88,94,106,112,114,119,135,138,148,149,156,162,201,202,235,312,545],rpi:180,rplanguag:[106,157,201,202,235,341,348,350,545],rpm:185,rpobject:350,rpsystem:[58,102,106,120,157,201,202,235,302,341,545],rpsystemcmdset:[106,350],rred:469,rsa:[436,437],rspli8t:142,rsplit:[165,469],rss2chan:[26,143,192,223],rss:[9,180,197,201,202,205,223,231,412,421,424,434,545],rss_enabl:[192,223],rss_rate:205,rss_update_interv:223,rss_url:[192,205,223],rssbot:205,rssbotfactori:435,rsschan:223,rssfactori:435,rssreader:435,rst:545,rstop:218,rstrip:[142,469],rsyslog:376,rtest2:60,rtext:[141,479],rthe:76,rthi:[60,151],rtype:461,rubbish:215,rubbl:118,rubi:123,rudimentari:[115,370],ruin:[155,316,372],rule:[4,11,14,15,22,33,55,60,95,104,106,112,122,125,135,148,152,156,157,163,175,180,241,293,308,309,312,349,354,382,390,470,545],rulebook:[158,164],rumor:31,rumour:155,run:[0,2,5,6,9,10,11,12,13,14,15,16,18,19,20,25,28,30,31,33,40,41,42,47,48,49,50,51,52,53,54,62,64,67,71,75,77,80,81,90,95,96,97,115,118,120,121,123,125,126,127,128,133,134,136,137,139,141,142,143,144,146,148,149,150,151,152,154,155,156,157,158,159,161,162,165,167,169,170,174,175,176,177,178,180,181,182,183,184,185,187,189,191,194,195,198,199,201,204,205,209,210,212,213,217,218,224,225,228,229,232,245,257,258,266,274,292,308,309,310,311,312,317,325,329,337,338,350,369,376,386,393,394,398,402,403,405,406,409,410,411,416,420,422,426,433,434,441,445,447,450,454,455,459,461,466,469,470,474,476,477,479,480,485,489,490,492,518,543,544,545],run_async:[54,492],run_connect_wizard:416,run_custom_command:416,run_dummyrunn:416,run_evscaperoom_menu:274,run_exec:476,run_exec_then_goto:476,run_init_hook:454,run_initial_setup:454,run_menu:416,run_option_menu:274,run_start_hook:[48,466],rundown:154,runexec:476,runexec_kwarg:476,runnabl:41,runner:[2,5,7,229,371,447,545],runsnak:5,runsnakerun:5,runtest:[229,239,242,245,248,252,258,267,269,279,284,287,290,294,297,300,303,306,313,317,323,326,328,335,344,347,351,353,360,367,373,378,383,385,442,452,484,490,497,516,527,533],runtim:[19,22,55,136,213,241,270,480,492],runtimeerror:[162,204,205,254,257,260,292,336,339,349,354,382,402,434,464,476,479,492],runtimewarn:[336,402],rusernam:28,rush:128,russel:77,russian:64,rusti:[49,58,141],ruv:2,ryou:76,s3boto3storag:[77,238],s3boto3storagefil:238,s3boto3storagetest:239,s3boto3testcas:239,sad:[177,439,476],sadli:230,safe:[0,6,11,20,37,52,53,79,96,104,118,123,129,133,140,157,158,177,187,195,197,204,215,283,394,411,425,457,461,466,470,473,479,483,492,545],safe_convert_input:492,safe_convert_to_typ:[30,492],safe_ev:492,safe_join:238,safer:[14,55],safest:[44,97,191,466],safeti:[11,12,37,48,79,104,133,157,165,191,218,283,397,470,545],sai:[0,5,8,9,13,15,17,18,19,20,22,26,28,33,37,39,41,48,50,51,53,54,55,60,62,72,74,76,77,79,92,95,96,97,106,112,113,118,123,126,128,130,131,133,134,135,136,137,142,143,144,146,149,151,152,157,158,159,161,162,164,165,171,172,175,179,185,191,212,224,232,260,273,275,283,343,349,350,354,364,372,380,386,398,476,479],said:[0,28,46,54,65,76,95,96,97,124,131,132,134,142,149,151,157,158,170,172,178,210,223,227,329,337,350,398,428,464,466,476],sake:[14,73,134,151,156,158,159,175,230,251,542,543],sale:141,salt:[86,292],same:[0,3,5,6,7,8,9,11,12,13,14,15,16,18,19,20,22,27,30,31,32,33,34,35,37,39,41,42,44,46,47,48,50,52,53,54,55,56,57,58,60,62,63,64,65,67,68,69,70,75,76,77,80,87,90,95,97,99,104,106,107,111,112,113,117,118,119,120,122,123,125,127,128,131,133,134,135,136,137,139,141,142,143,144,146,147,148,149,150,151,152,153,158,159,161,162,164,165,169,170,174,175,177,178,179,182,185,187,191,192,193,195,198,199,204,209,210,211,212,213,216,218,223,226,227,228,229,230,233,238,239,241,247,256,257,270,275,276,280,286,289,292,299,308,309,310,311,312,316,322,329,331,338,340,346,349,350,354,366,370,372,382,386,388,393,398,402,403,406,407,411,420,425,437,440,441,455,456,457,459,461,464,465,466,467,469,470,472,476,477,478,479,480,485,486,490,492,495,501,508,518,532,543,545],sampl:[2,113,133,181,193,386],san:346,sand:[136,293],sandi:170,sandwitch:86,sane:[1,118,120,156,180,338,543],sanit:[532,543],saniti:[8,75,118,132,151,170,486],sarah:[72,224],sat:[74,125,275],satisfi:[69,226,464],satur:194,sauc:151,save:[2,3,6,11,16,19,22,27,28,34,35,36,37,41,42,44,45,46,47,48,50,53,67,75,76,77,78,95,96,97,106,123,125,128,133,143,145,148,149,151,164,165,177,183,184,187,193,194,199,204,215,218,228,232,234,239,241,257,289,349,394,397,398,400,402,403,407,409,410,411,414,421,434,449,454,461,464,466,473,474,483,486,487,488,492,500,501,502,505,506,508,545],save_a:[502,504,505,506,507],save_as_new:[501,508],save_buff:474,save_data:486,save_for_next:[22,213],save_handl:486,save_kwarg:487,save_model:[500,502,505,506],save_nam:411,save_on_top:[502,504,505,506,507],save_prototyp:402,save_recip:305,savefunc:[27,474,487],savehandl:487,saver:473,saverdict:473,saverlist:473,saverset:473,saveyesnocmdset:474,savvi:159,saw:[54,86,95,96,137,149,151],say_text:172,saytext:350,scale:[7,50,60,106,120,134,148,156,162,182,349,544],scalewai:191,scam:158,scan:[118,181,209,337,338,340,370,372],scarf:[83,286],scari:[149,151],scatter:[310,470],scedul:87,scenario:[135,335],scene:[6,13,32,41,46,60,95,107,122,125,152,155,158,162,164,175,354,372,382,406,411,483],schedul:[19,85,87,95,104,136,247,257,289,410,480],schema:[48,67,123,124,492,545],schemaless:78,scheme:[22,60,67,90,127,151,185,218,228,469],schneier:77,school:158,sci:118,scienc:132,scientif:180,scipi:[118,338],scissor:164,scm:75,scope:[32,50,95,122,123,128,156,157,158,161,178,250,382,405,472],score:[135,276,492,545],scott:77,scraper:538,scratch:[9,10,53,62,96,112,134,135,157,158,165,169,185,274,339,354,420],scream:155,screen:[6,22,24,28,29,31,32,41,42,44,56,60,63,89,94,100,118,139,141,148,150,177,193,195,230,250,251,312,346,421,436,477,479,492,500,545],screenheight:[32,421],screenread:[26,32,230,421,444,445],screenshot:177,screenwidth:[32,213,421],script:[2,5,7,8,10,13,14,15,19,24,26,30,33,34,35,37,41,44,45,46,47,48,49,51,67,69,79,80,91,104,105,107,110,117,118,121,122,133,134,136,141,143,144,147,148,149,153,155,158,159,164,171,173,176,177,185,188,191,194,195,199,201,202,204,205,217,218,228,233,234,235,236,247,253,254,260,271,272,283,305,308,309,310,311,312,316,325,329,339,349,358,359,364,372,382,397,398,402,403,416,449,454,470,471,472,479,480,487,489,490,492,498,499,512,515,518,523,533,545],script_copi:405,script_search:405,script_typeclass:[360,490,533],scriptadmin:506,scriptattributeinlin:506,scriptbas:409,scriptclass:408,scriptdb:[48,121,201,406,463,506,512,515],scriptdb_db_attribut:506,scriptdb_db_tag:506,scriptdb_set:[207,397,464,467],scriptdbfilterset:[512,518],scriptdbmanag:[405,406],scriptdbseri:[515,518],scriptdbviewset:518,scriptform:506,scripthandl:[201,202,404,545],scriptlistseri:[515,518],scriptmanag:405,scriptnam:[218,471],scripttaginlin:506,scroll:[6,29,31,95,147,151,165,185,477],scrollback:18,scrub:[78,457],sdesc:[106,133,157,302,350],sdesc_regex:350,sdescerror:350,sdeschandl:[106,350],sdk:185,sea:[155,170],seal:157,seamless:[106,350],seamlessli:40,search:[3,8,11,12,14,18,22,26,27,30,31,35,36,37,41,42,48,64,74,75,76,95,97,106,118,122,123,125,129,135,138,143,146,147,148,149,150,151,154,158,159,161,162,164,165,169,178,195,201,202,204,206,209,211,213,218,223,225,232,233,256,275,278,283,299,305,308,309,310,311,312,329,331,337,338,340,350,372,388,389,390,391,393,396,398,402,403,405,408,422,464,465,466,467,468,469,472,474,479,492,512,521,545],search_:[19,146,153],search_account:[19,45,121,135,153,201,206,398,489],search_account_tag:489,search_at_multimatch_input:398,search_at_result:[350,398],search_channel:[19,121,201,223,233,489],search_channel_tag:489,search_field:[225,500,502,504,505,506,507,508],search_for_obj:218,search_help:[19,31,121,201,389],search_help_entri:489,search_helpentri:389,search_index_entri:[213,215,216,217,218,223,224,225,226,227,228,229,230,241,251,255,266,269,270,273,283,286,292,293,296,299,302,305,308,309,310,311,312,316,322,325,331,343,350,364,366,370,371,372,380,386,388,390,391,398,447,474,476,477],search_messag:[19,35,121,201,233,489],search_mod:350,search_multimatch_regex:398,search_object:[13,14,18,19,48,80,121,149,151,153,170,174,201,204,396,489],search_object_attribut:153,search_objects_with_prototyp:402,search_prototyp:402,search_script:[19,42,118,121,201,405,489],search_script_tag:489,search_tag:[46,74,121,146,153,201,489],search_tag_account:46,search_tag_script:46,search_target:299,searchabl:[147,256],searchdata:[204,350,396,398,489],searching_cal:545,season:[91,104,156,157,159,316,545],seat:156,sebastian:77,sec:[32,54,87,128,136,247,428,480],secmsg:485,second:[5,13,15,19,20,22,28,30,33,39,41,42,47,54,56,58,60,67,68,76,77,85,95,97,99,104,110,112,114,118,120,125,126,128,130,136,137,140,141,142,143,149,151,153,157,164,165,173,174,175,176,178,185,191,194,195,199,204,205,210,218,223,225,229,247,256,257,260,280,289,292,308,309,310,311,312,325,337,350,354,359,370,393,398,403,405,410,411,416,421,430,435,448,459,469,472,476,479,480,485,492,493],secondari:[139,456],secondli:[37,145],secret:[75,77,78,88,104,148,156,186,188,343,416,545],secret_kei:[75,238],secret_key_nam:238,secret_set:[75,77,124,148,182,186,416],sect_insid:132,section:[0,2,5,11,13,16,20,22,25,28,30,31,33,37,42,48,50,51,53,58,62,67,70,75,76,91,95,106,118,120,124,125,126,128,130,135,136,137,138,144,146,147,149,150,151,153,154,158,170,177,182,185,190,191,193,198,225,316,349,398,403,469,470,476,493,512,545],sector:132,sector_typ:132,secur:[0,13,14,30,33,41,60,69,76,77,104,107,134,141,165,177,178,185,191,197,213,217,228,232,238,377,388,390,398,436,466,479,485,492,532,545],secure_attr:33,secure_url:238,security_token:238,security_token_nam:238,sed:2,sedat:[112,354],see:[0,3,4,5,7,8,9,10,11,12,13,14,15,18,19,20,21,22,25,27,28,29,30,31,32,33,35,36,37,39,41,42,44,47,48,50,51,52,53,54,55,57,58,60,62,64,67,68,69,70,73,75,76,78,79,81,82,84,85,86,87,89,94,96,97,98,99,100,103,104,105,106,107,108,110,111,112,113,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,139,140,142,143,144,146,147,148,149,150,151,152,154,155,157,158,159,161,164,165,167,169,170,171,172,173,174,175,176,177,178,181,182,185,186,187,188,189,190,191,192,193,194,195,199,204,213,215,217,218,223,224,225,226,228,229,230,232,235,238,241,251,254,269,270,273,275,278,280,283,289,292,293,299,305,308,309,310,311,312,329,331,336,337,338,340,346,349,350,354,359,364,366,370,372,377,382,386,388,390,391,397,398,405,410,414,416,418,419,427,428,429,430,432,436,437,439,441,443,444,445,447,448,456,457,461,464,469,472,473,474,475,478,479,487,488,490,492,495,496,526,532,537,540,543,544,545],seed:[86,292,294,338],seek:[155,275,394,485],seem:[20,41,51,76,99,106,115,124,130,133,154,156,159,161,165,174,183,185,190,199,230,464,470],seen:[20,28,44,58,62,76,82,95,96,97,99,120,128,132,134,135,137,139,142,143,146,149,150,152,154,161,170,173,174,175,241,428,478],sefsefiwwj3:75,segment:[174,461],seldomli:[213,229],select:[7,11,12,19,20,28,39,44,50,51,52,53,67,74,76,99,137,141,144,157,165,170,173,177,184,185,195,210,211,216,274,309,384,385,386,466,474,476,510,515,545],selet:476,self:[3,8,12,13,14,19,20,22,27,28,33,36,37,39,41,42,47,48,50,54,62,64,67,72,75,76,79,82,83,85,86,88,90,91,95,97,98,99,102,103,105,106,109,110,112,116,117,118,120,125,126,127,128,129,130,131,132,133,134,135,136,139,140,141,143,144,149,150,151,152,153,157,158,161,162,164,165,171,172,173,174,176,178,185,188,189,204,205,207,209,211,212,213,215,218,219,223,226,228,229,230,232,234,241,254,266,270,273,274,275,278,283,286,289,292,293,299,302,305,308,309,310,311,312,316,322,325,329,331,336,339,343,350,354,359,364,369,370,371,372,380,386,388,393,398,410,414,416,418,419,423,427,428,434,436,437,439,441,443,444,445,447,455,456,457,464,466,467,469,474,476,477,479,483,486,487,488,490,492,526,545],self_fire_damag:293,self_pid:492,self_refer:13,selfaccount:135,selfself:42,sell:[141,157,158,179,283],semi:[5,106,144,151,176,280,349],semicolon:[33,394,396,405,472],send:[5,12,18,19,22,28,29,30,32,33,37,39,42,44,45,47,49,51,52,53,55,65,70,74,76,77,78,79,86,92,95,98,99,104,118,123,126,128,135,139,142,143,148,150,153,158,162,164,165,172,173,175,177,187,188,194,197,199,204,205,212,213,216,218,223,232,233,234,238,275,283,292,296,299,312,337,338,350,359,362,369,370,377,380,398,410,411,413,416,418,419,421,425,426,427,428,429,431,434,435,436,438,439,440,442,444,445,447,448,455,456,457,458,469,472,473,476,478,490,492,496,545],send_:[62,65,434],send_adminportal2serv:426,send_adminserver2port:413,send_authent:427,send_channel:[427,428],send_default:[62,65,427,428,434,436,439,444,445],send_defeated_to:370,send_emot:[106,350],send_functioncal:425,send_game_detail:418,send_heartbeat:427,send_instruct:416,send_mail:299,send_msgportal2serv:426,send_msgserver2port:413,send_p:428,send_privmsg:428,send_prompt:[65,436,439,444,445],send_random_messag:359,send_reconnect:428,send_request_nicklist:428,send_status2launch:426,send_subscrib:427,send_testing_tag:369,send_text:[62,65,436,439,444,445],send_to_online_onli:[18,232],send_unsubscrib:427,sender:[18,35,45,101,204,205,232,233,234,275,283,350,362,398,427,458,472,483,489,502],sender_account_set:207,sender_extern:234,sender_object:458,sender_object_set:397,sender_script_set:406,sender_str:232,senderobj:[233,472],sendlin:[436,439,444],sendmessag:[62,380],sens:[20,33,37,52,53,54,64,67,76,112,118,119,133,135,152,161,174,182,211,354,364,396,472,473,476],sensibl:[18,31,191],sensit:[13,28,31,33,39,78,135,146,206,233,238,241,247,257,316,340,351,377,378,389,465,467,480,489],sensivit:382,sent:[5,18,28,30,32,35,44,45,51,53,65,68,70,78,89,92,95,98,101,104,126,135,137,142,148,151,187,204,205,209,223,232,233,234,241,251,257,270,275,299,360,362,377,380,398,413,416,418,421,425,426,427,428,436,440,444,455,457,464,476,489,490,515,545],sentenc:[58,64,95,96,106,142,260,275,349,350,492],senwmaplink:[118,338],sep:[64,469,492],sep_kei:[76,241],separ:[5,7,8,11,13,14,15,18,20,22,28,31,33,34,36,37,40,42,44,46,47,51,53,58,62,67,72,74,80,86,95,96,98,103,104,106,112,113,117,118,119,120,123,128,134,135,136,141,142,143,144,146,150,151,152,156,157,165,169,174,175,177,181,182,188,189,190,192,194,210,212,213,218,224,225,226,228,241,257,260,266,289,292,299,308,309,310,311,312,329,333,337,338,340,349,350,354,372,386,389,394,396,397,398,402,405,407,411,435,440,445,457,466,469,470,472,475,479,489,490,492,496,501,545],separatli:128,sepat:292,seq:36,sequenc:[14,15,16,22,33,36,37,52,54,70,79,80,120,123,139,148,155,158,161,175,213,217,232,247,278,292,337,350,394,414,420,469,470,476,478,490,491,492],sequenti:158,seri:[4,11,18,28,60,90,100,104,151,157,158,159,161,169,180,478],serial:[13,50,65,201,202,401,410,411,434,473,486,488,492,498,500,502,505,506,511,518,545],serializ:445,serialized_str:[500,502,505,506],serializer_class:518,seriou:[130,199],serious:185,serrano:77,serv:[52,53,65,73,77,104,123,132,143,148,152,153,158,170,187,194,195,211,233,238,310,445,461,470,472,530],server:[0,2,5,6,7,8,9,11,12,13,14,16,18,19,20,22,25,26,28,30,31,32,33,34,37,41,42,45,47,48,50,51,52,53,54,55,57,62,63,65,67,68,70,73,75,77,78,84,86,88,89,90,95,97,100,102,103,104,106,110,112,118,120,121,122,123,124,125,126,127,128,133,134,135,136,137,139,142,143,147,149,150,151,152,154,155,158,159,161,162,164,169,170,172,174,177,178,179,180,184,185,186,187,188,189,190,193,194,199,201,202,204,205,206,212,216,218,223,228,230,232,235,238,241,244,251,257,266,273,277,292,302,316,325,329,332,333,339,343,350,354,370,371,372,374,375,376,388,398,405,406,407,409,411,462,466,470,472,473,476,480,483,485,492,498,499,515,523,544,545],server_connect:434,server_disconnect:434,server_disconnect_al:434,server_epoch:[19,480],server_l:426,server_logged_in:434,server_nam:195,server_pid:[426,492],server_receive_adminportal2serv:413,server_receive_msgportal2serv:413,server_receive_statu:413,server_reload:[407,411],server_run:416,server_runn:454,server_servic:492,server_services_plugin:[62,148,195],server_services_plugin_modul:62,server_session_class:[44,78],server_session_sync:434,server_st:416,server_twistd_cmd:426,server_twisted_cmd:426,serverconf:[216,411,545],serverconfig:[410,411,422,423],serverconfigadmin:507,serverconfigmanag:[422,423],serverfactori:[426,436,439],serverload:[26,228],serverlogobserv:485,servermsg:485,servernam:[32,53,75,124,181,184,191,195],serversess:[44,62,78,143,201,202,377,394,412,434,457,464,545],serversessionhandl:[44,62,457,545],serverset:[33,223,393],servic:[11,26,55,62,77,143,148,177,182,187,188,191,193,194,195,199,201,202,228,238,412,413,416,417,425,426,433,454,461,492,545],sessdata:[456,457],sessid:[8,12,22,44,165,397,398,413,425,426,434,457],session:[8,12,16,20,22,24,26,28,30,32,34,37,39,42,45,55,62,68,121,134,139,140,142,143,147,149,150,158,165,183,193,201,202,204,205,206,207,209,210,211,213,215,216,219,221,226,230,251,274,296,369,376,377,378,380,397,398,400,401,402,407,412,413,421,425,426,427,428,434,435,436,439,444,445,454,455,457,459,474,476,477,479,492,493,515,545],session_data:457,session_from_account:457,session_from_sessid:457,session_handl:[44,121,201],session_id:515,session_portal_partial_sync:457,session_portal_sync:457,sessioncmdset:[20,26,150,221],sessionhandl:[62,65,201,202,204,398,412,421,427,428,434,435,455,456,545],sessionid:434,sessions_from_account:457,sessions_from_charact:457,sessions_from_csessid:[434,457],sessions_from_puppet:457,sessionsmain:121,sesslen:398,set:[0,2,3,5,6,8,9,10,12,13,14,15,16,17,18,19,21,22,24,25,26,27,29,30,31,32,35,36,37,39,41,42,44,45,46,48,49,50,51,53,54,55,56,57,58,60,62,63,64,65,67,69,70,71,72,73,76,78,82,83,84,85,86,87,89,91,92,93,95,96,97,99,100,105,106,112,113,115,117,118,119,120,121,122,123,125,126,128,129,130,131,133,134,135,137,140,141,142,143,144,145,146,147,148,150,151,152,156,159,161,163,164,167,169,170,171,173,174,175,177,178,181,182,183,185,187,188,190,193,197,198,199,201,203,204,205,206,207,209,210,211,212,213,215,216,218,219,220,221,222,223,225,226,229,230,231,232,238,239,241,242,244,245,247,251,255,257,260,267,270,273,274,275,276,277,278,279,284,286,289,290,292,293,294,296,302,305,306,308,309,310,311,312,313,316,317,322,325,328,329,331,332,333,334,335,337,338,340,343,349,350,351,353,354,360,364,369,370,371,372,376,380,386,388,389,393,394,396,397,398,401,402,403,405,408,409,410,411,413,415,416,420,421,422,423,426,427,429,430,432,433,436,438,439,441,442,447,448,450,452,454,455,456,457,459,461,462,464,465,466,467,469,470,471,472,473,474,475,476,477,478,479,480,483,484,485,486,487,488,489,490,491,492,493,501,504,505,507,508,513,514,516,517,518,521,525,532,533,540,545],set_active_coordin:329,set_al:370,set_alias:213,set_atribut:518,set_attr:218,set_attribut:518,set_cach:464,set_character_flag:275,set_class_from_typeclass:466,set_dead:370,set_desc:223,set_descript:28,set_detail:[316,372],set_flag:[275,276],set_gamedir:416,set_kei:213,set_lock:223,set_log_filenam:232,set_nam:28,set_password:204,set_posit:275,set_task:257,set_trac:[3,201],setattr:242,setcolor:139,setdesc:[26,134,143,224,322],sete:8,setflag:[273,275],setgend:[93,296],sethelp:[26,31,143,144,225,388],sethom:[26,143,218],setlock:322,setnam:62,setobjalia:[26,218],setperm:216,setpow:545,setspe:[104,110,325],sett:192,settabl:[32,67,149,439],setter:130,settestattr:27,settingnam:33,settings_chang:45,settings_default:[8,121,124,147,149,195,201,202,485,492,545],settings_ful:195,settings_mixin:[5,201,202,412,446,545],settl:[164,170],setup:[0,5,6,8,11,16,31,49,53,62,64,67,72,118,120,135,141,156,164,173,187,188,190,193,195,199,204,215,223,229,239,242,247,258,267,279,284,290,294,306,313,317,328,335,351,353,360,364,369,372,391,398,409,420,433,442,447,451,452,454,461,464,466,483,484,490,516,533,544,545],setup_sess:[378,490],setup_str:451,setuptool:[185,190],sever:[2,3,13,15,20,22,27,29,33,39,41,42,48,49,51,53,57,70,76,95,97,104,118,120,128,133,134,136,137,146,151,154,157,158,163,164,180,195,217,218,226,228,233,256,257,316,370,372,398,442,443,467,472,492,545],sewag:118,sex:296,sftpstorag:77,shadow:31,shall:[175,178],shaman:[41,134],shape:[76,117,130,135,144,156,170,293,329,478],sharabl:41,share:[2,3,18,20,33,44,46,48,52,67,73,75,96,119,123,126,134,148,154,158,164,177,185,186,191,194,256,257,403,411,447,464,465,467,478,492,500,515,518,526,545],shared_field:515,sharedloginmiddlewar:526,sharedmemorymanag:[465,482],sharedmemorymodel:[234,390,464,466,483,484,545],sharedmemorymodelbas:[207,234,390,397,406,464,466,483,484],sharedmemorystest:484,sharp:293,shaung:77,shaw:180,she:[22,31,58,76,82,93,97,106,133,142,157,175,241,296,349,479,495,496],sheer:[99,218],sheet:[28,51,120,157,158,177,178,182,475,545],sheet_lock:135,shell:[0,2,5,9,36,48,67,69,120,126,134,135,151,182,185,187,190,191,193,194,199,436,464],shell_plu:0,shelv:99,shield:[67,128],shift:[15,16,19,69,118,257,371,389,492],shiftroot:371,shine:[118,125,372],shini:[49,492],shinier:49,ship:[78,122,123,144,155,170,190],shire:136,shirt:[83,286],shoe:[83,286],shoot:[125,311,312,475],shop:[28,69,134,158,545],shop_exit:141,shopcmdset:141,shopkeep:[138,157],shopnam:141,shopper:141,short_descript:184,shortcom:141,shortcut:[4,13,18,19,20,22,30,45,48,72,76,82,86,95,97,120,128,137,142,147,151,164,167,177,178,182,193,201,205,212,213,218,223,241,254,292,329,394,398,486,492,545],shorten:[3,48,96,403,515],shorter:[48,62,69,118,120,149,161,171,172,176,195,232,233,349,389,464,465,472,485],shortest:[104,118,130,331,335,337,338,350],shorthand:[37,175,218],shortli:[76,97,161],shortsword:146,shot:311,should:[0,3,5,6,7,8,9,10,11,12,13,14,15,16,18,19,20,22,28,30,31,32,33,35,37,39,41,42,44,45,46,47,48,50,51,53,54,55,56,57,58,60,62,63,64,65,67,68,69,70,72,73,74,75,76,77,78,82,86,90,95,96,97,98,99,102,106,112,116,118,119,120,122,123,124,126,128,130,134,135,136,137,139,140,141,142,143,144,146,148,149,150,151,152,153,154,155,156,157,159,161,162,164,165,167,169,170,174,175,177,178,181,182,183,185,186,187,189,190,191,192,193,194,195,198,199,204,205,206,207,209,211,212,213,215,217,218,219,222,223,225,226,228,229,230,232,233,234,238,239,241,247,250,254,257,260,269,270,273,275,276,278,280,286,292,293,294,299,302,305,308,309,310,311,312,316,322,325,331,333,335,337,338,339,340,349,350,353,354,369,370,372,376,382,388,393,394,397,398,400,402,403,406,409,410,411,414,415,416,420,423,427,433,436,439,440,442,444,445,447,448,454,455,456,457,459,460,462,464,466,467,469,470,472,473,474,476,477,478,479,480,485,486,487,488,490,492,493,500,501,508,532,533,538,545],should_join:232,should_leav:232,should_list_top:225,should_show_help:225,shoulddrop:[312,398],shoulder:[83,135,286],shouldget:[312,398],shouldgiv:[312,398],shouldmov:[308,309,310,311,312,398],shouldn:[14,76,77,97,125,128,135,175,241,257,260,311,398,447],shouldrot:485,shout:[128,273,275],shove:125,show:[0,3,6,7,9,11,13,14,15,18,19,22,25,28,29,30,31,42,44,50,51,53,55,58,59,60,62,67,72,76,86,91,92,96,97,103,104,112,113,115,117,118,119,120,122,123,129,130,132,134,135,136,137,139,140,141,142,143,144,148,149,150,151,152,154,155,156,157,158,160,161,162,163,164,166,168,169,170,171,172,173,175,177,178,183,184,185,187,188,191,192,194,195,199,204,215,216,218,223,224,225,226,228,230,250,251,266,270,273,283,286,302,311,312,316,329,331,335,337,338,340,343,346,354,364,372,380,386,388,398,400,402,403,414,416,425,464,474,476,485,486,487,492,496,532,545],show_change_link:500,show_foot:477,show_map:132,show_non_edit:402,show_non_us:402,show_valu:346,show_version_info:416,show_warn:416,showcas:[20,99,148,155,170],shown:[22,25,28,31,41,42,50,59,75,76,90,97,106,107,112,124,126,128,132,134,136,149,161,174,177,184,213,216,223,227,229,241,250,266,280,286,292,337,338,350,354,364,371,382,398,416,476,477,521],showtim:136,shrink:[150,478],shrug:96,shuffl:19,shun:[0,69,191],shut:[5,51,97,124,128,151,193,195,204,228,398,409,411,416,418,425,426,433,434,454,457,545],shutdown:[5,20,26,42,44,55,57,135,143,199,204,205,228,405,411,416,425,426,433,454,455,466,472,476],shy:[0,72,156,159],sibl:[13,42,54,134,152],sid:[77,216],side:[2,8,13,30,32,42,44,46,51,53,65,79,88,97,104,109,118,120,132,135,142,146,157,158,162,175,177,183,204,205,207,218,224,226,234,283,322,338,343,390,397,406,413,421,425,426,434,437,440,441,444,455,456,457,464,466,467,469,478,484],sidebar:[53,163,166,545],sidestep:57,sidewai:478,sigint:416,sign:[7,15,47,65,95,96,97,118,142,144,146,148,153,165,176,191,223,275,316,337,398,411,464,469,493],signal:[5,24,95,199,201,202,308,309,310,311,312,336,412,416,439,445,447,483,545],signal_acccount_post_first_login:45,signal_account_:45,signal_account_post_connect:45,signal_account_post_cr:45,signal_account_post_last_logout:45,signal_account_post_login:45,signal_account_post_login_fail:45,signal_account_post_logout:45,signal_account_post_renam:45,signal_channel_post_cr:45,signal_helpentry_post_cr:45,signal_object_:45,signal_object_post_cr:45,signal_object_post_puppet:45,signal_object_post_unpuppet:45,signal_script_post_cr:45,signal_typed_object_post_renam:45,signatur:[22,30,162,213,254,278,289,336,354,388,410,414,416,418,419,427,436,437,439,441,444,445,464,469,476,487,488,526],signature_vers:238,signed_integ:493,signedinteg:486,signedon:428,signifi:[15,22,393,464],signific:[6,30,118,479,490],significantli:27,signup:124,silenc:[223,418],silenced_system_check:8,silent:[13,54,136,172,216,223,364,420,428],silli:[37,41,146],silmarillion:153,silvren:191,similar:[0,7,13,14,22,28,31,37,48,49,51,52,53,67,72,74,76,95,97,104,114,117,118,122,123,125,126,135,144,149,155,156,162,169,174,187,191,204,213,215,229,232,241,292,308,309,310,311,312,329,349,380,390,398,405,457,467,472,476,492,515,541,545],similarli:[46,112,118,135,136,191,270,309,354,501,508,515],simpl:[0,8,12,13,14,15,16,17,20,22,25,27,30,31,32,37,39,41,44,46,53,54,58,62,64,67,68,69,73,75,79,80,81,82,85,86,90,91,92,93,95,96,97,98,101,104,105,106,107,109,111,113,114,117,120,122,123,124,126,127,129,130,132,133,134,135,137,139,141,142,143,149,150,152,153,155,156,157,161,162,163,164,165,166,170,171,172,173,175,176,177,187,191,192,193,194,218,232,238,241,242,251,256,273,275,277,283,289,292,293,296,299,305,308,309,310,311,312,316,321,322,325,329,335,349,350,354,359,362,364,366,370,371,372,380,382,386,387,397,398,403,409,426,435,437,464,470,471,476,479,492,529,530,532,545],simple_ev:30,simpledoor:[201,202,235,314,545],simpledoorcmdset:[109,322],simpleev:30,simplemu:183,simpleobjectdbseri:515,simpler:[16,28,54,133,217,218,473,541],simpleresponsereceiv:418,simplest:[13,39,53,114,128,135,143,162,164,191,212,470,493],simpli:[8,9,11,13,14,17,20,28,33,39,46,48,53,55,60,62,65,74,76,77,82,85,90,91,99,110,113,119,120,125,126,128,130,132,135,139,141,144,147,150,156,157,161,162,165,172,174,176,181,182,185,188,189,194,195,204,211,212,213,229,230,232,241,251,258,289,308,309,310,311,312,316,325,337,362,364,371,386,388,390,398,434,464,466,470,471,475,477,492],simplic:[58,76,130,175,230,251,371],simplif:[158,164],simplifi:[5,54,64,137,149,164,170,172,193,254],simplist:[51,111,164,165,176,349,366],simul:[5,22,104,110,152,158,162,325],simultan:[68,135,158,164,396,492],sinc:[0,3,5,6,8,11,13,14,15,18,19,20,22,25,27,28,30,31,32,33,34,35,37,39,42,47,48,52,53,54,57,58,60,62,64,65,67,68,73,75,76,78,79,97,104,106,113,118,120,122,123,124,125,126,127,128,130,131,132,133,134,135,136,137,141,142,143,145,146,147,148,149,150,151,152,153,154,155,156,158,159,161,164,165,167,170,172,174,175,177,178,182,184,187,191,193,195,199,204,205,207,211,212,213,218,226,227,228,233,241,245,247,275,283,292,299,308,309,310,311,312,316,333,337,338,350,364,371,372,386,393,396,398,402,403,407,410,411,416,418,421,433,438,440,454,455,457,459,464,465,466,470,471,472,474,476,479,480,483,485,488,489,490,492,501,508,532],singl:[5,9,11,15,20,22,28,30,35,36,42,44,46,48,54,56,65,68,69,72,76,78,95,97,103,104,107,112,115,116,118,120,122,123,131,134,135,146,150,151,152,155,157,158,162,170,182,187,191,204,216,223,224,228,234,241,266,270,293,308,309,310,311,312,329,335,337,338,340,354,372,376,382,386,398,402,403,410,411,448,455,457,464,465,467,469,470,475,476,478,492,495,532,545],single_type_count:286,singleton:[34,44,47,118,407,410,471,545],singular:[120,135,398,495,497],sink:0,sint:29,sir:96,sit:[15,18,22,39,48,65,98,122,128,143,148,150,151,152,158,161,165,174,185,191,226,232,234,260,275,278,299,338,350,371,372,394,405,408,411,429,467,472,487,490],sitabl:48,sitat:372,site:[6,17,33,40,50,53,56,119,137,170,177,178,180,181,182,187,188,191,192,193,194,338,461,503,523,545],site_head:[50,523],site_id:53,sitekei:545,sitsondthi:161,sitsonthi:161,sittabl:[275,545],sittablein:161,sitter:161,situ:[13,466,473],situat:[3,13,22,30,31,42,44,48,52,64,65,67,76,95,96,97,119,136,150,153,161,212,213,218,256,276,483],six:[95,142,162,343,386],sixti:136,sizabl:[77,238],size:[3,6,51,56,69,104,117,118,132,135,159,170,183,201,238,239,329,337,338,418,432,469,475,477,478,483,485,492],size_limit:492,skeleton:165,sketch:164,skill:[28,58,104,106,112,122,127,128,129,138,146,148,151,156,157,162,164,174,177,178,180,199,293,340,349,350,353,354,475,545],skill_combat:162,skill_craft:86,skill_requir:293,skill_rol:293,skillnam:162,skillrecip:86,skim:[104,115,146,159],skin:[41,293],skip:[0,7,18,20,22,28,41,47,53,58,68,77,80,99,118,120,132,136,143,144,146,148,150,152,156,159,190,193,204,217,218,238,293,398,402,464,473,492,510],skip_cal:275,skipkei:445,skippabl:[22,72],skull:41,sky:[42,176],slack:180,slam:[92,380],slash:[53,122,144,154,155,162,164,239,371],slate:[150,170],sleep:[22,30,54,128,158,162],sleepi:13,slew:[162,190,470],slice:[215,469,477],slice_bright_bg:215,slice_bright_fg:215,slice_dark_bg:215,slice_dark_fg:215,slide:[293,364],slider:53,slight:[142,181,247,257],slightli:[3,31,136,157,164,165,180,185,234,270,309,316,500,543],slip:491,slogan:75,sloppi:120,slot:[53,92,112,135,178,309,311,316,354,380,403,492,545],slow:[5,19,104,115,157,164,228,233,324,325,326,329,333,338,370,402,429,435,469,489,492,545],slow_exit:[110,201,202,228,235,314,545],slowdoorcmdset:[110,325],slower:[5,42,136,158,191],slowexit:[110,325],slowexitcmdset:325,slowli:[112,180,354,544],slug:[213,232,388,390,466,540,543],slugifi:[537,540],slugify_cat:540,small:[5,6,9,15,16,22,35,52,56,69,81,86,90,104,115,117,118,119,122,124,126,129,134,135,137,138,139,141,142,155,156,157,158,159,161,165,166,170,180,185,191,192,289,292,311,329,331,332,335,337,343,354,364,439,474,475,478,492],smaller:[14,15,56,120,335,354,478],smallest:[39,87,95,106,112,135,136,191,247,349,354,475,492],smallshield:67,smart:[117,142,329,338],smarter:41,smartmaplink:338,smartreroutermaplink:338,smartteleportermaplink:338,smash:[108,364],smaug:[143,149,150,152],smedt:495,smell:[118,156,275],smellabl:275,smelli:41,smile:[22,30,149,157,224,273,497],smith:[58,475],smithi:128,smoothi:[104,105,305],smoothli:178,snake:[53,169],snap:140,snapshot:11,snazzi:179,sneak:394,snippet:[14,20,33,52,54,60,85,104,122,123,125,143,157,228,289,425,491,492],snonewaymaplink:[118,338],snoop:[187,194],snow:[86,292],snowbal:[86,292],snowball_recip:86,snuff:0,soak:150,social:[122,158,188],socializechat:448,societi:146,sofa:161,soft:[61,106,123,124,349,545],softcod:[30,72,95,104,158,545],softli:179,softwar:[2,11,185,191],solar:136,soldier:[141,152],sole:[134,137,205],solid:[60,122,132,159],solo:[148,158,185],solut:[8,15,19,28,31,47,48,75,97,112,118,126,128,130,133,137,141,142,155,158,161,162,170,172,174,191,194,227,337,338,354,394,545],solv:[6,19,90,104,105,118,125,131,132,138,155,156,170,185,278,305,337,371,545],some:[0,1,2,3,6,7,8,9,11,13,14,15,16,18,19,20,22,26,27,28,30,31,32,33,35,36,37,41,42,44,45,46,47,48,49,50,51,53,55,56,58,60,62,64,65,67,69,70,75,76,78,79,86,89,90,95,96,97,107,112,113,114,115,118,119,120,122,123,124,125,126,127,128,132,134,135,136,137,138,140,141,142,143,144,145,146,148,149,150,152,154,155,156,159,160,161,162,163,164,165,167,169,170,171,172,174,175,177,178,179,180,181,182,183,185,187,189,190,191,194,195,197,198,199,204,212,213,218,220,223,224,227,228,230,232,233,238,241,251,257,260,270,275,278,283,289,292,309,310,311,312,322,329,338,349,354,364,369,371,372,382,386,394,398,402,403,406,418,420,425,428,454,464,466,469,470,475,476,479,480,483,485,486,492,495,496,500,505,518,532,543,545],some_long_text_output:477,some_modul:147,somebodi:[95,97],someclass:147,somehow:[22,36,53,62,70,74,99,161,162,191,286,474],someon:[22,33,45,47,50,58,95,96,97,128,132,135,141,143,146,151,159,161,171,172,191,194,204,224,286,364,370,371,398],somepassword:182,someplac:370,someth:[5,8,9,11,13,15,18,19,22,28,29,30,31,33,37,39,41,42,45,47,48,50,51,52,54,55,58,60,62,65,67,69,72,73,75,76,77,79,85,86,95,96,97,99,104,107,110,112,116,118,119,120,122,123,124,126,128,129,130,131,132,133,134,135,136,137,140,141,142,143,144,146,149,151,152,153,155,156,159,161,162,165,167,170,177,178,181,182,186,187,188,189,190,191,195,197,204,211,213,218,224,226,229,241,260,270,283,286,289,293,296,308,309,310,311,312,325,329,338,350,354,371,372,382,394,398,403,455,466,470,476,477,479,486,492,538,545],something_els:42,sometim:[3,5,19,22,27,28,33,39,41,42,53,62,67,76,95,123,136,142,146,150,151,153,169,199,225,396],sometypeclass:[95,145],somewhat:[76,124,134,241],somewher:[8,11,41,42,48,55,90,97,118,119,150,161,162,174,191,213,218,232,331,388,390,466,492,545],somon:275,soon:[3,13,44,137,156,158,189,193,445,492],sophist:[19,54,69,122,164],sorl:124,sorri:[33,200,394],sort:[13,20,34,39,44,46,53,58,65,73,74,79,86,94,104,112,114,115,123,130,132,137,146,149,150,151,156,162,164,167,171,191,199,275,283,308,309,310,311,312,338,346,354,372,398,403,406,464,465,466,476,492,523,532,537,538,540,541,542,545],sort_kei:445,sort_stat:5,sortkei:5,sought:[204,210,232,388,390,398,464,466],soul:[159,170],sound:[33,47,64,65,76,90,99,104,106,119,128,135,140,146,156,157,161,170,195,349,440],sourc:[1,2,6,8,9,10,11,16,17,19,20,26,30,37,54,55,56,64,68,69,75,76,77,95,96,97,113,115,119,121,122,123,124,125,134,147,151,154,155,157,178,180,182,185,187,189,190,201,204,205,206,207,209,210,211,212,213,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,232,233,234,238,239,241,242,245,247,248,251,252,254,255,256,257,258,260,266,267,269,270,273,274,275,276,277,278,279,280,283,284,286,287,289,290,292,293,294,296,297,299,300,302,303,305,306,308,309,310,311,312,313,316,317,322,323,325,326,328,329,331,332,333,335,336,337,338,339,340,343,344,346,347,349,350,351,353,354,359,360,362,364,366,367,369,370,371,372,373,376,377,378,380,382,383,385,386,388,389,390,391,393,394,396,397,398,400,401,402,403,405,406,407,408,409,410,411,413,414,415,416,418,419,420,421,422,423,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,447,448,449,451,452,453,454,455,456,457,459,460,461,464,465,466,467,469,470,471,473,474,475,476,477,478,479,480,482,483,484,485,486,487,488,489,490,491,492,493,495,496,497,500,501,502,503,504,505,506,507,508,510,512,513,514,515,516,518,520,523,524,525,526,527,530,532,533,536,537,538,539,540,541,542,543,544,545],source_loc:[126,171,276,329,371,372,398],source_object:[230,251],sourceforg:[429,430,440,443],sourceurl:428,south:[76,97,99,118,131,132,161,170,174,218,331,337,338,448],south_north:170,south_room:99,southeast:[218,338],southern:170,southwest:[118,144,218,338],space:[13,18,22,25,30,31,33,36,41,42,51,58,60,72,75,76,77,78,95,96,99,118,120,125,126,132,134,142,143,144,150,151,152,154,164,170,172,175,210,213,218,223,224,225,226,229,230,238,293,302,312,337,338,349,350,371,398,460,466,469,470,475,476,478,479,491,492,496,521,545],spaceship:174,spacestart:491,spaghetti:[14,476],spam:[18,42,55,80,127,138,164,194,223,459],spammi:[55,164],span:[17,56,69],spanish:64,spare:[308,309,310,311,312,337],sparkly_mag:146,spars:78,spatial:170,spawen:[105,305],spawn:[5,18,26,35,51,86,90,104,105,118,121,143,147,155,158,173,201,216,218,292,305,309,310,332,335,337,338,339,400,401,402,403,545],spawn_alias:[118,338],spawn_link:[337,338],spawn_nod:337,spawner:[24,37,118,173,201,202,218,310,311,399,401,545],spawng:86,spd:178,speak:[16,18,57,70,96,97,104,106,158,171,172,175,177,224,275,350,398],speaker:[95,96,106,275,349,350],spear:41,special:[0,3,8,12,13,14,15,16,18,19,20,22,25,28,30,33,37,39,45,46,48,50,51,52,53,54,57,60,64,65,67,68,70,91,93,95,104,118,120,123,126,129,135,137,139,141,144,146,147,148,149,150,151,152,153,157,164,165,170,178,194,195,205,207,209,212,224,227,273,275,276,280,296,310,311,316,329,340,350,371,372,386,391,394,398,420,421,444,448,464,466,470,476,491,505,545],specic:337,specif:[0,2,3,8,11,12,13,19,20,22,27,28,33,36,37,39,44,45,46,47,48,49,51,55,58,62,68,73,75,76,79,82,85,86,95,96,97,104,107,118,119,120,121,122,123,124,126,130,133,136,137,140,142,146,147,148,149,151,152,153,155,156,158,164,165,170,174,175,176,177,178,179,180,182,183,187,191,193,199,204,206,209,216,218,225,228,230,234,235,241,254,255,256,257,273,275,283,289,292,293,299,331,337,338,339,350,382,389,393,396,398,405,407,416,420,421,428,444,445,455,464,466,469,470,474,476,477,478,492,496,501,503,512,543,544],specifi:[8,13,18,19,20,28,31,34,41,44,46,47,53,55,56,57,58,60,65,67,68,76,82,83,84,86,88,92,95,96,105,112,113,117,118,120,125,128,130,132,135,136,142,144,145,149,150,152,153,161,165,167,169,170,178,184,185,191,192,193,194,209,210,218,225,232,233,241,242,244,254,256,257,275,286,292,299,305,309,310,311,316,329,331,337,338,343,350,354,380,382,386,393,394,398,401,402,403,407,427,453,464,467,469,470,472,475,476,479,480,486,487,488,490,492,495,496,512,515,532,540,543],specifici:276,specii:58,spectacular:3,spectrum:158,speech:[273,398],speed:[5,13,36,67,79,104,110,136,140,158,164,178,325,396,403,434,467,489],speedup:402,spefifi:479,spell:[16,41,46,57,113,114,127,134,201,202,235,281,291,311,386,403,545],spell_attack:311,spell_book:86,spell_conjur:311,spell_heal:311,spell_nam:311,spellbook:[292,293],spellcast:[114,157],spellnam:[293,311],spend:[37,114,130,142,153,158,159,308,309,310,311,312],spend_act:[308,309,310,311,312],spend_item_us:310,spent:311,sphinx:120,spike:292,spiked_club:292,spin:[52,136,191,490],spit:[151,164,167,292],splashscreen:251,splinter:155,split:[20,22,44,75,117,118,126,135,142,150,151,158,165,169,170,172,174,195,210,226,247,329,371,391,400,442,457,469,470,480],split_nested_attr:218,spoiler:115,spoken:[96,97,106,157,189,349,350,398],spoof:[187,501,508],spool:185,sport:36,spot:[53,99,123,134,204,335,338],spread:[5,30,41,146,161,162,545],spring:[91,140,316,317],spring_desc:317,sprint:325,sprofil:416,spruce:58,spuriou:545,spy:35,spyrit:183,sql:[2,48,67,123,133,134,153,451,545],sqlite3:[5,8,9,11,67,123,148,165,197,198,492,545],sqlite3_prep:454,sqlite:[9,67,182,454],sqllite:2,sqrt:130,squar:[30,72,99,120,130],squeez:[67,120],src:[17,33,37,51,54,144,177,190,193,377],srcobj:[213,226],srun:420,srv:2,ssessionhandl:65,ssh:[44,62,65,75,123,126,191,199,201,202,412,424,455,456,545],ssh_interfac:191,ssh_port:191,sshd_config:194,sshfactori:436,sshprotocol:436,sshserverfactori:436,sshuserauthserv:436,ssl:[65,68,123,181,187,201,202,205,223,412,424,428,441,456,545],ssl_context:[437,441],ssl_interfac:191,ssl_port:191,sslcertificatefil:181,sslcertificatekeyfil:181,sslciphersuit:181,sslengin:181,ssllab:181,sslprotocol:[181,437,441],ssltest:181,sslv3:187,sta:475,stab:[128,155,371],stabil:[156,229,349],stabl:[53,62,133,193],stabli:[6,411],stack:[14,20,51,156,161,174,211,212,398,402,457,476,545],stackedinlin:500,stackexchang:8,stackoverflow:8,stacktrac:402,staf:69,staff:[18,22,39,41,50,57,69,75,95,104,126,134,156,162,165,170,177,211,340,403,470,545],staffer:[50,75,158],staffernam:75,stage:[2,11,12,133,156,165,170,177,500,502,505],stagger:428,stai:[20,28,48,90,132,142,151,174,175,185,191,197,329,338],stale:[48,193,410],stale_timeout:410,stalker:538,stamina:[94,112,129,157,311,346,354],stamp:[19,44,48,51,204,207,216,228,397,406,448,453,466],stanc:[30,106,158,164,350,398,479,495,545],stand:[8,11,14,17,33,50,67,76,95,104,106,115,118,120,125,126,128,132,133,144,147,151,153,155,157,161,162,164,165,170,174,177,185,189,191,224,273,275,283,340,350,370,398,406,411,447,467,470,472,478,508],standalon:[187,194],standard:[13,16,18,19,27,49,53,60,61,65,68,70,75,88,89,95,97,104,116,118,123,125,129,134,135,142,146,149,151,164,169,173,175,180,181,185,187,194,201,204,215,251,270,340,343,350,398,436,438,443,460,464,469,478,480,490,493,517,545],stander:161,stanislav:77,stanza:[58,426],stapl:158,star:218,start:[3,5,6,7,8,9,10,11,12,14,15,16,18,19,20,22,27,28,30,32,33,34,36,39,41,42,44,45,48,51,52,53,55,56,59,60,62,63,64,65,67,69,77,79,86,90,91,92,93,97,104,106,111,112,114,115,118,119,120,122,123,124,125,126,128,130,131,132,134,136,137,142,144,146,147,148,149,152,156,157,158,159,161,162,164,165,167,169,170,173,174,176,177,180,182,184,186,187,189,190,191,192,194,195,197,204,205,210,211,217,218,223,224,225,226,227,228,229,232,241,247,257,273,274,275,277,283,292,296,308,309,310,311,312,316,329,337,338,343,346,349,350,354,364,366,369,370,372,380,386,398,400,402,405,406,407,408,409,410,411,413,416,418,420,421,426,427,428,429,433,434,435,440,441,447,448,453,454,457,461,465,469,470,471,472,474,476,477,478,479,480,485,492,521,544,545],start_all_dummy_cli:447,start_attack:370,start_bot_sess:457,start_char:479,start_delai:[42,164,173,174,405,406,411,472],start_direct:338,start_driv:174,start_evennia:416,start_hunt:370,start_idl:370,start_index:223,start_lines1:416,start_lines2:416,start_loc_on_grid:132,start_of_messag:502,start_olc:400,start_only_serv:416,start_open:275,start_ov:28,start_patrol:370,start_plugin_servic:62,start_portal_interact:416,start_posit:275,start_read:275,start_rotat:275,start_serv:426,start_server_interact:416,start_sunrise_ev:136,start_text:386,start_turn:[308,309,310,311,312],start_xi:[118,337],startapp:[67,137,177,178],startclr:479,startcolor:30,startcoord:335,startedconnect:[413,427,428],starter:[75,154,155,169],starthour:126,startnod:[28,141,274,369,380,400,476],startnode_input:[28,274,369,380,400,476],startproduc:418,startservic:[419,461],startset:372,startswith:[31,34,218,469,490],starttupl:436,startup:[13,25,62,136,148,169,191,195,398,406,409,445,454,485,492],stat:[5,13,17,28,53,79,112,138,141,148,149,151,152,156,157,164,165,169,177,178,188,283,308,309,310,311,312,354,541,545],state:[3,11,13,14,15,20,22,26,27,28,33,42,44,51,60,85,90,104,108,122,123,133,148,149,152,155,158,164,174,175,193,199,201,202,204,209,211,212,215,222,230,232,235,271,272,273,275,276,279,280,289,308,309,310,311,312,322,364,370,372,403,406,408,409,411,416,436,464,474,476,545],state_001_start:90,state_chang:278,state_nam:278,state_unlog:222,statefultelnetprotocol:[439,447],statehandl:[276,278],statement:[3,14,15,19,20,28,53,54,67,77,122,132,135,146,151,172,364,470,491],statenam:[273,275,278],static_overrid:[51,73,148,169],static_root:169,staticfil:[77,104,238],staticfiles_storag:77,statict:218,statictrait:[112,354],station:[95,158,174],stationari:370,statist:[44,52,53,55,73,94,167,173,195,218,228,346,449,465,483],statu:[11,28,44,47,50,68,79,114,128,135,144,148,156,157,182,187,191,195,228,283,310,311,312,370,411,414,416,425,426,427,430,444,500,545],status:[156,545],status_cod:418,stderr:270,stdin_open:193,stdout:[193,270,416,485],steadi:123,steal:[35,141,225],stealth:158,steel:293,steer:174,step1:128,step2:128,step3:128,step:[0,2,6,7,9,14,15,18,20,22,27,28,41,67,69,82,95,96,97,104,118,120,124,125,128,130,135,137,138,140,141,142,158,159,160,162,165,174,175,178,181,182,185,193,217,223,241,293,335,337,338,353,372,411,420,432,443,447,448,457,466,470,473,474,476,477,545],step_sequ:331,stepper:[118,338],stick:[16,22,28,70,86,120,185,216],still:[0,1,7,9,11,13,14,15,16,18,20,22,44,45,48,50,57,58,60,62,64,65,69,75,76,86,90,95,97,103,104,112,113,117,118,120,122,123,124,126,128,130,132,134,135,136,142,143,144,148,149,150,151,158,161,165,174,175,178,179,180,185,187,194,199,204,211,218,223,225,230,232,251,266,278,292,308,309,310,311,312,329,338,353,354,369,372,386,396,398,402,408,448,476,478,479,480,488,492,540],sting:170,stock:[122,141,159,377,532],stolen:[194,469],stone:[22,28,58,144,153,159],stop:[3,5,7,9,15,18,19,30,32,37,39,42,44,47,51,54,55,64,69,75,95,104,108,109,110,112,118,126,128,132,134,135,136,140,144,147,148,151,154,157,158,161,164,165,173,174,185,187,191,193,195,197,215,218,223,228,232,247,256,258,283,293,309,312,322,325,338,350,354,364,398,405,408,409,410,411,415,416,418,421,433,434,454,455,461,469,470,472,492,545],stop_driv:174,stop_evennia:416,stop_serv:426,stop_server_onli:416,stopproduc:418,stopservic:[419,461],storag:[13,14,22,48,67,77,85,123,127,128,133,141,147,159,162,177,182,207,228,234,237,238,239,260,289,329,349,354,388,394,397,398,402,403,406,409,411,423,459,463,464,466,471,486,487,545],storage_modul:471,storagecontain:42,storagescript:42,store:[4,6,9,11,12,14,16,18,19,20,22,23,27,31,33,35,36,37,39,42,44,46,47,48,50,51,62,67,70,73,75,77,79,80,86,91,96,97,104,106,107,112,117,118,123,125,127,128,130,131,132,133,134,135,137,140,141,142,143,146,148,149,150,151,152,156,161,162,164,165,169,174,177,178,182,190,193,195,204,205,207,212,215,216,218,219,221,225,226,234,238,257,276,278,283,292,293,302,310,316,325,329,338,339,349,350,354,359,366,371,372,377,380,382,388,389,393,394,397,401,402,403,404,407,408,409,410,411,416,420,421,422,423,426,428,429,430,432,440,443,448,454,455,456,457,459,461,464,465,466,467,469,471,472,473,474,475,476,477,480,483,486,487,488,492,518,532,543,545],store_kei:[411,492],store_tru:[116,270],stored_obj:126,storekei:[141,411],storenam:141,storeroom:141,storeroom_exit:141,storeroom_kei:141,storeroom_key_nam:141,stori:[6,31,75,114,167,177],storm:127,storm_drain:86,storypag:167,storytel:165,stove:398,str:[13,19,27,28,30,32,34,35,42,48,54,62,70,76,92,95,97,99,104,112,118,126,130,135,140,142,143,149,150,151,157,162,177,178,201,204,205,206,209,210,211,212,213,218,223,225,232,233,234,238,241,247,254,255,256,257,260,270,274,275,276,278,280,283,286,289,292,296,299,308,309,310,311,312,316,322,329,337,338,339,340,346,349,350,353,354,362,364,369,372,377,380,382,386,388,389,390,391,394,396,397,398,401,402,403,405,407,408,409,411,413,414,416,420,421,422,423,425,426,427,428,429,431,434,435,436,439,440,441,444,445,447,453,454,455,456,457,459,460,461,464,465,466,467,469,470,471,472,474,475,476,477,478,479,485,486,487,488,489,490,491,492,493,495,496,501,510,512,515,524,538,540],straght:338,straight:[118,132,159,175,338,467],straightforward:[126,141,142,165,174],strang:[15,42,128,133,149,181,212,230],strange_bug:11,strangl:191,strap:158,strategi:[3,312],strattr:[13,464],strawberri:[116,270],stream:[7,238,425,429,455],streamlin:[2,283],streeter:77,stren:151,strengh:13,strength:[13,33,112,134,135,148,149,157,158,162,164,178,353,354],stress:[5,335,447],stretch:[118,120,170],stribg:492,strict:[54,294,402,469,540],stricter:[159,402],strictli:[28,57,89,146,177,251,311,478],strike:[28,140,164,224,311,312,366],string1:492,string2:492,string:[3,5,6,8,13,14,16,18,19,20,22,24,25,27,28,30,31,34,36,37,39,41,46,47,48,50,51,55,57,58,64,65,67,68,70,72,75,76,86,92,99,104,106,107,113,117,120,122,126,128,132,134,135,140,143,144,146,148,149,150,151,152,153,157,158,161,164,170,177,178,182,184,185,188,191,195,201,202,204,205,206,207,209,210,213,216,218,223,224,225,226,227,228,229,232,233,234,238,241,250,251,260,275,280,283,286,289,292,299,305,308,309,310,311,312,329,337,339,340,349,350,354,364,369,370,377,378,380,382,383,386,389,390,392,393,394,396,397,398,401,402,403,405,406,409,411,416,418,421,425,428,436,439,440,442,445,448,453,455,457,460,464,465,466,467,468,469,470,472,473,474,475,477,478,479,485,486,488,489,490,491,492,493,495,496,501,508,515,540,543,545],string_from_modul:492,string_partial_match:[396,492],string_similar:492,string_suggest:492,stringproduc:418,stringvalu:[112,354],strip:[22,28,30,31,32,60,69,76,95,120,125,135,139,141,143,150,161,165,172,210,218,225,226,227,238,275,293,350,396,403,421,436,439,440,469,470,474,476,479,490,492,545],strip_ansi:[139,469,491],strip_cmd_prefix:225,strip_control_sequ:492,strip_dir:5,strip_mxp:469,strip_raw_ansi:469,strip_raw_cod:469,strip_unsafe_input:492,strip_unsafe_token:469,strippabl:476,stroll:325,strong:[33,60,159,165,491],strongest:33,strongli:[11,18,49,119,123,151,158,162,349],strr:382,struct:133,structur:[13,22,28,30,31,39,41,53,65,68,75,77,104,119,122,123,132,133,137,143,146,147,148,151,158,169,177,178,185,218,223,232,238,337,339,350,391,398,402,403,440,445,467,473,476,513,529,541,545],strvalu:[13,464,465],stuck:[28,143,155,161,185],studi:545,stuff:[8,13,20,28,30,33,39,41,42,44,45,53,75,93,104,112,116,119,120,125,128,132,134,138,141,143,150,151,152,153,154,155,156,157,158,161,162,167,187,212,229,270,296,353,354,411,454,525,545],stumbl:[6,159],stupid:[11,153,159],sturdi:475,stutter:69,style:[7,13,18,19,22,26,28,36,56,60,62,72,83,84,86,98,104,105,112,113,114,119,120,122,125,134,135,138,143,151,154,155,156,158,159,163,164,167,170,180,207,213,215,226,244,265,268,270,280,286,292,299,308,354,380,402,474,478,479,492,545],styled_foot:213,styled_head:[22,213],styled_separ:213,styled_t:[22,213],sub:[2,13,18,30,31,41,42,51,53,68,69,75,103,106,120,134,137,146,148,164,186,191,203,208,223,225,231,235,241,242,266,270,335,350,387,389,391,392,395,403,404,412,463,468,469,479,491,498,502,534,545],sub_ansi:469,sub_app:177,sub_brightbg:469,sub_dblspac:491,sub_mxp_link:491,sub_mxp_url:491,sub_text:491,sub_to_channel:223,sub_xterm256:469,subbed_chan:223,subcategori:[225,391],subclass:[19,41,44,48,112,117,118,123,146,148,172,218,241,242,329,354,397,402,406,426,439,445,466,484,488,492,500,501,508,545],subcommand:118,subcrib:18,subdir:8,subdirectori:8,subdomain:[181,191,194],subfold:[67,73,119,148,151,178],subhead:120,subject:[2,35,58,67,93,130,139,146,191,296,299,479,496],sublim:154,submarin:174,submenu:[7,241,242,400],submenu_class:241,submenu_obj:241,submiss:[92,380,532],submit:[17,53,92,104,119,177,194,230,380,532,536,538,543],submitcmd:380,submodul:440,subnegoti:440,subnet:[55,182,216],subpackag:[8,68],subprocess:[126,492],subreddit:180,subscrib:[9,18,22,33,47,55,121,123,135,176,205,223,232,233,234,266,310,411,427,458],subscribernam:223,subscript:[18,22,42,47,135,176,180,223,233,234,411,502],subscriptionhandl:[18,234],subsect:337,subsequ:[22,54,106,151,164,185,266,273,349,470,492],subsequent_ind:478,subset:[8,46,133,148,158,337],subsid:48,substanti:[77,238,292],substitut:[7,36,188,398,469,491],substr:[150,469,479],subsub:[31,225,229],subsubhead:120,subsubsubhead:120,subsubtop:[31,225,229],subsubtopicn:229,subsystem:[67,75,114,157,185,394],subtext:276,subtitl:17,subtop:[223,225,229,388,391,545],subtopic_separator_char:225,subtract:[30,104,112,141,353],subturn:164,subwai:95,subword:492,suc:86,succe:[86,155,156,164,269,292,343,545],succeed:[28,116,223,270,343],success:[86,146,157,158,162,164,165,178,204,223,232,283,292,308,309,310,311,312,343,364,371,372,394,402,410,416,420,466,474,486,492,543],success_messag:[292,293],success_teleport_msg:372,success_teleport_to:372,success_url:[536,538],successfuli:[105,292,305],successfulli:[2,10,22,54,105,127,152,161,170,199,204,292,293,294,305,329,371,398,410,416,428,460,466,543],suddenli:[0,6,466],sudo:[185,187,193,194],sue:157,suffic:[17,134,151],suffici:[67,77,191,238],suffix:[6,19,30,469,479,485,492,518],suggest:[0,6,28,29,31,48,74,77,112,115,119,120,122,126,156,157,158,159,182,191,210,225,283,293,350,354,372,391,398,492],suggestion_cutoff:225,suggestion_maxnum:[225,391],suggests:31,suit:[10,114,123,128,159,171,229,492,541,545],suitabl:[11,22,30,33,36,42,46,50,65,68,104,111,118,119,122,123,125,126,143,146,151,154,185,191,206,211,223,275,292,337,394,450,457,472,476,479],sum:[118,119,140,142,147,154,212,276],summar:[97,104,119,143,180],summari:[50,95,96,97,119,165,180,199,241,545],summer:[91,157,158,316],sun:[118,136],sunris:136,sunt:29,super_long_text:477,superclass:500,superfici:[106,349],superflu:[11,491],supersus:394,superus:[5,8,12,14,15,33,50,57,75,80,83,95,109,115,124,125,126,135,139,144,148,149,150,151,154,155,158,161,170,178,182,185,198,204,206,207,217,228,232,286,322,370,393,394,398,403,416,466,470,472,500,545],supplement:28,suppli:[5,13,19,28,31,32,34,41,42,44,46,47,49,54,58,68,89,91,95,112,119,135,150,158,164,165,185,189,207,212,213,216,218,223,228,229,233,241,247,251,316,337,346,354,396,397,398,402,406,411,427,457,466,474,479,480,489,492],supporst:443,support:[3,12,13,18,22,27,28,30,31,32,35,36,41,42,59,60,62,63,64,65,67,70,75,77,84,85,88,91,95,103,104,116,118,119,120,122,123,124,131,132,133,134,135,139,142,147,150,151,153,154,156,157,158,159,165,175,181,182,185,186,190,191,192,193,194,197,198,199,204,215,224,225,228,238,244,247,260,266,270,275,289,316,338,343,355,393,398,402,403,411,421,429,430,431,432,436,438,439,440,441,443,445,456,464,469,473,476,477,478,479,489,490,492,495,524,540,545],supports_set:[32,421],suppos:[0,22,28,41,49,65,97,146,204,241],supposedli:[106,187,349,440],suppress:[183,438],suppress_ga:[201,202,412,424,545],suppressga:438,supress:438,sur:180,sure:[2,3,6,7,8,9,11,12,13,14,15,16,18,20,22,28,31,33,36,37,39,41,42,44,46,47,48,49,50,51,53,55,57,64,67,70,74,75,78,90,97,99,106,112,113,118,120,124,125,126,127,128,129,131,132,134,135,136,139,142,144,146,149,150,151,154,155,156,157,158,159,161,162,164,165,169,170,172,175,177,178,179,181,182,185,187,188,189,190,191,193,198,199,204,205,211,212,213,215,218,226,233,238,241,258,275,286,292,311,338,349,350,354,359,370,371,372,378,382,386,389,393,394,398,402,403,408,416,420,426,428,433,454,460,461,462,465,466,469,471,473,476,483,488,489,491,492,501,508,510,533,541,543],surfac:[104,115,135,140,194,275],surpris:[13,33,76,130,137,142,151],surround:[20,22,30,72,99,115,118,164,170,216,280,338,370,488,492,545],surviv:[13,19,20,27,28,30,34,42,44,47,112,127,149,164,175,205,212,228,241,289,354,396,405,406,407,411,472,474,476,492],survivor:158,suscept:[19,133,394],suspect:177,suspend:[7,193,194],suspici:28,suspicion:177,svg:238,svn:[2,69],swallow:[172,421,425,491],swam:[495,497],swap:[8,26,51,60,91,218,302,316,466,474,545],swap_autoind:474,swap_object:466,swap_typeclass:[48,204,466],swapcas:469,swapper:466,swedish:64,sweep:42,swiftli:54,swim:[495,497],swing:[22,127,128,140,150],switch1:72,switch2:72,switch_map:218,switch_opt:[215,216,217,218,223,224,225,226,228,266,316],sword:[13,22,49,67,79,86,95,104,112,127,141,144,146,153,155,157,158,161,162,201,202,235,275,281,283,291,292,294,350,354,396,403,489,492,545],swordbladerecip:293,swordguardrecip:293,swordhandlerecip:293,swordmanship:157,swordpommelrecip:293,swordrecip:[292,293],swordsmithingbaserecip:293,swum:[495,497],sylliaa:77,symbol:[7,15,16,22,69,117,118,132,146,190,230,329,332,335,337,338,340,350,386,477],symlink:[120,185],symlinkorcopi:77,symmetr:478,symmetri:8,sync:[11,44,52,65,123,337,338,339,405,434,439,454,455,456,457,464,473],sync_node_to_grid:338,sync_port:457,syncdata:[456,457],syncdb:8,synchron:[485,545],syntact:[394,492],syntax:[6,11,14,15,16,22,28,33,60,72,76,80,92,95,96,103,104,116,122,125,128,135,136,142,144,149,165,178,182,201,202,213,217,218,225,226,229,241,270,273,292,316,343,380,394,398,416,428,455,464,466,468,469,545],syntaxerror:151,sys:540,sys_cmd:211,syscmdkei:[22,121,201],syscommand:[201,202,208,214,398,545],syslog:[78,376],sysroot:190,system:[0,2,5,6,8,9,11,12,13,18,19,20,23,24,26,32,34,35,36,39,41,42,44,45,46,47,48,53,54,57,62,64,65,67,69,72,74,75,76,78,83,87,90,96,97,102,104,113,115,118,119,120,121,122,123,124,125,127,128,130,131,132,133,136,139,141,147,148,149,151,154,155,161,169,170,174,175,176,178,180,182,185,187,190,191,194,195,198,199,201,202,205,207,208,209,211,213,214,215,217,218,225,227,229,231,232,233,234,237,238,241,251,255,256,257,258,260,275,283,284,286,292,293,294,298,299,302,305,307,308,309,310,311,312,329,335,336,337,338,340,349,350,351,369,372,376,377,378,386,387,388,390,393,394,397,398,400,402,403,404,416,439,445,453,463,466,470,472,475,476,479,485,496,500,518,544,545],system_command:22,systemat:130,systemctl:181,systemd:187,systemmultimatch:227,systemnoinput:227,systemnomatch:227,tab:[0,2,7,15,51,52,60,75,129,137,151,152,154,159,469,478,491],tabl:[6,9,14,16,48,58,60,68,70,80,95,96,97,99,121,123,124,135,137,140,146,153,170,178,213,215,223,225,228,380,440,459,469,475,477,478,479,489,492,544,545],table_char:475,table_format:215,table_lin:478,table_str:135,tablea:475,tableb:475,tablechar:[135,475],tableclos:[68,440],tablecol:478,tableopen:[68,440],tablet:56,tabletop:[104,114,135,162,180,308,312],tabsiz:[469,478],tabstop:491,tabularinlin:[501,508],tack:[144,212],tackl:119,tactic:[158,162,164],taction:164,tag:[14,18,22,24,26,28,31,32,35,36,39,41,42,48,50,51,52,53,55,60,61,64,67,68,74,75,84,86,93,104,105,106,118,134,135,138,143,144,146,151,169,178,183,193,201,202,206,213,215,216,217,218,223,224,225,226,227,228,229,230,232,233,234,241,244,251,255,266,269,270,273,275,276,283,286,292,293,296,299,302,305,308,309,310,311,312,316,322,325,331,338,340,343,350,354,364,366,369,370,371,372,376,380,382,386,389,390,391,393,396,398,402,403,405,431,445,447,453,463,465,466,469,472,474,475,476,477,478,489,490,492,498,499,500,502,504,505,506,512,515,545],tag_all_charact:276,tag_categori:508,tag_charact:276,tag_data:508,tag_kei:508,tag_typ:[508,512],tagadmin:508,tagcategori:[275,276],tagcount:146,taget_map_xyz:338,tagform:508,tagformset:[501,508],taghandl:[46,48,467,508],taginlin:[500,502,504,505,506,508],tagkei:[393,396,467,472],taglin:17,tagnam:403,tagseri:515,tagshandl:515,tagstr:[403,467],tagtyp:[46,465,467,489,512],tagtypefilt:512,tail:[148,191,193,416,485],tail_log_fil:[416,485],tail_log_funct:485,tailor:[124,137,532],take:[0,3,7,8,14,15,16,17,18,19,20,22,28,29,30,32,33,39,41,44,48,54,56,57,60,62,64,65,69,75,76,78,86,87,90,92,95,96,97,99,104,107,113,115,118,119,120,122,123,124,125,126,127,128,132,133,134,135,136,137,138,141,142,144,148,149,150,151,154,155,157,158,159,160,161,163,164,165,166,167,168,169,170,174,175,177,178,180,190,191,194,195,197,204,205,210,211,215,227,232,234,247,250,273,278,280,283,286,292,305,308,309,310,311,312,316,322,325,331,335,350,364,369,370,372,376,380,382,386,394,403,436,444,447,456,457,465,466,469,474,475,476,477,479,486,490,492,493,496],taken:[0,20,123,133,152,164,165,173,174,194,224,251,308,309,310,311,312,376,389,398,436,460,469,472],takeov:458,tale:167,talk:[11,19,22,28,52,62,96,106,119,135,142,151,158,159,182,191,223,224,266,283,349,350,365,366,367,372,413,496,545],talker:122,talki:[18,123,158],talking_npc:[111,201,202,235,355,545],talkingcmdset:366,talkingnpc:[111,366],tall:[58,72,106,157,158,224,350],tallman:224,tan:293,tang:[143,293],tannin:293,tantal:15,tap:[78,104],target1:311,target2:311,target:[8,11,22,35,58,62,68,88,91,104,106,113,118,125,126,127,128,129,135,143,144,150,151,158,161,162,164,165,169,194,204,213,218,223,224,228,232,234,273,275,278,286,293,299,308,309,310,311,312,316,329,331,332,335,337,338,343,370,386,396,398,407,465,469,472,476,492],target_fire_damag:293,target_flag:275,target_loc:[276,325,329,372,398],target_map_xyz:[118,332,335,338],target_obj:394,target_path_styl:337,targetlist:299,task:[2,5,18,19,26,42,46,62,95,97,142,148,187,199,228,229,255,257,331,386,410,411,492],task_handl:[201,410,492],task_id:[228,257,410],taskhandl:[201,202,404,492,545],taskhandlertask:[410,492],tast:[76,155,159,177],tasti:292,tavern:[106,350],tax:[5,190],taylor:180,tb_basic:[114,201,202,235,281,307,545],tb_equip:[114,201,202,235,281,307,545],tb_filenam:470,tb_item:[114,201,202,235,281,307,545],tb_iter:470,tb_magic:[114,201,202,235,281,307,545],tb_rang:[114,201,202,235,281,307,545],tbbasiccharact:308,tbbasicturnhandl:308,tbearmor:309,tbequipcharact:309,tbequipturnhandl:309,tbeweapon:309,tbitemscharact:310,tbitemscharactertest:310,tbitemsturnhandl:310,tbmagiccharact:311,tbmagicturnhandl:311,tbodi:178,tbrangecharact:312,tbrangeobject:312,tbrangeturnhandl:312,tchar:164,tcp:194,tcpserver:[62,461],teach:[104,138,159],team:[2,11,22,31,69,123,156,158,159],teamciti:545,teardown:[8,229,248,258,279,294,313,335,351,353,360,442,490,516],teardown_account:490,teardown_sess:490,teaser:191,tech:[138,154,159,160,163,166,168,180,545],technic:[28,46,48,54,57,58,60,62,64,65,69,75,118,123,124,130,144,156,159,182,191,201,202,235,238,283,355,363,464,545],techniqu:[128,158,161,469],technolog:158,tediou:[7,170],teenag:[125,194],tehom:[75,146],tehomcd:75,tel:[26,55,97,135,142,143,174,185,218,331],telepath:158,telephathi:18,teleport:[15,26,55,74,104,135,141,144,155,218,224,331,335,338,372,470,545],teleport_her:218,teleportermaplink:[118,338],teleportmaplink:118,teleportroom:372,televis:20,tell:[0,3,4,9,10,11,13,14,20,22,26,28,32,33,35,36,39,41,42,54,55,57,64,65,67,73,76,78,86,88,90,95,96,97,106,125,128,132,135,137,142,143,144,148,149,150,151,152,158,162,164,167,171,174,176,178,181,182,190,191,193,194,199,205,215,223,224,234,338,343,350,372,398,416,434,445,457,474,541],telnet:[5,16,44,51,52,59,62,65,71,75,122,123,126,129,151,154,180,185,190,193,194,198,199,201,202,225,228,412,424,429,430,431,432,436,437,438,440,441,443,447,455,456,491,545],telnet_:191,telnet_hostnam:184,telnet_interfac:191,telnet_oob:[68,201,202,412,424,545],telnet_port:[2,5,75,148,184,191,448],telnet_ssl:[201,202,412,424,545],telnetoob:440,telnetprotocol:[437,439,441],telnetserverfactori:439,telport:155,temp:234,tempat:380,templ:[99,115],templat:[11,12,19,20,36,41,45,48,49,50,51,52,53,73,113,123,124,139,148,152,158,165,167,169,178,195,198,201,202,223,224,226,232,369,380,398,416,445,455,456,464,468,475,521,525,530,540,541,543,545],template2menu:[28,476],template_nam:[53,536,537,538,540,541,543],template_overrid:[51,73,124,148,169],template_regex:464,template_rend:45,template_str:[28,36],templates_overrid:73,templatestr:475,templatetag:[201,202,498,545],templateview:[53,541],tempmsg:[234,545],temporari:[8,11,13,155,199,212,234,238,260,308,309,310,311,312,411,476,545],temporarili:[0,6,8,18,20,28,42,52,112,144,149,157,191,223,228,257,292,305,354,364],tempt:[30,149,151,156,195,216],ten:[128,170,191],tend:[5,6,67,72,106,123,134,158,162,174,191,194,218,349,376],tens:[495,497],tent:170,term:[20,31,54,64,97,123,136,137,142,148,149,150,159,175,185,191,213,275,382,459],term_siz:[3,201],termin:[0,3,5,6,7,11,19,53,60,113,118,120,123,124,143,151,152,154,165,175,182,185,190,191,193,194,198,199,201,228,256,308,309,310,311,312,386,415,416,436,443,459,541],terminalrealm:436,terminals:436,terminalsessiontransport:436,terminalsessiontransport_getp:436,termux:545,terrain:[132,338],terribl:429,ters:42,test1:[13,32,478],test2010:143,test2028:143,test2:[13,22,32,60],test3:[13,478],test4:[13,478],test5:13,test6:13,test7:13,test8:13,test:[1,2,3,7,10,11,13,14,15,16,17,20,22,27,28,30,31,32,33,37,39,41,42,45,47,51,53,54,57,76,78,80,81,83,86,92,96,97,104,105,114,119,120,125,126,128,133,135,136,137,139,141,142,144,146,150,152,156,158,159,161,163,164,166,170,173,176,177,180,182,183,185,186,187,189,191,192,201,202,206,208,210,214,215,217,225,228,235,236,237,240,243,246,249,253,261,265,268,271,272,281,282,285,286,288,291,292,293,295,298,301,304,307,308,309,310,311,312,314,315,316,318,321,324,327,330,337,341,342,343,345,348,352,355,358,359,365,368,369,374,375,380,381,384,386,402,412,418,421,424,445,446,447,451,466,468,469,470,472,476,481,490,492,494,498,511,522,531,540,545],test_:8,test_about:229,test_accept:258,test_access:229,test_active_task:229,test_add:[258,290],test_add_choice_without_kei:242,test_add_float:290,test_add_multi:290,test_add_neg:290,test_add_non:290,test_add_overwrit:290,test_add_trait:353,test_add_valid:258,test_al:353,test_all_com:267,test_all_st:279,test_alternative_cal:8,test_amp_in:442,test_amp_out:442,test_at_repeat:360,test_attribute_command:229,test_audit:378,test_auto_creating_bucket:239,test_auto_creating_bucket_with_acl:239,test_available_languag:351,test_ban:229,test_base_pars:279,test_base_search:279,test_base_st:279,test_batch_command:229,test_bold:442,test_boundaries__bigmod:353,test_boundaries__change_boundari:353,test_boundaries__dis:353,test_boundaries__invers:353,test_boundaries__minmax:353,test_bridgeroom:373,test_build:335,test_c_creates_button:452,test_c_creates_obj:452,test_c_dig:452,test_c_examin:452,test_c_help:452,test_c_login:452,test_c_login_no_dig:452,test_c_logout:452,test_c_look:452,test_c_mov:452,test_c_move_:452,test_c_move_n:452,test_c_soci:452,test_cach:353,test_cal:[229,258],test_callback:242,test_cancel:229,test_cas:8,test_cboot:267,test_cdesc:267,test_cdestroi:267,test_channel__al:229,test_channel__alias__unalia:229,test_channel__ban__unban:229,test_channel__boot:229,test_channel__cr:229,test_channel__desc:229,test_channel__destroi:229,test_channel__histori:229,test_channel__list:229,test_channel__lock:229,test_channel__msg:229,test_channel__mut:229,test_channel__noarg:229,test_channel__sub:229,test_channel__unlock:229,test_channel__unmut:229,test_channel__unsub:229,test_channel__who:229,test_char_cr:229,test_char_delet:229,test_clean_nam:239,test_clean_name_norm:239,test_clean_name_trailing_slash:239,test_clean_name_window:239,test_cleanup:290,test_cleanup_doesnt_delete_anyth:290,test_clear:[290,353],test_climb:373,test_clock:267,test_clothingcommand:287,test_clothingfunct:287,test_cmd_armpuzzl:306,test_cmd_puzzl:306,test_cmd_us:306,test_cmddic:344,test_cmdextendedlook:317,test_cmdgametim:317,test_cmdmultidesc:303,test_cmdopen:323,test_cmdset_puzzl:306,test_cmdsetdetail:317,test_cmdtrad:284,test_cmdtradehelp:284,test_cmdtutori:373,test_color:442,test_color_test:229,test_command:351,test_comparisons_numer:353,test_comparisons_trait:353,test_compress_content_len:239,test_connect:252,test_connection_thread:239,test_content_typ:239,test_copi:229,test_craft__nocons__failur:294,test_craft__notools__failur:294,test_craft__success:294,test_craft_cons_excess__fail:294,test_craft_cons_excess__sucess:294,test_craft_cons_order__fail:294,test_craft_hook__fail:294,test_craft_hook__succe:294,test_craft_missing_cons__always_consume__fail:294,test_craft_missing_cons__fail:294,test_craft_missing_tool__fail:294,test_craft_sword:294,test_craft_tool_excess__fail:294,test_craft_tool_excess__sucess:294,test_craft_tool_order__fail:294,test_craft_wrong_tool__fail:294,test_creat:[229,516],test_create_wilderness_custom_nam:328,test_create_wilderness_default_nam:328,test_crumblingwal:373,test_curly_markup:245,test_curr:353,test_custom_gametim:248,test_cwho:267,test_darkroom:373,test_data_in:442,test_data_out:442,test_del:258,test_delet:[353,516],test_desc:[229,353],test_desc_default_to_room:229,test_destroi:229,test_destroy_sequ:229,test_dig:229,test_do_nested_lookup:229,test_do_task:229,test_e2:306,test_e2e_accumul:306,test_e2e_interchangeable_parts_and_result:306,test_echo:490,test_edit:258,test_edit_valid:258,test_emit:229,test_emot:279,test_empti:290,test_empty_desc:229,test_enter_wild:328,test_enter_wilderness_custom_coordin:328,test_enter_wilderness_custom_nam:328,test_error_format:294,test_examin:229,test_exit:[258,326],test_exit_command:229,test_extend:290,test_extend_float:290,test_extend_neg:290,test_extend_non:290,test_extended_path_tracking__horizont:335,test_extended_path_tracking__vert:335,test_failur:269,test_faulty_languag:351,test_field_funct:385,test_find:229,test_floordiv:353,test_focu:279,test_focus_interact:279,test_forc:229,test_func_name_manipul:229,test_gametime_to_realtim:248,test_gendercharact:297,test_gener:383,test_general_context:527,test_generated_url_is_encod:239,test_get:[353,533],test_get_and_drop:229,test_get_authent:533,test_get_dis:533,test_get_new_coordin:328,test_get_shortest_path:335,test_get_visual_range__nodes__charact:335,test_get_visual_range__nodes__character_0:335,test_get_visual_range__nodes__character_1:335,test_get_visual_range__nodes__character_2:335,test_get_visual_range__nodes__character_3:335,test_get_visual_range__nodes__character_4:335,test_get_visual_range__nodes__character_5:335,test_get_visual_range__nodes__character_6:335,test_get_visual_range__nodes__character_7:335,test_get_visual_range__nodes__character_8:335,test_get_visual_range__nodes__character_9:335,test_get_visual_range__scan:335,test_get_visual_range__scan_0:335,test_get_visual_range__scan_1:335,test_get_visual_range__scan_2:335,test_get_visual_range__scan_3:335,test_get_visual_range__scan__charact:335,test_get_visual_range__scan__character_0:335,test_get_visual_range__scan__character_1:335,test_get_visual_range__scan__character_2:335,test_get_visual_range__scan__character_3:335,test_get_visual_range_with_path:335,test_get_visual_range_with_path_0:335,test_get_visual_range_with_path_1:335,test_get_visual_range_with_path_2:335,test_get_visual_range_with_path_3:335,test_get_visual_range_with_path_4:335,test_giv:229,test_grid_cr:335,test_grid_creation_0:335,test_grid_creation_1:335,test_grid_pathfind:335,test_grid_pathfind_0:335,test_grid_pathfind_1:335,test_grid_vis:335,test_grid_visibility_0:335,test_grid_visibility_1:335,test_handl:258,test_healthbar:347,test_hello_world:152,test_help:229,test_hom:229,test_ic:229,test_ic__nonaccess:229,test_ic__other_object:229,test_ident:442,test_idl:452,test_info_command:229,test_init:353,test_interrupt_command:229,test_introroom:373,test_invalid_access:533,test_inventori:229,test_ital:442,test_large_msg:442,test_lightsourc:373,test_list:[258,516],test_list_cmdset:229,test_load_recip:294,test_location_leading_slash:239,test_location_search:8,test_lock:[229,258],test_lock_with_perm:533,test_locked_entri:533,test_look:[229,279],test_lspuzzlerecipes_lsarmedpuzzl:306,test_mail:300,test_mapping_with_opt:497,test_mapping_with_options_00_y:497,test_mapping_with_options_01_y:497,test_mapping_with_options_02_i:497,test_mapping_with_options_03_i:497,test_mapping_with_options_04_i:497,test_mapping_with_options_05_m:497,test_mapping_with_options_06_your:497,test_mapping_with_options_07_our:497,test_mapping_with_options_08_yourself:497,test_mapping_with_options_09_yourself:497,test_mapping_with_options_10_yourself:497,test_mapping_with_options_11_yourself:497,test_mapping_with_options_12_yourselv:497,test_mapping_with_options_13_h:497,test_mapping_with_options_14_h:497,test_mapping_with_options_15_h:497,test_mapping_with_options_16_h:497,test_mapping_with_options_17_h:497,test_mapping_with_options_18_their:497,test_mapping_with_options_19_their:497,test_mapping_with_options_20_itself:497,test_mapping_with_options_21_themselv:497,test_mapping_with_options_22_herself:497,test_mask:378,test_memplot:452,test_menu:[113,386],test_messag:453,test_misformed_command:229,test_mob:373,test_msg:294,test_mudlet_ttyp:442,test_mul_trait:353,test_multi_level:242,test_multimatch:229,test_mux_command:229,test_mux_markup:245,test_mycmd_char:8,test_mycmd_room:8,test_nam:229,test_nested_attribute_command:229,test_new_task_waiting_input:229,test_nick:229,test_no_input:229,test_no_task:229,test_node_from_coord:335,test_obelisk:373,test_obfuscate_languag:351,test_obfuscate_whisp:351,test_object:229,test_object_cach:533,test_object_search_charact:8,test_ooc:229,test_ooc_look:229,test_opt:229,test_ordered_permutation_regex:351,test_outroroom:373,test_override_class_vari:239,test_override_init_argu:239,test_overwrit:279,test_pag:229,test_parse_for_perspect:279,test_parse_for_th:279,test_parse_languag:351,test_password:229,test_path:335,test_paths_0:335,test_paths_1:335,test_pause_unpaus:229,test_percentag:353,test_perm:229,test_persistent_task:229,test_pi:229,test_pickle_with_bucket:239,test_pickle_without_bucket:239,test_plain_ansi:442,test_pos:229,test_pos_shortcut:353,test_pre_craft:294,test_pre_craft_fail:294,test_puzzleedit:306,test_puzzleedit_add_remove_parts_result:306,test_quel:229,test_queri:[201,202,412,446,545],test_quit:[229,242,252],test_read:373,test_real_seconds_until:248,test_realtime_to_gametim:248,test_recog_handl:351,test_regex_tuple_from_key_alia:351,test_remov:[229,353],test_repr:353,test_reset:290,test_reset_non_exist:290,test_resourc:[8,201,202,229,242,245,248,252,258,267,269,279,284,287,290,294,297,300,303,306,313,317,323,326,328,335,344,347,351,353,360,367,373,378,383,385,442,468,516,533,545],test_responce_of_y:229,test_retriev:516,test_return_appear:317,test_return_detail:317,test_return_valu:8,test_roll_dic:344,test_room_cr:328,test_room_method:279,test_rpsearch:351,test_sai:229,test_schedul:248,test_script:229,test_script_multi_delet:229,test_sdesc_handl:351,test_seed__success:294,test_send_case_sensitive_emot:351,test_send_emot:351,test_send_random_messag:360,test_server_load:229,test_sess:229,test_set:353,test_set_attribut:516,test_set_focu:279,test_set_help:229,test_set_hom:229,test_set_obj_alia:229,test_setattr:242,test_setgend:297,test_shortest_path:335,test_shortest_path_00:335,test_shortest_path_01:335,test_shortest_path_02:335,test_shortest_path_03:335,test_shortest_path_04:335,test_shortest_path_05:335,test_shortest_path_06:335,test_shortest_path_07:335,test_shortest_path_08:335,test_shortest_path_09:335,test_shortest_path_0:335,test_shortest_path_10:335,test_shortest_path_1:335,test_shortest_path_2:335,test_shortest_path_3:335,test_shortest_path_4:335,test_shortest_path_5:335,test_shortest_path_6:335,test_shortest_path_7:335,test_shortest_path_8:335,test_shortest_path_9:335,test_simple_default:229,test_spawn:[229,335],test_special_charact:239,test_speech:279,test_split_nested_attr:229,test_start:258,test_storage_delet:239,test_storage_exist:239,test_storage_exists_doesnt_create_bucket:239,test_storage_exists_fals:239,test_storage_listdir_bas:239,test_storage_listdir_subdir:239,test_storage_mtim:239,test_storage_open_no_overwrite_exist:239,test_storage_open_no_writ:239,test_storage_open_writ:239,test_storage_s:239,test_storage_sav:239,test_storage_save_gzip:239,test_storage_save_gzip_twic:239,test_storage_save_with_acl:239,test_storage_url:239,test_storage_url_slash:239,test_storage_write_beyond_buffer_s:239,test_str_output:335,test_strip_signing_paramet:239,test_sub_trait:353,test_submenu:242,test_subtopic_fetch:229,test_subtopic_fetch_00_test:229,test_subtopic_fetch_01_test_creating_extra_stuff:229,test_subtopic_fetch_02_test_cr:229,test_subtopic_fetch_03_test_extra:229,test_subtopic_fetch_04_test_extra_subsubtop:229,test_subtopic_fetch_05_test_creating_extra_subsub:229,test_subtopic_fetch_06_test_something_els:229,test_subtopic_fetch_07_test_mor:229,test_subtopic_fetch_08_test_more_second_mor:229,test_subtopic_fetch_09_test_more_mor:229,test_subtopic_fetch_10_test_more_second_more_again:229,test_subtopic_fetch_11_test_more_second_third:229,test_success:269,test_tag:229,test_talkingnpc:367,test_task_complete_waiting_input:229,test_tbbasicfunc:313,test_tbequipfunc:313,test_tbitemsfunc:313,test_tbrangefunc:313,test_teleport:229,test_teleportroom:373,test_time_to_tupl:248,test_timer_r:353,test_timer_ratetarget:353,test_toggle_com:267,test_tradehandler_bas:284,test_tradehandler_join:284,test_tradehandler_off:284,test_trait_db_connect:353,test_trait_getset:353,test_traitfield:353,test_tree_funct:385,test_tunnel:229,test_tunnel_exit_typeclass:229,test_turnbattlecmd:313,test_turnbattleequipcmd:313,test_turnbattleitemcmd:313,test_turnbattlemagiccmd:313,test_turnbattlerangecmd:313,test_tutorialobj:373,test_typeclass:229,test_unconnectedhelp:252,test_unconnectedlook:252,test_upd:516,test_valid_access:533,test_valid_access_multisession_0:533,test_valid_access_multisession_2:533,test_valid_char:533,test_validate_input__fail:353,test_validate_input__valid:353,test_valu:353,test_verb_actor_stance_compon:497,test_verb_actor_stance_components_00_hav:497,test_verb_actor_stance_components_01_swim:497,test_verb_actor_stance_components_02_g:497,test_verb_actor_stance_components_03_given:497,test_verb_actor_stance_components_04_am:497,test_verb_actor_stance_components_05_do:497,test_verb_actor_stance_components_06_ar:497,test_verb_actor_stance_components_07_had:497,test_verb_actor_stance_components_08_grin:497,test_verb_actor_stance_components_09_smil:497,test_verb_actor_stance_components_10_vex:497,test_verb_actor_stance_components_11_thrust:497,test_verb_conjug:497,test_verb_conjugate_0_inf:497,test_verb_conjugate_1_inf:497,test_verb_conjugate_2_inf:497,test_verb_conjugate_3_inf:497,test_verb_conjugate_4_inf:497,test_verb_conjugate_5_inf:497,test_verb_conjugate_6_inf:497,test_verb_conjugate_7_2sgpr:497,test_verb_conjugate_8_3sgpr:497,test_verb_get_all_tens:497,test_verb_infinit:497,test_verb_infinitive_0_hav:497,test_verb_infinitive_1_swim:497,test_verb_infinitive_2_g:497,test_verb_infinitive_3_given:497,test_verb_infinitive_4_am:497,test_verb_infinitive_5_do:497,test_verb_infinitive_6_ar:497,test_verb_is_past:497,test_verb_is_past_0_1st:497,test_verb_is_past_1_1st:497,test_verb_is_past_2_1st:497,test_verb_is_past_3_1st:497,test_verb_is_past_4_1st:497,test_verb_is_past_5_1st:497,test_verb_is_past_6_1st:497,test_verb_is_past_7_2nd:497,test_verb_is_past_participl:497,test_verb_is_past_participle_0_hav:497,test_verb_is_past_participle_1_swim:497,test_verb_is_past_participle_2_g:497,test_verb_is_past_participle_3_given:497,test_verb_is_past_participle_4_am:497,test_verb_is_past_participle_5_do:497,test_verb_is_past_participle_6_ar:497,test_verb_is_past_participle_7_had:497,test_verb_is_pres:497,test_verb_is_present_0_1st:497,test_verb_is_present_1_1st:497,test_verb_is_present_2_1st:497,test_verb_is_present_3_1st:497,test_verb_is_present_4_1st:497,test_verb_is_present_5_1st:497,test_verb_is_present_6_1st:497,test_verb_is_present_7_1st:497,test_verb_is_present_participl:497,test_verb_is_present_participle_0_hav:497,test_verb_is_present_participle_1_swim:497,test_verb_is_present_participle_2_g:497,test_verb_is_present_participle_3_given:497,test_verb_is_present_participle_4_am:497,test_verb_is_present_participle_5_do:497,test_verb_is_present_participle_6_ar:497,test_verb_is_tens:497,test_verb_is_tense_0_inf:497,test_verb_is_tense_1_inf:497,test_verb_is_tense_2_inf:497,test_verb_is_tense_3_inf:497,test_verb_is_tense_4_inf:497,test_verb_is_tense_5_inf:497,test_verb_is_tense_6_inf:497,test_verb_past:497,test_verb_past_0_1st:497,test_verb_past_1_1st:497,test_verb_past_2_1st:497,test_verb_past_3_1st:497,test_verb_past_4_1st:497,test_verb_past_5_1st:497,test_verb_past_6_1st:497,test_verb_past_7_2nd:497,test_verb_past_participl:497,test_verb_past_participle_0_hav:497,test_verb_past_participle_1_swim:497,test_verb_past_participle_2_g:497,test_verb_past_participle_3_given:497,test_verb_past_participle_4_am:497,test_verb_past_participle_5_do:497,test_verb_past_participle_6_ar:497,test_verb_pres:497,test_verb_present_0_1st:497,test_verb_present_1_1st:497,test_verb_present_2_1st:497,test_verb_present_3_1st:497,test_verb_present_4_1st:497,test_verb_present_5_1st:497,test_verb_present_6_1st:497,test_verb_present_7_2nd:497,test_verb_present_8_3rd:497,test_verb_present_participl:497,test_verb_present_participle_0_hav:497,test_verb_present_participle_1_swim:497,test_verb_present_participle_2_g:497,test_verb_present_participle_3_given:497,test_verb_present_participle_4_am:497,test_verb_present_participle_5_do:497,test_verb_present_participle_6_ar:497,test_verb_tens:497,test_verb_tense_0_hav:497,test_verb_tense_1_swim:497,test_verb_tense_2_g:497,test_verb_tense_3_given:497,test_verb_tense_4_am:497,test_verb_tense_5_do:497,test_verb_tense_6_ar:497,test_view:533,test_wal:229,test_weapon:373,test_weaponrack:373,test_weatherroom:373,test_whisp:229,test_who:229,test_wilderness_correct_exit:328,test_without_migr:8,test_wrong_func_nam:229,testaccount2:8,testaccount:[8,229],testadmin:229,testampserv:442,testapp:177,testbart:284,testbatchprocess:229,testbodyfunct:360,testbuild:229,testbuildexamplegrid:335,testbuildingmenu:242,testcas:[8,239,335,373,442,452,484,490,497,527],testclothingcmd:287,testclothingfunc:287,testcmdcallback:258,testcmdtask:229,testcolormarkup:245,testcomm:229,testcommand:28,testcommschannel:229,testcooldown:290,testcraftcommand:294,testcraftingrecip:294,testcraftingrecipebas:294,testcraftsword:294,testcraftutil:294,testcustomgametim:248,testdefaultcallback:258,testdic:344,testdummyrunnerset:452,testemaillogin:252,tester:[8,146,191,434],testevenniarestapi:516,testeventhandl:258,testevscaperoom:279,testevscaperoomcommand:279,testextendedroom:317,testfieldfillfunc:385,testform:475,testgendersub:297,testgener:229,testgeneralcontext:527,testhealthbar:347,testhelp:229,testid:22,testinterruptcommand:229,testirc:442,testlanguag:351,testlegacymuxcomm:267,testmail:300,testmap10:335,testmap11:335,testmap1:335,testmap2:335,testmap3:335,testmap4:335,testmap5:335,testmap6:335,testmap7:335,testmap8:335,testmap9:335,testmapstresstest:335,testmemplot:452,testmenu:[380,476],testmixedrefer:484,testmod:457,testmultidesc:303,testmymodel:8,testnnmain:229,testnumerictraitoper:353,testobj:[8,278,280],testobject:8,testobjectdelet:484,testok:142,testpronounmap:497,testpuzzl:306,testrandomstringgener:383,testregularrefer:484,testrenam:143,testrpsystem:351,testrpsystemcommand:351,testset:8,testsharedmemoryrefer:484,testsimpledoor:323,testslowexit:326,teststat:279,testsystem:229,testsystemcommand:229,testtabl:143,testtalkingnpc:367,testtelnet:442,testtrait:353,testtraitcount:353,testtraitcountertim:353,testtraitfield:353,testtraitgaug:353,testtraitgaugetim:353,testtraitstat:353,testtreeselectfunc:385,testturnbattlebasiccmd:313,testturnbattlebasicfunc:313,testturnbattleequipcmd:313,testturnbattleequipfunc:313,testturnbattleitemscmd:313,testturnbattleitemsfunc:313,testturnbattlemagiccmd:313,testturnbattlemagicfunc:313,testturnbattlerangecmd:313,testturnbattlerangefunc:313,testtutorialworldmob:373,testtutorialworldobject:373,testtutorialworldroom:373,testunconnectedcommand:229,testunixcommand:269,testutil:279,testverbconjug:497,testview:53,testwebsocket:442,testwild:328,testxyzgrid:335,testxyzgridtransit:335,text2html:[201,202,468,545],text:[0,6,11,12,13,14,15,16,17,18,22,25,26,27,29,30,31,33,35,36,39,41,42,46,51,53,54,58,59,60,62,64,65,67,68,69,75,76,82,90,91,92,93,94,96,97,104,106,112,118,119,121,122,125,129,133,134,135,139,141,142,144,148,150,152,154,155,157,158,159,160,161,162,165,170,172,174,175,177,179,180,183,185,187,189,191,192,193,199,204,205,210,213,215,216,217,218,223,224,225,226,227,228,229,230,233,234,238,241,250,251,255,257,266,269,270,273,274,275,280,283,286,292,293,296,299,302,305,308,309,310,311,312,316,322,325,331,343,346,349,350,354,362,364,366,370,371,372,377,380,386,388,390,391,394,398,400,403,406,413,414,421,427,428,431,434,435,436,439,440,444,445,447,455,456,457,460,461,464,465,467,469,470,472,474,475,476,477,478,479,486,489,490,491,492,493,500,502,506,532,544,545],text_:120,text_color:346,text_descript:[112,354],text_exit:[76,241],text_single_exit:76,textarea:[488,532],textbook:62,textbox:532,textfield:[67,177],textn:229,textstr:32,texttag:[139,175],texttohtmlpars:491,textual:130,textwrap:478,textwrapp:478,than:[0,3,4,5,6,7,8,9,11,12,13,14,15,18,20,22,24,25,28,29,30,31,33,37,39,41,42,44,46,47,48,51,53,56,57,58,60,64,67,70,72,73,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,122,123,124,126,128,130,132,134,135,136,137,140,142,143,146,148,149,150,151,153,154,155,156,157,159,161,162,164,165,175,178,181,182,184,187,188,191,194,195,197,199,204,207,210,211,212,215,216,217,218,219,225,226,228,229,241,247,250,257,266,270,275,278,283,292,308,309,310,311,312,325,333,337,338,339,340,346,349,350,354,371,382,386,393,396,398,400,402,416,442,457,462,464,465,466,467,469,470,476,477,478,479,483,485,487,488,489,491,492,501,508,521,541,545],thank:[28,124,178,299,461],thankfulli:177,the_answ:153,the_one_r:153,thead:178,theathr:31,theatr:31,thei:[3,4,5,6,7,8,11,12,13,14,15,16,17,18,19,20,22,28,30,31,33,37,39,40,41,42,44,45,46,48,50,51,52,53,54,55,56,57,58,60,62,63,64,65,67,68,69,70,74,75,76,77,79,80,85,86,91,93,95,96,97,99,104,106,109,112,116,117,118,120,122,123,124,125,126,128,129,130,131,133,134,135,137,138,139,141,142,143,144,145,146,148,149,150,151,152,153,156,157,159,161,162,164,165,169,170,172,174,175,176,178,179,181,182,185,190,191,194,198,199,204,211,212,215,217,218,223,224,226,227,228,232,238,241,250,256,266,270,275,283,286,289,292,293,296,308,309,310,311,312,316,329,337,338,340,343,349,350,354,371,372,388,393,394,397,398,402,403,404,406,408,409,411,416,436,437,439,440,441,445,448,454,455,456,457,459,464,469,470,471,473,476,478,479,492,493,496,501,508,513,515,518,532,538,542,543,545],theirs:[58,93,164,296,479,496,497],them:[0,5,6,7,8,9,11,12,13,14,15,16,18,19,20,22,25,27,28,30,31,32,33,35,36,37,39,41,42,44,46,47,48,50,51,53,54,55,56,58,60,62,63,64,65,67,68,70,73,74,75,76,77,78,84,86,90,91,93,94,95,96,97,104,105,106,112,113,118,119,120,122,123,124,125,127,128,129,130,134,135,136,137,140,141,142,143,146,148,149,150,151,152,153,155,156,157,159,161,162,164,165,168,169,170,172,174,175,177,178,182,184,188,190,191,192,194,195,199,204,209,210,211,213,215,217,218,223,225,226,229,232,233,238,244,250,254,256,270,276,286,292,293,296,305,308,309,310,311,312,316,337,346,350,354,364,370,372,380,382,386,389,394,398,403,408,411,416,434,436,439,447,451,454,455,457,464,466,467,469,470,472,476,479,488,490,491,496,501,508,510,515,523,538,541,543,545],themat:156,theme:[53,148,156,158,178],themself:310,themselv:[6,13,18,20,22,28,33,37,45,48,57,58,70,74,90,95,97,104,106,112,120,122,125,127,132,135,137,139,141,148,157,158,161,162,165,174,176,189,218,275,338,350,398,406,409,416,465,467,479,488,496,497],theoret:[20,69,118,160,340],theori:[3,20,134,165,180,204,211,545],thereaft:36,therefor:[42,97,118,132,136,142,155,217,241,254,275],therein:[16,22,215,226,228,230,273,305,316,372],thereof:[350,398],thess:396,thet:148,thi:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19,20,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,160,161,162,163,164,165,166,167,169,170,171,172,173,174,175,176,177,178,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,197,198,199,200,201,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,238,241,242,244,245,247,250,251,254,255,256,257,260,266,270,273,274,275,276,277,278,280,283,286,289,292,293,294,296,299,302,305,308,309,310,311,312,316,322,325,329,331,332,333,334,335,337,338,339,340,343,346,349,350,353,354,359,362,364,366,369,370,371,372,376,377,380,382,386,387,388,389,390,391,392,393,394,395,396,397,398,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,418,420,421,422,423,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,443,444,445,447,448,449,450,451,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,483,484,485,486,487,488,489,490,491,492,493,495,496,498,500,501,502,504,505,506,507,508,510,512,513,515,518,521,523,524,525,529,530,532,534,536,537,538,539,540,541,542,543,544,545],thie:28,thieveri:225,thin:[54,76,83,128,170,286,485],thing:[0,1,5,6,8,9,10,11,13,14,16,18,19,20,22,27,28,30,31,32,37,39,41,44,45,47,48,51,53,54,55,57,58,60,62,64,65,67,69,72,73,75,76,78,79,82,86,95,96,97,104,106,112,113,115,116,118,119,122,123,124,125,126,127,128,129,130,132,135,137,138,140,141,142,143,144,146,147,148,150,151,155,156,157,159,161,162,163,164,165,167,169,170,172,174,175,176,177,178,180,181,185,188,190,191,193,194,195,197,198,199,204,211,212,218,241,257,270,275,280,283,292,293,312,316,349,350,354,364,369,372,386,394,397,398,425,429,461,464,466,469,470,478,479,488,501,508,510,541,543,544,545],things_styl:280,think:[0,6,11,20,35,39,41,46,47,52,53,60,73,95,96,104,115,118,119,122,128,136,139,142,143,144,151,153,154,156,160,161,162,163,166,168,170,180,187,197,457,541],third:[3,9,13,19,28,30,59,75,95,97,119,120,123,130,137,151,159,161,174,178,181,182,189,190,191,218,229,275,469,476,479,545],third_person:280,thirdnod:28,this_is_provided_by_amazon:77,this_sign:458,thoma:[36,55,216],thorn:[37,153],thorough:0,those:[2,8,9,10,11,12,13,14,15,16,18,20,22,25,28,30,33,37,39,41,44,46,48,53,57,58,60,67,68,73,75,77,78,99,104,106,112,113,114,118,122,123,124,125,127,129,131,133,134,135,136,138,139,141,143,144,146,149,150,151,153,154,155,156,157,159,161,162,165,167,169,170,172,174,179,180,182,185,188,191,194,197,199,212,213,215,218,223,224,225,229,233,241,273,280,292,293,308,350,354,364,371,372,377,386,394,402,403,405,410,439,444,447,465,466,476,477,478,486,487,490,492,515,532,537,538,540,545],though:[0,6,9,12,13,14,15,16,19,20,28,37,50,54,55,64,72,76,81,82,95,103,104,112,118,119,123,129,130,134,136,137,139,142,143,145,147,149,151,155,157,158,159,161,164,165,174,175,180,182,185,187,189,190,191,193,194,195,199,204,213,241,270,308,309,311,312,338,346,354,372,398,402,403,464,469,476,492],thought:[33,34,130,151,156,158,180,182],thousand:[130,170,177,191],thread:[19,180,182,199,435,461,485,492],threadpool:461,threadsaf:[501,508],threat:194,three:[13,14,18,20,22,28,31,33,36,37,55,56,58,60,65,73,76,77,95,96,97,113,120,124,126,137,141,145,151,153,157,163,177,178,191,210,223,225,311,339,386,394,469,476],threshold:[118,360,459,470],thrill:141,throttl:[201,202,204,412,421,434,545],through:[5,6,7,12,14,15,17,19,20,22,28,29,30,31,33,36,37,41,42,44,45,50,52,53,62,65,68,69,74,75,79,90,91,95,96,97,104,109,114,115,118,120,122,123,126,129,130,131,133,134,135,136,137,141,142,147,148,152,153,154,155,158,159,160,161,163,164,168,169,171,174,182,188,191,192,194,195,197,199,201,204,212,218,223,225,245,254,278,279,283,308,309,310,311,312,316,322,329,337,338,377,392,394,397,398,407,408,411,416,418,423,432,436,439,445,448,453,455,456,465,466,470,472,475,476,477,490,491,492,501,508,532,541,545],throughout:[28,90,122,132,144,195,310,335],throughput:[232,233,472],thrown:[164,293],thrust:[371,497],thu:[15,18,20,22,28,30,33,35,39,48,57,60,65,67,69,73,77,130,131,134,135,146,151,158,162,165,169,170,174,178,184,206,215,219,337,338,340,349,350,394,398,411,448,462,464,465,472],thud:[93,296],thumb:[4,11,60],thumbnail:124,thunder:[99,182],thunderstorm:155,thusli:190,tick:[5,22,28,42,47,81,115,120,123,176,182,279,310,370,372,411,448],ticker1:[47,411],ticker2:[47,411],ticker:[26,32,42,121,143,176,205,228,370,372,407,411,421,492,545],ticker_class:411,ticker_handl:[47,121,176,201,411,492],ticker_pool_class:411,ticker_storag:411,tickerhandl:[19,24,42,85,110,164,176,201,202,228,289,310,325,372,404,492,545],tickerpool:411,tickerpool_layout:411,tidbit:122,tidi:193,tie:[137,164,340,545],tied:[18,83,95,104,123,153,212,225,275,278,286,339,364,390,405],tier:[77,191,238],ties:[53,73,132,220],tight:[83,286],tightli:[39,77,194,232],tild:146,tim:[83,92,94,104,113,114,285,286,307,308,309,310,311,312,345,346,379,380,384,386],time:[0,2,3,5,7,8,9,11,12,13,14,15,17,18,20,26,28,29,30,31,33,35,37,41,44,47,48,54,55,60,62,63,65,67,68,70,72,73,75,76,77,79,80,85,86,87,90,97,99,104,105,106,108,110,112,113,114,115,118,119,121,122,123,124,125,126,127,128,129,130,132,133,135,137,138,142,143,144,146,148,149,150,151,152,153,155,156,157,159,161,162,164,165,171,174,176,177,181,182,184,185,186,187,189,190,191,193,195,199,204,205,207,209,210,212,213,216,223,228,232,233,234,238,247,248,256,257,260,275,283,289,292,293,305,308,309,310,311,312,316,322,325,343,349,353,354,359,364,370,371,372,382,386,390,397,398,401,403,404,405,406,409,410,411,416,418,420,422,423,428,434,439,441,447,448,449,453,454,455,457,459,464,466,467,469,470,471,472,477,480,483,484,485,488,492,501,508,545],time_ev:260,time_factor:[19,136,247,480],time_format:[492,545],time_game_epoch:[19,136,480],time_left:289,time_str:136,time_to_tupl:247,time_unit:[87,136,247],time_until_next_repeat:42,timed_script:42,timedelai:[128,410,490,492],timedelta:[486,493],timeeventscript:257,timefactor:136,timeformat:[485,492],timeit:5,timelin:159,timeout:[164,173,185,187,439,459,483],timer:[19,22,47,65,81,85,91,104,108,123,133,144,147,148,158,164,218,289,310,316,353,359,364,371,404,405,409,410,411,447,455,489,518,545],timerobject:42,timerscript:42,timescript:480,timeslot:[91,316],timestamp:[19,64,126,317,447,448,459,480],timestep:[5,448],timestr:485,timetrac:[201,202,412,446,545],timetupl:136,timezon:[182,238,485,486,493],tin:152,tini:[130,139,182],tinker:6,tintin:[183,429,430,440,443],tinyfugu:183,tinymud:[69,134],tinymush:[69,72,134,230],tinymux:[69,134],tip:[46,180,194,545],tire:[144,212],titeuf87:[104,117,327,329],titl:[0,17,51,76,82,120,137,192,223,225,233,241,242,276,350,389,469,472,543,545],title_lone_categori:225,titlebar:51,titleblock:137,tlen:188,tls:181,tlsv10:187,tlsv1:181,tmp:[2,185],tmpmsg:18,to_be_impl:539,to_byt:[492,545],to_closed_st:364,to_cur:310,to_displai:241,to_dupl:211,to_execut:492,to_exit:[95,97],to_fil:[78,376],to_init:312,to_non:398,to_obj:[204,213,398],to_object:233,to_open_st:364,to_pickl:473,to_str:[492,545],to_syslog:376,tobox:425,todai:[94,158,346],todo:[23,38,43,66,135,145,163,166,168,196],toe:[69,151],togeth:[13,15,20,22,30,31,37,40,48,61,65,75,76,90,97,98,102,104,105,118,120,123,128,132,134,135,146,148,151,152,153,155,156,157,158,159,161,162,164,165,166,167,175,181,188,191,209,218,220,225,276,292,293,302,305,316,337,338,349,350,371,372,396,397,403,425,444,457,469,470,489,501,508,545],toggl:[139,439],toggle_nop_keepal:439,togglecolor:139,togrid:118,toi:86,toint:[30,41,479],token:[18,161,188,436,439,470,479],told:[9,58,60,70,131,142,148,151,165,191,488],tolimbo:118,tolkien:136,tom:[30,36,58,72,93,106,135,157,165,218,224,296,350,475,479,495],tomb:115,tomdesmedt:495,tommi:[36,39,57,479],ton:[134,140],tone:60,tonon:[218,331],too:[3,5,7,9,13,14,15,17,18,19,22,28,31,34,48,50,55,58,60,65,75,76,95,96,97,113,115,120,124,125,126,128,130,132,134,135,141,142,143,144,147,149,150,153,154,156,157,158,159,161,162,164,165,174,177,185,216,218,235,293,294,311,338,339,364,386,393,396,421,425,459,461,467,470,475,476,477,478,489,492],took:[8,147,492],tool2:294,tool:[30,39,41,46,50,53,60,67,69,86,104,118,121,123,124,128,134,136,149,151,153,154,156,158,159,160,163,166,168,169,170,181,182,185,187,191,193,292,293,294,544,545],tool_kwarg:292,tool_nam:292,tool_tag:[86,292,293],tool_tag_categori:[86,292],toolbox:180,toolkit:53,tooltip:51,top:[0,5,10,11,14,20,22,27,29,30,31,42,46,48,50,53,58,75,76,83,86,90,102,117,118,120,128,130,134,135,137,141,143,147,150,151,152,165,170,171,177,178,180,185,190,195,199,207,212,234,241,247,270,273,286,302,329,337,338,350,386,388,390,397,406,416,458,464,466,467,470,477,478,485],topcistr:389,topic:[3,5,20,22,31,44,50,54,62,64,67,78,122,124,137,144,146,149,151,158,175,225,273,275,308,309,310,311,312,389,391,489,532,540],topicstr:389,topolog:[104,118,337,338],toppl:95,tostr:425,total:[5,19,33,44,49,60,77,95,118,136,140,142,157,172,195,206,228,238,338,343,453,477,478,480],total_num:483,touch:[6,60,120,148,149,181,184,194,195,459],tour:[142,148,154,160,163,166,168],toward:[3,22,62,76,99,118,142,156,158,159,170,312,346,370],tower:[170,316,372],town:[118,331],trace:[65,118,257,338,453,476],traceback:[6,8,14,19,42,53,64,73,95,134,143,151,165,177,199,257,302,401,425,466,470,485,492,545],tracemessag:453,track:[9,13,19,42,44,67,85,90,104,108,112,114,123,129,132,134,140,148,151,156,157,162,164,174,176,177,192,193,204,212,232,289,312,335,338,354,407,427,428,433,436,439,454,459,473,474,486,545],tracker:[26,115],trade:[79,96,104,157,158,283],tradehandl:[79,283],trader:96,tradetimeout:283,tradit:[2,16,32,54,60,65,144,148,151,158,162,164,191,194,292,329,439,455,477],tradition:[65,134,156,158,159,293],traffic:[77,181,194,238,429],trail:[53,239],train:[112,138,143,158,180,354,545],traindriv:174,traindrivingscript:174,trainobject:174,trainscript:174,trainstop:174,trainstoppedscript:174,trait1:[112,354],trait2:[112,354],trait:[19,120,158,162,201,202,235,341,403,545],trait_class_path:[112,354],trait_data:354,trait_kei:[112,354],trait_properti:354,trait_typ:[112,353,354],traitexcept:354,traitfield:[353,354],traithandl:[201,235,341,352,353,545],traithandler_nam:354,traithandlertest:353,traitproperti:[201,235,341,352,353,545],traitshandl:[353,354],transact:[79,104,157,283],transfer:[141,177,212,427,437,441,478],transform:[2,146],transit:[37,90,104,332,335,337,338,545],transitionmapnod:[118,332,335,338],transitiontocav:332,transitiontolargetre:332,transitiontomapa:118,transitiontomapc:118,translat:[15,36,41,58,60,62,68,70,106,148,175,180,238,349,350,403,418,469,545],transmiss:376,transmit:[70,515],transpar:[18,44,51,175,187,396,397,411],transport:[425,436,445],transportfactori:436,transpos:175,trap:[15,115,140,155],traumat:28,travel:[65,68,110,132,140,325,329],travers:[13,33,37,77,95,104,110,118,131,132,141,174,238,322,325,329,337,338,370,371,393,398,518],traverse_:22,traversing_object:[322,325,329,398],travi:[1,545],travis_build_dir:10,treasur:[75,153,157,329],treasurechest:39,treat:[13,15,22,44,46,48,54,118,123,146,152,153,170,204,209,212,296,338,362,388,396,398,403,448,457,476,478,489,545],tree:[11,22,28,39,74,86,90,116,118,120,121,123,156,157,167,185,201,202,235,241,270,281,291,332,350,384,385,386,398,403,416,445,461,476,492,514,545],tree_select:[113,201,202,235,374,545],treestr:[113,386],trembl:[149,152],treshold:483,trhr:[77,104,237,238],tri:[15,22,33,35,36,44,45,55,64,65,70,77,92,128,135,142,143,150,153,156,158,161,164,177,183,191,210,228,283,371,372,380,420,459,492,493],trial:[7,373,442],tribal:170,trick:[76,150,161,180,181,466,532,545],tricki:[41,175],trickier:[75,137],tried_kei:39,trigger:[2,3,18,20,22,28,32,34,37,44,45,47,59,65,73,82,95,96,99,104,108,125,132,133,134,137,159,164,171,172,174,178,183,193,204,205,209,210,213,215,229,241,260,275,289,364,370,372,397,398,403,405,411,418,421,425,447,454,458,472,476],trim:469,tripl:[19,120,151,492],triumph:[155,158],trivial:[3,5,19,22,62,142,155,161],troll:55,troubl:[35,44,75,96,119,135,142,144,151,154,181,182,185,190,197,198,464],troubleshoot:[75,198,545],troublesom:[14,15,55],trove:[75,157],truestr:[92,380],truli:[44,55,97,130,316],trunc:238,trust:[28,30,57,95,104,134,157,158,228,470],truth:3,truthfulli:22,truthi:[143,410],try_num_differenti:210,ttarget:164,tto:439,tty:[75,193],ttype:[201,202,412,424,436,439,545],ttype_step:443,tuck:170,tulip:153,tun:[26,218],tune:[148,158,175,187],tunnel:[26,76,97,118,131,132,135,143,144,150,161,174,218,441],tup:[130,350],tupl:[3,5,13,28,30,36,39,41,50,67,68,95,99,117,130,143,146,161,164,178,191,201,204,210,216,218,223,225,226,233,238,241,247,254,274,280,283,292,296,310,311,329,331,337,338,339,340,343,350,362,369,389,391,393,394,396,398,402,403,405,411,413,416,425,426,436,437,441,448,455,457,464,467,469,471,472,474,476,480,485,487,492,495,496,516],tuple_of_arg_convert:30,tupled:485,turbo:190,turkish:204,turn:[8,11,13,19,20,22,27,28,33,44,45,53,54,55,60,63,65,68,73,90,97,99,104,113,118,120,123,134,135,139,143,149,150,151,152,153,155,157,158,161,170,171,172,174,175,177,180,191,199,204,213,228,229,232,233,260,266,308,309,310,311,312,340,350,370,372,386,398,403,416,421,429,436,439,447,457,463,466,470,472,476,477,478,479,490,492,501,521,523,545],turn_act:164,turn_end_check:[308,309,310,311,312],turnbattl:[114,201,202,235,281,545],turnchar:310,tut:[155,372],tutor:[115,369],tutori:[3,17,20,21,22,25,28,46,47,53,54,56,60,73,76,80,81,82,101,108,110,111,119,120,122,123,124,126,127,128,130,132,134,135,139,140,142,143,144,146,148,149,150,151,152,157,159,167,170,175,177,180,185,188,191,198,201,202,229,235,241,309,544,545],tutorial_bridge_posist:372,tutorial_cmdset:372,tutorial_exampl:[14,15,144,148,151,359],tutorial_info:372,tutorial_world:[76,115,155,185,201,202,235,355,545],tutorialclimb:371,tutorialevmenu:369,tutorialmirror:[151,362,545],tutorialobject:[370,371],tutorialread:371,tutorialroom:[370,372],tutorialroomcmdset:372,tutorialroomlook:372,tutorialweapon:[370,371],tutorialweaponrack:371,tutorialworld:[371,372],tutoru:151,tweak:[6,13,18,31,41,48,53,75,104,118,126,134,135,143,149,157,163,171,181,187,204,364,461,469,490,500,505],tweet:[138,545],tweet_output:173,tweet_stat:173,tweetstat:173,twenti:135,twice:[28,99,126,136,155,164,239,257,312,476],twist:[6,19,22,52,54,62,128,180,185,189,190,194,373,398,410,413,416,418,419,425,426,427,428,433,436,439,442,444,445,447,454,457,461,485,545],twistd:[7,185,199,433,454],twistedcli:62,twistedweb:194,twitch:164,twitter:[173,197,545],twitter_api:188,two:[4,5,6,8,11,13,14,15,16,19,20,22,27,28,30,31,32,33,34,37,40,41,42,44,46,48,51,56,57,58,62,64,65,67,68,69,70,72,73,74,76,79,80,90,95,96,97,98,104,106,107,109,110,112,113,116,118,120,123,124,126,127,128,130,131,132,134,135,137,141,142,144,145,146,147,148,149,150,151,152,153,154,155,157,158,159,160,161,162,163,164,165,170,174,175,177,178,182,186,187,191,193,194,195,199,211,218,223,232,234,241,270,275,283,292,293,299,310,312,322,325,335,337,338,343,354,364,372,382,386,398,400,416,445,456,457,465,467,470,476,478,479,485,492,493,545],twowai:218,txt:[0,27,62,75,77,106,118,120,151,179,190,191,205,349,432,440,474,476,492,495],tyepclass:396,tying:[191,521],type:[0,3,6,9,15,17,18,19,20,22,25,26,27,28,30,31,33,35,36,41,42,44,45,46,47,48,49,50,51,55,56,57,58,60,65,67,68,69,70,76,77,80,83,85,86,90,92,95,96,97,98,104,106,110,116,118,120,122,123,125,126,127,128,131,132,133,134,135,136,139,140,142,144,145,146,147,148,149,151,152,155,156,157,158,161,162,163,164,165,170,171,172,173,174,175,177,180,181,183,190,191,194,199,201,202,204,205,213,218,223,225,228,229,230,232,233,234,235,239,241,251,254,257,260,270,273,275,276,278,286,289,292,293,299,308,309,310,311,312,325,336,337,338,340,341,350,352,353,364,371,372,380,388,390,393,394,397,398,402,403,405,410,411,414,416,418,419,425,427,428,434,436,437,439,440,441,443,444,445,447,455,457,461,464,465,466,467,469,470,472,473,476,477,478,479,487,488,489,491,492,496,500,501,508,512,513,515,518,526,532,540,545],type_count:286,typecalass:464,typecalss:257,typeclas:149,typeclass:[0,8,12,13,14,18,19,22,24,26,31,33,34,35,37,39,41,42,44,45,46,50,53,55,63,64,65,75,76,83,85,86,91,97,99,104,105,106,110,111,112,117,118,120,125,126,130,131,132,133,135,136,137,138,140,141,142,144,145,146,147,152,154,157,162,163,164,165,170,171,172,173,174,176,177,178,201,202,204,205,206,207,212,218,223,232,233,234,235,236,253,256,257,260,273,275,278,280,286,289,292,305,308,309,310,311,312,314,316,322,324,329,331,340,350,354,364,366,372,389,394,396,397,398,402,403,405,406,407,409,411,454,471,472,489,490,492,510,512,515,518,523,533,542,545],typeclass_path:[42,48,207,218,406,465,466],typeclass_search:[206,396,405,465],typeclasses:149,typeclasslistserializermixin:515,typeclassmanag:[206,233,396,405],typeclassmixin:[536,537,538,542],typeclassserializermixin:515,typeclassviewsetmixin:518,typedobject:[48,207,213,234,329,340,350,397,398,406,464,465,466,467,487,492],typedobjectmanag:[206,233,389,396,405,465],typeerror:[3,343,445],typelass:18,typenam:[76,204,205,207,232,234,247,257,275,276,277,283,286,296,305,308,309,310,311,312,316,322,325,329,339,340,349,350,359,362,364,366,370,371,372,382,390,397,398,402,406,409,423,449,464,466,480,483,484],typeobject:467,types_count:286,typic:[8,19,95,112,122,142,311,312,354,515,542],typo:[119,120,194],ubuntu:[6,11,181,182,185,187,191,194],uemail:206,ufw:194,ugli:[41,51,133,151,486],uid:[193,206,207,428,435,456,457],uit:[76,82,241],ulrik:135,ultima:180,umlaut:16,unabl:[188,346],unaccept:22,unaffect:[28,164,310,410],unalia:[18,103,223,266],unam:206,unari:353,unarm:309,unarmor:309,unauthenticated_respons:533,unavoid:47,unban:[18,55,103,143,216,223,229,232,266],unban_us:223,unbias:[88,343],unbroken:475,uncal:410,uncas:469,uncategor:489,unchang:[6,36,106,112,349,354,403,492],uncleanli:277,unclear:[58,118,129,159,338],uncolor:[60,139],uncom:[187,191],uncommit:11,uncompress:429,unconnect:[118,230,251],uncov:286,undefin:[2,46,67],under:[2,3,5,7,9,18,22,28,30,31,41,42,48,51,53,64,67,69,73,75,77,88,90,92,95,96,100,103,104,112,113,115,116,119,120,123,134,143,144,146,149,150,152,156,157,158,162,165,169,177,178,179,180,183,185,190,193,199,213,215,218,270,292,353,354,380,386,394,409,416,443,464,469,476,477,478,492,495,496,509,545],undergar:[83,286],undergon:257,underground:118,underli:[11,33,50,123,134,156],underlin:[478,491],underneath:[75,466],underpin:166,underscor:[6,28,30,32,68,86,97,120,151,211,479,492],underscror:211,understand:[0,3,11,16,20,22,39,41,44,52,54,60,65,70,71,86,107,114,119,120,122,124,126,128,129,130,131,132,138,139,142,143,146,148,149,150,151,152,156,157,158,159,161,165,169,170,177,178,180,182,183,185,194,195,210,211,223,293,349,350,382,461,469,492,545],understood:[31,58,65,86,142,158,170,338,444,445],undertak:159,undestand:126,undo:[27,194,474],undon:215,undoubtedli:134,uneven:338,unexpect:[8,142,175,476,492],unexpectedli:483,unfair:158,unfamiliar:[32,33,53,68,151,172,185,191],unfocu:273,unfocus:275,unformat:[28,476,480],unfortun:[124,156],ungm:545,unhappi:75,unheard:58,unhilit:491,unicod:[16,65,70,118,204,338,469,492],unicodeencodeerror:469,unifi:[177,456],uniform:44,unimpl:545,uninflect:495,uninform:181,uninstal:[185,545],uninstati:492,unintent:270,union:[20,28,149,211,364,476],uniqu:[2,12,14,20,22,25,33,34,35,41,42,44,46,48,50,51,55,58,62,65,96,99,104,105,118,120,123,134,144,146,149,153,165,188,191,204,206,209,211,213,218,223,230,232,233,247,251,256,275,289,292,309,310,322,331,337,338,340,349,350,370,372,382,386,389,398,402,403,405,411,413,425,426,434,447,448,456,457,464,465,466,467,472,474,479,486,489,492,496],unit:[1,2,10,11,19,20,45,53,78,87,95,119,123,136,140,180,233,247,260,279,294,310,353,418,472,480,492,497,545],unittest:[8,10,126,229,396,457,472,490],univers:[15,16,136,266],unix:[0,29,36,104,120,183,185,187,224,268,270,477,485,492,545],unixcommand:[116,201,202,235,236,545],unixcommandpars:270,unixtim:485,unjoin:283,unknown:[51,133,137,149,338,402,492],unknown_top:540,unleash:127,unless:[13,18,19,22,28,30,33,34,35,37,47,55,68,74,76,77,104,115,118,120,124,125,128,149,152,156,158,165,179,182,187,189,191,199,204,211,212,216,218,223,225,226,232,256,312,349,350,371,382,388,393,394,398,403,414,429,445,457,464,466,479,489,490,492,493,540],unlik:[45,82,104,105,112,118,119,123,158,162,191,204,241,310,338,354,466],unlimit:[117,329,337],unlink:[26,143,218],unload:[118,490],unload_modul:490,unlock:[18,39,135,149,223,275,464],unlock_flag:275,unlocks_red_chest:39,unlog:[5,216,221,222,230,250,251,457],unloggedin:[44,201,202,208,214,457,545],unloggedincmdset:[25,26,44,89,100,150,222,250,251],unlucki:[55,115],unmask:350,unmodifi:[104,115,210,227,316,476],unmonitor:[421,545],unmut:[18,103,223,232,266],unmute_channel:223,unnam:[46,211],unneccesari:70,unnecessari:[2,156],unnecessarili:146,unneed:[117,329],unpaced_data:425,unpack:[142,393],unpars:[32,36,210,444,445,479],unpaus:[42,193,218,228,410],unpickl:[50,65,425,464,473,488],unplay:[44,126],unpredict:492,unprivileg:403,unprogram:162,unpuppet:[26,45,95,165,215,500],unpuppet_al:204,unpuppet_object:[12,204],unquel:[26,39,144,151,215],unreal:180,unrecogn:479,unrecord_ip:459,unregist:73,unrel:[11,28,245],unrepat:492,unrepeat:[421,492,545],unreport:421,unrestrict:157,unsaf:[199,211,372,492],unsafe_token:469,unsatisfactori:170,unsav:474,unsel:141,unset:[13,22,37,78,112,132,135,164,216,275,276,278,337,339,350,354,370,394,398,402,403,405,411,464,472,476,477,478,479,485,490],unset_character_flag:275,unset_flag:[275,276],unset_lock:223,unsign:493,unsigned_integ:[486,493],unsignedinteg:486,unskil:[112,354],unspawn:338,unstabl:193,unstrip:210,unsuar:119,unsub:[18,103,223,266],unsub_from_channel:223,unsubscrib:[18,47,135,266,411,427],unsuccessful:64,unsuit:[57,402,467],unsupport:13,unsur:[16,30,110,119,143,164,185,188,191],unsurprisingli:151,untag:51,untest:[8,183,185],until:[0,2,5,6,13,14,20,22,28,36,42,47,51,52,54,55,60,67,79,85,99,104,106,108,114,118,123,128,129,144,146,151,152,155,156,157,158,161,165,169,175,181,185,247,260,283,286,289,308,309,310,311,312,337,353,364,370,371,372,398,410,416,445,447,464,469,470,480,492],untouch:[118,152,469],untrust:[14,30,95,158,492],unus:[22,86,118,139,158,204,209,213,223,232,277,312,316,340,362,372,386,398,409,439,455,460,465],unusu:[87,104,159,194],unwant:95,unwield:309,unwieldli:212,unwil:78,upcom:[184,197],updat:[1,2,5,6,8,12,13,14,15,22,26,28,31,34,37,42,47,49,64,65,67,68,73,75,77,84,90,91,95,104,111,118,120,123,124,127,128,129,130,132,134,135,136,139,142,148,151,156,161,162,164,165,169,177,178,180,181,182,183,185,187,188,190,191,192,193,197,205,212,213,218,223,226,228,229,232,244,257,311,316,333,339,350,353,372,390,394,397,398,400,401,403,405,407,432,434,435,440,454,455,457,459,464,466,473,474,475,476,477,478,483,492,500,501,508,513,517,532,533,542,543,545],update_attribut:464,update_buff:474,update_cached_inst:483,update_charsheet:135,update_current_descript:316,update_default:454,update_flag:455,update_lock:513,update_method:51,update_po:132,update_scripts_after_server_start:405,update_session_count:455,update_undo:474,update_weath:372,updated_bi:254,updated_on:254,updatemethod:51,updateview:[542,543],upenn:495,upfir:7,upgrad:[123,185,190,545],upload:[77,123,124,185,191,193,238,545],upmaplink:[118,338],upon:[15,33,49,53,67,70,78,92,128,156,165,171,191,193,194,308,309,310,311,312,377,380,408,418,427,459,477,542],upp:372,upper:[49,60,67,112,118,128,130,215,337,338,354,469],upper_bound:[112,354],upper_bound_inclus:354,uppercas:[60,350,469],upping:60,upsel:191,upset:143,upsid:[117,329],upstart:62,upstream:[0,9,11,123,195,545],upt:212,uptim:[19,26,30,55,136,228,430,480],urfgar:41,uri:[213,232,388,390,466],url:[11,49,50,52,53,59,73,123,148,169,178,181,191,192,201,202,205,213,223,232,238,239,388,390,435,445,461,466,491,498,499,511,518,528,531,537,538,540,543,545],url_nam:[518,533],url_or_ref:120,url_path:518,url_protocol:238,url_to_online_repo:11,urlencod:137,urlpattern:[53,73,124,137,167,177,178],usabl:[63,86,114,124,151,157,165,218,241,275,310,346,393,459,476],usag:[3,5,22,28,31,35,41,47,55,72,76,95,97,119,120,123,125,127,128,129,135,139,140,141,142,143,150,151,161,162,164,165,174,188,191,198,201,202,213,215,216,217,218,223,224,225,228,229,230,235,241,247,251,266,270,273,283,286,292,293,296,299,302,305,308,309,310,311,312,314,316,322,325,327,331,333,341,342,349,350,364,366,369,370,371,372,377,380,393,401,410,416,447,476,478,479,483,545],use:[0,2,3,4,5,7,8,9,10,11,12,13,14,15,16,17,19,20,22,25,27,28,29,30,31,32,33,34,35,36,37,39,41,42,44,45,46,48,49,50,51,52,53,54,55,56,57,58,60,62,63,64,65,67,68,69,70,72,73,74,75,76,77,78,79,81,83,85,86,87,88,90,91,93,94,95,96,97,98,99,102,103,104,105,106,107,109,111,112,113,114,115,116,117,118,119,120,123,124,125,126,127,128,130,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,148,149,150,151,152,153,154,155,156,159,160,161,162,163,164,165,166,167,168,169,170,172,173,174,175,176,177,178,180,181,182,183,184,185,186,187,188,189,191,192,193,194,195,197,198,201,204,205,206,207,209,210,211,212,213,215,218,219,223,224,225,226,228,229,230,232,233,234,238,241,256,260,270,273,275,276,280,283,286,289,292,293,296,299,302,305,308,309,310,311,312,316,322,325,329,331,332,333,337,338,340,343,346,349,350,354,359,364,366,369,370,371,372,382,386,388,393,394,396,397,398,402,403,410,411,414,421,425,438,440,441,444,447,448,455,456,457,464,465,466,467,469,470,471,472,474,475,476,477,478,479,483,485,486,488,490,492,493,496,501,503,508,513,515,518,538,541,545],use_dbref:[350,396,398,489],use_destin:398,use_i18n:64,use_int:289,use_item:310,use_nick:[204,350,398],use_required_attribut:[502,504,506,508,532],use_ssl:238,use_success_location_messag:305,use_success_messag:305,use_tz:238,use_xterm256:469,useabl:[117,329],used:[5,8,9,11,12,13,14,16,17,18,19,20,23,25,27,28,29,30,31,32,33,34,35,36,37,39,41,42,44,45,46,47,48,50,51,52,53,54,56,57,58,60,62,64,65,67,68,69,70,71,72,73,75,76,78,79,80,83,85,86,87,89,91,92,93,94,95,96,97,98,99,103,104,105,106,107,112,113,114,116,117,118,119,120,123,128,129,133,134,135,136,137,140,141,142,144,145,146,147,148,149,150,151,152,153,154,155,158,161,162,164,165,167,169,170,172,173,174,175,177,178,180,182,183,184,185,187,189,191,193,194,195,199,201,202,204,205,209,211,212,213,215,218,223,225,226,227,228,229,230,232,233,235,238,241,245,247,250,251,254,256,257,260,266,270,275,276,278,281,283,286,289,291,292,296,299,308,309,310,311,312,316,325,329,331,334,337,338,339,340,346,349,350,354,364,370,371,372,380,382,386,388,389,390,391,392,393,394,396,398,402,403,407,409,410,411,412,413,414,418,421,422,425,426,427,428,429,430,431,432,433,434,436,438,439,440,443,444,445,448,455,457,458,464,465,466,467,468,469,470,472,473,474,476,477,478,479,485,486,487,488,489,490,492,493,496,500,501,505,508,510,515,518,532,536,538,540,541,542,545],useful:[0,1,2,3,5,8,11,13,14,15,16,17,19,20,27,28,30,31,33,36,37,39,41,42,45,46,47,48,50,53,54,55,56,57,60,63,76,79,82,86,95,96,97,104,106,112,116,118,119,120,121,123,124,126,127,128,129,130,134,135,137,138,139,142,143,144,146,147,149,150,151,152,153,155,158,160,161,164,165,170,173,176,177,182,185,191,195,197,199,209,211,212,213,215,217,218,225,226,229,232,235,241,256,257,270,275,280,283,292,299,329,338,339,349,350,354,364,372,377,393,398,402,403,416,436,464,466,470,476,480,488,492,514,544,545],usefulli:150,useless:[149,161,370],user:[0,2,3,5,6,8,10,12,14,15,18,20,25,27,28,29,30,31,32,33,36,39,44,45,48,49,50,51,52,54,55,59,60,62,63,68,70,71,73,76,77,78,83,86,90,93,95,99,103,104,106,109,115,118,119,120,122,123,124,126,127,128,129,132,138,139,141,142,143,144,148,149,151,153,154,158,161,165,169,174,175,177,178,180,181,182,185,186,187,188,189,190,191,192,193,195,198,204,205,207,210,213,216,218,223,225,228,232,233,234,238,239,241,250,255,257,266,274,275,277,286,289,292,296,310,312,316,329,338,340,350,362,372,376,377,386,388,390,394,398,403,409,412,414,420,428,435,436,439,444,445,455,457,460,464,466,469,474,476,477,478,479,486,490,492,493,500,513,521,524,532,537,538,539,540,541,543,545],user_change_password:500,user_input:28,user_permiss:[207,500],useradmin:500,userauth:436,userchangeform:500,usercreationform:[500,532],userguid:77,usermanag:206,usernam:[11,12,25,28,32,45,49,89,104,124,157,178,185,193,204,207,251,436,460,500,512,515,524,532],usernamefield:532,userpassword:[55,143,216],uses:[5,8,10,11,13,14,16,17,18,20,22,28,30,31,33,35,41,42,45,46,47,48,50,51,53,56,58,60,62,67,68,70,75,76,79,87,89,91,95,97,98,100,104,106,109,112,116,123,128,129,130,131,134,137,139,146,148,149,151,152,157,169,182,191,192,211,225,270,275,283,292,299,310,316,329,337,338,343,349,350,353,354,372,394,396,406,411,425,445,459,464,467,485,486,490,492,512,515,521,540],uses_databas:492,using:[0,2,5,6,8,9,11,12,13,14,15,16,18,19,20,22,26,27,28,30,31,32,33,36,37,39,41,42,44,45,46,47,48,49,50,51,52,53,54,55,57,58,60,65,67,68,69,72,74,75,76,77,82,86,87,94,95,96,99,104,105,106,110,113,117,118,119,120,121,122,123,124,125,126,127,128,129,130,132,133,134,135,136,139,141,142,143,144,145,146,147,148,151,152,156,157,158,159,161,162,163,164,165,170,171,172,173,174,175,176,177,178,179,180,181,182,183,185,187,188,189,191,193,194,198,199,204,207,209,212,213,215,217,218,223,225,226,227,228,232,238,241,247,256,270,275,283,292,293,294,305,308,309,310,311,312,316,322,325,329,331,332,337,338,340,343,346,349,350,354,366,369,370,372,380,386,388,391,394,396,398,401,402,403,406,410,411,427,428,429,434,435,439,445,448,457,458,459,461,464,466,467,469,470,474,476,477,480,485,486,487,488,489,490,492,498,513,517,518,532,540,541,544,545],usr:[123,185,190,193],usu:42,usual:[0,5,6,7,11,12,13,18,19,20,22,27,28,29,32,33,35,36,37,39,41,42,44,46,47,48,50,52,53,57,58,60,62,64,75,76,95,96,97,104,112,118,119,120,123,124,125,126,128,129,134,136,139,142,143,145,146,148,149,151,152,153,155,158,159,161,169,175,177,181,182,185,187,189,191,193,199,204,205,206,210,211,212,213,215,218,223,224,228,229,234,247,256,257,260,270,278,289,337,338,340,349,350,354,372,382,394,396,397,398,402,403,416,418,423,448,455,464,466,469,471,472,476,477,479,485,487,489,490,492,501,508],usuallyj:118,utc:[182,317,493],utf8:[2,182],utf:[16,32,70,99,135,170,183,230,238,421,427,444,478,492],util:[6,8,13,14,15,27,28,29,37,42,50,51,54,56,60,67,78,85,87,90,91,92,95,99,107,108,112,113,119,132,134,135,136,139,141,145,147,154,159,170,171,177,178,181,185,194,201,202,217,228,229,232,234,235,236,238,242,245,247,248,252,253,257,258,267,269,271,272,274,279,284,287,289,290,294,297,300,303,306,311,313,314,316,317,323,325,326,328,330,335,344,347,351,353,354,360,364,367,369,373,387,390,396,398,400,402,409,410,423,442,447,464,465,466,498,499,501,502,504,506,508,516,532,533,545],utilis:476,uyi:[106,349],v19:185,vagu:125,val1:[13,479],val2:[13,479],val:[13,68,204,215,440,492],vala:13,valb:13,valid:[0,3,6,10,13,14,20,22,28,30,37,41,53,59,60,68,86,92,95,99,104,107,113,117,118,129,131,135,137,142,148,151,165,177,178,187,191,194,199,201,202,204,206,210,212,218,226,232,233,241,254,257,258,270,283,292,294,311,329,337,350,353,354,371,372,380,382,386,394,398,400,402,403,405,407,409,410,411,412,414,416,440,444,455,464,465,467,470,472,476,479,486,487,488,489,490,491,492,493,496,515,532,536,538,543,545],valid_handl:486,validate_cal:479,validate_email_address:492,validate_input:354,validate_nam:398,validate_onli:394,validate_password:[28,204],validate_prototyp:402,validate_sess:457,validate_usernam:204,validated_consum:[86,292],validated_input:292,validated_tool:[86,292],validationerror:[204,402,460,486,488],validator_config:204,validator_kei:486,validatorfunc:[201,202,468,545],valign:478,valu:[3,6,8,9,12,13,17,19,20,22,27,30,32,33,34,36,42,47,48,49,50,51,54,55,60,67,68,76,77,78,85,92,94,95,97,104,106,112,114,118,120,123,124,126,127,130,132,135,136,137,139,140,141,143,144,146,148,149,150,151,153,156,157,162,164,165,170,175,177,178,185,187,191,204,206,207,209,211,213,215,216,218,232,234,238,241,254,257,258,275,286,289,296,305,308,309,310,311,312,329,337,338,340,343,346,349,350,353,354,360,362,372,378,380,382,390,393,394,396,397,398,401,402,403,405,406,410,411,414,421,422,423,425,434,439,440,455,456,457,462,464,465,466,467,469,471,472,473,474,475,476,479,483,484,486,487,488,489,490,492,493,496,512,515,532,541,543,545],valuabl:155,value1:[41,120],value2:[41,120],value3:120,value_a:13,value_b:13,value_displai:515,value_from_datadict:488,value_to_obj:402,value_to_obj_or_ani:402,value_to_str:488,valueerror:[41,142,165,206,238,241,247,302,382,464,467,469,472,492,493],valuei:170,values_list:146,valuex:170,vampir:146,vanilla:[0,48,67,75,77,132,133,135,149,156,545],vaniti:28,vari:[31,48,62,64,69,95,104,106,112,118,119,123,129,140,148,151,255,312,340,349,354,455,464,466],variabl:[4,5,6,7,13,14,20,22,28,30,31,33,41,42,51,63,64,68,70,73,77,84,86,92,96,97,118,120,122,123,127,132,133,135,137,142,143,146,149,150,151,152,167,174,177,178,185,193,194,195,204,207,209,213,215,218,223,226,228,229,230,232,238,244,250,254,256,257,260,273,305,316,337,339,354,372,380,393,397,398,402,403,413,416,426,429,430,432,436,438,448,455,462,469,470,476,479,492,525,545],variable_from_modul:492,variable_nam:[254,257],variablenam:492,varianc:349,variant:[13,46,89,104,110,122,151,212,241,242,251,325,427,469,545],variat:[39,91,136,146,158,161,162,164,211,316,349,492],varieti:[114,122,140,164,173,310,311],variou:[5,6,13,16,22,35,37,41,42,44,46,47,48,51,53,62,66,68,71,95,96,104,106,113,115,118,119,121,134,136,137,139,146,147,148,151,153,157,161,162,164,165,166,187,191,194,199,211,227,247,275,310,311,338,349,350,364,370,371,386,394,397,398,403,404,411,448,472,478,489,490,521],varnam:440,vast:[67,69,170,182],vastli:123,vavera:77,vcc:[106,349],vccv:[106,349],vccvccvc:349,vcpython27:75,vcv:349,vcvccv:[106,349],vcvcvcc:[106,349],vcvcvvccvcvv:[106,349],vcvvccvvc:[106,349],vector:492,vehicl:[125,545],velit:29,venu:[11,233],venv:[185,190],ver:182,verb:[30,58,126,398,452,479,495,497],verb_actor_stance_compon:495,verb_all_tens:495,verb_conjug:[30,201,202,468,545],verb_infinit:495,verb_is_past:495,verb_is_past_participl:495,verb_is_pres:495,verb_is_present_participl:495,verb_is_tens:495,verb_past:495,verb_past_participl:495,verb_pres:495,verb_present_participl:495,verb_tens:495,verb_tenses_kei:495,verbal:[81,104,398],verbatim:[30,144,151,496,545],verbatim_el:492,verbos:[0,8,164],verbose_nam:[177,466,500,501,508],verbose_name_plur:[501,508],veri:[0,3,5,6,8,9,11,12,13,14,15,17,18,19,20,22,25,27,28,29,30,31,32,33,41,42,45,46,47,48,50,51,53,54,58,60,62,67,68,69,72,74,75,76,82,83,90,95,96,97,104,106,107,111,113,114,115,117,118,119,120,122,123,124,125,127,128,130,132,133,134,135,138,141,142,144,146,148,149,151,152,153,154,155,156,157,158,159,161,162,164,165,170,174,176,178,179,180,181,182,187,189,191,195,199,204,205,211,213,229,232,233,234,241,256,257,270,286,292,311,322,325,329,349,350,366,370,382,386,389,397,402,420,465,467,472,474,476,492,541],verif:191,verifi:[2,5,11,28,89,92,104,149,185,191,218,238,292,311,380,441,490],verify_online_play:380,verify_or_create_ssl_key_and_cert:441,verify_ssl_key_and_cert:437,verifyfunc:[92,380],versa:[44,53,58,62,68,118,164,223,331,425,479,496],version:[1,2,9,12,13,14,15,18,20,22,25,26,28,31,32,35,36,42,48,51,53,60,64,67,69,80,90,104,118,119,123,124,125,128,129,134,139,142,143,144,148,150,151,156,158,161,165,169,170,175,180,182,183,184,185,190,191,193,198,218,226,228,230,238,251,280,286,309,310,311,312,316,350,364,371,398,403,416,421,435,459,464,469,477,492,500,501,502,505,506,509,515,532,544,545],version_info:416,versionad:120,versionchang:120,versu:[122,545],vertic:[335,337,338,371,478,492],very_strong:394,very_weak:33,vest:194,vet:41,veteran:180,vex:497,vfill_char:478,vhost:545,via:[5,11,13,18,19,28,29,30,32,39,40,41,42,48,49,51,54,60,62,65,67,69,77,119,122,133,134,141,146,148,149,151,156,162,165,175,185,187,191,194,231,233,234,238,331,364,376,397,406,464,467,469,479,484,545],viabl:[86,158,370],vice:[44,53,58,62,68,118,164,223,331,425,479,496],vicin:[22,224,316,372],video:[51,60,148,180],vidual:118,vienv:75,view:[0,3,11,13,17,19,27,28,29,31,33,42,47,49,50,52,53,58,67,104,106,115,118,120,122,123,124,135,138,140,143,148,149,151,154,158,164,165,169,170,185,189,191,197,198,199,201,202,204,213,215,216,218,223,224,225,228,232,266,286,308,309,310,311,312,329,350,388,390,398,400,451,466,477,479,498,503,510,511,513,515,517,521,525,528,531,532,545],view_attr:218,view_lock:513,view_on_sit:[500,502,504,505,506,508],viewabl:[121,122,225],viewer:[120,126,137,329,350,398,466],viewpoint:[479,496,497,545],viewport:3,viewset:[49,517,518],vim:[15,27,154,180,474],vincent:[82,91,95,100,104,107,116,240,241,270,315,316,382],violent:28,virginia:77,virtual:[91,118,122,124,134,180,185,191,228,316,338,480],virtual_env:190,virtualenv:[0,2,5,6,7,9,64,75,77,120,182,185,190,191,193,198,199,545],virtualhost:181,viru:185,visibl:[2,11,13,14,20,31,35,44,48,53,60,106,118,120,126,137,139,156,157,158,161,165,184,185,187,191,198,224,225,335,337,338,350,398,428,461,476,492,540],vision:[13,135,156],visit:[76,77,116,132,170,177,178,191,270,476],visitor:[73,178,194],vista:185,visual:[5,31,51,60,94,104,118,126,134,185,204,225,335,337,338,340,346,469],visual_rang:340,vital:142,vlgeoff:[87,104,107,116,246,247,268,381],vniftg:185,vnum:133,vocabulari:[96,492,545],voic:[22,95,96,545],volatil:402,volcano:153,volum:[125,156,170,193,545],volund:146,volunt:64,voluntari:119,volupt:29,vowel:[106,349],vpad_char:478,vscode:154,vulner:[128,194],vvc:[106,349],vvcc:[106,349],vvccv:[106,349],vvccvvcc:[106,349],w001:8,wai:[3,5,6,7,8,9,11,12,13,14,15,16,19,20,22,30,31,32,33,34,35,36,37,39,40,41,42,44,45,46,47,48,52,53,54,55,57,58,60,62,65,67,68,70,72,74,75,76,77,79,80,86,87,88,89,90,92,94,95,96,97,100,102,104,106,109,112,113,115,119,120,122,123,125,127,129,130,131,132,133,134,135,136,137,138,140,141,142,143,144,145,146,147,148,149,152,153,155,156,158,159,161,162,164,165,169,170,171,172,174,175,176,177,180,182,184,185,189,190,191,192,194,195,198,199,204,210,211,218,225,232,247,256,260,270,275,278,283,292,293,308,309,310,311,312,316,322,325,331,335,338,343,346,349,354,364,369,370,371,380,386,388,394,398,402,411,416,421,425,436,457,459,461,462,463,464,465,467,470,475,476,478,483,485,488,492,496,510,517,518,541,543,545],wail:132,waist:286,wait:[3,19,22,28,42,54,95,97,108,112,115,126,127,128,144,155,157,158,174,205,229,256,260,308,309,310,311,312,354,364,405,416,426,445,447,459,472,476,492],wait_for_disconnect:426,wait_for_server_connect:426,wait_for_statu:416,wait_for_status_repli:416,waiter:416,waitinf:229,wake:[92,380],waldemar:77,walias:218,walk:[15,20,58,95,96,97,113,117,118,122,125,130,132,136,141,156,158,161,325,329,331,338,364,386,470],walki:[18,123,158],wall:[99,115,143,151,155,161,170,216,224,316,371,372],wand:[86,292,293],wanna:[79,157,283,364],want:[0,3,4,5,6,7,8,9,11,12,13,14,15,16,18,19,20,22,25,27,28,30,31,32,33,34,35,36,37,39,41,42,44,45,47,48,49,50,51,53,54,55,57,58,60,62,63,64,65,67,68,69,70,73,74,75,76,77,78,79,80,85,86,89,90,95,96,97,100,104,106,108,112,118,119,120,123,124,125,126,127,128,129,130,131,132,134,135,136,137,139,140,141,142,143,144,146,147,148,149,150,151,152,153,154,156,157,159,160,161,162,163,165,166,167,168,169,170,172,174,175,176,177,178,179,181,182,183,184,185,187,188,189,190,191,192,194,195,197,198,199,204,211,212,213,215,218,224,225,229,230,241,251,275,283,289,292,308,309,310,311,312,316,329,337,338,340,346,350,354,364,372,376,380,382,386,393,394,398,403,407,409,411,432,434,440,447,457,462,464,466,474,476,477,483,488,490,492,501,508,510,517,532,537,540,541,543,544,545],wanted_id:33,war:[31,388],warchannel:223,ware:141,warehous:[376,470],wari:[60,329,398,466],warm:[42,199,420],warn:[9,13,19,20,31,44,74,104,118,123,142,148,151,170,178,181,185,191,195,211,232,238,377,415,416,441,485,544,545],warnmsg:485,warrior:[39,127,134,135,155,158,165,223],wasclean:[427,444],wasn:[3,97,178],wast:[15,47],watch:[7,15,34],water:[86,99,104,212,292,293,305],waterballon:305,watt:77,wave:170,wavi:118,wcach:228,wcactu:311,wcommandnam:270,wcure:311,wdestin:218,weak:403,weakref:483,weaksharedmemorymodel:[423,483],weaksharedmemorymodelbas:[423,483],weakvalu:483,wealth:141,weap:13,weapon:[13,28,41,67,114,115,123,128,140,141,143,145,146,150,155,156,157,162,163,164,293,309,370,371,403,545],weapon_ineffective_msg:370,weapon_prototyp:371,weaponrack_cmdset:371,weaponstr:150,weapoon:155,wear:[83,108,140,157,163,286,309,350,364],wearabl:[83,104,286],wearer:286,wearstyl:286,weather:[42,46,47,74,129,138,148,155,156,162,170,372,545],weather_script:42,weatherroom:[176,372],web:[17,31,33,41,49,52,56,59,64,75,77,104,120,121,122,123,124,126,129,137,144,147,151,154,156,168,180,181,182,185,189,190,198,199,201,202,238,418,420,430,434,440,444,445,455,459,461,467,473,545],web_client_url:184,web_get_admin_url:[213,232,388,390,466],web_get_create_url:[232,390,466],web_get_delete_url:[232,390,466],web_get_detail_url:[213,232,388,390,466],web_get_puppet_url:466,web_get_update_url:[232,390,466],web_help_entri:540,web_plugin:148,webclient:[24,44,51,53,59,60,62,65,68,71,73,77,121,123,129,137,148,151,183,184,187,194,199,201,202,225,228,238,275,369,412,421,424,440,445,456,476,498,526,533,545],webclient_ajax:[51,201,202,412,424,545],webclient_en:194,webclient_gui:545,webclient_opt:421,webclientdata:445,webclienttest:533,webpag:[17,181,191,529,545],webport:2,webserv:[24,49,53,62,73,75,147,148,167,181,182,187,191,193,195,197,201,202,412,545],webserver_en:194,webserver_interfac:[187,191],webserver_port:[2,191],webservic:194,websit:[17,49,50,51,52,75,77,120,121,122,123,134,137,138,148,167,169,177,180,187,191,192,194,201,202,445,461,498,500,526,545],websocket:[51,52,62,123,191,193,427,433,444,456,545],websocket_client_interfac:[187,191],websocket_client_port:191,websocket_client_url:[181,187,191],websocket_clos:444,websocketcli:444,websocketclientfactori:427,websocketclientprotocol:427,websocketserverfactori:433,websocketserverprotocol:444,weed:[0,211],week:[87,95,104,136,148,247,485,493],weeklylogfil:485,weigh:[140,447],weight:[69,106,118,120,156,182,337,338,346,349,465,545],weird:[31,143,158,161,492],welcom:[25,53,64,76,119,124,141,154,167,185,189],well:[0,7,8,9,11,12,13,17,18,22,26,27,28,29,30,31,32,37,39,41,44,48,50,53,55,56,57,62,63,68,69,70,73,75,76,77,88,91,95,96,102,104,106,113,114,118,119,120,122,123,124,125,126,130,131,132,134,135,136,137,139,141,142,146,149,150,151,152,153,155,157,158,159,161,164,165,169,172,173,177,178,182,188,190,192,194,195,198,207,211,212,213,218,231,232,256,266,273,274,275,283,286,302,310,311,312,316,337,340,349,350,354,364,370,386,398,406,410,412,416,425,427,428,434,451,459,464,465,469,473,476,479,480,488,492,501,508],went:[8,11,134,152,161,198,199,407,411],weonewaymaplink:[118,338],were:[3,8,13,14,18,20,22,28,30,41,42,48,51,54,67,69,86,95,103,104,113,118,119,123,131,135,137,140,141,142,146,148,149,150,151,152,158,165,175,183,193,195,204,210,211,212,223,232,266,337,338,382,386,398,402,463,466,470,479,489,492,495,497],weren:136,werewolf:[126,545],werewolv:146,werkzeug:492,wesson:58,west:[99,118,126,131,132,144,170,218,337,338,372],west_east:170,west_exit:372,west_room:99,western:170,westward:372,wet:158,wether:[206,283,472],wevennia:76,wflame:311,wflushmem:228,wfull:311,wguild:223,what:[0,3,5,6,8,9,10,11,12,14,15,18,19,20,22,28,30,31,32,33,35,37,41,42,44,47,48,49,52,53,54,55,57,58,60,62,65,67,68,69,70,72,74,75,76,80,86,88,95,96,97,99,104,105,106,107,112,115,118,119,120,123,124,125,126,128,130,131,132,133,134,135,136,137,139,141,143,144,146,147,149,150,151,155,156,157,160,161,162,163,164,165,166,168,169,170,171,172,174,175,176,177,178,179,180,181,182,185,187,189,191,192,194,195,199,204,209,211,212,213,215,218,229,232,257,273,275,276,280,292,293,305,310,311,337,338,339,340,350,354,366,370,372,376,382,388,390,394,398,401,402,403,416,418,421,428,440,445,460,462,464,466,467,469,470,476,486,487,490,492,493,515,521,523,524,532,541,542,545],whatev:[8,11,12,13,15,19,22,28,30,37,62,76,92,95,96,101,118,123,125,133,135,140,142,151,152,156,157,159,165,170,177,178,179,182,187,193,198,204,205,212,218,273,292,311,362,370,371,380,398,403,406,407,427,436,439,444,457,464,477,486,541],wheat:292,wheel:[47,86,134,185,190],whelp:[225,270],when:[0,1,2,3,6,7,8,9,11,12,13,14,15,16,17,18,19,20,22,25,27,28,29,30,31,32,33,34,36,37,39,41,42,44,45,46,48,50,51,52,53,54,55,57,58,60,62,63,64,65,67,68,69,70,72,75,76,77,80,82,83,87,89,90,91,92,93,95,96,97,98,99,102,104,106,108,112,113,116,117,118,119,120,123,124,125,128,129,130,131,132,133,134,135,136,137,140,141,142,143,144,146,147,148,149,150,151,152,153,154,155,157,158,159,160,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,179,180,181,182,183,185,186,187,190,191,192,193,194,195,198,199,201,204,205,207,209,211,212,213,215,217,218,223,224,225,226,227,228,230,232,233,234,238,239,241,247,250,251,257,258,260,270,275,276,277,278,283,286,289,292,293,296,299,302,305,308,309,310,311,312,316,322,329,336,337,338,339,343,346,349,350,354,359,360,364,366,369,370,371,372,380,382,383,386,389,390,393,394,396,397,398,400,402,403,405,406,407,409,410,411,413,416,418,422,423,425,426,427,428,429,430,431,432,434,436,437,438,439,440,441,444,445,447,448,454,455,456,457,458,459,464,466,467,469,470,472,473,474,475,476,477,478,483,484,485,487,492,496,505,521,523,532,536,538,543,545],when_stop:416,whenev:[7,9,13,18,22,32,33,34,36,41,42,45,54,58,63,70,76,96,123,126,149,161,170,171,191,192,193,204,212,232,278,370,371,372,396,398,407,409,418,435,455,456,457],where:[0,2,3,4,5,11,13,14,15,18,20,22,27,28,29,30,31,33,35,39,41,42,44,48,50,51,53,54,55,58,59,60,62,64,65,67,68,69,70,73,75,76,77,78,85,86,95,96,97,99,104,106,112,118,120,123,125,126,128,130,132,133,134,135,136,137,141,142,143,144,148,149,150,151,152,154,155,156,158,160,161,162,163,165,167,169,170,171,172,174,177,178,182,190,191,193,194,195,197,198,210,211,216,218,224,225,227,232,233,238,275,289,293,299,310,329,337,338,339,340,343,349,350,353,354,371,372,377,391,393,394,396,398,402,403,407,416,418,421,425,448,453,457,464,466,469,470,474,476,477,478,479,480,486,487,490,492,496,508,515,543,545],wherea:[0,3,5,6,9,13,14,20,22,28,33,44,48,55,57,58,60,62,67,70,86,118,125,133,139,141,151,164,194,206,292,338,349,396,405,411,445,464,483],whereabout:155,wherebi:311,wherev:[8,58,82,112,123,153,170,185,187,193,241,310,338,354,376],whether:[28,55,78,96,97,122,130,136,137,150,174,204,205,212,218,223,225,232,289,308,309,310,311,312,380,386,398,411,427,444,459,464,465,469,486,488,492,495],whewiu:75,which:[0,2,3,4,5,6,7,8,11,13,14,15,16,18,19,20,22,24,26,28,29,30,31,32,33,35,36,37,39,41,42,44,45,46,47,48,49,51,52,54,55,57,58,60,62,63,65,67,68,69,70,73,74,75,76,77,82,83,84,86,90,91,92,94,95,96,97,99,104,109,111,112,113,114,116,118,119,120,123,124,126,127,128,129,130,131,132,133,134,135,136,137,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,155,156,157,158,159,161,162,164,165,167,169,170,171,172,173,174,175,176,177,178,182,183,185,186,187,188,189,191,193,194,195,198,199,204,205,209,211,212,213,215,216,218,224,225,226,229,230,232,233,234,238,241,244,247,260,270,273,275,280,283,286,289,292,293,299,302,308,309,310,311,312,316,322,329,337,338,339,340,346,350,354,364,366,370,371,372,376,377,380,386,390,394,396,397,398,402,403,405,406,407,409,411,413,415,416,420,421,428,434,436,444,445,447,448,455,456,457,459,462,464,465,466,467,469,470,472,473,476,477,478,479,480,483,485,486,488,489,490,492,495,501,508,515,518,521,523,524,525,532,538,541,543],whichev:[19,156,159,191,194,372],whilst:[99,170],whimper:155,whisk:278,whisp:[106,349],whisper:[26,95,96,104,143,224,260,273,275,349,350,398,545],whistl:58,white:[32,60,77,175,469,492],whitelist:32,whitenois:[104,112,352,354],whitespac:[15,19,22,135,139,143,146,154,161,165,226,302,350,469,470,478,492],who:[13,18,26,28,30,31,33,36,39,41,42,48,49,54,55,58,60,64,90,95,96,103,122,124,125,132,133,135,146,150,151,152,155,156,157,159,161,162,164,165,174,176,177,194,205,213,215,218,223,232,234,257,266,273,275,283,308,309,310,311,312,349,350,371,380,388,390,394,398,403,466,474,476,479,496,513,545],whoever:177,whole:[36,46,56,72,104,118,122,124,132,134,143,156,158,161,165,170,187,211,218,273,312,478,523],wholist:[18,232],whome:218,whomev:[162,174,364],whoopi:161,whose:[30,48,68,86,146,148,149,204,213,229,257,308,309,310,311,312,350,386,405,421,471,476,479,492],whould:476,why:[0,13,28,48,55,76,90,95,96,97,122,123,126,130,131,140,142,144,157,159,161,165,170,175,185,194,198,216,308,311,312,338,382,413,414,476],wick:464,wide:[19,30,35,56,67,117,118,126,130,135,142,151,162,187,216,310,311,329,475,478,492],widen:[55,161],wider:[55,126,130,216,478],widest:492,widget:[488,500,501,502,504,505,506,508,515,532],width:[17,19,22,30,31,32,41,56,118,126,132,170,201,213,337,340,421,436,455,469,474,475,477,478,479,492],wield:[41,114,140,157,163,309],wifi:[191,194],wiki:[22,48,64,69,75,85,122,123,135,138,164,170,180,241,289,444,544,545],wiki_account_handl:124,wiki_account_signup_allow:124,wiki_can:124,wiki_can_admin:124,wiki_can_assign:124,wiki_can_assign_own:124,wiki_can_change_permiss:124,wiki_can_delet:124,wiki_can_moder:124,wiki_can_read:124,wiki_can_writ:124,wikiconfig:124,wikipedia:[8,11,16,70,122,123,164,444],wil:[13,18],wild:[53,69,118,146,156,175,339,340],wildcard:[36,55,118,134,216,218,337,339,340,492],wildcard_to_regexp:492,wilder:[201,202,235,314,545],wildernessexit:329,wildernessmap:329,wildernessmapprovid:[117,329],wildernessroom:329,wildernessscript:329,wildli:349,wildr:95,wilfr:95,will_suppress_ga:438,will_transform:146,will_ttyp:443,willing:[135,156,159,180,545],wim:77,win10:185,win7:185,win8:185,win:[28,75,142,164,183,273],wind:[95,155,176],winder:158,windmil:292,window:[0,5,6,7,9,11,20,29,37,44,51,52,65,68,118,120,123,124,126,131,132,144,151,154,157,182,189,198,199,213,225,275,277,416,432,455,459,492,545],windowid:455,windows10:185,wine:[153,155],wingd:170,winpti:75,winter:[91,316],wintertim:157,wintext_templ:162,wip:[120,544],wipe:[9,11,13,14,18,26,75,90,143,151,170,182,211,218,228,277,310],wire:[19,62,65,68,70,123,187,191,227,413,425,426,457,469],wis:135,wisdom:5,wise:[0,11,14,15,16,33,73,135,149,157,172],wiser:[42,144,161],wish:[2,11,22,82,130,169,173,190,241,312,469,491,532],with_tag:305,withdraw:[164,312],withdrawl:312,within:[0,6,11,13,20,22,28,30,31,47,51,54,75,76,77,90,91,94,118,119,120,123,130,132,133,135,146,148,151,153,161,164,169,171,172,173,175,178,181,182,183,191,193,204,207,209,218,254,283,316,339,346,377,389,398,403,410,459,464,465,469,479,485,492,532,538,543],withot:338,without:[3,5,6,8,9,11,13,14,15,18,19,20,22,25,27,28,30,35,40,41,42,45,47,48,50,52,53,55,56,60,62,63,64,67,68,69,72,76,86,88,90,91,95,96,97,99,104,106,109,113,117,118,120,123,125,126,128,129,131,132,134,135,142,143,144,145,146,148,150,151,152,156,157,158,159,161,165,169,172,174,175,177,181,182,185,187,191,193,195,198,204,205,210,213,215,216,218,223,224,225,226,227,228,229,232,233,234,239,242,254,257,266,278,283,286,292,308,311,312,316,322,338,349,350,354,364,370,372,386,394,396,398,401,402,403,409,410,425,436,439,440,447,457,458,464,466,469,470,472,473,474,476,477,479,485,488,489,490,492,525],withstand:33,wiz:135,wizard:[41,95,158,372,403,414,416,545],wkei:218,wlocat:218,wlock:218,wmagic:311,wmass:311,wndb_:218,wnn:18,woah:[149,150],woman:[157,158],won:[3,12,13,14,16,20,48,49,51,54,55,60,65,67,76,90,92,96,97,104,107,120,124,125,128,134,137,139,141,142,143,146,150,151,156,158,160,162,165,170,178,179,182,185,193,212,335,359,364,380,382,461,469,488],wonder:[56,75,133,140],wont_suppress_ga:438,wont_ttyp:443,woo:143,wood:[86,158,292,293],wooden:[41,86,292,293],woodenpuppetrecip:86,woosh:125,word:[5,6,11,15,18,19,22,27,30,31,37,58,64,68,95,96,104,106,132,136,137,142,143,149,151,154,157,159,169,170,175,189,210,225,226,230,251,260,280,349,350,396,428,474,479,489,492,496,545],word_fil:349,word_length_vari:[106,349],wordi:349,work:[0,2,3,4,5,6,7,8,9,12,13,14,15,16,18,19,20,26,28,30,31,33,34,37,41,42,44,46,47,50,52,53,54,56,58,60,63,65,67,69,72,75,76,79,86,90,91,97,102,104,109,113,119,120,123,124,125,126,127,128,131,132,133,134,135,136,139,141,143,144,146,147,148,149,150,151,152,153,154,156,157,159,161,164,165,166,168,169,170,171,175,176,177,178,181,182,183,185,187,188,189,190,191,194,197,198,209,212,213,215,218,223,224,226,228,229,230,232,241,266,270,273,283,292,294,302,305,310,311,312,316,322,329,338,350,372,386,388,390,393,394,398,402,403,416,420,421,433,448,461,463,464,466,467,470,475,476,477,478,486,492,525,536,537,538,540,542,545],workaround:[11,185,193,545],workflow:[500,545],world:[8,13,14,15,16,18,19,20,22,28,31,39,41,53,54,67,69,70,75,79,86,87,90,95,99,102,104,112,117,118,120,122,123,125,130,132,134,135,136,140,145,149,150,152,154,159,160,162,163,164,165,166,168,170,171,174,179,180,185,189,191,195,204,217,218,223,225,247,283,292,302,308,309,310,311,312,314,329,337,350,354,368,371,372,388,390,406,455,457,469,470,480,490,545],world_map:170,worm:[132,158],worm_has_map:132,worn:[83,104,286,309],worri:[2,13,16,28,50,60,70,95,97,119,130,146,155,161,165,195,275,276,283],wors:[157,159],worst:156,worth:[5,28,42,48,58,97,119,125,128,142,157,158,159,177,180,181,283],worthi:156,worthless:191,would:[2,3,5,7,8,9,13,14,15,16,19,20,22,28,30,31,33,35,37,41,42,44,46,47,48,52,53,54,56,57,60,67,68,73,74,75,76,77,79,83,86,87,95,96,97,104,112,113,118,122,123,124,125,126,128,130,131,132,133,134,135,136,137,139,140,141,142,143,144,146,147,148,149,150,151,152,154,156,157,158,159,161,162,164,165,169,170,171,172,174,175,177,178,181,185,191,193,204,210,211,212,213,218,227,232,238,245,247,257,270,275,283,292,293,329,337,338,349,354,364,386,388,390,394,402,403,428,440,466,469,470,473,476,487,488,490,492,501,508],wouldn:[31,130,150,175],wound:311,wow:[137,159],wpermiss:218,wprototype_desc:218,wprototype_kei:218,wprototype_lock:218,wprototype_par:218,wprototype_tag:218,wrap:[28,41,42,54,92,129,132,146,151,153,161,169,275,286,293,350,380,423,463,478,492],wrap_conflictual_object:488,wrapper:[5,19,28,32,44,48,54,67,86,128,204,207,233,234,278,280,322,354,390,391,397,398,406,410,421,423,455,464,466,467,469,478,479,483,484,485,492,503,508],wresid:228,write:[5,10,13,15,16,19,20,22,28,31,36,48,54,56,58,68,69,72,76,78,82,90,95,96,97,119,120,124,126,131,133,135,136,142,143,144,146,149,150,151,152,155,157,158,159,161,165,182,185,186,188,189,218,223,225,232,238,239,241,270,376,377,398,429,485,490,541,543,545],writeabl:190,written:[16,18,19,41,52,118,120,133,134,135,137,143,146,148,149,150,151,152,153,177,178,180,184,194,200,225,338,376,470,541],wrong:[0,3,8,139,141,151,157,182,185,199,211,218,228,292,294,350],wrote:[146,149,490],wserver:228,wservic:223,wsgi:[181,461],wsgi_resourc:461,wsgiwebserv:461,wsl:[120,185],wss:[181,191,545],wtypeclass:218,wwhere:398,www:[9,49,69,75,76,120,122,123,130,177,181,191,201,228,431,432,438,440,491,495,532],wyou:140,x0c:218,x1b:[469,491],x2x:135,x4x:475,x5x:475,x6x:475,x7x:475,x8x:475,x9x:475,x_r:130,xcode:185,xforward:461,xgettext:64,xgiven:340,xit:[76,82,241],xml:238,xmlcharrefreplac:469,xp_gain:162,xpo:478,xtag:495,xterm256:[32,51,65,71,84,139,151,215,244,346,421,436,439,469,545],xterm256_bg:469,xterm256_bg_sub:469,xterm256_fg:469,xterm256_fg_sub:469,xterm256_gbg:469,xterm256_gbg_sub:469,xterm256_gfg:469,xterm256_gfg_sub:469,xterm:[60,151,175],xterms256:60,xval:22,xxx:[3,107,126,382],xxxx:[107,382],xxxxx1xxxxx:475,xxxxx3xxxxx:475,xxxxx:95,xxxxxxx2xxxxxxx:475,xxxxxxxxxx3xxxxxxxxxxx:135,xxxxxxxxxx4xxxxxxxxxxx:135,xxxxxxxxxxx:475,xxxxxxxxxxxxxx1xxxxxxxxxxxxxxx:135,xxxxxxxxxxxxxxxxxxxxxx:135,xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:135,xygrid:[337,338],xymap:[201,202,235,314,330,331,332,335,338,339,340,545],xymap_data:[118,337,339],xymap_data_list:[118,337,339],xymap_legend:[118,201,202,235,314,330,332,335,545],xyroom:340,xyz:[36,118,331,334,338,339,340],xyz_destin:[118,340],xyz_destination_coord:340,xyz_exit:[118,334,338],xyz_room:[118,334,338],xyzcommand:[118,332,333],xyzexit:[339,340,545],xyzexit_prototype_overrid:118,xyzexitmanag:340,xyzgrid:[201,202,235,314,545],xyzgrid_cmdset:331,xyzgrid_use_db_prototyp:118,xyzgridcmdset:[118,331],xyzmanag:340,xyzmap:118,xyzroom:[201,202,235,314,330,339,545],xyzroom_prototype_overrid:118,y_r:130,yan:[60,469],yank:27,yard:115,year:[68,69,77,87,95,104,119,122,136,154,158,191,238,247,480,485,492,532],yearli:[136,191],yeast:[86,104,292],yellow:[11,60,118,175,371],yer:157,yes:[22,28,54,58,96,120,130,175,218,228,260,414,474,476,492],yes_act:476,yes_no_question_cmdset:476,yesno:[28,120,474],yesnoquestioncmdset:476,yet:[2,3,9,11,12,15,25,28,41,44,55,64,67,76,85,96,97,99,104,118,123,124,126,127,132,143,146,149,159,161,170,174,177,178,180,184,185,187,191,198,200,204,223,230,251,257,283,289,338,364,394,397,410,434,457,461,469,539],yield:[22,33,54,69,78,182,218,377,478,490,492,545],yml:[10,193],yogurt:[105,305],yoshimura:77,you:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,22,25,27,28,30,31,32,33,34,35,36,37,39,40,41,42,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,62,63,64,65,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,89,90,91,92,94,95,96,97,98,99,100,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,151,152,153,156,157,159,160,161,162,163,164,165,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,197,198,199,204,212,213,215,218,223,224,225,226,227,228,229,230,232,238,241,244,247,255,256,257,260,266,270,273,275,276,280,283,286,289,292,293,299,302,305,308,309,310,311,312,316,322,325,329,331,333,337,338,346,349,350,353,354,359,364,366,371,372,376,377,380,382,386,388,393,394,398,403,407,408,409,410,411,418,427,428,429,445,447,457,459,461,462,464,466,469,470,472,475,476,478,479,480,488,489,490,492,495,496,497,512,515,517,518,532,541,543,544,545],you_obj:30,you_replac:273,your:[2,3,5,7,10,13,14,15,16,17,18,19,20,25,27,28,30,31,33,35,36,39,41,42,44,45,46,47,48,49,50,52,53,54,55,56,58,60,63,64,65,68,70,72,73,74,75,76,77,78,79,81,82,83,84,85,86,87,88,89,91,92,93,94,95,96,97,99,100,102,104,106,108,109,110,113,114,115,116,117,118,119,120,122,123,125,126,128,129,131,132,133,134,135,136,137,138,139,140,141,142,146,147,149,150,151,152,153,154,155,156,157,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,178,179,180,181,182,184,185,186,187,188,189,190,192,195,197,198,199,201,202,204,207,210,212,213,215,216,218,223,224,225,228,229,230,235,238,241,242,244,247,251,256,270,273,275,283,286,289,292,293,308,309,310,311,312,316,322,325,329,331,332,337,341,343,346,349,350,352,359,364,371,372,376,377,380,382,386,393,394,397,447,466,469,474,476,478,479,488,489,490,492,493,496,497,501,508,518,532,538,541,545],your_act:275,your_bucket_nam:77,your_email:11,yourchar:151,yourgam:376,yourgamenam:77,yourhostnam:187,yournam:[119,143,149,150,181],yourpassword:182,yourrepo:7,yourself:[0,3,8,10,11,12,15,20,28,33,37,48,53,56,57,58,67,69,73,76,77,95,97,99,104,109,112,115,118,119,120,122,135,137,142,150,151,153,157,158,159,161,162,165,170,179,182,185,191,218,224,273,275,283,296,311,322,331,350,354,359,476,479,496,497,545],yourselv:[58,479,496,497],yoursit:177,yourtest:8,yourusernam:11,yourwebsit:177,yousuck:55,yousuckmor:55,youth:[92,380],youtub:11,ypo:478,yrs:247,ythi:60,yum:[11,181,187],yvonn:135,z_destin:340,z_r:130,z_sourc:340,zcoord:[331,335,337,339,545],zed:180,zero:[19,35,41,144,149,151,153,223,289,292,339,350,391,398,464,469,479],zip:[194,238],zlib:[190,425,429],zmud:[183,431],zone:[46,96,133,138,148,159,180,467,485,545],zoord:339,zope:6,zopeinterfac:185,zuggsoft:431},titles:["Coding Introduction","Coding and development help","Continuous Integration","Debugging","Things to remember about the flat API","Profiling","Quirks","Setting up PyCharm","Unit Testing","Updating Your Game","Using Travis","Version Control","Accounts","Attributes","Batch Code Processor","Batch Command Processor","Batch Processors","Bootstrap Components and Utilities","Channels","Coding Utils","Command Sets","Command System","Commands","Communications","Core Components","Connection Screen","Default Commands","EvEditor","EvMenu","EvMore","The Inline Function Parser","Help System","Inputfuncs","Locks","MonitorHandler","Msg","Nicks","Objects","Outputfuncs","Permissions","Portal And Server","Spawner and Prototypes","Scripts","Server component","Sessions","Signals","Tags","TickerHandler","Typeclasses","Evennia REST API","The Web Admin","Web Client","Webserver","Game website","Async Process","Banning","Bootstrap & Evennia","Building Permissions","Sending different messages depending on viewpoint and receiver","Clickable links","Colors","Core Concepts","Custom Protocols","Guest Logins","Internationalization","Messagepath","Multisession modes","New Models","OOB","Soft Code","Text Encodings","In-text tags parsed by Evennia","Using MUX as a Standard","Web Features","Zones","Arxcode installing help","Building menus","AWSstorage system","Input/Output Auditing","Barter system","Batch processor examples","Script example","Building menu","Clothing","Color markups","Cooldowns","Crafting system","Custom gameime","Dice","Email-based login system","EvscapeRoom","Extended Room","Easy fillable form","Gendersub","Health Bar","Evennia in-game Python system","Dialogues in events","A voice operated elevator using events","In-Game Mail system","Map Builder","Menu-based login system","TutorialMirror","Evennia Multidescer","Legacy Comms-commands","Contribs","Puzzles System","Roleplaying base system for Evennia","Pseudo-random generator and registry","Red Button example","SimpleDoor","Slow Exit","Talkative NPC example","Traits","Easy menu selection tree","Turn based battle system framework","Evennia Tutorial World","Unix-like Command style parent","Wilderness system","XYZgrid","How To Contribute And Get Help","Contributing to Evennia Docs","API Summary","Evennia Introduction","Glossary","Add a wiki on your website","Building a mech tutorial","Coding FAQ","Command Cooldown","Command Duration","Command Prompt","Coordinates","Default Exit Errors","Dynamic In Game Map","Evennia for Diku Users","Evennia for MUSH Users","Evennia for roleplaying sessions","Gametime Tutorial","Help System Tutorial","Tutorials and Howto\u2019s","Manually Configuring Color","Mass and weight for objects","NPC shop Tutorial","Parsing command arguments, theory and best practices","Our own commands","Using the game and building stuff","Creating things","Django Database queries","Overview of the Evennia library","Overview of your new Game Dir","Persistent objects and typeclasses","More about Commands","Starting to code Evennia","Python Classes and objects","Searching for things","Starting Tutorial (Part 1)","The Tutorial World","On Planning a Game","Planning the use of some useful contribs","Planning our tutorial game","Where do I begin?","Evennia Starting Tutorial (Part 2)","Making a sittable object","Implementing a game rule system","Evennia Starting Tutorial (Part 3)","Turn based Combat System","Tutorial for basic MUSH like game","Evennia Starting Tutorial (Part 4)","Add a simple new web page","Evennia Starting Tutorial (part 5)","Web Tutorial","Static In Game Map","Tutorial Aggressive NPCs","Tutorial NPCs listening","Tutorial Tweeting Game Stats","Tutorial Vehicles","Understanding Color Tags","Weather Tutorial","Web Character Generation","Web Character View Tutorial","Licensing","Links","Apache Config","Choosing An SQL Server","Client Support Grid","Evennia Game Index","Getting Started","Grapevine","Making Evennia, HTTPS and WSS (Secure Websockets) play nicely together","How to connect Evennia to Twitter","IRC","Installing on Android","Online Setup","RSS","Running Evennia in Docker","Security","Server Conf","The Evennia Default Settings file","Server Setup and Life","Setup quickstart","Start Stop Reload","Unimplemented","evennia","evennia","evennia.accounts","evennia.accounts.accounts","evennia.accounts.bots","evennia.accounts.manager","evennia.accounts.models","evennia.commands","evennia.commands.cmdhandler","evennia.commands.cmdparser","evennia.commands.cmdset","evennia.commands.cmdsethandler","evennia.commands.command","evennia.commands.default","evennia.commands.default.account","evennia.commands.default.admin","evennia.commands.default.batchprocess","evennia.commands.default.building","evennia.commands.default.cmdset_account","evennia.commands.default.cmdset_character","evennia.commands.default.cmdset_session","evennia.commands.default.cmdset_unloggedin","evennia.commands.default.comms","evennia.commands.default.general","evennia.commands.default.help","evennia.commands.default.muxcommand","evennia.commands.default.syscommands","evennia.commands.default.system","evennia.commands.default.tests","evennia.commands.default.unloggedin","evennia.comms","evennia.comms.comms","evennia.comms.managers","evennia.comms.models","evennia.contrib","evennia.contrib.base_systems","evennia.contrib.base_systems.awsstorage","evennia.contrib.base_systems.awsstorage.aws_s3_cdn","evennia.contrib.base_systems.awsstorage.tests","evennia.contrib.base_systems.building_menu","evennia.contrib.base_systems.building_menu.building_menu","evennia.contrib.base_systems.building_menu.tests","evennia.contrib.base_systems.color_markups","evennia.contrib.base_systems.color_markups.color_markups","evennia.contrib.base_systems.color_markups.tests","evennia.contrib.base_systems.custom_gametime","evennia.contrib.base_systems.custom_gametime.custom_gametime","evennia.contrib.base_systems.custom_gametime.tests","evennia.contrib.base_systems.email_login","evennia.contrib.base_systems.email_login.connection_screens","evennia.contrib.base_systems.email_login.email_login","evennia.contrib.base_systems.email_login.tests","evennia.contrib.base_systems.ingame_python","evennia.contrib.base_systems.ingame_python.callbackhandler","evennia.contrib.base_systems.ingame_python.commands","evennia.contrib.base_systems.ingame_python.eventfuncs","evennia.contrib.base_systems.ingame_python.scripts","evennia.contrib.base_systems.ingame_python.tests","evennia.contrib.base_systems.ingame_python.typeclasses","evennia.contrib.base_systems.ingame_python.utils","evennia.contrib.base_systems.menu_login","evennia.contrib.base_systems.menu_login.connection_screens","evennia.contrib.base_systems.menu_login.menu_login","evennia.contrib.base_systems.menu_login.tests","evennia.contrib.base_systems.mux_comms_cmds","evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds","evennia.contrib.base_systems.mux_comms_cmds.tests","evennia.contrib.base_systems.unixcommand","evennia.contrib.base_systems.unixcommand.tests","evennia.contrib.base_systems.unixcommand.unixcommand","evennia.contrib.full_systems","evennia.contrib.full_systems.evscaperoom","evennia.contrib.full_systems.evscaperoom.commands","evennia.contrib.full_systems.evscaperoom.menu","evennia.contrib.full_systems.evscaperoom.objects","evennia.contrib.full_systems.evscaperoom.room","evennia.contrib.full_systems.evscaperoom.scripts","evennia.contrib.full_systems.evscaperoom.state","evennia.contrib.full_systems.evscaperoom.tests","evennia.contrib.full_systems.evscaperoom.utils","evennia.contrib.game_systems","evennia.contrib.game_systems.barter","evennia.contrib.game_systems.barter.barter","evennia.contrib.game_systems.barter.tests","evennia.contrib.game_systems.clothing","evennia.contrib.game_systems.clothing.clothing","evennia.contrib.game_systems.clothing.tests","evennia.contrib.game_systems.cooldowns","evennia.contrib.game_systems.cooldowns.cooldowns","evennia.contrib.game_systems.cooldowns.tests","evennia.contrib.game_systems.crafting","evennia.contrib.game_systems.crafting.crafting","evennia.contrib.game_systems.crafting.example_recipes","evennia.contrib.game_systems.crafting.tests","evennia.contrib.game_systems.gendersub","evennia.contrib.game_systems.gendersub.gendersub","evennia.contrib.game_systems.gendersub.tests","evennia.contrib.game_systems.mail","evennia.contrib.game_systems.mail.mail","evennia.contrib.game_systems.mail.tests","evennia.contrib.game_systems.multidescer","evennia.contrib.game_systems.multidescer.multidescer","evennia.contrib.game_systems.multidescer.tests","evennia.contrib.game_systems.puzzles","evennia.contrib.game_systems.puzzles.puzzles","evennia.contrib.game_systems.puzzles.tests","evennia.contrib.game_systems.turnbattle","evennia.contrib.game_systems.turnbattle.tb_basic","evennia.contrib.game_systems.turnbattle.tb_equip","evennia.contrib.game_systems.turnbattle.tb_items","evennia.contrib.game_systems.turnbattle.tb_magic","evennia.contrib.game_systems.turnbattle.tb_range","evennia.contrib.game_systems.turnbattle.tests","evennia.contrib.grid","evennia.contrib.grid.extended_room","evennia.contrib.grid.extended_room.extended_room","evennia.contrib.grid.extended_room.tests","evennia.contrib.grid.mapbuilder","evennia.contrib.grid.mapbuilder.mapbuilder","evennia.contrib.grid.mapbuilder.tests","evennia.contrib.grid.simpledoor","evennia.contrib.grid.simpledoor.simpledoor","evennia.contrib.grid.simpledoor.tests","evennia.contrib.grid.slow_exit","evennia.contrib.grid.slow_exit.slow_exit","evennia.contrib.grid.slow_exit.tests","evennia.contrib.grid.wilderness","evennia.contrib.grid.wilderness.tests","evennia.contrib.grid.wilderness.wilderness","evennia.contrib.grid.xyzgrid","evennia.contrib.grid.xyzgrid.commands","evennia.contrib.grid.xyzgrid.example","evennia.contrib.grid.xyzgrid.launchcmd","evennia.contrib.grid.xyzgrid.prototypes","evennia.contrib.grid.xyzgrid.tests","evennia.contrib.grid.xyzgrid.utils","evennia.contrib.grid.xyzgrid.xymap","evennia.contrib.grid.xyzgrid.xymap_legend","evennia.contrib.grid.xyzgrid.xyzgrid","evennia.contrib.grid.xyzgrid.xyzroom","evennia.contrib.rpg","evennia.contrib.rpg.dice","evennia.contrib.rpg.dice.dice","evennia.contrib.rpg.dice.tests","evennia.contrib.rpg.health_bar","evennia.contrib.rpg.health_bar.health_bar","evennia.contrib.rpg.health_bar.tests","evennia.contrib.rpg.rpsystem","evennia.contrib.rpg.rpsystem.rplanguage","evennia.contrib.rpg.rpsystem.rpsystem","evennia.contrib.rpg.rpsystem.tests","evennia.contrib.rpg.traits","evennia.contrib.rpg.traits.tests","evennia.contrib.rpg.traits.traits","evennia.contrib.tutorials","evennia.contrib.tutorials.batchprocessor","evennia.contrib.tutorials.batchprocessor.example_batch_code","evennia.contrib.tutorials.bodyfunctions","evennia.contrib.tutorials.bodyfunctions.bodyfunctions","evennia.contrib.tutorials.bodyfunctions.tests","evennia.contrib.tutorials.mirror","evennia.contrib.tutorials.mirror.mirror","evennia.contrib.tutorials.red_button","evennia.contrib.tutorials.red_button.red_button","evennia.contrib.tutorials.talking_npc","evennia.contrib.tutorials.talking_npc.talking_npc","evennia.contrib.tutorials.talking_npc.tests","evennia.contrib.tutorials.tutorial_world","evennia.contrib.tutorials.tutorial_world.intro_menu","evennia.contrib.tutorials.tutorial_world.mob","evennia.contrib.tutorials.tutorial_world.objects","evennia.contrib.tutorials.tutorial_world.rooms","evennia.contrib.tutorials.tutorial_world.tests","evennia.contrib.utils","evennia.contrib.utils.auditing","evennia.contrib.utils.auditing.outputs","evennia.contrib.utils.auditing.server","evennia.contrib.utils.auditing.tests","evennia.contrib.utils.fieldfill","evennia.contrib.utils.fieldfill.fieldfill","evennia.contrib.utils.random_string_generator","evennia.contrib.utils.random_string_generator.random_string_generator","evennia.contrib.utils.random_string_generator.tests","evennia.contrib.utils.tree_select","evennia.contrib.utils.tree_select.tests","evennia.contrib.utils.tree_select.tree_select","evennia.help","evennia.help.filehelp","evennia.help.manager","evennia.help.models","evennia.help.utils","evennia.locks","evennia.locks.lockfuncs","evennia.locks.lockhandler","evennia.objects","evennia.objects.manager","evennia.objects.models","evennia.objects.objects","evennia.prototypes","evennia.prototypes.menus","evennia.prototypes.protfuncs","evennia.prototypes.prototypes","evennia.prototypes.spawner","evennia.scripts","evennia.scripts.manager","evennia.scripts.models","evennia.scripts.monitorhandler","evennia.scripts.scripthandler","evennia.scripts.scripts","evennia.scripts.taskhandler","evennia.scripts.tickerhandler","evennia.server","evennia.server.amp_client","evennia.server.connection_wizard","evennia.server.deprecations","evennia.server.evennia_launcher","evennia.server.game_index_client","evennia.server.game_index_client.client","evennia.server.game_index_client.service","evennia.server.initial_setup","evennia.server.inputfuncs","evennia.server.manager","evennia.server.models","evennia.server.portal","evennia.server.portal.amp","evennia.server.portal.amp_server","evennia.server.portal.grapevine","evennia.server.portal.irc","evennia.server.portal.mccp","evennia.server.portal.mssp","evennia.server.portal.mxp","evennia.server.portal.naws","evennia.server.portal.portal","evennia.server.portal.portalsessionhandler","evennia.server.portal.rss","evennia.server.portal.ssh","evennia.server.portal.ssl","evennia.server.portal.suppress_ga","evennia.server.portal.telnet","evennia.server.portal.telnet_oob","evennia.server.portal.telnet_ssl","evennia.server.portal.tests","evennia.server.portal.ttype","evennia.server.portal.webclient","evennia.server.portal.webclient_ajax","evennia.server.profiling","evennia.server.profiling.dummyrunner","evennia.server.profiling.dummyrunner_settings","evennia.server.profiling.memplot","evennia.server.profiling.settings_mixin","evennia.server.profiling.test_queries","evennia.server.profiling.tests","evennia.server.profiling.timetrace","evennia.server.server","evennia.server.serversession","evennia.server.session","evennia.server.sessionhandler","evennia.server.signals","evennia.server.throttle","evennia.server.validators","evennia.server.webserver","evennia.settings_default","evennia.typeclasses","evennia.typeclasses.attributes","evennia.typeclasses.managers","evennia.typeclasses.models","evennia.typeclasses.tags","evennia.utils","evennia.utils.ansi","evennia.utils.batchprocessors","evennia.utils.containers","evennia.utils.create","evennia.utils.dbserialize","evennia.utils.eveditor","evennia.utils.evform","evennia.utils.evmenu","evennia.utils.evmore","evennia.utils.evtable","evennia.utils.funcparser","evennia.utils.gametime","evennia.utils.idmapper","evennia.utils.idmapper.manager","evennia.utils.idmapper.models","evennia.utils.idmapper.tests","evennia.utils.logger","evennia.utils.optionclasses","evennia.utils.optionhandler","evennia.utils.picklefield","evennia.utils.search","evennia.utils.test_resources","evennia.utils.text2html","evennia.utils.utils","evennia.utils.validatorfuncs","evennia.utils.verb_conjugation","evennia.utils.verb_conjugation.conjugate","evennia.utils.verb_conjugation.pronouns","evennia.utils.verb_conjugation.tests","evennia.web","evennia.web.admin","evennia.web.admin.accounts","evennia.web.admin.attributes","evennia.web.admin.comms","evennia.web.admin.frontpage","evennia.web.admin.help","evennia.web.admin.objects","evennia.web.admin.scripts","evennia.web.admin.server","evennia.web.admin.tags","evennia.web.admin.urls","evennia.web.admin.utils","evennia.web.api","evennia.web.api.filters","evennia.web.api.permissions","evennia.web.api.root","evennia.web.api.serializers","evennia.web.api.tests","evennia.web.api.urls","evennia.web.api.views","evennia.web.templatetags","evennia.web.templatetags.addclass","evennia.web.urls","evennia.web.utils","evennia.web.utils.adminsite","evennia.web.utils.backends","evennia.web.utils.general_context","evennia.web.utils.middleware","evennia.web.utils.tests","evennia.web.webclient","evennia.web.webclient.urls","evennia.web.webclient.views","evennia.web.website","evennia.web.website.forms","evennia.web.website.tests","evennia.web.website.urls","evennia.web.website.views","evennia.web.website.views.accounts","evennia.web.website.views.channels","evennia.web.website.views.characters","evennia.web.website.views.errors","evennia.web.website.views.help","evennia.web.website.views.index","evennia.web.website.views.mixins","evennia.web.website.views.objects","Evennia Documentation","<no title>"],titleterms:{"break":146,"case":[97,158],"class":[8,19,22,48,76,95,148,149,152,158],"default":[26,30,32,33,51,53,118,126,129,131,149,150,196,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230],"final":[132,190],"function":[3,30,33,37,53,76,121,151,153],"goto":28,"import":[0,4,107,118,120,147,151,152],"new":[6,8,42,48,53,67,86,95,124,135,137,148,149,158,167,177,198],"public":[184,197],"return":[28,44,146,151],"static":[112,170,354],"super":[57,150],AWS:77,Adding:[20,32,46,50,53,62,67,75,86,95,97,124,126,130,131,144,150,174,177],And:[40,119],Are:158,Going:197,One:[99,118],PMs:135,TLS:181,The:[0,5,14,15,27,28,30,31,39,41,42,50,54,56,57,65,73,76,95,96,118,128,132,135,137,138,141,155,156,159,164,165,167,196,198],Use:[0,194],Uses:30,Using:[5,8,10,13,18,29,30,31,34,41,46,53,67,72,74,95,112,119,132,138,144,191,354],Will:158,Yes:28,_famili:146,_should:158,abl:158,abort:128,about:[4,9,47,48,118,128,150,152,158],absolut:147,abus:55,access:[50,61],access_typ:33,account:[6,12,50,77,123,135,145,158,203,204,205,206,207,215,500,536],accountcmdset:98,across:161,action:158,activ:[134,158,177],actor:58,actor_stance_cal:30,actual:[22,48],add:[53,124,126,167,182],add_choic:76,addclass:520,addit:[75,130,131,193],address:126,admin:[6,50,73,123,216,499,500,501,502,503,504,505,506,507,508,509,510],administr:[18,156,158],adminsit:523,advanc:[1,36,121,128,150,182,199],aggress:171,alia:6,alias:[46,153],all:[95,126,137,149,158,187],allow:[18,158],alpha:156,also:158,altern:[7,75],amount:158,amp:425,amp_client:413,amp_serv:426,analyz:5,android:190,ani:[14,122],annot:146,anoth:[42,120,150],ansi:[19,60,175,469],apach:181,api:[4,49,51,120,121,147,511,512,513,514,515,516,517,518],app:[137,177],appear:158,arbitrari:28,area:[165,170],arg:142,arg_regex:22,argument:[28,142,149,151],arm:125,around:144,arx:75,arxcod:75,ascii:19,ask:[22,28],asset:159,assign:[22,57],assort:[15,20,22,28,46,54,62,172],async:54,asynchron:54,at_cmdset_cr:98,at_object_cr:149,attach:[7,42,45],attack:[158,165],attribut:[6,13,50,123,149,153,464,501],attributeproperti:13,audit:[78,104,375,376,377,378],auto:31,automat:126,avail:[25,45],awai:1,aws_s3_cdn:238,awsstorag:[77,104,237,238,239],backend:524,ban:55,bank:158,bar:94,barter:[79,104,157,158,282,283,284],base:[41,89,100,106,114,118,126,158,164],base_system:[104,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270],basic:[14,15,52,95,122,124,165,169,188],batch:[14,15,16,80,470],batchcod:14,batchprocess:217,batchprocessor:[104,356,357,470],battl:114,befor:0,begin:159,behavior:18,best:142,beta:156,between:[14,28,48],block:[14,118,120,128],blockquot:120,blurb:53,board:158,bodyfunct:[104,358,359,360],bold:120,boot:55,bootstrap:[17,56],border:17,bot:205,branch:28,brief:137,briefli:68,broken:158,bug:6,build:[50,57,76,82,120,125,132,135,141,144,156,158,170,218],builder:[99,158],building_menu:[76,104,240,241,242],built:158,bulletin:158,busi:141,button:[17,108,144],calendar:136,call:[22,95,149],call_ev:95,callabl:30,callback:[51,95,96,97],callbackhandl:254,caller:28,can:[13,76,122,152,153,158],cannot:158,capabl:158,capcha:177,card:17,care:194,carri:158,cast:293,caveat:[14,15,48,60,190],certain:146,certif:187,chain:95,chair:[158,161],chang:[6,9,11,50,53,64,69,91,95,97,120,126,135,149,158,169,194],channel:[18,123,126,135,158,537],charact:[18,37,50,96,123,126,135,140,149,156,158,161,162,165,177,178,183,538],charactercmdset:98,chargen:165,chat:18,cheat:3,check:[13,33,39,77],checker:0,checkpoint:177,children:152,choic:76,choos:182,clean:75,clickabl:59,client:[51,65,68,73,154,183,191,418],client_opt:32,clone:[11,75],cloth:[83,104,157,285,286,287],cloud9:191,cmdhandler:209,cmdparser:210,cmdset:[143,150,211],cmdset_account:219,cmdset_charact:220,cmdset_sess:221,cmdset_unloggedin:222,cmdsethandl:212,code:[0,1,3,9,11,13,14,18,19,27,35,36,42,69,76,88,95,119,120,126,141,143,151,156,158,162,181,292,470],coin:158,collabor:134,color:[17,19,53,60,84,126,139,175],color_markup:[104,243,244,245],colour:60,combat:[164,165],comfort:193,comm:[103,223,231,232,233,234,502],command:[3,6,15,20,21,22,24,25,26,31,42,76,91,95,98,103,116,121,126,127,128,129,131,135,136,139,141,142,143,148,149,150,151,154,161,164,165,174,188,193,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,255,273,331,470],comment:[115,131,132,152],commit:11,commom:53,commun:[14,23,119],complet:33,complex:[76,146],compon:[17,24,43,338],comput:191,concept:[1,61,132,158,164],conclud:[130,165],conclus:[76,142,146,149,151,157,158,159,161,170],condit:126,conf:[148,195],config:[121,139,181],configur:[7,11,77,78,139,177,181,182,186,187,188,189,192,197],congratul:156,conjug:495,connect:[6,25,184,188,191],connection_screen:[250,262],connection_wizard:414,contain:[42,193,471],content:126,continu:[2,161],contrib:[8,76,104,119,123,157,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386],contribut:[119,120,121],control:11,convert:[30,142],cooldown:[85,104,127,288,289,290],coordin:130,copi:181,core:[8,24,61,121,123,133],cost:77,counter:[112,354],cprofil:5,craft:[86,104,158,291,292,293,294],crafter:86,creat:[2,6,12,19,22,37,48,55,67,95,97,121,125,137,138,143,144,145,149,151,158,165,167,170,174,177,193,472],create_object:149,createnpc:165,creation:159,creatur:193,credit:[149,155],crop:19,current:[3,136],custom:[8,18,28,30,31,33,44,49,50,51,53,54,62,70,73,76,86,87,124,134,136,139,143,197],custom_gametim:[104,246,247,248],customis:[117,329],dai:158,data:[7,13,28,44,52,62],databas:[6,9,24,31,41,67,75,121,146,149],dbref:153,dbserial:473,deal:42,death:158,debug:[3,14,194],debugg:7,decid:158,decor:[28,54],dedent:19,dedic:177,deep:138,deeper:86,default_cmd:98,defaultobject:6,defeat:158,defin:[11,20,22,28,30,33,42,67,118],definit:33,delai:[19,42,54,128],delimit:126,demo:156,deni:95,depend:[9,58,75,77],deploi:193,deprec:[120,415],desc:[28,112,354],descer:134,descript:[91,158,193],design:[90,141],detail:[77,91,105,117,118,137,177,329],detect:158,develop:[1,134,180,193,194,199],dialogu:96,dice:[88,104,135,157,342,343,344],dictionari:28,differ:[48,58,133,158],diku:133,dir:[8,148,154,197],direct:[7,120],director:58,directori:[191,195],disabl:[95,194],discuss:180,displai:[19,132,136,183],dive:138,django:[33,73,123,146,177,199],doc:[0,120],docker:193,docstr:[120,152],document:[72,119,120,544],doe:158,doing:159,don:[14,122,161,193],donat:119,done:155,down:[118,144,174,199],dummyrunn:[5,447],dummyrunner_set:448,durat:128,dure:199,dynam:[22,28,132],each:[153,158],easi:[92,113],echo:32,economi:158,edit:[27,76,95,120,165],editnpc:165,editor:[27,95,154],elev:97,els:158,email:89,email_login:[104,249,250,251,252],emot:106,emul:133,encod:[16,70],encrypt:191,enemi:158,enforc:158,engin:159,enjoi:181,enough:[155,158],enter:174,entir:97,entit:24,entiti:158,entri:[31,144],error:[42,131,143,151,199,539],eval:120,eveditor:[27,474],even:86,evennia:[0,3,4,7,8,9,11,30,41,49,51,56,64,71,74,75,77,95,102,106,115,119,120,122,124,126,133,134,135,142,147,151,158,160,163,166,168,175,180,181,182,184,187,188,190,191,193,196,199,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543,544],evennia_launch:416,event:[95,96,97,136],eventfunc:[95,256],everi:129,everyth:76,evform:[135,475],evmenu:[28,126,476],evmor:[29,477],evscaperoom:[90,104,272,273,274,275,276,277,278,279,280],evtabl:[126,135,478],examin:[3,95,149],exampl:[3,27,28,30,33,39,42,51,53,69,80,81,84,85,86,96,99,107,108,111,117,118,130,147,162,164,191,329,332,470],example_batch_cod:357,example_recip:293,except:161,execut:3,exist:[48,158],exit:[22,37,97,110,126,131,325],expand:[112,164,174,354],experi:158,explan:76,explor:[0,147],extend:[61,91,118,157],extended_room:[104,315,316,317],extern:[120,194],extra:[91,95,149,155],fail:158,familiar:[133,134],faq:[126,138],faster:8,featur:[61,73,91,137],feel:133,field:[92,123,146],fieldfil:[104,379,380],fight:158,figur:143,file:[11,14,15,16,31,120,195,196,470],filehelp:388,fill:19,fillabl:92,filter:512,find:[1,130,151,153],firewal:194,first:[76,96,97,118,134,149,151],fix:11,flat:[4,53],flexibl:120,flow:[52,158],flower:158,folder:[0,11,75],foreground:199,forget:6,fork:[11,119],form:[17,53,92,158,177,532],formal:158,format:28,forum:180,framework:[114,180],from:[4,28,31,51,88,122,124,126,144,151,177,191,193,476],front:[53,169],frontpag:503,full:[76,137],full_system:[104,271,272,273,274,275,276,277,278,279,280],func:39,funcpars:[30,479],funcparser_cal:30,further:[54,169,181],futur:125,gain:158,game:[0,8,9,11,13,18,19,31,42,53,90,95,98,122,130,132,134,135,136,144,148,154,156,158,159,162,165,170,173,184,191,193,197,198,292],game_index_cli:[417,418,419],game_system:[104,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313],gamedir:120,gameim:87,gameplai:155,gametim:[136,480],gaug:[112,354],gendersub:[93,104,295,296,297],gener:[17,61,76,107,158,165,177,180,224,476],general_context:525,get:[28,95,119,138,144,146,185,187],get_client_opt:32,get_input:28,get_inputfunc:32,get_valu:32,git:[11,123],github:[11,123],give:158,given:46,global:[121,142,158],global_script:42,glossari:123,gmcp:68,godhood:144,goldenlayout:51,good:152,googl:177,grant:[50,135],grapevin:[186,427],graphic:151,grid:[104,118,132,183,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340],group:146,guest:63,guid:75,guidelin:119,had:155,handl:[55,137,158,194,199],handler:[45,121,164],haproxi:187,have:[138,152,154,158,165],head:120,health:94,health_bar:[104,345,346,347],hello:151,help:[0,1,31,75,119,137,144,225,387,388,389,390,391,504,540],here:[0,122],hidden:158,hide:158,hierarchi:[39,135,158],hint:[5,42,64,115,155,181],hit:143,hold:150,hook:48,host:191,hous:144,how:[12,22,37,48,70,119,135,138,158,174,188,193],howto:138,html:[53,167,177],http:[181,187],human:158,idea:79,idmapp:[481,482,483,484],imag:[193,194],implement:[117,158,162,329],improv:[137,158],index:[137,177,184,541],infinit:158,influenc:158,info:[79,180,199],inform:191,infrastructur:162,ingame_python:[104,253,254,255,256,257,258,259,260],ingo:65,inherit:[41,74,152],inherits_from:19,init:[147,149],initi:[126,164,182,198],initial_setup:420,inlin:30,input:[22,28,30,68,78,151],inputfunc:[32,65,421],instal:[11,75,77,78,79,82,83,84,85,87,88,89,90,91,93,95,98,99,100,101,102,103,105,106,109,110,111,112,115,116,117,118,124,177,181,182,185,187,188,190,191,193,197,198,292,325,343,354],instanc:[22,48,67,152],intal:86,integr:2,interact:[0,14,15,54,151,185],interfac:194,intern:120,internation:64,interpret:7,interrupt:118,intro_menu:369,introduct:[0,5,28,75,90,122,132,170,177],inventori:140,ipython:151,irc:[189,428],issu:183,ital:120,item:156,itself:161,join:18,jumbotron:17,jupyt:0,just:[122,158],kei:[28,41,76,92,153],keyword:[96,149],kill:[158,199],kind:158,know:[122,194],known:[6,158],languag:[28,64,106],larg:158,last:126,latest:[9,11,193],latin:126,launch:[27,28],launchcmd:333,layout:56,learn:[0,122],leav:174,legaci:103,legend:[118,338],lesson:[154,160],let:[3,14,137,191],librari:147,licens:[77,179],life:197,lift:55,like:[14,116,133,158,165],limit:[14,15,158],line:[3,27,125,146,151,154,161],link:[50,59,118,120,180],linux:[2,185,199],list:[3,120,149,150,158],list_nod:28,listen:172,literatur:180,live:199,local:[120,142,191],locat:153,lock:[13,31,33,39,150,174,392,393,394],lockdown:191,lockfunc:[161,393],lockhandl:394,log:[18,19,75,137,148,151,194,198],logfil:7,logger:485,login:[32,63,89,100],logo:[53,169],longer:96,look:[31,133,144,158,165],lookup:[121,146],loop:149,loot:158,mac:[185,199],machin:191,magic:6,mai:158,mail:[11,98,104,298,299,300],main:[120,121,153,544],make:[8,11,19,90,119,125,134,135,143,144,149,151,158,161,165,174,187],manag:[13,39,51,124,206,233,389,396,405,422,465,482],manual:[139,158,184],map:[99,115,118,132,170,338],mapbuild:[104,318,319,320],mapper:132,mariadb:182,markup:[84,469],mass:140,master:[11,135,158],match:[6,150],matter:158,mccp:429,mean:158,mech:125,mechan:158,memori:13,memplot:449,menu:[19,28,76,82,100,113,141,274,400,476],menu_login:[104,261,262,263,264],merg:20,messag:[58,65,68,97,126],messagepath:65,method:[6,22,42,139,149,151],middlewar:526,migrat:[9,123,124],mind:11,minimap:170,mirror:[104,361,362],mixin:542,mob:[138,158,370],mod_proxi:181,mod_ssl:181,mod_wsgi:181,mode:[14,15,44,66,123,191,199],model:[8,67,121,177,207,234,390,397,406,423,466,483],modif:135,modifi:[53,129,149,181],modul:[41,151,162,164,188],monitor:32,monitorhandl:[34,407],more:[0,9,33,41,56,58,60,73,86,120,121,128,134,139,150,158],most:0,motiv:159,move:[126,161,174],msdp:68,msg:[35,65,139],mssp:430,mud:[154,180],multi:[134,150,151,152,158],multidesc:[102,104,134,301,302,303],multipl:[13,158,161],multisess:[44,66,123],mush:[134,165],must:158,mutabl:[6,13],mux:72,mux_comms_cmd:[104,265,266,267],muxcommand:226,mxp:431,mygam:[98,325],mysql:182,myst:120,name:[6,55,149,158],nattribut:13,naw:432,need:[97,122,150,154,158],nest:76,network:24,next:[134,185,188,198],nice:187,nick:36,night:158,node:[28,118],non:[13,126,127,184,185],nop:183,note:[8,15,16,20,22,28,31,36,46,52,54,62,81,89,100,110,115,120,172,181,325],notebook:0,npc:[79,111,138,141,157,158,165,171,172],number:142,numer:158,obfusc:106,obj:39,object:[6,13,19,33,37,42,44,46,50,58,123,126,140,144,145,146,149,150,151,152,153,156,158,161,170,174,275,371,395,396,397,398,505,543],obtain:177,off:[126,158],offici:180,olc:41,onc:[95,155],one:[120,130,158],onli:[120,146,158,199],onlin:[11,191],oob:68,oop:152,open:141,oper:[54,97],option:[28,76,92,118,135,142,191,194,199],optionclass:486,optionhandl:487,other:[22,42,50,53,58,90,151,153,158,180,182,191,195],our:[69,76,97,137,143,149,151,156,158,174,177],ourselv:149,out:[62,135,143,158],outgo:65,output:[18,78,376],outputcommand:68,outputfunc:38,outsid:191,overal:162,overload:[48,73,139],overrid:6,overview:[2,67,118,147,148,164,169],own:[12,22,32,37,51,62,90,112,143,151,158,191,193,354],page:[53,73,124,137,167,169],paramet:95,parent:[67,95,116,134],pars:[71,126,142,150,151],parser:30,part3:138,part:[138,154,160,163,166,168],parti:180,pass:151,patch:119,path:[14,65,148],pathfind:118,paus:[22,97,128],pax:75,pdb:3,penalti:158,percent:[112,354],perman:158,permiss:[33,39,46,57,95,135,513],perpetu:156,persist:[13,27,127,128,143,149],person:[144,158],philosophi:90,physic:158,picklefield:488,pictur:177,pip:[123,124],place:120,plai:[90,158,187],plan:[0,156,157,158,170],player:[134,158],plugin:51,point:0,polici:72,port:[191,194],portal:[40,44,65,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445],portalsess:65,portalsessionhandl:[65,434],post:158,postgresql:182,practic:142,prefix:22,prepar:2,prerequisit:190,prevent:126,prioriti:31,prison:158,privileg:[124,158],problem:69,process:[54,61,199],processor:[14,15,16,80,470],product:[125,193],profil:[5,446,447,448,449,450,451,452,453],program:[3,122],project:[2,7],prompt:[28,129],pron:58,pronoun:496,prop:158,properti:[12,13,18,20,22,28,35,37,44,46,48,118,123,146],protfunc:[41,401],protocol:[62,68],prototyp:[41,118,334,399,400,401,402,403],proxi:[181,191],pseudo:107,pudb:3,pull:11,puppet:123,push:[11,144],put:[11,137,187],puzzl:[104,105,304,305,306],pvp:158,pycharm:7,python:[0,14,95,122,134,148,151,152,180,188],quell:[39,57,150],queri:[48,146,149],queryset:[146,153],quest:158,quick:[2,158,185],quickstart:198,quiet:142,quirk:6,race:158,rais:161,random:107,random_string_gener:[104,381,382,383],rate:[112,354],read:[0,54,60,73,169],real:14,reboot:199,recapcha:177,receiv:[58,62,68],recip:[86,292,293],recog:58,red:108,red_button:[104,363,364],refer:[120,126],referenc:58,regard:95,regist:191,registri:107,regular:158,rel:[147,153],relat:[95,136,138],releas:[120,156],relev:191,reli:14,reload:[6,126,152,181,199],remark:165,rememb:[4,120,152],remind:137,remot:[11,182,191],remov:[46,95,126,150],repair:158,repeat:[28,32,42],replac:150,repo:75,repos:119,repositori:[0,11,123],reput:158,request:11,requir:[92,185],reset:[9,199],reshuffl:144,resourc:180,respawn:158,rest:[49,161],restart:[181,198],restrict:18,retriev:13,role:[135,158],roleplai:[58,106,135,158],roll:88,roller:135,rom:133,room:[37,91,97,115,126,130,132,135,140,156,157,158,276,372],root:514,router:118,rpg:[104,158,341,342,343,344,345,346,347,348,349,350,351,352,353,354],rplanguag:349,rpsystem:[104,348,349,350,351],rss:[192,435],rst:120,rule:[20,158,162,164],run:[3,7,8,22,122,124,190,193,197],runner:8,safe:30,safeti:14,same:[28,96],save:13,schema:9,score:165,screen:25,script:[42,81,95,123,174,257,277,404,405,406,407,408,409,410,411,506],scripthandl:408,search:[19,20,46,67,121,130,142,153,489],searching_cal:30,season:158,secret:177,section:544,secur:[95,181,187,194],see:[6,95,137,198],select:[113,126],self:142,send:[58,62,68,129,151],sent:129,separ:[76,158,161],serial:515,server:[24,40,43,44,61,64,148,165,181,182,191,195,197,198,377,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,507],serverconf:195,serversess:[65,455],serversessionhandl:65,servic:419,session:[44,65,123,126,135,456],sessionhandl:[44,457],set:[1,7,11,20,28,33,75,77,90,124,132,136,139,149,154,158,165,184,186,189,191,192,194,195,196],setpow:165,settings_default:462,settings_mixin:450,setup:[2,75,181,182,185,191,197,198],sever:[96,130,142],share:11,sharedmemorymodel:67,sheet:[3,135],shop:141,shortcut:121,should:158,show:[138,165],shut:199,sidebar:120,signal:[45,458],similar:158,simpl:[3,5,28,33,42,76,128,158,167],simpledoor:[104,109,321,322,323],singl:13,singleton:121,site:[73,123],sitekei:177,sittabl:161,skill:[86,158,159],slot:91,slow:110,slow_exit:[104,324,325,326],soft:69,softcod:[69,134],solut:69,solv:158,some:[39,130,133,151,157,158],someth:158,somewher:122,sort:158,sourc:[7,31,120],space:[17,149],spawn:[41,134],spawner:[41,403],special:158,spell:293,spread:119,spuriou:183,sql:[146,182],sqlite3:182,ssh:[68,194,436],ssl:[191,437],stack:158,staff:158,stanc:58,standard:[72,136],start:[0,75,95,135,138,141,151,154,160,163,166,168,185,193,198,199],stat:173,state:278,statement:143,statu:[158,199],status:158,step:[3,11,75,134,144,156,177,186,188,189,190,192,198],stop:[198,199],storag:[28,42],store:[13,28,41,126,158],string:[33,118,142,476],strip:142,structur:[95,120],studi:97,stuff:[122,144,165],style:[17,53,116],sub:76,subclass:37,subtop:31,succe:158,suit:8,summari:[55,121,143,150,152,153],superus:39,support:[0,68,183],suppress_ga:438,surround:3,swap:48,sword:[150,293],synchron:54,syntax:[0,120,134,199,470],syscommand:227,system:[21,22,31,33,56,58,77,79,86,89,95,98,100,105,106,114,117,137,138,156,157,158,162,164,165,228],tabl:[19,67,120,126],tag:[46,71,91,123,130,153,175,467,508],talk:[111,157],talking_npc:[104,365,366,367],taskhandl:410,tb_basic:308,tb_equip:309,tb_item:310,tb_magic:311,tb_rang:312,teamciti:2,tech:156,technic:[31,77,79,90,108,120,364],teleport:118,telnet:[68,183,191,439],telnet_oob:440,telnet_ssl:441,templat:[2,28,92,137,177,476],templatetag:[519,520],tempmsg:35,temporari:28,term:152,termux:190,test:[5,8,91,122,151,165,229,239,242,245,248,252,258,264,267,269,279,284,287,290,294,297,300,303,306,313,317,320,323,326,328,335,344,347,351,353,360,367,373,378,383,385,442,452,484,497,516,527,533],test_queri:451,test_resourc:490,text2html:491,text:[19,28,32,61,70,71,120,151,169],than:158,thei:158,them:158,theori:142,thi:[137,159],thing:[4,120,133,134,145,149,152,153,154,158],third:180,those:158,throttl:459,through:[3,193],ticker:[47,123],tickerhandl:[47,411],tie:135,time:[19,22,42,69,91,95,136,158],time_format:19,timer:[5,42],timetrac:453,tip:11,titl:[50,53],to_byt:19,to_str:19,togeth:[137,187],tool:[19,24,55,180],traceback:0,track:[11,158],train:174,trait:[104,112,157,352,353,354],traithandl:[112,354],traitproperti:[112,354],transit:118,translat:64,travi:10,treat:14,tree:[113,158,293],tree_select:[104,384,385,386],trick:11,troubleshoot:[11,185,190],ttype:443,tupl:[149,150],turn:[6,114,126,164],turnbattl:[104,157,307,308,309,310,311,312,313],tutori:[0,95,96,97,104,115,125,136,137,138,141,154,155,156,158,160,163,164,165,166,168,169,171,172,173,174,176,178,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373],tutorial_world:[104,368,369,370,371,372,373],tutorialmirror:101,tweet:[173,188],twist:123,twitter:188,two:99,type:[12,13,37,112,354],typeclass:[6,48,74,95,121,123,134,139,143,148,149,153,161,259,325,463,464,465,466,467],under:11,understand:175,ungm:135,unimpl:200,uninstal:[77,155],unit:8,unix:116,unixcommand:[104,268,269,270],unloggedin:230,unmonitor:32,unquel:150,unrepeat:32,updat:[9,11,48,126,149],upgrad:9,upload:194,upstream:6,url:[120,124,137,167,177,509,517,521,529,534],usag:[14,15,27,49,50,79,80,82,86,87,88,92,93,94,99,105,106,107,109,117,118,182,329,343],use:[6,18,47,122,157,158],used:[22,126,293],useful:[22,90,157,180],user:[11,22,53,57,64,133,134,137,194],using:[3,97,149,153],util:[7,17,19,22,24,30,104,121,128,180,260,280,336,374,375,376,377,378,379,380,381,382,383,384,385,386,391,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,510,522,523,524,525,526,527],valid:[33,460],validatorfunc:493,valu:[28,41,158],vanilla:158,variabl:[3,95],variant:161,vehicl:[138,174],verb_conjug:[494,495,496,497],verbatim:120,version:[11,77,120],versu:54,vhost:181,via:158,view:[18,73,137,167,177,178,518,530,535,536,537,538,539,540,541,542,543],viewpoint:58,virtualenv:123,vocabulari:95,voic:97,volum:158,wai:[1,28,118,128,150,151],want:[122,138,158,193],warn:[95,120],weapon:158,weather:[158,176],web:[6,50,51,53,61,68,73,138,148,167,169,177,178,191,194,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541,542,543],webclient:[52,444,528,529,530],webclient_ajax:445,webclient_gui:51,webpag:53,webserv:[52,194,461],websit:[53,73,124,531,532,533,534,535,536,537,538,539,540,541,542,543],websocket:[181,187],weight:[140,158],werewolf:146,what:[2,13,56,122,138,142,152,153,154,158,159,193],when:[4,47,126,161],where:[122,147,159,185],whisper:106,who:[22,143],wiki:124,wilder:[104,117,327,328,329],willing:122,window:[64,75,185],wizard:184,word:119,work:[11,22,48,77,95,118,122,137,142,158,174,193],workaround:183,workflow:1,world:[115,138,144,148,151,155,156,158],write:[8,51,62],wss:187,xterm256:[60,175],xymap:[118,337],xymap_legend:338,xyzexit:118,xyzgrid:[104,118,330,331,332,333,334,335,336,337,338,339,340],xyzroom:[118,340],yield:[28,128],you:[0,122,150,154,155,158],your:[0,1,6,8,9,11,12,22,32,37,51,57,62,67,69,90,112,124,130,143,144,148,158,159,177,191,193,194,354],yourself:[144,156],zcoord:118,zone:74}}) \ No newline at end of file diff --git a/docs/1.0-dev/toc.html b/docs/1.0-dev/toc.html index 3badc5f7f9..6da6c9255b 100644 --- a/docs/1.0-dev/toc.html +++ b/docs/1.0-dev/toc.html @@ -5018,7 +5018,6 @@

      Versions