Merge branch 'evennia:main' into spawnupdate-fix

This commit is contained in:
Tegiminis 2023-01-04 16:54:31 -08:00 committed by GitHub
commit 7c81d37e36
47 changed files with 422 additions and 373 deletions

View file

@ -1,27 +0,0 @@
---
name: Bug report (branch-develop)
about: Use this to report errors in the Evennia `develop` branch
title: "[BUG - Develop] (Enter a brief description here)"
labels: bug, branch-develop, needs-triage
assignees: ''
---
#### Describe the bug
<!--(This is for bugs in the develop-branch only. Make sure you test with the latest version.)-->
#### To Reproduce
Steps to reproduce the behavior:
1.
2.
3.
4. See error
#### Expected behavior
<!--(Replace with a clear and concise description of what you expected to happen.-->)
#### Develop-branch commit
<!--(The commit-hash. If unsure, run `evennia -v` or get the first few lines of the `about` command in-game.)-->
#### Additional context
<!--(Replace with any other context about the problem, or ideas on how to solve.)-->

View file

@ -4,12 +4,12 @@ name: documentation
on:
push:
branches: [ master, develop ]
branches: [ main, develop ]
paths:
- 'docs/**'
- 'evennia/contrib/**'
pull_request:
branches: [ master, develop ]
branches: [ main, develop ]
paths:
- 'docs/**'
- 'evennia/contrib/**'
@ -48,8 +48,8 @@ jobs:
cd gamedir
evennia migrate
- name: Build and deploy docs (only from master/develop branch)
if: ${{ github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master'}}
- name: Build and deploy docs (only from main/develop branch)
if: ${{ github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/main'}}
run: |
git config --global user.email "docbuilder@evennia.com"
git config --global user.name "Evennia docbuilder action"

View file

@ -1,37 +0,0 @@
# This Evennia workflow will deploy the Evennia package automatically to
# pypi if vNN tag was given.
#
name: publish-evennia
on:
push:
tags: ['v*']
jobs:
build-and-publish:
name: Build and publish Evennia to PyPi
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Set up Python 3.11
uses: actions/setup-python@v3
with:
python-version: "3.11"
- name: Install build
run: |
python -m pip install --upgrade pip
python -m pip install build --user
- name: Build binary wheel and source tarball
run: |
python -m build --sdist --wheel --outdir dist/ .
- name: Publish Evennia PyPi (on tag)
if: startsWith(github.ref, 'refs/tags')
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}

View file

@ -26,6 +26,12 @@ jobs:
TESTING_DB: "sqlite3"
coverage-test: true
timeout-minutes: 35
env:
UNIT_TEST_SETTINGS: "--settings=settings --keepdb --parallel 4 --timing"
COVERAGE_TEST_SETTINGS: "--settings=settings --timing"
steps:
- uses: actions/checkout@v3
@ -67,12 +73,7 @@ jobs:
if: ${{ ! matrix.coverage-test }}
working-directory: testing_mygame
run: |
evennia test \
--settings=settings \
--keepdb \
--parallel 4 \
--timing \
evennia
evennia test ${{ env.UNIT_TEST_SETTINGS }} evennia
# OBS - it's important to not run the coverage tests with --parallel, it messes up the coverage
# calculation!
@ -80,13 +81,8 @@ jobs:
if: ${{ matrix.coverage-test }}
working-directory: testing_mygame
run: |
coverage run \
--source=evennia \
--omit=*/migrations/*,*/urls.py,*/test*.py,*.sh,*.txt,*.md,*.pyc,*.service \
../bin/unix/evennia test \
--settings=settings \
--timing \
evennia
coverage run --rcfile=../pyproject.toml ../bin/unix/evennia test ${{ env.COVERAGE_TEST_SETTINGS }} evennia
coverage combine
coverage xml
coverage --version
coverage report | grep TOTAL
@ -107,7 +103,7 @@ jobs:
name: Deploy Docker Image
needs: test
runs-on: ubuntu-latest
if: ${{ github.repository == 'evennia/evennia' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/develop') }}
if: ${{ github.repository == 'evennia/evennia' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop') }}
steps:
- uses: actions/checkout@v3
@ -123,9 +119,9 @@ jobs:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push for master
if: ${{ github.ref == 'refs/heads/master' }}
id: docker_build_master
- name: Build and push for main
if: ${{ github.ref == 'refs/heads/main' }}
id: docker_build_main
uses: docker/build-push-action@v3
with:
push: true

45
.release.sh Executable file
View file

@ -0,0 +1,45 @@
# Release helper
VERSION=$(cat evennia/VERSION.txt)
echo "This will release Evennia $VERSION (based on evennia/VERSION.txt)."
echo "Before continuing:"
echo " 1. Make sure you have Evennia upload credentials for Github (tagging) and PyPi (main package)."
echo " 2. Update CHANGELOG.md."
echo " 3. Run 'make local' in docs/ to update dynamic docs and autodocstrings (may have to run twice)."
echo " 4. Make sure VERSION.txt and pyproject.toml both show version $VERSION."
echo " 5. Make sure all changes are committed, e.g. as 'Evennia 1.x.x bug-fix release' (un-staged files will be wiped)."
echo " 6. Make sure all unit tests pass!"
read -p "Continue? [Y/n]> " yn
case $yn in
[nN] ) echo "Aborting.";
exit;;
* ) echo "Starting release ...";;
esac
# clean and build the pypi distribution
echo "Preparing and Building PyPi package ..."
rm -Rf dist/
git clean -xdf
pip install --upgrade pip
pip install build twine
python -m build --sdist --wheel --outdir dist/ .
echo "Uploading PyPi package (requires PyPi credentials) ..."
python -m twine upload dist/*
# tag the latest git commit
echo "Creating and pushing release tag tag v$VERSION (requires GitHub credentials)..."
git tag -a v$VERSION -m "Evennia release v$VERSION"
git push --tags
echo "... Release complete."
echo ""
echo "Post-release actions:"
echo " 1. Make sure to push all commits."
echo " 2. Update github discussions to report on release."
echo " 2. Make post in discord #announcements channel pointing to discussion post."
echo " 3. Any other announcements as needed."

View file

@ -1,11 +1,22 @@
# Changelog
### Evennia 1.0
### Evennia 1.0.2
Dec 21, 2022
2019-2022 develop branch
Bug fix release. Fix more issues with discord bot reconnecting. Some doc
updates.
Changed to using `main` branch to follow github standard. Old `master` branch remains
for now but will not be used anymore, so as to not break installs during transition.
### Evennia 1.0.1
Dec 7, 2022
Bug fix release. Main issue was reconnect bug for discord bot.
## Evennia 1.0
2019-2022
_Changed to using `main` branch to follow github standard. Old `master` branch remains
for now but will not be used anymore, so as to not break installs during transition._
Increase requirements: Django 4.1+, Twisted 22.10+ Python 3.10, 3.11. PostgreSQL 11+.

View file

@ -13,7 +13,7 @@ default:
@echo " make test - run evennia test suite with all default values."
@echo " make tests=evennia.path test - run only specific test or tests."
@echo " make testp - run test suite using multiple cores."
@echo " make publish - publish evennia to pypi (requires pypi credentials)
@echo " make release - publish evennia to pypi (requires pypi credentials)
install:
pip install -e .
@ -44,10 +44,8 @@ testp:
evennia migrate;\
evennia test --keepdb --parallel 4 $(TESTS);\
version:
echo $(VERSION)
release:
rm -Rf dist/
git clean -xdf
pip install --upgrade pip
pip install build twine
python -m build --sdist --wheel --outdir dist/ .
python -m twine upload dist/*
./.release.sh

View file

@ -1,5 +1,5 @@
# Evennia MUD/MU\* Creation System ![][logo]
[![Build Status][unittestciimg]][unittestcilink] [![Coverage Status][coverimg]][coverlink] [![Pypi Version][pypibadge]][pypilink]
[![unittestciimg]][unittestcilink] [![Coverage Status][coverimg]][coverlink] [![Pypi Version][pypibadge]][pypilink]
[Evennia][homepage] is a modern library for creating [online multiplayer text
@ -48,8 +48,8 @@ Welcome!
[logo]: https://github.com/evennia/evennia/blob/master/evennia/web/website/static/website/images/evennia_logo.png
[unittestciimg]: https://github.com/evennia/evennia/workflows/test-suite/badge.svg
[unittestcilink]: https://github.com/evennia/evennia/actions?query=workflow%3Atest-suite
[coverimg]: https://coveralls.io/repos/github/evennia/evennia/badge.svg?branch=master
[coverlink]: https://coveralls.io/github/evennia/evennia?branch=master
[coverimg]: https://coveralls.io/repos/github/evennia/evennia/badge.svg?branch=main
[coverlink]: https://coveralls.io/github/evennia/evennia?branch=main
[pypibadge]: https://img.shields.io/pypi/v/evennia?color=blue
[pypilink]: https://pypi.org/project/evennia/
[introduction]: https://www.evennia.com/docs/latest/Evennia-Introduction.html

View file

@ -1,11 +1,22 @@
# Changelog
### Evennia 1.0
### Evennia 1.0.2
Dec 21, 2022
2019-2022 develop branch
Bug fix release. Fix more issues with discord bot reconnecting. Some doc
updates.
Changed to using `main` branch to follow github standard. Old `master` branch remains
for now but will not be used anymore, so as to not break installs during transition.
### Evennia 1.0.1
Dec 7, 2022
Bug fix release. Main issue was reconnect bug for discord bot.
## Evennia 1.0
2019-2022
_Changed to using `main` branch to follow github standard. Old `master` branch remains
for now but will not be used anymore, so as to not break installs during transition._
Increase requirements: Django 4.1+, Twisted 22.10+ Python 3.10, 3.11. PostgreSQL 11+.

View file

@ -2,6 +2,8 @@
This summarizes the changes. See the [Changelog](./Changelog.md) for the full list.
- Main development now on `main` branch. `master` branch remains, but will not be updated anymore.
## Minimum requirements
- Python 3.10 is now required minimum. Ubuntu LTS now installs with 3.10. Evennia 1.0 is also tested with Python 3.11 - this is the recommended version for Linux/Mac. Windows users may want to stay on Python 3.10 unless they are okay with installing a C++ compiler.

View file

@ -43,7 +43,7 @@ forces Evennia to use this settings file over the default one.
You can also test specific things by giving their path
evennia test --settings settings.py .world.tests.YourTest
evennia test --settings settings.py world.tests.YourTest
## Writing new unit tests
@ -106,15 +106,15 @@ To test this, run
to run the entire test module
evennia test --settings setings.py .world.tests
evennia test --settings setings.py world.tests
or a specific class:
evennia test --settings settings.py .world.tests.TestObj
evennia test --settings settings.py world.tests.TestObj
You can also run a specific test:
evennia test --settings settings.py .world.tests.TestObj.test_alternative_call
evennia test --settings settings.py world.tests.TestObj.test_alternative_call
You might also want to read the [Python documentation for the unittest module](https://docs.python.org/library/unittest.html).
@ -303,4 +303,4 @@ After doing so, you can then run tests without migrations by adding the `--nomig
```
evennia test --settings settings.py --nomigrations .
```
```

View file

@ -295,7 +295,7 @@ You can't do `git push upstream` unless you have write-access to the upstream Ev
This should be done in your fork of Evennia. You should _always_ do this in a _separate git branch_ based off the Evennia branch you want to improve.
git checkout main (or develop)
git branch - b myfixbranch
git branch -b myfixbranch
Now fix whatever needs fixing. Abide by the [Evennia code style](./Evennia-Code-Style.md). You can `git commit` commit your changes along the way as normal.

View file

@ -19,7 +19,7 @@ updated after Sept 2022 will be missing some translations.
+---------------+----------------------+--------------+
| es | Spanish | Aug 2019 |
+---------------+----------------------+--------------+
| fr | French | Mar 2022 |
| fr | French | Dec 2022 |
+---------------+----------------------+--------------+
| it | Italian | Oct 2022 |
+---------------+----------------------+--------------+

View file

@ -42,7 +42,7 @@ is being combined instead):
See the [sword example](evennia.contrib.game_systems.crafting.example_recipes) for an example
of how to design a recipe tree for crafting a sword from base elements.
## Intallation and Usage
## Installation and Usage
Import the `CmdCraft` command from evennia/contrib/crafting/crafting.py and
add it to your Character cmdset. Reload and the `craft` command will be

View file

@ -16,11 +16,12 @@ In more detail, in `mygame/commands/default_cmdsets.py`:
```python
...
from evennia.contrib import extended_room # <---
from evennia.contrib.grid import extended_room # <---
class CharacterCmdset(default_cmds.Character_CmdSet):
class CharacterCmdset(default_cmds.CharacterCmdSet):
...
def at_cmdset_creation(self):
super().at_cmdset_creation()
...
self.add(extended_room.ExtendedRoomCmdSet) # <---
@ -28,7 +29,10 @@ class CharacterCmdset(default_cmds.Character_CmdSet):
Then reload to make the new commands available. Note that they only work
on rooms with the typeclass `ExtendedRoom`. Create new rooms with the right
typeclass or use the `typeclass` command to swap existing rooms.
typeclass or use the `typeclass` command to swap existing rooms. Note that since
this contrib overrides the `look` command, you will need to add the
`extended_room.ExtendedRoomCmdSet` to the default character cmdset *after*
super().at_cmdset_creation(), or it will be overridden by the default look.
## Features

View file

@ -64,6 +64,7 @@ Start small. Evennia's [Beginner tutorial](Howtos/Beginner-Tutorial/Beginner-Tut
```{sidebar}
See also our [link page](./Links.md) for some reading suggestions.
```
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. The beginner-tutorial has a [basic introduction to Python](Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Python-basic-introduction.md), but if you are completely new, you should probably also sit down with a full Python beginner's tutorial at some point. There are plenty of them on the web if you look around.
To 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:

View file

@ -113,7 +113,7 @@ class LivingMixin:
healed = min(damage, hp)
self.hp += healed
self.msg("You heal for {healed} HP.")
self.msg(f"You heal for {healed} HP.")
def at_pay(self, amount):
"""When paying coins, make sure to never detract more than we have"""

View file

@ -92,6 +92,7 @@ If `localhost` doesn't work when trying to connect to your local game, try `127.
instead. Some MUD clients on Windows does not appear to understand the alias `localhost`.
- 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 `22.1` failed, install `22.0` manually with `pip install twisted==22.0`. Alternatively you could check that you are using the 64-bit version of Python and uninstall any 32bit one. If so, you must then `deactivate` the virtualenv, delete the `evenv` folder and recreate it anew with your new Python.
- If you've done a git installation, and your server won't start with an error message like `AttributeError: module 'evennia' has no attribute '_init'`, it may be a python path issue. In a terminal, cd to `(your python directory)\site-packages` and run the command `echo "C:\absolute\path\to\evennia" > local-vendors.pth`. Open the created file in your favorite IDE and make sure it is saved with *UTF-8* encoding and not *UTF-8 with BOM*.
- 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

View file

@ -16,8 +16,8 @@ Prior to 1.0, all Evennia installs were [Git-installs](./Installation-Git.md). T
- Make a _new_ `evenv` virtualenv (see the [virtualenv instructions](./Installation-Git.md#virtualenv) for help) and make sure it's active
- `cd` into your `evennia/` root folder (you want to be where you see the `docs/` and `bin/` directories as well as a nested `evennia/` folder)
- `git pull`
- `git checkout main` (the `master`)
- `pip install -e --upgrade .`
- `git checkout main` (instead of `master` which was used for `0.9.5`)
- `pip install --upgrade -e .`
- If you want the optional extra libs (needed by some contribs), do `pip install -e --upgrade .[extra]`
- Test that you can run the `evennia` command.

View file

@ -328,7 +328,7 @@ Evennia users:
| [Amazon Lightsail][9] | Cloud | $5/month | Free first month. AWS's "fixed cost" offering.|
| [Azure App Services][12] | Cloud | Free | Free tier with limited regions for hobbyists. |
| [Huawei Cloud][13] | Cloud | on demand | Similar to Amazon. Free 12-month tier with limited regions. |
| [Host1Plus][5] | VPS & Cloud | $4/month | $4-$8/month depending on length of sign-up period.
| [Heficed][5] | VPS & Cloud | $6/month | $6/month for a 1GB ram server. |
| [Scaleway][6] | Cloud | &euro;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|
@ -340,7 +340,7 @@ Evennia users:
[2]: https://www.digitalocean.com/pricing
[3]: https://aws.amazon.com/pricing/
[4]: https://www.genesismuds.com/
[5]: https://www.host1plus.com/
[5]: https://www.heficed.com/
[6]: https://www.scaleway.com/
[7]: https://lowendbox.com/
[8]: https://www.lowendtalk.com

View file

@ -1 +1 @@
1.0-dev
1.0.2

View file

@ -22,7 +22,6 @@ import time
from codecs import lookup as codecs_lookup
from django.conf import settings
from evennia.server.sessionhandler import SESSIONS
from evennia.utils import create, logger, search, utils
@ -191,7 +190,8 @@ class CmdCharCreate(COMMAND_DEFAULT_CLASS):
elif not new_character.db.desc:
new_character.db.desc = "This is a character."
self.msg(
f"Created new character {new_character.key}. Use |wic {new_character.key}|n to enter the game as this character."
f"Created new character {new_character.key}. Use |wic {new_character.key}|n to enter"
" the game as this character."
)
logger.log_sec(
f"Character Created: {new_character} (Caller: {account}, IP: {self.session.address})."
@ -317,11 +317,13 @@ class CmdIC(COMMAND_DEFAULT_CLASS):
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,
utils.make_iter(
account.search(
self.args,
candidates=account.db._playable_characters,
search_object=True,
quiet=True,
)
)
)
@ -370,12 +372,14 @@ class CmdIC(COMMAND_DEFAULT_CLASS):
account.puppet_object(session, new_character)
account.db._last_puppet = new_character
logger.log_sec(
f"Puppet Success: (Caller: {account}, Target: {new_character}, IP: {self.session.address})."
f"Puppet Success: (Caller: {account}, Target: {new_character}, IP:"
f" {self.session.address})."
)
except RuntimeError as exc:
self.msg(f"|rYou cannot become |C{new_character.name}|n: {exc}")
logger.log_sec(
f"Puppet Failed: %s (Caller: {account}, Target: {new_character}, IP: {self.session.address})."
f"Puppet Failed: %s (Caller: {account}, Target: {new_character}, IP:"
f" {self.session.address})."
)
@ -670,7 +674,8 @@ class CmdOption(COMMAND_DEFAULT_CLASS):
else:
flags[new_name] = new_val
self.msg(
f"Option |w{new_name}|n was changed from '|w{old_val}|n' to '|w{new_val}|n'."
f"Option |w{new_name}|n was changed from '|w{old_val}|n' to"
f" '|w{new_val}|n'."
)
return {new_name: new_val}
except Exception as err:
@ -1024,7 +1029,7 @@ class CmdStyle(COMMAND_DEFAULT_CLASS):
style <option> = <value>
Configure stylings for in-game display elements like table borders, help
entriest etc. Use without arguments to see all available options.
entries etc. Use without arguments to see all available options.
"""

View file

@ -1925,6 +1925,7 @@ class CmdDiscord2Chan(COMMAND_DEFAULT_CLASS):
/delete - alias to remove
/guild - toggle the Discord server tag on/off
/channel - toggle the Evennia/Discord channel tags on/off
/start - tell the bot to start, in case it lost its connection
Example:
discord2chan mydiscord = 555555555555555
@ -1943,6 +1944,7 @@ class CmdDiscord2Chan(COMMAND_DEFAULT_CLASS):
"guild",
"list",
"remove",
"start",
)
locks = "cmd:serversetting(DISCORD_ENABLED) and pperm(Developer)"
help_category = "Comms"
@ -1973,6 +1975,13 @@ class CmdDiscord2Chan(COMMAND_DEFAULT_CLASS):
f"WARNING: The Discord bot's typeclass is '{discord_bot.typeclass_path}'. This does not match {settings.DISCORD_BOT_CLASS} in settings!"
)
if "start" in self.switches:
if discord_bot.sessions.all():
self.msg("The Discord bot is already running.")
else:
discord_bot.start()
return
if "guild" in self.switches:
discord_bot.db.tag_guild = not discord_bot.db.tag_guild
self.msg(

View file

@ -371,8 +371,9 @@ class CmdInventory(COMMAND_DEFAULT_CLASS):
table = self.styled_table(border="header")
for item in items:
singular, _ = item.get_numbered_name(1, self.caller)
table.add_row(
f"|C{item.name}|n",
f"|C{singular}|n",
"{}|n".format(utils.crop(raw_ansi(item.db.desc or ""), width=50) or ""),
)
string = f"|wYou are carrying:\n{table}"
@ -424,8 +425,8 @@ class CmdGet(COMMAND_DEFAULT_CLASS):
if not success:
caller.msg("This can't be picked up.")
else:
caller.msg(f"You pick up {obj.name}.")
caller.location.msg_contents(f"{caller.name} picks up {obj.name}.", exclude=caller)
singular, _ = obj.get_numbered_name(1, caller)
caller.location.msg_contents(f"$You() $conj(pick) up {singular}.", from_obj=caller)
# calling at_get hook method
obj.at_get(caller)
@ -472,8 +473,8 @@ class CmdDrop(COMMAND_DEFAULT_CLASS):
if not success:
caller.msg("This couldn't be dropped.")
else:
caller.msg("You drop %s." % (obj.name,))
caller.location.msg_contents(f"{caller.name} drops {obj.name}.", exclude=caller)
singular, _ = obj.get_numbered_name(1, caller)
caller.location.msg_contents(f"$You() $conj(drop) {singular}.", from_obj=caller)
# Call the object script's at_drop() method.
obj.at_drop(caller)
@ -510,11 +511,13 @@ class CmdGive(COMMAND_DEFAULT_CLASS):
target = caller.search(self.rhs)
if not (to_give and target):
return
singular, _ = to_give.get_numbered_name(1, caller)
if target == caller:
caller.msg(f"You keep {to_give.key} to yourself.")
caller.msg(f"You keep {singular} to yourself.")
return
if not to_give.location == caller:
caller.msg(f"You are not holding {to_give.key}.")
caller.msg(f"You are not holding {singular}.")
return
# calling at_pre_give hook method
@ -524,10 +527,10 @@ class CmdGive(COMMAND_DEFAULT_CLASS):
# give object
success = to_give.move_to(target, quiet=True, move_type="give")
if not success:
caller.msg(f"You could not give {to_give.key}.")
caller.msg(f"You could not give {singular} to {target.key}.")
else:
caller.msg(f"You give {to_give.key} to {target.key}.")
target.msg(f"{caller.key} gives you {to_give.key}.")
caller.msg(f"You give {singular} to {target.key}.")
target.msg(f"{caller.key} gives you {singular}.")
# Call the object script's at_give() method.
to_give.at_give(caller, target)

View file

@ -627,7 +627,7 @@ class CmdHelp(COMMAND_DEFAULT_CLASS):
)
if suggestions:
help_text += (
"\n... But matches where found within the help "
"\n... But matches were found within the help "
"texts of the suggestions below."
)
suggestions = [

View file

@ -112,13 +112,13 @@ class TestGeneral(BaseEvenniaCommandTest):
self.call(general.CmdNick(), "/list", "Defined Nicks:")
def test_get_and_drop(self):
self.call(general.CmdGet(), "Obj", "You pick up Obj.")
self.call(general.CmdDrop(), "Obj", "You drop Obj.")
self.call(general.CmdGet(), "Obj", "You pick up an Obj.")
self.call(general.CmdDrop(), "Obj", "You drop an Obj.")
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.CmdGet(), "Obj", "You pick up an Obj.")
self.call(general.CmdGive(), "Obj to Char2", "You give")
self.call(general.CmdGive(), "Obj = Char", "You give", caller=self.char2)

View file

@ -30,7 +30,7 @@ class Character(ComponentHolderMixin, DefaultCharacter):
Components need to inherit the Component class directly and require a name.
```python
from evennia.contrib.components import Component
from evennia.contrib.base_systems.components import Component
class Health(Component):
name = "health"

View file

@ -42,7 +42,7 @@ is being combined instead):
See the [sword example](evennia.contrib.game_systems.crafting.example_recipes) for an example
of how to design a recipe tree for crafting a sword from base elements.
## Intallation and Usage
## Installation and Usage
Import the `CmdCraft` command from evennia/contrib/crafting/crafting.py and
add it to your Character cmdset. Reload and the `craft` command will be
@ -115,7 +115,7 @@ class RecipeBread(CraftingRecipe):
## Adding new recipes
A *recipe* is a class inheriting from
`evennia.contrib.crafting.crafting.CraftingRecipe`. This class implements the
`evennia.contrib.game_systems.crafting.CraftingRecipe`. This class implements the
most common form of crafting - that using in-game objects. Each recipe is a
separate class which gets initialized with the consumables/tools you provide.
@ -137,7 +137,7 @@ example setting:
```python
# in mygame/world/myrecipes.py
from evennia.contrib.crafting.crafting import CraftingRecipe
from evennia.contrib.game_systems.crafting import CraftingRecipe
class WoodenPuppetRecipe(CraftingRecipe):
"""A puppet""""
@ -200,7 +200,7 @@ in-game command:
In code we would do
```python
from evennia.contrib.crafting.crafting import craft
from evennia.contrib.game_systems.crafting import craft
puppet = craft(crafter, "wooden puppet", knife, wood)
```
@ -259,7 +259,7 @@ parent class and have your recipes inherit from this.
```python
from random import randint
from evennia.contrib.crafting.crafting import CraftingRecipe
from evennia.contrib.game_systems.crafting import CraftingRecipe
class SkillRecipe(CraftingRecipe):
"""A recipe that considers skill"""

View file

@ -16,11 +16,12 @@ In more detail, in `mygame/commands/default_cmdsets.py`:
```python
...
from evennia.contrib import extended_room # <---
from evennia.contrib.grid import extended_room # <---
class CharacterCmdset(default_cmds.Character_CmdSet):
class CharacterCmdset(default_cmds.CharacterCmdSet):
...
def at_cmdset_creation(self):
super().at_cmdset_creation()
...
self.add(extended_room.ExtendedRoomCmdSet) # <---
@ -28,7 +29,10 @@ class CharacterCmdset(default_cmds.Character_CmdSet):
Then reload to make the new commands available. Note that they only work
on rooms with the typeclass `ExtendedRoom`. Create new rooms with the right
typeclass or use the `typeclass` command to swap existing rooms.
typeclass or use the `typeclass` command to swap existing rooms. Note that since
this contrib overrides the `look` command, you will need to add the
`extended_room.ExtendedRoomCmdSet` to the default character cmdset *after*
super().at_cmdset_creation(), or it will be overridden by the default look.
## Features

View file

@ -21,7 +21,7 @@ Specifically, in `mygame/commands/default_cmdsets.py`:
...
from evennia.contrib.grid.ingame_map_display import MapDisplayCmdSet # <---
class CharacterCmdset(default_cmds.Character_CmdSet):
class CharacterCmdset(default_cmds.CharacterCmdSet):
...
def at_cmdset_creation(self):
...

View file

@ -2,14 +2,6 @@
XYZGrid - Griatch 2021
"""
from . import example, launchcmd, prototypes, tests, utils, xymap, xymap_legend, xyzgrid, xyzroom
from . import commands # noqa
from . import example # noqa
from . import launchcmd # noqa
from . import prototypes # noqa
from . import tests # noqa
from . import utils # noqa
from . import xymap # noqa
from . import xymap_legend # noqa
from . import xyzgrid # noqa
from . import xyzroom # noqa
from . import commands # isort:skip - this needs to be imported last

View file

@ -463,7 +463,10 @@ class XYZRoom(DefaultRoom):
)
sessions = looker.sessions.get()
client_width, _ = sessions[0].get_client_size() if sessions else CLIENT_DEFAULT_WIDTH
if sessions:
client_width, _ = sessions[0].get_client_size()
else:
client_width = CLIENT_DEFAULT_WIDTH
map_width = xymap.max_x

View file

@ -166,7 +166,7 @@ This module adds no new commands; embed it in your say/emote/whisper commands.
### Usage:
```python
from evennia.contrib import rplanguage
from evennia.contrib.rpg.rpsystem import rplanguage
# need to be done once, here we create the "default" lang
rplanguage.add_language()

View file

@ -128,7 +128,6 @@ class EvAdventureDungeonRoom(EvAdventureRoom):
class EvAdventureDungeonExit(DefaultExit):
"""
Dungeon exit. This will not create the target room until it's traversed.
It must be created referencing the dungeon_orchestrator it belongs to.
"""
@ -142,7 +141,8 @@ class EvAdventureDungeonExit(DefaultExit):
def at_traverse(self, traversing_object, target_location, **kwargs):
"""
Called when traversing. `target_location` will be None if the
target was not yet created.
target was not yet created. It checks the current location to get the
dungeon-orchestrator in use.
"""
if target_location == self.location:

View file

@ -7,7 +7,7 @@ object with its own functionality and state tracking.
Create the button with
create/drop button:tutorials.red_button.RedButton
create/drop button:contrib.tutorials.red_button.RedButton
Note that you must drop the button before you can see its messages! It's
imperative that you press the red button. You know you want to.

View file

@ -17,7 +17,7 @@ Evmenu.
Log in as superuser (#1), then run
batchcommand tutorials.tutorial_world.build
batchcommand contrib.tutorials.tutorial_world.build
Wait a little while for building to complete and don't run the command
again even if it's slow. This builds the world and connect it to Limbo

View file

@ -31,25 +31,27 @@ HELP_ENTRY_DICTS = [
"category": "General",
"locks": "read:perm(Developer)",
"text": """
Evennia is a MUD game server in Python.
Evennia is a MU-game server and framework written in Python. You can read more
on https://www.evennia.com.
# subtopics
## Installation
You'll find installation instructions on https:evennia.com
You'll find installation instructions on https://www.evennia.com.
## Community
There are many ways to get help and communicate with other devs!
### IRC
### Discussions
The irc channel is #evennia on irc.freenode.net
The Discussions forum is found at https://github.com/evennia/evennia/discussions.
### Discord
There is also a discord channel you can find from the sidebard on evennia.com.
There is also a discord channel for chatting - connect using the
following link: https://discord.gg/AJJpcRUhtF
""",
},
@ -58,7 +60,7 @@ HELP_ENTRY_DICTS = [
"category": "building",
"text": """
Evennia comes with a bunch of default building commands. You can
find a building tutorial in the evennia documentation.
find a beginner tutorial in the Evennia documentation.
""",
},

View file

@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-10-29 18:53+0000\n"
"PO-Revision-Date: 2022-03-20 19:55+0100\n"
"PO-Revision-Date: 2022-12-16 15:09+0100\n"
"Last-Translator: Christophe Petry <toktoktheeo@outlook.com>\n"
"Language-Team: \n"
"Language: fr\n"
@ -16,7 +16,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Generator: Poedit 3.0.1\n"
"X-Generator: Poedit 3.2.2\n"
#: accounts/accounts.py:341
#, python-brace-format
@ -28,6 +28,8 @@ msgstr "|c{key}|R est déjà contrôlé par un autre compte."
msgid ""
"You cannot control any more puppets (max {_MAX_NR_SIMULTANEOUS_PUPPETS})"
msgstr ""
"Vous ne pouvez contrôler plus de poupées (Maximum : "
"{_MAX_NR_SIMULTANEOUS_PUPPETS})"
#: accounts/accounts.py:555
msgid "Too many login failures; please try again in a few minutes."
@ -73,9 +75,8 @@ msgstr ""
"problème persiste."
#: accounts/accounts.py:918
#, fuzzy
msgid "Account being deleted."
msgstr "Suppression du compte."
msgstr "Le compte a été supprimé."
#: accounts/accounts.py:1475 accounts/accounts.py:1819
#, python-brace-format
@ -382,12 +383,12 @@ msgstr "Vous avez maintenant {name} en votre possession."
#: objects/objects.py:1863
#, python-brace-format
msgid "{object} arrives to {destination} from {origin}."
msgstr ""
msgstr "{object} arrive à {destination} depuis {origin}."
#: objects/objects.py:1865
#, python-brace-format
msgid "{object} arrives to {destination}."
msgstr ""
msgstr "{object} arrive à {destination}."
#: objects/objects.py:2530
msgid "Invalid character name."
@ -421,10 +422,9 @@ msgid "{name} has entered the game."
msgstr "{name} est entré(e) dans le jeu."
#: objects/objects.py:2716
#, fuzzy, python-brace-format
#| msgid "{name} has left the game."
#, python-brace-format
msgid "{name} has left the game{reason}."
msgstr "{name} est sorti(e) du jeu."
msgstr "{name} est sorti(e) du jeu ({reason})."
#: objects/objects.py:2838
msgid "This is a room."
@ -552,6 +552,8 @@ msgid ""
"Diff contains non-dicts that are not on the form (old, new, action_to_take): "
"{diffpart}"
msgstr ""
"\"diff\" contient des non-dicts qui ne sont pas formatés (ancien, nouveau, "
"action à prendre): {diffpart}"
#: scripts/scripthandler.py:51
#, fuzzy, python-brace-format
@ -613,7 +615,7 @@ msgstr "délai d'inactivité dépassé"
#: server/server.py:177
msgid " (connection lost)"
msgstr ""
msgstr " (connexion perdue)"
#: server/sessionhandler.py:41
msgid "Your client sent an incorrect UTF-8 sequence."
@ -738,6 +740,8 @@ msgstr ""
#: utils/eveditor.py:143
msgid "|rNo save function defined. Buffer cannot be saved.|n"
msgstr ""
"|rAucune fonction d'enregistrement définie. La pile ne peut être "
"sauvegardée.|n"
#: utils/eveditor.py:145
msgid "No changes need saving"
@ -745,7 +749,7 @@ msgstr "Aucune modification ne doit être sauvegardée"
#: utils/eveditor.py:146
msgid "Exited editor."
msgstr "Sortie de l'éditeur:"
msgstr "Sortie de l'éditeur."
#: utils/eveditor.py:149
#, python-brace-format
@ -755,6 +759,10 @@ msgid ""
"\n"
"|rQuit function gave an error. Skipping.|n\n"
msgstr ""
"\n"
"{error}\n"
"\n"
"|rLa fonction quitter à retourner une erreur. On passe.|n\n"
#: utils/eveditor.py:157
#, python-brace-format
@ -766,6 +774,13 @@ msgid ""
"to non-persistent mode (which means the editor session won't survive\n"
"an eventual server reload - so save often!)|n\n"
msgstr ""
"\n"
"{error}\n"
"\n"
"L'éditeur n'a pas pu sauvergarder en mode persistent. Changement pour le "
"mode non-persistant. \n"
"Cela signifie que l'éditeur ne survivra pas à un rechargement du serveur, \n"
"alors sauvegardez souvent !\n"
#: utils/eveditor.py:167
msgid ""
@ -773,26 +788,29 @@ msgid ""
"EvEditor callbacks could not be pickled, for example because it's a class "
"method or is defined inside another function."
msgstr ""
"EvEditeur erreur du mode persistant. Usuellement, c'est lorsque un ou "
"plusieurs appel n'ont pu aboutir dans l'éditeur. Par exemple, c'est "
"parcequ'une méthode de class et définie à l'intérieur d'une autre fonction."
#: utils/eveditor.py:173
msgid "Nothing to undo."
msgstr ""
msgstr "Rien pour revenir en arrière."
#: utils/eveditor.py:174
msgid "Nothing to redo."
msgstr ""
msgstr "Rien à rétablir."
#: utils/eveditor.py:175
msgid "Undid one step."
msgstr ""
msgstr "Un pas supprimé."
#: utils/eveditor.py:176
msgid "Redid one step."
msgstr ""
msgstr "Un pas ajouté."
#: utils/eveditor.py:494
msgid "Single ':' added to buffer."
msgstr ""
msgstr "Un seul ':' ajouté à la pile."
#: utils/eveditor.py:509
msgid "Save before quitting?"
@ -806,7 +824,7 @@ msgstr ""
#: utils/eveditor.py:529
#, python-brace-format
msgid "Deleted {string}."
msgstr ""
msgstr "{string} supprimé."
#: utils/eveditor.py:534
msgid "You must give a search word to delete."
@ -815,17 +833,17 @@ msgstr "Vous devez donner un mot de recherche à supprimer."
#: utils/eveditor.py:540
#, python-brace-format
msgid "Removed {arg1} for lines {l1}-{l2}."
msgstr ""
msgstr "{arg1} retiré des lignes {l1}-{l2}."
#: utils/eveditor.py:546
#, python-brace-format
msgid "Removed {arg1} for {line}."
msgstr ""
msgstr "{arg1} retiré de la ligne {line}"
#: utils/eveditor.py:562
#, python-brace-format
msgid "Cleared {nlines} lines from buffer."
msgstr ""
msgstr "{nlines} lignes nettoyées depuis la pile."
#: utils/eveditor.py:567
#, python-brace-format
@ -835,7 +853,7 @@ msgstr ""
#: utils/eveditor.py:574
#, python-brace-format
msgid "{line}, {cbuf} cut."
msgstr ""
msgstr "{line}, {cbuf} coupée."
#: utils/eveditor.py:578
msgid "Copy buffer is empty."
@ -844,7 +862,7 @@ msgstr "Le tampon de copie est vide."
#: utils/eveditor.py:583
#, python-brace-format
msgid "Pasted buffer {cbuf} to {line}."
msgstr ""
msgstr "La Pile (buffer) copié de {cbuf} à {line}"
#: utils/eveditor.py:591
msgid "You need to enter a new line and where to insert it."
@ -853,7 +871,7 @@ msgstr "Vous devez saisir une nouvelle ligne et indiquer où l'insérer."
#: utils/eveditor.py:596
#, python-brace-format
msgid "Inserted {num} new line(s) at {line}."
msgstr ""
msgstr "{num} ligne(s) insérée(s) depuis la ligne : {line}."
#: utils/eveditor.py:604
msgid "You need to enter a replacement string."
@ -862,7 +880,7 @@ msgstr "Vous devez saisir une chaîne de remplacement."
#: utils/eveditor.py:609
#, python-brace-format
msgid "Replaced {num} line(s) at {line}."
msgstr ""
msgstr "{num} lignes remplacées à partir de la ligne {line}."
#: utils/eveditor.py:616
msgid "You need to enter text to insert."
@ -871,16 +889,16 @@ msgstr "Vous devez saisir le texte à insérer."
#: utils/eveditor.py:624
#, python-brace-format
msgid "Inserted text at beginning of {line}."
msgstr ""
msgstr "Texte ajouté au début de la ligne {line}."
#: utils/eveditor.py:628
msgid "You need to enter text to append."
msgstr ""
msgstr "Vous avez besoin d'insérer du texte à ajouter."
#: utils/eveditor.py:636
#, python-brace-format
msgid "Appended text to end of {line}."
msgstr ""
msgstr "Text ajouté à la fin de la ligne {line}."
#: utils/eveditor.py:641
msgid "You must give a search word and something to replace it with."
@ -890,36 +908,36 @@ msgstr ""
#: utils/eveditor.py:647
#, python-brace-format
msgid "Search-replaced {arg1} -> {arg2} for lines {l1}-{l2}."
msgstr ""
msgstr "Rechercher-remplacer {arg1} -> {arg2} pour les lignes {l1}-{l2}."
#: utils/eveditor.py:653
#, python-brace-format
msgid "Search-replaced {arg1} -> {arg2} for {line}."
msgstr ""
msgstr "Recherche-remplacer {arg1} -> {arg2} pour la ligne {line}."
#: utils/eveditor.py:677
#, python-brace-format
msgid "Flood filled lines {l1}-{l2}."
msgstr ""
msgstr "Lignes remplies (inondées ?) {l1}-{l2}."
#: utils/eveditor.py:679
#, python-brace-format
msgid "Flood filled {line}."
msgstr ""
msgstr "\"flood\" rempli {line}."
#: utils/eveditor.py:701
msgid "Valid justifications are"
msgstr ""
msgstr "Les justification validées sont"
#: utils/eveditor.py:710
#, python-brace-format
msgid "{align}-justified lines {l1}-{l2}."
msgstr ""
msgstr "{align}-lignes justifiées{l1}-{l2}."
#: utils/eveditor.py:716
#, python-brace-format
msgid "{align}-justified {line}."
msgstr ""
msgstr "{align}-justified {line}."
#: utils/eveditor.py:728
#, python-brace-format
@ -976,11 +994,11 @@ msgstr "Auto-indentation désactivée."
#: utils/eveditor.py:1093
#, python-brace-format
msgid "Line Editor [{name}]"
msgstr ""
msgstr "Édition ligne [{name}]"
#: utils/eveditor.py:1101
msgid "(:h for help)"
msgstr ""
msgstr "(:h pour l'aide)"
#: utils/evmenu.py:302
#, python-brace-format
@ -1026,15 +1044,15 @@ msgstr "|rChoix invalide.|n"
#: utils/evmenu.py:1439
msgid "|Wcurrent|n"
msgstr ""
msgstr "|WActuel|n"
#: utils/evmenu.py:1447
msgid "|wp|Wrevious page|n"
msgstr ""
msgstr "|wp|Wage précédente|n"
#: utils/evmenu.py:1454
msgid "|wn|Wext page|n"
msgstr ""
msgstr "|wp|Wpage suivante|n"
#: utils/evmenu.py:1689
msgid "Aborted."

View file

@ -538,8 +538,16 @@ 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)]
portal_cmd = [
TWISTED_BINARY,
f"--python={PORTAL_PY_FILE}",
"--logger=evennia.utils.logger.GetPortalLogObserver",
]
server_cmd = [
TWISTED_BINARY,
f"--python={SERVER_PY_FILE}",
"--logger=evennia.utils.logger.GetServerLogObserver",
]
if os.name != "nt":
# PID files only for UNIX
@ -1363,8 +1371,8 @@ def set_gamedir(path):
global GAMEDIR
Ndepth = 10
settings_path = os.path.join("server", "conf", "settings.py")
os.chdir(GAMEDIR)
settings_path = SETTINGS_DOTPATH.replace(".", os.sep) + ".py"
os.chdir(path)
for i in range(Ndepth):
gpath = os.getcwd()
if "server" in os.listdir(gpath):

View file

@ -84,7 +84,7 @@ def should_retry(status_code):
class DiscordWebsocketServerFactory(WebSocketClientFactory, protocol.ReconnectingClientFactory):
"""
A variant of the websocket-factory that auto-reconnects.
A customized websocket client factory that navigates the Discord gateway process.
"""
@ -94,7 +94,7 @@ class DiscordWebsocketServerFactory(WebSocketClientFactory, protocol.Reconnectin
noisy = False
gateway = None
resume_url = None
do_retry = True
is_connecting = False
def __init__(self, sessionhandler, *args, **kwargs):
self.uid = kwargs.get("uid")
@ -122,8 +122,8 @@ class DiscordWebsocketServerFactory(WebSocketClientFactory, protocol.Reconnectin
d = readBody(response)
d.addCallback(self.websocket_init, *args, **kwargs)
return d
elif should_retry(response.code):
delay(300, self.get_gateway_url, *args, **kwargs)
else:
logger.log_warn("Discord gateway request failed.")
d.addCallback(cbResponse)
@ -132,6 +132,7 @@ class DiscordWebsocketServerFactory(WebSocketClientFactory, protocol.Reconnectin
callback for when the URL is gotten
"""
data = json.loads(str(payload, "utf-8"))
self.is_connecting = False
if url := data.get("url"):
self.gateway = f"{url}/?v={DISCORD_API_VERSION}&encoding=json".encode("utf-8")
useragent = kwargs.pop("useragent", DISCORD_USER_AGENT)
@ -179,30 +180,7 @@ class DiscordWebsocketServerFactory(WebSocketClientFactory, protocol.Reconnectin
connector (Connector): Represents the connection.
"""
logger.log_info("Attempting connection to Discord...")
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)
def clientConnectionLost(self, connector, reason):
"""
Called when Client loses connection.
Args:
connector (Connection): Represents the connection.
reason (str): The reason for the failure.
"""
if self.do_retry or not self.bot:
self.retry(connector)
logger.log_info("Connecting to Discord...")
def reconnect(self):
"""
@ -210,33 +188,30 @@ class DiscordWebsocketServerFactory(WebSocketClientFactory, protocol.Reconnectin
de-registering the session and then reattaching a new one.
"""
# set the retry flag to False so it doesn't attempt an automatic retry
# and duplicate the connection
self.do_retry = False
# disconnect everything
self.bot.transport.loseConnection()
self.sessionhandler.server_disconnect(self.bot)
# set up the reconnection
if self.resume_url:
self.url = self.resume_url
elif self.gateway:
self.url = self.gateway
else:
# we don't know where to reconnect to! start from the beginning
self.get_gateway_url()
return
self.start()
# we don't know where to reconnect to! we'll start from the beginning
self.url = None
# reset the internal delay, since this is a deliberate disconnect
self.delay = self.initialDelay
# disconnect to allow the reconnection process to kick in
self.bot.sendClose()
self.sessionhandler.server_disconnect(self.bot)
def start(self):
"Connect protocol to remote server"
if not self.gateway:
# we can't actually start yet
# we don't know where to connect to
# get the gateway URL from Discord
self.is_connecting = True
self.get_gateway_url()
else:
# set the retry flag so we maintain this connection
self.do_retry = True
elif not self.is_connecting:
# everything is good, connect
connectWS(self)
@ -255,7 +230,6 @@ class DiscordClient(WebSocketClientProtocol, _BASE_SESSION_CLASS):
def __init__(self):
WebSocketClientProtocol.__init__(self)
_BASE_SESSION_CLASS.__init__(self)
self.restart_downtime = None
def at_login(self):
pass
@ -265,8 +239,7 @@ class DiscordClient(WebSocketClientProtocol, _BASE_SESSION_CLASS):
Called when connection is established.
"""
self.restart_downtime = None
self.restart_task = None
logger.log_msg("Discord connection established.")
self.factory.bot = self
self.init_session("discord", "discord.gg", self.factory.sessionhandler)
@ -352,11 +325,11 @@ class DiscordClient(WebSocketClientProtocol, _BASE_SESSION_CLASS):
"""
if self.nextHeartbeatCall:
self.nextHeartbeatCall.cancel()
self.disconnect(reason)
if code >= 4000:
logger.log_err(f"Discord connection closed: {reason}")
self.nextHeartbeatCall = None
if wasClean:
logger.log_info(f"Discord connection closed ({code}) reason: {reason}")
else:
logger.log_info(f"Discord disconnected: {reason}")
logger.log_info(f"Discord connection lost.")
def _send_json(self, data):
"""

View file

@ -68,27 +68,27 @@ class TestLauncher(TwistedTestCase):
@patch("evennia.server.evennia_launcher.os.name", new="posix")
def test_get_twisted_cmdline(self):
pcmd, scmd = evennia_launcher._get_twistd_cmdline(False, False)
self.assertTrue("portal.py" in pcmd[1])
self.assertTrue("--pidfile" in pcmd[2])
self.assertTrue("server.py" in scmd[1])
self.assertTrue("--pidfile" in scmd[2])
self.assertIn("portal.py", pcmd[1])
self.assertIn("--pidfile", pcmd[3])
self.assertIn("server.py", scmd[1])
self.assertIn("--pidfile", scmd[3])
pcmd, scmd = evennia_launcher._get_twistd_cmdline(True, True)
self.assertTrue("portal.py" in pcmd[1])
self.assertTrue("--pidfile" in pcmd[2])
self.assertTrue("--profiler=cprofile" in pcmd[4], "actual: {}".format(pcmd))
self.assertTrue("--profile=" in pcmd[5])
self.assertTrue("server.py" in scmd[1])
self.assertTrue("--pidfile" in scmd[2])
self.assertTrue("--pidfile" in scmd[2])
self.assertTrue("--profiler=cprofile" in scmd[4], "actual: {}".format(scmd))
self.assertTrue("--profile=" in scmd[5])
self.assertIn("portal.py", pcmd[1])
self.assertIn("--pidfile", pcmd[3])
self.assertIn("--profiler=cprofile", pcmd[5], pcmd)
self.assertIn("--profile=", pcmd[6])
self.assertIn("server.py", scmd[1])
self.assertIn("--pidfile", scmd[3])
self.assertIn("--pidfile", scmd[3])
self.assertIn("--profiler=cprofile", scmd[5], "actual: {}".format(scmd))
self.assertIn("--profile=", scmd[6])
@patch("evennia.server.evennia_launcher.os.name", new="nt")
def test_get_twisted_cmdline_nt(self):
pcmd, scmd = evennia_launcher._get_twistd_cmdline(False, False)
self.assertTrue(len(pcmd) == 2, "actual: {}".format(pcmd))
self.assertTrue(len(scmd) == 2, "actual: {}".format(scmd))
self.assertTrue(len(pcmd) == 3, pcmd)
self.assertTrue(len(scmd) == 3, scmd)
@patch("evennia.server.evennia_launcher.reactor.stop")
def test_reactor_stop(self, mockstop):

View file

@ -1737,7 +1737,7 @@ class NickHandler(AttributeHandler):
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)
is_match, raw_string = parse_nick_template(raw_string, regex, template)
if is_match:
break
return raw_string

View file

@ -30,6 +30,7 @@ except ImportError:
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist
from django.utils.safestring import SafeString
from evennia.utils import logger
from evennia.utils.utils import is_iter, to_bytes, uses_database

View file

@ -273,22 +273,12 @@ from django.conf import settings
# i18n
from django.utils.translation import gettext as _
from evennia import CmdSet, Command
from evennia.commands import cmdhandler
from evennia.utils import logger
from evennia.utils.ansi import strip_ansi
from evennia.utils.evtable import EvColumn, EvTable
from evennia.utils.utils import (
crop,
dedent,
is_iter,
m_len,
make_iter,
mod_import,
pad,
to_str,
)
from evennia.utils.utils import crop, dedent, is_iter, m_len, make_iter, mod_import, pad, to_str
# read from protocol NAWS later?
_MAX_TEXT_WIDTH = settings.CLIENT_DEFAULT_WIDTH

View file

@ -288,8 +288,8 @@ def justify(text, width=None, align="l", indent=0, fillchar=" "):
# absolute mode - just crop or fill to width
abs_lines = []
for line in text.split("\n"):
nlen = len(line)
if len(line) < width:
nlen = m_len(line)
if m_len(line) < width:
line += sp * (width - nlen)
else:
line = crop(line, width=width, suffix="")
@ -304,7 +304,7 @@ def justify(text, width=None, align="l", indent=0, fillchar=" "):
for ip, paragraph in enumerate(paragraphs):
if ip > 0:
words.append(("\n", 0))
words.extend((word, len(word)) for word in paragraph.split())
words.extend((word, m_len(word)) for word in paragraph.split())
if not words:
# Just whitespace!

View file

@ -4,98 +4,117 @@ build-backend = "setuptools.build_meta"
[project]
name = "evennia"
version = "1.0rc11"
maintainers = [
{ name="Griatch", email="griatch@gmail.com" },
]
version = "1.0.2"
maintainers = [{ name = "Griatch", email = "griatch@gmail.com" }]
description = "A full-featured toolkit and server for text-based multiplayer games (MUDs, MU*, etc)."
requires-python = ">=3.10"
readme = { file="README.md", content-type="text/markdown" }
license = { text="BSD" }
readme = { file = "README.md", content-type = "text/markdown" }
license = { text = "BSD" }
keywords = [
"MUD", "MUSH", "MUX", "MMO", "text-only", "multiplayer", "online", "rpg", "game", "engine",
"framework", "text", "adventure", "telnet", "websocket", "blind", "accessible", "ascii",
"utf-8", "terminal", "online", "server", "beginner", "tutorials"
"MUD",
"MUSH",
"MUX",
"MMO",
"text-only",
"multiplayer",
"online",
"rpg",
"game",
"engine",
"framework",
"text",
"adventure",
"telnet",
"websocket",
"blind",
"accessible",
"ascii",
"utf-8",
"terminal",
"online",
"server",
"beginner",
"tutorials",
]
classifiers = [
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: JavaScript",
"Development Status :: 5 - Production/Stable",
"License :: OSI Approved :: BSD License",
"Environment :: Console",
"Environment :: Web Environment",
"Framework :: Django",
"Framework :: Twisted",
"Intended Audience :: Developers",
"Intended Audience :: Education",
"Operating System :: MacOS",
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX :: Linux",
"Topic :: Database",
"Topic :: Education",
"Topic :: Games/Entertainment :: Multi-User Dungeons (MUD)",
"Topic :: Games/Entertainment :: Puzzle Games",
"Topic :: Games/Entertainment :: Role-Playing",
"Topic :: Games/Entertainment :: Simulation",
"Topic :: Software Development :: Libraries :: Application Frameworks",
"Topic :: Internet :: WWW/HTTP :: WSGI :: Server"
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: JavaScript",
"Development Status :: 5 - Production/Stable",
"License :: OSI Approved :: BSD License",
"Environment :: Console",
"Environment :: Web Environment",
"Framework :: Django",
"Framework :: Twisted",
"Intended Audience :: Developers",
"Intended Audience :: Education",
"Operating System :: MacOS",
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX :: Linux",
"Topic :: Database",
"Topic :: Education",
"Topic :: Games/Entertainment :: Multi-User Dungeons (MUD)",
"Topic :: Games/Entertainment :: Puzzle Games",
"Topic :: Games/Entertainment :: Role-Playing",
"Topic :: Games/Entertainment :: Simulation",
"Topic :: Software Development :: Libraries :: Application Frameworks",
"Topic :: Internet :: WWW/HTTP :: WSGI :: Server",
]
dependencies = [
# core dependencies
"django >= 4.1.3, < 4.2",
"twisted >= 22.10, < 23",
"pytz >= 2022.6",
"djangorestframework >= 3.14, < 3.15",
"pyyaml >= 6.0",
"django-filter == 2.4",
"django-sekizai == 2.0.0",
"inflect >= 5.2.0",
"autobahn >= 20.7.1, < 21.0.0",
"lunr == 0.6.0",
"simpleeval <= 1.0",
"uritemplate == 4.1.1",
"Jinja2 < 3.1",
"tzdata >= 2022.6",
# for unit tests and code formatting
"mock >= 4.0.3",
"model_mommy >= 2.0",
"anything ==0.2.1",
"black >= 22.6",
"isort >= 5.10",
"parameterized ==0.8.1",
# core dependencies
"django >= 4.1.3, < 4.2",
"twisted >= 22.10, < 23",
"pytz >= 2022.6",
"djangorestframework >= 3.14, < 3.15",
"pyyaml >= 6.0",
"django-filter == 2.4",
"django-sekizai == 2.0.0",
"inflect >= 5.2.0",
"autobahn >= 20.7.1, < 21.0.0",
"lunr == 0.6.0",
"simpleeval <= 1.0",
"uritemplate == 4.1.1",
"Jinja2 < 3.1",
"tzdata >= 2022.6",
# for unit tests and code formatting
"mock >= 4.0.3",
"model_mommy >= 2.0",
"anything ==0.2.1",
"black >= 22.6",
"isort >= 5.10",
"parameterized ==0.8.1",
]
[project.optional-dependencies]
extra = [
# contrib optional dependencies
# install with 'pip install evennia[extra]`
# contrib optional dependencies
# install with 'pip install evennia[extra]`
# crypto libraries for ssh support
"cryptography >= 2.8",
"pyasn1 >= 0.4.8",
"bcrypt >= 3.1.7",
# crypto libraries for ssh support
"cryptography >= 2.8",
"pyasn1 >= 0.4.8",
"bcrypt >= 3.1.7",
# Telnet-SSL support
"pyopenssl >= 19.1",
"service_identity >= 18.1.0",
# Telnet-SSL support
"pyopenssl >= 19.1",
"service_identity >= 18.1.0",
# AWS storage contrib
"boto3 >= 1.4.4",
"botocore >= 1.15",
# AWS storage contrib
"boto3 >= 1.4.4",
"botocore >= 1.15",
# Jupyter Notebook support
"jupyter >= 1.0.0",
"ipython >= 7.19.0",
"django-extensions >= 3.1.0",
# Jupyter Notebook support
"jupyter >= 1.0.0",
"ipython >= 7.19.0",
"django-extensions >= 3.1.0",
# xyzroom contrib
"scipy == 1.9.3",
# xyzroom contrib
"scipy == 1.9.3",
# Git contrib
"gitpython >= 3.1.27"
# Git contrib
"gitpython >= 3.1.27",
]
[project.urls]
@ -133,3 +152,20 @@ exclude = '''
)
'''
[tool.coverage]
[tool.coverage.run]
concurrency = ["multiprocessing"]
parallel = true
source = ["evennia"]
omit = [
"*/migrations/*",
"*/urls.py",
"*/test*.py",
"*.sh",
"*.txt",
"*.md",
"*.pyc",
"*.service",
]