buildzaar-design/README.md

81 lines
15 KiB
Markdown

# Concepts
* Domain - a publicly resolvable DNS domain name, backed by a server that forms part of the federated network. Other objects are owned by a specific domain.
* Central Operator - while the protocol is predominately based on federation, a select few features require a central operator of the entire network to register unique short IDs. The overall system is resilient to the Central Operator being unreachable (apart from registering new short IDs).
* Object - generic term for something owned by a domain.
* Player - an object representing a player (can be human or bot).
* Client - a program that operates as the player's agent, allowing them to explore across multiple domains.
* Room - an object representing a place where a player can be. Not necessarily indoors.
* Possession - an object intended to be movable (change location, including to a player, i.e. in their inventory).
* Region - an object representing a broader container for rooms.
* Map - a view of the topology of all or part of a region (created dynamically for a particular player and room).
* Verb - a command that an object (including a player object, triggered by the client) can send to an object. The object decides whether or not to accept it. There are some special verb types explained below.
* Attribute - a piece of data attached to an object. There are three types that differ based on ownership. Attributes have access control rules, with the access control decision ultimately decided by the domain which stores the attribute.
* Standard Local Attribute - these are well-known attributes that are stored by the domain that owns the object. The access control on when they can be read or updated follow rules that differ by the attribute. Examples include location of an object / player.
* Owned Attribute - these are attributes (scoped as URLs under the owning domain) where all attribute values are stored by the owning domain, which sets and enforces the rules for exactly how the attribute can be updated.
* Standard Owned Attribute - these attributes are stored with the attribute owner, but follow the access rules of Owned Attributes, but have well-known names (under each domain) like Standard Local Attributes.
* Central Attribute - these are Owned Attributes where the owner is the Central Operator. Restricted to special cases - notably a Short Name attribute for Regions. These attributes are effectively write-once (except they expire and can be re-created with a different value if not renewed by the Central Operator) - the Central Operator generates a signed certificate of the value.
# Object name mechanics
Every object has a unique ID in the form NanoID@domain, where domain is the domain name of the owner. This is used in API calls to reference an object, but is generally not the preferred form to display to the user.
Objects always have a long name, which ends in '@domain', where domain is the domain name of the owner. The "name" Standard Local Attribute provides the part before the '@domain' to identify the object.
An Object can have a short name (a human readable, globally unique name), but it requires a certificate chain. The first entry in this chain is always a certificate from the Central Operator allowing for the usage of the name by a domain. There are two options: the authorised domain on the first entry can match the domain that owns the object, or there can be a second 'delegation' certificate signed with the private key of the domain in the first certificate, delegating to the domain that owns the object.
Note that the certificate from the central authority is always valid for all objects on the domain (so multiple objects can have the same short name). When creating a delegation certificate, it can either be to a particular NanoID@domain, or to the wildcard *@domain.
Short ID name certificates can include variables and sets of values - for example, they might authorise `"$article $adjective killbot"`, and a set `adjective=[grumpy,murderous,mean,awful,horrible,terrible]` and `article=[a,an]`. The actual shortname attribute value set on the object includes the final shortname and the certificate chain authorising it. If the certificate is not valid (e.g. expired, not for the right domain or not matching the name), the client should fall back to displaying the long name, or failing that the unique ID.
Note that while the reuse of Short ID certificates provides something like a 'type' for objects, there is no protocol-level concept of an object type hierarchy. Server implementations are free to experiment with inheritence schemes, but this is an implementation detail not exposed at the protocol level.
# Location mechanics
The general principle is that the object's domain is the authority for which domain the object is located in (via the `locdomain` Standard Local Attribute), but the referenced `locdomain` domain is the authority for exactly which object (e.g. room, player, container possession) in the domain the user is located in (through the `location` Standard Owned Attribute).
Together, the `locdomain` on the domain that owns the object, and the `location` on that domain identify the position of the object.
When an object moves locations within a domain (i.e. the source and destination are in the same domain), the previous location SHOULD inform the player with an 'indomainplayermoved' verb containing the `newloc` parameter referencing the new location.
An object moving between domains is more complex, as there are potentially 3 domains involved - the domain of the object being moved, the previous location domain, and the proposed new location domain. Such a move can be initiated by either the previous location domain, or the moving object. When initiated by the previous location, the location MUST send a 'removedfromdomain' verb to the moving object with a 'proposedloc' parameter containing the NanoID@domain the previous location recommends the object be moved to. This verb may optionally include a destdata parameter (e.g. including a certificate from the source to the proposedloc). When initiated by the moving object (a 'teleport'), the moving object MUST send the previous location a 'leftdomain' verb message. In both cases, these are purely informative to the recipient - there is no option to reject the move. To avoid loops, the recipient of a removedfromdomain or leftdomain verb MUST NOT reply with a leftdomain or removedfromdomain verb. When a removedfromdomain message is received, the 'proposedloc' MAY be treated as only a suggestion, and the moving object's domain MAY choose to substitute a different destination location. In any case, the moving object MUST send a 'enterdomain' to the proposed destination object (except, if the proposed destination object is on the same domain as the moving object, this verb MAY be skipped). The request SHOULD include the destdata parameter copied from the removedfromdomain (if any). The response for the verb SHALL include a 'status' field, with allowed values 'success', and 'rejected'. If the response is 'success', the standard parameters on a indomainplayermoved verb should be included, and in addition a 'dest' unique ID should be included. If the response is 'rejected', the 'reason' field should provide a human readable explanation. In the event that a move is rejected or the verb cannot be sent successfully, the moving object's domain SHOULD instead move the object to a location on the moving object's domain as a fallback.
When the 'dest' attribute in the response to an 'enterdomain' verb refers to another domain, this is treated as a cross-domain redirect. Upon receiving such a redirect, servers MAY re-send the 'enterdomain' request, adjusted to the proposed new dest, to the newly referenced domain. Servers MUST apply an upper limit on how long a chain of redirects can be to prevent infinite loops. If a server chooses not to follow a redirect (either for policy reasons, or due to the length of the redirect chain), it is RECOMMENDED that it instead move the object to an appropriate location on the server's own domain.
A domain is free to entirely reject an object from entering that domain - it does not have control to stop the `locdomain` attribute being updated, but it need not set a `location` domain. Domains MUST be robust to the possibility that the `locdomain` on an object points to a domain that doesn't have a `location` attribute for the object. However, as this eventuality can be confusing when the object is a player, domain servers SHOULD endeavour to recover from that scenario by moving the object to a safe location on their own domain.
## Advice for implementing games on the protocol
Games may wish to restrict a player from teleporting to arbitrary locatons; an option is, on receiving an enterdomain verb, to check that the enterdomain recipient accepts the player. If that room / object is not expected to ever accept a player enter the domain, rejecting the verb is recommended. If the object is the correct portal in, but game mechanics mean it is preferrable for a player to be in a different object, the verb could succeed but respond with a dest pointing and the correct location the player has been teleported to within the domain.
The location mechanics mean it is not possible to block a player from leaving to another locdomain, even if game mechanics otherwise prevent the player from moving. This is a necessary consequence of not allowing any one domain too much control over other domain's objects. However, that is not to say that your game can't enforce consequences for a player teleporting out of a situation like being stunned, dead or in combat. One solution is to use Owned Attributes (locked down as to who can update them outside your domain) to remember the player was in this situation, and ensure they return to the same situation when they return to your domain. Domains may choose to make these Owned Attributes writable by a network of other trusted domains, the administrators of which have agreed to follow consistent rules (e.g. if a group of domains form part of a consistent game, the administrators might choose to enforce consistent rules for what to do when a player is dead - e.g. to not admit movement until the player rectifies the situation in accordance with the rules).
# Inventory mechanics
Inventory is a special case of location mechanics, as the inventory of a player is merely the objects located at the player. At a protocol level, the normal 'removedfromdomain' and 'enterdomain' mechanics exist.
In practice, domains MAY choose to allow a player to send a 'get' verb to a possession object in their current room. The object MAY respond by sending an 'enterdomain' command to the player object. Note that the player object MAY choose to reject this move or to accept it, taking it into their inventory. For inventory related commands, it is RECOMMENDED that redirects not be followed.
Posession objects MAY choose to accept a 'drop' verb, which triggers a 'removedfromdomain' verb back to the player. It is RECOMMENDED that server domains also provide an option for users to forcibly drop an object even without the cooperation of the source domain.
Domains may also choose to implement other mechanisms that trigger a 'removedfromdomain' verb - for example, a domain implementing a game might implement a stealing mechanic. Note that this is only possible with the cooperation of the domain that owns the property object (noting that having an object in a player's inventory is not the same thing as protocol-level ownership) - it is possible for a game domain, for example, to allow stealing all objects originating from that domain (or other cooperating domains), but not to allowing stealing everything from a player.
Domains with particular game balancing requirements (e.g. to enforce carry limits, and to not allow a player to teleport out, take a heavy item into their possession from storage, and teleport back in) MAY choose to separately track inventory and disallow usage of inventory not handled in accordance with that game's rules.
To support domains which do not manage their own list of inventories, objects SHOULD implement a 'listcontents' verb, accessible when invoked by the objects's current location, which returns a response attribute called `list` containing the NanoID@domain of a page of objects inside the object. The verb SHOULD enforce pagination limits, and if the results are truncated, also include a `continuation_token` response attribute. The `continuation_token` may be included as a request attribute to paginate through the results.
## Inventory position
On players, there is a standard attribute: `worn` describes what the player is wearing, formatted as a map from body position to a list of NanoID@domain IDs at that body position. The protocol does not impose a standard list of body positions. Domains which require more structured data or which are games that need to impose armour rules MAY instead ignore the `worn` standard attribute, and use an Owned Attribute to track a player's clothes or armour.
# Display mechanics
The authority on what an object looks like to a player object is the player's location. The `look` verb should be sent to the location object, with a `what` attribute of the string of what to look at. The location object's domain SHOULD consider resolving the object by name against both the source object's inventory, and all the object in the location's inventory. It MAY fetch information about objects by dispatching a `describe` verb to the objects. The `describe` verb response should include human readable `description` and `short_description` attributes. It is up to the location domain to decide what processing to do, or even whether to show nothing at all (e.g. if it is too dark).
When implementing the `describe` verb on players, it is recommended that the description allow customisation, and consider what the player is wearing.
# Messaging mechanics
The `rawmsg` verb takes a request attribute `contents` and allows sending plain text to a player. Domains SHOULD reject `rawmsg` verbs that do not originate from the current location object of the player, to avoid spoofing attacks. The `contents` contains HTML (which SHOULD be sanitised against an element allowlist to remove scripts and other undesirable content) before being rendered for the user (for example, displayed using ANSI formatted text, or as HTML in a browser). The intention of a `rawmsg` is for it to be displayed without making the source prominent (to avoid immersion breaking; however, clients MAY provide functionality to allow tracing messages).
The `msg` verb follows the same format, but may be sent from any object to a player. Domains SHOULD implement blocklist functionality to allow players to block unwanted `msg` verbs from being displayed, but SHOULD otherwise generally be displayed to the player, with clear attribution of the source.