diff --git a/docs/sphinx/source/contents.rst b/docs/sphinx/source/contents.rst index bbb4db384a..34771bba49 100644 --- a/docs/sphinx/source/contents.rst +++ b/docs/sphinx/source/contents.rst @@ -6,6 +6,7 @@ Alphabetical page index :titlesonly: wiki/AddingCommandTutorial + wiki/AddingObjectTypeclassTutorial wiki/AdminDocs wiki/ApacheConfig wiki/AsyncProcess @@ -17,6 +18,7 @@ Alphabetical page index wiki/BuilderDocs wiki/BuildingPermissions wiki/BuildingQuickstart + wiki/Caches wiki/ChoosingAnSQLServer wiki/CodingIntroduction wiki/CodingUtils diff --git a/docs/sphinx/source/wiki/AddingObjectTypeclassTutorial.rst b/docs/sphinx/source/wiki/AddingObjectTypeclassTutorial.rst new file mode 100644 index 0000000000..0399d9842c --- /dev/null +++ b/docs/sphinx/source/wiki/AddingObjectTypeclassTutorial.rst @@ -0,0 +1,178 @@ +Creating your own object classes +================================ + +Evennia comes with a few very basic classes of in-game entities: + +:: + + Object + | + Character + Room + Exit + +So the more specific object-types are just children of the basic +``Object`` class (technically these are all +`Typeclasses `_ entities, but for this tutorial, just +treat them as normal Python classes). + +For your own game you will most likely want to expand on these very +simple beginnings. It's normal to want your Characters to have various +attributes. Maybe Rooms should hold extra information or even *all* +Objects in your game should have properties not included in basic +Evennia. + +First a brief overview of how Evennia handles its object classes. The +default classes are defined under ``src/objects/objects.py``. You can +look at them there or you can bring up a Python prompt and interactively +examine ``ev.Object``, ``ev.Room`` etc. + +You will create your own object classes in ``game/gamesrc/objects``. You +should normally inherit from the default classes (normal Python class +inheritance) and go from there. Once you have a working new class you +can immediately start to create objects in-game inheriting from that +class. + +If you want to change the *default* object classes, there is one more +step. Evennia's default commands and internal creation mechanisms look +at a range of variables in your ``settings.py`` file to determine which +are the "default" classes. These defaults are used by the vanilla +creation commands if you don't specify the typeclass specifically. They +are also used as a fallback by Evennia if there are errors in other +typeclasses, so make sure that your new default class is bug-free. + +The following sections spells this out more explicitly. + +Create a new Typeclass +---------------------- + +This is the simplest case. Say you want to create a new "Heavy" object +that characters should not have the ability to pick up. + +#. Go to ``game/gamesrc/objects/``. It should already contain a + directory ``examples/``. +#. Create a new module here, named ``heavy.py``. Alternatively you can + copy ``examples/object.py`` up one level and rename that file to + ``heavy.py`` instead - you will then have a template to start from. +#. Code away in the ``heavy.py`` module, implementing the chair + functionality. See `Objects `_ for more details and the + example class below. Let's call the typeclass simply ``Heavy``. +#. Once you are done, log into the game with a build-capable account and + do ``@create/drop rock:heavy.Heavy`` to drop a new heavy "rock" + object in your location. Note that you have to log in as a + non-superuser (i.e. not as User #1) when trying to get the rock in + order to see its heavy effects. + +That's it. Below is a ``Heavy`` Typeclass that you could try. Note that +the `lock `_ and `Attribute `_ here set in +the typeclass could just as well have been set using commands in-game, +so this is a *very* simple example. + +:: + + # file game/gamesrc/objects/heavy.py + from ev import Object + + class Heavy(Object): + "Heavy object" + at_object_creation(self): + "Called whenever a new object is created" + # lock the object down by default + self.locks.add("get:false()") + # the default "get" command looks for this Attribute in order + # return a customized error message (we just happen to know + # this, you'd have to look at the code of the 'get' command to + # find out). + self.db.get_err_msg = "This is too heavy for you to pick up." + +Change Default Rooms, Exits, Character Typeclass +------------------------------------------------ + +This is only slightly more complex than creating any other Typeclass. In +fact it only includes one extra step - telling Evennia to use the new +default. + +Let's say we want to change Rooms to use our new typeclass ``MyRoom``. + +#. Create a new module in ``game/gamesrc/objects/myroom.py`` and code + your ``MyRoom`` typeclass as described in the previous section. Make + sure to test it by digging a few rooms of this class (e.g. + ``@dig Hall:myroom.MyRoom``). +#. Once you are sure the new class works as it should, edit + ``game/settings.py`` and add + ``BASE_ROOM_TYPECLASS="game.gamesrc.objects.myroom.MyRoom"``. +#. Reload Evennia. + +For example the ``@dig`` and ``@tunnel`` commands will henceforth use +this new default when digging new rooms whenever you don't give a +typeclass explicitly. For the other sub-types, change +``BASE_CHARACTER_TYPECLASS`` (used by character creation commands) and +``BASE_EXIT_TYPECLASS`` (used by ``@dig``/``@tunnel`` etc) respectively. + +Change the default Object Typeclass +----------------------------------- + +Changing the root ``Object`` class works identically to changing the +``Character``, ``Room`` or ``Exit`` typeclass. After having created your +new typeclass, set ``settings.BASE_EXIT_TYPECLASS`` to point to your new +class. Let's say you call your new default ``Object`` class +``MyObject``. + +There however one important further thing to remember: ``Characters``, +``Rooms`` and ``Exits`` will still inherit from the *old* ``Object`` at +this point (not ``MyObject``). This is by design - depending on your +type of game, you may not need some or all of these subclasses to +inherit any of the new stuff you put in ``MyObject``. + +If you do want that however, you need to also overload these subclasses. +For each of the ``Character``, ``Room`` and ``Exit`` you want to +customize, do the following: + +#. Create a new module in ``game/gamesrc/``, e.g. ``mycharacter.py`` + etc. A good flexible solution for overloading only parts of the + default is to make inheriting classes *multi-inherited* (see below). + As a place-holder you can make the class empty for now (just put + ``pass`` in it). +#. In your ``settings.py`` file, add and define + ``BASE_CHARACTER_TYPECLASS``, ``BASE_ROOM_TYPECLASS`` and + ``BASE_EXIT_TYPECLASS`` to point to your new typeclasses. +#. Reload Evennia. + +This will give you maximum flexibility with creating and expanding your +own types of rooms, characters and exit objects (or not). Below is an +example of a new ``myroom.py``: + +:: + + # file gamesrc/objects/myroom.py + from ev import Object + from gamesrc.objects.myobject import MyObject + # we use multi-inheritance, this will primarily use MyObject, + # falling back to the default Object for things MyObject do + # not overload + class MyRoom(MyObject, Object): + "My own expandable room class" + pass + +Notes +===== + +All above examples puts each class in its own module. This makes it easy +to find, but it is really up to you how you organize things. There is +nothing stopping you from putting all base classes into one module, for +example. + +Also remember that Python may dynamically rename module classes as they +are imported. So if you feel it annoying to have to refer to your new +default as ``MyObject`` all the time, you can also import them to +another name like in the below example: + +:: + + from ev import Object as BaseObject + from gamesrc.objects.myobject import MyObject as Object + class MyRoom(Object, BaseObject): + [...] + +This doesn't actually change the meaning of the code, but might make the +relationships clearer inside a module. diff --git a/docs/sphinx/source/wiki/Attributes.rst b/docs/sphinx/source/wiki/Attributes.rst index e8aa5101e9..f5bfd82c09 100644 --- a/docs/sphinx/source/wiki/Attributes.rst +++ b/docs/sphinx/source/wiki/Attributes.rst @@ -161,10 +161,17 @@ situations though. What types of data can I save in an Attribute? ---------------------------------------------- -If you store a single object (that is, not an iterable list of objects), -you can practically store any Python object that can be -`pickled `_. Evennia uses -the ``pickle`` module to serialize Attribute data into the database. +Evennia uses the ``pickle`` module to serialize Attribute data into the +database. So if you store a single object (that is, not an iterable list +of objects), you can practically store any Python object that can be +`pickled `_. + +If you store many objects however, you can only store them using normal +Python structures (i.e. in either a *tuple*, *list*, *dictionary* or +*set*). All other iterables (such as custom containers) are converted to +*lists* by the Attribute (see next section for the reason for this). +Since you can nest dictionaries, sets, lists and tuples together in any +combination, this is usually not much of a limitation. There is one notable type of object that cannot be pickled - and that is a Django database object. These will instead be stored as a wrapper @@ -177,19 +184,12 @@ recursively traverse all iterables to make sure all database objects in them are stored safely. So for efficiency, it can be a good idea to avoid deeply nested lists with objects if you can. -To store several objects, you may only use python *lists*, -*dictionaries* or *tuples* to store them. If you try to save any other -form of iterable (like a ``set`` or a home-made class), the Attribute -will convert, store and retrieve it as a list instead. Since you can -nest dictionaries, lists and tuples together in any combination, this is -usually not a limitation you need to worry about. - *Note that you could fool the safety check if you for example created custom, non-iterable classes and stored database objects in them. So to make this clear - saving such an object is **not supported** and will probably make your game unstable. Store your database objects using -lists, tuples, dictionaries or a combination of the three and you should -be fine.* +lists, tuples, dictionaries, sets or a combination of the four and you +should be fine.* Examples of valid attribute data: @@ -232,13 +232,13 @@ Example of non-supported save: Retrieving Mutable objects -------------------------- -A side effect of the way Evennia stores Attributes is that Python Lists -and Dictionaries (only) are handled by custom objects called PackedLists -and PackedDicts. These behave just like normal lists and dicts except -they have the special property that they save to the database whenever -new data gets assigned to them. This allows you to do things like -``self.db.mylist[4]`` = val without having to extract the mylist -Attribute into a temporary variable first. +A side effect of the way Evennia stores Attributes is that Python Lists, +Dictionaries and Sets are handled by custom objects called PackedLists, +PackedDicts and PackedSets. These behave just like normal lists and +dicts except they have the special property that they save to the +database whenever new data gets assigned to them. This allows you to do +things like ``self.db.mylist[4]`` = val without having to extract the +mylist Attribute into a temporary variable first. There is however an important thing to remember. If you retrieve this data into another variable, e.g. ``mylist2 = obj.db.mylist``, your new @@ -287,9 +287,92 @@ stop any changes to the structure from updating the database. # iterable is a tuple, so we can edit the internal list as we want # without affecting the database. -Notes ------ +Locking and checking Attributes +------------------------------- + +Attributes are normally not locked down by default, but you can easily +change that for individual Attributes (like those that may be +game-sensitive in games with user-level building). + +First you need to set a *lock string* on your Attribute. Lock strings +are specified `here `_. The relevant lock types are + +- *attrread* - limits who may read the value of the Attribute +- *attredit* - limits who may set/change this Attribute + +You cannot use e.g. ``obj.db.attrname`` handler to modify Attribute +objects (such as setting a lock on them - you will only get the +Attribute *value* that way, not the actual Attribute *object*. You get +the latter with ``get_attribute_obj`` (see next section) which allows +you to set the lock something like this: + +:: + + obj.get_attribute_obj.locks.add("attread:all();attredit:perm(Wizards)") + +A lock is no good if nothing checks it -- and by default Evennia does +not check locks on Attributes. You have to add a check to your +commands/code wherever it fits (such as before setting an Attribute). + +:: + + # in some command code where we want to limit + # setting of a given attribute name on an object + attr = obj.get_attribute_obj(attrname, default=None) + if not (attr and attr.locks.check(caller, 'attredit', default=True)): + caller.msg("You cannot edit that Attribute!") + return + # edit the Attribute here + +Note that in this example this lock check will default to ``True`` if no +lock was defined on the Attribute (which is the case by default). You +can set this to False if you know all your Attributes always check +access in all situations. If you want some special control over what the +default Attribute access is (such as allowing everyone to view, but +never allowing anyone to edit unless explicitly allowing it with a +lock), you can use the ``secure_attr`` method on Typeclassed objects +like this: + +:: + + obj.secure_attr(caller, attrname, value=None, + delete=False, + default_access_read=True, + default_access_edit=False, + default_access_create=True) + +The secure\_attr will try to retrieve the attribute value of an existing +Attribute if the ``value`` keyword is not set and create/set/delete it +otherwise. The *default\_access* keywords specify what should be the +default policy for each operation if no appropriate lock string is set +on the Attribute. + +Other ways to access Attributes +------------------------------- + +Normally ``db`` is all you need. But there there are also several other +ways to access information about Attributes, some of which cannot be +replicated by ``db``. These are available on all Typeclassed objects: + +- ``has_attribute(attrname)`` - checks if the object has an attribute + with the given name. This is equivalent to doing ``obj.db.attrname``. +- ``set_attribute(attrname, value)`` - equivalent to + ``obj.db.attrname = value``. +- ``get_attribute(attrname)`` - returns the attribute value. Equivalent + to ``obj.db.attrname``. +- ``get_attribute_raise(attrname)`` - returns the attribute value, but + instead of returning ``None`` if no such attribute is found, this + method raises ``AttributeError``. +- ``get_attribute_obj(attrname)`` - returns the attribute *object* + itself rather than the value stored in it. +- ``del_attribute(attrname)`` - equivalent to ``del obj.db.attrname``. + Quietly fails if ``attrname`` is not found. +- ``del_attribute_raise(attrname)`` - deletes attribute, raising + ``AttributeError`` if no matching Attribute is found. +- ``get_all_attributes`` - equivalent to ``obj.db.all`` +- ``attr(attrname, value=None, delete=False)`` - this is a convenience + function for getting, setting and deleting Attributes. It's + recommended to use ``db`` instead. +- ``secure_attr(...)`` - lock-checking version of ``attr``. See example + in previous section. -There are several other ways to assign Attributes to be found on the -typeclassed objects, all being more 'low-level' underpinnings to -``db``/``ndb``. Read their descriptions in the respective modules. diff --git a/docs/sphinx/source/wiki/Caches.rst b/docs/sphinx/source/wiki/Caches.rst new file mode 100644 index 0000000000..20529bb4e2 --- /dev/null +++ b/docs/sphinx/source/wiki/Caches.rst @@ -0,0 +1,169 @@ +Caches +====== + +*Note: This is an advanced topic. You might want to skip it on a first +read-through.* + +Evennia is a fully persistent system, which means that it will store +things in the database whenever its state changes. Since accessing the +database i comparably expensive, Evennia uses an extensive *caching* +scheme. Caching normally means that once data is read from the database, +it is stored in memory for quick retrieval henceforth. Only when data +changes will the database be accessed again (and the cache updated). + +With a few exceptions, caching are primarily motivated by speed and to +minimize bottlenecks found by profiling the server. Some systems must +access certain pieces of data often, and going through the django API +over and over builds up. Depending on operation, individual speedups of +hundreds of times can be achieved by clever caching. + +The price for extended caching is memory consumption and added +complexity. This page tries to explain the various cache strategies in +place. Most users should not have to worry about them, but if you ever +try to "bang the metal" with Evennia, you should know what you are +seeing. + +The default ``@server`` command will give a brief listing of the memory +usage of most relevant caches. + +Idmapper +-------- + +Evennia's django object model is extended by *idmapper* functionality. +The idmapper is an external third-party system that sits in +``src/utils/idmapper``. The idmapper is an on-demand memory mapper for +all database models in the game. This means that a given database object +is represented by the same memory area whenever it is accessed. This may +sound trivial but it is not - in plain Django there is no such +guarantee. Doing something like ``objdb.test = "Test"`` (were objdb is a +django model instance) would be unsafe and most likely the ``test`` +variable would be lost next time the model is retrieved from the +database. As Evennia ties `Typeclasses `_ to django +models, this would be a catastophy. + +Idmapper is originally a memory saver for django websites. In the case +of a website, object access is brief and fleeting - not so for us. So we +have extended idmapper to never loose its reference to a stored object +(not doing this was the cause of a very long-standing, very hard-to-find +bug). + +Idmapper is an on-demand cache, meaning that it will only cache objects +that are actually accessed. Whereas it is possible to clean the idmapper +cache via on-model methods, this does not necessarily mean its memory +will be freed - this depends on any lingering references in the system +(this is how Python's reference counting works). If you ever need to +clean the idmapper cache, the safest way is therefore a soft-reload of +the server (via e.g. the ``@reload`` command). + +Most developers will not need to care with the idmapper cache - it just +makes models work intuitively. It is visible mostly in that all database +models in Evennia inherits from +``src.utils.idmapper.models.SharedMemoryModel``. + +On-object variable cache +------------------------ + +All database fields on all objects in Evennia are cached by use of +`Python +properties `_. +So when you do ``name = obj.key``, you are actually *not* directly +accessing a database field "key" on the object. What you are doing is +actually to access a handler. This handler looks for hidden variable +named ``_cached_db_key``. If that can be found, it is what is returned. +If not, the actual database field, named ``db_key`` are accessed. The +result is returned and cached for next time. + +The naming scheme is consistent, so a given property ``obj.foo`` is a +handler with a cache named ``obj._cached_db_foo`` and a database field +``obj.db_key.`` The handler methods for the property are always named +``obj.foo_get()``, ``obj.foo_set()`` and ``obj.foo_del()`` (all are not +always needed). + +Apart from caching, property handlers also serves another function - +they hide away Django administration. So doing ``obj.key = "Peter"`` +will not only assign (and cache) the string "Peter" in the database +field ``obj.db_key``, it will also call ``obj.save()`` for you in order +to update the database. + +Hiding away the model fields presents one complication for developers, +and that is searching using normal django methods. Basically, if you +search using e.g. the standard django ``filter`` method, you must search +for ``db_key``, not ``key``. Only the former is known by django, the +latter will give an invalid-field error. If you use Evennia's own search +methods you don't need to worry about this, they look for the right +things behind the scenes for you. + +Mutable variable caches +~~~~~~~~~~~~~~~~~~~~~~~ + +Some object properties may appear mutable - that is, they return lists. +One such example is the ``permissions`` property. This is however not +actually a list - it's just a handler that *returns* and *accepts* +lists. ``db_permissions`` is actually stored as a comma-separated +string. The uptake of this is that you cannot do list operations on the +handler. So ``obj.permissions.append('Immortals')`` will not work. +Rather, you will have to do such operations on what is returned. Like +this: + +:: + + perms = obj.permissions # this returns a list! + perms.append("Immortals") + obj.permissions = perms # overwrites with new list + +Content cache +~~~~~~~~~~~~~ + +A special case of on-object caching is the *content* cache. Finding the +"contents" of a particular location turns out to be a very common and +pretty expensive operation. Whenever a person moves, says something or +does other things, "everyone else" in a given location must be informed. +This means a database search for which objects share the location. + +``obj.contents`` is a convenient container that at every moment contains +a cached list of all objects "inside" that particular object. It is +updated by the ``location`` property. So ``obj1.location = obj2`` will +update ``obj2.contents`` on the fly to contain ``obj1``. It will also +remove ``obj1`` from the ``contents`` list of its previous location. +Testing shows that when moving from one room to another, finding and +messaging everyone in the room took up as much as *25%* of the total +computer time needed for the operation. After caching ``contents``, +messaging now takes up *0.25%* instead ... + +The contents cache should be used at all times. The main thing to +remember is that if you were to somehow bypass the ``location`` handler +(such as by setting the ``db_location`` field manually), you will bring +the cache and database out of sync until you reload the server. + +Typeclass cache +~~~~~~~~~~~~~~~ + +All typeclasses are cached on the database model. This allows for quick +access to the typeclass through ``dbobj.typeclass``. Behind the scenes +this operation will import the typeclass definition from a path stored +in ``db_typeclass_path`` (available via the property handler +``typeclass_path``). All checks and eventual debug messages will be +handled, and the result cached. + +The only exception to the caching is if the typeclass module had some +sort of syntax error or other show-stopping bug. The default typeclass +(as defined in ``settings``) will then be loaded instead. The error will +be reported and *no* caching will take place. This is in order to keep +reloading the typeclass also next try, until it is fixed. + +On-object Attribute cache +------------------------- + +`Attribute `_ lookups are cached by use of hidden +dictionaries on all `Typeclassed `_ objects - this +removes the necessity for subsequent database look-ups in order to +retrieve attributes. Both ``db`` and ``ndn`` work the same way in this +regard. + +Attribute value cache +--------------------- + +Each Attribute object also caches the values stored in it. Whenever +retrieving an attribute value, it is also cached for future accesses. In +effect this means that (after the first time) accessing an attribute is +equivalent to accessing any normal property. diff --git a/docs/sphinx/source/wiki/DefaultCommandHelp.rst b/docs/sphinx/source/wiki/DefaultCommandHelp.rst index 88aba5f18b..8d2da73f77 100644 --- a/docs/sphinx/source/wiki/DefaultCommandHelp.rst +++ b/docs/sphinx/source/wiki/DefaultCommandHelp.rst @@ -27,7 +27,7 @@ defined on. DefaultCmdset and available in the game. The full set of available commands (all three sub-sets above) currently -contains 85 commands in 6 categories. More information about how +contains 86 commands in 6 categories. More information about how commands work can be found in the `Command `_ documentation. @@ -666,7 +666,7 @@ module `` +- ``aliases`` = ``@sethome`` - `locks `_ = ``cmd:perm(@home) or perm(Builders)`` - `help\_category `_ = ``Building`` - [`HelpSystem `_\ #Auto-help\_system Auto-help] @@ -910,19 +910,29 @@ module =] + @tel/switch [ =] + + Examples: + @tel Limbo + @tel/quiet box Limbo + @tel/tonone box Switches: quiet - don't echo leave/arrive messages to the source/target locations for the move. intoexit - if target is an exit, teleport INTO the exit object instead of to its destination + tonone - if set, teleport the object to a None-location. If this + switch is set, is ignored. + Note that the only way to retrieve + an object from a None location is by direct #dbref + reference. - Teleports an object or yourself somewhere. - + Teleports an object somewhere. If no object is given, you yourself + is teleported to the target location. @tunnel ~~~~~~~ @@ -1487,6 +1497,29 @@ General `Link to Python module `_ +@color +~~~~~~ + +- ``key`` = ``@color`` +- ``aliases`` = ```` +- `locks `_ = ``cmd:all()`` +- `help\_category `_ = ``General`` +- [`HelpSystem `_\ #Auto-help\_system Auto-help] + (``__doc__ string``) = + +:: + + testing colors + + Usage: + @color ansi|xterm256 + + Print a color map along with in-mud color codes, while testing what is supported in your client. + Choices are 16-color ansi (supported in most muds) or the 256-color xterm256 standard. + No checking is done to determine your client supports color - if not you will + see rubbish appear. + + @encoding (OOC command) ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/sphinx/source/wiki/Licensing.rst b/docs/sphinx/source/wiki/Licensing.rst index 2fa91b9575..e2a4eb1d17 100644 --- a/docs/sphinx/source/wiki/Licensing.rst +++ b/docs/sphinx/source/wiki/Licensing.rst @@ -1,47 +1,33 @@ Evennia Licence FAQ =================== -Evennia is licensed under the very friendly *Modified Clarified Artistic -License*. You can find the license as ``LICENCE`` in the Evennia root -directory. You can also read the full license file +Evennia is licensed under the very friendly BSD License. You can find +the license as ``LICENCE.txt`` in the Evennia root directory. You can +also read the full license file `here `_. -You should read the full license text to know what it says exactly, but -here are some answers to common questions. - Q: When creating a game using Evennia, what does the licence permit me to do with it? ------------------------------------------------------------------------------------- -**A:** It's your own game world to do with as you please! To summarize, -a MUD world you create using Evennia (i.e. the files you create in -``/game/``) falls under **§6** of the license (it's a sort of -"library"). So your game world and all its contents belongs to you (as -it should be). Keep it to yourself or re-distribute it under any license -of your choice - or sell it and become filthy rich for all we care. +**A:** It's your own game world to do with as you please! Keep it to +yourself or re-distribute it under any license of your choice - or sell +it and become filthy rich for all we care. Q: I have modified Evennia itself, what does the license say about that? ------------------------------------------------------------------------ -**A:** The Evennia package itself (i.e. the stuff you download from us) -is referred to as "The Package, Standard version" in the license. +**A:** The License allows you to do whatever you want with your modified +Evennia, including re-distributing or selling it, as long as you include +our license and copyright info in the ``LICENSE.txt`` file along with +your distribution. -- If you just fixed a typo or bug, that falls under **§2** - that is, - you don't *have* to do anything to appease the license. Regardless, - we'd of course appreciate it if you submitted bugs/fixes to us so - Evennia becomes more complete!. -- If you made bigger modifications or added new features to the server, - that's also ok, but falls under **§3** - you must make a clear note - of the changes you did and put those changes into public domain - (since it's then no longer a "Standard version"). You could also - contact the Evennia developers to make separate arrangements ... but - of course, if you plan to add new features to the server, the easiest - way to do so is to simply become an Evennia developer! +... Of course, if you add bug fixes or add some new snazzy features we +still *softly nudge* you to make those changes available upstream so +they could be added to the core Evennia package. The license don't +require you to do it, but that doesn't mean we can't still greatly +appreciate it if you do! Q: Can I re-distribute the Evennia server package along with my custom game implementation? ------------------------------------------------------------------------------------------- -**A:** Sure. This is covered in **§4** - just package the "Standard -version" (that is, the one you download from us) with your game files. -Also make sure to include the original license and disclaimers and note -where users may get "plain" Evennia should they want to download it of -their own. +**A:** Sure. As long as the text in LICENSE.txt is included. diff --git a/docs/sphinx/source/wiki/Links.rst b/docs/sphinx/source/wiki/Links.rst index 5b6e2eb7b5..c387c3329c 100644 --- a/docs/sphinx/source/wiki/Links.rst +++ b/docs/sphinx/source/wiki/Links.rst @@ -34,6 +34,10 @@ Third-party Evennia links - `Avaloria `_ (MUD under development, using Evennia) +- `Winter's Oasis `_ (MUCK under + development, using Evennia) +- `Latitude `_ (MUCK under + development, using Evennia) General mud/game development ideas and discussions -------------------------------------------------- diff --git a/docs/sphinx/source/wiki/Tutorials.rst b/docs/sphinx/source/wiki/Tutorials.rst index 9a91a14c50..84955766dc 100644 --- a/docs/sphinx/source/wiki/Tutorials.rst +++ b/docs/sphinx/source/wiki/Tutorials.rst @@ -20,6 +20,8 @@ Central `_. - `Tutorial: Adding a new default command `_ +- `Tutorial: Adding new Object typeclasses and + defaults `_ Implementation ideas --------------------