This manual page describes the interface as presented to an engine once it has been loaded by spree . A loaded instance of an engine is responsible for a particular clique , in which one or more members participate. Messages sent by members are interpreted by the engine, which responds by making changes to the hierarchical object database held by the clique. Behind the scenes spree distributes updates to this database to members of the clique as appropriate (see spree (4) for details).
Note that the visibility set of an object does not alter the visibility of that object's attributes, but only that of its children (and of their children: in general an object is visible to a member if the intersection of all its ancestors' visibility sets contains that member).
Objects can be transferred inside the hierarchy from one parent to another. If an object is moved to a parent whose visibility conceals it from a member, then it will appear to that member to have been deleted; if it is later made visible, then it will be recreated for that member. A clique engine can almost always ignore this technicality, except for one thing: the identifier used by a particular member to identify an object is not necessarily the same as that used by the clique engine. Thus when an engine receives an object id in a member's message, it should convert it using the member .obj() function.
10 clique .objects This array holds the objects in the clique. An object with identifier id is found at clique .objects[ id ].
clique .new(archive, owner) New creates a new clique. Archive is an archive of the game to be created; archive \.argv should be non-nil; its first element should name the engine to be loaded (as a path relative to the engine module directory, and without the .dis extension).
clique .newobject(parent, visibility, objtype) Newobject creates a new object at the end of parent 's children; If parent is nil, the new object is created under the root object. The new object has visibility visibility , and type objtype . An object's type cannot be changed once it has been created.
clique .action(cmd, objs, rest, whoto) Action sends a message to some members without affecting the object hierarchy. It can be used to send transient events that have no meaning when stored statically (for example, network latency probes). The message is sent to the set of members given by whoto . Objs is assumed to be a list of object ids, which are converted appropriately for each member receiving the message; the final message is a string built by concatenating cmd , the list of object ids, and rest , separated by spaces.
clique .breakmsg(whoto) Messages are usually sent to clients in an uninterrupted stream (as documented in spree (4)), with a single read returning a potentially large set of messages. Breakmsg arranges that subsequent messages received by the members specified in whoto will see not be merged with messages sent prior to the call to breakmsg . This is used to enable a new client module to be started without needing to pass it data received in the previous read.
clique .member(id) Member yields the member corresponding to identifier id , or nil if there is none.
clique .membernamed(name) Membernamed searches for a member of clique named name and returns it if it finds it, otherwise nil .
clique .members() Members returns a list of all the members of clique , including those that have been suspended.
clique .owner() Owner returns the name of the owner of the clique; i.e. the user that created it.
clique .hangup() Hangup terminates a game and informs all the players of that fact.
clique .notify(cliqueid, msg) Notify sends an informational message to another clique. The clique so referenced must be either the parent or a child of clique . The message is not sent synchronously, and care should be taken not to send messages that can cause an indefinite recursion.
10 member .id The member's identifier is an integer unique across all current members of the clique, but ids of members that have left the clique will be reused. There may not be two members of the same name in the same clique.
member .name Name holds the authenticated name of the member. This is necessarily unique over the members of a clique.
member .obj(id) Obj converts from a member's external object identifier to the clique's local Object that it represents. It returns nil if there is no such object.
member .del(suspend) Del deletes member from the clique; no more requests from member will be received by the clique engine. If suspend is non-zero, if a member of the same name joins again it will be allocated the same object id, allowing a member to leave and join again without losing state.
10 obj .setattr(name, val, vis) Setattr sets attribute name in obj to val. If the attribute is being created for the first time, then it will be given visibility vis . Name should be non-empty, and should not contain any space characters. Note that it is not possible for an attribute to refer directly to an object by its identifier; if this facility is needed, another identifying scheme should be used. This also applies to member identifiers, which will change if the clique is saved and loaded again.
obj .getattr(name) Getattr yields the current value of the attribute name in obj . If an attribute is not set, it yields nil .
obj .delete() Delete removes obj from the object hierarchy.
obj .deletechildren(r) Deletechildren deletes children in range r from obj .
obj .transfer(r, dst, i) Transfer transfers the children in range r from obj to just before the object at index i in dst . It is permissible for obj and dst to be the same object.
obj .setvisibility(visibility) Setvisibility allows the set of members given in visibility to see the children of obj , and denies access to all others. Members are notified of the change.
obj .setattrvisibility(name, visibility) Setattrvisibility allows the set of members given in visibility to see the value of obj 's attribute name , and denies access to all others. Members are not notified of the change; if there is a need to communicate the fact of an attribute becoming invisible to members, it should be done by using another (visible) attribute to communicate the change.
Read opens file and returns it as an Archive adt, say a . A .argv holds the command line arguments to the clique module (including the name of the module, its first element); a .members gives the names of all archived members - the id of an archived member is given by its index in the array; a .info gives the list of attributes an values as stored by write ; a .objects holds the clique objects. Readheader is just like read except that it parses the header only, so will return an Archive adt such that a .objects is nil.
mod ->init(srvmod, clique, argv) Init initialises the clique engine. Clique is the clique that the engine is controlling, and srvmod is the Spree module holding its associated data. An error response from this function causes the clique to be aborted. Argv gives a list of arguments to the engine, starting with its module name.
mod ->join(member, e, suspended) Member has made a request to join the clique; an error response causes the request to be refused, otherwise the member joins the clique. E is a message from the client about how it would like to join the clique (e.g. join , watch , etc). Suspended is non-zero if the member was previously suspended from the clique.
mod ->leave(member) Member has left the clique. If leave returns zero, the member will not be deleted from the clique, but merely suspended until they should join again.
mod ->command(member, e) Member has sent the command e . The command usually follows the simple message conventions used in spree (4), i.e. simple space-separated tokens.
mod ->notify(cliqueid, s) A notification, s , has been posted to the current clique by the clique identified by cliqueid . The posting clique is either a parent or a child of the current clique.
mod .
.EX .vs -1 implement Cliquemodule; include "sys.m"; sys: Sys; include "draw.m"; include "../spree.m"; spree: Spree; Clique, Member: import spree; clique: ref Clique; clienttype(): string { return "chat"; } init(g: ref Clique, srvmod: Spree): string { (sys, clique, spree) = (load Sys Sys->PATH, g, srvmod); return nil; } join(nil: ref Member): string { return nil; } leave(nil: ref Member) { } command(member: ref Member, cmd: string): string { clique.action("say " + string member.id + " " + cmd, nil, nil, ~0); return nil; } .vs +1