using Core.Annotations; using Core.Helpers; using Core.Helpers.Dialogue; using Core.Models.Eft.Dialog; using Core.Models.Eft.Profile; using Core.Models.Enums; using Core.Models.Spt.Config; using Core.Models.Utils; using Core.Servers; using Core.Services; using Core.Utils; namespace Core.Controllers; [Injectable] public class DialogueController { protected ISptLogger _logger; protected TimeUtil _timeUtil; protected DialogueHelper _dialogueHelper; protected ProfileHelper _profileHelper; protected ConfigServer _configServer; protected SaveServer _saveServer; protected LocalisationService _localisationService; protected List _dialogueChatBots; protected CoreConfig _coreConfig; public DialogueController( ISptLogger logger, TimeUtil timeUtil, DialogueHelper dialogueHelper, ProfileHelper profileHelper, ConfigServer configServer, SaveServer saveServer, LocalisationService localisationService, IEnumerable dialogueChatBots) { _logger = logger; _timeUtil = timeUtil; _dialogueHelper = dialogueHelper; _profileHelper = profileHelper; _configServer = configServer; _saveServer = saveServer; _localisationService = localisationService; _dialogueChatBots = dialogueChatBots.ToList(); _coreConfig = _configServer.GetConfig(); } /// /// /// /// public void RegisterChatBot(IDialogueChatBot chatBot) // TODO: this is in with the helper types { if (_dialogueChatBots.Any((cb) => cb.GetChatBot().Id == chatBot.GetChatBot().Id)) { _logger.Error(_localisationService.GetText("dialog-chatbot_id_already_exists", chatBot.GetChatBot().Id)); } _dialogueChatBots.Add(chatBot); } /// /// Handle onUpdate spt event /// public void Update() { var profiles = _saveServer.GetProfiles(); foreach (var kvp in profiles) { RemoveExpiredItemsFromMessages(kvp.Key); } } /// /// Handle client/friend/list /// /// session id /// GetFriendListDataResponse public GetFriendListDataResponse GetFriendList(string sessionId) { // Add all chatbots to the friends list var friends = GetActiveChatBots(); // Add any friends the user has after the chatbots var profile = _profileHelper.GetFullProfile(sessionId); if (profile?.FriendProfileIds is not null) { foreach (var friendId in profile.FriendProfileIds) { var friendProfile = _profileHelper.GetChatRoomMemberFromSessionId(friendId); if (friendProfile is not null) { friends.Add(new UserDialogInfo { Id = friendProfile.Id, Aid = friendProfile.Aid, Info = friendProfile.Info, } ); } } } return new GetFriendListDataResponse { Friends = friends, Ignore = [], InIgnoreList = [] }; } private List GetActiveChatBots() { var activeBots = new List(); var chatBotConfig = _coreConfig.Features.ChatbotFeatures; foreach (var bot in _dialogueChatBots) { var botData = bot.GetChatBot(); if (chatBotConfig.EnabledBots.ContainsKey(botData.Id)) { activeBots.Add(botData); } } return activeBots; } /// /// Handle client/mail/dialog/list /// Create array holding trader dialogs and mail interactions with player /// Set the content of the dialogue on the list tab. /// /// Session Id /// list of dialogs public List GenerateDialogueList(string sessionId) { var data = new List(); foreach (var dialogueId in _dialogueHelper.GetDialogsForProfile(sessionId)) { data.Add(GetDialogueInfo(dialogueId.Key, sessionId)); } return data; } /// /// Get the content of a dialogue /// /// Dialog id /// Session Id /// DialogueInfo public DialogueInfo GetDialogueInfo( string? dialogueId, string sessionId) { var dialogs = _dialogueHelper.GetDialogsForProfile(sessionId); var dialogue = dialogs.GetValueOrDefault(dialogueId); var result = new DialogueInfo { Id = dialogueId, Type = dialogue.Type ?? MessageType.NPC_TRADER, Message = _dialogueHelper.GetMessagePreview(dialogue), New = dialogue.New, AttachmentsNew = dialogue.AttachmentsNew, Pinned = dialogue.Pinned, Users = GetDialogueUsers(dialogue, dialogue.Type.Value, sessionId), }; return result; } /// /// Get the users involved in a dialog (player + other party) /// /// The dialog to check for users /// What type of message is being sent /// Player id /// UserDialogInfo list public List GetDialogueUsers( Dialogue dialog, MessageType messageType, string sessionId) { var profile = _saveServer.GetProfile(sessionId); // User to user messages are special in that they need the player to exist in them, add if they don't if (messageType == MessageType.USER_MESSAGE && dialog.Users.All(userDialog => userDialog.Id != profile.CharacterData.PmcData.SessionId)) { // Nullguard dialog.Users ??= []; dialog.Users.Add( new UserDialogInfo { Id = profile.CharacterData.PmcData.SessionId, Aid = profile.CharacterData.PmcData.Aid, Info = new UserDialogDetails { Level = profile.CharacterData.PmcData.Info.Level, Nickname = profile.CharacterData.PmcData.Info.Nickname, Side = profile.CharacterData.PmcData.Info.Side, MemberCategory = profile.CharacterData.PmcData.Info.MemberCategory, SelectedMemberCategory = profile.CharacterData.PmcData.Info.SelectedMemberCategory, }, }); } return dialog.Users; } /// /// Handle client/mail/dialog/view /// Handle player clicking 'messenger' and seeing all the messages they've received /// Set the content of the dialogue on the details panel, showing all the messages /// for the specified dialogue. /// /// Get dialog request /// Session id /// GetMailDialogViewResponseData object public GetMailDialogViewResponseData GenerateDialogueView( GetMailDialogViewRequestData request, string sessionId) { throw new NotImplementedException(); } /// /// Get dialog from player profile, create if doesn't exist /// /// Player profile /// get dialog request /// Dialogue private Dialogue GetDialogByIdFromProfile( SptProfile profile, GetMailDialogViewRequestData request) { throw new NotImplementedException(); } /// /// Get the users involved in a mail between two entities /// /// Player profile /// The participants of the mail /// UserDialogInfo list private List GetProfilesForMail( SptProfile fullProfile, List? userDialogs) { throw new NotImplementedException(); } /// /// Get a count of messages with attachments from a particular dialog /// /// Session id /// Dialog id /// Count of messages with attachments private int GetUnreadMessagesWithAttachmentsCount( string sessionId, string dialogueId) { throw new NotImplementedException(); } /// /// Does list have messages with uncollected rewards (includes expired rewards) /// /// Messages to check /// true if uncollected rewards found private bool MessagesHaveUncollectedRewards(List messages) { throw new NotImplementedException(); } /// /// Handle client/mail/dialog/remove /// Remove an entire dialog with an entity (trader/user) /// /// id of the dialog to remove /// Player id public void RemoveDialogue( string? dialogueId, string sessionId) { throw new NotImplementedException(); } /// /// Handle client/mail/dialog/pin && Handle client/mail/dialog/unpin /// /// /// /// public void SetDialoguePin( string? dialogueId, bool shouldPin, string sessionId) { throw new NotImplementedException(); } /// /// Handle client/mail/dialog/read /// Set a dialog to be read (no number alert/attachment alert) /// /// Dialog ids to set as read /// Player profile id public void SetRead( List? dialogueIds, string sessionId) { throw new NotImplementedException(); } /// /// Handle client/mail/dialog/getAllAttachments /// Get all uncollected items attached to mail in a particular dialog /// /// Dialog to get mail attachments from /// Session id /// GetAllAttachmentsResponse or null if dialogue doesnt exist public GetAllAttachmentsResponse? GetAllAttachments( string dialogueId, string sessionId) { throw new NotImplementedException(); } /// /// handle client/mail/msg/send /// /// /// /// public string SendMessage( string sessionId, SendMessageRequest request) { throw new NotImplementedException(); } /// /// Get messages from a specific dialog that have items not expired /// /// Session id /// Dialog to get mail attachments from /// message list private List GetActiveMessagesFromDialogue( string sessionId, string dialogueId) { throw new NotImplementedException(); } /// /// Return list of messages with uncollected items (includes expired) /// /// Messages to parse /// messages with items to collect private List GetMessageWithAttachments(List messages) { throw new NotImplementedException(); } /// /// Delete expired items from all messages in player profile. triggers when updating traders. /// /// Session id private void RemoveExpiredItemsFromMessages(string sessionId) { foreach (var dialogueId in _dialogueHelper.GetDialogsForProfile(sessionId)) { RemoveExpiredItemsFromMessage(sessionId, dialogueId.Key); } } /// /// Removes expired items from a message in player profile /// /// Session id /// Dialog id private void RemoveExpiredItemsFromMessage( string sessionId, string dialogueId) { var dialogs = _dialogueHelper.GetDialogsForProfile(sessionId); if (!dialogs.TryGetValue(dialogueId, out var dialog)) { return; } foreach (var message in dialog.Messages) { if (MessageHasExpired(message)) { message.Items = new MessageItems(); } } } /** * Has a dialog message expired * @param message Message to check expiry of * @returns true or false */ protected bool MessageHasExpired(Message message) { return _timeUtil.GetTimeStamp() > message.DateTime + (message.MaxStorageTime ?? 0); } public FriendRequestSendResponse SendFriendRequest(string sessionId, FriendRequestData request) { throw new NotImplementedException(); } public void DeleteFriend(string sessionID, DeleteFriendRequest request) { throw new NotImplementedException(); } }