HeroEngine Forums
Welcome, Guest. Please login or Register for HeroCloud Account.
Pages: 1 [2]

Author Topic: Chat System Assistance  (Read 5987 times)

keeperofstars

  • General Accounts
  • *
  • Posts: 998
    • View Profile
    • StarKeeper Online
Re: Chat System Assistance
« Reply #15 on: May 28, 13, 12:37:35 AM »

ok, so with Jrome's help.

Used this function

shared function _OnReplicationFieldUpdated(update_node as NodeRef, update_field as String)

to get the replicationFieldUpdates, and am now getting the channels to print out to the HBchatPanel now just a matter of redirecting that to my gui chat window.

Once I get that working and things cleaned up a bunch. I will work on a tutorial for using the system.

Tonight had the missing piece for me and that was how to manage multiple subscriptions to like guild chat that needed to have unique channel ids for each guild. Figured that piece out tonight and now just need to pull it all together.

Logged
[img]http://screencast.com/t/x7btcSSyp3h0[\img]

FI-ScottZ

  • General Accounts
  • *
  • Posts: 1407
    • View Profile
    • Forever Interactive, Inc.
Re: Chat System Assistance
« Reply #16 on: May 28, 13, 12:38:50 PM »

The reason there are two copies of each channel is that each Chat System Instance replicates each chat channel to the subscribers.  There is always the Chat Edit Instance, known as the Control Instance, then at least one other instance.

At the start, that is all you have: two instances, hence two copies of each chat channel on your client.  Recall, though, that the client doesn't need to deal with the chat channel nodes themselves directly.  They are grouped into a logical chat channel, which is the single interface through which to deal with the channel.

The _LogicalChatChannel class has a method _GotChatChannelMessage(), which will in turn call that on any nodes which are listening to it (e.g. gui controls) as well as pass it along to the heroblade chat panel if you are in HeroBlade.   As mentioned, what is missing is the call to _GotChatChannelMessage on the logical chat channel itself.  I believe that is what is meant to go in shared function _OnReplicationFieldUpdated() of the chat channel class.

That way, when any of those chat channels on your client receive a field update (which happens from server chat channels setting _chatChannelMessageID and the rest), they find their logical chat channel and call _GotChatChannelMessage(), going on from there to any listeners.

Bottomline is that then any listeners, such as a guicontrol, only need to listen to one node, the logical chat channel, to get notifications of the channel no matter which Chat System instance it came from or which client-side chat channel received it.
Logged
Scott Zarnke
Lead Programmer, Visions of Zosimos
CTO, Forever Interactive, Inc.

FI-ScottZ

  • General Accounts
  • *
  • Posts: 1407
    • View Profile
    • Forever Interactive, Inc.
Re: Chat System Assistance
« Reply #17 on: May 28, 13, 12:57:03 PM »

As far as the $CHAT._logicalChatChannelMap not removing the slot when unsubscribing I believe this is it:

The logical chat channels are created in $CHAT._GetLogicalChatChannel() when the desired channel does not yet exist.  Upon creation, it sets me._logicalChatChannelMap[ logical_channel_identifier ] = logicalChannel.

Later, when unsubscribing, _UnsubscribeFromChatChannel is called on the logical channel from the chat channel _OnReplicationNodeRelease() method.  In _UnsubscribeFromChatChannel, if the channel has no listeners it deletes itself, but it does not clean up the _logicalChatChannelMap.  That leaves the slot in there, and the next time _GetLogicalChatChannel() is called, such as in _GetChatChannelListFromLogicalChatChannel(), it sees that the node is not valid and recreates it.

So, it would seem that in method _Delete() of the logical channel, the code calling destroyNode( me ) should be replaced by something like this:
Code: [Select]
  //delete
  if $CHAT._logicalChatChannelMap has me._logicalChatChannelIdentifier
    remove me._logicalChatChannelIdentifier from $CHAT._logicalChatChannelMap destroy
  else
    destroyNode( me )
  .
Then it is removed from the list and destroyed.  If, for some odd reason it was not in the list, then it just destroys itself normally.
Logged
Scott Zarnke
Lead Programmer, Visions of Zosimos
CTO, Forever Interactive, Inc.

FI-ScottZ

  • General Accounts
  • *
  • Posts: 1407
    • View Profile
    • Forever Interactive, Inc.
Re: Chat System Assistance
« Reply #18 on: May 28, 13, 01:17:06 PM »

Here's something else about why there were multiple debug chat channel pairs, a new one created for each call to subscribe:

A search on the server for "._chatChannelSpecKey = " shows that it is always being set using either $CHAT._GetDefaultChatChannelSpecKey(), $CHAT._GetAreaChatChannelSpecKey(), or $CHAT._GetWorldChatChannelSpecKey().  For our own subscribe calls (whether from the client directly or the server via /hechat subscribe) it uses $CHAT._GetDefaultChatChannelSpecKey(), which if not overridden uses _ChatChannelSpec2.  The logical chat identifier in the spec determines which logical chat channel the chat channels get added to.

Since all of our subscribes are using the debug spec (_ChatChannelSpec2), all of our channels go in the debug logical chat channel.  Which I think is sort of a problem, since the code seems to be mostly set up expecting only one named channel per logical channel, though I could be wrong on that.

And, unfortunately, the override method,
Code: [Select]
method HE_GetDefaultChatChannelSpecKey() as Boolean
  //Used by _ChatHandler ($CHAT system node)
  return false
.
Provides no mechanism for supplying a different key.  I have noticed many such overrides that can't actually do anything, including HE_CreateChatChannel().  Overriding that one would be nice so we could call chat_channel._InitChatChannel() to specify a Display Name.  Also, _InitChatChannel() is the only place that _OnChatChannelCreated() gets called and as of now _InitChatChannel() is not being called anywhere.
Logged
Scott Zarnke
Lead Programmer, Visions of Zosimos
CTO, Forever Interactive, Inc.

FI-ScottZ

  • General Accounts
  • *
  • Posts: 1407
    • View Profile
    • Forever Interactive, Inc.
Re: Chat System Assistance
« Reply #19 on: May 30, 13, 04:28:11 PM »

Here is a question for the IF engineers:

Looking at how _DebugChatChannel handles _GotChatChannelMessageThroughChatSystemCommand() I see that it sets 4 fields on itself, all of which are set to replicate to clients:
  • _chatChannelMessageID
  • _chatChannelMessageSenderName
  • _chatChannelMessage
  • _chatChannelMessageSenderID

So then to process that, the client side version of _DebugChatChannel would need to have something like this:

Code: [Select]
//-------------------------------------------------------------------------------
// Called when fields whose Client Callback propery was set to YES are updated
shared function _OnReplicationFieldUpdated(update_node as NodeRef, update_field as String)
  channel as NodeRef of Class _DebugChatChannel = update_node
 
  var commandPool = $CHAT._GetChatSystemClientCommandPool( "_ChatSystemClientCommandMessageText" )
  chat_message as NodeRef of Class _ChatSystemClientCommandMessageText = commandPool._GetChatPoolObject()
 
  chat_message._chatChannelUniqueIdentifier   = channel._chatChannelUniqueIdentifier
  chat_message._chatChannelMessageSenderName  = channel._chatChannelMessageSenderName
  chat_message._chatChannelMessage            = channel._chatChannelMessage
  chat_message._chatChannelMessageSenderID    = channel._chatChannelMessageSenderID

  channel._GetMyLogicalChatChannel()._GotChatChannelMessage(chat_message)
 
  //Release the pool object:
  commandPool._PutChatPoolObject(chat_message)
.

Which should work.  But since all 4 fields are replicated, will this change function be called 4 times?

And if so, how do we know when all fields have been received if we are not sure of the order they will be received?

***EDIT: So a little experimentation revealed this:  any of those four fields which are changed will replicate, so the replication function could be called up to four times per message.  But if any of the fields are not changed, they don't replicate. So if the same client sends the same message, then the only field that changes is the message ID.  It is different for each message, so it always replicates and thus is the field to respond to.

As far as the timing, they appeared to be received in the order that they are set on the server, but I don't know if that is guaranteed to always be the case.

This means it will be best for the server to always set the message ID last.  Otherwise, since the client is going based on that ID getting updated, if another field was updated after it then the message sent to the logical channel will get that field out-of-date.

***EDIT 2: The standard 4 fields that are changed are marked as Discrete, which means they will always replicate even if set to the same value, which is good. The order received does seem to be consistent with the order they were set, though I found that for a field I added to the channel it was not being received before the ID even though it was set before it.  I noticed that I had not set the field to Discrete and setting that field to true seemed to do the trick.

So, it appears that for any such field you wish to have replicated for a channel message, have it set to Discrete.



Also, since method  _GotChatChannelMessage needs to receive a NodeRef of Class _ChatSystemClientCommandMessage, I assumed that I should use the Pool to get one.  But then I am uncertain when it should be released.  If I do it right away in this function, it becomes available and might be reused while listeners are still using it.

So, count on listeners to release it?  Even if I create a new node in this function, it still remains of when to destroy it.

Maybe since the listeners only need to read data, they could be sent a copy of a Class object instead of a nodeRef.  Then there is no worry of releasing it.

Thanks.
« Last Edit: Jun 23, 13, 03:01:44 PM by ScottZarnke »
Logged
Scott Zarnke
Lead Programmer, Visions of Zosimos
CTO, Forever Interactive, Inc.

keeperofstars

  • General Accounts
  • *
  • Posts: 998
    • View Profile
    • StarKeeper Online
Re: Chat System Assistance
« Reply #20 on: May 31, 13, 02:13:12 AM »

Scott you are correct with the order of the fields being updated playing a key role / issue.

For the default specs of World and Area, the messageID is updated first. This means the message goes out before it's updated to the client. So when the player types a message the first time it's empty, the 2nd time it's the first message they typed. Been running into this issue since I got other parts worked out last night.

You can use when update_field
is ("field name") to isolate the replication call backs to just one field, ideally when the messageID changes but that doesn't work well cause it's updated first, so need to make sure it gets updated last on the server. Then using the is("messageID") can "hold" the message till all the other fields replicate and then get pushed out. Key though is messageID has to be the last thing replicated.

If you set it to update on message change that works great, but won't let the player repeat the same message.


I've been working on trying to get my own chatChannelSpecs and classes to work properly, so I can override them and try to make sure the messageID gets increased last, and thus replicated last, or so we hope.

I have everything setup how it appears it needs to be, but the client never initalizes the node on the client side, so it doesn't work when I set the specKeyID, it some how still gets the debugChannelSpecKeyID.


Logged
[img]http://screencast.com/t/x7btcSSyp3h0[\img]

FI-ScottZ

  • General Accounts
  • *
  • Posts: 1407
    • View Profile
    • Forever Interactive, Inc.
Re: Chat System Assistance
« Reply #21 on: May 31, 13, 04:04:45 AM »

Quote
it doesn't work when I set the specKeyID
Where in the code are you setting the key?
Logged
Scott Zarnke
Lead Programmer, Visions of Zosimos
CTO, Forever Interactive, Inc.

keeperofstars

  • General Accounts
  • *
  • Posts: 998
    • View Profile
    • StarKeeper Online
Re: Chat System Assistance
« Reply #22 on: Jun 01, 13, 02:04:23 PM »

if you subscribe using the server side you can set.
_chatChannelSpecKey by default uses $Chat._GetDefaultChatChannelSpecKey() but this returns the debug channel spec

but you can set it to any ID and it will work. In the below script I pass it the SpecKey I want to use, which gets determined by the client code making the call to the subscribe script. Down the road I will probably override the default server chatHandler to add in other options to the _GetDefaultChatChannelSpecKey() to include them for my own channels, then just use the channel being passed down to set which _get it uses. But want to get rest working before I add that.

Code: [Select]
untrusted remote method skd_subscribeToChannel(channel as String, channelSpecKey as ID, password as String, playerCharacter as String)
  if channel <> ""
    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._chatChannelSpecKey = channelSpecKey
    subscribe_command._chatChannelSubscriberID = playerCharacter
 
    MsgPlayer(playerCharacter,"","System.Info.PlayerCharacter is: " + channelSpecKey )
   // println("System.Info.PlayerCharacter is: " + playerSubscriberID )  //SYSTEM.INFO.PLAYERCHARACTER
    subscribe_command._chatChannelUniqueIdentifier = channel
    subscribe_command._chatChannelSubscriptionPassword = password     
    //println("skd_Chat:skd_subscribeToChannel subscribe_command is: " + subscribe_command)
   
    MsgPLayer(playerCharacter,"","skd_Chat:skd_subscribeToChannel subscribe_command is: " + subscribe_command._chatChannelUniqueIdentifier + " Subscribe.command._chatChannelSubscriberID is: " + subscribe_command._chatChannelSubscriberID )
    $CHAT._SendChatSystemCommand( subscribe_command )
  .   
.
Logged
[img]http://screencast.com/t/x7btcSSyp3h0[\img]

FI-ScottZ

  • General Accounts
  • *
  • Posts: 1407
    • View Profile
    • Forever Interactive, Inc.
Re: Chat System Assistance
« Reply #23 on: Jun 01, 13, 03:28:46 PM »

Keeper,
I see.  So you have the spec key being specified in the command to subscibe?

What I have ended up doing is defining a method in our chat handler class that looks through the chat channel specs for one whose logical identifier matches (case-insensitive) the channel they are subscribing to and returns that spec key, else the debug one:
Code: [Select]
//Looks for a spec with the same logical name as the supplied channel name.
//If found, returns that key, else returns the debug channel key so as to be the default.
method GetSpecKeyForLogicalChannelName(chatChannelUniqueIdentifier as String) as ID
  var channelName = ToLower(chatChannelUniqueIdentifier)
  var oracle = $SPECORACLEUTILS._GetOracleFromType( "_ChatChannelSpecOracle" )
  spec as NodeRef of Class _ChatChannelSpec
  debugSpecKey as ID
  foreach specKey in oracle.SpecKeyMap
    spec = GetPrototypeByID(oracle.SpecKeyMap[specKey])
    if spec._specIsDeleted
      continue
    .
    if ToLower(spec._logicalChatChannelIdentifier) == channelName
      return specKey
    else if spec._logicalChatChannelIdentifier == "debug"
      debugSpecKey = specKey
    .
  .
  return debugSpecKey
.

Then in our HE_ProcessChatSlashCommandInput() method we handle the "subscribe" command and use
Code: [Select]
command._chatChannelSpecKey = $CHAT.GetSpecKeyForLogicalChannelName(args[3])to set the key, which covers subscribing via /hechat command.

Also, for HE_CreateChatChannel, we changed its signature to:
Code: [Select]
method HE_CreateChatChannel( chat_system_command as NodeRef of Class _ChatSystemCommand, chat_channel references NodeRef of Class _ChatChannel ) as Booleanadding the channel ref argument so we can actually set that ourselves and changed method _CreateChatChannel() so that if the HE_ method sets the channel, then the default code is skipped.

Finally, we used the GetSpecKeyForLogicalChannelName method in HE_CreateChatChannel to choose the spec key.
Code: [Select]
channel_spec as NodeRef of Class _ChatChannelSpec = oracle.GetSpecByKey($CHAT.GetSpecKeyForLogicalChannelName(chat_system_command._GetChatSystemCommandChatChannelUniqueIdentifier()))***EDIT: Changed the argument for GetSpecKeyForLogicalChannelName from using the chat_command (which doesn't exist, yet) to use instead the chat_system_command.

That covers subscribing from the client via _ChatSystemClientCommandSubscribe.
« Last Edit: Jun 01, 13, 05:37:13 PM by ScottZarnke »
Logged
Scott Zarnke
Lead Programmer, Visions of Zosimos
CTO, Forever Interactive, Inc.

FI-ScottZ

  • General Accounts
  • *
  • Posts: 1407
    • View Profile
    • Forever Interactive, Inc.
Re: Chat System Assistance
« Reply #24 on: Jun 01, 13, 03:45:01 PM »

Here is another question for the engineers that know better how the system is supposed to work:

In server _ChatHandler method _CreateChatChannel, the new channel is added to _chatChannelMap and an association is added.  Yet, in method _RemoveChatChannelFromRegistration it only removes it from _chatChannelMap.  Should it also be removing the association?
« Last Edit: Jun 01, 13, 05:37:37 PM by ScottZarnke »
Logged
Scott Zarnke
Lead Programmer, Visions of Zosimos
CTO, Forever Interactive, Inc.

keeperofstars

  • General Accounts
  • *
  • Posts: 998
    • View Profile
    • StarKeeper Online
Re: Chat System Assistance
« Reply #25 on: Jun 01, 13, 06:46:59 PM »

for now I am just subscribing via server side,

but like how you guys did it to add to the client sides ability to subscribe to different spec than the debug.
Also resolves the issue of hard coding an ID.

I orginally built it server side cause that is how the wiki stated it was required, now that I got them to update the wiki a bit, it's helping me shift things back to the client.
 
Logged
[img]http://screencast.com/t/x7btcSSyp3h0[\img]

keeperofstars

  • General Accounts
  • *
  • Posts: 998
    • View Profile
    • StarKeeper Online
Re: Chat System Assistance
« Reply #26 on: Jun 02, 13, 12:31:40 AM »

just update on chat replication order.

found if on the your server side script for the chatchannel you set me._chatChannelMessageID to set / update last,
Code: [Select]
//assign message fields to the chat channel replication fields
      me._chatChannelMessageSenderName  = $WORLD._GetCharacterName(chat_system_command._chatChannelMessageSenderID)
      me._chatChannelMessage            = chat_system_command._chatChannelMessage
      me._chatChannelMessageSenderID    = chat_system_command._chatChannelMessageSenderID
      me._chatChannelMessageID          = me._chatChannelMessageID + 1

Then in your client side chat class, for _OnReplicationFieldUpdated you check for when update_field is "_chatChannelMessageID" it should only fire the _GotChatChannelMessage command once all the fields are updated.

Code: [Select]
shared function _OnReplicationFieldUpdated(update_node as NodeRef, update_field as String)
            println(update_field)
     
      when update_field
        is "_chatChannelMessageID"
          println("Replication via LFGChat Happened")
          chatChannel as NodeRef of Class _DebugChatChannel = update_node
          logicalChannel as NodeRef of Class _LogicalChatChannel = chatChannel._GetMyLogicalChatChannel()
       
          message_command_pool as NodeRef of Class _ChatSystemClientCommandPool = $CHAT._GetChatSystemClientCommandPool( "_ChatSystemClientCommandMessageText" )
          message_command as NodeRef of Class _ChatSystemClientCommandMessageText = message_command_pool._GetChatPoolObject()
       
          message_command._chatChannelMessage = chatChannel._chatChannelMessage
          message_command._chatChannelMessageSenderName = chatChannel._chatChannelMessageSenderName
          message_command._chatChannelUniqueIdentifier = chatChannel._chatChannelUniqueIdentifier
       
          logicalChannel._GotChatChannelMessage(message_command)
          message_command_pool._PutChatPoolObject(message_command)
        .
      .
    .

Do note though that by default World, Area, and Debug channels set the messageID +1 first, and that causes problems, as the messageID fires the Gotmessage, before the new message is replicated, so the players chat messages are always lagging behind one message.
Logged
[img]http://screencast.com/t/x7btcSSyp3h0[\img]

FI-ScottZ

  • General Accounts
  • *
  • Posts: 1407
    • View Profile
    • Forever Interactive, Inc.
Re: Chat System Assistance
« Reply #27 on: Jun 02, 13, 08:55:16 AM »

Quote
World, Area, and Debug channels set the messageID +1 first
Yeah, I just went ahead and changed the Clean Engine code and made note of it.  Hopefully that will go in a future update.
Logged
Scott Zarnke
Lead Programmer, Visions of Zosimos
CTO, Forever Interactive, Inc.

FI-ScottZ

  • General Accounts
  • *
  • Posts: 1407
    • View Profile
    • Forever Interactive, Inc.
Re: Chat System Assistance
« Reply #28 on: Jun 21, 13, 10:47:12 AM »

Quote
In server _ChatHandler method _CreateChatChannel, the new channel is added to _chatChannelMap and an association is added.  Yet, in method _RemoveChatChannelFromRegistration it only removes it from _chatChannelMap.  Should it also be removing the association?

I see why the removal of the association was not put in: for the Clean Engine code, _RemoveChatChannelFromRegistration is only called when a channel is being deleted.  The destruction of the channel node will automatically remove any associations it is part of.

To be thorough, _RemoveChatChannelFromRegistration could remove the association in case it were ever called without destroying the channel, but there does not seem to be any reason to do that right now.
Logged
Scott Zarnke
Lead Programmer, Visions of Zosimos
CTO, Forever Interactive, Inc.
Pages: 1 [2]