The HeroEngine Chat System is a framework for passing messages between clients through server areas.
Issues addressed by the Chat System
- Provides a framework for building robust chat systems
- Channels run in a dedicated Chat System Area to reduce overhead in the World's Play Areas.
- Distributes load across multiple Chat System Areas to service a large amounts of communication
- Contains working samples with basic messaging functionality
- Provides a method of inter-area communication
- Supports arbitrarily named channels, each with its own unique ID
- Messages, Subscriptions and Unsubscriptions are passed as easily extensible command objects
- By default, channels delete themselves when no longer needed.
- Accepts slash-commands as input through the HeroBlade Chat panel
Features not in the current version
- Custom behaviors for Chat Channels, if desired, must be implemented.
- The current version of the Chat System does not contain its own dedicated GUI.
- The Chat System provides a basic framework for building robust chat functionality. Specific behavior (such as party, guild or combat chat) is left as the responsibility of the developer to implement.
The Chat System delegates the majority of its processes to the Chat System Area: a System Area with a customizable number of instances. Each instance can house an arbitrary number of chat channels. Channels may be subscribed to by users. All messages accepted by the channels are subsequently replicated to their subscribers.
The Chat System Area
The Chat System Area is composed of n-1 Instances and one EDIT Instance, referred to as the "Control Instance". The Control Instance is responsible for registration and initialization of the Chat System and spinning-up of Chat System Instances at world-load time. It also catches requests that fail if one of the Chat System Instances is unexpectedly found down.
When a channel is "created" within the Chat System, a channel object with the same unique identifier is instantiated from a spec within each Chat System Instance. Assume Each instance houses x _ChatChannel objects. If there are n Chat System Area instances (including the Control Instance), then there will be x*n total _ChatChannel objects in the System Area.
This is done so that requests can go to any of the Chat System Instances and traffic does not congregate onto one instance.
Every Play Area Instance should communicate with only one Chat System Instance. Within the Chat System Node in every Play Area Instance in the world, there is a field called "_designatedChatInstance" of type ID. This field corresponds to the Chat System Area Instance that Play Area Instance should communicate with. As New Play Instances are spun up, one of the existing Chat System Instances will be designated to them. This behavior is not dynamic; the Chat System Area will not automatically spin up new System Instances as traffic increases. The relationship between Chat System Instances and Play Area Instances is one-to-many.
The Server Play Area
The area in which the client's player character is currently residing is considered the Play Area. Communication from the client to the server must always go through this area before proceeding to the Chat System Area. When a client subscribes to or unsubscribes from a channel, that request is broadcast to the same channel in each instance. The request first goes to the Chat System Area Designated Instance for that Server Play Area and then disperses to all other Chat System Instances. This reduces the amount of remote calls made from the Server Play Area.
Clients may send requests which include but are not limited to subscribing to, unsubscribing from or send a messages to a given channel. All GUI-related operations are also handled exclusively on the client. Since there are n copies of each channel replicating to the client, _LogicalChatChannel objects are used to aggregate their respective Chat Channels.
_ChatChannel objects exist within the Chat System Area instances in order to handle incoming messages from all potential subscribers. They dictate who can and cannot subscribe through a simple password field, but more advanced restrictions can be implemented by creating subclasses of _ChatChannel.
_DebugChatChannel is a sample child of _ChatChannel with basic string messaging functionality. When a user subscribes to a _ChatChannel object, that user is added to the replication group of that object and every other _ChatChannel object with the same _chatChannelUniqueIdentifier field. Therefore, whenever anyone sends a message to a _ChatChannel object, the message is replicated down to all clients within its replication group.
_ChatChannel nodes are replicated to the client and aggregated with a _LogicalChatChannel node. Recall that for each channel which is visible to the user, n copies of that channel exist in the Chat System Area Instances, one for each instance.
_LogicalChatChannel (Client only)
Since _ChatChannel nodes with the same _chatChannelUniqueIdentifier exist across all spun-up Chat System Area Instances, it's helpful to have all their replicated events aggregated into one object. The purpose of the _LogicalChatChannel is to allow client listeners to refer to this one object for replicated messages and events across any number of _ChatChannels which could exist on the server.
The _LogicalChatChannel node will associates itself with all replicated channels with the same _chatChannelUniqueIdentifier. In this way, all traffic from these channels are collected into one place for reference by any listeners.
_LogicalChatChannel objects inherit from ObsSubject allowing other systems to listen to them for events. Any listeners may use ObsListener as a parent and implement method calls _LogicalChatChannel generates for its events such as
method _SubscribeToChatChannel( chat_channel as NodeRef ) method _UnsubscribeFromChatChannel( chat_channel as NodeRef ) method _GotChatChannelMessage( chat_message as NodeRef of Class _ChatMessage )
Subscription and Message Command Objects
ChatSystemCommand objects are used to carry information from the client to and across server areas. There are three kinds of ChatSystemCommand objects.
- _ChatSystemClientCommand (Client) - A command object with fields only applicable to a client.
- _ChatSystemCommand (Server) - A command object with fields and methods necessary for tracking its progress across server areas.
- _ChatSystemClientCommand (Server) - Once a serialized client command reaches the server, it is deserialized and placed into a ChatSystemClientCommand object on the server. The server script for this command is capable of accepting the reference to a ChatSystemCommand object and setting its fields based on what operation the command needs to perform.
To create a new custom client command, subclasses of these three objects should be implemented. For new server-only commands, a subclass of ChatSystemCommand (server) is all that needs to be implemented.
The Chat System abstracts requests between the client and channels located on the server. Since requests are passed between servers and clients, remote methods on the system nodes accept marshaled command objects as parameters.
Sending a command from a client to the server requires the use of these three separate objects. In the case of a subscription, a _ChatSystemClientCommandSubscription object would have to be created or allocated on the client, have its fields set and sent to the Client Chat System Node. The Server Chat System Node will receive the serialized _ChatSystemClientCommandSubscription and deserialize that into a server version of the class _ChatSystemClientCommandSubscription which has the ability to transfer the values in it's fields to a _ChatSystemCommandSubscription object reference passed to it.
All Chat System Command classes provided derive from _ChatPoolItem, following the object pool design pattern. This was done to reduce the memory footprint of creating a new object every time a request is made.
The $CHAT system node on the server contains pool maps for _ChatSystemCommand and _ChatSystemClientCommand pool objects so that Command pools can be stored on the server system node. The $CHAT system node on the client has a single pool map for _ChatSystemClientCommand pool objects.
Sending System Commands
To subscribe to a channel, the user sends a Client Chat System Command through a remote call from the client-side $CHAT system node. Client Chat System Commands can contain any set of instructions. They simply need to be inherited from _ChatSystemClientCommand. The method for sending a basic client command from the $CHAT system node on the client is
method _SendChatSystemCommand( chat_system_client_command as NodeRef of Class _ChatSystemClientCommand)
The Play Area accommodating that client's character receives the request on the server-side $CHAT system node. The server class for this node is _ChatHandler. The receiving method for this request is
untrusted method _ReceiveChatSystemClientCommand(serialized_chat_system_client_command as String, client_command_type as String)
Recall the purpose of server-side _ChatSystemClientCommand objects is to store and transfer information from client-side _ChatSystemClientCommand objects into _ChatSystemCommand objects. Therefore, this method first deserializes the _ChatSystemClientCommand into its server counterpart object. It then tasks the server-side _ChatSystemClientCommand with transferring its values to a _ChatSystemCommand (server-only) object.
Once the _ChatSystemCommand has been created and populated with values from the client command, it is passed to another method in charge of setting server-only values so that the command can be routed correctly across the Chat System Area.
remote method _SendChatSystemCommand( chat_system_command as NodeRef of Class _ChatSystemCommand )
The Chat System Command is then serialized and sent to the $CHAT system node in the Chat System Area. The method which receives the serialized object is
remote method _ReceiveChatSystemCommand( command_type as String, serialized_chat_system_command as String )This method deserializes the string into an object again allocated from a pool. If the command is a broadcast-type command, this method will call itself in the remaining Chat System Instances, forwarding those instances copies of the serialized command.
By design, each instance holds a _ChatChannel object for every channel with the same _chatChannelUniqueIdentifier. Hence, subscriptions and Unsubscriptions are broadcast-type commands. Because each subscriber is subscribed to all copies of a channel, messages need not be broadcast to all copies of a channel. Therefore messages are not broadcast-type commands. Custom commands may or may not be broadcast commands. The intended use will dictate which type they will be.
Finally, this method calls a method on the chat system command object itself.
Each Chat System Command is implemented to perform its own custom set of instructions. The methods on _ChatSystemCommand itself are abstract and must be overridden. _ChatSystemCommandSubscribe, _ChatSystemCommandUnsubscribe and _ChatSystemCommandMessage all inherit from _ChatSystemCommand.
The _ChatSystemCommandSubscribe command implements the method _ProcessChatSystemCommand() with the following behavior. It attempts to get the _ChatChannel with the corresponding unique identifier in its own fields. If that channel does not yet exist, it is created. The command then sends itself to the channel through the method
method _SubscribeToChatChannelThroughChatSystemCommand( chat_system_command as NodeRef of Class _ChatSystemCommand )
Where the subscription sender is added to the replication group of the channel and decorators to that channel are notified.
When all initial set fields in the channel have replicated to the client for the first time,
method _OnReplicationGroupAdded()is called on the client _ChatChannel class. This method requests the spec from the server so more information can be accessed later.
_logicalChatChannelIdentifier fields are located on each channel's spec. The Logical Chat Channel Identifier is what is used to determine which replicated _ChatChannel object arriving on the client should be associated with which Logical Chat Channels. The _AreaChatChannelSpec has a _logicalChatChannelIdentifier value of "area". Hence all channels replicated to the client with that field value will be associated with the same Logical Chat Channel with a _logicalChatChannelIdentifier of "area". Chat Channels are associated to corresponding Logical Chat Channels through a logical_chat_channel_association.
The Logical Chat Channel generates events so that listeners such as a GUI can respond to incoming communication by registering as a listener and implementing the same method signatures. The events in the base _LogicalChatChannel class are
method _SubscribeToChatChannel( chat_channel as NodeRef ) method _UnsubscribeFromChatChannel( chat_channel as NodeRef ) method _GotChatChannelMessage( chat_message as NodeRef of Class _ChatMessage )Subscribers will receive all future communication until that subscriber disconnects or unsubscribes.
Unsubscription requests are handled nearly identically to subscription requests. Practically, there are few reasons to deny a subscriber from purposefully unsubscribing from a channel. Ergo, the unsubscription routine follows the same steps, usually without as many checks to credentials on the _ChatChannel level. All that is required to send an unsubcription request is to create or allocate a _ChatSystemCommandUnsubscribe object, populate it with the appropriate fields and pass it to
//From Chat_Handler (client) method _SendChatSystemCommand( chat_system_client_command as NodeRef of Class _ChatSystemClientCommand)Where the command will follow the same routine as the subscription scenario above apart from ultimately removing the client from the replication group of the _ChatChannel objects in the Chat System Area.
Sending a Message
Likewise, _ChatSystemMessageCommandText is a child of _ChatSystemCommandMessage and follows the same routine as the previous two commands. Apart from containing a slightly different set of fields (which includes a message string), the text message command is not a broadcast-type command, meaning it does not propagate to all other Chat System instances upon arriving at the designated instance for its originating area.
When passed to a chat channel, a text message command's fields will be applied to that channel. Detecting a change in their values, the channel will replicate its fields to all subscribing clients. Since all clients subscribe to each occurrence of a given channel across each instance in the Chat System Area, messages need to be sent to only one channel.
Using the Base System
The following calls should be made from a client script.
To request a subscription to a channel, execute the following calls in your server script.
subscribe_command_pool as NodeRef of Class _ChatSystemCommandPool = $CHAT._GetChatSystemCommandPool( "_ChatSystemCommandSubscribe" ) subscribe_command as NodeRef of Class _ChatSystemCommandSubscribe = subscribe_command_pool._GetChatPoolObject() subscribe_command._chatChannelSpecKey = $CHAT._GetDefaultChatChannelSpecKey() subscribe_command._chatChannelSubscriberID = SYSTEM.INFO.PLAYERCHARACTER subscribe_command._chatChannelUniqueIdentifier = "test_channel_123" subscribe_command._chatChannelSubscriptionPassword = "" $CHAT._SendChatSystemCommand( subscribe_command )
If the channel does not exist prior to the subscription request, the _chatChannelPassword field on the _ChatChannel is set as the password in the subscription request.
n _ChatChannel objects should now be replicated to your client (one for each Chat System Instance). Perform a query node command for _ChatChannel objects on the client to see them.
Upon entering an area, each player is automatically subscribed to world and area chat channels.
Sending a Message
This example will send a message to the channel with the same unique_identifier that was specified in the subscription calls above. Execute the following code in your client script to do so.
message_command_pool as NodeRef of Class _ChatSystemCommandPool = $CHAT._GetChatSystemCommandPool( "_ChatSystemCommandMessageText" ) message_command as NodeRef of Class _ChatSystemCommandMessageText = message_command_pool._GetChatPoolObject() message_command._chatChannelMessage = "Bow ties are cool." message_command._chatChannelMessageSenderID = SYSTEM.INFO.PLAYERCHARACTER message_command._chatChannelUniqueIdentifier = "test_channel_123" $CHAT._SendChatSystemCommand( message_command )
Once the message is received by the _ChatChannel object in the system area, its fields will be set and replicated to the client. One of the _ChatChannel nodes on the client should have "Bow ties are cool." as its _chatChannelMessage field value. Perform a show node command on the CLI to view the fields of the _ChatChannel nodes individually and verify this.
To unsubscribe and remove yourself from the replication group of a _ChatChannel, make the following calls from your client script.
unsubscribe_command_pool as NodeRef of Class _ChatSystemCommandPool = $CHAT._GetChatSystemCommandPool( "_ChatSystemCommandUnsubscribe" ) unsubscribe_command as NodeRef of Class _ChatSystemCommandUnsubscribe = unsubscribe_command_pool._GetChatPoolObject() unsubscribe_command._chatChannelUnsubscriberID = SYSTEM.INFO.PLAYERCHARACTER unsubscribe_command._chatChannelUniqueIdentifier = "test_channel_123" $CHAT._SendChatSystemCommand( unsubscribe_command )
After unsubscribing from a channel, that channels noderefs should no longer exist on the client. Perform another query node in the CLI to verify this.
Chat Panel Integration
The Chat System supports slash command input from the HeroBlade Chat Panel. The following slash commands are currently supported.
/hechat area <text message> Sends a chat message to the area channel for the area in which the player currently resides.
/hechat world <text message> Sends a chat message to the world channel, visible to all players in each area of the world.
/hechat sendmessage <unique identifier> <text message> Sends a chat message to the channel with the provided unique identifier.
/hechat subscribe <unique identifier> <password (optional)> Subscribes the client to the chat channel with the given unique identifier. If it doesn't yet exist, it will be created.
/hechat unsubscribe <unique identifier> Unsubscribes the client from the chat channel with the given unique identifier. By default, chat channels are deleted once their last subscriber unsubscribes.
New Chat Panel slash commands or the behaviors of the existing one can be implemented by overriding the following method on the $CHAT server system node
method _ProcessChatSlashCommandInput(account as NodeRef of Class _PlayerAccount, input as String)and including the string input as recognizable commands in the following two methods in _CommandHandlerClassMethods (server script).
unique method _ProcessCommand(connection as NodeRef, input as String) method _isHECommand(command as String) as Boolean
This example will illustrate how to extend the chat system to include Guild Channels and Guild-specific system commands. This scenario leverages components of the Social System and will assume there is a guild which currently exists as a _SocialCircle associated with a _SocialAnchor.
Create and configure new child classes of _DebugChatChannelSpec and _DebugChatChannel. call them _GuildChatChannelSpec and _GuildChatChannel on both the client and server. _DebugChatChannel implementes the method
method _GotChatChannelMessageThroughChatSystemCommand( chat_system_command as NodeRef of Class _ChatSystemCommand )which is abstract in _ChatChannel. Override this method in GuildChatChannel and implement the logic for accepting message system commands.
_DebugChatChannel on the server is a good example of how to override this method. After verifying whether the sender of the object is a subscriber, it applies the information located within that message to the channel itself. The information is then replicated to all subscribers. If communication within Guild Chat Channels is to be restricted to guild members, an additional check should be performed against a Social Anchor field within _GuildChatChannel to determine whether the message sender is allowed to actually send the message. This restriction (as well as others) could be implemented in
method _AllowMessageToBeSentOnChatChannel(chat_system_command as NodeRef of Class _ChatSystemCommand) as Booleanand called from within the _GotChatChannelMessageThroughChatSystemCommand method before applying the message fields to the channel because doing so will result in immediate replication to all subscribers.
The behavior to prevent members of guild from unsubscribing to Guild Chat is an understandable restriction. To implement this, override the parent method <hsl>method _UnsubscribeFromChatChannelThroughChatSystemCommand( chat_system_command as NodeRef of Class _ChatSystemCommand )</hsl> and before removing the subscriber from the channel's replication group, use the same social data to determine whether that client is a member of the guild for this channel. If so, simply ignore the request.
Assuming that Guild chat should be subscribed to when a client logs in, a subscription command can be sent from the following method on the $CHAT server system node
untrusted method _ChatSystemOnPlayerEnteredArea(player_character as ID)
Logically, the subscriber should be unsubscribed when logging off. Within the if(sessionEnd) condition block, send an unsubscription command from the following method on the $CHAT server system node.
untrusted method _ChatSystemOnPlayerExitingArea(player_character as ID, sessionEnd as Boolean)
Guild Chat System Commands
This example demonstrated implementing a new channel and using it from within the Chat System Area to address custom restrictions. Checking whether a given client is a member of the guild to which the channel belongs is possible from within the Subscription and Message commands themselves. This is an alternative and entirely acceptable implementation. It should be noted however that this task would best be performed from within the Chat System Area so the area the player is currently in is not taxed with additional operations which need not be performed there.
To add custom behavior to a chat system command, it will have to be subclassed just as the _DebugChatChannel was in the above example. However, all three commands
- _ChatSystemCommand (server-only)
- _ChatSystemClientCommand (server)
- _ChatSystemClientCommand (client)
Will have to be overridden appropriately to translate the new behavior from the client to the server in an extensible way. _ChatSystemCommandMessageText is a subclass of _ChatSystemCommandMessage which is, in turn, a subclass of _ChatSystemCommand. Likewise, both _ChatSystemClientCommandMessageText classed (server and client) share the same hierarchy with _ChatSystemClientCommandMessage and _ChatSystemClientCommand. Hence,
- _ChatSystemCommandMessageText (server-only)
- _ChatSystemClientCommandMessageText (server)
- _ChatSystemClientCommandMessageText (client)
are already included in the Chat System and a good set of examples on how to extend the base command objects to perform custom and extensible operations across the client and servers.
Methods located on the system nodes (_ChatHandler) have HE_Overrides, allowing override of their default behaviors by writing new methods with the signatures "HE_<method signature>".
method _GetDefaultChatSystemAreaInstanceCount() as Integercan be overridden as
method HE_GetDefaultChatSystemAreaInstanceCount() as Integerand implemented to return 5 instead of the default value of 3.
//Interpret slash command input from the Chat Panel method _ProcessChatSlashCommandInput(account as NodeRef of Class _PlayerAccount, input as String) //details on how to use available slash commands are output to the Chat Panel method _ProcessChatSlashCommandInputCommandUsage(account as NodeRef of Class _PlayerAccount, input as String) //Receive a _ChatSystemClientCommand from a client, translate it to a _ChatSystemCommand and forward //it along to the Chat System Area untrusted method _ReceiveChatSystemClientCommand(serialized_chat_system_client_command as String, client_command_type as String) //Sends a chat system command to the system area instance that handles the current area server's chat traffic //destroys the command node when it finishes with it. remote method _SendChatSystemCommand( chat_system_command as NodeRef of Class _ChatSystemCommand ) //Receive a serialized _ChatSystemCommand object within the Chat System Area //Deserialize and process it remote method _ReceiveChatSystemCommand( command_type as String, serialized_chat_system_command as String ) //Calling _ReceiveChatSystemCommand() has failed on the the initial call to the Designated Instance //Reassign the designated instance for the play instance which failed remote method _ReceiveChatSystemCommandFailure(command_type as String, serialized_chat_system_command as String) //Create a single chat channel in this instance method _CreateChatChannel( chat_system_command as NodeRef of Class _ChatSystemCommand ) as NodeRef of Class _ChatChannel //Remove the chat channel from the channel map in this instance method _RemoveChatChannelFromRegistration( chat_channel as NodeRef of Class _ChatChannel ) //Checked when the world spins up to determine whether to initialize the Chat System method _IsChatSystemEnabled() as Boolean //Request that the world spin up the Chat System Edit instance (the Control Instance) remote method _SpinupChatSystemArea() //Initialize the Chat System Area when the world is spun up //And create a World Chat Channel remote method _ChatSystemOnWorldLoad() //return the unique identifier string field for the area chat channel for this area method _GetAreaChatChannelUniqueIdentifier() as String //return the unique identifier string field for the world chat channel method _GetWorldChatChannelUniqueIdentifier() as String //Called when a player is exiting an area untrusted method _ChatSystemOnPlayerExitingArea(player_character as ID, sessionEnd as Boolean) //Called when a player has entered an area untrusted method _ChatSystemOnPlayerEnteredArea(player_character as ID) method _ChatSystemOnAreaLoad() //Distribute the current system node id to all areas which existed before the //Chat System Area was spun up remote method _UpdateChatSystemNodeAcrossAllAreas(chat_system_area_id as ID) //Initialize the Chat System, register it for events with the world, //add it to the keepup list and change its spindown spec //spin up n Chat System Instances remote method _RegisterChatSystemArea() //Request the refresh of Chat System Area data for newly spun-up instances remote method _UpdateChatSystemAreaInstance(instance_id as ID) //Spin down all the Chat System Area Instances remote method _SpindownChatSystemArea() //Unregister the Chat System Area for events from the world remote method _UnregisterForEventsWithWorld() //Called to explicitly shut down the system area even when the it has //been added to the keep-up list remote method _UnregisterChatSystemArea(instance_id as ID) //Request a specific Chat System Area Instance for this play area to speak to directly remote method _RequestChatSystemDesignatedInstance(command_type as String, serialized_chat_system_command as String) //Serialize a _ChatSystemClientCommand object method _SerializeChatSystemClientCommand(chat_system_client_command as NodeRef of Class _ChatSystemClientCommand) as String //Deserialize a _ChatSystemClientCommand object method _DeserializeChatSystemClientCommand(serialized_chat_system_client_command as String, chat_system_client_command as NodeRef of Class _ChatSystemClientCommand, fail_silently as Boolean) //Serialize a _ChatSystemCommand object method _SerializeChatSystemCommand(chat_system_command as NodeRef of Class _ChatSystemCommand) as String //Deserialize a _ChatSystemCommand object method _DeserializeChatSystemCommand(serialized_chat_system_command as String, chat_system_command as NodeRef of Class _ChatSystemCommand, fail_silently as Boolean) //default starting instance count for the chat system area (not counting the Control Instance) method _GetDefaultChatSystemAreaInstanceCount() as Integer //maximum starting instance count for the chat system area method _GetMaximumChatSystemAreaInstanceCount() as Integer //return the noderef of a channel in the current instance method _GetChatChannel(unique_channel_identifier as String) as NodeRef of Class _ChatChannel // Determine whether a channel exists within the channel map for this instance method _IsChatChannelUniqueIdentifierRegistered( unique_channel_identifier as String) as Boolean //Add the chat system area to the keepup list remote method _KeepChatSystemAreaInstanceUp(instance_id as ID) //apply the designation to this instance remote method _SetChatSystemDesignatedInstance(instance_id as ID) //retrieve the ID of the chat system area instance that has been designated as servicing the current area instance method _GetChatSystemDesignatedInstance() as ID //return the default spec value for a _DebugChatChannel method _GetDefaultChatChannelSpecKey() as ID //return the default spec value for a _WorldChatChannel method _GetWorldChatChannelSpecKey() as ID //return the default spec value for an _AreaChatChannel method _GetAreaChatChannelSpecKey() as ID //return the chat system area ID method _GetChatSystemAreaID() as ID remote method _FindChatSystemAreaID(area_id as ID, instance_id as ID) //assign the chat system area id to a field for future reference remote method _GoToAndSetChatSystemAreaID(area_id as ID, instance_id as ID, chat_system_area_id as ID) //assign the chat system area id to a field on this system node for future reference method _SetChatSystemAreaID(chat_system_area_id as ID) //determine whether the script is in the chat system area (any instance) method _InChatSystemArea() as Boolean //check whether in specific instance of the chat system area method _InChatSystemAreaInstance(instance_id as ID) as Boolean //return the control instance ID method _GetChatSystemAreaControlInstanceID() as ID //determine whether the script is in the edit/control instance of the chat system area method _InChatSystemAreaControlInstance() as Boolean //return the apporpriate pool method _GetChatSystemCommandPool(chat_system_command_type as String) as NodeRef of Class //return the apporpriate pool method _GetChatSystemClientCommandPool(chat_system_client_command_type as String) as NodeRef of //return a list of currently running instances in the chat system area method _GetAllInstancesForChatSystemArea() as List of ID // Called from C++ when the area has a chat message to interpret. unique method _AreaGotChat(fromPlayer as ID, message as String, channel as String) // Called from C++ when the world has a chat message to interpret. unique method _WorldGotChat(message as String, channel as String) // Called from C++ when the world has a chat message to interpret. unique method _WorldGotError(message as String, errorType as Enum _ErrorTypes) // Send a chat message to specified client method ChatPlayer(toPlayer as ID, channel as String, message as String) // Send a message to players currently loaded in the area method ChatArea(channel as String, message as String) // Send a message to players loaded in the area and all currently loaded // player reference tokens method ChatAreaAndPlayerReferences( channel as String, message as String ) // Send a message to all currently loaded player reference tokens method ChatPlayerReferences( channel as String, message as String ) // Send a message to a list of clients method ChatList(toPlayers as List of ID, channel as String, message as String) // Send a message to all clients loaded in the current area excluding those in a list method ChatExcludeList(excludedPlayers as List of ID, channel as String, message as String) // Send a message to all clients logged into the world remote method ChatWorld(channel as String, message as String)
//Using a timer, delay the call to the server until client is reliably updated to the chat system area remote method _ChatSystemOnPlayerEnteredArea() //Tick function for the _chatSystemOnPlayerEnteredAreaTimer function _chatSystemOnPlayerEnteredAreaTimer_tick() //Stop the timer and notify the server the client has entered the area method _ChatSystemNotifyServerOnPlayerEnteredArea() //Serialize and forward a _ChatSystemClientCommand noderef to the server method _SendChatSystemCommand( chat_system_client_command as NodeRef of Class _ChatSystemClientCommand) //Return a noderef pointing to the logical chat channel requested via its _chatChannelUniqueIdentifier field. //Create it if the requested Logical Channel doesn't exist method _GetLogicalChatChannel( logical_channel_identifier as String) as NodeRef of Class _LogicalChatChannel //List the channels a user is currently subscribed to within the logical channel map method _GetChatChannelListFromLogicalChatChannel() as List of String //return the apporpriate pool method _GetChatSystemClientCommandPool(chat_system_client_command_type as String) as NodeRef of Class _ChatSystemClientCommandPool //Serialize a _ChatSystemClientCommand object method _SerializeChatSystemClientCommand(chat_system_client_command as NodeRef of Class _ChatSystemClientCommand) as String //Deserialize a _ChatSystemClientCommand object method _DeserializeChatSystemClientCommand(serialized_chat_system_client_command as String, chat_system_client_command as NodeRef of Class _ChatSystemClientCommand, fail_silently as Boolean) unique method _GotChatMessage(chatMessage as String, channelName as String) // Puts chatMessage in HeroBlade's chat panel. unique method _GotChatMessageForHBPanel(chatMessage as String, channelName as String) // Called from HeroBlade's chat panel when ENTER is pressed. (Won't be called for blank lines.) // The in-game chat GUI can use this or not as desired. unique method _ProcessChatInput(chatMessage as String)
//Receive a subscription command and add use the data within to add a user to the channel's replication group method _SubscribeToChatChannelThroughChatSystemCommand( chat_system_command as NodeRef of Class _ChatSystemCommand ) //Remove a user from the replication group of the channel. method _UnsubscribeFromChatChannelThroughChatSystemCommand( chat_system_command as NodeRef of Class _ChatSystemCommand ) //Initialize fields and set up the replication group method _InitChatChannel(unique_channel_identifier as String, channel_display_name as String) //Compare the subscription object password to the password field of the channel method _ValidateChatChannelPassword(subscription_password as String) as Boolean //return the replication group for this channel // Parameters: // create - create the replication group if it does not yet exist? method _getReplicationGroup(create as Boolean) as NodeRef of Class _ReplicationGroup //Destroy self method _Delete() //receive a _ChatSystemCommandMessage method _GotChatChannelMessageThroughChatSystemCommand( chat_system_command as NodeRef of Class _ChatSystemCommand ) //determine whether message sender is allowed to send messages to this channel method _AllowMessageToBeSentOnChatChannel(chat_system_command as NodeRef of Class //shared function called when the channel is created shared function _OnChatChannelCreated( chat_channel as NodeRef of Class _ChatChannel ) //shared function called when the channel is destroyed shared function _OnChatChannelDestroyed( chat_channel as NodeRef of Class _ChatChannel ) //shared function called when a user subscribes to the channel shared function _OnSubscribedToChatChannel( chat_channel as NodeRef of Class _ChatChannel, chat_system_command as NodeRef of Class _ChatSystemCommand) //shared function called when a user unsubscribes from the channel shared function _OnUnsubscribedFromChatChannel( chat_channel as NodeRef of Class _ChatChannel, chat_system_command as NodeRef of Class _ChatSystemCommand ) //shared function called when a user sends a message to the channel shared function _OnReceivedChatMessage( chat_channel as NodeRef of Class _ChatChannel, chat_system_command as NodeRef of Class _ChatSystemCommand)
// As each node is added by replication, a callback is made to the primary node notifying it that a new node // has arrived with its initial set data. method _OnReplicationNodeAdded(addedNode as NodeRef) //Called when all of the nodes that are part of the replication group have been added. At this point, all nodes are present //with those of their fields marked "Initial Set" set to the replicated values method _OnReplicationGroupAdded() //Return a noderef to the _LogicalChatChannel associated with this _ChatChannel method _GetMyLogicalChatChannel() as NodeRef of Class _LogicalChatChannel // Called when fields whose Client Callback propery was set to YES are updated shared function _OnReplicationFieldUpdated(update_node as NodeRef, update_field as String) //Tell the logical channel to unsubscribe itself from this channels replicaiton events method _OnReplicationNodeRelease(releasedNode as NodeRef) as Boolean // Only important there are fields that are reference frame adjusted for seamless world as a part of this class, which there are not method _OnReplicationGroupRehomed(oldArea as ID, oldInstance as ID, oldOffset as Vector3, //SpecOracle method method getMySpecOracle() as NodeRef of Class SpecOracle //Receives the corresponding _ChatChannel spec from the server and subscribes //the channel to the appropriate logical channel based on the logicalChannelIdentifier //field within the spec method EventRaised( obs as NodeRef of Class ObsSubject, data as NodeRef )
//Notify listeners of a subscribed event method _SubscribeToChatChannel( chat_channel as NodeRef ) //Notify listeners of an unsubscribed event method _UnsubscribeFromChatChannel( chat_channel as NodeRef ) //Notify listeners of a got-message event method _GotChatChannelMessage( chat_message as NodeRef of Class _ChatSystemClientCommandMessage ) //Set the display name field for the logical channel method _SetChatChannelDisplayName(display_name as String) //Destroy self method _Delete() //event signature define method _GotChatChannelSubscription(chat_channel as NodeRef) //event signature define method _GotChatChannelUnsubscription(chat_channel as NodeRef)
//Allocate n _ChatPoolObjects and put them in the pool method _CreateChatPoolObjects(object_type as String, how_many as Integer) //Add an object to the back of the pool method _PutChatPoolObject(chat_object as NodeRef of Class _ChatPoolObject) //Return a _ChatPoolObject and remove it from the pool method _GetChatPoolObject() as NodeRef of Class _ChatPoolObject //Return the starting pool size method _GetDefaultChatObjectPoolSize() as Integer //Return the number of allocated objects in this pool method _GetChatObjectCount() as Integer //set the pool object type //the object type must be set before any objects can be created within the pool method _SetChatObjectType(object_type as String) //return the maximum size the pool can achieve at any given time method _GetMaximumChatObjectPoolSize() as Integer //return the maximum number of objects which can be created by this pool method _GetChatObjectCreationLimit() as Integer
_chatChannelUniqueIdentifier - StringAlmost every structure in the Chat System has this field. It is the string value which represents the identification of a specific channel. Message noderefs use it as a destination, Subscriptions use it as a search parameter, Logical Channels use it to identify individual channels with which they are associated.
_chatChannelSubscriberID - ID _chatChannelUnsubscriberID - ID _chatChannelMessageSenderID - IDThe GUID of the user or node making the request. These are necessary for callbacks to the subscriber from the chat channels receiving the request and to later acquire more information about that subscriber.
_chatChannelSubscriptionPassword - StringA string password field in the base _ChatChannel class.
_chatChannelSubscriberCount - IntegerAn integer counter used to keep track of how many subscribers are currently in a channel. If the subscriber count is zero and someone is attempting to subscribe to it, the channel has just been created. This is how the channel knows when to set its password field.
_chatChannelMessageID - IntegerA counter used in an Atomic Set on the _DebugChatChannel in order to ensure that even duplicate messages are replicated to all subscribers.
_chatChannelDisplayName - StringThe string name of a channel which will be visible to users through a GUI.
_chatChannelMap - Lookuplist indexed by String of IDA LookupList for all Chat Channels in a given Chat System Instance. This is used to find a channel, if it exists. A channel is added to the LookupList, when it is created and removed when it is destroyed.
_chatSystemCommandPool - NodeRef of Class _ChatSystemCommandPool _chatSystemClientCommandPool - NodeRef of Class _ChatSystemClientCommandPoolPool fields stored on the Chat System Nodes, referenced so that pools do not have to be created every time _chatPoolObjects are needed.
_chatSystemCommandPoolMap - LookupList indexed by String of NodeRef of Class _ChatSystemCommandPool _chatSystemClientCommandPoolMap - LookupList indexed by String of NodeRef of Class _ChatSystemClientCommandPoolSince various types of requests may pass through the system nodes(e.g. _DebugChatMessages and GuildChatMessages), LookupLists of pools are maintained as fields in the system nodes and referenced whenever a specific _ChatPoolItem is required.
method _GetDefaultChatSystemAreaInstanceCount() as IntegerWill return the number of Chat System Area Instances spun up at world-load time.
method _GetMaximumChatSystemAreaInstanceCount() as IntegerWill return the maximum number of Chat System Area Instances which can be spun up at any given time.
method _GetDefaultPoolSize() as IntegerWill return the default pool size for a _ChatObjectPool. This is set to 4 by default.