using SPTarkov.DI.Annotations; using SPTarkov.Server.Core.Helpers; using SPTarkov.Server.Core.Models.Common; using SPTarkov.Server.Core.Models.Eft.Profile; using SPTarkov.Server.Core.Models.Enums; using SPTarkov.Server.Core.Models.Spt.Config; using SPTarkov.Server.Core.Models.Spt.Dialog; using SPTarkov.Server.Core.Models.Utils; using SPTarkov.Server.Core.Servers; using SPTarkov.Server.Core.Utils; using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel; namespace SPTarkov.Server.Core.Services; [Injectable(InjectionType.Singleton)] public class GiftService( ISptLogger logger, MailSendService mailSendService, ServerLocalisationService serverLocalisationService, TimeUtil timeUtil, ProfileHelper profileHelper, ConfigServer configServer ) { protected readonly GiftsConfig GiftConfig = configServer.GetConfig(); /// /// Does a gift with a specific ID exist in db /// /// Gift id to check for /// True if it exists in db public bool GiftExists(string giftId) { return GiftConfig.Gifts.ContainsKey(giftId); } public Gift? GetGiftById(string giftId) { GiftConfig.Gifts.TryGetValue(giftId, out var gift); return gift; } /// /// Get dictionary of all gifts /// /// Dict keyed by gift id public Dictionary GetGifts() { return GiftConfig.Gifts; } /// /// Get an array of all gift ids /// /// String list of gift ids public IEnumerable GetGiftIds() { return GiftConfig.Gifts.Keys; } /// /// Send player a gift from a range of sources /// /// Player to send gift to / sessionID /// ID of gift in configs/gifts.json to send player /// Outcome of sending gift to player public GiftSentResult SendGiftToPlayer(MongoId playerId, string giftId) { var giftData = GetGiftById(giftId); if (giftData is null) { return GiftSentResult.FAILED_GIFT_DOESNT_EXIST; } var maxGiftsToSendCount = giftData.MaxToSendPlayer ?? 1; if (profileHelper.PlayerHasReceivedMaxNumberOfGift(playerId, giftId, maxGiftsToSendCount)) { if (logger.IsLogEnabled(LogLevel.Debug)) { logger.Debug($"Player already received gift: {giftId}"); } return GiftSentResult.FAILED_GIFT_ALREADY_RECEIVED; } if (giftData.Items?.Count > 0 && giftData.CollectionTimeHours is null) { logger.Warning($"Gift {giftId} has items but no collection time limit, defaulting to 48 hours"); } // Handle system messages if (giftData.Sender == GiftSenderType.System) { // Has a localisable text id to send to player if (giftData.LocaleTextId is not null) { mailSendService.SendLocalisedSystemMessageToPlayer( playerId, giftData.LocaleTextId, giftData.Items, giftData.ProfileChangeEvents, timeUtil.GetHoursAsSeconds(giftData.CollectionTimeHours ?? 1) ); } else { mailSendService.SendSystemMessageToPlayer( playerId, giftData.MessageText, giftData.Items, timeUtil.GetHoursAsSeconds(giftData.CollectionTimeHours ?? 1), giftData.ProfileChangeEvents ); } } // Handle user messages else if (giftData.Sender == GiftSenderType.User) { mailSendService.SendUserMessageToPlayer( playerId, giftData.SenderDetails, giftData.MessageText, giftData.Items, timeUtil.GetHoursAsSeconds(giftData.CollectionTimeHours ?? 1) ); } else if (giftData.Sender == GiftSenderType.Trader) { mailSendService.SendLocalisedNpcMessageToPlayer( playerId, giftData.Trader, MessageType.MessageWithItems, giftData.LocaleTextId ?? giftData.LocaleTextId, giftData.Items, timeUtil.GetHoursAsSeconds(giftData.CollectionTimeHours ?? 1) ); } else { // TODO: further split out into different message systems like above SYSTEM method // Trader / ragfair SendMessageDetails details = new() { RecipientId = playerId, Sender = GetMessageType(giftData), SenderDetails = new UserDialogInfo { Id = GetSenderId(giftData), Aid = 1234567, // TODO - pass proper aid value Info = null, }, MessageText = giftData.MessageText, Items = giftData.Items, ItemsMaxStorageLifetimeSeconds = timeUtil.GetHoursAsSeconds(giftData.CollectionTimeHours ?? 0), }; if (giftData.Trader is not null) { details.Trader = giftData.Trader; } mailSendService.SendMessageToPlayer(details); } profileHelper.FlagGiftReceivedInProfile(playerId, giftId, maxGiftsToSendCount); return GiftSentResult.SUCCESS; } /// /// Get sender id based on gifts sender type enum /// /// Gift to send player /// trader/user/system id private string? GetSenderId(Gift giftData) { if (giftData.Sender == GiftSenderType.Trader) { return Enum.GetName(typeof(GiftSenderType), giftData.Sender); } if (giftData.Sender == GiftSenderType.User) { return giftData.Sender.ToString(); } return null; } /// /// Convert GiftSenderType into a dialog MessageType /// /// Gift to send player /// MessageType enum value protected MessageType? GetMessageType(Gift giftData) { switch (giftData.Sender) { case GiftSenderType.System: return MessageType.SystemMessage; case GiftSenderType.Trader: return MessageType.NpcTraderMessage; case GiftSenderType.User: return MessageType.UserMessage; default: logger.Error(serverLocalisationService.GetText("gift-unable_to_handle_message_type_command", giftData.Sender)); return null; } } /// /// Prapor sends gifts to player for first week after profile creation /// /// Player ID /// What day to give gift for public void SendPraporStartingGift(MongoId sessionId, int day) { var giftId = day switch { 1 => "PraporGiftDay1", 2 => "PraporGiftDay2", _ => null, }; if (giftId is not null) { if (!profileHelper.PlayerHasReceivedMaxNumberOfGift(sessionId, giftId, 1)) { SendGiftToPlayer(sessionId, giftId); } } } /// /// Send player a gift with silent received check /// /// ID of gift to send /// Session ID of player to send to /// Optional, how many to send public void SendGiftWithSilentReceivedCheck(string giftId, MongoId sessionId, int giftCount) { if (!profileHelper.PlayerHasReceivedMaxNumberOfGift(sessionId, giftId, giftCount)) { SendGiftToPlayer(sessionId, giftId); } } }