Continue documentation of web components

This commit is contained in:
Griatch 2021-05-22 16:11:48 +02:00
parent 72e9fd6fd1
commit 4bea4d5703
18 changed files with 450 additions and 84 deletions

View file

@ -1,11 +1,71 @@
# Webserver
When Evennia starts it also spins up its own Twisted-based web server. The webserver is responsible for serving the html pages of the game's website. It can also serve static resources like images and music.
When Evennia starts it also spins up its own Twisted-based web server. The
webserver is responsible for serving the html pages of the game's website. It
can also serve static resources like images and music.
The webclient runs as part of the [Server](Portal-And-Server) process of Evennia. This means that it can directly access cached objects modified in-game, and there is no risk of working with objects that are temporarily out-of-sync in the database.
The webclient runs as part of the [Server](Portal-And-Server) process of
Evennia. This means that it can directly access cached objects modified
in-game, and there is no risk of working with objects that are temporarily
out-of-sync in the database.
The webserver runs on Twisted and is meant to be used in a production environment. It leverages the Django web framework and provides:
The webserver runs on Twisted and is meant to be used in a production
environment. It leverages the Django web framework and provides:
- A [Game Website](Website) - this is what you see when you go to `localhost:4001`. The look of the website is meant to be customized to your game. Users logged into the website will be auto-logged into the game if they do so with the webclient since they share the same login credentials (there is no way to safely do auto-login with telnet clients).
- The [Web Admin](Web-Admin) is based on the Django web admin and allows you to edit the game database in a graphical interface.
- The [Webclient](Webclient) page is served by the webserver, but the actual game communication (sending/receiving data) is done by the javascript client on the page opening a websocket connection directly to Evennia's Portal.
- A [Game Website](Website) - this is what you see when you go to
- `localhost:4001`. The look of the website is meant to be customized to your
- game. Users logged into the website will be auto-logged into the game if they
- do so with the webclient since they share the same login credentials (there
- is no way to safely do auto-login with telnet clients).
- The [Web Admin](Web-Admin) is based on the Django web admin and allows you to
- edit the game database in a graphical interface.
- The [Webclient](Webclient) page is served by the webserver, but the actual
- game communication (sending/receiving data) is done by the javascript client
on the page opening a websocket connection directly to Evennia's Portal.
## Basic Webserver data flow
1. A user enters an url in their browser (or clicks a button). This leads to
the browser sending a _HTTP request_ to the server containing an url-path
(like for `https://localhost:4001/`, the part of the url we need to consider
`/`). Other possibilities would be `/admin/`, `/login/`, `/channels/` etc.
2. evennia (through Django) will make use of the regular expressions registered
in the `urls.py` file. This acts as a rerouter to _views_, which are
regular Python functions or callable classes able to process the incoming
request (think of these as similar to the right Evennia Command being
selected to handle your input - views are like Commands in this sense). In
the case of `/` we reroute to a view handling the main index-page of the
website.
3. The view code will prepare all the data needed by the web page. For the default
index page, this means gather the game statistics so you can see how many
are currently connected to the game etc.
4. The view will next fetch a _template_. A template is a HTML-document with special
'placeholder' tags (written as `{{...}}` or `{% ... %}` usually). These
placeholders allow the view to inject dynamic content into the HTML and make
the page customized to the current situation. For the index page, it means
injecting the current player-count in the right places of the html page. This
is called 'rendering' the template. The result is a complete HTML page.
5. (The view can also pull in a _form_ to customize user-input in a similar way.)
6. The finished HTML page is packed into a _HTTP response_ and returned to the
web browser, which can now display the page!
### A note on the webclient
The web browser can also execute code directly without talking to the Server.
This code must be written/loaded into the web page and is written using the
Javascript programming language (there is no way around this, it is what web
browsers understand). Executing Javascript is something the web browser does,
it operates independently from Evennia. Small snippets of javascript can be
used on a page to have buttons react, make small animations etc that doesn't
require the server.
In the case of the [Webclient](Webclient), Evennia will load the Webclient page
as above, but the page then initiates Javascript code (a lot of it) responsible
for actually displaying the client GUI, allows you to resize windows etc.
After it starts, the webclient 'calls home' and spins up a
[websocket](https://en.wikipedia.org/wiki/WebSocket) link to the Evennia Portal - this
is how all data is then exchanged. So after the initial loading of the
webclient page, the above sequence doesn't happen again until close the tab and
come back or you reload it manually in your browser.

View file

@ -1,7 +1,209 @@
# Game Website
When Evennia starts it will also start a [Webserver](Webserver) as part of the [Server](Portal-And-Server) process. This uses Django to serve a simple but functional default game website.
When Evennia starts it will also start a [Webserver](Webserver) as part of the
[Server](Portal-And-Server) process. This uses Django to serve a simple but
functional default game website. With the default setup, open your browser to
`localhost:4001` or `127.0.0.1:4001` to see it.
With the default setup, open your browser to `localhost:4001` or `127.0.0.1:4001` to see it.
The website allows existing players to log in using an account-name and
password they previously used to register with the game. If a user logs in with
the [Webclient](Webclient) they will also log into the website and vice-versa.
So if you are logged into the website, opening the webclient will automatically
log you into the game as that account.
The default website allows you to
The default website shows a "Welcome!" page with a few links to useful
resources. It also shows some statistics about how many players are currently
connected.
In the top menu you can find
- Home - Get back to front page.
- Document - A link to the latest stable Evennia documentation.
- Characters - This is a demo of connecting in-game characters to the website.
It will display a list of all entities of the
_typeclasses.characters.Character` typeclass and allow you to view their
description with an optional image. The list is only available to logged-in
users.
- Channels - This is a demo of connecting in-game chats to the website. It will
show a list of all channels available to you and allow you to view the latest
discussions. Most channels require logging in, but the `Public` channel can
also be viewed by non-loggedin users.
- Help - This ties the in-game [Help system](Help-System) to the website. All
database-based help entries that are publicly available or accessible to your
account can be read. This is a good way to present a body of help for people
to read outside of the game.
- Play Online - This opens the [Webclient](Webclient) in the browser.
## Modifying the default Website
You can modify and override all aspects of the web site from your game dir.
You'll mostly be doing so in your settings file
(`mygame/server/conf/settings.py` and in the gamedir's `web/folder`
(`mygame/web/` if your game folder is `mygame/`).
As explained on the [Webserver](Webserver) page, the process for getting a web
page is
1. Web browser sends HTTP request to server with an URL
2. `urls.py` uses regex to match that URL to a _view_ (a Python function or callable class).
3. The correct Python view is loaded and executes.
4. The view pulls in a _template_, a HTML document with placeholder markers in it,
and fills those in as needed (it may also use a _form_ to customize user-input in the same way).
A HTML page may also in turn point to static resources (usually CSS, sometimes images etc).
5. The rendered HTML page is returned to the browser as a HTTP response. If
the HTML page requires static resources are requested, the browser will
fetch those separately before displaying it to the user.
If you look at the [evennia/web/](github:develop/evennia/web) directory you'll find the following
structure (leaving out stuff not relevant to the website):
```
evennia/web/
...
static/
website/
css/
(css style files)
images/
(images to show)
templates/
website/
(html files)
website/
urls.py
views/
(all python files related to website)
urls.py
```
The top-level `web/urls.py` file 'includes' the `web/website/urls.py` file -
that way all the website-related url-handling is kept in the same place.
This is the layout of the `mygame/web/` folder relevant for the website:
```
mygame/web/
...
static/
website/
css/
images/
templates/
website/
website/
urls.py
views/
urls.py
```
```versionchanged:: 1.0
Game folders created with older versions of Evennia will lack most of this
convenient `mygame/web/` layout. If you use a game dir from an older version,
you should copy over the missing `evennia/game_template/web/` folders from
there, as well as the main urls.py file.
```
As you can see, the `mygame/web/` folder is a copy of the `evennia/web/` folder
structure except the `mygame` folders are mostly empty.
For static- and template-files, Evennia will _first_
look in `mygame/static` and `mygame/templates` before going to the default
locations in `evennia/web/`. So override these resources, you just need to put
a file with the same name in the right spot under `mygame/web/` (and then
reload the server). Easiest is often to copy the original over and modify it.
Overridden views (Python modules) also need an additional tweak to the
`website/urls.py` file - you must make sure to repoint the url to the new
version rather than it using the original.
### Title and blurb
The website's title and blurb are simply changed by tweaking
`settings.SERVERNAME` and `settings.GAME_SLOGAN`. Your settings file is in
`mygame/server/conf/settings.py`, just change `SERVERNAME = "My Awesome Game"`
and add `GAME_SLOGAN = "The best game in the world"` or something.
### Logo
The Evennia googly-eyed snake logo is probably not what you want for your game.
The template looks for a file `web/static/website/images/evennia_logo.png`. Just
plop your own PNG logo (64x64 pixels large) in there and name it the same.
### Index page
This is the front page of the website (the 'index' in HTML parlance).
#### Index HTML template
The frontpage template is found in
`evennia/web/templates/website/index.html`. Just copy this to the equivalent place in
`mygame/web/`. Modify it there and reload the server to see your changes.
Django templates has a few special features that separate them from normal HTML
documents - they contain a special templating language marked with `{% ... %}` and
`{{ ... }}`.
Some important things to know:
- `{% extends "base.html" %}` - This is equivalent to a Python
`from othermodule import *` statement, but for templates. It allows a given template
to use everything from the imported (extended) template, but also to override anything
it wants to change. This makes it easy to keep all pages looking the same and avoids
a lot of boiler plate.
- `{% block blockname %}...{% endblock %}` - Blocks are inheritable, named pieces of code
that are modified in one place and then used elsewhere. This works a bit in reverse to
normal inheritance, because it's commonly in such a way that `base.html` defines an empty
block, let's say `contents`: `{% block contents %}{% endblock %}` but makes sure to put
that _in the right place_, say in the main body, next to the sidebar etc. Then each page
does `{% extends "base.html %"}` and makes their own `{% block contents} <actual content> {% endblock %}`.
Their `contents` block will now override the empty one in `base.html` and appear in the right
place in the document, without the extending template having to specifying everything else
around it!
- `{{ ... }}` are 'slots' usually embedded inside HTML tags or content. They reference a
_context_ (basically a dict) that the Python _view_ makes available to it.
Keys on the context are accessed with dot-notation, so if you provide a
context `{"stats": {"hp": 10, "mp": 5}}` to your template, you could access
that as `{{ stats.hp }}` to display `10` at that location to display `10` at
that location.
This allows for template inheritance (making it easier to make all
pages look the same without rewriting the same thing over and over)
There's a lot more information to be found in the [Django template language documentation](https://docs.djangoproject.com/en/3.2/ref/templates/language/).
#### Index View
To find where the index view is found, we look in `evennia/web/website/urls.py`. Here
we find the following line:
This is found in `evennia/web/website/views/index.py`. If you don't know
The frontpage view is a class `EvenniaIndexView`. This is a [Django class-based view](https://docs.djangoproject.com/en/3.2/topics/class-based-views/).
It's a little less visible what happens in a class-based view than in a function (since
the class implements a lot of functionality as methods), but it's powerful and
much easier to extend/modify.
The class property `template_name` sets the location of the template used under
the `templates/` folder. So `website/index.html` points to
`web/templates/website/index.html` (as we already explored above.
The `get_context_data` is a convenient method for providing the context for the
template. In the index-page's case we want the game stats (number of recent
players etc). These are then made available to use in `{{ ... }}` slots in the
template as described in the previous section.
### Other website pages
The other sub pages are handled in the same way - copy the template or static
resource to the right place

View file

@ -0,0 +1,51 @@
# Web
This folder contains overriding of web assets - the website and webclient
coming with the game.
This is the process for serving a new web site (see also the Django docs for
more details):
1. A user enters an url in their browser (or clicks a button). This leads to
the browser sending a _HTTP request_ to the server, with a specific type
(GET,POST etc) and url-path (like for `https://localhost:4001/`, the part of
the url we need to consider is `/`).
2. Evennia (through Django) will make use of the regular expressions registered
in the `urls.py` file. This acts as a rerouter to _views_, which are
regular Python functions able to process the incoming request (think of
these as similar to the right Evennia Command being selected to handle your
input - views are like Commands in this sense). In the case of `/` we
reroute to a view handling the main index-page of the website. The view is
either a function or a callable class (Evennia tends to have them as
functions).
3. The view-function will prepare all the data needed by the web page. For the default
index page, this means gather the game statistics so you can see how many
are currently connected to the game etc.
4. The view will next fetch a _template_. A template is a HTML-document with special
'placeholder' tags (written as `{{...}}` or `{% ... %}` usually). These
placeholders allow the view to inject dynamic content into the HTML and make
the page customized to the current situation. For the index page, it means
injecting the current player-count in the right places of the html page. This
is called 'rendering' the template. The result is a complete HTML page.
5. (The view can also pull in a _form_ to customize user-input in a similar way.)
6. The finished HTML page is packed in a _HTTP response_ and is returned to the
web browser, which can now display the page!
## A note on the webclient
The web browser can also execute code directly without talking to the Server.
This code must be written/loaded into the web page and is written using the
Javascript programming language (there is no way around this, it is what web
browsers understand). Executing Javascript is something the web browser does,
it operates independently from Evennia. Small snippets of javascript can be
used on a page to have buttons react, make small animations etc that doesn't
require the server.
In the case of the Webclient, Evennia will load the Webclient page as above,
but the page then contains Javascript code responsible for actually displaying
the client GUI, allows you to resize windows etc.
After it starts, the webclient 'calls home' and spins up a websocket link to
the Evennia Portal - this is how all data is then exchanged. So after the
initial loading of the webclient page, the above sequence doesn't happen again
until close the tab and come back or you reload it manually in your browser.

View file

@ -0,0 +1,5 @@
# Admin views
Evennia makes several customizations to the Django web admin, but you can make
further changes here. Customizing the admin is a big topic and
you are best off reading more about it in the [Django admin site documentation](https://docs.djangoproject.com/en/3.2/ref/contrib/admin/).

View file

@ -0,0 +1,20 @@
"""
This reroutes from an URL to a python view-function/class.
The main web/urls.py includes these routes for all urls starting with `admin/`
(the `admin/` part should not be included again here).
"""
from django.conf.urls import path
from evennia.web.admin.urls import urlpatterns as evennia_admin_urlpatterns
# add patterns here
urlpatterns = [
# path("url-pattern", imported_python_view),
# path("url-pattern", imported_python_view),
]
# read by Django
urlpatterns = urlpatterns + evennia_admin_urlpatterns

View file

@ -1,26 +1,30 @@
"""
This is the starting point when a user enters a url in their web browser.
This is the starting point when a user enters a url in their web browser.
The urls is matched (by regex) and mapped to a 'view' - a Python function or
callable class that in turn (usually) makes use of a 'template' (a html file
with slots that can be replaced by dynamic content) in order to render a HTML
page to show the user.
This file is already set up to correctly handle all of Evennia's existing web
pages (including the webclient). But if you want to add a new page you needs to
start add by adding its view to `custom_patterns`.
This file includes the urls in website, webclient and admin. To override you
should modify urls.py in those sub directories.
Search the Django documentation for "URL dispatcher" for more help.
"""
from django.conf.urls import url, include
from django.conf.urls import path, include
# default evennia patterns
from evennia.web.urls import urlpatterns as evennia_default_urlpatterns
# add custom patterns here
# add patterns
urlpatterns = [
# url(r'/desired/url/regex', 'path.to.python.view', name='example'),
# website
path("", include("web.website.urls")),
# webclient
path("webclient/", include("web.webclient.urls")),
# web admin
path("admin/", include("web.admin.urls"))
]
# 'urlpatterns' must be named such for Django to find it.

View file

@ -1,19 +0,0 @@
"""
A 'view' is python code (can be a function or a callabl class) responsible for
producing a HTML page for a user to view in response for going to a given URL
in their browser. In Evennia lingo, it's similar in function to a Command, with
the input/args being the URL/request and the output being a new web-page.
The urls.py file contains regular expressions that are run against the provided
URL - when a match is found, the execution is passed to a view which is
then responsible (usually) for producing the web page by filling in a
_template_ - a HTML document that can have special tags in it that are replaced
for dynamic content. It then returns the finished HTML page for the user to
view.
See the [Django docs on Views](https://docs.djangoproject.com/en/3.2/topics/http/views/) for
more information.
"""

View file

@ -0,0 +1,23 @@
# Webclient Views
The webclient is mainly controlled by Javascript directly in the browser, so
you usually customize it via `mygame/web/static/webclient/js/` - files instead.
There is very little you can change from here, unless you want to implement
your very own client from scratch.
## On views
A 'view' is python code (a function or callable class) responsible for
producing a HTML page for a user to view in response for going to a given URL
in their browser. In Evennia lingo, it's similar in function to a Command, with
the input/args being the URL/request and the output being a new web-page.
The urls.py file contains regular expressions that are run against the provided
URL - when a match is found, the execution is passed to a view which is then
responsible (usually) for producing the web page by filling in a _template_ - a
HTML document that can have special tags in it that are replaced for dynamic
content. It then returns the finished HTML page for the user to view.
See the [Django docs on Views](https://docs.djangoproject.com/en/3.2/topics/http/views/) for
more information.

View file

@ -0,0 +1,20 @@
"""
This reroutes from an URL to a python view-function/class.
The main web/urls.py includes these routes for all urls starting with `webclient/`
(the `webclient/` part should not be included again here).
"""
from django.conf.urls import path
from evennia.web.webclient.urls import urlpatterns as evennia_webclient_urlpatterns
# add patterns here
urlpatterns = [
# path("url-pattern", imported_python_view),
# path("url-pattern", imported_python_view),
]
# read by Django
urlpatterns = urlpatterns + evennia_webclient_urlpatterns

View file

@ -0,0 +1,24 @@
# Website views and other code
A 'view' is python code (a function or callable class) responsible for
producing a HTML page for a user to view in response for going to a given URL
in their browser. In Evennia lingo, it's similar in function to a Command, with
the input/args being the URL/request and the output being a new web-page.
The urls.py file contains regular expressions that are run against the provided
URL - when a match is found, the execution is passed to a view which is then
responsible (usually) for producing the web page by filling in a _template_ - a
HTML document that can have special tags in it that are replaced for dynamic
content. It then returns the finished HTML page for the user to view.
See the [Django docs on Views](https://docs.djangoproject.com/en/3.2/topics/http/views/) for
more information.
## Overriding a view
1. Copy the original code you want to change from `evennia/web/website/views/` into
`mygame/web/website/views/` and edit it as you like.
2. Look at `evennia/web/website/urls.py` and find the regex pointing to the view. Add this regex
to your own `mygam/website/urls.pye` but change it to import and point to your
changed version instead.
3. Reload the server and the page now uses your version of the view.

View file

@ -0,0 +1,20 @@
"""
This reroutes from an URL to a python view-function/class.
The main web/urls.py includes these routes for all urls (the root of the url)
so it can reroute to all website pages.
"""
from django.conf.urls import path
from evennia.web.website.urls import urlpatterns as evennia_website_urlpatterns
# add patterns here
urlpatterns = [
# path("url-pattern", imported_python_view),
# path("url-pattern", imported_python_view),
]
# read by Django
urlpatterns = urlpatterns + evennia_website_urlpatterns

View file

@ -3,16 +3,16 @@
This folder holds the functioning code, html, js and css files for use by the
Evennia website and -client. This is a standard Django web application.
1. When a user enters an url (or clicks a link) in their web browser, Django will
1. When a user enters an url (or clicks a link) in their web browser, Django will
use this incoming request to refer to the `urls.py` file.
2. The `urls.py` file will use regex to match the url to a _view_ - a Python function
or callable class. The incoming request data will be passed to this code.
3. The view will (usually) refer to a _template_, which is a html document with
templating slots that allows the system to replace parts of it with dynamic
3. The view will (usually) refer to a _template_, which is a html document with
templating slots that allows the system to replace parts of it with dynamic
content (like how many users are currently in-game).
4. The view will render the template with any context into a final HTML page
4. The view will render the template with any context into a final HTML page
that is returned to the user to view.
I many ways this works like an Evennia Command, with input being the browser's
request and the view being the Command's function body for producing a result.

View file

@ -15,8 +15,6 @@ def _gamestats():
"""
Generate a the gamestat context for the main index page
"""
# Some misc. configurable stuff.
# TODO: Move this to either SQL or settings.py based configuration.
fpage_account_limit = 4

View file

@ -1,42 +0,0 @@
"""
This file contains the generic, assorted views that don't fall under one of the other applications.
Views are django's way of processing e.g. html templates on the fly.
"""
from collections import OrderedDict
from django.contrib.admin.sites import site
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.admin.views.decorators import staff_member_required
from django.core.exceptions import PermissionDenied
from django.db.models.functions import Lower
from django.http import HttpResponseBadRequest, HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.generic import TemplateView, ListView, DetailView
from django.views.generic.base import RedirectView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from evennia import SESSION_HANDLER
from evennia.help.models import HelpEntry
from evennia.objects.models import ObjectDB
from evennia.accounts.models import AccountDB
from evennia.utils import class_from_module
from evennia.utils.logger import tail_log_file
from . import forms
from django.utils.text import slugify
#
# Channel views
#
#
# Help views
#