mirror of
https://github.com/evennia/evennia.git
synced 2026-03-25 09:16:32 +01:00
Cleanup tutorial docs
This commit is contained in:
parent
d1ddb80b22
commit
95d063e4e0
9 changed files with 429 additions and 276 deletions
|
|
@ -7,23 +7,26 @@ if we cannot find and use it afterwards.
|
|||
|
||||
The base tools are the `evennia.search_*` functions, such as `evennia.search_object`.
|
||||
|
||||
rose = evennia.search_object(key="rose")
|
||||
acct = evennia.search_account(key="MyAccountName", email="foo@bar.com")
|
||||
```python
|
||||
import evennia
|
||||
|
||||
roses = evennia.search_object(key="rose")
|
||||
accts = evennia.search_account(key="MyAccountName", email="foo@bar.com")
|
||||
```
|
||||
```
|
||||
|
||||
```{sidebar} Querysets
|
||||
|
||||
What is returned from the main search functions is actually a `queryset`. They can be treated like lists except that they can't modified in-place. We'll discuss querysets in the `next lesson` <Django-queries>`_.
|
||||
```
|
||||
|
||||
Strings are always case-insensitive, so searching for `"rose"`, `"Rose"` or `"rOsE"` give the same results.
|
||||
It's important to remember that what is returned from these search methods is a _listing_ of 0, one or more
|
||||
elements - all the matches to your search. To get the first match:
|
||||
Strings are always case-insensitive, so searching for `"rose"`, `"Rose"` or `"rOsE"` give the same results. It's important to remember that what is returned from these search methods is a _listing_ of zero, one or more elements - all the matches to your search. To get the first match:
|
||||
|
||||
rose = rose[0]
|
||||
rose = roses[0]
|
||||
|
||||
Often you really want all matches to the search parameters you specify. In other situations, having zero or
|
||||
more than one match is a sign of a problem and you need to handle this case yourself.
|
||||
Often you really want all matches to the search parameters you specify. In other situations, having zero or more than one match is a sign of a problem and you need to handle this case yourself.
|
||||
|
||||
```python
|
||||
the_one_ring = evennia.search_object(key="The one Ring")
|
||||
if not the_one_ring:
|
||||
# handle not finding the ring at all
|
||||
|
|
@ -32,21 +35,20 @@ more than one match is a sign of a problem and you need to handle this case your
|
|||
else:
|
||||
# ok - exactly one ring found
|
||||
the_one_ring = the_one_ring[0]
|
||||
```
|
||||
|
||||
There are equivalent search functions for all the main resources. You can find a listing of them
|
||||
[in the Search functions section](../../../Evennia-API.md) of the API frontpage.
|
||||
|
||||
## Searching using Object.search
|
||||
|
||||
On the `DefaultObject` is a `.search` method which we have already tried out when we made Commands. For
|
||||
this to be used you must already have an object available:
|
||||
On the `DefaultObject` is a `.search` method which we have already tried out when we made Commands. For this to be used you must already have an object available:
|
||||
|
||||
rose = obj.search("rose")
|
||||
|
||||
The `.search` method wraps `evennia.search_object` and handles its output in various ways.
|
||||
This searches for objects based on `key` or aliases. The `.search` method wraps `evennia.search_object` and handles its output in various ways.
|
||||
|
||||
- By default it will always search for objects among those in `obj.location.contents` and `obj.contents` (that is,
|
||||
things in obj's inventory or in the same room).
|
||||
- By default it will always search for objects among those in `obj.location.contents` and `obj.contents` (that is, things in obj's inventory or in the same room).
|
||||
- It will always return exactly one match. If it found zero or more than one match, the return is `None`.
|
||||
- On a no-match or multimatch, `.search` will automatically send an error message to `obj`.
|
||||
|
||||
|
|
@ -55,32 +57,39 @@ So this method handles error messaging for you. A very common way to use it is i
|
|||
```python
|
||||
from evennia import Command
|
||||
|
||||
class MyCommand(Command):
|
||||
class CmdQuickFind(Command):
|
||||
"""
|
||||
Find an item in your current location.
|
||||
|
||||
key = "findfoo"
|
||||
Usage:
|
||||
quickfind <query>
|
||||
|
||||
"""
|
||||
|
||||
key = "quickfind"
|
||||
|
||||
def func(self):
|
||||
|
||||
foo = self.caller.search("foo")
|
||||
if not foo:
|
||||
query = self.args
|
||||
result = self.caller.search(query)
|
||||
if not result
|
||||
return
|
||||
self.caller.msg(f"Found match for {query}: {foo}")
|
||||
```
|
||||
|
||||
Remember, `self.caller` is the one calling the command. This is usually a Character, which
|
||||
inherits from `DefaultObject`! This (rather stupid) Command searches for an object named "foo" in
|
||||
the same location. If it can't find it, `foo` will be `None`. The error has already been reported
|
||||
to `self.caller` so we just abort with `return`.
|
||||
inherits from `DefaultObject`!
|
||||
|
||||
This simple little Command takes its arguments and searches for a match. If it can't find it, `result` will be `None`. The error has already been reported to `self.caller` so we just abort with `return`.
|
||||
|
||||
You can use `.search` to find anything, not just stuff in the same room:
|
||||
|
||||
volcano = self.caller.search("Volcano", global=True)
|
||||
volcano = self.caller.search("Vesuvio", global=True)
|
||||
|
||||
If you only want to search for a specific list of things, you can do so too:
|
||||
|
||||
stone = self.caller.search("MyStone", candidates=[obj1, obj2, obj3, obj4])
|
||||
|
||||
This will only return a match if MyStone is one of the four provided candidate objects. This is quite powerful,
|
||||
here's how you'd find something only in your inventory:
|
||||
This will only return a match if "MyStone" is in the room (or in your inventory) _and_ is one of the four provided candidate objects. This is quite powerful, here's how you'd find something only in your inventory:
|
||||
|
||||
potion = self.caller.search("Healing potion", candidates=self.caller.contents)
|
||||
|
||||
|
|
@ -88,8 +97,7 @@ You can also turn off the automatic error handling:
|
|||
|
||||
swords = self.caller.search("Sword", quiet=True)
|
||||
|
||||
With `quiet=True` the user will not be notified on zero or multi-match errors. Instead you are expected to handle this
|
||||
yourself and what you get back is now a list of zero, one or more matches!
|
||||
With `quiet=True` the user will not be notified on zero or multi-match errors. Instead you are expected to handle this yourself. Furthermore, what is returned is now a list of zero, one or more matches!
|
||||
|
||||
## What can be searched for
|
||||
|
||||
|
|
@ -98,9 +106,9 @@ These are the main database entities one can search for:
|
|||
- [Objects](../../../Components/Objects.md)
|
||||
- [Accounts](../../../Components/Accounts.md)
|
||||
- [Scripts](../../../Components/Scripts.md),
|
||||
- [Channels](../../../Components/Channels.md),
|
||||
- [Messages](../../../Components/Msg.md)
|
||||
- [Help Entries](../../../Components/Help-System.md).
|
||||
- [Channels](../../../Components/Channels.md)
|
||||
- [Messages](../../../Components/Msg.md) (used by `page` command by default)
|
||||
- [Help Entries](../../../Components/Help-System.md) (help entries created manually)
|
||||
|
||||
Most of the time you'll likely spend your time searching for Objects and the occasional Accounts.
|
||||
|
||||
|
|
@ -112,8 +120,7 @@ The `key` is the name of the entity. Searching for this is always case-insensiti
|
|||
|
||||
### Search by aliases
|
||||
|
||||
Objects and Accounts can have any number of aliases. When searching for `key` these will searched too,
|
||||
you can't easily search only for aliases.
|
||||
Objects and Accounts can have any number of aliases. When searching for `key` these will searched too, you can't easily search only for aliases.
|
||||
|
||||
rose.aliases.add("flower")
|
||||
|
||||
|
|
@ -122,26 +129,26 @@ you can assign new aliases to things with the `alias` command.
|
|||
|
||||
### Search by location
|
||||
|
||||
Only Objects (things inheriting from `evennia.DefaultObject`) has a location. This is usually a room.
|
||||
The `Object.search` method will automatically limit it search by location, but it also works for the
|
||||
general search function. If we assume `room` is a particular Room instance,
|
||||
Only Objects (things inheriting from `evennia.DefaultObject`) has a location. The location is usually a room. The `Object.search` method will automatically limit it search by location, but it also works for the general search function. If we assume `room` is a particular Room instance,
|
||||
|
||||
chest = evennia.search_object("Treasure chest", location=room)
|
||||
|
||||
### Search by Tags
|
||||
|
||||
Think of a [Tag](../../../Components/Tags.md) as the label the airport puts on your luggage when flying.
|
||||
Everyone going on the same plane gets a tag grouping them together so the airport can know what should
|
||||
go to which plane. Entities in Evennia can be grouped in the same way. Any number of tags can be attached
|
||||
Think of a [Tag](../../../Components/Tags.md) as the label the airport puts on your luggage when flying. Everyone going on the same plane gets a tag grouping them together so the airport can know what should go to which plane. Entities in Evennia can be grouped in the same way. Any number of tags can be attached
|
||||
to each object.
|
||||
|
||||
rose.tags.add("flowers")
|
||||
rose.tags.add("thorny")
|
||||
daffodil.tags.add("flowers")
|
||||
tulip.tags.add("flowers")
|
||||
cactus.tags.add("flowers")
|
||||
cactus.tags.add("thorny")
|
||||
|
||||
You can now find all flowers using the `search_tag` function:
|
||||
|
||||
all_flowers = evennia.search_tag("flowers")
|
||||
roses_and_cactii = evennia.search_tag("thorny")
|
||||
|
||||
Tags can also have categories. By default this category is `None` which is also considered a category.
|
||||
|
||||
|
|
@ -196,13 +203,15 @@ You can also search using the typeclass itself:
|
|||
|
||||
all_roses = Rose.objects.all()
|
||||
|
||||
This last way of searching is a simple form of a Django _query_. This is a way to express SQL queries using
|
||||
Python.
|
||||
This last way of searching is a simple form of a Django _query_. This is a way to express SQL queries using Python. See [the next lesson](./Beginner-Tutorial-Django-queries.md), where we'll explore this way to searching in more detail.
|
||||
|
||||
### Search by dbref
|
||||
|
||||
The database id or `#dbref` is unique and never-reused within each database table. In search methods you can
|
||||
replace the search for `key` with the dbref to search for. This must be written as a string `#dbref`:
|
||||
```{sidebar} Will I run out of dbrefs?
|
||||
|
||||
Since dbrefs are not reused, do you need to worry about your database ids 'running out' in the future? [No, and here's why](../../../Components/Typeclasses.md#will-i-run-out-of-dbrefs).
|
||||
```
|
||||
The database id or `#dbref` is unique and never-reused within each database table. In search methods you can replace the search for `key` with the dbref to search for. This must be written as a string `#dbref`:
|
||||
|
||||
the_answer = self.caller.search("#42")
|
||||
eightball = evennia.search_object("#8")
|
||||
|
|
@ -211,16 +220,28 @@ Since `#dbref` is always unique, this search is always global.
|
|||
|
||||
```{warning} Relying on #dbrefs
|
||||
|
||||
You may be used to using #dbrefs a lot from other codebases. It is however considered
|
||||
`bad practice` in Evennia to rely on hard-coded #dbrefs. It makes your code hard to maintain
|
||||
and tied to the exact layout of the database. In 99% of cases you should pass the actual objects
|
||||
around and search by key/tags/attribute instead.
|
||||
In legacy code bases you may be used to relying a lot on #dbrefs to find and track things. Looking something up by #dbref can be practical - if used occationally. It is however considered **bad practice** to *rely* on hard-coded #dbrefs in Evennia. Especially to expect end users to know them. It makes your code fragile and hard to maintain, while tying your code to the exact layout of the database. In 99% of use cases you should organize your code such that you pass the actual objects around and search by key/tags/attribute instead.
|
||||
```
|
||||
|
||||
|
||||
## Finding objects relative each other
|
||||
|
||||
Let's consider a `chest` with a `coin` inside it. The chests stand in a room `dungeon`. In the dungeon is also
|
||||
a `door`. This is an exit leading outside.
|
||||
It's important to understand how objects relate to one another when searching.
|
||||
Let's consider a `chest` with a `coin` inside it. The chests stand in a room `dungeon`. In the dungeon is also a `door`. This is an exit leading outside.
|
||||
|
||||
```
|
||||
┌───────────────────────┐
|
||||
│dungeon │
|
||||
│ ┌─────────┐ │
|
||||
│ │chest │ ┌────┐ │
|
||||
│ │ ┌────┐ │ │door│ │
|
||||
│ │ │coin│ │ └────┘ │
|
||||
│ │ └────┘ │ │
|
||||
│ │ │ │
|
||||
│ └─────────┘ │
|
||||
│ │
|
||||
└───────────────────────┘
|
||||
```
|
||||
|
||||
- `coin.location` is `chest`.
|
||||
- `chest.location` is `dungeon`.
|
||||
|
|
@ -249,11 +270,22 @@ There is a property `.destination` which is only used by exits:
|
|||
- `door.destination` is `outside` (or wherever the door leads)
|
||||
- `room.destination` is `None` (same for all the other non-exit objects)
|
||||
|
||||
You can also include this information in searches:
|
||||
|
||||
```python
|
||||
from evennia import search_object
|
||||
|
||||
# we assume only one match of each
|
||||
dungeons = search_object("dungeon", typeclass="typeclasses.rooms.Room")
|
||||
chests = search_object("chest", location=dungeons[0])
|
||||
# find if there are any skulls in the chest
|
||||
skulls = search_object("Skull", candidates=chests[0].contents)
|
||||
```
|
||||
|
||||
More advanced, nested queries like this can however often be made more efficient by using the hints in the next lesson.
|
||||
|
||||
## Summary
|
||||
|
||||
Knowing how to find things is important and the tools from this section will serve you well. For most of your needs
|
||||
these tools will be all you need ...
|
||||
|
||||
... but not always. In the next lesson we will dive further into more complex searching when we look at
|
||||
Django queries and querysets in earnest.
|
||||
Knowing how to find things is important and the tools from this section will serve you well. These tools will cover most of your needs ...
|
||||
|
||||
... but not always. In the next lesson we will dive further into more complex searching when we look at Django queries and querysets in earnest.
|
||||
Loading…
Add table
Add a link
Reference in a new issue