class MessengerUtils { public static function GetCallableAndNonEmptyContacts( journal : JournalManager ) : array< IScriptable > { var i : Int32; var contact : ContactData; var contacts : array< IScriptable >; contacts = journal.GetContactDataArray( false, true ); for( i = contacts.Size() - 1; i >= 0; i -= 1 ) { contact = ( ( ContactData )( contacts[ i ] ) ); if( contact == NULL ) { continue; } if( ( !( contact.isCallable ) && ( contact.messagesCount == 0 ) ) && ( contact.repliesCount == 0 ) ) { contacts.Erase( i ); } } return contacts; } public static function GetSimpleContactDataArray( journal : JournalManager, includeUnknown : Bool, skipEmpty : Bool, includeWithNoUnread : Bool, optional activeDataSync : weak< MessengerContactSyncData > ) : array< IScriptable > { var i : Int32; var context : JournalRequestContext; var entries : array< weak< JournalEntry > >; var contactEntry : weak< JournalContact >; var trackedEntriesHashList : array< Int32 >; var contactDataArray : array< IScriptable >; context.stateFilter.active = true; journal.GetContacts( context, entries ); trackedEntriesHashList = FetchTrackedQuestCodexLinks( journal, context ); for( i = 0; i < entries.Size(); i += 1 ) { contactEntry = ( ( JournalContact )( entries[ i ] ) ); AddContactData( journal, contactDataArray, contactEntry, trackedEntriesHashList, includeUnknown, skipEmpty, includeWithNoUnread, false, activeDataSync ); } return contactDataArray; } public static function GetMessageDataArrayForContact( journal : JournalManager, concactHash : Int32, includeUnknown : Bool, skipEmpty : Bool, optional activeDataSync : weak< MessengerContactSyncData > ) : array< IScriptable > { var context : JournalRequestContext; var contactEntry : weak< JournalContact >; var contactDataArray : array< IScriptable >; var trackedEntriesHashList : array< Int32 >; context.stateFilter.active = true; contactEntry = ( ( JournalContact )( journal.GetEntry( ( ( Uint32 )( concactHash ) ) ) ) ); if( contactEntry == NULL ) { return contactDataArray; } trackedEntriesHashList = FetchTrackedQuestCodexLinks( journal, context ); AddContactData( journal, contactDataArray, contactEntry, trackedEntriesHashList, includeUnknown, skipEmpty, true, true, activeDataSync ); return contactDataArray; } private static function AddContactData( journal : JournalManager, contactDataArray : ref< array< IScriptable > >, contactEntry : JournalContact, const trackedEntriesHashList : ref< array< Int32 > >, includeUnknown : Bool, skipEmpty : Bool, includeWithNoUnread : Bool, includeWithNoReplies : Bool, optional activeDataSync : weak< MessengerContactSyncData > ) { var j, conversationsCount : Int32; var messagesReceived : array< weak< JournalEntry > >; var playerReplies : array< weak< JournalEntry > >; var conversations : array< weak< JournalEntry > >; var conversationEntry : weak< JournalPhoneConversation >; var singleThreadData : ContactData; var multiThreadData : ContactData; if( includeUnknown || contactEntry.IsKnown( journal ) ) { messagesReceived.Clear(); playerReplies.Clear(); journal.GetConversations( contactEntry, conversations ); journal.GetFlattenedMessagesAndChoices( contactEntry, messagesReceived, playerReplies ); if( ( skipEmpty && ( messagesReceived.Size() <= 0 ) ) && ( playerReplies.Size() <= 0 ) ) { return; } conversationsCount = conversations.Size(); if( conversationsCount > 1 ) { for( j = 0; j < conversationsCount; j += 1 ) { messagesReceived.Clear(); playerReplies.Clear(); conversationEntry = ( ( JournalPhoneConversation )( conversations[ j ] ) ); journal.GetMessagesAndChoices( conversationEntry, messagesReceived, playerReplies ); multiThreadData = new ContactData; multiThreadData.id = conversationEntry.GetId(); multiThreadData.hash = journal.GetEntryHash( contactEntry ); multiThreadData.conversationHash = journal.GetEntryHash( conversationEntry ); multiThreadData.localizedName = contactEntry.GetLocalizedName( journal ); multiThreadData.avatarID = contactEntry.GetAvatarID( journal ); multiThreadData.activeDataSync = activeDataSync; multiThreadData.type = MessengerContactType.MultiThread; multiThreadData.isCallable = contactEntry.IsCallable( journal ); multiThreadData.contactId = contactEntry.GetId(); SetTitle( multiThreadData, conversationEntry ); GetContactMessageData( multiThreadData, journal, messagesReceived, playerReplies ); SetTimestamp( multiThreadData, journal, messagesReceived, conversationEntry ); multiThreadData.questRelated = ContainsQuestRelatedMessage( journal, trackedEntriesHashList, messagesReceived ); if( includeWithNoUnread || ( multiThreadData.unreadMessages.Size() > 0 ) ) { contactDataArray.PushBack( multiThreadData ); } else if( ( includeWithNoReplies || multiThreadData.hasQuestImportantReply ) || multiThreadData.playerCanReply ) { contactDataArray.PushBack( multiThreadData ); } } } else { conversationEntry = ( ( JournalPhoneConversation )( ( ( conversationsCount == 1 ) ? ( conversations[ 0 ] ) : ( NULL ) ) ) ); singleThreadData = new ContactData; singleThreadData.id = contactEntry.GetId(); singleThreadData.hash = journal.GetEntryHash( contactEntry ); singleThreadData.conversationHash = GetConversationHash( journal, conversationEntry ); singleThreadData.localizedName = contactEntry.GetLocalizedName( journal ); singleThreadData.avatarID = contactEntry.GetAvatarID( journal ); singleThreadData.activeDataSync = activeDataSync; singleThreadData.type = MessengerContactType.SingleThread; singleThreadData.isCallable = contactEntry.IsCallable( journal ); singleThreadData.contactId = contactEntry.GetId(); SetTitle( singleThreadData, conversationEntry ); GetContactMessageData( singleThreadData, journal, messagesReceived, playerReplies ); SetTimestamp( singleThreadData, journal, messagesReceived, conversationEntry ); singleThreadData.questRelated = ContainsQuestRelatedMessage( journal, trackedEntriesHashList, messagesReceived ); if( includeWithNoUnread || ( singleThreadData.unreadMessages.Size() > 0 ) ) { contactDataArray.PushBack( singleThreadData ); } else if( ( includeWithNoReplies || singleThreadData.hasQuestImportantReply ) || singleThreadData.playerCanReply ) { contactDataArray.PushBack( singleThreadData ); } } } } private static function GetConversationHash( journal : JournalManager, conversationEntry : weak< JournalPhoneConversation > ) : Int32 { if( conversationEntry ) { return journal.GetEntryHash( conversationEntry ); } return 0; } private static function SetTitle( out contactData : ContactData, conversationEntry : weak< JournalPhoneConversation > ) { var localizedPreview : String; localizedPreview = conversationEntry.GetTitle(); if( IsStringValid( localizedPreview ) ) { contactData.hasValidTitle = true; contactData.localizedPreview = localizedPreview; } else { contactData.hasValidTitle = false; } } private static function SetTimestamp( out contactData : ContactData, journal : JournalManager, const messagesReceived : ref< array< weak< JournalEntry > > >, const conversationEntry : weak< JournalPhoneConversation > ) { if( messagesReceived.Size() > 0 ) { contactData.timeStamp = journal.GetEntryTimestamp( messagesReceived.Last() ); } else if( conversationEntry ) { contactData.timeStamp = journal.GetEntryTimestamp( conversationEntry ); } } public static function GetContactMessageData( out contactData : ContactData, journal : JournalManager, const messagesReceived : ref< array< weak< JournalEntry > > >, const playerReplies : ref< array< weak< JournalEntry > > > ) { var lastMessegeRecived : weak< JournalPhoneMessage >; var lastMessegeSent : weak< JournalPhoneChoiceEntry >; var choiceEntry : weak< JournalPhoneChoiceEntry >; var j : Int32; contactData.playerCanReply = playerReplies.Size() > 0; contactData.unreadMessages.Clear(); for( j = 0; j < messagesReceived.Size(); j += 1 ) { if( !( journal.IsEntryVisited( messagesReceived[ j ] ) ) ) { contactData.unreadMessages.PushBack( journal.GetEntryHash( messagesReceived[ j ] ) ); } } if( messagesReceived.Size() > 0 ) { lastMessegeRecived = ( ( JournalPhoneMessage )( messagesReceived.Last() ) ); if( lastMessegeRecived ) { contactData.lastMesssagePreview = lastMessegeRecived.GetText(); contactData.playerIsLastSender = false; } else { lastMessegeSent = ( ( JournalPhoneChoiceEntry )( messagesReceived.Last() ) ); contactData.lastMesssagePreview = lastMessegeSent.GetText(); contactData.playerIsLastSender = true; } } for( j = 0; j < playerReplies.Size(); j += 1 ) { choiceEntry = ( ( JournalPhoneChoiceEntry )( playerReplies[ j ] ) ); if( choiceEntry.IsQuestImportant() ) { contactData.hasQuestImportantReply = true; break; } } } public static function RefreshQuestRelatedStatus( out contactData : ContactData, journal : JournalManager, const messagesReceived : ref< array< weak< JournalEntry > > > ) { var context : JournalRequestContext; var trackedEntriesHashList : array< Int32 >; context.stateFilter.active = true; trackedEntriesHashList = FetchTrackedQuestCodexLinks( journal, context ); contactData.questRelated = ContainsQuestRelatedMessage( journal, trackedEntriesHashList, messagesReceived ); } public static function ContainsQuestRelatedMessage( journal : JournalManager, const trackedEntriesHashList : ref< array< Int32 > >, const messagesReceived : ref< array< weak< JournalEntry > > > ) : Bool { var j : Int32; var hash : Int32; for( j = 0; j < messagesReceived.Size(); j += 1 ) { hash = journal.GetEntryHash( messagesReceived[ j ] ); if( trackedEntriesHashList.Contains( hash ) ) { return true; } } return false; } public constexpr static function HasPhoneObjective( journal : JournalManager ) : Bool { return false; } public static function HasQuestImportantCalls( journal : JournalManager ) : Bool { var context : JournalRequestContext; var entries : array< weak< JournalEntry > >; var i : Int32; var contactEntry : weak< JournalContact >; var hash : Int32; var trackedChildEntriesHashList : array< Int32 >; context.stateFilter.active = true; trackedChildEntriesHashList = FetchTrackedQuestCodexLinks( journal, context ); if( trackedChildEntriesHashList.Size() == 0 ) { return false; } journal.GetContacts( context, entries ); for( i = 0; i < entries.Size(); i += 1 ) { contactEntry = ( ( JournalContact )( entries[ i ] ) ); if( contactEntry ) { if( !( contactEntry.IsCallable( journal ) ) || !( contactEntry.IsKnown( journal ) ) ) { continue; } hash = journal.GetEntryHash( contactEntry ); if( trackedChildEntriesHashList.Contains( hash ) ) { return true; } } } return false; } public static function HasQuestImportantMessages( journal : JournalManager ) : Bool { var context : JournalRequestContext; var entries : array< weak< JournalEntry > >; var trackedEntriesHashList : array< Int32 >; var contactEntry : weak< JournalContact >; var i : Int32; var messagesReceived : array< weak< JournalEntry > >; var playerReplies : array< weak< JournalEntry > >; context.stateFilter.active = true; trackedEntriesHashList = FetchTrackedQuestCodexLinks( journal, context ); if( trackedEntriesHashList.Size() == 0 ) { return false; } journal.GetContacts( context, entries ); for( i = 0; i < entries.Size(); i += 1 ) { contactEntry = ( ( JournalContact )( entries[ i ] ) ); if( contactEntry && contactEntry.IsKnown( journal ) ) { messagesReceived.Clear(); playerReplies.Clear(); journal.GetFlattenedMessagesAndChoices( contactEntry, messagesReceived, playerReplies ); if( ContainsQuestRelatedMessage( journal, trackedEntriesHashList, messagesReceived ) ) { return true; } } } return false; } public static function FetchTrackedQuestCodexLinks( journal : JournalManager, context : JournalRequestContext ) : array< Int32 > { var trackedObjective : JournalQuestObjective; var trackedChildEntriesList : array< weak< JournalEntry > >; var trackedChildEntry : weak< JournalQuestCodexLink >; var trackedChildEntriesCount : Int32; var j : Int32; var trackedChildEntriesHashList : array< Int32 >; trackedObjective = ( ( JournalQuestObjective )( journal.GetTrackedEntry() ) ); if( trackedObjective != NULL ) { journal.GetChildren( trackedObjective, context.stateFilter, trackedChildEntriesList ); trackedChildEntriesCount = trackedChildEntriesList.Size(); for( j = 0; j < trackedChildEntriesCount; j = j + 1 ) { trackedChildEntry = ( ( JournalQuestCodexLink )( trackedChildEntriesList[ j ] ) ); if( trackedChildEntry ) { trackedChildEntriesHashList.PushBack( ( ( Int32 )( trackedChildEntry.GetLinkPathHash() ) ) ); } } } return trackedChildEntriesHashList; } public static function GetUnreadMessagesCount( journal : JournalManager, contactEntry : weak< JournalContact > ) : Int32 { var messagesReceived : array< weak< JournalEntry > >; var playerReplies : array< weak< JournalEntry > >; journal.GetFlattenedMessagesAndChoices( contactEntry, messagesReceived, playerReplies ); return messagesReceived.Size(); } public static function FindConversationHash( journal : JournalManager, entry : weak< JournalEntry > ) : Int32 { var conversation : JournalPhoneConversation; while( entry != NULL ) { conversation = ( ( JournalPhoneConversation )( entry ) ); if( conversation ) { return journal.GetEntryHash( conversation ); } entry = journal.GetParentEntry( entry ); } return 0; } public static function FindContactHash( journal : JournalManager, entry : weak< JournalEntry > ) : Int32 { var contact : JournalContact; while( entry != NULL ) { contact = ( ( JournalContact )( entry ) ); if( contact ) { return journal.GetEntryHash( contact ); } entry = journal.GetParentEntry( entry ); } return 0; } }