The social system allows users to store, manage, and organize data about one another in game. This provides users an interface to interact (or not) with one another aside from meeting in physical space. The Social System provides each user with an interface to organize their own social connections (friends, enemies, acquaintances) and also the ability to view pertinent information about them (level, location, online status). An example would be a friends list.
What Issue(s) Does This Address?
- A way for players to aggregate, store, and sort their contacts.
- A way to view important information about contacts.
- Allows control over what information about players is made public.
- Provides an interface for other systems to use social data.
- Stores and manages persistent and non-persistent social connections between entities using the system.
- Provides basic load balancing on the Social system area.
What Issue(s) Does This NOT Address?
- GUI implementation.
- Does not provide custom, game-specific social features such as Guilds or Factions.
- Does not affect gameplay directly; developers must leverage the social system to provide game specific behavior.
When working with the Social System it is important to understand that little is happening from the user's current locale on the server, see Area Server. The majority of operations are carried out on the Social System Area, a System Area created for the explicit purpose of carrying out any specific Social System related work. To tie an object into the social system a developer would have to make it a _SocialDataOwner, denoting that the object makes use of the system. This object now a Social Data Owner is capable of having a Social Anchor and by proxy all that comes with. The Social Anchor provides the means for an object to interact with the Social System and other Social Data Owners.
The following is an overview of the main Social Objects used in the Social System.
Social Data Owner
A Social Data Owner is a class Glommed onto any object that is to have access to social system functionality. A Social Data Owner has the ability to have a Social Anchor, and all the functionality that comes with. While there can be no association between a Social Data Owner and a Social Anchor, the two are aware of one another by id. The Social Data Owner stores its anchor's id, and the instance on the Social System Area it is located.
A Social Anchor is an Arbitrary Root Node used as an anchor for various social data objects relative to the needs of a Social Data Owner. For example, any base Social Circle created, will have a base_hard_association to the Social Anchor, and thus be loaded and unloaded whenever the Social Anchor is. The Social Anchor is the main point of access for retrieving, storing, or interacting with, information regarding a Social Data Owner using the Social System.
Social Public Data Object
The Social Public Data Object is an outward facing Arbitrary Root Node with the sole purpose of conveying information a Social Data Owner to any node seeking it. For example, a Social Data Owner will have an associated Social Public Data Object which can detail information about that Owner, such as a player name, level, and location. Social Public Data Objects are what other users of the Social System see when inquiring about a connection. Similar to the relationship between Owner and Anchor, the Social Public Data Object retains no association between its associated anchor and itself. The two objects are aware of one another via node id, but that is the extent of the relationship.
Social Circles are Persisted Nodes that act as containers to store Social Public Data Object ID's. They contain only functionality to manipulate their list of Social Public Data Object ID's, functionality can of course be extended by developers with more specific uses in mind. Social Circles maintain a "base_hard_association" with a Social Anchor, to be loaded and unloaded in relation to that Anchor.
Social Queue Nodes
Social Queue Nodes carry out all the process requests of the Social System. An example would Creation / Destruction of Social Anchors, Social Circles, and Social Public Data Objects can be performed by Social Queue Nodes. Systems don't have to use Social Queue Nodes, but they may make things easier when calling for the functionality of the Social System Area from any other instance for example. The topic of Social Queues and specifically Social Queue Nodes is expanded upon in sections to come.
Social System Area
The Social System Area is where all the processing of Social Objects handled. For example, when a Social Anchor is created, the Social System assigns it an instance in the Social System Area to be loaded. This information is relayed to the Social Data Owner upon creation or load. Social Anchors, Social Circles, and Social Public Data Objects are all loaded on and handled by the Social System Area instances. The purpose being to relieve possible stress on other instances that could possibly be caused by excessive processing of Social Objects. An excess of players managing their friends list simultaneously may cause slow down if handled locally, it is better to have dedicated areas to handle this.
Social Public Data Objects are handled a bit differently than Social Anchors, though they are both created as root nodes, Social Public Data Objects are at times both loaded in as Arbitrary Root Nodes and as Non-Persistent Root Node Copies. This is done, in order to maintain the node's persistence and write out data to the database in one location, while allowing many other users to have access to the information. While, the owner of the persisted node is the only one allowed to make changes, those changes are broadcast across all Social System Area instances and changed on the node copies, anyone subscribed to that Social Public Data Object will be able to see the changed information.
- Node Persistence
- Offloading work to System Areas
- Non-Persistent Root Node Copies.
- Data Broadcasting across multiple instances.
Social System Queues
Image: The image illustrates the general process of Social Queues, a queue node is inserted into the Social Process Queue. After a given amount of time or a node limit is reached, the Social Process Queue begins to process each node. At this point the queue exhibits stack like behavior as it pops off a node from the front, removing it from the queue, calls the process method, and then moves on to the next one.
The Social System's Process Queue is used to process Queue Nodes. A system or player will pass in a queue node, and then the queue itself will invoke each queue node's process method. When a queue node is processed, it is removed from the queue, it's process method is invoked, and then the next node is handled. This is the basis of how the majority of queue node based operations are handled in the Social System.
Social Queue (Node(s))
As briefly mentioned earlier on, the Social System retains much of its functionality through the passing of information across instances in the form of SocialQueueNodes. When a user needs to access and perform an operation on a Social Anchor or a Social Public Data Object, that user will pass a social queue node to the Social System, which will then relay the queue node to the propera area / instance. All Social Queue Nodes inherit from the _SocialQueueNode class. This is done so that each child queue node may implement it's own version of the _ProcessSocialData() method. This allows the Social Process Queue to accept any type of Social Queue Node without needing to know relatively anything about it aside from the fact that it is a Social Queue Node and it has the _ProcessSocialData method. Once a queue node is created it is then sent to it's proper queue, from there it' may be routed to the proper instance via marshalling, Queue Nodes are processed in short intervals.
Developer created Queue Nodes are easily achieved, as only nodes that inherit from the _SocialQueueNode class are accepted into the process queue, that is what must be done. The developer will then implement the _ProcessSocialData method, which is the entry point into any queue node's functionality. And then implement custom functionality.
Below are several examples of existing queue nodes used within the Social System and a breif description about what they do.
_SocialQueueAnchorNode - The social queue anchor node takes care of the loading of social anchor objects. This type of queue node is used, because we have no knowledge of what area a player may load into. So when a player does enter the world, this type of queue node is sent off to the social system area for loading.
_SocialQueuePublicDataNode - Similar to the social queue anchor node, the social queue public data node takes care of not only loading Social Public Data Objects but also unloading them and swapping arbitrary root nodes for root node copies.
_SocialQueueSocialCircleNode - The social queue social circle node handles the creation and destruction of social circles.
_SocialQueuePublicUpdateOnlineStatusNode- This particular queue node is a good example of a queue node interacting with a social public data object. When the queue node is processed it seeks out the corresponding social public data ojbect node ref and changes a value; Online status on to Online status off, or vice versa.
Social Queue Node Pool
The Social Queue Node Pool, is a group of Queue Nodes created at one time. This is done to save time on memory allocation requests and subsequently cuts down on load. When using social queue nodes in the social system, it is a viable option to create them on the fly when needed, but it can be easier on the server to use the _SocialNodePoolArbiter. A class created to create and manage pools of Social Queue Nodes. When a type of Queue Node is requested, the arbiter queries its pools for any available node of that type and then returns an open one. If there are no nodes of that type in existence, or non are free, the arbiter will then create a batch of new nodes and return one immediately for use. The Social Node Pool Arbiter works with any type of Social Queue Node, including developer created nodes as long as the proper inheritance and methods are in place. By default all Social Queue Nodes are self realizing, in that they inherit a common _delete() method. Once a Queue node completes its goal it calls _delete() on itself. By default delete checks for a corresponding node pool, if one exists the Queue node will insert itself back into its pool, otherwise it will call DestroyNode on itself and be removed from memory.
Up till this point the majority of what has been covered is the relationships between the various parts that make up the Social System. Understanding these relationships is essential for success when utilizing it to achieve something as basic as friends lists, or when extending it to create further functionality.
With the example of a friends list, it is already known that Social Circles contain Social Public Data Object ID's, which are the public representations of Social Data Owners which in turn are the objects utilizing the Social System.
A Node can be designated as a social data owner by making a call to $_SOCIAL._RegisterWithSocialSystem( node ). This will glom and create the needed classes for a node to become a SocialDataOwner in addition to setting up the node in to the social system. The registration method does the following steps:
- Create a Social Data Owner
- This step gloms on the appropriate social data owner class on to a node so it can interface with the social system. This is primarily done through knowing its socialDataAnchorID and the system area that it is loaded in so an owner can communicate with it.
- Create a Social Anchor
- The Social Anchor is the center point of Social functionality, after creating a Social Data Owner the default clean engine implementation will create this as well since it is needed for basic social system functionality.
- Create a Social Public Data Object
- registration will also create a social public data object corresponding to the owner. If one did not exist the method will take care of invoking the creation step.
- Load Balance The New SocialDataOwner
- Requests the Social Anchor and Public Data object be placed in an appropriate social system area.
Those are the steps and pieces needed to create a simple friends list.
On the Client
Currently on the client side of things, when a player is registered with the Friend's layer that player's anchor is replicated to him or her. Inside the social system when performing operations, specifically on an anchor, if that anchor has a replication group, objects can be added and replicated down to the client. Currently this is done with Social Circles and Social Public Data Objects.
When an object is replicated to a client, an event is broadcast letting the social system know that the object has arrived.
"_SocialAnchorArrived" - A Social Anchor has arrived to the client
"_SocialCircleArrived" - A Social Circle has arrived on the client
"_SocialPublicDataObjectArrived" - A Social Public Data object has arrived on the client
The Social Anchor broadcasts events upon itself being replicated to the client, and upon a social circle being replicated to client. Base social circles are added to the Anchor's replication group since they are only ever accessed by that anchor. The Social Public Data Object broadcasts it's own arrival message since it will most likely be replicated to many destinations. Events on the client's _SocialSystem class, can be overriden by implementing "HE_SocialEventRaised". From there catching arrival events could provide information for custom GUI's to display.
- Replication Groups
- Observer Pattern
Social System Method Reference
_SocialSystem : Class Methods
Social system specific class methods.
method _IsSocialSystemEnabled() as Boolean
Returns a boolean value in relation to whether the Social System is enabled or disabled. By default implementation it will return true, this can be changed by implementing the "HE_IsSocialSystemEnabled" method.
remote method _InitSocialSystem()
This method initializes the Social System, and can be extended for the various types of area(s) and instance(s). By Default there are three sections of instantiation, System Area specific instantiation, General instantation, and mutual instantiation. This can be extended by implementing an HE_PostInitSocialSystem method
remote method _RegisterWithSocialSystem(social_data_owner_id as ID)
Registers a social public data owner with the Social System taking in the ID of the social data owner. The id passed in can be of a social data owner or of a node that wants to be a social data owner. If the node is already a social data owner it and its social public data object will be loaded. If it isn't a social data owner, it will be made into one. The registration process can be overridden by implementing the HE_RegisterWtihSocialSystem method.
method _RequestCreateSocialDataOwner(node_to_be as NodeRef) as Boolean
Gloms a _SocialDataOwner class onto the noderef passed in, returning true upon success.
method _RequestCreateSocialAnchor(social_public_owner_id as ID, area_origin_id as ID, inst_origin_id as ID, account_id as ID)
This methods puts in a request to the social system to create a _SocialAnchor object for the passed in social_public_data_owner. This is all done in the Social System Area space, so the area and instance of origin are required variable for a callback. If replication to the client is desired, the account_id parameter must be filled out, otherwise 0 can be passed in.
method _RequestLoadSocialAnchor(social_public_owner_id as ID, social_anchor_id as ID, area_origin_id as ID, inst_origin_id as ID, destination_inst as ID, account_id as ID)
Similar to the create method, this method just loads a social anchor, it has all the same parameters plus the additional destination id. This can be filled out if you wan't the anchor loaded to a specific SocialSystem system area instance, other one can pass in 0 and it will be assigned an instance.
method _RequestCreateSocialCircle(social_anchor_id as ID, social_anchor_inst_id as ID, social_circle_name as String, social_circle_spec_key as ID)
Creates a Social Circle. The social anchor id and the id of the instance it's loaded on must be passed in in order for the circle to be properly associated. This information is typically stored on the _SocialDataOwner itself. A spec key may be passed in for a custom social circle, passing in 0 or 1 will create a default social circle.
method _RequestDestroySocialCircle(social_anchor_id as ID, social_anchor_inst_id as ID, social_circle_name as String)
Destroys a Social Circle from a given social anchor.
method _RequestAddSocialPublicDataObjectToSocialCircle(social_anchor_id as ID, social_anchor_inst_id as ID, social_circle_name as String, social_public_data_object_to_add_id as ID)
Adds a _SocialPublicDataObject to a given social circle of a given anchor.
method _RequestRemoveSocialPublicDataObjectFromSocialCricleByCircleName(social_anchor_id as ID, social_anchor_inst_id as ID, social_circle_name as String, social_public_data_object_to_remove_id as ID)
Removes a _SocialPublicDataObject from a given social circle of a given anchor.
method _RequestCreateSocialPublicDataObject(social_anchor_id as ID, destination_inst_id as ID, social_public_data_owner_id as ID, social_public_data_spec_key as ID)
Creates a _SocialPublicDataObject. The associated social anchor id and anchor instance (the current instance on the SocialSystem System Area that the anchor is loaded) must be passed in, so that the anchor may have direct communication with the SocialPublicDataObject, the data owner and a spec key may also be passed in. A spec key of 0 or 1 may be passed in if one just want's the basic default _SocialPublicDataObject. _SocialPublicDataObject's are persisted nodes.
method _RequestLoadSocialPublicDataObject(social_anchor_id as ID, destination_inst_id as ID, social_public_data_object_id as ID, force_load_copy as Boolean)
If a _SocialPublicDataObject has been created in the past, and then since been unloaded, one can simply load it into the social system. This is accomplished by passing in the relative social anchor and anchor instance (destination), the id of the Social Public Data Object that is going to be loaded, and whether or not a copy is to be loaded. The copy being non-persistant.
method _RequestUnloadSocialPublicDataObject(social_anchor_id as ID, destination_inst_id as ID, social_public_data_object_id as ID)
Unloads a Social Public Data Object of the given Social Anchor on a given instance.
method _UnregisterSocialDataOwnerFromSocialSystem( social_data_owner as NodeRef of Class _SocialDataOwner)
Unregisters a social data owner from the social system, invoking the cleanup and unloading of the social anchor and corresponding social public data object.
The term social layers refers to layers that leverage the Social System. The social system alone only performs certain tasks on a set of its own data structures and system area. To obtain some sort of usefulness from it, layers have to be made to utilize and interpret the data correctly.
Extending Social Objects
A common theme expressed in the social system is inheritance, there are several types of social objects that inherit from parent classes. This is to allow for custom behavior between child types. For example there are several types of _SocialAnchor objects. There is the base _SocialAnchor, the parent class, and the _SocialPlayerCharacterAnchor. It is still a Social Anchor, but with a variation in functionality.
- When creating a derived Social Object, simply choose the object you with to derive from and set it as a parent in the DOM.
- The derived class will inherit all it's parent's fields and methods.
- Implement a parent's method on the child to override the parent's implementation, this allows for child specific functionality.
- All social objects can be treated as the parent type.
- If a method is called on an object that is both implemented on the parent and child, the child's will be called.
- This allows certain parts of the Social System to remain oblivious of new types of social objects while still processing them.
Taking a look at the _SocialAnchor and the _SocialPlayerCharacterAnchor would provide an excellent example of this exact behavior.
Here we look at an example of overriding a parent method. In the _SocialAnchorClassMethods there is a method to add a social public data object to a social circle.
This is the parent's implementation :
method _AddConnectionToSocialCircle (social_public_data_id as ID, social_circle_name as String) as Boolean myCircle as NodeRef = me._FindSocialCircle(social_circle_name) if(myCircle <> None) where myCircle is kindof _SocialCircle if(me._QueryCircleConnections(social_public_data_id, myCircle) != true) myCircle._AddSocialCircleConnection(social_public_data_id) return true . . . return false .
This is the child's implementation :
method _AddConnectionToSocialCircle(social_public_data_id as ID, social_circle_name as String) as Boolean if(parentClass::_AddConnectionToSocialCircle(social_public_data_id, social_circle_name)) me._CheckIfPublicDataObjectIsLoaded(social_public_data_id) return true . return false .
Social Objects, Method Breakdown.
The following is a method break down of important Social objects, that can be extended via overloading.
method _AddConnectionToSocialCircle (social_public_data_id as ID, social_circle_name as String) as BooleanThis method adds a social public data object to a social circle of the given name. Since all social circles maintain a "base_hard_association" with their social anchor, they are loaded and unloaded with the anchor. The anchor will query it's associated circles for the correct one and then add the social public data id to it.
method _CreateNewSocialCircle(social_circle_name as String, social_circle_spec_key as ID) as NodeRefThis will create a new social circle, associate itself with the anchor, and then add it to the Social Anchor's replication group. Overriding this method can provide custom circle creation steps. One could even call the parent version, parentClass:: , and then perform additional operations on the newly created circle.
method _RemoveConnectionFromSocialCircle(social_public_data_id as ID, social_circle_name as String) as BooleanThis method removes a given social public data id from the given circle. It will query all its circles for a matching name, then it will query that circle for the id. If it is found, it will be removed.
method _RemoveSocialCircle(social_circle_name as String) as BooleanThis method will query for the given circle, remove the association, and destroy the node returning true upon success. Overriding this method can allow time for operations before the circle is removed and destroyed, the parent class can be called afterwards if so desired.
method _SubscribeToSocialPublicDataObject(social_public_data_object as NodeRef of Class _SocialPublicDataObject)This is a method that will require overriding, while actual subscription nodes take care of actual subscribing each type of social anchor can handle this differently. There is no real base implementation, but taking a look at the _SocialPlayerCharacterAnchor's implementation will reveal that when this method is called, it will make a call to the SOCIAL system node to subscribe the associated player account to the social public data object.
method _SocialAnchorLoaded()There is no base implementation for this method, it is just used as an interface to override. This method is called after a social anchor is loaded, so if there is any functionality required after a custom anchor is loaded, this is where it would go. Taking a look at the _SocialPlayerCharacterAnchor class, it's implementation subscribes the account to the anchor, then begins to load the contents of the social circles associated with the anchor.
method _ShutdownSocialAnchor()The shutdown method is called whenever a social anchor un-registers with the social system. In the base implementation, all social public data object references used by a particular anchor are decremented, and so is the instance arbiter. It is recommended when implementing a custom version to call the parent class method at some point.
method _ShutdownSocialPublicDataObject()This method is called right before a _SocialPublicDataObject is unloaded when unregistering from the Social System.
method _SocialPublicDataObjectLoaded()This method is called whenever the social public data object is loaded, there is no base implementation. Taking a look at the _SocialPlayerCharacterPublicDataObject one can see that it will subscribe replicate itself to the account and toggle its online status.
method _ProcessSocialData()This method must be overridden in any inheriting queue node. Every time a queue node is processed this method is called, all custom functionality will reside here.
method _Delete()The _Delete method may or may not be overridden, as it currently stands it will attempt to return itself to its queue node pool or delete itself. And is typically called at the end of the _ProcessSocialData method.
Creating Social Specs
Specs are use in two places in the social system. They are used with _SocialAnchor based objects and with _SocialPublicDataObject based objects. When deriving from these objects a new spec will have to be created and added to the spec oracle to create them. Step by step information about creating specs can be found here.