mirror of
https://github.com/evennia/evennia.git
synced 2026-03-28 10:37:16 +01:00
Updated reST docs.
This commit is contained in:
parent
dfec9eeb7d
commit
e2b67b0ac4
10 changed files with 212 additions and 104 deletions
|
|
@ -75,29 +75,15 @@ Attributes like you would any normal Python property:
|
|||
This looks like any normal Python assignment, but calls ``db`` behind
|
||||
the scenes for you.
|
||||
|
||||
Assigning attributes this way is intuitive and makes for slightly less
|
||||
to write. There is a drawback to using this short-form though: Database
|
||||
objects and typeclasses *already* have a number of Python methods and
|
||||
properties defined on themselves. If you use one of those already-used
|
||||
names with this short form you will not be setting a new Attribute but
|
||||
will infact be editing an existing engine property.
|
||||
|
||||
For example, the property ``self.location`` on yourself is tied directly
|
||||
to the ``db_location`` database field and will not accept anything but
|
||||
an ``ObjectDB`` object or it will raise a traceback. ``self.delete`` is
|
||||
a method handling the deletion of objects, and so on. The reason these
|
||||
are available is of course that you may *want* to overload these
|
||||
functions with your own implementations - this is one of the main powers
|
||||
of Evennia. But if you blindly do e.g. ``self.msg = "Hello"`` you will
|
||||
happily be overloading the core ``msg()`` method and be in a world of
|
||||
pain.
|
||||
|
||||
Using ``db`` will always work like you expect. ``self.db.msg = 'Hello'``
|
||||
will create a new Attribute ``msg`` without affecting the core method
|
||||
named ``msg()`` at all. So in principle, whereas you can use the
|
||||
short-form for simple testing, it's best to use ``db`` when you want
|
||||
Attributes and skip it only when you explicitly want to edit/overload
|
||||
something in the base classes.
|
||||
Note however that this form stands the chance of overloading already
|
||||
existing properties on typeclasses and their database objects.
|
||||
``rose.msg()`` is for example an already defined method for sending
|
||||
messages. Doing ``rose.msg = "Ouch"`` will overload the method with a
|
||||
string and will create all sorts of trouble down the road (the engine
|
||||
uses ``msg()`` a lot to send text to you). Using
|
||||
``rose.db.msg = "Ouch"`` will always do what you expect and is usually
|
||||
the safer bet. And it also makes it visually clear at all times when you
|
||||
are saving to the database and not.
|
||||
|
||||
Persistent vs non-persistent
|
||||
----------------------------
|
||||
|
|
@ -117,8 +103,10 @@ situations though.
|
|||
simply writes to memory, it doesn't hit the database at all. It
|
||||
should be said that with the speed and quality of hardware these
|
||||
days, this point is less likely to be of any big concern except for
|
||||
the most extreme of situations. The default database even runs in RAM
|
||||
if possible, alleviating the need to write to disk.
|
||||
the most extreme of situations. Modern database systems cache data
|
||||
very efficiently for speed. Our default database even runs completely
|
||||
in RAM if possible, alleviating much of the need to write to disk
|
||||
during heavy loads.
|
||||
- You *want* to loose your state when logging off. Maybe you are
|
||||
testing a buggy `Script <Scripts.html>`_ that does potentially
|
||||
harmful stuff to your character object. With non-persistent storage
|
||||
|
|
@ -205,29 +193,31 @@ example, you can do
|
|||
::
|
||||
|
||||
# saving data
|
||||
obj.db.mydict = "key":"test0"
|
||||
obj.db.mydict["key"] = "test1"
|
||||
obj.db.mylist[34] = "test2"
|
||||
obj.db.mylist = [0,1,2,3]
|
||||
obj.db.mylist[3] = "test2"
|
||||
obj.db.mylist.append("test3")
|
||||
# retrieving data
|
||||
obj.db.mydict["key"] # returns "test1"
|
||||
obj.db.mylist[34] # returns "test2
|
||||
obj.db.mylist[3] # returns "test2
|
||||
obj.db.mylist[-1] # returns "test3"
|
||||
|
||||
and it will work fine, thanks to a lot of magic happening behind the
|
||||
scenes. What will *not* work however is editing *nested*
|
||||
lists/dictionaries in-place. This is due to the way Python referencing
|
||||
works. Consider the following:
|
||||
scenes. What will *not* work however is *assigning nested
|
||||
lists/dictionaries in-place*. This is due to the way Python referencing
|
||||
works, no way around it alas. Consider the following:
|
||||
|
||||
::
|
||||
|
||||
obj.db.mydict = 1:2:3
|
||||
|
||||
This is a perfectly valid nested dictionary and Evennia will store it
|
||||
just fine.
|
||||
just fine. Retrieving this data will also work normally:
|
||||
|
||||
::
|
||||
|
||||
obj.db.mydict[1][2] # correctly returns 3
|
||||
val = obj.db.mydict[1][2] # correctly returns 3
|
||||
|
||||
However:
|
||||
|
||||
|
|
@ -237,9 +227,10 @@ However:
|
|||
|
||||
will not work - trying to edit the nested structure will fail silently
|
||||
and nothing will have changed. No, this is not consistent with normal
|
||||
Python operation, it's where the database magic fails. All is not lost
|
||||
however. In order to change a nested structure, you simply need to use a
|
||||
temporary variable:
|
||||
Python operation, it's where the database magic fails. Sorry, but there
|
||||
does not seem to be a way around this (if you know one, let us know!)
|
||||
All is not lost however. In order to change a nested structure, you
|
||||
simply need to use a temporary variable:
|
||||
|
||||
::
|
||||
|
||||
|
|
@ -250,7 +241,7 @@ temporary variable:
|
|||
# save back to database
|
||||
obj.db.mydict = mydict
|
||||
# test
|
||||
obj.db.mydict[1][2] # now correctly returns "test"
|
||||
val = obj.db.mydict[1][2] # now correctly returns "test"
|
||||
|
||||
mydict was updated and recreated in the database.
|
||||
|
||||
|
|
|
|||
|
|
@ -621,7 +621,7 @@ non-commands as text input.
|
|||
- New session connection ('cmdhandler.CMD\_LOGINSTART'). This command
|
||||
name should be put in the ``settings.CMDSET_UNLOGGEDIN``. Whenever a
|
||||
new connection is established, this command is always called on the
|
||||
the server (default is to show the login screen).
|
||||
server (default is to show the login screen).
|
||||
|
||||
Below is an example of redefining what happens when the player don't
|
||||
give any input (e.g. just presses return). Of course the new system
|
||||
|
|
|
|||
|
|
@ -33,15 +33,9 @@ Properties defined on ``Msg``
|
|||
to.
|
||||
- ``channels`` - a list of target Channels to send to.
|
||||
- ``message`` - the actual text being sent
|
||||
- ``date_sent`` - when message was sent.
|
||||
- ``date_sent`` - when message was sent (auto-created).
|
||||
- ``locks`` - a `lock definition <Locks.html>`_.
|
||||
|
||||
The following is currently unimplemented in Evennia (stay tuned):
|
||||
|
||||
- hide*from*sender - bool if message should be hidden from sender
|
||||
- hide*from*receivers - list of receiver objects to hide message from
|
||||
- hide*from*channels - list of channels objects to hide message from
|
||||
|
||||
You create new messages in code using
|
||||
``src.utils.create.create_message.``
|
||||
|
||||
|
|
@ -64,7 +58,9 @@ There are three default channels created in stock Evennia - ``MUDinfo``,
|
|||
``MUDconnections`` and ``Public``. Two first ones are server-related
|
||||
messages meant for Admins, the last one is open to everyone to chat on
|
||||
(all new players are automatically joined to it when logging in, useful
|
||||
for asking questions).
|
||||
for asking questions). The default channels created are defined by
|
||||
``settings.CHANNEL_PUBLIC``, ``settings.CHANNEL_MUDINFO`` and
|
||||
``settings.CHANNEL_CONNECTINFO``.
|
||||
|
||||
You create new channels with ``src.utils.create.create_channel()``.
|
||||
|
||||
|
|
|
|||
|
|
@ -70,6 +70,12 @@ Programming Evennia
|
|||
- `Adding a Command prompt <CommandPrompt.html>`_
|
||||
- `Running processes asynchronously <AsyncProcess.html>`_
|
||||
|
||||
Game implementation hints
|
||||
-------------------------
|
||||
|
||||
- `Creating a Zoning system <Zones.html>`_
|
||||
- `Implementing cooldowns for commands <CommandCooldown.html>`_
|
||||
|
||||
Work in Progress - Developer brainstorms and whitepages
|
||||
-------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,10 @@ up-to-date documentation is the online wiki however.
|
|||
|
||||
Read ``sphinx/README`` for instructions on building the ReST
|
||||
documentation, based on a current snapshot of the wiki. This can be
|
||||
browsed offline or made into a PDF for printing etc.
|
||||
browsed offline or made into a PDF for printing etc. Since these files
|
||||
are automatically converted directly from the wiki files, there may be
|
||||
formatting problems here and there, especially if trying to convert to
|
||||
printable format.
|
||||
|
||||
You can create the Evennia *autodocs* by following the instructions in
|
||||
``doxygen/README``. This will make use of the source code itself to
|
||||
|
|
@ -66,22 +69,14 @@ the server.
|
|||
evennia.py
|
||||
manage.py gamesrc/
|
||||
commands/
|
||||
basecommand.py
|
||||
basecmdset.py
|
||||
examples/
|
||||
cmdset_red_button.py
|
||||
scripts/
|
||||
basescript.py
|
||||
examples/
|
||||
red_button_sripts.py
|
||||
objects/
|
||||
baseobjects.py
|
||||
examples/
|
||||
red_button.py
|
||||
world/
|
||||
examples/
|
||||
batch_cmds.ev
|
||||
batch_code.py
|
||||
conf/
|
||||
|
||||
``game/gamesrc/``
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
|
@ -126,18 +121,17 @@ Button* object itself.
|
|||
``gamesrc/world/``
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
``gamesrc/world/``, finally, contains all the rest that make up your
|
||||
world. This is where you would put your own custom economic system,
|
||||
combat mechanic, emote-parser or what have you; organized in whatever
|
||||
way you like. Just remember that if you create new folders under
|
||||
``world``, they must contain an empty file ``__init__.py``, or Python
|
||||
will not know how to import modules from them. The ``world`` folder is
|
||||
also where Evennia's `batch processors <BatchProcessors.html>`_ by
|
||||
default look for their input files. These allow you to build your world
|
||||
offline using your favourite text editor rather than have to do it
|
||||
online over a command line. The `Batch-Command
|
||||
processor <BatchCommandProcessor.html>`_ expects files ending with
|
||||
``.ev``, whereas the more advanced `Batch-Code
|
||||
``gamesrc/world/``, contains all the rest that make up your world. This
|
||||
is where you would put your own custom economic system, combat mechanic,
|
||||
emote-parser or what have you; organized in whatever way you like. Just
|
||||
remember that if you create new folders under ``world``, they must
|
||||
contain an empty file ``__init__.py``, or Python will not know how to
|
||||
import modules from them. The ``world`` folder is also where Evennia's
|
||||
`batch processors <BatchProcessors.html>`_ by default look for their
|
||||
input files. These allow you to build your world offline using your
|
||||
favourite text editor rather than have to do it online over a command
|
||||
line. The `Batch-Command processor <BatchCommandProcessor.html>`_
|
||||
expects files ending with ``.ev``, whereas the more advanced `Batch-Code
|
||||
processor <BatchCodeProcessor.html>`_ takes ``.py`` with some special
|
||||
formatting.
|
||||
|
||||
|
|
@ -145,6 +139,17 @@ formatting.
|
|||
creates a *Red Button* object in *Limbo* using their respective special
|
||||
syntax.
|
||||
|
||||
``gamesrc/conf/``
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
``gamesrc/world/`` holds optional extension modules for the Evennia
|
||||
engine. Certain functionality in the server is meant to be extended, and
|
||||
in order to allow you to do this without modifying the server itself, it
|
||||
imports files from this directory. Modifying these are optionally and
|
||||
you can usually change a variable in ``game/settings.py`` to change
|
||||
which module Evennia is looking for. There are dummy example files in
|
||||
here, read their headers for usage instructions.
|
||||
|
||||
The ``src/`` directory
|
||||
----------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,7 @@ and actions performed in the virtual world. Players typically interact
|
|||
with each other and the world by typing commands that resemble a natural
|
||||
language.*" - `Wikipedia <http://en.wikipedia.org/wiki/MUD>`_
|
||||
|
||||
Evennia introduction
|
||||
====================
|
||||
Evennia introduction=
|
||||
|
||||
If you are reading this, it's quite likely you are dreaming of creating
|
||||
and running a text-based massively-multiplayer game
|
||||
|
|
@ -54,15 +53,8 @@ commands, or to have the command syntax mimic other systems, like Diku,
|
|||
LP, MOO and so on. Or why not create a new and better command system of
|
||||
your own design.
|
||||
|
||||
There is already a default django website as well as an ajax web client
|
||||
shipping with Evennia. You can also edit the database from the browser
|
||||
using the admin interface. Apart from telnet, SSH, SSL and web
|
||||
connections, you can connect e.g. IRC and IMC2 channels to evennia's
|
||||
in-game channels so that your players can chat with people "outside" the
|
||||
game.
|
||||
|
||||
Can I test it somewhere?
|
||||
------------------------
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
There are Evennia-based muds under development but they are still not
|
||||
publicly available. If you do try to install Evennia (it's not hard), it
|
||||
|
|
@ -74,6 +66,63 @@ tutorial takes only one single in-game command to install as explained
|
|||
If you didn't see it before, here is also a
|
||||
`screenshot <Screenshot.html>`_ of Evennia running.
|
||||
|
||||
Brief summary of features
|
||||
=========================
|
||||
|
||||
Technical
|
||||
~~~~~~~~~
|
||||
|
||||
- Game development is done by the server importing your normal Python
|
||||
modules. Specific server features are implemented by overloading
|
||||
hooks that the engine calls appropriately.
|
||||
- All game entities are simply Python classes that handles database
|
||||
negotiations behind the scenes without you needing to worry.
|
||||
- Command sets are stored on individual objects (including characters)
|
||||
to offer unique functionality and object-specific commands. Sets can
|
||||
be updated and modified on the fly to expand/limit player input
|
||||
options during play.
|
||||
- Scripts are used to offer asynchronous/timed execution abilities.
|
||||
Scripts can also be persistent. There are easy mechanisms to thread
|
||||
particularly long-running processes.
|
||||
- In-game communication channels are modular and can be modified to any
|
||||
functionality, including mailing systems and full logging of all
|
||||
messages.
|
||||
- Server can be fully rebooted/reloaded without users disconnecting.
|
||||
- A session (player) can freely connect/disconnect from game-objects,
|
||||
offering an easy way to implement multi-character systems and
|
||||
puppeting.
|
||||
- All source code is extensively documented.
|
||||
- Unit-testing suite, including tests of default commands and plugins
|
||||
|
||||
Default content
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
- Basic classes for Objects, Characers, Rooms and Exits
|
||||
- Basic login system, using the Player's login name as their in-game
|
||||
Character's name for simplicity
|
||||
- "MUX-like" command set with administration, building, puppeting,
|
||||
channels and social commands
|
||||
- In-game Tutorial
|
||||
- Contributions folder with working, but optional, code such as
|
||||
alternative login, menus, character generation and more
|
||||
|
||||
Standards/Protocols supported
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Telnet with mud-specific extensions (MCCP, MSSP, TTYPE)
|
||||
- SSH
|
||||
- SSL
|
||||
- TCP/Comet, JavaScript browser webclient included
|
||||
- HTTP - Website served by in-built webserver and connected to same
|
||||
database as game.
|
||||
- IRC/IMC2 - external IRC and/or IMC2 channels can be connected to
|
||||
in-game chat channels
|
||||
- ANSI, xterm256 colours
|
||||
- Several different databases supported (SQLite3, MySQL, ...)
|
||||
|
||||
For more extensive feature information, see
|
||||
`here <http://code.google.com/p/evennia/wiki/DeveloperCentral>`_.
|
||||
|
||||
What you need to know to work with Evennia
|
||||
==========================================
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,33 @@ Third-party Evennia links
|
|||
- `Evennia on
|
||||
PyPi <http://pypi.python.org/pypi/Evennia%20MUD%20Server/Alpha>`_
|
||||
|
||||
General mud/game development ideas and discussions
|
||||
--------------------------------------------------
|
||||
|
||||
- `MudLab <http://mudlab.org/>`_ mud design discussion forum
|
||||
- `MudConnector <http://www.mudconnect.com/>`_ mud listing and forums
|
||||
- `MudBytes <http://www.mudbytes.net/>`_ mud listing and forums
|
||||
- `Top Mud bytes <http://www.topmudsites.com/>`_ mud listing and forums
|
||||
- `MudStandards wiki <http://www.mudstandards.org/MudStandards_Wiki>`_
|
||||
is an attempt at gathering protocol standards for MUD servers.
|
||||
|
||||
- `Planet Mud-Dev <http://planet-muddev.disinterest.org/>`_ is a blog
|
||||
aggregator following blogs of current MUD development around the
|
||||
'net.
|
||||
- Mud Dev mailing list archive
|
||||
(`mirror1 <http://nilgiri.net/MUD-Dev-archive/>`_),(`mirror2 <http://www.disinterest.org/resource/MUD-Dev/>`_)
|
||||
- Influential mailing list active 1996-2004. Advanced game design
|
||||
discussions.
|
||||
- `Imaginary
|
||||
Realities <http://disinterest.org/resource/imaginary-realities/>`_ is
|
||||
an e-magazine on game/MUD design which were active 1998-2001.
|
||||
Interesting articles.
|
||||
|
||||
- `Lost Garden <http://www.lostgarden.com/>`_ is a game development
|
||||
blog with long and interesting articles (not MUD-specific)
|
||||
- `What Games Are <http://whatgamesare.com/>`_ is a blog about general
|
||||
game design (not MUD-specific)
|
||||
|
||||
Frameworks
|
||||
----------
|
||||
|
||||
|
|
|
|||
|
|
@ -63,19 +63,9 @@ Defining locks
|
|||
|
||||
Defining a lock (i.e. an access restriction) in Evennia is done by
|
||||
adding simple strings of lock definitions to the object's ``locks``
|
||||
property using ``obj.locks.add()``. Such a *lockstring* formally looks
|
||||
like this:
|
||||
property using ``obj.locks.add()``.
|
||||
|
||||
::
|
||||
|
||||
access_type:[NOT] func1([arg1,..])[[AND|OR][ NOT] func2([arg1,...])[...]]
|
||||
|
||||
where ``[..]`` marks optional parts. AND, OR and NOT are not case
|
||||
sensitive and excess spaces are ignored. ``func1, func2`` etc are
|
||||
special *lock functions* available to the lock system.
|
||||
|
||||
This form of writing may look complicated, so let's immediately give
|
||||
some much nicer examples:
|
||||
Here are some examples of lock strings:
|
||||
|
||||
::
|
||||
|
||||
|
|
@ -83,7 +73,17 @@ some much nicer examples:
|
|||
edit:all() # let everyone edit
|
||||
get: not attr(very_weak) or perm(Wizard) # only those who are not "very_weak" or are Wizards may pick this up
|
||||
|
||||
So, a lockstring consists of the type of restriction (the
|
||||
Formally, a lockstring has the following syntax:
|
||||
|
||||
::
|
||||
|
||||
access_type:[not] func1([arg1,..])[[and|or][ not] func2([arg1,...])[...]]
|
||||
|
||||
where ``[..]`` marks optional parts. AND, OR and NOT are not case
|
||||
sensitive and excess spaces are ignored. ``func1, func2`` etc are
|
||||
special *lock functions* available to the lock system.
|
||||
|
||||
So, a lockstrings consists of the type of restriction (the
|
||||
``access_type``), a colon (``:``) and then a list of function calls that
|
||||
determine what is needed to pass the lock. Each function returns either
|
||||
``True`` or ``False``. AND/OR and NOT works like normal Python to
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ leaving the remaining poor characters in darkness once again.
|
|||
By combining state-changes with timers one can make a room look
|
||||
different during nighttime than it does during the day. Weather and
|
||||
seasons might come and go. But one can also achieve more complex things
|
||||
such as state-AI systems that make mobs move around and possibly persue
|
||||
such as state-AI systems that make mobs move around and possibly pursue
|
||||
characters between rooms.
|
||||
|
||||
... In short, Scripts make the game world *tick*. Scripts are
|
||||
|
|
@ -130,6 +130,30 @@ find longer descriptions of these in ``gamesrc/scripts/basescript.py``.
|
|||
- ``at_stop()`` - this is called when the script stops for whatever
|
||||
reason. It's a good place to do custom cleanup.
|
||||
|
||||
Running methods (usually called automatically by the engine, but
|
||||
possible to also invoke manually)
|
||||
|
||||
- ``start()`` - this will start the script. This is called
|
||||
automatically whenever you add a new script to a handler.
|
||||
``at_start()`` will be called.
|
||||
- ``stop()`` - this will stop the script and delete it. Removing a
|
||||
script from a handler will stop it auomatically. ``at_stop()`` will
|
||||
be called.
|
||||
- ``pause()`` - this pauses a running script, rendering it inactive,
|
||||
but not deleting it. Timers are saved and can be resumed. This is
|
||||
called automatically when the server reloads. No hooks are called -
|
||||
this is a suspension of the script, not a change of state.
|
||||
- ``unpause()`` - resumes a previously paused script. Timers etc are
|
||||
restored to what they were before pause. The server unpauses all
|
||||
paused scripts after a server reload. No hooks are called - as far as
|
||||
the script is concerned, it never stopped running.
|
||||
- ``time_until_next_repeat()`` - for timed scripts, this returns the
|
||||
time in seconds until it next fires. Returns None if not a timed
|
||||
script.
|
||||
|
||||
Example script
|
||||
--------------
|
||||
|
||||
::
|
||||
|
||||
import random
|
||||
|
|
@ -173,10 +197,18 @@ Or, from in-game, use the ``@script`` command:
|
|||
|
||||
@script here = weather.Weather
|
||||
|
||||
Further notes
|
||||
-------------
|
||||
Global scripts
|
||||
--------------
|
||||
|
||||
Should you *really* need to create a script unrelated to a particular
|
||||
Object (this is called a *Global* script), you can create it with
|
||||
``src.utils.create.create_script()`` and refrain from supplying an
|
||||
object to store it on. See that module for more info.
|
||||
You can create scripts that are not attached to a given object -
|
||||
*Global* scripts. You can create such a script with
|
||||
``src.utils.create.create_script()`` by refrainnig from supplying an
|
||||
object to store it on.
|
||||
|
||||
::
|
||||
|
||||
from src.utils.create import create_script
|
||||
create_script(globals.MyGlobalEconomy, key="economy", obj=None)
|
||||
|
||||
Assuming ``game.gamesrc.scripts.global.MyGlobalEconomy`` can be found,
|
||||
this will create and start it as a global script.
|
||||
|
|
|
|||
|
|
@ -21,12 +21,14 @@ basically means that they are (almost) normal Python classes that hide
|
|||
underlying database models ...
|
||||
|
||||
... and that's basically all you *really* need to know about how
|
||||
typeclasses work behind the scenes. To work with them you should know
|
||||
that all the listed game entities inherit a common interface from the
|
||||
typeclass system, properties you can *always* expect a typeclassed
|
||||
entity to have *beyond* the more specialized properties unique to each
|
||||
sub-type. Typeclasses also do some special things with their in-built
|
||||
class methods that you shouldn't edit.
|
||||
typeclasses work behind the scenes.
|
||||
|
||||
To work with them you should however know that all the listed game
|
||||
entities inherit a common interface from the typeclass system,
|
||||
properties you can *always* expect a typeclassed entity to have *beyond*
|
||||
the more specialized properties unique to each sub-type. Typeclasses
|
||||
also do some special things with their in-built class methods that you
|
||||
shouldn't edit.
|
||||
|
||||
Properties available to all typeclassed entities (Players, Objects,
|
||||
Scripts)
|
||||
|
|
@ -97,7 +99,7 @@ a few things that you need to remember however:
|
|||
or you *will* crash the server! You have been warned.
|
||||
|
||||
How typeclasses actually work
|
||||
-----------------------------
|
||||
=============================
|
||||
|
||||
\_You don't need to read this section to use typeclassed entities, but
|
||||
it might be useful if you want to do advanced things or are interested
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue